diff options
715 files changed, 16694 insertions, 7701 deletions
diff --git a/.github/renovate.json5 b/.github/renovate.json5 new file mode 100644 index 00000000000..87f5f103ddf --- /dev/null +++ b/.github/renovate.json5 @@ -0,0 +1,14 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + // Let Renovatebot keep an opened issue that tracks our dependencies + "dependencyDashboard": true, + // Disable "normal" package updates + "enabledManagers": [], + // Update lockfiles once per week + "lockFileMaintenance": { + "enabled": true, + "schedule": [ + "before 5am on Tuesday" + ] + } +} diff --git a/.gitignore b/.gitignore index ce9db8b861d..f84a3704ca9 100644 --- a/.gitignore +++ b/.gitignore @@ -88,12 +88,12 @@ package.json tests/rustdoc-gui/src/**.lock ## direnv -.envrc -.direnv/ +/.envrc +/.direnv/ ## nix -flake.nix +/flake.nix flake.lock -default.nix +/default.nix # Before adding new lines, see the comment at the top. diff --git a/Cargo.lock b/Cargo.lock index 12970dd1ebf..38b009bfc70 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -57,9 +57,9 @@ dependencies = [ [[package]] name = "allocator-api2" -version = "0.2.18" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" +checksum = "45862d1c77f2228b9e10bc609d5bc203d86ebc9b87ad8d5d5167a6c9abf739d9" [[package]] name = "ammonia" @@ -182,9 +182,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.92" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74f37166d7d48a0284b99dd824694c26119c700b53bf0d1540cdb147dbdaaf13" +checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775" dependencies = [ "backtrace", ] @@ -257,21 +257,15 @@ dependencies = [ [[package]] name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" [[package]] name = "blake3" -version = "1.5.4" +version = "1.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d82033247fd8e890df8f740e407ad4d038debb9eb1f40533fffb32e7d17dc6f7" +checksum = "b8ee0c1824c4dea5b5f81736aff91bae041d2c07ee1192bec91054e10e3e601e" dependencies = [ "arrayref", "arrayvec", @@ -291,12 +285,12 @@ dependencies = [ [[package]] name = "bstr" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40723b8fb387abc38f4f4a37c09073622e41dd12327033091ef8950659e6dc0c" +checksum = "1a68f1f47cdf0ec8ee4b941b2eee2a80cb796db73118c0dd09ac63fbe405be22" dependencies = [ "memchr", - "regex-automata 0.4.8", + "regex-automata 0.4.9", "serde", ] @@ -356,9 +350,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" +checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" [[package]] name = "camino" @@ -384,9 +378,9 @@ dependencies = [ [[package]] name = "cargo-platform" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24b1f0365a6c6bb4020cd05806fd0d33c44d38046b8bd7f0e40814b9763cabfc" +checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea" dependencies = [ "serde", ] @@ -476,9 +470,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.20" +version = "4.5.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8" +checksum = "fb3b4b9e5a7c7514dfa52869339ee98b3156b0bfb4e8a77c4ff4babb64b1604f" dependencies = [ "clap_builder", "clap_derive", @@ -496,9 +490,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.20" +version = "4.5.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54" +checksum = "b17a95aa67cc7b5ebd32aa5370189aa0d79069ef1c64ce893bd30fb24bff20ec" dependencies = [ "anstream", "anstyle", @@ -509,9 +503,9 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.5.36" +version = "4.5.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86bc73de94bc81e52f3bebec71bc4463e9748f7a59166663e32044669577b0e2" +checksum = "d9647a559c112175f17cf724dc72d3645680a883c58481332779192b0d8e7a01" dependencies = [ "clap", ] @@ -525,14 +519,14 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] name = "clap_lex" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" +checksum = "afb84c814227b90d6895e01398aee0d8033c00e7466aca416fb6a8e0eb19d8a7" [[package]] name = "clippy" @@ -556,7 +550,7 @@ dependencies = [ "rustc_tools_util", "serde", "serde_json", - "syn 2.0.87", + "syn 2.0.90", "tempfile", "termize", "tokio", @@ -650,23 +644,23 @@ dependencies = [ [[package]] name = "color-print" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ee543c60ff3888934877a5671f45494dd27ed4ba25c6670b9a7576b7ed7a8c0" +checksum = "3aa954171903797d5623e047d9ab69d91b493657917bdfb8c2c80ecaf9cdb6f4" dependencies = [ "color-print-proc-macro", ] [[package]] name = "color-print-proc-macro" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ff1a80c5f3cb1ca7c06ffdd71b6a6dd6d8f896c42141fbd43f50ed28dcdb93" +checksum = "692186b5ebe54007e45a59aea47ece9eb4108e141326c304cdc91699a7118a22" dependencies = [ "nom", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -770,9 +764,9 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.14" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" +checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3" dependencies = [ "libc", ] @@ -857,9 +851,9 @@ dependencies = [ [[package]] name = "curl-sys" -version = "0.4.77+curl-8.10.1" +version = "0.4.78+curl-8.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f469e8a5991f277a208224f6c7ad72ecb5f986e36d09ae1f2c1bb9259478a480" +checksum = "8eec768341c5c7789611ae51cf6c459099f22e64a5d5d0ce4892434e33821eaf" dependencies = [ "cc", "libc", @@ -891,7 +885,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -902,7 +896,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -939,7 +933,7 @@ checksum = "62d671cc41a825ebabc75757b62d3d168c577f9149b2d49ece1dad1f72119d25" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -960,7 +954,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -970,7 +964,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" dependencies = [ "derive_builder_core", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -982,7 +976,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -1060,7 +1054,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -1142,12 +1136,12 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.9" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -1185,9 +1179,9 @@ checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" [[package]] name = "fastrand" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" +checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4" [[package]] name = "field-offset" @@ -1213,9 +1207,9 @@ dependencies = [ [[package]] name = "flate2" -version = "1.0.34" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0" +checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" dependencies = [ "crc32fast", "miniz_oxide 0.8.0", @@ -1357,7 +1351,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -1482,7 +1476,7 @@ dependencies = [ "aho-corasick", "bstr", "log", - "regex-automata 0.4.8", + "regex-automata 0.4.9", "regex-syntax 0.8.5", ] @@ -1497,11 +1491,12 @@ dependencies = [ [[package]] name = "handlebars" -version = "5.1.2" +version = "6.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d08485b96a0e6393e9e4d1b8d48cf74ad6c063cd905eb33f42c1ce3f0377539b" +checksum = "fd4ccde012831f9a071a637b0d4e31df31c0f6c525784b35ae76a9ac6bc1e315" dependencies = [ "log", + "num-order", "pest", "pest_derive", "serde", @@ -1522,9 +1517,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.0" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" dependencies = [ "foldhash", ] @@ -1590,7 +1585,7 @@ dependencies = [ "markup5ever", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -1632,6 +1627,18 @@ dependencies = [ ] [[package]] +name = "icu_collections" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] name = "icu_list" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1685,6 +1692,51 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" [[package]] +name = "icu_normalizer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" + +[[package]] +name = "icu_properties" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" + +[[package]] name = "icu_provider" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1722,7 +1774,7 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -1739,12 +1791,23 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "idna" -version = "0.5.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" dependencies = [ - "unicode-bidi", - "unicode-normalization", + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +dependencies = [ + "icu_normalizer", + "icu_properties", ] [[package]] @@ -1763,7 +1826,7 @@ dependencies = [ "globset", "log", "memchr", - "regex-automata 0.4.8", + "regex-automata 0.4.9", "same-file", "walkdir", "winapi-util", @@ -1777,27 +1840,27 @@ checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" [[package]] name = "indexmap" -version = "2.6.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" +checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" dependencies = [ "equivalent", - "hashbrown 0.15.0", + "hashbrown 0.15.2", "rustc-rayon", "serde", ] [[package]] name = "indicatif" -version = "0.17.8" +version = "0.17.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "763a5a8f45087d6bcea4222e7b72c291a054edf80e4ef6efd2a4979878c7bea3" +checksum = "cbf675b85ed934d3c67b5c5469701eec7db22689d0a2139d856e0925fa28b281" dependencies = [ "console", - "instant", "number_prefix", "portable-atomic", - "unicode-width 0.1.14", + "unicode-width 0.2.0", + "web-time", ] [[package]] @@ -1829,15 +1892,6 @@ dependencies = [ ] [[package]] -name = "instant" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" -dependencies = [ - "cfg-if", -] - -[[package]] name = "intl-memoizer" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1873,9 +1927,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.11" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" [[package]] name = "jobserver" @@ -1888,10 +1942,11 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.72" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" +checksum = "a865e038f7f6ed956f788f0d7d60c541fff74c7bd74272c5d4cf15c63743e705" dependencies = [ + "once_cell", "wasm-bindgen", ] @@ -1914,7 +1969,7 @@ dependencies = [ "anyhow", "clap", "fs-err", - "rustc-hash 2.0.0", + "rustc-hash 2.1.0", "rustdoc-json-types", "serde", "serde_json", @@ -1957,9 +2012,9 @@ checksum = "baff4b617f7df3d896f97fe922b64817f6cd9a756bb81d40f8883f2f66dcb401" [[package]] name = "libc" -version = "0.2.164" +version = "0.2.167" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "433bfe06b8c75da9b2e3fbea6e5329ff87748f0b144ef75306e674c3f6f7c13f" +checksum = "09d6582e104315a817dff97f75133544b2e094ee22447d2acf4a74e189ba06fc" [[package]] name = "libdbus-sys" @@ -1992,9 +2047,9 @@ dependencies = [ [[package]] name = "libloading" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" +checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" dependencies = [ "cfg-if", "windows-targets 0.52.6", @@ -2012,7 +2067,7 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "bitflags 2.6.0", + "bitflags", "libc", "redox_syscall", ] @@ -2054,9 +2109,9 @@ checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" [[package]] name = "litemap" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "643cb0b8d4fcc284004d5fd0d67ccf61dfffadb7f75e1e71bc420f4688a3a704" +checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" [[package]] name = "lld-wrapper" @@ -2147,9 +2202,9 @@ dependencies = [ [[package]] name = "mdbook" -version = "0.4.40" +version = "0.4.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b45a38e19bd200220ef07c892b0157ad3d2365e5b5a267ca01ad12182491eea5" +checksum = "fe1f98b8d66e537d2f0ba06e7dec4f44001deec539a2d18bfc102d6a86189148" dependencies = [ "ammonia", "anyhow", @@ -2306,7 +2361,7 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" dependencies = [ - "bitflags 2.6.0", + "bitflags", "cfg-if", "cfg_aliases", "libc", @@ -2410,6 +2465,21 @@ dependencies = [ ] [[package]] +name = "num-modular" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17bb261bf36fa7d83f4c294f834e91256769097b3cb505d44831e0a179ac647f" + +[[package]] +name = "num-order" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "537b596b97c40fcf8056d153049eb22f481c17ebce72a513ec9286e4986d1bb6" +dependencies = [ + "num-modular", +] + +[[package]] name = "num-rational" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2462,7 +2532,7 @@ checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" dependencies = [ "crc32fast", "flate2", - "hashbrown 0.15.0", + "hashbrown 0.15.2", "indexmap", "memchr", "ruzstd", @@ -2610,9 +2680,9 @@ dependencies = [ [[package]] name = "pathdiff" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d61c5ce1153ab5b689d0c074c4e7fc613e942dfb7dd9eea5ab202d2ad91fe361" +checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" [[package]] name = "percent-encoding" @@ -2660,7 +2730,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -2762,9 +2832,9 @@ dependencies = [ [[package]] name = "portable-atomic" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2" +checksum = "280dc24453071f1b63954171985a0b0d30058d287960968b9b2aca264c8d4ee6" [[package]] name = "powerfmt" @@ -2805,9 +2875,9 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" [[package]] name = "proc-macro2" -version = "1.0.89" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" dependencies = [ "unicode-ident", ] @@ -2827,7 +2897,7 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57206b407293d2bcd3af849ce869d52068623f19e1b5ff8e8778e3309439682b" dependencies = [ - "bitflags 2.6.0", + "bitflags", "memchr", "unicase", ] @@ -2838,7 +2908,7 @@ version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76979bea66e7875e7509c4ec5300112b316af87fa7a252ca91c448b32dfe3993" dependencies = [ - "bitflags 2.6.0", + "bitflags", "memchr", "pulldown-cmark-escape 0.10.1", "unicase", @@ -2850,7 +2920,7 @@ version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "679341d22c78c6c649893cbd6c3278dcbe9fc4faa62fea3a9296ae2b50c14625" dependencies = [ - "bitflags 2.6.0", + "bitflags", "memchr", "pulldown-cmark-escape 0.11.0", "unicase", @@ -2954,7 +3024,7 @@ version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" dependencies = [ - "bitflags 2.6.0", + "bitflags", ] [[package]] @@ -2976,7 +3046,7 @@ checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.8", + "regex-automata 0.4.9", "regex-syntax 0.8.5", ] @@ -3000,9 +3070,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", @@ -3068,9 +3138,9 @@ dependencies = [ "proc-macro2", "quote", "rinja_parser", - "rustc-hash 2.0.0", + "rustc-hash 2.1.0", "serde", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -3103,7 +3173,7 @@ dependencies = [ "regex", "serde_json", "similar", - "wasmparser 0.216.0", + "wasmparser 0.219.1", ] [[package]] @@ -3132,9 +3202,9 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustc-hash" -version = "2.0.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" +checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497" [[package]] name = "rustc-main" @@ -3199,7 +3269,7 @@ version = "1.0.1" name = "rustc_abi" version = "0.0.0" dependencies = [ - "bitflags 2.6.0", + "bitflags", "rand", "rand_xoshiro", "rustc_data_structures", @@ -3213,11 +3283,11 @@ dependencies = [ [[package]] name = "rustc_apfloat" -version = "0.2.1+llvm-462a31f5a5ab" +version = "0.2.2+llvm-462a31f5a5ab" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "886d94c63c812a8037c4faca2607453a0fa4cf82f734665266876b022244543f" +checksum = "121e2195ff969977a4e2b5c9965ea867fce7e4cb5aee5b09dee698a7932d574f" dependencies = [ - "bitflags 1.3.2", + "bitflags", "smallvec", ] @@ -3232,7 +3302,7 @@ dependencies = [ name = "rustc_ast" version = "0.0.0" dependencies = [ - "bitflags 2.6.0", + "bitflags", "memchr", "rustc_ast_ir", "rustc_data_structures", @@ -3395,7 +3465,7 @@ dependencies = [ name = "rustc_codegen_llvm" version = "0.0.0" dependencies = [ - "bitflags 2.6.0", + "bitflags", "itertools", "libc", "measureme", @@ -3433,7 +3503,7 @@ version = "0.0.0" dependencies = [ "ar_archive_writer", "arrayvec", - "bitflags 2.6.0", + "bitflags", "cc", "either", "itertools", @@ -3445,6 +3515,7 @@ dependencies = [ "rustc_abi", "rustc_arena", "rustc_ast", + "rustc_ast_pretty", "rustc_attr", "rustc_data_structures", "rustc_errors", @@ -3470,7 +3541,7 @@ dependencies = [ "thin-vec", "thorin-dwp", "tracing", - "wasm-encoder 0.216.0", + "wasm-encoder 0.219.1", "windows", ] @@ -3505,7 +3576,7 @@ name = "rustc_data_structures" version = "0.0.0" dependencies = [ "arrayvec", - "bitflags 2.6.0", + "bitflags", "either", "elsa", "ena", @@ -3516,7 +3587,7 @@ dependencies = [ "memmap2", "parking_lot", "portable-atomic", - "rustc-hash 2.0.0", + "rustc-hash 2.1.0", "rustc-rayon", "rustc-stable-hash", "rustc_arena", @@ -3689,7 +3760,7 @@ dependencies = [ "fluent-syntax", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", "unic-langid", ] @@ -3823,7 +3894,7 @@ version = "0.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -3971,7 +4042,7 @@ version = "0.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", "synstructure", ] @@ -3979,7 +4050,7 @@ dependencies = [ name = "rustc_metadata" version = "0.0.0" dependencies = [ - "bitflags 2.6.0", + "bitflags", "libc", "libloading", "odht", @@ -4010,7 +4081,7 @@ dependencies = [ name = "rustc_middle" version = "0.0.0" dependencies = [ - "bitflags 2.6.0", + "bitflags", "derive-where", "either", "field-offset", @@ -4161,7 +4232,7 @@ dependencies = [ name = "rustc_parse" version = "0.0.0" dependencies = [ - "bitflags 2.6.0", + "bitflags", "rustc_ast", "rustc_ast_pretty", "rustc_data_structures", @@ -4218,7 +4289,7 @@ dependencies = [ name = "rustc_pattern_analysis" version = "0.0.0" dependencies = [ - "rustc-hash 2.0.0", + "rustc-hash 2.1.0", "rustc_abi", "rustc_apfloat", "rustc_arena", @@ -4301,7 +4372,7 @@ dependencies = [ name = "rustc_resolve" version = "0.0.0" dependencies = [ - "bitflags 2.6.0", + "bitflags", "pulldown-cmark 0.11.3", "rustc_arena", "rustc_ast", @@ -4329,7 +4400,7 @@ dependencies = [ name = "rustc_sanitizers" version = "0.0.0" dependencies = [ - "bitflags 2.6.0", + "bitflags", "rustc_abi", "rustc_data_structures", "rustc_hir", @@ -4356,7 +4427,7 @@ dependencies = [ name = "rustc_session" version = "0.0.0" dependencies = [ - "bitflags 2.6.0", + "bitflags", "getopts", "libc", "rustc_abi", @@ -4437,7 +4508,7 @@ dependencies = [ name = "rustc_target" version = "0.0.0" dependencies = [ - "bitflags 2.6.0", + "bitflags", "object 0.36.5", "rustc_abi", "rustc_data_structures", @@ -4538,7 +4609,7 @@ dependencies = [ name = "rustc_type_ir" version = "0.0.0" dependencies = [ - "bitflags 2.6.0", + "bitflags", "derive-where", "indexmap", "rustc-hash 1.1.0", @@ -4560,7 +4631,7 @@ version = "0.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", "synstructure", ] @@ -4614,7 +4685,7 @@ name = "rustdoc-json-types" version = "0.1.0" dependencies = [ "bincode", - "rustc-hash 2.0.0", + "rustc-hash 2.1.0", "serde", "serde_json", ] @@ -4649,7 +4720,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -4683,11 +4754,11 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.38" +version = "0.38.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa260229e6538e52293eeb577aabd09945a09d6d9cc0fc550ed7529056c2e32a" +checksum = "d7f649912bc1495e167a6edee79151c84b1bad49748cb4f1f1167f459f6224f6" dependencies = [ - "bitflags 2.6.0", + "bitflags", "errno", "libc", "linux-raw-sys", @@ -4726,9 +4797,9 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.26" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01227be5826fa0690321a2ba6c5cd57a19cf3f6a09e76973b58e61de6ab9d1c1" +checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" dependencies = [ "windows-sys 0.59.0", ] @@ -4771,29 +4842,29 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.214" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f55c3193aca71c12ad7890f1785d2b73e1b9f63a0bbc353c08ef26fe03fc56b5" +checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.214" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de523f781f095e28fa605cdce0f8307e451cc0fd14e2eb4cd2e98a355b147766" +checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] name = "serde_json" -version = "1.0.132" +version = "1.0.133" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" +checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" dependencies = [ "indexmap", "itoa", @@ -4883,9 +4954,9 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "socket2" -version = "0.5.7" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" dependencies = [ "libc", "windows-sys 0.52.0", @@ -4903,9 +4974,9 @@ dependencies = [ [[package]] name = "spdx" -version = "0.10.6" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47317bbaf63785b53861e1ae2d11b80d6b624211d42cb20efcd210ee6f8a14bc" +checksum = "bae30cc7bfe3656d60ee99bf6836f472b0c53dddcbf335e253329abb16e535a2" dependencies = [ "smallvec", ] @@ -5044,9 +5115,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.87" +version = "2.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" +checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" dependencies = [ "proc-macro2", "quote", @@ -5061,7 +5132,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -5098,9 +5169,9 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.13.0" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b" +checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" dependencies = [ "cfg-if", "fastrand", @@ -5142,9 +5213,9 @@ dependencies = [ [[package]] name = "terminal_size" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f599bd7ca042cfdf8f4512b277c02ba102247820f9d9d4a9f521f496751a6ef" +checksum = "5352447f921fda68cf61b4101566c0bdb5104eff6804d0678e5227580ab6a4e9" dependencies = [ "rustix", "windows-sys 0.59.0", @@ -5179,22 +5250,22 @@ checksum = "a38c90d48152c236a3ab59271da4f4ae63d678c5d7ad6b7714d7cb9760be5e4b" [[package]] name = "thiserror" -version = "1.0.66" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d171f59dbaa811dbbb1aee1e73db92ec2b122911a48e1390dfe327a821ddede" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.66" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b08be0f17bd307950653ce45db00cd31200d82b624b36e181337d9c7d92765b5" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -5238,7 +5309,7 @@ dependencies = [ "ignore", "miropt-test-tools", "regex", - "rustc-hash 2.0.0", + "rustc-hash 2.1.0", "semver", "similar", "termcolor", @@ -5317,9 +5388,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.41.0" +version = "1.41.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "145f3413504347a2be84393cc8a7d2fb4d863b375909ea59f2158261aa258bbb" +checksum = "22cfb5bee7a6a52939ca9224d6ac897bb669134078daa8735560897f69de4d33" dependencies = [ "backtrace", "bytes", @@ -5389,13 +5460,13 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.27" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -5410,9 +5481,9 @@ dependencies = [ [[package]] name = "tracing-error" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d686ec1c0f384b1277f097b2f279a2ecc11afe8c133c1aabf036a27cb4cd206e" +checksum = "8b1581020d7a273442f5b45074a6a57d5757ad0a47dac0e9f0bd57b81936f3db" dependencies = [ "tracing", "tracing-subscriber", @@ -5566,7 +5637,7 @@ checksum = "1ed7f4237ba393424195053097c1516bd4590dc82b84f2f97c5c69e12704555b" dependencies = [ "proc-macro-hack", "quote", - "syn 2.0.87", + "syn 2.0.90", "unic-langid-impl", ] @@ -5577,16 +5648,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7e51b68083f157f853b6379db119d1c1be0e6e4dec98101079dec41f6f5cf6df" [[package]] -name = "unicode-bidi" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893" - -[[package]] name = "unicode-ident" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" [[package]] name = "unicode-normalization" @@ -5669,9 +5734,9 @@ dependencies = [ [[package]] name = "url" -version = "2.5.2" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" dependencies = [ "form_urlencoded", "idna", @@ -5685,12 +5750,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" [[package]] +name = "utf16_iter" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" + +[[package]] name = "utf8-width" version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "86bd8d4e895da8537e5315b8254664e6b769c4ff3db18321b297a1e7004392e3" [[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] name = "utf8parse" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -5747,9 +5824,9 @@ checksum = "0f76d9fa52234153eeb40b088de91a8c13dc28a912cf6f31cd89ca4bac9024e0" [[package]] name = "wasm-bindgen" -version = "0.2.95" +version = "0.2.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" +checksum = "d15e63b4482863c109d70a7b8706c1e364eb6ea449b201a76c5b89cedcec2d5c" dependencies = [ "cfg-if", "once_cell", @@ -5758,24 +5835,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.95" +version = "0.2.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" +checksum = "8d36ef12e3aaca16ddd3f67922bc63e48e953f126de60bd33ccc0101ef9998cd" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.95" +version = "0.2.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" +checksum = "705440e08b42d3e4b36de7d66c944be628d579796b8090bfa3471478a2260051" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -5783,22 +5860,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.95" +version = "0.2.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" +checksum = "98c9ae5a76e46f4deecd0f0255cc223cfa18dc9b261213b8aa0c7b36f61b3f1d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.95" +version = "0.2.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" +checksum = "6ee99da9c5ba11bd675621338ef6fa52296b76b83305e9b6e5c77d4c286d6d49" [[package]] name = "wasm-component-ld" @@ -5829,21 +5906,22 @@ dependencies = [ [[package]] name = "wasm-encoder" -version = "0.216.0" +version = "0.219.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04c23aebea22c8a75833ae08ed31ccc020835b12a41999e58c31464271b94a88" +checksum = "29cbbd772edcb8e7d524a82ee8cef8dd046fc14033796a754c3ad246d019fa54" dependencies = [ "leb128", + "wasmparser 0.219.1", ] [[package]] name = "wasm-encoder" -version = "0.219.1" +version = "0.221.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29cbbd772edcb8e7d524a82ee8cef8dd046fc14033796a754c3ad246d019fa54" +checksum = "de35b6c3ef1f53ac7a31b5e69bc00f1542ea337e7e7162dc34c68b537ff82690" dependencies = [ "leb128", - "wasmparser 0.219.1", + "wasmparser 0.221.0", ] [[package]] @@ -5864,21 +5942,11 @@ dependencies = [ [[package]] name = "wasmparser" -version = "0.216.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcdee6bea3619d311fb4b299721e89a986c3470f804b6d534340e412589028e3" -dependencies = [ - "bitflags 2.6.0", - "indexmap", -] - -[[package]] -name = "wasmparser" version = "0.218.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b09e46c7fceceaa72b2dd1a8a137ea7fd8f93dfaa69806010a709918e496c5dc" dependencies = [ - "bitflags 2.6.0", + "bitflags", ] [[package]] @@ -5888,7 +5956,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c771866898879073c53b565a6c7b49953795159836714ac56a5befb581227c5" dependencies = [ "ahash", - "bitflags 2.6.0", + "bitflags", "hashbrown 0.14.5", "indexmap", "semver", @@ -5896,28 +5964,49 @@ dependencies = [ ] [[package]] +name = "wasmparser" +version = "0.221.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8659e755615170cfe20da468865c989da78c5da16d8652e69a75acda02406a92" +dependencies = [ + "bitflags", + "indexmap", + "semver", +] + +[[package]] name = "wast" -version = "219.0.1" +version = "221.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f79a9d9df79986a68689a6b40bcc8d5d40d807487b235bebc2ac69a242b54a1" +checksum = "9d8eb1933d493dd07484a255c3f52236123333f5befaa3be36182a50d393ec54" dependencies = [ "bumpalo", "leb128", "memchr", - "unicode-width 0.1.14", - "wasm-encoder 0.219.1", + "unicode-width 0.2.0", + "wasm-encoder 0.221.0", ] [[package]] name = "wat" -version = "1.219.1" +version = "1.221.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bc3cf014fb336883a411cd662f987abf6a1d2a27f2f0008616a0070bbf6bd0d" +checksum = "c813fd4e5b2b97242830b56e7b7dc5479bc17aaa8730109be35e61909af83993" dependencies = [ "wast", ] [[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] name = "winapi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -5968,7 +6057,7 @@ dependencies = [ "rayon", "serde", "serde_json", - "syn 2.0.87", + "syn 2.0.90", "windows-metadata", ] @@ -6001,7 +6090,7 @@ checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -6012,7 +6101,7 @@ checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -6200,7 +6289,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad1673163c0cb14a6a19ddbf44dd4efe6f015ec1ebb8156710ac32501f19fba2" dependencies = [ "anyhow", - "bitflags 2.6.0", + "bitflags", "indexmap", "log", "serde", @@ -6231,6 +6320,12 @@ dependencies = [ ] [[package]] +name = "write16" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" + +[[package]] name = "writeable" version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -6267,9 +6362,9 @@ dependencies = [ [[package]] name = "yoke" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c5b1314b079b0930c31e3af543d8ee1757b1951ae1e1565ec704403a7240ca5" +checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" dependencies = [ "serde", "stable_deref_trait", @@ -6279,13 +6374,13 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95" +checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", "synstructure", ] @@ -6307,27 +6402,27 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] name = "zerofrom" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ec111ce797d0e0784a1116d0ddcdbea84322cd79e5d5ad173daeba4f93ab55" +checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" dependencies = [ "zerofrom-derive", ] [[package]] name = "zerofrom-derive" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5" +checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", "synstructure", ] @@ -6350,5 +6445,5 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] diff --git a/README.md b/README.md index 3690a9c93c5..d84d96a0e91 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ standard library, and documentation. ## Why Rust? -- **Performance:** Fast and memory-efficient, suitable for critical services, embedded devices, and easily integrate with other languages. +- **Performance:** Fast and memory-efficient, suitable for critical services, embedded devices, and easily integrated with other languages. - **Reliability:** Our rich type system and ownership model ensure memory and thread safety, reducing bugs at compile-time. diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 69ba78282f9..650525a2f52 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -3119,6 +3119,7 @@ pub struct FieldDef { pub ident: Option<Ident>, pub ty: P<Ty>, + pub default: Option<AnonConst>, pub is_placeholder: bool, } diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 3a4a8ce266e..2c09059fe19 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -1120,13 +1120,14 @@ fn walk_poly_trait_ref<T: MutVisitor>(vis: &mut T, p: &mut PolyTraitRef) { } pub fn walk_field_def<T: MutVisitor>(visitor: &mut T, fd: &mut FieldDef) { - let FieldDef { span, ident, vis, id, ty, attrs, is_placeholder: _, safety } = fd; + let FieldDef { span, ident, vis, id, ty, attrs, is_placeholder: _, safety, default } = fd; visitor.visit_id(id); visit_attrs(visitor, attrs); visitor.visit_vis(vis); visit_safety(visitor, safety); visit_opt(ident, |ident| visitor.visit_ident(ident)); visitor.visit_ty(ty); + visit_opt(default, |default| visitor.visit_anon_const(default)); visitor.visit_span(span); } diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 0b000c8cef8..a7f7c37693a 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -975,11 +975,13 @@ pub fn walk_struct_def<'a, V: Visitor<'a>>( } pub fn walk_field_def<'a, V: Visitor<'a>>(visitor: &mut V, field: &'a FieldDef) -> V::Result { - let FieldDef { attrs, id: _, span: _, vis, ident, ty, is_placeholder: _, safety: _ } = field; + let FieldDef { attrs, id: _, span: _, vis, ident, ty, is_placeholder: _, safety: _, default } = + field; walk_list!(visitor, visit_attribute, attrs); try_visit!(visitor.visit_vis(vis)); visit_opt!(visitor, visit_ident, ident); try_visit!(visitor.visit_ty(ty)); + visit_opt!(visitor, visit_anon_const, &*default); V::Result::output() } diff --git a/compiler/rustc_ast_lowering/messages.ftl b/compiler/rustc_ast_lowering/messages.ftl index a4dbf981115..f96c9fe8e32 100644 --- a/compiler/rustc_ast_lowering/messages.ftl +++ b/compiler/rustc_ast_lowering/messages.ftl @@ -45,10 +45,6 @@ ast_lowering_bad_return_type_notation_output = ast_lowering_bad_return_type_notation_position = return type notation not allowed in this position yet -ast_lowering_base_expression_double_dot = - base expression required after `..` - .suggestion = add a base expression here - ast_lowering_clobber_abi_not_supported = `clobber_abi` is not supported on this target @@ -57,6 +53,9 @@ ast_lowering_closure_cannot_be_static = closures cannot be static ast_lowering_coroutine_too_many_parameters = too many parameters for a coroutine (expected 0 or 1 parameters) +ast_lowering_default_field_in_tuple = default fields are not supported in tuple structs + .label = default fields are only supported on structs + ast_lowering_does_not_support_modifiers = the `{$class_name}` register class does not support template modifiers diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs index 447af57354f..2564d4e2772 100644 --- a/compiler/rustc_ast_lowering/src/errors.rs +++ b/compiler/rustc_ast_lowering/src/errors.rs @@ -38,6 +38,14 @@ pub(crate) struct InvalidAbi { pub suggestion: Option<InvalidAbiSuggestion>, } +#[derive(Diagnostic)] +#[diag(ast_lowering_default_field_in_tuple)] +pub(crate) struct TupleStructWithDefault { + #[primary_span] + #[label] + pub span: Span, +} + pub(crate) struct InvalidAbiReason(pub &'static str); impl Subdiagnostic for InvalidAbiReason { @@ -115,14 +123,6 @@ pub(crate) struct UnderscoreExprLhsAssign { } #[derive(Diagnostic)] -#[diag(ast_lowering_base_expression_double_dot, code = E0797)] -pub(crate) struct BaseExpressionDoubleDot { - #[primary_span] - #[suggestion(code = "/* expr */", applicability = "has-placeholders", style = "verbose")] - pub span: Span, -} - -#[derive(Diagnostic)] #[diag(ast_lowering_await_only_in_async_fn_and_blocks, code = E0728)] pub(crate) struct AwaitOnlyInAsyncFnAndBlocks { #[primary_span] diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 84e648f4923..2ad0ff3200e 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -19,10 +19,10 @@ use thin_vec::{ThinVec, thin_vec}; use visit::{Visitor, walk_expr}; use super::errors::{ - AsyncCoroutinesNotSupported, AwaitOnlyInAsyncFnAndBlocks, BaseExpressionDoubleDot, - ClosureCannotBeStatic, CoroutineTooManyParameters, - FunctionalRecordUpdateDestructuringAssignment, InclusiveRangeWithNoEnd, MatchArmWithNoBody, - NeverPatternWithBody, NeverPatternWithGuard, UnderscoreExprLhsAssign, + AsyncCoroutinesNotSupported, AwaitOnlyInAsyncFnAndBlocks, ClosureCannotBeStatic, + CoroutineTooManyParameters, FunctionalRecordUpdateDestructuringAssignment, + InclusiveRangeWithNoEnd, MatchArmWithNoBody, NeverPatternWithBody, NeverPatternWithGuard, + UnderscoreExprLhsAssign, }; use super::{ GenericArgsMode, ImplTraitContext, LoweringContext, ParamMode, ResolverAstLoweringExt, @@ -357,12 +357,9 @@ impl<'hir> LoweringContext<'_, 'hir> { ), ExprKind::Struct(se) => { let rest = match &se.rest { - StructRest::Base(e) => Some(self.lower_expr(e)), - StructRest::Rest(sp) => { - let guar = self.dcx().emit_err(BaseExpressionDoubleDot { span: *sp }); - Some(&*self.arena.alloc(self.expr_err(*sp, guar))) - } - StructRest::None => None, + StructRest::Base(e) => hir::StructTailExpr::Base(self.lower_expr(e)), + StructRest::Rest(sp) => hir::StructTailExpr::DefaultFields(*sp), + StructRest::None => hir::StructTailExpr::None, }; hir::ExprKind::Struct( self.arena.alloc(self.lower_qpath( @@ -1526,7 +1523,7 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::ExprKind::Struct( self.arena.alloc(hir::QPath::LangItem(lang_item, self.lower_span(span))), fields, - None, + hir::StructTailExpr::None, ) } diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index fb09f1c7fee..7d6c41992eb 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -17,7 +17,10 @@ use smallvec::{SmallVec, smallvec}; use thin_vec::ThinVec; use tracing::instrument; -use super::errors::{InvalidAbi, InvalidAbiReason, InvalidAbiSuggestion, MisplacedRelaxTraitBound}; +use super::errors::{ + InvalidAbi, InvalidAbiReason, InvalidAbiSuggestion, MisplacedRelaxTraitBound, + TupleStructWithDefault, +}; use super::{ AstOwner, FnDeclKind, ImplTraitContext, ImplTraitPosition, LoweringContext, ParamMode, ResolverAstLoweringExt, @@ -690,13 +693,27 @@ impl<'hir> LoweringContext<'_, 'hir> { VariantData::Tuple(fields, id) => { let ctor_id = self.lower_node_id(*id); self.alias_attrs(ctor_id, parent_id); - hir::VariantData::Tuple( - self.arena.alloc_from_iter( - fields.iter().enumerate().map(|f| self.lower_field_def(f)), - ), - ctor_id, - self.local_def_id(*id), - ) + let fields = self + .arena + .alloc_from_iter(fields.iter().enumerate().map(|f| self.lower_field_def(f))); + for field in &fields[..] { + if let Some(default) = field.default { + // Default values in tuple struct and tuple variants are not allowed by the + // RFC due to concerns about the syntax, both in the item definition and the + // expression. We could in the future allow `struct S(i32 = 0);` and force + // users to construct the value with `let _ = S { .. };`. + if self.tcx.features().default_field_values() { + self.dcx().emit_err(TupleStructWithDefault { span: default.span }); + } else { + let _ = self.dcx().span_delayed_bug( + default.span, + "expected `default values on `struct` fields aren't supported` \ + feature-gate error but none was produced", + ); + } + } + } + hir::VariantData::Tuple(fields, ctor_id, self.local_def_id(*id)) } VariantData::Unit(id) => { let ctor_id = self.lower_node_id(*id); @@ -723,6 +740,7 @@ impl<'hir> LoweringContext<'_, 'hir> { None => Ident::new(sym::integer(index), self.lower_span(f.span)), }, vis_span: self.lower_span(f.vis.span), + default: f.default.as_ref().map(|v| self.lower_anon_const_to_anon_const(v)), ty, safety: self.lower_safety(f.safety, hir::Safety::Safe), } diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 390a575a186..aa3b772efb1 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -557,6 +557,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) { gate_all!(explicit_tail_calls, "`become` expression is experimental"); gate_all!(generic_const_items, "generic const items are experimental"); gate_all!(guard_patterns, "guard patterns are experimental", "consider using match arm guards"); + gate_all!(default_field_values, "default values on fields are experimental"); gate_all!(fn_delegation, "functions delegation is not yet fully implemented"); gate_all!(postfix_match, "postfix match is experimental"); gate_all!(mut_ref, "mutable by-reference bindings are experimental"); diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index b42c99e1a6d..8dcc5324fdf 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -1151,7 +1151,11 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { expr: &hir::Expr<'_>, ) { let typeck_results = self.infcx.tcx.typeck(self.mir_def_id()); - let hir::ExprKind::Struct(struct_qpath, fields, Some(base)) = expr.kind else { return }; + let hir::ExprKind::Struct(struct_qpath, fields, hir::StructTailExpr::Base(base)) = + expr.kind + else { + return; + }; let hir::QPath::Resolved(_, path) = struct_qpath else { return }; let hir::def::Res::Def(_, def_id) = path.res else { return }; let Some(expr_ty) = typeck_results.node_type_opt(expr.hir_id) else { return }; @@ -1239,7 +1243,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { expr: &'tcx hir::Expr<'tcx>, use_spans: Option<UseSpans<'tcx>>, ) { - if let hir::ExprKind::Struct(_, _, Some(_)) = expr.kind { + if let hir::ExprKind::Struct(_, _, hir::StructTailExpr::Base(_)) = expr.kind { // We have `S { foo: val, ..base }`. In `check_aggregate_rvalue` we have a single // `Location` that covers both the `S { ... }` literal, all of its fields and the // `base`. If the move happens because of `S { foo: val, bar: base.bar }` the `expr` diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 9b7474c2208..d7db92da18f 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -26,7 +26,7 @@ use rustc_data_structures::graph::dominators::Dominators; use rustc_errors::Diag; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; -use rustc_index::bit_set::{BitSet, ChunkedBitSet}; +use rustc_index::bit_set::{BitSet, MixedBitSet}; use rustc_index::{IndexSlice, IndexVec}; use rustc_infer::infer::{ InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin, TyCtxtInferExt, @@ -1797,7 +1797,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { location: Location, desired_action: InitializationRequiringAction, place_span: (PlaceRef<'tcx>, Span), - maybe_uninits: &ChunkedBitSet<MovePathIndex>, + maybe_uninits: &MixedBitSet<MovePathIndex>, from: u64, to: u64, ) { diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl index c05d44cb452..87d3d288013 100644 --- a/compiler/rustc_builtin_macros/messages.ftl +++ b/compiler/rustc_builtin_macros/messages.ftl @@ -261,7 +261,7 @@ builtin_macros_non_exhaustive_default = default variant must be exhaustive builtin_macros_non_generic_pointee = the `#[pointee]` attribute may only be used on generic parameters -builtin_macros_non_unit_default = the `#[default]` attribute may only be used on unit enum variants +builtin_macros_non_unit_default = the `#[default]` attribute may only be used on unit enum variants{$post} .help = consider a manual implementation of `Default` builtin_macros_only_one_argument = {$name} takes 1 argument diff --git a/compiler/rustc_builtin_macros/src/deriving/decodable.rs b/compiler/rustc_builtin_macros/src/deriving/decodable.rs index 686424770fc..469092e7b1c 100644 --- a/compiler/rustc_builtin_macros/src/deriving/decodable.rs +++ b/compiler/rustc_builtin_macros/src/deriving/decodable.rs @@ -205,7 +205,7 @@ where let fields = fields .iter() .enumerate() - .map(|(i, &(ident, span))| { + .map(|(i, &(ident, span, _))| { let arg = getarg(cx, span, ident.name, i); cx.field_imm(span, ident, arg) }) diff --git a/compiler/rustc_builtin_macros/src/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs index d4befd12190..6b1a6effad7 100644 --- a/compiler/rustc_builtin_macros/src/deriving/default.rs +++ b/compiler/rustc_builtin_macros/src/deriving/default.rs @@ -54,26 +54,38 @@ pub(crate) fn expand_deriving_default( trait_def.expand(cx, mitem, item, push) } +fn default_call(cx: &ExtCtxt<'_>, span: Span) -> ast::ptr::P<ast::Expr> { + // Note that `kw::Default` is "default" and `sym::Default` is "Default"! + let default_ident = cx.std_path(&[kw::Default, sym::Default, kw::Default]); + cx.expr_call_global(span, default_ident, ThinVec::new()) +} + fn default_struct_substructure( cx: &ExtCtxt<'_>, trait_span: Span, substr: &Substructure<'_>, summary: &StaticFields, ) -> BlockOrExpr { - // Note that `kw::Default` is "default" and `sym::Default` is "Default"! - let default_ident = cx.std_path(&[kw::Default, sym::Default, kw::Default]); - let default_call = |span| cx.expr_call_global(span, default_ident.clone(), ThinVec::new()); - let expr = match summary { Unnamed(_, IsTuple::No) => cx.expr_ident(trait_span, substr.type_ident), Unnamed(fields, IsTuple::Yes) => { - let exprs = fields.iter().map(|sp| default_call(*sp)).collect(); + let exprs = fields.iter().map(|sp| default_call(cx, *sp)).collect(); cx.expr_call_ident(trait_span, substr.type_ident, exprs) } Named(fields) => { let default_fields = fields .iter() - .map(|&(ident, span)| cx.field_imm(span, ident, default_call(span))) + .map(|(ident, span, default_val)| { + let value = match default_val { + // We use `Default::default()`. + None => default_call(cx, *span), + // We use the field default const expression. + Some(val) => { + cx.expr(val.value.span, ast::ExprKind::ConstBlock(val.clone())) + } + }; + cx.field_imm(*span, *ident, value) + }) .collect(); cx.expr_struct_ident(trait_span, substr.type_ident, default_fields) } @@ -93,10 +105,38 @@ fn default_enum_substructure( } { Ok(default_variant) => { // We now know there is exactly one unit variant with exactly one `#[default]` attribute. - cx.expr_path(cx.path(default_variant.span, vec![ - Ident::new(kw::SelfUpper, default_variant.span), - default_variant.ident, - ])) + match &default_variant.data { + VariantData::Unit(_) => cx.expr_path(cx.path(default_variant.span, vec![ + Ident::new(kw::SelfUpper, default_variant.span), + default_variant.ident, + ])), + VariantData::Struct { fields, .. } => { + // This only happens if `#![feature(default_field_values)]`. We have validated + // all fields have default values in the definition. + let default_fields = fields + .iter() + .map(|field| { + cx.field_imm(field.span, field.ident.unwrap(), match &field.default { + // We use `Default::default()`. + None => default_call(cx, field.span), + // We use the field default const expression. + Some(val) => { + cx.expr(val.value.span, ast::ExprKind::ConstBlock(val.clone())) + } + }) + }) + .collect(); + let path = cx.path(default_variant.span, vec![ + Ident::new(kw::SelfUpper, default_variant.span), + default_variant.ident, + ]); + cx.expr_struct(default_variant.span, path, default_fields) + } + // Logic error in `extract_default_variant`. + VariantData::Tuple(..) => { + cx.dcx().bug("encountered tuple variant annotated with `#[default]`") + } + } } Err(guar) => DummyResult::raw_expr(trait_span, Some(guar)), }; @@ -156,8 +196,20 @@ fn extract_default_variant<'a>( } }; - if !matches!(variant.data, VariantData::Unit(..)) { - let guar = cx.dcx().emit_err(errors::NonUnitDefault { span: variant.ident.span }); + if cx.ecfg.features.default_field_values() + && let VariantData::Struct { fields, .. } = &variant.data + && fields.iter().all(|f| f.default.is_some()) + // Disallow `#[default] Variant {}` + && !fields.is_empty() + { + // Allowed + } else if !matches!(variant.data, VariantData::Unit(..)) { + let post = if cx.ecfg.features.default_field_values() { + " or variants where every field has a default value" + } else { + "" + }; + let guar = cx.dcx().emit_err(errors::NonUnitDefault { span: variant.ident.span, post }); return Err(guar); } @@ -216,7 +268,12 @@ struct DetectNonVariantDefaultAttr<'a, 'b> { impl<'a, 'b> rustc_ast::visit::Visitor<'a> for DetectNonVariantDefaultAttr<'a, 'b> { fn visit_attribute(&mut self, attr: &'a rustc_ast::Attribute) { if attr.has_name(kw::Default) { - self.cx.dcx().emit_err(errors::NonUnitDefault { span: attr.span }); + let post = if self.cx.ecfg.features.default_field_values() { + " or variants where every field has a default value" + } else { + "" + }; + self.cx.dcx().emit_err(errors::NonUnitDefault { span: attr.span, post }); } rustc_ast::visit::walk_attribute(self, attr); diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index f6eea0b21ca..846d8784dea 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -182,8 +182,8 @@ pub(crate) use StaticFields::*; pub(crate) use SubstructureFields::*; use rustc_ast::ptr::P; use rustc_ast::{ - self as ast, BindingMode, ByRef, EnumDef, Expr, GenericArg, GenericParamKind, Generics, - Mutability, PatKind, VariantData, + self as ast, AnonConst, BindingMode, ByRef, EnumDef, Expr, GenericArg, GenericParamKind, + Generics, Mutability, PatKind, VariantData, }; use rustc_attr as attr; use rustc_expand::base::{Annotatable, ExtCtxt}; @@ -296,7 +296,7 @@ pub(crate) enum StaticFields { /// Tuple and unit structs/enum variants like this. Unnamed(Vec<Span>, IsTuple), /// Normal structs/struct variants. - Named(Vec<(Ident, Span)>), + Named(Vec<(Ident, Span, Option<AnonConst>)>), } /// A summary of the possible sets of fields. @@ -1435,7 +1435,7 @@ impl<'a> TraitDef<'a> { for field in struct_def.fields() { let sp = field.span.with_ctxt(self.span.ctxt()); match field.ident { - Some(ident) => named_idents.push((ident, sp)), + Some(ident) => named_idents.push((ident, sp, field.default.clone())), _ => just_spans.push(sp), } } diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs index f8e65661e52..c9bd3371e55 100644 --- a/compiler/rustc_builtin_macros/src/errors.rs +++ b/compiler/rustc_builtin_macros/src/errors.rs @@ -424,6 +424,7 @@ pub(crate) struct MultipleDefaultsSugg { pub(crate) struct NonUnitDefault { #[primary_span] pub(crate) span: Span, + pub(crate) post: &'static str, } #[derive(Diagnostic)] diff --git a/compiler/rustc_codegen_cranelift/example/mini_core.rs b/compiler/rustc_codegen_cranelift/example/mini_core.rs index 3da215fe6c0..a0a381638c0 100644 --- a/compiler/rustc_codegen_cranelift/example/mini_core.rs +++ b/compiler/rustc_codegen_cranelift/example/mini_core.rs @@ -55,26 +55,26 @@ impl<T: ?Sized> LegacyReceiver for &mut T {} impl<T: ?Sized> LegacyReceiver for Box<T> {} #[lang = "copy"] -pub unsafe trait Copy {} - -unsafe impl Copy for bool {} -unsafe impl Copy for u8 {} -unsafe impl Copy for u16 {} -unsafe impl Copy for u32 {} -unsafe impl Copy for u64 {} -unsafe impl Copy for u128 {} -unsafe impl Copy for usize {} -unsafe impl Copy for i8 {} -unsafe impl Copy for i16 {} -unsafe impl Copy for i32 {} -unsafe impl Copy for isize {} -unsafe impl Copy for f32 {} -unsafe impl Copy for f64 {} -unsafe impl Copy for char {} -unsafe impl<'a, T: ?Sized> Copy for &'a T {} -unsafe impl<T: ?Sized> Copy for *const T {} -unsafe impl<T: ?Sized> Copy for *mut T {} -unsafe impl<T: Copy> Copy for Option<T> {} +pub trait Copy {} + +impl Copy for bool {} +impl Copy for u8 {} +impl Copy for u16 {} +impl Copy for u32 {} +impl Copy for u64 {} +impl Copy for u128 {} +impl Copy for usize {} +impl Copy for i8 {} +impl Copy for i16 {} +impl Copy for i32 {} +impl Copy for isize {} +impl Copy for f32 {} +impl Copy for f64 {} +impl Copy for char {} +impl<'a, T: ?Sized> Copy for &'a T {} +impl<T: ?Sized> Copy for *const T {} +impl<T: ?Sized> Copy for *mut T {} +impl<T: Copy> Copy for Option<T> {} #[lang = "sync"] pub unsafe trait Sync {} diff --git a/compiler/rustc_codegen_gcc/example/mini_core.rs b/compiler/rustc_codegen_gcc/example/mini_core.rs index c887598f6e9..cdd151613df 100644 --- a/compiler/rustc_codegen_gcc/example/mini_core.rs +++ b/compiler/rustc_codegen_gcc/example/mini_core.rs @@ -52,24 +52,24 @@ impl<T: ?Sized> LegacyReceiver for &mut T {} impl<T: ?Sized, A: Allocator> LegacyReceiver for Box<T, A> {} #[lang = "copy"] -pub unsafe trait Copy {} - -unsafe impl Copy for bool {} -unsafe impl Copy for u8 {} -unsafe impl Copy for u16 {} -unsafe impl Copy for u32 {} -unsafe impl Copy for u64 {} -unsafe impl Copy for usize {} -unsafe impl Copy for i8 {} -unsafe impl Copy for i16 {} -unsafe impl Copy for i32 {} -unsafe impl Copy for isize {} -unsafe impl Copy for f32 {} -unsafe impl Copy for f64 {} -unsafe impl Copy for char {} -unsafe impl<'a, T: ?Sized> Copy for &'a T {} -unsafe impl<T: ?Sized> Copy for *const T {} -unsafe impl<T: ?Sized> Copy for *mut T {} +pub trait Copy {} + +impl Copy for bool {} +impl Copy for u8 {} +impl Copy for u16 {} +impl Copy for u32 {} +impl Copy for u64 {} +impl Copy for usize {} +impl Copy for i8 {} +impl Copy for i16 {} +impl Copy for i32 {} +impl Copy for isize {} +impl Copy for f32 {} +impl Copy for f64 {} +impl Copy for char {} +impl<'a, T: ?Sized> Copy for &'a T {} +impl<T: ?Sized> Copy for *const T {} +impl<T: ?Sized> Copy for *mut T {} #[lang = "sync"] pub unsafe trait Sync {} diff --git a/compiler/rustc_codegen_gcc/src/asm.rs b/compiler/rustc_codegen_gcc/src/asm.rs index a1f9eab10e7..415f8affab9 100644 --- a/compiler/rustc_codegen_gcc/src/asm.rs +++ b/compiler/rustc_codegen_gcc/src/asm.rs @@ -867,6 +867,13 @@ impl<'gcc, 'tcx> AsmCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { template_str.push_str("\n.popsection"); self.context.add_top_level_asm(None, &template_str); } + + fn mangled_name(&self, instance: Instance<'tcx>) -> String { + // TODO(@Amanieu): Additional mangling is needed on + // some targets to add a leading underscore (Mach-O) + // or byte count suffixes (x86 Windows). + self.tcx.symbol_name(instance).name.to_string() + } } fn modifier_to_gcc( diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index d1804cb49ad..3722d4350a2 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -442,6 +442,14 @@ impl<'tcx> AsmCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> { ); } } + + fn mangled_name(&self, instance: Instance<'tcx>) -> String { + let llval = self.get_fn(instance); + llvm::build_string(|s| unsafe { + llvm::LLVMRustGetMangledName(llval, s); + }) + .expect("symbol is not valid UTF-8") + } } pub(crate) fn inline_asm_call<'ll>( @@ -504,14 +512,13 @@ pub(crate) fn inline_asm_call<'ll>( let key = "srcloc"; let kind = llvm::LLVMGetMDKindIDInContext( bx.llcx, - key.as_ptr() as *const c_char, + key.as_ptr().cast::<c_char>(), key.len() as c_uint, ); - // srcloc contains one integer for each line of assembly code. - // Unfortunately this isn't enough to encode a full span so instead - // we just encode the start position of each line. - // FIXME: Figure out a way to pass the entire line spans. + // `srcloc` contains one 64-bit integer for each line of assembly code, + // where the lower 32 bits hold the lo byte position and the upper 32 bits + // hold the hi byte position. let mut srcloc = vec![]; if dia == llvm::AsmDialect::Intel && line_spans.len() > 1 { // LLVM inserts an extra line to add the ".intel_syntax", so add @@ -521,13 +528,13 @@ pub(crate) fn inline_asm_call<'ll>( // due to the asm template string coming from a macro. LLVM will // default to the first srcloc for lines that don't have an // associated srcloc. - srcloc.push(llvm::LLVMValueAsMetadata(bx.const_i32(0))); + srcloc.push(llvm::LLVMValueAsMetadata(bx.const_u64(0))); } - srcloc.extend( - line_spans - .iter() - .map(|span| llvm::LLVMValueAsMetadata(bx.const_i32(span.lo().to_u32() as i32))), - ); + srcloc.extend(line_spans.iter().map(|span| { + llvm::LLVMValueAsMetadata(bx.const_u64( + u64::from(span.lo().to_u32()) | (u64::from(span.hi().to_u32()) << 32), + )) + })); let md = llvm::LLVMMDNodeInContext2(bx.llcx, srcloc.as_ptr(), srcloc.len()); let md = llvm::LLVMMetadataAsValue(&bx.llcx, md); llvm::LLVMSetMetadata(call, kind, md); diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index cb958c1d4d7..5552a241060 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -395,17 +395,9 @@ pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>( to_add.push(MemoryEffects::None.create_attr(cx.llcx)); } if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) { - to_add.push(AttributeKind::Naked.create_attr(cx.llcx)); - // HACK(jubilee): "indirect branch tracking" works by attaching prologues to functions. - // And it is a module-level attribute, so the alternative is pulling naked functions into - // new LLVM modules. Otherwise LLVM's "naked" functions come with endbr prefixes per - // https://github.com/rust-lang/rust/issues/98768 - to_add.push(AttributeKind::NoCfCheck.create_attr(cx.llcx)); - if llvm_util::get_version() < (19, 0, 0) { - // Prior to LLVM 19, branch-target-enforcement was disabled by setting the attribute to - // the string "false". Now it is disabled by absence of the attribute. - to_add.push(llvm::CreateAttrStringValue(cx.llcx, "branch-target-enforcement", "false")); - } + // do nothing; a naked function is converted into an extern function + // and a global assembly block. LLVM's support for naked functions is + // not used. } else { // Do not set sanitizer attributes for naked functions. to_add.extend(sanitize_attrs(cx, codegen_fn_attrs.no_sanitize)); diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index bde6668929c..66ca4e2b473 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -25,8 +25,8 @@ use rustc_session::Session; use rustc_session::config::{ self, Lto, OutputType, Passes, RemapPathScopeComponents, SplitDwarfKind, SwitchWithOptPath, }; -use rustc_span::InnerSpan; use rustc_span::symbol::sym; +use rustc_span::{BytePos, InnerSpan, Pos, SpanData, SyntaxContext}; use rustc_target::spec::{CodeModel, RelocModel, SanitizerSet, SplitDebuginfo, TlsModel}; use tracing::debug; @@ -415,21 +415,32 @@ fn report_inline_asm( cgcx: &CodegenContext<LlvmCodegenBackend>, msg: String, level: llvm::DiagnosticLevel, - mut cookie: u64, + cookie: u64, source: Option<(String, Vec<InnerSpan>)>, ) { // In LTO build we may get srcloc values from other crates which are invalid // since they use a different source map. To be safe we just suppress these // in LTO builds. - if matches!(cgcx.lto, Lto::Fat | Lto::Thin) { - cookie = 0; - } + let span = if cookie == 0 || matches!(cgcx.lto, Lto::Fat | Lto::Thin) { + SpanData::default() + } else { + let lo = BytePos::from_u32(cookie as u32); + let hi = BytePos::from_u32((cookie >> 32) as u32); + SpanData { + lo, + // LLVM version < 19 silently truncates the cookie to 32 bits in some situations. + hi: if hi.to_u32() != 0 { hi } else { lo }, + ctxt: SyntaxContext::root(), + parent: None, + } + }; let level = match level { llvm::DiagnosticLevel::Error => Level::Error, llvm::DiagnosticLevel::Warning => Level::Warning, llvm::DiagnosticLevel::Note | llvm::DiagnosticLevel::Remark => Level::Note, }; - cgcx.diag_emitter.inline_asm_error(cookie.try_into().unwrap(), msg, level, source); + let msg = msg.strip_prefix("error: ").unwrap_or(&msg).to_string(); + cgcx.diag_emitter.inline_asm_error(span, msg, level, source); } unsafe extern "C" fn diagnostic_handler(info: &DiagnosticInfo, user: *mut c_void) { diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 8218126ea29..c602d99ff9d 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -159,6 +159,16 @@ pub(crate) unsafe fn create_module<'ll>( // See https://github.com/llvm/llvm-project/pull/112084 target_data_layout = target_data_layout.replace("-i128:128", ""); } + if sess.target.arch.starts_with("powerpc64") { + // LLVM 20 updates the powerpc64 layout to correctly align 128 bit integers to 128 bit. + // See https://github.com/llvm/llvm-project/pull/118004 + target_data_layout = target_data_layout.replace("-i128:128", ""); + } + if sess.target.arch.starts_with("wasm32") || sess.target.arch.starts_with("wasm64") { + // LLVM 20 updates the wasm(32|64) layout to correctly align 128 bit integers to 128 bit. + // See https://github.com/llvm/llvm-project/pull/119204 + target_data_layout = target_data_layout.replace("-i128:128", ""); + } } // Ensure the data-layout values hardcoded remain the defaults. diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs index a6e07ea2a60..1f133141c18 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/ffi.rs @@ -152,6 +152,34 @@ impl CoverageSpan { } } +/// Holds tables of the various region types in one struct. +/// +/// Don't pass this struct across FFI; pass the individual region tables as +/// pointer/length pairs instead. +/// +/// Each field name has a `_regions` suffix for improved readability after +/// exhaustive destructing, which ensures that all region types are handled. +#[derive(Clone, Debug, Default)] +pub(crate) struct Regions { + pub(crate) code_regions: Vec<CodeRegion>, + pub(crate) branch_regions: Vec<BranchRegion>, + pub(crate) mcdc_branch_regions: Vec<MCDCBranchRegion>, + pub(crate) mcdc_decision_regions: Vec<MCDCDecisionRegion>, +} + +impl Regions { + /// Returns true if none of this structure's tables contain any regions. + pub(crate) fn has_no_regions(&self) -> bool { + let Self { code_regions, branch_regions, mcdc_branch_regions, mcdc_decision_regions } = + self; + + code_regions.is_empty() + && branch_regions.is_empty() + && mcdc_branch_regions.is_empty() + && mcdc_decision_regions.is_empty() + } +} + /// Must match the layout of `LLVMRustCoverageCodeRegion`. #[derive(Clone, Debug)] #[repr(C)] diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/llvm_cov.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/llvm_cov.rs index 99c2d12b261..086cf1f44a0 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/llvm_cov.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/llvm_cov.rs @@ -62,11 +62,10 @@ pub(crate) fn write_filenames_to_buffer<'a>( pub(crate) fn write_function_mappings_to_buffer( virtual_file_mapping: &[u32], expressions: &[ffi::CounterExpression], - code_regions: &[ffi::CodeRegion], - branch_regions: &[ffi::BranchRegion], - mcdc_branch_regions: &[ffi::MCDCBranchRegion], - mcdc_decision_regions: &[ffi::MCDCDecisionRegion], + regions: &ffi::Regions, ) -> Vec<u8> { + let ffi::Regions { code_regions, branch_regions, mcdc_branch_regions, mcdc_decision_regions } = + regions; llvm::build_byte_buffer(|buffer| unsafe { llvm::LLVMRustCoverageWriteFunctionMappingsToBuffer( virtual_file_mapping.as_ptr(), diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs index 0752c718c70..c5d1ebdfe7c 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/map_data.rs @@ -1,159 +1,38 @@ use rustc_data_structures::captures::Captures; -use rustc_data_structures::fx::FxIndexSet; -use rustc_index::bit_set::BitSet; -use rustc_middle::mir::CoverageIdsInfo; use rustc_middle::mir::coverage::{ - CounterId, CovTerm, Expression, ExpressionId, FunctionCoverageInfo, Mapping, MappingKind, Op, + CovTerm, CoverageIdsInfo, Expression, FunctionCoverageInfo, Mapping, MappingKind, Op, SourceRegion, }; -use rustc_middle::ty::Instance; -use tracing::debug; use crate::coverageinfo::ffi::{Counter, CounterExpression, ExprKind}; -/// Holds all of the coverage mapping data associated with a function instance, -/// collected during traversal of `Coverage` statements in the function's MIR. -#[derive(Debug)] -pub(crate) struct FunctionCoverageCollector<'tcx> { - /// Coverage info that was attached to this function by the instrumentor. - function_coverage_info: &'tcx FunctionCoverageInfo, - ids_info: &'tcx CoverageIdsInfo, - is_used: bool, +pub(crate) struct FunctionCoverage<'tcx> { + pub(crate) function_coverage_info: &'tcx FunctionCoverageInfo, + /// If `None`, the corresponding function is unused. + ids_info: Option<&'tcx CoverageIdsInfo>, } -impl<'tcx> FunctionCoverageCollector<'tcx> { - /// Creates a new set of coverage data for a used (called) function. - pub(crate) fn new( - instance: Instance<'tcx>, - function_coverage_info: &'tcx FunctionCoverageInfo, - ids_info: &'tcx CoverageIdsInfo, - ) -> Self { - Self::create(instance, function_coverage_info, ids_info, true) - } - - /// Creates a new set of coverage data for an unused (never called) function. - pub(crate) fn unused( - instance: Instance<'tcx>, - function_coverage_info: &'tcx FunctionCoverageInfo, - ids_info: &'tcx CoverageIdsInfo, - ) -> Self { - Self::create(instance, function_coverage_info, ids_info, false) - } - - fn create( - instance: Instance<'tcx>, +impl<'tcx> FunctionCoverage<'tcx> { + pub(crate) fn new_used( function_coverage_info: &'tcx FunctionCoverageInfo, ids_info: &'tcx CoverageIdsInfo, - is_used: bool, ) -> Self { - let num_counters = function_coverage_info.num_counters; - let num_expressions = function_coverage_info.expressions.len(); - debug!( - "FunctionCoverage::create(instance={instance:?}) has \ - num_counters={num_counters}, num_expressions={num_expressions}, is_used={is_used}" - ); - - Self { function_coverage_info, ids_info, is_used } - } - - /// Identify expressions that will always have a value of zero, and note - /// their IDs in [`ZeroExpressions`]. Mappings that refer to a zero expression - /// can instead become mappings to a constant zero value. - /// - /// This method mainly exists to preserve the simplifications that were - /// already being performed by the Rust-side expression renumbering, so that - /// the resulting coverage mappings don't get worse. - fn identify_zero_expressions(&self) -> ZeroExpressions { - // The set of expressions that either were optimized out entirely, or - // have zero as both of their operands, and will therefore always have - // a value of zero. Other expressions that refer to these as operands - // can have those operands replaced with `CovTerm::Zero`. - let mut zero_expressions = ZeroExpressions::default(); - - // Simplify a copy of each expression based on lower-numbered expressions, - // and then update the set of always-zero expressions if necessary. - // (By construction, expressions can only refer to other expressions - // that have lower IDs, so one pass is sufficient.) - for (id, expression) in self.function_coverage_info.expressions.iter_enumerated() { - if !self.is_used || !self.ids_info.expressions_seen.contains(id) { - // If an expression was not seen, it must have been optimized away, - // so any operand that refers to it can be replaced with zero. - zero_expressions.insert(id); - continue; - } - - // We don't need to simplify the actual expression data in the - // expressions list; we can just simplify a temporary copy and then - // use that to update the set of always-zero expressions. - let Expression { mut lhs, op, mut rhs } = *expression; - - // If an expression has an operand that is also an expression, the - // operand's ID must be strictly lower. This is what lets us find - // all zero expressions in one pass. - let assert_operand_expression_is_lower = |operand_id: ExpressionId| { - assert!( - operand_id < id, - "Operand {operand_id:?} should be less than {id:?} in {expression:?}", - ) - }; - - // If an operand refers to a counter or expression that is always - // zero, then that operand can be replaced with `CovTerm::Zero`. - let maybe_set_operand_to_zero = |operand: &mut CovTerm| { - if let CovTerm::Expression(id) = *operand { - assert_operand_expression_is_lower(id); - } - - if is_zero_term(&self.ids_info.counters_seen, &zero_expressions, *operand) { - *operand = CovTerm::Zero; - } - }; - maybe_set_operand_to_zero(&mut lhs); - maybe_set_operand_to_zero(&mut rhs); - - // Coverage counter values cannot be negative, so if an expression - // involves subtraction from zero, assume that its RHS must also be zero. - // (Do this after simplifications that could set the LHS to zero.) - if lhs == CovTerm::Zero && op == Op::Subtract { - rhs = CovTerm::Zero; - } - - // After the above simplifications, if both operands are zero, then - // we know that this expression is always zero too. - if lhs == CovTerm::Zero && rhs == CovTerm::Zero { - zero_expressions.insert(id); - } - } - - zero_expressions + Self { function_coverage_info, ids_info: Some(ids_info) } } - pub(crate) fn into_finished(self) -> FunctionCoverage<'tcx> { - let zero_expressions = self.identify_zero_expressions(); - let FunctionCoverageCollector { function_coverage_info, ids_info, is_used, .. } = self; - - FunctionCoverage { function_coverage_info, ids_info, is_used, zero_expressions } + pub(crate) fn new_unused(function_coverage_info: &'tcx FunctionCoverageInfo) -> Self { + Self { function_coverage_info, ids_info: None } } -} - -pub(crate) struct FunctionCoverage<'tcx> { - pub(crate) function_coverage_info: &'tcx FunctionCoverageInfo, - ids_info: &'tcx CoverageIdsInfo, - is_used: bool, - - zero_expressions: ZeroExpressions, -} -impl<'tcx> FunctionCoverage<'tcx> { /// Returns true for a used (called) function, and false for an unused function. pub(crate) fn is_used(&self) -> bool { - self.is_used + self.ids_info.is_some() } /// Return the source hash, generated from the HIR node structure, and used to indicate whether /// or not the source code structure changed between different compilations. pub(crate) fn source_hash(&self) -> u64 { - if self.is_used { self.function_coverage_info.function_source_hash } else { 0 } + if self.is_used() { self.function_coverage_info.function_source_hash } else { 0 } } /// Convert this function's coverage expression data into a form that can be @@ -196,37 +75,10 @@ impl<'tcx> FunctionCoverage<'tcx> { } fn is_zero_term(&self, term: CovTerm) -> bool { - !self.is_used || is_zero_term(&self.ids_info.counters_seen, &self.zero_expressions, term) - } -} - -/// Set of expression IDs that are known to always evaluate to zero. -/// Any mapping or expression operand that refers to these expressions can have -/// that reference replaced with a constant zero value. -#[derive(Default)] -struct ZeroExpressions(FxIndexSet<ExpressionId>); - -impl ZeroExpressions { - fn insert(&mut self, id: ExpressionId) { - self.0.insert(id); - } - - fn contains(&self, id: ExpressionId) -> bool { - self.0.contains(&id) - } -} - -/// Returns `true` if the given term is known to have a value of zero, taking -/// into account knowledge of which counters are unused and which expressions -/// are always zero. -fn is_zero_term( - counters_seen: &BitSet<CounterId>, - zero_expressions: &ZeroExpressions, - term: CovTerm, -) -> bool { - match term { - CovTerm::Zero => true, - CovTerm::Counter(id) => !counters_seen.contains(id), - CovTerm::Expression(id) => zero_expressions.contains(id), + match self.ids_info { + Some(ids_info) => ids_info.is_zero_term(term), + // This function is unused, so all coverage counters/expressions are zero. + None => true, + } } } diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs index 8c24579fa7c..a573a37beb3 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs @@ -1,4 +1,3 @@ -use std::ffi::CString; use std::iter; use itertools::Itertools as _; @@ -9,21 +8,22 @@ use rustc_codegen_ssa::traits::{ use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_index::IndexVec; -use rustc_middle::mir::coverage::MappingKind; use rustc_middle::ty::{self, TyCtxt}; use rustc_middle::{bug, mir}; use rustc_session::RemapFileNameExt; use rustc_session::config::RemapPathScopeComponents; use rustc_span::def_id::DefIdSet; use rustc_span::{Span, Symbol}; -use rustc_target::spec::HasTargetSpec; use tracing::debug; use crate::common::CodegenCx; -use crate::coverageinfo::map_data::{FunctionCoverage, FunctionCoverageCollector}; -use crate::coverageinfo::{ffi, llvm_cov}; +use crate::coverageinfo::llvm_cov; +use crate::coverageinfo::map_data::FunctionCoverage; +use crate::coverageinfo::mapgen::covfun::prepare_covfun_record; use crate::llvm; +mod covfun; + /// Generates and exports the coverage map, which is embedded in special /// linker sections in the final binary. /// @@ -63,16 +63,11 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) { None => return, }; if function_coverage_map.is_empty() { - // This module has no functions with coverage instrumentation + // This CGU has no functions with coverage instrumentation. return; } - let function_coverage_entries = function_coverage_map - .into_iter() - .map(|(instance, function_coverage)| (instance, function_coverage.into_finished())) - .collect::<Vec<_>>(); - - let all_file_names = function_coverage_entries + let all_file_names = function_coverage_map .iter() .map(|(_, fn_cov)| fn_cov.function_coverage_info.body_span) .map(|span| span_file_name(tcx, span)); @@ -85,47 +80,28 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) { let filenames_val = cx.const_bytes(&filenames_buffer); let filenames_ref = llvm_cov::hash_bytes(&filenames_buffer); - // Generate the coverage map header, which contains the filenames used by - // this CGU's coverage mappings, and store it in a well-known global. - generate_covmap_record(cx, covmap_version, filenames_size, filenames_val); - let mut unused_function_names = Vec::new(); - // Encode coverage mappings and generate function records - for (instance, function_coverage) in function_coverage_entries { - debug!("Generate function coverage for {}, {:?}", cx.codegen_unit.name(), instance); - - let mangled_function_name = tcx.symbol_name(instance).name; - let source_hash = function_coverage.source_hash(); - let is_used = function_coverage.is_used(); - - let coverage_mapping_buffer = - encode_mappings_for_function(tcx, &global_file_table, &function_coverage); + let covfun_records = function_coverage_map + .into_iter() + .filter_map(|(instance, function_coverage)| { + prepare_covfun_record(tcx, &global_file_table, instance, &function_coverage) + }) + .collect::<Vec<_>>(); - if coverage_mapping_buffer.is_empty() { - if function_coverage.is_used() { - bug!( - "A used function should have had coverage mapping data but did not: {}", - mangled_function_name - ); - } else { - debug!("unused function had no coverage mapping data: {}", mangled_function_name); - continue; - } - } + // If there are no covfun records for this CGU, don't generate a covmap record. + // Emitting a covmap record without any covfun records causes `llvm-cov` to + // fail when generating coverage reports, and if there are no covfun records + // then the covmap record isn't useful anyway. + // This should prevent a repeat of <https://github.com/rust-lang/rust/issues/133606>. + if covfun_records.is_empty() { + return; + } - if !is_used { - unused_function_names.push(mangled_function_name); - } + for covfun in &covfun_records { + unused_function_names.extend(covfun.mangled_function_name_if_unused()); - generate_covfun_record( - cx, - mangled_function_name, - source_hash, - filenames_ref, - coverage_mapping_buffer, - is_used, - ); + covfun::generate_covfun_record(cx, filenames_ref, covfun) } // For unused functions, we need to take their mangled names and store them @@ -146,6 +122,11 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) { llvm::set_linkage(array, llvm::Linkage::InternalLinkage); llvm::set_initializer(array, initializer); } + + // Generate the coverage map header, which contains the filenames used by + // this CGU's coverage mappings, and store it in a well-known global. + // (This is skipped if we returned early due to having no covfun records.) + generate_covmap_record(cx, covmap_version, filenames_size, filenames_val); } /// Maps "global" (per-CGU) file ID numbers to their underlying filenames. @@ -213,7 +194,7 @@ rustc_index::newtype_index! { /// Holds a mapping from "local" (per-function) file IDs to "global" (per-CGU) /// file IDs. -#[derive(Default)] +#[derive(Debug, Default)] struct VirtualFileMapping { local_to_global: IndexVec<LocalFileId, GlobalFileId>, global_to_local: FxIndexMap<GlobalFileId, LocalFileId>, @@ -227,10 +208,10 @@ impl VirtualFileMapping { .or_insert_with(|| self.local_to_global.push(global_file_id)) } - fn into_vec(self) -> Vec<u32> { - // This conversion should be optimized away to ~zero overhead. - // In any case, it's probably not hot enough to worry about. - self.local_to_global.into_iter().map(|global| global.as_u32()).collect() + fn to_vec(&self) -> Vec<u32> { + // This clone could be avoided by transmuting `&[GlobalFileId]` to `&[u32]`, + // but it isn't hot or expensive enough to justify the extra unsafety. + self.local_to_global.iter().map(|&global| GlobalFileId::as_u32(global)).collect() } } @@ -241,83 +222,6 @@ fn span_file_name(tcx: TyCtxt<'_>, span: Span) -> Symbol { Symbol::intern(&name) } -/// Using the expressions and counter regions collected for a single function, -/// generate the variable-sized payload of its corresponding `__llvm_covfun` -/// entry. The payload is returned as a vector of bytes. -/// -/// Newly-encountered filenames will be added to the global file table. -fn encode_mappings_for_function( - tcx: TyCtxt<'_>, - global_file_table: &GlobalFileTable, - function_coverage: &FunctionCoverage<'_>, -) -> Vec<u8> { - let counter_regions = function_coverage.counter_regions(); - if counter_regions.is_empty() { - return Vec::new(); - } - - let expressions = function_coverage.counter_expressions().collect::<Vec<_>>(); - - let mut virtual_file_mapping = VirtualFileMapping::default(); - let mut code_regions = vec![]; - let mut branch_regions = vec![]; - let mut mcdc_branch_regions = vec![]; - let mut mcdc_decision_regions = vec![]; - - // Currently a function's mappings must all be in the same file as its body span. - let file_name = span_file_name(tcx, function_coverage.function_coverage_info.body_span); - - // Look up the global file ID for that filename. - let global_file_id = global_file_table.global_file_id_for_file_name(file_name); - - // Associate that global file ID with a local file ID for this function. - let local_file_id = virtual_file_mapping.local_id_for_global(global_file_id); - debug!(" file id: {local_file_id:?} => {global_file_id:?} = '{file_name:?}'"); - - // For each counter/region pair in this function+file, convert it to a - // form suitable for FFI. - for (mapping_kind, region) in counter_regions { - debug!("Adding counter {mapping_kind:?} to map for {region:?}"); - let span = ffi::CoverageSpan::from_source_region(local_file_id, region); - match mapping_kind { - MappingKind::Code(term) => { - code_regions.push(ffi::CodeRegion { span, counter: ffi::Counter::from_term(term) }); - } - MappingKind::Branch { true_term, false_term } => { - branch_regions.push(ffi::BranchRegion { - span, - true_counter: ffi::Counter::from_term(true_term), - false_counter: ffi::Counter::from_term(false_term), - }); - } - MappingKind::MCDCBranch { true_term, false_term, mcdc_params } => { - mcdc_branch_regions.push(ffi::MCDCBranchRegion { - span, - true_counter: ffi::Counter::from_term(true_term), - false_counter: ffi::Counter::from_term(false_term), - mcdc_branch_params: ffi::mcdc::BranchParameters::from(mcdc_params), - }); - } - MappingKind::MCDCDecision(mcdc_decision_params) => { - mcdc_decision_regions.push(ffi::MCDCDecisionRegion { - span, - mcdc_decision_params: ffi::mcdc::DecisionParameters::from(mcdc_decision_params), - }); - } - } - } - - // Encode the function's coverage mappings into a buffer. - llvm_cov::write_function_mappings_to_buffer( - &virtual_file_mapping.into_vec(), - &expressions, - &code_regions, - &branch_regions, - &mcdc_branch_regions, - &mcdc_decision_regions, - ) -} - /// Generates the contents of the covmap record for this CGU, which mostly /// consists of a header and a list of filenames. The record is then stored /// as a global variable in the `__llvm_covmap` section. @@ -355,61 +259,6 @@ fn generate_covmap_record<'ll>( cx.add_used_global(llglobal); } -/// Generates the contents of the covfun record for this function, which -/// contains the function's coverage mapping data. The record is then stored -/// as a global variable in the `__llvm_covfun` section. -fn generate_covfun_record( - cx: &CodegenCx<'_, '_>, - mangled_function_name: &str, - source_hash: u64, - filenames_ref: u64, - coverage_mapping_buffer: Vec<u8>, - is_used: bool, -) { - // Concatenate the encoded coverage mappings - let coverage_mapping_size = coverage_mapping_buffer.len(); - let coverage_mapping_val = cx.const_bytes(&coverage_mapping_buffer); - - let func_name_hash = llvm_cov::hash_bytes(mangled_function_name.as_bytes()); - let func_name_hash_val = cx.const_u64(func_name_hash); - let coverage_mapping_size_val = cx.const_u32(coverage_mapping_size as u32); - let source_hash_val = cx.const_u64(source_hash); - let filenames_ref_val = cx.const_u64(filenames_ref); - let func_record_val = cx.const_struct( - &[ - func_name_hash_val, - coverage_mapping_size_val, - source_hash_val, - filenames_ref_val, - coverage_mapping_val, - ], - /*packed=*/ true, - ); - - // Choose a variable name to hold this function's covfun data. - // Functions that are used have a suffix ("u") to distinguish them from - // unused copies of the same function (from different CGUs), so that if a - // linker sees both it won't discard the used copy's data. - let func_record_var_name = - CString::new(format!("__covrec_{:X}{}", func_name_hash, if is_used { "u" } else { "" })) - .unwrap(); - debug!("function record var name: {:?}", func_record_var_name); - - let llglobal = llvm::add_global(cx.llmod, cx.val_ty(func_record_val), &func_record_var_name); - llvm::set_initializer(llglobal, func_record_val); - llvm::set_global_constant(llglobal, true); - llvm::set_linkage(llglobal, llvm::Linkage::LinkOnceODRLinkage); - llvm::set_visibility(llglobal, llvm::Visibility::Hidden); - llvm::set_section(llglobal, cx.covfun_section_name()); - // LLVM's coverage mapping format specifies 8-byte alignment for items in this section. - // <https://llvm.org/docs/CoverageMappingFormat.html> - llvm::set_alignment(llglobal, Align::EIGHT); - if cx.target_spec().supports_comdat() { - llvm::set_comdat(cx.llmod, llglobal, &func_record_var_name); - } - cx.add_used_global(llglobal); -} - /// Each CGU will normally only emit coverage metadata for the functions that it actually generates. /// But since we don't want unused functions to disappear from coverage reports, we also scan for /// functions that were instrumented but are not participating in codegen. @@ -536,11 +385,6 @@ fn add_unused_function_coverage<'tcx>( ); // An unused function's mappings will all be rewritten to map to zero. - let function_coverage = FunctionCoverageCollector::unused( - instance, - function_coverage_info, - tcx.coverage_ids_info(instance.def), - ); - + let function_coverage = FunctionCoverage::new_unused(function_coverage_info); cx.coverage_cx().function_coverage_map.borrow_mut().insert(instance, function_coverage); } diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs new file mode 100644 index 00000000000..530e6827f55 --- /dev/null +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/covfun.rs @@ -0,0 +1,200 @@ +//! For each function that was instrumented for coverage, we need to embed its +//! corresponding coverage mapping metadata inside the `__llvm_covfun`[^win] +//! linker section of the final binary. +//! +//! [^win]: On Windows the section name is `.lcovfun`. + +use std::ffi::CString; + +use rustc_abi::Align; +use rustc_codegen_ssa::traits::{ + BaseTypeCodegenMethods, ConstCodegenMethods, StaticCodegenMethods, +}; +use rustc_middle::bug; +use rustc_middle::mir::coverage::MappingKind; +use rustc_middle::ty::{Instance, TyCtxt}; +use rustc_target::spec::HasTargetSpec; +use tracing::debug; + +use crate::common::CodegenCx; +use crate::coverageinfo::map_data::FunctionCoverage; +use crate::coverageinfo::mapgen::{GlobalFileTable, VirtualFileMapping, span_file_name}; +use crate::coverageinfo::{ffi, llvm_cov}; +use crate::llvm; + +/// Intermediate coverage metadata for a single function, used to help build +/// the final record that will be embedded in the `__llvm_covfun` section. +#[derive(Debug)] +pub(crate) struct CovfunRecord<'tcx> { + mangled_function_name: &'tcx str, + source_hash: u64, + is_used: bool, + + virtual_file_mapping: VirtualFileMapping, + expressions: Vec<ffi::CounterExpression>, + regions: ffi::Regions, +} + +impl<'tcx> CovfunRecord<'tcx> { + /// FIXME(Zalathar): Make this the responsibility of the code that determines + /// which functions are unused. + pub(crate) fn mangled_function_name_if_unused(&self) -> Option<&'tcx str> { + (!self.is_used).then_some(self.mangled_function_name) + } +} + +pub(crate) fn prepare_covfun_record<'tcx>( + tcx: TyCtxt<'tcx>, + global_file_table: &GlobalFileTable, + instance: Instance<'tcx>, + function_coverage: &FunctionCoverage<'tcx>, +) -> Option<CovfunRecord<'tcx>> { + let mut covfun = CovfunRecord { + mangled_function_name: tcx.symbol_name(instance).name, + source_hash: function_coverage.source_hash(), + is_used: function_coverage.is_used(), + virtual_file_mapping: VirtualFileMapping::default(), + expressions: function_coverage.counter_expressions().collect::<Vec<_>>(), + regions: ffi::Regions::default(), + }; + + fill_region_tables(tcx, global_file_table, function_coverage, &mut covfun); + + if covfun.regions.has_no_regions() { + if covfun.is_used { + bug!("a used function should have had coverage mapping data but did not: {covfun:?}"); + } else { + debug!(?covfun, "unused function had no coverage mapping data"); + return None; + } + } + + Some(covfun) +} + +/// Populates the mapping region tables in the current function's covfun record. +fn fill_region_tables<'tcx>( + tcx: TyCtxt<'tcx>, + global_file_table: &GlobalFileTable, + function_coverage: &FunctionCoverage<'tcx>, + covfun: &mut CovfunRecord<'tcx>, +) { + let counter_regions = function_coverage.counter_regions(); + if counter_regions.is_empty() { + return; + } + + // Currently a function's mappings must all be in the same file as its body span. + let file_name = span_file_name(tcx, function_coverage.function_coverage_info.body_span); + + // Look up the global file ID for that filename. + let global_file_id = global_file_table.global_file_id_for_file_name(file_name); + + // Associate that global file ID with a local file ID for this function. + let local_file_id = covfun.virtual_file_mapping.local_id_for_global(global_file_id); + debug!(" file id: {local_file_id:?} => {global_file_id:?} = '{file_name:?}'"); + + let ffi::Regions { code_regions, branch_regions, mcdc_branch_regions, mcdc_decision_regions } = + &mut covfun.regions; + + // For each counter/region pair in this function+file, convert it to a + // form suitable for FFI. + for (mapping_kind, region) in counter_regions { + debug!("Adding counter {mapping_kind:?} to map for {region:?}"); + let span = ffi::CoverageSpan::from_source_region(local_file_id, region); + match mapping_kind { + MappingKind::Code(term) => { + code_regions.push(ffi::CodeRegion { span, counter: ffi::Counter::from_term(term) }); + } + MappingKind::Branch { true_term, false_term } => { + branch_regions.push(ffi::BranchRegion { + span, + true_counter: ffi::Counter::from_term(true_term), + false_counter: ffi::Counter::from_term(false_term), + }); + } + MappingKind::MCDCBranch { true_term, false_term, mcdc_params } => { + mcdc_branch_regions.push(ffi::MCDCBranchRegion { + span, + true_counter: ffi::Counter::from_term(true_term), + false_counter: ffi::Counter::from_term(false_term), + mcdc_branch_params: ffi::mcdc::BranchParameters::from(mcdc_params), + }); + } + MappingKind::MCDCDecision(mcdc_decision_params) => { + mcdc_decision_regions.push(ffi::MCDCDecisionRegion { + span, + mcdc_decision_params: ffi::mcdc::DecisionParameters::from(mcdc_decision_params), + }); + } + } + } +} + +/// Generates the contents of the covfun record for this function, which +/// contains the function's coverage mapping data. The record is then stored +/// as a global variable in the `__llvm_covfun` section. +pub(crate) fn generate_covfun_record<'tcx>( + cx: &CodegenCx<'_, 'tcx>, + filenames_ref: u64, + covfun: &CovfunRecord<'tcx>, +) { + let &CovfunRecord { + mangled_function_name, + source_hash, + is_used, + ref virtual_file_mapping, + ref expressions, + ref regions, + } = covfun; + + // Encode the function's coverage mappings into a buffer. + let coverage_mapping_buffer = llvm_cov::write_function_mappings_to_buffer( + &virtual_file_mapping.to_vec(), + expressions, + regions, + ); + + // Concatenate the encoded coverage mappings + let coverage_mapping_size = coverage_mapping_buffer.len(); + let coverage_mapping_val = cx.const_bytes(&coverage_mapping_buffer); + + let func_name_hash = llvm_cov::hash_bytes(mangled_function_name.as_bytes()); + let func_name_hash_val = cx.const_u64(func_name_hash); + let coverage_mapping_size_val = cx.const_u32(coverage_mapping_size as u32); + let source_hash_val = cx.const_u64(source_hash); + let filenames_ref_val = cx.const_u64(filenames_ref); + let func_record_val = cx.const_struct( + &[ + func_name_hash_val, + coverage_mapping_size_val, + source_hash_val, + filenames_ref_val, + coverage_mapping_val, + ], + /*packed=*/ true, + ); + + // Choose a variable name to hold this function's covfun data. + // Functions that are used have a suffix ("u") to distinguish them from + // unused copies of the same function (from different CGUs), so that if a + // linker sees both it won't discard the used copy's data. + let func_record_var_name = + CString::new(format!("__covrec_{:X}{}", func_name_hash, if is_used { "u" } else { "" })) + .unwrap(); + debug!("function record var name: {:?}", func_record_var_name); + + let llglobal = llvm::add_global(cx.llmod, cx.val_ty(func_record_val), &func_record_var_name); + llvm::set_initializer(llglobal, func_record_val); + llvm::set_global_constant(llglobal, true); + llvm::set_linkage(llglobal, llvm::Linkage::LinkOnceODRLinkage); + llvm::set_visibility(llglobal, llvm::Visibility::Hidden); + llvm::set_section(llglobal, cx.covfun_section_name()); + // LLVM's coverage mapping format specifies 8-byte alignment for items in this section. + // <https://llvm.org/docs/CoverageMappingFormat.html> + llvm::set_alignment(llglobal, Align::EIGHT); + if cx.target_spec().supports_comdat() { + llvm::set_comdat(cx.llmod, llglobal, &func_record_var_name); + } + cx.add_used_global(llglobal); +} diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs index c2fcb33f98b..82b6677e203 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs @@ -13,7 +13,7 @@ use tracing::{debug, instrument}; use crate::builder::Builder; use crate::common::CodegenCx; -use crate::coverageinfo::map_data::FunctionCoverageCollector; +use crate::coverageinfo::map_data::FunctionCoverage; use crate::llvm; pub(crate) mod ffi; @@ -24,8 +24,7 @@ mod mapgen; /// Extra per-CGU context/state needed for coverage instrumentation. pub(crate) struct CguCoverageContext<'ll, 'tcx> { /// Coverage data for each instrumented function identified by DefId. - pub(crate) function_coverage_map: - RefCell<FxIndexMap<Instance<'tcx>, FunctionCoverageCollector<'tcx>>>, + pub(crate) function_coverage_map: RefCell<FxIndexMap<Instance<'tcx>, FunctionCoverage<'tcx>>>, pub(crate) pgo_func_name_var_map: RefCell<FxHashMap<Instance<'tcx>, &'ll llvm::Value>>, pub(crate) mcdc_condition_bitmap_map: RefCell<FxHashMap<Instance<'tcx>, Vec<&'ll llvm::Value>>>, @@ -42,9 +41,7 @@ impl<'ll, 'tcx> CguCoverageContext<'ll, 'tcx> { } } - fn take_function_coverage_map( - &self, - ) -> FxIndexMap<Instance<'tcx>, FunctionCoverageCollector<'tcx>> { + fn take_function_coverage_map(&self) -> FxIndexMap<Instance<'tcx>, FunctionCoverage<'tcx>> { self.function_coverage_map.replace(FxIndexMap::default()) } @@ -161,8 +158,7 @@ impl<'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'_, '_, 'tcx> { // This includes functions that were not partitioned into this CGU, // but were MIR-inlined into one of this CGU's functions. coverage_cx.function_coverage_map.borrow_mut().entry(instance).or_insert_with(|| { - FunctionCoverageCollector::new( - instance, + FunctionCoverage::new_used( function_coverage_info, bx.tcx.coverage_ids_info(instance.def), ) diff --git a/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs b/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs index a4cb5a25d1b..11043b664f5 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs @@ -151,7 +151,7 @@ impl InlineAsmDiagnostic { unsafe { SrcMgrDiagnostic::unpack(super::LLVMRustGetSMDiagnostic(di, &mut cookie)) }; InlineAsmDiagnostic { level: smdiag.level, - cookie: cookie.into(), + cookie, message: smdiag.message, source: smdiag.source, } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index b1ace0033ba..8b4523bd252 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -2317,7 +2317,7 @@ unsafe extern "C" { pub fn LLVMRustGetSMDiagnostic<'a>( DI: &'a DiagnosticInfo, - cookie_out: &mut c_uint, + cookie_out: &mut u64, ) -> &'a SMDiagnostic; pub fn LLVMRustUnpackSMDiagnostic( diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index db2b03d9aed..07eb89e6041 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -230,6 +230,8 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option<LLVMFea "aarch64" } else if sess.target.arch == "sparc64" { "sparc" + } else if sess.target.arch == "powerpc64" { + "powerpc" } else { &*sess.target.arch }; @@ -289,6 +291,7 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option<LLVMFea // https://github.com/llvm/llvm-project/blob/llvmorg-18.1.0/llvm/lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp#L26 ("sparc", "v8plus") if get_version().0 == 19 => Some(LLVMFeature::new("v9")), ("sparc", "v8plus") if get_version().0 < 19 => None, + ("powerpc", "power8-crypto") => Some(LLVMFeature::new("crypto")), (_, s) => Some(LLVMFeature::new(s)), } } diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml index b898cfec796..c81e36dfc8d 100644 --- a/compiler/rustc_codegen_ssa/Cargo.toml +++ b/compiler/rustc_codegen_ssa/Cargo.toml @@ -17,6 +17,7 @@ regex = "1.4" rustc_abi = { path = "../rustc_abi" } rustc_arena = { path = "../rustc_arena" } rustc_ast = { path = "../rustc_ast" } +rustc_ast_pretty = { path = "../rustc_ast_pretty" } rustc_attr = { path = "../rustc_attr" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } @@ -42,7 +43,7 @@ tempfile = "3.2" thin-vec = "0.2.12" thorin-dwp = "0.8" tracing = "0.1" -wasm-encoder = "0.216.0" +wasm-encoder = "0.219" # tidy-alphabetical-end [target.'cfg(unix)'.dependencies] diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl index 62db3d5a98c..56188714b44 100644 --- a/compiler/rustc_codegen_ssa/messages.ftl +++ b/compiler/rustc_codegen_ssa/messages.ftl @@ -201,6 +201,11 @@ codegen_ssa_missing_memory_ordering = Atomic intrinsic missing memory ordering codegen_ssa_missing_query_depgraph = found CGU-reuse attribute but `-Zquery-dep-graph` was not specified +codegen_ssa_mixed_export_name_and_no_mangle = `{$no_mangle_attr}` attribute may not be used in combination with `#[export_name]` + .label = `{$no_mangle_attr}` is ignored + .note = `#[export_name]` takes precedence + .suggestion = remove the `{$no_mangle_attr}` attribute + codegen_ssa_msvc_missing_linker = the msvc targets depend on the msvc linker but `link.exe` was not found codegen_ssa_multiple_external_func_decl = multiple declarations of external function `{$function}` from library `{$library_name}` have different calling conventions diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index f8b3ba79c0d..b030ea3f6df 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -992,12 +992,12 @@ fn link_natively( let mut output = prog.stderr.clone(); output.extend_from_slice(&prog.stdout); let escaped_output = escape_linker_output(&output, flavor); - // FIXME: Add UI tests for this error. let err = errors::LinkingFailed { linker_path: &linker_path, exit_status: prog.status, - command: &cmd, + command: cmd, escaped_output, + verbose: sess.opts.verbose, }; sess.dcx().emit_err(err); // If MSVC's `link.exe` was expected but the return code @@ -2745,6 +2745,15 @@ fn add_upstream_rust_crates( .find(|(ty, _)| *ty == crate_type) .expect("failed to find crate type in dependency format list"); + if sess.target.is_like_aix { + // Unlike ELF linkers, AIX doesn't feature `DT_SONAME` to override + // the dependency name when outputing a shared library. Thus, `ld` will + // use the full path to shared libraries as the dependency if passed it + // by default unless `noipath` is passed. + // https://www.ibm.com/docs/en/aix/7.3?topic=l-ld-command. + cmd.link_or_cc_arg("-bnoipath"); + } + for &cnum in &codegen_results.crate_info.used_crates { // We may not pass all crates through to the linker. Some crates may appear statically in // an existing dylib, meaning we'll pick up all the symbols from the dylib. diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 05dfbd40a0a..4c5eb98e890 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -1694,6 +1694,8 @@ impl<'a> Linker for AixLinker<'a> { fn pgo_gen(&mut self) { self.link_arg("-bdbg:namedsects:ss"); + self.link_arg("-u"); + self.link_arg("__llvm_profile_runtime"); } fn control_flow_guard(&mut self) {} diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 90d48d6ee7e..501f7517919 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -34,7 +34,7 @@ use rustc_session::config::{ }; use rustc_span::source_map::SourceMap; use rustc_span::symbol::sym; -use rustc_span::{BytePos, FileName, InnerSpan, Pos, Span}; +use rustc_span::{FileName, InnerSpan, Span, SpanData}; use rustc_target::spec::{MergeFunctions, SanitizerSet}; use tracing::debug; @@ -1837,7 +1837,7 @@ fn spawn_work<'a, B: ExtraBackendMethods>( enum SharedEmitterMessage { Diagnostic(Diagnostic), - InlineAsmError(u32, String, Level, Option<(String, Vec<InnerSpan>)>), + InlineAsmError(SpanData, String, Level, Option<(String, Vec<InnerSpan>)>), Fatal(String), } @@ -1859,12 +1859,12 @@ impl SharedEmitter { pub fn inline_asm_error( &self, - cookie: u32, + span: SpanData, msg: String, level: Level, source: Option<(String, Vec<InnerSpan>)>, ) { - drop(self.sender.send(SharedEmitterMessage::InlineAsmError(cookie, msg, level, source))); + drop(self.sender.send(SharedEmitterMessage::InlineAsmError(span, msg, level, source))); } fn fatal(&self, msg: &str) { @@ -1953,17 +1953,12 @@ impl SharedEmitterMain { dcx.emit_diagnostic(d); sess.dcx().abort_if_errors(); } - Ok(SharedEmitterMessage::InlineAsmError(cookie, msg, level, source)) => { + Ok(SharedEmitterMessage::InlineAsmError(span, msg, level, source)) => { assert_matches!(level, Level::Error | Level::Warning | Level::Note); - let msg = msg.strip_prefix("error: ").unwrap_or(&msg).to_string(); let mut err = Diag::<()>::new(sess.dcx(), level, msg); - - // If the cookie is 0 then we don't have span information. - if cookie != 0 { - let pos = BytePos::from_u32(cookie); - let span = Span::with_root_ctxt(pos, pos); - err.span(span); - }; + if !span.is_dummy() { + err.span(span.span()); + } // Point to the generated assembly if it is available. if let Some((buffer, spans)) = source { diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index a5acd8170ab..ab2d24e8d2d 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -3,11 +3,10 @@ use rustc_attr::{InlineAttr, InstructionSetAttr, OptimizeAttr, list_contains_nam use rustc_data_structures::fx::FxHashMap; use rustc_errors::codes::*; use rustc_errors::{DiagMessage, SubdiagMessage, struct_span_code_err}; -use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId}; use rustc_hir::weak_lang_items::WEAK_LANG_ITEMS; -use rustc_hir::{LangItem, lang_items}; +use rustc_hir::{self as hir, HirId, LangItem, lang_items}; use rustc_middle::middle::codegen_fn_attrs::{ CodegenFnAttrFlags, CodegenFnAttrs, PatchableFunctionEntry, }; @@ -78,6 +77,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { let mut inline_span = None; let mut link_ordinal_span = None; let mut no_sanitize_span = None; + let mut mixed_export_name_no_mangle_lint_state = MixedExportNameAndNoMangleState::default(); for attr in attrs.iter() { // In some cases, attribute are only valid on functions, but it's the `check_attr` @@ -116,7 +116,12 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { sym::naked => codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED, sym::no_mangle => { if tcx.opt_item_name(did.to_def_id()).is_some() { - codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE + codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE; + mixed_export_name_no_mangle_lint_state.track_no_mangle( + attr.span, + tcx.local_def_id_to_hir_id(did), + attr, + ); } else { tcx.dcx() .struct_span_err( @@ -240,6 +245,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { .emit(); } codegen_fn_attrs.export_name = Some(s); + mixed_export_name_no_mangle_lint_state.track_export_name(attr.span); } } sym::target_feature => { @@ -513,6 +519,8 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { } } + mixed_export_name_no_mangle_lint_state.lint_if_mixed(tcx); + codegen_fn_attrs.inline = attrs.iter().fold(InlineAttr::None, |ia, attr| { if !attr.has_name(sym::inline) { return ia; @@ -542,6 +550,13 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { } }); + // naked function MUST NOT be inlined! This attribute is required for the rust compiler itself, + // but not for the code generation backend because at that point the naked function will just be + // a declaration, with a definition provided in global assembly. + if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) { + codegen_fn_attrs.inline = InlineAttr::Never; + } + codegen_fn_attrs.optimize = attrs.iter().fold(OptimizeAttr::None, |ia, attr| { if !attr.has_name(sym::optimize) { return ia; @@ -626,10 +641,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { } } - if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) { - codegen_fn_attrs.inline = InlineAttr::Never; - } - // Weak lang items have the same semantics as "std internal" symbols in the // sense that they're preserved through all our LTO passes and only // strippable by the linker. @@ -779,6 +790,49 @@ fn check_link_name_xor_ordinal( } } +#[derive(Default)] +struct MixedExportNameAndNoMangleState<'a> { + export_name: Option<Span>, + hir_id: Option<HirId>, + no_mangle: Option<Span>, + no_mangle_attr: Option<&'a ast::Attribute>, +} + +impl<'a> MixedExportNameAndNoMangleState<'a> { + fn track_export_name(&mut self, span: Span) { + self.export_name = Some(span); + } + + fn track_no_mangle(&mut self, span: Span, hir_id: HirId, attr_name: &'a ast::Attribute) { + self.no_mangle = Some(span); + self.hir_id = Some(hir_id); + self.no_mangle_attr = Some(attr_name); + } + + /// Emit diagnostics if the lint condition is met. + fn lint_if_mixed(self, tcx: TyCtxt<'_>) { + if let Self { + export_name: Some(export_name), + no_mangle: Some(no_mangle), + hir_id: Some(hir_id), + no_mangle_attr: Some(no_mangle_attr), + } = self + { + tcx.emit_node_span_lint( + lint::builtin::UNUSED_ATTRIBUTES, + hir_id, + no_mangle, + errors::MixedExportNameAndNoMangle { + no_mangle, + no_mangle_attr: rustc_ast_pretty::pprust::attribute_to_string(no_mangle_attr), + export_name, + removal_span: no_mangle, + }, + ); + } + } +} + pub(crate) fn provide(providers: &mut Providers) { *providers = Providers { codegen_fn_attrs, should_inherit_track_caller, ..*providers }; } diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index f93cb52ea3e..c7213bbc801 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -1,6 +1,7 @@ //! Errors emitted by codegen_ssa use std::borrow::Cow; +use std::ffi::OsString; use std::io::Error; use std::num::ParseIntError; use std::path::{Path, PathBuf}; @@ -10,7 +11,7 @@ use rustc_errors::codes::*; use rustc_errors::{ Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, IntoDiagArg, Level, }; -use rustc_macros::{Diagnostic, Subdiagnostic}; +use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_middle::ty::Ty; use rustc_middle::ty::layout::LayoutError; use rustc_span::{Span, Symbol}; @@ -345,21 +346,82 @@ impl<G: EmissionGuarantee> Diagnostic<'_, G> for ThorinErrorWrapper { } pub(crate) struct LinkingFailed<'a> { - pub linker_path: &'a PathBuf, + pub linker_path: &'a Path, pub exit_status: ExitStatus, - pub command: &'a Command, + pub command: Command, pub escaped_output: String, + pub verbose: bool, } impl<G: EmissionGuarantee> Diagnostic<'_, G> for LinkingFailed<'_> { - fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { + fn into_diag(mut self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { let mut diag = Diag::new(dcx, level, fluent::codegen_ssa_linking_failed); diag.arg("linker_path", format!("{}", self.linker_path.display())); diag.arg("exit_status", format!("{}", self.exit_status)); let contains_undefined_ref = self.escaped_output.contains("undefined reference to"); - diag.note(format!("{:?}", self.command)).note(self.escaped_output); + if self.verbose { + diag.note(format!("{:?}", self.command)); + } else { + enum ArgGroup { + Regular(OsString), + Objects(usize), + Rlibs(PathBuf, Vec<OsString>), + } + + // Omit rust object files and fold rlibs in the error by default to make linker errors a + // bit less verbose. + let orig_args = self.command.take_args(); + let mut args: Vec<ArgGroup> = vec![]; + for arg in orig_args { + if arg.as_encoded_bytes().ends_with(b".rcgu.o") { + if let Some(ArgGroup::Objects(n)) = args.last_mut() { + *n += 1; + } else { + args.push(ArgGroup::Objects(1)); + } + } else if arg.as_encoded_bytes().ends_with(b".rlib") { + let rlib_path = Path::new(&arg); + let dir = rlib_path.parent().unwrap(); + let filename = rlib_path.file_name().unwrap().to_owned(); + if let Some(ArgGroup::Rlibs(parent, rlibs)) = args.last_mut() { + if parent == dir { + rlibs.push(filename); + } else { + args.push(ArgGroup::Rlibs(dir.to_owned(), vec![filename])); + } + } else { + args.push(ArgGroup::Rlibs(dir.to_owned(), vec![filename])); + } + } else { + args.push(ArgGroup::Regular(arg)); + } + } + self.command.args(args.into_iter().map(|arg_group| match arg_group { + ArgGroup::Regular(arg) => arg, + ArgGroup::Objects(n) => OsString::from(format!("<{n} object files omitted>")), + ArgGroup::Rlibs(dir, rlibs) => { + let mut arg = dir.into_os_string(); + arg.push("/{"); + let mut first = true; + for rlib in rlibs { + if !first { + arg.push(","); + } + first = false; + arg.push(rlib); + } + arg.push("}"); + arg + } + })); + + diag.note(format!("{:?}", self.command)); + diag.note("some arguments are omitted. use `--verbose` to show all linker arguments"); + } + + diag.note(self.escaped_output); // Trying to match an error from OS linkers // which by now we have no way to translate. @@ -1114,3 +1176,15 @@ impl<G: EmissionGuarantee> Diagnostic<'_, G> for TargetFeatureDisableOrEnable<'_ #[derive(Diagnostic)] #[diag(codegen_ssa_aix_strip_not_used)] pub(crate) struct AixStripNotUsed; + +#[derive(LintDiagnostic)] +#[diag(codegen_ssa_mixed_export_name_and_no_mangle)] +pub(crate) struct MixedExportNameAndNoMangle { + #[label] + pub no_mangle: Span, + pub no_mangle_attr: String, + #[note] + pub export_name: Span, + #[suggestion(style = "verbose", code = "", applicability = "machine-applicable")] + pub removal_span: Span, +} diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index 0cbc5c45736..62f69af3f2f 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -20,6 +20,7 @@ mod coverageinfo; pub mod debuginfo; mod intrinsic; mod locals; +mod naked_asm; pub mod operand; pub mod place; mod rvalue; @@ -176,6 +177,11 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let fn_abi = cx.fn_abi_of_instance(instance, ty::List::empty()); debug!("fn_abi: {:?}", fn_abi); + if cx.tcx().codegen_fn_attrs(instance.def_id()).flags.contains(CodegenFnAttrFlags::NAKED) { + crate::mir::naked_asm::codegen_naked_asm::<Bx>(cx, &mir, instance); + return; + } + let debug_context = cx.create_function_debug_context(instance, fn_abi, llfn, mir); let start_llbb = Bx::append_block(cx, llfn, "start"); diff --git a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs new file mode 100644 index 00000000000..c08758a9796 --- /dev/null +++ b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs @@ -0,0 +1,266 @@ +use rustc_attr::InstructionSetAttr; +use rustc_middle::mir::mono::{Linkage, MonoItem, MonoItemData, Visibility}; +use rustc_middle::mir::{Body, InlineAsmOperand}; +use rustc_middle::ty::layout::{HasTyCtxt, HasTypingEnv, LayoutOf}; +use rustc_middle::ty::{Instance, TyCtxt}; +use rustc_middle::{bug, ty}; +use rustc_span::sym; + +use crate::common; +use crate::traits::{AsmCodegenMethods, BuilderMethods, GlobalAsmOperandRef, MiscCodegenMethods}; + +pub(crate) fn codegen_naked_asm<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( + cx: &'a Bx::CodegenCx, + mir: &Body<'tcx>, + instance: Instance<'tcx>, +) { + let rustc_middle::mir::TerminatorKind::InlineAsm { + asm_macro: _, + template, + ref operands, + options, + line_spans, + targets: _, + unwind: _, + } = mir.basic_blocks.iter().next().unwrap().terminator().kind + else { + bug!("#[naked] functions should always terminate with an asm! block") + }; + + let operands: Vec<_> = + operands.iter().map(|op| inline_to_global_operand::<Bx>(cx, instance, op)).collect(); + + let item_data = cx.codegen_unit().items().get(&MonoItem::Fn(instance)).unwrap(); + let name = cx.mangled_name(instance); + let (begin, end) = prefix_and_suffix(cx.tcx(), instance, &name, item_data); + + let mut template_vec = Vec::new(); + template_vec.push(rustc_ast::ast::InlineAsmTemplatePiece::String(begin.into())); + template_vec.extend(template.iter().cloned()); + template_vec.push(rustc_ast::ast::InlineAsmTemplatePiece::String(end.into())); + + cx.codegen_global_asm(&template_vec, &operands, options, line_spans); +} + +fn inline_to_global_operand<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( + cx: &'a Bx::CodegenCx, + instance: Instance<'tcx>, + op: &InlineAsmOperand<'tcx>, +) -> GlobalAsmOperandRef<'tcx> { + match op { + InlineAsmOperand::Const { value } => { + let const_value = instance + .instantiate_mir_and_normalize_erasing_regions( + cx.tcx(), + cx.typing_env(), + ty::EarlyBinder::bind(value.const_), + ) + .eval(cx.tcx(), cx.typing_env(), value.span) + .expect("erroneous constant missed by mono item collection"); + + let mono_type = instance.instantiate_mir_and_normalize_erasing_regions( + cx.tcx(), + cx.typing_env(), + ty::EarlyBinder::bind(value.ty()), + ); + + let string = common::asm_const_to_str( + cx.tcx(), + value.span, + const_value, + cx.layout_of(mono_type), + ); + + GlobalAsmOperandRef::Const { string } + } + InlineAsmOperand::SymFn { value } => { + let mono_type = instance.instantiate_mir_and_normalize_erasing_regions( + cx.tcx(), + cx.typing_env(), + ty::EarlyBinder::bind(value.ty()), + ); + + let instance = match mono_type.kind() { + &ty::FnDef(def_id, args) => Instance::new(def_id, args), + _ => bug!("asm sym is not a function"), + }; + + GlobalAsmOperandRef::SymFn { instance } + } + InlineAsmOperand::SymStatic { def_id } => { + GlobalAsmOperandRef::SymStatic { def_id: *def_id } + } + InlineAsmOperand::In { .. } + | InlineAsmOperand::Out { .. } + | InlineAsmOperand::InOut { .. } + | InlineAsmOperand::Label { .. } => { + bug!("invalid operand type for naked_asm!") + } + } +} + +enum AsmBinaryFormat { + Elf, + Macho, + Coff, +} + +impl AsmBinaryFormat { + fn from_target(target: &rustc_target::spec::Target) -> Self { + if target.is_like_windows { + Self::Coff + } else if target.is_like_osx { + Self::Macho + } else { + Self::Elf + } + } +} + +fn prefix_and_suffix<'tcx>( + tcx: TyCtxt<'tcx>, + instance: Instance<'tcx>, + asm_name: &str, + item_data: &MonoItemData, +) -> (String, String) { + use std::fmt::Write; + + let asm_binary_format = AsmBinaryFormat::from_target(&tcx.sess.target); + + let is_arm = tcx.sess.target.arch == "arm"; + let is_thumb = tcx.sess.unstable_target_features.contains(&sym::thumb_mode); + + let attrs = tcx.codegen_fn_attrs(instance.def_id()); + let link_section = attrs.link_section.map(|symbol| symbol.as_str().to_string()); + let align = attrs.alignment.map(|a| a.bytes()).unwrap_or(4); + + // See https://sourceware.org/binutils/docs/as/ARM-Directives.html for info on these directives. + // In particular, `.arm` can also be written `.code 32` and `.thumb` as `.code 16`. + let (arch_prefix, arch_suffix) = if is_arm { + ( + match attrs.instruction_set { + None => match is_thumb { + true => ".thumb\n.thumb_func", + false => ".arm", + }, + Some(InstructionSetAttr::ArmT32) => ".thumb\n.thumb_func", + Some(InstructionSetAttr::ArmA32) => ".arm", + }, + match is_thumb { + true => ".thumb", + false => ".arm", + }, + ) + } else { + ("", "") + }; + + let emit_fatal = |msg| tcx.dcx().span_fatal(tcx.def_span(instance.def_id()), msg); + + // see https://godbolt.org/z/cPK4sxKor. + let write_linkage = |w: &mut String| -> std::fmt::Result { + match item_data.linkage { + Linkage::External => { + writeln!(w, ".globl {asm_name}")?; + } + Linkage::LinkOnceAny | Linkage::LinkOnceODR | Linkage::WeakAny | Linkage::WeakODR => { + match asm_binary_format { + AsmBinaryFormat::Elf | AsmBinaryFormat::Coff => { + writeln!(w, ".weak {asm_name}")?; + } + AsmBinaryFormat::Macho => { + writeln!(w, ".globl {asm_name}")?; + writeln!(w, ".weak_definition {asm_name}")?; + } + } + } + Linkage::Internal | Linkage::Private => { + // write nothing + } + Linkage::Appending => emit_fatal("Only global variables can have appending linkage!"), + Linkage::Common => emit_fatal("Functions may not have common linkage"), + Linkage::AvailableExternally => { + // this would make the function equal an extern definition + emit_fatal("Functions may not have available_externally linkage") + } + Linkage::ExternalWeak => { + // FIXME: actually this causes a SIGILL in LLVM + emit_fatal("Functions may not have external weak linkage") + } + } + + Ok(()) + }; + + let mut begin = String::new(); + let mut end = String::new(); + match asm_binary_format { + AsmBinaryFormat::Elf => { + let section = link_section.unwrap_or(format!(".text.{asm_name}")); + + let progbits = match is_arm { + true => "%progbits", + false => "@progbits", + }; + + let function = match is_arm { + true => "%function", + false => "@function", + }; + + writeln!(begin, ".pushsection {section},\"ax\", {progbits}").unwrap(); + writeln!(begin, ".balign {align}").unwrap(); + write_linkage(&mut begin).unwrap(); + if let Visibility::Hidden = item_data.visibility { + writeln!(begin, ".hidden {asm_name}").unwrap(); + } + writeln!(begin, ".type {asm_name}, {function}").unwrap(); + if !arch_prefix.is_empty() { + writeln!(begin, "{}", arch_prefix).unwrap(); + } + writeln!(begin, "{asm_name}:").unwrap(); + + writeln!(end).unwrap(); + writeln!(end, ".size {asm_name}, . - {asm_name}").unwrap(); + writeln!(end, ".popsection").unwrap(); + if !arch_suffix.is_empty() { + writeln!(end, "{}", arch_suffix).unwrap(); + } + } + AsmBinaryFormat::Macho => { + let section = link_section.unwrap_or("__TEXT,__text".to_string()); + writeln!(begin, ".pushsection {},regular,pure_instructions", section).unwrap(); + writeln!(begin, ".balign {align}").unwrap(); + write_linkage(&mut begin).unwrap(); + if let Visibility::Hidden = item_data.visibility { + writeln!(begin, ".private_extern {asm_name}").unwrap(); + } + writeln!(begin, "{asm_name}:").unwrap(); + + writeln!(end).unwrap(); + writeln!(end, ".popsection").unwrap(); + if !arch_suffix.is_empty() { + writeln!(end, "{}", arch_suffix).unwrap(); + } + } + AsmBinaryFormat::Coff => { + let section = link_section.unwrap_or(format!(".text.{asm_name}")); + writeln!(begin, ".pushsection {},\"xr\"", section).unwrap(); + writeln!(begin, ".balign {align}").unwrap(); + write_linkage(&mut begin).unwrap(); + writeln!(begin, ".def {asm_name}").unwrap(); + writeln!(begin, ".scl 2").unwrap(); + writeln!(begin, ".type 32").unwrap(); + writeln!(begin, ".endef {asm_name}").unwrap(); + writeln!(begin, "{asm_name}:").unwrap(); + + writeln!(end).unwrap(); + writeln!(end, ".popsection").unwrap(); + if !arch_suffix.is_empty() { + writeln!(end, "{}", arch_suffix).unwrap(); + } + } + } + + (begin, end) +} diff --git a/compiler/rustc_codegen_ssa/src/mono_item.rs b/compiler/rustc_codegen_ssa/src/mono_item.rs index 038c5857fac..6749bc63327 100644 --- a/compiler/rustc_codegen_ssa/src/mono_item.rs +++ b/compiler/rustc_codegen_ssa/src/mono_item.rs @@ -1,4 +1,5 @@ use rustc_hir as hir; +use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::mir::mono::{Linkage, MonoItem, Visibility}; use rustc_middle::ty::Instance; @@ -135,7 +136,13 @@ impl<'a, 'tcx: 'a> MonoItemExt<'a, 'tcx> for MonoItem<'tcx> { cx.predefine_static(def_id, linkage, visibility, symbol_name); } MonoItem::Fn(instance) => { - cx.predefine_fn(instance, linkage, visibility, symbol_name); + let attrs = cx.tcx().codegen_fn_attrs(instance.def_id()); + + if attrs.flags.contains(CodegenFnAttrFlags::NAKED) { + // do not define this function; it will become a global assembly block + } else { + cx.predefine_fn(instance, linkage, visibility, symbol_name); + }; } MonoItem::GlobalAsm(..) => {} } diff --git a/compiler/rustc_codegen_ssa/src/traits/asm.rs b/compiler/rustc_codegen_ssa/src/traits/asm.rs index f4853da1156..7767bffbfbf 100644 --- a/compiler/rustc_codegen_ssa/src/traits/asm.rs +++ b/compiler/rustc_codegen_ssa/src/traits/asm.rs @@ -68,4 +68,11 @@ pub trait AsmCodegenMethods<'tcx> { options: InlineAsmOptions, line_spans: &[Span], ); + + /// The mangled name of this instance + /// + /// Additional mangling is used on + /// some targets to add a leading underscore (Mach-O) + /// or byte count suffixes (x86 Windows). + fn mangled_name(&self, instance: Instance<'tcx>) -> String; } diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs index 3cb77d1dcb5..fee7287951d 100644 --- a/compiler/rustc_const_eval/src/const_eval/error.rs +++ b/compiler/rustc_const_eval/src/const_eval/error.rs @@ -170,7 +170,7 @@ where let reported = if allowed_in_infallible { ReportedErrorInfo::allowed_in_infallible(g) } else { - ReportedErrorInfo::from(g) + ReportedErrorInfo::const_eval_error(g) }; ErrorHandled::Reported(reported, span) } diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index 647d880e2bf..ce8eceebdf8 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -3,13 +3,13 @@ use std::sync::atomic::Ordering::Relaxed; use either::{Left, Right}; use rustc_abi::{self as abi, BackendRepr}; use rustc_hir::def::DefKind; -use rustc_middle::bug; -use rustc_middle::mir::interpret::{AllocId, ErrorHandled, InterpErrorInfo}; +use rustc_middle::mir::interpret::{AllocId, ErrorHandled, InterpErrorInfo, ReportedErrorInfo}; use rustc_middle::mir::{self, ConstAlloc, ConstValue}; use rustc_middle::query::TyCtxtAt; use rustc_middle::ty::layout::{HasTypingEnv, LayoutOf}; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::{bug, throw_inval}; use rustc_span::def_id::LocalDefId; use rustc_span::{DUMMY_SP, Span}; use tracing::{debug, instrument, trace}; @@ -93,18 +93,18 @@ fn eval_body_using_ecx<'tcx, R: InterpretationResult<'tcx>>( match intern_result { Ok(()) => {} Err(InternResult::FoundDanglingPointer) => { - return Err(ecx - .tcx - .dcx() - .emit_err(errors::DanglingPtrInFinal { span: ecx.tcx.span, kind: intern_kind })) - .into(); + throw_inval!(AlreadyReported(ReportedErrorInfo::non_const_eval_error( + ecx.tcx + .dcx() + .emit_err(errors::DanglingPtrInFinal { span: ecx.tcx.span, kind: intern_kind }), + ))); } Err(InternResult::FoundBadMutablePointer) => { - return Err(ecx - .tcx - .dcx() - .emit_err(errors::MutablePtrInFinal { span: ecx.tcx.span, kind: intern_kind })) - .into(); + throw_inval!(AlreadyReported(ReportedErrorInfo::non_const_eval_error( + ecx.tcx + .dcx() + .emit_err(errors::MutablePtrInFinal { span: ecx.tcx.span, kind: intern_kind }), + ))); } } diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 11e0fac51d8..56325eaa1be 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -8,6 +8,7 @@ use rustc_data_structures::fx::{FxHashMap, FxIndexMap, IndexEntry}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::{self as hir, CRATE_HIR_ID, LangItem}; use rustc_middle::mir::AssertMessage; +use rustc_middle::mir::interpret::ReportedErrorInfo; use rustc_middle::query::TyCtxtAt; use rustc_middle::ty::layout::{HasTypingEnv, TyAndLayout}; use rustc_middle::ty::{self, Ty, TyCtxt}; @@ -563,7 +564,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { .tcx .dcx() .span_delayed_bug(span, "The deny lint should have already errored"); - throw_inval!(AlreadyReported(guard.into())); + throw_inval!(AlreadyReported(ReportedErrorInfo::allowed_in_infallible(guard))); } } else if new_steps > start && new_steps.is_power_of_two() { // Only report after a certain number of terminators have been evaluated and the diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs index 515028e6826..6f51b09323d 100644 --- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs +++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs @@ -1,6 +1,6 @@ use rustc_abi::{BackendRepr, VariantIdx}; use rustc_data_structures::stack::ensure_sufficient_stack; -use rustc_middle::mir::interpret::{EvalToValTreeResult, GlobalId}; +use rustc_middle::mir::interpret::{EvalToValTreeResult, GlobalId, ReportedErrorInfo}; use rustc_middle::ty::layout::{LayoutCx, LayoutOf, TyAndLayout}; use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt}; use rustc_middle::{bug, mir}; @@ -261,7 +261,7 @@ pub(crate) fn eval_to_valtree<'tcx>( ValTreeCreationError::NodesOverflow => { let handled = tcx.dcx().emit_err(MaxNumNodesInConstErr { span, global_const_id }); - Err(handled.into()) + Err(ReportedErrorInfo::allowed_in_infallible(handled).into()) } ValTreeCreationError::NonSupportedType(ty) => Ok(Err(ty)), } diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index 241be5e175c..95a72d3cbc1 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -268,7 +268,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { }; // do not continue if typeck errors occurred (can only occur in local crate) if let Some(err) = body.tainted_by_errors { - throw_inval!(AlreadyReported(ReportedErrorInfo::from(err))); + throw_inval!(AlreadyReported(ReportedErrorInfo::non_const_eval_error(err))); } interp_ok(body) } @@ -317,7 +317,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { Ok(None) => throw_inval!(TooGeneric), // FIXME(eddyb) this could be a bit more specific than `AlreadyReported`. - Err(error_reported) => throw_inval!(AlreadyReported(error_reported.into())), + Err(error_guaranteed) => throw_inval!(AlreadyReported( + ReportedErrorInfo::non_const_eval_error(error_guaranteed) + )), } } diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index f54a932e1b6..810e9356b26 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -5,8 +5,7 @@ use std::assert_matches::assert_matches; use either::{Either, Left, Right}; -use rustc_abi::{Align, BackendRepr, HasDataLayout, Size}; -use rustc_ast::Mutability; +use rustc_abi::{BackendRepr, HasDataLayout, Size}; use rustc_middle::ty::Ty; use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; use rustc_middle::{bug, mir, span_bug}; @@ -1018,40 +1017,31 @@ where self.allocate_dyn(layout, kind, MemPlaceMeta::None) } - /// Allocates a sequence of bytes in the interpreter's memory. - /// For immutable allocations, uses deduplication to reuse existing memory. - /// For mutable allocations, creates a new unique allocation. - pub fn allocate_bytes( + /// Allocates a sequence of bytes in the interpreter's memory with alignment 1. + /// This is allocated in immutable global memory and deduplicated. + pub fn allocate_bytes_dedup( &mut self, bytes: &[u8], - align: Align, - kind: MemoryKind<M::MemoryKind>, - mutbl: Mutability, ) -> InterpResult<'tcx, Pointer<M::Provenance>> { - // Use cache for immutable strings. - if mutbl.is_not() { - // Use dedup'd allocation function. - let salt = M::get_global_alloc_salt(self, None); - let id = self.tcx.allocate_bytes_dedup(bytes, salt); - - // Turn untagged "global" pointers (obtained via `tcx`) into the machine pointer to the allocation. - M::adjust_alloc_root_pointer(&self, Pointer::from(id), Some(kind)) - } else { - // Allocate new memory for mutable data. - self.allocate_bytes_ptr(bytes, align, kind, mutbl) - } + let salt = M::get_global_alloc_salt(self, None); + let id = self.tcx.allocate_bytes_dedup(bytes, salt); + + // Turn untagged "global" pointers (obtained via `tcx`) into the machine pointer to the allocation. + M::adjust_alloc_root_pointer( + &self, + Pointer::from(id), + M::GLOBAL_KIND.map(MemoryKind::Machine), + ) } - /// Allocates a string in the interpreter's memory with metadata for length. - /// Uses `allocate_bytes` internally but adds string-specific metadata handling. - pub fn allocate_str( + /// Allocates a string in the interpreter's memory, returning it as a (wide) place. + /// This is allocated in immutable global memory and deduplicated. + pub fn allocate_str_dedup( &mut self, str: &str, - kind: MemoryKind<M::MemoryKind>, - mutbl: Mutability, ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> { let bytes = str.as_bytes(); - let ptr = self.allocate_bytes(bytes, Align::ONE, kind, mutbl)?; + let ptr = self.allocate_bytes_dedup(bytes)?; // Create length metadata for the string. let meta = Scalar::from_target_usize(u64::try_from(bytes.len()).unwrap(), self); diff --git a/compiler/rustc_const_eval/src/util/caller_location.rs b/compiler/rustc_const_eval/src/util/caller_location.rs index 9bf16d4fe16..6593547cd23 100644 --- a/compiler/rustc_const_eval/src/util/caller_location.rs +++ b/compiler/rustc_const_eval/src/util/caller_location.rs @@ -1,7 +1,7 @@ use rustc_hir::LangItem; use rustc_middle::query::TyCtxtAt; use rustc_middle::ty::layout::LayoutOf; -use rustc_middle::ty::{self, Mutability}; +use rustc_middle::ty::{self}; use rustc_middle::{bug, mir}; use rustc_span::symbol::Symbol; use tracing::trace; @@ -20,12 +20,9 @@ fn alloc_caller_location<'tcx>( // This can fail if rustc runs out of memory right here. Trying to emit an error would be // pointless, since that would require allocating more memory than these short strings. let file = if loc_details.file { - ecx.allocate_str(filename.as_str(), MemoryKind::CallerLocation, Mutability::Not).unwrap() + ecx.allocate_str_dedup(filename.as_str()).unwrap() } else { - // FIXME: This creates a new allocation each time. It might be preferable to - // perform this allocation only once, and re-use the `MPlaceTy`. - // See https://github.com/rust-lang/rust/pull/89920#discussion_r730012398 - ecx.allocate_str("<redacted>", MemoryKind::CallerLocation, Mutability::Not).unwrap() + ecx.allocate_str_dedup("<redacted>").unwrap() }; let file = file.map_provenance(CtfeProvenance::as_immutable); let line = if loc_details.line { Scalar::from_u32(line) } else { Scalar::from_u32(0) }; diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 6232c875ee8..fc44340851c 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -1291,7 +1291,7 @@ impl<'a> DiagCtxtHandle<'a> { Diag::<ErrorGuaranteed>::new(self, DelayedBug, msg.into()).emit() } - /// Ensures that an error is printed. See `Level::DelayedBug`. + /// Ensures that an error is printed. See [`Level::DelayedBug`]. /// /// Note: this function used to be called `delay_span_bug`. It was renamed /// to match similar functions like `span_err`, `span_warn`, etc. diff --git a/compiler/rustc_expand/src/placeholders.rs b/compiler/rustc_expand/src/placeholders.rs index f044d964f13..9e459bd81a1 100644 --- a/compiler/rustc_expand/src/placeholders.rs +++ b/compiler/rustc_expand/src/placeholders.rs @@ -174,6 +174,7 @@ pub(crate) fn placeholder( vis, is_placeholder: true, safety: Safety::Default, + default: None, }]), AstFragmentKind::Variants => AstFragment::Variants(smallvec![ast::Variant { attrs: Default::default(), diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index bf26b5d25d2..93a605e197c 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -455,6 +455,9 @@ declare_features! ( (unstable, custom_test_frameworks, "1.30.0", Some(50297)), /// Allows declarative macros 2.0 (`macro`). (unstable, decl_macro, "1.17.0", Some(39412)), + /// Allows the use of default values on struct definitions and the construction of struct + /// literals with the functional update syntax without a base. + (unstable, default_field_values, "CURRENT_RUSTC_VERSION", Some(132162)), /// Allows using `#[deprecated_safe]` to deprecate the safeness of a function or trait (unstable, deprecated_safe, "1.61.0", Some(94978)), /// Allows having using `suggestion` in the `#[deprecated]` attribute. diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs index 0b7ffc4af45..705de389e07 100644 --- a/compiler/rustc_hir/src/def.rs +++ b/compiler/rustc_hir/src/def.rs @@ -9,7 +9,6 @@ use rustc_macros::{Decodable, Encodable, HashStable_Generic}; use rustc_span::Symbol; use rustc_span::def_id::{DefId, LocalDefId}; use rustc_span::hygiene::MacroKind; -use rustc_span::symbol::kw; use crate::definitions::DefPathData; use crate::hir; @@ -256,7 +255,6 @@ impl DefKind { pub fn def_path_data(self, name: Symbol) -> DefPathData { match self { - DefKind::Struct | DefKind::Union if name == kw::Empty => DefPathData::AnonAdt, DefKind::Mod | DefKind::Struct | DefKind::Union diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs index 9873a58cfe9..d85f9586d42 100644 --- a/compiler/rustc_hir/src/definitions.rs +++ b/compiler/rustc_hir/src/definitions.rs @@ -289,8 +289,6 @@ pub enum DefPathData { /// An existential `impl Trait` type node. /// Argument position `impl Trait` have a `TypeNs` with their pretty-printed name. OpaqueTy, - /// An anonymous struct or union type i.e. `struct { foo: Type }` or `union { bar: Type }` - AnonAdt, } impl Definitions { @@ -415,7 +413,7 @@ impl DefPathData { TypeNs(name) | ValueNs(name) | MacroNs(name) | LifetimeNs(name) => Some(name), Impl | ForeignMod | CrateRoot | Use | GlobalAsm | Closure | Ctor | AnonConst - | OpaqueTy | AnonAdt => None, + | OpaqueTy => None, } } @@ -438,7 +436,6 @@ impl DefPathData { Ctor => DefPathDataName::Anon { namespace: sym::constructor }, AnonConst => DefPathDataName::Anon { namespace: sym::constant }, OpaqueTy => DefPathDataName::Anon { namespace: sym::opaque }, - AnonAdt => DefPathDataName::Anon { namespace: sym::anon_adt }, } } } diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index a9696627f11..4800a479ff4 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1857,7 +1857,12 @@ impl Expr<'_> { base.can_have_side_effects() } ExprKind::Struct(_, fields, init) => { - fields.iter().map(|field| field.expr).chain(init).any(|e| e.can_have_side_effects()) + let init_side_effects = match init { + StructTailExpr::Base(init) => init.can_have_side_effects(), + StructTailExpr::DefaultFields(_) | StructTailExpr::None => false, + }; + fields.iter().map(|field| field.expr).any(|e| e.can_have_side_effects()) + || init_side_effects } ExprKind::Array(args) @@ -1926,20 +1931,52 @@ impl Expr<'_> { ExprKind::Path(QPath::Resolved(None, path2)), ) => path1.res == path2.res, ( - ExprKind::Struct(QPath::LangItem(LangItem::RangeTo, _), [val1], None), - ExprKind::Struct(QPath::LangItem(LangItem::RangeTo, _), [val2], None), + ExprKind::Struct( + QPath::LangItem(LangItem::RangeTo, _), + [val1], + StructTailExpr::None, + ), + ExprKind::Struct( + QPath::LangItem(LangItem::RangeTo, _), + [val2], + StructTailExpr::None, + ), ) | ( - ExprKind::Struct(QPath::LangItem(LangItem::RangeToInclusive, _), [val1], None), - ExprKind::Struct(QPath::LangItem(LangItem::RangeToInclusive, _), [val2], None), + ExprKind::Struct( + QPath::LangItem(LangItem::RangeToInclusive, _), + [val1], + StructTailExpr::None, + ), + ExprKind::Struct( + QPath::LangItem(LangItem::RangeToInclusive, _), + [val2], + StructTailExpr::None, + ), ) | ( - ExprKind::Struct(QPath::LangItem(LangItem::RangeFrom, _), [val1], None), - ExprKind::Struct(QPath::LangItem(LangItem::RangeFrom, _), [val2], None), + ExprKind::Struct( + QPath::LangItem(LangItem::RangeFrom, _), + [val1], + StructTailExpr::None, + ), + ExprKind::Struct( + QPath::LangItem(LangItem::RangeFrom, _), + [val2], + StructTailExpr::None, + ), ) => val1.expr.equivalent_for_indexing(val2.expr), ( - ExprKind::Struct(QPath::LangItem(LangItem::Range, _), [val1, val3], None), - ExprKind::Struct(QPath::LangItem(LangItem::Range, _), [val2, val4], None), + ExprKind::Struct( + QPath::LangItem(LangItem::Range, _), + [val1, val3], + StructTailExpr::None, + ), + ExprKind::Struct( + QPath::LangItem(LangItem::Range, _), + [val2, val4], + StructTailExpr::None, + ), ) => { val1.expr.equivalent_for_indexing(val2.expr) && val3.expr.equivalent_for_indexing(val4.expr) @@ -2096,7 +2133,7 @@ pub enum ExprKind<'hir> { /// /// E.g., `Foo {x: 1, y: 2}`, or `Foo {x: 1, .. base}`, /// where `base` is the `Option<Expr>`. - Struct(&'hir QPath<'hir>, &'hir [ExprField<'hir>], Option<&'hir Expr<'hir>>), + Struct(&'hir QPath<'hir>, &'hir [ExprField<'hir>], StructTailExpr<'hir>), /// An array literal constructed from one repeated element. /// @@ -2111,6 +2148,19 @@ pub enum ExprKind<'hir> { Err(rustc_span::ErrorGuaranteed), } +#[derive(Debug, Clone, Copy, HashStable_Generic)] +pub enum StructTailExpr<'hir> { + /// A struct expression where all the fields are explicitly enumerated: `Foo { a, b }`. + None, + /// A struct expression with a "base", an expression of the same type as the outer struct that + /// will be used to populate any fields not explicitly mentioned: `Foo { ..base }` + Base(&'hir Expr<'hir>), + /// A struct expression with a `..` tail but no "base" expression. The values from the struct + /// fields' default values will be used to populate any fields not explicitly mentioned: + /// `Foo { .. }`. + DefaultFields(Span), +} + /// Represents an optionally `Self`-qualified value/type path or associated extension. /// /// To resolve the path to a `DefId`, call [`qpath_res`]. @@ -2832,8 +2882,6 @@ pub enum TyKind<'hir> { Never, /// A tuple (`(A, B, C, D, ...)`). Tup(&'hir [Ty<'hir>]), - /// An anonymous struct or union type i.e. `struct { foo: Type }` or `union { foo: Type }` - AnonAdt(ItemId), /// A path to a type definition (`module::module::...::Type`), or an /// associated type (e.g., `<Vec<T> as Trait>::Type` or `<T>::Target`). /// @@ -3172,6 +3220,7 @@ pub struct FieldDef<'hir> { pub def_id: LocalDefId, pub ty: &'hir Ty<'hir>, pub safety: Safety, + pub default: Option<&'hir AnonConst>, } impl FieldDef<'_> { diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 602aa8be740..8dbfefffee4 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -748,7 +748,10 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) ExprKind::Struct(ref qpath, fields, ref optional_base) => { try_visit!(visitor.visit_qpath(qpath, expression.hir_id, expression.span)); walk_list!(visitor, visit_expr_field, fields); - visit_opt!(visitor, visit_expr, optional_base); + match optional_base { + StructTailExpr::Base(base) => try_visit!(visitor.visit_expr(base)), + StructTailExpr::None | StructTailExpr::DefaultFields(_) => {} + } } ExprKind::Tup(subexpressions) => { walk_list!(visitor, visit_expr, subexpressions); @@ -901,9 +904,6 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) -> V::Resul } TyKind::Typeof(ref expression) => try_visit!(visitor.visit_anon_const(expression)), TyKind::Infer | TyKind::InferDelegation(..) | TyKind::Err(_) => {} - TyKind::AnonAdt(item_id) => { - try_visit!(visitor.visit_nested_item(item_id)); - } TyKind::Pat(ty, pat) => { try_visit!(visitor.visit_ty(ty)); try_visit!(visitor.visit_pattern_type_pattern(pat)); @@ -1190,10 +1190,14 @@ pub fn walk_struct_def<'v, V: Visitor<'v>>( V::Result::output() } -pub fn walk_field_def<'v, V: Visitor<'v>>(visitor: &mut V, field: &'v FieldDef<'v>) -> V::Result { - try_visit!(visitor.visit_id(field.hir_id)); - try_visit!(visitor.visit_ident(field.ident)); - visitor.visit_ty(field.ty) +pub fn walk_field_def<'v, V: Visitor<'v>>( + visitor: &mut V, + FieldDef { hir_id, ident, ty, default, span: _, vis_span: _, def_id: _, safety: _ }: &'v FieldDef<'v>, +) -> V::Result { + try_visit!(visitor.visit_id(*hir_id)); + try_visit!(visitor.visit_ident(*ident)); + visit_opt!(visitor, visit_anon_const, default); + visitor.visit_ty(*ty) } pub fn walk_enum_def<'v, V: Visitor<'v>>( diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 070d63b48b7..32498d9c5ab 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -96,12 +96,14 @@ hir_analysis_coercion_between_struct_same_note = expected coercion between the s hir_analysis_coercion_between_struct_single_note = expected a single field to be coerced, none found -hir_analysis_const_bound_for_non_const_trait = - `{$modifier}` can only be applied to `#[const_trait]` traits - -hir_analysis_const_impl_for_non_const_trait = - const `impl` for trait `{$trait_name}` which is not marked with `#[const_trait]` - .suggestion = mark `{$trait_name}` as const +hir_analysis_const_bound_for_non_const_trait = `{$modifier}` can only be applied to `#[const_trait]` traits + .label = can't be applied to `{$trait_name}` + .note = `{$trait_name}` can't be used with `{$modifier}` because it isn't annotated with `#[const_trait]` + .suggestion = {$suggestion_pre}mark `{$trait_name}` as `#[const_trait]` to allow it to have `const` implementations + +hir_analysis_const_impl_for_non_const_trait = const `impl` for trait `{$trait_name}` which is not marked with `#[const_trait]` + .label = this trait is not `const` + .suggestion = {$suggestion_pre}mark `{$trait_name}` as `#[const_trait]` to allow it to have `const` implementations .note = marking a trait with `#[const_trait]` ensures all default method bodies are `const` .adding = adding a non-const method body in the future would be a breaking change diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 2b33da3c49a..c9773972d9a 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -1104,6 +1104,25 @@ fn check_type_defn<'tcx>( for variant in variants.iter() { // All field types must be well-formed. for field in &variant.fields { + if let Some(def_id) = field.value + && let Some(_ty) = tcx.type_of(def_id).no_bound_vars() + { + // FIXME(generic_const_exprs, default_field_values): this is a hack and needs to + // be refactored to check the instantiate-ability of the code better. + if let Some(def_id) = def_id.as_local() + && let hir::Node::AnonConst(anon) = tcx.hir_node_by_def_id(def_id) + && let expr = &tcx.hir().body(anon.body).value + && let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind + && let Res::Def(DefKind::ConstParam, _def_id) = path.res + { + // Do not evaluate bare `const` params, as those would ICE and are only + // usable if `#![feature(generic_const_exprs)]` is enabled. + } else { + // Evaluate the constant proactively, to emit an error if the constant has + // an unconditional error. We only do so if the const has no type params. + let _ = tcx.const_eval_poly(def_id.into()); + } + } let field_id = field.did.expect_local(); let hir::FieldDef { ty: hir_ty, .. } = tcx.hir_node_by_def_id(field_id).expect_field(); diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index 3b49bc41ffe..2eea65125b0 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -103,7 +103,7 @@ fn visit_implementation_of_copy(checker: &Checker<'_>) -> Result<(), ErrorGuaran } let cause = traits::ObligationCause::misc(DUMMY_SP, impl_did); - match type_allowed_to_implement_copy(tcx, param_env, self_type, cause) { + match type_allowed_to_implement_copy(tcx, param_env, self_type, cause, impl_header.safety) { Ok(()) => Ok(()), Err(CopyImplementationError::InfringingFields(fields)) => { let span = tcx.hir().expect_item(impl_did).expect_impl().self_ty.span; @@ -123,6 +123,12 @@ fn visit_implementation_of_copy(checker: &Checker<'_>) -> Result<(), ErrorGuaran let span = tcx.hir().expect_item(impl_did).expect_impl().self_ty.span; Err(tcx.dcx().emit_err(errors::CopyImplOnTypeWithDtor { span })) } + Err(CopyImplementationError::HasUnsafeFields) => { + let span = tcx.hir().expect_item(impl_did).expect_impl().self_ty.span; + Err(tcx + .dcx() + .span_delayed_bug(span, format!("cannot implement `Copy` for `{}`", self_type))) + } } } diff --git a/compiler/rustc_hir_analysis/src/coherence/unsafety.rs b/compiler/rustc_hir_analysis/src/coherence/unsafety.rs index d66114a50d7..86839e40330 100644 --- a/compiler/rustc_hir_analysis/src/coherence/unsafety.rs +++ b/compiler/rustc_hir_analysis/src/coherence/unsafety.rs @@ -3,7 +3,7 @@ use rustc_errors::codes::*; use rustc_errors::struct_span_code_err; -use rustc_hir::Safety; +use rustc_hir::{LangItem, Safety}; use rustc_middle::ty::ImplPolarity::*; use rustc_middle::ty::print::PrintTraitRefExt as _; use rustc_middle::ty::{ImplTraitHeader, TraitDef, TyCtxt}; @@ -20,7 +20,19 @@ pub(super) fn check_item( tcx.generics_of(def_id).own_params.iter().find(|p| p.pure_wrt_drop).map(|_| "may_dangle"); let trait_ref = trait_header.trait_ref.instantiate_identity(); - match (trait_def.safety, unsafe_attr, trait_header.safety, trait_header.polarity) { + let is_copy = tcx.is_lang_item(trait_def.def_id, LangItem::Copy); + let trait_def_safety = if is_copy { + // If `Self` has unsafe fields, `Copy` is unsafe to implement. + if trait_header.trait_ref.skip_binder().self_ty().has_unsafe_fields() { + rustc_hir::Safety::Unsafe + } else { + rustc_hir::Safety::Safe + } + } else { + trait_def.safety + }; + + match (trait_def_safety, unsafe_attr, trait_header.safety, trait_header.polarity) { (Safety::Safe, None, Safety::Unsafe, Positive | Reservation) => { let span = tcx.def_span(def_id); return Err(struct_span_code_err!( @@ -48,12 +60,22 @@ pub(super) fn check_item( "the trait `{}` requires an `unsafe impl` declaration", trait_ref.print_trait_sugared() ) - .with_note(format!( - "the trait `{}` enforces invariants that the compiler can't check. \ - Review the trait documentation and make sure this implementation \ - upholds those invariants before adding the `unsafe` keyword", - trait_ref.print_trait_sugared() - )) + .with_note(if is_copy { + format!( + "the trait `{}` cannot be safely implemented for `{}` \ + because it has unsafe fields. Review the invariants \ + of those fields before adding an `unsafe impl`", + trait_ref.print_trait_sugared(), + trait_ref.self_ty(), + ) + } else { + format!( + "the trait `{}` enforces invariants that the compiler can't check. \ + Review the trait documentation and make sure this implementation \ + upholds those invariants before adding the `unsafe` keyword", + trait_ref.print_trait_sugared() + ) + }) .with_span_suggestion_verbose( span.shrink_to_lo(), "add `unsafe` to this trait implementation", diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index a4636da3f62..96d2714252a 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -1021,12 +1021,12 @@ impl<'tcx> FieldUniquenessCheckContext<'tcx> { } } -fn lower_variant( - tcx: TyCtxt<'_>, +fn lower_variant<'tcx>( + tcx: TyCtxt<'tcx>, variant_did: Option<LocalDefId>, ident: Ident, discr: ty::VariantDiscr, - def: &hir::VariantData<'_>, + def: &hir::VariantData<'tcx>, adt_kind: ty::AdtKind, parent_did: LocalDefId, ) -> ty::VariantDef { @@ -1042,6 +1042,7 @@ fn lower_variant( name: f.ident.name, vis: tcx.visibility(f.def_id), safety: f.safety, + value: f.default.map(|v| v.def_id.to_def_id()), }) .collect(); let recovered = match def { @@ -1637,11 +1638,23 @@ fn check_impl_constness( } let trait_name = tcx.item_name(trait_def_id).to_string(); + let (local_trait_span, suggestion_pre) = + match (trait_def_id.is_local(), tcx.sess.is_nightly_build()) { + (true, true) => ( + Some(tcx.def_span(trait_def_id).shrink_to_lo()), + if tcx.features().const_trait_impl() { + "" + } else { + "enable `#![feature(const_trait_impl)]` in your crate and " + }, + ), + (false, _) | (_, false) => (None, ""), + }; Some(tcx.dcx().emit_err(errors::ConstImplForNonConstTrait { trait_ref_span: hir_trait_ref.path.span, trait_name, - local_trait_span: - trait_def_id.as_local().map(|_| tcx.def_span(trait_def_id).shrink_to_lo()), + local_trait_span, + suggestion_pre, marking: (), adding: (), })) diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index ca2597e79fd..1a6c0a93436 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -711,12 +711,19 @@ pub(super) fn assert_only_contains_predicates_from<'tcx>( `{filter:?}` implied bounds: {clause:?}" ); } + ty::ClauseKind::HostEffect(host_effect_predicate) => { + assert_eq!( + host_effect_predicate.self_ty(), + ty, + "expected `Self` predicate when computing \ + `{filter:?}` implied bounds: {clause:?}" + ); + } ty::ClauseKind::RegionOutlives(_) | ty::ClauseKind::ConstArgHasType(_, _) | ty::ClauseKind::WellFormed(_) - | ty::ClauseKind::ConstEvaluatable(_) - | ty::ClauseKind::HostEffect(..) => { + | ty::ClauseKind::ConstEvaluatable(_) => { bug!( "unexpected non-`Self` predicate when computing \ `{filter:?}` implied bounds: {clause:?}" diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index 72d5b3ac4f5..5595504c3d9 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -125,6 +125,12 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { return ty; } + Node::Field(&hir::FieldDef { default: Some(c), def_id: field_def_id, .. }) + if c.hir_id == hir_id => + { + tcx.type_of(field_def_id).instantiate_identity() + } + _ => Ty::new_error_with_message( tcx, span, diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 4142dcff226..7f62ccc91f0 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -530,10 +530,16 @@ pub(crate) struct GenericArgsOnOverriddenImpl { #[diag(hir_analysis_const_impl_for_non_const_trait)] pub(crate) struct ConstImplForNonConstTrait { #[primary_span] + #[label] pub trait_ref_span: Span, pub trait_name: String, - #[suggestion(applicability = "machine-applicable", code = "#[const_trait]")] + #[suggestion( + applicability = "machine-applicable", + code = "#[const_trait] ", + style = "verbose" + )] pub local_trait_span: Option<Span>, + pub suggestion_pre: &'static str, #[note] pub marking: (), #[note(hir_analysis_adding)] @@ -544,8 +550,19 @@ pub(crate) struct ConstImplForNonConstTrait { #[diag(hir_analysis_const_bound_for_non_const_trait)] pub(crate) struct ConstBoundForNonConstTrait { #[primary_span] + #[label] pub span: Span, pub modifier: &'static str, + #[note] + pub def_span: Option<Span>, + pub suggestion_pre: &'static str, + #[suggestion( + applicability = "machine-applicable", + code = "#[const_trait] ", + style = "verbose" + )] + pub suggestion: Option<Span>, + pub trait_name: String, } #[derive(Diagnostic)] diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs index 321a8aba7f7..d3c86989440 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs @@ -203,7 +203,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // corresponding `Projection` clause for def_ids in associated_types.values_mut() { for (projection_bound, span) in &projection_bounds { - let def_id = projection_bound.projection_def_id(); + let def_id = projection_bound.item_def_id(); def_ids.swap_remove(&def_id); if tcx.generics_require_sized_self(def_id) { tcx.emit_node_span_lint( @@ -413,7 +413,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { late_bound_in_projection_term, late_bound_in_term, |br_name| { - let item_name = tcx.item_name(pred.projection_def_id()); + let item_name = tcx.item_name(pred.item_def_id()); struct_span_code_err!( self.dcx(), span, diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 3313339abb3..7683c87168b 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -50,7 +50,7 @@ use rustc_span::{DUMMY_SP, Span}; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::wf::object_region_bounds; use rustc_trait_selection::traits::{self, ObligationCtxt}; -use tracing::{debug, debug_span, instrument}; +use tracing::{debug, instrument}; use crate::bounds::Bounds; use crate::check::check_abi_fn_ptr; @@ -737,9 +737,26 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { if let hir::BoundConstness::Always(span) | hir::BoundConstness::Maybe(span) = constness && !self.tcx().is_const_trait(trait_def_id) { + let (def_span, suggestion, suggestion_pre) = + match (trait_def_id.is_local(), self.tcx().sess.is_nightly_build()) { + (true, true) => ( + None, + Some(tcx.def_span(trait_def_id).shrink_to_lo()), + if self.tcx().features().const_trait_impl() { + "" + } else { + "enable `#![feature(const_trait_impl)]` in your crate and " + }, + ), + (false, _) | (_, false) => (Some(tcx.def_span(trait_def_id)), None, ""), + }; self.dcx().emit_err(crate::errors::ConstBoundForNonConstTrait { span, modifier: constness.as_str(), + def_span, + trait_name: self.tcx().def_path_str(trait_def_id), + suggestion_pre, + suggestion, }); } @@ -2287,19 +2304,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { hir::TyKind::Tup(fields) => { Ty::new_tup_from_iter(tcx, fields.iter().map(|t| self.lower_ty(t))) } - hir::TyKind::AnonAdt(item_id) => { - let _guard = debug_span!("AnonAdt"); - - let did = item_id.owner_id.def_id; - let adt_def = tcx.adt_def(did); - - let args = ty::GenericArgs::for_item(tcx, did.to_def_id(), |param, _| { - tcx.mk_param_from_def(param) - }); - debug!(?args); - - Ty::new_adt(tcx, adt_def, tcx.mk_args(args)) - } hir::TyKind::BareFn(bf) => { require_c_abi_if_c_variadic(tcx, bf.decl, bf.abi, hir_ty.span); diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 0f3dcebc092..20ba9ae2632 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -330,7 +330,6 @@ impl<'a> State<'a> { hir::TyKind::Infer | hir::TyKind::InferDelegation(..) => { self.word("_"); } - hir::TyKind::AnonAdt(..) => self.word("/* anonymous adt */"), hir::TyKind::Pat(ty, pat) => { self.print_type(ty); self.word(" is "); @@ -1080,22 +1079,36 @@ impl<'a> State<'a> { &mut self, qpath: &hir::QPath<'_>, fields: &[hir::ExprField<'_>], - wth: Option<&hir::Expr<'_>>, + wth: hir::StructTailExpr<'_>, ) { self.print_qpath(qpath, true); self.word("{"); self.commasep_cmnt(Consistent, fields, |s, field| s.print_expr_field(field), |f| f.span); - if let Some(expr) = wth { - self.ibox(INDENT_UNIT); - if !fields.is_empty() { - self.word(","); - self.space(); + match wth { + hir::StructTailExpr::Base(expr) => { + self.ibox(INDENT_UNIT); + if !fields.is_empty() { + self.word(","); + self.space(); + } + self.word(".."); + self.print_expr(expr); + self.end(); + } + hir::StructTailExpr::DefaultFields(_) => { + self.ibox(INDENT_UNIT); + if !fields.is_empty() { + self.word(","); + self.space(); + } + self.word(".."); + self.end(); + } + hir::StructTailExpr::None => { + if !fields.is_empty() { + self.word(","); + } } - self.word(".."); - self.print_expr(expr); - self.end(); - } else if !fields.is_empty() { - self.word(","); } self.word("}"); diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl index b27f7215ae4..a93da52b270 100644 --- a/compiler/rustc_hir_typeck/messages.ftl +++ b/compiler/rustc_hir_typeck/messages.ftl @@ -10,6 +10,12 @@ hir_typeck_address_of_temporary_taken = cannot take address of a temporary hir_typeck_arg_mismatch_indeterminate = argument type mismatch was detected, but rustc had trouble determining where .note = we would appreciate a bug report: https://github.com/rust-lang/rust/issues/new +hir_typeck_base_expression_double_dot = base expression required after `..` +hir_typeck_base_expression_double_dot_add_expr = add a base expression here +hir_typeck_base_expression_double_dot_enable_default_field_values = + add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields +hir_typeck_base_expression_double_dot_remove = remove the `..` as all the fields are already present + hir_typeck_candidate_trait_note = `{$trait_name}` defines an item `{$item_name}`{$action_or_ty -> [NONE] {""} [implement] , perhaps you need to implement it diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index e715a7f7e15..b8652d82d91 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -454,20 +454,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { closure_kind: hir::ClosureKind, projection: ty::PolyProjectionPredicate<'tcx>, ) -> Option<ExpectedSig<'tcx>> { - let tcx = self.tcx; - - let trait_def_id = projection.trait_def_id(tcx); + let def_id = projection.item_def_id(); // For now, we only do signature deduction based off of the `Fn` and `AsyncFn` traits, // for closures and async closures, respectively. match closure_kind { - hir::ClosureKind::Closure - if self.tcx.fn_trait_kind_from_def_id(trait_def_id).is_some() => - { + hir::ClosureKind::Closure if self.tcx.is_lang_item(def_id, LangItem::FnOnceOutput) => { self.extract_sig_from_projection(cause_span, projection) } hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Async) - if self.tcx.async_fn_trait_kind_from_def_id(trait_def_id).is_some() => + if self.tcx.is_lang_item(def_id, LangItem::AsyncFnOnceOutput) => { self.extract_sig_from_projection(cause_span, projection) } @@ -475,7 +471,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // `F: FnOnce() -> Fut, Fut: Future<Output = T>` style bound. Let's still // guide inference here, since it's beneficial for the user. hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Async) - if self.tcx.fn_trait_kind_from_def_id(trait_def_id).is_some() => + if self.tcx.is_lang_item(def_id, LangItem::FnOnceOutput) => { self.extract_sig_from_projection_and_future_bound(cause_span, projection) } diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index a2e00859307..7746a5a7132 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -16,6 +16,47 @@ use rustc_span::{Span, Symbol}; use crate::fluent_generated as fluent; #[derive(Diagnostic)] +#[diag(hir_typeck_base_expression_double_dot, code = E0797)] +pub(crate) struct BaseExpressionDoubleDot { + #[primary_span] + pub span: Span, + #[subdiagnostic] + pub default_field_values: Option<BaseExpressionDoubleDotEnableDefaultFieldValues>, + #[subdiagnostic] + pub add_expr: Option<BaseExpressionDoubleDotAddExpr>, + #[subdiagnostic] + pub remove_dots: Option<BaseExpressionDoubleDotRemove>, +} + +#[derive(Subdiagnostic)] +#[suggestion( + hir_typeck_base_expression_double_dot_remove, + code = "", + applicability = "machine-applicable", + style = "verbose" +)] +pub(crate) struct BaseExpressionDoubleDotRemove { + #[primary_span] + pub span: Span, +} + +#[derive(Subdiagnostic)] +#[suggestion( + hir_typeck_base_expression_double_dot_add_expr, + code = "/* expr */", + applicability = "has-placeholders", + style = "verbose" +)] +pub(crate) struct BaseExpressionDoubleDotAddExpr { + #[primary_span] + pub span: Span, +} + +#[derive(Subdiagnostic)] +#[help(hir_typeck_base_expression_double_dot_enable_default_field_values)] +pub(crate) struct BaseExpressionDoubleDotEnableDefaultFieldValues; + +#[derive(Diagnostic)] #[diag(hir_typeck_field_multiply_specified_in_initializer, code = E0062)] pub(crate) struct FieldMultiplySpecifiedInInitializer { #[primary_span] diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 04c06169d33..b3ce1df3def 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -44,10 +44,11 @@ use crate::Expectation::{self, ExpectCastableToType, ExpectHasType, NoExpectatio use crate::TupleArgumentsFlag::DontTupleArguments; use crate::coercion::{CoerceMany, DynamicCoerceMany}; use crate::errors::{ - AddressOfTemporaryTaken, FieldMultiplySpecifiedInInitializer, - FunctionalRecordUpdateOnNonStruct, HelpUseLatestEdition, ReturnLikeStatementKind, - ReturnStmtOutsideOfFnBody, StructExprNonExhaustive, TypeMismatchFruTypo, - YieldExprOutsideOfCoroutine, + AddressOfTemporaryTaken, BaseExpressionDoubleDot, BaseExpressionDoubleDotAddExpr, + BaseExpressionDoubleDotEnableDefaultFieldValues, BaseExpressionDoubleDotRemove, + FieldMultiplySpecifiedInInitializer, FunctionalRecordUpdateOnNonStruct, HelpUseLatestEdition, + ReturnLikeStatementKind, ReturnStmtOutsideOfFnBody, StructExprNonExhaustive, + TypeMismatchFruTypo, YieldExprOutsideOfCoroutine, }; use crate::{ BreakableCtxt, CoroutineTypes, Diverges, FnCtxt, Needs, cast, fatally_break_rust, @@ -402,6 +403,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }) | hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Const(..), .. }) => true, + hir::Node::Pat(_) => { + self.dcx().span_delayed_bug(expr.span, "place expr not allowed in pattern"); + true + } + // These nodes do not have direct sub-exprs. hir::Node::Param(_) | hir::Node::Item(_) @@ -414,7 +420,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | hir::Node::Ty(_) | hir::Node::AssocItemConstraint(_) | hir::Node::TraitRef(_) - | hir::Node::Pat(_) | hir::Node::PatField(_) | hir::Node::LetStmt(_) | hir::Node::Synthetic @@ -723,7 +728,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.suggest_assoc_method_call(segs); let e = self.dcx().span_delayed_bug(qpath.span(), "`Res::Err` but no error emitted"); - self.set_tainted_by_errors(e); Ty::new_error(tcx, e) } Res::Def(DefKind::Variant, _) => { @@ -1855,11 +1859,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn check_expr_struct( &self, - expr: &hir::Expr<'_>, + expr: &hir::Expr<'tcx>, expected: Expectation<'tcx>, - qpath: &QPath<'tcx>, + qpath: &'tcx QPath<'tcx>, fields: &'tcx [hir::ExprField<'tcx>], - base_expr: &'tcx Option<&'tcx hir::Expr<'tcx>>, + base_expr: &'tcx hir::StructTailExpr<'tcx>, ) -> Ty<'tcx> { // Find the relevant variant let (variant, adt_ty) = match self.check_struct_path(qpath, expr.hir_id) { @@ -1899,7 +1903,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span: Span, variant: &'tcx ty::VariantDef, hir_fields: &'tcx [hir::ExprField<'tcx>], - base_expr: &'tcx Option<&'tcx hir::Expr<'tcx>>, + base_expr: &'tcx hir::StructTailExpr<'tcx>, ) { let tcx = self.tcx; @@ -2023,13 +2027,90 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // the fields with the base_expr. This could cause us to hit errors later // when certain fields are assumed to exist that in fact do not. if error_happened { - if let Some(base_expr) = base_expr { + if let hir::StructTailExpr::Base(base_expr) = base_expr { self.check_expr(base_expr); } return; } - if let Some(base_expr) = base_expr { + if let hir::StructTailExpr::DefaultFields(span) = *base_expr { + let mut missing_mandatory_fields = Vec::new(); + let mut missing_optional_fields = Vec::new(); + for f in &variant.fields { + let ident = self.tcx.adjust_ident(f.ident(self.tcx), variant.def_id); + if let Some(_) = remaining_fields.remove(&ident) { + if f.value.is_none() { + missing_mandatory_fields.push(ident); + } else { + missing_optional_fields.push(ident); + } + } + } + if !self.tcx.features().default_field_values() { + self.dcx().emit_err(BaseExpressionDoubleDot { + span: span.shrink_to_hi(), + // We only mention enabling the feature if this is a nightly rustc *and* the + // expression would make sense with the feature enabled. + default_field_values: if self.tcx.sess.is_nightly_build() + && missing_mandatory_fields.is_empty() + && !missing_optional_fields.is_empty() + { + Some(BaseExpressionDoubleDotEnableDefaultFieldValues) + } else { + None + }, + add_expr: if !missing_mandatory_fields.is_empty() + || !missing_optional_fields.is_empty() + { + Some(BaseExpressionDoubleDotAddExpr { span: span.shrink_to_hi() }) + } else { + None + }, + remove_dots: if missing_mandatory_fields.is_empty() + && missing_optional_fields.is_empty() + { + Some(BaseExpressionDoubleDotRemove { span }) + } else { + None + }, + }); + return; + } + if !missing_mandatory_fields.is_empty() { + let s = pluralize!(missing_mandatory_fields.len()); + let fields: Vec<_> = + missing_mandatory_fields.iter().map(|f| format!("`{f}`")).collect(); + let fields = match &fields[..] { + [] => unreachable!(), + [only] => only.to_string(), + [start @ .., last] => format!("{} and {last}", start.join(", ")), + }; + self.dcx() + .struct_span_err( + span.shrink_to_hi(), + format!("missing mandatory field{s} {fields}"), + ) + .emit(); + return; + } + let fru_tys = match adt_ty.kind() { + ty::Adt(adt, args) if adt.is_struct() => variant + .fields + .iter() + .map(|f| self.normalize(span, f.ty(self.tcx, args))) + .collect(), + ty::Adt(adt, args) if adt.is_enum() => variant + .fields + .iter() + .map(|f| self.normalize(span, f.ty(self.tcx, args))) + .collect(), + _ => { + self.dcx().emit_err(FunctionalRecordUpdateOnNonStruct { span }); + return; + } + }; + self.typeck_results.borrow_mut().fru_field_types_mut().insert(expr.hir_id, fru_tys); + } else if let hir::StructTailExpr::Base(base_expr) = base_expr { // FIXME: We are currently creating two branches here in order to maintain // consistency. But they should be merged as much as possible. let fru_tys = if self.tcx.features().type_changing_struct_update() { @@ -2161,12 +2242,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn check_struct_fields_on_error( &self, fields: &'tcx [hir::ExprField<'tcx>], - base_expr: &'tcx Option<&'tcx hir::Expr<'tcx>>, + base_expr: &'tcx hir::StructTailExpr<'tcx>, ) { for field in fields { self.check_expr(field.expr); } - if let Some(base) = *base_expr { + if let hir::StructTailExpr::Base(base) = *base_expr { self.check_expr(base); } } @@ -2611,33 +2692,46 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { None } - // Check field access expressions + /// Check field access expressions, this works for both structs and tuples. + /// Returns the Ty of the field. + /// + /// ```not_rust + /// base.field + /// ^^^^^^^^^^ expr + /// ^^^^ base + /// ^^^^^ field + /// ``` fn check_expr_field( &self, expr: &'tcx hir::Expr<'tcx>, base: &'tcx hir::Expr<'tcx>, field: Ident, + // The expected type hint of the field. expected: Expectation<'tcx>, ) -> Ty<'tcx> { debug!("check_field(expr: {:?}, base: {:?}, field: {:?})", expr, base, field); let base_ty = self.check_expr(base); let base_ty = self.structurally_resolve_type(base.span, base_ty); + + // Whether we are trying to access a private field. Used for error reporting. let mut private_candidate = None; + + // Field expressions automatically deref let mut autoderef = self.autoderef(expr.span, base_ty); while let Some((deref_base_ty, _)) = autoderef.next() { debug!("deref_base_ty: {:?}", deref_base_ty); match deref_base_ty.kind() { ty::Adt(base_def, args) if !base_def.is_enum() => { debug!("struct named {:?}", deref_base_ty); - let body_hir_id = self.tcx.local_def_id_to_hir_id(self.body_id); - let (ident, def_scope) = - self.tcx.adjust_ident_and_get_scope(field, base_def.did(), body_hir_id); - // we don't care to report errors for a struct if the struct itself is tainted if let Err(guar) = base_def.non_enum_variant().has_errors() { return Ty::new_error(self.tcx(), guar); } + let fn_body_hir_id = self.tcx.local_def_id_to_hir_id(self.body_id); + let (ident, def_scope) = + self.tcx.adjust_ident_and_get_scope(field, base_def.did(), fn_body_hir_id); + if let Some((idx, field)) = self.find_adt_field(*base_def, ident) { self.write_field_index(expr.hir_id, idx); @@ -2671,6 +2765,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => {} } } + // We failed to check the expression, report an error. + + // Emits an error if we deref an infer variable, like calling `.field` on a base type of &_. self.structurally_resolve_type(autoderef.span(), autoderef.final_ty(false)); if let Some((adjustments, did)) = private_candidate { @@ -2695,6 +2792,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expr.hir_id, expected.only_has_type(self), ) { + // If taking a method instead of calling it self.ban_take_value_of_method(expr, base_ty, field) } else if !base_ty.is_primitive_ty() { self.ban_nonexisting_field(field, base, expr, base_ty) diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs index 774d00edea0..27ec2e9e0d4 100644 --- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -686,7 +686,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx fn walk_struct_expr<'hir>( &self, fields: &[hir::ExprField<'_>], - opt_with: &Option<&'hir hir::Expr<'_>>, + opt_with: &hir::StructTailExpr<'hir>, ) -> Result<(), Cx::Error> { // Consume the expressions supplying values for each field. for field in fields { @@ -702,8 +702,8 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx } let with_expr = match *opt_with { - Some(w) => &*w, - None => { + hir::StructTailExpr::Base(w) => &*w, + hir::StructTailExpr::DefaultFields(_) | hir::StructTailExpr::None => { return Ok(()); } }; diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 44582390a4b..6b1cceefbee 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -903,6 +903,34 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + let detect_dotdot = |err: &mut Diag<'_>, ty: Ty<'_>, expr: &hir::Expr<'_>| { + if let ty::Adt(adt, _) = ty.kind() + && self.tcx().lang_items().get(hir::LangItem::RangeFull) == Some(adt.did()) + && let hir::ExprKind::Struct( + hir::QPath::LangItem(hir::LangItem::RangeFull, _), + [], + _, + ) = expr.kind + { + // We have `Foo(a, .., c)`, where the user might be trying to use the "rest" syntax + // from default field values, which is not supported on tuples. + let explanation = if self.tcx.features().default_field_values() { + "this is only supported on non-tuple struct literals" + } else if self.tcx.sess.is_nightly_build() { + "this is only supported on non-tuple struct literals when \ + `#![feature(default_field_values)]` is enabled" + } else { + "this is not supported" + }; + let msg = format!( + "you might have meant to use `..` to skip providing a value for \ + expected fields, but {explanation}; it is instead interpreted as a \ + `std::ops::RangeFull` literal", + ); + err.span_help(expr.span, msg); + } + }; + let mut reported = None; errors.retain(|error| { let Error::Invalid(provided_idx, expected_idx, Compatibility::Incompatible(Some(e))) = @@ -1009,6 +1037,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { tuple_arguments, ); suggest_confusable(&mut err); + detect_dotdot(&mut err, provided_ty, provided_args[provided_idx]); return err.emit(); } @@ -1133,6 +1162,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { None, None, ); + detect_dotdot(&mut err, provided_ty, provided_args[provided_idx]); } Error::Extra(arg_idx) => { let (provided_ty, provided_span) = provided_arg_tys[arg_idx]; @@ -1216,6 +1246,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; prev_extra_idx = Some(arg_idx.index()) } + detect_dotdot(&mut err, provided_ty, provided_args[arg_idx]); } Error::Missing(expected_idx) => { // If there are multiple missing arguments adjacent to each other, diff --git a/compiler/rustc_index/src/bit_set.rs b/compiler/rustc_index/src/bit_set.rs index de6fa132ca0..aba1e938296 100644 --- a/compiler/rustc_index/src/bit_set.rs +++ b/compiler/rustc_index/src/bit_set.rs @@ -296,6 +296,111 @@ impl<T: Idx> From<GrowableBitSet<T>> for BitSet<T> { } } +impl<T> Clone for BitSet<T> { + fn clone(&self) -> Self { + BitSet { domain_size: self.domain_size, words: self.words.clone(), marker: PhantomData } + } + + fn clone_from(&mut self, from: &Self) { + self.domain_size = from.domain_size; + self.words.clone_from(&from.words); + } +} + +impl<T: Idx> fmt::Debug for BitSet<T> { + fn fmt(&self, w: &mut fmt::Formatter<'_>) -> fmt::Result { + w.debug_list().entries(self.iter()).finish() + } +} + +impl<T: Idx> ToString for BitSet<T> { + fn to_string(&self) -> String { + let mut result = String::new(); + let mut sep = '['; + + // Note: this is a little endian printout of bytes. + + // i tracks how many bits we have printed so far. + let mut i = 0; + for word in &self.words { + let mut word = *word; + for _ in 0..WORD_BYTES { + // for each byte in `word`: + let remain = self.domain_size - i; + // If less than a byte remains, then mask just that many bits. + let mask = if remain <= 8 { (1 << remain) - 1 } else { 0xFF }; + assert!(mask <= 0xFF); + let byte = word & mask; + + result.push_str(&format!("{sep}{byte:02x}")); + + if remain <= 8 { + break; + } + word >>= 8; + i += 8; + sep = '-'; + } + sep = '|'; + } + result.push(']'); + + result + } +} + +pub struct BitIter<'a, T: Idx> { + /// A copy of the current word, but with any already-visited bits cleared. + /// (This lets us use `trailing_zeros()` to find the next set bit.) When it + /// is reduced to 0, we move onto the next word. + word: Word, + + /// The offset (measured in bits) of the current word. + offset: usize, + + /// Underlying iterator over the words. + iter: slice::Iter<'a, Word>, + + marker: PhantomData<T>, +} + +impl<'a, T: Idx> BitIter<'a, T> { + #[inline] + fn new(words: &'a [Word]) -> BitIter<'a, T> { + // We initialize `word` and `offset` to degenerate values. On the first + // call to `next()` we will fall through to getting the first word from + // `iter`, which sets `word` to the first word (if there is one) and + // `offset` to 0. Doing it this way saves us from having to maintain + // additional state about whether we have started. + BitIter { + word: 0, + offset: usize::MAX - (WORD_BITS - 1), + iter: words.iter(), + marker: PhantomData, + } + } +} + +impl<'a, T: Idx> Iterator for BitIter<'a, T> { + type Item = T; + fn next(&mut self) -> Option<T> { + loop { + if self.word != 0 { + // Get the position of the next set bit in the current word, + // then clear the bit. + let bit_pos = self.word.trailing_zeros() as usize; + self.word ^= 1 << bit_pos; + return Some(T::new(bit_pos + self.offset)); + } + + // Move onto the next word. `wrapping_add()` is needed to handle + // the degenerate initial value given to `offset` in `new()`. + self.word = *self.iter.next()?; + self.offset = self.offset.wrapping_add(WORD_BITS); + } + } +} + /// A fixed-size bitset type with a partially dense, partially sparse /// representation. The bitset is broken into chunks, and chunks that are all /// zeros or all ones are represented and handled very efficiently. @@ -305,6 +410,9 @@ impl<T: Idx> From<GrowableBitSet<T>> for BitSet<T> { /// some stretches with lots of 0s and 1s mixed in a way that causes trouble /// for `IntervalSet`. /// +/// Best used via `MixedBitSet`, rather than directly, because `MixedBitSet` +/// has better performance for small bitsets. +/// /// `T` is an index type, typically a newtyped `usize` wrapper, but it can also /// just be `usize`. /// @@ -958,117 +1066,12 @@ fn sequential_update<T: Idx>( it.fold(false, |changed, elem| self_update(elem) | changed) } -impl<T> Clone for BitSet<T> { - fn clone(&self) -> Self { - BitSet { domain_size: self.domain_size, words: self.words.clone(), marker: PhantomData } - } - - fn clone_from(&mut self, from: &Self) { - self.domain_size = from.domain_size; - self.words.clone_from(&from.words); - } -} - -impl<T: Idx> fmt::Debug for BitSet<T> { - fn fmt(&self, w: &mut fmt::Formatter<'_>) -> fmt::Result { - w.debug_list().entries(self.iter()).finish() - } -} - impl<T: Idx> fmt::Debug for ChunkedBitSet<T> { fn fmt(&self, w: &mut fmt::Formatter<'_>) -> fmt::Result { w.debug_list().entries(self.iter()).finish() } } -impl<T: Idx> ToString for BitSet<T> { - fn to_string(&self) -> String { - let mut result = String::new(); - let mut sep = '['; - - // Note: this is a little endian printout of bytes. - - // i tracks how many bits we have printed so far. - let mut i = 0; - for word in &self.words { - let mut word = *word; - for _ in 0..WORD_BYTES { - // for each byte in `word`: - let remain = self.domain_size - i; - // If less than a byte remains, then mask just that many bits. - let mask = if remain <= 8 { (1 << remain) - 1 } else { 0xFF }; - assert!(mask <= 0xFF); - let byte = word & mask; - - result.push_str(&format!("{sep}{byte:02x}")); - - if remain <= 8 { - break; - } - word >>= 8; - i += 8; - sep = '-'; - } - sep = '|'; - } - result.push(']'); - - result - } -} - -pub struct BitIter<'a, T: Idx> { - /// A copy of the current word, but with any already-visited bits cleared. - /// (This lets us use `trailing_zeros()` to find the next set bit.) When it - /// is reduced to 0, we move onto the next word. - word: Word, - - /// The offset (measured in bits) of the current word. - offset: usize, - - /// Underlying iterator over the words. - iter: slice::Iter<'a, Word>, - - marker: PhantomData<T>, -} - -impl<'a, T: Idx> BitIter<'a, T> { - #[inline] - fn new(words: &'a [Word]) -> BitIter<'a, T> { - // We initialize `word` and `offset` to degenerate values. On the first - // call to `next()` we will fall through to getting the first word from - // `iter`, which sets `word` to the first word (if there is one) and - // `offset` to 0. Doing it this way saves us from having to maintain - // additional state about whether we have started. - BitIter { - word: 0, - offset: usize::MAX - (WORD_BITS - 1), - iter: words.iter(), - marker: PhantomData, - } - } -} - -impl<'a, T: Idx> Iterator for BitIter<'a, T> { - type Item = T; - fn next(&mut self) -> Option<T> { - loop { - if self.word != 0 { - // Get the position of the next set bit in the current word, - // then clear the bit. - let bit_pos = self.word.trailing_zeros() as usize; - self.word ^= 1 << bit_pos; - return Some(T::new(bit_pos + self.offset)); - } - - // Move onto the next word. `wrapping_add()` is needed to handle - // the degenerate initial value given to `offset` in `new()`. - self.word = *self.iter.next()?; - self.offset = self.offset.wrapping_add(WORD_BITS); - } - } -} - #[inline] fn bitwise<Op>(out_vec: &mut [Word], in_vec: &[Word], op: Op) -> bool where @@ -1106,6 +1109,158 @@ where false } +/// A bitset with a mixed representation, using `BitSet` for small and medium +/// bitsets, and `ChunkedBitSet` for large bitsets, i.e. those with enough bits +/// for at least two chunks. This is a good choice for many bitsets that can +/// have large domain sizes (e.g. 5000+). +/// +/// `T` is an index type, typically a newtyped `usize` wrapper, but it can also +/// just be `usize`. +/// +/// All operations that involve an element will panic if the element is equal +/// to or greater than the domain size. All operations that involve two bitsets +/// will panic if the bitsets have differing domain sizes. +#[derive(PartialEq, Eq)] +pub enum MixedBitSet<T> { + Small(BitSet<T>), + Large(ChunkedBitSet<T>), +} + +impl<T> MixedBitSet<T> { + pub fn domain_size(&self) -> usize { + match self { + MixedBitSet::Small(set) => set.domain_size(), + MixedBitSet::Large(set) => set.domain_size(), + } + } +} + +impl<T: Idx> MixedBitSet<T> { + #[inline] + pub fn new_empty(domain_size: usize) -> MixedBitSet<T> { + if domain_size <= CHUNK_BITS { + MixedBitSet::Small(BitSet::new_empty(domain_size)) + } else { + MixedBitSet::Large(ChunkedBitSet::new_empty(domain_size)) + } + } + + #[inline] + pub fn is_empty(&self) -> bool { + match self { + MixedBitSet::Small(set) => set.is_empty(), + MixedBitSet::Large(set) => set.is_empty(), + } + } + + #[inline] + pub fn contains(&self, elem: T) -> bool { + match self { + MixedBitSet::Small(set) => set.contains(elem), + MixedBitSet::Large(set) => set.contains(elem), + } + } + + #[inline] + pub fn insert(&mut self, elem: T) -> bool { + match self { + MixedBitSet::Small(set) => set.insert(elem), + MixedBitSet::Large(set) => set.insert(elem), + } + } + + pub fn insert_all(&mut self) { + match self { + MixedBitSet::Small(set) => set.insert_all(), + MixedBitSet::Large(set) => set.insert_all(), + } + } + + #[inline] + pub fn remove(&mut self, elem: T) -> bool { + match self { + MixedBitSet::Small(set) => set.remove(elem), + MixedBitSet::Large(set) => set.remove(elem), + } + } + + pub fn iter(&self) -> MixedBitIter<'_, T> { + match self { + MixedBitSet::Small(set) => MixedBitIter::Small(set.iter()), + MixedBitSet::Large(set) => MixedBitIter::Large(set.iter()), + } + } + + bit_relations_inherent_impls! {} +} + +impl<T> Clone for MixedBitSet<T> { + fn clone(&self) -> Self { + match self { + MixedBitSet::Small(set) => MixedBitSet::Small(set.clone()), + MixedBitSet::Large(set) => MixedBitSet::Large(set.clone()), + } + } + + /// WARNING: this implementation of clone_from may panic if the two + /// bitsets have different domain sizes. This constraint is not inherent to + /// `clone_from`, but it works with the existing call sites and allows a + /// faster implementation, which is important because this function is hot. + fn clone_from(&mut self, from: &Self) { + match (self, from) { + (MixedBitSet::Small(set), MixedBitSet::Small(from)) => set.clone_from(from), + (MixedBitSet::Large(set), MixedBitSet::Large(from)) => set.clone_from(from), + _ => panic!("MixedBitSet size mismatch"), + } + } +} + +impl<T: Idx> BitRelations<MixedBitSet<T>> for MixedBitSet<T> { + fn union(&mut self, other: &MixedBitSet<T>) -> bool { + match (self, other) { + (MixedBitSet::Small(set), MixedBitSet::Small(other)) => set.union(other), + (MixedBitSet::Large(set), MixedBitSet::Large(other)) => set.union(other), + _ => panic!("MixedBitSet size mismatch"), + } + } + + fn subtract(&mut self, other: &MixedBitSet<T>) -> bool { + match (self, other) { + (MixedBitSet::Small(set), MixedBitSet::Small(other)) => set.subtract(other), + (MixedBitSet::Large(set), MixedBitSet::Large(other)) => set.subtract(other), + _ => panic!("MixedBitSet size mismatch"), + } + } + + fn intersect(&mut self, _other: &MixedBitSet<T>) -> bool { + unimplemented!("implement if/when necessary"); + } +} + +impl<T: Idx> fmt::Debug for MixedBitSet<T> { + fn fmt(&self, w: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + MixedBitSet::Small(set) => set.fmt(w), + MixedBitSet::Large(set) => set.fmt(w), + } + } +} + +pub enum MixedBitIter<'a, T: Idx> { + Small(BitIter<'a, T>), + Large(ChunkedBitIter<'a, T>), +} + +impl<'a, T: Idx> Iterator for MixedBitIter<'a, T> { + type Item = T; + fn next(&mut self) -> Option<T> { + match self { + MixedBitIter::Small(iter) => iter.next(), + MixedBitIter::Large(iter) => iter.next(), + } + } +} + /// A resizable bitset type with a dense representation. /// /// `T` is an index type, typically a newtyped `usize` wrapper, but it can also @@ -1374,7 +1529,7 @@ impl<R: Idx, C: Idx> fmt::Debug for BitMatrix<R, C> { /// sparse representation. /// /// Initially, every row has no explicit representation. If any bit within a -/// row is set, the entire row is instantiated as `Some(<ChunkedBitSet>)`. +/// row is set, the entire row is instantiated as `Some(<BitSet>)`. /// Furthermore, any previously uninstantiated rows prior to it will be /// instantiated as `None`. Those prior rows may themselves become fully /// instantiated later on if any of their bits are set. @@ -1388,7 +1543,7 @@ where C: Idx, { num_columns: usize, - rows: IndexVec<R, Option<ChunkedBitSet<C>>>, + rows: IndexVec<R, Option<BitSet<C>>>, } impl<R: Idx, C: Idx> SparseBitMatrix<R, C> { @@ -1397,10 +1552,10 @@ impl<R: Idx, C: Idx> SparseBitMatrix<R, C> { Self { num_columns, rows: IndexVec::new() } } - fn ensure_row(&mut self, row: R) -> &mut ChunkedBitSet<C> { - // Instantiate any missing rows up to and including row `row` with an empty ChunkedBitSet. - // Then replace row `row` with a full ChunkedBitSet if necessary. - self.rows.get_or_insert_with(row, || ChunkedBitSet::new_empty(self.num_columns)) + fn ensure_row(&mut self, row: R) -> &mut BitSet<C> { + // Instantiate any missing rows up to and including row `row` with an empty `BitSet`. + // Then replace row `row` with a full `BitSet` if necessary. + self.rows.get_or_insert_with(row, || BitSet::new_empty(self.num_columns)) } /// Sets the cell at `(row, column)` to true. Put another way, insert @@ -1474,7 +1629,7 @@ impl<R: Idx, C: Idx> SparseBitMatrix<R, C> { self.row(row).into_iter().flat_map(|r| r.iter()) } - pub fn row(&self, row: R) -> Option<&ChunkedBitSet<C>> { + pub fn row(&self, row: R) -> Option<&BitSet<C>> { self.rows.get(row)?.as_ref() } @@ -1484,7 +1639,7 @@ impl<R: Idx, C: Idx> SparseBitMatrix<R, C> { /// Returns true if the row was changed. pub fn intersect_row<Set>(&mut self, row: R, set: &Set) -> bool where - ChunkedBitSet<C>: BitRelations<Set>, + BitSet<C>: BitRelations<Set>, { match self.rows.get_mut(row) { Some(Some(row)) => row.intersect(set), @@ -1498,7 +1653,7 @@ impl<R: Idx, C: Idx> SparseBitMatrix<R, C> { /// Returns true if the row was changed. pub fn subtract_row<Set>(&mut self, row: R, set: &Set) -> bool where - ChunkedBitSet<C>: BitRelations<Set>, + BitSet<C>: BitRelations<Set>, { match self.rows.get_mut(row) { Some(Some(row)) => row.subtract(set), @@ -1512,7 +1667,7 @@ impl<R: Idx, C: Idx> SparseBitMatrix<R, C> { /// Returns true if the row was changed. pub fn union_row<Set>(&mut self, row: R, set: &Set) -> bool where - ChunkedBitSet<C>: BitRelations<Set>, + BitSet<C>: BitRelations<Set>, { self.ensure_row(row).union(set) } diff --git a/compiler/rustc_index/src/bit_set/tests.rs b/compiler/rustc_index/src/bit_set/tests.rs index 3f9198ce37f..f6142323979 100644 --- a/compiler/rustc_index/src/bit_set/tests.rs +++ b/compiler/rustc_index/src/bit_set/tests.rs @@ -503,15 +503,15 @@ fn sparse_matrix_operations() { matrix.insert(2, 99); matrix.insert(4, 0); - let mut disjoint: ChunkedBitSet<usize> = ChunkedBitSet::new_empty(100); + let mut disjoint: BitSet<usize> = BitSet::new_empty(100); disjoint.insert(33); - let mut superset = ChunkedBitSet::new_empty(100); + let mut superset = BitSet::new_empty(100); superset.insert(22); superset.insert(75); superset.insert(33); - let mut subset = ChunkedBitSet::new_empty(100); + let mut subset = BitSet::new_empty(100); subset.insert(22); // SparseBitMatrix::remove diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs index 6caeec1b5cc..aa4abf678b9 100644 --- a/compiler/rustc_lexer/src/lib.rs +++ b/compiler/rustc_lexer/src/lib.rs @@ -33,6 +33,7 @@ pub mod unescape; mod tests; use unicode_properties::UnicodeEmoji; +pub use unicode_xid::UNICODE_VERSION as UNICODE_XID_VERSION; use self::LiteralKind::*; use self::TokenKind::*; diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 422629cd11d..49e6b763590 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -359,6 +359,7 @@ lint_improper_ctypes_128bit = 128-bit integers don't currently have a known stab lint_improper_ctypes_array_help = consider passing a pointer to the array lint_improper_ctypes_array_reason = passing raw arrays by value is not FFI-safe +lint_improper_ctypes_box = box cannot be represented as a single pointer lint_improper_ctypes_char_help = consider using `u32` or `libc::wchar_t` instead @@ -376,9 +377,7 @@ lint_improper_ctypes_enum_repr_help = lint_improper_ctypes_enum_repr_reason = enum has no representation hint lint_improper_ctypes_fnptr_help = consider using an `extern fn(...) -> ...` function pointer instead -lint_improper_ctypes_fnptr_indirect_reason = the function pointer to `{$ty}` is FFI-unsafe due to `{$inner_ty}` lint_improper_ctypes_fnptr_reason = this function pointer has Rust-specific calling convention - lint_improper_ctypes_non_exhaustive = this enum is non-exhaustive lint_improper_ctypes_non_exhaustive_variant = this enum has non-exhaustive variants @@ -389,11 +388,7 @@ lint_improper_ctypes_opaque = opaque types have no C equivalent lint_improper_ctypes_pat_help = consider using the base type instead lint_improper_ctypes_pat_reason = pattern types have no C equivalent - -lint_improper_ctypes_sized_ptr_to_unsafe_type = - this reference (`{$ty}`) is ABI-compatible with a C pointer, but `{$inner_ty}` itself does not have a C layout - -lint_improper_ctypes_slice_help = consider using a raw pointer to the slice's first element (and a length) instead +lint_improper_ctypes_slice_help = consider using a raw pointer instead lint_improper_ctypes_slice_reason = slices have no C equivalent lint_improper_ctypes_str_help = consider using `*const u8` and a length instead @@ -419,10 +414,6 @@ lint_improper_ctypes_union_layout_help = consider adding a `#[repr(C)]` or `#[re lint_improper_ctypes_union_layout_reason = this union has unspecified layout lint_improper_ctypes_union_non_exhaustive = this union is non-exhaustive -lint_improper_ctypes_unsized_box = this box for an unsized type contains metadata, which makes it incompatible with a C pointer -lint_improper_ctypes_unsized_ptr = this pointer to an unsized type contains metadata, which makes it incompatible with a C pointer -lint_improper_ctypes_unsized_ref = this reference to an unsized type contains metadata, which makes it incompatible with a C pointer - lint_incomplete_include = include macro expected single expression in source diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index ec085198922..093cc16fb4c 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -625,6 +625,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations { cx.param_env, ty, traits::ObligationCause::misc(item.span, item.owner_id.def_id), + hir::Safety::Safe, ) .is_ok() { diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 9fa263799eb..20822f23bf1 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -1851,44 +1851,13 @@ pub(crate) struct UnpredictableFunctionPointerComparisonsSuggestion<'a> { pub right: Span, } -pub(crate) struct ImproperCTypesLayer<'a> { - pub ty: Ty<'a>, - pub inner_ty: Option<Ty<'a>>, - pub note: DiagMessage, - pub span_note: Option<Span>, - pub help: Option<DiagMessage>, -} - -impl<'a> Subdiagnostic for ImproperCTypesLayer<'a> { - fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>( - self, - diag: &mut Diag<'_, G>, - f: &F, - ) { - diag.arg("ty", self.ty); - if let Some(ty) = self.inner_ty { - diag.arg("inner_ty", ty); - } - - if let Some(help) = self.help { - let msg = f(diag, help.into()); - diag.help(msg); - } - - let msg = f(diag, self.note.into()); - diag.note(msg); - if let Some(note) = self.span_note { - let msg = f(diag, fluent::lint_note.into()); - diag.span_note(note, msg); - }; - } -} - pub(crate) struct ImproperCTypes<'a> { pub ty: Ty<'a>, pub desc: &'a str, pub label: Span, - pub reasons: Vec<ImproperCTypesLayer<'a>>, + pub help: Option<DiagMessage>, + pub note: DiagMessage, + pub span_note: Option<Span>, } // Used because of the complexity of Option<DiagMessage>, DiagMessage, and Option<Span> @@ -1898,8 +1867,12 @@ impl<'a> LintDiagnostic<'a, ()> for ImproperCTypes<'_> { diag.arg("ty", self.ty); diag.arg("desc", self.desc); diag.span_label(self.label, fluent::lint_label); - for reason in self.reasons.into_iter() { - diag.subdiagnostic(reason); + if let Some(help) = self.help { + diag.help(help); + } + diag.note(self.note); + if let Some(note) = self.span_note { + diag.span_note(note, fluent::lint_note); } } } diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 90d44371ab5..33650be056d 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -22,10 +22,10 @@ mod improper_ctypes; use crate::lints::{ AmbiguousWidePointerComparisons, AmbiguousWidePointerComparisonsAddrMetadataSuggestion, AmbiguousWidePointerComparisonsAddrSuggestion, AtomicOrderingFence, AtomicOrderingLoad, - AtomicOrderingStore, ImproperCTypes, ImproperCTypesLayer, InvalidAtomicOrderingDiag, - InvalidNanComparisons, InvalidNanComparisonsSuggestion, - UnpredictableFunctionPointerComparisons, UnpredictableFunctionPointerComparisonsSuggestion, - UnusedComparisons, VariantSizeDifferencesDiag, + AtomicOrderingStore, ImproperCTypes, InvalidAtomicOrderingDiag, InvalidNanComparisons, + InvalidNanComparisonsSuggestion, UnpredictableFunctionPointerComparisons, + UnpredictableFunctionPointerComparisonsSuggestion, UnusedComparisons, + VariantSizeDifferencesDiag, }; use crate::{LateContext, LateLintPass, LintContext, fluent_generated as fluent}; @@ -727,109 +727,7 @@ struct CTypesVisitorState<'tcx> { enum FfiResult<'tcx> { FfiSafe, FfiPhantom(Ty<'tcx>), - FfiUnsafe { - ty: Ty<'tcx>, - reason: DiagMessage, - help: Option<DiagMessage>, - }, - FfiUnsafeWrapper { - ty: Ty<'tcx>, - reason: DiagMessage, - help: Option<DiagMessage>, - wrapped: Box<FfiResult<'tcx>>, - }, -} - -/// Determine if a type is sized or not, and wether it affects references/pointers/boxes to it -#[derive(Clone, Copy)] -enum TypeSizedness { - /// type of definite size (pointers are C-compatible) - Definite, - /// unsized type because it includes an opaque/foreign type (pointers are C-compatible) - UnsizedWithExternType, - /// unsized type for other reasons (slice, string, dyn Trait, closure, ...) (pointers are not C-compatible) - UnsizedWithMetadata, -} - -/// Is this type unsized because it contains (or is) a foreign type? -/// (Returns Err if the type happens to be sized after all) -fn get_type_sizedness<'tcx, 'a>(cx: &'a LateContext<'tcx>, ty: Ty<'tcx>) -> TypeSizedness { - let tcx = cx.tcx; - - if ty.is_sized(tcx, cx.typing_env()) { - TypeSizedness::Definite - } else { - match ty.kind() { - ty::Slice(_) => TypeSizedness::UnsizedWithMetadata, - ty::Str => TypeSizedness::UnsizedWithMetadata, - ty::Dynamic(..) => TypeSizedness::UnsizedWithMetadata, - ty::Foreign(..) => TypeSizedness::UnsizedWithExternType, - // While opaque types are checked for earlier, if a projection in a struct field - // normalizes to an opaque type, then it will reach this branch. - ty::Alias(ty::Opaque, ..) => todo!("We... don't know enough about this type yet?"), - ty::Adt(def, args) => { - // for now assume: boxes and phantoms don't mess with this - match def.adt_kind() { - AdtKind::Union | AdtKind::Enum => { - bug!("unions and enums are necessarily sized") - } - AdtKind::Struct => { - if let Some(sym::cstring_type | sym::cstr_type) = - tcx.get_diagnostic_name(def.did()) - { - return TypeSizedness::UnsizedWithMetadata; - } - // FIXME: how do we deal with non-exhaustive unsized structs/unions? - - if def.non_enum_variant().fields.is_empty() { - bug!("an empty struct is necessarily sized"); - } - - let variant = def.non_enum_variant(); - - // only the last field may be unsized - let n_fields = variant.fields.len(); - let last_field = &variant.fields[(n_fields - 1).into()]; - let field_ty = last_field.ty(cx.tcx, args); - let field_ty = cx - .tcx - .try_normalize_erasing_regions(cx.typing_env(), field_ty) - .unwrap_or(field_ty); - match get_type_sizedness(cx, field_ty) { - s @ (TypeSizedness::UnsizedWithMetadata - | TypeSizedness::UnsizedWithExternType) => s, - TypeSizedness::Definite => { - bug!("failed to find the reason why struct `{:?}` is unsized", ty) - } - } - } - } - } - ty::Tuple(tuple) => { - // only the last field may be unsized - let n_fields = tuple.len(); - let field_ty: Ty<'tcx> = tuple[n_fields - 1]; - //let field_ty = last_field.ty(cx.tcx, args); - let field_ty = cx - .tcx - .try_normalize_erasing_regions(cx.typing_env(), field_ty) - .unwrap_or(field_ty); - match get_type_sizedness(cx, field_ty) { - s @ (TypeSizedness::UnsizedWithMetadata - | TypeSizedness::UnsizedWithExternType) => s, - TypeSizedness::Definite => { - bug!("failed to find the reason why tuple `{:?}` is unsized", ty) - } - } - } - ty => { - bug!( - "we shouldn't be trying to determine if this is unsized for a reason or another: `{:?}`", - ty - ) - } - } - } + FfiUnsafe { ty: Ty<'tcx>, reason: DiagMessage, help: Option<DiagMessage> }, } pub(crate) fn nonnull_optimization_guaranteed<'tcx>( @@ -866,7 +764,7 @@ fn ty_is_known_nonnull<'tcx>( match ty.kind() { ty::FnPtr(..) => true, ty::Ref(..) => true, - ty::Adt(def, _) if def.is_box() => true, + ty::Adt(def, _) if def.is_box() && matches!(mode, CItemKind::Definition) => true, ty::Adt(def, args) if def.repr().transparent() && !def.is_union() => { let marked_non_null = nonnull_optimization_guaranteed(tcx, *def); @@ -1035,13 +933,12 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { /// Check if the type is array and emit an unsafe type lint. fn check_for_array_ty(&mut self, sp: Span, ty: Ty<'tcx>) -> bool { if let ty::Array(..) = ty.kind() { - self.emit_ffi_unsafe_type_lint(ty.clone(), sp, vec![ImproperCTypesLayer { + self.emit_ffi_unsafe_type_lint( ty, - note: fluent::lint_improper_ctypes_array_reason, - help: Some(fluent::lint_improper_ctypes_array_help), - inner_ty: None, - span_note: None, - }]); + sp, + fluent::lint_improper_ctypes_array_reason, + Some(fluent::lint_improper_ctypes_array_help), + ); true } else { false @@ -1098,9 +995,9 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { all_phantom &= match self.check_field_type_for_ffi(acc, field, args) { FfiSafe => false, // `()` fields are FFI-safe! - FfiUnsafe { ty, .. } | FfiUnsafeWrapper { ty, .. } if ty.is_unit() => false, + FfiUnsafe { ty, .. } if ty.is_unit() => false, FfiPhantom(..) => true, - r @ (FfiUnsafe { .. } | FfiUnsafeWrapper { .. }) => return r, + r @ FfiUnsafe { .. } => return r, } } @@ -1134,47 +1031,16 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { match *ty.kind() { ty::Adt(def, args) => { - if let Some(inner_ty) = ty.boxed_ty() { - if let TypeSizedness::UnsizedWithExternType | TypeSizedness::Definite = - get_type_sizedness(self.cx, inner_ty) - { - // discussion on declaration vs definition: - // see the `ty::RawPtr(inner_ty, _) | ty::Ref(_, inner_ty, _)` arm - // of this `match *ty.kind()` block - if matches!(self.mode, CItemKind::Definition) { - return FfiSafe; - } else { - let inner_res = self.check_type_for_ffi(acc, inner_ty); - return match inner_res { - FfiUnsafe { .. } | FfiUnsafeWrapper { .. } => FfiUnsafeWrapper { - ty, - reason: fluent::lint_improper_ctypes_sized_ptr_to_unsafe_type, - wrapped: Box::new(inner_res), - help: None, - }, - _ => inner_res, - }; - } + if let Some(boxed) = ty.boxed_ty() + && matches!(self.mode, CItemKind::Definition) + { + if boxed.is_sized(tcx, self.cx.typing_env()) { + return FfiSafe; } else { - let help = match inner_ty.kind() { - ty::Str => Some(fluent::lint_improper_ctypes_str_help), - ty::Slice(_) => Some(fluent::lint_improper_ctypes_slice_help), - ty::Adt(def, _) - if matches!(def.adt_kind(), AdtKind::Struct | AdtKind::Union) - && matches!( - tcx.get_diagnostic_name(def.did()), - Some(sym::cstring_type | sym::cstr_type) - ) - && !acc.base_ty.is_mutable_ptr() => - { - Some(fluent::lint_improper_ctypes_cstr_help) - } - _ => None, - }; return FfiUnsafe { ty, - reason: fluent::lint_improper_ctypes_unsized_box, - help, + reason: fluent::lint_improper_ctypes_box, + help: None, }; } } @@ -1330,6 +1196,15 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { help: Some(fluent::lint_improper_ctypes_tuple_help), }, + ty::RawPtr(ty, _) | ty::Ref(_, ty, _) + if { + matches!(self.mode, CItemKind::Definition) + && ty.is_sized(self.cx.tcx, self.cx.typing_env()) + } => + { + FfiSafe + } + ty::RawPtr(ty, _) if match ty.kind() { ty::Tuple(tuple) => tuple.is_empty(), @@ -1339,70 +1214,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { FfiSafe } - ty::RawPtr(inner_ty, _) | ty::Ref(_, inner_ty, _) => { - if let TypeSizedness::UnsizedWithExternType | TypeSizedness::Definite = - get_type_sizedness(self.cx, inner_ty) - { - // there's a nuance on what this lint should do for - // function definitions (`extern "C" fn fn_name(...) {...}`) - // versus declarations (`unsafe extern "C" {fn fn_name(...);}`). - // This is touched upon in https://github.com/rust-lang/rust/issues/66220 - // and https://github.com/rust-lang/rust/pull/72700 - // - // The big question is: what does "ABI safety" mean? if you have something translated to a C pointer - // (which has a stable layout) but points to FFI-unsafe type, is it safe? - // On one hand, the function's ABI will match that of a similar C-declared function API, - // on the other, dereferencing the pointer on the other side of the FFI boundary will be painful. - // In this code, the opinion on is split between function declarations and function definitions, - // with the idea that at least one side of the FFI boundary needs to treat the pointee as an opaque type. - // For declarations, we see this as unsafe, but for definitions, we see this as safe. - // - // For extern function declarations, the actual definition of the function is written somewhere else, - // meaning the declaration is free to express this opaqueness with an extern type (opaque caller-side) or a std::ffi::c_void (opaque callee-side) - // For extern function definitions, however, in the case where the type is opaque caller-side, it is not opaque callee-side, - // and having the full type information is necessary to compile the function. - if matches!(self.mode, CItemKind::Definition) { - return FfiSafe; - } else if matches!(ty.kind(), ty::RawPtr(..)) - && matches!(inner_ty.kind(), ty::Tuple(tuple) if tuple.is_empty()) - { - FfiSafe - } else { - let inner_res = self.check_type_for_ffi(acc, inner_ty); - return match inner_res { - FfiSafe => inner_res, - _ => FfiUnsafeWrapper { - ty, - reason: fluent::lint_improper_ctypes_sized_ptr_to_unsafe_type, - wrapped: Box::new(inner_res), - help: None, - }, - }; - } - } else { - let help = match inner_ty.kind() { - ty::Str => Some(fluent::lint_improper_ctypes_str_help), - ty::Slice(_) => Some(fluent::lint_improper_ctypes_slice_help), - ty::Adt(def, _) - if matches!(def.adt_kind(), AdtKind::Struct | AdtKind::Union) - && matches!( - tcx.get_diagnostic_name(def.did()), - Some(sym::cstring_type | sym::cstr_type) - ) - && !acc.base_ty.is_mutable_ptr() => - { - Some(fluent::lint_improper_ctypes_cstr_help) - } - _ => None, - }; - let reason = match ty.kind() { - ty::RawPtr(..) => fluent::lint_improper_ctypes_unsized_ptr, - ty::Ref(..) => fluent::lint_improper_ctypes_unsized_ref, - _ => unreachable!(), - }; - FfiUnsafe { ty, reason, help } - } - } + ty::RawPtr(ty, _) | ty::Ref(_, ty, _) => self.check_type_for_ffi(acc, ty), ty::Array(inner_ty, _) => self.check_type_for_ffi(acc, inner_ty), @@ -1420,14 +1232,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { for arg in sig.inputs() { match self.check_type_for_ffi(acc, *arg) { FfiSafe => {} - r => { - return FfiUnsafeWrapper { - ty, - reason: fluent::lint_improper_ctypes_fnptr_indirect_reason, - help: None, - wrapped: Box::new(r), - }; - } + r => return r, } } @@ -1436,15 +1241,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { return FfiSafe; } - match self.check_type_for_ffi(acc, ret_ty) { - r @ (FfiSafe | FfiPhantom(_)) => r, - r => FfiUnsafeWrapper { - ty: ty.clone(), - reason: fluent::lint_improper_ctypes_fnptr_indirect_reason, - help: None, - wrapped: Box::new(r), - }, - } + self.check_type_for_ffi(acc, ret_ty) } ty::Foreign(..) => FfiSafe, @@ -1481,7 +1278,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { &mut self, ty: Ty<'tcx>, sp: Span, - mut reasons: Vec<ImproperCTypesLayer<'tcx>>, + note: DiagMessage, + help: Option<DiagMessage>, ) { let lint = match self.mode { CItemKind::Declaration => IMPROPER_CTYPES, @@ -1491,17 +1289,21 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { CItemKind::Declaration => "block", CItemKind::Definition => "fn", }; - for reason in reasons.iter_mut() { - reason.span_note = if let ty::Adt(def, _) = reason.ty.kind() - && let Some(sp) = self.cx.tcx.hir().span_if_local(def.did()) - { - Some(sp) - } else { - None - }; - } - - self.cx.emit_span_lint(lint, sp, ImproperCTypes { ty, desc, label: sp, reasons }); + let span_note = if let ty::Adt(def, _) = ty.kind() + && let Some(sp) = self.cx.tcx.hir().span_if_local(def.did()) + { + Some(sp) + } else { + None + }; + self.cx.emit_span_lint(lint, sp, ImproperCTypes { + ty, + desc, + label: sp, + help, + note, + span_note, + }); } fn check_for_opaque_ty(&mut self, sp: Span, ty: Ty<'tcx>) -> bool { @@ -1530,13 +1332,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { .visit_with(&mut ProhibitOpaqueTypes) .break_value() { - self.emit_ffi_unsafe_type_lint(ty.clone(), sp, vec![ImproperCTypesLayer { - ty, - note: fluent::lint_improper_ctypes_opaque, - span_note: Some(sp), - help: None, - inner_ty: None, - }]); + self.emit_ffi_unsafe_type_lint(ty, sp, fluent::lint_improper_ctypes_opaque, None); true } else { false @@ -1575,71 +1371,15 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { match self.check_type_for_ffi(&mut acc, ty) { FfiResult::FfiSafe => {} FfiResult::FfiPhantom(ty) => { - self.emit_ffi_unsafe_type_lint(ty.clone(), sp, vec![ImproperCTypesLayer { + self.emit_ffi_unsafe_type_lint( ty, - note: fluent::lint_improper_ctypes_only_phantomdata, - span_note: None, // filled later - help: None, - inner_ty: None, - }]); + sp, + fluent::lint_improper_ctypes_only_phantomdata, + None, + ); } FfiResult::FfiUnsafe { ty, reason, help } => { - self.emit_ffi_unsafe_type_lint(ty.clone(), sp, vec![ImproperCTypesLayer { - ty, - help, - note: reason, - span_note: None, // filled later - inner_ty: None, - }]); - } - ffir @ FfiResult::FfiUnsafeWrapper { .. } => { - let mut ffiresult_recursor = ControlFlow::Continue(&ffir); - let mut cimproper_layers: Vec<ImproperCTypesLayer<'tcx>> = vec![]; - - // this whole while block converts the arbitrarily-deep - // FfiResult stack to an ImproperCTypesLayer Vec - while let ControlFlow::Continue(ref ffir_rec) = ffiresult_recursor { - match ffir_rec { - FfiResult::FfiPhantom(ty) => { - if let Some(layer) = cimproper_layers.last_mut() { - layer.inner_ty = Some(ty.clone()); - } - cimproper_layers.push(ImproperCTypesLayer { - ty: ty.clone(), - inner_ty: None, - help: None, - note: fluent::lint_improper_ctypes_only_phantomdata, - span_note: None, // filled later - }); - ffiresult_recursor = ControlFlow::Break(()); - } - FfiResult::FfiUnsafe { ty, reason, help } - | FfiResult::FfiUnsafeWrapper { ty, reason, help, .. } => { - if let Some(layer) = cimproper_layers.last_mut() { - layer.inner_ty = Some(ty.clone()); - } - cimproper_layers.push(ImproperCTypesLayer { - ty: ty.clone(), - inner_ty: None, - help: help.clone(), - note: reason.clone(), - span_note: None, // filled later - }); - - if let FfiResult::FfiUnsafeWrapper { wrapped, .. } = ffir_rec { - ffiresult_recursor = ControlFlow::Continue(wrapped.as_ref()); - } else { - ffiresult_recursor = ControlFlow::Break(()); - } - } - FfiResult::FfiSafe => { - bug!("malformed FfiResult stack: it should be unsafe all the way down") - } - }; - } - // should always have at least one type - let last_ty = cimproper_layers.last().unwrap().ty.clone(); - self.emit_ffi_unsafe_type_lint(last_ty, sp, cimproper_layers); + self.emit_ffi_unsafe_type_lint(ty, sp, reason, help); } } } diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 06550728f0f..b79205ff946 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -1535,7 +1535,7 @@ extern "C" LLVMTypeKind LLVMRustGetTypeKind(LLVMTypeRef Ty) { DEFINE_SIMPLE_CONVERSION_FUNCTIONS(SMDiagnostic, LLVMSMDiagnosticRef) extern "C" LLVMSMDiagnosticRef LLVMRustGetSMDiagnostic(LLVMDiagnosticInfoRef DI, - unsigned *Cookie) { + uint64_t *Cookie) { llvm::DiagnosticInfoSrcMgr *SM = static_cast<llvm::DiagnosticInfoSrcMgr *>(unwrap(DI)); *Cookie = SM->getLocCookie(); diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index f3f5af49412..b9586338655 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -1104,6 +1104,7 @@ impl<'a> CrateMetadataRef<'a> { name: self.item_name(did.index), vis: self.get_visibility(did.index), safety: self.get_safety(did.index), + value: self.get_default_field(did.index), }) .collect(), adt_kind, @@ -1169,6 +1170,10 @@ impl<'a> CrateMetadataRef<'a> { self.root.tables.safety.get(self, id).unwrap_or_else(|| self.missing("safety", id)) } + fn get_default_field(self, id: DefIndex) -> Option<DefId> { + self.root.tables.default_fields.get(self, id).map(|d| d.decode(self)) + } + fn get_trait_item_def_id(self, id: DefIndex) -> Option<DefId> { self.root.tables.trait_item_def_id.get(self, id).map(|d| d.decode_from_cdata(self)) } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index d4ea1276d00..5c80d24f502 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1401,6 +1401,13 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { continue; } + if def_kind == DefKind::Field + && let hir::Node::Field(field) = tcx.hir_node_by_def_id(local_id) + && let Some(anon) = field.default + { + record!(self.tables.default_fields[def_id] <- anon.def_id.to_def_id()); + } + if should_encode_span(def_kind) { let def_span = tcx.def_span(local_id); record!(self.tables.def_span[def_id] <- def_span); diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index a5e21ab51fd..4961464833a 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -450,6 +450,7 @@ define_tables! { trait_def: Table<DefIndex, LazyValue<ty::TraitDef>>, trait_item_def_id: Table<DefIndex, RawDefId>, expn_that_defined: Table<DefIndex, LazyValue<ExpnId>>, + default_fields: Table<DefIndex, LazyValue<DefId>>, params_in_repr: Table<DefIndex, LazyValue<BitSet<u32>>>, repr_options: Table<DefIndex, LazyValue<ReprOptions>>, // `def_keys` and `def_path_hashes` represent a lazy version of a diff --git a/compiler/rustc_middle/src/mir/consts.rs b/compiler/rustc_middle/src/mir/consts.rs index 7983329b0f7..52009422d98 100644 --- a/compiler/rustc_middle/src/mir/consts.rs +++ b/compiler/rustc_middle/src/mir/consts.rs @@ -8,6 +8,7 @@ use rustc_session::config::RemapPathScopeComponents; use rustc_span::{DUMMY_SP, Span}; use rustc_type_ir::visit::TypeVisitableExt; +use super::interpret::ReportedErrorInfo; use crate::mir::interpret::{AllocId, ConstAllocation, ErrorHandled, Scalar, alloc_range}; use crate::mir::{Promoted, pretty_print_const_value}; use crate::ty::print::{pretty_print_const, with_no_trimmed_paths}; @@ -331,7 +332,10 @@ impl<'tcx> Const<'tcx> { ConstKind::Expr(_) => { bug!("Normalization of `ty::ConstKind::Expr` is unimplemented") } - _ => Err(tcx.dcx().delayed_bug("Unevaluated `ty::Const` in MIR body").into()), + _ => Err(ReportedErrorInfo::non_const_eval_error( + tcx.dcx().delayed_bug("Unevaluated `ty::Const` in MIR body"), + ) + .into()), } } Const::Unevaluated(uneval, _) => { diff --git a/compiler/rustc_middle/src/mir/coverage.rs b/compiler/rustc_middle/src/mir/coverage.rs index b7410ca5f18..962176290df 100644 --- a/compiler/rustc_middle/src/mir/coverage.rs +++ b/compiler/rustc_middle/src/mir/coverage.rs @@ -3,6 +3,7 @@ use std::fmt::{self, Debug, Formatter}; use rustc_index::IndexVec; +use rustc_index::bit_set::BitSet; use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; use rustc_span::Span; @@ -310,3 +311,41 @@ pub struct MCDCDecisionSpan { pub decision_depth: u16, pub num_conditions: usize, } + +/// Summarizes coverage IDs inserted by the `InstrumentCoverage` MIR pass +/// (for compiler option `-Cinstrument-coverage`), after MIR optimizations +/// have had a chance to potentially remove some of them. +/// +/// Used by the `coverage_ids_info` query. +#[derive(Clone, TyEncodable, TyDecodable, Debug, HashStable)] +pub struct CoverageIdsInfo { + pub counters_seen: BitSet<CounterId>, + pub zero_expressions: BitSet<ExpressionId>, +} + +impl CoverageIdsInfo { + /// Coverage codegen needs to know how many coverage counters are ever + /// incremented within a function, so that it can set the `num-counters` + /// argument of the `llvm.instrprof.increment` intrinsic. + /// + /// This may be less than the highest counter ID emitted by the + /// InstrumentCoverage MIR pass, if the highest-numbered counter increments + /// were removed by MIR optimizations. + pub fn num_counters_after_mir_opts(&self) -> u32 { + // FIXME(Zalathar): Currently this treats an unused counter as "used" + // if its ID is less than that of the highest counter that really is + // used. Fixing this would require adding a renumbering step somewhere. + self.counters_seen.last_set_in(..).map_or(0, |max| max.as_u32() + 1) + } + + /// Returns `true` if the given term is known to have a value of zero, taking + /// into account knowledge of which counters are unused and which expressions + /// are always zero. + pub fn is_zero_term(&self, term: CovTerm) -> bool { + match term { + CovTerm::Zero => true, + CovTerm::Counter(id) => !self.counters_seen.contains(id), + CovTerm::Expression(id) => self.zero_expressions.contains(id), + } + } +} diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index ad5d678178d..fbada6ec405 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -28,10 +28,10 @@ pub enum ErrorHandled { TooGeneric(Span), } -impl From<ErrorGuaranteed> for ErrorHandled { +impl From<ReportedErrorInfo> for ErrorHandled { #[inline] - fn from(error: ErrorGuaranteed) -> ErrorHandled { - ErrorHandled::Reported(error.into(), DUMMY_SP) + fn from(error: ReportedErrorInfo) -> ErrorHandled { + ErrorHandled::Reported(error, DUMMY_SP) } } @@ -65,6 +65,20 @@ pub struct ReportedErrorInfo { impl ReportedErrorInfo { #[inline] + pub fn const_eval_error(error: ErrorGuaranteed) -> ReportedErrorInfo { + ReportedErrorInfo { allowed_in_infallible: false, error } + } + + /// Use this when the error that led to this is *not* a const-eval error + /// (e.g., a layout or type checking error). + #[inline] + pub fn non_const_eval_error(error: ErrorGuaranteed) -> ReportedErrorInfo { + ReportedErrorInfo { allowed_in_infallible: true, error } + } + + /// Use this when the error that led to this *is* a const-eval error, but + /// we do allow it to occur in infallible constants (e.g., resource exhaustion). + #[inline] pub fn allowed_in_infallible(error: ErrorGuaranteed) -> ReportedErrorInfo { ReportedErrorInfo { allowed_in_infallible: true, error } } @@ -74,13 +88,6 @@ impl ReportedErrorInfo { } } -impl From<ErrorGuaranteed> for ReportedErrorInfo { - #[inline] - fn from(error: ErrorGuaranteed) -> ReportedErrorInfo { - ReportedErrorInfo { allowed_in_infallible: false, error } - } -} - impl Into<ErrorGuaranteed> for ReportedErrorInfo { #[inline] fn into(self) -> ErrorGuaranteed { @@ -180,12 +187,6 @@ fn print_backtrace(backtrace: &Backtrace) { eprintln!("\n\nAn error occurred in the MIR interpreter:\n{backtrace}"); } -impl From<ErrorGuaranteed> for InterpErrorInfo<'_> { - fn from(err: ErrorGuaranteed) -> Self { - InterpErrorKind::InvalidProgram(InvalidProgramInfo::AlreadyReported(err.into())).into() - } -} - impl From<ErrorHandled> for InterpErrorInfo<'_> { fn from(err: ErrorHandled) -> Self { InterpErrorKind::InvalidProgram(match err { diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs index e540f0194ec..f7f38575bd0 100644 --- a/compiler/rustc_middle/src/mir/interpret/queries.rs +++ b/compiler/rustc_middle/src/mir/interpret/queries.rs @@ -6,6 +6,7 @@ use tracing::{debug, instrument}; use super::{ ErrorHandled, EvalToAllocationRawResult, EvalToConstValueResult, EvalToValTreeResult, GlobalId, + ReportedErrorInfo, }; use crate::mir; use crate::query::TyCtxtEnsure; @@ -81,7 +82,9 @@ impl<'tcx> TyCtxt<'tcx> { // For errors during resolution, we deliberately do not point at the usage site of the constant, // since for these errors the place the constant is used shouldn't matter. Ok(None) => Err(ErrorHandled::TooGeneric(DUMMY_SP)), - Err(err) => Err(ErrorHandled::Reported(err.into(), DUMMY_SP)), + Err(err) => { + Err(ErrorHandled::Reported(ReportedErrorInfo::non_const_eval_error(err), DUMMY_SP)) + } } } @@ -138,7 +141,9 @@ impl<'tcx> TyCtxt<'tcx> { // For errors during resolution, we deliberately do not point at the usage site of the constant, // since for these errors the place the constant is used shouldn't matter. Ok(None) => Err(ErrorHandled::TooGeneric(DUMMY_SP)), - Err(err) => Err(ErrorHandled::Reported(err.into(), DUMMY_SP)), + Err(err) => { + Err(ErrorHandled::Reported(ReportedErrorInfo::non_const_eval_error(err), DUMMY_SP)) + } } } diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index 161716610fe..1f50b67cb50 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -19,6 +19,7 @@ use rustc_target::spec::SymbolVisibility; use tracing::debug; use crate::dep_graph::{DepNode, WorkProduct, WorkProductId}; +use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags; use crate::ty::{GenericArgs, Instance, InstanceKind, SymbolName, TyCtxt}; /// Describes how a monomorphization will be instantiated in object files. @@ -104,7 +105,9 @@ impl<'tcx> MonoItem<'tcx> { let entry_def_id = tcx.entry_fn(()).map(|(id, _)| id); // If this function isn't inlined or otherwise has an extern // indicator, then we'll be creating a globally shared version. - if tcx.codegen_fn_attrs(instance.def_id()).contains_extern_indicator() + let codegen_fn_attrs = tcx.codegen_fn_attrs(instance.def_id()); + if codegen_fn_attrs.contains_extern_indicator() + || codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) || !instance.def.generates_cgu_internal_copy(tcx) || Some(instance.def_id()) == entry_def_id { diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index 80dfcbf2e69..f690359e012 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -8,7 +8,7 @@ use rustc_abi::{FieldIdx, VariantIdx}; use rustc_data_structures::fx::FxIndexMap; use rustc_errors::ErrorGuaranteed; use rustc_hir::def_id::LocalDefId; -use rustc_index::bit_set::{BitMatrix, BitSet}; +use rustc_index::bit_set::BitMatrix; use rustc_index::{Idx, IndexVec}; use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; use rustc_span::Span; @@ -16,7 +16,6 @@ use rustc_span::symbol::Symbol; use smallvec::SmallVec; use super::{ConstValue, SourceInfo}; -use crate::mir; use crate::ty::fold::fold_regions; use crate::ty::{self, CoroutineArgsExt, OpaqueHiddenType, Ty, TyCtxt}; @@ -351,30 +350,3 @@ pub struct DestructuredConstant<'tcx> { pub variant: Option<VariantIdx>, pub fields: &'tcx [(ConstValue<'tcx>, Ty<'tcx>)], } - -/// Summarizes coverage IDs inserted by the `InstrumentCoverage` MIR pass -/// (for compiler option `-Cinstrument-coverage`), after MIR optimizations -/// have had a chance to potentially remove some of them. -/// -/// Used by the `coverage_ids_info` query. -#[derive(Clone, TyEncodable, TyDecodable, Debug, HashStable)] -pub struct CoverageIdsInfo { - pub counters_seen: BitSet<mir::coverage::CounterId>, - pub expressions_seen: BitSet<mir::coverage::ExpressionId>, -} - -impl CoverageIdsInfo { - /// Coverage codegen needs to know how many coverage counters are ever - /// incremented within a function, so that it can set the `num-counters` - /// argument of the `llvm.instrprof.increment` intrinsic. - /// - /// This may be less than the highest counter ID emitted by the - /// InstrumentCoverage MIR pass, if the highest-numbered counter increments - /// were removed by MIR optimizations. - pub fn num_counters_after_mir_opts(&self) -> u32 { - // FIXME(Zalathar): Currently this treats an unused counter as "used" - // if its ID is less than that of the highest counter that really is - // used. Fixing this would require adding a renumbering step somewhere. - self.counters_seen.last_set_in(..).map_or(0, |max| max.as_u32() + 1) - } -} diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index a3976c3dda1..fc3d690a8a9 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -581,7 +581,7 @@ rustc_queries! { /// Summarizes coverage IDs inserted by the `InstrumentCoverage` MIR pass /// (for compiler option `-Cinstrument-coverage`), after MIR optimizations /// have had a chance to potentially remove some of them. - query coverage_ids_info(key: ty::InstanceKind<'tcx>) -> &'tcx mir::CoverageIdsInfo { + query coverage_ids_info(key: ty::InstanceKind<'tcx>) -> &'tcx mir::coverage::CoverageIdsInfo { desc { |tcx| "retrieving coverage IDs info from MIR for `{}`", tcx.def_path_str(key.def_id()) } arena_cache } diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 9cf6bc1b777..86014c34b45 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -158,8 +158,21 @@ pub struct AdtExpr<'tcx> { pub user_ty: UserTy<'tcx>, pub fields: Box<[FieldExpr]>, - /// The base, e.g. `Foo {x: 1, .. base}`. - pub base: Option<FruInfo<'tcx>>, + /// The base, e.g. `Foo {x: 1, ..base}`. + pub base: AdtExprBase<'tcx>, +} + +#[derive(Clone, Debug, HashStable)] +pub enum AdtExprBase<'tcx> { + /// A struct expression where all the fields are explicitly enumerated: `Foo { a, b }`. + None, + /// A struct expression with a "base", an expression of the same type as the outer struct that + /// will be used to populate any fields not explicitly mentioned: `Foo { ..base }` + Base(FruInfo<'tcx>), + /// A struct expression with a `..` tail but no "base" expression. The values from the struct + /// fields' default values will be used to populate any fields not explicitly mentioned: + /// `Foo { .. }`. + DefaultFields(Box<[Ty<'tcx>]>), } #[derive(Clone, Debug, HashStable)] diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs index 81202a6eaad..64bac12b266 100644 --- a/compiler/rustc_middle/src/thir/visit.rs +++ b/compiler/rustc_middle/src/thir/visit.rs @@ -2,6 +2,7 @@ use super::{ AdtExpr, Arm, Block, ClosureExpr, Expr, ExprKind, InlineAsmExpr, InlineAsmOperand, Pat, PatKind, Stmt, StmtKind, Thir, }; +use crate::thir::AdtExprBase; pub trait Visitor<'thir, 'tcx: 'thir>: Sized { fn thir(&self) -> &'thir Thir<'tcx>; @@ -127,7 +128,7 @@ pub fn walk_expr<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>( for field in &**fields { visitor.visit_expr(&visitor.thir()[field.expr]); } - if let Some(base) = base { + if let AdtExprBase::Base(base) = base { visitor.visit_expr(&visitor.thir()[base.base]); } } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index d4835bb07f6..2841470d248 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1479,7 +1479,7 @@ impl<'tcx> TyCtxt<'tcx> { self.mk_adt_def_from_data(ty::AdtDefData::new(self, did, kind, variants, repr)) } - /// Allocates a read-only byte or string literal for `mir::interpret`. + /// Allocates a read-only byte or string literal for `mir::interpret` with alignment 1. /// Returns the same `AllocId` if called again with the same bytes. pub fn allocate_bytes_dedup(self, bytes: &[u8], salt: usize) -> interpret::AllocId { // Create an allocation that just contains these bytes. diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index c7a2223ecd7..70e0568b202 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1364,6 +1364,7 @@ pub struct FieldDef { pub name: Symbol, pub vis: Visibility<DefId>, pub safety: hir::Safety, + pub value: Option<DefId>, } impl PartialEq for FieldDef { @@ -1376,9 +1377,9 @@ impl PartialEq for FieldDef { // of `FieldDef` changes, a compile-error will be produced, reminding // us to revisit this assumption. - let Self { did: lhs_did, name: _, vis: _, safety: _ } = &self; + let Self { did: lhs_did, name: _, vis: _, safety: _, value: _ } = &self; - let Self { did: rhs_did, name: _, vis: _, safety: _ } = other; + let Self { did: rhs_did, name: _, vis: _, safety: _, value: _ } = other; let res = lhs_did == rhs_did; @@ -1405,7 +1406,7 @@ impl Hash for FieldDef { // of `FieldDef` changes, a compile-error will be produced, reminding // us to revisit this assumption. - let Self { did, name: _, vis: _, safety: _ } = &self; + let Self { did, name: _, vis: _, safety: _, value: _ } = &self; did.hash(s) } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index cd4123f0a3f..40e0fb0087f 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1020,7 +1020,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { self.insert_trait_and_projection( trait_ref, - Some((proj.projection_def_id(), proj.term())), + Some((proj.item_def_id(), proj.term())), &mut traits, &mut fn_traits, ); diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 474062218c9..3fbc23924f5 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -980,11 +980,7 @@ impl<'tcx> rustc_type_ir::inherent::Ty<TyCtxt<'tcx>> for Ty<'tcx> { } fn has_unsafe_fields(self) -> bool { - if let ty::Adt(adt_def, ..) = self.kind() { - adt_def.all_fields().any(|x| x.safety == hir::Safety::Unsafe) - } else { - false - } + Ty::has_unsafe_fields(self) } } diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 57054bd1a0b..b9a45ea3c2c 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -1288,6 +1288,15 @@ impl<'tcx> Ty<'tcx> { } } + /// Checks whether this type is an ADT that has unsafe fields. + pub fn has_unsafe_fields(self) -> bool { + if let ty::Adt(adt_def, ..) = self.kind() { + adt_def.all_fields().any(|x| x.safety == hir::Safety::Unsafe) + } else { + false + } + } + /// Get morphology of the async drop glue, needed for types which do not /// use async drop. To get async drop glue morphology for a definition see /// [`TyCtxt::async_drop_glue_morphology`]. Used for `AsyncDestruct::Destructor` diff --git a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs index c3e9bd302de..67114efdff5 100644 --- a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs +++ b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs @@ -283,7 +283,7 @@ impl<'a, 'tcx> ParseCtxt<'a, 'tcx> { fields.iter().map(|e| self.parse_operand(*e)).collect::<Result<_, _>>()? )) }, - ExprKind::Adt(box AdtExpr{ adt_def, variant_index, args, fields, .. }) => { + ExprKind::Adt(box AdtExpr { adt_def, variant_index, args, fields, .. }) => { let is_union = adt_def.is_union(); let active_field_index = is_union.then(|| fields[0].name); diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs index bebb44faba6..a3d5376dcd4 100644 --- a/compiler/rustc_mir_build/src/build/expr/into.rs +++ b/compiler/rustc_mir_build/src/build/expr/into.rs @@ -1,7 +1,5 @@ //! See docs in build/expr/mod.rs -use std::iter; - use rustc_ast::{AsmMacro, InlineAsmOptions}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stack::ensure_sufficient_stack; @@ -344,25 +342,51 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }) .collect(); - let field_names = adt_def.variant(variant_index).fields.indices(); - - let fields = if let Some(FruInfo { base, field_types }) = base { - let place_builder = unpack!(block = this.as_place_builder(block, *base)); + let variant = adt_def.variant(variant_index); + let field_names = variant.fields.indices(); - // MIR does not natively support FRU, so for each - // base-supplied field, generate an operand that - // reads it from the base. - iter::zip(field_names, &**field_types) - .map(|(n, ty)| match fields_map.get(&n) { - Some(v) => v.clone(), - None => { - let place = place_builder.clone_project(PlaceElem::Field(n, *ty)); - this.consume_by_copy_or_move(place.to_place(this)) - } - }) - .collect() - } else { - field_names.filter_map(|n| fields_map.get(&n).cloned()).collect() + let fields = match base { + AdtExprBase::None => { + field_names.filter_map(|n| fields_map.get(&n).cloned()).collect() + } + AdtExprBase::Base(FruInfo { base, field_types }) => { + let place_builder = unpack!(block = this.as_place_builder(block, *base)); + + // We desugar FRU as we lower to MIR, so for each + // base-supplied field, generate an operand that + // reads it from the base. + itertools::zip_eq(field_names, &**field_types) + .map(|(n, ty)| match fields_map.get(&n) { + Some(v) => v.clone(), + None => { + let place = + place_builder.clone_project(PlaceElem::Field(n, *ty)); + this.consume_by_copy_or_move(place.to_place(this)) + } + }) + .collect() + } + AdtExprBase::DefaultFields(field_types) => { + itertools::zip_eq(field_names, &**field_types) + .map(|(n, ty)| match fields_map.get(&n) { + Some(v) => v.clone(), + None => match variant.fields[n].value { + Some(def) => { + let value = Const::from_unevaluated(this.tcx, def) + .instantiate(this.tcx, args); + this.literal_operand(expr_span, value) + } + None => { + let name = variant.fields[n].name; + span_bug!( + expr_span, + "missing mandatory field `{name}` of type `{ty}`", + ); + } + }, + }) + .collect() + } }; let inferred_ty = expr.ty; diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index ee9bcce104e..d75f01dfba0 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -222,7 +222,7 @@ impl<'tcx> Cx<'tcx> { args, fields: Box::new([FieldExpr { name: FieldIdx::from(0u32), expr }]), user_ty: None, - base: None, + base: AdtExprBase::None, })); debug!(?kind); @@ -464,7 +464,7 @@ impl<'tcx> Cx<'tcx> { variant_index: index, fields: field_refs, user_ty, - base: None, + base: AdtExprBase::None, })) } else { ExprKind::Call { @@ -594,20 +594,36 @@ impl<'tcx> Cx<'tcx> { args, user_ty, fields: self.field_refs(fields), - base: base.map(|base| FruInfo { - base: self.mirror_expr(base), - field_types: self.typeck_results().fru_field_types()[expr.hir_id] - .iter() - .copied() - .collect(), - }), + base: match base { + hir::StructTailExpr::Base(base) => AdtExprBase::Base(FruInfo { + base: self.mirror_expr(base), + field_types: self.typeck_results().fru_field_types() + [expr.hir_id] + .iter() + .copied() + .collect(), + }), + hir::StructTailExpr::DefaultFields(_) => { + AdtExprBase::DefaultFields( + self.typeck_results().fru_field_types()[expr.hir_id] + .iter() + .copied() + .collect(), + ) + } + hir::StructTailExpr::None => AdtExprBase::None, + }, })) } AdtKind::Enum => { let res = self.typeck_results().qpath_res(qpath, expr.hir_id); match res { Res::Def(DefKind::Variant, variant_id) => { - assert!(base.is_none()); + assert!(matches!( + base, + hir::StructTailExpr::None + | hir::StructTailExpr::DefaultFields(_) + )); let index = adt.variant_index_with_id(variant_id); let user_provided_types = @@ -621,7 +637,21 @@ impl<'tcx> Cx<'tcx> { args, user_ty, fields: self.field_refs(fields), - base: None, + base: match base { + hir::StructTailExpr::DefaultFields(_) => { + AdtExprBase::DefaultFields( + self.typeck_results().fru_field_types() + [expr.hir_id] + .iter() + .copied() + .collect(), + ) + } + hir::StructTailExpr::Base(base) => { + span_bug!(base.span, "unexpected res: {:?}", res); + } + hir::StructTailExpr::None => AdtExprBase::None, + }, })) } _ => { @@ -1029,7 +1059,7 @@ impl<'tcx> Cx<'tcx> { args, user_ty, fields: Box::new([]), - base: None, + base: AdtExprBase::None, })), _ => bug!("unexpected ty: {:?}", ty), } diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs index 6be0ed5fb31..2bcdb67c58a 100644 --- a/compiler/rustc_mir_build/src/thir/print.rs +++ b/compiler/rustc_mir_build/src/thir/print.rs @@ -566,11 +566,17 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> { self.print_expr(field_expr.expr, depth_lvl + 2); } - if let Some(ref base) = adt_expr.base { - print_indented!(self, "base:", depth_lvl + 1); - self.print_fru_info(base, depth_lvl + 2); - } else { - print_indented!(self, "base: None", depth_lvl + 1); + match adt_expr.base { + AdtExprBase::Base(ref base) => { + print_indented!(self, "base:", depth_lvl + 1); + self.print_fru_info(base, depth_lvl + 2); + } + AdtExprBase::DefaultFields(_) => { + print_indented!(self, "base: {{ defaulted fields }}", depth_lvl + 1); + } + AdtExprBase::None => { + print_indented!(self, "base: None", depth_lvl + 1); + } } } diff --git a/compiler/rustc_mir_dataflow/src/framework/fmt.rs b/compiler/rustc_mir_dataflow/src/framework/fmt.rs index dc176ba2d03..faf2c411dde 100644 --- a/compiler/rustc_mir_dataflow/src/framework/fmt.rs +++ b/compiler/rustc_mir_dataflow/src/framework/fmt.rs @@ -4,7 +4,7 @@ use std::fmt; use rustc_index::Idx; -use rustc_index::bit_set::{BitSet, ChunkedBitSet}; +use rustc_index::bit_set::{BitSet, ChunkedBitSet, MixedBitSet}; use super::lattice::MaybeReachable; @@ -85,8 +85,8 @@ where let size = self.domain_size(); assert_eq!(size, old.domain_size()); - let mut set_in_self = ChunkedBitSet::new_empty(size); - let mut cleared_in_self = ChunkedBitSet::new_empty(size); + let mut set_in_self = MixedBitSet::new_empty(size); + let mut cleared_in_self = MixedBitSet::new_empty(size); for i in (0..size).map(T::new) { match (self.contains(i), old.contains(i)) { @@ -112,8 +112,8 @@ where let size = self.domain_size(); assert_eq!(size, old.domain_size()); - let mut set_in_self = ChunkedBitSet::new_empty(size); - let mut cleared_in_self = ChunkedBitSet::new_empty(size); + let mut set_in_self = MixedBitSet::new_empty(size); + let mut cleared_in_self = MixedBitSet::new_empty(size); for i in (0..size).map(T::new) { match (self.contains(i), old.contains(i)) { @@ -127,6 +127,26 @@ where } } +impl<T, C> DebugWithContext<C> for MixedBitSet<T> +where + T: Idx + DebugWithContext<C>, +{ + fn fmt_with(&self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + MixedBitSet::Small(set) => set.fmt_with(ctxt, f), + MixedBitSet::Large(set) => set.fmt_with(ctxt, f), + } + } + + fn fmt_diff_with(&self, old: &Self, ctxt: &C, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match (self, old) { + (MixedBitSet::Small(set), MixedBitSet::Small(old)) => set.fmt_diff_with(old, ctxt, f), + (MixedBitSet::Large(set), MixedBitSet::Large(old)) => set.fmt_diff_with(old, ctxt, f), + _ => panic!("MixedBitSet size mismatch"), + } + } +} + impl<S, C> DebugWithContext<C> for MaybeReachable<S> where S: DebugWithContext<C>, @@ -159,8 +179,8 @@ where } fn fmt_diff<T, C>( - inserted: &ChunkedBitSet<T>, - removed: &ChunkedBitSet<T>, + inserted: &MixedBitSet<T>, + removed: &MixedBitSet<T>, ctxt: &C, f: &mut fmt::Formatter<'_>, ) -> fmt::Result diff --git a/compiler/rustc_mir_dataflow/src/framework/lattice.rs b/compiler/rustc_mir_dataflow/src/framework/lattice.rs index e2b56aedca3..e063eaf74bd 100644 --- a/compiler/rustc_mir_dataflow/src/framework/lattice.rs +++ b/compiler/rustc_mir_dataflow/src/framework/lattice.rs @@ -40,7 +40,7 @@ use std::iter; -use rustc_index::bit_set::{BitSet, ChunkedBitSet}; +use rustc_index::bit_set::{BitSet, MixedBitSet}; use rustc_index::{Idx, IndexVec}; use crate::framework::BitSetExt; @@ -126,7 +126,7 @@ impl<T: Idx> JoinSemiLattice for BitSet<T> { } } -impl<T: Idx> JoinSemiLattice for ChunkedBitSet<T> { +impl<T: Idx> JoinSemiLattice for MixedBitSet<T> { fn join(&mut self, other: &Self) -> bool { self.union(other) } diff --git a/compiler/rustc_mir_dataflow/src/framework/mod.rs b/compiler/rustc_mir_dataflow/src/framework/mod.rs index 13384d6f285..7f5a68e884e 100644 --- a/compiler/rustc_mir_dataflow/src/framework/mod.rs +++ b/compiler/rustc_mir_dataflow/src/framework/mod.rs @@ -35,7 +35,7 @@ use std::cmp::Ordering; use rustc_data_structures::work_queue::WorkQueue; -use rustc_index::bit_set::{BitSet, ChunkedBitSet}; +use rustc_index::bit_set::{BitSet, MixedBitSet}; use rustc_index::{Idx, IndexVec}; use rustc_middle::bug; use rustc_middle::mir::{self, BasicBlock, CallReturnPlaces, Location, TerminatorEdges, traversal}; @@ -71,7 +71,7 @@ impl<T: Idx> BitSetExt<T> for BitSet<T> { } } -impl<T: Idx> BitSetExt<T> for ChunkedBitSet<T> { +impl<T: Idx> BitSetExt<T> for MixedBitSet<T> { fn contains(&self, elem: T) -> bool { self.contains(elem) } @@ -327,7 +327,7 @@ impl<T: Idx> GenKill<T> for BitSet<T> { } } -impl<T: Idx> GenKill<T> for ChunkedBitSet<T> { +impl<T: Idx> GenKill<T> for MixedBitSet<T> { fn gen_(&mut self, elem: T) { self.insert(elem); } diff --git a/compiler/rustc_mir_dataflow/src/impls/initialized.rs b/compiler/rustc_mir_dataflow/src/impls/initialized.rs index 2c10d4b1cd3..91677657602 100644 --- a/compiler/rustc_mir_dataflow/src/impls/initialized.rs +++ b/compiler/rustc_mir_dataflow/src/impls/initialized.rs @@ -1,7 +1,7 @@ use std::assert_matches::assert_matches; use rustc_index::Idx; -use rustc_index::bit_set::{BitSet, ChunkedBitSet}; +use rustc_index::bit_set::{BitSet, MixedBitSet}; use rustc_middle::bug; use rustc_middle::mir::{self, Body, CallReturnPlaces, Location, TerminatorEdges}; use rustc_middle::ty::{self, TyCtxt}; @@ -70,7 +70,7 @@ impl<'a, 'tcx> MaybeInitializedPlaces<'a, 'tcx> { pub fn is_unwind_dead( &self, place: mir::Place<'tcx>, - state: &MaybeReachable<ChunkedBitSet<MovePathIndex>>, + state: &MaybeReachable<MixedBitSet<MovePathIndex>>, ) -> bool { if let LookupResult::Exact(path) = self.move_data().rev_lookup.find(place.as_ref()) { let mut maybe_live = false; @@ -244,8 +244,8 @@ impl<'tcx> MaybeUninitializedPlaces<'_, 'tcx> { impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { /// There can be many more `MovePathIndex` than there are locals in a MIR body. - /// We use a chunked bitset to avoid paying too high a memory footprint. - type Domain = MaybeReachable<ChunkedBitSet<MovePathIndex>>; + /// We use a mixed bitset to avoid paying too high a memory footprint. + type Domain = MaybeReachable<MixedBitSet<MovePathIndex>>; const NAME: &'static str = "maybe_init"; @@ -256,7 +256,7 @@ impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { fn initialize_start_block(&self, _: &mir::Body<'tcx>, state: &mut Self::Domain) { *state = - MaybeReachable::Reachable(ChunkedBitSet::new_empty(self.move_data().move_paths.len())); + MaybeReachable::Reachable(MixedBitSet::new_empty(self.move_data().move_paths.len())); drop_flag_effects_for_function_entry(self.body, self.move_data, |path, s| { assert!(s == DropFlagState::Present); state.gen_(path); @@ -371,14 +371,14 @@ impl<'tcx> Analysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { /// There can be many more `MovePathIndex` than there are locals in a MIR body. - /// We use a chunked bitset to avoid paying too high a memory footprint. - type Domain = ChunkedBitSet<MovePathIndex>; + /// We use a mixed bitset to avoid paying too high a memory footprint. + type Domain = MixedBitSet<MovePathIndex>; const NAME: &'static str = "maybe_uninit"; fn bottom_value(&self, _: &mir::Body<'tcx>) -> Self::Domain { // bottom = initialized (start_block_effect counters this at outset) - ChunkedBitSet::new_empty(self.move_data().move_paths.len()) + MixedBitSet::new_empty(self.move_data().move_paths.len()) } // sets on_entry bits for Arg places @@ -492,14 +492,14 @@ impl<'tcx> Analysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { impl<'tcx> Analysis<'tcx> for EverInitializedPlaces<'_, 'tcx> { /// There can be many more `InitIndex` than there are locals in a MIR body. - /// We use a chunked bitset to avoid paying too high a memory footprint. - type Domain = ChunkedBitSet<InitIndex>; + /// We use a mixed bitset to avoid paying too high a memory footprint. + type Domain = MixedBitSet<InitIndex>; const NAME: &'static str = "ever_init"; fn bottom_value(&self, _: &mir::Body<'tcx>) -> Self::Domain { // bottom = no initialized variables by default - ChunkedBitSet::new_empty(self.move_data().inits.len()) + MixedBitSet::new_empty(self.move_data().inits.len()) } fn initialize_start_block(&self, body: &mir::Body<'tcx>, state: &mut Self::Domain) { diff --git a/compiler/rustc_mir_transform/src/coverage/counters.rs b/compiler/rustc_mir_transform/src/coverage/counters.rs index 46efdd16ee8..9e80f1f1c4a 100644 --- a/compiler/rustc_mir_transform/src/coverage/counters.rs +++ b/compiler/rustc_mir_transform/src/coverage/counters.rs @@ -9,7 +9,7 @@ use rustc_index::bit_set::BitSet; use rustc_middle::mir::coverage::{CounterId, CovTerm, Expression, ExpressionId, Op}; use tracing::{debug, debug_span, instrument}; -use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph, TraverseCoverageGraphWithLoops}; +use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph, ReadyFirstTraversal}; #[cfg(test)] mod tests; @@ -236,23 +236,12 @@ impl<'a> CountersBuilder<'a> { // Traverse the coverage graph, ensuring that every node that needs a // coverage counter has one. - // - // The traversal tries to ensure that, when a loop is encountered, all - // nodes within the loop are visited before visiting any nodes outside - // the loop. - let mut traversal = TraverseCoverageGraphWithLoops::new(self.graph); - while let Some(bcb) = traversal.next() { + for bcb in ReadyFirstTraversal::new(self.graph) { let _span = debug_span!("traversal", ?bcb).entered(); if self.bcb_needs_counter.contains(bcb) { self.make_node_counter_and_out_edge_counters(bcb); } } - - assert!( - traversal.is_complete(), - "`TraverseCoverageGraphWithLoops` missed some `BasicCoverageBlock`s: {:?}", - traversal.unvisited(), - ); } /// Make sure the given node has a node counter, and then make sure each of diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs index 092bce1de2c..ad6774fccd6 100644 --- a/compiler/rustc_mir_transform/src/coverage/graph.rs +++ b/compiler/rustc_mir_transform/src/coverage/graph.rs @@ -9,7 +9,6 @@ use rustc_data_structures::graph::dominators::Dominators; use rustc_data_structures::graph::{self, DirectedGraph, StartNode}; use rustc_index::IndexVec; use rustc_index::bit_set::BitSet; -use rustc_middle::bug; use rustc_middle::mir::{self, BasicBlock, Terminator, TerminatorKind}; use tracing::debug; @@ -462,138 +461,6 @@ fn bcb_filtered_successors<'a, 'tcx>(terminator: &'a Terminator<'tcx>) -> Covera CoverageSuccessors { targets, is_yield } } -/// Maintains separate worklists for each loop in the BasicCoverageBlock CFG, plus one for the -/// CoverageGraph outside all loops. This supports traversing the BCB CFG in a way that -/// ensures a loop is completely traversed before processing Blocks after the end of the loop. -#[derive(Debug)] -struct TraversalContext { - /// BCB with one or more incoming loop backedges, indicating which loop - /// this context is for. - /// - /// If `None`, this is the non-loop context for the function as a whole. - loop_header: Option<BasicCoverageBlock>, - - /// Worklist of BCBs to be processed in this context. - worklist: VecDeque<BasicCoverageBlock>, -} - -pub(crate) struct TraverseCoverageGraphWithLoops<'a> { - basic_coverage_blocks: &'a CoverageGraph, - - context_stack: Vec<TraversalContext>, - visited: BitSet<BasicCoverageBlock>, -} - -impl<'a> TraverseCoverageGraphWithLoops<'a> { - pub(crate) fn new(basic_coverage_blocks: &'a CoverageGraph) -> Self { - let worklist = VecDeque::from([basic_coverage_blocks.start_node()]); - let context_stack = vec![TraversalContext { loop_header: None, worklist }]; - - // `context_stack` starts with a `TraversalContext` for the main function context (beginning - // with the `start` BasicCoverageBlock of the function). New worklists are pushed to the top - // of the stack as loops are entered, and popped off of the stack when a loop's worklist is - // exhausted. - let visited = BitSet::new_empty(basic_coverage_blocks.num_nodes()); - Self { basic_coverage_blocks, context_stack, visited } - } - - pub(crate) fn next(&mut self) -> Option<BasicCoverageBlock> { - debug!( - "TraverseCoverageGraphWithLoops::next - context_stack: {:?}", - self.context_stack.iter().rev().collect::<Vec<_>>() - ); - - while let Some(context) = self.context_stack.last_mut() { - let Some(bcb) = context.worklist.pop_front() else { - // This stack level is exhausted; pop it and try the next one. - self.context_stack.pop(); - continue; - }; - - if !self.visited.insert(bcb) { - debug!("Already visited: {bcb:?}"); - continue; - } - debug!("Visiting {bcb:?}"); - - if self.basic_coverage_blocks.is_loop_header.contains(bcb) { - debug!("{bcb:?} is a loop header! Start a new TraversalContext..."); - self.context_stack - .push(TraversalContext { loop_header: Some(bcb), worklist: VecDeque::new() }); - } - self.add_successors_to_worklists(bcb); - return Some(bcb); - } - - None - } - - fn add_successors_to_worklists(&mut self, bcb: BasicCoverageBlock) { - let successors = &self.basic_coverage_blocks.successors[bcb]; - debug!("{:?} has {} successors:", bcb, successors.len()); - - for &successor in successors { - if successor == bcb { - debug!( - "{:?} has itself as its own successor. (Note, the compiled code will \ - generate an infinite loop.)", - bcb - ); - // Don't re-add this successor to the worklist. We are already processing it. - // FIXME: This claims to skip just the self-successor, but it actually skips - // all other successors as well. Does that matter? - break; - } - - // Add successors of the current BCB to the appropriate context. Successors that - // stay within a loop are added to the BCBs context worklist. Successors that - // exit the loop (they are not dominated by the loop header) must be reachable - // from other BCBs outside the loop, and they will be added to a different - // worklist. - // - // Branching blocks (with more than one successor) must be processed before - // blocks with only one successor, to prevent unnecessarily complicating - // `Expression`s by creating a Counter in a `BasicCoverageBlock` that the - // branching block would have given an `Expression` (or vice versa). - - let context = self - .context_stack - .iter_mut() - .rev() - .find(|context| match context.loop_header { - Some(loop_header) => { - self.basic_coverage_blocks.dominates(loop_header, successor) - } - None => true, - }) - .unwrap_or_else(|| bug!("should always fall back to the root non-loop context")); - debug!("adding to worklist for {:?}", context.loop_header); - - // FIXME: The code below had debug messages claiming to add items to a - // particular end of the worklist, but was confused about which end was - // which. The existing behaviour has been preserved for now, but it's - // unclear what the intended behaviour was. - - if self.basic_coverage_blocks.successors[successor].len() > 1 { - context.worklist.push_back(successor); - } else { - context.worklist.push_front(successor); - } - } - } - - pub(crate) fn is_complete(&self) -> bool { - self.visited.count() == self.visited.domain_size() - } - - pub(crate) fn unvisited(&self) -> Vec<BasicCoverageBlock> { - let mut unvisited_set: BitSet<BasicCoverageBlock> = - BitSet::new_filled(self.visited.domain_size()); - unvisited_set.subtract(&self.visited); - unvisited_set.iter().collect::<Vec<_>>() - } -} - /// Wrapper around a [`mir::BasicBlocks`] graph that restricts each node's /// successors to only the ones considered "relevant" when building a coverage /// graph. @@ -622,3 +489,126 @@ impl<'a, 'tcx> graph::Successors for CoverageRelevantSubgraph<'a, 'tcx> { self.coverage_successors(bb).into_iter() } } + +/// State of a node in the coverage graph during ready-first traversal. +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] +enum ReadyState { + /// This node has not yet been added to the fallback queue or ready queue. + Unqueued, + /// This node is currently in the fallback queue. + InFallbackQueue, + /// This node's predecessors have all been visited, so it is in the ready queue. + /// (It might also have a stale entry in the fallback queue.) + InReadyQueue, + /// This node has been visited. + /// (It might also have a stale entry in the fallback queue.) + Visited, +} + +/// Iterator that visits nodes in the coverage graph, in an order that always +/// prefers "ready" nodes whose predecessors have already been visited. +pub(crate) struct ReadyFirstTraversal<'a> { + graph: &'a CoverageGraph, + + /// For each node, the number of its predecessor nodes that haven't been visited yet. + n_unvisited_preds: IndexVec<BasicCoverageBlock, u32>, + /// Indicates whether a node has been visited, or which queue it is in. + state: IndexVec<BasicCoverageBlock, ReadyState>, + + /// Holds unvisited nodes whose predecessors have all been visited. + ready_queue: VecDeque<BasicCoverageBlock>, + /// Holds unvisited nodes with some unvisited predecessors. + /// Also contains stale entries for nodes that were upgraded to ready. + fallback_queue: VecDeque<BasicCoverageBlock>, +} + +impl<'a> ReadyFirstTraversal<'a> { + pub(crate) fn new(graph: &'a CoverageGraph) -> Self { + let num_nodes = graph.num_nodes(); + + let n_unvisited_preds = + IndexVec::from_fn_n(|node| graph.predecessors[node].len() as u32, num_nodes); + let mut state = IndexVec::from_elem_n(ReadyState::Unqueued, num_nodes); + + // We know from coverage graph construction that the start node is the + // only node with no predecessors. + debug_assert!( + n_unvisited_preds.iter_enumerated().all(|(node, &n)| (node == START_BCB) == (n == 0)) + ); + let ready_queue = VecDeque::from(vec![START_BCB]); + state[START_BCB] = ReadyState::InReadyQueue; + + Self { graph, state, n_unvisited_preds, ready_queue, fallback_queue: VecDeque::new() } + } + + /// Returns the next node from the ready queue, or else the next unvisited + /// node from the fallback queue. + fn next_inner(&mut self) -> Option<BasicCoverageBlock> { + // Always prefer to yield a ready node if possible. + if let Some(node) = self.ready_queue.pop_front() { + assert_eq!(self.state[node], ReadyState::InReadyQueue); + return Some(node); + } + + while let Some(node) = self.fallback_queue.pop_front() { + match self.state[node] { + // This entry in the fallback queue is not stale, so yield it. + ReadyState::InFallbackQueue => return Some(node), + // This node was added to the fallback queue, but later became + // ready and was visited via the ready queue. Ignore it here. + ReadyState::Visited => {} + // Unqueued nodes can't be in the fallback queue, by definition. + // We know that the ready queue is empty at this point. + ReadyState::Unqueued | ReadyState::InReadyQueue => unreachable!( + "unexpected state for {node:?} in the fallback queue: {:?}", + self.state[node] + ), + } + } + + None + } + + fn mark_visited_and_enqueue_successors(&mut self, node: BasicCoverageBlock) { + assert!(self.state[node] < ReadyState::Visited); + self.state[node] = ReadyState::Visited; + + // For each of this node's successors, decrease the successor's + // "unvisited predecessors" count, and enqueue it if appropriate. + for &succ in &self.graph.successors[node] { + let is_unqueued = match self.state[succ] { + ReadyState::Unqueued => true, + ReadyState::InFallbackQueue => false, + ReadyState::InReadyQueue => { + unreachable!("nodes in the ready queue have no unvisited predecessors") + } + // The successor was already visited via one of its other predecessors. + ReadyState::Visited => continue, + }; + + self.n_unvisited_preds[succ] -= 1; + if self.n_unvisited_preds[succ] == 0 { + // This node's predecessors have all been visited, so add it to + // the ready queue. If it's already in the fallback queue, that + // fallback entry will be ignored later. + self.state[succ] = ReadyState::InReadyQueue; + self.ready_queue.push_back(succ); + } else if is_unqueued { + // This node has unvisited predecessors, so add it to the + // fallback queue in case we run out of ready nodes later. + self.state[succ] = ReadyState::InFallbackQueue; + self.fallback_queue.push_back(succ); + } + } + } +} + +impl<'a> Iterator for ReadyFirstTraversal<'a> { + type Item = BasicCoverageBlock; + + fn next(&mut self) -> Option<Self::Item> { + let node = self.next_inner()?; + self.mark_visited_and_enqueue_successors(node); + Some(node) + } +} diff --git a/compiler/rustc_mir_transform/src/coverage/query.rs b/compiler/rustc_mir_transform/src/coverage/query.rs index 0090f6f3040..edaec3c7965 100644 --- a/compiler/rustc_mir_transform/src/coverage/query.rs +++ b/compiler/rustc_mir_transform/src/coverage/query.rs @@ -1,8 +1,11 @@ use rustc_data_structures::captures::Captures; use rustc_index::bit_set::BitSet; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; -use rustc_middle::mir::coverage::{CovTerm, CoverageKind, MappingKind}; -use rustc_middle::mir::{Body, CoverageIdsInfo, Statement, StatementKind}; +use rustc_middle::mir::coverage::{ + CounterId, CovTerm, CoverageIdsInfo, CoverageKind, Expression, ExpressionId, + FunctionCoverageInfo, MappingKind, Op, +}; +use rustc_middle::mir::{Body, Statement, StatementKind}; use rustc_middle::query::TyCtxtAt; use rustc_middle::ty::{self, TyCtxt}; use rustc_middle::util::Providers; @@ -87,10 +90,10 @@ fn coverage_ids_info<'tcx>( ) -> CoverageIdsInfo { let mir_body = tcx.instance_mir(instance_def); - let Some(fn_cov_info) = mir_body.function_coverage_info.as_ref() else { + let Some(fn_cov_info) = mir_body.function_coverage_info.as_deref() else { return CoverageIdsInfo { counters_seen: BitSet::new_empty(0), - expressions_seen: BitSet::new_empty(0), + zero_expressions: BitSet::new_empty(0), }; }; @@ -123,7 +126,10 @@ fn coverage_ids_info<'tcx>( } } - CoverageIdsInfo { counters_seen, expressions_seen } + let zero_expressions = + identify_zero_expressions(fn_cov_info, &counters_seen, &expressions_seen); + + CoverageIdsInfo { counters_seen, zero_expressions } } fn all_coverage_in_mir_body<'a, 'tcx>( @@ -141,3 +147,94 @@ fn is_inlined(body: &Body<'_>, statement: &Statement<'_>) -> bool { let scope_data = &body.source_scopes[statement.source_info.scope]; scope_data.inlined.is_some() || scope_data.inlined_parent_scope.is_some() } + +/// Identify expressions that will always have a value of zero, and note +/// their IDs in a `BitSet`. Mappings that refer to a zero expression +/// can instead become mappings to a constant zero value. +/// +/// This function mainly exists to preserve the simplifications that were +/// already being performed by the Rust-side expression renumbering, so that +/// the resulting coverage mappings don't get worse. +fn identify_zero_expressions( + fn_cov_info: &FunctionCoverageInfo, + counters_seen: &BitSet<CounterId>, + expressions_seen: &BitSet<ExpressionId>, +) -> BitSet<ExpressionId> { + // The set of expressions that either were optimized out entirely, or + // have zero as both of their operands, and will therefore always have + // a value of zero. Other expressions that refer to these as operands + // can have those operands replaced with `CovTerm::Zero`. + let mut zero_expressions = BitSet::new_empty(fn_cov_info.expressions.len()); + + // Simplify a copy of each expression based on lower-numbered expressions, + // and then update the set of always-zero expressions if necessary. + // (By construction, expressions can only refer to other expressions + // that have lower IDs, so one pass is sufficient.) + for (id, expression) in fn_cov_info.expressions.iter_enumerated() { + if !expressions_seen.contains(id) { + // If an expression was not seen, it must have been optimized away, + // so any operand that refers to it can be replaced with zero. + zero_expressions.insert(id); + continue; + } + + // We don't need to simplify the actual expression data in the + // expressions list; we can just simplify a temporary copy and then + // use that to update the set of always-zero expressions. + let Expression { mut lhs, op, mut rhs } = *expression; + + // If an expression has an operand that is also an expression, the + // operand's ID must be strictly lower. This is what lets us find + // all zero expressions in one pass. + let assert_operand_expression_is_lower = |operand_id: ExpressionId| { + assert!( + operand_id < id, + "Operand {operand_id:?} should be less than {id:?} in {expression:?}", + ) + }; + + // If an operand refers to a counter or expression that is always + // zero, then that operand can be replaced with `CovTerm::Zero`. + let maybe_set_operand_to_zero = |operand: &mut CovTerm| { + if let CovTerm::Expression(id) = *operand { + assert_operand_expression_is_lower(id); + } + + if is_zero_term(&counters_seen, &zero_expressions, *operand) { + *operand = CovTerm::Zero; + } + }; + maybe_set_operand_to_zero(&mut lhs); + maybe_set_operand_to_zero(&mut rhs); + + // Coverage counter values cannot be negative, so if an expression + // involves subtraction from zero, assume that its RHS must also be zero. + // (Do this after simplifications that could set the LHS to zero.) + if lhs == CovTerm::Zero && op == Op::Subtract { + rhs = CovTerm::Zero; + } + + // After the above simplifications, if both operands are zero, then + // we know that this expression is always zero too. + if lhs == CovTerm::Zero && rhs == CovTerm::Zero { + zero_expressions.insert(id); + } + } + + zero_expressions +} + +/// Returns `true` if the given term is known to have a value of zero, taking +/// into account knowledge of which counters are unused and which expressions +/// are always zero. +fn is_zero_term( + counters_seen: &BitSet<CounterId>, + zero_expressions: &BitSet<ExpressionId>, + term: CovTerm, +) -> bool { + match term { + CovTerm::Zero => true, + CovTerm::Counter(id) => !counters_seen.contains(id), + CovTerm::Expression(id) => zero_expressions.contains(id), + } +} diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index d017202f48b..b94c925b1db 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -534,8 +534,13 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { // This allows the set of visited edges to grow monotonically with the lattice. FlatSet::Bottom => TerminatorEdges::None, FlatSet::Elem(scalar) => { - let choice = scalar.assert_scalar_int().to_bits_unchecked(); - TerminatorEdges::Single(targets.target_for_value(choice)) + if let Ok(scalar_int) = scalar.try_to_scalar_int() { + TerminatorEdges::Single( + targets.target_for_value(scalar_int.to_bits_unchecked()), + ) + } else { + TerminatorEdges::SwitchInt { discr, targets } + } } FlatSet::Top => TerminatorEdges::SwitchInt { discr, targets }, } diff --git a/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs b/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs index 732a9cd9890..7fb421dea0c 100644 --- a/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs +++ b/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs @@ -7,7 +7,7 @@ use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_errors::Subdiagnostic; use rustc_hir::CRATE_HIR_ID; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_index::bit_set::ChunkedBitSet; +use rustc_index::bit_set::MixedBitSet; use rustc_index::{IndexSlice, IndexVec}; use rustc_macros::{LintDiagnostic, Subdiagnostic}; use rustc_middle::bug; @@ -49,24 +49,24 @@ struct DropsReachable<'a, 'mir, 'tcx> { move_data: &'a MoveData<'tcx>, maybe_init: &'a mut ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'mir, 'tcx>>, block_drop_value_info: &'a mut IndexSlice<BasicBlock, MovePathIndexAtBlock>, - collected_drops: &'a mut ChunkedBitSet<MovePathIndex>, - visited: FxHashMap<BasicBlock, Rc<RefCell<ChunkedBitSet<MovePathIndex>>>>, + collected_drops: &'a mut MixedBitSet<MovePathIndex>, + visited: FxHashMap<BasicBlock, Rc<RefCell<MixedBitSet<MovePathIndex>>>>, } impl<'a, 'mir, 'tcx> DropsReachable<'a, 'mir, 'tcx> { fn visit(&mut self, block: BasicBlock) { let move_set_size = self.move_data.move_paths.len(); - let make_new_path_set = || Rc::new(RefCell::new(ChunkedBitSet::new_empty(move_set_size))); + let make_new_path_set = || Rc::new(RefCell::new(MixedBitSet::new_empty(move_set_size))); let data = &self.body.basic_blocks[block]; let Some(terminator) = &data.terminator else { return }; - // Given that we observe these dropped locals here at `block` so far, - // we will try to update the successor blocks. - // An occupied entry at `block` in `self.visited` signals that we have visited `block` before. + // Given that we observe these dropped locals here at `block` so far, we will try to update + // the successor blocks. An occupied entry at `block` in `self.visited` signals that we + // have visited `block` before. let dropped_local_here = Rc::clone(self.visited.entry(block).or_insert_with(make_new_path_set)); - // We could have invoked reverse lookup for a `MovePathIndex` every time, but unfortunately it is expensive. - // Let's cache them in `self.block_drop_value_info`. + // We could have invoked reverse lookup for a `MovePathIndex` every time, but unfortunately + // it is expensive. Let's cache them in `self.block_drop_value_info`. match self.block_drop_value_info[block] { MovePathIndexAtBlock::Some(dropped) => { dropped_local_here.borrow_mut().insert(dropped); @@ -76,23 +76,24 @@ impl<'a, 'mir, 'tcx> DropsReachable<'a, 'mir, 'tcx> { && let LookupResult::Exact(idx) | LookupResult::Parent(Some(idx)) = self.move_data.rev_lookup.find(place.as_ref()) { - // Since we are working with MIRs at a very early stage, - // observing a `drop` terminator is not indicative enough that - // the drop will definitely happen. - // That is decided in the drop elaboration pass instead. - // Therefore, we need to consult with the maybe-initialization information. + // Since we are working with MIRs at a very early stage, observing a `drop` + // terminator is not indicative enough that the drop will definitely happen. + // That is decided in the drop elaboration pass instead. Therefore, we need to + // consult with the maybe-initialization information. self.maybe_init.seek_before_primary_effect(Location { block, statement_index: data.statements.len(), }); - // Check if the drop of `place` under inspection is really in effect. - // This is true only when `place` may have been initialized along a control flow path from a BID to the drop program point today. - // In other words, this is where the drop of `place` will happen in the future instead. + // Check if the drop of `place` under inspection is really in effect. This is + // true only when `place` may have been initialized along a control flow path + // from a BID to the drop program point today. In other words, this is where + // the drop of `place` will happen in the future instead. if let MaybeReachable::Reachable(maybe_init) = self.maybe_init.get() && maybe_init.contains(idx) { - // We also cache the drop information, so that we do not need to check on data-flow cursor again + // We also cache the drop information, so that we do not need to check on + // data-flow cursor again. self.block_drop_value_info[block] = MovePathIndexAtBlock::Some(idx); dropped_local_here.borrow_mut().insert(idx); } else { @@ -139,8 +140,9 @@ impl<'a, 'mir, 'tcx> DropsReachable<'a, 'mir, 'tcx> { // Let's check the observed dropped places in. self.collected_drops.union(&*dropped_local_there.borrow()); if self.drop_span.is_none() { - // FIXME(@dingxiangfei2009): it turns out that `self.body.source_scopes` are still a bit wonky. - // There is a high chance that this span still points to a block rather than a statement semicolon. + // FIXME(@dingxiangfei2009): it turns out that `self.body.source_scopes` are + // still a bit wonky. There is a high chance that this span still points to a + // block rather than a statement semicolon. *self.drop_span = Some(terminator.source_info.span); } // Now we have discovered a simple control flow path from a future drop point @@ -394,10 +396,10 @@ pub(crate) fn run_lint<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &Body< for (&block, candidates) in &bid_per_block { // We will collect drops on locals on paths between BID points to their actual drop locations // into `all_locals_dropped`. - let mut all_locals_dropped = ChunkedBitSet::new_empty(move_data.move_paths.len()); + let mut all_locals_dropped = MixedBitSet::new_empty(move_data.move_paths.len()); let mut drop_span = None; for &(_, place) in candidates.iter() { - let mut collected_drops = ChunkedBitSet::new_empty(move_data.move_paths.len()); + let mut collected_drops = MixedBitSet::new_empty(move_data.move_paths.len()); // ## On detecting change in relative drop order ## // Iterate through each BID-containing block `block`. // If the place `P` targeted by the BID is "maybe initialized", @@ -425,8 +427,9 @@ pub(crate) fn run_lint<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &Body< // We shall now exclude some local bindings for the following cases. { - let mut to_exclude = ChunkedBitSet::new_empty(all_locals_dropped.domain_size()); - // We will now do subtraction from the candidate dropped locals, because of the following reasons. + let mut to_exclude = MixedBitSet::new_empty(all_locals_dropped.domain_size()); + // We will now do subtraction from the candidate dropped locals, because of the + // following reasons. for path_idx in all_locals_dropped.iter() { let move_path = &move_data.move_paths[path_idx]; let dropped_local = move_path.place.local; diff --git a/compiler/rustc_mir_transform/src/remove_uninit_drops.rs b/compiler/rustc_mir_transform/src/remove_uninit_drops.rs index f786c676e9e..e955d8277a4 100644 --- a/compiler/rustc_mir_transform/src/remove_uninit_drops.rs +++ b/compiler/rustc_mir_transform/src/remove_uninit_drops.rs @@ -1,5 +1,5 @@ use rustc_abi::FieldIdx; -use rustc_index::bit_set::ChunkedBitSet; +use rustc_index::bit_set::MixedBitSet; use rustc_middle::mir::{Body, TerminatorKind}; use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, VariantDef}; use rustc_mir_dataflow::impls::MaybeInitializedPlaces; @@ -67,7 +67,7 @@ impl<'tcx> crate::MirPass<'tcx> for RemoveUninitDrops { fn is_needs_drop_and_init<'tcx>( tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>, - maybe_inits: &ChunkedBitSet<MovePathIndex>, + maybe_inits: &MixedBitSet<MovePathIndex>, move_data: &MoveData<'tcx>, ty: Ty<'tcx>, mpi: MovePathIndex, diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs index f5b1b23b8e9..63dbee2640b 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs @@ -144,7 +144,7 @@ where then: impl FnOnce(&mut EvalCtxt<'_, D>) -> QueryResult<I>, ) -> Result<Candidate<I>, NoSolution> { if let Some(projection_pred) = assumption.as_projection_clause() { - if projection_pred.projection_def_id() == goal.predicate.def_id() { + if projection_pred.item_def_id() == goal.predicate.def_id() { let cx = ecx.cx(); if !DeepRejectCtxt::relate_rigid_rigid(ecx.cx()).args_may_unify( goal.predicate.alias.args, diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index e5cd4622dae..d50bd18a1d7 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -169,9 +169,6 @@ parse_enum_struct_mutually_exclusive = `enum` and `struct` are mutually exclusiv parse_eq_field_init = expected `:`, found `=` .suggestion = replace equals symbol with a colon -parse_equals_struct_default = default values on `struct` fields aren't supported - .suggestion = remove this unsupported default value - parse_escape_only_char = {$byte -> [true] byte *[false] character diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 14f2dd32e92..4c4e03cdfa3 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -3067,14 +3067,6 @@ pub(crate) struct SingleColonStructType { } #[derive(Diagnostic)] -#[diag(parse_equals_struct_default)] -pub(crate) struct EqualsStructDefault { - #[primary_span] - #[suggestion(code = "", applicability = "machine-applicable", style = "verbose")] - pub span: Span, -} - -#[derive(Diagnostic)] #[diag(parse_macro_rules_missing_bang)] pub(crate) struct MacroRulesMissingBang { #[primary_span] diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index d97f05dc7eb..2426eb81678 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -822,7 +822,7 @@ impl<'psess, 'src> Lexer<'psess, 'src> { /// Detect guarded string literal syntax /// - /// RFC 3598 reserved this syntax for future use. As of Rust 2024, + /// RFC 3593 reserved this syntax for future use. As of Rust 2024, /// using this syntax produces an error. In earlier editions, however, it /// only results in an (allowed by default) lint, and is treated as /// separate tokens. diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index 2792050a0b3..f963a424a7f 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -24,6 +24,7 @@ use rustc_data_structures::sync::Lrc; use rustc_errors::{Diag, FatalError, PResult}; use rustc_session::parse::ParseSess; use rustc_span::{FileName, SourceFile, Span}; +pub use unicode_normalization::UNICODE_VERSION as UNICODE_NORMALIZATION_VERSION; pub const MACRO_ARGUMENTS: Option<&str> = Some("macro arguments"); diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 3a9e9b480ec..eeb83a85e59 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -3533,7 +3533,7 @@ impl<'a> Parser<'a> { let exp_span = self.prev_token.span; // We permit `.. }` on the left-hand side of a destructuring assignment. if self.check(&token::CloseDelim(close_delim)) { - base = ast::StructRest::Rest(self.prev_token.span.shrink_to_hi()); + base = ast::StructRest::Rest(self.prev_token.span); break; } match self.parse_expr() { diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 475cd09147f..58b4bf8980b 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1836,6 +1836,22 @@ impl<'a> Parser<'a> { return Err(err); } }; + let mut default = None; + if p.token == token::Eq { + let mut snapshot = p.create_snapshot_for_diagnostic(); + snapshot.bump(); + match snapshot.parse_expr_anon_const() { + Ok(const_expr) => { + let sp = ty.span.shrink_to_hi().to(const_expr.value.span); + p.psess.gated_spans.gate(sym::default_field_values, sp); + p.restore_snapshot(snapshot); + default = Some(const_expr); + } + Err(err) => { + err.cancel(); + } + } + } Ok(( FieldDef { @@ -1845,6 +1861,7 @@ impl<'a> Parser<'a> { ident: None, id: DUMMY_NODE_ID, ty, + default, attrs, is_placeholder: false, }, @@ -2024,12 +2041,15 @@ impl<'a> Parser<'a> { if self.token == token::Colon && self.look_ahead(1, |t| *t != token::Colon) { self.dcx().emit_err(errors::SingleColonStructType { span: self.token.span }); } - if self.token == token::Eq { + let default = if self.token == token::Eq { self.bump(); let const_expr = self.parse_expr_anon_const()?; let sp = ty.span.shrink_to_hi().to(const_expr.value.span); - self.dcx().emit_err(errors::EqualsStructDefault { span: sp }); - } + self.psess.gated_spans.gate(sym::default_field_values, sp); + Some(const_expr) + } else { + None + }; Ok(FieldDef { span: lo.to(self.prev_token.span), ident: Some(name), @@ -2037,6 +2057,7 @@ impl<'a> Parser<'a> { safety, id: DUMMY_NODE_ID, ty, + default, attrs, is_placeholder: false, }) diff --git a/compiler/rustc_passes/src/debugger_visualizer.rs b/compiler/rustc_passes/src/debugger_visualizer.rs index fec149c8c43..062d56a79a0 100644 --- a/compiler/rustc_passes/src/debugger_visualizer.rs +++ b/compiler/rustc_passes/src/debugger_visualizer.rs @@ -1,7 +1,6 @@ //! Detecting usage of the `#[debugger_visualizer]` attribute. use rustc_ast::Attribute; -use rustc_data_structures::sync::Lrc; use rustc_expand::base::resolve_path; use rustc_middle::middle::debugger_visualizer::{DebuggerVisualizerFile, DebuggerVisualizerType}; use rustc_middle::query::{LocalCrate, Providers}; @@ -49,10 +48,10 @@ impl DebuggerVisualizerCollector<'_> { } }; - match std::fs::read(&file) { - Ok(contents) => { + match self.sess.source_map().load_binary_file(&file) { + Ok((source, _)) => { self.visualizers.push(DebuggerVisualizerFile::new( - Lrc::from(contents), + source, visualizer_type, file, )); diff --git a/compiler/rustc_passes/src/input_stats.rs b/compiler/rustc_passes/src/input_stats.rs index f2a37307cee..76edb51c0bc 100644 --- a/compiler/rustc_passes/src/input_stats.rs +++ b/compiler/rustc_passes/src/input_stats.rs @@ -337,7 +337,6 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { BareFn, Never, Tup, - AnonAdt, Path, OpaqueDef, TraitObject, diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index 9cd95a0b02d..09cbb648f9b 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -1007,7 +1007,12 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { hir::ExprKind::Array(exprs) => self.propagate_through_exprs(exprs, succ), hir::ExprKind::Struct(_, fields, ref with_expr) => { - let succ = self.propagate_through_opt_expr(with_expr.as_deref(), succ); + let succ = match with_expr { + hir::StructTailExpr::Base(base) => { + self.propagate_through_opt_expr(Some(base), succ) + } + hir::StructTailExpr::None | hir::StructTailExpr::DefaultFields(_) => succ, + }; fields .iter() .rev() diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index c845d60ac07..3057f13e3a7 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -947,6 +947,25 @@ impl<'tcx> NamePrivacyVisitor<'tcx> { }); } } + + fn check_expanded_fields( + &mut self, + adt: ty::AdtDef<'tcx>, + variant: &'tcx ty::VariantDef, + fields: &[hir::ExprField<'tcx>], + hir_id: hir::HirId, + span: Span, + ) { + for (vf_index, variant_field) in variant.fields.iter_enumerated() { + let field = + fields.iter().find(|f| self.typeck_results().field_index(f.hir_id) == vf_index); + let (hir_id, use_ctxt, span) = match field { + Some(field) => (field.hir_id, field.ident.span, field.span), + None => (hir_id, span, span), + }; + self.check_field(hir_id, use_ctxt, span, adt, variant_field, true); + } + } } impl<'tcx> Visitor<'tcx> for NamePrivacyVisitor<'tcx> { @@ -966,25 +985,29 @@ impl<'tcx> Visitor<'tcx> for NamePrivacyVisitor<'tcx> { let res = self.typeck_results().qpath_res(qpath, expr.hir_id); let adt = self.typeck_results().expr_ty(expr).ty_adt_def().unwrap(); let variant = adt.variant_of_res(res); - if let Some(base) = *base { - // If the expression uses FRU we need to make sure all the unmentioned fields - // are checked for privacy (RFC 736). Rather than computing the set of - // unmentioned fields, just check them all. - for (vf_index, variant_field) in variant.fields.iter_enumerated() { - let field = fields - .iter() - .find(|f| self.typeck_results().field_index(f.hir_id) == vf_index); - let (hir_id, use_ctxt, span) = match field { - Some(field) => (field.hir_id, field.ident.span, field.span), - None => (base.hir_id, base.span, base.span), - }; - self.check_field(hir_id, use_ctxt, span, adt, variant_field, true); + match *base { + hir::StructTailExpr::Base(base) => { + // If the expression uses FRU we need to make sure all the unmentioned fields + // are checked for privacy (RFC 736). Rather than computing the set of + // unmentioned fields, just check them all. + self.check_expanded_fields(adt, variant, fields, base.hir_id, base.span); } - } else { - for field in fields { - let (hir_id, use_ctxt, span) = (field.hir_id, field.ident.span, field.span); - let index = self.typeck_results().field_index(field.hir_id); - self.check_field(hir_id, use_ctxt, span, adt, &variant.fields[index], false); + hir::StructTailExpr::DefaultFields(span) => { + self.check_expanded_fields(adt, variant, fields, expr.hir_id, span); + } + hir::StructTailExpr::None => { + for field in fields { + let (hir_id, use_ctxt, span) = (field.hir_id, field.ident.span, field.span); + let index = self.typeck_results().field_index(field.hir_id); + self.check_field( + hir_id, + use_ctxt, + span, + adt, + &variant.fields[index], + false, + ); + } } } } diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index fc92dc8b4ed..789d74876f7 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -13,7 +13,9 @@ use std::collections::hash_map::Entry; use std::mem::{replace, swap, take}; use rustc_ast::ptr::P; -use rustc_ast::visit::{AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor, visit_opt, walk_list}; +use rustc_ast::visit::{ + AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor, try_visit, visit_opt, walk_list, +}; use rustc_ast::*; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; use rustc_errors::codes::*; @@ -749,8 +751,8 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r self.resolve_block(block); self.parent_scope.macro_rules = old_macro_rules; } - fn visit_anon_const(&mut self, _constant: &'ast AnonConst) { - bug!("encountered anon const without a manual call to `resolve_anon_const`"); + fn visit_anon_const(&mut self, constant: &'ast AnonConst) { + bug!("encountered anon const without a manual call to `resolve_anon_const`: {constant:#?}"); } fn visit_expr(&mut self, expr: &'ast Expr) { self.resolve_expr(expr, None); @@ -1346,7 +1348,24 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r fn visit_field_def(&mut self, f: &'ast FieldDef) { self.resolve_doc_links(&f.attrs, MaybeExported::Ok(f.id)); - visit::walk_field_def(self, f) + let FieldDef { + attrs, + id: _, + span: _, + vis, + ident, + ty, + is_placeholder: _, + default, + safety: _, + } = f; + walk_list!(self, visit_attribute, attrs); + try_visit!(self.visit_vis(vis)); + visit_opt!(self, visit_ident, ident); + try_visit!(self.visit_ty(ty)); + if let Some(v) = &default { + self.resolve_anon_const(v, AnonConstKind::ConstArg(IsRepeatExpr::No)); + } } } diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs index 2f4387e412d..34e1c31683a 100644 --- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs +++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs @@ -716,8 +716,7 @@ fn encode_ty_name(tcx: TyCtxt<'_>, def_id: DefId) -> String { | hir::definitions::DefPathData::Use | hir::definitions::DefPathData::GlobalAsm | hir::definitions::DefPathData::MacroNs(..) - | hir::definitions::DefPathData::LifetimeNs(..) - | hir::definitions::DefPathData::AnonAdt => { + | hir::definitions::DefPathData::LifetimeNs(..) => { bug!("encode_ty_name: unexpected `{:?}`", disambiguated_data.data); } }); diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 958d4f0c251..bd8b93bb4d1 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -523,6 +523,12 @@ impl SpanData { } } +impl Default for SpanData { + fn default() -> Self { + Self { lo: BytePos(0), hi: BytePos(0), ctxt: SyntaxContext::root(), parent: None } + } +} + impl PartialOrd for Span { fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> { PartialOrd::partial_cmp(&self.data(), &rhs.data()) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 818d4afffc6..d30b17c9cd8 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -728,6 +728,7 @@ symbols! { declare_lint_pass, decode, default_alloc_error_handler, + default_field_values, default_fn, default_lib_allocator, default_method_body_is_const, diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 1a10ab8829c..def741e3546 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -772,8 +772,7 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { | DefPathData::GlobalAsm | DefPathData::Impl | DefPathData::MacroNs(_) - | DefPathData::LifetimeNs(_) - | DefPathData::AnonAdt => { + | DefPathData::LifetimeNs(_) => { bug!("symbol_names: unexpected DefPathData: {:?}", disambiguated_data.data) } }; diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_ibm_aix.rs b/compiler/rustc_target/src/spec/targets/powerpc64_ibm_aix.rs index 0f361054f7a..edabbbf5f00 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc64_ibm_aix.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc64_ibm_aix.rs @@ -19,7 +19,7 @@ pub(crate) fn target() -> Target { std: None, // ? }, pointer_width: 64, - data_layout: "E-m:a-Fi64-i64:64-n32:64-S128-v256:256:256-v512:512:512".into(), + data_layout: "E-m:a-Fi64-i64:64-i128:128-n32:64-S128-v256:256:256-v512:512:512".into(), arch: "powerpc64".into(), options: base, } diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_freebsd.rs b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_freebsd.rs index 680b024cb6e..68a3718035c 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_freebsd.rs @@ -17,7 +17,7 @@ pub(crate) fn target() -> Target { std: Some(true), }, pointer_width: 64, - data_layout: "E-m:e-Fn32-i64:64-n32:64".into(), + data_layout: "E-m:e-Fn32-i64:64-i128:128-n32:64".into(), arch: "powerpc64".into(), options: TargetOptions { endian: Endian::Big, mcount: "_mcount".into(), ..base }, } diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_gnu.rs index 5acd9205a8c..351ffa65eba 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_gnu.rs @@ -17,7 +17,7 @@ pub(crate) fn target() -> Target { std: Some(true), }, pointer_width: 64, - data_layout: "E-m:e-Fi64-i64:64-n32:64-S128-v256:256:256-v512:512:512".into(), + data_layout: "E-m:e-Fi64-i64:64-i128:128-n32:64-S128-v256:256:256-v512:512:512".into(), arch: "powerpc64".into(), options: TargetOptions { endian: Endian::Big, mcount: "_mcount".into(), ..base }, } diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs index 62c30aebc51..a964f417799 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs @@ -17,7 +17,7 @@ pub(crate) fn target() -> Target { std: Some(true), }, pointer_width: 64, - data_layout: "E-m:e-Fn32-i64:64-n32:64-S128-v256:256:256-v512:512:512".into(), + data_layout: "E-m:e-Fn32-i64:64-i128:128-n32:64-S128-v256:256:256-v512:512:512".into(), arch: "powerpc64".into(), options: TargetOptions { endian: Endian::Big, mcount: "_mcount".into(), ..base }, } diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_openbsd.rs b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_openbsd.rs index c723847cada..31fbb141524 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_openbsd.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_openbsd.rs @@ -17,7 +17,7 @@ pub(crate) fn target() -> Target { std: Some(true), }, pointer_width: 64, - data_layout: "E-m:e-Fn32-i64:64-n32:64".into(), + data_layout: "E-m:e-Fn32-i64:64-i128:128-n32:64".into(), arch: "powerpc64".into(), options: TargetOptions { endian: Endian::Big, mcount: "_mcount".into(), ..base }, } diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_wrs_vxworks.rs b/compiler/rustc_target/src/spec/targets/powerpc64_wrs_vxworks.rs index 1d3d9f1b77d..c37aa8d502a 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc64_wrs_vxworks.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc64_wrs_vxworks.rs @@ -17,7 +17,7 @@ pub(crate) fn target() -> Target { std: Some(true), }, pointer_width: 64, - data_layout: "E-m:e-Fi64-i64:64-n32:64-S128-v256:256:256-v512:512:512".into(), + data_layout: "E-m:e-Fi64-i64:64-i128:128-n32:64-S128-v256:256:256-v512:512:512".into(), arch: "powerpc64".into(), options: TargetOptions { endian: Endian::Big, ..base }, } diff --git a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_freebsd.rs b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_freebsd.rs index 0c1218bd059..13885c7326a 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_freebsd.rs @@ -16,7 +16,7 @@ pub(crate) fn target() -> Target { std: Some(true), }, pointer_width: 64, - data_layout: "e-m:e-Fn32-i64:64-n32:64".into(), + data_layout: "e-m:e-Fn32-i64:64-i128:128-n32:64".into(), arch: "powerpc64".into(), options: TargetOptions { mcount: "_mcount".into(), ..base }, } diff --git a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_gnu.rs index 23913687a1f..06ae54063ce 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_gnu.rs @@ -16,7 +16,7 @@ pub(crate) fn target() -> Target { std: Some(true), }, pointer_width: 64, - data_layout: "e-m:e-Fn32-i64:64-n32:64-S128-v256:256:256-v512:512:512".into(), + data_layout: "e-m:e-Fn32-i64:64-i128:128-n32:64-S128-v256:256:256-v512:512:512".into(), arch: "powerpc64".into(), options: TargetOptions { mcount: "_mcount".into(), ..base }, } diff --git a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_musl.rs index 50946ae4ce6..04fe5f9af33 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_musl.rs @@ -16,7 +16,7 @@ pub(crate) fn target() -> Target { std: Some(true), }, pointer_width: 64, - data_layout: "e-m:e-Fn32-i64:64-n32:64-S128-v256:256:256-v512:512:512".into(), + data_layout: "e-m:e-Fn32-i64:64-i128:128-n32:64-S128-v256:256:256-v512:512:512".into(), arch: "powerpc64".into(), options: TargetOptions { mcount: "_mcount".into(), ..base }, } diff --git a/compiler/rustc_target/src/spec/targets/wasm32_unknown_emscripten.rs b/compiler/rustc_target/src/spec/targets/wasm32_unknown_emscripten.rs index a70cebbd9c8..bdb1fc55711 100644 --- a/compiler/rustc_target/src/spec/targets/wasm32_unknown_emscripten.rs +++ b/compiler/rustc_target/src/spec/targets/wasm32_unknown_emscripten.rs @@ -32,7 +32,8 @@ pub(crate) fn target() -> Target { std: Some(true), }, pointer_width: 32, - data_layout: "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-f128:64-n32:64-S128-ni:1:10:20".into(), + data_layout: "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-f128:64-n32:64-S128-ni:1:10:20" + .into(), arch: "wasm32".into(), options: opts, } diff --git a/compiler/rustc_target/src/spec/targets/wasm32_unknown_unknown.rs b/compiler/rustc_target/src/spec/targets/wasm32_unknown_unknown.rs index e7165533b9c..96237f20891 100644 --- a/compiler/rustc_target/src/spec/targets/wasm32_unknown_unknown.rs +++ b/compiler/rustc_target/src/spec/targets/wasm32_unknown_unknown.rs @@ -37,7 +37,7 @@ pub(crate) fn target() -> Target { std: Some(true), }, pointer_width: 32, - data_layout: "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20".into(), + data_layout: "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20".into(), arch: "wasm32".into(), options, } diff --git a/compiler/rustc_target/src/spec/targets/wasm32_wasip1.rs b/compiler/rustc_target/src/spec/targets/wasm32_wasip1.rs index 1cd30f21bec..0862958d05d 100644 --- a/compiler/rustc_target/src/spec/targets/wasm32_wasip1.rs +++ b/compiler/rustc_target/src/spec/targets/wasm32_wasip1.rs @@ -55,7 +55,7 @@ pub(crate) fn target() -> Target { std: Some(true), }, pointer_width: 32, - data_layout: "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20".into(), + data_layout: "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20".into(), arch: "wasm32".into(), options, } diff --git a/compiler/rustc_target/src/spec/targets/wasm32_wasip1_threads.rs b/compiler/rustc_target/src/spec/targets/wasm32_wasip1_threads.rs index 19bc5db4d9b..0c2e2bfeda6 100644 --- a/compiler/rustc_target/src/spec/targets/wasm32_wasip1_threads.rs +++ b/compiler/rustc_target/src/spec/targets/wasm32_wasip1_threads.rs @@ -66,7 +66,7 @@ pub(crate) fn target() -> Target { std: Some(true), }, pointer_width: 32, - data_layout: "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20".into(), + data_layout: "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20".into(), arch: "wasm32".into(), options, } diff --git a/compiler/rustc_target/src/spec/targets/wasm32_wasip2.rs b/compiler/rustc_target/src/spec/targets/wasm32_wasip2.rs index f06112160d1..3f4618fad5a 100644 --- a/compiler/rustc_target/src/spec/targets/wasm32_wasip2.rs +++ b/compiler/rustc_target/src/spec/targets/wasm32_wasip2.rs @@ -66,7 +66,7 @@ pub(crate) fn target() -> Target { std: Some(true), }, pointer_width: 32, - data_layout: "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20".into(), + data_layout: "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20".into(), arch: "wasm32".into(), options, } diff --git a/compiler/rustc_target/src/spec/targets/wasm32v1_none.rs b/compiler/rustc_target/src/spec/targets/wasm32v1_none.rs index bf35ae009c6..5c35e9c21d3 100644 --- a/compiler/rustc_target/src/spec/targets/wasm32v1_none.rs +++ b/compiler/rustc_target/src/spec/targets/wasm32v1_none.rs @@ -44,7 +44,7 @@ pub(crate) fn target() -> Target { std: Some(false), }, pointer_width: 32, - data_layout: "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20".into(), + data_layout: "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20".into(), arch: "wasm32".into(), options, } diff --git a/compiler/rustc_target/src/spec/targets/wasm64_unknown_unknown.rs b/compiler/rustc_target/src/spec/targets/wasm64_unknown_unknown.rs index 5ba0fca9f64..22fa26d3cdb 100644 --- a/compiler/rustc_target/src/spec/targets/wasm64_unknown_unknown.rs +++ b/compiler/rustc_target/src/spec/targets/wasm64_unknown_unknown.rs @@ -40,7 +40,7 @@ pub(crate) fn target() -> Target { std: None, // ? }, pointer_width: 64, - data_layout: "e-m:e-p:64:64-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20".into(), + data_layout: "e-m:e-p:64:64-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20".into(), arch: "wasm64".into(), options, } diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index 67c047dddfc..3a130607265 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -412,6 +412,7 @@ const POWERPC_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("partword-atomics", Unstable(sym::powerpc_target_feature), &[]), ("power10-vector", Unstable(sym::powerpc_target_feature), &["power9-vector"]), ("power8-altivec", Unstable(sym::powerpc_target_feature), &["altivec"]), + ("power8-crypto", Unstable(sym::powerpc_target_feature), &["power8-altivec"]), ("power8-vector", Unstable(sym::powerpc_target_feature), &["vsx", "power8-altivec"]), ("power9-altivec", Unstable(sym::powerpc_target_feature), &["power8-altivec"]), ("power9-vector", Unstable(sym::powerpc_target_feature), &["power8-vector", "power9-altivec"]), diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs index afac6fc6004..68fe90f0de2 100644 --- a/compiler/rustc_trait_selection/src/errors.rs +++ b/compiler/rustc_trait_selection/src/errors.rs @@ -10,7 +10,7 @@ use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::{Visitor, walk_ty}; -use rustc_hir::{FnRetTy, GenericParamKind}; +use rustc_hir::{FnRetTy, GenericParamKind, Node}; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_middle::ty::print::{PrintTraitRefExt as _, TraitRefPrintOnlyTraitPath}; use rustc_middle::ty::{self, Binder, ClosureKind, FnSig, PolyTraitRef, Region, Ty, TyCtxt}; @@ -1888,10 +1888,35 @@ pub fn impl_trait_overcapture_suggestion<'tcx>( .collect::<Vec<_>>() .join(", "); - suggs.push(( - tcx.def_span(opaque_def_id).shrink_to_hi(), - format!(" + use<{concatenated_bounds}>"), - )); + let opaque_hir_id = tcx.local_def_id_to_hir_id(opaque_def_id); + // FIXME: This is a bit too conservative, since it ignores parens already written in AST. + let (lparen, rparen) = match tcx + .hir() + .parent_iter(opaque_hir_id) + .nth(1) + .expect("expected ty to have a parent always") + .1 + { + Node::PathSegment(segment) + if segment.args().paren_sugar_output().is_some_and(|ty| ty.hir_id == opaque_hir_id) => + { + ("(", ")") + } + Node::Ty(ty) => match ty.kind { + rustc_hir::TyKind::Ptr(_) | rustc_hir::TyKind::Ref(..) => ("(", ")"), + // FIXME: RPITs are not allowed to be nested in `impl Fn() -> ...`, + // but we eventually could support that, and that would necessitate + // making this more sophisticated. + _ => ("", ""), + }, + _ => ("", ""), + }; + + let rpit_span = tcx.def_span(opaque_def_id); + if !lparen.is_empty() { + suggs.push((rpit_span.shrink_to_lo(), lparen.to_string())); + } + suggs.push((rpit_span.shrink_to_hi(), format!(" + use<{concatenated_bounds}>{rparen}"))); Some(AddPreciseCapturingForOvercapture { suggs, apit_spans }) } diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs index 3b17fa6b032..d216ae72913 100644 --- a/compiler/rustc_trait_selection/src/traits/misc.rs +++ b/compiler/rustc_trait_selection/src/traits/misc.rs @@ -18,6 +18,7 @@ pub enum CopyImplementationError<'tcx> { InfringingFields(Vec<(&'tcx ty::FieldDef, Ty<'tcx>, InfringingFieldsReason<'tcx>)>), NotAnAdt, HasDestructor, + HasUnsafeFields, } pub enum ConstParamTyImplementationError<'tcx> { @@ -39,11 +40,16 @@ pub enum InfringingFieldsReason<'tcx> { /// /// If it's not an ADT, int ty, `bool`, float ty, `char`, raw pointer, `!`, /// a reference or an array returns `Err(NotAnAdt)`. +/// +/// If the impl is `Safe`, `self_type` must not have unsafe fields. When used to +/// generate suggestions in lints, `Safe` should be supplied so as to not +/// suggest implementing `Copy` for types with unsafe fields. pub fn type_allowed_to_implement_copy<'tcx>( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, self_type: Ty<'tcx>, parent_cause: ObligationCause<'tcx>, + impl_safety: hir::Safety, ) -> Result<(), CopyImplementationError<'tcx>> { let (adt, args) = match self_type.kind() { // These types used to have a builtin impl. @@ -78,6 +84,10 @@ pub fn type_allowed_to_implement_copy<'tcx>( return Err(CopyImplementationError::HasDestructor); } + if impl_safety == hir::Safety::Safe && self_type.has_unsafe_fields() { + return Err(CopyImplementationError::HasUnsafeFields); + } + Ok(()) } diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 49c34550f8e..541c0c915ff 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -744,7 +744,7 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>( let Some(clause) = clause.as_projection_clause() else { return ControlFlow::Continue(()); }; - if clause.projection_def_id() != obligation.predicate.def_id { + if clause.item_def_id() != obligation.predicate.def_id { return ControlFlow::Continue(()); } @@ -847,7 +847,7 @@ fn assemble_candidates_from_predicates<'cx, 'tcx>( let bound_predicate = predicate.kind(); if let ty::ClauseKind::Projection(data) = predicate.kind().skip_binder() { let data = bound_predicate.rebind(data); - if data.projection_def_id() != obligation.predicate.def_id { + if data.item_def_id() != obligation.predicate.def_id { continue; } diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 3e2c8467d32..5e27fd43789 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -795,8 +795,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::Never | ty::Tuple(_) | ty::CoroutineWitness(..) => { - use rustc_type_ir::inherent::*; - // Only consider auto impls of unsafe traits when there are // no unsafe fields. if self.tcx().trait_is_unsafe(def_id) && self_ty.has_unsafe_fields() { diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index d362866cbc3..25fe43e3a0e 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1737,7 +1737,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { env_predicate: PolyProjectionPredicate<'tcx>, potentially_unnormalized_candidates: bool, ) -> ProjectionMatchesProjection { - debug_assert_eq!(obligation.predicate.def_id, env_predicate.projection_def_id()); + debug_assert_eq!(obligation.predicate.def_id, env_predicate.item_def_id()); let mut nested_obligations = PredicateObligations::new(); let infer_predicate = self.infcx.instantiate_binder_with_fresh_vars( diff --git a/compiler/rustc_type_ir/src/predicate.rs b/compiler/rustc_type_ir/src/predicate.rs index 4213ef4803b..9a80f97e274 100644 --- a/compiler/rustc_type_ir/src/predicate.rs +++ b/compiler/rustc_type_ir/src/predicate.rs @@ -692,7 +692,7 @@ impl<I: Interner> ty::Binder<I, ProjectionPredicate<I>> { /// /// Note that this is not the `DefId` of the `TraitRef` containing this /// associated type, which is in `tcx.associated_item(projection_def_id()).container`. - pub fn projection_def_id(&self) -> I::DefId { + pub fn item_def_id(&self) -> I::DefId { // Ok to skip binder since trait `DefId` does not care about regions. self.skip_binder().projection_term.def_id } diff --git a/config.example.toml b/config.example.toml index 9ec0d77e79b..5ea6774ce03 100644 --- a/config.example.toml +++ b/config.example.toml @@ -311,9 +311,8 @@ # Indicate whether the vendored sources are used for Rust dependencies or not. # # Vendoring requires additional setup. We recommend using the pre-generated source tarballs if you -# want to use vendoring. See -# https://forge.rust-lang.org/infra/other-installation-methods.html#source-code. -#vendor = false +# want to use vendoring. See https://forge.rust-lang.org/infra/other-installation-methods.html#source-code. +#vendor = if "is a tarball source" && "vendor" dir exists && ".cargo/config.toml" file exists { true } else { false } # Typically the build system will build the Rust compiler twice. The second # compiler, however, will simply use its own libraries to link against. If you diff --git a/library/Cargo.lock b/library/Cargo.lock index f9b0af2c6e8..03c2356e542 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -36,9 +36,9 @@ dependencies = [ [[package]] name = "allocator-api2" -version = "0.2.18" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" +checksum = "45862d1c77f2228b9e10bc609d5bc203d86ebc9b87ad8d5d5167a6c9abf739d9" [[package]] name = "cc" @@ -403,9 +403,9 @@ dependencies = [ [[package]] name = "unwinding" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "637d511437df708cee34bdec7ba2f1548d256b7acf3ff20e0a1c559f9bf3a987" +checksum = "e2c6cb20f236dae10c69b0b45d82ef50af8b7e45c10e429e7901d26b49b4dbf3" dependencies = [ "compiler_builtins", "gimli 0.31.1", diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index e3c7835f1d1..edc8d99f2f9 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -27,6 +27,8 @@ pub use core::slice::ArrayChunksMut; pub use core::slice::ArrayWindows; #[stable(feature = "inherent_ascii_escape", since = "1.60.0")] pub use core::slice::EscapeAscii; +#[unstable(feature = "get_many_mut", issue = "104642")] +pub use core::slice::GetManyMutError; #[stable(feature = "slice_get_slice", since = "1.28.0")] pub use core::slice::SliceIndex; #[cfg(not(no_global_oom_handling))] diff --git a/library/core/src/error.rs b/library/core/src/error.rs index 95a39cc3aed..91549f49f9f 100644 --- a/library/core/src/error.rs +++ b/library/core/src/error.rs @@ -1076,4 +1076,4 @@ impl Error for crate::time::TryFromFloatSecsError {} impl Error for crate::ffi::FromBytesUntilNulError {} #[unstable(feature = "get_many_mut", issue = "104642")] -impl<const N: usize> Error for crate::slice::GetManyMutError<N> {} +impl Error for crate::slice::GetManyMutError {} diff --git a/library/core/src/ffi/mod.rs b/library/core/src/ffi/mod.rs index dc107c5d22c..7a161f595f4 100644 --- a/library/core/src/ffi/mod.rs +++ b/library/core/src/ffi/mod.rs @@ -91,59 +91,86 @@ pub type c_ssize_t = isize; mod c_char_definition { cfg_if! { - // These are the targets on which c_char is unsigned. - if #[cfg(any( - all( - target_os = "linux", - any( - target_arch = "aarch64", - target_arch = "arm", - target_arch = "hexagon", - target_arch = "powerpc", - target_arch = "powerpc64", - target_arch = "s390x", - target_arch = "riscv64", - target_arch = "riscv32", - target_arch = "csky" - ) - ), - all(target_os = "android", any(target_arch = "aarch64", target_arch = "arm")), - all(target_os = "l4re", target_arch = "x86_64"), - all( - any(target_os = "freebsd", target_os = "openbsd", target_os = "rtems"), - any( - target_arch = "aarch64", - target_arch = "arm", - target_arch = "powerpc", - target_arch = "powerpc64", - target_arch = "riscv64" - ) - ), - all( - target_os = "netbsd", - any( - target_arch = "aarch64", - target_arch = "arm", - target_arch = "powerpc", - target_arch = "riscv64" - ) - ), - all( - target_os = "vxworks", - any( - target_arch = "aarch64", - target_arch = "arm", - target_arch = "powerpc64", - target_arch = "powerpc" - ) - ), - all( - target_os = "fuchsia", - any(target_arch = "aarch64", target_arch = "riscv64") - ), - all(target_os = "nto", target_arch = "aarch64"), - target_os = "horizon", - target_os = "aix", + // These are the targets on which c_char is unsigned. Usually the + // signedness is the same for all target_os values on a given architecture + // but there are some exceptions (see isSignedCharDefault() in clang). + // + // aarch64: + // Section 10 "Arm C and C++ language mappings" in Procedure Call Standard for the Arm® + // 64-bit Architecture (AArch64) says C/C++ char is unsigned byte. + // https://github.com/ARM-software/abi-aa/blob/2024Q3/aapcs64/aapcs64.rst#arm-c-and-c-language-mappings + // arm: + // Section 8 "Arm C and C++ Language Mappings" in Procedure Call Standard for the Arm® + // Architecture says C/C++ char is unsigned byte. + // https://github.com/ARM-software/abi-aa/blob/2024Q3/aapcs32/aapcs32.rst#arm-c-and-c-language-mappings + // csky: + // Section 2.1.2 "Primary Data Type" in C-SKY V2 CPU Applications Binary Interface + // Standards Manual says ANSI C char is unsigned byte. + // https://github.com/c-sky/csky-doc/blob/9f7121f7d40970ba5cc0f15716da033db2bb9d07/C-SKY_V2_CPU_Applications_Binary_Interface_Standards_Manual.pdf + // Note: this doesn't seem to match Clang's default (https://github.com/rust-lang/rust/issues/129945). + // hexagon: + // Section 3.1 "Basic data type" in Qualcomm Hexagonâ„¢ Application + // Binary Interface User Guide says "By default, the `char` data type is unsigned." + // https://docs.qualcomm.com/bundle/publicresource/80-N2040-23_REV_K_Qualcomm_Hexagon_Application_Binary_Interface_User_Guide.pdf + // msp430: + // Section 2.1 "Basic Types" in MSP430 Embedded Application Binary + // Interface says "The char type is unsigned by default". + // https://www.ti.com/lit/an/slaa534a/slaa534a.pdf + // Note: this doesn't seem to match Clang's default (https://github.com/rust-lang/rust/issues/129945). + // powerpc/powerpc64: + // - PPC32 SysV: "Table 3-1 Scalar Types" in System V Application Binary Interface PowerPC + // Processor Supplement says ANSI C char is unsigned byte + // https://refspecs.linuxfoundation.org/elf/elfspec_ppc.pdf + // - PPC64 ELFv1: Section 3.1.4 "Fundamental Types" in 64-bit PowerPC ELF Application + // Binary Interface Supplement 1.9 says ANSI C is unsigned byte + // https://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi.html#FUND-TYPE + // - PPC64 ELFv2: Section 2.1.2.2 "Fundamental Types" in 64-Bit ELF V2 ABI Specification + // says char is unsigned byte + // https://openpowerfoundation.org/specifications/64bitelfabi/ + // - AIX: XL C for AIX Language Reference says "By default, char behaves like an unsigned char." + // https://www.ibm.com/docs/en/xl-c-aix/13.1.3?topic=specifiers-character-types + // riscv32/riscv64: + // C/C++ type representations section in RISC-V Calling Conventions + // page in RISC-V ELF psABI Document says "char is unsigned." + // https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/draft-20240829-13bfa9f54634cb60d86b9b333e109f077805b4b3/riscv-cc.adoc#cc-type-representations + // s390x: + // - ELF: "Table 1.1.: Scalar types" in ELF Application Binary Interface s390x Supplement + // Version 1.6.1 categorize ISO C char in unsigned integer + // https://github.com/IBM/s390x-abi/releases/tag/v1.6.1 + // - z/OS: XL C/C++ Language Reference says: "By default, char behaves like an unsigned char." + // https://www.ibm.com/docs/en/zos/3.1.0?topic=specifiers-character-types + // Xtensa: + // - "The char type is unsigned by default for Xtensa processors." + // + // On the following operating systems, c_char is signed by default, regardless of architecture. + // Darwin (macOS, iOS, etc.): + // Apple targets' c_char is signed by default even on arm + // https://developer.apple.com/documentation/xcode/writing-arm64-code-for-apple-platforms#Handle-data-types-and-data-alignment-properly + // Windows: + // Windows MSVC C++ Language Reference says "Microsoft-specific: Variables of type char + // are promoted to int as if from type signed char by default, unless the /J compilation + // option is used." + // https://learn.microsoft.com/en-us/cpp/cpp/fundamental-types-cpp?view=msvc-170#character-types) + // L4RE: + // The kernel builds with -funsigned-char on all targets (but useserspace follows the + // architecture defaults). As we only have a target for userspace apps so there are no + // special cases for L4RE below. + if #[cfg(all( + not(windows), + not(target_vendor = "apple"), + any( + target_arch = "aarch64", + target_arch = "arm", + target_arch = "csky", + target_arch = "hexagon", + target_arch = "msp430", + target_arch = "powerpc", + target_arch = "powerpc64", + target_arch = "riscv64", + target_arch = "riscv32", + target_arch = "s390x", + target_arch = "xtensa", + ) ))] { pub type c_char = u8; } else { diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index e36f20fd576..357a85ae843 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -77,6 +77,31 @@ pub use saturating::Saturating; #[stable(feature = "rust1", since = "1.0.0")] pub use wrapping::Wrapping; +macro_rules! u8_xe_bytes_doc { + () => { + " + +**Note**: This function is meaningless on `u8`. Byte order does not exist as a +concept for byte-sized integers. This function is only provided in symmetry +with larger integer types. + +" + }; +} + +macro_rules! i8_xe_bytes_doc { + () => { + " + +**Note**: This function is meaningless on `i8`. Byte order does not exist as a +concept for byte-sized integers. This function is only provided in symmetry +with larger integer types. You can cast from and to `u8` using `as i8` and `as +u8`. + +" + }; +} + macro_rules! usize_isize_to_xe_bytes_doc { () => { " @@ -348,8 +373,8 @@ impl i8 { reversed = "0x48", le_bytes = "[0x12]", be_bytes = "[0x12]", - to_xe_bytes_doc = "", - from_xe_bytes_doc = "", + to_xe_bytes_doc = i8_xe_bytes_doc!(), + from_xe_bytes_doc = i8_xe_bytes_doc!(), bound_condition = "", } midpoint_impl! { i8, i16, signed } @@ -547,8 +572,8 @@ impl u8 { reversed = "0x48", le_bytes = "[0x12]", be_bytes = "[0x12]", - to_xe_bytes_doc = "", - from_xe_bytes_doc = "", + to_xe_bytes_doc = u8_xe_bytes_doc!(), + from_xe_bytes_doc = u8_xe_bytes_doc!(), bound_condition = "", } widening_impl! { u8, u16, 8, unsigned } diff --git a/library/core/src/ops/control_flow.rs b/library/core/src/ops/control_flow.rs index c4429b3cd7d..c8fcee5c140 100644 --- a/library/core/src/ops/control_flow.rs +++ b/library/core/src/ops/control_flow.rs @@ -141,8 +141,8 @@ impl<B, C> ControlFlow<B, C> { /// ``` /// use std::ops::ControlFlow; /// - /// assert!(ControlFlow::<i32, String>::Break(3).is_break()); - /// assert!(!ControlFlow::<String, i32>::Continue(3).is_break()); + /// assert!(ControlFlow::<&str, i32>::Break("Stop right there!").is_break()); + /// assert!(!ControlFlow::<&str, i32>::Continue(3).is_break()); /// ``` #[inline] #[stable(feature = "control_flow_enum_is", since = "1.59.0")] @@ -157,8 +157,8 @@ impl<B, C> ControlFlow<B, C> { /// ``` /// use std::ops::ControlFlow; /// - /// assert!(!ControlFlow::<i32, String>::Break(3).is_continue()); - /// assert!(ControlFlow::<String, i32>::Continue(3).is_continue()); + /// assert!(!ControlFlow::<&str, i32>::Break("Stop right there!").is_continue()); + /// assert!(ControlFlow::<&str, i32>::Continue(3).is_continue()); /// ``` #[inline] #[stable(feature = "control_flow_enum_is", since = "1.59.0")] @@ -174,8 +174,8 @@ impl<B, C> ControlFlow<B, C> { /// ``` /// use std::ops::ControlFlow; /// - /// assert_eq!(ControlFlow::<i32, String>::Break(3).break_value(), Some(3)); - /// assert_eq!(ControlFlow::<String, i32>::Continue(3).break_value(), None); + /// assert_eq!(ControlFlow::<&str, i32>::Break("Stop right there!").break_value(), Some("Stop right there!")); + /// assert_eq!(ControlFlow::<&str, i32>::Continue(3).break_value(), None); /// ``` #[inline] #[stable(feature = "control_flow_enum", since = "1.83.0")] @@ -205,8 +205,8 @@ impl<B, C> ControlFlow<B, C> { /// ``` /// use std::ops::ControlFlow; /// - /// assert_eq!(ControlFlow::<i32, String>::Break(3).continue_value(), None); - /// assert_eq!(ControlFlow::<String, i32>::Continue(3).continue_value(), Some(3)); + /// assert_eq!(ControlFlow::<&str, i32>::Break("Stop right there!").continue_value(), None); + /// assert_eq!(ControlFlow::<&str, i32>::Continue(3).continue_value(), Some(3)); /// ``` #[inline] #[stable(feature = "control_flow_enum", since = "1.83.0")] diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index 0ad1cad6914..6b601405e1c 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -217,7 +217,7 @@ impl<T: ?Sized> NonNull<T> { /// } /// ``` #[stable(feature = "nonnull", since = "1.25.0")] - #[rustc_const_unstable(feature = "const_nonnull_new", issue = "93235")] + #[rustc_const_stable(feature = "const_nonnull_new", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn new(ptr: *mut T) -> Option<Self> { if !ptr.is_null() { diff --git a/library/core/src/ptr/unique.rs b/library/core/src/ptr/unique.rs index ebdc918a729..4810ebe01f9 100644 --- a/library/core/src/ptr/unique.rs +++ b/library/core/src/ptr/unique.rs @@ -92,8 +92,6 @@ impl<T: ?Sized> Unique<T> { /// Creates a new `Unique` if `ptr` is non-null. #[inline] - // rustc_const_unstable attribute can be removed when `const_nonnull_new` is stable - #[rustc_const_unstable(feature = "ptr_internals", issue = "none")] pub const fn new(ptr: *mut T) -> Option<Self> { if let Some(pointer) = NonNull::new(ptr) { Some(Unique { pointer, _marker: PhantomData }) diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 191eaccff98..97a7338b0bf 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -4629,13 +4629,11 @@ impl<T> [T] { pub fn get_many_mut<I, const N: usize>( &mut self, indices: [I; N], - ) -> Result<[&mut I::Output; N], GetManyMutError<N>> + ) -> Result<[&mut I::Output; N], GetManyMutError> where I: GetManyMutIndex + SliceIndex<Self>, { - if !get_many_check_valid(&indices, self.len()) { - return Err(GetManyMutError { _private: () }); - } + get_many_check_valid(&indices, self.len())?; // SAFETY: The `get_many_check_valid()` call checked that all indices // are disjunct and in bounds. unsafe { Ok(self.get_many_unchecked_mut(indices)) } @@ -4978,53 +4976,59 @@ impl<T, const N: usize> SlicePattern for [T; N] { /// This will do `binomial(N + 1, 2) = N * (N + 1) / 2 = 0, 1, 3, 6, 10, ..` /// comparison operations. #[inline] -fn get_many_check_valid<I: GetManyMutIndex, const N: usize>(indices: &[I; N], len: usize) -> bool { +fn get_many_check_valid<I: GetManyMutIndex, const N: usize>( + indices: &[I; N], + len: usize, +) -> Result<(), GetManyMutError> { // NB: The optimizer should inline the loops into a sequence // of instructions without additional branching. - let mut valid = true; for (i, idx) in indices.iter().enumerate() { - valid &= idx.is_in_bounds(len); + if !idx.is_in_bounds(len) { + return Err(GetManyMutError::IndexOutOfBounds); + } for idx2 in &indices[..i] { - valid &= !idx.is_overlapping(idx2); + if idx.is_overlapping(idx2) { + return Err(GetManyMutError::OverlappingIndices); + } } } - valid + Ok(()) } -/// The error type returned by [`get_many_mut<N>`][`slice::get_many_mut`]. +/// The error type returned by [`get_many_mut`][`slice::get_many_mut`]. /// /// It indicates one of two possible errors: /// - An index is out-of-bounds. -/// - The same index appeared multiple times in the array. +/// - The same index appeared multiple times in the array +/// (or different but overlapping indices when ranges are provided). /// /// # Examples /// /// ``` /// #![feature(get_many_mut)] +/// use std::slice::GetManyMutError; /// /// let v = &mut [1, 2, 3]; -/// assert!(v.get_many_mut([0, 999]).is_err()); -/// assert!(v.get_many_mut([1, 1]).is_err()); +/// assert_eq!(v.get_many_mut([0, 999]), Err(GetManyMutError::IndexOutOfBounds)); +/// assert_eq!(v.get_many_mut([1, 1]), Err(GetManyMutError::OverlappingIndices)); /// ``` #[unstable(feature = "get_many_mut", issue = "104642")] -// NB: The N here is there to be forward-compatible with adding more details -// to the error type at a later point -#[derive(Clone, PartialEq, Eq)] -pub struct GetManyMutError<const N: usize> { - _private: (), +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum GetManyMutError { + /// An index provided was out-of-bounds for the slice. + IndexOutOfBounds, + /// Two indices provided were overlapping. + OverlappingIndices, } #[unstable(feature = "get_many_mut", issue = "104642")] -impl<const N: usize> fmt::Debug for GetManyMutError<N> { +impl fmt::Display for GetManyMutError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("GetManyMutError").finish_non_exhaustive() - } -} - -#[unstable(feature = "get_many_mut", issue = "104642")] -impl<const N: usize> fmt::Display for GetManyMutError<N> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt("an index is out of bounds or appeared multiple times in the array", f) + let msg = match self { + GetManyMutError::IndexOutOfBounds => "an index is out of bounds", + GetManyMutError::OverlappingIndices => "there were overlapping indices", + }; + fmt::Display::fmt(msg, f) } } diff --git a/library/core/src/task/wake.rs b/library/core/src/task/wake.rs index 6762ed54e5c..bfffcc24a46 100644 --- a/library/core/src/task/wake.rs +++ b/library/core/src/task/wake.rs @@ -61,7 +61,6 @@ impl RawWaker { } #[stable(feature = "noop_waker", since = "CURRENT_RUSTC_VERSION")] - #[rustc_const_stable(feature = "noop_waker", since = "CURRENT_RUSTC_VERSION")] const NOOP: RawWaker = { const VTABLE: RawWakerVTable = RawWakerVTable::new( // Cloning just returns a new no-op raw waker diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index a4a794691fe..89b65eefd02 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -15,7 +15,6 @@ #![feature(clone_to_uninit)] #![feature(const_black_box)] #![feature(const_eval_select)] -#![feature(const_nonnull_new)] #![feature(const_swap)] #![feature(const_trait_impl)] #![feature(core_intrinsics)] diff --git a/library/std/src/sys/pal/wasi/fs.rs b/library/std/src/sys/pal/wasi/fs.rs index 0667eb90101..7779d2b97d7 100644 --- a/library/std/src/sys/pal/wasi/fs.rs +++ b/library/std/src/sys/pal/wasi/fs.rs @@ -27,10 +27,27 @@ pub struct FileAttr { pub struct ReadDir { inner: Arc<ReadDirInner>, - cookie: Option<wasi::Dircookie>, - buf: Vec<u8>, - offset: usize, - cap: usize, + state: ReadDirState, +} + +enum ReadDirState { + /// Fill `buf` with `buf.len()` bytes starting from `next_read_offset`. + FillBuffer { + next_read_offset: wasi::Dircookie, + buf: Vec<u8>, + }, + ProcessEntry { + buf: Vec<u8>, + next_read_offset: Option<wasi::Dircookie>, + offset: usize, + }, + /// There is no more data to get in [`Self::FillBuffer`]; keep returning + /// entries via ProcessEntry until `buf` is exhausted. + RunUntilExhaustion { + buf: Vec<u8>, + offset: usize, + }, + Done, } struct ReadDirInner { @@ -147,11 +164,8 @@ impl FileType { impl ReadDir { fn new(dir: File, root: PathBuf) -> ReadDir { ReadDir { - cookie: Some(0), - buf: vec![0; 128], - offset: 0, - cap: 0, inner: Arc::new(ReadDirInner { dir, root }), + state: ReadDirState::FillBuffer { next_read_offset: 0, buf: vec![0; 128] }, } } } @@ -162,78 +176,99 @@ impl fmt::Debug for ReadDir { } } +impl core::iter::FusedIterator for ReadDir {} + impl Iterator for ReadDir { type Item = io::Result<DirEntry>; fn next(&mut self) -> Option<io::Result<DirEntry>> { - loop { - // If we've reached the capacity of our buffer then we need to read - // some more from the OS, otherwise we pick up at our old offset. - let offset = if self.offset == self.cap { - let cookie = self.cookie.take()?; - match self.inner.dir.fd.readdir(&mut self.buf, cookie) { - Ok(bytes) => self.cap = bytes, - Err(e) => return Some(Err(e)), - } - self.offset = 0; - self.cookie = Some(cookie); - - // If we didn't actually read anything, this is in theory the - // end of the directory. - if self.cap == 0 { - self.cookie = None; - return None; - } - - 0 - } else { - self.offset - }; - let data = &self.buf[offset..self.cap]; - - // If we're not able to read a directory entry then that means it - // must have been truncated at the end of the buffer, so reset our - // offset so we can go back and reread into the buffer, picking up - // where we last left off. - let dirent_size = mem::size_of::<wasi::Dirent>(); - if data.len() < dirent_size { - assert!(self.cookie.is_some()); - assert!(self.buf.len() >= dirent_size); - self.offset = self.cap; - continue; - } - let (dirent, data) = data.split_at(dirent_size); - let dirent = unsafe { ptr::read_unaligned(dirent.as_ptr() as *const wasi::Dirent) }; - - // If the file name was truncated, then we need to reinvoke - // `readdir` so we truncate our buffer to start over and reread this - // descriptor. Note that if our offset is 0 that means the file name - // is massive and we need a bigger buffer. - if data.len() < dirent.d_namlen as usize { - if offset == 0 { - let amt_to_add = self.buf.capacity(); - self.buf.extend(iter::repeat(0).take(amt_to_add)); + match &mut self.state { + ReadDirState::FillBuffer { next_read_offset, ref mut buf } => { + let result = self.inner.dir.fd.readdir(buf, *next_read_offset); + match result { + Ok(read_bytes) => { + if read_bytes < buf.len() { + buf.truncate(read_bytes); + self.state = + ReadDirState::RunUntilExhaustion { buf: mem::take(buf), offset: 0 }; + } else { + debug_assert_eq!(read_bytes, buf.len()); + self.state = ReadDirState::ProcessEntry { + buf: mem::take(buf), + offset: 0, + next_read_offset: Some(*next_read_offset), + }; + } + self.next() + } + Err(e) => { + self.state = ReadDirState::Done; + return Some(Err(e)); + } } - assert!(self.cookie.is_some()); - self.offset = self.cap; - continue; } - self.cookie = Some(dirent.d_next); - self.offset = offset + dirent_size + dirent.d_namlen as usize; + ReadDirState::ProcessEntry { ref mut buf, next_read_offset, offset } => { + let contents = &buf[*offset..]; + const DIRENT_SIZE: usize = crate::mem::size_of::<wasi::Dirent>(); + if contents.len() >= DIRENT_SIZE { + let (dirent, data) = contents.split_at(DIRENT_SIZE); + let dirent = + unsafe { ptr::read_unaligned(dirent.as_ptr() as *const wasi::Dirent) }; + // If the file name was truncated, then we need to reinvoke + // `readdir` so we truncate our buffer to start over and reread this + // descriptor. + if data.len() < dirent.d_namlen as usize { + if buf.len() < dirent.d_namlen as usize + DIRENT_SIZE { + buf.resize(dirent.d_namlen as usize + DIRENT_SIZE, 0); + } + if let Some(next_read_offset) = *next_read_offset { + self.state = + ReadDirState::FillBuffer { next_read_offset, buf: mem::take(buf) }; + } else { + self.state = ReadDirState::Done; + } + + return self.next(); + } + next_read_offset.as_mut().map(|cookie| { + *cookie = dirent.d_next; + }); + *offset = *offset + DIRENT_SIZE + dirent.d_namlen as usize; - let name = &data[..(dirent.d_namlen as usize)]; + let name = &data[..(dirent.d_namlen as usize)]; + + // These names are skipped on all other platforms, so let's skip + // them here too + if name == b"." || name == b".." { + return self.next(); + } - // These names are skipped on all other platforms, so let's skip - // them here too - if name == b"." || name == b".." { - continue; + return Some(Ok(DirEntry { + meta: dirent, + name: name.to_vec(), + inner: self.inner.clone(), + })); + } else if let Some(next_read_offset) = *next_read_offset { + self.state = ReadDirState::FillBuffer { next_read_offset, buf: mem::take(buf) }; + } else { + self.state = ReadDirState::Done; + } + self.next() } + ReadDirState::RunUntilExhaustion { buf, offset } => { + if *offset >= buf.len() { + self.state = ReadDirState::Done; + } else { + self.state = ReadDirState::ProcessEntry { + buf: mem::take(buf), + offset: *offset, + next_read_offset: None, + }; + } - return Some(Ok(DirEntry { - meta: dirent, - name: name.to_vec(), - inner: self.inner.clone(), - })); + self.next() + } + ReadDirState::Done => None, } } } diff --git a/library/std/src/sys/thread_local/key/unix.rs b/library/std/src/sys/thread_local/key/unix.rs index 28e48a750b9..b4b58b34706 100644 --- a/library/std/src/sys/thread_local/key/unix.rs +++ b/library/std/src/sys/thread_local/key/unix.rs @@ -1,5 +1,25 @@ use crate::mem; +// For WASI add a few symbols not in upstream `libc` just yet. +#[cfg(all(target_os = "wasi", target_env = "p1", target_feature = "atomics"))] +mod libc { + use crate::ffi; + + #[allow(non_camel_case_types)] + pub type pthread_key_t = ffi::c_uint; + + extern "C" { + pub fn pthread_key_create( + key: *mut pthread_key_t, + destructor: unsafe extern "C" fn(*mut ffi::c_void), + ) -> ffi::c_int; + #[allow(dead_code)] + pub fn pthread_getspecific(key: pthread_key_t) -> *mut ffi::c_void; + pub fn pthread_setspecific(key: pthread_key_t, value: *const ffi::c_void) -> ffi::c_int; + pub fn pthread_key_delete(key: pthread_key_t) -> ffi::c_int; + } +} + pub type Key = libc::pthread_key_t; #[inline] diff --git a/library/std/src/sys/thread_local/mod.rs b/library/std/src/sys/thread_local/mod.rs index 31d3b439060..f0a13323ec9 100644 --- a/library/std/src/sys/thread_local/mod.rs +++ b/library/std/src/sys/thread_local/mod.rs @@ -86,7 +86,9 @@ pub(crate) mod guard { mod windows; pub(crate) use windows::enable; } else if #[cfg(any( - target_family = "wasm", + all(target_family = "wasm", not( + all(target_os = "wasi", target_env = "p1", target_feature = "atomics") + )), target_os = "uefi", target_os = "zkvm", ))] { @@ -135,6 +137,7 @@ pub(crate) mod key { target_family = "unix", ), target_os = "teeos", + all(target_os = "wasi", target_env = "p1", target_feature = "atomics"), ))] { mod racy; mod unix; diff --git a/src/bootstrap/src/bin/main.rs b/src/bootstrap/src/bin/main.rs index ee813de1c9e..74dfe2e7ec8 100644 --- a/src/bootstrap/src/bin/main.rs +++ b/src/bootstrap/src/bin/main.rs @@ -48,9 +48,9 @@ fn main() { err => { drop(err); if let Ok(pid) = pid { - println!("WARNING: build directory locked by process {pid}, waiting for lock"); + eprintln!("WARNING: build directory locked by process {pid}, waiting for lock"); } else { - println!("WARNING: build directory locked, waiting for lock"); + eprintln!("WARNING: build directory locked, waiting for lock"); } let mut lock = t!(build_lock.write()); t!(lock.write(process::id().to_string().as_ref())); @@ -70,13 +70,13 @@ fn main() { // changelog warning, not the `x.py setup` message. let suggest_setup = config.config.is_none() && !matches!(config.cmd, Subcommand::Setup { .. }); if suggest_setup { - println!("WARNING: you have not made a `config.toml`"); - println!( + eprintln!("WARNING: you have not made a `config.toml`"); + eprintln!( "HELP: consider running `./x.py setup` or copying `config.example.toml` by running \ `cp config.example.toml config.toml`" ); } else if let Some(suggestion) = &changelog_suggestion { - println!("{suggestion}"); + eprintln!("{suggestion}"); } let pre_commit = config.src.join(".git").join("hooks").join("pre-commit"); @@ -86,13 +86,13 @@ fn main() { Build::new(config).build(); if suggest_setup { - println!("WARNING: you have not made a `config.toml`"); - println!( + eprintln!("WARNING: you have not made a `config.toml`"); + eprintln!( "HELP: consider running `./x.py setup` or copying `config.example.toml` by running \ `cp config.example.toml config.toml`" ); } else if let Some(suggestion) = &changelog_suggestion { - println!("{suggestion}"); + eprintln!("{suggestion}"); } // Give a warning if the pre-commit script is in pre-commit and not pre-push. @@ -102,14 +102,14 @@ fn main() { if fs::read_to_string(pre_commit).is_ok_and(|contents| { contents.contains("https://github.com/rust-lang/rust/issues/77620#issuecomment-705144570") }) { - println!( + eprintln!( "WARNING: You have the pre-push script installed to .git/hooks/pre-commit. \ Consider moving it to .git/hooks/pre-push instead, which runs less often." ); } if suggest_setup || changelog_suggestion.is_some() { - println!("NOTE: this message was printed twice to make it more likely to be seen"); + eprintln!("NOTE: this message was printed twice to make it more likely to be seen"); } if dump_bootstrap_shims { diff --git a/src/bootstrap/src/bin/rustc.rs b/src/bootstrap/src/bin/rustc.rs index 88595ff7e51..e57ed488f97 100644 --- a/src/bootstrap/src/bin/rustc.rs +++ b/src/bootstrap/src/bin/rustc.rs @@ -306,7 +306,7 @@ fn main() { // should run on success, after this block. } if verbose > 0 { - println!("\nDid not run successfully: {status}\n{cmd:?}\n-------------"); + eprintln!("\nDid not run successfully: {status}\n{cmd:?}\n-------------"); } if let Some(mut on_fail) = on_fail { diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs index d46c0ab7fef..2af2e83db8f 100644 --- a/src/bootstrap/src/core/build_steps/check.rs +++ b/src/bootstrap/src/core/build_steps/check.rs @@ -287,7 +287,7 @@ impl Step for CodegenBackend { fn run(self, builder: &Builder<'_>) { // FIXME: remove once https://github.com/rust-lang/rust/issues/112393 is resolved if builder.build.config.vendor && self.backend == "gcc" { - println!("Skipping checking of `rustc_codegen_gcc` with vendoring enabled."); + eprintln!("Skipping checking of `rustc_codegen_gcc` with vendoring enabled."); return; } diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 0cacd6e4f37..93f8091299f 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -1611,7 +1611,7 @@ impl Step for Sysroot { let sysroot = sysroot_dir(compiler.stage); builder - .verbose(|| println!("Removing sysroot {} to avoid caching bugs", sysroot.display())); + .verbose(|| eprintln!("Removing sysroot {} to avoid caching bugs", sysroot.display())); let _ = fs::remove_dir_all(&sysroot); t!(fs::create_dir_all(&sysroot)); @@ -1681,7 +1681,7 @@ impl Step for Sysroot { return true; } if !filtered_files.iter().all(|f| f != path.file_name().unwrap()) { - builder.verbose_than(1, || println!("ignoring {}", path.display())); + builder.verbose_than(1, || eprintln!("ignoring {}", path.display())); false } else { true @@ -2240,7 +2240,7 @@ pub fn stream_cargo( cargo.arg(arg); } - builder.verbose(|| println!("running: {cargo:?}")); + builder.verbose(|| eprintln!("running: {cargo:?}")); if builder.config.dry_run() { return true; @@ -2266,7 +2266,7 @@ pub fn stream_cargo( cb(msg) } // If this was informational, just print it out and continue - Err(_) => println!("{line}"), + Err(_) => eprintln!("{line}"), } } diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index 0c739115165..57fce206f95 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -2080,7 +2080,7 @@ fn maybe_install_llvm( { let mut cmd = command(llvm_config); cmd.arg("--libfiles"); - builder.verbose(|| println!("running {cmd:?}")); + builder.verbose(|| eprintln!("running {cmd:?}")); let files = cmd.run_capture_stdout(builder).stdout(); let build_llvm_out = &builder.llvm_out(builder.config.build); let target_llvm_out = &builder.llvm_out(target); diff --git a/src/bootstrap/src/core/build_steps/format.rs b/src/bootstrap/src/core/build_steps/format.rs index 29a96f77672..d32e06d8748 100644 --- a/src/bootstrap/src/core/build_steps/format.rs +++ b/src/bootstrap/src/core/build_steps/format.rs @@ -107,10 +107,10 @@ fn print_paths(verb: &str, adjective: Option<&str>, paths: &[String]) { if let Some(adjective) = adjective { format!("{adjective} ") } else { String::new() }; if len <= 10 { for path in paths { - println!("fmt: {verb} {adjective}file {path}"); + eprintln!("fmt: {verb} {adjective}file {path}"); } } else { - println!("fmt: {verb} {len} {adjective}files"); + eprintln!("fmt: {verb} {len} {adjective}files"); } } @@ -199,7 +199,7 @@ pub fn format(build: &Builder<'_>, check: bool, all: bool, paths: &[PathBuf]) { match get_modified_rs_files(build) { Ok(Some(files)) => { if files.is_empty() { - println!("fmt info: No modified files detected for formatting."); + eprintln!("fmt info: No modified files detected for formatting."); return; } diff --git a/src/bootstrap/src/core/build_steps/install.rs b/src/bootstrap/src/core/build_steps/install.rs index 0ce86eadbce..b6862c2d5c4 100644 --- a/src/bootstrap/src/core/build_steps/install.rs +++ b/src/bootstrap/src/core/build_steps/install.rs @@ -21,9 +21,9 @@ const SHELL: &str = "sh"; /// We have to run a few shell scripts, which choke quite a bit on both `\` /// characters and on `C:\` paths, so normalize both of them away. -fn sanitize_sh(path: &Path) -> String { +fn sanitize_sh(path: &Path, is_cygwin: bool) -> String { let path = path.to_str().unwrap().replace('\\', "/"); - return change_drive(unc_to_lfs(&path)).unwrap_or(path); + return if is_cygwin { path } else { change_drive(unc_to_lfs(&path)).unwrap_or(path) }; fn unc_to_lfs(s: &str) -> &str { s.strip_prefix("//?/").unwrap_or(s) @@ -71,6 +71,7 @@ fn install_sh( let prefix = default_path(&builder.config.prefix, "/usr/local"); let sysconfdir = prefix.join(default_path(&builder.config.sysconfdir, "/etc")); let destdir_env = env::var_os("DESTDIR").map(PathBuf::from); + let is_cygwin = builder.config.build.is_cygwin(); // Sanity checks on the write access of user. // @@ -103,14 +104,14 @@ fn install_sh( let mut cmd = command(SHELL); cmd.current_dir(&empty_dir) - .arg(sanitize_sh(&tarball.decompressed_output().join("install.sh"))) - .arg(format!("--prefix={}", prepare_dir(&destdir_env, prefix))) - .arg(format!("--sysconfdir={}", prepare_dir(&destdir_env, sysconfdir))) - .arg(format!("--datadir={}", prepare_dir(&destdir_env, datadir))) - .arg(format!("--docdir={}", prepare_dir(&destdir_env, docdir))) - .arg(format!("--bindir={}", prepare_dir(&destdir_env, bindir))) - .arg(format!("--libdir={}", prepare_dir(&destdir_env, libdir))) - .arg(format!("--mandir={}", prepare_dir(&destdir_env, mandir))) + .arg(sanitize_sh(&tarball.decompressed_output().join("install.sh"), is_cygwin)) + .arg(format!("--prefix={}", prepare_dir(&destdir_env, prefix, is_cygwin))) + .arg(format!("--sysconfdir={}", prepare_dir(&destdir_env, sysconfdir, is_cygwin))) + .arg(format!("--datadir={}", prepare_dir(&destdir_env, datadir, is_cygwin))) + .arg(format!("--docdir={}", prepare_dir(&destdir_env, docdir, is_cygwin))) + .arg(format!("--bindir={}", prepare_dir(&destdir_env, bindir, is_cygwin))) + .arg(format!("--libdir={}", prepare_dir(&destdir_env, libdir, is_cygwin))) + .arg(format!("--mandir={}", prepare_dir(&destdir_env, mandir, is_cygwin))) .arg("--disable-ldconfig"); cmd.run(builder); t!(fs::remove_dir_all(&empty_dir)); @@ -120,7 +121,7 @@ fn default_path(config: &Option<PathBuf>, default: &str) -> PathBuf { config.as_ref().cloned().unwrap_or_else(|| PathBuf::from(default)) } -fn prepare_dir(destdir_env: &Option<PathBuf>, mut path: PathBuf) -> String { +fn prepare_dir(destdir_env: &Option<PathBuf>, mut path: PathBuf, is_cygwin: bool) -> String { // The DESTDIR environment variable is a standard way to install software in a subdirectory // while keeping the original directory structure, even if the prefix or other directories // contain absolute paths. @@ -146,7 +147,7 @@ fn prepare_dir(destdir_env: &Option<PathBuf>, mut path: PathBuf) -> String { assert!(path.is_absolute(), "could not make the path relative"); } - sanitize_sh(&path) + sanitize_sh(&path, is_cygwin) } macro_rules! install { diff --git a/src/bootstrap/src/core/build_steps/setup.rs b/src/bootstrap/src/core/build_steps/setup.rs index 7ed01f25c94..175e9982cc1 100644 --- a/src/bootstrap/src/core/build_steps/setup.rs +++ b/src/bootstrap/src/core/build_steps/setup.rs @@ -134,7 +134,7 @@ impl Step for Profile { t!(fs::remove_file(path)); } _ => { - println!("Exiting."); + eprintln!("Exiting."); crate::exit!(1); } } @@ -184,15 +184,15 @@ pub fn setup(config: &Config, profile: Profile) { Profile::Dist => &["dist", "build"], }; - println!(); + eprintln!(); - println!("To get started, try one of the following commands:"); + eprintln!("To get started, try one of the following commands:"); for cmd in suggestions { - println!("- `x.py {cmd}`"); + eprintln!("- `x.py {cmd}`"); } if profile != Profile::Dist { - println!( + eprintln!( "For more suggestions, see https://rustc-dev-guide.rust-lang.org/building/suggested.html" ); } @@ -224,7 +224,7 @@ fn setup_config_toml(path: &PathBuf, profile: Profile, config: &Config) { t!(fs::write(path, settings)); let include_path = profile.include_path(&config.src); - println!("`x.py` will now use the configuration at {}", include_path.display()); + eprintln!("`x.py` will now use the configuration at {}", include_path.display()); } /// Creates a toolchain link for stage1 using `rustup` @@ -256,7 +256,7 @@ impl Step for Link { } if !rustup_installed(builder) { - println!("WARNING: `rustup` is not installed; Skipping `stage1` toolchain linking."); + eprintln!("WARNING: `rustup` is not installed; Skipping `stage1` toolchain linking."); return; } @@ -296,7 +296,7 @@ fn attempt_toolchain_link(builder: &Builder<'_>, stage_path: &str) { } if try_link_toolchain(builder, stage_path) { - println!( + eprintln!( "Added `stage1` rustup toolchain; try `cargo +stage1 build` on a separate rust project to run a newly-built toolchain" ); } else { @@ -321,14 +321,14 @@ fn toolchain_is_linked(builder: &Builder<'_>) -> bool { return false; } // The toolchain has already been linked. - println!( + eprintln!( "`stage1` toolchain already linked; not attempting to link `stage1` toolchain" ); } None => { // In this case, we don't know if the `stage1` toolchain has been linked; // but `rustup` failed, so let's not go any further. - println!( + eprintln!( "`rustup` failed to list current toolchains; not attempting to link `stage1` toolchain" ); } @@ -389,12 +389,12 @@ pub fn interactive_path() -> io::Result<Profile> { input.parse() } - println!("Welcome to the Rust project! What do you want to do with x.py?"); + eprintln!("Welcome to the Rust project! What do you want to do with x.py?"); for ((letter, _), profile) in abbrev_all() { - println!("{}) {}: {}", letter, profile, profile.purpose()); + eprintln!("{}) {}: {}", letter, profile, profile.purpose()); } let template = loop { - print!( + eprint!( "Please choose one ({}): ", abbrev_all().map(|((l, _), _)| l).collect::<Vec<_>>().join("/") ); @@ -428,7 +428,7 @@ enum PromptResult { fn prompt_user(prompt: &str) -> io::Result<Option<PromptResult>> { let mut input = String::new(); loop { - print!("{prompt} "); + eprint!("{prompt} "); io::stdout().flush()?; input.clear(); io::stdin().read_line(&mut input)?; @@ -490,7 +490,7 @@ fn install_git_hook_maybe(builder: &Builder<'_>, config: &Config) -> io::Result< return Ok(()); } - println!( + eprintln!( "\nRust's CI will automatically fail if it doesn't pass `tidy`, the internal tool for ensuring code quality. If you'd like, x.py can install a git hook for you that will automatically run `test tidy` before pushing your code to ensure your code is up to par. If you decide later that this behavior is @@ -498,7 +498,7 @@ undesirable, simply delete the `pre-push` file from .git/hooks." ); if prompt_user("Would you like to install the git hook?: [y/N]")? != Some(PromptResult::Yes) { - println!("Ok, skipping installation!"); + eprintln!("Ok, skipping installation!"); return Ok(()); } if !hooks_dir.exists() { @@ -515,7 +515,7 @@ undesirable, simply delete the `pre-push` file from .git/hooks." ); return Err(e); } - Ok(_) => println!("Linked `src/etc/pre-push.sh` to `.git/hooks/pre-push`"), + Ok(_) => eprintln!("Linked `src/etc/pre-push.sh` to `.git/hooks/pre-push`"), }; Ok(()) } @@ -541,7 +541,7 @@ Select which editor you would like to set up [default: None]: "; let mut input = String::new(); loop { - print!("{}", prompt_str); + eprint!("{}", prompt_str); io::stdout().flush()?; input.clear(); io::stdin().read_line(&mut input)?; @@ -656,7 +656,7 @@ impl Step for Editor { if let Some(editor_kind) = editor_kind { while !t!(create_editor_settings_maybe(config, editor_kind.clone())) {} } else { - println!("Ok, skipping editor setup!"); + eprintln!("Ok, skipping editor setup!"); } } Err(e) => eprintln!("Could not determine the editor: {e}"), @@ -689,7 +689,7 @@ fn create_editor_settings_maybe(config: &Config, editor: EditorKind) -> io::Resu mismatched_settings = Some(false); } } - println!( + eprintln!( "\nx.py can automatically install the recommended `{settings_filename}` file for rustc development" ); @@ -708,7 +708,7 @@ fn create_editor_settings_maybe(config: &Config, editor: EditorKind) -> io::Resu Some(PromptResult::Yes) => true, Some(PromptResult::Print) => false, _ => { - println!("Ok, skipping settings!"); + eprintln!("Ok, skipping settings!"); return Ok(true); } }; @@ -735,9 +735,9 @@ fn create_editor_settings_maybe(config: &Config, editor: EditorKind) -> io::Resu _ => "Created", }; fs::write(&settings_path, editor.settings_template())?; - println!("{verb} `{}`", settings_filename); + eprintln!("{verb} `{}`", settings_filename); } else { - println!("\n{}", editor.settings_template()); + eprintln!("\n{}", editor.settings_template()); } Ok(should_create) } diff --git a/src/bootstrap/src/core/build_steps/suggest.rs b/src/bootstrap/src/core/build_steps/suggest.rs index ba9b1b2fc33..7b2d9fff8f5 100644 --- a/src/bootstrap/src/core/build_steps/suggest.rs +++ b/src/bootstrap/src/core/build_steps/suggest.rs @@ -66,6 +66,6 @@ pub fn suggest(builder: &Builder<'_>, run: bool) { build.build(); } } else { - println!("HELP: consider using the `--run` flag to automatically run suggested tests"); + eprintln!("HELP: consider using the `--run` flag to automatically run suggested tests"); } } diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 30fdea7e19e..380626952b2 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -471,11 +471,11 @@ impl Miri { // We re-use the `cargo` from above. cargo.arg("--print-sysroot"); - builder.verbose(|| println!("running: {cargo:?}")); + builder.verbose(|| eprintln!("running: {cargo:?}")); let stdout = cargo.run_capture_stdout(builder).stdout(); // Output is "<sysroot>\n". let sysroot = stdout.trim_end(); - builder.verbose(|| println!("`cargo miri setup --print-sysroot` said: {sysroot:?}")); + builder.verbose(|| eprintln!("`cargo miri setup --print-sysroot` said: {sysroot:?}")); PathBuf::from(sysroot) } } @@ -2488,7 +2488,7 @@ fn markdown_test(builder: &Builder<'_>, compiler: Compiler, markdown: &Path) -> } } - builder.verbose(|| println!("doc tests for: {}", markdown.display())); + builder.verbose(|| eprintln!("doc tests for: {}", markdown.display())); let mut cmd = builder.rustdoc_cmd(compiler); builder.add_rust_test_threads(&mut cmd); // allow for unstable options such as new editions diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs index 77f6edaabb2..38abca8b8da 100644 --- a/src/bootstrap/src/core/builder/cargo.rs +++ b/src/bootstrap/src/core/builder/cargo.rs @@ -523,7 +523,7 @@ impl Builder<'_> { let sysroot_str = sysroot.as_os_str().to_str().expect("sysroot should be UTF-8"); if self.is_verbose() && !matches!(self.config.dry_run, DryRun::SelfCheck) { - println!("using sysroot {sysroot_str}"); + eprintln!("using sysroot {sysroot_str}"); } let mut rustflags = Rustflags::new(target); diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index 026c26479d3..ffe3e053e72 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -392,14 +392,14 @@ impl StepDescription { fn is_excluded(&self, builder: &Builder<'_>, pathset: &PathSet) -> bool { if builder.config.skip.iter().any(|e| pathset.has(e, builder.kind)) { if !matches!(builder.config.dry_run, DryRun::SelfCheck) { - println!("Skipping {pathset:?} because it is excluded"); + eprintln!("Skipping {pathset:?} because it is excluded"); } return true; } if !builder.config.skip.is_empty() && !matches!(builder.config.dry_run, DryRun::SelfCheck) { builder.verbose(|| { - println!( + eprintln!( "{:?} not skipped for {:?} -- not in {:?}", pathset, self.name, builder.config.skip ) @@ -1437,11 +1437,11 @@ impl<'a> Builder<'a> { panic!("{}", out); } if let Some(out) = self.cache.get(&step) { - self.verbose_than(1, || println!("{}c {:?}", " ".repeat(stack.len()), step)); + self.verbose_than(1, || eprintln!("{}c {:?}", " ".repeat(stack.len()), step)); return out; } - self.verbose_than(1, || println!("{}> {:?}", " ".repeat(stack.len()), step)); + self.verbose_than(1, || eprintln!("{}> {:?}", " ".repeat(stack.len()), step)); stack.push(Box::new(step.clone())); } @@ -1462,7 +1462,7 @@ impl<'a> Builder<'a> { let step_string = format!("{step:?}"); let brace_index = step_string.find('{').unwrap_or(0); let type_string = type_name::<S>(); - println!( + eprintln!( "[TIMING] {} {} -- {}.{:03}", &type_string.strip_prefix("bootstrap::").unwrap_or(type_string), &step_string[brace_index..], @@ -1479,7 +1479,9 @@ impl<'a> Builder<'a> { let cur_step = stack.pop().expect("step stack empty"); assert_eq!(cur_step.downcast_ref(), Some(&step)); } - self.verbose_than(1, || println!("{}< {:?}", " ".repeat(self.stack.borrow().len()), step)); + self.verbose_than(1, || { + eprintln!("{}< {:?}", " ".repeat(self.stack.borrow().len()), step) + }); self.cache.put(step, out.clone()); out } diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index b06147055f2..002b990bb52 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -565,6 +565,12 @@ impl TargetSelection { self.ends_with("windows-gnu") } + pub fn is_cygwin(&self) -> bool { + self.is_windows() && + // ref. https://cygwin.com/pipermail/cygwin/2022-February/250802.html + env::var("OSTYPE").is_ok_and(|v| v.to_lowercase().contains("cygwin")) + } + /// Path to the file defining the custom target, if any. pub fn filepath(&self) -> Option<&Path> { self.file.as_ref().map(Path::new) @@ -1293,7 +1299,7 @@ impl Config { .map(|change_id| change_id.inner.map(crate::find_recent_config_change_ids)) { if !changes.is_empty() { - println!( + eprintln!( "WARNING: There have been changes to x.py since you last updated:\n{}", crate::human_readable_changes(&changes) ); @@ -1559,7 +1565,7 @@ impl Config { } if cargo_clippy.is_some() && rustc.is_none() { - println!( + eprintln!( "WARNING: Using `build.cargo-clippy` without `build.rustc` usually fails due to toolchain conflict." ); } @@ -1632,7 +1638,6 @@ impl Config { set(&mut config.docs_minification, docs_minification); set(&mut config.docs, docs); set(&mut config.locked_deps, locked_deps); - set(&mut config.vendor, vendor); set(&mut config.full_bootstrap, full_bootstrap); set(&mut config.extended, extended); config.tools = tools; @@ -1711,6 +1716,12 @@ impl Config { config.in_tree_llvm_info = GitInfo::new(false, &config.src.join("src/llvm-project")); config.in_tree_gcc_info = GitInfo::new(false, &config.src.join("src/gcc")); + config.vendor = vendor.unwrap_or( + config.rust_info.is_from_tarball() + && config.src.join("vendor").exists() + && config.src.join(".cargo/config.toml").exists(), + ); + if let Some(rust) = toml.rust { let Rust { optimize: optimize_toml, @@ -1841,7 +1852,7 @@ impl Config { // FIXME: Remove this option at the end of 2024. if parallel_compiler.is_some() { - println!( + eprintln!( "WARNING: The `rust.parallel-compiler` option is deprecated and does nothing. The parallel compiler (with one thread) is now the default" ); } @@ -1873,7 +1884,7 @@ impl Config { if available_backends.contains(&backend) { panic!("Invalid value '{s}' for 'rust.codegen-backends'. Instead, please use '{backend}'."); } else { - println!("HELP: '{s}' for 'rust.codegen-backends' might fail. \ + eprintln!("HELP: '{s}' for 'rust.codegen-backends' might fail. \ Codegen backends are mostly defined without the '{CODEGEN_BACKEND_PREFIX}' prefix. \ In this case, it would be referred to as '{backend}'."); } @@ -1902,7 +1913,7 @@ impl Config { // tests may fail due to using a different channel than the one used by the compiler during tests. if let Some(commit) = &config.download_rustc_commit { if is_user_configured_rust_channel { - println!( + eprintln!( "WARNING: `rust.download-rustc` is enabled. The `rust.channel` option will be overridden by the CI rustc's channel." ); @@ -1992,10 +2003,10 @@ impl Config { if config.llvm_from_ci { let warn = |option: &str| { - println!( + eprintln!( "WARNING: `{option}` will only be used on `compiler/rustc_llvm` build, not for the LLVM build." ); - println!( + eprintln!( "HELP: To use `{option}` for LLVM builds, set `download-ci-llvm` option to false." ); }; @@ -2014,12 +2025,12 @@ impl Config { // if they've chosen a different value. if libzstd.is_some() { - println!( + eprintln!( "WARNING: when using `download-ci-llvm`, the local `llvm.libzstd` option, \ like almost all `llvm.*` options, will be ignored and set by the LLVM CI \ artifacts builder config." ); - println!( + eprintln!( "HELP: To use `llvm.libzstd` for LLVM/LLD builds, set `download-ci-llvm` option to false." ); } @@ -2088,7 +2099,7 @@ impl Config { if available_backends.contains(&backend) { panic!("Invalid value '{s}' for 'target.{triple}.codegen-backends'. Instead, please use '{backend}'."); } else { - println!("HELP: '{s}' for 'target.{triple}.codegen-backends' might fail. \ + eprintln!("HELP: '{s}' for 'target.{triple}.codegen-backends' might fail. \ Codegen backends are mostly defined without the '{CODEGEN_BACKEND_PREFIX}' prefix. \ In this case, it would be referred to as '{backend}'."); } @@ -2304,7 +2315,7 @@ impl Config { if self.dry_run() { return Ok(()); } - self.verbose(|| println!("running: {cmd:?}")); + self.verbose(|| eprintln!("running: {cmd:?}")); build_helper::util::try_run(cmd, self.is_verbose()) } @@ -2479,7 +2490,7 @@ impl Config { // This happens when LLVM submodule is updated in CI, we should disable ci-rustc without an error // to not break CI. For non-CI environments, we should return an error. if CiEnv::is_ci() { - println!("WARNING: LLVM submodule has changes, `download-rustc` will be disabled."); + eprintln!("WARNING: LLVM submodule has changes, `download-rustc` will be disabled."); return None; } else { panic!("ERROR: LLVM submodule has changes, `download-rustc` can't be used."); @@ -2490,8 +2501,8 @@ impl Config { let ci_config_toml = match self.get_builder_toml("ci-rustc") { Ok(ci_config_toml) => ci_config_toml, Err(e) if e.to_string().contains("unknown field") => { - println!("WARNING: CI rustc has some fields that are no longer supported in bootstrap; download-rustc will be disabled."); - println!("HELP: Consider rebasing to a newer commit if available."); + eprintln!("WARNING: CI rustc has some fields that are no longer supported in bootstrap; download-rustc will be disabled."); + eprintln!("HELP: Consider rebasing to a newer commit if available."); return None; }, Err(e) => { @@ -2516,7 +2527,7 @@ impl Config { .is_some_and(|s| s == "1" || s == "true"); if disable_ci_rustc_if_incompatible && res.is_err() { - println!("WARNING: download-rustc is disabled with `DISABLE_CI_RUSTC_IF_INCOMPATIBLE` env."); + eprintln!("WARNING: download-rustc is disabled with `DISABLE_CI_RUSTC_IF_INCOMPATIBLE` env."); return None; } @@ -2701,7 +2712,7 @@ impl Config { return; } - println!("Updating submodule {relative_path}"); + eprintln!("Updating submodule {relative_path}"); self.check_run( helpers::git(Some(&self.src)) .run_always() @@ -2824,7 +2835,7 @@ impl Config { Some(StringOrBool::Bool(true)) => false, Some(StringOrBool::String(s)) if s == "if-unchanged" => { if !self.rust_info.is_managed_git_subrepository() { - println!( + eprintln!( "ERROR: `download-rustc=if-unchanged` is only compatible with Git managed sources." ); crate::exit!(1); @@ -2857,10 +2868,10 @@ impl Config { if if_unchanged { return None; } - println!("ERROR: could not find commit hash for downloading rustc"); - println!("HELP: maybe your repository history is too shallow?"); - println!("HELP: consider setting `rust.download-rustc=false` in config.toml"); - println!("HELP: or fetch enough history to include one upstream commit"); + eprintln!("ERROR: could not find commit hash for downloading rustc"); + eprintln!("HELP: maybe your repository history is too shallow?"); + eprintln!("HELP: consider setting `rust.download-rustc=false` in config.toml"); + eprintln!("HELP: or fetch enough history to include one upstream commit"); crate::exit!(1); } }; @@ -2899,7 +2910,7 @@ impl Config { let if_unchanged = || { if self.rust_info.is_from_tarball() { // Git is needed for running "if-unchanged" logic. - println!( + eprintln!( "WARNING: 'if-unchanged' has no effect on tarball sources; ignoring `download-ci-llvm`." ); return false; @@ -2948,10 +2959,10 @@ impl Config { // Only commits merged by bors will have CI artifacts. let commit = get_closest_merge_commit(Some(&self.src), &self.git_config(), &[]).unwrap(); if commit.is_empty() { - println!("error: could not find commit hash for downloading components from CI"); - println!("help: maybe your repository history is too shallow?"); - println!("help: consider disabling `{option_name}`"); - println!("help: or fetch enough history to include one upstream commit"); + eprintln!("error: could not find commit hash for downloading components from CI"); + eprintln!("help: maybe your repository history is too shallow?"); + eprintln!("help: consider disabling `{option_name}`"); + eprintln!("help: or fetch enough history to include one upstream commit"); crate::exit!(1); } @@ -2963,14 +2974,14 @@ impl Config { if has_changes { if if_unchanged { if self.is_verbose() { - println!( + eprintln!( "warning: saw changes to one of {modified_paths:?} since {commit}; \ ignoring `{option_name}`" ); } return None; } - println!( + eprintln!( "warning: `{option_name}` is enabled, but there are changes to one of {modified_paths:?}" ); } @@ -3007,7 +3018,7 @@ pub(crate) fn check_incompatible_options_for_ci_llvm( ($current:expr, $expected:expr) => { if let Some(current) = &$current { if Some(current) != $expected.as_ref() { - println!( + eprintln!( "WARNING: `llvm.{}` has no effect with `llvm.download-ci-llvm`. \ Current value: {:?}, Expected value(s): {}{:?}", stringify!($expected).replace("_", "-"), @@ -3112,7 +3123,7 @@ fn check_incompatible_options_for_ci_rustc( ($current:expr, $expected:expr, $config_section:expr) => { if let Some(current) = &$current { if Some(current) != $expected.as_ref() { - println!( + eprintln!( "WARNING: `{}` has no effect with `rust.download-rustc`. \ Current value: {:?}, Expected value(s): {}{:?}", format!("{}.{}", $config_section, stringify!($expected).replace("_", "-")), diff --git a/src/bootstrap/src/core/config/flags.rs b/src/bootstrap/src/core/config/flags.rs index bfeb811508c..66b9f5ed84e 100644 --- a/src/bootstrap/src/core/config/flags.rs +++ b/src/bootstrap/src/core/config/flags.rs @@ -196,12 +196,12 @@ impl Flags { if let Ok(HelpVerboseOnly { help: true, verbose: 1.., cmd: subcommand }) = HelpVerboseOnly::try_parse_from(normalize_args(args)) { - println!("NOTE: updating submodules before printing available paths"); + eprintln!("NOTE: updating submodules before printing available paths"); let config = Config::parse(Self::parse(&[String::from("build")])); let build = Build::new(config); let paths = Builder::get_help(&build, subcommand); if let Some(s) = paths { - println!("{s}"); + eprintln!("{s}"); } else { panic!("No paths available for subcommand `{}`", subcommand.as_str()); } diff --git a/src/bootstrap/src/core/download.rs b/src/bootstrap/src/core/download.rs index db35e6907e6..05b91c518cf 100644 --- a/src/bootstrap/src/core/download.rs +++ b/src/bootstrap/src/core/download.rs @@ -77,7 +77,7 @@ impl Config { if self.dry_run() && !cmd.run_always { return true; } - self.verbose(|| println!("running: {cmd:?}")); + self.verbose(|| eprintln!("running: {cmd:?}")); check_run(cmd, self.is_verbose()) } @@ -144,7 +144,7 @@ impl Config { /// Please see <https://nixos.org/patchelf.html> for more information fn fix_bin_or_dylib(&self, fname: &Path) { assert_eq!(SHOULD_FIX_BINS_AND_DYLIBS.get(), Some(&true)); - println!("attempting to patch {}", fname.display()); + eprintln!("attempting to patch {}", fname.display()); // Only build `.nix-deps` once. static NIX_DEPS_DIR: OnceLock<PathBuf> = OnceLock::new(); @@ -206,7 +206,7 @@ impl Config { } fn download_file(&self, url: &str, dest_path: &Path, help_on_error: &str) { - self.verbose(|| println!("download {url}")); + self.verbose(|| eprintln!("download {url}")); // Use a temporary file in case we crash while downloading, to avoid a corrupt download in cache/. let tempfile = self.tempdir().join(dest_path.file_name().unwrap()); // While bootstrap itself only supports http and https downloads, downstream forks might @@ -226,7 +226,7 @@ impl Config { } fn download_http_with_retries(&self, tempfile: &Path, url: &str, help_on_error: &str) { - println!("downloading {url}"); + eprintln!("downloading {url}"); // Try curl. If that fails and we are on windows, fallback to PowerShell. // options should be kept in sync with // src/bootstrap/src/core/download.rs @@ -341,7 +341,7 @@ impl Config { short_path = short_path.strip_prefix(pattern).unwrap_or(short_path); let dst_path = dst.join(short_path); self.verbose(|| { - println!("extracting {} to {}", original_path.display(), dst.display()) + eprintln!("extracting {} to {}", original_path.display(), dst.display()) }); if !t!(member.unpack_in(dst)) { panic!("path traversal attack ??"); @@ -365,7 +365,7 @@ impl Config { pub(crate) fn verify(&self, path: &Path, expected: &str) -> bool { use sha2::Digest; - self.verbose(|| println!("verifying {}", path.display())); + self.verbose(|| eprintln!("verifying {}", path.display())); if self.dry_run() { return false; @@ -391,7 +391,7 @@ impl Config { let verified = checksum == expected; if !verified { - println!( + eprintln!( "invalid checksum: \n\ found: {checksum}\n\ expected: {expected}", @@ -421,7 +421,7 @@ enum DownloadSource { /// Functions that are only ever called once, but named for clarify and to avoid thousand-line functions. impl Config { pub(crate) fn download_clippy(&self) -> PathBuf { - self.verbose(|| println!("downloading stage0 clippy artifacts")); + self.verbose(|| eprintln!("downloading stage0 clippy artifacts")); let date = &self.stage0_metadata.compiler.date; let version = &self.stage0_metadata.compiler.version; @@ -518,7 +518,7 @@ impl Config { } pub(crate) fn download_ci_rustc(&self, commit: &str) { - self.verbose(|| println!("using downloaded stage2 artifacts from CI (commit {commit})")); + self.verbose(|| eprintln!("using downloaded stage2 artifacts from CI (commit {commit})")); let version = self.artifact_version_part(commit); // download-rustc doesn't need its own cargo, it can just use beta's. But it does need the @@ -539,7 +539,7 @@ impl Config { #[cfg(not(feature = "bootstrap-self-test"))] pub(crate) fn download_beta_toolchain(&self) { - self.verbose(|| println!("downloading stage0 beta artifacts")); + self.verbose(|| eprintln!("downloading stage0 beta artifacts")); let date = &self.stage0_metadata.compiler.date; let version = &self.stage0_metadata.compiler.version; @@ -677,7 +677,7 @@ impl Config { return; } else { self.verbose(|| { - println!( + eprintln!( "ignoring cached file {} due to failed verification", tarball.display() ) @@ -776,10 +776,10 @@ download-rustc = false t!(check_incompatible_options_for_ci_llvm(current_config_toml, ci_config_toml)); } Err(e) if e.to_string().contains("unknown field") => { - println!( + eprintln!( "WARNING: CI LLVM has some fields that are no longer supported in bootstrap; download-ci-llvm will be disabled." ); - println!("HELP: Consider rebasing to a newer commit if available."); + eprintln!("HELP: Consider rebasing to a newer commit if available."); } Err(e) => { eprintln!("ERROR: Failed to parse CI LLVM config.toml: {e}"); diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs index dcf68cbeeda..71e7f40f032 100644 --- a/src/bootstrap/src/core/sanity.rs +++ b/src/bootstrap/src/core/sanity.rs @@ -237,11 +237,11 @@ than building it. stage0_supported_target_list.intersection(&missing_targets_hashset).collect(); if !duplicated_targets.is_empty() { - println!( + eprintln!( "Following targets supported from the stage0 compiler, please remove them from STAGE0_MISSING_TARGETS list." ); for duplicated_target in duplicated_targets { - println!(" {duplicated_target}"); + eprintln!(" {duplicated_target}"); } std::process::exit(1); } diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index 0ecf61ffcd9..5f778223d7d 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -406,11 +406,11 @@ impl Build { .unwrap() .trim(); if local_release.split('.').take(2).eq(version.split('.').take(2)) { - build.verbose(|| println!("auto-detected local-rebuild {local_release}")); + build.verbose(|| eprintln!("auto-detected local-rebuild {local_release}")); build.local_rebuild = true; } - build.verbose(|| println!("finding compilers")); + build.verbose(|| eprintln!("finding compilers")); utils::cc_detect::find(&build); // When running `setup`, the profile is about to change, so any requirements we have now may // be different on the next invocation. Don't check for them until the next time x.py is @@ -418,7 +418,7 @@ impl Build { // // Similarly, for `setup` we don't actually need submodules or cargo metadata. if !matches!(build.config.cmd, Subcommand::Setup { .. }) { - build.verbose(|| println!("running sanity check")); + build.verbose(|| eprintln!("running sanity check")); crate::core::sanity::check(&mut build); // Make sure we update these before gathering metadata so we don't get an error about missing @@ -436,7 +436,7 @@ impl Build { // Now, update all existing submodules. build.update_existing_submodules(); - build.verbose(|| println!("learning about cargo")); + build.verbose(|| eprintln!("learning about cargo")); crate::core::metadata::build(&mut build); } @@ -605,7 +605,7 @@ impl Build { let stamp = dir.join(".stamp"); let mut cleared = false; if mtime(&stamp) < mtime(input) { - self.verbose(|| println!("Dirty - {}", dir.display())); + self.verbose(|| eprintln!("Dirty - {}", dir.display())); let _ = fs::remove_dir_all(dir); cleared = true; } else if stamp.exists() { @@ -890,7 +890,7 @@ impl Build { let executed_at = std::panic::Location::caller(); self.verbose(|| { - println!("running: {command:?} (created at {created_at}, executed at {executed_at})") + eprintln!("running: {command:?} (created at {created_at}, executed at {executed_at})") }); let cmd = command.as_command_mut(); @@ -947,7 +947,7 @@ Executed at: {executed_at}"#, let fail = |message: &str, output: CommandOutput| -> ! { if self.is_verbose() { - println!("{message}"); + eprintln!("{message}"); } else { let (stdout, stderr) = (output.stdout_if_present(), output.stderr_if_present()); // If the command captures output, the user would not see any indication that @@ -957,16 +957,16 @@ Executed at: {executed_at}"#, if let Some(stdout) = output.stdout_if_present().take_if(|s| !s.trim().is_empty()) { - println!("STDOUT:\n{stdout}\n"); + eprintln!("STDOUT:\n{stdout}\n"); } if let Some(stderr) = output.stderr_if_present().take_if(|s| !s.trim().is_empty()) { - println!("STDERR:\n{stderr}\n"); + eprintln!("STDERR:\n{stderr}\n"); } - println!("Command {command:?} has failed. Rerun with -v to see more details."); + eprintln!("Command {command:?} has failed. Rerun with -v to see more details."); } else { - println!("Command has failed. Rerun with -v to see more details."); + eprintln!("Command has failed. Rerun with -v to see more details."); } } exit!(1); @@ -1011,7 +1011,7 @@ Executed at: {executed_at}"#, match self.config.dry_run { DryRun::SelfCheck => (), DryRun::Disabled | DryRun::UserSelected => { - println!("{msg}"); + eprintln!("{msg}"); } } } @@ -1666,7 +1666,7 @@ Executed at: {executed_at}"#, if self.config.dry_run() { return; } - self.verbose_than(1, || println!("Copy/Link {src:?} to {dst:?}")); + self.verbose_than(1, || eprintln!("Copy/Link {src:?} to {dst:?}")); if src == dst { return; } @@ -1775,7 +1775,7 @@ Executed at: {executed_at}"#, return; } let dst = dstdir.join(src.file_name().unwrap()); - self.verbose_than(1, || println!("Install {src:?} to {dst:?}")); + self.verbose_than(1, || eprintln!("Install {src:?} to {dst:?}")); t!(fs::create_dir_all(dstdir)); if !src.exists() { panic!("ERROR: File \"{}\" not found!", src.display()); diff --git a/src/bootstrap/src/utils/cc_detect.rs b/src/bootstrap/src/utils/cc_detect.rs index 0df00469452..e8d5b60948a 100644 --- a/src/bootstrap/src/utils/cc_detect.rs +++ b/src/bootstrap/src/utils/cc_detect.rs @@ -155,15 +155,15 @@ pub fn find_target(build: &Build, target: TargetSelection) { build.cxx.borrow_mut().insert(target, compiler); } - build.verbose(|| println!("CC_{} = {:?}", target.triple, build.cc(target))); - build.verbose(|| println!("CFLAGS_{} = {cflags:?}", target.triple)); + build.verbose(|| eprintln!("CC_{} = {:?}", target.triple, build.cc(target))); + build.verbose(|| eprintln!("CFLAGS_{} = {cflags:?}", target.triple)); if let Ok(cxx) = build.cxx(target) { let cxxflags = build.cflags(target, GitRepo::Rustc, CLang::Cxx); - build.verbose(|| println!("CXX_{} = {cxx:?}", target.triple)); - build.verbose(|| println!("CXXFLAGS_{} = {cxxflags:?}", target.triple)); + build.verbose(|| eprintln!("CXX_{} = {cxx:?}", target.triple)); + build.verbose(|| eprintln!("CXXFLAGS_{} = {cxxflags:?}", target.triple)); } if let Some(ar) = ar { - build.verbose(|| println!("AR_{} = {ar:?}", target.triple)); + build.verbose(|| eprintln!("AR_{} = {ar:?}", target.triple)); build.ar.borrow_mut().insert(target, ar); } diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs index 41a541d7269..f4f189c718a 100644 --- a/src/bootstrap/src/utils/change_tracker.rs +++ b/src/bootstrap/src/utils/change_tracker.rs @@ -310,4 +310,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[ severity: ChangeSeverity::Warning, summary: "Revert `rust.download-rustc` global default to `false` and only use `rust.download-rustc = \"if-unchanged\"` default for library and tools profile. As alt CI rustc is built without debug assertions, `rust.debug-assertions = true` will now inhibit downloading CI rustc.", }, + ChangeInfo { + change_id: 133853, + severity: ChangeSeverity::Info, + summary: "`build.vendor` is now enabled by default for dist/tarball sources when 'vendor' directory and '.cargo/config.toml' file are present.", + }, ]; diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs index 923cc2dfc28..c0d52fd3430 100644 --- a/src/bootstrap/src/utils/helpers.rs +++ b/src/bootstrap/src/utils/helpers.rs @@ -135,7 +135,7 @@ impl Drop for TimeIt { fn drop(&mut self) { let time = self.1.elapsed(); if !self.0 { - println!("\tfinished in {}.{:03} seconds", time.as_secs(), time.subsec_millis()); + eprintln!("\tfinished in {}.{:03} seconds", time.as_secs(), time.subsec_millis()); } } } @@ -267,12 +267,12 @@ pub fn check_run(cmd: &mut BootstrapCommand, print_cmd_on_fail: bool) -> bool { let status = match cmd.as_command_mut().status() { Ok(status) => status, Err(e) => { - println!("failed to execute command: {cmd:?}\nERROR: {e}"); + eprintln!("failed to execute command: {cmd:?}\nERROR: {e}"); return false; } }; if !status.success() && print_cmd_on_fail { - println!( + eprintln!( "\n\ncommand did not execute successfully: {cmd:?}\n\ expected success, got: {status}\n\n" ); diff --git a/src/bootstrap/src/utils/metrics.rs b/src/bootstrap/src/utils/metrics.rs index b51fd490535..06d3add6281 100644 --- a/src/bootstrap/src/utils/metrics.rs +++ b/src/bootstrap/src/utils/metrics.rs @@ -185,7 +185,7 @@ impl BuildMetrics { if version.format_version == CURRENT_FORMAT_VERSION { t!(serde_json::from_slice::<JsonRoot>(&contents)).invocations } else { - println!( + eprintln!( "WARNING: overriding existing build/metrics.json, as it's not \ compatible with build metrics format version {CURRENT_FORMAT_VERSION}." ); diff --git a/src/bootstrap/src/utils/render_tests.rs b/src/bootstrap/src/utils/render_tests.rs index eb2c8254dc0..7a3ec61c6da 100644 --- a/src/bootstrap/src/utils/render_tests.rs +++ b/src/bootstrap/src/utils/render_tests.rs @@ -56,7 +56,7 @@ fn run_tests(builder: &Builder<'_>, cmd: &mut BootstrapCommand, stream: bool) -> let cmd = cmd.as_command_mut(); cmd.stdout(Stdio::piped()); - builder.verbose(|| println!("running: {cmd:?}")); + builder.verbose(|| eprintln!("running: {cmd:?}")); let mut process = cmd.spawn().unwrap(); @@ -71,7 +71,7 @@ fn run_tests(builder: &Builder<'_>, cmd: &mut BootstrapCommand, stream: bool) -> let result = process.wait_with_output().unwrap(); if !result.status.success() && builder.is_verbose() { - println!( + eprintln!( "\n\ncommand did not execute successfully: {cmd:?}\n\ expected success, got: {}", result.status @@ -135,7 +135,9 @@ impl<'a> Renderer<'a> { if self.up_to_date_tests > 0 { let n = self.up_to_date_tests; let s = if n > 1 { "s" } else { "" }; - println!("help: ignored {n} up-to-date test{s}; use `--force-rerun` to prevent this\n"); + eprintln!( + "help: ignored {n} up-to-date test{s}; use `--force-rerun` to prevent this\n" + ); } } @@ -185,12 +187,12 @@ impl<'a> Renderer<'a> { } fn render_test_outcome_verbose(&self, outcome: Outcome<'_>, test: &TestOutcome) { - print!("test {} ... ", test.name); - self.builder.colored_stdout(|stdout| outcome.write_long(stdout)).unwrap(); + eprint!("test {} ... ", test.name); + self.builder.colored_stderr(|stdout| outcome.write_long(stdout)).unwrap(); if let Some(exec_time) = test.exec_time { - print!(" ({exec_time:.2?})"); + eprint!(" ({exec_time:.2?})"); } - println!(); + eprintln!(); } fn render_test_outcome_terse(&mut self, outcome: Outcome<'_>, test: &TestOutcome) { @@ -198,45 +200,45 @@ impl<'a> Renderer<'a> { if let Some(total) = self.tests_count { let total = total.to_string(); let executed = format!("{:>width$}", self.executed_tests - 1, width = total.len()); - print!(" {executed}/{total}"); + eprint!(" {executed}/{total}"); } - println!(); + eprintln!(); self.terse_tests_in_line = 0; } self.terse_tests_in_line += 1; - self.builder.colored_stdout(|stdout| outcome.write_short(stdout, &test.name)).unwrap(); + self.builder.colored_stderr(|stdout| outcome.write_short(stdout, &test.name)).unwrap(); let _ = std::io::stdout().flush(); } fn render_suite_outcome(&self, outcome: Outcome<'_>, suite: &SuiteOutcome) { // The terse output doesn't end with a newline, so we need to add it ourselves. if !self.builder.config.verbose_tests { - println!(); + eprintln!(); } if !self.failures.is_empty() { - println!("\nfailures:\n"); + eprintln!("\nfailures:\n"); for failure in &self.failures { if failure.stdout.is_some() || failure.message.is_some() { - println!("---- {} stdout ----", failure.name); + eprintln!("---- {} stdout ----", failure.name); if let Some(stdout) = &failure.stdout { - println!("{stdout}"); + eprintln!("{stdout}"); } if let Some(message) = &failure.message { - println!("NOTE: {message}"); + eprintln!("NOTE: {message}"); } } } - println!("\nfailures:"); + eprintln!("\nfailures:"); for failure in &self.failures { - println!(" {}", failure.name); + eprintln!(" {}", failure.name); } } if !self.benches.is_empty() { - println!("\nbenchmarks:"); + eprintln!("\nbenchmarks:"); let mut rows = Vec::new(); for bench in &self.benches { @@ -251,13 +253,13 @@ impl<'a> Renderer<'a> { let max_1 = rows.iter().map(|r| r.1.len()).max().unwrap_or(0); let max_2 = rows.iter().map(|r| r.2.len()).max().unwrap_or(0); for row in &rows { - println!(" {:<max_0$} {:>max_1$} {:>max_2$}", row.0, row.1, row.2); + eprintln!(" {:<max_0$} {:>max_1$} {:>max_2$}", row.0, row.1, row.2); } } - print!("\ntest result: "); - self.builder.colored_stdout(|stdout| outcome.write_long(stdout)).unwrap(); - println!( + eprint!("\ntest result: "); + self.builder.colored_stderr(|stdout| outcome.write_long(stdout)).unwrap(); + eprintln!( ". {} passed; {} failed; {} ignored; {} measured; {} filtered out{time}\n", suite.passed, suite.failed, @@ -274,7 +276,7 @@ impl<'a> Renderer<'a> { fn render_message(&mut self, message: Message) { match message { Message::Suite(SuiteMessage::Started { test_count }) => { - println!("\nrunning {test_count} tests"); + eprintln!("\nrunning {test_count} tests"); self.executed_tests = 0; self.terse_tests_in_line = 0; self.tests_count = Some(test_count); @@ -314,7 +316,7 @@ impl<'a> Renderer<'a> { self.failures.push(outcome); } Message::Test(TestMessage::Timeout { name }) => { - println!("test {name} has been running for a long time"); + eprintln!("test {name} has been running for a long time"); } Message::Test(TestMessage::Started) => {} // Not useful } diff --git a/src/bootstrap/src/utils/tarball.rs b/src/bootstrap/src/utils/tarball.rs index 3c6c7a7fa18..f60498a4872 100644 --- a/src/bootstrap/src/utils/tarball.rs +++ b/src/bootstrap/src/utils/tarball.rs @@ -344,7 +344,7 @@ impl<'a> Tarball<'a> { // For `x install` tarball files aren't needed, so we can speed up the process by not producing them. let compression_profile = if self.builder.kind == Kind::Install { self.builder.verbose(|| { - println!("Forcing dist.compression-profile = 'no-op' for `x install`.") + eprintln!("Forcing dist.compression-profile = 'no-op' for `x install`.") }); // "no-op" indicates that the rust-installer won't produce compressed tarball sources. "no-op" diff --git a/src/ci/docker/host-x86_64/dist-arm-linux/Dockerfile b/src/ci/docker/host-aarch64/dist-arm-linux/Dockerfile index 420c42bc9d8..4a749473004 100644 --- a/src/ci/docker/host-x86_64/dist-arm-linux/Dockerfile +++ b/src/ci/docker/host-aarch64/dist-arm-linux/Dockerfile @@ -19,7 +19,7 @@ RUN sh /scripts/rustbuild-setup.sh WORKDIR /tmp COPY scripts/crosstool-ng-build.sh /scripts/ -COPY host-x86_64/dist-arm-linux/arm-linux-gnueabi.defconfig /tmp/crosstool.defconfig +COPY host-aarch64/dist-arm-linux/arm-linux-gnueabi.defconfig /tmp/crosstool.defconfig RUN /scripts/crosstool-ng-build.sh COPY scripts/sccache.sh /scripts/ diff --git a/src/ci/docker/host-x86_64/dist-arm-linux/arm-linux-gnueabi.defconfig b/src/ci/docker/host-aarch64/dist-arm-linux/arm-linux-gnueabi.defconfig index e7afdbe9d4d..e7afdbe9d4d 100644 --- a/src/ci/docker/host-x86_64/dist-arm-linux/arm-linux-gnueabi.defconfig +++ b/src/ci/docker/host-aarch64/dist-arm-linux/arm-linux-gnueabi.defconfig diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 288b133f0da..959a9580e60 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -43,7 +43,7 @@ runners: os: windows-2022-16core-64gb <<: *base-job - - &job-aarch64-linux + - &job-linux-8c-aarch64 os: ubuntu-22.04-arm64-8core-32gb envs: @@ -139,10 +139,10 @@ auto: ############################# - image: aarch64-gnu - <<: *job-aarch64-linux + <<: *job-linux-8c-aarch64 - image: aarch64-gnu-debug - <<: *job-aarch64-linux + <<: *job-linux-8c-aarch64 - image: arm-android <<: *job-linux-4c @@ -159,7 +159,7 @@ auto: <<: *job-linux-4c - image: dist-arm-linux - <<: *job-linux-8c + <<: *job-linux-8c-aarch64 - image: dist-armhf-linux <<: *job-linux-4c diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 34141c47cf3..50dfe0a1b56 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1841,9 +1841,6 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T TyKind::BareFn(barefn) => BareFunction(Box::new(clean_bare_fn_ty(barefn, cx))), // Rustdoc handles `TyKind::Err`s by turning them into `Type::Infer`s. TyKind::Infer | TyKind::Err(_) | TyKind::Typeof(..) | TyKind::InferDelegation(..) => Infer, - TyKind::AnonAdt(..) => { - unimplemented!("Anonymous structs or unions are not supported yet") - } } } diff --git a/src/tools/clippy/clippy_lints/src/default.rs b/src/tools/clippy/clippy_lints/src/default.rs index de775b64795..ffdd946aadb 100644 --- a/src/tools/clippy/clippy_lints/src/default.rs +++ b/src/tools/clippy/clippy_lints/src/default.rs @@ -5,7 +5,7 @@ use clippy_utils::{contains_name, get_parent_expr, in_automatically_derived, is_ use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; use rustc_hir::def::Res; -use rustc_hir::{Block, Expr, ExprKind, PatKind, QPath, Stmt, StmtKind}; +use rustc_hir::{Block, Expr, ExprKind, PatKind, QPath, Stmt, StmtKind, StructTailExpr}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_middle::ty::print::with_forced_trimmed_paths; @@ -285,7 +285,7 @@ fn field_reassigned_by_stmt<'tcx>(this: &Stmt<'tcx>, binding_name: Symbol) -> Op /// Returns whether `expr` is the update syntax base: `Foo { a: 1, .. base }` fn is_update_syntax_base<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool { if let Some(parent) = get_parent_expr(cx, expr) - && let ExprKind::Struct(_, _, Some(base)) = parent.kind + && let ExprKind::Struct(_, _, StructTailExpr::Base(base)) = parent.kind { base.hir_id == expr.hir_id } else { diff --git a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs index ef6b141920d..6819ad547f8 100644 --- a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs +++ b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs @@ -4,7 +4,7 @@ use clippy_utils::source::snippet_opt; use rustc_ast::ast::{LitFloatType, LitIntType, LitKind}; use rustc_errors::Applicability; use rustc_hir::intravisit::{Visitor, walk_expr, walk_stmt}; -use rustc_hir::{Block, Body, ConstContext, Expr, ExprKind, FnRetTy, HirId, Lit, Stmt, StmtKind}; +use rustc_hir::{Block, Body, ConstContext, Expr, ExprKind, FnRetTy, HirId, Lit, Stmt, StmtKind, StructTailExpr}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::{self, FloatTy, IntTy, PolyFnSig, Ty}; @@ -197,7 +197,7 @@ impl<'tcx> Visitor<'tcx> for NumericFallbackVisitor<'_, 'tcx> { } // Visit base with no bound. - if let Some(base) = base { + if let StructTailExpr::Base(base) = base { self.ty_bounds.push(ExplicitTyBound(false)); self.visit_expr(base); self.ty_bounds.pop(); diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs index c449a1a875b..c300f7cd665 100644 --- a/src/tools/clippy/clippy_lints/src/dereference.rs +++ b/src/tools/clippy/clippy_lints/src/dereference.rs @@ -818,7 +818,6 @@ impl TyCoercionStability { | TyKind::Typeof(..) | TyKind::TraitObject(..) | TyKind::InferDelegation(..) - | TyKind::AnonAdt(..) | TyKind::Err(_) => Self::Reborrow, }; } diff --git a/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs b/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs index d386bfca6ba..4fcd2abb769 100644 --- a/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs +++ b/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs @@ -3,7 +3,7 @@ use clippy_utils::fulfill_or_allowed; use clippy_utils::source::snippet; use rustc_data_structures::fx::FxHashMap; use rustc_errors::Applicability; -use rustc_hir::{self as hir, ExprKind}; +use rustc_hir::{self as hir, ExprKind, StructTailExpr}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; use rustc_span::symbol::Symbol; @@ -95,7 +95,7 @@ impl<'tcx> LateLintPass<'tcx> for InconsistentStructConstructor { } fields_snippet.push_str(&last_ident.to_string()); - let base_snippet = if let Some(base) = base { + let base_snippet = if let StructTailExpr::Base(base) = base { format!(", ..{}", snippet(cx, base.span, "..")) } else { String::new() diff --git a/src/tools/clippy/clippy_lints/src/init_numbered_fields.rs b/src/tools/clippy/clippy_lints/src/init_numbered_fields.rs index 7f183bb601e..7a14bbfb9e8 100644 --- a/src/tools/clippy/clippy_lints/src/init_numbered_fields.rs +++ b/src/tools/clippy/clippy_lints/src/init_numbered_fields.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::{snippet_with_applicability, snippet_with_context}; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::{Expr, ExprKind}; +use rustc_hir::{Expr, ExprKind, StructTailExpr}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; use rustc_span::SyntaxContext; @@ -43,7 +43,7 @@ declare_lint_pass!(NumberedFields => [INIT_NUMBERED_FIELDS]); impl<'tcx> LateLintPass<'tcx> for NumberedFields { fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { - if let ExprKind::Struct(path, fields @ [field, ..], None) = e.kind + if let ExprKind::Struct(path, fields @ [field, ..], StructTailExpr::None) = e.kind // If the first character of any field is a digit it has to be a tuple. && field.ident.as_str().as_bytes().first().is_some_and(u8::is_ascii_digit) // Type aliases can't be used as functions. diff --git a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs index 1c55e3e22e8..ed9879de13b 100644 --- a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs @@ -5,7 +5,7 @@ use clippy_utils::higher::ForLoop; use clippy_utils::macros::root_macro_call_first_node; use clippy_utils::source::snippet; use rustc_errors::Applicability; -use rustc_hir::{Block, Destination, Expr, ExprKind, HirId, InlineAsmOperand, Pat, Stmt, StmtKind}; +use rustc_hir::{Block, Destination, Expr, ExprKind, HirId, InlineAsmOperand, Pat, Stmt, StmtKind, StructTailExpr}; use rustc_lint::LateContext; use rustc_span::{Span, sym}; use std::iter::once; @@ -164,7 +164,7 @@ fn never_loop_expr<'tcx>( }, ExprKind::Struct(_, fields, base) => { let fields = never_loop_expr_all(cx, fields.iter().map(|f| f.expr), local_labels, main_loop_id); - if let Some(base) = base { + if let StructTailExpr::Base(base) = base { combine_seq(fields, || never_loop_expr(cx, base, local_labels, main_loop_id)) } else { fields diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs index cd90d2f90f7..6f3f371a68d 100644 --- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs +++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs @@ -200,6 +200,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { cx.param_env, ty, traits::ObligationCause::dummy_with_span(span), + rustc_hir::Safety::Safe, ) .is_ok() { diff --git a/src/tools/clippy/clippy_lints/src/needless_update.rs b/src/tools/clippy/clippy_lints/src/needless_update.rs index 6a2893cefbd..0cba72bd2c6 100644 --- a/src/tools/clippy/clippy_lints/src/needless_update.rs +++ b/src/tools/clippy/clippy_lints/src/needless_update.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint; -use rustc_hir::{Expr, ExprKind}; +use rustc_hir::{Expr, ExprKind, StructTailExpr}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::declare_lint_pass; @@ -51,7 +51,7 @@ declare_lint_pass!(NeedlessUpdate => [NEEDLESS_UPDATE]); impl<'tcx> LateLintPass<'tcx> for NeedlessUpdate { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if let ExprKind::Struct(_, fields, Some(base)) = expr.kind { + if let ExprKind::Struct(_, fields, StructTailExpr::Base(base)) = expr.kind { let ty = cx.typeck_results().expr_ty(expr); if let ty::Adt(def, _) = ty.kind() { if fields.len() == def.non_enum_variant().fields.len() diff --git a/src/tools/clippy/clippy_lints/src/no_effect.rs b/src/tools/clippy/clippy_lints/src/no_effect.rs index 8ecff9c3f9b..9e44bb02c56 100644 --- a/src/tools/clippy/clippy_lints/src/no_effect.rs +++ b/src/tools/clippy/clippy_lints/src/no_effect.rs @@ -8,7 +8,7 @@ use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{ BinOpKind, BlockCheckMode, Expr, ExprKind, HirId, HirIdMap, ItemKind, LocalSource, Node, PatKind, Stmt, StmtKind, - UnsafeSource, is_range_literal, + UnsafeSource, StructTailExpr, is_range_literal, }; use rustc_infer::infer::TyCtxtInferExt as _; use rustc_lint::{LateContext, LateLintPass, LintContext}; @@ -238,7 +238,10 @@ fn has_no_effect(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { ExprKind::Struct(_, fields, ref base) => { !has_drop(cx, cx.typeck_results().expr_ty(expr)) && fields.iter().all(|field| has_no_effect(cx, field.expr)) - && base.as_ref().is_none_or(|base| has_no_effect(cx, base)) + && match &base { + StructTailExpr::None | StructTailExpr::DefaultFields(_) => true, + StructTailExpr::Base(base) => has_no_effect(cx, base), + } }, ExprKind::Call(callee, args) => { if let ExprKind::Path(ref qpath) = callee.kind { @@ -342,6 +345,10 @@ fn reduce_expression<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<Vec if has_drop(cx, cx.typeck_results().expr_ty(expr)) { None } else { + let base = match base { + StructTailExpr::Base(base) => Some(base), + StructTailExpr::None | StructTailExpr::DefaultFields(_) => None, + }; Some(fields.iter().map(|f| &f.expr).chain(base).map(Deref::deref).collect()) } }, diff --git a/src/tools/clippy/clippy_lints/src/non_copy_const.rs b/src/tools/clippy/clippy_lints/src/non_copy_const.rs index 5f253b9e5d5..ebd301d5156 100644 --- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs +++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs @@ -11,7 +11,7 @@ use rustc_hir::{ BodyId, Expr, ExprKind, HirId, Impl, ImplItem, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind, UnOp, }; use rustc_lint::{LateContext, LateLintPass, Lint}; -use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult, GlobalId}; +use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult, GlobalId, ReportedErrorInfo}; use rustc_middle::ty::adjustment::Adjust; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::impl_lint_pass; @@ -302,7 +302,10 @@ impl<'tcx> NonCopyConst<'tcx> { tcx.const_eval_global_id_for_typeck(typing_env, cid, span) }, Ok(None) => Err(ErrorHandled::TooGeneric(span)), - Err(err) => Err(ErrorHandled::Reported(err.into(), span)), + Err(err) => Err(ErrorHandled::Reported( + ReportedErrorInfo::non_const_eval_error(err), + span, + )), } } } diff --git a/src/tools/clippy/clippy_lints/src/single_range_in_vec_init.rs b/src/tools/clippy/clippy_lints/src/single_range_in_vec_init.rs index 44e585953bf..bb11daecc07 100644 --- a/src/tools/clippy/clippy_lints/src/single_range_in_vec_init.rs +++ b/src/tools/clippy/clippy_lints/src/single_range_in_vec_init.rs @@ -6,7 +6,7 @@ use clippy_utils::source::SpanRangeExt; use clippy_utils::ty::implements_trait; use rustc_ast::{LitIntType, LitKind, UintTy}; use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind, LangItem, QPath}; +use rustc_hir::{Expr, ExprKind, LangItem, QPath, StructTailExpr}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; use std::fmt::{self, Display, Formatter}; @@ -86,7 +86,7 @@ impl LateLintPass<'_> for SingleRangeInVecInit { return; }; - let ExprKind::Struct(QPath::LangItem(lang_item, ..), [start, end], None) = inner_expr.kind else { + let ExprKind::Struct(QPath::LangItem(lang_item, ..), [start, end], StructTailExpr::None) = inner_expr.kind else { return; }; diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_struct_initialization.rs b/src/tools/clippy/clippy_lints/src/unnecessary_struct_initialization.rs index afdd3505cdd..0a90d31db7e 100644 --- a/src/tools/clippy/clippy_lints/src/unnecessary_struct_initialization.rs +++ b/src/tools/clippy/clippy_lints/src/unnecessary_struct_initialization.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; use clippy_utils::ty::is_copy; use clippy_utils::{get_parent_expr, path_to_local}; -use rustc_hir::{BindingMode, Expr, ExprField, ExprKind, Node, PatKind, Path, QPath, UnOp}; +use rustc_hir::{BindingMode, Expr, ExprField, ExprKind, Node, PatKind, Path, QPath, UnOp, StructTailExpr}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; @@ -59,15 +59,15 @@ impl LateLintPass<'_> for UnnecessaryStruct { let field_path = same_path_in_all_fields(cx, expr, fields); let sugg = match (field_path, base) { - (Some(&path), None) => { + (Some(&path), StructTailExpr::None | StructTailExpr::DefaultFields(_)) => { // all fields match, no base given path.span }, - (Some(path), Some(base)) if base_is_suitable(cx, expr, base) && path_matches_base(path, base) => { + (Some(path), StructTailExpr::Base(base)) if base_is_suitable(cx, expr, base) && path_matches_base(path, base) => { // all fields match, has base: ensure that the path of the base matches base.span }, - (None, Some(base)) if fields.is_empty() && base_is_suitable(cx, expr, base) => { + (None, StructTailExpr::Base(base)) if fields.is_empty() && base_is_suitable(cx, expr, base) => { // just the base, no explicit fields base.span }, diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index 51001d374b4..311ed427cb9 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -4,7 +4,7 @@ use rustc_ast::ast::{LitFloatType, LitKind}; use rustc_data_structures::fx::FxHashMap; use rustc_hir::{ self as hir, BindingMode, CaptureBy, Closure, ClosureKind, ConstArg, ConstArgKind, CoroutineKind, - ExprKind, FnRetTy, HirId, Lit, PatKind, QPath, StmtKind, TyKind, + ExprKind, FnRetTy, HirId, Lit, PatKind, QPath, StmtKind, TyKind, StructTailExpr, }; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::declare_lint_pass; @@ -598,7 +598,10 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { }, ExprKind::Struct(qpath, fields, base) => { bind!(self, qpath, fields); - opt_bind!(self, base); + let base = OptionPat::new(match base { + StructTailExpr::Base(base) => Some(self.bind("base", base)), + StructTailExpr::None | StructTailExpr::DefaultFields(_) => None, + }); kind!("Struct({qpath}, {fields}, {base})"); self.qpath(qpath); self.slice(fields, |field| { diff --git a/src/tools/clippy/clippy_utils/src/higher.rs b/src/tools/clippy/clippy_utils/src/higher.rs index 11bbe734844..d216879cbd2 100644 --- a/src/tools/clippy/clippy_utils/src/higher.rs +++ b/src/tools/clippy/clippy_utils/src/higher.rs @@ -8,7 +8,7 @@ use crate::ty::is_type_diagnostic_item; use rustc_ast::ast; use rustc_hir as hir; -use rustc_hir::{Arm, Block, Expr, ExprKind, HirId, LoopSource, MatchSource, Node, Pat, QPath}; +use rustc_hir::{Arm, Block, Expr, ExprKind, StructTailExpr, HirId, LoopSource, MatchSource, Node, Pat, QPath}; use rustc_lint::LateContext; use rustc_span::{Span, sym, symbol}; @@ -236,7 +236,7 @@ impl<'a> Range<'a> { limits: ast::RangeLimits::Closed, }) }, - ExprKind::Struct(path, fields, None) => match (path, fields) { + ExprKind::Struct(path, fields, StructTailExpr::None) => match (path, fields) { (QPath::LangItem(hir::LangItem::RangeFull, ..), []) => Some(Range { start: None, end: None, diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index 7f3e331e7f6..e318ad8671c 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -10,7 +10,7 @@ use rustc_hir::{ AssocItemConstraint, BinOpKind, BindingMode, Block, BodyId, Closure, ConstArg, ConstArgKind, Expr, ExprField, ExprKind, FnRetTy, GenericArg, GenericArgs, HirId, HirIdMap, InlineAsmOperand, LetExpr, Lifetime, LifetimeName, Pat, PatField, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitBoundModifiers, Ty, - TyKind, + TyKind, StructTailExpr, }; use rustc_lexer::{TokenKind, tokenize}; use rustc_lint::LateContext; @@ -380,7 +380,12 @@ impl HirEqInterExpr<'_, '_, '_> { (ExprKind::Ret(l), ExprKind::Ret(r)) => both(l.as_ref(), r.as_ref(), |l, r| self.eq_expr(l, r)), (&ExprKind::Struct(l_path, lf, ref lo), &ExprKind::Struct(r_path, rf, ref ro)) => { self.eq_qpath(l_path, r_path) - && both(lo.as_ref(), ro.as_ref(), |l, r| self.eq_expr(l, r)) + && match (lo, ro) { + (StructTailExpr::Base(l),StructTailExpr::Base(r)) => self.eq_expr(l, r), + (StructTailExpr::None, StructTailExpr::None) => true, + (StructTailExpr::DefaultFields(_), StructTailExpr::DefaultFields(_)) => true, + _ => false, + } && over(lf, rf, |l, r| self.eq_expr_field(l, r)) }, (&ExprKind::Tup(l_tup), &ExprKind::Tup(r_tup)) => self.eq_exprs(l_tup, r_tup), @@ -591,7 +596,6 @@ impl HirEqInterExpr<'_, '_, '_> { (TyKind::Path(l), TyKind::Path(r)) => self.eq_qpath(l, r), (&TyKind::Tup(l), &TyKind::Tup(r)) => over(l, r, |l, r| self.eq_ty(l, r)), (&TyKind::Infer, &TyKind::Infer) => true, - (TyKind::AnonAdt(l_item_id), TyKind::AnonAdt(r_item_id)) => l_item_id == r_item_id, _ => false, } } @@ -1017,7 +1021,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { self.hash_expr(f.expr); } - if let Some(e) = *expr { + if let StructTailExpr::Base(e) = *expr { self.hash_expr(e); } }, @@ -1241,8 +1245,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { | TyKind::Infer | TyKind::Never | TyKind::InferDelegation(..) - | TyKind::OpaqueDef(_) - | TyKind::AnonAdt(_) => {}, + | TyKind::OpaqueDef(_) => {}, } } diff --git a/src/tools/clippy/clippy_utils/src/visitors.rs b/src/tools/clippy/clippy_utils/src/visitors.rs index a79be5ca7d4..351e619d7b1 100644 --- a/src/tools/clippy/clippy_utils/src/visitors.rs +++ b/src/tools/clippy/clippy_utils/src/visitors.rs @@ -7,7 +7,7 @@ use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::intravisit::{self, Visitor, walk_block, walk_expr}; use rustc_hir::{ AnonConst, Arm, Block, BlockCheckMode, Body, BodyId, Expr, ExprKind, HirId, ItemId, ItemKind, LetExpr, Pat, QPath, - Safety, Stmt, UnOp, UnsafeSource, + Safety, Stmt, UnOp, UnsafeSource, StructTailExpr, }; use rustc_lint::LateContext; use rustc_middle::hir::nested_filter; @@ -663,7 +663,7 @@ pub fn for_each_unconsumed_temporary<'tcx, B>( for field in fields { helper(typeck, true, field.expr, f)?; } - if let Some(default) = default { + if let StructTailExpr::Base(default) = default { helper(typeck, false, default, f)?; } }, diff --git a/src/tools/compiletest/src/compute_diff.rs b/src/tools/compiletest/src/compute_diff.rs index 92c80c27de0..3ace6c5b6d7 100644 --- a/src/tools/compiletest/src/compute_diff.rs +++ b/src/tools/compiletest/src/compute_diff.rs @@ -144,7 +144,7 @@ where } if !wrote_data { - println!("note: diff is identical to nightly rustdoc"); + eprintln!("note: diff is identical to nightly rustdoc"); assert!(diff_output.metadata().unwrap().len() == 0); return false; } else if verbose { diff --git a/src/tools/compiletest/src/debuggers.rs b/src/tools/compiletest/src/debuggers.rs index b605bc813f1..e75c8a5993e 100644 --- a/src/tools/compiletest/src/debuggers.rs +++ b/src/tools/compiletest/src/debuggers.rs @@ -20,7 +20,7 @@ pub(crate) fn configure_gdb(config: &Config) -> Option<Arc<Config>> { } if config.remote_test_client.is_some() && !config.target.contains("android") { - println!( + eprintln!( "WARNING: debuginfo tests are not available when \ testing with remote" ); @@ -28,7 +28,7 @@ pub(crate) fn configure_gdb(config: &Config) -> Option<Arc<Config>> { } if config.target.contains("android") { - println!( + eprintln!( "{} debug-info test uses tcp 5039 port.\ please reserve it", config.target @@ -50,7 +50,7 @@ pub(crate) fn configure_lldb(config: &Config) -> Option<Arc<Config>> { config.lldb_python_dir.as_ref()?; if let Some(350) = config.lldb_version { - println!( + eprintln!( "WARNING: The used version of LLDB (350) has a \ known issue that breaks debuginfo tests. See \ issue #32520 for more information. Skipping all \ diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index a5a166af33b..9acb7d393b4 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -188,8 +188,8 @@ pub fn parse_config(args: Vec<String>) -> Config { let (argv0, args_) = args.split_first().unwrap(); if args.len() == 1 || args[1] == "-h" || args[1] == "--help" { let message = format!("Usage: {} [OPTIONS] [TESTNAME...]", argv0); - println!("{}", opts.usage(&message)); - println!(); + eprintln!("{}", opts.usage(&message)); + eprintln!(); panic!() } @@ -200,8 +200,8 @@ pub fn parse_config(args: Vec<String>) -> Config { if matches.opt_present("h") || matches.opt_present("help") { let message = format!("Usage: {} [OPTIONS] [TESTNAME...]", argv0); - println!("{}", opts.usage(&message)); - println!(); + eprintln!("{}", opts.usage(&message)); + eprintln!(); panic!() } @@ -508,7 +508,7 @@ pub fn run_tests(config: Arc<Config>) { // easy to miss which tests failed, and as such fail to reproduce // the failure locally. - println!( + eprintln!( "Some tests failed in compiletest suite={}{} mode={} host={} target={}", config.suite, config diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 7b11bf3b121..ca746ed8c55 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -131,7 +131,7 @@ pub fn run(config: Arc<Config>, testpaths: &TestPaths, revision: Option<&str>) { if config.verbose { // We're going to be dumping a lot of info. Start on a new line. - print!("\n\n"); + eprintln!("\n"); } debug!("running {:?}", testpaths.file.display()); let mut props = TestProps::from_file(&testpaths.file, revision, &config); @@ -353,7 +353,7 @@ impl<'test> TestCx<'test> { { self.error(&format!("{} test did not emit an error", self.config.mode)); if self.config.mode == crate::common::Mode::Ui { - println!("note: by default, ui tests are expected not to compile"); + eprintln!("note: by default, ui tests are expected not to compile"); } proc_res.fatal(None, || ()); }; @@ -774,20 +774,20 @@ impl<'test> TestCx<'test> { unexpected.len(), not_found.len() )); - println!("status: {}\ncommand: {}\n", proc_res.status, proc_res.cmdline); + eprintln!("status: {}\ncommand: {}\n", proc_res.status, proc_res.cmdline); if !unexpected.is_empty() { - println!("{}", "--- unexpected errors (from JSON output) ---".green()); + eprintln!("{}", "--- unexpected errors (from JSON output) ---".green()); for error in &unexpected { - println!("{}", error.render_for_expected()); + eprintln!("{}", error.render_for_expected()); } - println!("{}", "---".green()); + eprintln!("{}", "---".green()); } if !not_found.is_empty() { - println!("{}", "--- not found errors (from test file) ---".red()); + eprintln!("{}", "--- not found errors (from test file) ---".red()); for error in ¬_found { - println!("{}", error.render_for_expected()); + eprintln!("{}", error.render_for_expected()); } - println!("{}", "---\n".red()); + eprintln!("{}", "---\n".red()); } panic!("errors differ from expected"); } @@ -1876,18 +1876,18 @@ impl<'test> TestCx<'test> { fn maybe_dump_to_stdout(&self, out: &str, err: &str) { if self.config.verbose { - println!("------stdout------------------------------"); - println!("{}", out); - println!("------stderr------------------------------"); - println!("{}", err); - println!("------------------------------------------"); + eprintln!("------stdout------------------------------"); + eprintln!("{}", out); + eprintln!("------stderr------------------------------"); + eprintln!("{}", err); + eprintln!("------------------------------------------"); } } fn error(&self, err: &str) { match self.revision { - Some(rev) => println!("\nerror in revision `{}`: {}", rev, err), - None => println!("\nerror: {}", err), + Some(rev) => eprintln!("\nerror in revision `{}`: {}", rev, err), + None => eprintln!("\nerror: {}", err), } } @@ -1972,7 +1972,7 @@ impl<'test> TestCx<'test> { if !self.config.has_html_tidy { return; } - println!("info: generating a diff against nightly rustdoc"); + eprintln!("info: generating a diff against nightly rustdoc"); let suffix = self.safe_revision().map_or("nightly".into(), |path| path.to_owned() + "-nightly"); @@ -2082,7 +2082,7 @@ impl<'test> TestCx<'test> { .output() .unwrap(); assert!(output.status.success()); - println!("{}", String::from_utf8_lossy(&output.stdout)); + eprintln!("{}", String::from_utf8_lossy(&output.stdout)); eprintln!("{}", String::from_utf8_lossy(&output.stderr)); } else { use colored::Colorize; @@ -2496,7 +2496,7 @@ impl<'test> TestCx<'test> { )"# ) .replace_all(&output, |caps: &Captures<'_>| { - println!("{}", &caps[0]); + eprintln!("{}", &caps[0]); caps[0].replace(r"\", "/") }) .replace("\r\n", "\n") @@ -2601,14 +2601,14 @@ impl<'test> TestCx<'test> { if let Err(err) = fs::write(&actual_path, &actual) { self.fatal(&format!("failed to write {stream} to `{actual_path:?}`: {err}",)); } - println!("Saved the actual {stream} to {actual_path:?}"); + eprintln!("Saved the actual {stream} to {actual_path:?}"); let expected_path = expected_output_path(self.testpaths, self.revision, &self.config.compare_mode, stream); if !self.config.bless { if expected.is_empty() { - println!("normalized {}:\n{}\n", stream, actual); + eprintln!("normalized {}:\n{}\n", stream, actual); } else { self.show_diff( stream, @@ -2631,10 +2631,10 @@ impl<'test> TestCx<'test> { if let Err(err) = fs::write(&expected_path, &actual) { self.fatal(&format!("failed to write {stream} to `{expected_path:?}`: {err}")); } - println!("Blessing the {stream} of {test_name} in {expected_path:?}"); + eprintln!("Blessing the {stream} of {test_name} in {expected_path:?}"); } - println!("\nThe actual {0} differed from the expected {0}.", stream); + eprintln!("\nThe actual {0} differed from the expected {0}.", stream); if self.config.bless { 0 } else { 1 } } @@ -2783,7 +2783,7 @@ impl<'test> TestCx<'test> { fs::create_dir_all(&incremental_dir).unwrap(); if self.config.verbose { - println!("init_incremental_test: incremental_dir={}", incremental_dir.display()); + eprintln!("init_incremental_test: incremental_dir={}", incremental_dir.display()); } } @@ -2841,7 +2841,7 @@ impl ProcRes { } } - println!( + eprintln!( "status: {}\ncommand: {}\n{}\n{}\n", self.status, self.cmdline, @@ -2852,7 +2852,7 @@ impl ProcRes { pub fn fatal(&self, err: Option<&str>, on_failure: impl FnOnce()) -> ! { if let Some(e) = err { - println!("\nerror: {}", e); + eprintln!("\nerror: {}", e); } self.print_info(); on_failure(); diff --git a/src/tools/compiletest/src/runtest/codegen_units.rs b/src/tools/compiletest/src/runtest/codegen_units.rs index 6c866cbef21..6acd140183d 100644 --- a/src/tools/compiletest/src/runtest/codegen_units.rs +++ b/src/tools/compiletest/src/runtest/codegen_units.rs @@ -64,13 +64,13 @@ impl TestCx<'_> { if !missing.is_empty() { missing.sort(); - println!("\nThese items should have been contained but were not:\n"); + eprintln!("\nThese items should have been contained but were not:\n"); for item in &missing { - println!("{}", item); + eprintln!("{}", item); } - println!("\n"); + eprintln!("\n"); } if !unexpected.is_empty() { @@ -80,24 +80,24 @@ impl TestCx<'_> { sorted }; - println!("\nThese items were contained but should not have been:\n"); + eprintln!("\nThese items were contained but should not have been:\n"); for item in sorted { - println!("{}", item); + eprintln!("{}", item); } - println!("\n"); + eprintln!("\n"); } if !wrong_cgus.is_empty() { wrong_cgus.sort_by_key(|pair| pair.0.name.clone()); - println!("\nThe following items were assigned to wrong codegen units:\n"); + eprintln!("\nThe following items were assigned to wrong codegen units:\n"); for &(ref expected_item, ref actual_item) in &wrong_cgus { - println!("{}", expected_item.name); - println!(" expected: {}", codegen_units_to_str(&expected_item.codegen_units)); - println!(" actual: {}", codegen_units_to_str(&actual_item.codegen_units)); - println!(); + eprintln!("{}", expected_item.name); + eprintln!(" expected: {}", codegen_units_to_str(&expected_item.codegen_units)); + eprintln!(" actual: {}", codegen_units_to_str(&actual_item.codegen_units)); + eprintln!(); } } diff --git a/src/tools/compiletest/src/runtest/debuginfo.rs b/src/tools/compiletest/src/runtest/debuginfo.rs index c621c22ac99..7322e730e53 100644 --- a/src/tools/compiletest/src/runtest/debuginfo.rs +++ b/src/tools/compiletest/src/runtest/debuginfo.rs @@ -260,7 +260,7 @@ impl TestCx<'_> { cmdline, }; if adb.kill().is_err() { - println!("Adb process is already finished."); + eprintln!("Adb process is already finished."); } } else { let rust_src_root = @@ -275,7 +275,7 @@ impl TestCx<'_> { match self.config.gdb_version { Some(version) => { - println!("NOTE: compiletest thinks it is using GDB version {}", version); + eprintln!("NOTE: compiletest thinks it is using GDB version {}", version); if version > extract_gdb_version("7.4").unwrap() { // Add the directory containing the pretty printers to @@ -297,7 +297,7 @@ impl TestCx<'_> { } } _ => { - println!( + eprintln!( "NOTE: compiletest does not know which version of \ GDB it is using" ); @@ -392,10 +392,10 @@ impl TestCx<'_> { match self.config.lldb_version { Some(ref version) => { - println!("NOTE: compiletest thinks it is using LLDB version {}", version); + eprintln!("NOTE: compiletest thinks it is using LLDB version {}", version); } _ => { - println!( + eprintln!( "NOTE: compiletest does not know which version of \ LLDB it is using" ); diff --git a/src/tools/compiletest/src/runtest/incremental.rs b/src/tools/compiletest/src/runtest/incremental.rs index 591aff0defe..4f26786129b 100644 --- a/src/tools/compiletest/src/runtest/incremental.rs +++ b/src/tools/compiletest/src/runtest/incremental.rs @@ -30,7 +30,7 @@ impl TestCx<'_> { assert!(incremental_dir.exists(), "init_incremental_test failed to create incremental dir"); if self.config.verbose { - print!("revision={:?} props={:#?}", revision, self.props); + eprint!("revision={:?} props={:#?}", revision, self.props); } if revision.starts_with("cpass") { diff --git a/src/tools/compiletest/src/runtest/mir_opt.rs b/src/tools/compiletest/src/runtest/mir_opt.rs index d1ec0035744..64a2addaa28 100644 --- a/src/tools/compiletest/src/runtest/mir_opt.rs +++ b/src/tools/compiletest/src/runtest/mir_opt.rs @@ -89,7 +89,7 @@ impl TestCx<'_> { } let expected_string = fs::read_to_string(&expected_file).unwrap(); if dumped_string != expected_string { - print!("{}", write_diff(&expected_string, &dumped_string, 3)); + eprint!("{}", write_diff(&expected_string, &dumped_string, 3)); panic!( "Actual MIR output differs from expected MIR output {}", expected_file.display() diff --git a/src/tools/compiletest/src/runtest/rustdoc_json.rs b/src/tools/compiletest/src/runtest/rustdoc_json.rs index 31fdb0a5d13..84376d346af 100644 --- a/src/tools/compiletest/src/runtest/rustdoc_json.rs +++ b/src/tools/compiletest/src/runtest/rustdoc_json.rs @@ -29,7 +29,7 @@ impl TestCx<'_> { if !res.status.success() { self.fatal_proc_rec_with_ctx("jsondocck failed!", &res, |_| { - println!("Rustdoc Output:"); + eprintln!("Rustdoc Output:"); proc_res.print_info(); }) } diff --git a/src/tools/compiletest/src/runtest/ui.rs b/src/tools/compiletest/src/runtest/ui.rs index 172b1e32aad..bc860bf18c7 100644 --- a/src/tools/compiletest/src/runtest/ui.rs +++ b/src/tools/compiletest/src/runtest/ui.rs @@ -109,10 +109,10 @@ impl TestCx<'_> { } if errors > 0 { - println!("To update references, rerun the tests and pass the `--bless` flag"); + eprintln!("To update references, rerun the tests and pass the `--bless` flag"); let relative_path_to_file = self.testpaths.relative_dir.join(self.testpaths.file.file_name().unwrap()); - println!( + eprintln!( "To only update this specific test, also pass `--test-args {}`", relative_path_to_file.display(), ); diff --git a/src/tools/compiletest/src/util.rs b/src/tools/compiletest/src/util.rs index bff02f1db9f..7b50e62c29b 100644 --- a/src/tools/compiletest/src/util.rs +++ b/src/tools/compiletest/src/util.rs @@ -30,7 +30,7 @@ fn path_div() -> &'static str { pub fn logv(config: &Config, s: String) { debug!("{}", s); if config.verbose { - println!("{}", s); + eprintln!("{}", s); } } diff --git a/src/tools/jsondocck/src/cache.rs b/src/tools/jsondocck/src/cache.rs index 9f95f9fb408..47512039740 100644 --- a/src/tools/jsondocck/src/cache.rs +++ b/src/tools/jsondocck/src/cache.rs @@ -28,7 +28,8 @@ impl Cache { } } - pub fn value(&self) -> &Value { - &self.value + // FIXME: Make this failible, so jsonpath syntax error has line number. + pub fn select(&self, path: &str) -> Vec<&Value> { + jsonpath_lib::select(&self.value, path).unwrap() } } diff --git a/src/tools/jsondocck/src/error.rs b/src/tools/jsondocck/src/error.rs index c4cd79a64fd..0a3e085b405 100644 --- a/src/tools/jsondocck/src/error.rs +++ b/src/tools/jsondocck/src/error.rs @@ -1,29 +1,7 @@ -use std::error::Error; -use std::fmt; - use crate::Command; #[derive(Debug)] -pub enum CkError { - /// A check failed. File didn't exist or failed to match the command - FailedCheck(String, Command), - /// An error triggered by some other error - Induced(Box<dyn Error>), -} - -impl fmt::Display for CkError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - CkError::FailedCheck(msg, cmd) => { - write!(f, "Failed check: {} on line {}", msg, cmd.lineno) - } - CkError::Induced(err) => write!(f, "Check failed: {}", err), - } - } -} - -impl<T: Error + 'static> From<T> for CkError { - fn from(err: T) -> CkError { - CkError::Induced(Box::new(err)) - } +pub struct CkError { + pub message: String, + pub command: Command, } diff --git a/src/tools/jsondocck/src/main.rs b/src/tools/jsondocck/src/main.rs index c08bbbc769a..b6a1d7dfa7a 100644 --- a/src/tools/jsondocck/src/main.rs +++ b/src/tools/jsondocck/src/main.rs @@ -1,8 +1,8 @@ use std::borrow::Cow; +use std::process::ExitCode; use std::sync::OnceLock; -use std::{env, fmt, fs}; +use std::{env, fs}; -use jsonpath_lib::select; use regex::{Regex, RegexBuilder}; use serde_json::Value; @@ -14,90 +14,134 @@ use cache::Cache; use config::parse_config; use error::CkError; -fn main() -> Result<(), String> { +fn main() -> ExitCode { let config = parse_config(env::args().collect()); let mut failed = Vec::new(); let mut cache = Cache::new(&config); - let commands = get_commands(&config.template) - .map_err(|_| format!("Jsondocck failed for {}", &config.template))?; + let Ok(commands) = get_commands(&config.template) else { + eprintln!("Jsondocck failed for {}", &config.template); + return ExitCode::FAILURE; + }; for command in commands { - if let Err(e) = check_command(command, &mut cache) { - failed.push(e); + if let Err(message) = check_command(&command, &mut cache) { + failed.push(CkError { command, message }); } } if failed.is_empty() { - Ok(()) + ExitCode::SUCCESS } else { for i in failed { - eprintln!("{}", i); + eprintln!("{}:{}, command failed", config.template, i.command.lineno); + eprintln!("{}", i.message) } - Err(format!("Jsondocck failed for {}", &config.template)) + ExitCode::FAILURE } } #[derive(Debug)] pub struct Command { - negated: bool, kind: CommandKind, - args: Vec<String>, + path: String, lineno: usize, } #[derive(Debug)] -pub enum CommandKind { - Has, - Count, - Is, - IsMany, - Set, +enum CommandKind { + /// `//@ has <path>` + /// + /// Checks the path exists. + HasPath, + + /// `//@ has <path> <value>` + /// + /// Check one thing at the path is equal to the value. + HasValue { value: String }, + + /// `//@ !has <path>` + /// + /// Checks the path doesn't exist. + HasNotPath, + + /// `//@ is <path> <value>` + /// + /// Check the path is the given value. + Is { value: String }, + + /// `//@ is <path> <value> <value>...` + /// + /// Check that the path matches to exactly every given value. + IsMany { values: Vec<String> }, + + /// `//@ !is <path> <value>` + /// + /// Check the path isn't the given value. + IsNot { value: String }, + + /// `//@ count <path> <value>` + /// + /// Check the path has the expected number of matches. + CountIs { expected: usize }, + + /// `//@ set <name> = <path>` + Set { variable: String }, } impl CommandKind { - fn validate(&self, args: &[String], lineno: usize) -> bool { - // FIXME(adotinthevoid): We should "parse, don't validate" here, so we avoid ad-hoc - // indexing in check_command. - let count = match self { - CommandKind::Has => (1..=2).contains(&args.len()), - CommandKind::IsMany => args.len() >= 2, - CommandKind::Count | CommandKind::Is => 2 == args.len(), - CommandKind::Set => 3 == args.len(), - }; + /// Returns both the kind and the path. + /// + /// Returns `None` if the command isn't from jsondocck (e.g. from compiletest). + fn parse<'a>(command_name: &str, negated: bool, args: &'a [String]) -> Option<(Self, &'a str)> { + let kind = match (command_name, negated) { + ("count", false) => { + assert_eq!(args.len(), 2); + let expected = args[1].parse().expect("invalid number for `count`"); + Self::CountIs { expected } + } - if !count { - print_err(&format!("Incorrect number of arguments to `{}`", self), lineno); - return false; - } + ("ismany", false) => { + // FIXME: Make this >= 3, and migrate len(values)==1 cases to @is + assert!(args.len() >= 2, "Not enough args to `ismany`"); + let values = args[1..].to_owned(); + Self::IsMany { values } + } - if let CommandKind::Count = self { - if args[1].parse::<usize>().is_err() { - print_err( - &format!( - "Second argument to `count` must be a valid usize (got `{}`)", - args[1] - ), - lineno, - ); - return false; + ("is", false) => { + assert_eq!(args.len(), 2); + Self::Is { value: args[1].clone() } + } + ("is", true) => { + assert_eq!(args.len(), 2); + Self::IsNot { value: args[1].clone() } } - } - true - } -} + ("set", false) => { + assert_eq!(args.len(), 3); + assert_eq!(args[1], "="); + return Some((Self::Set { variable: args[0].clone() }, &args[2])); + } -impl fmt::Display for CommandKind { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let text = match self { - CommandKind::Has => "has", - CommandKind::IsMany => "ismany", - CommandKind::Count => "count", - CommandKind::Is => "is", - CommandKind::Set => "set", + ("has", false) => match args { + [_path] => Self::HasPath, + [_path, value] => Self::HasValue { value: value.clone() }, + _ => panic!("`//@ has` must have 2 or 3 arguments, but got {args:?}"), + }, + ("has", true) => { + assert_eq!(args.len(), 1, "args={args:?}"); + Self::HasNotPath + } + + (_, false) if KNOWN_DIRECTIVE_NAMES.contains(&command_name) => { + return None; + } + _ => { + panic!("Invalid command `//@ {}{command_name}`", if negated { "!" } else { "" }) + } }; - write!(f, "{}", text) + + Some((kind, &args[0])) } } @@ -125,8 +169,7 @@ fn print_err(msg: &str, lineno: usize) { // See <https://github.com/rust-lang/rust/issues/125813#issuecomment-2141953780>. include!(concat!(env!("CARGO_MANIFEST_DIR"), "/../compiletest/src/directive-list.rs")); -/// Get a list of commands from a file. Does the work of ensuring the commands -/// are syntactically valid. +/// Get a list of commands from a file. fn get_commands(template: &str) -> Result<Vec<Command>, ()> { let mut commands = Vec::new(); let mut errors = false; @@ -142,217 +185,102 @@ fn get_commands(template: &str) -> Result<Vec<Command>, ()> { let negated = cap.name("negated").unwrap().as_str() == "!"; - let cmd = match cap.name("cmd").unwrap().as_str() { - "has" => CommandKind::Has, - "count" => CommandKind::Count, - "is" => CommandKind::Is, - "ismany" => CommandKind::IsMany, - "set" => CommandKind::Set, - // FIXME: See the comment above the `include!(...)`. - cmd if KNOWN_DIRECTIVE_NAMES.contains(&cmd) => continue, - cmd => { - print_err(&format!("Unrecognized command name `{cmd}`"), lineno); - errors = true; - continue; - } - }; - - let args = cap.name("args").map_or(Some(vec![]), |m| shlex::split(m.as_str())); - - let args = match args { + let args_str = &cap["args"]; + let args = match shlex::split(args_str) { Some(args) => args, None => { - print_err( - &format!( - "Invalid arguments to shlex::split: `{}`", - cap.name("args").unwrap().as_str() - ), - lineno, - ); + print_err(&format!("Invalid arguments to shlex::split: `{args_str}`",), lineno); errors = true; continue; } }; - if !cmd.validate(&args, lineno) { - errors = true; - continue; + if let Some((kind, path)) = CommandKind::parse(&cap["cmd"], negated, &args) { + commands.push(Command { kind, lineno, path: path.to_owned() }) } - - commands.push(Command { negated, kind: cmd, args, lineno }) } if !errors { Ok(commands) } else { Err(()) } } -/// Performs the actual work of ensuring a command passes. Generally assumes the command -/// is syntactically valid. -fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> { - // FIXME: Be more granular about why, (e.g. syntax error, count not equal) - let result = match command.kind { - CommandKind::Has => { - match command.args.len() { - // `has <jsonpath>`: Check that `jsonpath` exists. - 1 => { - let val = cache.value(); - let results = select(val, &command.args[0]).unwrap(); - !results.is_empty() - } - // `has <jsonpath> <value>`: Check *any* item matched by `jsonpath` equals `value`. - 2 => { - let val = cache.value().clone(); - let results = select(&val, &command.args[0]).unwrap(); - let pat = string_to_value(&command.args[1], cache); - let has = results.contains(&pat.as_ref()); - // Give better error for when `has` check fails. - if !command.negated && !has { - return Err(CkError::FailedCheck( - format!( - "{} matched to {:?} but didn't have {:?}", - &command.args[0], - results, - pat.as_ref() - ), - command, - )); - } else { - has - } - } - _ => unreachable!(), +/// Performs the actual work of ensuring a command passes. +fn check_command(command: &Command, cache: &mut Cache) -> Result<(), String> { + let matches = cache.select(&command.path); + match &command.kind { + CommandKind::HasPath => { + if matches.is_empty() { + return Err("matched to no values".to_owned()); + } + } + CommandKind::HasNotPath => { + if !matches.is_empty() { + return Err(format!("matched to {matches:?}, but wanted no matches")); + } + } + CommandKind::HasValue { value } => { + let want_value = string_to_value(value, cache); + if !matches.contains(&want_value.as_ref()) { + return Err(format!("matched to {matches:?}, which didn't contain {want_value:?}")); + } + } + CommandKind::Is { value } => { + let want_value = string_to_value(value, cache); + let matched = get_one(&matches)?; + if matched != want_value.as_ref() { + return Err(format!("matched to {matched:?} but want {want_value:?}")); + } + } + CommandKind::IsNot { value } => { + let wantnt_value = string_to_value(value, cache); + let matched = get_one(&matches)?; + if matched == wantnt_value.as_ref() { + return Err(format!("got value {wantnt_value:?}, but want anything else")); } } - // `ismany <path> <jsonpath> <value...>` - CommandKind::IsMany => { - assert!(!command.negated, "`ismany` may not be negated"); - let (query, values) = if let [query, values @ ..] = &command.args[..] { - (query, values) - } else { - unreachable!("Checked in CommandKind::validate") - }; - let val = cache.value(); - let got_values = select(val, &query).unwrap(); + CommandKind::IsMany { values } => { // Serde json doesn't implement Ord or Hash for Value, so we must // use a Vec here. While in theory that makes setwize equality // O(n^2), in practice n will never be large enough to matter. let expected_values = values.iter().map(|v| string_to_value(v, cache)).collect::<Vec<_>>(); - if expected_values.len() != got_values.len() { - return Err(CkError::FailedCheck( - format!( - "Expected {} values, but `{}` matched to {} values ({:?})", - expected_values.len(), - query, - got_values.len(), - got_values - ), - command, + if expected_values.len() != matches.len() { + return Err(format!( + "Expected {} values, but matched to {} values ({:?})", + expected_values.len(), + matches.len(), + matches )); }; - for got_value in got_values { + for got_value in matches { if !expected_values.iter().any(|exp| &**exp == got_value) { - return Err(CkError::FailedCheck( - format!("`{}` has match {:?}, which was not expected", query, got_value), - command, - )); + return Err(format!("has match {got_value:?}, which was not expected",)); } } - true - } - // `count <jsonpath> <count>`: Check that `jsonpath` matches exactly `count` times. - CommandKind::Count => { - assert_eq!(command.args.len(), 2); - let expected: usize = command.args[1].parse().unwrap(); - let val = cache.value(); - let results = select(val, &command.args[0]).unwrap(); - let eq = results.len() == expected; - if !command.negated && !eq { - return Err(CkError::FailedCheck( - format!( - "`{}` matched to `{:?}` with length {}, but expected length {}", - &command.args[0], - results, - results.len(), - expected - ), - command, - )); - } else { - eq - } } - // `has <jsonpath> <value>`: Check` *exactly one* item matched by `jsonpath`, and it equals `value`. - CommandKind::Is => { - assert_eq!(command.args.len(), 2); - let val = cache.value().clone(); - let results = select(&val, &command.args[0]).unwrap(); - let pat = string_to_value(&command.args[1], cache); - let is = results.len() == 1 && results[0] == pat.as_ref(); - if !command.negated && !is { - return Err(CkError::FailedCheck( - format!( - "{} matched to {:?}, but expected {:?}", - &command.args[0], - results, - pat.as_ref() - ), - command, + CommandKind::CountIs { expected } => { + if *expected != matches.len() { + return Err(format!( + "matched to `{matches:?}` with length {}, but expected length {expected}", + matches.len(), )); - } else { - is } } - // `set <name> = <jsonpath>` - CommandKind::Set => { - assert!(!command.negated, "`set` may not be negated"); - assert_eq!(command.args.len(), 3); - assert_eq!(command.args[1], "=", "Expected an `=`"); - let val = cache.value().clone(); - let results = select(&val, &command.args[2]).unwrap(); - assert_eq!( - results.len(), - 1, - "Expected 1 match for `{}` (because of `set`): matched to {:?}", - command.args[2], - results - ); - match results.len() { - 0 => false, - 1 => { - let r = cache.variables.insert(command.args[0].clone(), results[0].clone()); - assert!(r.is_none(), "Name collision: {} is duplicated", command.args[0]); - true - } - _ => { - panic!( - "Got multiple results in `set` for `{}`: {:?}", - &command.args[2], results, - ); - } - } + CommandKind::Set { variable } => { + let value = get_one(&matches)?; + let r = cache.variables.insert(variable.to_owned(), value.clone()); + assert!(r.is_none(), "name collision: {variable:?} is duplicated"); } - }; + } - if result == command.negated { - if command.negated { - Err(CkError::FailedCheck( - format!("`!{} {}` matched when it shouldn't", command.kind, command.args.join(" ")), - command, - )) - } else { - // FIXME: In the future, try 'peeling back' each step, and see at what level the match failed - Err(CkError::FailedCheck( - format!( - "`{} {}` didn't match when it should", - command.kind, - command.args.join(" ") - ), - command, - )) - } - } else { - Ok(()) + Ok(()) +} + +fn get_one<'a>(matches: &[&'a Value]) -> Result<&'a Value, String> { + match matches { + [] => Err("matched to no values".to_owned()), + [matched] => Ok(matched), + _ => Err(format!("matched to multiple values {matches:?}, but want exactly 1")), } } diff --git a/src/tools/miri/src/shims/backtrace.rs b/src/tools/miri/src/shims/backtrace.rs index 64bd546458d..c7b399228bf 100644 --- a/src/tools/miri/src/shims/backtrace.rs +++ b/src/tools/miri/src/shims/backtrace.rs @@ -1,5 +1,4 @@ use rustc_abi::{ExternAbi, Size}; -use rustc_ast::ast::Mutability; use rustc_middle::ty::layout::LayoutOf as _; use rustc_middle::ty::{self, Instance, Ty}; use rustc_span::{BytePos, Loc, Symbol, hygiene}; @@ -179,14 +178,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { match flags { 0 => { - // These are "mutable" allocations as we consider them to be owned by the callee. - let name_alloc = - this.allocate_str(&name, MiriMemoryKind::Rust.into(), Mutability::Mut)?; - let filename_alloc = - this.allocate_str(&filename, MiriMemoryKind::Rust.into(), Mutability::Mut)?; - - this.write_immediate(name_alloc.to_ref(this), &this.project_field(dest, 0)?)?; - this.write_immediate(filename_alloc.to_ref(this), &this.project_field(dest, 1)?)?; + throw_unsup_format!("miri_resolve_frame: v0 is not supported any more"); } 1 => { this.write_scalar( diff --git a/src/tools/miri/src/shims/panic.rs b/src/tools/miri/src/shims/panic.rs index 722c3a2f0c5..93479540009 100644 --- a/src/tools/miri/src/shims/panic.rs +++ b/src/tools/miri/src/shims/panic.rs @@ -12,7 +12,6 @@ //! metadata we remembered when pushing said frame. use rustc_abi::ExternAbi; -use rustc_ast::Mutability; use rustc_middle::{mir, ty}; use rustc_target::spec::PanicStrategy; @@ -161,7 +160,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let this = self.eval_context_mut(); // First arg: message. - let msg = this.allocate_str(msg, MiriMemoryKind::Machine.into(), Mutability::Not)?; + let msg = this.allocate_str_dedup(msg)?; // Call the lang item. let panic = this.tcx.lang_items().panic_fn().unwrap(); @@ -180,7 +179,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let this = self.eval_context_mut(); // First arg: message. - let msg = this.allocate_str(msg, MiriMemoryKind::Machine.into(), Mutability::Not)?; + let msg = this.allocate_str_dedup(msg)?; // Call the lang item. let panic = this.tcx.lang_items().panic_nounwind().unwrap(); diff --git a/src/tools/miri/tests/pass/backtrace/backtrace-api-v0.rs b/src/tools/miri/tests/pass/backtrace/backtrace-api-v0.rs deleted file mode 100644 index 3fff7921aff..00000000000 --- a/src/tools/miri/tests/pass/backtrace/backtrace-api-v0.rs +++ /dev/null @@ -1,69 +0,0 @@ -//@normalize-stderr-test: "::<.*>" -> "" - -#[inline(never)] -fn func_a() -> Box<[*mut ()]> { - func_b::<u8>() -} -#[inline(never)] -fn func_b<T>() -> Box<[*mut ()]> { - func_c() -} - -macro_rules! invoke_func_d { - () => { - func_d() - }; -} - -#[inline(never)] -fn func_c() -> Box<[*mut ()]> { - invoke_func_d!() -} -#[inline(never)] -fn func_d() -> Box<[*mut ()]> { - unsafe { miri_get_backtrace(0) } -} - -fn main() { - let mut seen_main = false; - let frames = func_a(); - for frame in frames.iter() { - let miri_frame = unsafe { miri_resolve_frame(*frame, 0) }; - let name = String::from_utf8(miri_frame.name.into()).unwrap(); - let filename = String::from_utf8(miri_frame.filename.into()).unwrap(); - - if name == "func_a" { - assert_eq!(func_a as *mut (), miri_frame.fn_ptr); - } - - // Print every frame to stderr. - let out = format!("{}:{}:{} ({})", filename, miri_frame.lineno, miri_frame.colno, name); - eprintln!("{}", out); - // Print the 'main' frame (and everything before it) to stdout, skipping - // the printing of internal (and possibly fragile) libstd frames. - // Stdout is less normalized so we see more, but it also means we can print less - // as platform differences would lead to test suite failures. - if !seen_main { - println!("{}", out); - seen_main = name == "main"; - } - } -} - -// This goes at the bottom of the file so that we can change it -// without disturbing line numbers of the functions in the backtrace. - -extern "Rust" { - fn miri_get_backtrace(flags: u64) -> Box<[*mut ()]>; - fn miri_resolve_frame(ptr: *mut (), flags: u64) -> MiriFrame; -} - -#[derive(Debug)] -#[repr(C)] -struct MiriFrame { - name: Box<[u8]>, - filename: Box<[u8]>, - lineno: u32, - colno: u32, - fn_ptr: *mut (), -} diff --git a/src/tools/miri/tests/pass/backtrace/backtrace-api-v0.stderr b/src/tools/miri/tests/pass/backtrace/backtrace-api-v0.stderr deleted file mode 100644 index 9849a1aa74e..00000000000 --- a/src/tools/miri/tests/pass/backtrace/backtrace-api-v0.stderr +++ /dev/null @@ -1,18 +0,0 @@ -tests/pass/backtrace/backtrace-api-v0.rs:LL:CC (func_d) -tests/pass/backtrace/backtrace-api-v0.rs:LL:CC (func_c) -tests/pass/backtrace/backtrace-api-v0.rs:LL:CC (func_b) -tests/pass/backtrace/backtrace-api-v0.rs:LL:CC (func_a) -tests/pass/backtrace/backtrace-api-v0.rs:LL:CC (main) -RUSTLIB/core/src/ops/function.rs:LL:CC (<fn() as std::ops::FnOnce<()>>::call_once - shim(fn())) -RUSTLIB/std/src/sys/backtrace.rs:LL:CC (std::sys::backtrace::__rust_begin_short_backtrace) -RUSTLIB/std/src/rt.rs:LL:CC (std::rt::lang_start::{closure#0}) -RUSTLIB/core/src/ops/function.rs:LL:CC (std::ops::function::impls::call_once) -RUSTLIB/std/src/panicking.rs:LL:CC (std::panicking::r#try::do_call) -RUSTLIB/std/src/panicking.rs:LL:CC (std::panicking::r#try) -RUSTLIB/std/src/panic.rs:LL:CC (std::panic::catch_unwind) -RUSTLIB/std/src/rt.rs:LL:CC (std::rt::lang_start_internal::{closure#1}) -RUSTLIB/std/src/panicking.rs:LL:CC (std::panicking::r#try::do_call) -RUSTLIB/std/src/panicking.rs:LL:CC (std::panicking::r#try) -RUSTLIB/std/src/panic.rs:LL:CC (std::panic::catch_unwind) -RUSTLIB/std/src/rt.rs:LL:CC (std::rt::lang_start_internal) -RUSTLIB/std/src/rt.rs:LL:CC (std::rt::lang_start) diff --git a/src/tools/miri/tests/pass/backtrace/backtrace-api-v0.stdout b/src/tools/miri/tests/pass/backtrace/backtrace-api-v0.stdout deleted file mode 100644 index 8c1bc5c353e..00000000000 --- a/src/tools/miri/tests/pass/backtrace/backtrace-api-v0.stdout +++ /dev/null @@ -1,5 +0,0 @@ -tests/pass/backtrace/backtrace-api-v0.rs:24:14 (func_d) -tests/pass/backtrace/backtrace-api-v0.rs:14:9 (func_c) -tests/pass/backtrace/backtrace-api-v0.rs:9:5 (func_b::<u8>) -tests/pass/backtrace/backtrace-api-v0.rs:5:5 (func_a) -tests/pass/backtrace/backtrace-api-v0.rs:29:18 (main) diff --git a/src/tools/nix-dev-shell/envrc-flake b/src/tools/nix-dev-shell/envrc-flake index 9def420f05c..849ed1f4fc5 100644 --- a/src/tools/nix-dev-shell/envrc-flake +++ b/src/tools/nix-dev-shell/envrc-flake @@ -1,7 +1,7 @@ # If you want to use this as an .envrc file to create a shell with necessery components # to develop rustc, use the following command in the root of the rusr checkout: # -# ln -s ./src/tools/nix-dev-shell/envrc-flake ./.envrc && nix flake update --flake ./src/tools/nix-dev-shell && echo .envrc >> .git/info/exclude +# ln -s ./src/tools/nix-dev-shell/envrc-flake ./.envrc && nix flake update --flake ./src/tools/nix-dev-shell if nix flake show path:./src/tools/nix-dev-shell &> /dev/null; then use flake path:./src/tools/nix-dev-shell diff --git a/src/tools/nix-dev-shell/envrc-shell b/src/tools/nix-dev-shell/envrc-shell index fb7231a6c30..d8f900fe86a 100644 --- a/src/tools/nix-dev-shell/envrc-shell +++ b/src/tools/nix-dev-shell/envrc-shell @@ -1,7 +1,7 @@ # If you want to use this as an .envrc file to create a shell with necessery components # to develop rustc, use the following command in the root of the rusr checkout: # -# ln -s ./src/tools/nix-dev-shell/envrc-shell ./.envrc && echo .envrc >> .git/info/exclude +# ln -s ./src/tools/nix-dev-shell/envrc-shell ./.envrc use nix ./src/tools/nix-dev-shell/shell.nix diff --git a/src/tools/nix-dev-shell/flake.nix b/src/tools/nix-dev-shell/flake.nix index 8ab5e097427..1b838bd2f7b 100644 --- a/src/tools/nix-dev-shell/flake.nix +++ b/src/tools/nix-dev-shell/flake.nix @@ -24,9 +24,8 @@ # Avoid creating text files for ICEs. RUSTC_ICE = "0"; # Provide `libstdc++.so.6` for the self-contained lld. - LD_LIBRARY_PATH = "${with pkgs; lib.makeLibraryPath [ - stdenv.cc.cc.lib - ]}"; + # Provide `libz.so.1`. + LD_LIBRARY_PATH = "${with pkgs; lib.makeLibraryPath [stdenv.cc.cc.lib zlib]}"; }; } ); diff --git a/src/tools/nix-dev-shell/shell.nix b/src/tools/nix-dev-shell/shell.nix index 8a5cbb7c89e..a3f5969bd81 100644 --- a/src/tools/nix-dev-shell/shell.nix +++ b/src/tools/nix-dev-shell/shell.nix @@ -13,7 +13,6 @@ pkgs.mkShell { # Avoid creating text files for ICEs. RUSTC_ICE = "0"; # Provide `libstdc++.so.6` for the self-contained lld. - LD_LIBRARY_PATH = "${with pkgs; lib.makeLibraryPath [ - stdenv.cc.cc.lib - ]}"; + # Provide `libz.so.1` + LD_LIBRARY_PATH = "${with pkgs; lib.makeLibraryPath [stdenv.cc.cc.lib zlib]}"; } diff --git a/src/tools/run-make-support/Cargo.toml b/src/tools/run-make-support/Cargo.toml index 3c172b2d956..15ed03ad5c2 100644 --- a/src/tools/run-make-support/Cargo.toml +++ b/src/tools/run-make-support/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" bstr = "1.6.0" object = "0.36.2" similar = "2.5.0" -wasmparser = { version = "0.216", default-features = false, features = ["std"] } +wasmparser = { version = "0.219", default-features = false, features = ["std"] } regex = "1.8" # 1.8 to avoid memchr 2.6.0, as 2.5.0 is pinned in the workspace gimli = "0.31.0" build_helper = { path = "../../build_helper" } diff --git a/src/tools/run-make-support/src/command.rs b/src/tools/run-make-support/src/command.rs index 9e09527d6d0..e73413085fa 100644 --- a/src/tools/run-make-support/src/command.rs +++ b/src/tools/run-make-support/src/command.rs @@ -329,7 +329,7 @@ impl CompletedProcess { /// Checks that `stderr` does not contain the regex pattern `unexpected`. #[track_caller] pub fn assert_stderr_not_contains_regex<S: AsRef<str>>(&self, unexpected: S) -> &Self { - assert_not_contains_regex(&self.stdout_utf8(), unexpected); + assert_not_contains_regex(&self.stderr_utf8(), unexpected); self } diff --git a/src/tools/run-make-support/src/external_deps/rustc.rs b/src/tools/run-make-support/src/external_deps/rustc.rs index ffe10092cc2..8894ea7fb20 100644 --- a/src/tools/run-make-support/src/external_deps/rustc.rs +++ b/src/tools/run-make-support/src/external_deps/rustc.rs @@ -325,6 +325,12 @@ impl Rustc { self } + /// Pass the `--verbose` flag. + pub fn verbose(&mut self) -> &mut Self { + self.cmd.arg("--verbose"); + self + } + /// `EXTRARSCXXFLAGS` pub fn extra_rs_cxx_flags(&mut self) -> &mut Self { // Adapted from tools.mk (trimmed): diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index 2bd4d17fe22..8c1d82de1da 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -85,6 +85,12 @@ dependencies = [ ] [[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] name = "bitflags" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -509,6 +515,7 @@ dependencies = [ "base-db", "cfg", "either", + "expect-test", "hir-def", "hir-expand", "hir-ty", @@ -519,6 +526,9 @@ dependencies = [ "span", "stdx", "syntax", + "syntax-bridge", + "test-fixture", + "test-utils", "tracing", "triomphe", "tt", @@ -1492,9 +1502,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_abi" -version = "0.80.0" +version = "0.85.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613760a3071b25a67a8d7bc97b37c7fd4722562e9479137b83ae9cf8f8c1601a" +checksum = "af462c3a2d524b84a51b6848b439787f01b35c6c1086d3e3086a5f5eea92ed9a" dependencies = [ "bitflags 2.6.0", "ra-ap-rustc_index", @@ -1503,20 +1513,19 @@ dependencies = [ [[package]] name = "ra-ap-rustc_index" -version = "0.80.0" +version = "0.85.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b2bc6b4ecede8ff28295041e22c2e66853f8e0125990c05135bad3c30bad12c" +checksum = "be6bb8cb0ab78d94a222f1ffd3e87254cdfb57413382b8d6ebe26a85482f99d1" dependencies = [ - "arrayvec", "ra-ap-rustc_index_macros", "smallvec", ] [[package]] name = "ra-ap-rustc_index_macros" -version = "0.80.0" +version = "0.85.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2374a39fb2d92d0509178c2b442eadca3cc10e403ef9729a040c1855b08ff261" +checksum = "c24b1641455b46e87435b7321219672077066e678963d239a4a2904732979b16" dependencies = [ "proc-macro2", "quote", @@ -1525,9 +1534,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_lexer" -version = "0.80.0" +version = "0.85.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a2cf8e48b69af3ecc29ed3449892e8a999111d2f75212a78aa242e117cf1711" +checksum = "94daa86974417981fed2f12bd8fb00158dfa6fee561152bed689278c846d0272" dependencies = [ "unicode-properties", "unicode-xid", @@ -1535,9 +1544,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_parse_format" -version = "0.80.0" +version = "0.85.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d6f59a22b559263c5c42747ae362cf5d4fb272293fa119a4623f8ec288f9656" +checksum = "fc07f6bd581746f358e39c4b6bfe8d455b3d6ad1a857821016d0d42eeb5e1e3e" dependencies = [ "ra-ap-rustc_index", "ra-ap-rustc_lexer", @@ -1545,9 +1554,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_pattern_analysis" -version = "0.80.0" +version = "0.85.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7d0575b54ffe09bc5d2f158454bc05f0c30c01d9992310965f854be50ae22b8" +checksum = "2f49b86e1276c1c3c72898410def29b699415f4e7d1dfb3531daf79794694372" dependencies = [ "ra-ap-rustc_index", "rustc-hash 2.0.0", @@ -1645,6 +1654,7 @@ version = "0.0.0" dependencies = [ "always-assert", "anyhow", + "base64", "cargo_metadata", "cfg", "crossbeam-channel", @@ -1655,6 +1665,7 @@ dependencies = [ "hir-def", "hir-ty", "ide", + "ide-completion", "ide-db", "ide-ssr", "intern", @@ -1683,6 +1694,7 @@ dependencies = [ "stdx", "syntax", "syntax-bridge", + "tenthash", "test-fixture", "test-utils", "tikv-jemallocator", @@ -1987,6 +1999,12 @@ dependencies = [ ] [[package]] +name = "tenthash" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d67f9f3cf70e0852941d7bc3cb884b49b24b8ee956baf91ad0abae31f5ef11fb" + +[[package]] name = "test-fixture" version = "0.0.0" dependencies = [ diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml index 632b290ba98..f7074f91354 100644 --- a/src/tools/rust-analyzer/Cargo.toml +++ b/src/tools/rust-analyzer/Cargo.toml @@ -84,11 +84,11 @@ tt = { path = "./crates/tt", version = "0.0.0" } vfs-notify = { path = "./crates/vfs-notify", version = "0.0.0" } vfs = { path = "./crates/vfs", version = "0.0.0" } -ra-ap-rustc_lexer = { version = "0.80", default-features = false } -ra-ap-rustc_parse_format = { version = "0.80", default-features = false } -ra-ap-rustc_index = { version = "0.80", default-features = false } -ra-ap-rustc_abi = { version = "0.80", default-features = false } -ra-ap-rustc_pattern_analysis = { version = "0.80", default-features = false } +ra-ap-rustc_lexer = { version = "0.85", default-features = false } +ra-ap-rustc_parse_format = { version = "0.85", default-features = false } +ra-ap-rustc_index = { version = "0.85", default-features = false } +ra-ap-rustc_abi = { version = "0.85", default-features = false } +ra-ap-rustc_pattern_analysis = { version = "0.85", default-features = false } # local crates that aren't published to crates.io. These should not have versions. test-fixture = { path = "./crates/test-fixture" } diff --git a/src/tools/rust-analyzer/crates/base-db/src/input.rs b/src/tools/rust-analyzer/crates/base-db/src/input.rs index 57522d69321..e86944eeb35 100644 --- a/src/tools/rust-analyzer/crates/base-db/src/input.rs +++ b/src/tools/rust-analyzer/crates/base-db/src/input.rs @@ -547,29 +547,6 @@ impl CrateGraph { None } - // Work around for https://github.com/rust-lang/rust-analyzer/issues/6038. - // As hacky as it gets. - pub fn patch_cfg_if(&mut self) -> bool { - // we stupidly max by version in an attempt to have all duplicated std's depend on the same cfg_if so that deduplication still works - let cfg_if = - self.hacky_find_crate("cfg_if").max_by_key(|&it| self.arena[it].version.clone()); - let std = self.hacky_find_crate("std").next(); - match (cfg_if, std) { - (Some(cfg_if), Some(std)) => { - self.arena[cfg_if].dependencies.clear(); - self.arena[std] - .dependencies - .push(Dependency::new(CrateName::new("cfg_if").unwrap(), cfg_if)); - true - } - _ => false, - } - } - - fn hacky_find_crate<'a>(&'a self, display_name: &'a str) -> impl Iterator<Item = CrateId> + 'a { - self.iter().filter(move |it| self[*it].display_name.as_deref() == Some(display_name)) - } - /// Removes all crates from this crate graph except for the ones in `to_keep` and fixes up the dependencies. /// Returns a mapping from old crate ids to new crate ids. pub fn remove_crates_except(&mut self, to_keep: &[CrateId]) -> Vec<Option<CrateId>> { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body.rs b/src/tools/rust-analyzer/crates/hir-def/src/body.rs index 5a386f6cf8d..867bee95bed 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/body.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/body.rs @@ -31,7 +31,7 @@ use crate::{ path::{ModPath, Path}, src::HasSource, type_ref::{TypeRef, TypeRefId, TypesMap, TypesSourceMap}, - BlockId, DefWithBodyId, HasModule, Lookup, + BlockId, DefWithBodyId, HasModule, Lookup, SyntheticSyntax, }; /// A wrapper around [`span::SyntaxContextId`] that is intended only for comparisons. @@ -141,7 +141,7 @@ pub struct BodySourceMap { field_map_back: FxHashMap<ExprId, FieldSource>, pat_field_map_back: FxHashMap<PatId, PatFieldSource>, - types: TypesSourceMap, + pub types: TypesSourceMap, // FIXME: Make this a sane struct. template_map: Option< @@ -160,9 +160,6 @@ pub struct BodySourceMap { diagnostics: Vec<BodyDiagnostic>, } -#[derive(Default, Debug, Eq, PartialEq, Clone, Copy)] -pub struct SyntheticSyntax; - #[derive(Debug, Eq, PartialEq)] pub enum BodyDiagnostic { InactiveCode { node: InFile<SyntaxNodePtr>, cfg: CfgExpr, opts: CfgOptions }, @@ -408,7 +405,8 @@ impl Body { f(else_branch); } } - Expr::Let { expr, .. } => { + Expr::Let { expr, pat } => { + self.walk_exprs_in_pat(*pat, &mut f); f(*expr); } Expr::Block { statements, tail, .. } @@ -444,7 +442,10 @@ impl Body { } Expr::Match { expr, arms } => { f(*expr); - arms.iter().map(|arm| arm.expr).for_each(f); + arms.iter().for_each(|arm| { + f(arm.expr); + self.walk_exprs_in_pat(arm.pat, &mut f); + }); } Expr::Break { expr, .. } | Expr::Return { expr } @@ -505,6 +506,131 @@ impl Body { } } + pub fn walk_child_exprs_without_pats(&self, expr_id: ExprId, mut f: impl FnMut(ExprId)) { + let expr = &self[expr_id]; + match expr { + Expr::Continue { .. } + | Expr::Const(_) + | Expr::Missing + | Expr::Path(_) + | Expr::OffsetOf(_) + | Expr::Literal(_) + | Expr::Underscore => {} + Expr::InlineAsm(it) => it.operands.iter().for_each(|(_, op)| match op { + AsmOperand::In { expr, .. } + | AsmOperand::Out { expr: Some(expr), .. } + | AsmOperand::InOut { expr, .. } => f(*expr), + AsmOperand::SplitInOut { in_expr, out_expr, .. } => { + f(*in_expr); + if let Some(out_expr) = out_expr { + f(*out_expr); + } + } + AsmOperand::Out { expr: None, .. } + | AsmOperand::Const(_) + | AsmOperand::Label(_) + | AsmOperand::Sym(_) => (), + }), + Expr::If { condition, then_branch, else_branch } => { + f(*condition); + f(*then_branch); + if let &Some(else_branch) = else_branch { + f(else_branch); + } + } + Expr::Let { expr, .. } => { + f(*expr); + } + Expr::Block { statements, tail, .. } + | Expr::Unsafe { statements, tail, .. } + | Expr::Async { statements, tail, .. } => { + for stmt in statements.iter() { + match stmt { + Statement::Let { initializer, else_branch, .. } => { + if let &Some(expr) = initializer { + f(expr); + } + if let &Some(expr) = else_branch { + f(expr); + } + } + Statement::Expr { expr: expression, .. } => f(*expression), + Statement::Item(_) => (), + } + } + if let &Some(expr) = tail { + f(expr); + } + } + Expr::Loop { body, .. } => f(*body), + Expr::Call { callee, args, .. } => { + f(*callee); + args.iter().copied().for_each(f); + } + Expr::MethodCall { receiver, args, .. } => { + f(*receiver); + args.iter().copied().for_each(f); + } + Expr::Match { expr, arms } => { + f(*expr); + arms.iter().map(|arm| arm.expr).for_each(f); + } + Expr::Break { expr, .. } + | Expr::Return { expr } + | Expr::Yield { expr } + | Expr::Yeet { expr } => { + if let &Some(expr) = expr { + f(expr); + } + } + Expr::Become { expr } => f(*expr), + Expr::RecordLit { fields, spread, .. } => { + for field in fields.iter() { + f(field.expr); + } + if let &Some(expr) = spread { + f(expr); + } + } + Expr::Closure { body, .. } => { + f(*body); + } + Expr::BinaryOp { lhs, rhs, .. } => { + f(*lhs); + f(*rhs); + } + Expr::Range { lhs, rhs, .. } => { + if let &Some(lhs) = rhs { + f(lhs); + } + if let &Some(rhs) = lhs { + f(rhs); + } + } + Expr::Index { base, index, .. } => { + f(*base); + f(*index); + } + Expr::Field { expr, .. } + | Expr::Await { expr } + | Expr::Cast { expr, .. } + | Expr::Ref { expr, .. } + | Expr::UnaryOp { expr, .. } + | Expr::Box { expr } => { + f(*expr); + } + Expr::Tuple { exprs, .. } => exprs.iter().copied().for_each(f), + Expr::Array(a) => match a { + Array::ElementList { elements, .. } => elements.iter().copied().for_each(f), + Array::Repeat { initializer, repeat } => { + f(*initializer); + f(*repeat) + } + }, + &Expr::Assignment { target: _, value } => f(value), + } + } + pub fn walk_exprs_in_pat(&self, pat_id: PatId, f: &mut impl FnMut(ExprId)) { self.walk_pats(pat_id, &mut |pat| { if let Pat::Expr(expr) | Pat::ConstBlock(expr) = self[pat] { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs index 1ab49e91569..3b73d409634 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs @@ -1510,20 +1510,20 @@ impl ExprCollector<'_> { BuiltinShadowMode::Other, None, ); + // Funnily enough, record structs/variants *can* be shadowed + // by pattern bindings (but unit or tuple structs/variants + // can't). match resolved.take_values() { Some(ModuleDefId::ConstId(_)) => (None, Pat::Path(name.into())), - Some(ModuleDefId::EnumVariantId(_)) => { - // this is only really valid for unit variants, but - // shadowing other enum variants with a pattern is - // an error anyway + Some(ModuleDefId::EnumVariantId(variant)) + if self.db.variant_data(variant.into()).kind() + != StructKind::Record => + { (None, Pat::Path(name.into())) } Some(ModuleDefId::AdtId(AdtId::StructId(s))) if self.db.struct_data(s).variant_data.kind() != StructKind::Record => { - // Funnily enough, record structs *can* be shadowed - // by pattern bindings (but unit or tuple structs - // can't). (None, Pat::Path(name.into())) } // shadowing statics is an error as well, so we just ignore that case here diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs index 3b29d98d198..8f010915845 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs @@ -1,6 +1,5 @@ mod block; -use base_db::SourceDatabase; use expect_test::{expect, Expect}; use test_fixture::WithFixture; @@ -11,7 +10,7 @@ use super::*; fn lower(ra_fixture: &str) -> (TestDB, Arc<Body>, DefWithBodyId) { let db = TestDB::with_files(ra_fixture); - let krate = db.crate_graph().iter().next().unwrap(); + let krate = db.fetch_test_crate(); let def_map = db.crate_def_map(krate); let mut fn_def = None; 'outer: for (_, module) in def_map.modules() { @@ -404,3 +403,26 @@ fn foo() { }"#]] .assert_eq(&body.pretty_print(&db, def, Edition::CURRENT)) } + +#[test] +fn shadowing_record_variant() { + let (_, body, _) = lower( + r#" +enum A { + B { field: i32 }, +} +fn f() { + use A::*; + match () { + B => {} + }; +} + "#, + ); + assert_eq!(body.bindings.len(), 1, "should have a binding for `B`"); + assert_eq!( + body.bindings[BindingId::from_raw(RawIdx::from_u32(0))].name.as_str(), + "B", + "should have a binding for `B`", + ); +} diff --git a/src/tools/rust-analyzer/crates/hir-def/src/data.rs b/src/tools/rust-analyzer/crates/hir-def/src/data.rs index 2a13f74aac7..15dd6aba311 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/data.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/data.rs @@ -369,7 +369,7 @@ impl ImplData { let item_tree = tree_id.item_tree(db); let impl_def = &item_tree[tree_id.value]; - let target_trait = impl_def.target_trait.clone(); + let target_trait = impl_def.target_trait; let self_ty = impl_def.self_ty; let is_negative = impl_def.is_negative; let is_unsafe = impl_def.is_unsafe; diff --git a/src/tools/rust-analyzer/crates/hir-def/src/generics.rs b/src/tools/rust-analyzer/crates/hir-def/src/generics.rs index 11e9bb0d886..7b3f1d06d21 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/generics.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/generics.rs @@ -26,8 +26,8 @@ use crate::{ nameres::{DefMap, MacroSubNs}, path::{AssociatedTypeBinding, GenericArg, GenericArgs, NormalPath, Path}, type_ref::{ - ArrayType, ConstRef, FnType, LifetimeRef, RefType, TypeBound, TypeRef, TypeRefId, TypesMap, - TypesSourceMap, + ArrayType, ConstRef, FnType, LifetimeRef, PathId, RefType, TypeBound, TypeRef, TypeRefId, + TypesMap, TypesSourceMap, }, AdtId, ConstParamId, GenericDefId, HasModule, ItemTreeLoc, LifetimeParamId, LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup, TypeOrConstParamId, TypeParamId, @@ -225,6 +225,11 @@ impl GenericParams { } #[inline] + pub fn no_predicates(&self) -> bool { + self.where_predicates.is_empty() + } + + #[inline] pub fn where_predicates(&self) -> std::slice::Iter<'_, WherePredicate> { self.where_predicates.iter() } @@ -874,14 +879,20 @@ fn copy_type_bound( to: &mut TypesMap, to_source_map: &mut TypesSourceMap, ) -> TypeBound { + let mut copy_path_id = |path: PathId| { + let new_path = copy_path(&from[path], from, from_source_map, to, to_source_map); + let new_path_id = to.types.alloc(TypeRef::Path(new_path)); + if let Some(&ptr) = from_source_map.types_map_back.get(path.type_ref()) { + to_source_map.types_map_back.insert(new_path_id, ptr); + } + PathId::from_type_ref_unchecked(new_path_id) + }; + match bound { - TypeBound::Path(path, modifier) => { - TypeBound::Path(copy_path(path, from, from_source_map, to, to_source_map), *modifier) + &TypeBound::Path(path, modifier) => TypeBound::Path(copy_path_id(path), modifier), + TypeBound::ForLifetime(lifetimes, path) => { + TypeBound::ForLifetime(lifetimes.clone(), copy_path_id(*path)) } - TypeBound::ForLifetime(lifetimes, path) => TypeBound::ForLifetime( - lifetimes.clone(), - copy_path(path, from, from_source_map, to, to_source_map), - ), TypeBound::Lifetime(lifetime) => TypeBound::Lifetime(lifetime.clone()), TypeBound::Use(use_args) => TypeBound::Use(use_args.clone()), TypeBound::Error => TypeBound::Error, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs b/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs index 4d83ef99c84..6d4d519cd2b 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/hir/type_ref.rs @@ -23,6 +23,7 @@ use crate::{ hir::Literal, lower::LowerCtx, path::{GenericArg, Path}, + SyntheticSyntax, }; #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] @@ -91,19 +92,37 @@ impl Rawness { } } -#[derive(Clone, PartialEq, Eq, Hash, Debug)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] +/// A `TypeRefId` that is guaranteed to always be `TypeRef::Path`. We use this for things like +/// impl's trait, that are always paths but need to be traced back to source code. +pub struct PathId(TypeRefId); + +impl PathId { + #[inline] + pub fn from_type_ref_unchecked(type_ref: TypeRefId) -> Self { + Self(type_ref) + } + + #[inline] + pub fn type_ref(self) -> TypeRefId { + self.0 + } +} + +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] pub struct TraitRef { - pub path: Path, + pub path: PathId, } impl TraitRef { /// Converts an `ast::PathType` to a `hir::TraitRef`. pub(crate) fn from_ast(ctx: &mut LowerCtx<'_>, node: ast::Type) -> Option<Self> { // FIXME: Use `Path::from_src` - match node { - ast::Type::PathType(path) => { - path.path().and_then(|it| ctx.lower_path(it)).map(|path| TraitRef { path }) - } + match &node { + ast::Type::PathType(path) => path + .path() + .and_then(|it| ctx.lower_path(it)) + .map(|path| TraitRef { path: ctx.alloc_path(path, AstPtr::new(&node)) }), _ => None, } } @@ -173,11 +192,24 @@ impl TypesMap { impl Index<TypeRefId> for TypesMap { type Output = TypeRef; + #[inline] fn index(&self, index: TypeRefId) -> &Self::Output { &self.types[index] } } +impl Index<PathId> for TypesMap { + type Output = Path; + + #[inline] + fn index(&self, index: PathId) -> &Self::Output { + let TypeRef::Path(path) = &self[index.type_ref()] else { + unreachable!("`PathId` always points to `TypeRef::Path`"); + }; + path + } +} + pub type TypePtr = AstPtr<ast::Type>; pub type TypeSource = InFile<TypePtr>; @@ -187,6 +219,12 @@ pub struct TypesSourceMap { } impl TypesSourceMap { + pub const EMPTY: Self = Self { types_map_back: ArenaMap::new() }; + + pub fn type_syntax(&self, id: TypeRefId) -> Result<TypeSource, SyntheticSyntax> { + self.types_map_back.get(id).cloned().ok_or(SyntheticSyntax) + } + pub(crate) fn shrink_to_fit(&mut self) { let TypesSourceMap { types_map_back } = self; types_map_back.shrink_to_fit(); @@ -214,15 +252,15 @@ impl LifetimeRef { #[derive(Clone, PartialEq, Eq, Hash, Debug)] pub enum TypeBound { - Path(Path, TraitBoundModifier), - ForLifetime(Box<[Name]>, Path), + Path(PathId, TraitBoundModifier), + ForLifetime(Box<[Name]>, PathId), Lifetime(LifetimeRef), Use(Box<[UseArgRef]>), Error, } #[cfg(target_pointer_width = "64")] -const _: [(); 32] = [(); ::std::mem::size_of::<TypeBound>()]; +const _: [(); 24] = [(); ::std::mem::size_of::<TypeBound>()]; #[derive(Clone, PartialEq, Eq, Hash, Debug)] pub enum UseArgRef { @@ -365,8 +403,8 @@ impl TypeRef { TypeRef::ImplTrait(bounds) | TypeRef::DynTrait(bounds) => { for bound in bounds { match bound { - TypeBound::Path(path, _) | TypeBound::ForLifetime(_, path) => { - go_path(path, f, map) + &TypeBound::Path(path, _) | &TypeBound::ForLifetime(_, path) => { + go_path(&map[path], f, map) } TypeBound::Lifetime(_) | TypeBound::Error | TypeBound::Use(_) => (), } @@ -397,8 +435,8 @@ impl TypeRef { } for bound in binding.bounds.iter() { match bound { - TypeBound::Path(path, _) | TypeBound::ForLifetime(_, path) => { - go_path(path, f, map) + &TypeBound::Path(path, _) | &TypeBound::ForLifetime(_, path) => { + go_path(&map[path], f, map) } TypeBound::Lifetime(_) | TypeBound::Error | TypeBound::Use(_) => (), } @@ -425,7 +463,7 @@ pub(crate) fn type_bounds_from_ast( impl TypeBound { pub(crate) fn from_ast(ctx: &mut LowerCtx<'_>, node: ast::TypeBound) -> Self { - let mut lower_path_type = |path_type: ast::PathType| ctx.lower_path(path_type.path()?); + let mut lower_path_type = |path_type: &ast::PathType| ctx.lower_path(path_type.path()?); match node.kind() { ast::TypeBoundKind::PathType(path_type) => { @@ -433,8 +471,10 @@ impl TypeBound { Some(_) => TraitBoundModifier::Maybe, None => TraitBoundModifier::None, }; - lower_path_type(path_type) - .map(|p| TypeBound::Path(p, m)) + lower_path_type(&path_type) + .map(|p| { + TypeBound::Path(ctx.alloc_path(p, AstPtr::new(&path_type).upcast()), m) + }) .unwrap_or(TypeBound::Error) } ast::TypeBoundKind::ForType(for_type) => { @@ -445,12 +485,14 @@ impl TypeBound { .collect(), None => Box::default(), }; - let path = for_type.ty().and_then(|ty| match ty { - ast::Type::PathType(path_type) => lower_path_type(path_type), + let path = for_type.ty().and_then(|ty| match &ty { + ast::Type::PathType(path_type) => lower_path_type(path_type).map(|p| (p, ty)), _ => None, }); match path { - Some(p) => TypeBound::ForLifetime(lt_refs, p), + Some((p, ty)) => { + TypeBound::ForLifetime(lt_refs, ctx.alloc_path(p, AstPtr::new(&ty))) + } None => TypeBound::Error, } } @@ -470,10 +512,10 @@ impl TypeBound { } } - pub fn as_path(&self) -> Option<(&Path, &TraitBoundModifier)> { + pub fn as_path<'a>(&self, map: &'a TypesMap) -> Option<(&'a Path, TraitBoundModifier)> { match self { - TypeBound::Path(p, m) => Some((p, m)), - TypeBound::ForLifetime(_, p) => Some((p, &TraitBoundModifier::None)), + &TypeBound::Path(p, m) => Some((&map[p], m)), + &TypeBound::ForLifetime(_, p) => Some((&map[p], TraitBoundModifier::None)), TypeBound::Lifetime(_) | TypeBound::Error | TypeBound::Use(_) => None, } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs index d519c1708b3..71848845a84 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs @@ -34,7 +34,7 @@ use crate::{ lower::LowerCtx, path::AssociatedTypeBinding, type_ref::{ - LifetimeRef, RefType, TraitBoundModifier, TraitRef, TypeBound, TypeRef, TypeRefId, + LifetimeRef, PathId, RefType, TraitBoundModifier, TraitRef, TypeBound, TypeRef, TypeRefId, TypesMap, TypesSourceMap, }, visibility::RawVisibility, @@ -514,7 +514,7 @@ impl<'a> Ctx<'a> { }; let ret_type = if func.async_token().is_some() { - let future_impl = desugar_future_path(ret_type); + let future_impl = desugar_future_path(&mut body_ctx, ret_type); let ty_bound = TypeBound::Path(future_impl, TraitBoundModifier::None); body_ctx.alloc_type_ref_desugared(TypeRef::ImplTrait(ThinVec::from_iter([ty_bound]))) } else { @@ -936,7 +936,7 @@ impl<'a> Ctx<'a> { } } -fn desugar_future_path(orig: TypeRefId) -> Path { +fn desugar_future_path(ctx: &mut LowerCtx<'_>, orig: TypeRefId) -> PathId { let path = path![core::future::Future]; let mut generic_args: Vec<_> = std::iter::repeat(None).take(path.segments().len() - 1).collect(); @@ -948,7 +948,8 @@ fn desugar_future_path(orig: TypeRefId) -> Path { }; generic_args.push(Some(GenericArgs { bindings: Box::new([binding]), ..GenericArgs::empty() })); - Path::from_known_path(path, generic_args) + let path = Path::from_known_path(path, generic_args); + PathId::from_type_ref_unchecked(ctx.alloc_type_ref_desugared(TypeRef::Path(path))) } enum HasImplicitSelf { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs index b6816a1f968..70bf2f13c88 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs @@ -484,7 +484,7 @@ impl Printer<'_> { w!(self, "!"); } if let Some(tr) = target_trait { - self.print_path(&tr.path, types_map); + self.print_path(&types_map[tr.path], types_map); w!(self, " for "); } self.print_type_ref(*self_ty, types_map); @@ -648,9 +648,9 @@ impl Printer<'_> { let (target, bound) = match pred { WherePredicate::TypeBound { target, bound } => (target, bound), WherePredicate::Lifetime { target, bound } => { - wln!( + w!( this, - "{}: {},", + "{}: {}", target.name.display(self.db.upcast(), edition), bound.name.display(self.db.upcast(), edition) ); diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs index 5c07369f4b5..0f53969d6c7 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs @@ -351,7 +351,8 @@ trait Tr<'a, T: 'a>: Super where Self: for<'a> Tr<'a, T> {} where T: Copy, T: 'a, - T: 'b + T: 'b, + 'b: 'a { pub(self) field: &'a &'b T, } @@ -370,7 +371,8 @@ trait Tr<'a, T: 'a>: Super where Self: for<'a> Tr<'a, T> {} where T: Copy, T: 'a, - T: 'b + T: 'b, + 'b: 'a { // AstId: 9 pub(self) fn f<G>( diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs b/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs index 166c965d14c..0629d87e544 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs @@ -376,6 +376,9 @@ language_item_table! { Fn, sym::fn_, fn_trait, Target::Trait, GenericRequirement::Exact(1); FnMut, sym::fn_mut, fn_mut_trait, Target::Trait, GenericRequirement::Exact(1); FnOnce, sym::fn_once, fn_once_trait, Target::Trait, GenericRequirement::Exact(1); + AsyncFn, sym::async_fn, async_fn_trait, Target::Trait, GenericRequirement::Exact(1); + AsyncFnMut, sym::async_fn_mut, async_fn_mut_trait, Target::Trait, GenericRequirement::Exact(1); + AsyncFnOnce, sym::async_fn_once, async_fn_once_trait, Target::Trait, GenericRequirement::Exact(1); FnOnceOutput, sym::fn_once_output, fn_once_output, Target::AssocTy, GenericRequirement::None; diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs index eb55ba1d53d..8af27513ebc 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs @@ -1535,3 +1535,6 @@ fn macro_call_as_call_id_with_eager( pub struct UnresolvedMacro { pub path: hir_expand::mod_path::ModPath, } + +#[derive(Default, Debug, Eq, PartialEq, Clone, Copy)] +pub struct SyntheticSyntax; diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/lower.rs index 6d1a3d17447..7cddd48eb17 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/lower.rs @@ -2,7 +2,7 @@ use std::{cell::OnceCell, mem}; use hir_expand::{span_map::SpanMap, AstId, HirFileId, InFile}; -use span::{AstIdMap, AstIdNode}; +use span::{AstIdMap, AstIdNode, Edition, EditionedFileId, FileId, RealSpanMap}; use stdx::thin_vec::ThinVec; use syntax::ast; use triomphe::Arc; @@ -10,7 +10,7 @@ use triomphe::Arc; use crate::{ db::DefDatabase, path::Path, - type_ref::{TypeBound, TypePtr, TypeRef, TypeRefId, TypesMap, TypesSourceMap}, + type_ref::{PathId, TypeBound, TypePtr, TypeRef, TypeRefId, TypesMap, TypesSourceMap}, }; pub struct LowerCtx<'a> { @@ -63,6 +63,30 @@ impl<'a> LowerCtx<'a> { } } + /// Prepares a `LowerCtx` for synthetic AST that needs to be lowered. This is intended for IDE things. + pub fn for_synthetic_ast( + db: &'a dyn DefDatabase, + ast_id_map: Arc<AstIdMap>, + types_map: &'a mut TypesMap, + types_source_map: &'a mut TypesSourceMap, + ) -> Self { + let file_id = EditionedFileId::new( + FileId::from_raw(EditionedFileId::MAX_FILE_ID), + Edition::Edition2015, + ); + LowerCtx { + db, + // Make up an invalid file id, so that if we will try to actually access it salsa will panic. + file_id: file_id.into(), + span_map: SpanMap::RealSpanMap(Arc::new(RealSpanMap::absolute(file_id))).into(), + ast_id_map: ast_id_map.into(), + impl_trait_bounds: Vec::new(), + outer_impl_trait: false, + types_map, + types_source_map, + } + } + pub(crate) fn span_map(&self) -> &SpanMap { self.span_map.get_or_init(|| self.db.span_map(self.file_id)) } @@ -118,4 +142,8 @@ impl<'a> LowerCtx<'a> { pub(crate) fn alloc_error_type(&mut self) -> TypeRefId { self.types_map.types.alloc(TypeRef::Error) } + + pub(crate) fn alloc_path(&mut self, path: Path, node: TypePtr) -> PathId { + PathId::from_type_ref_unchecked(self.alloc_type_ref(TypeRef::Path(path), node)) + } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs index d568f6faa72..511626b5ed9 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs @@ -1733,7 +1733,7 @@ m!(C("0")); macro_rules! m { ($k:expr) => { fn f() { K::$k; } } } -/* parse error: expected identifier */ +/* parse error: expected identifier, `self`, `super`, `crate`, or `Self` */ /* parse error: expected SEMICOLON */ /* parse error: expected SEMICOLON */ /* parse error: expected expression, item or let statement */ @@ -1759,8 +1759,9 @@ fn f() { // NAME_REF@6..7 // IDENT@6..7 "K" // COLON2@7..9 "::" -// ERROR@9..10 -// L_PAREN@9..10 "(" +// PATH_SEGMENT@9..10 +// ERROR@9..10 +// L_PAREN@9..10 "(" // EXPR_STMT@10..16 // CALL_EXPR@10..16 // PATH_EXPR@10..11 diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/matching.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/matching.rs index 23d8b023b8b..e9a977da913 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/matching.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/matching.rs @@ -184,3 +184,31 @@ fn test() { "#]], ); } + +#[test] +fn meta_variable_raw_name_equals_non_raw() { + check( + r#" +macro_rules! m { + ($r#name:tt) => { + $name + } +} + +fn test() { + m!(1234) +} +"#, + expect![[r#" +macro_rules! m { + ($r#name:tt) => { + $name + } +} + +fn test() { + 1234 +} +"#]], + ); +} diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs index d5b94f0ae44..0475e40c5b2 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs @@ -16,7 +16,6 @@ mod proc_macros; use std::{iter, ops::Range, sync}; -use base_db::SourceDatabase; use expect_test::Expect; use hir_expand::{ db::ExpandDatabase, @@ -63,7 +62,7 @@ pub fn identity_when_valid(_attr: TokenStream, item: TokenStream) -> TokenStream }, )]; let db = TestDB::with_files_extra_proc_macros(ra_fixture, extra_proc_macros); - let krate = db.crate_graph().iter().next().unwrap(); + let krate = db.fetch_test_crate(); let def_map = db.crate_def_map(krate); let local_id = DefMap::ROOT; let module = def_map.module_id(local_id); diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs index a37e3c70e22..98b08bcf708 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs @@ -910,8 +910,13 @@ impl DefCollector<'_> { self.update(module_id, &items, vis, Some(ImportType::Glob(id))); // record the glob import in case we add further items let glob = self.glob_imports.entry(m.local_id).or_default(); - if !glob.iter().any(|(mid, _, _)| *mid == module_id) { - glob.push((module_id, vis, id)); + match glob.iter_mut().find(|(mid, _, _)| *mid == module_id) { + None => glob.push((module_id, vis, id)), + Some((_, old_vis, _)) => { + if let Some(new_vis) = old_vis.max(vis, &self.def_map) { + *old_vis = new_vis; + } + } } } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs index e1e30e5cec9..32c158415ba 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs @@ -13,13 +13,13 @@ use crate::{db::DefDatabase, nameres::DefMap, test_db::TestDB}; fn compute_crate_def_map(ra_fixture: &str) -> Arc<DefMap> { let db = TestDB::with_files(ra_fixture); - let krate = db.crate_graph().iter().next().unwrap(); + let krate = db.fetch_test_crate(); db.crate_def_map(krate) } fn render_crate_def_map(ra_fixture: &str) -> String { let db = TestDB::with_files(ra_fixture); - let krate = db.crate_graph().iter().next().unwrap(); + let krate = db.fetch_test_crate(); db.crate_def_map(krate).dump(&db) } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/globs.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/globs.rs index 543ab41cd59..8963a576794 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/globs.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/globs.rs @@ -451,3 +451,42 @@ mod glob_target { "#]], ); } + +#[test] +fn regression_18580() { + check( + r#" +pub mod libs { + pub struct Placeholder; +} + +pub mod reexport_2 { + use reexport_1::*; + pub use reexport_1::*; + + pub mod reexport_1 { + pub use crate::libs::*; + } +} + +use reexport_2::*; +"#, + expect![[r#" + crate + Placeholder: t v + libs: t + reexport_1: t + reexport_2: t + + crate::libs + Placeholder: t v + + crate::reexport_2 + Placeholder: t v + reexport_1: t + + crate::reexport_2::reexport_1 + Placeholder: t v + "#]], + ); +} diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs index d920c108266..1cfbabca28c 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs @@ -1,15 +1,11 @@ -use base_db::{SourceDatabase, SourceDatabaseFileInputExt as _}; +use base_db::SourceDatabaseFileInputExt as _; use test_fixture::WithFixture; use crate::{db::DefDatabase, nameres::tests::TestDB, AdtId, ModuleDefId}; fn check_def_map_is_not_recomputed(ra_fixture_initial: &str, ra_fixture_change: &str) { let (mut db, pos) = TestDB::with_position(ra_fixture_initial); - let krate = { - let crate_graph = db.crate_graph(); - // Some of these tests use minicore/proc-macros which will be injected as the first crate - crate_graph.iter().last().unwrap() - }; + let krate = db.fetch_test_crate(); { let events = db.log_executed(|| { db.crate_def_map(krate); @@ -120,28 +116,31 @@ fn f() { foo } ); } -#[test] -fn typing_inside_an_attribute_arg_should_not_invalidate_def_map() { - check_def_map_is_not_recomputed( - r" -//- proc_macros: identity -//- /lib.rs -mod foo; +// Would be nice if this was the case, but as attribute inputs are stored in the item tree, this is +// not currently the case. +// #[test] +// fn typing_inside_an_attribute_arg_should_not_invalidate_def_map() { +// check_def_map_is_not_recomputed( +// r" +// //- proc_macros: identity +// //- /lib.rs +// mod foo; + +// //- /foo/mod.rs +// pub mod bar; + +// //- /foo/bar.rs +// $0 +// #[proc_macros::identity] +// fn f() {} +// ", +// r" +// #[proc_macros::identity(foo)] +// fn f() {} +// ", +// ); +// } -//- /foo/mod.rs -pub mod bar; - -//- /foo/bar.rs -$0 -#[proc_macros::identity] -fn f() {} -", - r" -#[proc_macros::identity(foo)] -fn f() {} -", - ); -} #[test] fn typing_inside_macro_heavy_file_should_not_invalidate_def_map() { check_def_map_is_not_recomputed( @@ -198,31 +197,33 @@ pub struct S {} ); } -#[test] -fn typing_inside_a_derive_should_not_invalidate_def_map() { - check_def_map_is_not_recomputed( - r" -//- proc_macros: derive_identity -//- minicore:derive -//- /lib.rs -mod foo; - -//- /foo/mod.rs -pub mod bar; - -//- /foo/bar.rs -$0 -#[derive(proc_macros::DeriveIdentity)] -#[allow()] -struct S; -", - r" -#[derive(proc_macros::DeriveIdentity)] -#[allow(dead_code)] -struct S; -", - ); -} +// Would be nice if this was the case, but as attribute inputs are stored in the item tree, this is +// not currently the case. +// #[test] +// fn typing_inside_a_derive_should_not_invalidate_def_map() { +// check_def_map_is_not_recomputed( +// r" +// //- proc_macros: derive_identity +// //- minicore:derive +// //- /lib.rs +// mod foo; + +// //- /foo/mod.rs +// pub mod bar; + +// //- /foo/bar.rs +// $0 +// #[derive(proc_macros::DeriveIdentity)] +// #[allow()] +// struct S; +// ", +// r" +// #[derive(proc_macros::DeriveIdentity)] +// #[allow(dead_code)] +// struct S; +// ", +// ); +// } #[test] fn typing_inside_a_function_should_not_invalidate_item_expansions() { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/path.rs b/src/tools/rust-analyzer/crates/hir-def/src/path.rs index aa2c4a6f1bc..44e132061ad 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/path.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/path.rs @@ -1,5 +1,7 @@ //! A desugared representation of paths like `crate::foo` or `<Type as Trait>::bar`. mod lower; +#[cfg(test)] +mod tests; use std::{ fmt::{self, Display}, @@ -19,6 +21,8 @@ use syntax::ast; pub use hir_expand::mod_path::{path, ModPath, PathKind}; +pub use lower::hir_segment_to_ast_segment; + #[derive(Debug, Clone, PartialEq, Eq)] pub enum ImportAlias { /// Unnamed alias, as in `use Foo as _;` @@ -230,7 +234,7 @@ impl Path { } } -#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct PathSegment<'a> { pub name: &'a Name, pub args_and_bindings: Option<&'a GenericArgs>, @@ -274,6 +278,12 @@ impl<'a> PathSegments<'a> { generic_args: self.generic_args.map(|it| it.get(..len).unwrap_or(it)), } } + pub fn strip_last(&self) -> PathSegments<'a> { + PathSegments { + segments: self.segments.split_last().map_or(&[], |it| it.1), + generic_args: self.generic_args.map(|it| it.split_last().map_or(&[][..], |it| it.1)), + } + } pub fn iter(&self) -> impl Iterator<Item = PathSegment<'a>> { self.segments .iter() diff --git a/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs index 553e615b94f..3b7e7653fba 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs @@ -17,13 +17,31 @@ use crate::{ type_ref::{LifetimeRef, TypeBound, TypeRef}, }; +#[cfg(test)] +thread_local! { + /// This is used to test `hir_segment_to_ast_segment()`. It's a hack, but it makes testing much easier. + pub(super) static SEGMENT_LOWERING_MAP: std::cell::RefCell<rustc_hash::FxHashMap<ast::PathSegment, usize>> = std::cell::RefCell::default(); +} + /// Converts an `ast::Path` to `Path`. Works with use trees. /// It correctly handles `$crate` based path from macro call. +// If you modify the logic of the lowering, make sure to check if `hir_segment_to_ast_segment()` +// also needs an update. pub(super) fn lower_path(ctx: &mut LowerCtx<'_>, mut path: ast::Path) -> Option<Path> { let mut kind = PathKind::Plain; let mut type_anchor = None; let mut segments = Vec::new(); let mut generic_args = Vec::new(); + #[cfg(test)] + let mut ast_segments = Vec::new(); + #[cfg(test)] + let mut ast_segments_offset = 0; + #[allow(unused_mut)] + let mut push_segment = |_segment: &ast::PathSegment, segments: &mut Vec<Name>, name| { + #[cfg(test)] + ast_segments.push(_segment.clone()); + segments.push(name); + }; loop { let segment = path.segment()?; @@ -34,6 +52,10 @@ pub(super) fn lower_path(ctx: &mut LowerCtx<'_>, mut path: ast::Path) -> Option< match segment.kind()? { ast::PathSegmentKind::Name(name_ref) => { if name_ref.text() == "$crate" { + if path.qualifier().is_some() { + // FIXME: Report an error. + return None; + } break kind = resolve_crate_root( ctx.db.upcast(), ctx.span_map().span_for_range(name_ref.syntax().text_range()).ctx, @@ -48,7 +70,7 @@ pub(super) fn lower_path(ctx: &mut LowerCtx<'_>, mut path: ast::Path) -> Option< .or_else(|| { lower_generic_args_from_fn_path( ctx, - segment.param_list(), + segment.parenthesized_arg_list(), segment.ret_type(), ) }); @@ -56,10 +78,10 @@ pub(super) fn lower_path(ctx: &mut LowerCtx<'_>, mut path: ast::Path) -> Option< generic_args.resize(segments.len(), None); generic_args.push(args); } - segments.push(name); + push_segment(&segment, &mut segments, name); } ast::PathSegmentKind::SelfTypeKw => { - segments.push(Name::new_symbol_root(sym::Self_.clone())); + push_segment(&segment, &mut segments, Name::new_symbol_root(sym::Self_.clone())); } ast::PathSegmentKind::Type { type_ref, trait_ref } => { assert!(path.qualifier().is_none()); // this can only occur at the first segment @@ -81,6 +103,10 @@ pub(super) fn lower_path(ctx: &mut LowerCtx<'_>, mut path: ast::Path) -> Option< kind = mod_path.kind; segments.extend(mod_path.segments().iter().cloned().rev()); + #[cfg(test)] + { + ast_segments_offset = mod_path.segments().len(); + } if let Some(path_generic_args) = path_generic_args { generic_args.resize(segments.len() - num_segments, None); generic_args.extend(Vec::from(path_generic_args).into_iter().rev()); @@ -112,10 +138,18 @@ pub(super) fn lower_path(ctx: &mut LowerCtx<'_>, mut path: ast::Path) -> Option< } } ast::PathSegmentKind::CrateKw => { + if path.qualifier().is_some() { + // FIXME: Report an error. + return None; + } kind = PathKind::Crate; break; } ast::PathSegmentKind::SelfKw => { + if path.qualifier().is_some() { + // FIXME: Report an error. + return None; + } // don't break out if `self` is the last segment of a path, this mean we got a // use tree like `foo::{self}` which we want to resolve as `foo` if !segments.is_empty() { @@ -162,6 +196,13 @@ pub(super) fn lower_path(ctx: &mut LowerCtx<'_>, mut path: ast::Path) -> Option< } } + #[cfg(test)] + { + ast_segments.reverse(); + SEGMENT_LOWERING_MAP + .with_borrow_mut(|map| map.extend(ast_segments.into_iter().zip(ast_segments_offset..))); + } + let mod_path = Interned::new(ModPath::from_segments(kind, segments)); if type_anchor.is_none() && generic_args.is_empty() { return Some(Path::BarePath(mod_path)); @@ -181,6 +222,41 @@ pub(super) fn lower_path(ctx: &mut LowerCtx<'_>, mut path: ast::Path) -> Option< } } +/// This function finds the AST segment that corresponds to the HIR segment +/// with index `segment_idx` on the path that is lowered from `path`. +pub fn hir_segment_to_ast_segment(path: &ast::Path, segment_idx: u32) -> Option<ast::PathSegment> { + // Too tightly coupled to `lower_path()`, but unfortunately we cannot decouple them, + // as keeping source maps for all paths segments will have a severe impact on memory usage. + + let mut segments = path.segments(); + if let Some(ast::PathSegmentKind::Type { trait_ref: Some(trait_ref), .. }) = + segments.clone().next().and_then(|it| it.kind()) + { + segments.next(); + return find_segment(trait_ref.path()?.segments().chain(segments), segment_idx); + } + return find_segment(segments, segment_idx); + + fn find_segment( + segments: impl Iterator<Item = ast::PathSegment>, + segment_idx: u32, + ) -> Option<ast::PathSegment> { + segments + .filter(|segment| match segment.kind() { + Some( + ast::PathSegmentKind::CrateKw + | ast::PathSegmentKind::SelfKw + | ast::PathSegmentKind::SuperKw + | ast::PathSegmentKind::Type { .. }, + ) + | None => false, + Some(ast::PathSegmentKind::Name(name)) => name.text() != "$crate", + Some(ast::PathSegmentKind::SelfTypeKw) => true, + }) + .nth(segment_idx as usize) + } +} + pub(super) fn lower_generic_args( lower_ctx: &mut LowerCtx<'_>, node: ast::GenericArgList, @@ -247,12 +323,12 @@ pub(super) fn lower_generic_args( /// -> Z` (which desugars to `Fn<(X, Y), Output=Z>`). fn lower_generic_args_from_fn_path( ctx: &mut LowerCtx<'_>, - params: Option<ast::ParamList>, + args: Option<ast::ParenthesizedArgList>, ret_type: Option<ast::RetType>, ) -> Option<GenericArgs> { - let params = params?; + let params = args?; let mut param_types = Vec::new(); - for param in params.params() { + for param in params.type_args() { let type_ref = TypeRef::from_ast_opt(ctx, param.ty()); param_types.push(type_ref); } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/path/tests.rs b/src/tools/rust-analyzer/crates/hir-def/src/path/tests.rs new file mode 100644 index 00000000000..67a27bf85e8 --- /dev/null +++ b/src/tools/rust-analyzer/crates/hir-def/src/path/tests.rs @@ -0,0 +1,126 @@ +use expect_test::{expect, Expect}; +use span::Edition; +use syntax::ast::{self, make}; +use test_fixture::WithFixture; + +use crate::{ + lower::LowerCtx, + path::{ + lower::{hir_segment_to_ast_segment, SEGMENT_LOWERING_MAP}, + Path, + }, + pretty, + test_db::TestDB, + type_ref::{TypesMap, TypesSourceMap}, +}; + +fn lower_path(path: ast::Path) -> (TestDB, TypesMap, Option<Path>) { + let (db, file_id) = TestDB::with_single_file(""); + let mut types_map = TypesMap::default(); + let mut types_source_map = TypesSourceMap::default(); + let mut ctx = LowerCtx::new(&db, file_id.into(), &mut types_map, &mut types_source_map); + let lowered_path = ctx.lower_path(path); + (db, types_map, lowered_path) +} + +#[track_caller] +fn check_hir_to_ast(path: &str, ignore_segments: &[&str]) { + let path = make::path_from_text(path); + SEGMENT_LOWERING_MAP.with_borrow_mut(|map| map.clear()); + let _ = lower_path(path.clone()).2.expect("failed to lower path"); + SEGMENT_LOWERING_MAP.with_borrow(|map| { + for (segment, segment_idx) in map { + if ignore_segments.contains(&&*segment.to_string()) { + continue; + } + + let restored_segment = hir_segment_to_ast_segment(&path, *segment_idx as u32) + .unwrap_or_else(|| { + panic!( + "failed to map back segment `{segment}` \ + numbered {segment_idx} in HIR from path `{path}`" + ) + }); + assert_eq!( + segment, &restored_segment, + "mapping back `{segment}` numbered {segment_idx} in HIR \ + from path `{path}` produced incorrect segment `{restored_segment}`" + ); + } + }); +} + +#[test] +fn hir_to_ast_trait_ref() { + check_hir_to_ast("<A as B::C::D>::E::F", &["A"]); +} + +#[test] +fn hir_to_ast_plain_path() { + check_hir_to_ast("A::B::C::D::E::F", &[]); +} + +#[test] +fn hir_to_ast_crate_path() { + check_hir_to_ast("crate::A::B::C", &[]); + check_hir_to_ast("crate::super::super::A::B::C", &[]); +} + +#[test] +fn hir_to_ast_self_path() { + check_hir_to_ast("self::A::B::C", &[]); + check_hir_to_ast("self::super::super::A::B::C", &[]); +} + +#[test] +fn hir_to_ast_super_path() { + check_hir_to_ast("super::A::B::C", &[]); + check_hir_to_ast("super::super::super::A::B::C", &[]); +} + +#[test] +fn hir_to_ast_type_anchor_path() { + check_hir_to_ast("<A::B>::C::D", &["A", "B"]); +} + +#[test] +fn hir_to_ast_path_super_in_middle() { + check_hir_to_ast("A::super::B::super::super::C::D", &[]); +} + +#[track_caller] +fn check_fail_lowering(path: &str) { + let (_, _, lowered_path) = lower_path(make::path_from_text(path)); + assert!(lowered_path.is_none(), "path `{path}` should fail lowering"); +} + +#[test] +fn keywords_in_middle_fail_lowering1() { + check_fail_lowering("self::A::self::B::super::C::crate::D"); +} + +#[test] +fn keywords_in_middle_fail_lowering2() { + check_fail_lowering("A::super::self::C::D"); +} + +#[test] +fn keywords_in_middle_fail_lowering3() { + check_fail_lowering("A::crate::B::C::D"); +} + +#[track_caller] +fn check_path_lowering(path: &str, expected: Expect) { + let (db, types_map, lowered_path) = lower_path(make::path_from_text(path)); + let lowered_path = lowered_path.expect("failed to lower path"); + let mut buf = String::new(); + pretty::print_path(&db, &lowered_path, &types_map, &mut buf, Edition::CURRENT) + .expect("failed to pretty-print path"); + expected.assert_eq(&buf); +} + +#[test] +fn fn_like_path_with_coloncolon() { + check_path_lowering("Fn::(A, B) -> C", expect![[r#"Fn::<(A, B), Output = C>"#]]); + check_path_lowering("Fn::(A, B)", expect![[r#"Fn::<(A, B), Output = ()>"#]]); +} diff --git a/src/tools/rust-analyzer/crates/hir-def/src/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/pretty.rs index 9ceb82d5fd6..eb9488feaa9 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/pretty.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/pretty.rs @@ -271,7 +271,7 @@ pub(crate) fn print_type_bounds( TraitBoundModifier::None => (), TraitBoundModifier::Maybe => write!(buf, "?")?, } - print_path(db, path, map, buf, edition)?; + print_path(db, &map[*path], map, buf, edition)?; } TypeBound::ForLifetime(lifetimes, path) => { write!( @@ -279,7 +279,7 @@ pub(crate) fn print_type_bounds( "for<{}> ", lifetimes.iter().map(|it| it.display(db.upcast(), edition)).format(", ") )?; - print_path(db, path, map, buf, edition)?; + print_path(db, &map[*path], map, buf, edition)?; } TypeBound::Lifetime(lt) => write!(buf, "{}", lt.name.display(db.upcast(), edition))?, TypeBound::Use(args) => { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs index 26655e40ca7..316406c151f 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs @@ -576,10 +576,12 @@ impl Resolver { match scope { Scope::BlockScope(m) => traits.extend(m.def_map[m.module_id].scope.traits()), &Scope::ImplDefScope(impl_) => { - if let Some(target_trait) = &db.impl_data(impl_).target_trait { - if let Some(TypeNs::TraitId(trait_)) = - self.resolve_path_in_type_ns_fully(db, &target_trait.path) - { + let impl_data = db.impl_data(impl_); + if let Some(target_trait) = impl_data.target_trait { + if let Some(TypeNs::TraitId(trait_)) = self.resolve_path_in_type_ns_fully( + db, + &impl_data.types_map[target_trait.path], + ) { traits.insert(trait_); } } @@ -640,9 +642,9 @@ impl Resolver { }) } - pub fn generic_params(&self) -> Option<&Arc<GenericParams>> { + pub fn generic_params(&self) -> Option<&GenericParams> { self.scopes().find_map(|scope| match scope { - Scope::GenericParams { params, .. } => Some(params), + Scope::GenericParams { params, .. } => Some(&**params), _ => None, }) } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs b/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs index 0c36c88fb09..54e6c1fd206 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs @@ -78,6 +78,19 @@ impl FileLoader for TestDB { } impl TestDB { + pub(crate) fn fetch_test_crate(&self) -> CrateId { + let crate_graph = self.crate_graph(); + let it = crate_graph + .iter() + .find(|&idx| { + crate_graph[idx].display_name.as_ref().map(|it| it.canonical_name().as_str()) + == Some("ra_test_fixture") + }) + .or_else(|| crate_graph.iter().next()) + .unwrap(); + it + } + pub(crate) fn module_for_file(&self, file_id: FileId) -> ModuleId { for &krate in self.relevant_crates(file_id).iter() { let crate_def_map = self.crate_def_map(krate); diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/files.rs b/src/tools/rust-analyzer/crates/hir-expand/src/files.rs index d41f69812ee..8c04d054029 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/files.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/files.rs @@ -180,6 +180,13 @@ impl<FileId: FileIdToSyntax, T> InFileWrapper<FileId, T> { } } +#[allow(private_bounds)] +impl<FileId: FileIdToSyntax, N: AstNode> InFileWrapper<FileId, AstPtr<N>> { + pub fn to_node(&self, db: &dyn ExpandDatabase) -> N { + self.value.to_node(&self.file_syntax(db)) + } +} + impl<FileId: Copy, N: AstNode> InFileWrapper<FileId, N> { pub fn syntax(&self) -> InFileWrapper<FileId, &SyntaxNode> { self.with_value(self.value.syntax()) diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs b/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs index b6d5828da96..0af29681a13 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs @@ -110,7 +110,8 @@ pub(crate) fn fixup_syntax( } }, ast::ExprStmt(it) => { - if it.semicolon_token().is_none() { + let needs_semi = it.semicolon_token().is_none() && it.expr().map_or(false, |e| e.syntax().kind() != SyntaxKind::BLOCK_EXPR); + if needs_semi { append.insert(node.clone().into(), vec![ Leaf::Punct(Punct { char: ';', @@ -908,4 +909,19 @@ fn foo () {|| __ra_fixup} "#]], ); } + + #[test] + fn fixup_regression_() { + check( + r#" +fn foo() { + {} + {} +} +"#, + expect![[r#" +fn foo () {{} {}} +"#]], + ); + } } diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs index 7d2f556406d..2ee598dfbfd 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs @@ -269,6 +269,13 @@ pub enum MacroDefKind { ProcMacro(AstId<ast::Fn>, CustomProcMacroExpander, ProcMacroKind), } +impl MacroDefKind { + #[inline] + pub fn is_declarative(&self) -> bool { + matches!(self, MacroDefKind::Declarative(..)) + } +} + #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct EagerCallInfo { /// The expanded argument of the eager macro. diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs index 3a3a05c369a..6856eaa3e02 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs @@ -22,7 +22,7 @@ use crate::{ consteval::ConstEvalError, dyn_compatibility::DynCompatibilityViolation, layout::{Layout, LayoutError}, - lower::{GenericDefaults, GenericPredicates}, + lower::{Diagnostics, GenericDefaults, GenericPredicates}, method_resolution::{InherentImpls, TraitImpls, TyFingerprint}, mir::{BorrowckResult, MirBody, MirLowerError}, Binders, ClosureId, Const, FnDefId, ImplTraitId, ImplTraits, InferenceResult, Interner, @@ -115,21 +115,35 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> { #[ra_salsa::cycle(crate::lower::ty_recover)] fn ty(&self, def: TyDefId) -> Binders<Ty>; + #[ra_salsa::invoke(crate::lower::type_for_type_alias_with_diagnostics_query)] + fn type_for_type_alias_with_diagnostics(&self, def: TypeAliasId) -> (Binders<Ty>, Diagnostics); + /// Returns the type of the value of the given constant, or `None` if the `ValueTyDefId` is /// a `StructId` or `EnumVariantId` with a record constructor. #[ra_salsa::invoke(crate::lower::value_ty_query)] fn value_ty(&self, def: ValueTyDefId) -> Option<Binders<Ty>>; + #[ra_salsa::invoke(crate::lower::impl_self_ty_with_diagnostics_query)] + #[ra_salsa::cycle(crate::lower::impl_self_ty_with_diagnostics_recover)] + fn impl_self_ty_with_diagnostics(&self, def: ImplId) -> (Binders<Ty>, Diagnostics); #[ra_salsa::invoke(crate::lower::impl_self_ty_query)] - #[ra_salsa::cycle(crate::lower::impl_self_ty_recover)] fn impl_self_ty(&self, def: ImplId) -> Binders<Ty>; + #[ra_salsa::invoke(crate::lower::const_param_ty_with_diagnostics_query)] + fn const_param_ty_with_diagnostics(&self, def: ConstParamId) -> (Ty, Diagnostics); #[ra_salsa::invoke(crate::lower::const_param_ty_query)] fn const_param_ty(&self, def: ConstParamId) -> Ty; + #[ra_salsa::invoke(crate::lower::impl_trait_with_diagnostics_query)] + fn impl_trait_with_diagnostics(&self, def: ImplId) -> Option<(Binders<TraitRef>, Diagnostics)>; #[ra_salsa::invoke(crate::lower::impl_trait_query)] fn impl_trait(&self, def: ImplId) -> Option<Binders<TraitRef>>; + #[ra_salsa::invoke(crate::lower::field_types_with_diagnostics_query)] + fn field_types_with_diagnostics( + &self, + var: VariantId, + ) -> (Arc<ArenaMap<LocalFieldId, Binders<Ty>>>, Diagnostics); #[ra_salsa::invoke(crate::lower::field_types_query)] fn field_types(&self, var: VariantId) -> Arc<ArenaMap<LocalFieldId, Binders<Ty>>>; @@ -154,6 +168,11 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> { #[ra_salsa::invoke(crate::lower::generic_predicates_query)] fn generic_predicates(&self, def: GenericDefId) -> GenericPredicates; + #[ra_salsa::invoke(crate::lower::generic_predicates_without_parent_with_diagnostics_query)] + fn generic_predicates_without_parent_with_diagnostics( + &self, + def: GenericDefId, + ) -> (GenericPredicates, Diagnostics); #[ra_salsa::invoke(crate::lower::generic_predicates_without_parent_query)] fn generic_predicates_without_parent(&self, def: GenericDefId) -> GenericPredicates; @@ -164,8 +183,13 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> { #[ra_salsa::invoke(crate::lower::trait_environment_query)] fn trait_environment(&self, def: GenericDefId) -> Arc<TraitEnvironment>; + #[ra_salsa::invoke(crate::lower::generic_defaults_with_diagnostics_query)] + #[ra_salsa::cycle(crate::lower::generic_defaults_with_diagnostics_recover)] + fn generic_defaults_with_diagnostics( + &self, + def: GenericDefId, + ) -> (GenericDefaults, Diagnostics); #[ra_salsa::invoke(crate::lower::generic_defaults_query)] - #[ra_salsa::cycle(crate::lower::generic_defaults_recover)] fn generic_defaults(&self, def: GenericDefId) -> GenericDefaults; #[ra_salsa::invoke(InherentImpls::inherent_impls_in_crate_query)] diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics.rs index af4d2c9fc04..30c02a2936d 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics.rs @@ -9,5 +9,5 @@ pub use crate::diagnostics::{ expr::{ record_literal_missing_fields, record_pattern_missing_fields, BodyValidationDiagnostic, }, - unsafe_check::{missing_unsafe, unsafe_expressions, UnsafeExpr}, + unsafe_check::{missing_unsafe, unsafe_expressions, InsideUnsafeBlock, UnsafetyReason}, }; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs index 58de19ba81e..5452f5c680d 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs @@ -383,9 +383,6 @@ impl<'db> PatCx for MatchCheckCtx<'db> { } else { let variant = Self::variant_id_for_adt(self.db, ctor, adt).unwrap(); - // Whether we must not match the fields of this variant exhaustively. - let is_non_exhaustive = - LazyCell::new(|| self.is_foreign_non_exhaustive(adt)); let visibilities = LazyCell::new(|| self.db.field_visibilities(variant)); self.list_variant_fields(ty, variant) @@ -396,8 +393,7 @@ impl<'db> PatCx for MatchCheckCtx<'db> { .is_visible_from(self.db.upcast(), self.module) }; let is_uninhabited = self.is_uninhabited(&ty); - let private_uninhabited = - is_uninhabited && (!is_visible() || *is_non_exhaustive); + let private_uninhabited = is_uninhabited && !is_visible(); (ty, PrivateUninhabitedField(private_uninhabited)) }) .collect() diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs index c7f7fb7ad3d..193aaa52c26 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs @@ -1,12 +1,16 @@ //! Provides validations for unsafe code. Currently checks if unsafe functions are missing //! unsafe blocks. +use std::mem; + +use either::Either; use hir_def::{ body::Body, - hir::{Expr, ExprId, ExprOrPatId, Pat, UnaryOp}, - resolver::{resolver_for_expr, ResolveValueResult, Resolver, ValueNs}, + hir::{Expr, ExprId, ExprOrPatId, Pat, PatId, Statement, UnaryOp}, + path::Path, + resolver::{HasResolver, ResolveValueResult, Resolver, ValueNs}, type_ref::Rawness, - DefWithBodyId, + AdtId, DefWithBodyId, FieldId, VariantId, }; use crate::{ @@ -16,7 +20,10 @@ use crate::{ /// Returns `(unsafe_exprs, fn_is_unsafe)`. /// /// If `fn_is_unsafe` is false, `unsafe_exprs` are hard errors. If true, they're `unsafe_op_in_unsafe_fn`. -pub fn missing_unsafe(db: &dyn HirDatabase, def: DefWithBodyId) -> (Vec<ExprOrPatId>, bool) { +pub fn missing_unsafe( + db: &dyn HirDatabase, + def: DefWithBodyId, +) -> (Vec<(ExprOrPatId, UnsafetyReason)>, bool) { let _p = tracing::info_span!("missing_unsafe").entered(); let mut res = Vec::new(); @@ -30,111 +37,243 @@ pub fn missing_unsafe(db: &dyn HirDatabase, def: DefWithBodyId) -> (Vec<ExprOrPa let body = db.body(def); let infer = db.infer(def); - unsafe_expressions(db, &infer, def, &body, body.body_expr, &mut |expr| { - if !expr.inside_unsafe_block { - res.push(expr.node); + let mut callback = |node, inside_unsafe_block, reason| { + if inside_unsafe_block == InsideUnsafeBlock::No { + res.push((node, reason)); } - }); + }; + let mut visitor = UnsafeVisitor::new(db, &infer, &body, def, &mut callback); + visitor.walk_expr(body.body_expr); + + if !is_unsafe { + // Unsafety in function parameter patterns (that can only be union destructuring) + // cannot be inserted into an unsafe block, so even with `unsafe_op_in_unsafe_fn` + // it is turned off for unsafe functions. + for ¶m in &body.params { + visitor.walk_pat(param); + } + } (res, is_unsafe) } -pub struct UnsafeExpr { - pub node: ExprOrPatId, - pub inside_unsafe_block: bool, +#[derive(Debug, Clone, Copy)] +pub enum UnsafetyReason { + UnionField, + UnsafeFnCall, + InlineAsm, + RawPtrDeref, + MutableStatic, + ExternStatic, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum InsideUnsafeBlock { + No, + Yes, } -// FIXME: Move this out, its not a diagnostic only thing anymore, and handle unsafe pattern accesses as well pub fn unsafe_expressions( db: &dyn HirDatabase, infer: &InferenceResult, def: DefWithBodyId, body: &Body, current: ExprId, - unsafe_expr_cb: &mut dyn FnMut(UnsafeExpr), + unsafe_expr_cb: &mut dyn FnMut(ExprOrPatId, InsideUnsafeBlock, UnsafetyReason), ) { - walk_unsafe( - db, - infer, - body, - &mut resolver_for_expr(db.upcast(), def, current), - def, - current, - false, - unsafe_expr_cb, - ) + let mut visitor = UnsafeVisitor::new(db, infer, body, def, unsafe_expr_cb); + _ = visitor.resolver.update_to_inner_scope(db.upcast(), def, current); + visitor.walk_expr(current); } -fn walk_unsafe( - db: &dyn HirDatabase, - infer: &InferenceResult, - body: &Body, - resolver: &mut Resolver, +struct UnsafeVisitor<'a> { + db: &'a dyn HirDatabase, + infer: &'a InferenceResult, + body: &'a Body, + resolver: Resolver, def: DefWithBodyId, - current: ExprId, - inside_unsafe_block: bool, - unsafe_expr_cb: &mut dyn FnMut(UnsafeExpr), -) { - let mut mark_unsafe_path = |path, node| { - let g = resolver.update_to_inner_scope(db.upcast(), def, current); - let hygiene = body.expr_or_pat_path_hygiene(node); - let value_or_partial = resolver.resolve_path_in_value_ns(db.upcast(), path, hygiene); - if let Some(ResolveValueResult::ValueNs(ValueNs::StaticId(id), _)) = value_or_partial { - let static_data = db.static_data(id); - if static_data.mutable || (static_data.is_extern && !static_data.has_safe_kw) { - unsafe_expr_cb(UnsafeExpr { node, inside_unsafe_block }); + inside_unsafe_block: InsideUnsafeBlock, + inside_assignment: bool, + inside_union_destructure: bool, + unsafe_expr_cb: &'a mut dyn FnMut(ExprOrPatId, InsideUnsafeBlock, UnsafetyReason), +} + +impl<'a> UnsafeVisitor<'a> { + fn new( + db: &'a dyn HirDatabase, + infer: &'a InferenceResult, + body: &'a Body, + def: DefWithBodyId, + unsafe_expr_cb: &'a mut dyn FnMut(ExprOrPatId, InsideUnsafeBlock, UnsafetyReason), + ) -> Self { + let resolver = def.resolver(db.upcast()); + Self { + db, + infer, + body, + resolver, + def, + inside_unsafe_block: InsideUnsafeBlock::No, + inside_assignment: false, + inside_union_destructure: false, + unsafe_expr_cb, + } + } + + fn call_cb(&mut self, node: ExprOrPatId, reason: UnsafetyReason) { + (self.unsafe_expr_cb)(node, self.inside_unsafe_block, reason); + } + + fn walk_pats_top(&mut self, pats: impl Iterator<Item = PatId>, parent_expr: ExprId) { + let guard = self.resolver.update_to_inner_scope(self.db.upcast(), self.def, parent_expr); + pats.for_each(|pat| self.walk_pat(pat)); + self.resolver.reset_to_guard(guard); + } + + fn walk_pat(&mut self, current: PatId) { + let pat = &self.body.pats[current]; + + if self.inside_union_destructure { + match pat { + Pat::Tuple { .. } + | Pat::Record { .. } + | Pat::Range { .. } + | Pat::Slice { .. } + | Pat::Path(..) + | Pat::Lit(..) + | Pat::Bind { .. } + | Pat::TupleStruct { .. } + | Pat::Ref { .. } + | Pat::Box { .. } + | Pat::Expr(..) + | Pat::ConstBlock(..) => self.call_cb(current.into(), UnsafetyReason::UnionField), + // `Or` only wraps other patterns, and `Missing`/`Wild` do not constitute a read. + Pat::Missing | Pat::Wild | Pat::Or(_) => {} } } - resolver.reset_to_guard(g); - }; - let expr = &body.exprs[current]; - match expr { - &Expr::Call { callee, .. } => { - if let Some(func) = infer[callee].as_fn_def(db) { - if is_fn_unsafe_to_call(db, func) { - unsafe_expr_cb(UnsafeExpr { node: current.into(), inside_unsafe_block }); + match pat { + Pat::Record { .. } => { + if let Some((AdtId::UnionId(_), _)) = self.infer[current].as_adt() { + let old_inside_union_destructure = + mem::replace(&mut self.inside_union_destructure, true); + self.body.walk_pats_shallow(current, |pat| self.walk_pat(pat)); + self.inside_union_destructure = old_inside_union_destructure; + return; } } - } - Expr::Path(path) => mark_unsafe_path(path, current.into()), - Expr::Ref { expr, rawness: Rawness::RawPtr, mutability: _ } => { - if let Expr::Path(_) = body.exprs[*expr] { - // Do not report unsafe for `addr_of[_mut]!(EXTERN_OR_MUT_STATIC)`, - // see https://github.com/rust-lang/rust/pull/125834. - return; + Pat::Path(path) => self.mark_unsafe_path(current.into(), path), + &Pat::ConstBlock(expr) => { + let old_inside_assignment = mem::replace(&mut self.inside_assignment, false); + self.walk_expr(expr); + self.inside_assignment = old_inside_assignment; } + &Pat::Expr(expr) => self.walk_expr(expr), + _ => {} } - Expr::MethodCall { .. } => { - if infer - .method_resolution(current) - .map(|(func, _)| is_fn_unsafe_to_call(db, func)) - .unwrap_or(false) - { - unsafe_expr_cb(UnsafeExpr { node: current.into(), inside_unsafe_block }); + + self.body.walk_pats_shallow(current, |pat| self.walk_pat(pat)); + } + + fn walk_expr(&mut self, current: ExprId) { + let expr = &self.body.exprs[current]; + let inside_assignment = mem::replace(&mut self.inside_assignment, false); + match expr { + &Expr::Call { callee, .. } => { + if let Some(func) = self.infer[callee].as_fn_def(self.db) { + if is_fn_unsafe_to_call(self.db, func) { + self.call_cb(current.into(), UnsafetyReason::UnsafeFnCall); + } + } } - } - Expr::UnaryOp { expr, op: UnaryOp::Deref } => { - if let TyKind::Raw(..) = &infer[*expr].kind(Interner) { - unsafe_expr_cb(UnsafeExpr { node: current.into(), inside_unsafe_block }); + Expr::Path(path) => { + let guard = + self.resolver.update_to_inner_scope(self.db.upcast(), self.def, current); + self.mark_unsafe_path(current.into(), path); + self.resolver.reset_to_guard(guard); } - } - Expr::Unsafe { .. } => { - return body.walk_child_exprs(current, |child| { - walk_unsafe(db, infer, body, resolver, def, child, true, unsafe_expr_cb); - }); - } - &Expr::Assignment { target, value: _ } => { - body.walk_pats(target, &mut |pat| { - if let Pat::Path(path) = &body[pat] { - mark_unsafe_path(path, pat.into()); + Expr::Ref { expr, rawness: Rawness::RawPtr, mutability: _ } => { + if let Expr::Path(_) = self.body.exprs[*expr] { + // Do not report unsafe for `addr_of[_mut]!(EXTERN_OR_MUT_STATIC)`, + // see https://github.com/rust-lang/rust/pull/125834. + return; + } + } + Expr::MethodCall { .. } => { + if self + .infer + .method_resolution(current) + .map(|(func, _)| is_fn_unsafe_to_call(self.db, func)) + .unwrap_or(false) + { + self.call_cb(current.into(), UnsafetyReason::UnsafeFnCall); } - }); + } + Expr::UnaryOp { expr, op: UnaryOp::Deref } => { + if let TyKind::Raw(..) = &self.infer[*expr].kind(Interner) { + self.call_cb(current.into(), UnsafetyReason::RawPtrDeref); + } + } + Expr::Unsafe { .. } => { + let old_inside_unsafe_block = + mem::replace(&mut self.inside_unsafe_block, InsideUnsafeBlock::Yes); + self.body.walk_child_exprs_without_pats(current, |child| self.walk_expr(child)); + self.inside_unsafe_block = old_inside_unsafe_block; + return; + } + &Expr::Assignment { target, value: _ } => { + let old_inside_assignment = mem::replace(&mut self.inside_assignment, true); + self.walk_pats_top(std::iter::once(target), current); + self.inside_assignment = old_inside_assignment; + } + Expr::InlineAsm(_) => self.call_cb(current.into(), UnsafetyReason::InlineAsm), + // rustc allows union assignment to propagate through field accesses and casts. + Expr::Cast { .. } => self.inside_assignment = inside_assignment, + Expr::Field { .. } => { + self.inside_assignment = inside_assignment; + if !inside_assignment { + if let Some(Either::Left(FieldId { parent: VariantId::UnionId(_), .. })) = + self.infer.field_resolution(current) + { + self.call_cb(current.into(), UnsafetyReason::UnionField); + } + } + } + Expr::Block { statements, .. } | Expr::Async { statements, .. } => { + self.walk_pats_top( + statements.iter().filter_map(|statement| match statement { + &Statement::Let { pat, .. } => Some(pat), + _ => None, + }), + current, + ); + } + Expr::Match { arms, .. } => { + self.walk_pats_top(arms.iter().map(|arm| arm.pat), current); + } + &Expr::Let { pat, .. } => { + self.walk_pats_top(std::iter::once(pat), current); + } + Expr::Closure { args, .. } => { + self.walk_pats_top(args.iter().copied(), current); + } + _ => {} } - _ => {} + + self.body.walk_child_exprs_without_pats(current, |child| self.walk_expr(child)); } - body.walk_child_exprs(current, |child| { - walk_unsafe(db, infer, body, resolver, def, child, inside_unsafe_block, unsafe_expr_cb); - }); + fn mark_unsafe_path(&mut self, node: ExprOrPatId, path: &Path) { + let hygiene = self.body.expr_or_pat_path_hygiene(node); + let value_or_partial = + self.resolver.resolve_path_in_value_ns(self.db.upcast(), path, hygiene); + if let Some(ResolveValueResult::ValueNs(ValueNs::StaticId(id), _)) = value_or_partial { + let static_data = self.db.static_data(id); + if static_data.mutable { + self.call_cb(node, UnsafetyReason::MutableStatic); + } else if static_data.is_extern && !static_data.has_safe_kw { + self.call_cb(node, UnsafetyReason::ExternStatic); + } + } + } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs index 4e95bdf219f..3dfa0e97cec 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs @@ -1047,10 +1047,14 @@ impl HirDisplay for Ty { ); // We print all params except implicit impl Trait params. Still a bit weird; should we leave out parent and self? if parameters.len() - impl_ > 0 { + let params_len = parameters.len(); // `parameters` are in the order of fn's params (including impl traits), fn's lifetimes let parameters = generic_args_sans_defaults(f, Some(generic_def_id), parameters); - let without_impl = self_param as usize + type_ + const_ + lifetime; + assert!(params_len >= parameters.len()); + let defaults = params_len - parameters.len(); + let without_impl = + self_param as usize + type_ + const_ + lifetime - defaults; // parent's params (those from enclosing impl or trait, if any). let (fn_params, parent_params) = parameters.split_at(without_impl + impl_); @@ -2062,12 +2066,12 @@ impl HirDisplayWithTypesMap for TypeBound { types_map: &TypesMap, ) -> Result<(), HirDisplayError> { match self { - TypeBound::Path(path, modifier) => { + &TypeBound::Path(path, modifier) => { match modifier { TraitBoundModifier::None => (), TraitBoundModifier::Maybe => write!(f, "?")?, } - path.hir_fmt(f, types_map) + types_map[path].hir_fmt(f, types_map) } TypeBound::Lifetime(lifetime) => { write!(f, "{}", lifetime.name.display(f.db.upcast(), f.edition())) @@ -2079,7 +2083,7 @@ impl HirDisplayWithTypesMap for TypeBound { "for<{}> ", lifetimes.iter().map(|it| it.display(f.db.upcast(), edition)).format(", ") )?; - path.hir_fmt(f, types_map) + types_map[*path].hir_fmt(f, types_map) } TypeBound::Use(args) => { let edition = f.edition(); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs b/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs index c094bc39512..fe7541d2374 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs @@ -55,6 +55,10 @@ impl Generics { self.def } + pub(crate) fn self_types_map(&self) -> &TypesMap { + &self.params.types_map + } + pub(crate) fn iter_id(&self) -> impl Iterator<Item = GenericParamId> + '_ { self.iter_self_id().chain(self.iter_parent_id()) } @@ -86,15 +90,13 @@ impl Generics { self.iter_self().chain(self.iter_parent()) } - pub(crate) fn iter_with_types_map( + pub(crate) fn iter_parents_with_types_map( &self, ) -> impl Iterator<Item = ((GenericParamId, GenericParamDataRef<'_>), &TypesMap)> + '_ { - self.iter_self().zip(std::iter::repeat(&self.params.types_map)).chain( - self.iter_parent().zip( - self.parent_generics() - .into_iter() - .flat_map(|it| std::iter::repeat(&it.params.types_map)), - ), + self.iter_parent().zip( + self.parent_generics() + .into_iter() + .flat_map(|it| std::iter::repeat(&it.params.types_map)), ) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs index 01e0b635b22..dbee5a1a919 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs @@ -58,7 +58,7 @@ use crate::{ fold_tys, generics::Generics, infer::{coerce::CoerceMany, expr::ExprIsRead, unify::InferenceTable}, - lower::ImplTraitLoweringMode, + lower::{ImplTraitLoweringMode, TyLoweringDiagnostic}, mir::MirSpan, to_assoc_type_id, traits::FnTrait, @@ -191,6 +191,14 @@ impl<T> InferOk<T> { } } +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +pub enum InferenceTyDiagnosticSource { + /// Diagnostics that come from types in the body. + Body, + /// Diagnostics that come from types in fn parameters/return type, or static & const types. + Signature, +} + #[derive(Debug)] pub(crate) struct TypeError; pub(crate) type InferResult<T> = Result<InferOk<T>, TypeError>; @@ -264,6 +272,10 @@ pub enum InferenceDiagnostic { expr_ty: Ty, cast_ty: Ty, }, + TyDiagnostic { + source: InferenceTyDiagnosticSource, + diag: TyLoweringDiagnostic, + }, } /// A mismatch between an expected and an inferred type. @@ -858,7 +870,8 @@ impl<'a> InferenceContext<'a> { } fn collect_const(&mut self, data: &ConstData) { - let return_ty = self.make_ty(data.type_ref, &data.types_map); + let return_ty = + self.make_ty(data.type_ref, &data.types_map, InferenceTyDiagnosticSource::Signature); // Constants might be defining usage sites of TAITs. self.make_tait_coercion_table(iter::once(&return_ty)); @@ -867,7 +880,8 @@ impl<'a> InferenceContext<'a> { } fn collect_static(&mut self, data: &StaticData) { - let return_ty = self.make_ty(data.type_ref, &data.types_map); + let return_ty = + self.make_ty(data.type_ref, &data.types_map, InferenceTyDiagnosticSource::Signature); // Statics might be defining usage sites of TAITs. self.make_tait_coercion_table(iter::once(&return_ty)); @@ -877,11 +891,12 @@ impl<'a> InferenceContext<'a> { fn collect_fn(&mut self, func: FunctionId) { let data = self.db.function_data(func); - let mut param_tys = self.with_ty_lowering(&data.types_map, |ctx| { - ctx.type_param_mode(ParamLoweringMode::Placeholder) - .impl_trait_mode(ImplTraitLoweringMode::Param); - data.params.iter().map(|&type_ref| ctx.lower_ty(type_ref)).collect::<Vec<_>>() - }); + let mut param_tys = + self.with_ty_lowering(&data.types_map, InferenceTyDiagnosticSource::Signature, |ctx| { + ctx.type_param_mode(ParamLoweringMode::Placeholder) + .impl_trait_mode(ImplTraitLoweringMode::Param); + data.params.iter().map(|&type_ref| ctx.lower_ty(type_ref)).collect::<Vec<_>>() + }); // Check if function contains a va_list, if it does then we append it to the parameter types // that are collected from the function data if data.is_varargs() { @@ -918,11 +933,12 @@ impl<'a> InferenceContext<'a> { } let return_ty = data.ret_type; - let return_ty = self.with_ty_lowering(&data.types_map, |ctx| { - ctx.type_param_mode(ParamLoweringMode::Placeholder) - .impl_trait_mode(ImplTraitLoweringMode::Opaque) - .lower_ty(return_ty) - }); + let return_ty = + self.with_ty_lowering(&data.types_map, InferenceTyDiagnosticSource::Signature, |ctx| { + ctx.type_param_mode(ParamLoweringMode::Placeholder) + .impl_trait_mode(ImplTraitLoweringMode::Opaque) + .lower_ty(return_ty) + }); let return_ty = self.insert_type_vars(return_ty); let return_ty = if let Some(rpits) = self.db.return_type_impl_traits(func) { @@ -1226,9 +1242,20 @@ impl<'a> InferenceContext<'a> { self.result.diagnostics.push(diagnostic); } + fn push_ty_diagnostics( + &mut self, + source: InferenceTyDiagnosticSource, + diagnostics: Vec<TyLoweringDiagnostic>, + ) { + self.result.diagnostics.extend( + diagnostics.into_iter().map(|diag| InferenceDiagnostic::TyDiagnostic { source, diag }), + ); + } + fn with_ty_lowering<R>( - &self, + &mut self, types_map: &TypesMap, + types_source: InferenceTyDiagnosticSource, f: impl FnOnce(&mut crate::lower::TyLoweringContext<'_>) -> R, ) -> R { let mut ctx = crate::lower::TyLoweringContext::new( @@ -1237,32 +1264,41 @@ impl<'a> InferenceContext<'a> { types_map, self.owner.into(), ); - f(&mut ctx) + let result = f(&mut ctx); + self.push_ty_diagnostics(types_source, ctx.diagnostics); + result } fn with_body_ty_lowering<R>( - &self, + &mut self, f: impl FnOnce(&mut crate::lower::TyLoweringContext<'_>) -> R, ) -> R { - self.with_ty_lowering(&self.body.types, f) + self.with_ty_lowering(&self.body.types, InferenceTyDiagnosticSource::Body, f) } - fn make_ty(&mut self, type_ref: TypeRefId, types_map: &TypesMap) -> Ty { - let ty = self.with_ty_lowering(types_map, |ctx| ctx.lower_ty(type_ref)); + fn make_ty( + &mut self, + type_ref: TypeRefId, + types_map: &TypesMap, + type_source: InferenceTyDiagnosticSource, + ) -> Ty { + let ty = self.with_ty_lowering(types_map, type_source, |ctx| ctx.lower_ty(type_ref)); let ty = self.insert_type_vars(ty); self.normalize_associated_types_in(ty) } fn make_body_ty(&mut self, type_ref: TypeRefId) -> Ty { - self.make_ty(type_ref, &self.body.types) + self.make_ty(type_ref, &self.body.types, InferenceTyDiagnosticSource::Body) } fn err_ty(&self) -> Ty { self.result.standard_types.unknown.clone() } - fn make_lifetime(&mut self, lifetime_ref: &LifetimeRef) -> Lifetime { - let lt = self.with_ty_lowering(TypesMap::EMPTY, |ctx| ctx.lower_lifetime(lifetime_ref)); + fn make_body_lifetime(&mut self, lifetime_ref: &LifetimeRef) -> Lifetime { + let lt = self.with_ty_lowering(TypesMap::EMPTY, InferenceTyDiagnosticSource::Body, |ctx| { + ctx.lower_lifetime(lifetime_ref) + }); self.insert_type_vars(lt) } @@ -1431,12 +1467,20 @@ impl<'a> InferenceContext<'a> { Some(ResolveValueResult::ValueNs(value, _)) => match value { ValueNs::EnumVariantId(var) => { let substs = ctx.substs_from_path(path, var.into(), true); + self.push_ty_diagnostics( + InferenceTyDiagnosticSource::Body, + ctx.diagnostics, + ); let ty = self.db.ty(var.lookup(self.db.upcast()).parent.into()); let ty = self.insert_type_vars(ty.substitute(Interner, &substs)); return (ty, Some(var.into())); } ValueNs::StructId(strukt) => { let substs = ctx.substs_from_path(path, strukt.into(), true); + self.push_ty_diagnostics( + InferenceTyDiagnosticSource::Body, + ctx.diagnostics, + ); let ty = self.db.ty(strukt.into()); let ty = self.insert_type_vars(ty.substitute(Interner, &substs)); return (ty, Some(strukt.into())); @@ -1462,18 +1506,21 @@ impl<'a> InferenceContext<'a> { return match resolution { TypeNs::AdtId(AdtId::StructId(strukt)) => { let substs = ctx.substs_from_path(path, strukt.into(), true); + self.push_ty_diagnostics(InferenceTyDiagnosticSource::Body, ctx.diagnostics); let ty = self.db.ty(strukt.into()); let ty = self.insert_type_vars(ty.substitute(Interner, &substs)); forbid_unresolved_segments((ty, Some(strukt.into())), unresolved) } TypeNs::AdtId(AdtId::UnionId(u)) => { let substs = ctx.substs_from_path(path, u.into(), true); + self.push_ty_diagnostics(InferenceTyDiagnosticSource::Body, ctx.diagnostics); let ty = self.db.ty(u.into()); let ty = self.insert_type_vars(ty.substitute(Interner, &substs)); forbid_unresolved_segments((ty, Some(u.into())), unresolved) } TypeNs::EnumVariantId(var) => { let substs = ctx.substs_from_path(path, var.into(), true); + self.push_ty_diagnostics(InferenceTyDiagnosticSource::Body, ctx.diagnostics); let ty = self.db.ty(var.lookup(self.db.upcast()).parent.into()); let ty = self.insert_type_vars(ty.substitute(Interner, &substs)); forbid_unresolved_segments((ty, Some(var.into())), unresolved) @@ -1519,6 +1566,9 @@ impl<'a> InferenceContext<'a> { resolved_segment, current_segment, false, + &mut |_, _reason| { + // FIXME: Report an error. + }, ); ty = self.table.insert_type_vars(ty); @@ -1532,6 +1582,7 @@ impl<'a> InferenceContext<'a> { remaining_idx += 1; remaining_segments = remaining_segments.skip(1); } + self.push_ty_diagnostics(InferenceTyDiagnosticSource::Body, ctx.diagnostics); let variant = ty.as_adt().and_then(|(id, _)| match id { AdtId::StructId(s) => Some(VariantId::StructId(s)), @@ -1550,6 +1601,7 @@ impl<'a> InferenceContext<'a> { }; let substs = ctx.substs_from_path_segment(resolved_seg, Some(it.into()), true, None); + self.push_ty_diagnostics(InferenceTyDiagnosticSource::Body, ctx.diagnostics); let ty = self.db.ty(it.into()); let ty = self.insert_type_vars(ty.substitute(Interner, &substs)); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs index 366c3cb0f17..2fe90a8a924 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs @@ -125,7 +125,11 @@ impl CoerceMany { // pointers to have a chance at getting a match. See // https://github.com/rust-lang/rust/blob/7b805396bf46dce972692a6846ce2ad8481c5f85/src/librustc_typeck/check/coercion.rs#L877-L916 let sig = match (self.merged_ty().kind(Interner), expr_ty.kind(Interner)) { - (TyKind::FnDef(x, _), TyKind::FnDef(y, _)) if x == y => None, + (TyKind::FnDef(x, _), TyKind::FnDef(y, _)) + if x == y && ctx.table.unify(&self.merged_ty(), &expr_ty) => + { + None + } (TyKind::Closure(x, _), TyKind::Closure(y, _)) if x == y => None, (TyKind::FnDef(..) | TyKind::Closure(..), TyKind::FnDef(..) | TyKind::Closure(..)) => { // FIXME: we're ignoring safety here. To be more correct, if we have one FnDef and one Closure, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs index 32b4ea2f28b..a13541be695 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs @@ -1287,8 +1287,8 @@ impl InferenceContext<'_> { tgt_expr: ExprId, ) { match fn_x { - FnTrait::FnOnce => (), - FnTrait::FnMut => { + FnTrait::FnOnce | FnTrait::AsyncFnOnce => (), + FnTrait::FnMut | FnTrait::AsyncFnMut => { if let TyKind::Ref(Mutability::Mut, lt, inner) = derefed_callee.kind(Interner) { if adjustments .last() @@ -1312,7 +1312,7 @@ impl InferenceContext<'_> { )); } } - FnTrait::Fn => { + FnTrait::Fn | FnTrait::AsyncFn => { if !matches!(derefed_callee.kind(Interner), TyKind::Ref(Mutability::Not, _, _)) { adjustments.push(Adjustment::borrow( Mutability::Not, @@ -2155,7 +2155,7 @@ impl InferenceContext<'_> { DebruijnIndex::INNERMOST, ) }, - |this, lt_ref| this.make_lifetime(lt_ref), + |this, lt_ref| this.make_body_lifetime(lt_ref), ), }; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs index 7550d197a3b..a6296c3af23 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs @@ -19,7 +19,7 @@ use crate::{ TyBuilder, TyExt, TyKind, ValueTyDefId, }; -use super::{ExprOrPatId, InferenceContext}; +use super::{ExprOrPatId, InferenceContext, InferenceTyDiagnosticSource}; impl InferenceContext<'_> { pub(super) fn infer_path(&mut self, path: &Path, id: ExprOrPatId) -> Option<Ty> { @@ -163,6 +163,7 @@ impl InferenceContext<'_> { let remaining_segments_for_ty = path.segments().take(path.segments().len() - 1); let (ty, _) = ctx.lower_ty_relative_path(ty, orig_ns, remaining_segments_for_ty); + self.push_ty_diagnostics(InferenceTyDiagnosticSource::Body, ctx.diagnostics); let ty = self.table.insert_type_vars(ty); let ty = self.table.normalize_associated_types_in(ty); self.resolve_ty_assoc_item(ty, last.name, id).map(|(it, substs)| (it, Some(substs)))? @@ -265,6 +266,9 @@ impl InferenceContext<'_> { resolved_segment, remaining_segments_for_ty, true, + &mut |_, _reason| { + // FIXME: Report an error. + }, ) }); if ty.is_unknown() { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs index 54aa18ce207..165861c1b17 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs @@ -666,7 +666,7 @@ impl<'a> InferenceTable<'a> { highest_known_var: InferenceVar, } impl TypeFolder<Interner> for VarFudger<'_, '_> { - fn as_dyn(&mut self) -> &mut dyn TypeFolder<Interner, Error = Self::Error> { + fn as_dyn(&mut self) -> &mut dyn TypeFolder<Interner> { self } @@ -794,69 +794,75 @@ impl<'a> InferenceTable<'a> { ty: &Ty, num_args: usize, ) -> Option<(FnTrait, Vec<Ty>, Ty)> { - let krate = self.trait_env.krate; - let fn_once_trait = FnTrait::FnOnce.get_id(self.db, krate)?; - let trait_data = self.db.trait_data(fn_once_trait); - let output_assoc_type = - trait_data.associated_type_by_name(&Name::new_symbol_root(sym::Output.clone()))?; - - let mut arg_tys = Vec::with_capacity(num_args); - let arg_ty = TyBuilder::tuple(num_args) - .fill(|it| { - let arg = match it { - ParamKind::Type => self.new_type_var(), - ParamKind::Lifetime => unreachable!("Tuple with lifetime parameter"), - ParamKind::Const(_) => unreachable!("Tuple with const parameter"), - }; - arg_tys.push(arg.clone()); - arg.cast(Interner) - }) - .build(); - - let b = TyBuilder::trait_ref(self.db, fn_once_trait); - if b.remaining() != 2 { - return None; - } - let mut trait_ref = b.push(ty.clone()).push(arg_ty).build(); + for (fn_trait_name, output_assoc_name, subtraits) in [ + (FnTrait::FnOnce, sym::Output.clone(), &[FnTrait::Fn, FnTrait::FnMut][..]), + (FnTrait::AsyncFnMut, sym::CallRefFuture.clone(), &[FnTrait::AsyncFn]), + (FnTrait::AsyncFnOnce, sym::CallOnceFuture.clone(), &[]), + ] { + let krate = self.trait_env.krate; + let fn_trait = fn_trait_name.get_id(self.db, krate)?; + let trait_data = self.db.trait_data(fn_trait); + let output_assoc_type = + trait_data.associated_type_by_name(&Name::new_symbol_root(output_assoc_name))?; + + let mut arg_tys = Vec::with_capacity(num_args); + let arg_ty = TyBuilder::tuple(num_args) + .fill(|it| { + let arg = match it { + ParamKind::Type => self.new_type_var(), + ParamKind::Lifetime => unreachable!("Tuple with lifetime parameter"), + ParamKind::Const(_) => unreachable!("Tuple with const parameter"), + }; + arg_tys.push(arg.clone()); + arg.cast(Interner) + }) + .build(); + + let b = TyBuilder::trait_ref(self.db, fn_trait); + if b.remaining() != 2 { + return None; + } + let mut trait_ref = b.push(ty.clone()).push(arg_ty).build(); - let projection = { - TyBuilder::assoc_type_projection( + let projection = TyBuilder::assoc_type_projection( self.db, output_assoc_type, Some(trait_ref.substitution.clone()), ) - .build() - }; + .fill_with_unknown() + .build(); - let trait_env = self.trait_env.env.clone(); - let obligation = InEnvironment { - goal: trait_ref.clone().cast(Interner), - environment: trait_env.clone(), - }; - let canonical = self.canonicalize(obligation.clone()); - if self.db.trait_solve(krate, self.trait_env.block, canonical.cast(Interner)).is_some() { - self.register_obligation(obligation.goal); - let return_ty = self.normalize_projection_ty(projection); - for fn_x in [FnTrait::Fn, FnTrait::FnMut, FnTrait::FnOnce] { - let fn_x_trait = fn_x.get_id(self.db, krate)?; - trait_ref.trait_id = to_chalk_trait_id(fn_x_trait); - let obligation: chalk_ir::InEnvironment<chalk_ir::Goal<Interner>> = InEnvironment { - goal: trait_ref.clone().cast(Interner), - environment: trait_env.clone(), - }; - let canonical = self.canonicalize(obligation.clone()); - if self - .db - .trait_solve(krate, self.trait_env.block, canonical.cast(Interner)) - .is_some() - { - return Some((fn_x, arg_tys, return_ty)); + let trait_env = self.trait_env.env.clone(); + let obligation = InEnvironment { + goal: trait_ref.clone().cast(Interner), + environment: trait_env.clone(), + }; + let canonical = self.canonicalize(obligation.clone()); + if self.db.trait_solve(krate, self.trait_env.block, canonical.cast(Interner)).is_some() + { + self.register_obligation(obligation.goal); + let return_ty = self.normalize_projection_ty(projection); + for &fn_x in subtraits { + let fn_x_trait = fn_x.get_id(self.db, krate)?; + trait_ref.trait_id = to_chalk_trait_id(fn_x_trait); + let obligation: chalk_ir::InEnvironment<chalk_ir::Goal<Interner>> = + InEnvironment { + goal: trait_ref.clone().cast(Interner), + environment: trait_env.clone(), + }; + let canonical = self.canonicalize(obligation.clone()); + if self + .db + .trait_solve(krate, self.trait_env.block, canonical.cast(Interner)) + .is_some() + { + return Some((fn_x, arg_tys, return_ty)); + } } + return Some((fn_trait_name, arg_tys, return_ty)); } - unreachable!("It should at least implement FnOnce at this point"); - } else { - None } + None } pub(super) fn insert_type_vars<T>(&mut self, ty: T) -> T @@ -1004,7 +1010,7 @@ mod resolve { where F: Fn(InferenceVar, VariableKind, GenericArg, DebruijnIndex) -> GenericArg, { - fn as_dyn(&mut self) -> &mut dyn TypeFolder<Interner, Error = Self::Error> { + fn as_dyn(&mut self) -> &mut dyn TypeFolder<Interner> { self } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs b/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs index c0a781b17ee..56b549436c7 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs @@ -5,8 +5,7 @@ use chalk_ir::{ visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor}, DebruijnIndex, }; -use hir_def::{visibility::Visibility, AdtId, EnumVariantId, HasModule, ModuleId, VariantId}; -use intern::sym; +use hir_def::{visibility::Visibility, AdtId, EnumVariantId, ModuleId, VariantId}; use rustc_hash::FxHashSet; use crate::{ @@ -118,11 +117,6 @@ impl UninhabitedFrom<'_> { variant: VariantId, subst: &Substitution, ) -> ControlFlow<VisiblyUninhabited> { - let is_local = variant.krate(self.db.upcast()) == self.target_mod.krate(); - if !is_local && self.db.attrs(variant.into()).by_key(&sym::non_exhaustive).exists() { - return CONTINUE_OPAQUELY_INHABITED; - } - let variant_data = self.db.variant_data(variant); let fields = variant_data.fields(); if fields.is_empty() { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs index 22e7b1d920f..8bb90ca31e4 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs @@ -84,12 +84,14 @@ pub use infer::{ cast::CastError, closure::{CaptureKind, CapturedItem}, could_coerce, could_unify, could_unify_deeply, Adjust, Adjustment, AutoBorrow, BindingMode, - InferenceDiagnostic, InferenceResult, OverloadedDeref, PointerCast, + InferenceDiagnostic, InferenceResult, InferenceTyDiagnosticSource, OverloadedDeref, + PointerCast, }; pub use interner::Interner; pub use lower::{ - associated_type_shorthand_candidates, ImplTraitLoweringMode, ParamLoweringMode, TyDefId, - TyLoweringContext, ValueTyDefId, + associated_type_shorthand_candidates, GenericArgsProhibitedReason, ImplTraitLoweringMode, + ParamLoweringMode, TyDefId, TyLoweringContext, TyLoweringDiagnostic, TyLoweringDiagnosticKind, + ValueTyDefId, }; pub use mapping::{ from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, from_placeholder_idx, @@ -385,7 +387,6 @@ pub enum FnAbi { Fastcall, FastcallUnwind, Msp430Interrupt, - PlatformIntrinsic, PtxKernel, RiscvInterruptM, RiscvInterruptS, @@ -444,7 +445,6 @@ impl FnAbi { s if *s == sym::fastcall_dash_unwind => FnAbi::FastcallUnwind, s if *s == sym::fastcall => FnAbi::Fastcall, s if *s == sym::msp430_dash_interrupt => FnAbi::Msp430Interrupt, - s if *s == sym::platform_dash_intrinsic => FnAbi::PlatformIntrinsic, s if *s == sym::ptx_dash_kernel => FnAbi::PtxKernel, s if *s == sym::riscv_dash_interrupt_dash_m => FnAbi::RiscvInterruptM, s if *s == sym::riscv_dash_interrupt_dash_s => FnAbi::RiscvInterruptS, @@ -487,7 +487,6 @@ impl FnAbi { FnAbi::Fastcall => "fastcall", FnAbi::FastcallUnwind => "fastcall-unwind", FnAbi::Msp430Interrupt => "msp430-interrupt", - FnAbi::PlatformIntrinsic => "platform-intrinsic", FnAbi::PtxKernel => "ptx-kernel", FnAbi::RiscvInterruptM => "riscv-interrupt-m", FnAbi::RiscvInterruptS => "riscv-interrupt-s", @@ -646,7 +645,7 @@ pub(crate) fn fold_free_vars<T: HasInterner<Interner = Interner> + TypeFoldable< F2: FnMut(Ty, BoundVar, DebruijnIndex) -> Const, > TypeFolder<Interner> for FreeVarFolder<F1, F2> { - fn as_dyn(&mut self) -> &mut dyn TypeFolder<Interner, Error = Self::Error> { + fn as_dyn(&mut self) -> &mut dyn TypeFolder<Interner> { self } @@ -697,7 +696,7 @@ pub(crate) fn fold_tys_and_consts<T: HasInterner<Interner = Interner> + TypeFold impl<F: FnMut(Either<Ty, Const>, DebruijnIndex) -> Either<Ty, Const>> TypeFolder<Interner> for TyFolder<F> { - fn as_dyn(&mut self) -> &mut dyn TypeFolder<Interner, Error = Self::Error> { + fn as_dyn(&mut self) -> &mut dyn TypeFolder<Interner> { self } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs index b868ea95f85..b23f2749ab2 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs @@ -33,8 +33,8 @@ use hir_def::{ path::{GenericArg, GenericArgs, ModPath, Path, PathKind, PathSegment, PathSegments}, resolver::{HasResolver, LifetimeNs, Resolver, TypeNs}, type_ref::{ - ConstRef, LifetimeRef, TraitBoundModifier, TraitRef as HirTraitRef, TypeBound, TypeRef, - TypeRefId, TypesMap, TypesSourceMap, + ConstRef, LifetimeRef, PathId, TraitBoundModifier, TraitRef as HirTraitRef, TypeBound, + TypeRef, TypeRefId, TypesMap, TypesSourceMap, }, AdtId, AssocItemId, CallableDefId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, FunctionId, GenericDefId, GenericParamId, HasModule, ImplId, InTypeConstLoc, ItemContainerId, @@ -48,7 +48,7 @@ use rustc_pattern_analysis::Captures; use smallvec::SmallVec; use stdx::{impl_from, never}; use syntax::ast; -use triomphe::Arc; +use triomphe::{Arc, ThinArc}; use crate::{ all_super_traits, @@ -102,6 +102,31 @@ impl ImplTraitLoweringState { } } +type TypeSource = Either<TypeRefId, hir_def::type_ref::TypeSource>; + +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct TyLoweringDiagnostic { + pub source: TypeSource, + pub kind: TyLoweringDiagnosticKind, +} + +#[derive(Debug, PartialEq, Eq, Clone)] +pub enum TyLoweringDiagnosticKind { + GenericArgsProhibited { segment: u32, reason: GenericArgsProhibitedReason }, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum GenericArgsProhibitedReason { + Module, + TyParam, + SelfTy, + PrimitiveTy, + /// When there is a generic enum, within the expression `Enum::Variant`, + /// either `Enum` or `Variant` are allowed to have generic arguments, but not both. + // FIXME: This is not used now but it should be. + EnumVariant, +} + #[derive(Debug)] pub struct TyLoweringContext<'a> { pub db: &'a dyn HirDatabase, @@ -125,6 +150,7 @@ pub struct TyLoweringContext<'a> { expander: Option<Expander>, /// Tracks types with explicit `?Sized` bounds. pub(crate) unsized_types: FxHashSet<Ty>, + pub(crate) diagnostics: Vec<TyLoweringDiagnostic>, } impl<'a> TyLoweringContext<'a> { @@ -159,6 +185,7 @@ impl<'a> TyLoweringContext<'a> { type_param_mode, expander: None, unsized_types: FxHashSet::default(), + diagnostics: Vec::new(), } } @@ -198,6 +225,20 @@ impl<'a> TyLoweringContext<'a> { self.type_param_mode = type_param_mode; self } + + pub fn push_diagnostic(&mut self, type_ref: TypeRefId, kind: TyLoweringDiagnosticKind) { + let source = match self.types_source_map { + Some(source_map) => { + let Ok(source) = source_map.type_syntax(type_ref) else { + stdx::never!("error in synthetic type"); + return; + }; + Either::Right(source) + } + None => Either::Left(type_ref), + }; + self.diagnostics.push(TyLoweringDiagnostic { source, kind }); + } } #[derive(Copy, Clone, Debug, PartialEq, Eq, Default)] @@ -264,7 +305,8 @@ impl<'a> TyLoweringContext<'a> { .intern(Interner) } TypeRef::Path(path) => { - let (ty, res_) = self.lower_path(path); + let (ty, res_) = + self.lower_path(path, PathId::from_type_ref_unchecked(type_ref_id)); res = res_; ty } @@ -463,6 +505,7 @@ impl<'a> TyLoweringContext<'a> { impl_trait_mode: mem::take(&mut self.impl_trait_mode), expander: self.expander.take(), unsized_types: mem::take(&mut self.unsized_types), + diagnostics: mem::take(&mut self.diagnostics), }; let ty = inner_ctx.lower_ty(type_ref); @@ -470,6 +513,7 @@ impl<'a> TyLoweringContext<'a> { self.impl_trait_mode = inner_ctx.impl_trait_mode; self.expander = inner_ctx.expander; self.unsized_types = inner_ctx.unsized_types; + self.diagnostics = inner_ctx.diagnostics; self.expander.as_mut().unwrap().exit(mark); Some(ty) @@ -541,6 +585,10 @@ impl<'a> TyLoweringContext<'a> { resolved_segment: PathSegment<'_>, remaining_segments: PathSegments<'_>, infer_args: bool, + on_prohibited_generics_for_resolved_segment: &mut dyn FnMut( + &mut Self, + GenericArgsProhibitedReason, + ), ) -> (Ty, Option<TypeNs>) { let ty = match resolution { TypeNs::TraitId(trait_) => { @@ -607,28 +655,44 @@ impl<'a> TyLoweringContext<'a> { // FIXME(trait_alias): Implement trait alias. return (TyKind::Error.intern(Interner), None); } - TypeNs::GenericParam(param_id) => match self.type_param_mode { - ParamLoweringMode::Placeholder => { - TyKind::Placeholder(to_placeholder_idx(self.db, param_id.into())) + TypeNs::GenericParam(param_id) => { + if resolved_segment.args_and_bindings.is_some() { + on_prohibited_generics_for_resolved_segment( + self, + GenericArgsProhibitedReason::TyParam, + ); } - ParamLoweringMode::Variable => { - let idx = match self - .generics() - .expect("generics in scope") - .type_or_const_param_idx(param_id.into()) - { - None => { - never!("no matching generics"); - return (TyKind::Error.intern(Interner), None); - } - Some(idx) => idx, - }; - TyKind::BoundVar(BoundVar::new(self.in_binders, idx)) + match self.type_param_mode { + ParamLoweringMode::Placeholder => { + TyKind::Placeholder(to_placeholder_idx(self.db, param_id.into())) + } + ParamLoweringMode::Variable => { + let idx = match self + .generics() + .expect("generics in scope") + .type_or_const_param_idx(param_id.into()) + { + None => { + never!("no matching generics"); + return (TyKind::Error.intern(Interner), None); + } + Some(idx) => idx, + }; + + TyKind::BoundVar(BoundVar::new(self.in_binders, idx)) + } } + .intern(Interner) } - .intern(Interner), TypeNs::SelfType(impl_id) => { + if resolved_segment.args_and_bindings.is_some() { + on_prohibited_generics_for_resolved_segment( + self, + GenericArgsProhibitedReason::SelfTy, + ); + } + let generics = self.generics().expect("impl should have generic param scope"); match self.type_param_mode { @@ -654,6 +718,13 @@ impl<'a> TyLoweringContext<'a> { } } TypeNs::AdtSelfType(adt) => { + if resolved_segment.args_and_bindings.is_some() { + on_prohibited_generics_for_resolved_segment( + self, + GenericArgsProhibitedReason::SelfTy, + ); + } + let generics = generics(self.db.upcast(), adt.into()); let substs = match self.type_param_mode { ParamLoweringMode::Placeholder => generics.placeholder_subst(self.db), @@ -666,6 +737,12 @@ impl<'a> TyLoweringContext<'a> { TypeNs::AdtId(it) => self.lower_path_inner(resolved_segment, it.into(), infer_args), TypeNs::BuiltinType(it) => { + if resolved_segment.args_and_bindings.is_some() { + on_prohibited_generics_for_resolved_segment( + self, + GenericArgsProhibitedReason::PrimitiveTy, + ); + } self.lower_path_inner(resolved_segment, it.into(), infer_args) } TypeNs::TypeAliasId(it) => { @@ -677,7 +754,7 @@ impl<'a> TyLoweringContext<'a> { self.lower_ty_relative_path(ty, Some(resolution), remaining_segments) } - pub(crate) fn lower_path(&mut self, path: &Path) -> (Ty, Option<TypeNs>) { + pub(crate) fn lower_path(&mut self, path: &Path, path_id: PathId) -> (Ty, Option<TypeNs>) { // Resolve the path (in type namespace) if let Some(type_ref) = path.type_anchor() { let (ty, res) = self.lower_ty_ext(type_ref); @@ -692,19 +769,44 @@ impl<'a> TyLoweringContext<'a> { if matches!(resolution, TypeNs::TraitId(_)) && remaining_index.is_none() { // trait object type without dyn - let bound = TypeBound::Path(path.clone(), TraitBoundModifier::None); + let bound = TypeBound::Path(path_id, TraitBoundModifier::None); let ty = self.lower_dyn_trait(&[bound]); return (ty, None); } - let (resolved_segment, remaining_segments) = match remaining_index { - None => ( - path.segments().last().expect("resolved path has at least one element"), - PathSegments::EMPTY, - ), - Some(i) => (path.segments().get(i - 1).unwrap(), path.segments().skip(i)), - }; - self.lower_partly_resolved_path(resolution, resolved_segment, remaining_segments, false) + let (module_segments, resolved_segment_idx, resolved_segment, remaining_segments) = + match remaining_index { + None => ( + path.segments().strip_last(), + path.segments().len() - 1, + path.segments().last().expect("resolved path has at least one element"), + PathSegments::EMPTY, + ), + Some(i) => ( + path.segments().take(i - 1), + i - 1, + path.segments().get(i - 1).unwrap(), + path.segments().skip(i), + ), + }; + + self.prohibit_generics(path_id, 0, module_segments, GenericArgsProhibitedReason::Module); + + self.lower_partly_resolved_path( + resolution, + resolved_segment, + remaining_segments, + false, + &mut |this, reason| { + this.push_diagnostic( + path_id.type_ref(), + TyLoweringDiagnosticKind::GenericArgsProhibited { + segment: resolved_segment_idx as u32, + reason, + }, + ) + }, + ) } fn select_associated_type(&mut self, res: Option<TypeNs>, segment: PathSegment<'_>) -> Ty { @@ -741,12 +843,8 @@ impl<'a> TyLoweringContext<'a> { // generic params. It's inefficient to splice the `Substitution`s, so we may want // that method to optionally take parent `Substitution` as we already know them at // this point (`t.substitution`). - let substs = self.substs_from_path_segment( - segment.clone(), - Some(associated_ty.into()), - false, - None, - ); + let substs = + self.substs_from_path_segment(segment, Some(associated_ty.into()), false, None); let len_self = crate::generics::generics(self.db.upcast(), associated_ty.into()).len_self(); @@ -998,12 +1096,41 @@ impl<'a> TyLoweringContext<'a> { TraitRef { trait_id: to_chalk_trait_id(resolved), substitution: substs } } - fn lower_trait_ref_from_path(&mut self, path: &Path, explicit_self_ty: Ty) -> Option<TraitRef> { + fn prohibit_generics( + &mut self, + path_id: PathId, + idx: u32, + segments: PathSegments<'_>, + reason: GenericArgsProhibitedReason, + ) { + segments.iter().zip(idx..).for_each(|(segment, idx)| { + if segment.args_and_bindings.is_some() { + self.push_diagnostic( + path_id.type_ref(), + TyLoweringDiagnosticKind::GenericArgsProhibited { segment: idx, reason }, + ); + } + }); + } + + fn lower_trait_ref_from_path( + &mut self, + path_id: PathId, + explicit_self_ty: Ty, + ) -> Option<TraitRef> { + let path = &self.types_map[path_id]; let resolved = match self.resolver.resolve_path_in_type_ns_fully(self.db.upcast(), path)? { // FIXME(trait_alias): We need to handle trait alias here. TypeNs::TraitId(tr) => tr, _ => return None, }; + // Do this after we verify it's indeed a trait to not confuse the user if they're not modules. + self.prohibit_generics( + path_id, + 0, + path.segments().strip_last(), + GenericArgsProhibitedReason::Module, + ); let segment = path.segments().last().expect("path should have at least one segment"); Some(self.lower_trait_ref_from_resolved_path(resolved, segment, explicit_self_ty)) } @@ -1013,7 +1140,7 @@ impl<'a> TyLoweringContext<'a> { trait_ref: &HirTraitRef, explicit_self_ty: Ty, ) -> Option<TraitRef> { - self.lower_trait_ref_from_path(&trait_ref.path, explicit_self_ty) + self.lower_trait_ref_from_path(trait_ref.path, explicit_self_ty) } fn trait_ref_substs_from_path( @@ -1072,11 +1199,11 @@ impl<'a> TyLoweringContext<'a> { ) -> impl Iterator<Item = QuantifiedWhereClause> + use<'b, 'a> { let mut trait_ref = None; let clause = match bound { - TypeBound::Path(path, TraitBoundModifier::None) => { + &TypeBound::Path(path, TraitBoundModifier::None) => { trait_ref = self.lower_trait_ref_from_path(path, self_ty); trait_ref.clone().map(WhereClause::Implemented).map(crate::wrap_empty_binders) } - TypeBound::Path(path, TraitBoundModifier::Maybe) => { + &TypeBound::Path(path, TraitBoundModifier::Maybe) => { let sized_trait = self .db .lang_item(self.resolver.krate(), LangItem::Sized) @@ -1092,7 +1219,7 @@ impl<'a> TyLoweringContext<'a> { } None } - TypeBound::ForLifetime(_, path) => { + &TypeBound::ForLifetime(_, path) => { // FIXME Don't silently drop the hrtb lifetimes here trait_ref = self.lower_trait_ref_from_path(path, self_ty); trait_ref.clone().map(WhereClause::Implemented).map(crate::wrap_empty_binders) @@ -1121,8 +1248,8 @@ impl<'a> TyLoweringContext<'a> { trait_ref: TraitRef, ) -> impl Iterator<Item = QuantifiedWhereClause> + use<'b, 'a> { let last_segment = match bound { - TypeBound::Path(path, TraitBoundModifier::None) | TypeBound::ForLifetime(_, path) => { - path.segments().last() + &TypeBound::Path(path, TraitBoundModifier::None) | &TypeBound::ForLifetime(_, path) => { + self.types_map[path].segments().last() } TypeBound::Path(_, TraitBoundModifier::Maybe) | TypeBound::Use(_) @@ -1227,7 +1354,9 @@ impl<'a> TyLoweringContext<'a> { } _ => unreachable!(), } - ext.lower_ty(type_ref) + let ty = ext.lower_ty(type_ref); + self.diagnostics.extend(ext.diagnostics); + ty } else { self.lower_ty(type_ref) }; @@ -1523,11 +1652,24 @@ fn named_associated_type_shorthand_candidates<R>( } } -/// Build the type of all specific fields of a struct or enum variant. +pub(crate) type Diagnostics = Option<ThinArc<(), TyLoweringDiagnostic>>; + +fn create_diagnostics(diagnostics: Vec<TyLoweringDiagnostic>) -> Diagnostics { + (!diagnostics.is_empty()).then(|| ThinArc::from_header_and_iter((), diagnostics.into_iter())) +} + pub(crate) fn field_types_query( db: &dyn HirDatabase, variant_id: VariantId, ) -> Arc<ArenaMap<LocalFieldId, Binders<Ty>>> { + db.field_types_with_diagnostics(variant_id).0 +} + +/// Build the type of all specific fields of a struct or enum variant. +pub(crate) fn field_types_with_diagnostics_query( + db: &dyn HirDatabase, + variant_id: VariantId, +) -> (Arc<ArenaMap<LocalFieldId, Binders<Ty>>>, Diagnostics) { let var_data = variant_id.variant_data(db.upcast()); let (resolver, def): (_, GenericDefId) = match variant_id { VariantId::StructId(it) => (it.resolver(db.upcast()), it.into()), @@ -1543,7 +1685,7 @@ pub(crate) fn field_types_query( for (field_id, field_data) in var_data.fields().iter() { res.insert(field_id, make_binders(db, &generics, ctx.lower_ty(field_data.type_ref))); } - Arc::new(res) + (Arc::new(res), create_diagnostics(ctx.diagnostics)) } /// This query exists only to be used when resolving short-hand associated types @@ -1593,9 +1735,10 @@ pub(crate) fn generic_predicates_for_param_query( } match bound { - TypeBound::ForLifetime(_, path) | TypeBound::Path(path, _) => { + &TypeBound::ForLifetime(_, path) | &TypeBound::Path(path, _) => { // Only lower the bound if the trait could possibly define the associated // type we're looking for. + let path = &ctx.types_map[path]; let Some(assoc_name) = &assoc_name else { return true }; let Some(TypeNs::TraitId(tr)) = @@ -1743,15 +1886,22 @@ pub(crate) fn generic_predicates_query( db: &dyn HirDatabase, def: GenericDefId, ) -> GenericPredicates { - generic_predicates_filtered_by(db, def, |_, _| true) + generic_predicates_filtered_by(db, def, |_, _| true).0 } -/// Resolve the where clause(s) of an item with generics, -/// except the ones inherited from the parent pub(crate) fn generic_predicates_without_parent_query( db: &dyn HirDatabase, def: GenericDefId, ) -> GenericPredicates { + db.generic_predicates_without_parent_with_diagnostics(def).0 +} + +/// Resolve the where clause(s) of an item with generics, +/// except the ones inherited from the parent +pub(crate) fn generic_predicates_without_parent_with_diagnostics_query( + db: &dyn HirDatabase, + def: GenericDefId, +) -> (GenericPredicates, Diagnostics) { generic_predicates_filtered_by(db, def, |_, d| *d == def) } @@ -1761,7 +1911,7 @@ fn generic_predicates_filtered_by<F>( db: &dyn HirDatabase, def: GenericDefId, filter: F, -) -> GenericPredicates +) -> (GenericPredicates, Diagnostics) where F: Fn(&WherePredicate, &GenericDefId) -> bool, { @@ -1802,7 +1952,10 @@ where ); }; } - GenericPredicates(predicates.is_empty().not().then(|| predicates.into())) + ( + GenericPredicates(predicates.is_empty().not().then(|| predicates.into())), + create_diagnostics(ctx.diagnostics), + ) } /// Generate implicit `: Sized` predicates for all generics that has no `?Sized` bound. @@ -1855,75 +2008,110 @@ impl ops::Deref for GenericDefaults { } } -/// Resolve the default type params from generics pub(crate) fn generic_defaults_query(db: &dyn HirDatabase, def: GenericDefId) -> GenericDefaults { + db.generic_defaults_with_diagnostics(def).0 +} + +/// Resolve the default type params from generics. +/// +/// Diagnostics are only returned for this `GenericDefId` (returned defaults include parents). +pub(crate) fn generic_defaults_with_diagnostics_query( + db: &dyn HirDatabase, + def: GenericDefId, +) -> (GenericDefaults, Diagnostics) { let generic_params = generics(db.upcast(), def); if generic_params.len() == 0 { - return GenericDefaults(None); + return (GenericDefaults(None), None); } let resolver = def.resolver(db.upcast()); let parent_start_idx = generic_params.len_self(); - let mut ctx = TyLoweringContext::new(db, &resolver, TypesMap::EMPTY, def.into()) - .with_impl_trait_mode(ImplTraitLoweringMode::Disallowed) - .with_type_param_mode(ParamLoweringMode::Variable); - GenericDefaults(Some(Arc::from_iter(generic_params.iter_with_types_map().enumerate().map( - |(idx, ((id, p), types_map))| { - ctx.types_map = types_map; - match p { - GenericParamDataRef::TypeParamData(p) => { - let ty = p.default.as_ref().map_or(TyKind::Error.intern(Interner), |ty| { - // Each default can only refer to previous parameters. - // Type variable default referring to parameter coming - // after it is forbidden (FIXME: report diagnostic) - fallback_bound_vars(ctx.lower_ty(*ty), idx, parent_start_idx) - }); - crate::make_binders(db, &generic_params, ty.cast(Interner)) - } - GenericParamDataRef::ConstParamData(p) => { - let GenericParamId::ConstParamId(id) = id else { - unreachable!("Unexpected lifetime or type argument") - }; + let mut ctx = + TyLoweringContext::new(db, &resolver, generic_params.self_types_map(), def.into()) + .with_impl_trait_mode(ImplTraitLoweringMode::Disallowed) + .with_type_param_mode(ParamLoweringMode::Variable); + let mut idx = 0; + let mut defaults = generic_params + .iter_self() + .map(|(id, p)| { + let result = + handle_generic_param(&mut ctx, idx, id, p, parent_start_idx, &generic_params); + idx += 1; + result + }) + .collect::<Vec<_>>(); + let diagnostics = create_diagnostics(mem::take(&mut ctx.diagnostics)); + defaults.extend(generic_params.iter_parents_with_types_map().map(|((id, p), types_map)| { + ctx.types_map = types_map; + let result = handle_generic_param(&mut ctx, idx, id, p, parent_start_idx, &generic_params); + idx += 1; + result + })); + let defaults = GenericDefaults(Some(Arc::from_iter(defaults))); + return (defaults, diagnostics); + + fn handle_generic_param( + ctx: &mut TyLoweringContext<'_>, + idx: usize, + id: GenericParamId, + p: GenericParamDataRef<'_>, + parent_start_idx: usize, + generic_params: &Generics, + ) -> Binders<crate::GenericArg> { + match p { + GenericParamDataRef::TypeParamData(p) => { + let ty = p.default.as_ref().map_or(TyKind::Error.intern(Interner), |ty| { + // Each default can only refer to previous parameters. + // Type variable default referring to parameter coming + // after it is forbidden (FIXME: report diagnostic) + fallback_bound_vars(ctx.lower_ty(*ty), idx, parent_start_idx) + }); + crate::make_binders(ctx.db, generic_params, ty.cast(Interner)) + } + GenericParamDataRef::ConstParamData(p) => { + let GenericParamId::ConstParamId(id) = id else { + unreachable!("Unexpected lifetime or type argument") + }; - let mut val = p.default.as_ref().map_or_else( - || unknown_const_as_generic(db.const_param_ty(id)), - |c| { - let param_ty = ctx.lower_ty(p.ty); - let c = ctx.lower_const(c, param_ty); - c.cast(Interner) - }, - ); - // Each default can only refer to previous parameters, see above. - val = fallback_bound_vars(val, idx, parent_start_idx); - make_binders(db, &generic_params, val) - } - GenericParamDataRef::LifetimeParamData(_) => { - make_binders(db, &generic_params, error_lifetime().cast(Interner)) - } + let mut val = p.default.as_ref().map_or_else( + || unknown_const_as_generic(ctx.db.const_param_ty(id)), + |c| { + let param_ty = ctx.lower_ty(p.ty); + let c = ctx.lower_const(c, param_ty); + c.cast(Interner) + }, + ); + // Each default can only refer to previous parameters, see above. + val = fallback_bound_vars(val, idx, parent_start_idx); + make_binders(ctx.db, generic_params, val) } - }, - )))) + GenericParamDataRef::LifetimeParamData(_) => { + make_binders(ctx.db, generic_params, error_lifetime().cast(Interner)) + } + } + } } -pub(crate) fn generic_defaults_recover( +pub(crate) fn generic_defaults_with_diagnostics_recover( db: &dyn HirDatabase, _cycle: &Cycle, def: &GenericDefId, -) -> GenericDefaults { +) -> (GenericDefaults, Diagnostics) { let generic_params = generics(db.upcast(), *def); if generic_params.len() == 0 { - return GenericDefaults(None); + return (GenericDefaults(None), None); } // FIXME: this code is not covered in tests. // we still need one default per parameter - GenericDefaults(Some(Arc::from_iter(generic_params.iter_id().map(|id| { + let defaults = GenericDefaults(Some(Arc::from_iter(generic_params.iter_id().map(|id| { let val = match id { GenericParamId::TypeParamId(_) => TyKind::Error.intern(Interner).cast(Interner), GenericParamId::ConstParamId(id) => unknown_const_as_generic(db.const_param_ty(id)), GenericParamId::LifetimeParamId(_) => error_lifetime().cast(Interner), }; crate::make_binders(db, &generic_params, val) - })))) + })))); + (defaults, None) } fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig { @@ -2066,7 +2254,10 @@ fn type_for_adt(db: &dyn HirDatabase, adt: AdtId) -> Binders<Ty> { make_binders(db, &generics, ty) } -fn type_for_type_alias(db: &dyn HirDatabase, t: TypeAliasId) -> Binders<Ty> { +pub(crate) fn type_for_type_alias_with_diagnostics_query( + db: &dyn HirDatabase, + t: TypeAliasId, +) -> (Binders<Ty>, Diagnostics) { let generics = generics(db.upcast(), t.into()); let resolver = t.resolver(db.upcast()); let type_alias_data = db.type_alias_data(t); @@ -2081,7 +2272,7 @@ fn type_for_type_alias(db: &dyn HirDatabase, t: TypeAliasId) -> Binders<Ty> { .map(|type_ref| ctx.lower_ty(type_ref)) .unwrap_or_else(|| TyKind::Error.intern(Interner)) }; - make_binders(db, &generics, inner) + (make_binders(db, &generics, inner), create_diagnostics(ctx.diagnostics)) } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -2124,7 +2315,7 @@ pub(crate) fn ty_query(db: &dyn HirDatabase, def: TyDefId) -> Binders<Ty> { match def { TyDefId::BuiltinType(it) => Binders::empty(Interner, TyBuilder::builtin(it)), TyDefId::AdtId(it) => type_for_adt(db, it), - TyDefId::TypeAliasId(it) => type_for_type_alias(db, it), + TyDefId::TypeAliasId(it) => db.type_for_type_alias_with_diagnostics(it).0, } } @@ -2149,47 +2340,73 @@ pub(crate) fn value_ty_query(db: &dyn HirDatabase, def: ValueTyDefId) -> Option< } pub(crate) fn impl_self_ty_query(db: &dyn HirDatabase, impl_id: ImplId) -> Binders<Ty> { + db.impl_self_ty_with_diagnostics(impl_id).0 +} + +pub(crate) fn impl_self_ty_with_diagnostics_query( + db: &dyn HirDatabase, + impl_id: ImplId, +) -> (Binders<Ty>, Diagnostics) { let impl_data = db.impl_data(impl_id); let resolver = impl_id.resolver(db.upcast()); let generics = generics(db.upcast(), impl_id.into()); let mut ctx = TyLoweringContext::new(db, &resolver, &impl_data.types_map, impl_id.into()) .with_type_param_mode(ParamLoweringMode::Variable); - make_binders(db, &generics, ctx.lower_ty(impl_data.self_ty)) + ( + make_binders(db, &generics, ctx.lower_ty(impl_data.self_ty)), + create_diagnostics(ctx.diagnostics), + ) } -// returns None if def is a type arg pub(crate) fn const_param_ty_query(db: &dyn HirDatabase, def: ConstParamId) -> Ty { + db.const_param_ty_with_diagnostics(def).0 +} + +// returns None if def is a type arg +pub(crate) fn const_param_ty_with_diagnostics_query( + db: &dyn HirDatabase, + def: ConstParamId, +) -> (Ty, Diagnostics) { let parent_data = db.generic_params(def.parent()); let data = &parent_data[def.local_id()]; let resolver = def.parent().resolver(db.upcast()); let mut ctx = TyLoweringContext::new(db, &resolver, &parent_data.types_map, def.parent().into()); - match data { + let ty = match data { TypeOrConstParamData::TypeParamData(_) => { never!(); Ty::new(Interner, TyKind::Error) } TypeOrConstParamData::ConstParamData(d) => ctx.lower_ty(d.ty), - } + }; + (ty, create_diagnostics(ctx.diagnostics)) } -pub(crate) fn impl_self_ty_recover( +pub(crate) fn impl_self_ty_with_diagnostics_recover( db: &dyn HirDatabase, _cycle: &Cycle, impl_id: &ImplId, -) -> Binders<Ty> { +) -> (Binders<Ty>, Diagnostics) { let generics = generics(db.upcast(), (*impl_id).into()); - make_binders(db, &generics, TyKind::Error.intern(Interner)) + (make_binders(db, &generics, TyKind::Error.intern(Interner)), None) } pub(crate) fn impl_trait_query(db: &dyn HirDatabase, impl_id: ImplId) -> Option<Binders<TraitRef>> { + db.impl_trait_with_diagnostics(impl_id).map(|it| it.0) +} + +pub(crate) fn impl_trait_with_diagnostics_query( + db: &dyn HirDatabase, + impl_id: ImplId, +) -> Option<(Binders<TraitRef>, Diagnostics)> { let impl_data = db.impl_data(impl_id); let resolver = impl_id.resolver(db.upcast()); let mut ctx = TyLoweringContext::new(db, &resolver, &impl_data.types_map, impl_id.into()) .with_type_param_mode(ParamLoweringMode::Variable); let (self_ty, binders) = db.impl_self_ty(impl_id).into_value_and_skipped_binders(); let target_trait = impl_data.target_trait.as_ref()?; - Some(Binders::new(binders, ctx.lower_trait_ref(target_trait, self_ty)?)) + let trait_ref = Binders::new(binders, ctx.lower_trait_ref(target_trait, self_ty)?); + Some((trait_ref, create_diagnostics(ctx.diagnostics))) } pub(crate) fn return_type_impl_traits( diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs index c4e06400510..1d1044df6e9 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs @@ -2023,11 +2023,11 @@ pub fn mir_body_for_closure_query( ctx.result.locals.alloc(Local { ty: infer[*root].clone() }); let closure_local = ctx.result.locals.alloc(Local { ty: match kind { - FnTrait::FnOnce => infer[expr].clone(), - FnTrait::FnMut => { + FnTrait::FnOnce | FnTrait::AsyncFnOnce => infer[expr].clone(), + FnTrait::FnMut | FnTrait::AsyncFnMut => { TyKind::Ref(Mutability::Mut, error_lifetime(), infer[expr].clone()).intern(Interner) } - FnTrait::Fn => { + FnTrait::Fn | FnTrait::AsyncFn => { TyKind::Ref(Mutability::Not, error_lifetime(), infer[expr].clone()).intern(Interner) } }, @@ -2055,8 +2055,10 @@ pub fn mir_body_for_closure_query( let mut err = None; let closure_local = ctx.result.locals.iter().nth(1).unwrap().0; let closure_projection = match kind { - FnTrait::FnOnce => vec![], - FnTrait::FnMut | FnTrait::Fn => vec![ProjectionElem::Deref], + FnTrait::FnOnce | FnTrait::AsyncFnOnce => vec![], + FnTrait::FnMut | FnTrait::Fn | FnTrait::AsyncFnMut | FnTrait::AsyncFn => { + vec![ProjectionElem::Deref] + } }; ctx.result.walk_places(|p, store| { if let Some(it) = upvar_map.get(&p.local) { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs index bcf9d5ceff0..cabeeea2bd8 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs @@ -18,13 +18,13 @@ use std::sync::LazyLock; use base_db::SourceDatabaseFileInputExt as _; use expect_test::Expect; use hir_def::{ - body::{Body, BodySourceMap, SyntheticSyntax}, + body::{Body, BodySourceMap}, db::DefDatabase, hir::{ExprId, Pat, PatId}, item_scope::ItemScope, nameres::DefMap, src::HasSource, - AssocItemId, DefWithBodyId, HasModule, LocalModuleId, Lookup, ModuleDefId, + AssocItemId, DefWithBodyId, HasModule, LocalModuleId, Lookup, ModuleDefId, SyntheticSyntax, }; use hir_expand::{db::ExpandDatabase, FileRange, InFile}; use itertools::Itertools; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs index 273571901ad..7992f1feeeb 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs @@ -942,3 +942,19 @@ fn main() { "#, ) } + +#[test] +fn regression_18626() { + check_no_mismatches( + r#" +fn f() { + trait T { + fn f() {} + } + impl T for i32 {} + impl T for u32 {} + &[i32::f, u32::f] as &[fn()]; +} + "#, + ); +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs index 624148cab20..e15d44bd6de 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs @@ -1631,6 +1631,29 @@ fn test<'lifetime>( } #[test] +fn lifetime_bounds() { + check_infer( + r#" +//- minicore: sized, coerce_unsized +trait Trait<'a>: Sized { + fn f(&'a self) {} +} +fn test<'a, 'b: 'a>(it: impl Trait<'a>){ + it.f(); +} +"#, + expect![[r#" + 38..42 'self': &'a Self + 44..46 '{}': () + 69..71 'it': impl Trait<'a> + 88..103 '{ it.f(); }': () + 94..96 'it': impl Trait<'a> + 94..100 'it.f()': () + "#]], + ); +} + +#[test] fn error_bound_chalk() { check_types( r#" @@ -4811,3 +4834,53 @@ fn bar(v: *const ()) { "#]], ); } + +#[test] +fn async_fn_traits() { + check_infer( + r#" +//- minicore: async_fn +async fn foo<T: AsyncFn(u32) -> i32>(a: T) { + let fut1 = a(0); + fut1.await; +} +async fn bar<T: AsyncFnMut(u32) -> i32>(mut b: T) { + let fut2 = b(0); + fut2.await; +} +async fn baz<T: AsyncFnOnce(u32) -> i32>(c: T) { + let fut3 = c(0); + fut3.await; +} + "#, + expect![[r#" + 37..38 'a': T + 43..83 '{ ...ait; }': () + 43..83 '{ ...ait; }': impl Future<Output = ()> + 53..57 'fut1': AsyncFnMut::CallRefFuture<'?, T, (u32,)> + 60..61 'a': T + 60..64 'a(0)': AsyncFnMut::CallRefFuture<'?, T, (u32,)> + 62..63 '0': u32 + 70..74 'fut1': AsyncFnMut::CallRefFuture<'?, T, (u32,)> + 70..80 'fut1.await': i32 + 124..129 'mut b': T + 134..174 '{ ...ait; }': () + 134..174 '{ ...ait; }': impl Future<Output = ()> + 144..148 'fut2': AsyncFnMut::CallRefFuture<'?, T, (u32,)> + 151..152 'b': T + 151..155 'b(0)': AsyncFnMut::CallRefFuture<'?, T, (u32,)> + 153..154 '0': u32 + 161..165 'fut2': AsyncFnMut::CallRefFuture<'?, T, (u32,)> + 161..171 'fut2.await': i32 + 216..217 'c': T + 222..262 '{ ...ait; }': () + 222..262 '{ ...ait; }': impl Future<Output = ()> + 232..236 'fut3': AsyncFnOnce::CallOnceFuture<T, (u32,)> + 239..240 'c': T + 239..243 'c(0)': AsyncFnOnce::CallOnceFuture<T, (u32,)> + 241..242 '0': u32 + 249..253 'fut3': AsyncFnOnce::CallOnceFuture<T, (u32,)> + 249..259 'fut3.await': i32 + "#]], + ); +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs index 51ccd4ef293..8cb7dbf60f3 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs @@ -220,6 +220,10 @@ pub enum FnTrait { FnOnce, FnMut, Fn, + + AsyncFnOnce, + AsyncFnMut, + AsyncFn, } impl fmt::Display for FnTrait { @@ -228,6 +232,9 @@ impl fmt::Display for FnTrait { FnTrait::FnOnce => write!(f, "FnOnce"), FnTrait::FnMut => write!(f, "FnMut"), FnTrait::Fn => write!(f, "Fn"), + FnTrait::AsyncFnOnce => write!(f, "AsyncFnOnce"), + FnTrait::AsyncFnMut => write!(f, "AsyncFnMut"), + FnTrait::AsyncFn => write!(f, "AsyncFn"), } } } @@ -238,6 +245,9 @@ impl FnTrait { FnTrait::FnOnce => "call_once", FnTrait::FnMut => "call_mut", FnTrait::Fn => "call", + FnTrait::AsyncFnOnce => "async_call_once", + FnTrait::AsyncFnMut => "async_call_mut", + FnTrait::AsyncFn => "async_call", } } @@ -246,6 +256,9 @@ impl FnTrait { FnTrait::FnOnce => LangItem::FnOnce, FnTrait::FnMut => LangItem::FnMut, FnTrait::Fn => LangItem::Fn, + FnTrait::AsyncFnOnce => LangItem::AsyncFnOnce, + FnTrait::AsyncFnMut => LangItem::AsyncFnMut, + FnTrait::AsyncFn => LangItem::AsyncFn, } } @@ -254,15 +267,19 @@ impl FnTrait { LangItem::FnOnce => Some(FnTrait::FnOnce), LangItem::FnMut => Some(FnTrait::FnMut), LangItem::Fn => Some(FnTrait::Fn), + LangItem::AsyncFnOnce => Some(FnTrait::AsyncFnOnce), + LangItem::AsyncFnMut => Some(FnTrait::AsyncFnMut), + LangItem::AsyncFn => Some(FnTrait::AsyncFn), _ => None, } } pub const fn to_chalk_ir(self) -> rust_ir::ClosureKind { + // Chalk doesn't support async fn traits. match self { - FnTrait::FnOnce => rust_ir::ClosureKind::FnOnce, - FnTrait::FnMut => rust_ir::ClosureKind::FnMut, - FnTrait::Fn => rust_ir::ClosureKind::Fn, + FnTrait::AsyncFnOnce | FnTrait::FnOnce => rust_ir::ClosureKind::FnOnce, + FnTrait::AsyncFnMut | FnTrait::FnMut => rust_ir::ClosureKind::FnMut, + FnTrait::AsyncFn | FnTrait::Fn => rust_ir::ClosureKind::Fn, } } @@ -271,6 +288,9 @@ impl FnTrait { FnTrait::FnOnce => Name::new_symbol_root(sym::call_once.clone()), FnTrait::FnMut => Name::new_symbol_root(sym::call_mut.clone()), FnTrait::Fn => Name::new_symbol_root(sym::call.clone()), + FnTrait::AsyncFnOnce => Name::new_symbol_root(sym::async_call_once.clone()), + FnTrait::AsyncFnMut => Name::new_symbol_root(sym::async_call_mut.clone()), + FnTrait::AsyncFn => Name::new_symbol_root(sym::async_call.clone()), } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs index 28bda1e10e5..06719b09f73 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs @@ -185,7 +185,7 @@ fn direct_super_traits_cb(db: &dyn DefDatabase, trait_: TraitId, cb: impl FnMut( } }; match is_trait { - true => bound.as_path(), + true => bound.as_path(&generic_params.types_map), false => None, } } diff --git a/src/tools/rust-analyzer/crates/hir/Cargo.toml b/src/tools/rust-analyzer/crates/hir/Cargo.toml index 26666d6feb0..6aadc5c4f7e 100644 --- a/src/tools/rust-analyzer/crates/hir/Cargo.toml +++ b/src/tools/rust-analyzer/crates/hir/Cargo.toml @@ -33,6 +33,14 @@ syntax.workspace = true tt.workspace = true span.workspace = true +[dev-dependencies] +expect-test.workspace = true + +# local deps +test-utils.workspace = true +test-fixture.workspace = true +syntax-bridge.workspace = true + [features] in-rust-tree = ["hir-expand/in-rust-tree"] diff --git a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs index 8297acde857..612c6adb207 100644 --- a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs @@ -3,21 +3,35 @@ //! //! This probably isn't the best way to do this -- ideally, diagnostics should //! be expressed in terms of hir types themselves. -pub use hir_ty::diagnostics::{CaseType, IncorrectCase}; -use hir_ty::{ - db::HirDatabase, diagnostics::BodyValidationDiagnostic, CastError, InferenceDiagnostic, -}; - use cfg::{CfgExpr, CfgOptions}; use either::Either; -pub use hir_def::VariantId; -use hir_def::{body::SyntheticSyntax, hir::ExprOrPatId, path::ModPath, AssocItemId, DefWithBodyId}; +use hir_def::{ + hir::ExprOrPatId, + path::{hir_segment_to_ast_segment, ModPath}, + type_ref::TypesSourceMap, + AssocItemId, DefWithBodyId, SyntheticSyntax, +}; use hir_expand::{name::Name, HirFileId, InFile}; -use syntax::{ast, AstPtr, SyntaxError, SyntaxNodePtr, TextRange}; +use hir_ty::{ + db::HirDatabase, + diagnostics::{BodyValidationDiagnostic, UnsafetyReason}, + CastError, InferenceDiagnostic, InferenceTyDiagnosticSource, TyLoweringDiagnostic, + TyLoweringDiagnosticKind, +}; +use syntax::{ + ast::{self, HasGenericArgs}, + AstPtr, SyntaxError, SyntaxNodePtr, TextRange, +}; use triomphe::Arc; use crate::{AssocItem, Field, Local, Trait, Type}; +pub use hir_def::VariantId; +pub use hir_ty::{ + diagnostics::{CaseType, IncorrectCase}, + GenericArgsProhibitedReason, +}; + macro_rules! diagnostics { ($($diag:ident,)*) => { #[derive(Debug)] @@ -96,6 +110,7 @@ diagnostics![ UnresolvedIdent, UnusedMut, UnusedVariable, + GenericArgsProhibited, ]; #[derive(Debug)] @@ -258,9 +273,10 @@ pub struct PrivateField { #[derive(Debug)] pub struct MissingUnsafe { - pub expr: InFile<AstPtr<Either<ast::Expr, ast::Pat>>>, + pub node: InFile<AstPtr<Either<ast::Expr, ast::Pat>>>, /// If true, the diagnostics is an `unsafe_op_in_unsafe_fn` lint instead of a hard error. pub only_lint: bool, + pub reason: UnsafetyReason, } #[derive(Debug)] @@ -385,6 +401,12 @@ pub struct InvalidCast { pub cast_ty: Type, } +#[derive(Debug)] +pub struct GenericArgsProhibited { + pub args: InFile<AstPtr<Either<ast::GenericArgList, ast::ParenthesizedArgList>>>, + pub reason: GenericArgsProhibitedReason, +} + impl AnyDiagnostic { pub(crate) fn body_validation_diagnostic( db: &dyn HirDatabase, @@ -524,6 +546,7 @@ impl AnyDiagnostic { db: &dyn HirDatabase, def: DefWithBodyId, d: &InferenceDiagnostic, + outer_types_source_map: &TypesSourceMap, source_map: &hir_def::body::BodySourceMap, ) -> Option<AnyDiagnostic> { let expr_syntax = |expr| { @@ -637,6 +660,44 @@ impl AnyDiagnostic { let cast_ty = Type::new(db, def, cast_ty.clone()); InvalidCast { expr, error: *error, expr_ty, cast_ty }.into() } + InferenceDiagnostic::TyDiagnostic { source, diag } => { + let source_map = match source { + InferenceTyDiagnosticSource::Body => &source_map.types, + InferenceTyDiagnosticSource::Signature => outer_types_source_map, + }; + Self::ty_diagnostic(diag, source_map, db)? + } + }) + } + + pub(crate) fn ty_diagnostic( + diag: &TyLoweringDiagnostic, + source_map: &TypesSourceMap, + db: &dyn HirDatabase, + ) -> Option<AnyDiagnostic> { + let source = match diag.source { + Either::Left(type_ref_id) => { + let Ok(source) = source_map.type_syntax(type_ref_id) else { + stdx::never!("error on synthetic type syntax"); + return None; + }; + source + } + Either::Right(source) => source, + }; + let syntax = || source.value.to_node(&db.parse_or_expand(source.file_id)); + Some(match diag.kind { + TyLoweringDiagnosticKind::GenericArgsProhibited { segment, reason } => { + let ast::Type::PathType(syntax) = syntax() else { return None }; + let segment = hir_segment_to_ast_segment(&syntax.path()?, segment)?; + let args = if let Some(generics) = segment.generic_arg_list() { + AstPtr::new(&generics).wrap_left() + } else { + AstPtr::new(&segment.parenthesized_arg_list()?).wrap_right() + }; + let args = source.with_value(args); + GenericArgsProhibited { args, reason }.into() + } }) } } diff --git a/src/tools/rust-analyzer/crates/hir/src/display.rs b/src/tools/rust-analyzer/crates/hir/src/display.rs index 9275f45d881..959d62d5951 100644 --- a/src/tools/rust-analyzer/crates/hir/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir/src/display.rs @@ -132,12 +132,18 @@ impl HirDisplay for Function { } else { match &data.types_map[data.ret_type] { TypeRef::ImplTrait(bounds) => match &bounds[0] { - TypeBound::Path(path, _) => Some( - *path.segments().iter().last().unwrap().args_and_bindings.unwrap().bindings - [0] - .type_ref - .as_ref() - .unwrap(), + &TypeBound::Path(path, _) => Some( + *data.types_map[path] + .segments() + .iter() + .last() + .unwrap() + .args_and_bindings + .unwrap() + .bindings[0] + .type_ref + .as_ref() + .unwrap(), ), _ => None, }, diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index c9498b3aead..83d72dfcf14 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -20,12 +20,11 @@ #![cfg_attr(feature = "in-rust-tree", feature(rustc_private))] #![recursion_limit = "512"] -mod semantics; -mod source_analyzer; - mod attrs; mod from_id; mod has_source; +mod semantics; +mod source_analyzer; pub mod db; pub mod diagnostics; @@ -43,7 +42,7 @@ use arrayvec::ArrayVec; use base_db::{CrateDisplayName, CrateId, CrateOrigin}; use either::Either; use hir_def::{ - body::{BodyDiagnostic, SyntheticSyntax}, + body::BodyDiagnostic, data::adt::VariantData, generics::{LifetimeParamData, TypeOrConstParamData, TypeParamProvenance}, hir::{BindingAnnotation, BindingId, ExprId, ExprOrPatId, LabelId, Pat}, @@ -54,11 +53,12 @@ use hir_def::{ path::ImportAlias, per_ns::PerNs, resolver::{HasResolver, Resolver}, + type_ref::TypesSourceMap, AssocItemId, AssocItemLoc, AttrDefId, CallableDefId, ConstId, ConstParamId, CrateRootModuleId, DefWithBodyId, EnumId, EnumVariantId, ExternCrateId, FunctionId, GenericDefId, GenericParamId, HasModule, ImplId, InTypeConstId, ItemContainerId, LifetimeParamId, LocalFieldId, Lookup, - MacroExpander, ModuleId, StaticId, StructId, TraitAliasId, TraitId, TupleId, TypeAliasId, - TypeOrConstParamId, TypeParamId, UnionId, + MacroExpander, ModuleId, StaticId, StructId, SyntheticSyntax, TraitAliasId, TraitId, TupleId, + TypeAliasId, TypeOrConstParamId, TypeParamId, UnionId, }; use hir_expand::{ attrs::collect_attrs, proc_macro::ProcMacroKind, AstId, MacroCallKind, RenderedExpandError, @@ -76,8 +76,8 @@ use hir_ty::{ traits::FnTrait, AliasTy, CallableSig, Canonical, CanonicalVarKinds, Cast, ClosureId, GenericArg, GenericArgData, Interner, ParamKind, QuantifiedWhereClause, Scalar, Substitution, - TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyDefId, TyExt, TyKind, ValueTyDefId, - WhereClause, + TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyDefId, TyExt, TyKind, TyLoweringDiagnostic, + ValueTyDefId, WhereClause, }; use itertools::Itertools; use nameres::diagnostics::DefDiagnosticKind; @@ -89,7 +89,7 @@ use syntax::{ ast::{self, HasAttrs as _, HasGenericParams, HasName}, format_smolstr, AstNode, AstPtr, SmolStr, SyntaxNode, SyntaxNodePtr, TextRange, ToSmolStr, T, }; -use triomphe::Arc; +use triomphe::{Arc, ThinArc}; use crate::db::{DefDatabase, HirDatabase}; @@ -147,6 +147,7 @@ pub use { }, hir_ty::{ consteval::ConstEvalError, + diagnostics::UnsafetyReason, display::{ClosureStyle, HirDisplay, HirDisplayError, HirWrite}, dyn_compatibility::{DynCompatibilityViolation, MethodViolationCode}, layout::LayoutError, @@ -410,6 +411,10 @@ impl ModuleDef { } } + if let Some(def) = self.as_self_generic_def() { + def.diagnostics(db, &mut acc); + } + acc } @@ -430,6 +435,23 @@ impl ModuleDef { } } + /// Returns only defs that have generics from themselves, not their parent. + pub fn as_self_generic_def(self) -> Option<GenericDef> { + match self { + ModuleDef::Function(it) => Some(it.into()), + ModuleDef::Adt(it) => Some(it.into()), + ModuleDef::Trait(it) => Some(it.into()), + ModuleDef::TraitAlias(it) => Some(it.into()), + ModuleDef::TypeAlias(it) => Some(it.into()), + ModuleDef::Module(_) + | ModuleDef::Variant(_) + | ModuleDef::Static(_) + | ModuleDef::Const(_) + | ModuleDef::BuiltinType(_) + | ModuleDef::Macro(_) => None, + } + } + pub fn attrs(&self, db: &dyn HirDatabase) -> Option<AttrsWithOwner> { Some(match self { ModuleDef::Module(it) => it.attrs(db), @@ -604,17 +626,42 @@ impl Module { ModuleDef::Adt(adt) => { match adt { Adt::Struct(s) => { + let tree_id = s.id.lookup(db.upcast()).id; + let tree_source_maps = tree_id.item_tree_with_source_map(db.upcast()).1; + push_ty_diagnostics( + db, + acc, + db.field_types_with_diagnostics(s.id.into()).1, + tree_source_maps.strukt(tree_id.value).item(), + ); for diag in db.struct_data_with_diagnostics(s.id).1.iter() { emit_def_diagnostic(db, acc, diag, edition); } } Adt::Union(u) => { + let tree_id = u.id.lookup(db.upcast()).id; + let tree_source_maps = tree_id.item_tree_with_source_map(db.upcast()).1; + push_ty_diagnostics( + db, + acc, + db.field_types_with_diagnostics(u.id.into()).1, + tree_source_maps.union(tree_id.value).item(), + ); for diag in db.union_data_with_diagnostics(u.id).1.iter() { emit_def_diagnostic(db, acc, diag, edition); } } Adt::Enum(e) => { for v in e.variants(db) { + let tree_id = v.id.lookup(db.upcast()).id; + let tree_source_maps = + tree_id.item_tree_with_source_map(db.upcast()).1; + push_ty_diagnostics( + db, + acc, + db.field_types_with_diagnostics(v.id.into()).1, + tree_source_maps.variant(tree_id.value), + ); acc.extend(ModuleDef::Variant(v).diagnostics(db, style_lints)); for diag in db.enum_variant_data_with_diagnostics(v.id).1.iter() { emit_def_diagnostic(db, acc, diag, edition); @@ -625,6 +672,17 @@ impl Module { acc.extend(def.diagnostics(db, style_lints)) } ModuleDef::Macro(m) => emit_macro_def_diagnostics(db, acc, m), + ModuleDef::TypeAlias(type_alias) => { + let tree_id = type_alias.id.lookup(db.upcast()).id; + let tree_source_maps = tree_id.item_tree_with_source_map(db.upcast()).1; + push_ty_diagnostics( + db, + acc, + db.type_for_type_alias_with_diagnostics(type_alias.id).1, + tree_source_maps.type_alias(tree_id.value).item(), + ); + acc.extend(def.diagnostics(db, style_lints)); + } _ => acc.extend(def.diagnostics(db, style_lints)), } } @@ -634,8 +692,11 @@ impl Module { let mut impl_assoc_items_scratch = vec![]; for impl_def in self.impl_defs(db) { + GenericDef::Impl(impl_def).diagnostics(db, acc); + let loc = impl_def.id.lookup(db.upcast()); - let tree = loc.id.item_tree(db.upcast()); + let (tree, tree_source_maps) = loc.id.item_tree_with_source_map(db.upcast()); + let source_map = tree_source_maps.impl_(loc.id.value).item(); let node = &tree[loc.id.value]; let file_id = loc.id.file_id(); if file_id.macro_file().map_or(false, |it| it.is_builtin_derive(db.upcast())) { @@ -770,6 +831,19 @@ impl Module { impl_assoc_items_scratch.clear(); } + push_ty_diagnostics( + db, + acc, + db.impl_self_ty_with_diagnostics(impl_def.id).1, + source_map, + ); + push_ty_diagnostics( + db, + acc, + db.impl_trait_with_diagnostics(impl_def.id).and_then(|it| it.1), + source_map, + ); + for &item in db.impl_data(impl_def.id).items.iter() { AssocItem::from(item).diagnostics(db, acc, style_lints); } @@ -1801,6 +1875,25 @@ impl DefWithBody { let krate = self.module(db).id.krate(); let (body, source_map) = db.body_with_source_map(self.into()); + let item_tree_source_maps; + let outer_types_source_map = match self { + DefWithBody::Function(function) => { + let function = function.id.lookup(db.upcast()).id; + item_tree_source_maps = function.item_tree_with_source_map(db.upcast()).1; + item_tree_source_maps.function(function.value).item() + } + DefWithBody::Static(statik) => { + let statik = statik.id.lookup(db.upcast()).id; + item_tree_source_maps = statik.item_tree_with_source_map(db.upcast()).1; + item_tree_source_maps.statik(statik.value) + } + DefWithBody::Const(konst) => { + let konst = konst.id.lookup(db.upcast()).id; + item_tree_source_maps = konst.item_tree_with_source_map(db.upcast()).1; + item_tree_source_maps.konst(konst.value) + } + DefWithBody::Variant(_) | DefWithBody::InTypeConst(_) => &TypesSourceMap::EMPTY, + }; for (_, def_map) in body.blocks(db.upcast()) { Module { id: def_map.module_id(DefMap::ROOT) }.diagnostics(db, acc, style_lints); @@ -1860,7 +1953,13 @@ impl DefWithBody { let infer = db.infer(self.into()); for d in &infer.diagnostics { - acc.extend(AnyDiagnostic::inference_diagnostic(db, self.into(), d, &source_map)); + acc.extend(AnyDiagnostic::inference_diagnostic( + db, + self.into(), + d, + outer_types_source_map, + &source_map, + )); } for (pat_or_expr, mismatch) in infer.type_mismatches() { @@ -1890,10 +1989,10 @@ impl DefWithBody { ); } - let (unafe_exprs, only_lint) = hir_ty::diagnostics::missing_unsafe(db, self.into()); - for expr in unafe_exprs { - match source_map.expr_or_pat_syntax(expr) { - Ok(expr) => acc.push(MissingUnsafe { expr, only_lint }.into()), + let (unsafe_exprs, only_lint) = hir_ty::diagnostics::missing_unsafe(db, self.into()); + for (node, reason) in unsafe_exprs { + match source_map.expr_or_pat_syntax(node) { + Ok(node) => acc.push(MissingUnsafe { node, only_lint, reason }.into()), Err(SyntheticSyntax) => { // FIXME: Here and elsewhere in this file, the `expr` was // desugared, report or assert that this doesn't happen. @@ -3324,12 +3423,22 @@ impl AssocItem { ) { match self { AssocItem::Function(func) => { + GenericDef::Function(func).diagnostics(db, acc); DefWithBody::from(func).diagnostics(db, acc, style_lints); } AssocItem::Const(const_) => { DefWithBody::from(const_).diagnostics(db, acc, style_lints); } AssocItem::TypeAlias(type_alias) => { + GenericDef::TypeAlias(type_alias).diagnostics(db, acc); + let tree_id = type_alias.id.lookup(db.upcast()).id; + let tree_source_maps = tree_id.item_tree_with_source_map(db.upcast()).1; + push_ty_diagnostics( + db, + acc, + db.type_for_type_alias_with_diagnostics(type_alias.id).1, + tree_source_maps.type_alias(tree_id.value).item(), + ); for diag in hir_ty::diagnostics::incorrect_case(db, type_alias.id.into()) { acc.push(diag.into()); } @@ -3416,6 +3525,97 @@ impl GenericDef { }) .collect() } + + fn id(self) -> GenericDefId { + match self { + GenericDef::Function(it) => it.id.into(), + GenericDef::Adt(it) => it.into(), + GenericDef::Trait(it) => it.id.into(), + GenericDef::TraitAlias(it) => it.id.into(), + GenericDef::TypeAlias(it) => it.id.into(), + GenericDef::Impl(it) => it.id.into(), + GenericDef::Const(it) => it.id.into(), + } + } + + pub fn diagnostics(self, db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>) { + let def = self.id(); + + let item_tree_source_maps; + let (generics, generics_source_map) = db.generic_params_with_source_map(def); + + if generics.is_empty() && generics.no_predicates() { + return; + } + + let source_map = match &generics_source_map { + Some(it) => it, + None => match def { + GenericDefId::FunctionId(it) => { + let id = it.lookup(db.upcast()).id; + item_tree_source_maps = id.item_tree_with_source_map(db.upcast()).1; + item_tree_source_maps.function(id.value).generics() + } + GenericDefId::AdtId(AdtId::EnumId(it)) => { + let id = it.lookup(db.upcast()).id; + item_tree_source_maps = id.item_tree_with_source_map(db.upcast()).1; + item_tree_source_maps.enum_generic(id.value) + } + GenericDefId::AdtId(AdtId::StructId(it)) => { + let id = it.lookup(db.upcast()).id; + item_tree_source_maps = id.item_tree_with_source_map(db.upcast()).1; + item_tree_source_maps.strukt(id.value).generics() + } + GenericDefId::AdtId(AdtId::UnionId(it)) => { + let id = it.lookup(db.upcast()).id; + item_tree_source_maps = id.item_tree_with_source_map(db.upcast()).1; + item_tree_source_maps.union(id.value).generics() + } + GenericDefId::TraitId(it) => { + let id = it.lookup(db.upcast()).id; + item_tree_source_maps = id.item_tree_with_source_map(db.upcast()).1; + item_tree_source_maps.trait_generic(id.value) + } + GenericDefId::TraitAliasId(it) => { + let id = it.lookup(db.upcast()).id; + item_tree_source_maps = id.item_tree_with_source_map(db.upcast()).1; + item_tree_source_maps.trait_alias_generic(id.value) + } + GenericDefId::TypeAliasId(it) => { + let id = it.lookup(db.upcast()).id; + item_tree_source_maps = id.item_tree_with_source_map(db.upcast()).1; + item_tree_source_maps.type_alias(id.value).generics() + } + GenericDefId::ImplId(it) => { + let id = it.lookup(db.upcast()).id; + item_tree_source_maps = id.item_tree_with_source_map(db.upcast()).1; + item_tree_source_maps.impl_(id.value).generics() + } + GenericDefId::ConstId(_) => return, + }, + }; + + push_ty_diagnostics(db, acc, db.generic_defaults_with_diagnostics(def).1, source_map); + push_ty_diagnostics( + db, + acc, + db.generic_predicates_without_parent_with_diagnostics(def).1, + source_map, + ); + for (param_id, param) in generics.iter_type_or_consts() { + if let TypeOrConstParamData::ConstParamData(_) = param { + push_ty_diagnostics( + db, + acc, + db.const_param_ty_with_diagnostics(ConstParamId::from_unchecked( + TypeOrConstParamId { parent: def, local_id: param_id }, + )) + .1, + source_map, + ); + } + } + } } /// A single local definition. @@ -3581,6 +3781,18 @@ impl Local { } } +impl PartialOrd for Local { + fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> { + Some(self.cmp(other)) + } +} + +impl Ord for Local { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + self.binding_id.cmp(&other.binding_id) + } +} + #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub struct DeriveHelper { pub(crate) derive: MacroId, @@ -5799,3 +6011,19 @@ pub enum DocLinkDef { Field(Field), SelfType(Trait), } + +fn push_ty_diagnostics( + db: &dyn HirDatabase, + acc: &mut Vec<AnyDiagnostic>, + diagnostics: Option<ThinArc<(), TyLoweringDiagnostic>>, + source_map: &TypesSourceMap, +) { + if let Some(diagnostics) = diagnostics { + acc.extend( + diagnostics + .slice + .iter() + .filter_map(|diagnostic| AnyDiagnostic::ty_diagnostic(diagnostic, source_map, db)), + ); + } +} diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs index 9d3f8e5fba4..f9d3f9d07e6 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs @@ -34,7 +34,7 @@ use intern::Symbol; use itertools::Itertools; use rustc_hash::{FxHashMap, FxHashSet}; use smallvec::{smallvec, SmallVec}; -use span::{EditionedFileId, FileId, HirFileIdRepr, SyntaxContextId}; +use span::{AstIdMap, EditionedFileId, FileId, HirFileIdRepr, SyntaxContextId}; use stdx::TupleExt; use syntax::{ algo::skip_trivia_token, @@ -42,6 +42,7 @@ use syntax::{ AstNode, AstToken, Direction, SyntaxKind, SyntaxNode, SyntaxNodePtr, SyntaxToken, TextRange, TextSize, }; +use triomphe::Arc; use crate::{ db::HirDatabase, @@ -509,6 +510,22 @@ impl<'db> SemanticsImpl<'db> { self.with_ctx(|ctx| ctx.has_derives(adt)) } + pub fn derive_helpers_in_scope(&self, adt: &ast::Adt) -> Option<Vec<(Symbol, Symbol)>> { + let sa = self.analyze_no_infer(adt.syntax())?; + let id = self.db.ast_id_map(sa.file_id).ast_id(adt); + let result = sa + .resolver + .def_map() + .derive_helpers_in_scope(InFile::new(sa.file_id, id))? + .iter() + .map(|(name, macro_, _)| { + let macro_name = Macro::from(*macro_).name(self.db).symbol().clone(); + (name.symbol().clone(), macro_name) + }) + .collect(); + Some(result) + } + pub fn derive_helper(&self, attr: &ast::Attr) -> Option<Vec<(Macro, MacroFileId)>> { let adt = attr.syntax().ancestors().find_map(ast::Item::cast).and_then(|it| match it { ast::Item::Struct(it) => Some(ast::Adt::Struct(it)), @@ -1500,6 +1517,10 @@ impl<'db> SemanticsImpl<'db> { self.analyze(path.syntax())?.resolve_path(self.db, path) } + pub fn resolve_use_type_arg(&self, name: &ast::NameRef) -> Option<TypeParam> { + self.analyze(name.syntax())?.resolve_use_type_arg(name) + } + pub fn resolve_mod_path( &self, scope: &SyntaxNode, @@ -1973,10 +1994,16 @@ impl SemanticsScope<'_> { /// Resolve a path as-if it was written at the given scope. This is /// necessary a heuristic, as it doesn't take hygiene into account. pub fn speculative_resolve(&self, ast_path: &ast::Path) -> Option<PathResolution> { + let root = ast_path.syntax().ancestors().last().unwrap(); + let ast_id_map = Arc::new(AstIdMap::from_source(&root)); let (mut types_map, mut types_source_map) = (TypesMap::default(), TypesSourceMap::default()); - let mut ctx = - LowerCtx::new(self.db.upcast(), self.file_id, &mut types_map, &mut types_source_map); + let mut ctx = LowerCtx::for_synthetic_ast( + self.db.upcast(), + ast_id_map, + &mut types_map, + &mut types_source_map, + ); let path = Path::from_src(&mut ctx, ast_path.clone())?; resolve_hir_path( self.db, @@ -2003,6 +2030,10 @@ impl SemanticsScope<'_> { ) } + pub fn generic_def(&self) -> Option<crate::GenericDef> { + self.resolver.generic_def().map(|id| id.into()) + } + pub fn extern_crates(&self) -> impl Iterator<Item = (Name, Module)> + '_ { self.resolver.extern_crates_in_scope().map(|(name, id)| (name, Module { id })) } diff --git a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs index c16454cff68..4329a888b39 100644 --- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs +++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs @@ -36,7 +36,7 @@ use hir_expand::{ use hir_ty::{ diagnostics::{ record_literal_missing_fields, record_pattern_missing_fields, unsafe_expressions, - UnsafeExpr, + InsideUnsafeBlock, }, lang_items::lang_items_for_bin_op, method_resolution, Adjustment, InferenceResult, Interner, Substitution, Ty, TyExt, TyKind, @@ -642,6 +642,14 @@ impl SourceAnalyzer { } } + pub(crate) fn resolve_use_type_arg(&self, name: &ast::NameRef) -> Option<crate::TypeParam> { + let name = name.as_name(); + self.resolver + .all_generic_params() + .find_map(|(params, parent)| params.find_type_by_name(&name, *parent)) + .map(crate::TypeParam::from) + } + pub(crate) fn resolve_path( &self, db: &dyn HirDatabase, @@ -939,8 +947,8 @@ impl SourceAnalyzer { *def, body, expr_id, - &mut |UnsafeExpr { inside_unsafe_block, .. }| { - is_unsafe |= !inside_unsafe_block + &mut |_, inside_unsafe_block, _| { + is_unsafe |= inside_unsafe_block == InsideUnsafeBlock::No }, ) }; diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs index 7f8ea44fb12..57df39d541e 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs @@ -2318,4 +2318,49 @@ impl<'a> Test<'a, i32> for bool { "#, ); } + + #[test] + fn issue_17321() { + check_assist( + add_missing_impl_members, + r#" +fn main() {} + +mod other_file_1 { + pub const SOME_CONSTANT: usize = 8; +} + +mod other_file_2 { + use crate::other_file_1::SOME_CONSTANT; + + pub trait Trait { + type Iter: Iterator<Item = [u8; SOME_CONSTANT]>; + } +} + +pub struct MyStruct; + +impl other_file_2::Trait for MyStruct$0 {}"#, + r#" +fn main() {} + +mod other_file_1 { + pub const SOME_CONSTANT: usize = 8; +} + +mod other_file_2 { + use crate::other_file_1::SOME_CONSTANT; + + pub trait Trait { + type Iter: Iterator<Item = [u8; SOME_CONSTANT]>; + } +} + +pub struct MyStruct; + +impl other_file_2::Trait for MyStruct { + $0type Iter; +}"#, + ); + } } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_turbo_fish.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_turbo_fish.rs index 17efbcbd6c9..0f6970d9403 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_turbo_fish.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_turbo_fish.rs @@ -1,8 +1,9 @@ use either::Either; use ide_db::defs::{Definition, NameRefClass}; use syntax::{ - ast::{self, make, HasArgList, HasGenericArgs}, - ted, AstNode, + ast::{self, make, syntax_factory::SyntaxFactory, HasArgList, HasGenericArgs}, + syntax_editor::Position, + AstNode, }; use crate::{ @@ -91,20 +92,34 @@ pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti AssistId("add_type_ascription", AssistKind::RefactorRewrite), "Add `: _` before assignment operator", ident.text_range(), - |edit| { - let let_stmt = edit.make_mut(let_stmt); + |builder| { + let mut editor = builder.make_editor(let_stmt.syntax()); if let_stmt.semicolon_token().is_none() { - ted::append_child(let_stmt.syntax(), make::tokens::semicolon()); + editor.insert( + Position::last_child_of(let_stmt.syntax()), + make::tokens::semicolon(), + ); } let placeholder_ty = make::ty_placeholder().clone_for_update(); - let_stmt.set_ty(Some(placeholder_ty.clone())); - - if let Some(cap) = ctx.config.snippet_cap { - edit.add_placeholder_snippet(cap, placeholder_ty); + if let Some(pat) = let_stmt.pat() { + let elements = vec![ + make::token(syntax::SyntaxKind::COLON).into(), + make::token(syntax::SyntaxKind::WHITESPACE).into(), + placeholder_ty.syntax().clone().into(), + ]; + editor.insert_all(Position::after(pat.syntax()), elements); + if let Some(cap) = ctx.config.snippet_cap { + editor.add_annotation( + placeholder_ty.syntax(), + builder.make_placeholder_snippet(cap), + ); + } } + + builder.add_file_edits(ctx.file_id(), editor); }, )? } else { @@ -123,38 +138,58 @@ pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti AssistId("add_turbo_fish", AssistKind::RefactorRewrite), "Add `::<>`", ident.text_range(), - |edit| { - edit.trigger_parameter_hints(); + |builder| { + builder.trigger_parameter_hints(); + + let make = SyntaxFactory::new(); + let mut editor = match &turbofish_target { + Either::Left(it) => builder.make_editor(it.syntax()), + Either::Right(it) => builder.make_editor(it.syntax()), + }; + + let fish_head = get_fish_head(&make, number_of_arguments); - let new_arg_list = match turbofish_target { + match turbofish_target { Either::Left(path_segment) => { - edit.make_mut(path_segment).get_or_create_generic_arg_list() + if let Some(generic_arg_list) = path_segment.generic_arg_list() { + editor.replace(generic_arg_list.syntax(), fish_head.syntax()); + } else { + editor.insert( + Position::last_child_of(path_segment.syntax()), + fish_head.syntax(), + ); + } } Either::Right(method_call) => { - edit.make_mut(method_call).get_or_create_generic_arg_list() + if let Some(generic_arg_list) = method_call.generic_arg_list() { + editor.replace(generic_arg_list.syntax(), fish_head.syntax()); + } else { + let position = if let Some(arg_list) = method_call.arg_list() { + Position::before(arg_list.syntax()) + } else { + Position::last_child_of(method_call.syntax()) + }; + editor.insert(position, fish_head.syntax()); + } } }; - let fish_head = get_fish_head(number_of_arguments).clone_for_update(); - - // Note: we need to replace the `new_arg_list` instead of being able to use something like - // `GenericArgList::add_generic_arg` as `PathSegment::get_or_create_generic_arg_list` - // always creates a non-turbofish form generic arg list. - ted::replace(new_arg_list.syntax(), fish_head.syntax()); - if let Some(cap) = ctx.config.snippet_cap { for arg in fish_head.generic_args() { - edit.add_placeholder_snippet(cap, arg) + editor.add_annotation(arg.syntax(), builder.make_placeholder_snippet(cap)); } } + + editor.add_mappings(make.finish_with_mappings()); + builder.add_file_edits(ctx.file_id(), editor); }, ) } /// This will create a turbofish generic arg list corresponding to the number of arguments -fn get_fish_head(number_of_arguments: usize) -> ast::GenericArgList { +fn get_fish_head(make: &SyntaxFactory, number_of_arguments: usize) -> ast::GenericArgList { let args = (0..number_of_arguments).map(|_| make::type_arg(make::ty_placeholder()).into()); - make::turbofish_generic_arg_list(args) + make.turbofish_generic_arg_list(args) } #[cfg(test)] diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bool_to_enum.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bool_to_enum.rs index 605fd140523..f699899066b 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bool_to_enum.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bool_to_enum.rs @@ -512,9 +512,11 @@ fn make_bool_enum(make_pub: bool) -> ast::Enum { let enum_def = make::enum_( if make_pub { Some(make::visibility_pub()) } else { None }, make::name("Bool"), + None, + None, make::variant_list(vec![ - make::variant(make::name("True"), None), - make::variant(make::name("False"), None), + make::variant(None, make::name("True"), None, None), + make::variant(None, make::name("False"), None, None), ]), ) .clone_for_update(); diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs index ad0be896450..6937d33ebc1 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs @@ -18,6 +18,7 @@ use ide_db::{ }, FxIndexSet, RootDatabase, }; +use itertools::Itertools; use syntax::{ ast::{ self, edit::IndentLevel, edit_in_place::Indent, AstNode, AstToken, HasGenericParams, @@ -114,8 +115,7 @@ pub(crate) fn extract_function(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op return; } - let params = - body.extracted_function_params(ctx, &container_info, locals_used.iter().copied()); + let params = body.extracted_function_params(ctx, &container_info, locals_used); let name = make_function_name(&semantics_scope); @@ -1067,9 +1067,11 @@ impl FunctionBody { &self, ctx: &AssistContext<'_>, container_info: &ContainerInfo, - locals: impl Iterator<Item = Local>, + locals: FxIndexSet<Local>, ) -> Vec<Param> { locals + .into_iter() + .sorted() .map(|local| (local, local.primary_source(ctx.db()))) .filter(|(_, src)| is_defined_outside_of_body(ctx, self, src)) .filter_map(|(local, src)| match src.into_ident_pat() { @@ -3167,11 +3169,11 @@ fn foo() { let mut c = C { p: P { n: 0 } }; let mut v = C { p: P { n: 0 } }; let u = C { p: P { n: 0 } }; - fun_name(&mut c, &u, &mut v); + fun_name(&mut c, &mut v, &u); let m = c.p.n + v.p.n + u.p.n; } -fn $0fun_name(c: &mut C, u: &C, v: &mut C) { +fn $0fun_name(c: &mut C, v: &mut C, u: &C) { c.p.n += u.p.n; let r = &mut v.p.n; } @@ -5602,10 +5604,10 @@ fn parent(factor: i32) { fn parent(factor: i32) { let v = &[1, 2, 3]; - fun_name(v, factor); + fun_name(factor, v); } -fn $0fun_name(v: &[i32; 3], factor: i32) { +fn $0fun_name(factor: i32, v: &[i32; 3]) { v.iter().map(|it| it * factor); } "#, @@ -5786,11 +5788,11 @@ struct Struct<T: Into<i32>>(T); impl <T: Into<i32> + Copy> Struct<T> { fn func<V: Into<i32>>(&self, v: V) -> i32 { let t = self.0; - fun_name(t, v) + fun_name(v, t) } } -fn $0fun_name<T: Into<i32> + Copy, V: Into<i32>>(t: T, v: V) -> i32 { +fn $0fun_name<T: Into<i32> + Copy, V: Into<i32>>(v: V, t: T) -> i32 { t.into() + v.into() } "#, @@ -5815,11 +5817,11 @@ struct Struct<T: Into<i32>, U: Debug>(T, U); impl <T: Into<i32> + Copy, U: Debug> Struct<T, U> { fn func<V: Into<i32>>(&self, v: V) -> i32 { let t = self.0; - fun_name(t, v) + fun_name(v, t) } } -fn $0fun_name<T: Into<i32> + Copy, V: Into<i32>>(t: T, v: V) -> i32 { +fn $0fun_name<T: Into<i32> + Copy, V: Into<i32>>(v: V, t: T) -> i32 { t.into() + v.into() } "#, @@ -5844,11 +5846,11 @@ struct Struct<T>(T) where T: Into<i32>; impl <T> Struct<T> where T: Into<i32> + Copy { fn func<V>(&self, v: V) -> i32 where V: Into<i32> { let t = self.0; - fun_name(t, v) + fun_name(v, t) } } -fn $0fun_name<T, V>(t: T, v: V) -> i32 where T: Into<i32> + Copy, V: Into<i32> { +fn $0fun_name<T, V>(v: V, t: T) -> i32 where T: Into<i32> + Copy, V: Into<i32> { t.into() + v.into() } "#, @@ -5873,11 +5875,11 @@ struct Struct<T, U>(T, U) where T: Into<i32>, U: Debug; impl <T, U> Struct<T, U> where T: Into<i32> + Copy, U: Debug { fn func<V>(&self, v: V) -> i32 where V: Into<i32> { let t = self.0; - fun_name(t, v) + fun_name(v, t) } } -fn $0fun_name<T, V>(t: T, v: V) -> i32 where T: Into<i32> + Copy, V: Into<i32> { +fn $0fun_name<T, V>(v: V, t: T) -> i32 where T: Into<i32> + Copy, V: Into<i32> { t.into() + v.into() } "#, @@ -6107,6 +6109,31 @@ fn $0fun_name() -> i32 { } #[test] + fn sort_params_in_order() { + check_assist( + extract_function, + r#" +fn existing(a: i32, b: i32, c: i32) { + let x = 32; + + let p = $0x + b + c + a$0; +} +"#, + r#" +fn existing(a: i32, b: i32, c: i32) { + let x = 32; + + let p = fun_name(a, b, c, x); +} + +fn $0fun_name(a: i32, b: i32, c: i32, x: i32) -> i32 { + x + b + c + a +} +"#, + ); + } + + #[test] fn in_left_curly_is_not_applicable() { cov_mark::check!(extract_function_in_braces_is_not_applicable); check_assist_not_applicable(extract_function, r"fn foo() { $0}$0"); diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_binexpr.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_binexpr.rs index 8b46a23f9a6..818a868fe34 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_binexpr.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_binexpr.rs @@ -1,4 +1,7 @@ -use syntax::ast::{self, AstNode, BinExpr}; +use syntax::{ + ast::{self, syntax_factory::SyntaxFactory, AstNode, BinExpr}, + SyntaxKind, T, +}; use crate::{AssistContext, AssistId, AssistKind, Assists}; @@ -19,22 +22,17 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; // ``` pub(crate) fn flip_binexpr(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { let expr = ctx.find_node_at_offset::<BinExpr>()?; - let rhs = expr.rhs()?.syntax().clone(); - let lhs = expr.lhs()?.syntax().clone(); - - let lhs = if let Some(bin_expr) = BinExpr::cast(lhs.clone()) { - if bin_expr.op_kind() == expr.op_kind() { - bin_expr.rhs()?.syntax().clone() - } else { - lhs - } - } else { - lhs + let lhs = expr.lhs()?; + let rhs = expr.rhs()?; + + let lhs = match &lhs { + ast::Expr::BinExpr(bin_expr) if bin_expr.op_kind() == expr.op_kind() => bin_expr.rhs()?, + _ => lhs, }; - let op_range = expr.op_token()?.text_range(); + let op_token = expr.op_token()?; // The assist should be applied only if the cursor is on the operator - let cursor_in_range = op_range.contains_range(ctx.selection_trimmed()); + let cursor_in_range = op_token.text_range().contains_range(ctx.selection_trimmed()); if !cursor_in_range { return None; } @@ -47,13 +45,17 @@ pub(crate) fn flip_binexpr(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option acc.add( AssistId("flip_binexpr", AssistKind::RefactorRewrite), "Flip binary expression", - op_range, - |edit| { - if let FlipAction::FlipAndReplaceOp(new_op) = action { - edit.replace(op_range, new_op); - } - edit.replace(lhs.text_range(), rhs.text()); - edit.replace(rhs.text_range(), lhs.text()); + op_token.text_range(), + |builder| { + let mut editor = builder.make_editor(&expr.syntax().parent().unwrap()); + let make = SyntaxFactory::new(); + if let FlipAction::FlipAndReplaceOp(binary_op) = action { + editor.replace(op_token, make.token(binary_op)) + }; + editor.replace(lhs.syntax(), rhs.syntax()); + editor.replace(rhs.syntax(), lhs.syntax()); + editor.add_mappings(make.finish_with_mappings()); + builder.add_file_edits(ctx.file_id(), editor); }, ) } @@ -62,7 +64,7 @@ enum FlipAction { // Flip the expression Flip, // Flip the expression and replace the operator with this string - FlipAndReplaceOp(&'static str), + FlipAndReplaceOp(SyntaxKind), // Do not flip the expression DontFlip, } @@ -73,10 +75,10 @@ impl From<ast::BinaryOp> for FlipAction { ast::BinaryOp::Assignment { .. } => FlipAction::DontFlip, ast::BinaryOp::CmpOp(ast::CmpOp::Ord { ordering, strict }) => { let rev_op = match (ordering, strict) { - (ast::Ordering::Less, true) => ">", - (ast::Ordering::Less, false) => ">=", - (ast::Ordering::Greater, true) => "<", - (ast::Ordering::Greater, false) => "<=", + (ast::Ordering::Less, true) => T![>], + (ast::Ordering::Less, false) => T![>=], + (ast::Ordering::Greater, true) => T![<], + (ast::Ordering::Greater, false) => T![<=], }; FlipAction::FlipAndReplaceOp(rev_op) } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_comma.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_comma.rs index af2c2c759ec..95e035c0537 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_comma.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_comma.rs @@ -1,7 +1,8 @@ -use ide_db::base_db::SourceDatabase; -use syntax::TextSize; use syntax::{ - algo::non_trivia_sibling, ast, AstNode, Direction, SyntaxKind, SyntaxToken, TextRange, T, + algo::non_trivia_sibling, + ast::{self, syntax_factory::SyntaxFactory}, + syntax_editor::{Element, SyntaxMapping}, + AstNode, Direction, NodeOrToken, SyntaxElement, SyntaxKind, SyntaxToken, T, }; use crate::{AssistContext, AssistId, AssistKind, Assists}; @@ -25,8 +26,6 @@ pub(crate) fn flip_comma(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<( let comma = ctx.find_token_syntax_at_offset(T![,])?; let prev = non_trivia_sibling(comma.clone().into(), Direction::Prev)?; let next = non_trivia_sibling(comma.clone().into(), Direction::Next)?; - let (mut prev_text, mut next_text) = (prev.to_string(), next.to_string()); - let (mut prev_range, mut next_range) = (prev.text_range(), next.text_range()); // Don't apply a "flip" in case of a last comma // that typically comes before punctuation @@ -40,53 +39,84 @@ pub(crate) fn flip_comma(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<( return None; } - if let Some(parent) = comma.parent().and_then(ast::TokenTree::cast) { - // An attribute. It often contains a path followed by a token tree (e.g. `align(2)`), so we have - // to be smarter. - let prev_start = - match comma.siblings_with_tokens(Direction::Prev).skip(1).find(|it| it.kind() == T![,]) - { - Some(it) => position_after_token(it.as_token().unwrap()), - None => position_after_token(&parent.left_delimiter_token()?), - }; - let prev_end = prev.text_range().end(); - let next_start = next.text_range().start(); - let next_end = - match comma.siblings_with_tokens(Direction::Next).skip(1).find(|it| it.kind() == T![,]) - { - Some(it) => position_before_token(it.as_token().unwrap()), - None => position_before_token(&parent.right_delimiter_token()?), - }; - prev_range = TextRange::new(prev_start, prev_end); - next_range = TextRange::new(next_start, next_end); - let file_text = ctx.db().file_text(ctx.file_id().file_id()); - prev_text = file_text[prev_range].to_owned(); - next_text = file_text[next_range].to_owned(); - } + let prev = match prev { + SyntaxElement::Node(node) => node.syntax_element(), + _ => prev, + }; + let next = match next { + SyntaxElement::Node(node) => node.syntax_element(), + _ => next, + }; acc.add( AssistId("flip_comma", AssistKind::RefactorRewrite), "Flip comma", comma.text_range(), - |edit| { - edit.replace(prev_range, next_text); - edit.replace(next_range, prev_text); + |builder| { + let parent = comma.parent().unwrap(); + let mut editor = builder.make_editor(&parent); + + if let Some(parent) = ast::TokenTree::cast(parent) { + // An attribute. It often contains a path followed by a + // token tree (e.g. `align(2)`), so we have to be smarter. + let (new_tree, mapping) = flip_tree(parent.clone(), comma); + editor.replace(parent.syntax(), new_tree.syntax()); + editor.add_mappings(mapping); + } else { + editor.replace(prev.clone(), next.clone()); + editor.replace(next.clone(), prev.clone()); + } + + builder.add_file_edits(ctx.file_id(), editor); }, ) } -fn position_before_token(token: &SyntaxToken) -> TextSize { - match non_trivia_sibling(token.clone().into(), Direction::Prev) { - Some(prev_token) => prev_token.text_range().end(), - None => token.text_range().start(), - } -} - -fn position_after_token(token: &SyntaxToken) -> TextSize { - match non_trivia_sibling(token.clone().into(), Direction::Next) { - Some(prev_token) => prev_token.text_range().start(), - None => token.text_range().end(), - } +fn flip_tree(tree: ast::TokenTree, comma: SyntaxToken) -> (ast::TokenTree, SyntaxMapping) { + let mut tree_iter = tree.token_trees_and_tokens(); + let before: Vec<_> = + tree_iter.by_ref().take_while(|it| it.as_token() != Some(&comma)).collect(); + let after: Vec<_> = tree_iter.collect(); + + let not_ws = |element: &NodeOrToken<_, SyntaxToken>| match element { + NodeOrToken::Token(token) => token.kind() != SyntaxKind::WHITESPACE, + NodeOrToken::Node(_) => true, + }; + + let is_comma = |element: &NodeOrToken<_, SyntaxToken>| match element { + NodeOrToken::Token(token) => token.kind() == T![,], + NodeOrToken::Node(_) => false, + }; + + let prev_start_untrimmed = match before.iter().rposition(is_comma) { + Some(pos) => pos + 1, + None => 1, + }; + let prev_end = 1 + before.iter().rposition(not_ws).unwrap(); + let prev_start = prev_start_untrimmed + + before[prev_start_untrimmed..prev_end].iter().position(not_ws).unwrap(); + + let next_start = after.iter().position(not_ws).unwrap(); + let next_end_untrimmed = match after.iter().position(is_comma) { + Some(pos) => pos, + None => after.len() - 1, + }; + let next_end = 1 + after[..next_end_untrimmed].iter().rposition(not_ws).unwrap(); + + let result = [ + &before[1..prev_start], + &after[next_start..next_end], + &before[prev_end..], + &[NodeOrToken::Token(comma)], + &after[..next_start], + &before[prev_start..prev_end], + &after[next_end..after.len() - 1], + ] + .concat(); + + let make = SyntaxFactory::new(); + let new_token_tree = make.token_tree(tree.left_delimiter_token().unwrap().kind(), result); + (new_token_tree, make.finish_with_mappings()) } #[cfg(test)] @@ -147,4 +177,9 @@ mod tests { r#"#[foo(bar, qux, baz(1 + 1), other)] struct Foo;"#, ); } + + #[test] + fn flip_comma_attribute_incomplete() { + check_assist_not_applicable(flip_comma, r#"#[repr(align(2),$0)] struct Foo;"#); + } } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_trait_bound.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_trait_bound.rs index 70b5efcb645..298e5bd82c9 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_trait_bound.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_trait_bound.rs @@ -23,11 +23,11 @@ pub(crate) fn flip_trait_bound(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op let plus = ctx.find_token_syntax_at_offset(T![+])?; // Make sure we're in a `TypeBoundList` - ast::TypeBoundList::cast(plus.parent()?)?; + let parent = ast::TypeBoundList::cast(plus.parent()?)?; let (before, after) = ( - non_trivia_sibling(plus.clone().into(), Direction::Prev)?, - non_trivia_sibling(plus.clone().into(), Direction::Next)?, + non_trivia_sibling(plus.clone().into(), Direction::Prev)?.into_node()?, + non_trivia_sibling(plus.clone().into(), Direction::Next)?.into_node()?, ); let target = plus.text_range(); @@ -35,9 +35,11 @@ pub(crate) fn flip_trait_bound(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op AssistId("flip_trait_bound", AssistKind::RefactorRewrite), "Flip trait bounds", target, - |edit| { - edit.replace(before.text_range(), after.to_string()); - edit.replace(after.text_range(), before.to_string()); + |builder| { + let mut editor = builder.make_editor(parent.syntax()); + editor.replace(before.clone(), after.clone()); + editor.replace(after, before); + builder.add_file_edits(ctx.file_id(), editor); }, ) } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_documentation_template.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_documentation_template.rs index c5c70c9f8eb..862be791d17 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_documentation_template.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_documentation_template.rs @@ -88,7 +88,7 @@ pub(crate) fn generate_documentation_template( // /// # Examples // /// // /// ``` -// /// use test::add; +// /// use ra_test_fixture::add; // /// // /// assert_eq!(add(a, b), ); // /// ``` @@ -596,7 +596,7 @@ pub fn noop_with_param(_a: i32) {} /// # Examples /// /// ``` -/// use test::noop_with_param; +/// use ra_test_fixture::noop_with_param; /// /// noop_with_param(_a); /// ``` @@ -641,7 +641,7 @@ pub unsafe fn noop_unsafe() {} /// # Examples /// /// ``` -/// use test::noop_unsafe; +/// use ra_test_fixture::noop_unsafe; /// /// unsafe { noop_unsafe() }; /// ``` @@ -758,7 +758,7 @@ pub fn returns_a_value$0() -> i32 { /// # Examples /// /// ``` -/// use test::returns_a_value; +/// use ra_test_fixture::returns_a_value; /// /// assert_eq!(returns_a_value(), ); /// ``` @@ -807,7 +807,7 @@ pub fn modifies_a_value$0(a: &mut i32) { /// # Examples /// /// ``` -/// use test::modifies_a_value; +/// use ra_test_fixture::modifies_a_value; /// /// let mut a = ; /// modifies_a_value(&mut a); @@ -836,7 +836,7 @@ pub fn sum3$0(a: i32, b: i32, c: i32) -> i32 { /// # Examples /// /// ``` -/// use test::sum3; +/// use ra_test_fixture::sum3; /// /// let result = sum3(a, b, c); /// assert_eq!(result, ); @@ -868,7 +868,7 @@ pub mod a { /// # Examples /// /// ``` - /// use test::a::b::noop; + /// use ra_test_fixture::a::b::noop; /// /// noop(); /// ``` @@ -898,7 +898,7 @@ impl MyStruct { /// # Examples /// /// ``` - /// use test::MyStruct; + /// use ra_test_fixture::MyStruct; /// /// MyStruct::noop(); /// ``` @@ -1169,7 +1169,7 @@ impl<T> MyGenericStruct<T> { /// # Examples /// /// ``` - /// use test::MyGenericStruct; + /// use ra_test_fixture::MyGenericStruct; /// /// let my_generic_struct = ; /// my_generic_struct.consume(); @@ -1199,7 +1199,7 @@ impl<T> MyGenericStruct<T> { /// # Examples /// /// ``` - /// use test::MyGenericStruct; + /// use ra_test_fixture::MyGenericStruct; /// /// let mut my_generic_struct = ; /// my_generic_struct.modify(new_value); diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_variant.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_variant.rs index 5d584591210..bb08cb904ea 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_variant.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_variant.rs @@ -1,7 +1,7 @@ use hir::{HasSource, HirDisplay, InRealFile}; use ide_db::assists::{AssistId, AssistKind}; use syntax::{ - ast::{self, make, HasArgList}, + ast::{self, syntax_factory::SyntaxFactory, HasArgList}, match_ast, AstNode, SyntaxNode, }; @@ -33,7 +33,7 @@ use crate::assist_context::{AssistContext, Assists}; // ``` pub(crate) fn generate_enum_variant(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { let path: ast::Path = ctx.find_node_at_offset()?; - let parent = path_parent(&path)?; + let parent = PathParent::new(&path)?; if ctx.sema.resolve_path(&path).is_some() { // No need to generate anything if the path resolves @@ -46,14 +46,32 @@ pub(crate) fn generate_enum_variant(acc: &mut Assists, ctx: &AssistContext<'_>) return None; } - if let Some(hir::PathResolution::Def(hir::ModuleDef::Adt(hir::Adt::Enum(e)))) = + let Some(hir::PathResolution::Def(hir::ModuleDef::Adt(hir::Adt::Enum(e)))) = ctx.sema.resolve_path(&path.qualifier()?) - { - let target = path.syntax().text_range(); - return add_variant_to_accumulator(acc, ctx, target, e, &name_ref, parent); - } + else { + return None; + }; - None + let target = path.syntax().text_range(); + let name_ref: &ast::NameRef = &name_ref; + let db = ctx.db(); + let InRealFile { file_id, value: enum_node } = e.source(db)?.original_ast_node_rooted(db)?; + + acc.add( + AssistId("generate_enum_variant", AssistKind::Generate), + "Generate variant", + target, + |builder| { + let mut editor = builder.make_editor(enum_node.syntax()); + let make = SyntaxFactory::new(); + let field_list = parent.make_field_list(ctx, &make); + let variant = make.variant(None, make.name(&name_ref.text()), field_list, None); + if let Some(it) = enum_node.variant_list() { + it.add_variant(&mut editor, &variant); + } + builder.add_file_edits(file_id, editor); + }, + ) } #[derive(Debug)] @@ -65,6 +83,20 @@ enum PathParent { } impl PathParent { + fn new(path: &ast::Path) -> Option<Self> { + let parent = path.syntax().parent()?; + + match_ast! { + match parent { + ast::PathExpr(it) => Some(PathParent::PathExpr(it)), + ast::RecordExpr(it) => Some(PathParent::RecordExpr(it)), + ast::PathPat(it) => Some(PathParent::PathPat(it)), + ast::UseTree(it) => Some(PathParent::UseTree(it)), + _ => None + } + } + } + fn syntax(&self) -> &SyntaxNode { match self { PathParent::PathExpr(it) => it.syntax(), @@ -74,97 +106,49 @@ impl PathParent { } } - fn make_field_list(&self, ctx: &AssistContext<'_>) -> Option<ast::FieldList> { + fn make_field_list( + &self, + ctx: &AssistContext<'_>, + make: &SyntaxFactory, + ) -> Option<ast::FieldList> { let scope = ctx.sema.scope(self.syntax())?; match self { PathParent::PathExpr(it) => { - if let Some(call_expr) = it.syntax().parent().and_then(ast::CallExpr::cast) { - make_tuple_field_list(call_expr, ctx, &scope) - } else { - None - } + let call_expr = ast::CallExpr::cast(it.syntax().parent()?)?; + let args = call_expr.arg_list()?.args(); + let tuple_fields = args.map(|arg| { + let ty = + expr_ty(ctx, make, arg, &scope).unwrap_or_else(|| make.ty_infer().into()); + make.tuple_field(None, ty) + }); + Some(make.tuple_field_list(tuple_fields).into()) + } + PathParent::RecordExpr(it) => { + let fields = it.record_expr_field_list()?.fields(); + let record_fields = fields.map(|field| { + let name = name_from_field(make, &field); + + let ty = field + .expr() + .and_then(|it| expr_ty(ctx, make, it, &scope)) + .unwrap_or_else(|| make.ty_infer().into()); + + make.record_field(None, name, ty) + }); + Some(make.record_field_list(record_fields).into()) } - PathParent::RecordExpr(it) => make_record_field_list(it, ctx, &scope), PathParent::UseTree(_) | PathParent::PathPat(_) => None, } } } -fn path_parent(path: &ast::Path) -> Option<PathParent> { - let parent = path.syntax().parent()?; - - match_ast! { - match parent { - ast::PathExpr(it) => Some(PathParent::PathExpr(it)), - ast::RecordExpr(it) => Some(PathParent::RecordExpr(it)), - ast::PathPat(it) => Some(PathParent::PathPat(it)), - ast::UseTree(it) => Some(PathParent::UseTree(it)), - _ => None - } - } -} - -fn add_variant_to_accumulator( - acc: &mut Assists, - ctx: &AssistContext<'_>, - target: syntax::TextRange, - adt: hir::Enum, - name_ref: &ast::NameRef, - parent: PathParent, -) -> Option<()> { - let db = ctx.db(); - let InRealFile { file_id, value: enum_node } = adt.source(db)?.original_ast_node_rooted(db)?; - - acc.add( - AssistId("generate_enum_variant", AssistKind::Generate), - "Generate variant", - target, - |builder| { - builder.edit_file(file_id.file_id()); - let node = builder.make_mut(enum_node); - let variant = make_variant(ctx, name_ref, parent); - if let Some(it) = node.variant_list() { - it.add_variant(variant.clone_for_update()) - } - }, - ) -} - -fn make_variant( - ctx: &AssistContext<'_>, - name_ref: &ast::NameRef, - parent: PathParent, -) -> ast::Variant { - let field_list = parent.make_field_list(ctx); - make::variant(make::name(&name_ref.text()), field_list) -} - -fn make_record_field_list( - record: &ast::RecordExpr, - ctx: &AssistContext<'_>, - scope: &hir::SemanticsScope<'_>, -) -> Option<ast::FieldList> { - let fields = record.record_expr_field_list()?.fields(); - let record_fields = fields.map(|field| { - let name = name_from_field(&field); - - let ty = field - .expr() - .and_then(|it| expr_ty(ctx, it, scope)) - .unwrap_or_else(make::ty_placeholder); - - make::record_field(None, name, ty) - }); - Some(make::record_field_list(record_fields).into()) -} - -fn name_from_field(field: &ast::RecordExprField) -> ast::Name { +fn name_from_field(make: &SyntaxFactory, field: &ast::RecordExprField) -> ast::Name { let text = match field.name_ref() { Some(it) => it.to_string(), None => name_from_field_shorthand(field).unwrap_or("unknown".to_owned()), }; - make::name(&text) + make.name(&text) } fn name_from_field_shorthand(field: &ast::RecordExprField) -> Option<String> { @@ -175,27 +159,15 @@ fn name_from_field_shorthand(field: &ast::RecordExprField) -> Option<String> { Some(path.as_single_name_ref()?.to_string()) } -fn make_tuple_field_list( - call_expr: ast::CallExpr, - ctx: &AssistContext<'_>, - scope: &hir::SemanticsScope<'_>, -) -> Option<ast::FieldList> { - let args = call_expr.arg_list()?.args(); - let tuple_fields = args.map(|arg| { - let ty = expr_ty(ctx, arg, scope).unwrap_or_else(make::ty_placeholder); - make::tuple_field(None, ty) - }); - Some(make::tuple_field_list(tuple_fields).into()) -} - fn expr_ty( ctx: &AssistContext<'_>, + make: &SyntaxFactory, arg: ast::Expr, scope: &hir::SemanticsScope<'_>, ) -> Option<ast::Type> { let ty = ctx.sema.type_of_expr(&arg).map(|it| it.adjusted())?; let text = ty.display_source_code(ctx.db(), scope.module().into(), false).ok()?; - Some(make::ty(&text)) + Some(make.ty(&text)) } #[cfg(test)] diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs index bf6ac1719f3..8c276415bb1 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_generic.rs @@ -1,9 +1,6 @@ use ide_db::syntax_helpers::suggest_name; use itertools::Itertools; -use syntax::{ - ast::{self, edit_in_place::GenericParamsOwnerEdit, make, AstNode, HasGenericParams, HasName}, - ted, -}; +use syntax::ast::{self, syntax_factory::SyntaxFactory, AstNode, HasGenericParams, HasName}; use crate::{AssistContext, AssistId, AssistKind, Assists}; @@ -25,42 +22,42 @@ pub(crate) fn introduce_named_generic(acc: &mut Assists, ctx: &AssistContext<'_> let type_bound_list = impl_trait_type.type_bound_list()?; + let make = SyntaxFactory::new(); let target = fn_.syntax().text_range(); acc.add( AssistId("introduce_named_generic", AssistKind::RefactorRewrite), "Replace impl trait with generic", target, - |edit| { - let impl_trait_type = edit.make_mut(impl_trait_type); - let fn_ = edit.make_mut(fn_); - let fn_generic_param_list = fn_.get_or_create_generic_param_list(); - - let existing_names = fn_generic_param_list - .generic_params() - .flat_map(|param| match param { - ast::GenericParam::TypeParam(t) => t.name().map(|name| name.to_string()), - p => Some(p.to_string()), - }) - .collect_vec(); + |builder| { + let mut editor = builder.make_editor(fn_.syntax()); + + let existing_names = match fn_.generic_param_list() { + Some(generic_param_list) => generic_param_list + .generic_params() + .flat_map(|param| match param { + ast::GenericParam::TypeParam(t) => t.name().map(|name| name.to_string()), + p => Some(p.to_string()), + }) + .collect_vec(), + None => Vec::new(), + }; let type_param_name = suggest_name::NameGenerator::new_with_names( existing_names.iter().map(|s| s.as_str()), ) .for_impl_trait_as_generic(&impl_trait_type); - let type_param = make::type_param(make::name(&type_param_name), Some(type_bound_list)) - .clone_for_update(); - let new_ty = make::ty(&type_param_name).clone_for_update(); + let type_param = make.type_param(make.name(&type_param_name), Some(type_bound_list)); + let new_ty = make.ty(&type_param_name); - ted::replace(impl_trait_type.syntax(), new_ty.syntax()); - fn_generic_param_list.add_generic_param(type_param.into()); + editor.replace(impl_trait_type.syntax(), new_ty.syntax()); + editor.add_generic_param(&fn_, type_param.clone().into()); if let Some(cap) = ctx.config.snippet_cap { - if let Some(generic_param) = - fn_.generic_param_list().and_then(|it| it.generic_params().last()) - { - edit.add_tabstop_before(cap, generic_param); - } + editor.add_annotation(type_param.syntax(), builder.make_tabstop_before(cap)); } + + editor.add_mappings(make.finish_with_mappings()); + builder.add_file_edits(ctx.file_id(), editor); }, ) } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_fields.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_fields.rs index 4d3e85ab1b2..972303c2a04 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_fields.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_fields.rs @@ -92,10 +92,9 @@ fn replace<T: AstNode + PartialEq>( fields: impl Iterator<Item = T>, sorted_fields: impl IntoIterator<Item = T>, ) { - fields.zip(sorted_fields).for_each(|(field, sorted_field)| { - // FIXME: remove `clone_for_update` when `SyntaxEditor` handles it for us - editor.replace(field.syntax(), sorted_field.syntax().clone_for_update()) - }); + fields + .zip(sorted_fields) + .for_each(|(field, sorted_field)| editor.replace(field.syntax(), sorted_field.syntax())); } fn compute_fields_ranks( diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_impl_items.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_impl_items.rs index d7fa8826125..eb1d538f874 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_impl_items.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_impl_items.rs @@ -101,10 +101,10 @@ pub(crate) fn reorder_impl_items(acc: &mut Assists, ctx: &AssistContext<'_>) -> |builder| { let mut editor = builder.make_editor(&parent_node); - assoc_items.into_iter().zip(sorted).for_each(|(old, new)| { - // FIXME: remove `clone_for_update` when `SyntaxEditor` handles it for us - editor.replace(old.syntax(), new.clone_for_update().syntax()) - }); + assoc_items + .into_iter() + .zip(sorted) + .for_each(|(old, new)| editor.replace(old.syntax(), new.syntax())); builder.add_file_edits(ctx.file_id(), editor); }, diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/sort_items.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/sort_items.rs index 64e30b18345..54e16d4d80a 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/sort_items.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/sort_items.rs @@ -4,7 +4,7 @@ use itertools::Itertools; use syntax::{ ast::{self, HasName}, - ted, AstNode, TextRange, + AstNode, SyntaxNode, }; use crate::{utils::get_methods, AssistContext, AssistId, AssistKind, Assists}; @@ -114,7 +114,7 @@ trait AddRewrite { label: &str, old: Vec<T>, new: Vec<T>, - target: TextRange, + target: &SyntaxNode, ) -> Option<()>; } @@ -124,15 +124,22 @@ impl AddRewrite for Assists { label: &str, old: Vec<T>, new: Vec<T>, - target: TextRange, + target: &SyntaxNode, ) -> Option<()> { - self.add(AssistId("sort_items", AssistKind::RefactorRewrite), label, target, |builder| { - let mutable: Vec<T> = old.into_iter().map(|it| builder.make_mut(it)).collect(); - mutable - .into_iter() - .zip(new) - .for_each(|(old, new)| ted::replace(old.syntax(), new.clone_for_update().syntax())); - }) + self.add( + AssistId("sort_items", AssistKind::RefactorRewrite), + label, + target.text_range(), + |builder| { + let mut editor = builder.make_editor(target); + + old.into_iter() + .zip(new) + .for_each(|(old, new)| editor.replace(old.syntax(), new.syntax())); + + builder.add_file_edits(builder.file_id, editor) + }, + ) } } @@ -167,7 +174,7 @@ fn add_sort_methods_assist( return None; } - acc.add_rewrite("Sort methods alphabetically", methods, sorted, item_list.syntax().text_range()) + acc.add_rewrite("Sort methods alphabetically", methods, sorted, item_list.syntax()) } fn add_sort_fields_assist( @@ -182,12 +189,7 @@ fn add_sort_fields_assist( return None; } - acc.add_rewrite( - "Sort fields alphabetically", - fields, - sorted, - record_field_list.syntax().text_range(), - ) + acc.add_rewrite("Sort fields alphabetically", fields, sorted, record_field_list.syntax()) } fn add_sort_variants_assist(acc: &mut Assists, variant_list: ast::VariantList) -> Option<()> { @@ -199,12 +201,7 @@ fn add_sort_variants_assist(acc: &mut Assists, variant_list: ast::VariantList) - return None; } - acc.add_rewrite( - "Sort variants alphabetically", - variants, - sorted, - variant_list.syntax().text_range(), - ) + acc.add_rewrite("Sort variants alphabetically", variants, sorted, variant_list.syntax()) } fn sort_by_name<T: HasName + Clone>(initial: &[T]) -> Vec<T> { diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs index eef4da55e94..69ea200db16 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs @@ -1392,7 +1392,7 @@ pub fn add(a: i32, b: i32) -> i32 { a + b } /// # Examples /// /// ``` -/// use test::add; +/// use ra_test_fixture::add; /// /// assert_eq!(add(a, b), ); /// ``` diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs index d0b489c4e83..cf5427bae38 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs @@ -86,10 +86,21 @@ pub(crate) fn complete_attribute_path( acc: &mut Completions, ctx: &CompletionContext<'_>, path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx, - &AttrCtx { kind, annotated_item_kind }: &AttrCtx, + &AttrCtx { kind, annotated_item_kind, ref derive_helpers }: &AttrCtx, ) { let is_inner = kind == AttrKind::Inner; + for (derive_helper, derive_name) in derive_helpers { + let mut item = CompletionItem::new( + SymbolKind::Attribute, + ctx.source_range(), + derive_helper.as_str(), + ctx.edition, + ); + item.detail(format!("derive helper of `{derive_name}`")); + item.add_to(acc, ctx.db); + } + match qualified { Qualified::With { resolution: Some(hir::PathResolution::Def(hir::ModuleDef::Module(module))), diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_abi.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_abi.rs index b0e417e6b33..847fa4cf889 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_abi.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_abi.rs @@ -38,7 +38,6 @@ const SUPPORTED_CALLING_CONVENTIONS: &[&str] = &[ "system-unwind", "rust-intrinsic", "rust-call", - "platform-intrinsic", "unadjusted", ]; diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/lifetime.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/lifetime.rs index 9efc52428ef..0692446381b 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/lifetime.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/lifetime.rs @@ -8,7 +8,6 @@ //! show up for normal completions, or they won't show completions other than lifetimes depending //! on the fixture input. use hir::{sym, Name, ScopeDef}; -use syntax::{ast, ToSmolStr, TokenText}; use crate::{ completions::Completions, @@ -21,33 +20,24 @@ pub(crate) fn complete_lifetime( ctx: &CompletionContext<'_>, lifetime_ctx: &LifetimeContext, ) { - let (lp, lifetime) = match lifetime_ctx { - LifetimeContext { kind: LifetimeKind::Lifetime, lifetime } => (None, lifetime), - LifetimeContext { - kind: LifetimeKind::LifetimeParam { is_decl: false, param }, - lifetime, - } => (Some(param), lifetime), - _ => return, - }; - let param_lifetime = match (lifetime, lp.and_then(|lp| lp.lifetime())) { - (Some(lt), Some(lp)) if lp == lt.clone() => return, - (Some(_), Some(lp)) => Some(lp), - _ => None, + let &LifetimeContext { kind: LifetimeKind::Lifetime { in_lifetime_param_bound, def }, .. } = + lifetime_ctx + else { + return; }; - let param_lifetime = param_lifetime.as_ref().map(ast::Lifetime::text); - let param_lifetime = param_lifetime.as_ref().map(TokenText::as_str); ctx.process_all_names_raw(&mut |name, res| { - if matches!( - res, - ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_)) - if param_lifetime != Some(&*name.display_no_db(ctx.edition).to_smolstr()) - ) { + if matches!(res, ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_))) { acc.add_lifetime(ctx, name); } }); - if param_lifetime.is_none() { - acc.add_lifetime(ctx, Name::new_symbol_root(sym::tick_static.clone())); + acc.add_lifetime(ctx, Name::new_symbol_root(sym::tick_static.clone())); + if !in_lifetime_param_bound + && def.is_some_and(|def| { + !matches!(def, hir::GenericDef::Function(_) | hir::GenericDef::Impl(_)) + }) + { + acc.add_lifetime(ctx, Name::new_symbol_root(sym::tick_underscore.clone())); } } @@ -222,6 +212,8 @@ fn foo<'footime, 'lifetime: 'a$0>() {} "#, expect![[r#" lt 'footime + lt 'lifetime + lt 'static "#]], ); } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs index efbee39a2d4..3a661706336 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs @@ -7,8 +7,8 @@ mod tests; use std::{iter, ops::ControlFlow}; use hir::{ - HasAttrs, Local, ModuleSource, Name, PathResolution, ScopeDef, Semantics, SemanticsScope, Type, - TypeInfo, + HasAttrs, Local, ModuleSource, Name, PathResolution, ScopeDef, Semantics, SemanticsScope, + Symbol, Type, TypeInfo, }; use ide_db::{ base_db::SourceDatabase, famous_defs::FamousDefs, helpers::is_editable_crate, FilePosition, @@ -133,6 +133,7 @@ pub(crate) type ExistingDerives = FxHashSet<hir::Macro>; pub(crate) struct AttrCtx { pub(crate) kind: AttrKind, pub(crate) annotated_item_kind: Option<SyntaxKind>, + pub(crate) derive_helpers: Vec<(Symbol, Symbol)>, } #[derive(Debug, PartialEq, Eq)] @@ -289,15 +290,14 @@ pub(crate) struct ParamContext { /// The state of the lifetime we are completing. #[derive(Debug)] pub(crate) struct LifetimeContext { - pub(crate) lifetime: Option<ast::Lifetime>, pub(crate) kind: LifetimeKind, } /// The kind of lifetime we are completing. #[derive(Debug)] pub(crate) enum LifetimeKind { - LifetimeParam { is_decl: bool, param: ast::LifetimeParam }, - Lifetime, + LifetimeParam, + Lifetime { in_lifetime_param_bound: bool, def: Option<hir::GenericDef> }, LabelRef, LabelDef, } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs index 468ad81ad2f..4a678963b93 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs @@ -562,7 +562,7 @@ fn expected_type_and_name( } fn classify_lifetime( - _sema: &Semantics<'_, RootDatabase>, + sema: &Semantics<'_, RootDatabase>, original_file: &SyntaxNode, lifetime: ast::Lifetime, ) -> Option<LifetimeContext> { @@ -571,21 +571,22 @@ fn classify_lifetime( return None; } + let lifetime = + find_node_at_offset::<ast::Lifetime>(original_file, lifetime.syntax().text_range().start()); let kind = match_ast! { match parent { - ast::LifetimeParam(param) => LifetimeKind::LifetimeParam { - is_decl: param.lifetime().as_ref() == Some(&lifetime), - param - }, + ast::LifetimeParam(_) => LifetimeKind::LifetimeParam, ast::BreakExpr(_) => LifetimeKind::LabelRef, ast::ContinueExpr(_) => LifetimeKind::LabelRef, ast::Label(_) => LifetimeKind::LabelDef, - _ => LifetimeKind::Lifetime, + _ => { + let def = lifetime.as_ref().and_then(|lt| sema.scope(lt.syntax())?.generic_def()); + LifetimeKind::Lifetime { in_lifetime_param_bound: ast::TypeBound::can_cast(parent.kind()), def } + }, } }; - let lifetime = find_node_at_offset(original_file, lifetime.syntax().text_range().start()); - Some(LifetimeContext { lifetime, kind }) + Some(LifetimeContext { kind }) } fn classify_name( @@ -1129,7 +1130,22 @@ fn classify_name_ref( let is_trailing_outer_attr = kind != AttrKind::Inner && non_trivia_sibling(attr.syntax().clone().into(), syntax::Direction::Next).is_none(); let annotated_item_kind = if is_trailing_outer_attr { None } else { Some(attached.kind()) }; - Some(PathKind::Attr { attr_ctx: AttrCtx { kind, annotated_item_kind } }) + let derive_helpers = annotated_item_kind + .filter(|kind| { + matches!( + kind, + SyntaxKind::STRUCT + | SyntaxKind::ENUM + | SyntaxKind::UNION + | SyntaxKind::VARIANT + | SyntaxKind::TUPLE_FIELD + | SyntaxKind::RECORD_FIELD + ) + }) + .and_then(|_| nameref.as_ref()?.syntax().ancestors().find_map(ast::Adt::cast)) + .and_then(|adt| sema.derive_helpers_in_scope(&adt)) + .unwrap_or_default(); + Some(PathKind::Attr { attr_ctx: AttrCtx { kind, annotated_item_kind, derive_helpers } }) }; // Infer the path kind diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/item.rs b/src/tools/rust-analyzer/crates/ide-completion/src/item.rs index 52f6bedaaa9..8878fbbea30 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/item.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/item.rs @@ -346,8 +346,7 @@ pub enum CompletionItemKind { impl_from!(SymbolKind for CompletionItemKind); impl CompletionItemKind { - #[cfg(test)] - pub(crate) fn tag(self) -> &'static str { + pub fn tag(self) -> &'static str { match self { CompletionItemKind::SymbolKind(kind) => match kind { SymbolKind::Attribute => "at", diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs b/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs index dfee01b187e..14f42b40055 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs @@ -19,7 +19,7 @@ use ide_db::{ }, items_locator, syntax_helpers::tree_diff::diff, - FilePosition, RootDatabase, + FilePosition, FxHashSet, RootDatabase, }; use crate::{ @@ -34,6 +34,7 @@ pub use crate::{ config::{CallableSnippets, CompletionConfig}, item::{ CompletionItem, CompletionItemKind, CompletionRelevance, CompletionRelevancePostfixMatch, + CompletionRelevanceReturnType, CompletionRelevanceTypeMatch, }, snippet::{Snippet, SnippetScope}, }; @@ -50,6 +51,18 @@ pub struct CompletionFieldsToResolve { } impl CompletionFieldsToResolve { + pub fn from_client_capabilities(client_capability_fields: &FxHashSet<&str>) -> Self { + Self { + resolve_label_details: client_capability_fields.contains("labelDetails"), + resolve_tags: client_capability_fields.contains("tags"), + resolve_detail: client_capability_fields.contains("detail"), + resolve_documentation: client_capability_fields.contains("documentation"), + resolve_filter_text: client_capability_fields.contains("filterText"), + resolve_text_edit: client_capability_fields.contains("textEdit"), + resolve_command: client_capability_fields.contains("command"), + } + } + pub const fn empty() -> Self { Self { resolve_label_details: false, diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs index 45679355b42..1443ebc6c0c 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs @@ -9,6 +9,70 @@ fn check(ra_fixture: &str, expect: Expect) { } #[test] +fn derive_helpers() { + check( + r#" +//- /mac.rs crate:mac +#![crate_type = "proc-macro"] + +#[proc_macro_derive(MyDerive, attributes(my_cool_helper_attribute))] +pub fn my_derive() {} + +//- /lib.rs crate:lib deps:mac +#[rustc_builtin_macro] +pub macro derive($item:item) {} + +#[derive(mac::MyDerive)] +pub struct Foo(#[m$0] i32); +"#, + expect![[r#" + at allow(…) + at automatically_derived + at cfg(…) + at cfg_attr(…) + at cold + at deny(…) + at deprecated + at derive macro derive + at derive(…) + at doc = "…" + at doc(alias = "…") + at doc(hidden) + at expect(…) + at export_name = "…" + at forbid(…) + at global_allocator + at ignore = "…" + at inline + at link + at link_name = "…" + at link_section = "…" + at macro_export + at macro_use + at must_use + at my_cool_helper_attribute derive helper of `MyDerive` + at no_mangle + at non_exhaustive + at panic_handler + at path = "…" + at proc_macro + at proc_macro_attribute + at proc_macro_derive(…) + at repr(…) + at should_panic + at target_feature(enable = "…") + at test + at track_caller + at used + at warn(…) + md mac + kw crate:: + kw self:: + "#]], + ) +} + +#[test] fn proc_macros() { check( r#" diff --git a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs index fdac4dd2efb..932ca373020 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs @@ -733,6 +733,12 @@ impl NameRefClass { } None }, + ast::UseBoundGenericArgs(_) => { + sema.resolve_use_type_arg(name_ref) + .map(GenericParam::TypeParam) + .map(Definition::GenericParam) + .map(NameRefClass::Definition) + }, ast::ExternCrate(extern_crate_ast) => { let extern_crate = sema.to_def(&extern_crate_ast)?; let krate = extern_crate.resolved_crate(sema.db)?; @@ -764,6 +770,7 @@ impl NameRefClass { sema.resolve_label(lifetime).map(Definition::Label).map(NameRefClass::Definition) } SyntaxKind::LIFETIME_ARG + | SyntaxKind::USE_BOUND_GENERIC_ARGS | SyntaxKind::SELF_PARAM | SyntaxKind::TYPE_BOUND | SyntaxKind::WHERE_PRED @@ -772,16 +779,6 @@ impl NameRefClass { .map(GenericParam::LifetimeParam) .map(Definition::GenericParam) .map(NameRefClass::Definition), - // lifetime bounds, as in the 'b in 'a: 'b aren't wrapped in TypeBound nodes so we gotta check - // if our lifetime is in a LifetimeParam without being the constrained lifetime - _ if ast::LifetimeParam::cast(parent).and_then(|param| param.lifetime()).as_ref() - != Some(lifetime) => - { - sema.resolve_lifetime_param(lifetime) - .map(GenericParam::LifetimeParam) - .map(Definition::GenericParam) - .map(NameRefClass::Definition) - } _ => None, } } diff --git a/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs b/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs index 49b3ca290f0..a508f2fedd6 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs @@ -286,7 +286,8 @@ impl Ctx<'_> { return None; } if path.segment().map_or(false, |s| { - s.param_list().is_some() || (s.self_token().is_some() && path.parent_path().is_none()) + s.parenthesized_arg_list().is_some() + || (s.self_token().is_some() && path.parent_path().is_none()) }) { // don't try to qualify `Fn(Foo) -> Bar` paths, they are in prelude anyway // don't try to qualify sole `self` either, they are usually locals, but are returned as modules due to namespace clashing diff --git a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs index 2679cbef61b..b3ecc26cb22 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs @@ -29,7 +29,7 @@ const USELESS_NAME_PREFIXES: &[&str] = &["from_", "with_", "into_"]; /// # Examples /// `Option<Name>` -> `Name` /// `Result<User, Error>` -> `User` -const WRAPPER_TYPES: &[&str] = &["Box", "Option", "Result"]; +const WRAPPER_TYPES: &[&str] = &["Box", "Arc", "Rc", "Option", "Result"]; /// Prefixes to strip from methods names /// @@ -859,6 +859,32 @@ fn foo() { $0(bar())$0; } } #[test] + fn arc_value() { + check( + r#" +struct Arc<T>(*const T); +struct Seed; +fn bar() -> Arc<Seed> {} +fn foo() { $0(bar())$0; } +"#, + "seed", + ); + } + + #[test] + fn rc_value() { + check( + r#" +struct Rc<T>(*const T); +struct Seed; +fn bar() -> Rc<Seed> {} +fn foo() { $0(bar())$0; } +"#, + "seed", + ); + } + + #[test] fn ref_call() { check( r#" diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/expected_function.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/expected_function.rs index 02299197b12..e3a1e12e029 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/expected_function.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/expected_function.rs @@ -37,4 +37,25 @@ fn foo() { "#, ); } + + #[test] + fn no_error_for_async_fn_traits() { + check_diagnostics( + r#" +//- minicore: async_fn +async fn f(it: impl AsyncFn(u32) -> i32) { + let fut = it(0); + let _: i32 = fut.await; +} +async fn g(mut it: impl AsyncFnMut(u32) -> i32) { + let fut = it(0); + let _: i32 = fut.await; +} +async fn h(it: impl AsyncFnOnce(u32) -> i32) { + let fut = it(0); + let _: i32 = fut.await; +} + "#, + ); + } } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/generic_args_prohibited.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/generic_args_prohibited.rs new file mode 100644 index 00000000000..a319a0bcf6d --- /dev/null +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/generic_args_prohibited.rs @@ -0,0 +1,442 @@ +use either::Either; +use hir::GenericArgsProhibitedReason; +use ide_db::assists::Assist; +use ide_db::source_change::SourceChange; +use ide_db::text_edit::TextEdit; +use syntax::{ast, AstNode, TextRange}; + +use crate::{fix, Diagnostic, DiagnosticCode, DiagnosticsContext}; + +// Diagnostic: generic-args-prohibited +// +// This diagnostic is shown when generic arguments are provided for a type that does not accept +// generic arguments. +pub(crate) fn generic_args_prohibited( + ctx: &DiagnosticsContext<'_>, + d: &hir::GenericArgsProhibited, +) -> Diagnostic { + Diagnostic::new_with_syntax_node_ptr( + ctx, + DiagnosticCode::RustcHardError("E0109"), + describe_reason(d.reason), + d.args.map(Into::into), + ) + .with_fixes(fixes(ctx, d)) +} + +fn describe_reason(reason: GenericArgsProhibitedReason) -> String { + let kind = match reason { + GenericArgsProhibitedReason::Module => "modules", + GenericArgsProhibitedReason::TyParam => "type parameters", + GenericArgsProhibitedReason::SelfTy => "`Self`", + GenericArgsProhibitedReason::PrimitiveTy => "builtin types", + GenericArgsProhibitedReason::EnumVariant => { + return "you can specify generic arguments on either the enum or the variant, but not both" + .to_owned(); + } + }; + format!("generic arguments are not allowed on {kind}") +} + +fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::GenericArgsProhibited) -> Option<Vec<Assist>> { + let file_id = d.args.file_id.file_id()?; + let syntax = d.args.to_node(ctx.sema.db); + let range = match &syntax { + Either::Left(_) => syntax.syntax().text_range(), + Either::Right(param_list) => { + let path_segment = ast::PathSegment::cast(param_list.syntax().parent()?)?; + let start = if let Some(coloncolon) = path_segment.coloncolon_token() { + coloncolon.text_range().start() + } else { + param_list.syntax().text_range().start() + }; + let end = if let Some(ret_type) = path_segment.ret_type() { + ret_type.syntax().text_range().end() + } else { + param_list.syntax().text_range().end() + }; + TextRange::new(start, end) + } + }; + Some(vec![fix( + "remove_generic_args", + "Remove these generics", + SourceChange::from_text_edit(file_id, TextEdit::delete(range)), + syntax.syntax().text_range(), + )]) +} + +#[cfg(test)] +mod tests { + // This diagnostic was the first to be emitted in ty lowering, so the tests here also test + // diagnostics in ty lowering in general (which is why there are so many of them). + + use crate::tests::{check_diagnostics, check_fix}; + + #[test] + fn primitives() { + check_diagnostics( + r#" +//- /core.rs crate:core library +#![rustc_coherence_is_core] +impl str { + pub fn trim() {} +} + +//- /lib.rs crate:foo deps:core +fn bar<T>() {} + +fn foo() { + let _: (bool<()>, ()); + // ^^^^ 💡 error: generic arguments are not allowed on builtin types + let _ = <str<'_>>::trim; + // ^^^^ 💡 error: generic arguments are not allowed on builtin types + bar::<u32<{ const { 1 + 1 } }>>(); + // ^^^^^^^^^^^^^^^^^^^^^ 💡 error: generic arguments are not allowed on builtin types +} + "#, + ); + } + + #[test] + fn modules() { + check_diagnostics( + r#" +pub mod foo { + pub mod bar { + pub struct Baz; + + impl Baz { + pub fn qux() {} + } + } +} + +fn foo() { + let _: foo::<'_>::bar::Baz; + // ^^^^^^ 💡 error: generic arguments are not allowed on modules + let _ = <foo::bar<()>::Baz>::qux; + // ^^^^ 💡 error: generic arguments are not allowed on modules +} + "#, + ); + } + + #[test] + fn type_parameters() { + check_diagnostics( + r#" +fn foo<T, U>() { + let _: T<'a>; + // ^^^^ 💡 error: generic arguments are not allowed on type parameters + let _: U::<{ 1 + 2 }>; + // ^^^^^^^^^^^^^ 💡 error: generic arguments are not allowed on type parameters +} + "#, + ); + } + + #[test] + fn fn_like_generic_args() { + check_diagnostics( + r#" +fn foo() { + let _: bool(bool, i32) -> (); + // ^^^^^^^^^^^ 💡 error: generic arguments are not allowed on builtin types +} + "#, + ); + } + + #[test] + fn fn_signature() { + check_diagnostics( + r#" +fn foo( + _a: bool<'_>, + // ^^^^ 💡 error: generic arguments are not allowed on builtin types + _b: i32::<i64>, + // ^^^^^^^ 💡 error: generic arguments are not allowed on builtin types + _c: &(&str<1>) + // ^^^ 💡 error: generic arguments are not allowed on builtin types +) -> ((), i32<bool>) { + // ^^^^^^ 💡 error: generic arguments are not allowed on builtin types + ((), 0) +} + "#, + ); + } + + #[test] + fn const_static_type() { + check_diagnostics( + r#" +const A: i32<bool> = 0; + // ^^^^^^ 💡 error: generic arguments are not allowed on builtin types +static A: i32::<{ 1 + 3 }> = 0; + // ^^^^^^^^^^^^^ 💡 error: generic arguments are not allowed on builtin types + "#, + ); + } + + #[test] + fn fix() { + check_fix( + r#" +fn foo() { + let _: bool<'_, (), { 1 + 1 }>$0; +}"#, + r#" +fn foo() { + let _: bool; +}"#, + ); + check_fix( + r#" +fn foo() { + let _: bool::$0<'_, (), { 1 + 1 }>; +}"#, + r#" +fn foo() { + let _: bool; +}"#, + ); + check_fix( + r#" +fn foo() { + let _: bool(i$032); +}"#, + r#" +fn foo() { + let _: bool; +}"#, + ); + check_fix( + r#" +fn foo() { + let _: bool$0(i32) -> i64; +}"#, + r#" +fn foo() { + let _: bool; +}"#, + ); + check_fix( + r#" +fn foo() { + let _: bool::(i$032) -> i64; +}"#, + r#" +fn foo() { + let _: bool; +}"#, + ); + check_fix( + r#" +fn foo() { + let _: bool::(i32)$0; +}"#, + r#" +fn foo() { + let _: bool; +}"#, + ); + } + + #[test] + fn in_fields() { + check_diagnostics( + r#" +struct A(bool<i32>); + // ^^^^^ 💡 error: generic arguments are not allowed on builtin types +struct B { v: bool<(), 1> } + // ^^^^^^^ 💡 error: generic arguments are not allowed on builtin types +union C { + a: bool<i32>, + // ^^^^^ 💡 error: generic arguments are not allowed on builtin types + b: i32<bool>, + // ^^^^^^ 💡 error: generic arguments are not allowed on builtin types + } +enum D { + A(bool<i32>), + // ^^^^^ 💡 error: generic arguments are not allowed on builtin types + B { v: i32<bool> }, + // ^^^^^^ 💡 error: generic arguments are not allowed on builtin types +} + "#, + ); + } + + #[test] + fn in_generics() { + check_diagnostics( + r#" +mod foo { + pub trait Trait {} +} + +struct A<A: foo::<()>::Trait>(A) + // ^^^^^^ 💡 error: generic arguments are not allowed on modules + where bool<i32>: foo::Trait; + // ^^^^^ 💡 error: generic arguments are not allowed on builtin types +union B<A: foo::<()>::Trait> + // ^^^^^^ 💡 error: generic arguments are not allowed on modules + where bool<i32>: foo::Trait + // ^^^^^ 💡 error: generic arguments are not allowed on builtin types +{ a: A } +enum C<A: foo::<()>::Trait> + // ^^^^^^ 💡 error: generic arguments are not allowed on modules + where bool<i32>: foo::Trait + // ^^^^^ 💡 error: generic arguments are not allowed on builtin types +{} + +fn f<A: foo::<()>::Trait>() + // ^^^^^^ 💡 error: generic arguments are not allowed on modules + where bool<i32>: foo::Trait + // ^^^^^ 💡 error: generic arguments are not allowed on builtin types +{} + +type D<A: foo::<()>::Trait> = A + // ^^^^^^ 💡 error: generic arguments are not allowed on modules + where bool<i32>: foo::Trait; + // ^^^^^ 💡 error: generic arguments are not allowed on builtin types + +trait E<A: foo::<()>::Trait> + // ^^^^^^ 💡 error: generic arguments are not allowed on modules + where bool<i32>: foo::Trait + // ^^^^^ 💡 error: generic arguments are not allowed on builtin types +{ + fn f<B: foo::<()>::Trait>() + // ^^^^^^ 💡 error: generic arguments are not allowed on modules + where bool<i32>: foo::Trait + // ^^^^^ 💡 error: generic arguments are not allowed on builtin types + {} + + type D<B: foo::<()>::Trait> = A + // ^^^^^^ 💡 error: generic arguments are not allowed on modules + where bool<i32>: foo::Trait; + // ^^^^^ 💡 error: generic arguments are not allowed on builtin types +} + +impl<A: foo::<()>::Trait> E for () + // ^^^^^^ 💡 error: generic arguments are not allowed on modules + where bool<i32>: foo::Trait + // ^^^^^ 💡 error: generic arguments are not allowed on builtin types +{ + fn f<B: foo::<()>::Trait>() + // ^^^^^^ 💡 error: generic arguments are not allowed on modules + where bool<i32>: foo::Trait + // ^^^^^ 💡 error: generic arguments are not allowed on builtin types + {} + + type D<B: foo::<()>::Trait> = A + // ^^^^^^ 💡 error: generic arguments are not allowed on modules + where bool<i32>: foo::Trait; + // ^^^^^ 💡 error: generic arguments are not allowed on builtin types +} + "#, + ); + } + + #[test] + fn assoc_items() { + check_diagnostics( + r#" +struct Foo; + +trait Trait { + fn f() -> bool<i32> { true } + // ^^^^^ 💡 error: generic arguments are not allowed on builtin types + type T = i32<bool>; + // ^^^^^^ 💡 error: generic arguments are not allowed on builtin types +} + +impl Trait for Foo { + fn f() -> bool<i32> { true } + // ^^^^^ 💡 error: generic arguments are not allowed on builtin types + type T = i32<bool>; + // ^^^^^^ 💡 error: generic arguments are not allowed on builtin types +} + +impl Foo { + fn f() -> bool<i32> { true } + // ^^^^^ 💡 error: generic arguments are not allowed on builtin types + type T = i32<bool>; + // ^^^^^^ 💡 error: generic arguments are not allowed on builtin types +} + "#, + ); + } + + #[test] + fn const_param_ty() { + check_diagnostics( + r#" +fn foo< + const A: bool<i32>, + // ^^^^^ 💡 error: generic arguments are not allowed on builtin types + B, + C, + const D: bool<i32>, + // ^^^^^ 💡 error: generic arguments are not allowed on builtin types + const E: bool<i32>, + // ^^^^^ 💡 error: generic arguments are not allowed on builtin types +>() {} + "#, + ); + } + + #[test] + fn generic_defaults() { + check_diagnostics( + r#" +struct Foo<A = bool<i32>>(A); + // ^^^^^ 💡 error: generic arguments are not allowed on builtin types + "#, + ); + } + + #[test] + fn impl_self_ty() { + check_diagnostics( + r#" +struct Foo<A>(A); +trait Trait {} +impl Foo<bool<i32>> {} + // ^^^^^ 💡 error: generic arguments are not allowed on builtin types +impl Trait for Foo<bool<i32>> {} + // ^^^^^ 💡 error: generic arguments are not allowed on builtin types + "#, + ); + } + + #[test] + fn impl_trait() { + check_diagnostics( + r#" +mod foo { + pub trait Trait {} +} +impl foo::<()>::Trait for () {} + // ^^^^^^ 💡 error: generic arguments are not allowed on modules + "#, + ); + } + + #[test] + fn type_alias() { + check_diagnostics( + r#" +pub trait Trait { + type Assoc; +} +type T = bool<i32>; + // ^^^^^ 💡 error: generic arguments are not allowed on builtin types +impl Trait for () { + type Assoc = i32<bool>; + // ^^^^^^ 💡 error: generic arguments are not allowed on builtin types +} + "#, + ); + } +} diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs index f39738f2fb8..08e6e7dced9 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs @@ -1114,6 +1114,25 @@ fn test(x: Option<lib::PrivatelyUninhabited>) { } } + #[test] + fn non_exhaustive_may_be_empty() { + check_diagnostics_no_bails( + r" +//- /main.rs crate:main deps:dep +// In a different crate +fn empty_match_on_empty_struct<T>(x: dep::UninhabitedStruct) -> T { + match x {} +} +//- /dep.rs crate:dep +#[non_exhaustive] +pub struct UninhabitedStruct { + pub never: !, + // other fields +} +", + ); + } + mod false_negatives { //! The implementation of match checking here is a work in progress. As we roll this out, we //! prefer false negatives to false positives (ideally there would be no false positives). This diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs index a630d3c7c36..2bfdda35659 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs @@ -1,5 +1,5 @@ use hir::db::ExpandDatabase; -use hir::HirFileIdExt; +use hir::{HirFileIdExt, UnsafetyReason}; use ide_db::text_edit::TextEdit; use ide_db::{assists::Assist, source_change::SourceChange}; use syntax::{ast, SyntaxNode}; @@ -16,23 +16,35 @@ pub(crate) fn missing_unsafe(ctx: &DiagnosticsContext<'_>, d: &hir::MissingUnsaf } else { DiagnosticCode::RustcHardError("E0133") }; + let operation = display_unsafety_reason(d.reason); Diagnostic::new_with_syntax_node_ptr( ctx, code, - "this operation is unsafe and requires an unsafe function or block", - d.expr.map(|it| it.into()), + format!("{operation} is unsafe and requires an unsafe function or block"), + d.node.map(|it| it.into()), ) .with_fixes(fixes(ctx, d)) } +fn display_unsafety_reason(reason: UnsafetyReason) -> &'static str { + match reason { + UnsafetyReason::UnionField => "access to union field", + UnsafetyReason::UnsafeFnCall => "call to unsafe function", + UnsafetyReason::InlineAsm => "use of inline assembly", + UnsafetyReason::RawPtrDeref => "dereference of raw pointer", + UnsafetyReason::MutableStatic => "use of mutable static", + UnsafetyReason::ExternStatic => "use of extern static", + } +} + fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingUnsafe) -> Option<Vec<Assist>> { // The fixit will not work correctly for macro expansions, so we don't offer it in that case. - if d.expr.file_id.is_macro() { + if d.node.file_id.is_macro() { return None; } - let root = ctx.sema.db.parse_or_expand(d.expr.file_id); - let node = d.expr.value.to_node(&root); + let root = ctx.sema.db.parse_or_expand(d.node.file_id); + let node = d.node.value.to_node(&root); let expr = node.syntax().ancestors().find_map(ast::Expr::cast)?; let node_to_add_unsafe_block = pick_best_node_to_add_unsafe_block(&expr)?; @@ -40,7 +52,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingUnsafe) -> Option<Vec<Ass let replacement = format!("unsafe {{ {} }}", node_to_add_unsafe_block.text()); let edit = TextEdit::replace(node_to_add_unsafe_block.text_range(), replacement); let source_change = - SourceChange::from_text_edit(d.expr.file_id.original_file(ctx.sema.db), edit); + SourceChange::from_text_edit(d.node.file_id.original_file(ctx.sema.db), edit); Some(vec![fix("add_unsafe", "Add unsafe block", source_change, expr.syntax().text_range())]) } @@ -110,7 +122,7 @@ fn main() { let x = &5_usize as *const usize; unsafe { let _y = *x; } let _z = *x; -} //^^💡 error: this operation is unsafe and requires an unsafe function or block +} //^^💡 error: dereference of raw pointer is unsafe and requires an unsafe function or block "#, ) } @@ -136,9 +148,9 @@ unsafe fn unsafe_fn() { fn main() { unsafe_fn(); - //^^^^^^^^^^^💡 error: this operation is unsafe and requires an unsafe function or block + //^^^^^^^^^^^💡 error: call to unsafe function is unsafe and requires an unsafe function or block HasUnsafe.unsafe_fn(); - //^^^^^^^^^^^^^^^^^^^^^💡 error: this operation is unsafe and requires an unsafe function or block + //^^^^^^^^^^^^^^^^^^^^^💡 error: call to unsafe function is unsafe and requires an unsafe function or block unsafe { unsafe_fn(); HasUnsafe.unsafe_fn(); @@ -162,7 +174,7 @@ static mut STATIC_MUT: Ty = Ty { a: 0 }; fn main() { let _x = STATIC_MUT.a; - //^^^^^^^^^^💡 error: this operation is unsafe and requires an unsafe function or block + //^^^^^^^^^^💡 error: use of mutable static is unsafe and requires an unsafe function or block unsafe { let _x = STATIC_MUT.a; } @@ -184,9 +196,9 @@ extern "C" { fn main() { let _x = EXTERN; - //^^^^^^💡 error: this operation is unsafe and requires an unsafe function or block + //^^^^^^💡 error: use of extern static is unsafe and requires an unsafe function or block let _x = EXTERN_MUT; - //^^^^^^^^^^💡 error: this operation is unsafe and requires an unsafe function or block + //^^^^^^^^^^💡 error: use of mutable static is unsafe and requires an unsafe function or block unsafe { let _x = EXTERN; let _x = EXTERN_MUT; @@ -234,7 +246,7 @@ extern "rust-intrinsic" { fn main() { let _ = bitreverse(12); let _ = floorf32(12.0); - //^^^^^^^^^^^^^^💡 error: this operation is unsafe and requires an unsafe function or block + //^^^^^^^^^^^^^^💡 error: call to unsafe function is unsafe and requires an unsafe function or block } "#, ); @@ -567,7 +579,7 @@ unsafe fn not_safe() -> u8 { fn main() { ed2021::safe(); ed2024::not_safe(); - //^^^^^^^^^^^^^^^^^^💡 error: this operation is unsafe and requires an unsafe function or block + //^^^^^^^^^^^^^^^^^^💡 error: call to unsafe function is unsafe and requires an unsafe function or block } "#, ) @@ -591,7 +603,7 @@ unsafe fn foo(p: *mut i32) { #![warn(unsafe_op_in_unsafe_fn)] unsafe fn foo(p: *mut i32) { *p = 123; - //^^💡 warn: this operation is unsafe and requires an unsafe function or block + //^^💡 warn: dereference of raw pointer is unsafe and requires an unsafe function or block } "#, ) @@ -618,17 +630,119 @@ unsafe extern { fn main() { f(); g(); - //^^^💡 error: this operation is unsafe and requires an unsafe function or block + //^^^💡 error: call to unsafe function is unsafe and requires an unsafe function or block h(); - //^^^💡 error: this operation is unsafe and requires an unsafe function or block + //^^^💡 error: call to unsafe function is unsafe and requires an unsafe function or block let _ = S1; let _ = S2; - //^^💡 error: this operation is unsafe and requires an unsafe function or block + //^^💡 error: use of extern static is unsafe and requires an unsafe function or block let _ = S3; - //^^💡 error: this operation is unsafe and requires an unsafe function or block + //^^💡 error: use of extern static is unsafe and requires an unsafe function or block +} +"#, + ); + } + + #[test] + fn no_unsafe_diagnostic_when_destructuring_union_with_wildcard() { + check_diagnostics( + r#" +union Union { field: i32 } +fn foo(v: &Union) { + let Union { field: _ } = v; + let Union { field: _ | _ } = v; + Union { field: _ } = *v; +} +"#, + ); + } + + #[test] + fn union_destructuring() { + check_diagnostics( + r#" +union Union { field: u8 } +fn foo(v @ Union { field: _field }: &Union) { + // ^^^^^^ error: access to union field is unsafe and requires an unsafe function or block + let Union { mut field } = v; + // ^^^^^^^^^💡 error: access to union field is unsafe and requires an unsafe function or block + let Union { field: 0..=255 } = v; + // ^^^^^^^💡 error: access to union field is unsafe and requires an unsafe function or block + let Union { field: 0 + // ^💡 error: access to union field is unsafe and requires an unsafe function or block + | 1..=255 } = v; + // ^^^^^^^💡 error: access to union field is unsafe and requires an unsafe function or block + Union { field } = *v; + // ^^^^^💡 error: access to union field is unsafe and requires an unsafe function or block + match v { + Union { field: _field } => {} + // ^^^^^^💡 error: access to union field is unsafe and requires an unsafe function or block + } + if let Union { field: _field } = v {} + // ^^^^^^💡 error: access to union field is unsafe and requires an unsafe function or block + (|&Union { field }| { _ = field; })(v); + // ^^^^^💡 error: access to union field is unsafe and requires an unsafe function or block +} +"#, + ); + } + + #[test] + fn union_field_access() { + check_diagnostics( + r#" +union Union { field: u8 } +fn foo(v: &Union) { + v.field; + // ^^^^^^^💡 error: access to union field is unsafe and requires an unsafe function or block } "#, ); } + + #[test] + fn inline_asm() { + check_diagnostics( + r#" +//- minicore: asm +fn foo() { + core::arch::asm!(""); + // ^^^^ error: use of inline assembly is unsafe and requires an unsafe function or block +} +"#, + ); + } + + #[test] + fn unsafe_op_in_unsafe_fn_dismissed_in_signature() { + check_diagnostics( + r#" +#![warn(unsafe_op_in_unsafe_fn)] +union Union { field: u32 } +unsafe fn foo(Union { field: _field }: Union) {} + "#, + ) + } + + #[test] + fn union_assignment_allowed() { + check_diagnostics( + r#" +union Union { field: u32 } +fn foo(mut v: Union) { + v.field = 123; + (v.field,) = (123,); + *&mut v.field = 123; + // ^^^^^^^💡 error: access to union field is unsafe and requires an unsafe function or block +} +struct Struct { field: u32 } +union Union2 { field: Struct } +fn bar(mut v: Union2) { + v.field.field = 123; +} + + "#, + ) + } } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs index 93fe9374a3e..bfdda537405 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs @@ -1,12 +1,16 @@ use either::Either; -use hir::{db::ExpandDatabase, ClosureStyle, HirDisplay, HirFileIdExt, InFile, Type}; -use ide_db::text_edit::TextEdit; -use ide_db::{famous_defs::FamousDefs, source_change::SourceChange}; +use hir::{db::ExpandDatabase, CallableKind, ClosureStyle, HirDisplay, HirFileIdExt, InFile, Type}; +use ide_db::{ + famous_defs::FamousDefs, + source_change::{SourceChange, SourceChangeBuilder}, + text_edit::TextEdit, +}; use syntax::{ ast::{ self, edit::{AstNodeEdit, IndentLevel}, - BlockExpr, Expr, ExprStmt, + syntax_factory::SyntaxFactory, + BlockExpr, Expr, ExprStmt, HasArgList, }, AstNode, AstPtr, TextSize, }; @@ -63,6 +67,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::TypeMismatch) -> Option<Vec<Assi let expr_ptr = &InFile { file_id: d.expr_or_pat.file_id, value: expr_ptr }; add_reference(ctx, d, expr_ptr, &mut fixes); add_missing_ok_or_some(ctx, d, expr_ptr, &mut fixes); + remove_unnecessary_wrapper(ctx, d, expr_ptr, &mut fixes); remove_semicolon(ctx, d, expr_ptr, &mut fixes); str_ref_to_owned(ctx, d, expr_ptr, &mut fixes); } @@ -184,6 +189,89 @@ fn add_missing_ok_or_some( Some(()) } +fn remove_unnecessary_wrapper( + ctx: &DiagnosticsContext<'_>, + d: &hir::TypeMismatch, + expr_ptr: &InFile<AstPtr<ast::Expr>>, + acc: &mut Vec<Assist>, +) -> Option<()> { + let db = ctx.sema.db; + let root = db.parse_or_expand(expr_ptr.file_id); + let expr = expr_ptr.value.to_node(&root); + let expr = ctx.sema.original_ast_node(expr.clone())?; + + let Expr::CallExpr(call_expr) = expr else { + return None; + }; + + let callable = ctx.sema.resolve_expr_as_callable(&call_expr.expr()?)?; + let CallableKind::TupleEnumVariant(variant) = callable.kind() else { + return None; + }; + + let actual_enum = d.actual.as_adt()?.as_enum()?; + let famous_defs = FamousDefs(&ctx.sema, ctx.sema.scope(call_expr.syntax())?.krate()); + let core_option = famous_defs.core_option_Option(); + let core_result = famous_defs.core_result_Result(); + if Some(actual_enum) != core_option && Some(actual_enum) != core_result { + return None; + } + + let inner_type = variant.fields(db).first()?.ty_with_args(db, d.actual.type_arguments()); + if !d.expected.could_unify_with(db, &inner_type) { + return None; + } + + let inner_arg = call_expr.arg_list()?.args().next()?; + + let file_id = expr_ptr.file_id.original_file(db); + let mut builder = SourceChangeBuilder::new(file_id); + let mut editor; + match inner_arg { + // We're returning `()` + Expr::TupleExpr(tup) if tup.fields().next().is_none() => { + let parent = call_expr + .syntax() + .parent() + .and_then(Either::<ast::ReturnExpr, ast::StmtList>::cast)?; + + editor = builder.make_editor(parent.syntax()); + let make = SyntaxFactory::new(); + + match parent { + Either::Left(ret_expr) => { + editor.replace(ret_expr.syntax(), make.expr_return(None).syntax()); + } + Either::Right(stmt_list) => { + let new_block = if stmt_list.statements().next().is_none() { + make.expr_empty_block() + } else { + make.block_expr(stmt_list.statements(), None) + }; + + editor.replace(stmt_list.syntax().parent()?, new_block.syntax()); + } + } + + editor.add_mappings(make.finish_with_mappings()); + } + _ => { + editor = builder.make_editor(call_expr.syntax()); + editor.replace(call_expr.syntax(), inner_arg.syntax()); + } + } + + builder.add_file_edits(file_id, editor); + let name = format!("Remove unnecessary {}() wrapper", variant.name(db).as_str()); + acc.push(fix( + "remove_unnecessary_wrapper", + &name, + builder.finish(), + call_expr.syntax().text_range(), + )); + Some(()) +} + fn remove_semicolon( ctx: &DiagnosticsContext<'_>, d: &hir::TypeMismatch, @@ -243,7 +331,7 @@ fn str_ref_to_owned( #[cfg(test)] mod tests { use crate::tests::{ - check_diagnostics, check_diagnostics_with_disabled, check_fix, check_no_fix, + check_diagnostics, check_diagnostics_with_disabled, check_fix, check_has_fix, check_no_fix, }; #[test] @@ -260,7 +348,7 @@ fn test(_arg: &i32) {} } #[test] - fn test_add_reference_to_int() { + fn add_reference_to_int() { check_fix( r#" fn main() { @@ -278,7 +366,7 @@ fn test(_arg: &i32) {} } #[test] - fn test_add_mutable_reference_to_int() { + fn add_mutable_reference_to_int() { check_fix( r#" fn main() { @@ -296,7 +384,7 @@ fn test(_arg: &mut i32) {} } #[test] - fn test_add_reference_to_array() { + fn add_reference_to_array() { check_fix( r#" //- minicore: coerce_unsized @@ -315,7 +403,7 @@ fn test(_arg: &[i32]) {} } #[test] - fn test_add_reference_with_autoderef() { + fn add_reference_with_autoderef() { check_fix( r#" //- minicore: coerce_unsized, deref @@ -348,7 +436,7 @@ fn test(_arg: &Bar) {} } #[test] - fn test_add_reference_to_method_call() { + fn add_reference_to_method_call() { check_fix( r#" fn main() { @@ -372,7 +460,7 @@ impl Test { } #[test] - fn test_add_reference_to_let_stmt() { + fn add_reference_to_let_stmt() { check_fix( r#" fn main() { @@ -388,7 +476,7 @@ fn main() { } #[test] - fn test_add_reference_to_macro_call() { + fn add_reference_to_macro_call() { check_fix( r#" macro_rules! thousand { @@ -416,7 +504,7 @@ fn main() { } #[test] - fn test_add_mutable_reference_to_let_stmt() { + fn add_mutable_reference_to_let_stmt() { check_fix( r#" fn main() { @@ -432,29 +520,6 @@ fn main() { } #[test] - fn test_wrap_return_type_option() { - check_fix( - r#" -//- minicore: option, result -fn div(x: i32, y: i32) -> Option<i32> { - if y == 0 { - return None; - } - x / y$0 -} -"#, - r#" -fn div(x: i32, y: i32) -> Option<i32> { - if y == 0 { - return None; - } - Some(x / y) -} -"#, - ); - } - - #[test] fn const_generic_type_mismatch() { check_diagnostics( r#" @@ -487,59 +552,82 @@ fn div(x: i32, y: i32) -> Option<i32> { } #[test] - fn test_wrap_return_type_option_tails() { + fn wrap_return_type() { + check_fix( + r#" +//- minicore: option, result +fn div(x: i32, y: i32) -> Result<i32, ()> { + if y == 0 { + return Err(()); + } + x / y$0 +} +"#, + r#" +fn div(x: i32, y: i32) -> Result<i32, ()> { + if y == 0 { + return Err(()); + } + Ok(x / y) +} +"#, + ); + } + + #[test] + fn wrap_return_type_option() { check_fix( r#" //- minicore: option, result fn div(x: i32, y: i32) -> Option<i32> { if y == 0 { - Some(0) - } else if true { - 100$0 - } else { - None + return None; } + x / y$0 } "#, r#" fn div(x: i32, y: i32) -> Option<i32> { if y == 0 { - Some(0) - } else if true { - Some(100) - } else { - None + return None; } + Some(x / y) } "#, ); } #[test] - fn test_wrap_return_type() { + fn wrap_return_type_option_tails() { check_fix( r#" //- minicore: option, result -fn div(x: i32, y: i32) -> Result<i32, ()> { +fn div(x: i32, y: i32) -> Option<i32> { if y == 0 { - return Err(()); + Some(0) + } else if true { + 100$0 + } else { + None } - x / y$0 } "#, r#" -fn div(x: i32, y: i32) -> Result<i32, ()> { +fn div(x: i32, y: i32) -> Option<i32> { if y == 0 { - return Err(()); + Some(0) + } else if true { + Some(100) + } else { + None } - Ok(x / y) } "#, ); } #[test] - fn test_wrap_return_type_handles_generic_functions() { + fn wrap_return_type_handles_generic_functions() { check_fix( r#" //- minicore: option, result @@ -562,7 +650,7 @@ fn div<T>(x: T) -> Result<T, i32> { } #[test] - fn test_wrap_return_type_handles_type_aliases() { + fn wrap_return_type_handles_type_aliases() { check_fix( r#" //- minicore: option, result @@ -589,7 +677,7 @@ fn div(x: i32, y: i32) -> MyResult<i32> { } #[test] - fn test_wrapped_unit_as_block_tail_expr() { + fn wrapped_unit_as_block_tail_expr() { check_fix( r#" //- minicore: result @@ -619,7 +707,7 @@ fn foo() -> Result<(), ()> { } #[test] - fn test_wrapped_unit_as_return_expr() { + fn wrapped_unit_as_return_expr() { check_fix( r#" //- minicore: result @@ -642,7 +730,7 @@ fn foo(b: bool) -> Result<(), String> { } #[test] - fn test_in_const_and_static() { + fn wrap_in_const_and_static() { check_fix( r#" //- minicore: option, result @@ -664,7 +752,7 @@ const _: Option<()> = {Some(())}; } #[test] - fn test_wrap_return_type_not_applicable_when_expr_type_does_not_match_ok_type() { + fn wrap_return_type_not_applicable_when_expr_type_does_not_match_ok_type() { check_no_fix( r#" //- minicore: option, result @@ -674,7 +762,7 @@ fn foo() -> Result<(), i32> { 0$0 } } #[test] - fn test_wrap_return_type_not_applicable_when_return_type_is_not_result_or_option() { + fn wrap_return_type_not_applicable_when_return_type_is_not_result_or_option() { check_no_fix( r#" //- minicore: option, result @@ -686,6 +774,254 @@ fn foo() -> SomeOtherEnum { 0$0 } } #[test] + fn unwrap_return_type() { + check_fix( + r#" +//- minicore: option, result +fn div(x: i32, y: i32) -> i32 { + if y == 0 { + panic!(); + } + Ok(x / y)$0 +} +"#, + r#" +fn div(x: i32, y: i32) -> i32 { + if y == 0 { + panic!(); + } + x / y +} +"#, + ); + } + + #[test] + fn unwrap_return_type_option() { + check_fix( + r#" +//- minicore: option, result +fn div(x: i32, y: i32) -> i32 { + if y == 0 { + panic!(); + } + Some(x / y)$0 +} +"#, + r#" +fn div(x: i32, y: i32) -> i32 { + if y == 0 { + panic!(); + } + x / y +} +"#, + ); + } + + #[test] + fn unwrap_return_type_option_tails() { + check_fix( + r#" +//- minicore: option, result +fn div(x: i32, y: i32) -> i32 { + if y == 0 { + 42 + } else if true { + Some(100)$0 + } else { + 0 + } +} +"#, + r#" +fn div(x: i32, y: i32) -> i32 { + if y == 0 { + 42 + } else if true { + 100 + } else { + 0 + } +} +"#, + ); + } + + #[test] + fn unwrap_return_type_option_tail_unit() { + check_fix( + r#" +//- minicore: option, result +fn div(x: i32, y: i32) { + if y == 0 { + panic!(); + } + + Ok(())$0 +} +"#, + r#" +fn div(x: i32, y: i32) { + if y == 0 { + panic!(); + } +} +"#, + ); + } + + #[test] + fn unwrap_return_type_handles_generic_functions() { + check_fix( + r#" +//- minicore: option, result +fn div<T>(x: T) -> T { + if x == 0 { + panic!(); + } + $0Ok(x) +} +"#, + r#" +fn div<T>(x: T) -> T { + if x == 0 { + panic!(); + } + x +} +"#, + ); + } + + #[test] + fn unwrap_return_type_handles_type_aliases() { + check_fix( + r#" +//- minicore: option, result +type MyResult<T> = T; + +fn div(x: i32, y: i32) -> MyResult<i32> { + if y == 0 { + panic!(); + } + Ok(x $0/ y) +} +"#, + r#" +type MyResult<T> = T; + +fn div(x: i32, y: i32) -> MyResult<i32> { + if y == 0 { + panic!(); + } + x / y +} +"#, + ); + } + + #[test] + fn unwrap_tail_expr() { + check_fix( + r#" +//- minicore: result +fn foo() -> () { + println!("Hello, world!"); + Ok(())$0 +} + "#, + r#" +fn foo() -> () { + println!("Hello, world!"); +} + "#, + ); + } + + #[test] + fn unwrap_to_empty_block() { + check_fix( + r#" +//- minicore: result +fn foo() -> () { + Ok(())$0 +} + "#, + r#" +fn foo() -> () {} + "#, + ); + } + + #[test] + fn unwrap_to_return_expr() { + check_has_fix( + r#" +//- minicore: result +fn foo(b: bool) -> () { + if b { + return $0Ok(()); + } + + panic!("oh dear"); +}"#, + r#" +fn foo(b: bool) -> () { + if b { + return; + } + + panic!("oh dear"); +}"#, + ); + } + + #[test] + fn unwrap_in_const_and_static() { + check_fix( + r#" +//- minicore: option, result +static A: () = {Some(($0))}; + "#, + r#" +static A: () = {}; + "#, + ); + check_fix( + r#" +//- minicore: option, result +const _: () = {Some(($0))}; + "#, + r#" +const _: () = {}; + "#, + ); + } + + #[test] + fn unwrap_return_type_not_applicable_when_inner_type_does_not_match_return_type() { + check_no_fix( + r#" +//- minicore: result +fn foo() -> i32 { $0Ok(()) } +"#, + ); + } + + #[test] + fn unwrap_return_type_not_applicable_when_wrapper_type_is_not_result_or_option() { + check_no_fix( + r#" +//- minicore: option, result +enum SomeOtherEnum { Ok(i32), Err(String) } + +fn foo() -> i32 { SomeOtherEnum::Ok($042) } +"#, + ); + } + + #[test] fn remove_semicolon() { check_fix(r#"fn f() -> i32 { 92$0; }"#, r#"fn f() -> i32 { 92 }"#); } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs index 81cb4521218..4ab649cc162 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs @@ -167,9 +167,9 @@ fn assoc_func_fix(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedMethodCall) - } let method_name = call.name_ref()?; - let assoc_func_call = format!("{receiver_type_adt_name}::{method_name}()"); + let assoc_func_path = format!("{receiver_type_adt_name}::{method_name}"); - let assoc_func_call = make::expr_path(make::path_from_text(&assoc_func_call)); + let assoc_func_path = make::expr_path(make::path_from_text(&assoc_func_path)); let args: Vec<_> = if need_to_take_receiver_as_first_arg { std::iter::once(receiver).chain(call.arg_list()?.args()).collect() @@ -178,7 +178,7 @@ fn assoc_func_fix(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedMethodCall) - }; let args = make::arg_list(args); - let assoc_func_call_expr_string = make::expr_call(assoc_func_call, args).to_string(); + let assoc_func_call_expr_string = make::expr_call(assoc_func_path, args).to_string(); let file_id = ctx.sema.original_range_opt(call.receiver()?.syntax())?.file_id; diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs index 1f1b6478d36..ad339569081 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs @@ -27,6 +27,7 @@ mod handlers { pub(crate) mod await_outside_of_async; pub(crate) mod break_outside_of_loop; pub(crate) mod expected_function; + pub(crate) mod generic_args_prohibited; pub(crate) mod inactive_code; pub(crate) mod incoherent_impl; pub(crate) mod incorrect_case; @@ -468,6 +469,7 @@ pub fn semantic_diagnostics( Some(it) => it, None => continue, }, + AnyDiagnostic::GenericArgsProhibited(d) => handlers::generic_args_prohibited::generic_args_prohibited(&ctx, &d) }; res.push(d) } @@ -542,7 +544,13 @@ fn handle_diag_from_macros( sema.db.lookup_intern_syntax_context(span.ctx).outer_expn.is_some_and(|expansion| { let macro_call = sema.db.lookup_intern_macro_call(expansion.as_macro_file().macro_call_id); + // We don't want to show diagnostics for non-local macros at all, but proc macros authors + // seem to rely on being able to emit non-warning-free code, so we don't want to show warnings + // for them even when the proc macro comes from the same workspace (in rustc that's not a + // problem because it doesn't have the concept of workspaces, and proc macros always reside + // in a different crate). !Crate::from(macro_call.def.krate).origin(sema.db).is_local() + || !macro_call.def.kind.is_declarative() }) }) { // Disable suggestions for external macros, they'll change library code and it's just bad. diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs index 6569f0f5552..4edc3633fbe 100644 --- a/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs +++ b/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs @@ -359,8 +359,8 @@ impl<'db, 'sema> Matcher<'db, 'sema> { )?; self.attempt_match_opt( phase, - pattern_segment.param_list(), - code_segment.param_list(), + pattern_segment.parenthesized_arg_list(), + code_segment.parenthesized_arg_list(), )?; } if matches!(phase, Phase::Second(_)) { diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs index 0986d5542cd..ea18b89c5c9 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs @@ -288,7 +288,7 @@ m!(ab$0c); *abc* ```rust - test + ra_test_fixture ``` ```rust @@ -301,7 +301,7 @@ m!(ab$0c); --- ```rust - test::module + ra_test_fixture::module ``` ```rust @@ -327,7 +327,7 @@ fn main() { "#, expect![[r#" *foo* - test + ra_test_fixture pub fn foo() -> u32 "#]], @@ -487,7 +487,7 @@ fn main() { GoToType( [ HoverGotoTypeData { - mod_path: "test::S2", + mod_path: "ra_test_fixture::S2", nav: NavigationTarget { file_id: FileId( 0, @@ -500,7 +500,7 @@ fn main() { }, }, HoverGotoTypeData { - mod_path: "test::S", + mod_path: "ra_test_fixture::S", nav: NavigationTarget { file_id: FileId( 0, @@ -583,7 +583,7 @@ fn main() { let foo_test = fo$0o(); } *foo* ```rust - test + ra_test_fixture ``` ```rust @@ -605,7 +605,7 @@ fn main() { f$0oo(); } *foo* ```rust - test + ra_test_fixture ``` ```rust @@ -627,7 +627,7 @@ fn main() { m::f$0oo(); } *foo* ```rust - test::m + ra_test_fixture::m ``` ```rust @@ -649,7 +649,7 @@ fn main() { fo$0o(); } *foo* ```rust - test + ra_test_fixture ``` ```rust @@ -667,7 +667,7 @@ fn main() { fo$0o(); } *foo* ```rust - test + ra_test_fixture ``` ```rust @@ -691,7 +691,7 @@ fn main() { let foo_test = fo$0o(); } *foo* ```rust - test + ra_test_fixture ``` ```rust @@ -715,7 +715,7 @@ fn main() { } *foo* ```rust - test + ra_test_fixture ``` ```rust @@ -743,7 +743,7 @@ fn main() { } *foo* ```rust - test + ra_test_fixture ``` ```rust @@ -776,7 +776,7 @@ fn main() { } *foo* ```rust - test + ra_test_fixture ``` ```rust @@ -801,7 +801,7 @@ struct Foo { fiel$0d_a: u8, field_b: i32, field_c: i16 } *field_a* ```rust - test::Foo + ra_test_fixture::Foo ``` ```rust @@ -830,7 +830,7 @@ fn main() { *field_a* ```rust - test::Foo + ra_test_fixture::Foo ``` ```rust @@ -852,7 +852,7 @@ fn main() { *field_a* ```rust - test::Foo + ra_test_fixture::Foo ``` ```rust @@ -880,7 +880,7 @@ fn main() { *0* ```rust - test::Foo + ra_test_fixture::Foo ``` ```rust @@ -900,7 +900,7 @@ fn foo(foo: Foo) { *0* ```rust - test::Foo + ra_test_fixture::Foo ``` ```rust @@ -920,7 +920,7 @@ struct Foo$0(pub u32) where u32: Copy; *Foo* ```rust - test + ra_test_fixture ``` ```rust @@ -946,7 +946,7 @@ struct Foo$0 { field: u32 } *Foo* ```rust - test + ra_test_fixture ``` ```rust @@ -968,7 +968,7 @@ struct Foo$0 where u32: Copy { field: u32 } *Foo* ```rust - test + ra_test_fixture ``` ```rust @@ -998,7 +998,7 @@ fn hover_record_struct_limit() { *Foo* ```rust - test + ra_test_fixture ``` ```rust @@ -1023,7 +1023,7 @@ fn hover_record_struct_limit() { *Foo* ```rust - test + ra_test_fixture ``` ```rust @@ -1046,7 +1046,7 @@ fn hover_record_struct_limit() { *Foo* ```rust - test + ra_test_fixture ``` ```rust @@ -1072,7 +1072,7 @@ fn hover_record_struct_limit() { *Foo* ```rust - test + ra_test_fixture ``` ```rust @@ -1093,7 +1093,7 @@ fn hover_record_struct_limit() { *Foo* ```rust - test + ra_test_fixture ``` ```rust @@ -1116,7 +1116,7 @@ fn hover_record_struct_limit() { *Foo* ```rust - test + ra_test_fixture ``` ```rust @@ -1141,7 +1141,7 @@ fn hover_record_variant_limit() { *A* ```rust - test::Foo + ra_test_fixture::Foo ``` ```rust @@ -1162,7 +1162,7 @@ fn hover_record_variant_limit() { *A* ```rust - test::Foo + ra_test_fixture::Foo ``` ```rust @@ -1183,7 +1183,7 @@ fn hover_record_variant_limit() { *A* ```rust - test::Foo + ra_test_fixture::Foo ``` ```rust @@ -1204,7 +1204,7 @@ fn hover_record_variant_limit() { *A* ```rust - test::Foo + ra_test_fixture::Foo ``` ```rust @@ -1225,7 +1225,7 @@ fn hover_record_variant_limit() { *A* ```rust - test::Foo + ra_test_fixture::Foo ``` ```rust @@ -1248,7 +1248,7 @@ fn hover_enum_limit() { *Foo* ```rust - test + ra_test_fixture ``` ```rust @@ -1270,7 +1270,7 @@ fn hover_enum_limit() { *Foo* ```rust - test + ra_test_fixture ``` ```rust @@ -1292,7 +1292,7 @@ fn hover_enum_limit() { *Foo* ```rust - test + ra_test_fixture ``` ```rust @@ -1311,7 +1311,7 @@ fn hover_enum_limit() { *Foo* ```rust - test + ra_test_fixture ``` ```rust @@ -1339,7 +1339,7 @@ fn hover_enum_limit() { *Enum* ```rust - test + ra_test_fixture ``` ```rust @@ -1371,7 +1371,7 @@ fn hover_union_limit() { *Foo* ```rust - test + ra_test_fixture ``` ```rust @@ -1393,7 +1393,7 @@ fn hover_union_limit() { *Foo* ```rust - test + ra_test_fixture ``` ```rust @@ -1415,7 +1415,7 @@ fn hover_union_limit() { *Foo* ```rust - test + ra_test_fixture ``` ```rust @@ -1434,7 +1434,7 @@ fn hover_union_limit() { *Foo* ```rust - test + ra_test_fixture ``` ```rust @@ -1458,7 +1458,7 @@ struct Foo$0 where u32: Copy; *Foo* ```rust - test + ra_test_fixture ``` ```rust @@ -1484,7 +1484,7 @@ type Fo$0o: Trait = S where T: Trait; *Foo* ```rust - test + ra_test_fixture ``` ```rust @@ -1504,7 +1504,7 @@ fn hover_const_static() { *foo* ```rust - test + ra_test_fixture ``` ```rust @@ -1522,7 +1522,7 @@ const foo$0: u32 = { *foo* ```rust - test + ra_test_fixture ``` ```rust @@ -1540,7 +1540,7 @@ const foo$0: u32 = { *foo* ```rust - test + ra_test_fixture ``` ```rust @@ -1555,7 +1555,7 @@ const foo$0: u32 = { *FOO* ```rust - test + ra_test_fixture ``` ```rust @@ -1573,7 +1573,7 @@ const foo$0: u32 = { *BAR* ```rust - test + ra_test_fixture ``` ```rust @@ -1591,7 +1591,7 @@ fn hover_unsigned_max_const() { *A* ```rust - test + ra_test_fixture ``` ```rust @@ -1612,7 +1612,7 @@ fn hover_eval_complex_constants() { *foo* ```rust - test + ra_test_fixture ``` ```rust @@ -1667,16 +1667,16 @@ use Option::Some; fn main() { So$0me(12); } "#, expect![[r#" - *Some* + *Some* - ```rust - test::Option - ``` + ```rust + ra_test_fixture::Option + ``` - ```rust - Some(T) - ``` - "#]], + ```rust + Some(T) + ``` + "#]], ); check( @@ -1711,20 +1711,20 @@ enum Option<T> { } "#, expect![[r#" - *None* + *None* - ```rust - test::Option - ``` + ```rust + ra_test_fixture::Option + ``` - ```rust - None - ``` + ```rust + None + ``` - --- + --- - The None variant - "#]], + The None variant + "#]], ); check( @@ -1738,20 +1738,20 @@ fn main() { } "#, expect![[r#" - *Some* + *Some* - ```rust - test::Option - ``` + ```rust + ra_test_fixture::Option + ``` - ```rust - Some(T) - ``` + ```rust + Some(T) + ``` - --- + --- - The Some variant - "#]], + The Some variant + "#]], ); } @@ -1885,7 +1885,7 @@ fn main() { let foo_test = wrapper::Thing::new$0(); } *new* ```rust - test::wrapper::Thing + ra_test_fixture::wrapper::Thing ``` ```rust @@ -1916,7 +1916,7 @@ fn main() { *C* ```rust - test::X + ra_test_fixture::X ``` ```rust @@ -1936,18 +1936,18 @@ impl Thing { } "#, expect![[r#" - *Self* + *Self* - ```rust - test - ``` + ```rust + ra_test_fixture + ``` - ```rust - struct Thing { - x: u32, - } - ``` - "#]], + ```rust + struct Thing { + x: u32, + } + ``` + "#]], ); check_hover_fields_limit( None, @@ -1958,16 +1958,16 @@ impl Thing { } "#, expect![[r#" - *Self* + *Self* - ```rust - test - ``` + ```rust + ra_test_fixture + ``` - ```rust - struct Thing - ``` - "#]], + ```rust + struct Thing + ``` + "#]], ); check( r#" @@ -1977,18 +1977,18 @@ impl Thing { } "#, expect![[r#" - *Self* + *Self* - ```rust - test - ``` + ```rust + ra_test_fixture + ``` - ```rust - struct Thing { - x: u32, - } - ``` - "#]], + ```rust + struct Thing { + x: u32, + } + ``` + "#]], ); check( r#" @@ -2001,7 +2001,7 @@ impl Thing { *Self* ```rust - test + ra_test_fixture ``` ```rust @@ -2022,7 +2022,7 @@ impl Thing { *Self* ```rust - test + ra_test_fixture ``` ```rust @@ -2042,7 +2042,7 @@ impl usize { *Self* ```rust - test + ra_test_fixture ``` ```rust @@ -2060,7 +2060,7 @@ impl fn() -> usize { *Self* ```rust - test + ra_test_fixture ``` ```rust @@ -2103,7 +2103,7 @@ fn f() { fo$0o!(); } *foo* ```rust - test + ra_test_fixture ``` ```rust @@ -2128,7 +2128,7 @@ fn f() { fo$0o!(); } *foo* ```rust - test + ra_test_fixture ``` ```rust @@ -2172,7 +2172,7 @@ id! { *foo* ```rust - test + ra_test_fixture ``` ```rust @@ -2194,7 +2194,7 @@ fn foo$0() {} *foo* ```rust - test + ra_test_fixture ``` ```rust @@ -2252,7 +2252,7 @@ fn foo() { let a = id!([0u32, bar$0()] ); } *bar* ```rust - test + ra_test_fixture ``` ```rust @@ -2278,7 +2278,7 @@ fn foo() { *bar* ```rust - test + ra_test_fixture ``` ```rust @@ -2302,7 +2302,7 @@ fn foo(Foo { b$0ar }: &Foo) {} GoToType( [ HoverGotoTypeData { - mod_path: "test::Bar", + mod_path: "ra_test_fixture::Bar", nav: NavigationTarget { file_id: FileId( 0, @@ -2334,7 +2334,7 @@ fn bar() { fo$0o(); } *foo* ```rust - test + ra_test_fixture ``` ```rust @@ -2356,7 +2356,7 @@ fn test_hover_function_show_qualifiers() { *foo* ```rust - test + ra_test_fixture ``` ```rust @@ -2370,7 +2370,7 @@ fn test_hover_function_show_qualifiers() { *foo* ```rust - test + ra_test_fixture ``` ```rust @@ -2385,7 +2385,7 @@ fn test_hover_function_show_qualifiers() { *foo* ```rust - test::m + ra_test_fixture::m ``` ```rust @@ -2403,7 +2403,7 @@ fn test_hover_function_show_types() { *foo* ```rust - test + ra_test_fixture ``` ```rust @@ -2426,7 +2426,7 @@ fn main() { foo$0; } *foo* ```rust - test + ra_test_fixture ``` ```rust @@ -2446,7 +2446,7 @@ fn main() { foo$0; } *foo* ```rust - test + ra_test_fixture ``` ```rust @@ -2464,7 +2464,7 @@ fn test_hover_function_pointer_show_identifiers() { *foo* ```rust - test + ra_test_fixture ``` ```rust @@ -2486,7 +2486,7 @@ fn test_hover_function_pointer_no_identifier() { *foo* ```rust - test + ra_test_fixture ``` ```rust @@ -2601,16 +2601,16 @@ mod my { pub struct Bar; } fn my() {} "#, expect![[r#" - *my* + *my* - ```rust - test - ``` + ```rust + ra_test_fixture + ``` - ```rust - mod my - ``` - "#]], + ```rust + mod my + ``` + "#]], ); } @@ -2636,7 +2636,7 @@ fn foo() { let bar = Ba$0r; } *Bar* ```rust - test + ra_test_fixture ``` ```rust @@ -2672,7 +2672,7 @@ fn foo() { let bar = Ba$0r; } *Bar* ```rust - test + ra_test_fixture ``` ```rust @@ -2701,7 +2701,7 @@ fn foo() { let bar = Ba$0r; } *Bar* ```rust - test + ra_test_fixture ``` ```rust @@ -2729,7 +2729,7 @@ pub struct B$0ar *Bar* ```rust - test + ra_test_fixture ``` ```rust @@ -2760,7 +2760,7 @@ pub struct B$0ar *Bar* ```rust - test + ra_test_fixture ``` ```rust @@ -2809,7 +2809,7 @@ pub fn fo$0o() {} *foo* ```rust - test + ra_test_fixture ``` ```rust @@ -2853,7 +2853,7 @@ fn test_hover_layout_of_variant() { *Variant1* ```rust - test::Foo + ra_test_fixture::Foo ``` ```rust @@ -2878,7 +2878,7 @@ fn test_hover_layout_of_variant_generic() { *None* ```rust - test::Option + ra_test_fixture::Option ``` ```rust @@ -2899,7 +2899,7 @@ struct S$0<T>(core::marker::PhantomData<T>); *S* ```rust - test + ra_test_fixture ``` ```rust @@ -2924,7 +2924,7 @@ fn test_hover_layout_of_enum() { *Foo* ```rust - test + ra_test_fixture ``` ```rust @@ -2949,7 +2949,7 @@ fn test_hover_no_memory_layout() { *field_a* ```rust - test::Foo + ra_test_fixture::Foo ``` ```rust @@ -3003,7 +3003,7 @@ fn foo() { let bar = Bar; bar.fo$0o(); } *foo* ```rust - test::Bar + ra_test_fixture::Bar ``` ```rust @@ -3041,7 +3041,7 @@ fn foo() { let bar = Bar; bar.fo$0o(); } *foo* ```rust - test::Bar + ra_test_fixture::Bar ``` ```rust @@ -3069,7 +3069,7 @@ fn main() { let foo_test = unsafe { fo$0o(1, 2, 3); } } *foo* ```rust - test::<extern> + ra_test_fixture::<extern> ``` ```rust @@ -3267,7 +3267,7 @@ fn main() { let s$0t = S{ f1:0 }; } GoToType( [ HoverGotoTypeData { - mod_path: "test::S", + mod_path: "ra_test_fixture::S", nav: NavigationTarget { file_id: FileId( 0, @@ -3300,7 +3300,7 @@ fn main() { let s$0t = S{ f1:Arg(0) }; } GoToType( [ HoverGotoTypeData { - mod_path: "test::Arg", + mod_path: "ra_test_fixture::Arg", nav: NavigationTarget { file_id: FileId( 0, @@ -3313,7 +3313,7 @@ fn main() { let s$0t = S{ f1:Arg(0) }; } }, }, HoverGotoTypeData { - mod_path: "test::S", + mod_path: "ra_test_fixture::S", nav: NavigationTarget { file_id: FileId( 0, @@ -3359,7 +3359,7 @@ fn main() { let s$0t = S{ f1: S{ f1: Arg(0) } }; } GoToType( [ HoverGotoTypeData { - mod_path: "test::Arg", + mod_path: "ra_test_fixture::Arg", nav: NavigationTarget { file_id: FileId( 0, @@ -3372,7 +3372,7 @@ fn main() { let s$0t = S{ f1: S{ f1: Arg(0) } }; } }, }, HoverGotoTypeData { - mod_path: "test::S", + mod_path: "ra_test_fixture::S", nav: NavigationTarget { file_id: FileId( 0, @@ -3408,7 +3408,7 @@ fn main() { let s$0t = (A(1), B(2), M::C(3) ); } GoToType( [ HoverGotoTypeData { - mod_path: "test::A", + mod_path: "ra_test_fixture::A", nav: NavigationTarget { file_id: FileId( 0, @@ -3421,7 +3421,7 @@ fn main() { let s$0t = (A(1), B(2), M::C(3) ); } }, }, HoverGotoTypeData { - mod_path: "test::B", + mod_path: "ra_test_fixture::B", nav: NavigationTarget { file_id: FileId( 0, @@ -3434,7 +3434,7 @@ fn main() { let s$0t = (A(1), B(2), M::C(3) ); } }, }, HoverGotoTypeData { - mod_path: "test::M::C", + mod_path: "ra_test_fixture::M::C", nav: NavigationTarget { file_id: FileId( 0, @@ -3468,7 +3468,7 @@ fn main() { let s$0t = foo(); } GoToType( [ HoverGotoTypeData { - mod_path: "test::Foo", + mod_path: "ra_test_fixture::Foo", nav: NavigationTarget { file_id: FileId( 0, @@ -3502,7 +3502,7 @@ fn main() { let s$0t = foo(); } GoToType( [ HoverGotoTypeData { - mod_path: "test::Foo", + mod_path: "ra_test_fixture::Foo", nav: NavigationTarget { file_id: FileId( 0, @@ -3515,7 +3515,7 @@ fn main() { let s$0t = foo(); } }, }, HoverGotoTypeData { - mod_path: "test::S", + mod_path: "ra_test_fixture::S", nav: NavigationTarget { file_id: FileId( 0, @@ -3549,7 +3549,7 @@ fn main() { let s$0t = foo(); } GoToType( [ HoverGotoTypeData { - mod_path: "test::Bar", + mod_path: "ra_test_fixture::Bar", nav: NavigationTarget { file_id: FileId( 0, @@ -3562,7 +3562,7 @@ fn main() { let s$0t = foo(); } }, }, HoverGotoTypeData { - mod_path: "test::Foo", + mod_path: "ra_test_fixture::Foo", nav: NavigationTarget { file_id: FileId( 0, @@ -3599,7 +3599,7 @@ fn main() { let s$0t = foo(); } GoToType( [ HoverGotoTypeData { - mod_path: "test::Bar", + mod_path: "ra_test_fixture::Bar", nav: NavigationTarget { file_id: FileId( 0, @@ -3612,7 +3612,7 @@ fn main() { let s$0t = foo(); } }, }, HoverGotoTypeData { - mod_path: "test::Foo", + mod_path: "ra_test_fixture::Foo", nav: NavigationTarget { file_id: FileId( 0, @@ -3625,7 +3625,7 @@ fn main() { let s$0t = foo(); } }, }, HoverGotoTypeData { - mod_path: "test::S1", + mod_path: "ra_test_fixture::S1", nav: NavigationTarget { file_id: FileId( 0, @@ -3638,7 +3638,7 @@ fn main() { let s$0t = foo(); } }, }, HoverGotoTypeData { - mod_path: "test::S2", + mod_path: "ra_test_fixture::S2", nav: NavigationTarget { file_id: FileId( 0, @@ -3669,7 +3669,7 @@ fn foo(ar$0g: &impl Foo) {} GoToType( [ HoverGotoTypeData { - mod_path: "test::Foo", + mod_path: "ra_test_fixture::Foo", nav: NavigationTarget { file_id: FileId( 0, @@ -3703,7 +3703,7 @@ fn foo(ar$0g: &impl Foo + Bar<S>) {} GoToType( [ HoverGotoTypeData { - mod_path: "test::Bar", + mod_path: "ra_test_fixture::Bar", nav: NavigationTarget { file_id: FileId( 0, @@ -3716,7 +3716,7 @@ fn foo(ar$0g: &impl Foo + Bar<S>) {} }, }, HoverGotoTypeData { - mod_path: "test::Foo", + mod_path: "ra_test_fixture::Foo", nav: NavigationTarget { file_id: FileId( 0, @@ -3729,7 +3729,7 @@ fn foo(ar$0g: &impl Foo + Bar<S>) {} }, }, HoverGotoTypeData { - mod_path: "test::S", + mod_path: "ra_test_fixture::S", nav: NavigationTarget { file_id: FileId( 0, @@ -3816,7 +3816,7 @@ fn foo(ar$0g: &impl Foo<S>) {} GoToType( [ HoverGotoTypeData { - mod_path: "test::Foo", + mod_path: "ra_test_fixture::Foo", nav: NavigationTarget { file_id: FileId( 0, @@ -3829,7 +3829,7 @@ fn foo(ar$0g: &impl Foo<S>) {} }, }, HoverGotoTypeData { - mod_path: "test::S", + mod_path: "ra_test_fixture::S", nav: NavigationTarget { file_id: FileId( 0, @@ -3866,7 +3866,7 @@ fn main() { let s$0t = foo(); } GoToType( [ HoverGotoTypeData { - mod_path: "test::B", + mod_path: "ra_test_fixture::B", nav: NavigationTarget { file_id: FileId( 0, @@ -3879,7 +3879,7 @@ fn main() { let s$0t = foo(); } }, }, HoverGotoTypeData { - mod_path: "test::Foo", + mod_path: "ra_test_fixture::Foo", nav: NavigationTarget { file_id: FileId( 0, @@ -3892,7 +3892,7 @@ fn main() { let s$0t = foo(); } }, }, HoverGotoTypeData { - mod_path: "test::S", + mod_path: "ra_test_fixture::S", nav: NavigationTarget { file_id: FileId( 0, @@ -3923,7 +3923,7 @@ fn foo(ar$0g: &dyn Foo) {} GoToType( [ HoverGotoTypeData { - mod_path: "test::Foo", + mod_path: "ra_test_fixture::Foo", nav: NavigationTarget { file_id: FileId( 0, @@ -3955,7 +3955,7 @@ fn foo(ar$0g: &dyn Foo<S>) {} GoToType( [ HoverGotoTypeData { - mod_path: "test::Foo", + mod_path: "ra_test_fixture::Foo", nav: NavigationTarget { file_id: FileId( 0, @@ -3968,7 +3968,7 @@ fn foo(ar$0g: &dyn Foo<S>) {} }, }, HoverGotoTypeData { - mod_path: "test::S", + mod_path: "ra_test_fixture::S", nav: NavigationTarget { file_id: FileId( 0, @@ -4003,7 +4003,7 @@ fn foo(a$0rg: &impl ImplTrait<B<dyn DynTrait<B<S>>>>) {} GoToType( [ HoverGotoTypeData { - mod_path: "test::B", + mod_path: "ra_test_fixture::B", nav: NavigationTarget { file_id: FileId( 0, @@ -4016,7 +4016,7 @@ fn foo(a$0rg: &impl ImplTrait<B<dyn DynTrait<B<S>>>>) {} }, }, HoverGotoTypeData { - mod_path: "test::DynTrait", + mod_path: "ra_test_fixture::DynTrait", nav: NavigationTarget { file_id: FileId( 0, @@ -4029,7 +4029,7 @@ fn foo(a$0rg: &impl ImplTrait<B<dyn DynTrait<B<S>>>>) {} }, }, HoverGotoTypeData { - mod_path: "test::ImplTrait", + mod_path: "ra_test_fixture::ImplTrait", nav: NavigationTarget { file_id: FileId( 0, @@ -4042,7 +4042,7 @@ fn foo(a$0rg: &impl ImplTrait<B<dyn DynTrait<B<S>>>>) {} }, }, HoverGotoTypeData { - mod_path: "test::S", + mod_path: "ra_test_fixture::S", nav: NavigationTarget { file_id: FileId( 0, @@ -4084,7 +4084,7 @@ fn main() { let s$0t = test().get(); } GoToType( [ HoverGotoTypeData { - mod_path: "test::Foo", + mod_path: "ra_test_fixture::Foo", nav: NavigationTarget { file_id: FileId( 0, @@ -4117,7 +4117,7 @@ impl<const BAR: Bar> Foo<BAR$0> {} GoToType( [ HoverGotoTypeData { - mod_path: "test::Bar", + mod_path: "ra_test_fixture::Bar", nav: NavigationTarget { file_id: FileId( 0, @@ -4149,7 +4149,7 @@ fn foo<T: Foo>(t: T$0){} GoToType( [ HoverGotoTypeData { - mod_path: "test::Foo", + mod_path: "ra_test_fixture::Foo", nav: NavigationTarget { file_id: FileId( 0, @@ -4182,7 +4182,7 @@ impl Foo { GoToType( [ HoverGotoTypeData { - mod_path: "test::Foo", + mod_path: "ra_test_fixture::Foo", nav: NavigationTarget { file_id: FileId( 0, @@ -4257,7 +4257,7 @@ fn main() { --- ```rust - test::S + ra_test_fixture::S ``` ```rust @@ -4282,7 +4282,7 @@ struct S$0T<const C: usize = 1, T = Foo>(T); *ST* ```rust - test + ra_test_fixture ``` ```rust @@ -4307,7 +4307,7 @@ struct S$0T<const C: usize = {40 + 2}, T = Foo>(T); *ST* ```rust - test + ra_test_fixture ``` ```rust @@ -4333,7 +4333,7 @@ struct S$0T<const C: usize = VAL, T = Foo>(T); *ST* ```rust - test + ra_test_fixture ``` ```rust @@ -4527,21 +4527,21 @@ mod Foo$0 { } "#, expect![[r#" - *Foo* + *Foo* - ```rust - test - ``` + ```rust + ra_test_fixture + ``` - ```rust - mod Foo - ``` + ```rust + mod Foo + ``` - --- + --- - Be quick; - time is mana - "#]], + Be quick; + time is mana + "#]], ); } @@ -4558,21 +4558,21 @@ mod Foo$0 { } "#, expect![[r#" - *Foo* + *Foo* - ```rust - test - ``` + ```rust + ra_test_fixture + ``` - ```rust - mod Foo - ``` + ```rust + mod Foo + ``` - --- + --- - Be quick; - time is mana - "#]], + Be quick; + time is mana + "#]], ); } @@ -4592,7 +4592,7 @@ fn foo$0() {} *foo* ```rust - test + ra_test_fixture ``` ```rust @@ -4902,7 +4902,7 @@ type Fo$0o2 = Foo<2>; *Foo2* ```rust - test + ra_test_fixture ``` ```rust @@ -4948,7 +4948,7 @@ enum E { *A* ```rust - test::E + ra_test_fixture::E ``` ```rust @@ -4977,7 +4977,7 @@ enum E { *A* ```rust - test::E + ra_test_fixture::E ``` ```rust @@ -5007,7 +5007,7 @@ enum E { *B* ```rust - test::E + ra_test_fixture::E ``` ```rust @@ -5037,7 +5037,7 @@ enum E { *B* ```rust - test::E + ra_test_fixture::E ``` ```rust @@ -5074,7 +5074,7 @@ fn main() { *B* ```rust - test + ra_test_fixture ``` ```rust @@ -5111,7 +5111,7 @@ fn main() { *AA* ```rust - test + ra_test_fixture ``` ```rust @@ -5138,7 +5138,7 @@ fn main() { *B* ```rust - test::T + ra_test_fixture::T ``` ```rust @@ -5167,7 +5167,7 @@ fn main() { *B* ```rust - test::T + ra_test_fixture::T ``` ```rust @@ -5199,7 +5199,7 @@ fn main() { *B* ```rust - test::T + ra_test_fixture::T ``` ```rust @@ -5222,7 +5222,7 @@ const FOO$0: usize = 1 << 3; *FOO* ```rust - test + ra_test_fixture ``` ```rust @@ -5243,7 +5243,7 @@ const FOO$0: usize = (1 << 3) + (1 << 2); *FOO* ```rust - test + ra_test_fixture ``` ```rust @@ -5265,7 +5265,7 @@ const FOO$0: usize = 2 - 3; *FOO* ```rust - test + ra_test_fixture ``` ```rust @@ -5287,7 +5287,7 @@ const FOO$0: i32 = 2 - 3; *FOO* ```rust - test + ra_test_fixture ``` ```rust @@ -5308,7 +5308,7 @@ const FOO$0: &str = "bar"; *FOO* ```rust - test + ra_test_fixture ``` ```rust @@ -5330,7 +5330,7 @@ const FOO$0: char = 'a'; *FOO* ```rust - test + ra_test_fixture ``` ```rust @@ -5352,7 +5352,7 @@ const FOO$0: char = '\x61'; *FOO* ```rust - test + ra_test_fixture ``` ```rust @@ -5374,7 +5374,7 @@ const FOO$0: u8 = b'a'; *FOO* ```rust - test + ra_test_fixture ``` ```rust @@ -5396,7 +5396,7 @@ const FOO$0: u8 = b'\x61'; *FOO* ```rust - test + ra_test_fixture ``` ```rust @@ -5418,7 +5418,7 @@ const FOO$0: u8 = b'\x61'; *FOO* ```rust - test + ra_test_fixture ``` ```rust @@ -5440,7 +5440,7 @@ const FOO$0: f32 = 1f32; *FOO* ```rust - test + ra_test_fixture ``` ```rust @@ -5462,7 +5462,7 @@ const FOO$0: &i32 = &2; *FOO* ```rust - test + ra_test_fixture ``` ```rust @@ -5484,7 +5484,7 @@ const FOO$0: f64 = 1.0f64; *FOO* ```rust - test + ra_test_fixture ``` ```rust @@ -5512,7 +5512,7 @@ const FOO$0: f64 = expf64(1.2); *FOO* ```rust - test + ra_test_fixture ``` ```rust @@ -5530,7 +5530,7 @@ const FOO$0: f32 = 1.9999999403953552_f32; *FOO* ```rust - test + ra_test_fixture ``` ```rust @@ -5552,7 +5552,7 @@ const FOO$0: f16 = -1.0f16; *FOO* ```rust - test + ra_test_fixture ``` ```rust @@ -5573,7 +5573,7 @@ const FOO$0: f128 = -1.0f128; *FOO* ```rust - test + ra_test_fixture ``` ```rust @@ -5604,7 +5604,7 @@ const FOO$0: Enum = VX; *FOO* ```rust - test + ra_test_fixture ``` ```rust @@ -5621,7 +5621,7 @@ const FOO$0: Option<i32> = Some(2); *FOO* ```rust - test + ra_test_fixture ``` ```rust @@ -5638,7 +5638,7 @@ const FOO$0: Option<&i32> = Some(2).as_ref(); *FOO* ```rust - test + ra_test_fixture ``` ```rust @@ -5661,7 +5661,7 @@ const FOO$0: &dyn Debug = &2i32; *FOO* ```rust - test + ra_test_fixture ``` ```rust @@ -5682,7 +5682,7 @@ const FOO$0: &[i32] = &[1, 2, 3 + 4]; *FOO* ```rust - test + ra_test_fixture ``` ```rust @@ -5699,7 +5699,7 @@ const FOO$0: &[i32; 5] = &[12; 5]; *FOO* ```rust - test + ra_test_fixture ``` ```rust @@ -5720,7 +5720,7 @@ const FOO$0: (&i32, &[i32], &i32) = { *FOO* ```rust - test + ra_test_fixture ``` ```rust @@ -5743,7 +5743,7 @@ const FOO$0: Tree = { *FOO* ```rust - test + ra_test_fixture ``` ```rust @@ -5763,7 +5763,7 @@ const FOO$0: &S<[u8]> = core::mem::transmute::<&[u8], _>(&[1, 2, 3]); *FOO* ```rust - test + ra_test_fixture ``` ```rust @@ -5783,7 +5783,7 @@ const FOO$0: &str = "foo"; *FOO* ```rust - test + ra_test_fixture ``` ```rust @@ -5806,7 +5806,7 @@ const FOO$0: X = X { *FOO* ```rust - test + ra_test_fixture ``` ```rust @@ -5825,7 +5825,7 @@ const FOO$0: (&str, &str) = { *FOO* ```rust - test + ra_test_fixture ``` ```rust @@ -5856,7 +5856,7 @@ fn test() { *FOO* ```rust - test::S + ra_test_fixture::S ``` ```rust @@ -5883,7 +5883,7 @@ fn foo() { *FOO* ```rust - test + ra_test_fixture ``` ```rust @@ -5912,7 +5912,7 @@ fn foo(e: E) { *A* ```rust - test::E + ra_test_fixture::E ``` ```rust @@ -5942,7 +5942,7 @@ pub fn the_function() -> AA { *CONST* ```rust - test + ra_test_fixture ``` ```rust @@ -5984,20 +5984,20 @@ mod foo$0; //! For the horde! "#, expect![[r#" - *foo* + *foo* - ```rust - test - ``` + ```rust + ra_test_fixture + ``` - ```rust - mod foo - ``` + ```rust + mod foo + ``` - --- + --- - For the horde! - "#]], + For the horde! + "#]], ); } @@ -6013,20 +6013,20 @@ mod foo { use foo::bar::{self$0}; "#, expect![[r#" - *self* + *self* - ```rust - test::foo - ``` + ```rust + ra_test_fixture::foo + ``` - ```rust - mod bar - ``` + ```rust + mod bar + ``` - --- + --- - But this should appear - "#]], + But this should appear + "#]], ) } @@ -6166,7 +6166,7 @@ fn main() { *bar* ```rust - test + ra_test_fixture ``` ```rust @@ -6200,7 +6200,7 @@ pub fn gimme() -> theitem::TheItem { *[`TheItem`]* ```rust - test::theitem + ra_test_fixture::theitem ``` ```rust @@ -6248,7 +6248,7 @@ impl T1 for Foo { *Bar* ```rust - test::t2::T2 + ra_test_fixture::t2::T2 ``` ```rust @@ -6270,7 +6270,7 @@ trait A { *Assoc* ```rust - test::A + ra_test_fixture::A ``` ```rust @@ -6291,7 +6291,7 @@ trait A { *Assoc* ```rust - test::A + ra_test_fixture::A ``` ```rust @@ -6310,7 +6310,7 @@ trait A where *Assoc* ```rust - test::A + ra_test_fixture::A ``` ```rust @@ -6572,12 +6572,12 @@ fn hover_rename() { use self as foo$0; "#, expect![[r#" - *foo* + *foo* - ```rust - extern crate test - ``` - "#]], + ```rust + extern crate ra_test_fixture + ``` + "#]], ); check( r#" @@ -6585,16 +6585,16 @@ mod bar {} use bar::{self as foo$0}; "#, expect![[r#" - *foo* + *foo* - ```rust - test - ``` + ```rust + ra_test_fixture + ``` - ```rust - mod bar - ``` - "#]], + ```rust + mod bar + ``` + "#]], ); check( r#" @@ -6603,24 +6603,24 @@ mod bar { } "#, expect![[r#" - *foo* + *foo* - ```rust - extern crate test - ``` - "#]], + ```rust + extern crate ra_test_fixture + ``` + "#]], ); check( r#" use crate as foo$0; "#, expect![[r#" - *foo* + *foo* - ```rust - extern crate test - ``` - "#]], + ```rust + extern crate ra_test_fixture + ``` + "#]], ); } @@ -6645,7 +6645,7 @@ identity!{ *Copy* ```rust - test + ra_test_fixture ``` ```rust @@ -6669,7 +6669,7 @@ struct Foo; *Copy* ```rust - test + ra_test_fixture ``` ```rust @@ -6691,7 +6691,7 @@ struct Foo; *Copy* ```rust - test::foo + ra_test_fixture::foo ``` ```rust @@ -6910,7 +6910,7 @@ fn foo() { GoToType( [ HoverGotoTypeData { - mod_path: "test::Foo", + mod_path: "ra_test_fixture::Foo", nav: NavigationTarget { file_id: FileId( 0, @@ -7110,7 +7110,7 @@ foo_macro!( *[`Foo`]* ```rust - test + ra_test_fixture ``` ```rust @@ -7119,7 +7119,7 @@ foo_macro!( --- - Doc comment for [`Foo`](https://docs.rs/test/*/test/struct.Foo.html) + Doc comment for [`Foo`](https://docs.rs/ra_test_fixture/*/ra_test_fixture/struct.Foo.html) "#]], ); } @@ -7135,7 +7135,7 @@ pub struct Foo(i32); *[`Foo`]* ```rust - test + ra_test_fixture ``` ```rust @@ -7144,7 +7144,7 @@ pub struct Foo(i32); --- - Doc comment for [`Foo`](https://docs.rs/test/*/test/struct.Foo.html) + Doc comment for [`Foo`](https://docs.rs/ra_test_fixture/*/ra_test_fixture/struct.Foo.html) "#]], ); } @@ -7160,7 +7160,7 @@ pub struct Foo<T>(T); *[`Foo<T>`]* ```rust - test + ra_test_fixture ``` ```rust @@ -7169,7 +7169,7 @@ pub struct Foo<T>(T); --- - Doc comment for [`Foo<T>`](https://docs.rs/test/*/test/struct.Foo.html) + Doc comment for [`Foo<T>`](https://docs.rs/ra_test_fixture/*/ra_test_fixture/struct.Foo.html) "#]], ); } @@ -7259,7 +7259,7 @@ enum Enum { *RecordV* ```rust - test::Enum + ra_test_fixture::Enum ``` ```rust @@ -7285,7 +7285,7 @@ enum Enum { *field* ```rust - test::RecordV + ra_test_fixture::RecordV ``` ```rust @@ -7315,7 +7315,7 @@ impl T for () { *func* ```rust - test + ra_test_fixture ``` ```rust @@ -7341,7 +7341,7 @@ impl T$0 for () {} *T* ```rust - test + ra_test_fixture ``` ```rust @@ -7360,7 +7360,7 @@ impl T$0 for () {} *T* ```rust - test + ra_test_fixture ``` ```rust @@ -7383,7 +7383,7 @@ impl T$0 for () {} *T* ```rust - test + ra_test_fixture ``` ```rust @@ -7406,7 +7406,7 @@ impl T$0 for () {} *T* ```rust - test + ra_test_fixture ``` ```rust @@ -7433,7 +7433,7 @@ impl T$0 for () {} *T* ```rust - test + ra_test_fixture ``` ```rust @@ -7460,7 +7460,7 @@ impl T$0 for () {} *T* ```rust - test + ra_test_fixture ``` ```rust @@ -7529,7 +7529,7 @@ fn f() { *** ```rust - test::Struct + ra_test_fixture::Struct ``` ```rust @@ -7558,7 +7558,7 @@ fn main() { $0V; } *V* ```rust - test + ra_test_fixture ``` ```rust @@ -7585,7 +7585,7 @@ fn main() { $0V; } *V* ```rust - test + ra_test_fixture ``` ```rust @@ -7765,7 +7765,7 @@ fn test() { *foo* ```rust - test::S + ra_test_fixture::S ``` ```rust @@ -7794,7 +7794,7 @@ fn test() { *foo* ```rust - test::S + ra_test_fixture::S ``` ```rust @@ -7824,7 +7824,7 @@ mod m { *foo* ```rust - test::S + ra_test_fixture::S ``` ```rust @@ -7854,7 +7854,7 @@ fn test() { *A* ```rust - test::S + ra_test_fixture::S ``` ```rust @@ -7883,7 +7883,7 @@ fn test() { *A* ```rust - test::S + ra_test_fixture::S ``` ```rust @@ -7913,7 +7913,7 @@ mod m { *A* ```rust - test::S + ra_test_fixture::S ``` ```rust @@ -7936,7 +7936,7 @@ fn test() { *f* ```rust - test::S + ra_test_fixture::S ``` ```rust @@ -8091,7 +8091,7 @@ fn main() { *foo* ```rust - test::S + ra_test_fixture::S ``` ```rust @@ -8573,7 +8573,7 @@ impl Iterator for S { *S* ```rust - test + ra_test_fixture ``` ```rust @@ -8595,7 +8595,7 @@ extern "C" { *STATIC* ```rust - test::<extern> + ra_test_fixture::<extern> ``` ```rust @@ -8613,7 +8613,7 @@ extern "C" { *fun* ```rust - test::<extern> + ra_test_fixture::<extern> ``` ```rust @@ -8631,7 +8631,7 @@ extern "C" { *Ty* ```rust - test::<extern> + ra_test_fixture::<extern> ``` ```rust @@ -8731,7 +8731,7 @@ impl Iterator for S { }, }, HoverGotoTypeData { - mod_path: "test::Notable", + mod_path: "ra_test_fixture::Notable", nav: NavigationTarget { file_id: FileId( 0, @@ -8744,7 +8744,7 @@ impl Iterator for S { }, }, HoverGotoTypeData { - mod_path: "test::S2", + mod_path: "ra_test_fixture::S2", nav: NavigationTarget { file_id: FileId( 0, @@ -8775,7 +8775,7 @@ struct Pedro$0<'a> { *Pedro* ```rust - test + ra_test_fixture ``` ```rust @@ -8962,7 +8962,7 @@ fn test_hover_function_with_pat_param() { *test_1* ```rust - test + ra_test_fixture ``` ```rust @@ -8978,7 +8978,7 @@ fn test_hover_function_with_pat_param() { *test_2* ```rust - test + ra_test_fixture ``` ```rust @@ -8994,7 +8994,7 @@ fn test_hover_function_with_pat_param() { *test_3* ```rust - test + ra_test_fixture ``` ```rust @@ -9010,7 +9010,7 @@ fn test_hover_function_with_pat_param() { *test_4* ```rust - test + ra_test_fixture ``` ```rust @@ -9026,7 +9026,7 @@ fn test_hover_function_with_pat_param() { *test_5* ```rust - test + ra_test_fixture ``` ```rust @@ -9042,7 +9042,7 @@ fn test_hover_function_with_pat_param() { *test_6* ```rust - test + ra_test_fixture ``` ```rust @@ -9058,7 +9058,7 @@ fn test_hover_function_with_pat_param() { *test_7* ```rust - test + ra_test_fixture ``` ```rust @@ -9074,7 +9074,7 @@ fn test_hover_function_with_pat_param() { *test_8* ```rust - test + ra_test_fixture ``` ```rust @@ -9090,7 +9090,7 @@ fn test_hover_function_with_pat_param() { *test_9* ```rust - test + ra_test_fixture ``` ```rust @@ -9106,7 +9106,7 @@ fn test_hover_function_with_pat_param() { *test_10* ```rust - test + ra_test_fixture ``` ```rust @@ -9122,7 +9122,7 @@ fn test_hover_function_with_pat_param() { *test_10* ```rust - test + ra_test_fixture ``` ```rust @@ -9148,7 +9148,7 @@ mod m { *C* ```rust - test::m::m2 + ra_test_fixture::m::m2 ``` ```rust @@ -9173,17 +9173,17 @@ macro_rules! foo { foo!(BAR_$0); "#, expect![[r#" - *BAR_* + *BAR_* - ```rust - test - ``` + ```rust + ra_test_fixture + ``` - ```rust - pub static BAR_: {error} = Foo::new(||{ - crate; - }) - ``` + ```rust + pub static BAR_: {error} = Foo::new(||{ + crate; + }) + ``` "#]], ); } @@ -9202,7 +9202,7 @@ type A$0 = B; *A* ```rust - test + ra_test_fixture ``` ```rust @@ -9235,7 +9235,7 @@ type A$0 = B; *A* ```rust - test + ra_test_fixture ``` ```rust @@ -9269,7 +9269,7 @@ type A$0 = B; *A* ```rust - test + ra_test_fixture ``` ```rust @@ -9301,7 +9301,7 @@ type A$0 = B; *A* ```rust - test + ra_test_fixture ``` ```rust @@ -9362,7 +9362,7 @@ trait Compat$0 {} *Compat* ```rust - test + ra_test_fixture ``` ```rust @@ -9384,7 +9384,7 @@ trait UnCompat$0 { *UnCompat* ```rust - test + ra_test_fixture ``` ```rust @@ -9407,7 +9407,7 @@ fn f<T: UnCompat$0> *UnCompat* ```rust - test + ra_test_fixture ``` ```rust @@ -9416,3 +9416,53 @@ fn f<T: UnCompat$0> "#]], ); } + +#[test] +fn issue_18613() { + check( + r#" +fn main() { + struct S<T, D = bool>(); + let x$0 = S::<()>; +}"#, + expect![[r#" + *x* + + ```rust + let x: fn S<()>() -> S<()> + ``` + + --- + + size = 0, align = 1 + "#]], + ); + + check( + r#" +pub struct Global; +pub struct Box<T, A = Global>(T, A); + +impl<T> Box<T> { + pub fn new(x: T) -> Self { loop {} } +} + +pub struct String; + +fn main() { + let box_value$0 = Box::<String>new(); +} +"#, + expect![[r#" + *box_value* + + ```rust + let box_value: fn Box<String>(String, Global) -> Box<String> + ``` + + --- + + size = 0, align = 1 + "#]], + ); +} diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs index c58ca0f01cd..aa99ba49bc8 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs @@ -8,8 +8,8 @@ use hir::{ sym, ClosureStyle, HasVisibility, HirDisplay, HirDisplayError, HirWrite, ModuleDef, ModuleDefId, Semantics, }; -use ide_db::text_edit::TextEdit; use ide_db::{famous_defs::FamousDefs, FileRange, RootDatabase}; +use ide_db::{text_edit::TextEdit, FxHashSet}; use itertools::Itertools; use smallvec::{smallvec, SmallVec}; use span::{Edition, EditionedFileId}; @@ -29,6 +29,7 @@ mod closing_brace; mod closure_captures; mod closure_ret; mod discriminant; +mod extern_block; mod generic_param; mod implicit_drop; mod implicit_static; @@ -116,6 +117,7 @@ pub(crate) fn inlay_hints( #[derive(Default)] struct InlayHintCtx { lifetime_stacks: Vec<Vec<SmolStr>>, + extern_block_parent: Option<ast::ExternBlock>, } pub(crate) fn inlay_hints_resolve( @@ -174,12 +176,18 @@ fn handle_event(ctx: &mut InlayHintCtx, node: WalkEvent<SyntaxNode>) -> Option<S .unwrap_or_default(); ctx.lifetime_stacks.push(params); } + if let Some(node) = ast::ExternBlock::cast(node.clone()) { + ctx.extern_block_parent = Some(node); + } Some(node) } WalkEvent::Leave(n) => { if ast::AnyHasGenericParams::can_cast(n.kind()) { ctx.lifetime_stacks.pop(); } + if ast::ExternBlock::can_cast(n.kind()) { + ctx.extern_block_parent = None; + } None } } @@ -234,12 +242,20 @@ fn hints( ast::Item(it) => match it { ast::Item::Fn(it) => { implicit_drop::hints(hints, famous_defs, config, file_id, &it); + if let Some(extern_block) = &ctx.extern_block_parent { + extern_block::fn_hints(hints, famous_defs, config, file_id, &it, extern_block); + } lifetime::fn_hints(hints, ctx, famous_defs, config, file_id, it) }, - // static type elisions - ast::Item::Static(it) => implicit_static::hints(hints, famous_defs, config, file_id, Either::Left(it)), + ast::Item::Static(it) => { + if let Some(extern_block) = &ctx.extern_block_parent { + extern_block::static_hints(hints, famous_defs, config, file_id, &it, extern_block); + } + implicit_static::hints(hints, famous_defs, config, file_id, Either::Left(it)) + }, ast::Item::Const(it) => implicit_static::hints(hints, famous_defs, config, file_id, Either::Right(it)), ast::Item::Enum(it) => discriminant::enum_hints(hints, famous_defs, config, file_id, it), + ast::Item::ExternBlock(it) => extern_block::extern_block_hints(hints, famous_defs, config, file_id, it), _ => None, }, // FIXME: trait object type elisions @@ -289,6 +305,16 @@ pub struct InlayFieldsToResolve { } impl InlayFieldsToResolve { + pub fn from_client_capabilities(client_capability_fields: &FxHashSet<&str>) -> Self { + Self { + resolve_text_edits: client_capability_fields.contains("textEdits"), + resolve_hint_tooltip: client_capability_fields.contains("tooltip"), + resolve_label_tooltip: client_capability_fields.contains("label.tooltip"), + resolve_label_location: client_capability_fields.contains("label.location"), + resolve_label_command: client_capability_fields.contains("label.command"), + } + } + pub const fn empty() -> Self { Self { resolve_text_edits: false, @@ -358,6 +384,7 @@ pub enum InlayKind { Type, Drop, RangeExclusive, + ExternUnsafety, } #[derive(Debug, Hash)] diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/extern_block.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/extern_block.rs new file mode 100644 index 00000000000..4cc4925cda6 --- /dev/null +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/extern_block.rs @@ -0,0 +1,138 @@ +//! Extern block hints +use ide_db::{famous_defs::FamousDefs, text_edit::TextEdit}; +use span::EditionedFileId; +use syntax::{ast, AstNode, SyntaxToken}; + +use crate::{InlayHint, InlayHintsConfig}; + +pub(super) fn extern_block_hints( + acc: &mut Vec<InlayHint>, + FamousDefs(_sema, _): &FamousDefs<'_, '_>, + _config: &InlayHintsConfig, + _file_id: EditionedFileId, + extern_block: ast::ExternBlock, +) -> Option<()> { + if extern_block.unsafe_token().is_some() { + return None; + } + let abi = extern_block.abi()?; + acc.push(InlayHint { + range: abi.syntax().text_range(), + position: crate::InlayHintPosition::Before, + pad_left: false, + pad_right: true, + kind: crate::InlayKind::ExternUnsafety, + label: crate::InlayHintLabel::from("unsafe"), + text_edit: Some(TextEdit::insert(abi.syntax().text_range().start(), "unsafe ".to_owned())), + resolve_parent: Some(extern_block.syntax().text_range()), + }); + Some(()) +} + +pub(super) fn fn_hints( + acc: &mut Vec<InlayHint>, + FamousDefs(_sema, _): &FamousDefs<'_, '_>, + _config: &InlayHintsConfig, + _file_id: EditionedFileId, + fn_: &ast::Fn, + extern_block: &ast::ExternBlock, +) -> Option<()> { + let implicit_unsafe = fn_.safe_token().is_none() && fn_.unsafe_token().is_none(); + if !implicit_unsafe { + return None; + } + let fn_ = fn_.fn_token()?; + acc.push(item_hint(extern_block, fn_)); + Some(()) +} + +pub(super) fn static_hints( + acc: &mut Vec<InlayHint>, + FamousDefs(_sema, _): &FamousDefs<'_, '_>, + _config: &InlayHintsConfig, + _file_id: EditionedFileId, + static_: &ast::Static, + extern_block: &ast::ExternBlock, +) -> Option<()> { + let implicit_unsafe = static_.safe_token().is_none() && static_.unsafe_token().is_none(); + if !implicit_unsafe { + return None; + } + let static_ = static_.static_token()?; + acc.push(item_hint(extern_block, static_)); + Some(()) +} + +fn item_hint(extern_block: &ast::ExternBlock, token: SyntaxToken) -> InlayHint { + InlayHint { + range: token.text_range(), + position: crate::InlayHintPosition::Before, + pad_left: false, + pad_right: true, + kind: crate::InlayKind::ExternUnsafety, + label: crate::InlayHintLabel::from("unsafe"), + text_edit: { + let mut builder = TextEdit::builder(); + builder.insert(token.text_range().start(), "unsafe ".to_owned()); + if extern_block.unsafe_token().is_none() { + if let Some(abi) = extern_block.abi() { + builder.insert(abi.syntax().text_range().start(), "unsafe ".to_owned()); + } + } + Some(builder.finish()) + }, + resolve_parent: Some(extern_block.syntax().text_range()), + } +} + +#[cfg(test)] +mod tests { + use crate::inlay_hints::tests::{check_with_config, DISABLED_CONFIG}; + + #[test] + fn unadorned() { + check_with_config( + DISABLED_CONFIG, + r#" + extern "C" { +//^^^^^^^^^^ unsafe + static FOO: (); + // ^^^^^^ unsafe + pub static FOO: (); + // ^^^^^^unsafe + unsafe static FOO: (); + safe static FOO: (); + fn foo(); + // ^^ unsafe + pub fn foo(); + // ^^ unsafe + unsafe fn foo(); + safe fn foo(); +} +"#, + ); + } + + #[test] + fn adorned() { + check_with_config( + DISABLED_CONFIG, + r#" +unsafe extern "C" { + static FOO: (); + // ^^^^^^ unsafe + pub static FOO: (); + // ^^^^^^unsafe + unsafe static FOO: (); + safe static FOO: (); + fn foo(); + // ^^ unsafe + pub fn foo(); + // ^^ unsafe + unsafe fn foo(); + safe fn foo(); +} +"#, + ); + } +} diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/lifetime.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/lifetime.rs index 2163c959b18..1fdd6989917 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/lifetime.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/lifetime.rs @@ -41,7 +41,15 @@ pub(super) fn fn_hints( fd, config, file_id, - param_list, + param_list.params().filter_map(|it| { + Some(( + it.pat().and_then(|it| match it { + ast::Pat::IdentPat(p) => p.name(), + _ => None, + }), + it.ty()?, + )) + }), generic_param_list, ret_type, self_param, @@ -90,7 +98,15 @@ pub(super) fn fn_ptr_hints( fd, config, file_id, - param_list, + param_list.params().filter_map(|it| { + Some(( + it.pat().and_then(|it| match it { + ast::Pat::IdentPat(p) => p.name(), + _ => None, + }), + it.ty()?, + )) + }), generic_param_list, ret_type, None, @@ -148,7 +164,7 @@ pub(super) fn fn_path_hints( fd, config, file_id, - param_list, + param_list.type_args().filter_map(|it| Some((None, it.ty()?))), generic_param_list, ret_type, None, @@ -177,8 +193,8 @@ pub(super) fn fn_path_hints( ) } -fn path_as_fn(path: &ast::Path) -> Option<(ast::ParamList, Option<ast::RetType>)> { - path.segment().and_then(|it| it.param_list().zip(Some(it.ret_type()))) +fn path_as_fn(path: &ast::Path) -> Option<(ast::ParenthesizedArgList, Option<ast::RetType>)> { + path.segment().and_then(|it| it.parenthesized_arg_list().zip(Some(it.ret_type()))) } fn hints_( @@ -187,7 +203,7 @@ fn hints_( FamousDefs(_, _): &FamousDefs<'_, '_>, config: &InlayHintsConfig, _file_id: EditionedFileId, - param_list: ast::ParamList, + params: impl Iterator<Item = (Option<ast::Name>, ast::Type)>, generic_param_list: Option<ast::GenericParamList>, ret_type: Option<ast::RetType>, self_param: Option<ast::SelfParam>, @@ -217,45 +233,34 @@ fn hints_( let is_elided = is_elided(&lifetime); acc.push((None, self_param.amp_token(), lifetime, is_elided)); } - param_list - .params() - .filter_map(|it| { - Some(( - it.pat().and_then(|it| match it { - ast::Pat::IdentPat(p) => p.name(), - _ => None, - }), - it.ty()?, - )) - }) - .for_each(|(name, ty)| { - // FIXME: check path types - walk_ty(&ty, &mut |ty| match ty { - ast::Type::RefType(r) => { - let lifetime = r.lifetime(); - let is_elided = is_elided(&lifetime); - acc.push((name.clone(), r.amp_token(), lifetime, is_elided)); - false - } - ast::Type::FnPtrType(_) => { + params.for_each(|(name, ty)| { + // FIXME: check path types + walk_ty(&ty, &mut |ty| match ty { + ast::Type::RefType(r) => { + let lifetime = r.lifetime(); + let is_elided = is_elided(&lifetime); + acc.push((name.clone(), r.amp_token(), lifetime, is_elided)); + false + } + ast::Type::FnPtrType(_) => { + is_trivial = false; + true + } + ast::Type::PathType(t) => { + if t.path() + .and_then(|it| it.segment()) + .and_then(|it| it.parenthesized_arg_list()) + .is_some() + { is_trivial = false; true + } else { + false } - ast::Type::PathType(t) => { - if t.path() - .and_then(|it| it.segment()) - .and_then(|it| it.param_list()) - .is_some() - { - is_trivial = false; - true - } else { - false - } - } - _ => false, - }) - }); + } + _ => false, + }) + }); acc }; @@ -339,7 +344,10 @@ fn hints_( true } ast::Type::PathType(t) => { - if t.path().and_then(|it| it.segment()).and_then(|it| it.param_list()).is_some() + if t.path() + .and_then(|it| it.segment()) + .and_then(|it| it.parenthesized_arg_list()) + .is_some() { is_trivial = false; true diff --git a/src/tools/rust-analyzer/crates/ide/src/lib.rs b/src/tools/rust-analyzer/crates/ide/src/lib.rs index d4ef9570e1a..c960b88a3e9 100644 --- a/src/tools/rust-analyzer/crates/ide/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide/src/lib.rs @@ -402,6 +402,8 @@ impl Analysis { self.with_db(|db| typing::on_enter(db, position)) } + pub const SUPPORTED_TRIGGER_CHARS: &'static str = typing::TRIGGER_CHARS; + /// Returns an edit which should be applied after a character was typed. /// /// This is useful for some on-the-fly fixups, like adding `;` to `let =` @@ -410,14 +412,16 @@ impl Analysis { &self, position: FilePosition, char_typed: char, - autoclose: bool, + chars_to_exclude: Option<String>, ) -> Cancellable<Option<SourceChange>> { // Fast path to not even parse the file. if !typing::TRIGGER_CHARS.contains(char_typed) { return Ok(None); } - if char_typed == '<' && !autoclose { - return Ok(None); + if let Some(chars_to_exclude) = chars_to_exclude { + if chars_to_exclude.contains(char_typed) { + return Ok(None); + } } self.with_db(|db| typing::on_char_typed(db, position, char_typed)) diff --git a/src/tools/rust-analyzer/crates/ide/src/rename.rs b/src/tools/rust-analyzer/crates/ide/src/rename.rs index 665fc954d23..a9519c03b32 100644 --- a/src/tools/rust-analyzer/crates/ide/src/rename.rs +++ b/src/tools/rust-analyzer/crates/ide/src/rename.rs @@ -3105,4 +3105,73 @@ fn main() { let _: Baz; } "#, ); } + + #[test] + fn rename_type_param_ref_in_use_bound() { + check( + "U", + r#" +fn foo<T>() -> impl use<T$0> Trait {} +"#, + r#" +fn foo<U>() -> impl use<U> Trait {} +"#, + ); + } + + #[test] + fn rename_type_param_in_use_bound() { + check( + "U", + r#" +fn foo<T$0>() -> impl use<T> Trait {} +"#, + r#" +fn foo<U>() -> impl use<U> Trait {} +"#, + ); + } + + #[test] + fn rename_lifetime_param_ref_in_use_bound() { + check( + "u", + r#" +fn foo<'t>() -> impl use<'t$0> Trait {} +"#, + r#" +fn foo<'u>() -> impl use<'u> Trait {} +"#, + ); + } + + #[test] + fn rename_lifetime_param_in_use_bound() { + check( + "u", + r#" +fn foo<'t$0>() -> impl use<'t> Trait {} +"#, + r#" +fn foo<'u>() -> impl use<'u> Trait {} +"#, + ); + } + + #[test] + fn rename_parent_type_param_in_use_bound() { + check( + "U", + r#" +trait Trait<T> { + fn foo() -> impl use<T$0> Trait {} +} +"#, + r#" +trait Trait<U> { + fn foo() -> impl use<U> Trait {} +} +"#, + ); + } } diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs index 96375937a12..3767a3917ce 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs @@ -151,6 +151,14 @@ fn punctuation( T!['['] | T![']'] => HlPunct::Bracket, T!['{'] | T!['}'] => HlPunct::Brace, T!['('] | T![')'] => HlPunct::Parenthesis, + T![>] + if parent + .as_ref() + .and_then(SyntaxNode::parent) + .map_or(false, |it| it.kind() == MACRO_RULES) => + { + return HlOperator::Other.into() + } T![<] | T![>] => HlPunct::Angle, T![,] => HlPunct::Comma, T![:] => HlPunct::Colon, diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_block_mod_items.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_block_mod_items.html index 70f2d7203e9..edd9639768a 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_block_mod_items.html +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_block_mod_items.html @@ -46,7 +46,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd .unresolved_reference { color: #FC5555; text-decoration: wavy underline; } </style> <pre><code><span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">foo</span> <span class="brace">{</span> - <span class="parenthesis">(</span><span class="punctuation">$</span>foo<span class="colon">:</span>ident<span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">></span> <span class="brace">{</span> + <span class="parenthesis">(</span><span class="punctuation">$</span>foo<span class="colon">:</span>ident<span class="parenthesis">)</span> <span class="operator">=</span><span class="operator">></span> <span class="brace">{</span> <span class="keyword">mod</span> y <span class="brace">{</span> <span class="keyword">pub</span> <span class="keyword">struct</span> <span class="punctuation">$</span>foo<span class="semicolon">;</span> <span class="brace">}</span> diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_const.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_const.html index a14f2cc88cd..05289cfe3fe 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_const.html +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_const.html @@ -46,7 +46,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd .unresolved_reference { color: #FC5555; text-decoration: wavy underline; } </style> <pre><code><span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">id</span> <span class="brace">{</span> - <span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>tt<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">></span> <span class="brace">{</span> + <span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>tt<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="operator">></span> <span class="brace">{</span> <span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span> <span class="brace">}</span><span class="semicolon">;</span> <span class="brace">}</span> @@ -79,7 +79,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd <span class="brace">}</span> <span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">unsafe_deref</span> <span class="brace">{</span> - <span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">></span> <span class="brace">{</span> + <span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="operator">></span> <span class="brace">{</span> <span class="punctuation">*</span><span class="parenthesis">(</span><span class="punctuation">&</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="keyword">as</span> <span class="punctuation">*</span><span class="keyword">const</span> <span class="parenthesis">(</span><span class="parenthesis">)</span><span class="parenthesis">)</span> <span class="brace">}</span><span class="semicolon">;</span> <span class="brace">}</span></code></pre> \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html index 35650bbe87f..aa9d23250c1 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html @@ -147,11 +147,11 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd <span class="brace">}</span> <span class="comment documentation">/// ```</span> -<span class="comment documentation">///</span><span class="comment documentation"> </span><span class="keyword injected">macro_rules</span><span class="macro_bang injected">!</span><span class="none injected"> </span><span class="macro declaration injected">noop</span><span class="none injected"> </span><span class="brace injected">{</span><span class="none injected"> </span><span class="parenthesis injected">(</span><span class="punctuation injected">$</span><span class="none injected">expr</span><span class="colon injected">:</span><span class="none injected">expr</span><span class="parenthesis injected">)</span><span class="none injected"> </span><span class="operator injected">=</span><span class="angle injected">></span><span class="none injected"> </span><span class="brace injected">{</span><span class="none injected"> </span><span class="punctuation injected">$</span><span class="none injected">expr </span><span class="brace injected">}</span><span class="brace injected">}</span> +<span class="comment documentation">///</span><span class="comment documentation"> </span><span class="keyword injected">macro_rules</span><span class="macro_bang injected">!</span><span class="none injected"> </span><span class="macro declaration injected">noop</span><span class="none injected"> </span><span class="brace injected">{</span><span class="none injected"> </span><span class="parenthesis injected">(</span><span class="punctuation injected">$</span><span class="none injected">expr</span><span class="colon injected">:</span><span class="none injected">expr</span><span class="parenthesis injected">)</span><span class="none injected"> </span><span class="operator injected">=</span><span class="operator injected">></span><span class="none injected"> </span><span class="brace injected">{</span><span class="none injected"> </span><span class="punctuation injected">$</span><span class="none injected">expr </span><span class="brace injected">}</span><span class="brace injected">}</span> <span class="comment documentation">///</span><span class="comment documentation"> </span><span class="macro injected">noop</span><span class="macro_bang injected">!</span><span class="parenthesis injected macro">(</span><span class="numeric_literal injected macro">1</span><span class="parenthesis injected macro">)</span><span class="semicolon injected">;</span> <span class="comment documentation">/// ```</span> <span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">noop</span> <span class="brace">{</span> - <span class="parenthesis">(</span><span class="punctuation">$</span>expr<span class="colon">:</span>expr<span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">></span> <span class="brace">{</span> + <span class="parenthesis">(</span><span class="punctuation">$</span>expr<span class="colon">:</span>expr<span class="parenthesis">)</span> <span class="operator">=</span><span class="operator">></span> <span class="brace">{</span> <span class="punctuation">$</span>expr <span class="brace">}</span> <span class="brace">}</span> diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2015.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2015.html index a790b385786..c2bf94fd9b6 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2015.html +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2015.html @@ -54,7 +54,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd <span class="brace">}</span> <span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">void</span> <span class="brace">{</span> - <span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>tt<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">></span> <span class="brace">{</span><span class="brace">}</span> + <span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>tt<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="operator">></span> <span class="brace">{</span><span class="brace">}</span> <span class="brace">}</span> <span class="keyword">struct</span> <span class="struct declaration">__</span> <span class="keyword">where</span> <span class="self_type_keyword">Self</span><span class="colon">:</span><span class="semicolon">;</span> diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2018.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2018.html index 6dac066bfaa..a30d16d5327 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2018.html +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2018.html @@ -54,7 +54,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd <span class="brace">}</span> <span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">void</span> <span class="brace">{</span> - <span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>tt<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">></span> <span class="brace">{</span><span class="brace">}</span> + <span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>tt<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="operator">></span> <span class="brace">{</span><span class="brace">}</span> <span class="brace">}</span> <span class="keyword">struct</span> <span class="struct declaration">__</span> <span class="keyword">where</span> <span class="self_type_keyword">Self</span><span class="colon">:</span><span class="semicolon">;</span> diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2021.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2021.html index 6dac066bfaa..a30d16d5327 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2021.html +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2021.html @@ -54,7 +54,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd <span class="brace">}</span> <span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">void</span> <span class="brace">{</span> - <span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>tt<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">></span> <span class="brace">{</span><span class="brace">}</span> + <span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>tt<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="operator">></span> <span class="brace">{</span><span class="brace">}</span> <span class="brace">}</span> <span class="keyword">struct</span> <span class="struct declaration">__</span> <span class="keyword">where</span> <span class="self_type_keyword">Self</span><span class="colon">:</span><span class="semicolon">;</span> diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2024.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2024.html index 4ccc4079908..b82a3f9f819 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2024.html +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2024.html @@ -54,7 +54,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd <span class="brace">}</span> <span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">void</span> <span class="brace">{</span> - <span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>tt<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">></span> <span class="brace">{</span><span class="brace">}</span> + <span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>tt<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="operator">></span> <span class="brace">{</span><span class="brace">}</span> <span class="brace">}</span> <span class="keyword">struct</span> <span class="struct declaration">__</span> <span class="keyword">where</span> <span class="self_type_keyword">Self</span><span class="colon">:</span><span class="semicolon">;</span> diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html index 196552020ab..06673d1a73c 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html @@ -54,7 +54,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd <span class="brace macro proc_macro">}</span> <span class="struct declaration macro proc_macro">Foo</span> <span class="keyword macro proc_macro">struct</span> <span class="brace macro proc_macro">}</span> <span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">def_fn</span> <span class="brace">{</span> - <span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>tt<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">></span> <span class="brace">{</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span><span class="brace">}</span> + <span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>tt<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="operator">></span> <span class="brace">{</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span><span class="brace">}</span> <span class="brace">}</span> <span class="macro">def_fn</span><span class="macro_bang">!</span> <span class="brace macro">{</span> @@ -64,24 +64,24 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd <span class="brace macro">}</span> <span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">dont_color_me_braces</span> <span class="brace">{</span> - <span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">></span> <span class="brace">{</span><span class="numeric_literal">0</span><span class="brace">}</span> + <span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="operator">></span> <span class="brace">{</span><span class="numeric_literal">0</span><span class="brace">}</span> <span class="brace">}</span> <span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">noop</span> <span class="brace">{</span> - <span class="parenthesis">(</span><span class="punctuation">$</span>expr<span class="colon">:</span>expr<span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">></span> <span class="brace">{</span> + <span class="parenthesis">(</span><span class="punctuation">$</span>expr<span class="colon">:</span>expr<span class="parenthesis">)</span> <span class="operator">=</span><span class="operator">></span> <span class="brace">{</span> <span class="punctuation">$</span>expr <span class="brace">}</span> <span class="brace">}</span> <span class="comment documentation">/// textually shadow previous definition</span> <span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">noop</span> <span class="brace">{</span> - <span class="parenthesis">(</span><span class="punctuation">$</span>expr<span class="colon">:</span>expr<span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">></span> <span class="brace">{</span> + <span class="parenthesis">(</span><span class="punctuation">$</span>expr<span class="colon">:</span>expr<span class="parenthesis">)</span> <span class="operator">=</span><span class="operator">></span> <span class="brace">{</span> <span class="punctuation">$</span>expr <span class="brace">}</span> <span class="brace">}</span> <span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">keyword_frag</span> <span class="brace">{</span> - <span class="parenthesis">(</span><span class="punctuation">$</span>type<span class="colon">:</span>ty<span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">></span> <span class="parenthesis">(</span><span class="punctuation">$</span>type<span class="parenthesis">)</span> + <span class="parenthesis">(</span><span class="punctuation">$</span>type<span class="colon">:</span>ty<span class="parenthesis">)</span> <span class="operator">=</span><span class="operator">></span> <span class="parenthesis">(</span><span class="punctuation">$</span>type<span class="parenthesis">)</span> <span class="brace">}</span> <span class="keyword">macro</span> <span class="macro declaration">with_args</span><span class="parenthesis">(</span><span class="punctuation">$</span>i<span class="colon">:</span>ident<span class="parenthesis">)</span> <span class="brace">{</span> @@ -95,7 +95,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd <span class="brace">}</span> <span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">id</span> <span class="brace">{</span> - <span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>tt<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">></span> <span class="brace">{</span> + <span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>tt<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="operator">></span> <span class="brace">{</span> <span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span> <span class="brace">}</span><span class="semicolon">;</span> <span class="brace">}</span> diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html index 5594a36e731..1385ae0510a 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html @@ -46,7 +46,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd .unresolved_reference { color: #FC5555; text-decoration: wavy underline; } </style> <pre><code><span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">println</span> <span class="brace">{</span> - <span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>arg<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">></span> <span class="parenthesis">(</span><span class="brace">{</span> + <span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>arg<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="operator">></span> <span class="parenthesis">(</span><span class="brace">{</span> <span class="punctuation">$</span>crate<span class="colon">:</span><span class="colon">:</span>io<span class="colon">:</span><span class="colon">:</span>_print<span class="parenthesis">(</span>format_args_nl<span class="punctuation">!</span><span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>arg<span class="parenthesis">)</span><span class="punctuation">*</span><span class="parenthesis">)</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="brace">}</span><span class="parenthesis">)</span> <span class="brace">}</span> @@ -74,12 +74,12 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd <span class="brace">}</span> <span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">toho</span> <span class="brace">{</span> - <span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">></span> <span class="parenthesis">(</span><span class="punctuation">$</span>crate<span class="colon">:</span><span class="colon">:</span>panic<span class="punctuation">!</span><span class="parenthesis">(</span><span class="string_literal">"not yet implemented"</span><span class="parenthesis">)</span><span class="parenthesis">)</span><span class="semicolon">;</span> - <span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>arg<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">+</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">></span> <span class="parenthesis">(</span><span class="punctuation">$</span>crate<span class="colon">:</span><span class="colon">:</span>panic<span class="punctuation">!</span><span class="parenthesis">(</span><span class="string_literal">"not yet implemented: {}"</span><span class="comma">,</span> format_args<span class="punctuation">!</span><span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>arg<span class="parenthesis">)</span><span class="punctuation">+</span><span class="parenthesis">)</span><span class="parenthesis">)</span><span class="parenthesis">)</span><span class="semicolon">;</span> + <span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="operator">></span> <span class="parenthesis">(</span><span class="punctuation">$</span>crate<span class="colon">:</span><span class="colon">:</span>panic<span class="punctuation">!</span><span class="parenthesis">(</span><span class="string_literal">"not yet implemented"</span><span class="parenthesis">)</span><span class="parenthesis">)</span><span class="semicolon">;</span> + <span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>arg<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">+</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="operator">></span> <span class="parenthesis">(</span><span class="punctuation">$</span>crate<span class="colon">:</span><span class="colon">:</span>panic<span class="punctuation">!</span><span class="parenthesis">(</span><span class="string_literal">"not yet implemented: {}"</span><span class="comma">,</span> format_args<span class="punctuation">!</span><span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>arg<span class="parenthesis">)</span><span class="punctuation">+</span><span class="parenthesis">)</span><span class="parenthesis">)</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="brace">}</span> <span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">reuse_twice</span> <span class="brace">{</span> - <span class="parenthesis">(</span><span class="punctuation">$</span>literal<span class="colon">:</span>literal<span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">></span> <span class="brace">{</span><span class="brace">{</span>stringify<span class="punctuation">!</span><span class="parenthesis">(</span><span class="punctuation">$</span>literal<span class="parenthesis">)</span><span class="semicolon">;</span> format_args<span class="punctuation">!</span><span class="parenthesis">(</span><span class="punctuation">$</span>literal<span class="parenthesis">)</span><span class="brace">}</span><span class="brace">}</span><span class="semicolon">;</span> + <span class="parenthesis">(</span><span class="punctuation">$</span>literal<span class="colon">:</span>literal<span class="parenthesis">)</span> <span class="operator">=</span><span class="operator">></span> <span class="brace">{</span><span class="brace">{</span>stringify<span class="punctuation">!</span><span class="parenthesis">(</span><span class="punctuation">$</span>literal<span class="parenthesis">)</span><span class="semicolon">;</span> format_args<span class="punctuation">!</span><span class="parenthesis">(</span><span class="punctuation">$</span>literal<span class="parenthesis">)</span><span class="brace">}</span><span class="brace">}</span><span class="semicolon">;</span> <span class="brace">}</span> <span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span> diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html index be6176894b4..4e69c82f3da 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html @@ -46,12 +46,12 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd .unresolved_reference { color: #FC5555; text-decoration: wavy underline; } </style> <pre><code><span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">id</span> <span class="brace">{</span> - <span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>tt<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">></span> <span class="brace">{</span> + <span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>tt<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="operator">></span> <span class="brace">{</span> <span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span> <span class="brace">}</span><span class="semicolon">;</span> <span class="brace">}</span> <span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">unsafe_deref</span> <span class="brace">{</span> - <span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">></span> <span class="brace">{</span> + <span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="operator">></span> <span class="brace">{</span> <span class="punctuation">*</span><span class="parenthesis">(</span><span class="punctuation">&</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="keyword">as</span> <span class="punctuation">*</span><span class="keyword">const</span> <span class="parenthesis">(</span><span class="parenthesis">)</span><span class="parenthesis">)</span> <span class="brace">}</span><span class="semicolon">;</span> <span class="brace">}</span> diff --git a/src/tools/rust-analyzer/crates/ide/src/typing.rs b/src/tools/rust-analyzer/crates/ide/src/typing.rs index 9bb5de9f2e3..3d9146cc4c7 100644 --- a/src/tools/rust-analyzer/crates/ide/src/typing.rs +++ b/src/tools/rust-analyzer/crates/ide/src/typing.rs @@ -15,12 +15,14 @@ mod on_enter; +use std::iter; + use ide_db::{base_db::SourceDatabase, FilePosition, RootDatabase}; -use span::EditionedFileId; +use span::{Edition, EditionedFileId}; use syntax::{ algo::{ancestors_at_offset, find_node_at_offset}, ast::{self, edit::IndentLevel, AstToken}, - AstNode, Parse, SourceFile, SyntaxKind, TextRange, TextSize, T, + AstNode, Parse, SourceFile, SyntaxKind, TextRange, TextSize, }; use ide_db::text_edit::TextEdit; @@ -30,7 +32,7 @@ use crate::SourceChange; pub(crate) use on_enter::on_enter; // Don't forget to add new trigger characters to `server_capabilities` in `caps.rs`. -pub(crate) const TRIGGER_CHARS: &str = ".=<>{("; +pub(crate) const TRIGGER_CHARS: &str = ".=<>{(|"; struct ExtendedTextEdit { edit: TextEdit, @@ -47,6 +49,7 @@ struct ExtendedTextEdit { // - typing `.` in a chain method call auto-indents // - typing `{` or `(` in front of an expression inserts a closing `}` or `)` after the expression // - typing `{` in a use item adds a closing `}` in the right place +// - typing `>` to complete a return type `->` will insert a whitespace after it // // VS Code:: // @@ -66,55 +69,67 @@ pub(crate) fn on_char_typed( if !stdx::always!(TRIGGER_CHARS.contains(char_typed)) { return None; } - let file = &db.parse(EditionedFileId::current_edition(position.file_id)); - if !stdx::always!(file.tree().syntax().text().char_at(position.offset) == Some(char_typed)) { + // FIXME: We need to figure out the edition of the file here, but that means hitting the + // database for more than just parsing the file which is bad. + // FIXME: We are hitting the database here, if we are unlucky this call might block momentarily + // causing the editor to feel sluggish! + let edition = Edition::CURRENT_FIXME; + let file = &db.parse(EditionedFileId::new(position.file_id, edition)); + let char_matches_position = + file.tree().syntax().text().char_at(position.offset) == Some(char_typed); + if !stdx::always!(char_matches_position) { return None; } - let edit = on_char_typed_inner(file, position.offset, char_typed)?; + + let edit = on_char_typed_(file, position.offset, char_typed, edition)?; + let mut sc = SourceChange::from_text_edit(position.file_id, edit.edit); sc.is_snippet = edit.is_snippet; Some(sc) } -fn on_char_typed_inner( +fn on_char_typed_( file: &Parse<SourceFile>, offset: TextSize, char_typed: char, + edition: Edition, ) -> Option<ExtendedTextEdit> { - if !stdx::always!(TRIGGER_CHARS.contains(char_typed)) { - return None; - } - let conv = |text_edit: Option<TextEdit>| { - Some(ExtendedTextEdit { edit: text_edit?, is_snippet: false }) - }; match char_typed { - '.' => conv(on_dot_typed(&file.tree(), offset)), - '=' => conv(on_eq_typed(&file.tree(), offset)), - '<' => on_left_angle_typed(&file.tree(), offset), - '>' => conv(on_right_angle_typed(&file.tree(), offset)), - '{' => conv(on_opening_bracket_typed(file, offset, '{')), - '(' => conv(on_opening_bracket_typed(file, offset, '(')), + '.' => on_dot_typed(&file.tree(), offset), + '=' => on_eq_typed(&file.tree(), offset), + '>' => on_right_angle_typed(&file.tree(), offset), + '{' | '(' | '<' => on_opening_delimiter_typed(file, offset, char_typed, edition), + '|' => on_pipe_typed(&file.tree(), offset), _ => None, } + .map(conv) +} + +fn conv(edit: TextEdit) -> ExtendedTextEdit { + ExtendedTextEdit { edit, is_snippet: false } } -/// Inserts a closing bracket when the user types an opening bracket, wrapping an existing expression in a +/// Inserts a closing delimiter when the user types an opening bracket, wrapping an existing expression in a /// block, or a part of a `use` item (for `{`). -fn on_opening_bracket_typed( +fn on_opening_delimiter_typed( file: &Parse<SourceFile>, offset: TextSize, opening_bracket: char, + edition: Edition, ) -> Option<TextEdit> { - let (closing_bracket, expected_ast_bracket) = match opening_bracket { - '{' => ('}', SyntaxKind::L_CURLY), - '(' => (')', SyntaxKind::L_PAREN), + type FilterFn = fn(SyntaxKind) -> bool; + let (closing_bracket, expected_ast_bracket, allowed_kinds) = match opening_bracket { + '{' => ('}', SyntaxKind::L_CURLY, &[ast::Expr::can_cast as FilterFn] as &[FilterFn]), + '(' => ( + ')', + SyntaxKind::L_PAREN, + &[ast::Expr::can_cast as FilterFn, ast::Pat::can_cast, ast::Type::can_cast] + as &[FilterFn], + ), + '<' => ('>', SyntaxKind::L_ANGLE, &[ast::Type::can_cast as FilterFn] as &[FilterFn]), _ => return None, }; - if !stdx::always!(file.tree().syntax().text().char_at(offset) == Some(opening_bracket)) { - return None; - } - let brace_token = file.tree().syntax().token_at_offset(offset).right_biased()?; if brace_token.kind() != expected_ast_bracket { return None; @@ -125,58 +140,53 @@ fn on_opening_bracket_typed( if !stdx::always!(range.len() == TextSize::of(opening_bracket)) { return None; } - // FIXME: Edition - let file = file.reparse(range, "", span::Edition::CURRENT_FIXME); + let reparsed = file.reparse(range, "", edition).tree(); - if let Some(edit) = bracket_expr(&file.tree(), offset, opening_bracket, closing_bracket) { + if let Some(edit) = + on_delimited_node_typed(&reparsed, offset, opening_bracket, closing_bracket, allowed_kinds) + { return Some(edit); } - if closing_bracket == '}' { - if let Some(edit) = brace_use_path(&file.tree(), offset) { - return Some(edit); - } + match opening_bracket { + '{' => on_left_brace_typed(&reparsed, offset), + '<' => on_left_angle_typed(&file.tree(), &reparsed, offset), + _ => None, } +} - return None; - - fn brace_use_path(file: &SourceFile, offset: TextSize) -> Option<TextEdit> { - let segment: ast::PathSegment = find_node_at_offset(file.syntax(), offset)?; - if segment.syntax().text_range().start() != offset { - return None; - } - - let tree: ast::UseTree = find_node_at_offset(file.syntax(), offset)?; - - Some(TextEdit::insert(tree.syntax().text_range().end() + TextSize::of("{"), "}".to_owned())) +fn on_left_brace_typed(reparsed: &SourceFile, offset: TextSize) -> Option<TextEdit> { + let segment: ast::PathSegment = find_node_at_offset(reparsed.syntax(), offset)?; + if segment.syntax().text_range().start() != offset { + return None; } - fn bracket_expr( - file: &SourceFile, - offset: TextSize, - opening_bracket: char, - closing_bracket: char, - ) -> Option<TextEdit> { - let mut expr: ast::Expr = find_node_at_offset(file.syntax(), offset)?; - if expr.syntax().text_range().start() != offset { - return None; - } - - // Enclose the outermost expression starting at `offset` - while let Some(parent) = expr.syntax().parent() { - if parent.text_range().start() != expr.syntax().text_range().start() { - break; - } + let tree: ast::UseTree = find_node_at_offset(reparsed.syntax(), offset)?; - match ast::Expr::cast(parent) { - Some(parent) => expr = parent, - None => break, - } - } + Some(TextEdit::insert(tree.syntax().text_range().end() + TextSize::of("{"), "}".to_owned())) +} - if let Some(parent) = expr.syntax().parent().and_then(ast::Expr::cast) { - let mut node = expr.syntax().clone(); - let all_prev_sib_attr = loop { +fn on_delimited_node_typed( + reparsed: &SourceFile, + offset: TextSize, + opening_bracket: char, + closing_bracket: char, + kinds: &[fn(SyntaxKind) -> bool], +) -> Option<TextEdit> { + let t = reparsed.syntax().token_at_offset(offset).right_biased()?; + let (filter, node) = t + .parent_ancestors() + .take_while(|n| n.text_range().start() == offset) + .find_map(|n| kinds.iter().find(|&kind_filter| kind_filter(n.kind())).zip(Some(n)))?; + let mut node = node + .ancestors() + .take_while(|n| n.text_range().start() == offset && filter(n.kind())) + .last()?; + + if let Some(parent) = node.parent().filter(|it| filter(it.kind())) { + let all_prev_sib_attr = { + let mut node = node.clone(); + loop { match node.prev_sibling() { Some(sib) if sib.kind().is_trivia() || sib.kind() == SyntaxKind::ATTR => { node = sib @@ -184,26 +194,32 @@ fn on_opening_bracket_typed( Some(_) => break false, None => break true, }; - }; - - if all_prev_sib_attr { - expr = parent; } - } + }; - // Insert the closing bracket right after the expression. - Some(TextEdit::insert( - expr.syntax().text_range().end() + TextSize::of(opening_bracket), - closing_bracket.to_string(), - )) + if all_prev_sib_attr { + node = parent; + } } -} + // Insert the closing bracket right after the node. + Some(TextEdit::insert( + node.text_range().end() + TextSize::of(opening_bracket), + closing_bracket.to_string(), + )) +} /// Returns an edit which should be applied after `=` was typed. Primarily, /// this works when adding `let =`. // FIXME: use a snippet completion instead of this hack here. fn on_eq_typed(file: &SourceFile, offset: TextSize) -> Option<TextEdit> { - if !stdx::always!(file.syntax().text().char_at(offset) == Some('=')) { + let text = file.syntax().text(); + let has_newline = iter::successors(Some(offset), |&offset| Some(offset + TextSize::new(1))) + .filter_map(|offset| text.char_at(offset)) + .find(|&c| !c.is_whitespace() || c == '\n') + == Some('n'); + // don't attempt to add `;` if there is a newline after the `=`, the intent is likely to write + // out the expression afterwards! + if has_newline { return None; } @@ -289,9 +305,6 @@ fn on_eq_typed(file: &SourceFile, offset: TextSize) -> Option<TextEdit> { /// Returns an edit which should be applied when a dot ('.') is typed on a blank line, indenting the line appropriately. fn on_dot_typed(file: &SourceFile, offset: TextSize) -> Option<TextEdit> { - if !stdx::always!(file.syntax().text().char_at(offset) == Some('.')) { - return None; - } let whitespace = file.syntax().token_at_offset(offset).left_biased().and_then(ast::Whitespace::cast)?; @@ -342,14 +355,15 @@ fn on_dot_typed(file: &SourceFile, offset: TextSize) -> Option<TextEdit> { } /// Add closing `>` for generic arguments/parameters. -fn on_left_angle_typed(file: &SourceFile, offset: TextSize) -> Option<ExtendedTextEdit> { - let file_text = file.syntax().text(); - if !stdx::always!(file_text.char_at(offset) == Some('<')) { - return None; - } +fn on_left_angle_typed( + file: &SourceFile, + reparsed: &SourceFile, + offset: TextSize, +) -> Option<TextEdit> { + let file_text = reparsed.syntax().text(); - // Find the next non-whitespace char in the line. - let mut next_offset = offset + TextSize::of('<'); + // Find the next non-whitespace char in the line, check if its a `>` + let mut next_offset = offset; while file_text.char_at(next_offset) == Some(' ') { next_offset += TextSize::of(' ') } @@ -357,34 +371,36 @@ fn on_left_angle_typed(file: &SourceFile, offset: TextSize) -> Option<ExtendedTe return None; } - let range = TextRange::at(offset, TextSize::of('<')); - if let Some(t) = file.syntax().token_at_offset(offset).left_biased() { - if T![impl] == t.kind() { - return Some(ExtendedTextEdit { - edit: TextEdit::replace(range, "<$0>".to_owned()), - is_snippet: true, - }); - } - } - - if ancestors_at_offset(file.syntax(), offset).any(|n| { - ast::GenericParamList::can_cast(n.kind()) || ast::GenericArgList::can_cast(n.kind()) - }) { - Some(ExtendedTextEdit { - edit: TextEdit::replace(range, "<$0>".to_owned()), - is_snippet: true, + if ancestors_at_offset(file.syntax(), offset) + .take_while(|n| !ast::Item::can_cast(n.kind())) + .any(|n| { + ast::GenericParamList::can_cast(n.kind()) + || ast::GenericArgList::can_cast(n.kind()) + || ast::UseBoundGenericArgs::can_cast(n.kind()) }) + { + // Insert the closing bracket right after + Some(TextEdit::insert(offset + TextSize::of('<'), '>'.to_string())) } else { None } } +fn on_pipe_typed(file: &SourceFile, offset: TextSize) -> Option<TextEdit> { + let pipe_token = file.syntax().token_at_offset(offset).right_biased()?; + if pipe_token.kind() != SyntaxKind::PIPE { + return None; + } + if pipe_token.parent().and_then(ast::ParamList::cast)?.r_paren_token().is_some() { + return None; + } + let after_lpipe = offset + TextSize::of('|'); + Some(TextEdit::insert(after_lpipe, "|".to_owned())) +} + /// Adds a space after an arrow when `fn foo() { ... }` is turned into `fn foo() -> { ... }` fn on_right_angle_typed(file: &SourceFile, offset: TextSize) -> Option<TextEdit> { let file_text = file.syntax().text(); - if !stdx::always!(file_text.char_at(offset) == Some('>')) { - return None; - } let after_arrow = offset + TextSize::of('>'); if file_text.char_at(after_arrow) != Some('{') { return None; @@ -411,7 +427,7 @@ mod tests { let edit = TextEdit::insert(offset, char_typed.to_string()); edit.apply(&mut before); let parse = SourceFile::parse(&before, span::Edition::CURRENT_FIXME); - on_char_typed_inner(&parse, offset, char_typed).map(|it| { + on_char_typed_(&parse, offset, char_typed, span::Edition::CURRENT_FIXME).map(|it| { it.apply(&mut before); before.to_string() }) @@ -426,7 +442,7 @@ mod tests { fn type_char_noop(char_typed: char, ra_fixture_before: &str) { let file_change = do_type_char(char_typed, ra_fixture_before); - assert!(file_change.is_none()) + assert_eq!(file_change, None) } #[test] @@ -471,6 +487,15 @@ fn foo() { } ", ); + type_char_noop( + '=', + r" +fn foo() { + let foo =$0 + 1 + 1 +} +", + ); } #[test] @@ -1067,6 +1092,81 @@ fn f() { } #[test] + fn adds_closing_parenthesis_for_pat() { + type_char( + '(', + r#" +fn f() { match () { $0() => () } } +"#, + r#" +fn f() { match () { (()) => () } } +"#, + ); + type_char( + '(', + r#" +fn f($0n: ()) {} +"#, + r#" +fn f((n): ()) {} +"#, + ); + } + + #[test] + fn adds_closing_parenthesis_for_ty() { + type_char( + '(', + r#" +fn f(n: $0()) {} +"#, + r#" +fn f(n: (())) {} +"#, + ); + type_char( + '(', + r#" +fn f(n: $0a::b::<d>::c) {} +"#, + r#" +fn f(n: (a::b::<d>::c)) {} +"#, + ); + } + + #[test] + fn adds_closing_angles_for_ty() { + type_char( + '<', + r#" +fn f(n: $0()) {} +"#, + r#" +fn f(n: <()>) {} +"#, + ); + type_char( + '<', + r#" +fn f(n: $0a::b::<d>::c) {} +"#, + r#" +fn f(n: <a::b::<d>::c>) {} +"#, + ); + type_char( + '<', + r#" +fn f(n: a$0b::<d>::c) {} +"#, + r#" +fn f(n: a<>b::<d>::c) {} +"#, + ); + } + + #[test] fn parenthesis_noop_in_string_literal() { // Regression test for #9351 type_char_noop( @@ -1157,6 +1257,12 @@ use $0Thing as _; use some::pa$0th::to::Item; "#, ); + type_char_noop( + '<', + r#" +use some::pa$0th::to::Item; + "#, + ); } #[test] @@ -1170,7 +1276,7 @@ fn foo() { "#, r#" fn foo() { - bar::<$0> + bar::<> } "#, ); @@ -1184,7 +1290,7 @@ fn foo(bar: &[u64]) { "#, r#" fn foo(bar: &[u64]) { - bar.iter().collect::<$0>(); + bar.iter().collect::<>(); } "#, ); @@ -1198,7 +1304,7 @@ fn foo(bar: &[u64]) { fn foo$0() {} "#, r#" -fn foo<$0>() {} +fn foo<>() {} "#, ); type_char( @@ -1207,7 +1313,7 @@ fn foo<$0>() {} fn foo$0 "#, r#" -fn foo<$0> +fn foo<> "#, ); type_char( @@ -1216,7 +1322,7 @@ fn foo<$0> struct Foo$0 {} "#, r#" -struct Foo<$0> {} +struct Foo<> {} "#, ); type_char( @@ -1225,7 +1331,7 @@ struct Foo<$0> {} struct Foo$0(); "#, r#" -struct Foo<$0>(); +struct Foo<>(); "#, ); type_char( @@ -1234,7 +1340,7 @@ struct Foo<$0>(); struct Foo$0 "#, r#" -struct Foo<$0> +struct Foo<> "#, ); type_char( @@ -1243,7 +1349,7 @@ struct Foo<$0> enum Foo$0 "#, r#" -enum Foo<$0> +enum Foo<> "#, ); type_char( @@ -1252,7 +1358,7 @@ enum Foo<$0> trait Foo$0 "#, r#" -trait Foo<$0> +trait Foo<> "#, ); type_char( @@ -1261,16 +1367,7 @@ trait Foo<$0> type Foo$0 = Bar; "#, r#" -type Foo<$0> = Bar; - "#, - ); - type_char( - '<', - r#" -impl$0 Foo {} - "#, - r#" -impl<$0> Foo {} +type Foo<> = Bar; "#, ); type_char( @@ -1279,7 +1376,7 @@ impl<$0> Foo {} impl<T> Foo$0 {} "#, r#" -impl<T> Foo<$0> {} +impl<T> Foo<> {} "#, ); type_char( @@ -1288,7 +1385,7 @@ impl<T> Foo<$0> {} impl Foo$0 {} "#, r#" -impl Foo<$0> {} +impl Foo<> {} "#, ); } @@ -1438,4 +1535,42 @@ fn foo() { "#, ); } + + #[test] + fn completes_pipe_param_list() { + type_char( + '|', + r#" +fn foo() { + $0 +} +"#, + r#" +fn foo() { + || +} +"#, + ); + type_char( + '|', + r#" +fn foo() { + $0 a +} +"#, + r#" +fn foo() { + || a +} +"#, + ); + type_char_noop( + '|', + r#" +fn foo() { + let $0 +} +"#, + ); + } } diff --git a/src/tools/rust-analyzer/crates/intern/src/symbol.rs b/src/tools/rust-analyzer/crates/intern/src/symbol.rs index ef76192ba83..200b14027f8 100644 --- a/src/tools/rust-analyzer/crates/intern/src/symbol.rs +++ b/src/tools/rust-analyzer/crates/intern/src/symbol.rs @@ -77,8 +77,12 @@ impl TaggedArcPtr { } /// Retrieves the tag. + /// + /// # Safety + /// + /// You can only drop the `Arc` if the instance is dropped. #[inline] - pub(crate) fn try_as_arc_owned(self) -> Option<ManuallyDrop<Arc<Box<str>>>> { + pub(crate) unsafe fn try_as_arc_owned(self) -> Option<ManuallyDrop<Arc<Box<str>>>> { // Unpack the tag from the alignment niche let tag = Strict::addr(self.packed.as_ptr()) & Self::BOOL_BITS; if tag != 0 { @@ -245,16 +249,14 @@ impl Symbol { } } - ManuallyDrop::into_inner( - match shard.raw_entry_mut().from_key_hashed_nocheck::<str>(hash, arc.as_ref()) { - RawEntryMut::Occupied(occ) => occ.remove_entry(), - RawEntryMut::Vacant(_) => unreachable!(), - } - .0 - .0 - .try_as_arc_owned() - .unwrap(), - ); + let ptr = match shard.raw_entry_mut().from_key_hashed_nocheck::<str>(hash, arc.as_ref()) { + RawEntryMut::Occupied(occ) => occ.remove_entry(), + RawEntryMut::Vacant(_) => unreachable!(), + } + .0 + .0; + // SAFETY: We're dropping, we have ownership. + ManuallyDrop::into_inner(unsafe { ptr.try_as_arc_owned().unwrap() }); debug_assert_eq!(Arc::count(arc), 1); // Shrink the backing storage if the shard is less than 50% occupied. @@ -267,7 +269,8 @@ impl Symbol { impl Drop for Symbol { #[inline] fn drop(&mut self) { - let Some(arc) = self.repr.try_as_arc_owned() else { + // SAFETY: We're dropping, we have ownership. + let Some(arc) = (unsafe { self.repr.try_as_arc_owned() }) else { return; }; // When the last `Ref` is dropped, remove the object from the global map. @@ -288,7 +291,8 @@ impl Clone for Symbol { } fn increase_arc_refcount(repr: TaggedArcPtr) -> TaggedArcPtr { - let Some(arc) = repr.try_as_arc_owned() else { + // SAFETY: We're not dropping the `Arc`. + let Some(arc) = (unsafe { repr.try_as_arc_owned() }) else { return repr; }; // increase the ref count diff --git a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs index 865518fe941..1120d3c7d60 100644 --- a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs +++ b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs @@ -80,6 +80,7 @@ define_symbols! { self_ = "self", Self_ = "Self", tick_static = "'static", + tick_underscore = "'_", dollar_crate = "$crate", MISSING_NAME = "[missing name]", fn_ = "fn", @@ -99,7 +100,6 @@ define_symbols! { cdecl_dash_unwind = "cdecl-unwind", fastcall_dash_unwind = "fastcall-unwind", msp430_dash_interrupt = "msp430-interrupt", - platform_dash_intrinsic = "platform-intrinsic", ptx_dash_kernel = "ptx-kernel", riscv_dash_interrupt_dash_m = "riscv-interrupt-m", riscv_dash_interrupt_dash_s = "riscv-interrupt-s", @@ -150,6 +150,9 @@ define_symbols! { C, call_mut, call_once, + async_call_once, + async_call_mut, + async_call, call, cdecl, Center, @@ -221,6 +224,9 @@ define_symbols! { fn_mut, fn_once_output, fn_once, + async_fn_once, + async_fn_mut, + async_fn, fn_ptr_addr, fn_ptr_trait, format_alignment, @@ -334,6 +340,8 @@ define_symbols! { Option, Ord, Output, + CallRefFuture, + CallOnceFuture, owned_box, packed, panic_2015, diff --git a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs index 0e1606a6991..cf26845b119 100644 --- a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs +++ b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs @@ -123,7 +123,7 @@ pub fn load_workspace( .collect() }; - let project_folders = ProjectFolders::new(std::slice::from_ref(&ws), &[]); + let project_folders = ProjectFolders::new(std::slice::from_ref(&ws), &[], None); loader.set_config(vfs::loader::Config { load: project_folders.load, watch: vec![], @@ -153,7 +153,11 @@ pub struct ProjectFolders { } impl ProjectFolders { - pub fn new(workspaces: &[ProjectWorkspace], global_excludes: &[AbsPathBuf]) -> ProjectFolders { + pub fn new( + workspaces: &[ProjectWorkspace], + global_excludes: &[AbsPathBuf], + user_config_dir_path: Option<&AbsPath>, + ) -> ProjectFolders { let mut res = ProjectFolders::default(); let mut fsc = FileSetConfig::builder(); let mut local_filesets = vec![]; @@ -291,6 +295,22 @@ impl ProjectFolders { } } + if let Some(user_config_path) = user_config_dir_path { + let ratoml_path = { + let mut p = user_config_path.to_path_buf(); + p.push("rust-analyzer.toml"); + p + }; + + let file_set_roots = vec![VfsPath::from(ratoml_path.to_owned())]; + let entry = vfs::loader::Entry::Files(vec![ratoml_path.to_owned()]); + + res.watch.push(res.load.len()); + res.load.push(entry); + local_filesets.push(fsc.len() as u64); + fsc.add_file_set(file_set_roots) + } + let fsc = fsc.build(); res.source_root_config = SourceRootConfig { fsc, local_filesets }; diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar.rs b/src/tools/rust-analyzer/crates/parser/src/grammar.rs index a50a2182a7b..fe6b904bd88 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar.rs @@ -242,7 +242,7 @@ fn opt_visibility(p: &mut Parser<'_>, in_tuple_field: bool) -> bool { // struct MyStruct(pub ()); if !(in_tuple_field && matches!(p.nth(1), T![ident] | T![')'])) { p.bump(T!['(']); - paths::use_path(p); + paths::vis_path(p); p.expect(T![')']); } } @@ -252,7 +252,7 @@ fn opt_visibility(p: &mut Parser<'_>, in_tuple_field: bool) -> bool { T![in] => { p.bump(T!['(']); p.bump(T![in]); - paths::use_path(p); + paths::vis_path(p); p.expect(T![')']); } _ => {} @@ -307,13 +307,49 @@ fn name(p: &mut Parser<'_>) { name_r(p, TokenSet::EMPTY); } -fn name_ref(p: &mut Parser<'_>) { - if p.at(IDENT) { +fn name_ref_or_self(p: &mut Parser<'_>) { + if matches!(p.current(), T![ident] | T![self]) { let m = p.start(); - p.bump(IDENT); + p.bump_any(); + m.complete(p, NAME_REF); + } else { + p.err_and_bump("expected identifier or `self`"); + } +} + +fn name_ref_or_upper_self(p: &mut Parser<'_>) { + if matches!(p.current(), T![ident] | T![Self]) { + let m = p.start(); + p.bump_any(); + m.complete(p, NAME_REF); + } else { + p.err_and_bump("expected identifier or `Self`"); + } +} + +const PATH_NAME_REF_KINDS: TokenSet = + TokenSet::new(&[IDENT, T![self], T![super], T![crate], T![Self]]); + +fn name_ref_mod_path(p: &mut Parser<'_>) { + if p.at_ts(PATH_NAME_REF_KINDS) { + let m = p.start(); + p.bump_any(); + m.complete(p, NAME_REF); + } else { + p.err_and_bump("expected identifier, `self`, `super`, `crate`, or `Self`"); + } +} + +const PATH_NAME_REF_OR_INDEX_KINDS: TokenSet = + PATH_NAME_REF_KINDS.union(TokenSet::new(&[INT_NUMBER])); + +fn name_ref_mod_path_or_index(p: &mut Parser<'_>) { + if p.at_ts(PATH_NAME_REF_OR_INDEX_KINDS) { + let m = p.start(); + p.bump_any(); m.complete(p, NAME_REF); } else { - p.err_and_bump("expected identifier"); + p.err_and_bump("expected integer, identifier, `self`, `super`, `crate`, or `Self`"); } } diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/attributes.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/attributes.rs index 82e4d661488..ccb556b2cca 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/attributes.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/attributes.rs @@ -36,6 +36,14 @@ fn attr(p: &mut Parser<'_>, inner: bool) { attr.complete(p, ATTR); } +// test_err meta_recovery +// #![] +// #![p = ] +// #![p::] +// #![p:: =] +// #![unsafe] +// #![unsafe =] + // test metas // #![simple_ident] // #![simple::path] @@ -63,7 +71,7 @@ pub(super) fn meta(p: &mut Parser<'_>) { if is_unsafe { p.expect(T!['(']); } - paths::use_path(p); + paths::attr_path(p); match p.current() { T![=] => { diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs index e565874a421..3b3f11be130 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs @@ -449,7 +449,9 @@ fn postfix_dot_expr<const FLOAT_RECOVERY: bool>( let nth1 = if FLOAT_RECOVERY { 0 } else { 1 }; let nth2 = if FLOAT_RECOVERY { 1 } else { 2 }; - if p.nth(nth1) == IDENT && (p.nth(nth2) == T!['('] || p.nth_at(nth2, T![::])) { + if PATH_NAME_REF_KINDS.contains(p.nth(nth1)) + && (p.nth(nth2) == T!['('] || p.nth_at(nth2, T![::])) + { return Ok(method_call_expr::<FLOAT_RECOVERY>(p, lhs)); } @@ -510,22 +512,27 @@ fn index_expr(p: &mut Parser<'_>, lhs: CompletedMarker) -> CompletedMarker { // y.bar::<T>(1, 2,); // x.0.0.call(); // x.0. call(); +// x.0() // } fn method_call_expr<const FLOAT_RECOVERY: bool>( p: &mut Parser<'_>, lhs: CompletedMarker, ) -> CompletedMarker { if FLOAT_RECOVERY { - assert!(p.nth(0) == IDENT && (p.nth(1) == T!['('] || p.nth_at(1, T![::]))); + assert!(p.at_ts(PATH_NAME_REF_KINDS) && (p.nth(1) == T!['('] || p.nth_at(1, T![::]))); } else { - assert!(p.at(T![.]) && p.nth(1) == IDENT && (p.nth(2) == T!['('] || p.nth_at(2, T![::]))); + assert!( + p.at(T![.]) + && PATH_NAME_REF_KINDS.contains(p.nth(1)) + && (p.nth(2) == T!['('] || p.nth_at(2, T![::])) + ); } let m = lhs.precede(p); if !FLOAT_RECOVERY { p.bump(T![.]); } - name_ref(p); - generic_args::opt_generic_arg_list(p, true); + name_ref_mod_path(p); + generic_args::opt_generic_arg_list_expr(p); if p.at(T!['(']) { arg_list(p); } else { @@ -543,6 +550,8 @@ fn method_call_expr<const FLOAT_RECOVERY: bool>( // test field_expr // fn foo() { +// x.self; +// x.Self; // x.foo; // x.0.bar; // x.0.1; @@ -560,8 +569,8 @@ fn field_expr<const FLOAT_RECOVERY: bool>( if !FLOAT_RECOVERY { p.bump(T![.]); } - if p.at(IDENT) || p.at(INT_NUMBER) { - name_ref_or_index(p); + if p.at_ts(PATH_NAME_REF_OR_INDEX_KINDS) { + name_ref_mod_path_or_index(p); } else if p.at(FLOAT_NUMBER) { return match p.split_float(m) { (true, m) => { @@ -679,34 +688,37 @@ pub(crate) fn record_expr_field_list(p: &mut Parser<'_>) { IDENT | INT_NUMBER if p.nth_at(1, T![::]) => { // test_err record_literal_missing_ellipsis_recovery // fn main() { - // S { S::default() } + // S { S::default() }; + // S { 0::default() }; // } m.abandon(p); p.expect(T![..]); expr(p); } + IDENT | INT_NUMBER if p.nth_at(1, T![..]) => { + // test_err record_literal_before_ellipsis_recovery + // fn main() { + // S { field ..S::default() } + // S { 0 ..S::default() } + // } + name_ref_or_index(p); + p.error("expected `:`"); + m.complete(p, RECORD_EXPR_FIELD); + } IDENT | INT_NUMBER => { - if p.nth_at(1, T![..]) { - // test_err record_literal_before_ellipsis_recovery - // fn main() { - // S { field ..S::default() } - // } + // test_err record_literal_field_eq_recovery + // fn main() { + // S { field = foo } + // S { 0 = foo } + // } + if p.nth_at(1, T![:]) { name_ref_or_index(p); - p.error("expected `:`"); - } else { - // test_err record_literal_field_eq_recovery - // fn main() { - // S { field = foo } - // } - if p.nth_at(1, T![:]) { - name_ref_or_index(p); - p.bump(T![:]); - } else if p.nth_at(1, T![=]) { - name_ref_or_index(p); - p.err_and_bump("expected `:`"); - } - expr(p); + p.bump(T![:]); + } else if p.nth_at(1, T![=]) { + name_ref_or_index(p); + p.err_and_bump("expected `:`"); } + expr(p); m.complete(p, RECORD_EXPR_FIELD); } T![.] if p.at(T![..]) => { diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs index 97e0392ce15..407320e1d08 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs @@ -259,13 +259,7 @@ fn builtin_expr(p: &mut Parser<'_>) -> Option<CompletedMarker> { type_(p); p.expect(T![,]); while !p.at(EOF) && !p.at(T![')']) { - if p.at(IDENT) || p.at(INT_NUMBER) { - name_ref_or_index(p); - // } else if p.at(FLOAT_NUMBER) { - // FIXME: needs float hack - } else { - p.err_and_bump("expected field name or number"); - } + name_ref_mod_path_or_index(p); if !p.at(T![')']) { p.expect(T![.]); } @@ -351,10 +345,7 @@ fn parse_asm_expr(p: &mut Parser<'_>, m: Marker) -> Option<CompletedMarker> { name(p); p.bump(T![=]); allow_templates = false; - true - } else { - false - }; + } let op = p.start(); let dir_spec = p.start(); @@ -405,6 +396,19 @@ fn parse_asm_expr(p: &mut Parser<'_>, m: Marker) -> Option<CompletedMarker> { op.abandon(p); op_n.abandon(p); p.err_and_bump("expected asm operand"); + + // improves error recovery and handles err_and_bump recovering from `{` which gets + // the parser stuck here + if p.at(T!['{']) { + // test_err bad_asm_expr + // fn foo() { + // builtin#asm( + // label crashy = { return; } + // ); + // } + expr(p); + } + if p.at(T!['}']) { break; } @@ -465,9 +469,9 @@ fn parse_clobber_abi(p: &mut Parser<'_>) { fn parse_reg(p: &mut Parser<'_>) { p.expect(T!['(']); - if p.at(T![ident]) { + if p.at_ts(PATH_NAME_REF_KINDS) { let m = p.start(); - name_ref(p); + name_ref_mod_path(p); m.complete(p, ASM_REG_SPEC); } else if p.at(T![string]) { let m = p.start(); diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/generic_args.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/generic_args.rs index c62c8a9d3f9..b9d5bff6630 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/generic_args.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/generic_args.rs @@ -1,14 +1,13 @@ use super::*; -// test_err generic_arg_list_recover -// type T = T<0, ,T>; -pub(super) fn opt_generic_arg_list(p: &mut Parser<'_>, colon_colon_required: bool) { +// test_err generic_arg_list_recover_expr +// const _: () = T::<0, ,T>; +// const _: () = T::<0, ,T>(); +pub(super) fn opt_generic_arg_list_expr(p: &mut Parser<'_>) { let m; if p.at(T![::]) && p.nth(2) == T![<] { m = p.start(); p.bump(T![::]); - } else if !colon_colon_required && p.at(T![<]) && p.nth(1) != T![=] { - m = p.start(); } else { return; } @@ -25,7 +24,7 @@ pub(super) fn opt_generic_arg_list(p: &mut Parser<'_>, colon_colon_required: boo m.complete(p, GENERIC_ARG_LIST); } -const GENERIC_ARG_FIRST: TokenSet = TokenSet::new(&[ +pub(crate) const GENERIC_ARG_FIRST: TokenSet = TokenSet::new(&[ LIFETIME_IDENT, IDENT, T!['{'], @@ -46,21 +45,27 @@ const GENERIC_ARG_FIRST: TokenSet = TokenSet::new(&[ const GENERIC_ARG_RECOVERY_SET: TokenSet = TokenSet::new(&[T![>], T![,]]); // test generic_arg -// type T = S<i32>; -fn generic_arg(p: &mut Parser<'_>) -> bool { +// type T = S<i32, dyn T, fn()>; +pub(crate) fn generic_arg(p: &mut Parser<'_>) -> bool { match p.current() { LIFETIME_IDENT if !p.nth_at(1, T![+]) => lifetime_arg(p), T!['{'] | T![true] | T![false] | T![-] => const_arg(p), k if k.is_literal() => const_arg(p), - // test associated_type_bounds - // fn print_all<T: Iterator<Item, Item::Item, Item::<true>, Item: Display, Item<'a> = Item>>(printables: T) {} + // test generic_arg_bounds + // type Plain = Foo<Item, Item::Item, Item: Bound, Item = Item>; + // type GenericArgs = Foo<Item<T>, Item::<T>, Item<T>: Bound, Item::<T>: Bound, Item<T> = Item, Item::<T> = Item>; + // type ParenthesizedArgs = Foo<Item(T), Item::(T), Item(T): Bound, Item::(T): Bound, Item(T) = Item, Item::(T) = Item>; + // type RTN = Foo<Item(..), Item(..), Item(..): Bound, Item(..): Bound, Item(..) = Item, Item(..) = Item>; + // test edition_2015_dyn_prefix_inside_generic_arg 2015 + // type A = Foo<dyn T>; + T![ident] if !p.edition().at_least_2018() && types::is_dyn_weak(p) => type_arg(p), // test macro_inside_generic_arg // type A = Foo<syn::Token![_]>; - IDENT if [T![<], T![=], T![:]].contains(&p.nth(1)) && !p.nth_at(1, T![::]) => { + k if PATH_NAME_REF_KINDS.contains(k) => { let m = p.start(); - name_ref(p); - opt_generic_arg_list(p, false); + name_ref_mod_path(p); + paths::opt_path_type_args(p); match p.current() { T![=] => { p.bump_any(); @@ -88,45 +93,26 @@ fn generic_arg(p: &mut Parser<'_>) -> bool { } // test assoc_type_bound // type T = StreamingIterator<Item<'a>: Clone>; + // type T = StreamingIterator<Item(T): Clone>; T![:] if !p.at(T![::]) => { generic_params::bounds(p); m.complete(p, ASSOC_TYPE_ARG); } + // Turned out to be just a normal path type (mirror `path_or_macro_type`) _ => { let m = m.complete(p, PATH_SEGMENT).precede(p).complete(p, PATH); let m = paths::type_path_for_qualifier(p, m); - m.precede(p).complete(p, PATH_TYPE).precede(p).complete(p, TYPE_ARG); + let m = if p.at(T![!]) && !p.at(T![!=]) { + let m = m.precede(p); + items::macro_call_after_excl(p); + m.complete(p, MACRO_CALL).precede(p).complete(p, MACRO_TYPE) + } else { + m.precede(p).complete(p, PATH_TYPE) + }; + types::opt_type_bounds_as_dyn_trait_type(p, m).precede(p).complete(p, TYPE_ARG); } } } - IDENT if p.nth_at(1, T!['(']) => { - let m = p.start(); - name_ref(p); - if p.nth_at(1, T![..]) { - let rtn = p.start(); - p.bump(T!['(']); - p.bump(T![..]); - p.expect(T![')']); - rtn.complete(p, RETURN_TYPE_SYNTAX); - // test return_type_syntax_assoc_type_bound - // fn foo<T: Trait<method(..): Send>>() {} - generic_params::bounds(p); - m.complete(p, ASSOC_TYPE_ARG); - } else { - params::param_list_fn_trait(p); - // test bare_dyn_types_with_paren_as_generic_args - // type A = S<Fn(i32)>; - // type A = S<Fn(i32) + Send>; - // type B = S<Fn(i32) -> i32>; - // type C = S<Fn(i32) -> i32 + Send>; - opt_ret_type(p); - let m = m.complete(p, PATH_SEGMENT).precede(p).complete(p, PATH); - let m = paths::type_path_for_qualifier(p, m); - let m = m.precede(p).complete(p, PATH_TYPE); - let m = types::opt_type_bounds_as_dyn_trait_type(p, m); - m.precede(p).complete(p, TYPE_ARG); - } - } _ if p.at_ts(types::TYPE_FIRST) => type_arg(p), _ => return false, } @@ -168,10 +154,10 @@ pub(super) fn const_arg_expr(p: &mut Parser<'_>) { expressions::literal(p); lm.complete(p, PREFIX_EXPR); } - _ if paths::is_use_path_start(p) => { + _ if paths::is_path_start(p) => { // This shouldn't be hit by `const_arg` let lm = p.start(); - paths::use_path(p); + paths::expr_path(p); lm.complete(p, PATH_EXPR); } _ => { @@ -190,7 +176,7 @@ pub(super) fn const_arg(p: &mut Parser<'_>) { m.complete(p, CONST_ARG); } -fn type_arg(p: &mut Parser<'_>) { +pub(crate) fn type_arg(p: &mut Parser<'_>) { let m = p.start(); types::type_(p); m.complete(p, TYPE_ARG); diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs index 92311238c23..9d4fdbfaf2e 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs @@ -56,7 +56,7 @@ fn generic_param(p: &mut Parser<'_>, m: Marker) -> bool { fn lifetime_param(p: &mut Parser<'_>, m: Marker) { assert!(p.at(LIFETIME_IDENT)); lifetime(p); - if p.at(T![:]) { + if p.eat(T![:]) { lifetime_bounds(p); } m.complete(p, LIFETIME_PARAM); @@ -106,14 +106,19 @@ fn const_param(p: &mut Parser<'_>, m: Marker) { } fn lifetime_bounds(p: &mut Parser<'_>) { - assert!(p.at(T![:])); - p.bump(T![:]); - while p.at(LIFETIME_IDENT) { - lifetime(p); + let marker = p.start(); + while { + if !matches!(p.current(), LIFETIME_IDENT | T![>] | T![,]) { + p.error("expected lifetime"); + } + + type_bound(p) + } { if !p.eat(T![+]) { break; } } + marker.complete(p, TYPE_BOUND_LIST); } // test type_param_bounds @@ -145,6 +150,9 @@ fn type_bound(p: &mut Parser<'_>) -> bool { T![for] => types::for_type(p, false), // test precise_capturing // fn captures<'a: 'a, 'b: 'b, T>() -> impl Sized + use<'b, T, Self> {} + + // test_err precise_capturing_invalid + // type T = impl use<self, 1>; T![use] if p.nth_at(1, T![<]) => { p.bump_any(); let m = p.start(); @@ -156,14 +164,10 @@ fn type_bound(p: &mut Parser<'_>) -> bool { || "expected identifier or lifetime".into(), TokenSet::new(&[T![Self], IDENT, LIFETIME_IDENT]), |p| { - if p.at(T![Self]) { - let m = p.start(); - p.bump(T![Self]); - m.complete(p, NAME_REF); - } else if p.at(LIFETIME_IDENT) { + if p.at(LIFETIME_IDENT) { lifetime(p); } else { - name_ref(p); + name_ref_or_upper_self(p); } true }, diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/items.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/items.rs index 7d98499008d..8ece5af527d 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/items.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/items.rs @@ -254,22 +254,16 @@ fn opt_item_without_modifiers(p: &mut Parser<'_>, m: Marker) -> Result<(), Marke // test extern_crate // extern crate foo; +// extern crate self; fn extern_crate(p: &mut Parser<'_>, m: Marker) { p.bump(T![extern]); p.bump(T![crate]); - if p.at(T![self]) { - // test extern_crate_self - // extern crate self; - let m = p.start(); - p.bump(T![self]); - m.complete(p, NAME_REF); - } else { - name_ref(p); - } + name_ref_or_self(p); // test extern_crate_rename // extern crate foo as bar; + // extern crate self as bar; opt_rename(p); p.expect(T![;]); m.complete(p, EXTERN_CRATE); diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/params.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/params.rs index c535267c165..51ffcd07069 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/params.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/params.rs @@ -14,12 +14,6 @@ pub(super) fn param_list_fn_def(p: &mut Parser<'_>) { list_(p, Flavor::FnDef); } -// test param_list_opt_patterns -// fn foo<F: FnMut(&mut Foo<'a>)>(){} -pub(super) fn param_list_fn_trait(p: &mut Parser<'_>) { - list_(p, Flavor::FnTrait); -} - pub(super) fn param_list_fn_ptr(p: &mut Parser<'_>) { list_(p, Flavor::FnPointer); } @@ -28,10 +22,9 @@ pub(super) fn param_list_closure(p: &mut Parser<'_>) { list_(p, Flavor::Closure); } -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] enum Flavor { - FnDef, // Includes trait fn params; omitted param idents are not supported - FnTrait, // Params for `Fn(...)`/`FnMut(...)`/`FnOnce(...)` annotations + FnDef, // Includes trait fn params; omitted param idents are not supported FnPointer, Closure, } @@ -41,7 +34,7 @@ fn list_(p: &mut Parser<'_>, flavor: Flavor) { let (bra, ket) = match flavor { Closure => (T![|], T![|]), - FnDef | FnTrait | FnPointer => (T!['('], T![')']), + FnDef | FnPointer => (T!['('], T![')']), }; let list_marker = p.start(); @@ -119,11 +112,6 @@ fn param(p: &mut Parser<'_>, m: Marker, flavor: Flavor) { } } } - // test value_parameters_no_patterns - // type F = Box<Fn(i32, &i32, &i32, ())>; - Flavor::FnTrait => { - types::type_(p); - } // test fn_pointer_param_ident_path // type Foo = fn(Bar::Baz); // type Qux = fn(baz: Bar::Baz); diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/paths.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/paths.rs index 09db921803f..3410505cd46 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/paths.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/paths.rs @@ -19,6 +19,14 @@ pub(super) fn use_path(p: &mut Parser<'_>) { path(p, Mode::Use); } +pub(super) fn vis_path(p: &mut Parser<'_>) { + path(p, Mode::Vis); +} + +pub(super) fn attr_path(p: &mut Parser<'_>) { + path(p, Mode::Attr); +} + pub(crate) fn type_path(p: &mut Parser<'_>) { path(p, Mode::Type); } @@ -37,15 +45,20 @@ pub(crate) fn type_path_for_qualifier( #[derive(Clone, Copy, Eq, PartialEq)] enum Mode { Use, + Attr, Type, Expr, + Vis, } -fn path(p: &mut Parser<'_>, mode: Mode) { +fn path(p: &mut Parser<'_>, mode: Mode) -> Option<CompletedMarker> { let path = p.start(); - path_segment(p, mode, true); + if path_segment(p, mode, true).is_none() { + path.abandon(p); + return None; + } let qual = path.complete(p, PATH); - path_for_qualifier(p, mode, qual); + Some(path_for_qualifier(p, mode, qual)) } fn path_for_qualifier( @@ -71,7 +84,7 @@ const EXPR_PATH_SEGMENT_RECOVERY_SET: TokenSet = items::ITEM_RECOVERY_SET.union(TokenSet::new(&[T![')'], T![,], T![let]])); const TYPE_PATH_SEGMENT_RECOVERY_SET: TokenSet = types::TYPE_RECOVERY_SET; -fn path_segment(p: &mut Parser<'_>, mode: Mode, first: bool) { +fn path_segment(p: &mut Parser<'_>, mode: Mode, first: bool) -> Option<CompletedMarker> { let m = p.start(); // test qual_paths // type X = <A as B>::Output; @@ -93,75 +106,105 @@ fn path_segment(p: &mut Parser<'_>, mode: Mode, first: bool) { p.error("expected `::`"); } } else { - let empty = if first { - p.eat(T![::]); - false - } else { - true - }; - match p.current() { - IDENT => { - name_ref(p); - opt_path_type_args(p, mode); - } + let mut empty = if first { !p.eat(T![::]) } else { true }; + if p.at_ts(PATH_NAME_REF_KINDS) { // test crate_path // use crate::foo; - T![self] | T![super] | T![crate] | T![Self] => { - let m = p.start(); - p.bump_any(); - m.complete(p, NAME_REF); - } - _ => { - let recover_set = match mode { - Mode::Use => items::ITEM_RECOVERY_SET, - Mode::Type => TYPE_PATH_SEGMENT_RECOVERY_SET, - Mode::Expr => EXPR_PATH_SEGMENT_RECOVERY_SET, - }; - p.err_recover("expected identifier", recover_set); - if empty { - // test_err empty_segment - // use crate::; - m.abandon(p); - return; + name_ref_mod_path(p); + opt_path_args(p, mode); + } else { + let recover_set = match mode { + Mode::Use => items::ITEM_RECOVERY_SET, + Mode::Attr => { + items::ITEM_RECOVERY_SET.union(TokenSet::new(&[T![']'], T![=], T![#]])) } + Mode::Vis => items::ITEM_RECOVERY_SET.union(TokenSet::new(&[T![')']])), + Mode::Type => TYPE_PATH_SEGMENT_RECOVERY_SET, + Mode::Expr => EXPR_PATH_SEGMENT_RECOVERY_SET, + }; + empty &= p.err_recover( + "expected identifier, `self`, `super`, `crate`, or `Self`", + recover_set, + ); + if empty { + // test_err empty_segment + // use crate::; + m.abandon(p); + return None; } - }; + } } - m.complete(p, PATH_SEGMENT); + Some(m.complete(p, PATH_SEGMENT)) } -fn opt_path_type_args(p: &mut Parser<'_>, mode: Mode) { +pub(crate) fn opt_path_type_args(p: &mut Parser<'_>) { + // test typepathfn_with_coloncolon + // type F = Start::(Middle) -> (Middle)::End; + // type GenericArg = S<Start(Middle)::End>; + let m; + if p.at(T![::]) && matches!(p.nth(2), T![<] | T!['(']) { + m = p.start(); + p.bump(T![::]); + } else if (p.current() == T![<] && p.nth(1) != T![=]) || p.current() == T!['('] { + m = p.start(); + } else { + return; + } + let current = p.current(); + if current == T![<] { + // test_err generic_arg_list_recover + // type T = T<0, ,T>; + // type T = T::<0, ,T>; + delimited( + p, + T![<], + T![>], + T![,], + || "expected generic argument".into(), + generic_args::GENERIC_ARG_FIRST, + generic_args::generic_arg, + ); + m.complete(p, GENERIC_ARG_LIST); + } else if p.nth_at(1, T![..]) { + // test return_type_syntax_in_path + // fn foo<T>() + // where + // T::method(..): Send, + // method(..): Send, + // method::(..): Send, + // {} + p.bump(T!['(']); + p.bump(T![..]); + p.expect(T![')']); + m.complete(p, RETURN_TYPE_SYNTAX); + } else { + // test path_fn_trait_args + // type F = Box<Fn(i32) -> ()>; + // type F = Box<::Fn(i32) -> ()>; + // type F = Box<Fn::(i32) -> ()>; + // type F = Box<::Fn::(i32) -> ()>; + delimited( + p, + T!['('], + T![')'], + T![,], + || "expected type".into(), + types::TYPE_FIRST, + |p| { + let progress = types::TYPE_FIRST.contains(p.current()); + generic_args::type_arg(p); + progress + }, + ); + m.complete(p, PARENTHESIZED_ARG_LIST); + opt_ret_type(p); + } +} + +fn opt_path_args(p: &mut Parser<'_>, mode: Mode) { match mode { - Mode::Use => {} - Mode::Type => { - // test typepathfn_with_coloncolon - // type F = Start::(Middle) -> (Middle)::End; - // type GenericArg = S<Start(Middle)::End>; - if p.at(T![::]) && p.nth_at(2, T!['(']) { - p.bump(T![::]); - } - if p.at(T!['(']) { - if p.nth_at(1, T![..]) { - // test return_type_syntax_in_path - // fn foo<T>() - // where - // T::method(..): Send, - // {} - let rtn = p.start(); - p.bump(T!['(']); - p.bump(T![..]); - p.expect(T![')']); - rtn.complete(p, RETURN_TYPE_SYNTAX); - } else { - // test path_fn_trait_args - // type F = Box<Fn(i32) -> ()>; - params::param_list_fn_trait(p); - opt_ret_type(p); - } - } else { - generic_args::opt_generic_arg_list(p, false); - } - } - Mode::Expr => generic_args::opt_generic_arg_list(p, true), + Mode::Use | Mode::Attr | Mode::Vis => {} + Mode::Type => opt_path_type_args(p), + Mode::Expr => generic_args::opt_generic_arg_list_expr(p), } } diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/types.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/types.rs index f4e57d3d6f3..0133b7d5d82 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/types.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/types.rs @@ -50,7 +50,7 @@ fn type_with_bounds_cond(p: &mut Parser<'_>, allow_bounds: bool) { // Some path types are not allowed to have bounds (no plus) T![<] => path_type_bounds(p, allow_bounds), T![ident] if !p.edition().at_least_2018() && is_dyn_weak(p) => dyn_trait_type_weak(p), - _ if paths::is_path_start(p) => path_or_macro_type_(p, allow_bounds), + _ if paths::is_path_start(p) => path_or_macro_type(p, allow_bounds), LIFETIME_IDENT if p.nth_at(1, T![+]) => bare_dyn_trait_type(p), _ => { p.err_recover("expected type", TYPE_RECOVERY_SET); @@ -58,7 +58,7 @@ fn type_with_bounds_cond(p: &mut Parser<'_>, allow_bounds: bool) { } } -fn is_dyn_weak(p: &Parser<'_>) -> bool { +pub(crate) fn is_dyn_weak(p: &Parser<'_>) -> bool { const WEAK_DYN_PATH_FIRST: TokenSet = TokenSet::new(&[ IDENT, T![self], @@ -337,7 +337,7 @@ pub(super) fn path_type(p: &mut Parser<'_>) { // test macro_call_type // type A = foo!(); // type B = crate::foo!(); -fn path_or_macro_type_(p: &mut Parser<'_>, allow_bounds: bool) { +fn path_or_macro_type(p: &mut Parser<'_>, allow_bounds: bool) { assert!(paths::is_path_start(p)); let r = p.start(); let m = p.start(); diff --git a/src/tools/rust-analyzer/crates/parser/src/parser.rs b/src/tools/rust-analyzer/crates/parser/src/parser.rs index f6b3783d1ca..75a75f601cf 100644 --- a/src/tools/rust-analyzer/crates/parser/src/parser.rs +++ b/src/tools/rust-analyzer/crates/parser/src/parser.rs @@ -258,22 +258,25 @@ impl<'t> Parser<'t> { self.err_recover(message, TokenSet::EMPTY); } - /// Create an error node and consume the next token. - pub(crate) fn err_recover(&mut self, message: &str, recovery: TokenSet) { + /// Create an error node and consume the next token unless it is in the recovery set. + /// + /// Returns true if recovery kicked in. + pub(crate) fn err_recover(&mut self, message: &str, recovery: TokenSet) -> bool { if matches!(self.current(), T!['{'] | T!['}']) { self.error(message); - return; + return true; } if self.at_ts(recovery) { self.error(message); - return; + return true; } let m = self.start(); self.error(message); self.bump_any(); m.complete(self, ERROR); + false } fn do_bump(&mut self, kind: SyntaxKind, n_raw_tokens: u8) { @@ -324,10 +327,10 @@ impl Marker { self.bomb.defuse(); let idx = self.pos as usize; if idx == p.events.len() - 1 { - match p.events.pop() { - Some(Event::Start { kind: TOMBSTONE, forward_parent: None }) => (), - _ => unreachable!(), - } + assert!(matches!( + p.events.pop(), + Some(Event::Start { kind: TOMBSTONE, forward_parent: None }) + )); } } } diff --git a/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs b/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs index 21730244a33..0c9c6ffd715 100644 --- a/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs +++ b/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs @@ -256,6 +256,7 @@ pub enum SyntaxKind { OR_PAT, PARAM, PARAM_LIST, + PARENTHESIZED_ARG_LIST, PAREN_EXPR, PAREN_PAT, PAREN_TYPE, diff --git a/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs b/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs index 62b381b6688..003b7fda947 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs +++ b/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs @@ -39,10 +39,6 @@ mod ok { #[test] fn assoc_type_eq() { run_and_expect_no_errors("test_data/parser/inline/ok/assoc_type_eq.rs"); } #[test] - fn associated_type_bounds() { - run_and_expect_no_errors("test_data/parser/inline/ok/associated_type_bounds.rs"); - } - #[test] fn async_trait_bound() { run_and_expect_no_errors("test_data/parser/inline/ok/async_trait_bound.rs"); } @@ -59,12 +55,6 @@ mod ok { ); } #[test] - fn bare_dyn_types_with_paren_as_generic_args() { - run_and_expect_no_errors( - "test_data/parser/inline/ok/bare_dyn_types_with_paren_as_generic_args.rs", - ); - } - #[test] fn become_expr() { run_and_expect_no_errors("test_data/parser/inline/ok/become_expr.rs"); } #[test] fn bind_pat() { run_and_expect_no_errors("test_data/parser/inline/ok/bind_pat.rs"); } @@ -200,6 +190,13 @@ mod ok { ); } #[test] + fn edition_2015_dyn_prefix_inside_generic_arg() { + run_and_expect_no_errors_with_edition( + "test_data/parser/inline/ok/edition_2015_dyn_prefix_inside_generic_arg.rs", + crate::Edition::Edition2015, + ); + } + #[test] fn effect_blocks() { run_and_expect_no_errors("test_data/parser/inline/ok/effect_blocks.rs"); } #[test] fn exclusive_range_pat() { @@ -220,10 +217,6 @@ mod ok { run_and_expect_no_errors("test_data/parser/inline/ok/extern_crate_rename.rs"); } #[test] - fn extern_crate_self() { - run_and_expect_no_errors("test_data/parser/inline/ok/extern_crate_self.rs"); - } - #[test] fn field_expr() { run_and_expect_no_errors("test_data/parser/inline/ok/field_expr.rs"); } #[test] fn fn_() { run_and_expect_no_errors("test_data/parser/inline/ok/fn_.rs"); } @@ -281,6 +274,10 @@ mod ok { #[test] fn generic_arg() { run_and_expect_no_errors("test_data/parser/inline/ok/generic_arg.rs"); } #[test] + fn generic_arg_bounds() { + run_and_expect_no_errors("test_data/parser/inline/ok/generic_arg_bounds.rs"); + } + #[test] fn generic_param_attribute() { run_and_expect_no_errors("test_data/parser/inline/ok/generic_param_attribute.rs"); } @@ -423,10 +420,6 @@ mod ok { #[test] fn param_list() { run_and_expect_no_errors("test_data/parser/inline/ok/param_list.rs"); } #[test] - fn param_list_opt_patterns() { - run_and_expect_no_errors("test_data/parser/inline/ok/param_list_opt_patterns.rs"); - } - #[test] fn param_list_vararg() { run_and_expect_no_errors("test_data/parser/inline/ok/param_list_vararg.rs"); } @@ -521,12 +514,6 @@ mod ok { #[test] fn return_expr() { run_and_expect_no_errors("test_data/parser/inline/ok/return_expr.rs"); } #[test] - fn return_type_syntax_assoc_type_bound() { - run_and_expect_no_errors( - "test_data/parser/inline/ok/return_type_syntax_assoc_type_bound.rs", - ); - } - #[test] fn return_type_syntax_in_path() { run_and_expect_no_errors("test_data/parser/inline/ok/return_type_syntax_in_path.rs"); } @@ -685,10 +672,6 @@ mod ok { #[test] fn use_tree_star() { run_and_expect_no_errors("test_data/parser/inline/ok/use_tree_star.rs"); } #[test] - fn value_parameters_no_patterns() { - run_and_expect_no_errors("test_data/parser/inline/ok/value_parameters_no_patterns.rs"); - } - #[test] fn variant_discriminant() { run_and_expect_no_errors("test_data/parser/inline/ok/variant_discriminant.rs"); } @@ -728,6 +711,8 @@ mod err { run_and_expect_errors("test_data/parser/inline/err/async_without_semicolon.rs"); } #[test] + fn bad_asm_expr() { run_and_expect_errors("test_data/parser/inline/err/bad_asm_expr.rs"); } + #[test] fn comma_after_functional_update_syntax() { run_and_expect_errors( "test_data/parser/inline/err/comma_after_functional_update_syntax.rs", @@ -754,6 +739,10 @@ mod err { run_and_expect_errors("test_data/parser/inline/err/generic_arg_list_recover.rs"); } #[test] + fn generic_arg_list_recover_expr() { + run_and_expect_errors("test_data/parser/inline/err/generic_arg_list_recover_expr.rs"); + } + #[test] fn generic_param_list_recover() { run_and_expect_errors("test_data/parser/inline/err/generic_param_list_recover.rs"); } @@ -772,6 +761,8 @@ mod err { run_and_expect_errors("test_data/parser/inline/err/match_arms_recovery.rs"); } #[test] + fn meta_recovery() { run_and_expect_errors("test_data/parser/inline/err/meta_recovery.rs"); } + #[test] fn method_call_missing_argument_list() { run_and_expect_errors("test_data/parser/inline/err/method_call_missing_argument_list.rs"); } @@ -788,6 +779,10 @@ mod err { run_and_expect_errors("test_data/parser/inline/err/pointer_type_no_mutability.rs"); } #[test] + fn precise_capturing_invalid() { + run_and_expect_errors("test_data/parser/inline/err/precise_capturing_invalid.rs"); + } + #[test] fn pub_expr() { run_and_expect_errors("test_data/parser/inline/err/pub_expr.rs"); } #[test] fn record_literal_before_ellipsis_recovery() { diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0004_use_path_bad_segment.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0004_use_path_bad_segment.rast index 44e192a5fcb..7273c98456e 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0004_use_path_bad_segment.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0004_use_path_bad_segment.rast @@ -9,7 +9,8 @@ SOURCE_FILE NAME_REF IDENT "foo" COLON2 "::" - ERROR - INT_NUMBER "92" + PATH_SEGMENT + ERROR + INT_NUMBER "92" SEMICOLON ";" -error 9: expected identifier +error 9: expected identifier, `self`, `super`, `crate`, or `Self` diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0048_double_fish.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0048_double_fish.rast index 207a5c24dff..47daaf7b3b3 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0048_double_fish.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0048_double_fish.rast @@ -39,8 +39,9 @@ SOURCE_FILE IDENT "lol" R_ANGLE ">" COLON2 "::" - ERROR - L_ANGLE "<" + PATH_SEGMENT + ERROR + L_ANGLE "<" TYPE_ARG PATH_TYPE PATH @@ -91,8 +92,9 @@ SOURCE_FILE IDENT "lol" R_ANGLE ">" COLON2 "::" - ERROR - L_ANGLE "<" + PATH_SEGMENT + ERROR + L_ANGLE "<" EXPR_STMT BIN_EXPR PATH_EXPR @@ -113,10 +115,10 @@ SOURCE_FILE WHITESPACE "\n" R_CURLY "}" WHITESPACE "\n" -error 30: expected identifier +error 30: expected identifier, `self`, `super`, `crate`, or `Self` error 31: expected COMMA error 37: expected expression -error 75: expected identifier +error 75: expected identifier, `self`, `super`, `crate`, or `Self` error 76: expected SEMICOLON error 82: expected expression error 83: expected SEMICOLON diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/arg_list_recovery.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/arg_list_recovery.rast index cd5aa680c65..755b20bb271 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/arg_list_recovery.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/arg_list_recovery.rast @@ -98,7 +98,7 @@ SOURCE_FILE WHITESPACE "\n" R_CURLY "}" WHITESPACE "\n" -error 25: expected identifier +error 25: expected identifier, `self`, `super`, `crate`, or `Self` error 39: expected COMMA error 39: expected expression error 55: expected expression diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/bad_asm_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/bad_asm_expr.rast new file mode 100644 index 00000000000..306446e64dd --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/bad_asm_expr.rast @@ -0,0 +1,50 @@ +SOURCE_FILE + FN + FN_KW "fn" + WHITESPACE " " + NAME + IDENT "foo" + PARAM_LIST + L_PAREN "(" + R_PAREN ")" + WHITESPACE " " + BLOCK_EXPR + STMT_LIST + L_CURLY "{" + WHITESPACE "\n " + EXPR_STMT + ASM_EXPR + BUILTIN_KW "builtin" + POUND "#" + ASM_KW "asm" + L_PAREN "(" + WHITESPACE "\n " + PATH_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "label" + WHITESPACE " " + NAME + IDENT "crashy" + WHITESPACE " " + EQ "=" + WHITESPACE " " + BLOCK_EXPR + STMT_LIST + L_CURLY "{" + WHITESPACE " " + EXPR_STMT + RETURN_EXPR + RETURN_KW "return" + SEMICOLON ";" + WHITESPACE " " + R_CURLY "}" + WHITESPACE "\n " + R_PAREN ")" + SEMICOLON ";" + WHITESPACE "\n" + R_CURLY "}" + WHITESPACE "\n" +error 41: expected COMMA +error 50: expected asm operand diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/bad_asm_expr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/bad_asm_expr.rs new file mode 100644 index 00000000000..6056f925e33 --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/bad_asm_expr.rs @@ -0,0 +1,5 @@ +fn foo() { + builtin#asm( + label crashy = { return; } + ); +} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/crate_visibility_empty_recover.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/crate_visibility_empty_recover.rast index 0fe4ca42d79..172bc099b58 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/crate_visibility_empty_recover.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/crate_visibility_empty_recover.rast @@ -3,10 +3,7 @@ SOURCE_FILE VISIBILITY PUB_KW "pub" L_PAREN "(" - PATH - PATH_SEGMENT - ERROR - R_PAREN ")" + R_PAREN ")" WHITESPACE " " STRUCT_KW "struct" WHITESPACE " " @@ -14,5 +11,4 @@ SOURCE_FILE IDENT "S" SEMICOLON ";" WHITESPACE "\n" -error 4: expected identifier -error 5: expected R_PAREN +error 4: expected identifier, `self`, `super`, `crate`, or `Self` diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/empty_segment.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/empty_segment.rast index b03f5ad9f7e..7f256218eff 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/empty_segment.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/empty_segment.rast @@ -11,4 +11,4 @@ SOURCE_FILE COLON2 "::" SEMICOLON ";" WHITESPACE "\n" -error 11: expected identifier +error 11: expected identifier, `self`, `super`, `crate`, or `Self` diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/generic_arg_list_recover.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/generic_arg_list_recover.rast index 4cf5a3386b9..16183ce9ef5 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/generic_arg_list_recover.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/generic_arg_list_recover.rast @@ -30,4 +30,37 @@ SOURCE_FILE R_ANGLE ">" SEMICOLON ";" WHITESPACE "\n" + TYPE_ALIAS + TYPE_KW "type" + WHITESPACE " " + NAME + IDENT "T" + WHITESPACE " " + EQ "=" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "T" + GENERIC_ARG_LIST + COLON2 "::" + L_ANGLE "<" + CONST_ARG + LITERAL + INT_NUMBER "0" + COMMA "," + WHITESPACE " " + ERROR + COMMA "," + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "T" + R_ANGLE ">" + SEMICOLON ";" + WHITESPACE "\n" error 14: expected generic argument +error 35: expected generic argument diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/generic_arg_list_recover.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/generic_arg_list_recover.rs index 7d849aa1bee..aa65a0673a4 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/generic_arg_list_recover.rs +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/generic_arg_list_recover.rs @@ -1 +1,2 @@ type T = T<0, ,T>; +type T = T::<0, ,T>; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/generic_arg_list_recover_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/generic_arg_list_recover_expr.rast new file mode 100644 index 00000000000..de403d30494 --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/generic_arg_list_recover_expr.rast @@ -0,0 +1,79 @@ +SOURCE_FILE + CONST + CONST_KW "const" + WHITESPACE " " + UNDERSCORE "_" + COLON ":" + WHITESPACE " " + TUPLE_TYPE + L_PAREN "(" + R_PAREN ")" + WHITESPACE " " + EQ "=" + WHITESPACE " " + PATH_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "T" + GENERIC_ARG_LIST + COLON2 "::" + L_ANGLE "<" + CONST_ARG + LITERAL + INT_NUMBER "0" + COMMA "," + WHITESPACE " " + ERROR + COMMA "," + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "T" + R_ANGLE ">" + SEMICOLON ";" + WHITESPACE "\n" + CONST + CONST_KW "const" + WHITESPACE " " + UNDERSCORE "_" + COLON ":" + WHITESPACE " " + TUPLE_TYPE + L_PAREN "(" + R_PAREN ")" + WHITESPACE " " + EQ "=" + WHITESPACE " " + CALL_EXPR + PATH_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "T" + GENERIC_ARG_LIST + COLON2 "::" + L_ANGLE "<" + CONST_ARG + LITERAL + INT_NUMBER "0" + COMMA "," + WHITESPACE " " + ERROR + COMMA "," + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "T" + R_ANGLE ">" + ARG_LIST + L_PAREN "(" + R_PAREN ")" + SEMICOLON ";" + WHITESPACE "\n" +error 21: expected generic argument +error 47: expected generic argument diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/generic_arg_list_recover_expr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/generic_arg_list_recover_expr.rs new file mode 100644 index 00000000000..74cc63ac4a0 --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/generic_arg_list_recover_expr.rs @@ -0,0 +1,2 @@ +const _: () = T::<0, ,T>; +const _: () = T::<0, ,T>(); diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/meta_recovery.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/meta_recovery.rast new file mode 100644 index 00000000000..b5c16e0798c --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/meta_recovery.rast @@ -0,0 +1,83 @@ +SOURCE_FILE + ATTR + POUND "#" + BANG "!" + L_BRACK "[" + META + R_BRACK "]" + WHITESPACE "\n" + ATTR + POUND "#" + BANG "!" + L_BRACK "[" + META + PATH + PATH_SEGMENT + NAME_REF + IDENT "p" + WHITESPACE " " + EQ "=" + WHITESPACE " " + R_BRACK "]" + WHITESPACE "\n" + ATTR + POUND "#" + BANG "!" + L_BRACK "[" + META + PATH + PATH + PATH_SEGMENT + NAME_REF + IDENT "p" + COLON2 "::" + R_BRACK "]" + WHITESPACE "\n" + ATTR + POUND "#" + BANG "!" + L_BRACK "[" + META + PATH + PATH + PATH_SEGMENT + NAME_REF + IDENT "p" + COLON2 "::" + WHITESPACE " " + EQ "=" + R_BRACK "]" + WHITESPACE "\n" + ATTR + POUND "#" + BANG "!" + L_BRACK "[" + META + UNSAFE_KW "unsafe" + R_BRACK "]" + WHITESPACE "\n" + ATTR + POUND "#" + BANG "!" + L_BRACK "[" + META + UNSAFE_KW "unsafe" + WHITESPACE " " + EQ "=" + R_BRACK "]" + WHITESPACE "\n" +error 3: expected identifier, `self`, `super`, `crate`, or `Self` +error 11: expected expression +error 11: expected expression +error 20: expected identifier, `self`, `super`, `crate`, or `Self` +error 28: expected identifier, `self`, `super`, `crate`, or `Self` +error 30: expected expression +error 30: expected expression +error 41: expected L_PAREN +error 41: expected identifier, `self`, `super`, `crate`, or `Self` +error 41: expected R_PAREN +error 52: expected L_PAREN +error 52: expected identifier, `self`, `super`, `crate`, or `Self` +error 54: expected expression +error 54: expected expression +error 54: expected R_PAREN diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/meta_recovery.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/meta_recovery.rs new file mode 100644 index 00000000000..51d30adf8b4 --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/meta_recovery.rs @@ -0,0 +1,6 @@ +#![] +#![p = ] +#![p::] +#![p:: =] +#![unsafe] +#![unsafe =] diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/precise_capturing_invalid.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/precise_capturing_invalid.rast new file mode 100644 index 00000000000..5ae184c5feb --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/precise_capturing_invalid.rast @@ -0,0 +1,28 @@ +SOURCE_FILE + TYPE_ALIAS + TYPE_KW "type" + WHITESPACE " " + NAME + IDENT "T" + WHITESPACE " " + EQ "=" + WHITESPACE " " + IMPL_TRAIT_TYPE + IMPL_KW "impl" + WHITESPACE " " + TYPE_BOUND_LIST + TYPE_BOUND + USE_KW "use" + USE_BOUND_GENERIC_ARGS + L_ANGLE "<" + ERROR + SELF_KW "self" + COMMA "," + WHITESPACE " " + ERROR + INT_NUMBER "1" + R_ANGLE ">" + SEMICOLON ";" + WHITESPACE "\n" +error 18: expected identifier or `Self` +error 24: expected identifier or `Self` diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/precise_capturing_invalid.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/precise_capturing_invalid.rs new file mode 100644 index 00000000000..3180338d33f --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/precise_capturing_invalid.rs @@ -0,0 +1 @@ +type T = impl use<self, 1>; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_before_ellipsis_recovery.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_before_ellipsis_recovery.rast index 741b7845e7f..08ae906421c 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_before_ellipsis_recovery.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_before_ellipsis_recovery.rast @@ -12,6 +12,38 @@ SOURCE_FILE STMT_LIST L_CURLY "{" WHITESPACE "\n " + EXPR_STMT + RECORD_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "S" + WHITESPACE " " + RECORD_EXPR_FIELD_LIST + L_CURLY "{" + WHITESPACE " " + RECORD_EXPR_FIELD + NAME_REF + IDENT "field" + WHITESPACE " " + DOT2 ".." + CALL_EXPR + PATH_EXPR + PATH + PATH + PATH_SEGMENT + NAME_REF + IDENT "S" + COLON2 "::" + PATH_SEGMENT + NAME_REF + IDENT "default" + ARG_LIST + L_PAREN "(" + R_PAREN ")" + WHITESPACE " " + R_CURLY "}" + WHITESPACE "\n " RECORD_EXPR PATH PATH_SEGMENT @@ -23,7 +55,7 @@ SOURCE_FILE WHITESPACE " " RECORD_EXPR_FIELD NAME_REF - IDENT "field" + INT_NUMBER "0" WHITESPACE " " DOT2 ".." CALL_EXPR @@ -47,3 +79,6 @@ SOURCE_FILE WHITESPACE "\n" error 25: expected `:` error 25: expected COMMA +error 42: expected SEMICOLON +error 52: expected `:` +error 52: expected COMMA diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_before_ellipsis_recovery.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_before_ellipsis_recovery.rs index a4e5b2f6933..65398ccb88e 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_before_ellipsis_recovery.rs +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_before_ellipsis_recovery.rs @@ -1,3 +1,4 @@ fn main() { S { field ..S::default() } + S { 0 ..S::default() } } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_field_eq_recovery.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_field_eq_recovery.rast index ad4deeb0b67..ad3b6f208e6 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_field_eq_recovery.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_field_eq_recovery.rast @@ -12,6 +12,31 @@ SOURCE_FILE STMT_LIST L_CURLY "{" WHITESPACE "\n " + EXPR_STMT + RECORD_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "S" + WHITESPACE " " + RECORD_EXPR_FIELD_LIST + L_CURLY "{" + WHITESPACE " " + RECORD_EXPR_FIELD + NAME_REF + IDENT "field" + WHITESPACE " " + ERROR + EQ "=" + WHITESPACE " " + PATH_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "foo" + WHITESPACE " " + R_CURLY "}" + WHITESPACE "\n " RECORD_EXPR PATH PATH_SEGMENT @@ -23,7 +48,7 @@ SOURCE_FILE WHITESPACE " " RECORD_EXPR_FIELD NAME_REF - IDENT "field" + INT_NUMBER "0" WHITESPACE " " ERROR EQ "=" @@ -39,3 +64,5 @@ SOURCE_FILE R_CURLY "}" WHITESPACE "\n" error 26: expected `:` +error 33: expected SEMICOLON +error 44: expected `:` diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_field_eq_recovery.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_field_eq_recovery.rs index 1eb1aa9b926..9ddc46e0daf 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_field_eq_recovery.rs +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_field_eq_recovery.rs @@ -1,3 +1,4 @@ fn main() { S { field = foo } + S { 0 = foo } } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_missing_ellipsis_recovery.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_missing_ellipsis_recovery.rast index 0c5b618e6f0..9cd07d2ea38 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_missing_ellipsis_recovery.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_missing_ellipsis_recovery.rast @@ -12,32 +12,70 @@ SOURCE_FILE STMT_LIST L_CURLY "{" WHITESPACE "\n " - RECORD_EXPR - PATH - PATH_SEGMENT - NAME_REF - IDENT "S" - WHITESPACE " " - RECORD_EXPR_FIELD_LIST - L_CURLY "{" + EXPR_STMT + RECORD_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "S" WHITESPACE " " - CALL_EXPR - PATH_EXPR - PATH + RECORD_EXPR_FIELD_LIST + L_CURLY "{" + WHITESPACE " " + CALL_EXPR + PATH_EXPR PATH + PATH + PATH_SEGMENT + NAME_REF + IDENT "S" + COLON2 "::" PATH_SEGMENT NAME_REF - IDENT "S" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "default" - ARG_LIST - L_PAREN "(" - R_PAREN ")" + IDENT "default" + ARG_LIST + L_PAREN "(" + R_PAREN ")" + WHITESPACE " " + R_CURLY "}" + SEMICOLON ";" + WHITESPACE "\n " + EXPR_STMT + RECORD_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "S" WHITESPACE " " - R_CURLY "}" + RECORD_EXPR_FIELD_LIST + L_CURLY "{" + WHITESPACE " " + LITERAL + INT_NUMBER "0" + ERROR + COLON ":" + ERROR + COLON ":" + RECORD_EXPR_FIELD + CALL_EXPR + PATH_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "default" + ARG_LIST + L_PAREN "(" + R_PAREN ")" + WHITESPACE " " + R_CURLY "}" + SEMICOLON ";" WHITESPACE "\n" R_CURLY "}" WHITESPACE "\n" error 19: expected DOT2 +error 43: expected DOT2 +error 45: expected COMMA +error 45: expected identifier +error 46: expected COMMA +error 46: expected identifier +error 47: expected COMMA diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_missing_ellipsis_recovery.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_missing_ellipsis_recovery.rs index 1b594e8ab96..a63c3c9e7c2 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_missing_ellipsis_recovery.rs +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_missing_ellipsis_recovery.rs @@ -1,3 +1,4 @@ fn main() { - S { S::default() } + S { S::default() }; + S { 0::default() }; } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/assoc_type_bound.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/assoc_type_bound.rast index f2e4e01069c..0f62e1dd184 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/assoc_type_bound.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/assoc_type_bound.rast @@ -35,3 +35,42 @@ SOURCE_FILE R_ANGLE ">" SEMICOLON ";" WHITESPACE "\n" + TYPE_ALIAS + TYPE_KW "type" + WHITESPACE " " + NAME + IDENT "T" + WHITESPACE " " + EQ "=" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "StreamingIterator" + GENERIC_ARG_LIST + L_ANGLE "<" + ASSOC_TYPE_ARG + NAME_REF + IDENT "Item" + PARENTHESIZED_ARG_LIST + L_PAREN "(" + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "T" + R_PAREN ")" + COLON ":" + WHITESPACE " " + TYPE_BOUND_LIST + TYPE_BOUND + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Clone" + R_ANGLE ">" + SEMICOLON ";" + WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/assoc_type_bound.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/assoc_type_bound.rs index daae97e4fd5..83fea1c6c87 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/assoc_type_bound.rs +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/assoc_type_bound.rs @@ -1 +1,2 @@ type T = StreamingIterator<Item<'a>: Clone>; +type T = StreamingIterator<Item(T): Clone>; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/associated_type_bounds.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/associated_type_bounds.rast deleted file mode 100644 index 8cbc98c51ca..00000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/associated_type_bounds.rast +++ /dev/null @@ -1,111 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "print_all" - GENERIC_PARAM_LIST - L_ANGLE "<" - TYPE_PARAM - NAME - IDENT "T" - COLON ":" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Iterator" - GENERIC_ARG_LIST - L_ANGLE "<" - TYPE_ARG - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Item" - COMMA "," - WHITESPACE " " - TYPE_ARG - PATH_TYPE - PATH - PATH - PATH_SEGMENT - NAME_REF - IDENT "Item" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "Item" - COMMA "," - WHITESPACE " " - TYPE_ARG - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Item" - GENERIC_ARG_LIST - COLON2 "::" - L_ANGLE "<" - CONST_ARG - LITERAL - TRUE_KW "true" - R_ANGLE ">" - COMMA "," - WHITESPACE " " - ASSOC_TYPE_ARG - NAME_REF - IDENT "Item" - COLON ":" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Display" - COMMA "," - WHITESPACE " " - ASSOC_TYPE_ARG - NAME_REF - IDENT "Item" - GENERIC_ARG_LIST - L_ANGLE "<" - LIFETIME_ARG - LIFETIME - LIFETIME_IDENT "'a" - R_ANGLE ">" - WHITESPACE " " - EQ "=" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Item" - R_ANGLE ">" - R_ANGLE ">" - PARAM_LIST - L_PAREN "(" - PARAM - IDENT_PAT - NAME - IDENT "printables" - COLON ":" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "T" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/associated_type_bounds.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/associated_type_bounds.rs deleted file mode 100644 index 0f7a2d16083..00000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/associated_type_bounds.rs +++ /dev/null @@ -1 +0,0 @@ -fn print_all<T: Iterator<Item, Item::Item, Item::<true>, Item: Display, Item<'a> = Item>>(printables: T) {} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/async_trait_bound.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/async_trait_bound.rast index ebf758286a7..df0ba55d03d 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/async_trait_bound.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/async_trait_bound.rast @@ -23,9 +23,9 @@ SOURCE_FILE PATH_SEGMENT NAME_REF IDENT "Fn" - PARAM_LIST + PARENTHESIZED_ARG_LIST L_PAREN "(" - PARAM + TYPE_ARG REF_TYPE AMP "&" PATH_TYPE diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/bare_dyn_types_with_paren_as_generic_args.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/bare_dyn_types_with_paren_as_generic_args.rast deleted file mode 100644 index d5f97bad898..00000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/bare_dyn_types_with_paren_as_generic_args.rast +++ /dev/null @@ -1,175 +0,0 @@ -SOURCE_FILE - TYPE_ALIAS - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "A" - WHITESPACE " " - EQ "=" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "S" - GENERIC_ARG_LIST - L_ANGLE "<" - TYPE_ARG - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Fn" - PARAM_LIST - L_PAREN "(" - PARAM - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - R_PAREN ")" - R_ANGLE ">" - SEMICOLON ";" - WHITESPACE "\n" - TYPE_ALIAS - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "A" - WHITESPACE " " - EQ "=" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "S" - GENERIC_ARG_LIST - L_ANGLE "<" - TYPE_ARG - DYN_TRAIT_TYPE - TYPE_BOUND_LIST - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Fn" - PARAM_LIST - L_PAREN "(" - PARAM - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - R_PAREN ")" - WHITESPACE " " - PLUS "+" - WHITESPACE " " - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Send" - R_ANGLE ">" - SEMICOLON ";" - WHITESPACE "\n" - TYPE_ALIAS - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "B" - WHITESPACE " " - EQ "=" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "S" - GENERIC_ARG_LIST - L_ANGLE "<" - TYPE_ARG - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Fn" - PARAM_LIST - L_PAREN "(" - PARAM - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - R_PAREN ")" - WHITESPACE " " - RET_TYPE - THIN_ARROW "->" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - R_ANGLE ">" - SEMICOLON ";" - WHITESPACE "\n" - TYPE_ALIAS - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "C" - WHITESPACE " " - EQ "=" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "S" - GENERIC_ARG_LIST - L_ANGLE "<" - TYPE_ARG - DYN_TRAIT_TYPE - TYPE_BOUND_LIST - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Fn" - PARAM_LIST - L_PAREN "(" - PARAM - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - R_PAREN ")" - WHITESPACE " " - RET_TYPE - THIN_ARROW "->" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - WHITESPACE " " - PLUS "+" - WHITESPACE " " - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Send" - R_ANGLE ">" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/bare_dyn_types_with_paren_as_generic_args.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/bare_dyn_types_with_paren_as_generic_args.rs deleted file mode 100644 index 800002b1b82..00000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/bare_dyn_types_with_paren_as_generic_args.rs +++ /dev/null @@ -1,4 +0,0 @@ -type A = S<Fn(i32)>; -type A = S<Fn(i32) + Send>; -type B = S<Fn(i32) -> i32>; -type C = S<Fn(i32) -> i32 + Send>; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/edition_2015_dyn_prefix_inside_generic_arg.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/edition_2015_dyn_prefix_inside_generic_arg.rast new file mode 100644 index 00000000000..24e671b3438 --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/edition_2015_dyn_prefix_inside_generic_arg.rast @@ -0,0 +1,32 @@ +SOURCE_FILE + TYPE_ALIAS + COMMENT "// 2015" + WHITESPACE "\n" + TYPE_KW "type" + WHITESPACE " " + NAME + IDENT "A" + WHITESPACE " " + EQ "=" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Foo" + GENERIC_ARG_LIST + L_ANGLE "<" + TYPE_ARG + DYN_TRAIT_TYPE + DYN_KW "dyn" + WHITESPACE " " + TYPE_BOUND_LIST + TYPE_BOUND + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "T" + R_ANGLE ">" + SEMICOLON ";" + WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/edition_2015_dyn_prefix_inside_generic_arg.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/edition_2015_dyn_prefix_inside_generic_arg.rs new file mode 100644 index 00000000000..84cece5748d --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/edition_2015_dyn_prefix_inside_generic_arg.rs @@ -0,0 +1,2 @@ +// 2015 +type A = Foo<dyn T>; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/extern_crate.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/extern_crate.rast index 0a660957d15..aa555ed2293 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/extern_crate.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/extern_crate.rast @@ -8,3 +8,12 @@ SOURCE_FILE IDENT "foo" SEMICOLON ";" WHITESPACE "\n" + EXTERN_CRATE + EXTERN_KW "extern" + WHITESPACE " " + CRATE_KW "crate" + WHITESPACE " " + NAME_REF + SELF_KW "self" + SEMICOLON ";" + WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/extern_crate.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/extern_crate.rs index 49af74e1b74..3c498c8738f 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/extern_crate.rs +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/extern_crate.rs @@ -1 +1,2 @@ extern crate foo; +extern crate self; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/extern_crate_rename.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/extern_crate_rename.rast index 5a5aca96f91..5f0a5b5bb05 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/extern_crate_rename.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/extern_crate_rename.rast @@ -14,3 +14,18 @@ SOURCE_FILE IDENT "bar" SEMICOLON ";" WHITESPACE "\n" + EXTERN_CRATE + EXTERN_KW "extern" + WHITESPACE " " + CRATE_KW "crate" + WHITESPACE " " + NAME_REF + SELF_KW "self" + WHITESPACE " " + RENAME + AS_KW "as" + WHITESPACE " " + NAME + IDENT "bar" + SEMICOLON ";" + WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/extern_crate_rename.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/extern_crate_rename.rs index fc76e17dda4..6d1873d659e 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/extern_crate_rename.rs +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/extern_crate_rename.rs @@ -1 +1,2 @@ extern crate foo as bar; +extern crate self as bar; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/extern_crate_self.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/extern_crate_self.rast deleted file mode 100644 index edea4245f20..00000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/extern_crate_self.rast +++ /dev/null @@ -1,10 +0,0 @@ -SOURCE_FILE - EXTERN_CRATE - EXTERN_KW "extern" - WHITESPACE " " - CRATE_KW "crate" - WHITESPACE " " - NAME_REF - SELF_KW "self" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/extern_crate_self.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/extern_crate_self.rs deleted file mode 100644 index c969ed10936..00000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/extern_crate_self.rs +++ /dev/null @@ -1 +0,0 @@ -extern crate self; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/field_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/field_expr.rast index dd27dc48964..3bac226d343 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/field_expr.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/field_expr.rast @@ -21,6 +21,30 @@ SOURCE_FILE IDENT "x" DOT "." NAME_REF + SELF_KW "self" + SEMICOLON ";" + WHITESPACE "\n " + EXPR_STMT + FIELD_EXPR + PATH_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "x" + DOT "." + NAME_REF + SELF_TYPE_KW "Self" + SEMICOLON ";" + WHITESPACE "\n " + EXPR_STMT + FIELD_EXPR + PATH_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "x" + DOT "." + NAME_REF IDENT "foo" SEMICOLON ";" WHITESPACE "\n " diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/field_expr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/field_expr.rs index 98dbe45a7ec..b156d6f7d88 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/field_expr.rs +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/field_expr.rs @@ -1,4 +1,6 @@ fn foo() { + x.self; + x.Self; x.foo; x.0.bar; x.0.1; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/generic_arg.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/generic_arg.rast index 5a01f154bad..e32cf085657 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/generic_arg.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/generic_arg.rast @@ -20,6 +20,27 @@ SOURCE_FILE PATH_SEGMENT NAME_REF IDENT "i32" + COMMA "," + WHITESPACE " " + TYPE_ARG + DYN_TRAIT_TYPE + DYN_KW "dyn" + WHITESPACE " " + TYPE_BOUND_LIST + TYPE_BOUND + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "T" + COMMA "," + WHITESPACE " " + TYPE_ARG + FN_PTR_TYPE + FN_KW "fn" + PARAM_LIST + L_PAREN "(" + R_PAREN ")" R_ANGLE ">" SEMICOLON ";" WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/generic_arg.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/generic_arg.rs index f2ccc558bb5..cf991b5b366 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/generic_arg.rs +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/generic_arg.rs @@ -1 +1 @@ -type T = S<i32>; +type T = S<i32, dyn T, fn()>; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/generic_arg_bounds.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/generic_arg_bounds.rast new file mode 100644 index 00000000000..fee5913acaa --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/generic_arg_bounds.rast @@ -0,0 +1,461 @@ +SOURCE_FILE + TYPE_ALIAS + TYPE_KW "type" + WHITESPACE " " + NAME + IDENT "Plain" + WHITESPACE " " + EQ "=" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Foo" + GENERIC_ARG_LIST + L_ANGLE "<" + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Item" + COMMA "," + WHITESPACE " " + TYPE_ARG + PATH_TYPE + PATH + PATH + PATH_SEGMENT + NAME_REF + IDENT "Item" + COLON2 "::" + PATH_SEGMENT + NAME_REF + IDENT "Item" + COMMA "," + WHITESPACE " " + ASSOC_TYPE_ARG + NAME_REF + IDENT "Item" + COLON ":" + WHITESPACE " " + TYPE_BOUND_LIST + TYPE_BOUND + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Bound" + COMMA "," + WHITESPACE " " + ASSOC_TYPE_ARG + NAME_REF + IDENT "Item" + WHITESPACE " " + EQ "=" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Item" + R_ANGLE ">" + SEMICOLON ";" + WHITESPACE "\n" + TYPE_ALIAS + TYPE_KW "type" + WHITESPACE " " + NAME + IDENT "GenericArgs" + WHITESPACE " " + EQ "=" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Foo" + GENERIC_ARG_LIST + L_ANGLE "<" + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Item" + GENERIC_ARG_LIST + L_ANGLE "<" + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "T" + R_ANGLE ">" + COMMA "," + WHITESPACE " " + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Item" + GENERIC_ARG_LIST + COLON2 "::" + L_ANGLE "<" + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "T" + R_ANGLE ">" + COMMA "," + WHITESPACE " " + ASSOC_TYPE_ARG + NAME_REF + IDENT "Item" + GENERIC_ARG_LIST + L_ANGLE "<" + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "T" + R_ANGLE ">" + COLON ":" + WHITESPACE " " + TYPE_BOUND_LIST + TYPE_BOUND + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Bound" + COMMA "," + WHITESPACE " " + ASSOC_TYPE_ARG + NAME_REF + IDENT "Item" + GENERIC_ARG_LIST + COLON2 "::" + L_ANGLE "<" + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "T" + R_ANGLE ">" + COLON ":" + WHITESPACE " " + TYPE_BOUND_LIST + TYPE_BOUND + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Bound" + COMMA "," + WHITESPACE " " + ASSOC_TYPE_ARG + NAME_REF + IDENT "Item" + GENERIC_ARG_LIST + L_ANGLE "<" + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "T" + R_ANGLE ">" + WHITESPACE " " + EQ "=" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Item" + COMMA "," + WHITESPACE " " + ASSOC_TYPE_ARG + NAME_REF + IDENT "Item" + GENERIC_ARG_LIST + COLON2 "::" + L_ANGLE "<" + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "T" + R_ANGLE ">" + WHITESPACE " " + EQ "=" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Item" + R_ANGLE ">" + SEMICOLON ";" + WHITESPACE "\n" + TYPE_ALIAS + TYPE_KW "type" + WHITESPACE " " + NAME + IDENT "ParenthesizedArgs" + WHITESPACE " " + EQ "=" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Foo" + GENERIC_ARG_LIST + L_ANGLE "<" + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Item" + PARENTHESIZED_ARG_LIST + L_PAREN "(" + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "T" + R_PAREN ")" + COMMA "," + WHITESPACE " " + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Item" + PARENTHESIZED_ARG_LIST + COLON2 "::" + L_PAREN "(" + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "T" + R_PAREN ")" + COMMA "," + WHITESPACE " " + ASSOC_TYPE_ARG + NAME_REF + IDENT "Item" + PARENTHESIZED_ARG_LIST + L_PAREN "(" + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "T" + R_PAREN ")" + COLON ":" + WHITESPACE " " + TYPE_BOUND_LIST + TYPE_BOUND + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Bound" + COMMA "," + WHITESPACE " " + ASSOC_TYPE_ARG + NAME_REF + IDENT "Item" + PARENTHESIZED_ARG_LIST + COLON2 "::" + L_PAREN "(" + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "T" + R_PAREN ")" + COLON ":" + WHITESPACE " " + TYPE_BOUND_LIST + TYPE_BOUND + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Bound" + COMMA "," + WHITESPACE " " + ASSOC_TYPE_ARG + NAME_REF + IDENT "Item" + PARENTHESIZED_ARG_LIST + L_PAREN "(" + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "T" + R_PAREN ")" + WHITESPACE " " + EQ "=" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Item" + COMMA "," + WHITESPACE " " + ASSOC_TYPE_ARG + NAME_REF + IDENT "Item" + PARENTHESIZED_ARG_LIST + COLON2 "::" + L_PAREN "(" + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "T" + R_PAREN ")" + WHITESPACE " " + EQ "=" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Item" + R_ANGLE ">" + SEMICOLON ";" + WHITESPACE "\n" + TYPE_ALIAS + TYPE_KW "type" + WHITESPACE " " + NAME + IDENT "RTN" + WHITESPACE " " + EQ "=" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Foo" + GENERIC_ARG_LIST + L_ANGLE "<" + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Item" + RETURN_TYPE_SYNTAX + L_PAREN "(" + DOT2 ".." + R_PAREN ")" + COMMA "," + WHITESPACE " " + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Item" + RETURN_TYPE_SYNTAX + L_PAREN "(" + DOT2 ".." + R_PAREN ")" + COMMA "," + WHITESPACE " " + ASSOC_TYPE_ARG + NAME_REF + IDENT "Item" + RETURN_TYPE_SYNTAX + L_PAREN "(" + DOT2 ".." + R_PAREN ")" + COLON ":" + WHITESPACE " " + TYPE_BOUND_LIST + TYPE_BOUND + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Bound" + COMMA "," + WHITESPACE " " + ASSOC_TYPE_ARG + NAME_REF + IDENT "Item" + RETURN_TYPE_SYNTAX + L_PAREN "(" + DOT2 ".." + R_PAREN ")" + COLON ":" + WHITESPACE " " + TYPE_BOUND_LIST + TYPE_BOUND + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Bound" + COMMA "," + WHITESPACE " " + ASSOC_TYPE_ARG + NAME_REF + IDENT "Item" + RETURN_TYPE_SYNTAX + L_PAREN "(" + DOT2 ".." + R_PAREN ")" + WHITESPACE " " + EQ "=" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Item" + COMMA "," + WHITESPACE " " + ASSOC_TYPE_ARG + NAME_REF + IDENT "Item" + RETURN_TYPE_SYNTAX + L_PAREN "(" + DOT2 ".." + R_PAREN ")" + WHITESPACE " " + EQ "=" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Item" + R_ANGLE ">" + SEMICOLON ";" + WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/generic_arg_bounds.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/generic_arg_bounds.rs new file mode 100644 index 00000000000..1abd0aeb592 --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/generic_arg_bounds.rs @@ -0,0 +1,4 @@ +type Plain = Foo<Item, Item::Item, Item: Bound, Item = Item>; +type GenericArgs = Foo<Item<T>, Item::<T>, Item<T>: Bound, Item::<T>: Bound, Item<T> = Item, Item::<T> = Item>; +type ParenthesizedArgs = Foo<Item(T), Item::(T), Item(T): Bound, Item::(T): Bound, Item(T) = Item, Item::(T) = Item>; +type RTN = Foo<Item(..), Item(..), Item(..): Bound, Item(..): Bound, Item(..) = Item, Item(..) = Item>; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/lifetime_param.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/lifetime_param.rast index c595031f358..315200aca21 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/lifetime_param.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/lifetime_param.rast @@ -11,8 +11,10 @@ SOURCE_FILE LIFETIME_IDENT "'a" COLON ":" WHITESPACE " " - LIFETIME - LIFETIME_IDENT "'b" + TYPE_BOUND_LIST + TYPE_BOUND + LIFETIME + LIFETIME_IDENT "'b" R_ANGLE ">" PARAM_LIST L_PAREN "(" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/method_call_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/method_call_expr.rast index b28b8eb673a..3245042cf24 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/method_call_expr.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/method_call_expr.rast @@ -101,6 +101,20 @@ SOURCE_FILE L_PAREN "(" R_PAREN ")" SEMICOLON ";" + WHITESPACE "\n " + CALL_EXPR + FIELD_EXPR + PATH_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "x" + DOT "." + NAME_REF + INT_NUMBER "0" + ARG_LIST + L_PAREN "(" + R_PAREN ")" WHITESPACE "\n" R_CURLY "}" WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/method_call_expr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/method_call_expr.rs index 48bb6381e80..bb54d75c19b 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/method_call_expr.rs +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/method_call_expr.rs @@ -3,4 +3,5 @@ fn foo() { y.bar::<T>(1, 2,); x.0.0.call(); x.0. call(); + x.0() } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/param_list_opt_patterns.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/param_list_opt_patterns.rast deleted file mode 100644 index e9d93a0d0a4..00000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/param_list_opt_patterns.rast +++ /dev/null @@ -1,48 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - GENERIC_PARAM_LIST - L_ANGLE "<" - TYPE_PARAM - NAME - IDENT "F" - COLON ":" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "FnMut" - PARAM_LIST - L_PAREN "(" - PARAM - REF_TYPE - AMP "&" - MUT_KW "mut" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Foo" - GENERIC_ARG_LIST - L_ANGLE "<" - LIFETIME_ARG - LIFETIME - LIFETIME_IDENT "'a" - R_ANGLE ">" - R_PAREN ")" - R_ANGLE ">" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/param_list_opt_patterns.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/param_list_opt_patterns.rs deleted file mode 100644 index 9b93442c0f2..00000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/param_list_opt_patterns.rs +++ /dev/null @@ -1 +0,0 @@ -fn foo<F: FnMut(&mut Foo<'a>)>(){} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/path_fn_trait_args.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/path_fn_trait_args.rast index fd83daf841f..924f7ba2c9d 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/path_fn_trait_args.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/path_fn_trait_args.rast @@ -20,9 +20,133 @@ SOURCE_FILE PATH_SEGMENT NAME_REF IDENT "Fn" - PARAM_LIST + PARENTHESIZED_ARG_LIST L_PAREN "(" - PARAM + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "i32" + R_PAREN ")" + WHITESPACE " " + RET_TYPE + THIN_ARROW "->" + WHITESPACE " " + TUPLE_TYPE + L_PAREN "(" + R_PAREN ")" + R_ANGLE ">" + SEMICOLON ";" + WHITESPACE "\n" + TYPE_ALIAS + TYPE_KW "type" + WHITESPACE " " + NAME + IDENT "F" + WHITESPACE " " + EQ "=" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Box" + GENERIC_ARG_LIST + L_ANGLE "<" + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + COLON2 "::" + NAME_REF + IDENT "Fn" + PARENTHESIZED_ARG_LIST + L_PAREN "(" + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "i32" + R_PAREN ")" + WHITESPACE " " + RET_TYPE + THIN_ARROW "->" + WHITESPACE " " + TUPLE_TYPE + L_PAREN "(" + R_PAREN ")" + R_ANGLE ">" + SEMICOLON ";" + WHITESPACE "\n" + TYPE_ALIAS + TYPE_KW "type" + WHITESPACE " " + NAME + IDENT "F" + WHITESPACE " " + EQ "=" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Box" + GENERIC_ARG_LIST + L_ANGLE "<" + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Fn" + PARENTHESIZED_ARG_LIST + COLON2 "::" + L_PAREN "(" + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "i32" + R_PAREN ")" + WHITESPACE " " + RET_TYPE + THIN_ARROW "->" + WHITESPACE " " + TUPLE_TYPE + L_PAREN "(" + R_PAREN ")" + R_ANGLE ">" + SEMICOLON ";" + WHITESPACE "\n" + TYPE_ALIAS + TYPE_KW "type" + WHITESPACE " " + NAME + IDENT "F" + WHITESPACE " " + EQ "=" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Box" + GENERIC_ARG_LIST + L_ANGLE "<" + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + COLON2 "::" + NAME_REF + IDENT "Fn" + PARENTHESIZED_ARG_LIST + COLON2 "::" + L_PAREN "(" + TYPE_ARG PATH_TYPE PATH PATH_SEGMENT diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/path_fn_trait_args.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/path_fn_trait_args.rs index 17ed20e5b13..7aa655d7ea9 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/path_fn_trait_args.rs +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/path_fn_trait_args.rs @@ -1 +1,4 @@ type F = Box<Fn(i32) -> ()>; +type F = Box<::Fn(i32) -> ()>; +type F = Box<Fn::(i32) -> ()>; +type F = Box<::Fn::(i32) -> ()>; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/precise_capturing.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/precise_capturing.rast index f9c0a245af8..5a67cc21766 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/precise_capturing.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/precise_capturing.rast @@ -11,8 +11,10 @@ SOURCE_FILE LIFETIME_IDENT "'a" COLON ":" WHITESPACE " " - LIFETIME - LIFETIME_IDENT "'a" + TYPE_BOUND_LIST + TYPE_BOUND + LIFETIME + LIFETIME_IDENT "'a" COMMA "," WHITESPACE " " LIFETIME_PARAM @@ -20,8 +22,10 @@ SOURCE_FILE LIFETIME_IDENT "'b" COLON ":" WHITESPACE " " - LIFETIME - LIFETIME_IDENT "'b" + TYPE_BOUND_LIST + TYPE_BOUND + LIFETIME + LIFETIME_IDENT "'b" COMMA "," WHITESPACE " " TYPE_PARAM diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/return_type_syntax_assoc_type_bound.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/return_type_syntax_assoc_type_bound.rast deleted file mode 100644 index 30e0e73bbd6..00000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/return_type_syntax_assoc_type_bound.rast +++ /dev/null @@ -1,49 +0,0 @@ -SOURCE_FILE - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - GENERIC_PARAM_LIST - L_ANGLE "<" - TYPE_PARAM - NAME - IDENT "T" - COLON ":" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Trait" - GENERIC_ARG_LIST - L_ANGLE "<" - ASSOC_TYPE_ARG - NAME_REF - IDENT "method" - RETURN_TYPE_SYNTAX - L_PAREN "(" - DOT2 ".." - R_PAREN ")" - COLON ":" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Send" - R_ANGLE ">" - R_ANGLE ">" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - WHITESPACE " " - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/return_type_syntax_assoc_type_bound.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/return_type_syntax_assoc_type_bound.rs deleted file mode 100644 index 8a4cf4c3a07..00000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/return_type_syntax_assoc_type_bound.rs +++ /dev/null @@ -1 +0,0 @@ -fn foo<T: Trait<method(..): Send>>() {} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/return_type_syntax_in_path.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/return_type_syntax_in_path.rast index 501dccd79db..15a0558b53d 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/return_type_syntax_in_path.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/return_type_syntax_in_path.rast @@ -42,6 +42,49 @@ SOURCE_FILE NAME_REF IDENT "Send" COMMA "," + WHITESPACE "\n " + WHERE_PRED + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "method" + RETURN_TYPE_SYNTAX + L_PAREN "(" + DOT2 ".." + R_PAREN ")" + COLON ":" + WHITESPACE " " + TYPE_BOUND_LIST + TYPE_BOUND + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Send" + COMMA "," + WHITESPACE "\n " + WHERE_PRED + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "method" + RETURN_TYPE_SYNTAX + COLON2 "::" + L_PAREN "(" + DOT2 ".." + R_PAREN ")" + COLON ":" + WHITESPACE " " + TYPE_BOUND_LIST + TYPE_BOUND + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Send" + COMMA "," WHITESPACE "\n" BLOCK_EXPR STMT_LIST diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/return_type_syntax_in_path.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/return_type_syntax_in_path.rs index a9b63fb01c8..64b48c1638e 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/return_type_syntax_in_path.rs +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/return_type_syntax_in_path.rs @@ -1,4 +1,6 @@ fn foo<T>() where T::method(..): Send, + method(..): Send, + method::(..): Send, {} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/typepathfn_with_coloncolon.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/typepathfn_with_coloncolon.rast index 67277d0639a..fb442bfb739 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/typepathfn_with_coloncolon.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/typepathfn_with_coloncolon.rast @@ -13,10 +13,10 @@ SOURCE_FILE PATH_SEGMENT NAME_REF IDENT "Start" - COLON2 "::" - PARAM_LIST + PARENTHESIZED_ARG_LIST + COLON2 "::" L_PAREN "(" - PARAM + TYPE_ARG PATH_TYPE PATH PATH_SEGMENT @@ -63,9 +63,9 @@ SOURCE_FILE PATH_SEGMENT NAME_REF IDENT "Start" - PARAM_LIST + PARENTHESIZED_ARG_LIST L_PAREN "(" - PARAM + TYPE_ARG PATH_TYPE PATH PATH_SEGMENT diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/value_parameters_no_patterns.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/value_parameters_no_patterns.rast deleted file mode 100644 index 902b06484c8..00000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/value_parameters_no_patterns.rast +++ /dev/null @@ -1,60 +0,0 @@ -SOURCE_FILE - TYPE_ALIAS - TYPE_KW "type" - WHITESPACE " " - NAME - IDENT "F" - WHITESPACE " " - EQ "=" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Box" - GENERIC_ARG_LIST - L_ANGLE "<" - TYPE_ARG - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Fn" - PARAM_LIST - L_PAREN "(" - PARAM - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - COMMA "," - WHITESPACE " " - PARAM - REF_TYPE - AMP "&" - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - COMMA "," - WHITESPACE " " - PARAM - REF_TYPE - AMP "&" - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "i32" - COMMA "," - WHITESPACE " " - PARAM - TUPLE_TYPE - L_PAREN "(" - R_PAREN ")" - R_PAREN ")" - R_ANGLE ">" - SEMICOLON ";" - WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/value_parameters_no_patterns.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/value_parameters_no_patterns.rs deleted file mode 100644 index 93636e926e1..00000000000 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/value_parameters_no_patterns.rs +++ /dev/null @@ -1 +0,0 @@ -type F = Box<Fn(i32, &i32, &i32, ())>; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/where_pred_for.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/where_pred_for.rast index 8407e99f614..0cc365efbe6 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/where_pred_for.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/where_pred_for.rast @@ -40,9 +40,9 @@ SOURCE_FILE PATH_SEGMENT NAME_REF IDENT "Fn" - PARAM_LIST + PARENTHESIZED_ARG_LIST L_PAREN "(" - PARAM + TYPE_ARG REF_TYPE AMP "&" LIFETIME diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0018_struct_type_params.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0018_struct_type_params.rast index 11ebc7efb9f..1e4eb156095 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0018_struct_type_params.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0018_struct_type_params.rast @@ -96,6 +96,7 @@ SOURCE_FILE LIFETIME LIFETIME_IDENT "'a" COLON ":" + TYPE_BOUND_LIST R_ANGLE ">" SEMICOLON ";" WHITESPACE "\n" @@ -111,8 +112,10 @@ SOURCE_FILE LIFETIME_IDENT "'a" COLON ":" WHITESPACE " " - LIFETIME - LIFETIME_IDENT "'b" + TYPE_BOUND_LIST + TYPE_BOUND + LIFETIME + LIFETIME_IDENT "'b" R_ANGLE ">" SEMICOLON ";" WHITESPACE "\n" @@ -128,10 +131,12 @@ SOURCE_FILE LIFETIME_IDENT "'a" COLON ":" WHITESPACE " " - LIFETIME - LIFETIME_IDENT "'b" - WHITESPACE " " - PLUS "+" + TYPE_BOUND_LIST + TYPE_BOUND + LIFETIME + LIFETIME_IDENT "'b" + WHITESPACE " " + PLUS "+" WHITESPACE " " R_ANGLE ">" SEMICOLON ";" @@ -148,13 +153,16 @@ SOURCE_FILE LIFETIME_IDENT "'a" COLON ":" WHITESPACE " " - LIFETIME - LIFETIME_IDENT "'b" - WHITESPACE " " - PLUS "+" - WHITESPACE " " - LIFETIME - LIFETIME_IDENT "'c" + TYPE_BOUND_LIST + TYPE_BOUND + LIFETIME + LIFETIME_IDENT "'b" + WHITESPACE " " + PLUS "+" + WHITESPACE " " + TYPE_BOUND + LIFETIME + LIFETIME_IDENT "'c" R_ANGLE ">" SEMICOLON ";" WHITESPACE "\n" @@ -202,9 +210,11 @@ SOURCE_FILE LIFETIME_IDENT "'a" COLON ":" WHITESPACE " " - LIFETIME - LIFETIME_IDENT "'b" - PLUS "+" + TYPE_BOUND_LIST + TYPE_BOUND + LIFETIME + LIFETIME_IDENT "'b" + PLUS "+" COMMA "," WHITESPACE " " LIFETIME_PARAM @@ -212,8 +222,10 @@ SOURCE_FILE LIFETIME_IDENT "'b" COLON ":" WHITESPACE " " - LIFETIME - LIFETIME_IDENT "'c" + TYPE_BOUND_LIST + TYPE_BOUND + LIFETIME + LIFETIME_IDENT "'c" COMMA "," R_ANGLE ">" SEMICOLON ";" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0020_type_param_bounds.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0020_type_param_bounds.rast index 043a966ff97..448cf49446e 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0020_type_param_bounds.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0020_type_param_bounds.rast @@ -237,8 +237,10 @@ SOURCE_FILE LIFETIME_IDENT "'a" COLON ":" WHITESPACE " " - LIFETIME - LIFETIME_IDENT "'d" + TYPE_BOUND_LIST + TYPE_BOUND + LIFETIME + LIFETIME_IDENT "'d" COMMA "," WHITESPACE " " LIFETIME_PARAM @@ -246,13 +248,16 @@ SOURCE_FILE LIFETIME_IDENT "'d" COLON ":" WHITESPACE " " - LIFETIME - LIFETIME_IDENT "'a" - WHITESPACE " " - PLUS "+" - WHITESPACE " " - LIFETIME - LIFETIME_IDENT "'b" + TYPE_BOUND_LIST + TYPE_BOUND + LIFETIME + LIFETIME_IDENT "'a" + WHITESPACE " " + PLUS "+" + WHITESPACE " " + TYPE_BOUND + LIFETIME + LIFETIME_IDENT "'b" COMMA "," WHITESPACE " " TYPE_PARAM diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0045_block_attrs.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0045_block_attrs.rast index fad574a4769..c22d99f1ae1 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0045_block_attrs.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0045_block_attrs.rast @@ -180,7 +180,7 @@ SOURCE_FILE PATH_SEGMENT NAME_REF IDENT "Fn" - PARAM_LIST + PARENTHESIZED_ARG_LIST L_PAREN "(" R_PAREN ")" WHITESPACE " " diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0051_parameter_attrs.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0051_parameter_attrs.rast index f8b11e7782c..eafee90db42 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0051_parameter_attrs.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0051_parameter_attrs.rast @@ -138,63 +138,6 @@ SOURCE_FILE WHITESPACE " " R_CURLY "}" WHITESPACE "\n\n" - FN - FN_KW "fn" - WHITESPACE " " - NAME - IDENT "foo" - GENERIC_PARAM_LIST - L_ANGLE "<" - TYPE_PARAM - NAME - IDENT "F" - COLON ":" - WHITESPACE " " - TYPE_BOUND_LIST - TYPE_BOUND - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "FnMut" - PARAM_LIST - L_PAREN "(" - PARAM - ATTR - POUND "#" - L_BRACK "[" - META - PATH - PATH_SEGMENT - NAME_REF - IDENT "attr" - R_BRACK "]" - WHITESPACE " " - REF_TYPE - AMP "&" - MUT_KW "mut" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Foo" - GENERIC_ARG_LIST - L_ANGLE "<" - LIFETIME_ARG - LIFETIME - LIFETIME_IDENT "'a" - R_ANGLE ">" - R_PAREN ")" - R_ANGLE ">" - PARAM_LIST - L_PAREN "(" - R_PAREN ")" - BLOCK_EXPR - STMT_LIST - L_CURLY "{" - R_CURLY "}" - WHITESPACE "\n\n" TRAIT TRAIT_KW "trait" WHITESPACE " " diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0051_parameter_attrs.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0051_parameter_attrs.rs index de350d8587a..0a0100e5d00 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0051_parameter_attrs.rs +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0051_parameter_attrs.rs @@ -3,8 +3,6 @@ fn g2(#[attr1] x: u8) {} extern "C" { fn printf(format: *const i8, #[attr] ...) -> i32; } -fn foo<F: FnMut(#[attr] &mut Foo<'a>)>(){} - trait Foo { fn bar(#[attr] _: u64, # [attr] mut x: i32); } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0054_qual_path_in_type_arg.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0054_qual_path_in_type_arg.rast index 4e1e31f3767..31cca601ca2 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0054_qual_path_in_type_arg.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0054_qual_path_in_type_arg.rast @@ -58,9 +58,9 @@ SOURCE_FILE PATH_SEGMENT NAME_REF IDENT "FnMut" - PARAM_LIST + PARENTHESIZED_ARG_LIST L_PAREN "(" - PARAM + TYPE_ARG PATH_TYPE PATH PATH @@ -101,9 +101,9 @@ SOURCE_FILE PATH_SEGMENT NAME_REF IDENT "FnMut" - PARAM_LIST + PARENTHESIZED_ARG_LIST L_PAREN "(" - PARAM + TYPE_ARG REF_TYPE AMP "&" PATH_TYPE diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0065_plus_after_fn_trait_bound.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0065_plus_after_fn_trait_bound.rast index ba7b6042a9e..d7ee11077cd 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0065_plus_after_fn_trait_bound.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0065_plus_after_fn_trait_bound.rast @@ -32,7 +32,7 @@ SOURCE_FILE PATH_SEGMENT NAME_REF IDENT "Fn" - PARAM_LIST + PARENTHESIZED_ARG_LIST L_PAREN "(" R_PAREN ")" WHITESPACE " " diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0067_where_for_pred.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0067_where_for_pred.rast index 136fce93d7e..cd3b21ae94f 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0067_where_for_pred.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0067_where_for_pred.rast @@ -40,9 +40,9 @@ SOURCE_FILE PATH_SEGMENT NAME_REF IDENT "Fn" - PARAM_LIST + PARENTHESIZED_ARG_LIST L_PAREN "(" - PARAM + TYPE_ARG REF_TYPE AMP "&" LIFETIME @@ -165,9 +165,9 @@ SOURCE_FILE PATH_SEGMENT NAME_REF IDENT "Fn" - PARAM_LIST + PARENTHESIZED_ARG_LIST L_PAREN "(" - PARAM + TYPE_ARG REF_TYPE AMP "&" LIFETIME diff --git a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs index f5ba71fcd05..988eff9be44 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs @@ -747,17 +747,14 @@ impl ProjectWorkspace { let _p = tracing::info_span!("ProjectWorkspace::to_crate_graph").entered(); let Self { kind, sysroot, cfg_overrides, rustc_cfg, .. } = self; - let ((mut crate_graph, proc_macros), sysroot) = match kind { - ProjectWorkspaceKind::Json(project) => ( - project_json_to_crate_graph( - rustc_cfg.clone(), - load, - project, - sysroot, - extra_env, - cfg_overrides, - ), + let (crate_graph, proc_macros) = match kind { + ProjectWorkspaceKind::Json(project) => project_json_to_crate_graph( + rustc_cfg.clone(), + load, + project, sysroot, + extra_env, + cfg_overrides, ), ProjectWorkspaceKind::Cargo { cargo, @@ -766,20 +763,17 @@ impl ProjectWorkspace { cargo_config_extra_env: _, error: _, set_test, - } => ( - cargo_to_crate_graph( - load, - rustc.as_ref().map(|a| a.as_ref()).ok(), - cargo, - sysroot, - rustc_cfg.clone(), - cfg_overrides, - build_scripts, - *set_test, - ), + } => cargo_to_crate_graph( + load, + rustc.as_ref().map(|a| a.as_ref()).ok(), + cargo, sysroot, + rustc_cfg.clone(), + cfg_overrides, + build_scripts, + *set_test, ), - ProjectWorkspaceKind::DetachedFile { file, cargo: cargo_script, set_test, .. } => ( + ProjectWorkspaceKind::DetachedFile { file, cargo: cargo_script, set_test, .. } => { if let Some((cargo, build_scripts, _)) = cargo_script { cargo_to_crate_graph( &mut |path| load(path), @@ -800,16 +794,10 @@ impl ProjectWorkspace { cfg_overrides, *set_test, ) - }, - sysroot, - ), + } + } }; - if matches!(sysroot.mode(), SysrootMode::Stitched(_)) && crate_graph.patch_cfg_if() { - debug!("Patched std to depend on cfg-if") - } else { - debug!("Did not patch std to depend on cfg-if") - } (crate_graph, proc_macros) } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml index 2dd2f2242a0..7c8610280b3 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml +++ b/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml @@ -21,9 +21,11 @@ path = "src/bin/main.rs" [dependencies] anyhow.workspace = true +base64 = "0.22" crossbeam-channel.workspace = true dirs = "5.0.1" dissimilar.workspace = true +ide-completion.workspace = true itertools.workspace = true scip = "0.5.1" lsp-types = { version = "=0.95.0", features = ["proposed"] } @@ -34,6 +36,7 @@ rayon.workspace = true rustc-hash.workspace = true serde_json = { workspace = true, features = ["preserve_order"] } serde.workspace = true +tenthash = "0.4.0" num_cpus = "1.15.0" mimalloc = { version = "0.1.30", default-features = false, optional = true } lsp-server.workspace = true diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs index e872585c571..eac33be5664 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs @@ -20,7 +20,6 @@ use rust_analyzer::{ config::{Config, ConfigChange, ConfigErrors}, from_json, }; -use semver::Version; use tracing_subscriber::fmt::writer::BoxMakeWriter; use vfs::AbsPathBuf; @@ -204,18 +203,12 @@ fn run_server() -> anyhow::Result<()> { } }; - let mut visual_studio_code_version = None; - if let Some(client_info) = client_info { + if let Some(client_info) = &client_info { tracing::info!( "Client '{}' {}", client_info.name, client_info.version.as_deref().unwrap_or_default() ); - visual_studio_code_version = client_info - .name - .starts_with("Visual Studio Code") - .then(|| client_info.version.as_deref().map(Version::parse).and_then(Result::ok)) - .flatten(); } let workspace_roots = workspace_folders @@ -230,8 +223,7 @@ fn run_server() -> anyhow::Result<()> { }) .filter(|workspaces| !workspaces.is_empty()) .unwrap_or_else(|| vec![root_path.clone()]); - let mut config = - Config::new(root_path, capabilities, workspace_roots, visual_studio_code_version); + let mut config = Config::new(root_path, capabilities, workspace_roots, client_info); if let Some(json) = initialization_options { let mut change = ConfigChange::default(); change.change_client_config(json); diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs index 802d0c69a47..e3ea441f3ab 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs @@ -13,8 +13,9 @@ use hir::{ ModuleDef, Name, }; use hir_def::{ - body::{BodySourceMap, SyntheticSyntax}, + body::BodySourceMap, hir::{ExprId, PatId}, + SyntheticSyntax, }; use hir_ty::{Interner, Substitution, TyExt, TypeFlags}; use ide::{ diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs index 37d45255e29..bf7aca42faf 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs @@ -3,11 +3,7 @@ //! Of particular interest is the `feature_flags` hash map: while other fields //! configure the server itself, feature flags are passed into analysis, and //! tweak things like automatic insertion of `()` in completions. -use std::{ - env, fmt, iter, - ops::Not, - sync::{LazyLock, OnceLock}, -}; +use std::{env, fmt, iter, ops::Not, sync::OnceLock}; use cfg::{CfgAtom, CfgDiff}; use hir::Symbol; @@ -308,8 +304,8 @@ config_data! { /// Show documentation. signatureInfo_documentation_enable: bool = true, - /// Whether to insert closing angle brackets when typing an opening angle bracket of a generic argument list. - typing_autoClosingAngleBrackets_enable: bool = false, + /// Specify the characters to exclude from triggering typing assists. The default trigger characters are `.`, `=`, `<`, `>`, `{`, and `(`. + typing_excludeChars: Option<String> = Some("|<".to_owned()), /// Enables automatic discovery of projects using [`DiscoverWorkspaceConfig::command`]. @@ -730,6 +726,12 @@ enum RatomlFile { Crate(LocalConfigInput), } +#[derive(Clone, Debug)] +struct ClientInfo { + name: String, + version: Option<Version>, +} + #[derive(Clone)] pub struct Config { /// Projects that have a Cargo.toml or a rust-project.json in a @@ -744,7 +746,7 @@ pub struct Config { caps: ClientCapabilities, root_path: AbsPathBuf, snippets: Vec<Snippet>, - visual_studio_code_version: Option<Version>, + client_info: Option<ClientInfo>, default_config: &'static DefaultConfigData, /// Config node that obtains its initial value during the server initialization and @@ -777,7 +779,7 @@ impl fmt::Debug for Config { .field("caps", &self.caps) .field("root_path", &self.root_path) .field("snippets", &self.snippets) - .field("visual_studio_code_version", &self.visual_studio_code_version) + .field("client_info", &self.client_info) .field("client_config", &self.client_config) .field("user_config", &self.user_config) .field("ratoml_file", &self.ratoml_file) @@ -798,25 +800,14 @@ impl std::ops::Deref for Config { } impl Config { - /// Path to the root configuration file. This can be seen as a generic way to define what would be `$XDG_CONFIG_HOME/rust-analyzer/rust-analyzer.toml` in Linux. - /// This path is equal to: - /// - /// |Platform | Value | Example | - /// | ------- | ------------------------------------- | ---------------------------------------- | - /// | Linux | `$XDG_CONFIG_HOME` or `$HOME`/.config | /home/alice/.config | - /// | macOS | `$HOME`/Library/Application Support | /Users/Alice/Library/Application Support | - /// | Windows | `{FOLDERID_RoamingAppData}` | C:\Users\Alice\AppData\Roaming | - pub fn user_config_path() -> Option<&'static AbsPath> { - static USER_CONFIG_PATH: LazyLock<Option<AbsPathBuf>> = LazyLock::new(|| { - let user_config_path = if let Some(path) = env::var_os("__TEST_RA_USER_CONFIG_DIR") { - std::path::PathBuf::from(path) - } else { - dirs::config_dir()?.join("rust-analyzer") - } - .join("rust-analyzer.toml"); - Some(AbsPathBuf::assert_utf8(user_config_path)) - }); - USER_CONFIG_PATH.as_deref() + /// Path to the user configuration dir. This can be seen as a generic way to define what would be `$XDG_CONFIG_HOME/rust-analyzer` in Linux. + pub fn user_config_dir_path() -> Option<AbsPathBuf> { + let user_config_path = if let Some(path) = env::var_os("__TEST_RA_USER_CONFIG_DIR") { + std::path::PathBuf::from(path) + } else { + dirs::config_dir()?.join("rust-analyzer") + }; + Some(AbsPathBuf::assert_utf8(user_config_path)) } pub fn same_source_root_parent_map( @@ -1256,7 +1247,7 @@ pub struct NotificationsConfig { pub cargo_toml_not_found: bool, } -#[derive(Deserialize, Serialize, Debug, Clone)] +#[derive(Debug, Clone)] pub enum RustfmtConfig { Rustfmt { extra_args: Vec<String>, enable_range_formatting: bool }, CustomCommand { command: String, args: Vec<String> }, @@ -1335,7 +1326,7 @@ impl Config { root_path: AbsPathBuf, caps: lsp_types::ClientCapabilities, workspace_roots: Vec<AbsPathBuf>, - visual_studio_code_version: Option<Version>, + client_info: Option<lsp_types::ClientInfo>, ) -> Self { static DEFAULT_CONFIG_DATA: OnceLock<&'static DefaultConfigData> = OnceLock::new(); @@ -1346,7 +1337,10 @@ impl Config { root_path, snippets: Default::default(), workspace_roots, - visual_studio_code_version, + client_info: client_info.map(|it| ClientInfo { + name: it.name, + version: it.version.as_deref().map(Version::parse).and_then(Result::ok), + }), client_config: (FullConfigInput::default(), ConfigErrors(vec![])), default_config: DEFAULT_CONFIG_DATA.get_or_init(|| Box::leak(Box::default())), source_root_parent_map: Arc::new(FxHashMap::default()), @@ -1446,14 +1440,10 @@ impl Config { limit: self.completion_limit(source_root).to_owned(), enable_term_search: self.completion_termSearch_enable(source_root).to_owned(), term_search_fuel: self.completion_termSearch_fuel(source_root).to_owned() as u64, - fields_to_resolve: CompletionFieldsToResolve { - resolve_label_details: client_capability_fields.contains("labelDetails"), - resolve_tags: client_capability_fields.contains("tags"), - resolve_detail: client_capability_fields.contains("detail"), - resolve_documentation: client_capability_fields.contains("documentation"), - resolve_filter_text: client_capability_fields.contains("filterText"), - resolve_text_edit: client_capability_fields.contains("textEdit"), - resolve_command: client_capability_fields.contains("command"), + fields_to_resolve: if self.client_is_neovim() { + CompletionFieldsToResolve::empty() + } else { + CompletionFieldsToResolve::from_client_capabilities(&client_capability_fields) }, } } @@ -1614,13 +1604,9 @@ impl Config { } else { None }, - fields_to_resolve: InlayFieldsToResolve { - resolve_text_edits: client_capability_fields.contains("textEdits"), - resolve_hint_tooltip: client_capability_fields.contains("tooltip"), - resolve_label_tooltip: client_capability_fields.contains("label.tooltip"), - resolve_label_location: client_capability_fields.contains("label.location"), - resolve_label_command: client_capability_fields.contains("label.command"), - }, + fields_to_resolve: InlayFieldsToResolve::from_client_capabilities( + &client_capability_fields, + ), implicit_drop_hints: self.inlayHints_implicitDrops_enable().to_owned(), range_exclusive_hints: self.inlayHints_rangeExclusiveHints_enable().to_owned(), } @@ -2166,14 +2152,25 @@ impl Config { } } - pub fn typing_autoclose_angle(&self) -> bool { - *self.typing_autoClosingAngleBrackets_enable() + pub fn typing_exclude_chars(&self) -> Option<String> { + self.typing_excludeChars().clone() } // VSCode is our reference implementation, so we allow ourselves to work around issues by // special casing certain versions pub fn visual_studio_code_version(&self) -> Option<&Version> { - self.visual_studio_code_version.as_ref() + self.client_info + .as_ref() + .filter(|it| it.name.starts_with("Visual Studio Code")) + .and_then(|it| it.version.as_ref()) + } + + pub fn client_is_helix(&self) -> bool { + self.client_info.as_ref().map(|it| it.name == "helix").unwrap_or_default() + } + + pub fn client_is_neovim(&self) -> bool { + self.client_info.as_ref().map(|it| it.name == "Neovim").unwrap_or_default() } } // Deserialization definitions diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs index 7fbeaa4e3ea..5f835702840 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs @@ -392,7 +392,14 @@ impl GlobalState { || !self.config.same_source_root_parent_map(&self.local_roots_parent_map) { let config_change = { - let user_config_path = Config::user_config_path(); + let user_config_path = (|| { + let mut p = Config::user_config_dir_path()?; + p.push("rust-analyzer.toml"); + Some(p) + })(); + + let user_config_abs_path = user_config_path.as_deref(); + let mut change = ConfigChange::default(); let db = self.analysis_host.raw_database(); @@ -411,7 +418,7 @@ impl GlobalState { .collect_vec(); for (file_id, (_change_kind, vfs_path)) in modified_ratoml_files { - if vfs_path.as_path() == user_config_path { + if vfs_path.as_path() == user_config_abs_path { change.change_user_config(Some(db.file_text(file_id))); continue; } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs index bb03eb3c89b..5e7262b14ca 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs @@ -379,9 +379,7 @@ fn run_flycheck(state: &mut GlobalState, vfs_path: VfsPath) -> bool { for (id, package) in workspace_ids.clone() { if id == flycheck.id() { updated = true; - match package.filter(|_| { - !world.config.flycheck_workspace(source_root_id) && target.is_some() - }) { + match package.filter(|_| !world.config.flycheck_workspace(source_root_id)) { Some(package) => flycheck .restart_for_package(package, target.clone().map(TupleExt::head)), None => flycheck.restart_workspace(saved_file.clone()), diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs index 4975467ece9..fa78be5cb60 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs @@ -10,6 +10,7 @@ use std::{ use anyhow::Context; +use base64::{prelude::BASE64_STANDARD, Engine}; use ide::{ AnnotationConfig, AssistKind, AssistResolveStrategy, Cancellable, CompletionFieldsToResolve, FilePosition, FileRange, HoverAction, HoverGotoTypeData, InlayFieldsToResolve, Query, @@ -36,6 +37,7 @@ use triomphe::Arc; use vfs::{AbsPath, AbsPathBuf, FileId, VfsPath}; use crate::{ + completion_item_hash, config::{Config, RustfmtConfig, WorkspaceSymbolConfig}, diagnostics::convert_diagnostic, global_state::{FetchWorkspaceRequest, GlobalState, GlobalStateSnapshot}, @@ -459,9 +461,9 @@ pub(crate) fn handle_on_type_formatting( if char_typed == '>' { return Ok(None); } + let chars_to_exclude = snap.config.typing_exclude_chars(); - let edit = - snap.analysis.on_char_typed(position, char_typed, snap.config.typing_autoclose_angle())?; + let edit = snap.analysis.on_char_typed(position, char_typed, chars_to_exclude)?; let edit = match edit { Some(it) => it, None => return Ok(None), @@ -1127,7 +1129,7 @@ pub(crate) fn handle_completion_resolve( forced_resolve_completions_config.fields_to_resolve = CompletionFieldsToResolve::empty(); let position = FilePosition { file_id, offset }; - let Some(resolved_completions) = snap.analysis.completions( + let Some(completions) = snap.analysis.completions( &forced_resolve_completions_config, position, resolve_data.trigger_character, @@ -1135,6 +1137,19 @@ pub(crate) fn handle_completion_resolve( else { return Ok(original_completion); }; + let Ok(resolve_data_hash) = BASE64_STANDARD.decode(resolve_data.hash) else { + return Ok(original_completion); + }; + + let Some(corresponding_completion) = completions.into_iter().find(|completion_item| { + // Avoid computing hashes for items that obviously do not match + // r-a might append a detail-based suffix to the label, so we cannot check for equality + original_completion.label.starts_with(completion_item.label.as_str()) + && resolve_data_hash == completion_item_hash(completion_item, resolve_data.for_ref) + }) else { + return Ok(original_completion); + }; + let mut resolved_completions = to_proto::completion_items( &snap.config, &forced_resolve_completions_config.fields_to_resolve, @@ -1142,15 +1157,11 @@ pub(crate) fn handle_completion_resolve( snap.file_version(position.file_id), resolve_data.position, resolve_data.trigger_character, - resolved_completions, + vec![corresponding_completion], ); - - let mut resolved_completion = - if resolved_completions.get(resolve_data.completion_item_index).is_some() { - resolved_completions.swap_remove(resolve_data.completion_item_index) - } else { - return Ok(original_completion); - }; + let Some(mut resolved_completion) = resolved_completions.pop() else { + return Ok(original_completion); + }; if !resolve_data.imports.is_empty() { let additional_edits = snap @@ -2341,6 +2352,10 @@ fn run_rustfmt( ); Ok(None) } + // rustfmt panicked at lexing/parsing the file + Some(101) if !rustfmt_not_installed && captured_stderr.starts_with("error[") => { + Ok(None) + } _ => { // Something else happened - e.g. `rustfmt` is missing or caught a signal Err(LspError::new( diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs index 234204695cb..15d60c873fb 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs @@ -47,7 +47,9 @@ use self::lsp::ext as lsp_ext; #[cfg(test)] mod integrated_benchmarks; +use ide::{CompletionItem, CompletionRelevance}; use serde::de::DeserializeOwned; +use tenthash::TentHasher; pub use crate::{ lsp::capabilities::server_capabilities, main_loop::main_loop, reload::ws_to_crate_graph, @@ -61,3 +63,79 @@ pub fn from_json<T: DeserializeOwned>( serde_json::from_value(json.clone()) .map_err(|e| anyhow::format_err!("Failed to deserialize {what}: {e}; {json}")) } + +fn completion_item_hash(item: &CompletionItem, is_ref_completion: bool) -> [u8; 20] { + fn hash_completion_relevance(hasher: &mut TentHasher, relevance: &CompletionRelevance) { + use ide_completion::{ + CompletionRelevancePostfixMatch, CompletionRelevanceReturnType, + CompletionRelevanceTypeMatch, + }; + + hasher.update([ + u8::from(relevance.exact_name_match), + u8::from(relevance.is_local), + u8::from(relevance.is_name_already_imported), + u8::from(relevance.requires_import), + u8::from(relevance.is_private_editable), + ]); + if let Some(type_match) = &relevance.type_match { + let label = match type_match { + CompletionRelevanceTypeMatch::CouldUnify => "could_unify", + CompletionRelevanceTypeMatch::Exact => "exact", + }; + hasher.update(label); + } + if let Some(trait_) = &relevance.trait_ { + hasher.update([u8::from(trait_.is_op_method), u8::from(trait_.notable_trait)]); + } + if let Some(postfix_match) = &relevance.postfix_match { + let label = match postfix_match { + CompletionRelevancePostfixMatch::NonExact => "non_exact", + CompletionRelevancePostfixMatch::Exact => "exact", + }; + hasher.update(label); + } + if let Some(function) = &relevance.function { + hasher.update([u8::from(function.has_params), u8::from(function.has_self_param)]); + let label = match function.return_type { + CompletionRelevanceReturnType::Other => "other", + CompletionRelevanceReturnType::DirectConstructor => "direct_constructor", + CompletionRelevanceReturnType::Constructor => "constructor", + CompletionRelevanceReturnType::Builder => "builder", + }; + hasher.update(label); + } + } + + let mut hasher = TentHasher::new(); + hasher.update([ + u8::from(is_ref_completion), + u8::from(item.is_snippet), + u8::from(item.deprecated), + u8::from(item.trigger_call_info), + ]); + hasher.update(&item.label); + if let Some(label_detail) = &item.label_detail { + hasher.update(label_detail); + } + // NB: do not hash edits or source range, as those may change between the time the client sends the resolve request + // and the time it receives it: some editors do allow changing the buffer between that, leading to ranges being different. + // + // Documentation hashing is skipped too, as it's a large blob to process, + // while not really making completion properties more unique as they are already. + hasher.update(item.kind.tag()); + hasher.update(&item.lookup); + if let Some(detail) = &item.detail { + hasher.update(detail); + } + hash_completion_relevance(&mut hasher, &item.relevance); + if let Some((mutability, text_size)) = &item.ref_match { + hasher.update(mutability.as_keyword_for_ref()); + hasher.update(u32::from(*text_size).to_le_bytes()); + } + for (import_path, import_name) in &item.import_to_add { + hasher.update(import_path); + hasher.update(import_name); + } + hasher.finalize() +} diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs index 1db616898e8..b1136dbbdac 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/capabilities.rs @@ -1,4 +1,5 @@ //! Advertises the capabilities of the LSP Server. +use ide::{CompletionFieldsToResolve, InlayFieldsToResolve}; use ide_db::{line_index::WideEncoding, FxHashSet}; use lsp_types::{ CallHierarchyServerCapability, CodeActionKind, CodeActionOptions, CodeActionProviderCapability, @@ -40,7 +41,11 @@ pub fn server_capabilities(config: &Config) -> ServerCapabilities { })), hover_provider: Some(HoverProviderCapability::Simple(true)), completion_provider: Some(CompletionOptions { - resolve_provider: config.caps().completions_resolve_provider(), + resolve_provider: if config.client_is_neovim() { + config.completion_item_edit_resolve().then_some(true) + } else { + Some(config.caps().completions_resolve_provider()) + }, trigger_characters: Some(vec![ ":".to_owned(), ".".to_owned(), @@ -71,9 +76,12 @@ pub fn server_capabilities(config: &Config) -> ServerCapabilities { RustfmtConfig::Rustfmt { enable_range_formatting: true, .. } => Some(OneOf::Left(true)), _ => Some(OneOf::Left(false)), }, - document_on_type_formatting_provider: Some(DocumentOnTypeFormattingOptions { - first_trigger_character: "=".to_owned(), - more_trigger_character: Some(more_trigger_character(config)), + document_on_type_formatting_provider: Some({ + let mut chars = ide::Analysis::SUPPORTED_TRIGGER_CHARS.chars(); + DocumentOnTypeFormattingOptions { + first_trigger_character: chars.next().unwrap().to_string(), + more_trigger_character: Some(chars.map(|c| c.to_string()).collect()), + } }), selection_range_provider: Some(SelectionRangeProviderCapability::Simple(true)), folding_range_provider: Some(FoldingRangeProviderCapability::Simple(true)), @@ -136,7 +144,7 @@ pub fn server_capabilities(config: &Config) -> ServerCapabilities { inlay_hint_provider: Some(OneOf::Right(InlayHintServerCapabilities::Options( InlayHintOptions { work_done_progress_options: Default::default(), - resolve_provider: Some(true), + resolve_provider: Some(config.caps().inlay_hints_resolve_provider()), }, ))), inline_value_provider: None, @@ -176,8 +184,18 @@ impl ClientCapabilities { Self(caps) } - fn completions_resolve_provider(&self) -> Option<bool> { - self.completion_item_edit_resolve().then_some(true) + fn completions_resolve_provider(&self) -> bool { + let client_capabilities = self.completion_resolve_support_properties(); + let fields_to_resolve = + CompletionFieldsToResolve::from_client_capabilities(&client_capabilities); + fields_to_resolve != CompletionFieldsToResolve::empty() + } + + fn inlay_hints_resolve_provider(&self) -> bool { + let client_capabilities = self.inlay_hint_resolve_support_properties(); + let fields_to_resolve = + InlayFieldsToResolve::from_client_capabilities(&client_capabilities); + fields_to_resolve != InlayFieldsToResolve::empty() } fn experimental_bool(&self, index: &'static str) -> bool { @@ -517,11 +535,3 @@ impl ClientCapabilities { .unwrap_or_default() } } - -fn more_trigger_character(config: &Config) -> Vec<String> { - let mut res = vec![".".to_owned(), ">".to_owned(), "{".to_owned(), "(".to_owned()]; - if config.snippet_cap().is_some() { - res.push("<".to_owned()); - } - res -} diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs index 6ddfe118d5e..df06270a8b1 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs @@ -826,7 +826,8 @@ pub struct CompletionResolveData { pub imports: Vec<CompletionImport>, pub version: Option<i32>, pub trigger_character: Option<char>, - pub completion_item_index: usize, + pub for_ref: bool, + pub hash: String, } #[derive(Debug, Serialize, Deserialize)] diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs index d444f90a131..612cb547b41 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs @@ -5,6 +5,7 @@ use std::{ sync::atomic::{AtomicU32, Ordering}, }; +use base64::{prelude::BASE64_STANDARD, Engine}; use ide::{ Annotation, AnnotationKind, Assist, AssistKind, Cancellable, CompletionFieldsToResolve, CompletionItem, CompletionItemKind, CompletionRelevance, Documentation, FileId, FileRange, @@ -21,6 +22,7 @@ use serde_json::to_value; use vfs::AbsPath; use crate::{ + completion_item_hash, config::{CallInfoConfig, Config}, global_state::GlobalStateSnapshot, line_index::{LineEndings, LineIndex, PositionEncoding}, @@ -295,7 +297,7 @@ fn completion_item( // non-trivial mapping here. let mut text_edit = None; let source_range = item.source_range; - for indel in item.text_edit { + for indel in &item.text_edit { if indel.delete.contains_range(source_range) { // Extract this indel as the main edit text_edit = Some(if indel.delete == source_range { @@ -347,7 +349,7 @@ fn completion_item( something_to_resolve |= item.documentation.is_some(); None } else { - item.documentation.map(documentation) + item.documentation.clone().map(documentation) }; let mut lsp_item = lsp_types::CompletionItem { @@ -371,10 +373,10 @@ fn completion_item( } else { lsp_item.label_details = Some(lsp_types::CompletionItemLabelDetails { detail: item.label_detail.as_ref().map(ToString::to_string), - description: item.detail, + description: item.detail.clone(), }); } - } else if let Some(label_detail) = item.label_detail { + } else if let Some(label_detail) = &item.label_detail { lsp_item.label.push_str(label_detail.as_str()); } @@ -383,6 +385,7 @@ fn completion_item( let imports = if config.completion(None).enable_imports_on_the_fly && !item.import_to_add.is_empty() { item.import_to_add + .clone() .into_iter() .map(|(import_path, import_name)| lsp_ext::CompletionImport { full_import_path: import_path, @@ -393,16 +396,15 @@ fn completion_item( Vec::new() }; let (ref_resolve_data, resolve_data) = if something_to_resolve || !imports.is_empty() { - let mut item_index = acc.len(); let ref_resolve_data = if ref_match.is_some() { let ref_resolve_data = lsp_ext::CompletionResolveData { position: tdpp.clone(), imports: Vec::new(), version, trigger_character: completion_trigger_character, - completion_item_index: item_index, + for_ref: true, + hash: BASE64_STANDARD.encode(completion_item_hash(&item, true)), }; - item_index += 1; Some(to_value(ref_resolve_data).unwrap()) } else { None @@ -412,7 +414,8 @@ fn completion_item( imports, version, trigger_character: completion_trigger_character, - completion_item_index: item_index, + for_ref: false, + hash: BASE64_STANDARD.encode(completion_item_hash(&item, false)), }; (ref_resolve_data, Some(to_value(resolve_data).unwrap())) } else { diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs index 73fce42437f..a34f0a3c929 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs @@ -809,7 +809,7 @@ impl GlobalState { } } vfs::loader::Message::Progress { n_total, n_done, dir, config_version } => { - let _p = span!(Level::INFO, "GlobalState::handle_vfs_mgs/progress").entered(); + let _p = span!(Level::INFO, "GlobalState::handle_vfs_msg/progress").entered(); always!(config_version <= self.vfs_config_version); let (n_done, state) = match n_done { diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs index bc85afa0e49..4549735fef8 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs @@ -590,7 +590,7 @@ impl GlobalState { } watchers.extend( - iter::once(Config::user_config_path()) + iter::once(Config::user_config_dir_path().as_deref()) .chain(self.workspaces.iter().map(|ws| ws.manifest().map(ManifestPath::as_ref))) .flatten() .map(|glob_pattern| lsp_types::FileSystemWatcher { @@ -613,7 +613,11 @@ impl GlobalState { } let files_config = self.config.files(); - let project_folders = ProjectFolders::new(&self.workspaces, &files_config.exclude); + let project_folders = ProjectFolders::new( + &self.workspaces, + &files_config.exclude, + Config::user_config_dir_path().as_deref(), + ); if (self.proc_macro_clients.is_empty() || !same_workspaces) && self.config.expand_proc_macros() diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/ratoml.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/ratoml.rs index a857e0c2967..5dfaf0d3650 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/ratoml.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/ratoml.rs @@ -46,7 +46,7 @@ impl RatomlTest { project = project.with_config(client_config); } - let server = project.server().wait_until_workspace_is_loaded(); + let server = project.server_with_lock(true).wait_until_workspace_is_loaded(); let mut case = Self { urls: vec![], server, tmp_path }; let urls = fixtures.iter().map(|fixture| case.fixture_path(fixture)).collect::<Vec<_>>(); @@ -72,7 +72,7 @@ impl RatomlTest { let mut spl = spl.into_iter(); if let Some(first) = spl.next() { if first == "$$CONFIG_DIR$$" { - path = Config::user_config_path().unwrap().to_path_buf().into(); + path = Config::user_config_dir_path().unwrap().into(); } else { path = path.join(first); } @@ -285,7 +285,6 @@ enum Value { // } #[test] -#[ignore = "the user config is currently not being watched on startup, fix this"] fn ratoml_user_config_detected() { if skip_slow_tests() { return; @@ -294,7 +293,7 @@ fn ratoml_user_config_detected() { let server = RatomlTest::new( vec![ r#" -//- /$$CONFIG_DIR$$/rust-analyzer/rust-analyzer.toml +//- /$$CONFIG_DIR$$/rust-analyzer.toml assist.emitMustUse = true "#, r#" @@ -322,7 +321,6 @@ enum Value { } #[test] -#[ignore = "the user config is currently not being watched on startup, fix this"] fn ratoml_create_user_config() { if skip_slow_tests() { return; @@ -353,10 +351,7 @@ enum Value { 1, InternalTestingFetchConfigResponse::AssistEmitMustUse(false), ); - server.create( - "//- /$$CONFIG_DIR$$/rust-analyzer/rust-analyzer.toml", - RatomlTest::EMIT_MUST_USE.to_owned(), - ); + server.create("//- /$$CONFIG_DIR$$/rust-analyzer.toml", RatomlTest::EMIT_MUST_USE.to_owned()); server.query( InternalTestingFetchConfigOption::AssistEmitMustUse, 1, @@ -365,7 +360,6 @@ enum Value { } #[test] -#[ignore = "the user config is currently not being watched on startup, fix this"] fn ratoml_modify_user_config() { if skip_slow_tests() { return; @@ -386,7 +380,7 @@ enum Value { Text(String), }"#, r#" -//- /$$CONFIG_DIR$$/rust-analyzer/rust-analyzer.toml +//- /$$CONFIG_DIR$$/rust-analyzer.toml assist.emitMustUse = true"#, ], vec!["p1"], @@ -407,7 +401,6 @@ assist.emitMustUse = true"#, } #[test] -#[ignore = "the user config is currently not being watched on startup, fix this"] fn ratoml_delete_user_config() { if skip_slow_tests() { return; @@ -428,7 +421,7 @@ enum Value { Text(String), }"#, r#" -//- /$$CONFIG_DIR$$/rust-analyzer/rust-analyzer.toml +//- /$$CONFIG_DIR$$/rust-analyzer.toml assist.emitMustUse = true"#, ], vec!["p1"], diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs index 78572e37a9b..5a88a5515c7 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs @@ -1,7 +1,7 @@ use std::{ cell::{Cell, RefCell}, - fs, - sync::Once, + env, fs, + sync::{Once, OnceLock}, time::Duration, }; @@ -127,7 +127,53 @@ impl Project<'_> { } pub(crate) fn server(self) -> Server { - static CONFIG_DIR_LOCK: Mutex<()> = Mutex::new(()); + Project::server_with_lock(self, false) + } + + /// `prelock` : Forcefully acquire a lock that will maintain the path to the config dir throughout the whole test. + /// + /// When testing we set the user config dir by setting an envvar `__TEST_RA_USER_CONFIG_DIR`. + /// This value must be maintained until the end of a test case. When tests run in parallel + /// this value may change thus making the tests flaky. As such, we use a `MutexGuard` that locks + /// the process until `Server` is dropped. To optimize parallelization we use a lock only when it is + /// needed, that is when a test uses config directory to do stuff. Our naive approach is to use a lock + /// if there is a path to config dir in the test fixture. However, in certain cases we create a + /// file in the config dir after server is run, something where our naive approach comes short. + /// Using a `prelock` allows us to force a lock when we know we need it. + pub(crate) fn server_with_lock(self, config_lock: bool) -> Server { + static CONFIG_DIR_LOCK: OnceLock<(Utf8PathBuf, Mutex<()>)> = OnceLock::new(); + + let config_dir_guard = if config_lock { + Some({ + let (path, mutex) = CONFIG_DIR_LOCK.get_or_init(|| { + let value = TestDir::new().keep().path().to_owned(); + env::set_var("__TEST_RA_USER_CONFIG_DIR", &value); + (value, Mutex::new(())) + }); + #[allow(dyn_drop)] + (mutex.lock(), { + Box::new({ + struct Dropper(Utf8PathBuf); + impl Drop for Dropper { + fn drop(&mut self) { + for entry in fs::read_dir(&self.0).unwrap() { + let path = entry.unwrap().path(); + if path.is_file() { + fs::remove_file(path).unwrap(); + } else if path.is_dir() { + fs::remove_dir_all(path).unwrap(); + } + } + } + } + Dropper(path.clone()) + }) as Box<dyn Drop> + }) + }) + } else { + None + }; + let tmp_dir = self.tmp_dir.unwrap_or_else(|| { if self.root_dir_contains_symlink { TestDir::new_symlink() @@ -160,13 +206,9 @@ impl Project<'_> { assert!(mini_core.is_none()); assert!(toolchain.is_none()); - let mut config_dir_guard = None; for entry in fixture { if let Some(pth) = entry.path.strip_prefix("/$$CONFIG_DIR$$") { - if config_dir_guard.is_none() { - config_dir_guard = Some(CONFIG_DIR_LOCK.lock()); - } - let path = Config::user_config_path().unwrap().join(&pth['/'.len_utf8()..]); + let path = Config::user_config_dir_path().unwrap().join(&pth['/'.len_utf8()..]); fs::create_dir_all(path.parent().unwrap()).unwrap(); fs::write(path.as_path(), entry.text.as_bytes()).unwrap(); } else { @@ -269,12 +311,14 @@ pub(crate) struct Server { client: Connection, /// XXX: remove the tempdir last dir: TestDir, - _config_dir_guard: Option<MutexGuard<'static, ()>>, + #[allow(dyn_drop)] + _config_dir_guard: Option<(MutexGuard<'static, ()>, Box<dyn Drop>)>, } impl Server { + #[allow(dyn_drop)] fn new( - config_dir_guard: Option<MutexGuard<'static, ()>>, + config_dir_guard: Option<(MutexGuard<'static, ()>, Box<dyn Drop>)>, dir: TestDir, config: Config, ) -> Server { diff --git a/src/tools/rust-analyzer/crates/syntax/rust.ungram b/src/tools/rust-analyzer/crates/syntax/rust.ungram index 02c59646a99..30428329dd9 100644 --- a/src/tools/rust-analyzer/crates/syntax/rust.ungram +++ b/src/tools/rust-analyzer/crates/syntax/rust.ungram @@ -37,7 +37,7 @@ Path = PathSegment = '::'? NameRef | NameRef GenericArgList? -| NameRef ParamList RetType? +| NameRef ParenthesizedArgList RetType? | NameRef ReturnTypeSyntax | '<' Type ('as' PathType)? '>' @@ -49,6 +49,9 @@ ReturnTypeSyntax = // Generics // //*************************// +ParenthesizedArgList = + '::'? '(' (TypeArg (',' TypeArg)* ','?)? ')' + GenericArgList = '::'? '<' (GenericArg (',' GenericArg)* ','?)? '>' diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs index f1286e7aa21..ffe9f16cfd5 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs @@ -909,30 +909,6 @@ fn get_or_insert_comma_after(syntax: &SyntaxNode) -> SyntaxToken { } } -impl ast::VariantList { - pub fn add_variant(&self, variant: ast::Variant) { - let (indent, position) = match self.variants().last() { - Some(last_item) => ( - IndentLevel::from_node(last_item.syntax()), - Position::after(get_or_insert_comma_after(last_item.syntax())), - ), - None => match self.l_curly_token() { - Some(l_curly) => { - normalize_ws_between_braces(self.syntax()); - (IndentLevel::from_token(&l_curly) + 1, Position::after(&l_curly)) - } - None => (IndentLevel::single(), Position::last_child_of(self.syntax())), - }, - }; - let elements: Vec<SyntaxElement> = vec![ - make::tokens::whitespace(&format!("{}{indent}", "\n")).into(), - variant.syntax().clone().into(), - ast::make::token(T![,]).into(), - ]; - ted::insert_all(position, elements); - } -} - fn normalize_ws_between_braces(node: &SyntaxNode) -> Option<()> { let l = node .children_with_tokens() @@ -1055,8 +1031,6 @@ mod tests { use std::fmt; use parser::Edition; - use stdx::trim_indent; - use test_utils::assert_eq_text; use crate::SourceFile; @@ -1170,102 +1144,4 @@ mod tests { check("let a: u8 = 3;", "let a = 3;", None); check("let a: = 3;", "let a = 3;", None); } - - #[test] - fn add_variant_to_empty_enum() { - let variant = make::variant(make::name("Bar"), None).clone_for_update(); - - check_add_variant( - r#" -enum Foo {} -"#, - r#" -enum Foo { - Bar, -} -"#, - variant, - ); - } - - #[test] - fn add_variant_to_non_empty_enum() { - let variant = make::variant(make::name("Baz"), None).clone_for_update(); - - check_add_variant( - r#" -enum Foo { - Bar, -} -"#, - r#" -enum Foo { - Bar, - Baz, -} -"#, - variant, - ); - } - - #[test] - fn add_variant_with_tuple_field_list() { - let variant = make::variant( - make::name("Baz"), - Some(ast::FieldList::TupleFieldList(make::tuple_field_list(std::iter::once( - make::tuple_field(None, make::ty("bool")), - )))), - ) - .clone_for_update(); - - check_add_variant( - r#" -enum Foo { - Bar, -} -"#, - r#" -enum Foo { - Bar, - Baz(bool), -} -"#, - variant, - ); - } - - #[test] - fn add_variant_with_record_field_list() { - let variant = make::variant( - make::name("Baz"), - Some(ast::FieldList::RecordFieldList(make::record_field_list(std::iter::once( - make::record_field(None, make::name("x"), make::ty("bool")), - )))), - ) - .clone_for_update(); - - check_add_variant( - r#" -enum Foo { - Bar, -} -"#, - r#" -enum Foo { - Bar, - Baz { x: bool }, -} -"#, - variant, - ); - } - - fn check_add_variant(before: &str, expected: &str, variant: ast::Variant) { - let enum_ = ast_mut_from_text::<ast::Enum>(before); - if let Some(it) = enum_.variant_list() { - it.add_variant(variant) - } - let after = enum_.to_string(); - assert_eq_text!(&trim_indent(expected.trim()), &trim_indent(after.trim())); - } } diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs index 23d2b355a94..01dcb646b37 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs @@ -1363,6 +1363,21 @@ impl ParenType { } #[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct ParenthesizedArgList { + pub(crate) syntax: SyntaxNode, +} +impl ParenthesizedArgList { + #[inline] + pub fn type_args(&self) -> AstChildren<TypeArg> { support::children(&self.syntax) } + #[inline] + pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) } + #[inline] + pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) } + #[inline] + pub fn coloncolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![::]) } +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Path { pub(crate) syntax: SyntaxNode, } @@ -1403,7 +1418,9 @@ impl PathSegment { #[inline] pub fn name_ref(&self) -> Option<NameRef> { support::child(&self.syntax) } #[inline] - pub fn param_list(&self) -> Option<ParamList> { support::child(&self.syntax) } + pub fn parenthesized_arg_list(&self) -> Option<ParenthesizedArgList> { + support::child(&self.syntax) + } #[inline] pub fn path_type(&self) -> Option<PathType> { support::child(&self.syntax) } #[inline] @@ -3760,6 +3777,20 @@ impl AstNode for ParenType { #[inline] fn syntax(&self) -> &SyntaxNode { &self.syntax } } +impl AstNode for ParenthesizedArgList { + #[inline] + fn can_cast(kind: SyntaxKind) -> bool { kind == PARENTHESIZED_ARG_LIST } + #[inline] + fn cast(syntax: SyntaxNode) -> Option<Self> { + if Self::can_cast(syntax.kind()) { + Some(Self { syntax }) + } else { + None + } + } + #[inline] + fn syntax(&self) -> &SyntaxNode { &self.syntax } +} impl AstNode for Path { #[inline] fn can_cast(kind: SyntaxKind) -> bool { kind == PATH } @@ -7097,6 +7128,11 @@ impl std::fmt::Display for ParenType { std::fmt::Display::fmt(self.syntax(), f) } } +impl std::fmt::Display for ParenthesizedArgList { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} impl std::fmt::Display for Path { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs index 2ec83d23b27..05c2a8354da 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs @@ -402,7 +402,7 @@ pub fn join_paths(paths: impl IntoIterator<Item = ast::Path>) -> ast::Path { // FIXME: should not be pub pub fn path_from_text(text: &str) -> ast::Path { - ast_from_text(&format!("fn main() {{ let test = {text}; }}")) + ast_from_text(&format!("fn main() {{ let test: {text}; }}")) } pub fn use_tree_glob() -> ast::UseTree { @@ -1053,7 +1053,17 @@ pub fn variant_list(variants: impl IntoIterator<Item = ast::Variant>) -> ast::Va ast_from_text(&format!("enum f {{ {variants} }}")) } -pub fn variant(name: ast::Name, field_list: Option<ast::FieldList>) -> ast::Variant { +pub fn variant( + visibility: Option<ast::Visibility>, + name: ast::Name, + field_list: Option<ast::FieldList>, + discriminant: Option<ast::Expr>, +) -> ast::Variant { + let visibility = match visibility { + None => String::new(), + Some(it) => format!("{it} "), + }; + let field_list = match field_list { None => String::new(), Some(it) => match it { @@ -1061,7 +1071,12 @@ pub fn variant(name: ast::Name, field_list: Option<ast::FieldList>) -> ast::Vari ast::FieldList::TupleFieldList(tuple) => format!("{tuple}"), }, }; - ast_from_text(&format!("enum f {{ {name}{field_list} }}")) + + let discriminant = match discriminant { + Some(it) => format!(" = {it}"), + None => String::new(), + }; + ast_from_text(&format!("enum f {{ {visibility}{name}{field_list}{discriminant} }}")) } pub fn fn_( @@ -1122,6 +1137,8 @@ pub fn struct_( pub fn enum_( visibility: Option<ast::Visibility>, enum_name: ast::Name, + generic_param_list: Option<ast::GenericParamList>, + where_clause: Option<ast::WhereClause>, variant_list: ast::VariantList, ) -> ast::Enum { let visibility = match visibility { @@ -1129,7 +1146,12 @@ pub fn enum_( Some(it) => format!("{it} "), }; - ast_from_text(&format!("{visibility}enum {enum_name} {variant_list}")) + let generic_params = generic_param_list.map(|it| it.to_string()).unwrap_or_default(); + let where_clause = where_clause.map(|it| format!(" {it}")).unwrap_or_default(); + + ast_from_text(&format!( + "{visibility}enum {enum_name}{generic_params}{where_clause} {variant_list}" + )) } pub fn attr_outer(meta: ast::Meta) -> ast::Attr { diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs index 9f88add0f78..e86c291f76c 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs @@ -2,9 +2,9 @@ use itertools::Itertools; use crate::{ - ast::{self, make, HasName}, + ast::{self, make, HasGenericParams, HasName, HasTypeBounds, HasVisibility}, syntax_editor::SyntaxMappingBuilder, - AstNode, + AstNode, NodeOrToken, SyntaxKind, SyntaxNode, SyntaxToken, }; use super::SyntaxFactory; @@ -14,6 +14,40 @@ impl SyntaxFactory { make::name(name).clone_for_update() } + pub fn ty(&self, text: &str) -> ast::Type { + make::ty(text).clone_for_update() + } + + pub fn ty_infer(&self) -> ast::InferType { + let ast::Type::InferType(ast) = make::ty_placeholder().clone_for_update() else { + unreachable!() + }; + + ast + } + + pub fn type_param( + &self, + name: ast::Name, + bounds: Option<ast::TypeBoundList>, + ) -> ast::TypeParam { + let ast = make::type_param(name.clone(), bounds.clone()).clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_node(name.syntax().clone(), ast.name().unwrap().syntax().clone()); + if let Some(input) = bounds { + builder.map_node( + input.syntax().clone(), + ast.type_bound_list().unwrap().syntax().clone(), + ); + } + builder.finish(&mut mapping); + } + + ast + } + pub fn ident_pat(&self, ref_: bool, mut_: bool, name: ast::Name) -> ast::IdentPat { let ast = make::ident_pat(ref_, mut_, name.clone()).clone_for_update(); @@ -32,22 +66,52 @@ impl SyntaxFactory { tail_expr: Option<ast::Expr>, ) -> ast::BlockExpr { let stmts = stmts.into_iter().collect_vec(); - let input = stmts.iter().map(|it| it.syntax().clone()).collect_vec(); + let mut input = stmts.iter().map(|it| it.syntax().clone()).collect_vec(); let ast = make::block_expr(stmts, tail_expr.clone()).clone_for_update(); - if let Some((mut mapping, stmt_list)) = self.mappings().zip(ast.stmt_list()) { + if let Some(mut mapping) = self.mappings() { + let stmt_list = ast.stmt_list().unwrap(); let mut builder = SyntaxMappingBuilder::new(stmt_list.syntax().clone()); + if let Some(input) = tail_expr { + builder.map_node( + input.syntax().clone(), + stmt_list.tail_expr().unwrap().syntax().clone(), + ); + } else if let Some(ast_tail) = stmt_list.tail_expr() { + // The parser interpreted the last statement (probably a statement with a block) as an Expr + let last_stmt = input.pop().unwrap(); + + builder.map_node(last_stmt, ast_tail.syntax().clone()); + } + builder.map_children( input.into_iter(), stmt_list.statements().map(|it| it.syntax().clone()), ); - if let Some((input, output)) = tail_expr.zip(stmt_list.tail_expr()) { - builder.map_node(input.syntax().clone(), output.syntax().clone()); - } + builder.finish(&mut mapping); + } + + ast + } + + pub fn expr_empty_block(&self) -> ast::BlockExpr { + ast::BlockExpr { syntax: make::expr_empty_block().syntax().clone_for_update() } + } + pub fn expr_bin(&self, lhs: ast::Expr, op: ast::BinaryOp, rhs: ast::Expr) -> ast::BinExpr { + let ast::Expr::BinExpr(ast) = + make::expr_bin_op(lhs.clone(), op, rhs.clone()).clone_for_update() + else { + unreachable!() + }; + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_node(lhs.syntax().clone(), ast.lhs().unwrap().syntax().clone()); + builder.map_node(rhs.syntax().clone(), ast.rhs().unwrap().syntax().clone()); builder.finish(&mut mapping); } @@ -83,6 +147,22 @@ impl SyntaxFactory { ast.into() } + pub fn expr_return(&self, expr: Option<ast::Expr>) -> ast::ReturnExpr { + let ast::Expr::ReturnExpr(ast) = make::expr_return(expr.clone()).clone_for_update() else { + unreachable!() + }; + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + if let Some(input) = expr { + builder.map_node(input.syntax().clone(), ast.expr().unwrap().syntax().clone()); + } + builder.finish(&mut mapping); + } + + ast + } + pub fn let_stmt( &self, pattern: ast::Pat, @@ -107,4 +187,261 @@ impl SyntaxFactory { ast } + + pub fn turbofish_generic_arg_list( + &self, + args: impl IntoIterator<Item = ast::GenericArg> + Clone, + ) -> ast::GenericArgList { + let ast = make::turbofish_generic_arg_list(args.clone()).clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_children( + args.into_iter().map(|arg| arg.syntax().clone()), + ast.generic_args().map(|arg| arg.syntax().clone()), + ); + builder.finish(&mut mapping); + } + + ast + } + + pub fn record_field_list( + &self, + fields: impl IntoIterator<Item = ast::RecordField>, + ) -> ast::RecordFieldList { + let fields: Vec<ast::RecordField> = fields.into_iter().collect(); + let input: Vec<_> = fields.iter().map(|it| it.syntax().clone()).collect(); + let ast = make::record_field_list(fields).clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + + builder.map_children(input.into_iter(), ast.fields().map(|it| it.syntax().clone())); + + builder.finish(&mut mapping); + } + + ast + } + + pub fn record_field( + &self, + visibility: Option<ast::Visibility>, + name: ast::Name, + ty: ast::Type, + ) -> ast::RecordField { + let ast = + make::record_field(visibility.clone(), name.clone(), ty.clone()).clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + if let Some(visibility) = visibility { + builder.map_node( + visibility.syntax().clone(), + ast.visibility().unwrap().syntax().clone(), + ); + } + + builder.map_node(name.syntax().clone(), ast.name().unwrap().syntax().clone()); + builder.map_node(ty.syntax().clone(), ast.ty().unwrap().syntax().clone()); + + builder.finish(&mut mapping); + } + + ast + } + + pub fn tuple_field_list( + &self, + fields: impl IntoIterator<Item = ast::TupleField>, + ) -> ast::TupleFieldList { + let fields: Vec<ast::TupleField> = fields.into_iter().collect(); + let input: Vec<_> = fields.iter().map(|it| it.syntax().clone()).collect(); + let ast = make::tuple_field_list(fields).clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + + builder.map_children(input.into_iter(), ast.fields().map(|it| it.syntax().clone())); + + builder.finish(&mut mapping); + } + + ast + } + + pub fn tuple_field( + &self, + visibility: Option<ast::Visibility>, + ty: ast::Type, + ) -> ast::TupleField { + let ast = make::tuple_field(visibility.clone(), ty.clone()).clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + if let Some(visibility) = visibility { + builder.map_node( + visibility.syntax().clone(), + ast.visibility().unwrap().syntax().clone(), + ); + } + + builder.map_node(ty.syntax().clone(), ast.ty().unwrap().syntax().clone()); + + builder.finish(&mut mapping); + } + + ast + } + + pub fn item_enum( + &self, + visibility: Option<ast::Visibility>, + name: ast::Name, + generic_param_list: Option<ast::GenericParamList>, + where_clause: Option<ast::WhereClause>, + variant_list: ast::VariantList, + ) -> ast::Enum { + let ast = make::enum_( + visibility.clone(), + name.clone(), + generic_param_list.clone(), + where_clause.clone(), + variant_list.clone(), + ) + .clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + if let Some(visibility) = visibility { + builder.map_node( + visibility.syntax().clone(), + ast.visibility().unwrap().syntax().clone(), + ); + } + + builder.map_node(name.syntax().clone(), ast.name().unwrap().syntax().clone()); + + if let Some(generic_param_list) = generic_param_list { + builder.map_node( + generic_param_list.syntax().clone(), + ast.generic_param_list().unwrap().syntax().clone(), + ); + } + + if let Some(where_clause) = where_clause { + builder.map_node( + where_clause.syntax().clone(), + ast.where_clause().unwrap().syntax().clone(), + ); + } + + builder.map_node( + variant_list.syntax().clone(), + ast.variant_list().unwrap().syntax().clone(), + ); + + builder.finish(&mut mapping); + } + + ast + } + + pub fn variant_list( + &self, + variants: impl IntoIterator<Item = ast::Variant>, + ) -> ast::VariantList { + let variants: Vec<ast::Variant> = variants.into_iter().collect(); + let input: Vec<_> = variants.iter().map(|it| it.syntax().clone()).collect(); + let ast = make::variant_list(variants).clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + + builder.map_children(input.into_iter(), ast.variants().map(|it| it.syntax().clone())); + + builder.finish(&mut mapping); + } + + ast + } + + pub fn variant( + &self, + visibility: Option<ast::Visibility>, + name: ast::Name, + field_list: Option<ast::FieldList>, + discriminant: Option<ast::Expr>, + ) -> ast::Variant { + let ast = make::variant( + visibility.clone(), + name.clone(), + field_list.clone(), + discriminant.clone(), + ) + .clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + if let Some(visibility) = visibility { + builder.map_node( + visibility.syntax().clone(), + ast.visibility().unwrap().syntax().clone(), + ); + } + + builder.map_node(name.syntax().clone(), ast.name().unwrap().syntax().clone()); + + if let Some(field_list) = field_list { + builder.map_node( + field_list.syntax().clone(), + ast.field_list().unwrap().syntax().clone(), + ); + } + + if let Some(discriminant) = discriminant { + builder + .map_node(discriminant.syntax().clone(), ast.expr().unwrap().syntax().clone()); + } + + builder.finish(&mut mapping); + } + + ast + } + + pub fn token_tree( + &self, + delimiter: SyntaxKind, + tt: Vec<NodeOrToken<ast::TokenTree, SyntaxToken>>, + ) -> ast::TokenTree { + let tt: Vec<_> = tt.into_iter().collect(); + let input: Vec<_> = tt.iter().cloned().filter_map(only_nodes).collect(); + + let ast = make::token_tree(delimiter, tt).clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_children( + input.into_iter(), + ast.token_trees_and_tokens().filter_map(only_nodes), + ); + builder.finish(&mut mapping); + } + + return ast; + + fn only_nodes(element: NodeOrToken<ast::TokenTree, SyntaxToken>) -> Option<SyntaxNode> { + element.as_node().map(|it| it.syntax().clone()) + } + } + + pub fn token(&self, kind: SyntaxKind) -> SyntaxToken { + make::token(kind) + } + + pub fn whitespace(&self, text: &str) -> ast::SyntaxToken { + make::tokens::whitespace(text) + } } diff --git a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs index 714f5a99111..992a847663a 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs @@ -16,6 +16,7 @@ use rustc_hash::FxHashMap; use crate::{SyntaxElement, SyntaxNode, SyntaxToken}; mod edit_algo; +mod edits; mod mapping; pub use mapping::{SyntaxMapping, SyntaxMappingBuilder}; @@ -326,7 +327,7 @@ mod tests { use crate::{ ast::{self, make, syntax_factory::SyntaxFactory}, - AstNode, + AstNode, SyntaxKind, }; use super::*; @@ -539,4 +540,50 @@ mod tests { }"#]]; expect.assert_eq(&edit.new_root.to_string()); } + + #[test] + fn test_replace_token_in_parent() { + let parent_fn = make::fn_( + None, + make::name("it"), + None, + None, + make::param_list(None, []), + make::block_expr([], Some(make::expr_unit())), + Some(make::ret_type(make::ty_unit())), + false, + false, + false, + false, + ); + + let mut editor = SyntaxEditor::new(parent_fn.syntax().clone()); + + if let Some(ret_ty) = parent_fn.ret_type() { + editor.delete(ret_ty.syntax().clone()); + + if let Some(SyntaxElement::Token(token)) = ret_ty.syntax().next_sibling_or_token() { + if token.kind().is_trivia() { + editor.delete(token); + } + } + } + + if let Some(tail) = parent_fn.body().unwrap().tail_expr() { + // FIXME: We do this because `xtask tidy` will not allow us to have trailing whitespace in the expect string. + if let Some(SyntaxElement::Token(token)) = tail.syntax().prev_sibling_or_token() { + if let SyntaxKind::WHITESPACE = token.kind() { + editor.delete(token); + } + } + editor.delete(tail.syntax().clone()); + } + + let edit = editor.finish(); + + let expect = expect![[r#" +fn it() { +}"#]]; + expect.assert_eq(&edit.new_root.to_string()); + } } diff --git a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edit_algo.rs b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edit_algo.rs index b769c941105..57ecbe57019 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edit_algo.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edit_algo.rs @@ -73,7 +73,7 @@ pub(super) fn apply_edits(editor: SyntaxEditor) -> SyntaxEdit { }) .all(|(l, r)| { get_node_depth(l.target_parent()) != get_node_depth(r.target_parent()) - || l.target_range().intersect(r.target_range()).is_none() + || (l.target_range().end() <= r.target_range().start()) }); if stdx::never!( @@ -128,13 +128,14 @@ pub(super) fn apply_edits(editor: SyntaxEditor) -> SyntaxEdit { // Add to changed ancestors, if applicable match change { - Change::Insert(_, _) | Change::InsertAll(_, _) => {} - Change::Replace(target, _) | Change::ReplaceWithMany(target, _) => { + Change::Replace(SyntaxElement::Node(target), _) + | Change::ReplaceWithMany(SyntaxElement::Node(target), _) => { changed_ancestors.push_back(ChangedAncestor::single(target, change_index)) } Change::ReplaceAll(range, _) => { changed_ancestors.push_back(ChangedAncestor::multiple(range, change_index)) } + _ => (), } } @@ -154,6 +155,12 @@ pub(super) fn apply_edits(editor: SyntaxEditor) -> SyntaxEdit { } }; } + Change::Replace(SyntaxElement::Node(target), Some(SyntaxElement::Node(new_target))) => { + *target = tree_mutator.make_syntax_mut(target); + if new_target.ancestors().any(|node| node == tree_mutator.immutable) { + *new_target = new_target.clone_for_update(); + } + } Change::Replace(target, _) | Change::ReplaceWithMany(target, _) => { *target = tree_mutator.make_element_mut(target); } @@ -304,13 +311,8 @@ enum ChangedAncestorKind { } impl ChangedAncestor { - fn single(element: &SyntaxElement, change_index: usize) -> Self { - let kind = match element { - SyntaxElement::Node(node) => ChangedAncestorKind::Single { node: node.clone() }, - SyntaxElement::Token(token) => { - ChangedAncestorKind::Single { node: token.parent().unwrap() } - } - }; + fn single(node: &SyntaxNode, change_index: usize) -> Self { + let kind = ChangedAncestorKind::Single { node: node.clone() }; Self { kind, change_index } } diff --git a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edits.rs b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edits.rs new file mode 100644 index 00000000000..8069fdd06f7 --- /dev/null +++ b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edits.rs @@ -0,0 +1,274 @@ +//! Structural editing for ast using `SyntaxEditor` + +use crate::{ + ast::{ + self, edit::IndentLevel, make, syntax_factory::SyntaxFactory, AstNode, Fn, GenericParam, + HasGenericParams, HasName, + }, + syntax_editor::{Position, SyntaxEditor}, + Direction, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken, T, +}; + +impl SyntaxEditor { + /// Adds a new generic param to the function using `SyntaxEditor` + pub fn add_generic_param(&mut self, function: &Fn, new_param: GenericParam) { + match function.generic_param_list() { + Some(generic_param_list) => match generic_param_list.generic_params().last() { + Some(last_param) => { + // There exists a generic param list and it's not empty + let position = generic_param_list.r_angle_token().map_or_else( + || Position::last_child_of(function.syntax()), + Position::before, + ); + + if last_param + .syntax() + .next_sibling_or_token() + .map_or(false, |it| it.kind() == SyntaxKind::COMMA) + { + self.insert( + Position::after(last_param.syntax()), + new_param.syntax().clone(), + ); + self.insert( + Position::after(last_param.syntax()), + make::token(SyntaxKind::WHITESPACE), + ); + self.insert( + Position::after(last_param.syntax()), + make::token(SyntaxKind::COMMA), + ); + } else { + let elements = vec![ + make::token(SyntaxKind::COMMA).into(), + make::token(SyntaxKind::WHITESPACE).into(), + new_param.syntax().clone().into(), + ]; + self.insert_all(position, elements); + } + } + None => { + // There exists a generic param list but it's empty + let position = Position::after(generic_param_list.l_angle_token().unwrap()); + self.insert(position, new_param.syntax()); + } + }, + None => { + // There was no generic param list + let position = if let Some(name) = function.name() { + Position::after(name.syntax) + } else if let Some(fn_token) = function.fn_token() { + Position::after(fn_token) + } else if let Some(param_list) = function.param_list() { + Position::before(param_list.syntax) + } else { + Position::last_child_of(function.syntax()) + }; + let elements = vec![ + make::token(SyntaxKind::L_ANGLE).into(), + new_param.syntax().clone().into(), + make::token(SyntaxKind::R_ANGLE).into(), + ]; + self.insert_all(position, elements); + } + } + } +} + +fn get_or_insert_comma_after(editor: &mut SyntaxEditor, syntax: &SyntaxNode) -> SyntaxToken { + let make = SyntaxFactory::without_mappings(); + match syntax + .siblings_with_tokens(Direction::Next) + .filter_map(|it| it.into_token()) + .find(|it| it.kind() == T![,]) + { + Some(it) => it, + None => { + let comma = make.token(T![,]); + editor.insert(Position::after(syntax), &comma); + comma + } + } +} + +impl ast::VariantList { + pub fn add_variant(&self, editor: &mut SyntaxEditor, variant: &ast::Variant) { + let make = SyntaxFactory::without_mappings(); + let (indent, position) = match self.variants().last() { + Some(last_item) => ( + IndentLevel::from_node(last_item.syntax()), + Position::after(get_or_insert_comma_after(editor, last_item.syntax())), + ), + None => match self.l_curly_token() { + Some(l_curly) => { + normalize_ws_between_braces(editor, self.syntax()); + (IndentLevel::from_token(&l_curly) + 1, Position::after(&l_curly)) + } + None => (IndentLevel::single(), Position::last_child_of(self.syntax())), + }, + }; + let elements: Vec<SyntaxElement> = vec![ + make.whitespace(&format!("{}{indent}", "\n")).into(), + variant.syntax().clone().into(), + make.token(T![,]).into(), + ]; + editor.insert_all(position, elements); + } +} + +fn normalize_ws_between_braces(editor: &mut SyntaxEditor, node: &SyntaxNode) -> Option<()> { + let make = SyntaxFactory::without_mappings(); + let l = node + .children_with_tokens() + .filter_map(|it| it.into_token()) + .find(|it| it.kind() == T!['{'])?; + let r = node + .children_with_tokens() + .filter_map(|it| it.into_token()) + .find(|it| it.kind() == T!['}'])?; + + let indent = IndentLevel::from_node(node); + + match l.next_sibling_or_token() { + Some(ws) if ws.kind() == SyntaxKind::WHITESPACE => { + if ws.next_sibling_or_token()?.into_token()? == r { + editor.replace(ws, make.whitespace(&format!("\n{indent}"))); + } + } + Some(ws) if ws.kind() == T!['}'] => { + editor.insert(Position::after(l), make.whitespace(&format!("\n{indent}"))); + } + _ => (), + } + Some(()) +} + +#[cfg(test)] +mod tests { + use parser::Edition; + use stdx::trim_indent; + use test_utils::assert_eq_text; + + use crate::SourceFile; + + use super::*; + + fn ast_from_text<N: AstNode>(text: &str) -> N { + let parse = SourceFile::parse(text, Edition::CURRENT); + let node = match parse.tree().syntax().descendants().find_map(N::cast) { + Some(it) => it, + None => { + let node = std::any::type_name::<N>(); + panic!("Failed to make ast node `{node}` from text {text}") + } + }; + let node = node.clone_subtree(); + assert_eq!(node.syntax().text_range().start(), 0.into()); + node + } + + #[test] + fn add_variant_to_empty_enum() { + let make = SyntaxFactory::without_mappings(); + let variant = make.variant(None, make.name("Bar"), None, None); + + check_add_variant( + r#" +enum Foo {} +"#, + r#" +enum Foo { + Bar, +} +"#, + variant, + ); + } + + #[test] + fn add_variant_to_non_empty_enum() { + let make = SyntaxFactory::without_mappings(); + let variant = make.variant(None, make.name("Baz"), None, None); + + check_add_variant( + r#" +enum Foo { + Bar, +} +"#, + r#" +enum Foo { + Bar, + Baz, +} +"#, + variant, + ); + } + + #[test] + fn add_variant_with_tuple_field_list() { + let make = SyntaxFactory::without_mappings(); + let variant = make.variant( + None, + make.name("Baz"), + Some(make.tuple_field_list([make.tuple_field(None, make.ty("bool"))]).into()), + None, + ); + + check_add_variant( + r#" +enum Foo { + Bar, +} +"#, + r#" +enum Foo { + Bar, + Baz(bool), +} +"#, + variant, + ); + } + + #[test] + fn add_variant_with_record_field_list() { + let make = SyntaxFactory::without_mappings(); + let variant = make.variant( + None, + make.name("Baz"), + Some( + make.record_field_list([make.record_field(None, make.name("x"), make.ty("bool"))]) + .into(), + ), + None, + ); + + check_add_variant( + r#" +enum Foo { + Bar, +} +"#, + r#" +enum Foo { + Bar, + Baz { x: bool }, +} +"#, + variant, + ); + } + + fn check_add_variant(before: &str, expected: &str, variant: ast::Variant) { + let enum_ = ast_from_text::<ast::Enum>(before); + let mut editor = SyntaxEditor::new(enum_.syntax().clone()); + if let Some(it) = enum_.variant_list() { + it.add_variant(&mut editor, &variant) + } + let edit = editor.finish(); + let after = edit.new_root.to_string(); + assert_eq_text!(&trim_indent(expected.trim()), &trim_indent(after.trim())); + } +} diff --git a/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs b/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs index 593e31c2fbb..889a7d10ada 100644 --- a/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs +++ b/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs @@ -236,7 +236,7 @@ impl ChangeFixture { crate_graph.add_crate_root( crate_root, Edition::CURRENT, - Some(CrateName::new("test").unwrap().into()), + Some(CrateName::new("ra_test_fixture").unwrap().into()), None, From::from(default_cfg.clone()), Some(From::from(default_cfg)), diff --git a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs index 07767d5ae9f..99dfabe174e 100644 --- a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs +++ b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs @@ -12,6 +12,7 @@ //! asm: //! assert: //! as_ref: sized +//! async_fn: fn, tuple, future, copy //! bool_impl: option, fn //! builtin_impls: //! cell: copy, drop @@ -29,7 +30,7 @@ //! eq: sized //! error: fmt //! fmt: option, result, transmute, coerce_unsized, copy, clone, derive -//! fn: +//! fn: tuple //! from: sized //! future: pin //! coroutine: pin @@ -60,6 +61,7 @@ //! sync: sized //! transmute: //! try: infallible +//! tuple: //! unpin: sized //! unsize: sized //! todo: panic @@ -138,10 +140,10 @@ pub mod marker { } // endregion:copy - // region:fn + // region:tuple #[lang = "tuple_trait"] pub trait Tuple {} - // endregion:fn + // endregion:tuple // region:phantom_data #[lang = "phantom_data"] @@ -682,6 +684,112 @@ pub mod ops { } pub use self::function::{Fn, FnMut, FnOnce}; // endregion:fn + + // region:async_fn + mod async_function { + use crate::{future::Future, marker::Tuple}; + + #[lang = "async_fn"] + #[fundamental] + pub trait AsyncFn<Args: Tuple>: AsyncFnMut<Args> { + extern "rust-call" fn async_call(&self, args: Args) -> Self::CallRefFuture<'_>; + } + + #[lang = "async_fn_mut"] + #[fundamental] + pub trait AsyncFnMut<Args: Tuple>: AsyncFnOnce<Args> { + #[lang = "call_ref_future"] + type CallRefFuture<'a>: Future<Output = Self::Output> + where + Self: 'a; + extern "rust-call" fn async_call_mut(&mut self, args: Args) -> Self::CallRefFuture<'_>; + } + + #[lang = "async_fn_once"] + #[fundamental] + pub trait AsyncFnOnce<Args: Tuple> { + #[lang = "async_fn_once_output"] + type Output; + #[lang = "call_once_future"] + type CallOnceFuture: Future<Output = Self::Output>; + extern "rust-call" fn async_call_once(self, args: Args) -> Self::CallOnceFuture; + } + + mod impls { + use super::{AsyncFn, AsyncFnMut, AsyncFnOnce}; + use crate::marker::Tuple; + + impl<A: Tuple, F: ?Sized> AsyncFn<A> for &F + where + F: AsyncFn<A>, + { + extern "rust-call" fn async_call(&self, args: A) -> Self::CallRefFuture<'_> { + F::async_call(*self, args) + } + } + + impl<A: Tuple, F: ?Sized> AsyncFnMut<A> for &F + where + F: AsyncFn<A>, + { + type CallRefFuture<'a> + = F::CallRefFuture<'a> + where + Self: 'a; + + extern "rust-call" fn async_call_mut( + &mut self, + args: A, + ) -> Self::CallRefFuture<'_> { + F::async_call(*self, args) + } + } + + impl<'a, A: Tuple, F: ?Sized> AsyncFnOnce<A> for &'a F + where + F: AsyncFn<A>, + { + type Output = F::Output; + type CallOnceFuture = F::CallRefFuture<'a>; + + extern "rust-call" fn async_call_once(self, args: A) -> Self::CallOnceFuture { + F::async_call(self, args) + } + } + + impl<A: Tuple, F: ?Sized> AsyncFnMut<A> for &mut F + where + F: AsyncFnMut<A>, + { + type CallRefFuture<'a> + = F::CallRefFuture<'a> + where + Self: 'a; + + extern "rust-call" fn async_call_mut( + &mut self, + args: A, + ) -> Self::CallRefFuture<'_> { + F::async_call_mut(*self, args) + } + } + + impl<'a, A: Tuple, F: ?Sized> AsyncFnOnce<A> for &'a mut F + where + F: AsyncFnMut<A>, + { + type Output = F::Output; + type CallOnceFuture = F::CallRefFuture<'a>; + + extern "rust-call" fn async_call_once(self, args: A) -> Self::CallOnceFuture { + F::async_call_mut(self, args) + } + } + } + } + pub use self::async_function::{AsyncFn, AsyncFnMut, AsyncFnOnce}; + // endregion:async_fn + // region:try mod try_ { use crate::convert::Infallible; @@ -1684,6 +1792,7 @@ pub mod prelude { marker::Sync, // :sync mem::drop, // :drop ops::Drop, // :drop + ops::{AsyncFn, AsyncFnMut, AsyncFnOnce}, // :async_fn ops::{Fn, FnMut, FnOnce}, // :fn option::Option::{self, None, Some}, // :option panic, // :panic diff --git a/src/tools/rust-analyzer/docs/dev/lsp-extensions.md b/src/tools/rust-analyzer/docs/dev/lsp-extensions.md index b7c536e0279..2aad2cfa361 100644 --- a/src/tools/rust-analyzer/docs/dev/lsp-extensions.md +++ b/src/tools/rust-analyzer/docs/dev/lsp-extensions.md @@ -1,5 +1,5 @@ <!--- -lsp/ext.rs hash: 96f88b7a5d0080c6 +lsp/ext.rs hash: 14b7fb1309f5bb00 If you need to change the above hash to make the test pass, please check if you need to adjust this doc as well and ping this issue: diff --git a/src/tools/rust-analyzer/docs/user/generated_config.adoc b/src/tools/rust-analyzer/docs/user/generated_config.adoc index 052d0a2a41d..1195a85cf70 100644 --- a/src/tools/rust-analyzer/docs/user/generated_config.adoc +++ b/src/tools/rust-analyzer/docs/user/generated_config.adoc @@ -992,10 +992,10 @@ Show full signature of the callable. Only shows parameters if disabled. -- Show documentation. -- -[[rust-analyzer.typing.autoClosingAngleBrackets.enable]]rust-analyzer.typing.autoClosingAngleBrackets.enable (default: `false`):: +[[rust-analyzer.typing.excludeChars]]rust-analyzer.typing.excludeChars (default: `"|<"`):: + -- -Whether to insert closing angle brackets when typing an opening angle bracket of a generic argument list. +Specify the characters to exclude from triggering typing assists. The default trigger characters are `.`, `=`, `<`, `>`, `{`, and `(`. -- [[rust-analyzer.workspace.discoverConfig]]rust-analyzer.workspace.discoverConfig (default: `null`):: + diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json index 82c43b76fdd..469c1b458d5 100644 --- a/src/tools/rust-analyzer/editors/code/package.json +++ b/src/tools/rust-analyzer/editors/code/package.json @@ -425,6 +425,41 @@ ], "default": "openLogs", "markdownDescription": "Action to run when clicking the extension status bar item." + }, + "rust-analyzer.statusBar.documentSelector": { + "type": [ + "array", + "null" + ], + "items": { + "type": "object", + "properties": { + "language": { + "type": [ + "string", + "null" + ] + }, + "pattern": { + "type": [ + "string", + "null" + ] + } + } + }, + "default": [ + { + "language": "rust" + }, + { + "pattern": "**/Cargo.toml" + }, + { + "pattern": "**/Cargo.lock" + } + ], + "markdownDescription": "Determines when to show the extension status bar item based on the currently open file. Use `{ \"pattern\": \"**\" }` to always show. Use `null` to never show." } } }, @@ -2570,10 +2605,13 @@ { "title": "typing", "properties": { - "rust-analyzer.typing.autoClosingAngleBrackets.enable": { - "markdownDescription": "Whether to insert closing angle brackets when typing an opening angle bracket of a generic argument list.", - "default": false, - "type": "boolean" + "rust-analyzer.typing.excludeChars": { + "markdownDescription": "Specify the characters to exclude from triggering typing assists. The default trigger characters are `.`, `=`, `<`, `>`, `{`, and `(`.", + "default": "|<", + "type": [ + "null", + "string" + ] } } }, diff --git a/src/tools/rust-analyzer/editors/code/src/client.ts b/src/tools/rust-analyzer/editors/code/src/client.ts index eac7b849fdb..4ce19f5c665 100644 --- a/src/tools/rust-analyzer/editors/code/src/client.ts +++ b/src/tools/rust-analyzer/editors/code/src/client.ts @@ -324,7 +324,7 @@ class ExperimentalFeatures implements lc.StaticFeature { } fillClientCapabilities(capabilities: lc.ClientCapabilities): void { capabilities.experimental = { - snippetTextEdit: true, + snippetTextEdit: false, codeActionGroup: true, hoverActions: true, serverStatusNotification: true, diff --git a/src/tools/rust-analyzer/editors/code/src/config.ts b/src/tools/rust-analyzer/editors/code/src/config.ts index 67bc72f1e12..f7ef80df2ba 100644 --- a/src/tools/rust-analyzer/editors/code/src/config.ts +++ b/src/tools/rust-analyzer/editors/code/src/config.ts @@ -261,9 +261,9 @@ export class Config { return this.get<boolean | undefined>("testExplorer"); } - get runnablesExtraEnv() { + runnablesExtraEnv(label: string): Record<string, string> | undefined { const item = this.get<any>("runnables.extraEnv") ?? this.get<any>("runnableEnv"); - if (!item) return item; + if (!item) return undefined; const fixRecord = (r: Record<string, any>) => { for (const key in r) { if (typeof r[key] !== "string") { @@ -271,11 +271,28 @@ export class Config { } } }; + + const platform = process.platform; + const checkPlatform = (it: RunnableEnvCfgItem) => { + if (it.platform) { + const platforms = Array.isArray(it.platform) ? it.platform : [it.platform]; + return platforms.indexOf(platform) >= 0; + } + return true; + }; + if (item instanceof Array) { - item.forEach((x) => fixRecord(x.env)); - } else { - fixRecord(item); + const env = {}; + for (const it of item) { + const masked = !it.mask || new RegExp(it.mask).test(label); + if (masked && checkPlatform(it)) { + Object.assign(env, it.env); + } + } + fixRecord(env); + return env; } + fixRecord(item); return item; } @@ -331,6 +348,10 @@ export class Config { return this.get<string>("statusBar.clickAction"); } + get statusBarDocumentSelector() { + return this.get<vscode.DocumentSelector>("statusBar.documentSelector"); + } + get initializeStopped() { return this.get<boolean>("initializeStopped"); } diff --git a/src/tools/rust-analyzer/editors/code/src/ctx.ts b/src/tools/rust-analyzer/editors/code/src/ctx.ts index 234fe6ab024..4a3f66b00d0 100644 --- a/src/tools/rust-analyzer/editors/code/src/ctx.ts +++ b/src/tools/rust-analyzer/editors/code/src/ctx.ts @@ -88,6 +88,7 @@ export class Ctx implements RustAnalyzerExtensionApi { private _treeView: vscode.TreeView<Dependency | DependencyFile | DependencyId> | undefined; private lastStatus: ServerStatusParams | { health: "stopped" } = { health: "stopped" }; private _serverVersion: string; + private statusBarActiveEditorListener: Disposable; get serverPath(): string | undefined { return this._serverPath; @@ -119,6 +120,10 @@ export class Ctx implements RustAnalyzerExtensionApi { this._serverVersion = "<not running>"; this.config = new Config(extCtx.subscriptions); this.statusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left); + this.updateStatusBarVisibility(vscode.window.activeTextEditor); + this.statusBarActiveEditorListener = vscode.window.onDidChangeActiveTextEditor((editor) => + this.updateStatusBarVisibility(editor), + ); if (this.config.testExplorer) { this.testController = vscode.tests.createTestController( "rustAnalyzerTestController", @@ -141,6 +146,7 @@ export class Ctx implements RustAnalyzerExtensionApi { dispose() { this.config.dispose(); this.statusBar.dispose(); + this.statusBarActiveEditorListener.dispose(); this.testController?.dispose(); void this.disposeClient(); this.commandDisposables.forEach((disposable) => disposable.dispose()); @@ -404,7 +410,6 @@ export class Ctx implements RustAnalyzerExtensionApi { let icon = ""; const status = this.lastStatus; const statusBar = this.statusBar; - statusBar.show(); statusBar.tooltip = new vscode.MarkdownString("", true); statusBar.tooltip.isTrusted = true; switch (status.health) { @@ -472,6 +477,17 @@ export class Ctx implements RustAnalyzerExtensionApi { statusBar.text = `${icon}rust-analyzer`; } + private updateStatusBarVisibility(editor: vscode.TextEditor | undefined) { + const documentSelector = this.config.statusBarDocumentSelector; + if (documentSelector != null) { + if (editor != null && vscode.languages.match(documentSelector, editor.document) > 0) { + this.statusBar.show(); + return; + } + } + this.statusBar.hide(); + } + pushExtCleanup(d: Disposable) { this.extCtx.subscriptions.push(d); } diff --git a/src/tools/rust-analyzer/editors/code/src/debug.ts b/src/tools/rust-analyzer/editors/code/src/debug.ts index 9e2e3d2185b..f21ca2e8f96 100644 --- a/src/tools/rust-analyzer/editors/code/src/debug.ts +++ b/src/tools/rust-analyzer/editors/code/src/debug.ts @@ -148,8 +148,16 @@ async function getDebugConfiguration( return path.normalize(p).replace(wsFolder, `\${workspaceFolder${workspaceQualifier}}`); } - const env = prepareEnv(inheritEnv, runnable.label, runnableArgs, config.runnablesExtraEnv); - const executable = await getDebugExecutable(runnableArgs, env); + const executable = await getDebugExecutable( + runnableArgs, + prepareEnv(true, {}, config.runnablesExtraEnv(runnable.label)), + ); + + const env = prepareEnv( + inheritEnv, + runnableArgs.environment, + config.runnablesExtraEnv(runnable.label), + ); let sourceFileMap = debugOptions.sourceFileMap; if (sourceFileMap === "auto") { diff --git a/src/tools/rust-analyzer/editors/code/src/run.ts b/src/tools/rust-analyzer/editors/code/src/run.ts index 8a82a5a58cf..f71ab7ffbd8 100644 --- a/src/tools/rust-analyzer/editors/code/src/run.ts +++ b/src/tools/rust-analyzer/editors/code/src/run.ts @@ -5,7 +5,7 @@ import * as tasks from "./tasks"; import type { CtxInit } from "./ctx"; import { makeDebugConfig } from "./debug"; -import type { Config, RunnableEnvCfg, RunnableEnvCfgItem } from "./config"; +import type { Config } from "./config"; import type { LanguageClient } from "vscode-languageclient/node"; import { unwrapUndefinable, type RustEditor } from "./util"; @@ -81,32 +81,13 @@ export function prepareBaseEnv( export function prepareEnv( inheritEnv: boolean, - label: string, - runnableArgs: ra.CargoRunnableArgs, - runnableEnvCfg?: RunnableEnvCfg, + runnableEnv?: Record<string, string>, + runnableEnvCfg?: Record<string, string>, ): Record<string, string> { - const env = prepareBaseEnv(inheritEnv, runnableArgs.environment); - const platform = process.platform; - - const checkPlatform = (it: RunnableEnvCfgItem) => { - if (it.platform) { - const platforms = Array.isArray(it.platform) ? it.platform : [it.platform]; - return platforms.indexOf(platform) >= 0; - } - return true; - }; + const env = prepareBaseEnv(inheritEnv, runnableEnv); if (runnableEnvCfg) { - if (Array.isArray(runnableEnvCfg)) { - for (const it of runnableEnvCfg) { - const masked = !it.mask || new RegExp(it.mask).test(label); - if (masked && checkPlatform(it)) { - Object.assign(env, it.env); - } - } - } else { - Object.assign(env, runnableEnvCfg); - } + Object.assign(env, runnableEnvCfg); } return env; @@ -140,7 +121,11 @@ export async function createTaskFromRunnable( }; options = { cwd: runnableArgs.workspaceRoot || ".", - env: prepareEnv(true, runnable.label, runnableArgs, config.runnablesExtraEnv), + env: prepareEnv( + true, + runnableArgs.environment, + config.runnablesExtraEnv(runnable.label), + ), }; } else { const runnableArgs = runnable.args; diff --git a/src/tools/rust-analyzer/editors/code/tests/unit/runnable_env.test.ts b/src/tools/rust-analyzer/editors/code/tests/unit/runnable_env.test.ts deleted file mode 100644 index f0a62a3cce2..00000000000 --- a/src/tools/rust-analyzer/editors/code/tests/unit/runnable_env.test.ts +++ /dev/null @@ -1,122 +0,0 @@ -import * as assert from "assert"; -import { prepareEnv } from "../../src/run"; -import type { RunnableEnvCfg } from "../../src/config"; -import type { Context } from "."; -import type * as ra from "../../src/lsp_ext"; - -function makeRunnable(label: string): ra.Runnable { - return { - label, - kind: "cargo", - args: { - cargoArgs: [], - cwd: ".", - executableArgs: [], - }, - }; -} - -function fakePrepareEnv(runnableName: string, config?: RunnableEnvCfg): Record<string, string> { - const runnable = makeRunnable(runnableName); - const runnableArgs = runnable.args as ra.CargoRunnableArgs; - return prepareEnv(false, runnable.label, runnableArgs, config); -} - -export async function getTests(ctx: Context) { - await ctx.suite("Runnable env", (suite) => { - suite.addTest("Global config works", async () => { - const binEnv = fakePrepareEnv("run project_name", { GLOBAL: "g" }); - assert.strictEqual(binEnv["GLOBAL"], "g"); - - const testEnv = fakePrepareEnv("test some::mod::test_name", { GLOBAL: "g" }); - assert.strictEqual(testEnv["GLOBAL"], "g"); - }); - - suite.addTest("null mask works", async () => { - const config = [ - { - env: { DATA: "data" }, - }, - ]; - const binEnv = fakePrepareEnv("run project_name", config); - assert.strictEqual(binEnv["DATA"], "data"); - - const testEnv = fakePrepareEnv("test some::mod::test_name", config); - assert.strictEqual(testEnv["DATA"], "data"); - }); - - suite.addTest("order works", async () => { - const config = [ - { - env: { DATA: "data" }, - }, - { - env: { DATA: "newdata" }, - }, - ]; - const binEnv = fakePrepareEnv("run project_name", config); - assert.strictEqual(binEnv["DATA"], "newdata"); - - const testEnv = fakePrepareEnv("test some::mod::test_name", config); - assert.strictEqual(testEnv["DATA"], "newdata"); - }); - - suite.addTest("mask works", async () => { - const config = [ - { - env: { DATA: "data" }, - }, - { - mask: "^run", - env: { DATA: "rundata" }, - }, - { - mask: "special_test$", - env: { DATA: "special_test" }, - }, - ]; - const binEnv = fakePrepareEnv("run project_name", config); - assert.strictEqual(binEnv["DATA"], "rundata"); - - const testEnv = fakePrepareEnv("test some::mod::test_name", config); - assert.strictEqual(testEnv["DATA"], "data"); - - const specialTestEnv = fakePrepareEnv("test some::mod::special_test", config); - assert.strictEqual(specialTestEnv["DATA"], "special_test"); - }); - - suite.addTest("exact test name works", async () => { - const config = [ - { - env: { DATA: "data" }, - }, - { - mask: "some::mod::test_name", - env: { DATA: "test special" }, - }, - ]; - const testEnv = fakePrepareEnv("test some::mod::test_name", config); - assert.strictEqual(testEnv["DATA"], "test special"); - - const specialTestEnv = fakePrepareEnv("test some::mod::another_test", config); - assert.strictEqual(specialTestEnv["DATA"], "data"); - }); - - suite.addTest("test mod name works", async () => { - const config = [ - { - env: { DATA: "data" }, - }, - { - mask: "some::mod", - env: { DATA: "mod special" }, - }, - ]; - const testEnv = fakePrepareEnv("test some::mod::test_name", config); - assert.strictEqual(testEnv["DATA"], "mod special"); - - const specialTestEnv = fakePrepareEnv("test some::mod::another_test", config); - assert.strictEqual(specialTestEnv["DATA"], "mod special"); - }); - }); -} diff --git a/src/tools/rust-analyzer/rust-version b/src/tools/rust-analyzer/rust-version index 8f41ed9e14f..7d60fa6cb76 100644 --- a/src/tools/rust-analyzer/rust-version +++ b/src/tools/rust-analyzer/rust-version @@ -1 +1 @@ -f005c7437def424a1c43cbc380352a58d8ac920b +5a6036a1802262f8cf02192b02026688d396f1d7 diff --git a/src/tools/rustbook/Cargo.lock b/src/tools/rustbook/Cargo.lock index 024b8f9becb..e8c9c4f4cd1 100644 --- a/src/tools/rustbook/Cargo.lock +++ b/src/tools/rustbook/Cargo.lock @@ -47,9 +47,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.17" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23a1e53f0f5d86382dafe1cf314783b2044280f406e7e1506368220ad11b1338" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" dependencies = [ "anstyle", "anstyle-parse", @@ -96,9 +96,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.92" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74f37166d7d48a0284b99dd824694c26119c700b53bf0d1540cdb147dbdaaf13" +checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775" [[package]] name = "autocfg" @@ -138,9 +138,9 @@ dependencies = [ [[package]] name = "bstr" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40723b8fb387abc38f4f4a37c09073622e41dd12327033091ef8950659e6dc0c" +checksum = "1a68f1f47cdf0ec8ee4b941b2eee2a80cb796db73118c0dd09ac63fbe405be22" dependencies = [ "memchr", "regex-automata", @@ -190,9 +190,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.20" +version = "4.5.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8" +checksum = "fb3b4b9e5a7c7514dfa52869339ee98b3156b0bfb4e8a77c4ff4babb64b1604f" dependencies = [ "clap_builder", "clap_derive", @@ -200,9 +200,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.20" +version = "4.5.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54" +checksum = "b17a95aa67cc7b5ebd32aa5370189aa0d79069ef1c64ce893bd30fb24bff20ec" dependencies = [ "anstream", "anstyle", @@ -213,9 +213,9 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.5.36" +version = "4.5.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86bc73de94bc81e52f3bebec71bc4463e9748f7a59166663e32044669577b0e2" +checksum = "d9647a559c112175f17cf724dc72d3645680a883c58481332779192b0d8e7a01" dependencies = [ "clap", ] @@ -234,9 +234,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" +checksum = "afb84c814227b90d6895e01398aee0d8033c00e7466aca416fb6a8e0eb19d8a7" [[package]] name = "colorchoice" @@ -252,9 +252,9 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpufeatures" -version = "0.2.14" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" +checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3" dependencies = [ "libc", ] @@ -312,6 +312,17 @@ dependencies = [ ] [[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] name = "doc-comment" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -360,25 +371,25 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.9" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "fastrand" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" +checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4" [[package]] name = "flate2" -version = "1.0.34" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0" +checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" dependencies = [ "crc32fast", "miniz_oxide", @@ -456,9 +467,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.0" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" [[package]] name = "heck" @@ -525,20 +536,149 @@ dependencies = [ ] [[package]] +name = "icu_collections" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locid" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_locid_transform" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_locid_transform_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locid_transform_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" + +[[package]] +name = "icu_normalizer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" + +[[package]] +name = "icu_properties" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" + +[[package]] +name = "icu_provider" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_provider_macros", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_provider_macros" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] name = "idna" -version = "0.5.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" dependencies = [ - "unicode-bidi", - "unicode-normalization", + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +dependencies = [ + "icu_normalizer", + "icu_properties", ] [[package]] name = "indexmap" -version = "2.6.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" +checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" dependencies = [ "equivalent", "hashbrown", @@ -552,16 +692,17 @@ checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" [[package]] name = "itoa" -version = "1.0.11" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" [[package]] name = "js-sys" -version = "0.3.72" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" +checksum = "a865e038f7f6ed956f788f0d7d60c541fff74c7bd74272c5d4cf15c63743e705" dependencies = [ + "once_cell", "wasm-bindgen", ] @@ -573,9 +714,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.161" +version = "0.2.167" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" +checksum = "09d6582e104315a817dff97f75133544b2e094ee22447d2acf4a74e189ba06fc" [[package]] name = "libdbus-sys" @@ -603,6 +744,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" [[package]] +name = "litemap" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" + +[[package]] name = "lock_api" version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -646,9 +793,9 @@ dependencies = [ [[package]] name = "mdbook" -version = "0.4.42" +version = "0.4.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7624879735513024d323e7267a0b3a7176aceb0db537939beb4ee31d9e8945e3" +checksum = "fe1f98b8d66e537d2f0ba06e7dec4f44001deec539a2d18bfc102d6a86189148" dependencies = [ "ammonia", "anyhow", @@ -842,9 +989,9 @@ dependencies = [ [[package]] name = "pathdiff" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d61c5ce1153ab5b689d0c074c4e7fc613e942dfb7dd9eea5ab202d2ad91fe361" +checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" [[package]] name = "percent-encoding" @@ -986,9 +1133,9 @@ checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" [[package]] name = "proc-macro2" -version = "1.0.89" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" dependencies = [ "unicode-ident", ] @@ -1122,9 +1269,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", @@ -1151,9 +1298,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.38" +version = "0.38.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa260229e6538e52293eeb577aabd09945a09d6d9cc0fc550ed7529056c2e32a" +checksum = "d7f649912bc1495e167a6edee79151c84b1bad49748cb4f1f1167f459f6224f6" dependencies = [ "bitflags 2.6.0", "errno", @@ -1191,18 +1338,18 @@ checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" [[package]] name = "serde" -version = "1.0.214" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f55c3193aca71c12ad7890f1785d2b73e1b9f63a0bbc353c08ef26fe03fc56b5" +checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.214" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de523f781f095e28fa605cdce0f8307e451cc0fd14e2eb4cd2e98a355b147766" +checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" dependencies = [ "proc-macro2", "quote", @@ -1211,9 +1358,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.132" +version = "1.0.133" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" +checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" dependencies = [ "itoa", "memchr", @@ -1260,6 +1407,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] name = "string_cache" version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1293,9 +1446,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" -version = "2.0.87" +version = "2.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" +checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" dependencies = [ "proc-macro2", "quote", @@ -1303,6 +1456,17 @@ dependencies = [ ] [[package]] +name = "synstructure" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] name = "syntect" version = "5.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1324,9 +1488,9 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.13.0" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b" +checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" dependencies = [ "cfg-if", "fastrand", @@ -1348,9 +1512,9 @@ dependencies = [ [[package]] name = "terminal_size" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f599bd7ca042cfdf8f4512b277c02ba102247820f9d9d4a9f521f496751a6ef" +checksum = "5352447f921fda68cf61b4101566c0bdb5104eff6804d0678e5227580ab6a4e9" dependencies = [ "rustix", "windows-sys 0.59.0", @@ -1364,18 +1528,18 @@ checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" [[package]] name = "thiserror" -version = "1.0.66" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d171f59dbaa811dbbb1aee1e73db92ec2b122911a48e1390dfe327a821ddede" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.66" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b08be0f17bd307950653ce45db00cd31200d82b624b36e181337d9c7d92765b5" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", @@ -1383,21 +1547,16 @@ dependencies = [ ] [[package]] -name = "tinyvec" -version = "1.8.0" +name = "tinystr" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" dependencies = [ - "tinyvec_macros", + "displaydoc", + "zerovec", ] [[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - -[[package]] name = "toml" version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1465,25 +1624,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7e51b68083f157f853b6379db119d1c1be0e6e4dec98101079dec41f6f5cf6df" [[package]] -name = "unicode-bidi" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893" - -[[package]] name = "unicode-ident" -version = "1.0.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" - -[[package]] -name = "unicode-normalization" -version = "0.1.24" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" -dependencies = [ - "tinyvec", -] +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" [[package]] name = "unicode-width" @@ -1493,9 +1637,9 @@ checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" [[package]] name = "url" -version = "2.5.2" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" dependencies = [ "form_urlencoded", "idna", @@ -1509,6 +1653,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" [[package]] +name = "utf16_iter" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] name = "utf8parse" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1538,9 +1694,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.95" +version = "0.2.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" +checksum = "d15e63b4482863c109d70a7b8706c1e364eb6ea449b201a76c5b89cedcec2d5c" dependencies = [ "cfg-if", "once_cell", @@ -1549,9 +1705,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.95" +version = "0.2.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" +checksum = "8d36ef12e3aaca16ddd3f67922bc63e48e953f126de60bd33ccc0101ef9998cd" dependencies = [ "bumpalo", "log", @@ -1564,9 +1720,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.95" +version = "0.2.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" +checksum = "705440e08b42d3e4b36de7d66c944be628d579796b8090bfa3471478a2260051" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1574,9 +1730,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.95" +version = "0.2.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" +checksum = "98c9ae5a76e46f4deecd0f0255cc223cfa18dc9b261213b8aa0c7b36f61b3f1d" dependencies = [ "proc-macro2", "quote", @@ -1587,9 +1743,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.95" +version = "0.2.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" +checksum = "6ee99da9c5ba11bd675621338ef6fa52296b76b83305e9b6e5c77d4c286d6d49" [[package]] name = "winapi" @@ -1723,6 +1879,42 @@ dependencies = [ ] [[package]] +name = "write16" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" + +[[package]] +name = "writeable" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" + +[[package]] +name = "yoke" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] name = "zerocopy" version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1742,3 +1934,46 @@ dependencies = [ "quote", "syn", ] + +[[package]] +name = "zerofrom" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerovec" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 7d3287aaeb9..beeb33b46ff 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -12,7 +12,8 @@ use cargo_metadata::{Metadata, Package, PackageId}; #[rustfmt::skip] const LICENSES: &[&str] = &[ // tidy-alphabetical-start - "(MIT OR Apache-2.0) AND Unicode-DFS-2016", // unicode_ident + "(MIT OR Apache-2.0) AND Unicode-3.0", // unicode_ident (1.0.14) + "(MIT OR Apache-2.0) AND Unicode-DFS-2016", // unicode_ident (1.0.12) "0BSD OR MIT OR Apache-2.0", // adler license "0BSD", "Apache-2.0 / MIT", @@ -94,7 +95,6 @@ const EXCEPTIONS: ExceptionList = &[ ("dissimilar", "Apache-2.0"), // rustdoc, rustc_lexer (few tests) via expect-test, (dev deps) ("fluent-langneg", "Apache-2.0"), // rustc (fluent translations) ("foldhash", "Zlib"), // rustc - ("instant", "BSD-3-Clause"), // rustc_driver/tracing-subscriber/parking_lot ("mdbook", "MPL-2.0"), // mdbook ("option-ext", "MPL-2.0"), // cargo-miri (via `directories`) ("rustc_apfloat", "Apache-2.0 WITH LLVM-exception"), // rustc (license is the same as LLVM uses) diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index 3a021e189f3..25cd32063aa 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -2295,8 +2295,6 @@ ui/issues/issue-43853.rs ui/issues/issue-4387.rs ui/issues/issue-43910.rs ui/issues/issue-43923.rs -ui/issues/issue-43925.rs -ui/issues/issue-43926.rs ui/issues/issue-43988.rs ui/issues/issue-44023.rs ui/issues/issue-44056.rs @@ -2545,8 +2543,6 @@ ui/issues/issue-6936.rs ui/issues/issue-69455.rs ui/issues/issue-69602-type-err-during-codegen-ice.rs ui/issues/issue-69683.rs -ui/issues/issue-70093/issue-70093-link-directives.rs -ui/issues/issue-70093/issue-70093.rs ui/issues/issue-7012.rs ui/issues/issue-70381.rs ui/issues/issue-7044.rs @@ -2711,11 +2707,15 @@ ui/limits/issue-17913.rs ui/limits/issue-55878.rs ui/limits/issue-69485-var-size-diffs-too-large.rs ui/limits/issue-75158-64.rs +ui/link-native-libs/issue-109144.rs +ui/link-native-libs/issue-43925.rs +ui/link-native-libs/issue-43926.rs +ui/link-native-libs/issue-70093/issue-70093-link-directives.rs +ui/link-native-libs/issue-70093/issue-70093.rs ui/linkage-attr/auxiliary/issue-12133-dylib.rs ui/linkage-attr/auxiliary/issue-12133-dylib2.rs ui/linkage-attr/auxiliary/issue-12133-rlib.rs ui/linkage-attr/issue-10755.rs -ui/linkage-attr/issue-109144.rs ui/linkage-attr/issue-12133-1.rs ui/linkage-attr/issue-12133-2.rs ui/linkage-attr/issue-12133-3.rs diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index 11f9d5bb03d..401169c838f 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -17,7 +17,7 @@ use ignore::Walk; const ENTRY_LIMIT: u32 = 901; // FIXME: The following limits should be reduced eventually. -const ISSUES_ENTRY_LIMIT: u32 = 1672; +const ISSUES_ENTRY_LIMIT: u32 = 1667; const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[ "rs", // test source files diff --git a/tests/codegen/instrument-coverage/testprog.rs b/tests/codegen/instrument-coverage/testprog.rs index 655fe779fca..9e918499d57 100644 --- a/tests/codegen/instrument-coverage/testprog.rs +++ b/tests/codegen/instrument-coverage/testprog.rs @@ -73,11 +73,9 @@ fn main() { // WIN: $__llvm_profile_runtime_user = comdat any -// CHECK: @__llvm_coverage_mapping = private constant -// CHECK-SAME: section "[[INSTR_PROF_COVMAP]]", align 8 +// CHECK-DAG: @__llvm_coverage_mapping = private constant {{.*}}, section "[[INSTR_PROF_COVMAP]]", align 8 -// CHECK: @__covrec_{{[A-F0-9]+}}u = linkonce_odr hidden constant -// CHECK-SAME: section "[[INSTR_PROF_COVFUN]]"[[COMDAT_IF_SUPPORTED]], align 8 +// CHECK-DAG: @__covrec_{{[A-F0-9]+}}u = linkonce_odr hidden constant {{.*}}, section "[[INSTR_PROF_COVFUN]]"[[COMDAT_IF_SUPPORTED]], align 8 // WIN: @__llvm_profile_runtime = external{{.*}}global i32 diff --git a/tests/codegen/naked-asan.rs b/tests/codegen/naked-asan.rs index bcaa60baeff..8efedab6ea5 100644 --- a/tests/codegen/naked-asan.rs +++ b/tests/codegen/naked-asan.rs @@ -8,14 +8,15 @@ #![no_std] #![feature(abi_x86_interrupt, naked_functions)] -// CHECK: define x86_intrcc void @page_fault_handler(ptr {{.*}}%0, i64 {{.*}}%1){{.*}}#[[ATTRS:[0-9]+]] { -// CHECK-NOT: memcpy +pub fn caller() { + page_fault_handler(1, 2); +} + +// CHECK: declare x86_intrcc void @page_fault_handler(ptr {{.*}}, i64{{.*}}){{.*}}#[[ATTRS:[0-9]+]] #[naked] #[no_mangle] pub extern "x86-interrupt" fn page_fault_handler(_: u64, _: u64) { - unsafe { - core::arch::naked_asm!("ud2"); - } + unsafe { core::arch::naked_asm!("ud2") }; } // CHECK: #[[ATTRS]] = diff --git a/tests/codegen/naked-fn/aligned.rs b/tests/codegen/naked-fn/aligned.rs index 3bbd67981e5..d9dcd7f6c3e 100644 --- a/tests/codegen/naked-fn/aligned.rs +++ b/tests/codegen/naked-fn/aligned.rs @@ -6,15 +6,12 @@ #![feature(naked_functions, fn_align)] use std::arch::naked_asm; -// CHECK: Function Attrs: naked -// CHECK-NEXT: define{{.*}}void @naked_empty() -// CHECK: align 16 +// CHECK: .balign 16 +// CHECK-LABEL: naked_empty: #[repr(align(16))] #[no_mangle] #[naked] pub unsafe extern "C" fn naked_empty() { - // CHECK-NEXT: start: - // CHECK-NEXT: call void asm - // CHECK-NEXT: unreachable + // CHECK: ret naked_asm!("ret"); } diff --git a/tests/codegen/naked-fn/generics.rs b/tests/codegen/naked-fn/generics.rs new file mode 100644 index 00000000000..a33d213617a --- /dev/null +++ b/tests/codegen/naked-fn/generics.rs @@ -0,0 +1,116 @@ +//@ compile-flags: -O +//@ only-x86_64 + +#![crate_type = "lib"] +#![feature(naked_functions, asm_const)] + +use std::arch::naked_asm; + +#[no_mangle] +fn test(x: u64) { + // just making sure these symbols get used + using_const_generics::<1>(x); + using_const_generics::<2>(x); + + generic_function::<i64>(x as i64); + + let foo = Foo(x); + + foo.method(); + foo.trait_method(); +} + +// CHECK: .balign 4 +// CHECK: add rax, 2 +// CHECK: add rax, 42 + +// CHECK: .balign 4 +// CHECK: add rax, 1 +// CHECK: add rax, 42 + +#[naked] +pub extern "C" fn using_const_generics<const N: u64>(x: u64) -> u64 { + const M: u64 = 42; + + unsafe { + naked_asm!( + "xor rax, rax", + "add rax, rdi", + "add rax, {}", + "add rax, {}", + "ret", + const N, + const M, + ) + } +} + +trait Invert { + fn invert(self) -> Self; +} + +impl Invert for i64 { + fn invert(self) -> Self { + -1 * self + } +} + +// CHECK: .balign 4 +// CHECK-LABEL: generic_function: +// CHECK: call +// CHECK: ret + +#[naked] +#[no_mangle] +pub extern "C" fn generic_function<T: Invert>(x: i64) -> i64 { + unsafe { + naked_asm!( + "call {}", + "ret", + sym <T as Invert>::invert, + ) + } +} + +#[derive(Copy, Clone)] +#[repr(transparent)] +struct Foo(u64); + +// CHECK: .balign 4 +// CHECK-LABEL: method: +// CHECK: mov rax, rdi + +impl Foo { + #[naked] + #[no_mangle] + extern "C" fn method(self) -> u64 { + unsafe { naked_asm!("mov rax, rdi", "ret") } + } +} + +// CHECK: .balign 4 +// CHECK-LABEL: trait_method: +// CHECK: mov rax, rdi + +trait Bar { + extern "C" fn trait_method(self) -> u64; +} + +impl Bar for Foo { + #[naked] + #[no_mangle] + extern "C" fn trait_method(self) -> u64 { + unsafe { naked_asm!("mov rax, rdi", "ret") } + } +} + +// CHECK: .balign 4 +// CHECK-LABEL: naked_with_args_and_return: +// CHECK: lea rax, [rdi + rsi] + +// this previously ICE'd, see https://github.com/rust-lang/rust/issues/124375 +#[naked] +#[no_mangle] +pub unsafe extern "C" fn naked_with_args_and_return(a: isize, b: isize) -> isize { + naked_asm!("lea rax, [rdi + rsi]", "ret"); +} diff --git a/tests/codegen/naked-fn/instruction-set.rs b/tests/codegen/naked-fn/instruction-set.rs new file mode 100644 index 00000000000..5b790b2034c --- /dev/null +++ b/tests/codegen/naked-fn/instruction-set.rs @@ -0,0 +1,59 @@ +//@ revisions: arm-mode thumb-mode +//@ [arm-mode] compile-flags: --target armv5te-none-eabi +//@ [thumb-mode] compile-flags: --target thumbv5te-none-eabi +//@ [arm-mode] needs-llvm-components: arm +//@ [thumb-mode] needs-llvm-components: arm + +#![crate_type = "lib"] +#![feature(no_core, lang_items, rustc_attrs, naked_functions)] +#![no_core] + +#[rustc_builtin_macro] +macro_rules! naked_asm { + () => {}; +} + +#[lang = "sized"] +trait Sized {} +#[lang = "copy"] +trait Copy {} + +// arm-mode: .arm +// thumb-mode: .thumb +// CHECK-LABEL: test_unspecified: +// CHECK: bx lr +// CHECK: .popsection +// arm-mode: .arm +// thumb-mode: .thumb +#[no_mangle] +#[naked] +unsafe extern "C" fn test_unspecified() { + naked_asm!("bx lr"); +} + +// CHECK: .thumb +// CHECK: .thumb_func +// CHECK-LABEL: test_thumb: +// CHECK: bx lr +// CHECK: .popsection +// arm-mode: .arm +// thumb-mode: .thumb +#[no_mangle] +#[naked] +#[instruction_set(arm::t32)] +unsafe extern "C" fn test_thumb() { + naked_asm!("bx lr"); +} + +// CHECK: .arm +// CHECK-LABEL: test_arm: +// CHECK: bx lr +// CHECK: .popsection +// arm-mode: .arm +// thumb-mode: .thumb +#[no_mangle] +#[naked] +#[instruction_set(arm::a32)] +unsafe extern "C" fn test_arm() { + naked_asm!("bx lr"); +} diff --git a/tests/codegen/naked-fn/naked-functions.rs b/tests/codegen/naked-fn/naked-functions.rs index 3f7447af599..f505d27d48c 100644 --- a/tests/codegen/naked-fn/naked-functions.rs +++ b/tests/codegen/naked-fn/naked-functions.rs @@ -1,29 +1,147 @@ -//@ compile-flags: -C no-prepopulate-passes -Copt-level=0 -//@ needs-asm-support -//@ only-x86_64 +//@ revisions: linux win macos thumb +// +//@[linux] compile-flags: --target x86_64-unknown-linux-gnu +//@[linux] needs-llvm-components: x86 +//@[win] compile-flags: --target x86_64-pc-windows-gnu +//@[win] needs-llvm-components: x86 +//@[macos] compile-flags: --target aarch64-apple-darwin +//@[macos] needs-llvm-components: arm +//@[thumb] compile-flags: --target thumbv7em-none-eabi +//@[thumb] needs-llvm-components: arm #![crate_type = "lib"] -#![feature(naked_functions)] -use std::arch::naked_asm; +#![feature(no_core, lang_items, rustc_attrs, naked_functions)] +#![no_core] + +#[rustc_builtin_macro] +macro_rules! naked_asm { + () => {}; +} + +#[lang = "sized"] +trait Sized {} +#[lang = "copy"] +trait Copy {} + +// linux,win: .intel_syntax +// +// linux: .pushsection .text.naked_empty,\22ax\22, @progbits +// macos: .pushsection __TEXT,__text,regular,pure_instructions +// win: .pushsection .text.naked_empty,\22xr\22 +// thumb: .pushsection .text.naked_empty,\22ax\22, %progbits +// +// CHECK: .balign 4 +// +// linux,win,thumb: .globl naked_empty +// macos: .globl _naked_empty +// +// CHECK-NOT: .private_extern +// CHECK-NOT: .hidden +// +// linux: .type naked_empty, @function +// +// win: .def naked_empty +// win: .scl 2 +// win: .type 32 +// win: .endef naked_empty +// +// thumb: .type naked_empty, %function +// thumb: .thumb +// thumb: .thumb_func +// +// CHECK-LABEL: naked_empty: +// +// linux,macos,win: ret +// thumb: bx lr +// +// CHECK: .popsection +// +// thumb: .thumb +// +// linux,win: .att_syntax -// CHECK: Function Attrs: naked -// CHECK-NEXT: define{{.*}}void @naked_empty() #[no_mangle] #[naked] pub unsafe extern "C" fn naked_empty() { - // CHECK-NEXT: {{.+}}: - // CHECK-NEXT: call void asm - // CHECK-NEXT: unreachable + #[cfg(not(all(target_arch = "arm", target_feature = "thumb-mode")))] naked_asm!("ret"); + + #[cfg(all(target_arch = "arm", target_feature = "thumb-mode"))] + naked_asm!("bx lr"); } -// CHECK: Function Attrs: naked -// CHECK-NEXT: define{{.*}}i{{[0-9]+}} @naked_with_args_and_return(i64 %0, i64 %1) +// linux,win: .intel_syntax +// +// linux: .pushsection .text.naked_with_args_and_return,\22ax\22, @progbits +// macos: .pushsection __TEXT,__text,regular,pure_instructions +// win: .pushsection .text.naked_with_args_and_return,\22xr\22 +// thumb: .pushsection .text.naked_with_args_and_return,\22ax\22, %progbits +// +// CHECK: .balign 4 +// +// linux,win,thumb: .globl naked_with_args_and_return +// macos: .globl _naked_with_args_and_return +// +// CHECK-NOT: .private_extern +// CHECK-NOT: .hidden +// +// linux: .type naked_with_args_and_return, @function +// +// win: .def naked_with_args_and_return +// win: .scl 2 +// win: .type 32 +// win: .endef naked_with_args_and_return +// +// thumb: .type naked_with_args_and_return, %function +// thumb: .thumb +// thumb: .thumb_func +// +// CHECK-LABEL: naked_with_args_and_return: +// +// linux, win: lea rax, [rdi + rsi] +// macos: add x0, x0, x1 +// thumb: adds r0, r0, r1 +// +// linux,macos,win: ret +// thumb: bx lr +// +// CHECK: .popsection +// +// thumb: .thumb +// +// linux,win: .att_syntax + #[no_mangle] #[naked] pub unsafe extern "C" fn naked_with_args_and_return(a: isize, b: isize) -> isize { - // CHECK-NEXT: {{.+}}: - // CHECK-NEXT: call void asm - // CHECK-NEXT: unreachable - naked_asm!("lea rax, [rdi + rsi]", "ret"); + #[cfg(any(target_os = "windows", target_os = "linux"))] + { + naked_asm!("lea rax, [rdi + rsi]", "ret") + } + + #[cfg(target_os = "macos")] + { + naked_asm!("add x0, x0, x1", "ret") + } + + #[cfg(all(target_arch = "arm", target_feature = "thumb-mode"))] + { + naked_asm!("adds r0, r0, r1", "bx lr") + } +} + +// linux: .pushsection .text.some_different_name,\22ax\22, @progbits +// macos: .pushsection .text.some_different_name,regular,pure_instructions +// win: .pushsection .text.some_different_name,\22xr\22 +// thumb: .pushsection .text.some_different_name,\22ax\22, %progbits +// CHECK-LABEL: test_link_section: +#[no_mangle] +#[naked] +#[link_section = ".text.some_different_name"] +pub unsafe extern "C" fn test_link_section() { + #[cfg(not(all(target_arch = "arm", target_feature = "thumb-mode")))] + naked_asm!("ret"); + + #[cfg(all(target_arch = "arm", target_feature = "thumb-mode"))] + naked_asm!("bx lr"); } diff --git a/tests/codegen/naked-fn/naked-nocoverage.rs b/tests/codegen/naked-fn/naked-nocoverage.rs deleted file mode 100644 index f63661bcd3a..00000000000 --- a/tests/codegen/naked-fn/naked-nocoverage.rs +++ /dev/null @@ -1,19 +0,0 @@ -// Checks that naked functions are not instrumented by -Cinstrument-coverage. -// Regression test for issue #105170. -// -//@ needs-asm-support -//@ compile-flags: -Zno-profiler-runtime -//@ compile-flags: -Cinstrument-coverage -#![crate_type = "lib"] -#![feature(naked_functions)] -use std::arch::naked_asm; - -#[naked] -#[no_mangle] -pub unsafe extern "C" fn f() { - // CHECK: define {{(dso_local )?}}void @f() - // CHECK-NEXT: start: - // CHECK-NEXT: call void asm - // CHECK-NEXT: unreachable - naked_asm!(""); -} diff --git a/tests/codegen/naked-fn/naked-noinline.rs b/tests/codegen/naked-fn/naked-noinline.rs deleted file mode 100644 index 6ea36d96783..00000000000 --- a/tests/codegen/naked-fn/naked-noinline.rs +++ /dev/null @@ -1,31 +0,0 @@ -// Checks that naked functions are never inlined. -//@ compile-flags: -O -Zmir-opt-level=3 -//@ needs-asm-support -//@ ignore-wasm32 -#![crate_type = "lib"] -#![feature(naked_functions)] - -use std::arch::naked_asm; - -#[naked] -#[no_mangle] -pub unsafe extern "C" fn f() { - // Check that f has naked and noinline attributes. - // - // CHECK: define {{(dso_local )?}}void @f() unnamed_addr [[ATTR:#[0-9]+]] - // CHECK-NEXT: start: - // CHECK-NEXT: call void asm - naked_asm!(""); -} - -#[no_mangle] -pub unsafe fn g() { - // Check that call to f is not inlined. - // - // CHECK-LABEL: define {{(dso_local )?}}void @g() - // CHECK-NEXT: start: - // CHECK-NEXT: call void @f() - f(); -} - -// CHECK: attributes [[ATTR]] = { naked{{.*}}noinline{{.*}} } diff --git a/tests/coverage/branch/guard.cov-map b/tests/coverage/branch/guard.cov-map index 1ba1c6e1228..7ca499bd847 100644 --- a/tests/coverage/branch/guard.cov-map +++ b/tests/coverage/branch/guard.cov-map @@ -1,35 +1,37 @@ Function name: guard::branch_match_guard -Raw bytes (85): 0x[01, 01, 06, 19, 0d, 05, 09, 0f, 15, 13, 11, 17, 0d, 05, 09, 0d, 01, 0c, 01, 01, 10, 02, 03, 0b, 00, 0c, 15, 01, 14, 02, 0a, 0d, 03, 0e, 00, 0f, 19, 00, 14, 00, 19, 20, 0d, 02, 00, 14, 00, 1e, 0d, 00, 1d, 02, 0a, 11, 03, 0e, 00, 0f, 02, 00, 14, 00, 19, 20, 11, 05, 00, 14, 00, 1e, 11, 00, 1d, 02, 0a, 17, 03, 0e, 02, 0a, 0b, 04, 01, 00, 02] +Raw bytes (89): 0x[01, 01, 08, 05, 0d, 05, 17, 0d, 11, 1f, 17, 05, 09, 0d, 11, 1f, 15, 05, 09, 0d, 01, 0c, 01, 01, 10, 02, 03, 0b, 00, 0c, 15, 01, 14, 02, 0a, 0d, 03, 0e, 00, 0f, 05, 00, 14, 00, 19, 20, 0d, 02, 00, 14, 00, 1e, 0d, 00, 1d, 02, 0a, 11, 03, 0e, 00, 0f, 02, 00, 14, 00, 19, 20, 11, 06, 00, 14, 00, 1e, 11, 00, 1d, 02, 0a, 0e, 03, 0e, 02, 0a, 1b, 04, 01, 00, 02] Number of files: 1 - file 0 => global file 1 -Number of expressions: 6 -- expression 0 operands: lhs = Counter(6), rhs = Counter(3) -- expression 1 operands: lhs = Counter(1), rhs = Counter(2) -- expression 2 operands: lhs = Expression(3, Add), rhs = Counter(5) -- expression 3 operands: lhs = Expression(4, Add), rhs = Counter(4) -- expression 4 operands: lhs = Expression(5, Add), rhs = Counter(3) -- expression 5 operands: lhs = Counter(1), rhs = Counter(2) +Number of expressions: 8 +- expression 0 operands: lhs = Counter(1), rhs = Counter(3) +- expression 1 operands: lhs = Counter(1), rhs = Expression(5, Add) +- expression 2 operands: lhs = Counter(3), rhs = Counter(4) +- expression 3 operands: lhs = Expression(7, Add), rhs = Expression(5, Add) +- expression 4 operands: lhs = Counter(1), rhs = Counter(2) +- expression 5 operands: lhs = Counter(3), rhs = Counter(4) +- expression 6 operands: lhs = Expression(7, Add), rhs = Counter(5) +- expression 7 operands: lhs = Counter(1), rhs = Counter(2) Number of file 0 mappings: 13 - Code(Counter(0)) at (prev + 12, 1) to (start + 1, 16) - Code(Expression(0, Sub)) at (prev + 3, 11) to (start + 0, 12) - = (c6 - c3) + = (c1 - c3) - Code(Counter(5)) at (prev + 1, 20) to (start + 2, 10) - Code(Counter(3)) at (prev + 3, 14) to (start + 0, 15) -- Code(Counter(6)) at (prev + 0, 20) to (start + 0, 25) +- Code(Counter(1)) at (prev + 0, 20) to (start + 0, 25) - Branch { true: Counter(3), false: Expression(0, Sub) } at (prev + 0, 20) to (start + 0, 30) true = c3 - false = (c6 - c3) + false = (c1 - c3) - Code(Counter(3)) at (prev + 0, 29) to (start + 2, 10) - Code(Counter(4)) at (prev + 3, 14) to (start + 0, 15) - Code(Expression(0, Sub)) at (prev + 0, 20) to (start + 0, 25) - = (c6 - c3) -- Branch { true: Counter(4), false: Counter(1) } at (prev + 0, 20) to (start + 0, 30) + = (c1 - c3) +- Branch { true: Counter(4), false: Expression(1, Sub) } at (prev + 0, 20) to (start + 0, 30) true = c4 - false = c1 + false = (c1 - (c3 + c4)) - Code(Counter(4)) at (prev + 0, 29) to (start + 2, 10) -- Code(Expression(5, Add)) at (prev + 3, 14) to (start + 2, 10) - = (c1 + c2) -- Code(Expression(2, Add)) at (prev + 4, 1) to (start + 0, 2) - = ((((c1 + c2) + c3) + c4) + c5) -Highest counter ID seen: c6 +- Code(Expression(3, Sub)) at (prev + 3, 14) to (start + 2, 10) + = ((c1 + c2) - (c3 + c4)) +- Code(Expression(6, Add)) at (prev + 4, 1) to (start + 0, 2) + = ((c1 + c2) + c5) +Highest counter ID seen: c5 diff --git a/tests/coverage/branch/if-let.cov-map b/tests/coverage/branch/if-let.cov-map index 380765c7af4..773c5392465 100644 --- a/tests/coverage/branch/if-let.cov-map +++ b/tests/coverage/branch/if-let.cov-map @@ -19,14 +19,18 @@ Number of file 0 mappings: 7 Highest counter ID seen: c2 Function name: if_let::if_let_chain -Raw bytes (66): 0x[01, 01, 04, 01, 05, 05, 09, 0f, 0d, 05, 09, 0a, 01, 17, 01, 00, 33, 20, 02, 05, 01, 0c, 00, 13, 02, 00, 11, 00, 12, 01, 00, 16, 00, 17, 20, 0d, 09, 01, 10, 00, 17, 0d, 00, 15, 00, 16, 02, 00, 1a, 00, 1b, 0d, 01, 05, 03, 06, 0f, 03, 0c, 02, 06, 0b, 03, 05, 01, 02] +Raw bytes (74): 0x[01, 01, 08, 01, 05, 01, 1f, 05, 09, 01, 1f, 05, 09, 01, 1f, 05, 09, 05, 09, 0a, 01, 17, 01, 00, 33, 20, 02, 05, 01, 0c, 00, 13, 02, 00, 11, 00, 12, 01, 00, 16, 00, 17, 20, 16, 09, 01, 10, 00, 17, 16, 00, 15, 00, 16, 02, 00, 1a, 00, 1b, 16, 01, 05, 03, 06, 1f, 03, 0c, 02, 06, 01, 03, 05, 01, 02] Number of files: 1 - file 0 => global file 1 -Number of expressions: 4 +Number of expressions: 8 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -- expression 1 operands: lhs = Counter(1), rhs = Counter(2) -- expression 2 operands: lhs = Expression(3, Add), rhs = Counter(3) -- expression 3 operands: lhs = Counter(1), rhs = Counter(2) +- expression 1 operands: lhs = Counter(0), rhs = Expression(7, Add) +- expression 2 operands: lhs = Counter(1), rhs = Counter(2) +- expression 3 operands: lhs = Counter(0), rhs = Expression(7, Add) +- expression 4 operands: lhs = Counter(1), rhs = Counter(2) +- expression 5 operands: lhs = Counter(0), rhs = Expression(7, Add) +- expression 6 operands: lhs = Counter(1), rhs = Counter(2) +- expression 7 operands: lhs = Counter(1), rhs = Counter(2) Number of file 0 mappings: 10 - Code(Counter(0)) at (prev + 23, 1) to (start + 0, 51) - Branch { true: Expression(0, Sub), false: Counter(1) } at (prev + 1, 12) to (start + 0, 19) @@ -35,16 +39,17 @@ Number of file 0 mappings: 10 - Code(Expression(0, Sub)) at (prev + 0, 17) to (start + 0, 18) = (c0 - c1) - Code(Counter(0)) at (prev + 0, 22) to (start + 0, 23) -- Branch { true: Counter(3), false: Counter(2) } at (prev + 1, 16) to (start + 0, 23) - true = c3 +- Branch { true: Expression(5, Sub), false: Counter(2) } at (prev + 1, 16) to (start + 0, 23) + true = (c0 - (c1 + c2)) false = c2 -- Code(Counter(3)) at (prev + 0, 21) to (start + 0, 22) +- Code(Expression(5, Sub)) at (prev + 0, 21) to (start + 0, 22) + = (c0 - (c1 + c2)) - Code(Expression(0, Sub)) at (prev + 0, 26) to (start + 0, 27) = (c0 - c1) -- Code(Counter(3)) at (prev + 1, 5) to (start + 3, 6) -- Code(Expression(3, Add)) at (prev + 3, 12) to (start + 2, 6) +- Code(Expression(5, Sub)) at (prev + 1, 5) to (start + 3, 6) + = (c0 - (c1 + c2)) +- Code(Expression(7, Add)) at (prev + 3, 12) to (start + 2, 6) = (c1 + c2) -- Code(Expression(2, Add)) at (prev + 3, 5) to (start + 1, 2) - = ((c1 + c2) + c3) -Highest counter ID seen: c3 +- Code(Counter(0)) at (prev + 3, 5) to (start + 1, 2) +Highest counter ID seen: c2 diff --git a/tests/coverage/branch/if.cov-map b/tests/coverage/branch/if.cov-map index bab982dd44c..3d9a1d2e1ab 100644 --- a/tests/coverage/branch/if.cov-map +++ b/tests/coverage/branch/if.cov-map @@ -1,14 +1,11 @@ Function name: if::branch_and -Raw bytes (60): 0x[01, 01, 06, 05, 09, 0b, 09, 05, 11, 13, 09, 17, 11, 05, 0d, 08, 01, 2b, 01, 01, 10, 05, 03, 08, 00, 09, 20, 09, 02, 00, 08, 00, 09, 09, 00, 0d, 00, 0e, 20, 0d, 11, 00, 0d, 00, 0e, 0d, 00, 0f, 02, 06, 06, 02, 0c, 02, 06, 0e, 03, 01, 00, 02] +Raw bytes (54): 0x[01, 01, 03, 05, 09, 09, 0d, 05, 0d, 08, 01, 2b, 01, 01, 10, 05, 03, 08, 00, 09, 20, 09, 02, 00, 08, 00, 09, 09, 00, 0d, 00, 0e, 20, 0d, 06, 00, 0d, 00, 0e, 0d, 00, 0f, 02, 06, 0a, 02, 0c, 02, 06, 05, 03, 01, 00, 02] Number of files: 1 - file 0 => global file 1 -Number of expressions: 6 +Number of expressions: 3 - expression 0 operands: lhs = Counter(1), rhs = Counter(2) -- expression 1 operands: lhs = Expression(2, Add), rhs = Counter(2) -- expression 2 operands: lhs = Counter(1), rhs = Counter(4) -- expression 3 operands: lhs = Expression(4, Add), rhs = Counter(2) -- expression 4 operands: lhs = Expression(5, Add), rhs = Counter(4) -- expression 5 operands: lhs = Counter(1), rhs = Counter(3) +- expression 1 operands: lhs = Counter(2), rhs = Counter(3) +- expression 2 operands: lhs = Counter(1), rhs = Counter(3) Number of file 0 mappings: 8 - Code(Counter(0)) at (prev + 43, 1) to (start + 1, 16) - Code(Counter(1)) at (prev + 3, 8) to (start + 0, 9) @@ -16,15 +13,14 @@ Number of file 0 mappings: 8 true = c2 false = (c1 - c2) - Code(Counter(2)) at (prev + 0, 13) to (start + 0, 14) -- Branch { true: Counter(3), false: Counter(4) } at (prev + 0, 13) to (start + 0, 14) +- Branch { true: Counter(3), false: Expression(1, Sub) } at (prev + 0, 13) to (start + 0, 14) true = c3 - false = c4 + false = (c2 - c3) - Code(Counter(3)) at (prev + 0, 15) to (start + 2, 6) -- Code(Expression(1, Sub)) at (prev + 2, 12) to (start + 2, 6) - = ((c1 + c4) - c2) -- Code(Expression(3, Sub)) at (prev + 3, 1) to (start + 0, 2) - = (((c1 + c3) + c4) - c2) -Highest counter ID seen: c4 +- Code(Expression(2, Sub)) at (prev + 2, 12) to (start + 2, 6) + = (c1 - c3) +- Code(Counter(1)) at (prev + 3, 1) to (start + 0, 2) +Highest counter ID seen: c3 Function name: if::branch_not Raw bytes (116): 0x[01, 01, 07, 05, 09, 05, 0d, 05, 0d, 05, 11, 05, 11, 05, 15, 05, 15, 12, 01, 0c, 01, 01, 10, 05, 03, 08, 00, 09, 20, 09, 02, 00, 08, 00, 09, 09, 01, 09, 00, 11, 02, 01, 05, 00, 06, 05, 01, 08, 00, 0a, 20, 0a, 0d, 00, 08, 00, 0a, 0a, 00, 0b, 02, 06, 0d, 02, 05, 00, 06, 05, 01, 08, 00, 0b, 20, 11, 12, 00, 08, 00, 0b, 11, 00, 0c, 02, 06, 12, 02, 05, 00, 06, 05, 01, 08, 00, 0c, 20, 1a, 15, 00, 08, 00, 0c, 1a, 00, 0d, 02, 06, 15, 02, 05, 00, 06, 05, 01, 01, 00, 02] @@ -108,14 +104,16 @@ Number of file 0 mappings: 14 Highest counter ID seen: c4 Function name: if::branch_or -Raw bytes (56): 0x[01, 01, 04, 05, 09, 09, 0d, 0f, 11, 09, 0d, 08, 01, 35, 01, 01, 10, 05, 03, 08, 00, 09, 20, 09, 02, 00, 08, 00, 09, 02, 00, 0d, 00, 0e, 20, 0d, 11, 00, 0d, 00, 0e, 0f, 00, 0f, 02, 06, 11, 02, 0c, 02, 06, 0b, 03, 01, 00, 02] +Raw bytes (60): 0x[01, 01, 06, 05, 09, 05, 17, 09, 0d, 09, 0d, 05, 17, 09, 0d, 08, 01, 35, 01, 01, 10, 05, 03, 08, 00, 09, 20, 09, 02, 00, 08, 00, 09, 02, 00, 0d, 00, 0e, 20, 0d, 12, 00, 0d, 00, 0e, 17, 00, 0f, 02, 06, 12, 02, 0c, 02, 06, 05, 03, 01, 00, 02] Number of files: 1 - file 0 => global file 1 -Number of expressions: 4 +Number of expressions: 6 - expression 0 operands: lhs = Counter(1), rhs = Counter(2) -- expression 1 operands: lhs = Counter(2), rhs = Counter(3) -- expression 2 operands: lhs = Expression(3, Add), rhs = Counter(4) +- expression 1 operands: lhs = Counter(1), rhs = Expression(5, Add) +- expression 2 operands: lhs = Counter(2), rhs = Counter(3) - expression 3 operands: lhs = Counter(2), rhs = Counter(3) +- expression 4 operands: lhs = Counter(1), rhs = Expression(5, Add) +- expression 5 operands: lhs = Counter(2), rhs = Counter(3) Number of file 0 mappings: 8 - Code(Counter(0)) at (prev + 53, 1) to (start + 1, 16) - Code(Counter(1)) at (prev + 3, 8) to (start + 0, 9) @@ -124,13 +122,13 @@ Number of file 0 mappings: 8 false = (c1 - c2) - Code(Expression(0, Sub)) at (prev + 0, 13) to (start + 0, 14) = (c1 - c2) -- Branch { true: Counter(3), false: Counter(4) } at (prev + 0, 13) to (start + 0, 14) +- Branch { true: Counter(3), false: Expression(4, Sub) } at (prev + 0, 13) to (start + 0, 14) true = c3 - false = c4 -- Code(Expression(3, Add)) at (prev + 0, 15) to (start + 2, 6) + false = (c1 - (c2 + c3)) +- Code(Expression(5, Add)) at (prev + 0, 15) to (start + 2, 6) = (c2 + c3) -- Code(Counter(4)) at (prev + 2, 12) to (start + 2, 6) -- Code(Expression(2, Add)) at (prev + 3, 1) to (start + 0, 2) - = ((c2 + c3) + c4) -Highest counter ID seen: c4 +- Code(Expression(4, Sub)) at (prev + 2, 12) to (start + 2, 6) + = (c1 - (c2 + c3)) +- Code(Counter(1)) at (prev + 3, 1) to (start + 0, 2) +Highest counter ID seen: c3 diff --git a/tests/coverage/branch/lazy-boolean.cov-map b/tests/coverage/branch/lazy-boolean.cov-map index decb847f60e..94522734bcd 100644 --- a/tests/coverage/branch/lazy-boolean.cov-map +++ b/tests/coverage/branch/lazy-boolean.cov-map @@ -34,85 +34,67 @@ Number of file 0 mappings: 6 Highest counter ID seen: c2 Function name: lazy_boolean::chain -Raw bytes (169): 0x[01, 01, 1d, 5b, 0d, 5f, 15, 05, 11, 05, 09, 09, 0d, 6f, 25, 73, 21, 19, 1d, 5b, 67, 5f, 15, 05, 11, 0d, 19, 5b, 67, 5f, 15, 05, 11, 0d, 19, 5b, 63, 5f, 15, 05, 11, 67, 1d, 0d, 19, 5b, 63, 5f, 15, 05, 11, 67, 1d, 0d, 19, 6f, 25, 73, 21, 19, 1d, 13, 01, 24, 01, 01, 10, 02, 04, 09, 00, 0a, 05, 00, 0d, 00, 12, 20, 09, 0e, 00, 0d, 00, 12, 09, 00, 16, 00, 1b, 20, 0d, 12, 00, 16, 00, 1b, 0d, 00, 1f, 00, 24, 20, 11, 15, 00, 1f, 00, 24, 11, 00, 28, 00, 2d, 02, 01, 05, 00, 11, 6b, 03, 09, 00, 0a, 02, 00, 0d, 00, 12, 20, 19, 32, 00, 0d, 00, 12, 32, 00, 16, 00, 1b, 20, 1d, 56, 00, 16, 00, 1b, 56, 00, 1f, 00, 24, 20, 21, 25, 00, 1f, 00, 24, 25, 00, 28, 00, 2d, 6b, 01, 05, 01, 02] +Raw bytes (141): 0x[01, 01, 0f, 05, 09, 09, 0d, 0d, 11, 05, 15, 05, 15, 05, 3b, 15, 19, 05, 3b, 15, 19, 05, 37, 3b, 1d, 15, 19, 05, 37, 3b, 1d, 15, 19, 13, 01, 24, 01, 01, 10, 05, 04, 09, 00, 0a, 05, 00, 0d, 00, 12, 20, 09, 02, 00, 0d, 00, 12, 09, 00, 16, 00, 1b, 20, 0d, 06, 00, 16, 00, 1b, 0d, 00, 1f, 00, 24, 20, 11, 0a, 00, 1f, 00, 24, 11, 00, 28, 00, 2d, 05, 01, 05, 00, 11, 05, 03, 09, 00, 0a, 05, 00, 0d, 00, 12, 20, 15, 12, 00, 0d, 00, 12, 12, 00, 16, 00, 1b, 20, 19, 1e, 00, 16, 00, 1b, 1e, 00, 1f, 00, 24, 20, 1d, 32, 00, 1f, 00, 24, 32, 00, 28, 00, 2d, 05, 01, 05, 01, 02] Number of files: 1 - file 0 => global file 1 -Number of expressions: 29 -- expression 0 operands: lhs = Expression(22, Add), rhs = Counter(3) -- expression 1 operands: lhs = Expression(23, Add), rhs = Counter(5) -- expression 2 operands: lhs = Counter(1), rhs = Counter(4) -- expression 3 operands: lhs = Counter(1), rhs = Counter(2) -- expression 4 operands: lhs = Counter(2), rhs = Counter(3) -- expression 5 operands: lhs = Expression(27, Add), rhs = Counter(9) -- expression 6 operands: lhs = Expression(28, Add), rhs = Counter(8) -- expression 7 operands: lhs = Counter(6), rhs = Counter(7) -- expression 8 operands: lhs = Expression(22, Add), rhs = Expression(25, Add) -- expression 9 operands: lhs = Expression(23, Add), rhs = Counter(5) -- expression 10 operands: lhs = Counter(1), rhs = Counter(4) -- expression 11 operands: lhs = Counter(3), rhs = Counter(6) -- expression 12 operands: lhs = Expression(22, Add), rhs = Expression(25, Add) -- expression 13 operands: lhs = Expression(23, Add), rhs = Counter(5) -- expression 14 operands: lhs = Counter(1), rhs = Counter(4) -- expression 15 operands: lhs = Counter(3), rhs = Counter(6) -- expression 16 operands: lhs = Expression(22, Add), rhs = Expression(24, Add) -- expression 17 operands: lhs = Expression(23, Add), rhs = Counter(5) -- expression 18 operands: lhs = Counter(1), rhs = Counter(4) -- expression 19 operands: lhs = Expression(25, Add), rhs = Counter(7) -- expression 20 operands: lhs = Counter(3), rhs = Counter(6) -- expression 21 operands: lhs = Expression(22, Add), rhs = Expression(24, Add) -- expression 22 operands: lhs = Expression(23, Add), rhs = Counter(5) -- expression 23 operands: lhs = Counter(1), rhs = Counter(4) -- expression 24 operands: lhs = Expression(25, Add), rhs = Counter(7) -- expression 25 operands: lhs = Counter(3), rhs = Counter(6) -- expression 26 operands: lhs = Expression(27, Add), rhs = Counter(9) -- expression 27 operands: lhs = Expression(28, Add), rhs = Counter(8) -- expression 28 operands: lhs = Counter(6), rhs = Counter(7) +Number of expressions: 15 +- expression 0 operands: lhs = Counter(1), rhs = Counter(2) +- expression 1 operands: lhs = Counter(2), rhs = Counter(3) +- expression 2 operands: lhs = Counter(3), rhs = Counter(4) +- expression 3 operands: lhs = Counter(1), rhs = Counter(5) +- expression 4 operands: lhs = Counter(1), rhs = Counter(5) +- expression 5 operands: lhs = Counter(1), rhs = Expression(14, Add) +- expression 6 operands: lhs = Counter(5), rhs = Counter(6) +- expression 7 operands: lhs = Counter(1), rhs = Expression(14, Add) +- expression 8 operands: lhs = Counter(5), rhs = Counter(6) +- expression 9 operands: lhs = Counter(1), rhs = Expression(13, Add) +- expression 10 operands: lhs = Expression(14, Add), rhs = Counter(7) +- expression 11 operands: lhs = Counter(5), rhs = Counter(6) +- expression 12 operands: lhs = Counter(1), rhs = Expression(13, Add) +- expression 13 operands: lhs = Expression(14, Add), rhs = Counter(7) +- expression 14 operands: lhs = Counter(5), rhs = Counter(6) Number of file 0 mappings: 19 - Code(Counter(0)) at (prev + 36, 1) to (start + 1, 16) -- Code(Expression(0, Sub)) at (prev + 4, 9) to (start + 0, 10) - = (((c1 + c4) + c5) - c3) +- Code(Counter(1)) at (prev + 4, 9) to (start + 0, 10) - Code(Counter(1)) at (prev + 0, 13) to (start + 0, 18) -- Branch { true: Counter(2), false: Expression(3, Sub) } at (prev + 0, 13) to (start + 0, 18) +- Branch { true: Counter(2), false: Expression(0, Sub) } at (prev + 0, 13) to (start + 0, 18) true = c2 false = (c1 - c2) - Code(Counter(2)) at (prev + 0, 22) to (start + 0, 27) -- Branch { true: Counter(3), false: Expression(4, Sub) } at (prev + 0, 22) to (start + 0, 27) +- Branch { true: Counter(3), false: Expression(1, Sub) } at (prev + 0, 22) to (start + 0, 27) true = c3 false = (c2 - c3) - Code(Counter(3)) at (prev + 0, 31) to (start + 0, 36) -- Branch { true: Counter(4), false: Counter(5) } at (prev + 0, 31) to (start + 0, 36) +- Branch { true: Counter(4), false: Expression(2, Sub) } at (prev + 0, 31) to (start + 0, 36) true = c4 - false = c5 + false = (c3 - c4) - Code(Counter(4)) at (prev + 0, 40) to (start + 0, 45) -- Code(Expression(0, Sub)) at (prev + 1, 5) to (start + 0, 17) - = (((c1 + c4) + c5) - c3) -- Code(Expression(26, Add)) at (prev + 3, 9) to (start + 0, 10) - = (((c6 + c7) + c8) + c9) -- Code(Expression(0, Sub)) at (prev + 0, 13) to (start + 0, 18) - = (((c1 + c4) + c5) - c3) -- Branch { true: Counter(6), false: Expression(12, Sub) } at (prev + 0, 13) to (start + 0, 18) +- Code(Counter(1)) at (prev + 1, 5) to (start + 0, 17) +- Code(Counter(1)) at (prev + 3, 9) to (start + 0, 10) +- Code(Counter(1)) at (prev + 0, 13) to (start + 0, 18) +- Branch { true: Counter(5), false: Expression(4, Sub) } at (prev + 0, 13) to (start + 0, 18) + true = c5 + false = (c1 - c5) +- Code(Expression(4, Sub)) at (prev + 0, 22) to (start + 0, 27) + = (c1 - c5) +- Branch { true: Counter(6), false: Expression(7, Sub) } at (prev + 0, 22) to (start + 0, 27) true = c6 - false = (((c1 + c4) + c5) - (c3 + c6)) -- Code(Expression(12, Sub)) at (prev + 0, 22) to (start + 0, 27) - = (((c1 + c4) + c5) - (c3 + c6)) -- Branch { true: Counter(7), false: Expression(21, Sub) } at (prev + 0, 22) to (start + 0, 27) + false = (c1 - (c5 + c6)) +- Code(Expression(7, Sub)) at (prev + 0, 31) to (start + 0, 36) + = (c1 - (c5 + c6)) +- Branch { true: Counter(7), false: Expression(12, Sub) } at (prev + 0, 31) to (start + 0, 36) true = c7 - false = (((c1 + c4) + c5) - ((c3 + c6) + c7)) -- Code(Expression(21, Sub)) at (prev + 0, 31) to (start + 0, 36) - = (((c1 + c4) + c5) - ((c3 + c6) + c7)) -- Branch { true: Counter(8), false: Counter(9) } at (prev + 0, 31) to (start + 0, 36) - true = c8 - false = c9 -- Code(Counter(9)) at (prev + 0, 40) to (start + 0, 45) -- Code(Expression(26, Add)) at (prev + 1, 5) to (start + 1, 2) - = (((c6 + c7) + c8) + c9) -Highest counter ID seen: c9 + false = (c1 - ((c5 + c6) + c7)) +- Code(Expression(12, Sub)) at (prev + 0, 40) to (start + 0, 45) + = (c1 - ((c5 + c6) + c7)) +- Code(Counter(1)) at (prev + 1, 5) to (start + 1, 2) +Highest counter ID seen: c7 Function name: lazy_boolean::nested_mixed -Raw bytes (141): 0x[01, 01, 0f, 05, 09, 05, 1f, 09, 0d, 09, 0d, 1f, 11, 09, 0d, 1f, 11, 09, 0d, 3b, 21, 19, 1d, 05, 15, 15, 19, 05, 19, 3b, 21, 19, 1d, 13, 01, 31, 01, 01, 10, 05, 04, 09, 00, 0a, 05, 00, 0e, 00, 13, 20, 09, 02, 00, 0e, 00, 13, 02, 00, 17, 00, 1d, 20, 0d, 06, 00, 17, 00, 1d, 1f, 00, 23, 00, 28, 20, 11, 1a, 00, 23, 00, 28, 1a, 00, 2c, 00, 33, 05, 01, 05, 00, 11, 37, 03, 09, 00, 0a, 05, 00, 0e, 00, 13, 20, 15, 2a, 00, 0e, 00, 13, 15, 00, 17, 00, 1c, 20, 19, 2e, 00, 17, 00, 1c, 32, 00, 22, 00, 28, 20, 1d, 21, 00, 22, 00, 28, 1d, 00, 2c, 00, 33, 37, 01, 05, 01, 02] +Raw bytes (137): 0x[01, 01, 0d, 05, 09, 05, 1f, 09, 0d, 09, 0d, 1f, 11, 09, 0d, 1f, 11, 09, 0d, 05, 15, 15, 19, 05, 19, 05, 33, 19, 1d, 13, 01, 31, 01, 01, 10, 05, 04, 09, 00, 0a, 05, 00, 0e, 00, 13, 20, 09, 02, 00, 0e, 00, 13, 02, 00, 17, 00, 1d, 20, 0d, 06, 00, 17, 00, 1d, 1f, 00, 23, 00, 28, 20, 11, 1a, 00, 23, 00, 28, 1a, 00, 2c, 00, 33, 05, 01, 05, 00, 11, 05, 03, 09, 00, 0a, 05, 00, 0e, 00, 13, 20, 15, 22, 00, 0e, 00, 13, 15, 00, 17, 00, 1c, 20, 19, 26, 00, 17, 00, 1c, 2a, 00, 22, 00, 28, 20, 1d, 2e, 00, 22, 00, 28, 1d, 00, 2c, 00, 33, 05, 01, 05, 01, 02] Number of files: 1 - file 0 => global file 1 -Number of expressions: 15 +Number of expressions: 13 - expression 0 operands: lhs = Counter(1), rhs = Counter(2) - expression 1 operands: lhs = Counter(1), rhs = Expression(7, Add) - expression 2 operands: lhs = Counter(2), rhs = Counter(3) @@ -121,13 +103,11 @@ Number of expressions: 15 - expression 5 operands: lhs = Counter(2), rhs = Counter(3) - expression 6 operands: lhs = Expression(7, Add), rhs = Counter(4) - expression 7 operands: lhs = Counter(2), rhs = Counter(3) -- expression 8 operands: lhs = Expression(14, Add), rhs = Counter(8) -- expression 9 operands: lhs = Counter(6), rhs = Counter(7) -- expression 10 operands: lhs = Counter(1), rhs = Counter(5) -- expression 11 operands: lhs = Counter(5), rhs = Counter(6) -- expression 12 operands: lhs = Counter(1), rhs = Counter(6) -- expression 13 operands: lhs = Expression(14, Add), rhs = Counter(8) -- expression 14 operands: lhs = Counter(6), rhs = Counter(7) +- expression 8 operands: lhs = Counter(1), rhs = Counter(5) +- expression 9 operands: lhs = Counter(5), rhs = Counter(6) +- expression 10 operands: lhs = Counter(1), rhs = Counter(6) +- expression 11 operands: lhs = Counter(1), rhs = Expression(12, Add) +- expression 12 operands: lhs = Counter(6), rhs = Counter(7) Number of file 0 mappings: 19 - Code(Counter(0)) at (prev + 49, 1) to (start + 1, 16) - Code(Counter(1)) at (prev + 4, 9) to (start + 0, 10) @@ -148,23 +128,21 @@ Number of file 0 mappings: 19 - Code(Expression(6, Sub)) at (prev + 0, 44) to (start + 0, 51) = ((c2 + c3) - c4) - Code(Counter(1)) at (prev + 1, 5) to (start + 0, 17) -- Code(Expression(13, Add)) at (prev + 3, 9) to (start + 0, 10) - = ((c6 + c7) + c8) +- Code(Counter(1)) at (prev + 3, 9) to (start + 0, 10) - Code(Counter(1)) at (prev + 0, 14) to (start + 0, 19) -- Branch { true: Counter(5), false: Expression(10, Sub) } at (prev + 0, 14) to (start + 0, 19) +- Branch { true: Counter(5), false: Expression(8, Sub) } at (prev + 0, 14) to (start + 0, 19) true = c5 false = (c1 - c5) - Code(Counter(5)) at (prev + 0, 23) to (start + 0, 28) -- Branch { true: Counter(6), false: Expression(11, Sub) } at (prev + 0, 23) to (start + 0, 28) +- Branch { true: Counter(6), false: Expression(9, Sub) } at (prev + 0, 23) to (start + 0, 28) true = c6 false = (c5 - c6) -- Code(Expression(12, Sub)) at (prev + 0, 34) to (start + 0, 40) +- Code(Expression(10, Sub)) at (prev + 0, 34) to (start + 0, 40) = (c1 - c6) -- Branch { true: Counter(7), false: Counter(8) } at (prev + 0, 34) to (start + 0, 40) +- Branch { true: Counter(7), false: Expression(11, Sub) } at (prev + 0, 34) to (start + 0, 40) true = c7 - false = c8 + false = (c1 - (c6 + c7)) - Code(Counter(7)) at (prev + 0, 44) to (start + 0, 51) -- Code(Expression(13, Add)) at (prev + 1, 5) to (start + 1, 2) - = ((c6 + c7) + c8) -Highest counter ID seen: c8 +- Code(Counter(1)) at (prev + 1, 5) to (start + 1, 2) +Highest counter ID seen: c7 diff --git a/tests/coverage/branch/match-arms.cov-map b/tests/coverage/branch/match-arms.cov-map index a93df9814ee..53d0a4edbd0 100644 --- a/tests/coverage/branch/match-arms.cov-map +++ b/tests/coverage/branch/match-arms.cov-map @@ -1,40 +1,45 @@ Function name: match_arms::guards -Raw bytes (88): 0x[01, 01, 08, 07, 00, 0b, 11, 0f, 0d, 05, 09, 17, 25, 1b, 21, 1f, 1d, 03, 19, 0c, 01, 30, 01, 01, 10, 29, 03, 0b, 00, 10, 19, 01, 11, 00, 29, 20, 19, 05, 00, 17, 00, 1b, 1d, 01, 11, 00, 29, 20, 1d, 09, 00, 17, 00, 1b, 21, 01, 11, 00, 29, 20, 21, 0d, 00, 17, 00, 1b, 25, 01, 11, 00, 29, 20, 25, 11, 00, 17, 00, 1b, 03, 01, 0e, 00, 18, 13, 03, 05, 01, 02] +Raw bytes (98): 0x[01, 01, 0d, 11, 19, 27, 19, 2b, 00, 2f, 11, 33, 0d, 05, 09, 1f, 25, 23, 21, 27, 1d, 2b, 00, 2f, 11, 33, 0d, 05, 09, 0c, 01, 30, 01, 01, 10, 11, 03, 0b, 00, 10, 1d, 01, 11, 00, 29, 20, 1d, 05, 00, 17, 00, 1b, 21, 01, 11, 00, 29, 20, 21, 09, 00, 17, 00, 1b, 25, 01, 11, 00, 29, 20, 25, 0d, 00, 17, 00, 1b, 19, 01, 11, 00, 29, 20, 19, 02, 00, 17, 00, 1b, 06, 01, 0e, 00, 18, 1b, 03, 05, 01, 02] Number of files: 1 - file 0 => global file 1 -Number of expressions: 8 -- expression 0 operands: lhs = Expression(1, Add), rhs = Zero -- expression 1 operands: lhs = Expression(2, Add), rhs = Counter(4) -- expression 2 operands: lhs = Expression(3, Add), rhs = Counter(3) -- expression 3 operands: lhs = Counter(1), rhs = Counter(2) -- expression 4 operands: lhs = Expression(5, Add), rhs = Counter(9) -- expression 5 operands: lhs = Expression(6, Add), rhs = Counter(8) -- expression 6 operands: lhs = Expression(7, Add), rhs = Counter(7) -- expression 7 operands: lhs = Expression(0, Add), rhs = Counter(6) +Number of expressions: 13 +- expression 0 operands: lhs = Counter(4), rhs = Counter(6) +- expression 1 operands: lhs = Expression(9, Add), rhs = Counter(6) +- expression 2 operands: lhs = Expression(10, Add), rhs = Zero +- expression 3 operands: lhs = Expression(11, Add), rhs = Counter(4) +- expression 4 operands: lhs = Expression(12, Add), rhs = Counter(3) +- expression 5 operands: lhs = Counter(1), rhs = Counter(2) +- expression 6 operands: lhs = Expression(7, Add), rhs = Counter(9) +- expression 7 operands: lhs = Expression(8, Add), rhs = Counter(8) +- expression 8 operands: lhs = Expression(9, Add), rhs = Counter(7) +- expression 9 operands: lhs = Expression(10, Add), rhs = Zero +- expression 10 operands: lhs = Expression(11, Add), rhs = Counter(4) +- expression 11 operands: lhs = Expression(12, Add), rhs = Counter(3) +- expression 12 operands: lhs = Counter(1), rhs = Counter(2) Number of file 0 mappings: 12 - Code(Counter(0)) at (prev + 48, 1) to (start + 1, 16) -- Code(Counter(10)) at (prev + 3, 11) to (start + 0, 16) -- Code(Counter(6)) at (prev + 1, 17) to (start + 0, 41) -- Branch { true: Counter(6), false: Counter(1) } at (prev + 0, 23) to (start + 0, 27) - true = c6 - false = c1 +- Code(Counter(4)) at (prev + 3, 11) to (start + 0, 16) - Code(Counter(7)) at (prev + 1, 17) to (start + 0, 41) -- Branch { true: Counter(7), false: Counter(2) } at (prev + 0, 23) to (start + 0, 27) +- Branch { true: Counter(7), false: Counter(1) } at (prev + 0, 23) to (start + 0, 27) true = c7 - false = c2 + false = c1 - Code(Counter(8)) at (prev + 1, 17) to (start + 0, 41) -- Branch { true: Counter(8), false: Counter(3) } at (prev + 0, 23) to (start + 0, 27) +- Branch { true: Counter(8), false: Counter(2) } at (prev + 0, 23) to (start + 0, 27) true = c8 - false = c3 + false = c2 - Code(Counter(9)) at (prev + 1, 17) to (start + 0, 41) -- Branch { true: Counter(9), false: Counter(4) } at (prev + 0, 23) to (start + 0, 27) +- Branch { true: Counter(9), false: Counter(3) } at (prev + 0, 23) to (start + 0, 27) true = c9 - false = c4 -- Code(Expression(0, Add)) at (prev + 1, 14) to (start + 0, 24) - = ((((c1 + c2) + c3) + c4) + Zero) -- Code(Expression(4, Add)) at (prev + 3, 5) to (start + 1, 2) - = ((((((((c1 + c2) + c3) + c4) + Zero) + c6) + c7) + c8) + c9) -Highest counter ID seen: c10 + false = c3 +- Code(Counter(6)) at (prev + 1, 17) to (start + 0, 41) +- Branch { true: Counter(6), false: Expression(0, Sub) } at (prev + 0, 23) to (start + 0, 27) + true = c6 + false = (c4 - c6) +- Code(Expression(1, Sub)) at (prev + 1, 14) to (start + 0, 24) + = (((((c1 + c2) + c3) + c4) + Zero) - c6) +- Code(Expression(6, Add)) at (prev + 3, 5) to (start + 1, 2) + = (((((((c1 + c2) + c3) + c4) + Zero) + c7) + c8) + c9) +Highest counter ID seen: c9 Function name: match_arms::match_arms Raw bytes (45): 0x[01, 01, 03, 05, 07, 0b, 11, 09, 0d, 07, 01, 18, 01, 01, 10, 05, 03, 0b, 00, 10, 09, 01, 11, 00, 21, 0d, 01, 11, 00, 21, 11, 01, 11, 00, 21, 02, 01, 11, 00, 21, 05, 03, 05, 01, 02] diff --git a/tests/coverage/branch/while.cov-map b/tests/coverage/branch/while.cov-map index 305f6bc74d8..5eb08a42803 100644 --- a/tests/coverage/branch/while.cov-map +++ b/tests/coverage/branch/while.cov-map @@ -35,14 +35,14 @@ Number of file 0 mappings: 6 Highest counter ID seen: c2 Function name: while::while_op_and -Raw bytes (56): 0x[01, 01, 04, 05, 09, 03, 0d, 03, 0d, 0d, 11, 08, 01, 1e, 01, 01, 10, 05, 03, 09, 01, 12, 03, 02, 0b, 00, 10, 20, 0a, 0d, 00, 0b, 00, 10, 0a, 00, 14, 00, 19, 20, 09, 11, 00, 14, 00, 19, 09, 00, 1a, 03, 06, 0f, 04, 01, 00, 02] +Raw bytes (56): 0x[01, 01, 04, 05, 09, 03, 0d, 03, 0d, 05, 0d, 08, 01, 1e, 01, 01, 10, 05, 03, 09, 01, 12, 03, 02, 0b, 00, 10, 20, 0a, 0d, 00, 0b, 00, 10, 0a, 00, 14, 00, 19, 20, 09, 0e, 00, 14, 00, 19, 09, 00, 1a, 03, 06, 05, 04, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 4 - expression 0 operands: lhs = Counter(1), rhs = Counter(2) - expression 1 operands: lhs = Expression(0, Add), rhs = Counter(3) - expression 2 operands: lhs = Expression(0, Add), rhs = Counter(3) -- expression 3 operands: lhs = Counter(3), rhs = Counter(4) +- expression 3 operands: lhs = Counter(1), rhs = Counter(3) Number of file 0 mappings: 8 - Code(Counter(0)) at (prev + 30, 1) to (start + 1, 16) - Code(Counter(1)) at (prev + 3, 9) to (start + 1, 18) @@ -53,13 +53,12 @@ Number of file 0 mappings: 8 false = c3 - Code(Expression(2, Sub)) at (prev + 0, 20) to (start + 0, 25) = ((c1 + c2) - c3) -- Branch { true: Counter(2), false: Counter(4) } at (prev + 0, 20) to (start + 0, 25) +- Branch { true: Counter(2), false: Expression(3, Sub) } at (prev + 0, 20) to (start + 0, 25) true = c2 - false = c4 + false = (c1 - c3) - Code(Counter(2)) at (prev + 0, 26) to (start + 3, 6) -- Code(Expression(3, Add)) at (prev + 4, 1) to (start + 0, 2) - = (c3 + c4) -Highest counter ID seen: c4 +- Code(Counter(1)) at (prev + 4, 1) to (start + 0, 2) +Highest counter ID seen: c3 Function name: while::while_op_or Raw bytes (58): 0x[01, 01, 05, 07, 0d, 05, 09, 05, 0d, 05, 0d, 09, 0d, 08, 01, 29, 01, 01, 10, 05, 03, 09, 01, 12, 03, 02, 0b, 00, 10, 20, 09, 0f, 00, 0b, 00, 10, 0f, 00, 14, 00, 19, 20, 0d, 05, 00, 14, 00, 19, 13, 00, 1a, 03, 06, 05, 04, 01, 00, 02] diff --git a/tests/coverage/closure_macro.cov-map b/tests/coverage/closure_macro.cov-map index aedb924eca8..653848dd6ff 100644 --- a/tests/coverage/closure_macro.cov-map +++ b/tests/coverage/closure_macro.cov-map @@ -25,20 +25,20 @@ Number of file 0 mappings: 6 Highest counter ID seen: c1 Function name: closure_macro::main::{closure#0} -Raw bytes (35): 0x[01, 01, 03, 01, 05, 0b, 0d, 05, 09, 05, 01, 10, 1c, 03, 21, 05, 04, 11, 01, 27, 02, 03, 11, 00, 16, 0d, 00, 17, 00, 1e, 07, 02, 09, 00, 0a] +Raw bytes (35): 0x[01, 01, 03, 01, 05, 01, 0b, 05, 09, 05, 01, 10, 1c, 03, 21, 05, 04, 11, 01, 27, 02, 03, 11, 00, 16, 06, 00, 17, 00, 1e, 01, 02, 09, 00, 0a] Number of files: 1 - file 0 => global file 1 Number of expressions: 3 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -- expression 1 operands: lhs = Expression(2, Add), rhs = Counter(3) +- expression 1 operands: lhs = Counter(0), rhs = Expression(2, Add) - expression 2 operands: lhs = Counter(1), rhs = Counter(2) Number of file 0 mappings: 5 - Code(Counter(0)) at (prev + 16, 28) to (start + 3, 33) - Code(Counter(1)) at (prev + 4, 17) to (start + 1, 39) - Code(Expression(0, Sub)) at (prev + 3, 17) to (start + 0, 22) = (c0 - c1) -- Code(Counter(3)) at (prev + 0, 23) to (start + 0, 30) -- Code(Expression(1, Add)) at (prev + 2, 9) to (start + 0, 10) - = ((c1 + c2) + c3) -Highest counter ID seen: c3 +- Code(Expression(1, Sub)) at (prev + 0, 23) to (start + 0, 30) + = (c0 - (c1 + c2)) +- Code(Counter(0)) at (prev + 2, 9) to (start + 0, 10) +Highest counter ID seen: c1 diff --git a/tests/coverage/closure_macro_async.cov-map b/tests/coverage/closure_macro_async.cov-map index df4652ac9ce..1bd1460a147 100644 --- a/tests/coverage/closure_macro_async.cov-map +++ b/tests/coverage/closure_macro_async.cov-map @@ -34,20 +34,20 @@ Number of file 0 mappings: 6 Highest counter ID seen: c1 Function name: closure_macro_async::test::{closure#0}::{closure#0} -Raw bytes (35): 0x[01, 01, 03, 01, 05, 0b, 0d, 05, 09, 05, 01, 14, 1c, 03, 21, 05, 04, 11, 01, 27, 02, 03, 11, 00, 16, 0d, 00, 17, 00, 1e, 07, 02, 09, 00, 0a] +Raw bytes (35): 0x[01, 01, 03, 01, 05, 01, 0b, 05, 09, 05, 01, 14, 1c, 03, 21, 05, 04, 11, 01, 27, 02, 03, 11, 00, 16, 06, 00, 17, 00, 1e, 01, 02, 09, 00, 0a] Number of files: 1 - file 0 => global file 1 Number of expressions: 3 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -- expression 1 operands: lhs = Expression(2, Add), rhs = Counter(3) +- expression 1 operands: lhs = Counter(0), rhs = Expression(2, Add) - expression 2 operands: lhs = Counter(1), rhs = Counter(2) Number of file 0 mappings: 5 - Code(Counter(0)) at (prev + 20, 28) to (start + 3, 33) - Code(Counter(1)) at (prev + 4, 17) to (start + 1, 39) - Code(Expression(0, Sub)) at (prev + 3, 17) to (start + 0, 22) = (c0 - c1) -- Code(Counter(3)) at (prev + 0, 23) to (start + 0, 30) -- Code(Expression(1, Add)) at (prev + 2, 9) to (start + 0, 10) - = ((c1 + c2) + c3) -Highest counter ID seen: c3 +- Code(Expression(1, Sub)) at (prev + 0, 23) to (start + 0, 30) + = (c0 - (c1 + c2)) +- Code(Counter(0)) at (prev + 2, 9) to (start + 0, 10) +Highest counter ID seen: c1 diff --git a/tests/coverage/condition/conditions.cov-map b/tests/coverage/condition/conditions.cov-map index 72f39b88c6a..417637f2d2e 100644 --- a/tests/coverage/condition/conditions.cov-map +++ b/tests/coverage/condition/conditions.cov-map @@ -1,120 +1,103 @@ Function name: conditions::assign_3_and_or -Raw bytes (65): 0x[01, 01, 05, 07, 11, 09, 0d, 01, 05, 05, 09, 01, 09, 09, 01, 1c, 01, 00, 2f, 03, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 20, 05, 0a, 00, 0d, 00, 0e, 05, 00, 12, 00, 13, 20, 09, 0e, 00, 12, 00, 13, 12, 00, 17, 00, 18, 20, 0d, 11, 00, 17, 00, 18, 03, 01, 05, 01, 02] +Raw bytes (65): 0x[01, 01, 05, 01, 05, 05, 09, 01, 09, 01, 13, 09, 0d, 09, 01, 1c, 01, 00, 2f, 01, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 20, 05, 02, 00, 0d, 00, 0e, 05, 00, 12, 00, 13, 20, 09, 06, 00, 12, 00, 13, 0a, 00, 17, 00, 18, 20, 0d, 0e, 00, 17, 00, 18, 01, 01, 05, 01, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 5 -- expression 0 operands: lhs = Expression(1, Add), rhs = Counter(4) -- expression 1 operands: lhs = Counter(2), rhs = Counter(3) -- expression 2 operands: lhs = Counter(0), rhs = Counter(1) -- expression 3 operands: lhs = Counter(1), rhs = Counter(2) -- expression 4 operands: lhs = Counter(0), rhs = Counter(2) +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +- expression 1 operands: lhs = Counter(1), rhs = Counter(2) +- expression 2 operands: lhs = Counter(0), rhs = Counter(2) +- expression 3 operands: lhs = Counter(0), rhs = Expression(4, Add) +- expression 4 operands: lhs = Counter(2), rhs = Counter(3) Number of file 0 mappings: 9 - Code(Counter(0)) at (prev + 28, 1) to (start + 0, 47) -- Code(Expression(0, Add)) at (prev + 1, 9) to (start + 0, 10) - = ((c2 + c3) + c4) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 10) - Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14) -- Branch { true: Counter(1), false: Expression(2, Sub) } at (prev + 0, 13) to (start + 0, 14) +- Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 0, 13) to (start + 0, 14) true = c1 false = (c0 - c1) - Code(Counter(1)) at (prev + 0, 18) to (start + 0, 19) -- Branch { true: Counter(2), false: Expression(3, Sub) } at (prev + 0, 18) to (start + 0, 19) +- Branch { true: Counter(2), false: Expression(1, Sub) } at (prev + 0, 18) to (start + 0, 19) true = c2 false = (c1 - c2) -- Code(Expression(4, Sub)) at (prev + 0, 23) to (start + 0, 24) +- Code(Expression(2, Sub)) at (prev + 0, 23) to (start + 0, 24) = (c0 - c2) -- Branch { true: Counter(3), false: Counter(4) } at (prev + 0, 23) to (start + 0, 24) +- Branch { true: Counter(3), false: Expression(3, Sub) } at (prev + 0, 23) to (start + 0, 24) true = c3 - false = c4 -- Code(Expression(0, Add)) at (prev + 1, 5) to (start + 1, 2) - = ((c2 + c3) + c4) -Highest counter ID seen: c4 + false = (c0 - (c2 + c3)) +- Code(Counter(0)) at (prev + 1, 5) to (start + 1, 2) +Highest counter ID seen: c3 Function name: conditions::assign_3_or_and -Raw bytes (73): 0x[01, 01, 09, 07, 11, 0b, 0d, 05, 09, 01, 05, 01, 05, 01, 23, 05, 11, 01, 23, 05, 11, 09, 01, 17, 01, 00, 2f, 03, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 20, 05, 12, 00, 0d, 00, 0e, 12, 00, 12, 00, 13, 20, 1e, 11, 00, 12, 00, 13, 1e, 00, 17, 00, 18, 20, 09, 0d, 00, 17, 00, 18, 03, 01, 05, 01, 02] +Raw bytes (63): 0x[01, 01, 04, 01, 05, 01, 0b, 05, 09, 09, 0d, 09, 01, 17, 01, 00, 2f, 01, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 20, 05, 02, 00, 0d, 00, 0e, 02, 00, 12, 00, 13, 20, 09, 06, 00, 12, 00, 13, 09, 00, 17, 00, 18, 20, 0d, 0e, 00, 17, 00, 18, 01, 01, 05, 01, 02] Number of files: 1 - file 0 => global file 1 -Number of expressions: 9 -- expression 0 operands: lhs = Expression(1, Add), rhs = Counter(4) -- expression 1 operands: lhs = Expression(2, Add), rhs = Counter(3) +Number of expressions: 4 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +- expression 1 operands: lhs = Counter(0), rhs = Expression(2, Add) - expression 2 operands: lhs = Counter(1), rhs = Counter(2) -- expression 3 operands: lhs = Counter(0), rhs = Counter(1) -- expression 4 operands: lhs = Counter(0), rhs = Counter(1) -- expression 5 operands: lhs = Counter(0), rhs = Expression(8, Add) -- expression 6 operands: lhs = Counter(1), rhs = Counter(4) -- expression 7 operands: lhs = Counter(0), rhs = Expression(8, Add) -- expression 8 operands: lhs = Counter(1), rhs = Counter(4) +- expression 3 operands: lhs = Counter(2), rhs = Counter(3) Number of file 0 mappings: 9 - Code(Counter(0)) at (prev + 23, 1) to (start + 0, 47) -- Code(Expression(0, Add)) at (prev + 1, 9) to (start + 0, 10) - = (((c1 + c2) + c3) + c4) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 10) - Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14) -- Branch { true: Counter(1), false: Expression(4, Sub) } at (prev + 0, 13) to (start + 0, 14) +- Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 0, 13) to (start + 0, 14) true = c1 false = (c0 - c1) -- Code(Expression(4, Sub)) at (prev + 0, 18) to (start + 0, 19) +- Code(Expression(0, Sub)) at (prev + 0, 18) to (start + 0, 19) = (c0 - c1) -- Branch { true: Expression(7, Sub), false: Counter(4) } at (prev + 0, 18) to (start + 0, 19) - true = (c0 - (c1 + c4)) - false = c4 -- Code(Expression(7, Sub)) at (prev + 0, 23) to (start + 0, 24) - = (c0 - (c1 + c4)) -- Branch { true: Counter(2), false: Counter(3) } at (prev + 0, 23) to (start + 0, 24) +- Branch { true: Counter(2), false: Expression(1, Sub) } at (prev + 0, 18) to (start + 0, 19) true = c2 - false = c3 -- Code(Expression(0, Add)) at (prev + 1, 5) to (start + 1, 2) - = (((c1 + c2) + c3) + c4) -Highest counter ID seen: c4 + false = (c0 - (c1 + c2)) +- Code(Counter(2)) at (prev + 0, 23) to (start + 0, 24) +- Branch { true: Counter(3), false: Expression(3, Sub) } at (prev + 0, 23) to (start + 0, 24) + true = c3 + false = (c2 - c3) +- Code(Counter(0)) at (prev + 1, 5) to (start + 1, 2) +Highest counter ID seen: c3 Function name: conditions::assign_and -Raw bytes (51): 0x[01, 01, 04, 07, 05, 0b, 0d, 01, 09, 01, 05, 07, 01, 0d, 01, 00, 21, 02, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 20, 05, 0e, 00, 0d, 00, 0e, 05, 00, 12, 00, 13, 20, 09, 0d, 00, 12, 00, 13, 02, 01, 05, 01, 02] +Raw bytes (47): 0x[01, 01, 02, 01, 05, 05, 09, 07, 01, 0d, 01, 00, 21, 01, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 20, 05, 02, 00, 0d, 00, 0e, 05, 00, 12, 00, 13, 20, 09, 06, 00, 12, 00, 13, 01, 01, 05, 01, 02] Number of files: 1 - file 0 => global file 1 -Number of expressions: 4 -- expression 0 operands: lhs = Expression(1, Add), rhs = Counter(1) -- expression 1 operands: lhs = Expression(2, Add), rhs = Counter(3) -- expression 2 operands: lhs = Counter(0), rhs = Counter(2) -- expression 3 operands: lhs = Counter(0), rhs = Counter(1) +Number of expressions: 2 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +- expression 1 operands: lhs = Counter(1), rhs = Counter(2) Number of file 0 mappings: 7 - Code(Counter(0)) at (prev + 13, 1) to (start + 0, 33) -- Code(Expression(0, Sub)) at (prev + 1, 9) to (start + 0, 10) - = (((c0 + c2) + c3) - c1) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 10) - Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14) -- Branch { true: Counter(1), false: Expression(3, Sub) } at (prev + 0, 13) to (start + 0, 14) +- Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 0, 13) to (start + 0, 14) true = c1 false = (c0 - c1) - Code(Counter(1)) at (prev + 0, 18) to (start + 0, 19) -- Branch { true: Counter(2), false: Counter(3) } at (prev + 0, 18) to (start + 0, 19) +- Branch { true: Counter(2), false: Expression(1, Sub) } at (prev + 0, 18) to (start + 0, 19) true = c2 - false = c3 -- Code(Expression(0, Sub)) at (prev + 1, 5) to (start + 1, 2) - = (((c0 + c2) + c3) - c1) -Highest counter ID seen: c3 + false = (c1 - c2) +- Code(Counter(0)) at (prev + 1, 5) to (start + 1, 2) +Highest counter ID seen: c2 Function name: conditions::assign_or -Raw bytes (51): 0x[01, 01, 04, 07, 0d, 05, 09, 01, 05, 01, 05, 07, 01, 12, 01, 00, 20, 03, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 20, 05, 0e, 00, 0d, 00, 0e, 0e, 00, 12, 00, 13, 20, 09, 0d, 00, 12, 00, 13, 03, 01, 05, 01, 02] +Raw bytes (49): 0x[01, 01, 03, 01, 05, 01, 0b, 05, 09, 07, 01, 12, 01, 00, 20, 01, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 20, 05, 02, 00, 0d, 00, 0e, 02, 00, 12, 00, 13, 20, 09, 06, 00, 12, 00, 13, 01, 01, 05, 01, 02] Number of files: 1 - file 0 => global file 1 -Number of expressions: 4 -- expression 0 operands: lhs = Expression(1, Add), rhs = Counter(3) -- expression 1 operands: lhs = Counter(1), rhs = Counter(2) -- expression 2 operands: lhs = Counter(0), rhs = Counter(1) -- expression 3 operands: lhs = Counter(0), rhs = Counter(1) +Number of expressions: 3 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +- expression 1 operands: lhs = Counter(0), rhs = Expression(2, Add) +- expression 2 operands: lhs = Counter(1), rhs = Counter(2) Number of file 0 mappings: 7 - Code(Counter(0)) at (prev + 18, 1) to (start + 0, 32) -- Code(Expression(0, Add)) at (prev + 1, 9) to (start + 0, 10) - = ((c1 + c2) + c3) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 10) - Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14) -- Branch { true: Counter(1), false: Expression(3, Sub) } at (prev + 0, 13) to (start + 0, 14) +- Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 0, 13) to (start + 0, 14) true = c1 false = (c0 - c1) -- Code(Expression(3, Sub)) at (prev + 0, 18) to (start + 0, 19) +- Code(Expression(0, Sub)) at (prev + 0, 18) to (start + 0, 19) = (c0 - c1) -- Branch { true: Counter(2), false: Counter(3) } at (prev + 0, 18) to (start + 0, 19) +- Branch { true: Counter(2), false: Expression(1, Sub) } at (prev + 0, 18) to (start + 0, 19) true = c2 - false = c3 -- Code(Expression(0, Add)) at (prev + 1, 5) to (start + 1, 2) - = ((c1 + c2) + c3) -Highest counter ID seen: c3 + false = (c0 - (c1 + c2)) +- Code(Counter(0)) at (prev + 1, 5) to (start + 1, 2) +Highest counter ID seen: c2 Function name: conditions::foo Raw bytes (9): 0x[01, 01, 00, 01, 01, 21, 01, 02, 02] @@ -126,26 +109,23 @@ Number of file 0 mappings: 1 Highest counter ID seen: c0 Function name: conditions::func_call -Raw bytes (41): 0x[01, 01, 04, 01, 05, 0b, 05, 0f, 0d, 01, 09, 05, 01, 25, 01, 01, 0a, 20, 05, 02, 01, 09, 00, 0a, 05, 00, 0e, 00, 0f, 20, 09, 0d, 00, 0e, 00, 0f, 06, 01, 01, 00, 02] +Raw bytes (37): 0x[01, 01, 02, 01, 05, 05, 09, 05, 01, 25, 01, 01, 0a, 20, 05, 02, 01, 09, 00, 0a, 05, 00, 0e, 00, 0f, 20, 09, 06, 00, 0e, 00, 0f, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 -Number of expressions: 4 +Number of expressions: 2 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -- expression 1 operands: lhs = Expression(2, Add), rhs = Counter(1) -- expression 2 operands: lhs = Expression(3, Add), rhs = Counter(3) -- expression 3 operands: lhs = Counter(0), rhs = Counter(2) +- expression 1 operands: lhs = Counter(1), rhs = Counter(2) Number of file 0 mappings: 5 - Code(Counter(0)) at (prev + 37, 1) to (start + 1, 10) - Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 1, 9) to (start + 0, 10) true = c1 false = (c0 - c1) - Code(Counter(1)) at (prev + 0, 14) to (start + 0, 15) -- Branch { true: Counter(2), false: Counter(3) } at (prev + 0, 14) to (start + 0, 15) +- Branch { true: Counter(2), false: Expression(1, Sub) } at (prev + 0, 14) to (start + 0, 15) true = c2 - false = c3 -- Code(Expression(1, Sub)) at (prev + 1, 1) to (start + 0, 2) - = (((c0 + c2) + c3) - c1) -Highest counter ID seen: c3 + false = (c1 - c2) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) +Highest counter ID seen: c2 Function name: conditions::simple_assign Raw bytes (9): 0x[01, 01, 00, 01, 01, 08, 01, 03, 02] diff --git a/tests/coverage/conditions.cov-map b/tests/coverage/conditions.cov-map index 21b2ec9a19e..549b8bb0a20 100644 --- a/tests/coverage/conditions.cov-map +++ b/tests/coverage/conditions.cov-map @@ -1,294 +1,192 @@ Function name: conditions::main -Raw bytes (873): 0x[01, 01, b2, 01, 07, 19, 0b, 15, 0f, 11, 09, 0d, 01, 09, 8d, 01, 0d, 8d, 01, 33, 0d, 11, 33, 15, 0d, 11, 2f, 19, 33, 15, 0d, 11, 01, c7, 05, 09, 8d, 01, 03, 21, 03, 47, 21, 89, 01, 03, 4f, db, 03, 89, 01, 21, 25, 03, 5b, d7, 03, 89, 01, db, 03, 29, 21, 25, 77, 2d, 25, 29, 73, 31, 77, 2d, 25, 29, d3, 03, 31, d7, 03, 2d, db, 03, 29, 21, 25, 35, 3d, 35, 93, 01, 3d, 85, 01, 35, 9b, 01, af, 01, 85, 01, 3d, 41, 35, a7, 01, ab, 01, 85, 01, af, 01, 45, 3d, 41, c3, 01, 49, 41, 45, bf, 01, 4d, c3, 01, 49, 41, 45, bb, 03, 35, bf, 03, 4d, c3, 03, 49, c7, 03, 45, cb, 03, 41, cf, 03, 3d, d3, 03, 31, d7, 03, 2d, db, 03, 29, 21, 25, f3, 04, 65, f7, 04, 61, fb, 04, 5d, 55, 59, bb, 03, 35, bf, 03, 4d, c3, 03, 49, c7, 03, 45, cb, 03, 41, cf, 03, 3d, d3, 03, 31, d7, 03, 2d, db, 03, 29, 21, 25, bb, 03, eb, 03, bf, 03, 4d, c3, 03, 49, c7, 03, 45, cb, 03, 41, cf, 03, 3d, d3, 03, 31, d7, 03, 2d, db, 03, 29, 21, 25, 35, 55, bb, 03, fb, 02, bf, 03, 4d, c3, 03, 49, c7, 03, 45, cb, 03, 41, cf, 03, 3d, d3, 03, 31, d7, 03, 2d, db, 03, 29, 21, 25, eb, 03, 81, 01, 35, 55, bb, 03, ab, 03, bf, 03, 4d, c3, 03, 49, c7, 03, 45, cb, 03, 41, cf, 03, 3d, d3, 03, 31, d7, 03, 2d, db, 03, 29, 21, 25, e7, 03, 81, 01, eb, 03, 59, 35, 55, bb, 03, df, 03, bf, 03, 4d, c3, 03, 49, c7, 03, 45, cb, 03, 41, cf, 03, 3d, d3, 03, 31, d7, 03, 2d, db, 03, 29, 21, 25, e3, 03, 81, 01, e7, 03, 5d, eb, 03, 59, 35, 55, ff, 03, 61, 59, 5d, fb, 03, 65, ff, 03, 61, 59, 5d, 87, 04, 79, 83, 05, 75, 87, 05, 71, 69, 6d, f3, 04, 65, f7, 04, 61, fb, 04, 5d, 55, 59, ef, 04, 69, f3, 04, 65, f7, 04, 61, fb, 04, 5d, 55, 59, ef, 04, cb, 04, f3, 04, 65, f7, 04, 61, fb, 04, 5d, 55, 59, 69, 7d, ef, 04, e3, 04, f3, 04, 65, f7, 04, 61, fb, 04, 5d, 55, 59, 87, 05, 7d, 69, 6d, ef, 04, ff, 04, f3, 04, 65, f7, 04, 61, fb, 04, 5d, 55, 59, 83, 05, 7d, 87, 05, 71, 69, 6d, 9b, 05, 75, 6d, 71, 97, 05, 79, 9b, 05, 75, 6d, 71, a3, 05, c7, 05, a7, 05, 89, 01, ab, 05, 85, 01, af, 05, 81, 01, b3, 05, 7d, b7, 05, 79, bb, 05, 75, bf, 05, 71, c3, 05, 6d, 01, 69, 09, 8d, 01, 44, 01, 03, 01, 02, 0c, 05, 02, 0d, 02, 06, 00, 02, 05, 00, 06, 03, 03, 09, 00, 0a, 01, 00, 10, 00, 1d, 09, 01, 09, 01, 0a, 12, 02, 0f, 00, 1c, 8d, 01, 01, 0c, 00, 19, 16, 00, 1d, 00, 2a, 1a, 00, 2e, 00, 3c, 2f, 00, 3d, 02, 0a, 19, 02, 09, 00, 0a, 2b, 01, 09, 01, 12, 36, 03, 09, 00, 0f, 03, 03, 09, 01, 0c, 1d, 01, 0d, 02, 06, 00, 02, 05, 00, 06, 03, 02, 08, 00, 15, 21, 00, 16, 02, 06, 3e, 02, 0f, 00, 1c, 42, 01, 0c, 00, 19, 4a, 00, 1d, 00, 2a, 56, 00, 2e, 00, 3c, 73, 00, 3d, 02, 0a, 31, 02, 09, 00, 0a, 6f, 01, 09, 00, 17, 89, 01, 02, 09, 00, 0f, cf, 03, 03, 08, 00, 0c, 35, 01, 0d, 01, 10, 39, 01, 11, 02, 0a, 00, 02, 09, 00, 0a, 35, 02, 0c, 00, 19, 3d, 00, 1a, 02, 0a, 8a, 01, 04, 11, 00, 1e, 8e, 01, 01, 10, 00, 1d, 96, 01, 00, 21, 00, 2e, a2, 01, 00, 32, 00, 40, bf, 01, 00, 41, 02, 0e, 4d, 02, 0d, 00, 0e, bb, 01, 01, 0d, 00, 1b, 85, 01, 02, 0d, 00, 13, 00, 02, 05, 00, 06, fe, 01, 02, 09, 01, 0c, 51, 01, 0d, 02, 06, 00, 02, 05, 00, 06, ef, 04, 02, 09, 00, 0a, fe, 01, 00, 10, 00, 1d, 55, 00, 1e, 02, 06, a6, 02, 02, 0f, 00, 1c, d2, 02, 01, 0c, 00, 19, 82, 03, 00, 1d, 00, 2a, b6, 03, 00, 2e, 00, 3c, fb, 03, 00, 3d, 02, 0a, 65, 02, 09, 00, 0a, f7, 03, 01, 09, 00, 17, 81, 01, 02, 0d, 02, 0f, 83, 04, 05, 09, 00, 0a, ef, 04, 00, 10, 00, 1d, 69, 00, 1e, 02, 06, a2, 04, 02, 0f, 00, 1c, b6, 04, 01, 0c, 00, 19, ce, 04, 00, 1d, 00, 2a, ea, 04, 00, 2e, 00, 3c, 97, 05, 00, 3d, 02, 0a, 79, 02, 09, 00, 0a, 93, 05, 01, 09, 00, 17, 7d, 02, 09, 00, 0f, 9e, 05, 02, 01, 00, 02] +Raw bytes (545): 0x[01, 01, 4d, 09, 0d, 01, 09, 0d, 71, 0d, 27, 71, 75, 27, 79, 71, 75, 0d, 23, 27, 79, 71, 75, 01, 03, 03, 15, 19, 65, 19, 4f, 65, 69, 4f, 6d, 65, 69, 19, 4b, 4f, 6d, 65, 69, 03, ef, 01, 15, 19, 15, 19, 1d, 25, 29, 59, 29, 7f, 59, 5d, 7f, 61, 59, 5d, 29, 7b, 7f, 61, 59, 5d, 1d, 87, 01, 25, 29, e7, 01, 1d, eb, 01, 29, ef, 01, 25, 15, 19, 31, 35, e7, 01, 1d, eb, 01, 29, ef, 01, 25, 15, 19, e7, 01, f7, 01, eb, 01, 29, ef, 01, 25, 15, 19, 1d, 31, 35, 4d, 35, df, 01, 4d, 51, df, 01, 55, 4d, 51, 35, db, 01, df, 01, 55, 4d, 51, e7, 01, f3, 01, eb, 01, 29, ef, 01, 25, 15, 19, f7, 01, 35, 1d, 31, 39, 3d, 31, 35, af, 02, 39, 31, 35, 3d, 41, 3d, a7, 02, 41, 45, a7, 02, 49, 41, 45, 3d, a3, 02, a7, 02, 49, 41, 45, af, 02, b3, 02, 31, 35, 39, 3d, 44, 01, 03, 01, 02, 0c, 05, 02, 0d, 02, 06, 00, 02, 05, 00, 06, 03, 03, 09, 00, 0a, 01, 00, 10, 00, 1d, 09, 01, 09, 01, 0a, 06, 02, 0f, 00, 1c, 0d, 01, 0c, 00, 19, 0a, 00, 1d, 00, 2a, 0e, 00, 2e, 00, 3c, 23, 00, 3d, 02, 0a, 1e, 02, 09, 00, 0a, 0d, 01, 09, 01, 12, 2a, 03, 09, 00, 0f, 03, 03, 09, 01, 0c, 11, 01, 0d, 02, 06, 00, 02, 05, 00, 06, 03, 02, 08, 00, 15, 15, 00, 16, 02, 06, 2e, 02, 0f, 00, 1c, 19, 01, 0c, 00, 19, 32, 00, 1d, 00, 2a, 36, 00, 2e, 00, 3c, 4b, 00, 3d, 02, 0a, 46, 02, 09, 00, 0a, 19, 01, 09, 00, 17, 52, 02, 09, 00, 0f, ef, 01, 03, 08, 00, 0c, 1d, 01, 0d, 01, 10, 21, 01, 11, 02, 0a, 00, 02, 09, 00, 0a, 1d, 02, 0c, 00, 19, 25, 00, 1a, 02, 0a, 5e, 04, 11, 00, 1e, 29, 01, 10, 00, 1d, 62, 00, 21, 00, 2e, 66, 00, 32, 00, 40, 7b, 00, 41, 02, 0e, 76, 02, 0d, 00, 0e, 29, 01, 0d, 00, 1b, 82, 01, 02, 0d, 00, 13, 00, 02, 05, 00, 06, 9e, 01, 02, 09, 01, 0c, 2d, 01, 0d, 02, 06, 00, 02, 05, 00, 06, af, 02, 02, 09, 00, 0a, 9e, 01, 00, 10, 00, 1d, 31, 00, 1e, 02, 06, ae, 01, 02, 0f, 00, 1c, 35, 01, 0c, 00, 19, c2, 01, 00, 1d, 00, 2a, c6, 01, 00, 2e, 00, 3c, db, 01, 00, 3d, 02, 0a, d6, 01, 02, 09, 00, 0a, 35, 01, 09, 00, 17, e2, 01, 02, 0d, 02, 0f, b3, 02, 05, 09, 00, 0a, af, 02, 00, 10, 00, 1d, 39, 00, 1e, 02, 06, 82, 02, 02, 0f, 00, 1c, 3d, 01, 0c, 00, 19, 8a, 02, 00, 1d, 00, 2a, 8e, 02, 00, 2e, 00, 3c, a3, 02, 00, 3d, 02, 0a, 9e, 02, 02, 09, 00, 0a, 3d, 01, 09, 00, 17, aa, 02, 02, 09, 00, 0f, 01, 02, 01, 00, 02] Number of files: 1 - file 0 => global file 1 -Number of expressions: 178 -- expression 0 operands: lhs = Expression(1, Add), rhs = Counter(6) -- expression 1 operands: lhs = Expression(2, Add), rhs = Counter(5) -- expression 2 operands: lhs = Expression(3, Add), rhs = Counter(4) -- expression 3 operands: lhs = Counter(2), rhs = Counter(3) -- expression 4 operands: lhs = Counter(0), rhs = Counter(2) -- expression 5 operands: lhs = Counter(35), rhs = Counter(3) -- expression 6 operands: lhs = Counter(35), rhs = Expression(12, Add) -- expression 7 operands: lhs = Counter(3), rhs = Counter(4) -- expression 8 operands: lhs = Expression(12, Add), rhs = Counter(5) -- expression 9 operands: lhs = Counter(3), rhs = Counter(4) -- expression 10 operands: lhs = Expression(11, Add), rhs = Counter(6) -- expression 11 operands: lhs = Expression(12, Add), rhs = Counter(5) -- expression 12 operands: lhs = Counter(3), rhs = Counter(4) -- expression 13 operands: lhs = Counter(0), rhs = Expression(177, Add) -- expression 14 operands: lhs = Counter(2), rhs = Counter(35) -- expression 15 operands: lhs = Expression(0, Add), rhs = Counter(8) -- expression 16 operands: lhs = Expression(0, Add), rhs = Expression(17, Add) -- expression 17 operands: lhs = Counter(8), rhs = Counter(34) -- expression 18 operands: lhs = Expression(0, Add), rhs = Expression(19, Add) -- expression 19 operands: lhs = Expression(118, Add), rhs = Counter(34) -- expression 20 operands: lhs = Counter(8), rhs = Counter(9) -- expression 21 operands: lhs = Expression(0, Add), rhs = Expression(22, Add) -- expression 22 operands: lhs = Expression(117, Add), rhs = Counter(34) -- expression 23 operands: lhs = Expression(118, Add), rhs = Counter(10) -- expression 24 operands: lhs = Counter(8), rhs = Counter(9) -- expression 25 operands: lhs = Expression(29, Add), rhs = Counter(11) -- expression 26 operands: lhs = Counter(9), rhs = Counter(10) -- expression 27 operands: lhs = Expression(28, Add), rhs = Counter(12) -- expression 28 operands: lhs = Expression(29, Add), rhs = Counter(11) -- expression 29 operands: lhs = Counter(9), rhs = Counter(10) -- expression 30 operands: lhs = Expression(116, Add), rhs = Counter(12) -- expression 31 operands: lhs = Expression(117, Add), rhs = Counter(11) -- expression 32 operands: lhs = Expression(118, Add), rhs = Counter(10) -- expression 33 operands: lhs = Counter(8), rhs = Counter(9) -- expression 34 operands: lhs = Counter(13), rhs = Counter(15) -- expression 35 operands: lhs = Counter(13), rhs = Expression(36, Add) -- expression 36 operands: lhs = Counter(15), rhs = Counter(33) -- expression 37 operands: lhs = Counter(13), rhs = Expression(38, Add) -- expression 38 operands: lhs = Expression(43, Add), rhs = Counter(33) -- expression 39 operands: lhs = Counter(15), rhs = Counter(16) -- expression 40 operands: lhs = Counter(13), rhs = Expression(41, Add) -- expression 41 operands: lhs = Expression(42, Add), rhs = Counter(33) -- expression 42 operands: lhs = Expression(43, Add), rhs = Counter(17) -- expression 43 operands: lhs = Counter(15), rhs = Counter(16) -- expression 44 operands: lhs = Expression(48, Add), rhs = Counter(18) -- expression 45 operands: lhs = Counter(16), rhs = Counter(17) -- expression 46 operands: lhs = Expression(47, Add), rhs = Counter(19) -- expression 47 operands: lhs = Expression(48, Add), rhs = Counter(18) -- expression 48 operands: lhs = Counter(16), rhs = Counter(17) -- expression 49 operands: lhs = Expression(110, Add), rhs = Counter(13) -- expression 50 operands: lhs = Expression(111, Add), rhs = Counter(19) -- expression 51 operands: lhs = Expression(112, Add), rhs = Counter(18) -- expression 52 operands: lhs = Expression(113, Add), rhs = Counter(17) -- expression 53 operands: lhs = Expression(114, Add), rhs = Counter(16) -- expression 54 operands: lhs = Expression(115, Add), rhs = Counter(15) -- expression 55 operands: lhs = Expression(116, Add), rhs = Counter(12) -- expression 56 operands: lhs = Expression(117, Add), rhs = Counter(11) -- expression 57 operands: lhs = Expression(118, Add), rhs = Counter(10) -- expression 58 operands: lhs = Counter(8), rhs = Counter(9) -- expression 59 operands: lhs = Expression(156, Add), rhs = Counter(25) -- expression 60 operands: lhs = Expression(157, Add), rhs = Counter(24) -- expression 61 operands: lhs = Expression(158, Add), rhs = Counter(23) -- expression 62 operands: lhs = Counter(21), rhs = Counter(22) -- expression 63 operands: lhs = Expression(110, Add), rhs = Counter(13) -- expression 64 operands: lhs = Expression(111, Add), rhs = Counter(19) -- expression 65 operands: lhs = Expression(112, Add), rhs = Counter(18) -- expression 66 operands: lhs = Expression(113, Add), rhs = Counter(17) -- expression 67 operands: lhs = Expression(114, Add), rhs = Counter(16) -- expression 68 operands: lhs = Expression(115, Add), rhs = Counter(15) -- expression 69 operands: lhs = Expression(116, Add), rhs = Counter(12) -- expression 70 operands: lhs = Expression(117, Add), rhs = Counter(11) -- expression 71 operands: lhs = Expression(118, Add), rhs = Counter(10) -- expression 72 operands: lhs = Counter(8), rhs = Counter(9) -- expression 73 operands: lhs = Expression(110, Add), rhs = Expression(122, Add) -- expression 74 operands: lhs = Expression(111, Add), rhs = Counter(19) -- expression 75 operands: lhs = Expression(112, Add), rhs = Counter(18) -- expression 76 operands: lhs = Expression(113, Add), rhs = Counter(17) -- expression 77 operands: lhs = Expression(114, Add), rhs = Counter(16) -- expression 78 operands: lhs = Expression(115, Add), rhs = Counter(15) -- expression 79 operands: lhs = Expression(116, Add), rhs = Counter(12) -- expression 80 operands: lhs = Expression(117, Add), rhs = Counter(11) -- expression 81 operands: lhs = Expression(118, Add), rhs = Counter(10) -- expression 82 operands: lhs = Counter(8), rhs = Counter(9) -- expression 83 operands: lhs = Counter(13), rhs = Counter(21) -- expression 84 operands: lhs = Expression(110, Add), rhs = Expression(94, Add) -- expression 85 operands: lhs = Expression(111, Add), rhs = Counter(19) -- expression 86 operands: lhs = Expression(112, Add), rhs = Counter(18) -- expression 87 operands: lhs = Expression(113, Add), rhs = Counter(17) -- expression 88 operands: lhs = Expression(114, Add), rhs = Counter(16) -- expression 89 operands: lhs = Expression(115, Add), rhs = Counter(15) -- expression 90 operands: lhs = Expression(116, Add), rhs = Counter(12) -- expression 91 operands: lhs = Expression(117, Add), rhs = Counter(11) -- expression 92 operands: lhs = Expression(118, Add), rhs = Counter(10) -- expression 93 operands: lhs = Counter(8), rhs = Counter(9) -- expression 94 operands: lhs = Expression(122, Add), rhs = Counter(32) -- expression 95 operands: lhs = Counter(13), rhs = Counter(21) -- expression 96 operands: lhs = Expression(110, Add), rhs = Expression(106, Add) -- expression 97 operands: lhs = Expression(111, Add), rhs = Counter(19) -- expression 98 operands: lhs = Expression(112, Add), rhs = Counter(18) -- expression 99 operands: lhs = Expression(113, Add), rhs = Counter(17) -- expression 100 operands: lhs = Expression(114, Add), rhs = Counter(16) -- expression 101 operands: lhs = Expression(115, Add), rhs = Counter(15) -- expression 102 operands: lhs = Expression(116, Add), rhs = Counter(12) -- expression 103 operands: lhs = Expression(117, Add), rhs = Counter(11) -- expression 104 operands: lhs = Expression(118, Add), rhs = Counter(10) -- expression 105 operands: lhs = Counter(8), rhs = Counter(9) -- expression 106 operands: lhs = Expression(121, Add), rhs = Counter(32) -- expression 107 operands: lhs = Expression(122, Add), rhs = Counter(22) -- expression 108 operands: lhs = Counter(13), rhs = Counter(21) -- expression 109 operands: lhs = Expression(110, Add), rhs = Expression(119, Add) -- expression 110 operands: lhs = Expression(111, Add), rhs = Counter(19) -- expression 111 operands: lhs = Expression(112, Add), rhs = Counter(18) -- expression 112 operands: lhs = Expression(113, Add), rhs = Counter(17) -- expression 113 operands: lhs = Expression(114, Add), rhs = Counter(16) -- expression 114 operands: lhs = Expression(115, Add), rhs = Counter(15) -- expression 115 operands: lhs = Expression(116, Add), rhs = Counter(12) -- expression 116 operands: lhs = Expression(117, Add), rhs = Counter(11) -- expression 117 operands: lhs = Expression(118, Add), rhs = Counter(10) -- expression 118 operands: lhs = Counter(8), rhs = Counter(9) -- expression 119 operands: lhs = Expression(120, Add), rhs = Counter(32) -- expression 120 operands: lhs = Expression(121, Add), rhs = Counter(23) -- expression 121 operands: lhs = Expression(122, Add), rhs = Counter(22) -- expression 122 operands: lhs = Counter(13), rhs = Counter(21) -- expression 123 operands: lhs = Expression(127, Add), rhs = Counter(24) -- expression 124 operands: lhs = Counter(22), rhs = Counter(23) -- expression 125 operands: lhs = Expression(126, Add), rhs = Counter(25) -- expression 126 operands: lhs = Expression(127, Add), rhs = Counter(24) -- expression 127 operands: lhs = Counter(22), rhs = Counter(23) -- expression 128 operands: lhs = Expression(129, Add), rhs = Counter(30) -- expression 129 operands: lhs = Expression(160, Add), rhs = Counter(29) -- expression 130 operands: lhs = Expression(161, Add), rhs = Counter(28) -- expression 131 operands: lhs = Counter(26), rhs = Counter(27) -- expression 132 operands: lhs = Expression(156, Add), rhs = Counter(25) -- expression 133 operands: lhs = Expression(157, Add), rhs = Counter(24) -- expression 134 operands: lhs = Expression(158, Add), rhs = Counter(23) -- expression 135 operands: lhs = Counter(21), rhs = Counter(22) -- expression 136 operands: lhs = Expression(155, Add), rhs = Counter(26) -- expression 137 operands: lhs = Expression(156, Add), rhs = Counter(25) -- expression 138 operands: lhs = Expression(157, Add), rhs = Counter(24) -- expression 139 operands: lhs = Expression(158, Add), rhs = Counter(23) -- expression 140 operands: lhs = Counter(21), rhs = Counter(22) -- expression 141 operands: lhs = Expression(155, Add), rhs = Expression(146, Add) -- expression 142 operands: lhs = Expression(156, Add), rhs = Counter(25) -- expression 143 operands: lhs = Expression(157, Add), rhs = Counter(24) -- expression 144 operands: lhs = Expression(158, Add), rhs = Counter(23) -- expression 145 operands: lhs = Counter(21), rhs = Counter(22) -- expression 146 operands: lhs = Counter(26), rhs = Counter(31) -- expression 147 operands: lhs = Expression(155, Add), rhs = Expression(152, Add) -- expression 148 operands: lhs = Expression(156, Add), rhs = Counter(25) -- expression 149 operands: lhs = Expression(157, Add), rhs = Counter(24) -- expression 150 operands: lhs = Expression(158, Add), rhs = Counter(23) -- expression 151 operands: lhs = Counter(21), rhs = Counter(22) -- expression 152 operands: lhs = Expression(161, Add), rhs = Counter(31) -- expression 153 operands: lhs = Counter(26), rhs = Counter(27) -- expression 154 operands: lhs = Expression(155, Add), rhs = Expression(159, Add) -- expression 155 operands: lhs = Expression(156, Add), rhs = Counter(25) -- expression 156 operands: lhs = Expression(157, Add), rhs = Counter(24) -- expression 157 operands: lhs = Expression(158, Add), rhs = Counter(23) -- expression 158 operands: lhs = Counter(21), rhs = Counter(22) -- expression 159 operands: lhs = Expression(160, Add), rhs = Counter(31) -- expression 160 operands: lhs = Expression(161, Add), rhs = Counter(28) -- expression 161 operands: lhs = Counter(26), rhs = Counter(27) -- expression 162 operands: lhs = Expression(166, Add), rhs = Counter(29) -- expression 163 operands: lhs = Counter(27), rhs = Counter(28) -- expression 164 operands: lhs = Expression(165, Add), rhs = Counter(30) -- expression 165 operands: lhs = Expression(166, Add), rhs = Counter(29) -- expression 166 operands: lhs = Counter(27), rhs = Counter(28) -- expression 167 operands: lhs = Expression(168, Add), rhs = Expression(177, Add) -- expression 168 operands: lhs = Expression(169, Add), rhs = Counter(34) -- expression 169 operands: lhs = Expression(170, Add), rhs = Counter(33) -- expression 170 operands: lhs = Expression(171, Add), rhs = Counter(32) -- expression 171 operands: lhs = Expression(172, Add), rhs = Counter(31) -- expression 172 operands: lhs = Expression(173, Add), rhs = Counter(30) -- expression 173 operands: lhs = Expression(174, Add), rhs = Counter(29) -- expression 174 operands: lhs = Expression(175, Add), rhs = Counter(28) -- expression 175 operands: lhs = Expression(176, Add), rhs = Counter(27) -- expression 176 operands: lhs = Counter(0), rhs = Counter(26) -- expression 177 operands: lhs = Counter(2), rhs = Counter(35) +Number of expressions: 77 +- expression 0 operands: lhs = Counter(2), rhs = Counter(3) +- expression 1 operands: lhs = Counter(0), rhs = Counter(2) +- expression 2 operands: lhs = Counter(3), rhs = Counter(28) +- expression 3 operands: lhs = Counter(3), rhs = Expression(9, Add) +- expression 4 operands: lhs = Counter(28), rhs = Counter(29) +- expression 5 operands: lhs = Expression(9, Add), rhs = Counter(30) +- expression 6 operands: lhs = Counter(28), rhs = Counter(29) +- expression 7 operands: lhs = Counter(3), rhs = Expression(8, Add) +- expression 8 operands: lhs = Expression(9, Add), rhs = Counter(30) +- expression 9 operands: lhs = Counter(28), rhs = Counter(29) +- expression 10 operands: lhs = Counter(0), rhs = Expression(0, Add) +- expression 11 operands: lhs = Expression(0, Add), rhs = Counter(5) +- expression 12 operands: lhs = Counter(6), rhs = Counter(25) +- expression 13 operands: lhs = Counter(6), rhs = Expression(19, Add) +- expression 14 operands: lhs = Counter(25), rhs = Counter(26) +- expression 15 operands: lhs = Expression(19, Add), rhs = Counter(27) +- expression 16 operands: lhs = Counter(25), rhs = Counter(26) +- expression 17 operands: lhs = Counter(6), rhs = Expression(18, Add) +- expression 18 operands: lhs = Expression(19, Add), rhs = Counter(27) +- expression 19 operands: lhs = Counter(25), rhs = Counter(26) +- expression 20 operands: lhs = Expression(0, Add), rhs = Expression(59, Add) +- expression 21 operands: lhs = Counter(5), rhs = Counter(6) +- expression 22 operands: lhs = Counter(5), rhs = Counter(6) +- expression 23 operands: lhs = Counter(7), rhs = Counter(9) +- expression 24 operands: lhs = Counter(10), rhs = Counter(22) +- expression 25 operands: lhs = Counter(10), rhs = Expression(31, Add) +- expression 26 operands: lhs = Counter(22), rhs = Counter(23) +- expression 27 operands: lhs = Expression(31, Add), rhs = Counter(24) +- expression 28 operands: lhs = Counter(22), rhs = Counter(23) +- expression 29 operands: lhs = Counter(10), rhs = Expression(30, Add) +- expression 30 operands: lhs = Expression(31, Add), rhs = Counter(24) +- expression 31 operands: lhs = Counter(22), rhs = Counter(23) +- expression 32 operands: lhs = Counter(7), rhs = Expression(33, Add) +- expression 33 operands: lhs = Counter(9), rhs = Counter(10) +- expression 34 operands: lhs = Expression(57, Add), rhs = Counter(7) +- expression 35 operands: lhs = Expression(58, Add), rhs = Counter(10) +- expression 36 operands: lhs = Expression(59, Add), rhs = Counter(9) +- expression 37 operands: lhs = Counter(5), rhs = Counter(6) +- expression 38 operands: lhs = Counter(12), rhs = Counter(13) +- expression 39 operands: lhs = Expression(57, Add), rhs = Counter(7) +- expression 40 operands: lhs = Expression(58, Add), rhs = Counter(10) +- expression 41 operands: lhs = Expression(59, Add), rhs = Counter(9) +- expression 42 operands: lhs = Counter(5), rhs = Counter(6) +- expression 43 operands: lhs = Expression(57, Add), rhs = Expression(61, Add) +- expression 44 operands: lhs = Expression(58, Add), rhs = Counter(10) +- expression 45 operands: lhs = Expression(59, Add), rhs = Counter(9) +- expression 46 operands: lhs = Counter(5), rhs = Counter(6) +- expression 47 operands: lhs = Counter(7), rhs = Counter(12) +- expression 48 operands: lhs = Counter(13), rhs = Counter(19) +- expression 49 operands: lhs = Counter(13), rhs = Expression(55, Add) +- expression 50 operands: lhs = Counter(19), rhs = Counter(20) +- expression 51 operands: lhs = Expression(55, Add), rhs = Counter(21) +- expression 52 operands: lhs = Counter(19), rhs = Counter(20) +- expression 53 operands: lhs = Counter(13), rhs = Expression(54, Add) +- expression 54 operands: lhs = Expression(55, Add), rhs = Counter(21) +- expression 55 operands: lhs = Counter(19), rhs = Counter(20) +- expression 56 operands: lhs = Expression(57, Add), rhs = Expression(60, Add) +- expression 57 operands: lhs = Expression(58, Add), rhs = Counter(10) +- expression 58 operands: lhs = Expression(59, Add), rhs = Counter(9) +- expression 59 operands: lhs = Counter(5), rhs = Counter(6) +- expression 60 operands: lhs = Expression(61, Add), rhs = Counter(13) +- expression 61 operands: lhs = Counter(7), rhs = Counter(12) +- expression 62 operands: lhs = Counter(14), rhs = Counter(15) +- expression 63 operands: lhs = Counter(12), rhs = Counter(13) +- expression 64 operands: lhs = Expression(75, Add), rhs = Counter(14) +- expression 65 operands: lhs = Counter(12), rhs = Counter(13) +- expression 66 operands: lhs = Counter(15), rhs = Counter(16) +- expression 67 operands: lhs = Counter(15), rhs = Expression(73, Add) +- expression 68 operands: lhs = Counter(16), rhs = Counter(17) +- expression 69 operands: lhs = Expression(73, Add), rhs = Counter(18) +- expression 70 operands: lhs = Counter(16), rhs = Counter(17) +- expression 71 operands: lhs = Counter(15), rhs = Expression(72, Add) +- expression 72 operands: lhs = Expression(73, Add), rhs = Counter(18) +- expression 73 operands: lhs = Counter(16), rhs = Counter(17) +- expression 74 operands: lhs = Expression(75, Add), rhs = Expression(76, Add) +- expression 75 operands: lhs = Counter(12), rhs = Counter(13) +- expression 76 operands: lhs = Counter(14), rhs = Counter(15) Number of file 0 mappings: 68 - Code(Counter(0)) at (prev + 3, 1) to (start + 2, 12) - Code(Counter(1)) at (prev + 2, 13) to (start + 2, 6) - Code(Zero) at (prev + 2, 5) to (start + 0, 6) - Code(Expression(0, Add)) at (prev + 3, 9) to (start + 0, 10) - = ((((c2 + c3) + c4) + c5) + c6) + = (c2 + c3) - Code(Counter(0)) at (prev + 0, 16) to (start + 0, 29) - Code(Counter(2)) at (prev + 1, 9) to (start + 1, 10) -- Code(Expression(4, Sub)) at (prev + 2, 15) to (start + 0, 28) +- Code(Expression(1, Sub)) at (prev + 2, 15) to (start + 0, 28) = (c0 - c2) -- Code(Counter(35)) at (prev + 1, 12) to (start + 0, 25) -- Code(Expression(5, Sub)) at (prev + 0, 29) to (start + 0, 42) - = (c35 - c3) -- Code(Expression(6, Sub)) at (prev + 0, 46) to (start + 0, 60) - = (c35 - (c3 + c4)) -- Code(Expression(11, Add)) at (prev + 0, 61) to (start + 2, 10) - = ((c3 + c4) + c5) -- Code(Counter(6)) at (prev + 2, 9) to (start + 0, 10) -- Code(Expression(10, Add)) at (prev + 1, 9) to (start + 1, 18) - = (((c3 + c4) + c5) + c6) -- Code(Expression(13, Sub)) at (prev + 3, 9) to (start + 0, 15) - = (c0 - (c2 + c35)) +- Code(Counter(3)) at (prev + 1, 12) to (start + 0, 25) +- Code(Expression(2, Sub)) at (prev + 0, 29) to (start + 0, 42) + = (c3 - c28) +- Code(Expression(3, Sub)) at (prev + 0, 46) to (start + 0, 60) + = (c3 - (c28 + c29)) +- Code(Expression(8, Add)) at (prev + 0, 61) to (start + 2, 10) + = ((c28 + c29) + c30) +- Code(Expression(7, Sub)) at (prev + 2, 9) to (start + 0, 10) + = (c3 - ((c28 + c29) + c30)) +- Code(Counter(3)) at (prev + 1, 9) to (start + 1, 18) +- Code(Expression(10, Sub)) at (prev + 3, 9) to (start + 0, 15) + = (c0 - (c2 + c3)) - Code(Expression(0, Add)) at (prev + 3, 9) to (start + 1, 12) - = ((((c2 + c3) + c4) + c5) + c6) -- Code(Counter(7)) at (prev + 1, 13) to (start + 2, 6) + = (c2 + c3) +- Code(Counter(4)) at (prev + 1, 13) to (start + 2, 6) - Code(Zero) at (prev + 2, 5) to (start + 0, 6) - Code(Expression(0, Add)) at (prev + 2, 8) to (start + 0, 21) - = ((((c2 + c3) + c4) + c5) + c6) -- Code(Counter(8)) at (prev + 0, 22) to (start + 2, 6) -- Code(Expression(15, Sub)) at (prev + 2, 15) to (start + 0, 28) - = (((((c2 + c3) + c4) + c5) + c6) - c8) -- Code(Expression(16, Sub)) at (prev + 1, 12) to (start + 0, 25) - = (((((c2 + c3) + c4) + c5) + c6) - (c8 + c34)) -- Code(Expression(18, Sub)) at (prev + 0, 29) to (start + 0, 42) - = (((((c2 + c3) + c4) + c5) + c6) - ((c8 + c9) + c34)) -- Code(Expression(21, Sub)) at (prev + 0, 46) to (start + 0, 60) - = (((((c2 + c3) + c4) + c5) + c6) - (((c8 + c9) + c10) + c34)) -- Code(Expression(28, Add)) at (prev + 0, 61) to (start + 2, 10) - = ((c9 + c10) + c11) -- Code(Counter(12)) at (prev + 2, 9) to (start + 0, 10) -- Code(Expression(27, Add)) at (prev + 1, 9) to (start + 0, 23) - = (((c9 + c10) + c11) + c12) -- Code(Counter(34)) at (prev + 2, 9) to (start + 0, 15) -- Code(Expression(115, Add)) at (prev + 3, 8) to (start + 0, 12) - = ((((c8 + c9) + c10) + c11) + c12) -- Code(Counter(13)) at (prev + 1, 13) to (start + 1, 16) -- Code(Counter(14)) at (prev + 1, 17) to (start + 2, 10) + = (c2 + c3) +- Code(Counter(5)) at (prev + 0, 22) to (start + 2, 6) +- Code(Expression(11, Sub)) at (prev + 2, 15) to (start + 0, 28) + = ((c2 + c3) - c5) +- Code(Counter(6)) at (prev + 1, 12) to (start + 0, 25) +- Code(Expression(12, Sub)) at (prev + 0, 29) to (start + 0, 42) + = (c6 - c25) +- Code(Expression(13, Sub)) at (prev + 0, 46) to (start + 0, 60) + = (c6 - (c25 + c26)) +- Code(Expression(18, Add)) at (prev + 0, 61) to (start + 2, 10) + = ((c25 + c26) + c27) +- Code(Expression(17, Sub)) at (prev + 2, 9) to (start + 0, 10) + = (c6 - ((c25 + c26) + c27)) +- Code(Counter(6)) at (prev + 1, 9) to (start + 0, 23) +- Code(Expression(20, Sub)) at (prev + 2, 9) to (start + 0, 15) + = ((c2 + c3) - (c5 + c6)) +- Code(Expression(59, Add)) at (prev + 3, 8) to (start + 0, 12) + = (c5 + c6) +- Code(Counter(7)) at (prev + 1, 13) to (start + 1, 16) +- Code(Counter(8)) at (prev + 1, 17) to (start + 2, 10) - Code(Zero) at (prev + 2, 9) to (start + 0, 10) -- Code(Counter(13)) at (prev + 2, 12) to (start + 0, 25) -- Code(Counter(15)) at (prev + 0, 26) to (start + 2, 10) -- Code(Expression(34, Sub)) at (prev + 4, 17) to (start + 0, 30) - = (c13 - c15) -- Code(Expression(35, Sub)) at (prev + 1, 16) to (start + 0, 29) - = (c13 - (c15 + c33)) -- Code(Expression(37, Sub)) at (prev + 0, 33) to (start + 0, 46) - = (c13 - ((c15 + c16) + c33)) -- Code(Expression(40, Sub)) at (prev + 0, 50) to (start + 0, 64) - = (c13 - (((c15 + c16) + c17) + c33)) -- Code(Expression(47, Add)) at (prev + 0, 65) to (start + 2, 14) - = ((c16 + c17) + c18) -- Code(Counter(19)) at (prev + 2, 13) to (start + 0, 14) -- Code(Expression(46, Add)) at (prev + 1, 13) to (start + 0, 27) - = (((c16 + c17) + c18) + c19) -- Code(Counter(33)) at (prev + 2, 13) to (start + 0, 19) +- Code(Counter(7)) at (prev + 2, 12) to (start + 0, 25) +- Code(Counter(9)) at (prev + 0, 26) to (start + 2, 10) +- Code(Expression(23, Sub)) at (prev + 4, 17) to (start + 0, 30) + = (c7 - c9) +- Code(Counter(10)) at (prev + 1, 16) to (start + 0, 29) +- Code(Expression(24, Sub)) at (prev + 0, 33) to (start + 0, 46) + = (c10 - c22) +- Code(Expression(25, Sub)) at (prev + 0, 50) to (start + 0, 64) + = (c10 - (c22 + c23)) +- Code(Expression(30, Add)) at (prev + 0, 65) to (start + 2, 14) + = ((c22 + c23) + c24) +- Code(Expression(29, Sub)) at (prev + 2, 13) to (start + 0, 14) + = (c10 - ((c22 + c23) + c24)) +- Code(Counter(10)) at (prev + 1, 13) to (start + 0, 27) +- Code(Expression(32, Sub)) at (prev + 2, 13) to (start + 0, 19) + = (c7 - (c9 + c10)) - Code(Zero) at (prev + 2, 5) to (start + 0, 6) -- Code(Expression(63, Sub)) at (prev + 2, 9) to (start + 1, 12) - = ((((((((((c8 + c9) + c10) + c11) + c12) + c15) + c16) + c17) + c18) + c19) - c13) -- Code(Counter(20)) at (prev + 1, 13) to (start + 2, 6) +- Code(Expression(39, Sub)) at (prev + 2, 9) to (start + 1, 12) + = ((((c5 + c6) + c9) + c10) - c7) +- Code(Counter(11)) at (prev + 1, 13) to (start + 2, 6) - Code(Zero) at (prev + 2, 5) to (start + 0, 6) -- Code(Expression(155, Add)) at (prev + 2, 9) to (start + 0, 10) - = ((((c21 + c22) + c23) + c24) + c25) -- Code(Expression(63, Sub)) at (prev + 0, 16) to (start + 0, 29) - = ((((((((((c8 + c9) + c10) + c11) + c12) + c15) + c16) + c17) + c18) + c19) - c13) -- Code(Counter(21)) at (prev + 0, 30) to (start + 2, 6) -- Code(Expression(73, Sub)) at (prev + 2, 15) to (start + 0, 28) - = ((((((((((c8 + c9) + c10) + c11) + c12) + c15) + c16) + c17) + c18) + c19) - (c13 + c21)) -- Code(Expression(84, Sub)) at (prev + 1, 12) to (start + 0, 25) - = ((((((((((c8 + c9) + c10) + c11) + c12) + c15) + c16) + c17) + c18) + c19) - ((c13 + c21) + c32)) -- Code(Expression(96, Sub)) at (prev + 0, 29) to (start + 0, 42) - = ((((((((((c8 + c9) + c10) + c11) + c12) + c15) + c16) + c17) + c18) + c19) - (((c13 + c21) + c22) + c32)) -- Code(Expression(109, Sub)) at (prev + 0, 46) to (start + 0, 60) - = ((((((((((c8 + c9) + c10) + c11) + c12) + c15) + c16) + c17) + c18) + c19) - ((((c13 + c21) + c22) + c23) + c32)) -- Code(Expression(126, Add)) at (prev + 0, 61) to (start + 2, 10) - = ((c22 + c23) + c24) -- Code(Counter(25)) at (prev + 2, 9) to (start + 0, 10) -- Code(Expression(125, Add)) at (prev + 1, 9) to (start + 0, 23) - = (((c22 + c23) + c24) + c25) -- Code(Counter(32)) at (prev + 2, 13) to (start + 2, 15) -- Code(Expression(128, Add)) at (prev + 5, 9) to (start + 0, 10) - = ((((c26 + c27) + c28) + c29) + c30) -- Code(Expression(155, Add)) at (prev + 0, 16) to (start + 0, 29) - = ((((c21 + c22) + c23) + c24) + c25) -- Code(Counter(26)) at (prev + 0, 30) to (start + 2, 6) -- Code(Expression(136, Sub)) at (prev + 2, 15) to (start + 0, 28) - = (((((c21 + c22) + c23) + c24) + c25) - c26) -- Code(Expression(141, Sub)) at (prev + 1, 12) to (start + 0, 25) - = (((((c21 + c22) + c23) + c24) + c25) - (c26 + c31)) -- Code(Expression(147, Sub)) at (prev + 0, 29) to (start + 0, 42) - = (((((c21 + c22) + c23) + c24) + c25) - ((c26 + c27) + c31)) -- Code(Expression(154, Sub)) at (prev + 0, 46) to (start + 0, 60) - = (((((c21 + c22) + c23) + c24) + c25) - (((c26 + c27) + c28) + c31)) -- Code(Expression(165, Add)) at (prev + 0, 61) to (start + 2, 10) - = ((c27 + c28) + c29) -- Code(Counter(30)) at (prev + 2, 9) to (start + 0, 10) -- Code(Expression(164, Add)) at (prev + 1, 9) to (start + 0, 23) - = (((c27 + c28) + c29) + c30) -- Code(Counter(31)) at (prev + 2, 9) to (start + 0, 15) -- Code(Expression(167, Sub)) at (prev + 2, 1) to (start + 0, 2) - = ((((((((((c0 + c26) + c27) + c28) + c29) + c30) + c31) + c32) + c33) + c34) - (c2 + c35)) -Highest counter ID seen: c35 +- Code(Expression(75, Add)) at (prev + 2, 9) to (start + 0, 10) + = (c12 + c13) +- Code(Expression(39, Sub)) at (prev + 0, 16) to (start + 0, 29) + = ((((c5 + c6) + c9) + c10) - c7) +- Code(Counter(12)) at (prev + 0, 30) to (start + 2, 6) +- Code(Expression(43, Sub)) at (prev + 2, 15) to (start + 0, 28) + = ((((c5 + c6) + c9) + c10) - (c7 + c12)) +- Code(Counter(13)) at (prev + 1, 12) to (start + 0, 25) +- Code(Expression(48, Sub)) at (prev + 0, 29) to (start + 0, 42) + = (c13 - c19) +- Code(Expression(49, Sub)) at (prev + 0, 46) to (start + 0, 60) + = (c13 - (c19 + c20)) +- Code(Expression(54, Add)) at (prev + 0, 61) to (start + 2, 10) + = ((c19 + c20) + c21) +- Code(Expression(53, Sub)) at (prev + 2, 9) to (start + 0, 10) + = (c13 - ((c19 + c20) + c21)) +- Code(Counter(13)) at (prev + 1, 9) to (start + 0, 23) +- Code(Expression(56, Sub)) at (prev + 2, 13) to (start + 2, 15) + = ((((c5 + c6) + c9) + c10) - ((c7 + c12) + c13)) +- Code(Expression(76, Add)) at (prev + 5, 9) to (start + 0, 10) + = (c14 + c15) +- Code(Expression(75, Add)) at (prev + 0, 16) to (start + 0, 29) + = (c12 + c13) +- Code(Counter(14)) at (prev + 0, 30) to (start + 2, 6) +- Code(Expression(64, Sub)) at (prev + 2, 15) to (start + 0, 28) + = ((c12 + c13) - c14) +- Code(Counter(15)) at (prev + 1, 12) to (start + 0, 25) +- Code(Expression(66, Sub)) at (prev + 0, 29) to (start + 0, 42) + = (c15 - c16) +- Code(Expression(67, Sub)) at (prev + 0, 46) to (start + 0, 60) + = (c15 - (c16 + c17)) +- Code(Expression(72, Add)) at (prev + 0, 61) to (start + 2, 10) + = ((c16 + c17) + c18) +- Code(Expression(71, Sub)) at (prev + 2, 9) to (start + 0, 10) + = (c15 - ((c16 + c17) + c18)) +- Code(Counter(15)) at (prev + 1, 9) to (start + 0, 23) +- Code(Expression(74, Sub)) at (prev + 2, 9) to (start + 0, 15) + = ((c12 + c13) - (c14 + c15)) +- Code(Counter(0)) at (prev + 2, 1) to (start + 0, 2) +Highest counter ID seen: c15 diff --git a/tests/coverage/continue.cov-map b/tests/coverage/continue.cov-map index 55313d7db49..eb968fbb747 100644 --- a/tests/coverage/continue.cov-map +++ b/tests/coverage/continue.cov-map @@ -1,5 +1,5 @@ Function name: continue::main -Raw bytes (210): 0x[01, 01, 1c, 07, 09, 01, 05, 03, 0d, 1f, 15, 0d, 11, 1b, 19, 1f, 15, 0d, 11, 33, 21, 19, 1d, 2f, 25, 33, 21, 19, 1d, 47, 2d, 25, 29, 43, 31, 47, 2d, 25, 29, 5b, 39, 31, 35, 57, 3d, 5b, 39, 31, 35, 35, 39, 3d, 41, 6b, 45, 3d, 41, 45, 49, 1e, 01, 03, 01, 03, 12, 03, 04, 0e, 00, 13, 0a, 01, 0f, 00, 16, 05, 02, 11, 00, 19, 09, 02, 12, 04, 0e, 1b, 06, 0e, 00, 13, 16, 01, 0f, 00, 16, 15, 01, 16, 02, 0e, 11, 04, 11, 00, 19, 15, 03, 09, 00, 0e, 2f, 02, 0e, 00, 13, 2a, 01, 0f, 00, 16, 1d, 01, 15, 02, 0e, 21, 04, 11, 00, 19, 1d, 03, 09, 00, 0e, 43, 02, 0e, 00, 13, 3e, 01, 0c, 00, 13, 29, 01, 0d, 00, 15, 2d, 01, 0a, 01, 0e, 57, 03, 0e, 00, 13, 52, 01, 0f, 00, 16, 39, 01, 16, 02, 0e, 35, 03, 12, 02, 0e, 5f, 04, 09, 00, 0e, 6b, 02, 0e, 00, 13, 66, 01, 0f, 00, 16, 41, 01, 16, 02, 0e, 49, 04, 11, 00, 16, 41, 03, 09, 00, 0e, 6f, 02, 0d, 01, 02] +Raw bytes (210): 0x[01, 01, 1c, 07, 09, 01, 05, 03, 0d, 1f, 15, 0d, 11, 1b, 19, 1f, 15, 0d, 11, 33, 21, 19, 1d, 2f, 25, 33, 21, 19, 1d, 47, 2d, 25, 29, 43, 31, 47, 2d, 25, 29, 5b, 39, 31, 35, 57, 3d, 5b, 39, 31, 35, 35, 39, 3d, 41, 6b, 45, 3d, 41, 3d, 45, 1e, 01, 03, 01, 03, 12, 03, 04, 0e, 00, 13, 0a, 01, 0f, 00, 16, 05, 02, 11, 00, 19, 09, 02, 12, 04, 0e, 1b, 06, 0e, 00, 13, 16, 01, 0f, 00, 16, 15, 01, 16, 02, 0e, 11, 04, 11, 00, 19, 15, 03, 09, 00, 0e, 2f, 02, 0e, 00, 13, 2a, 01, 0f, 00, 16, 1d, 01, 15, 02, 0e, 21, 04, 11, 00, 19, 1d, 03, 09, 00, 0e, 43, 02, 0e, 00, 13, 3e, 01, 0c, 00, 13, 29, 01, 0d, 00, 15, 2d, 01, 0a, 01, 0e, 57, 03, 0e, 00, 13, 52, 01, 0f, 00, 16, 39, 01, 16, 02, 0e, 35, 03, 12, 02, 0e, 5f, 04, 09, 00, 0e, 6b, 02, 0e, 00, 13, 66, 01, 0f, 00, 16, 41, 01, 16, 02, 0e, 6e, 04, 11, 00, 16, 41, 03, 09, 00, 0e, 3d, 02, 0d, 01, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 28 @@ -30,7 +30,7 @@ Number of expressions: 28 - expression 24 operands: lhs = Counter(15), rhs = Counter(16) - expression 25 operands: lhs = Expression(26, Add), rhs = Counter(17) - expression 26 operands: lhs = Counter(15), rhs = Counter(16) -- expression 27 operands: lhs = Counter(17), rhs = Counter(18) +- expression 27 operands: lhs = Counter(15), rhs = Counter(17) Number of file 0 mappings: 30 - Code(Counter(0)) at (prev + 3, 1) to (start + 3, 18) - Code(Expression(0, Add)) at (prev + 4, 14) to (start + 0, 19) @@ -72,9 +72,9 @@ Number of file 0 mappings: 30 - Code(Expression(25, Sub)) at (prev + 1, 15) to (start + 0, 22) = ((c15 + c16) - c17) - Code(Counter(16)) at (prev + 1, 22) to (start + 2, 14) -- Code(Counter(18)) at (prev + 4, 17) to (start + 0, 22) +- Code(Expression(27, Sub)) at (prev + 4, 17) to (start + 0, 22) + = (c15 - c17) - Code(Counter(16)) at (prev + 3, 9) to (start + 0, 14) -- Code(Expression(27, Add)) at (prev + 2, 13) to (start + 1, 2) - = (c17 + c18) -Highest counter ID seen: c18 +- Code(Counter(15)) at (prev + 2, 13) to (start + 1, 2) +Highest counter ID seen: c16 diff --git a/tests/coverage/coroutine.cov-map b/tests/coverage/coroutine.cov-map index 21f6787e9f2..7457a528a86 100644 --- a/tests/coverage/coroutine.cov-map +++ b/tests/coverage/coroutine.cov-map @@ -13,18 +13,14 @@ Number of file 0 mappings: 4 Highest counter ID seen: c1 Function name: coroutine::main -Raw bytes (65): 0x[01, 01, 08, 07, 0d, 05, 09, 11, 15, 11, 1f, 15, 19, 15, 19, 11, 1f, 15, 19, 09, 01, 13, 01, 02, 16, 01, 08, 0b, 00, 2e, 11, 01, 2b, 00, 2d, 03, 01, 0e, 00, 35, 11, 02, 0b, 00, 2e, 0a, 01, 22, 00, 27, 1a, 00, 2c, 00, 2e, 1f, 01, 0e, 00, 35, 1a, 02, 01, 00, 02] +Raw bytes (57): 0x[01, 01, 04, 07, 0d, 05, 09, 11, 19, 11, 15, 09, 01, 13, 01, 02, 16, 01, 08, 0b, 00, 2e, 11, 01, 2b, 00, 2d, 03, 01, 0e, 00, 35, 11, 02, 0b, 00, 2e, 0a, 01, 22, 00, 27, 15, 00, 2c, 00, 2e, 0e, 01, 0e, 00, 35, 15, 02, 01, 00, 02] Number of files: 1 - file 0 => global file 1 -Number of expressions: 8 +Number of expressions: 4 - expression 0 operands: lhs = Expression(1, Add), rhs = Counter(3) - expression 1 operands: lhs = Counter(1), rhs = Counter(2) -- expression 2 operands: lhs = Counter(4), rhs = Counter(5) -- expression 3 operands: lhs = Counter(4), rhs = Expression(7, Add) -- expression 4 operands: lhs = Counter(5), rhs = Counter(6) -- expression 5 operands: lhs = Counter(5), rhs = Counter(6) -- expression 6 operands: lhs = Counter(4), rhs = Expression(7, Add) -- expression 7 operands: lhs = Counter(5), rhs = Counter(6) +- expression 2 operands: lhs = Counter(4), rhs = Counter(6) +- expression 3 operands: lhs = Counter(4), rhs = Counter(5) Number of file 0 mappings: 9 - Code(Counter(0)) at (prev + 19, 1) to (start + 2, 22) - Code(Counter(0)) at (prev + 8, 11) to (start + 0, 46) @@ -33,14 +29,12 @@ Number of file 0 mappings: 9 = ((c1 + c2) + c3) - Code(Counter(4)) at (prev + 2, 11) to (start + 0, 46) - Code(Expression(2, Sub)) at (prev + 1, 34) to (start + 0, 39) + = (c4 - c6) +- Code(Counter(5)) at (prev + 0, 44) to (start + 0, 46) +- Code(Expression(3, Sub)) at (prev + 1, 14) to (start + 0, 53) = (c4 - c5) -- Code(Expression(6, Sub)) at (prev + 0, 44) to (start + 0, 46) - = (c4 - (c5 + c6)) -- Code(Expression(7, Add)) at (prev + 1, 14) to (start + 0, 53) - = (c5 + c6) -- Code(Expression(6, Sub)) at (prev + 2, 1) to (start + 0, 2) - = (c4 - (c5 + c6)) -Highest counter ID seen: c4 +- Code(Counter(5)) at (prev + 2, 1) to (start + 0, 2) +Highest counter ID seen: c5 Function name: coroutine::main::{closure#0} Raw bytes (14): 0x[01, 01, 00, 02, 01, 16, 08, 01, 1f, 05, 02, 10, 01, 06] diff --git a/tests/coverage/inline.cov-map b/tests/coverage/inline.cov-map index 1b5b45695dc..39ba2b2d99b 100644 --- a/tests/coverage/inline.cov-map +++ b/tests/coverage/inline.cov-map @@ -41,7 +41,7 @@ Number of file 0 mappings: 1 Highest counter ID seen: c0 Function name: inline::permutate::<char> -Raw bytes (54): 0x[01, 01, 05, 01, 05, 01, 0b, 05, 0d, 13, 0d, 05, 09, 08, 01, 0f, 01, 02, 0e, 05, 02, 0f, 02, 06, 02, 02, 0f, 00, 14, 11, 01, 0d, 00, 0e, 06, 00, 12, 00, 16, 11, 00, 17, 04, 0a, 0d, 05, 0c, 02, 06, 0f, 03, 01, 00, 02] +Raw bytes (54): 0x[01, 01, 05, 01, 05, 01, 0b, 05, 0d, 13, 0d, 01, 09, 08, 01, 0f, 01, 02, 0e, 05, 02, 0f, 02, 06, 02, 02, 0f, 00, 14, 11, 01, 0d, 00, 0e, 0d, 00, 12, 00, 16, 11, 00, 17, 04, 0a, 06, 05, 0c, 02, 06, 0e, 03, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 5 @@ -49,19 +49,19 @@ Number of expressions: 5 - expression 1 operands: lhs = Counter(0), rhs = Expression(2, Add) - expression 2 operands: lhs = Counter(1), rhs = Counter(3) - expression 3 operands: lhs = Expression(4, Add), rhs = Counter(3) -- expression 4 operands: lhs = Counter(1), rhs = Counter(2) +- expression 4 operands: lhs = Counter(0), rhs = Counter(2) Number of file 0 mappings: 8 - Code(Counter(0)) at (prev + 15, 1) to (start + 2, 14) - Code(Counter(1)) at (prev + 2, 15) to (start + 2, 6) - Code(Expression(0, Sub)) at (prev + 2, 15) to (start + 0, 20) = (c0 - c1) - Code(Counter(4)) at (prev + 1, 13) to (start + 0, 14) -- Code(Expression(1, Sub)) at (prev + 0, 18) to (start + 0, 22) - = (c0 - (c1 + c3)) +- Code(Counter(3)) at (prev + 0, 18) to (start + 0, 22) - Code(Counter(4)) at (prev + 0, 23) to (start + 4, 10) -- Code(Counter(3)) at (prev + 5, 12) to (start + 2, 6) -- Code(Expression(3, Add)) at (prev + 3, 1) to (start + 0, 2) - = ((c1 + c2) + c3) +- Code(Expression(1, Sub)) at (prev + 5, 12) to (start + 2, 6) + = (c0 - (c1 + c3)) +- Code(Expression(3, Sub)) at (prev + 3, 1) to (start + 0, 2) + = ((c0 + c2) - c3) Highest counter ID seen: c4 Function name: inline::permutations::<char> diff --git a/tests/coverage/loops_branches.cov-map b/tests/coverage/loops_branches.cov-map index 14707701d8a..0279a1a5157 100644 --- a/tests/coverage/loops_branches.cov-map +++ b/tests/coverage/loops_branches.cov-map @@ -1,42 +1,32 @@ Function name: <loops_branches::DebugTest as core::fmt::Debug>::fmt -Raw bytes (174): 0x[01, 01, 22, 05, 00, 2f, 7b, 67, 00, 77, 19, 01, 15, 05, 21, 2f, 05, 67, 00, 77, 19, 01, 15, 2f, 7b, 67, 00, 77, 19, 01, 15, 05, 21, 67, 7b, 77, 19, 01, 15, 05, 21, 67, 5b, 77, 19, 01, 15, 7b, 00, 05, 21, 67, 7b, 77, 19, 01, 15, 05, 21, 77, 7b, 01, 15, 05, 21, 83, 01, 05, 87, 01, 15, 01, 11, 14, 01, 09, 05, 01, 10, 05, 02, 10, 00, 15, 00, 01, 17, 00, 1b, 00, 00, 1c, 00, 1e, 02, 01, 0d, 00, 0e, 05, 01, 0d, 00, 1e, 11, 00, 1e, 00, 1f, 00, 01, 10, 01, 0a, 2a, 03, 0d, 00, 0e, 1a, 00, 12, 00, 17, 2a, 01, 10, 00, 14, 62, 01, 14, 00, 19, 00, 01, 1b, 00, 1f, 00, 00, 20, 00, 22, 4e, 01, 11, 00, 12, 62, 01, 11, 00, 22, 72, 00, 22, 00, 23, 00, 01, 14, 01, 0e, 21, 03, 09, 00, 0f, 7e, 01, 05, 00, 06] +Raw bytes (152): 0x[01, 01, 18, 05, 00, 27, 57, 53, 00, 01, 1d, 11, 19, 27, 11, 53, 00, 01, 1d, 27, 57, 53, 00, 01, 1d, 11, 19, 53, 57, 01, 1d, 11, 19, 53, 47, 01, 1d, 57, 00, 11, 19, 53, 57, 01, 1d, 11, 19, 5f, 19, 11, 15, 14, 01, 09, 05, 01, 10, 05, 02, 10, 00, 15, 00, 01, 17, 00, 1b, 00, 00, 1c, 00, 1e, 02, 01, 0d, 00, 0e, 05, 01, 0d, 00, 1e, 11, 00, 1e, 00, 1f, 00, 01, 10, 01, 0a, 22, 03, 0d, 00, 0e, 16, 00, 12, 00, 17, 22, 01, 10, 00, 14, 4e, 01, 14, 00, 19, 00, 01, 1b, 00, 1f, 00, 00, 20, 00, 22, 3e, 01, 11, 00, 12, 4e, 01, 11, 00, 22, 15, 00, 22, 00, 23, 00, 01, 14, 01, 0e, 19, 03, 09, 00, 0f, 5b, 01, 05, 00, 06] Number of files: 1 - file 0 => global file 1 -Number of expressions: 34 +Number of expressions: 24 - expression 0 operands: lhs = Counter(1), rhs = Zero -- expression 1 operands: lhs = Expression(11, Add), rhs = Expression(30, Add) -- expression 2 operands: lhs = Expression(25, Add), rhs = Zero -- expression 3 operands: lhs = Expression(29, Add), rhs = Counter(6) -- expression 4 operands: lhs = Counter(0), rhs = Counter(5) -- expression 5 operands: lhs = Counter(1), rhs = Counter(8) -- expression 6 operands: lhs = Expression(11, Add), rhs = Counter(1) -- expression 7 operands: lhs = Expression(25, Add), rhs = Zero -- expression 8 operands: lhs = Expression(29, Add), rhs = Counter(6) -- expression 9 operands: lhs = Counter(0), rhs = Counter(5) -- expression 10 operands: lhs = Expression(11, Add), rhs = Expression(30, Add) -- expression 11 operands: lhs = Expression(25, Add), rhs = Zero -- expression 12 operands: lhs = Expression(29, Add), rhs = Counter(6) -- expression 13 operands: lhs = Counter(0), rhs = Counter(5) -- expression 14 operands: lhs = Counter(1), rhs = Counter(8) -- expression 15 operands: lhs = Expression(25, Add), rhs = Expression(30, Add) -- expression 16 operands: lhs = Expression(29, Add), rhs = Counter(6) -- expression 17 operands: lhs = Counter(0), rhs = Counter(5) -- expression 18 operands: lhs = Counter(1), rhs = Counter(8) -- expression 19 operands: lhs = Expression(25, Add), rhs = Expression(22, Add) -- expression 20 operands: lhs = Expression(29, Add), rhs = Counter(6) -- expression 21 operands: lhs = Counter(0), rhs = Counter(5) -- expression 22 operands: lhs = Expression(30, Add), rhs = Zero -- expression 23 operands: lhs = Counter(1), rhs = Counter(8) -- expression 24 operands: lhs = Expression(25, Add), rhs = Expression(30, Add) -- expression 25 operands: lhs = Expression(29, Add), rhs = Counter(6) -- expression 26 operands: lhs = Counter(0), rhs = Counter(5) -- expression 27 operands: lhs = Counter(1), rhs = Counter(8) -- expression 28 operands: lhs = Expression(29, Add), rhs = Expression(30, Add) -- expression 29 operands: lhs = Counter(0), rhs = Counter(5) -- expression 30 operands: lhs = Counter(1), rhs = Counter(8) -- expression 31 operands: lhs = Expression(32, Add), rhs = Counter(1) -- expression 32 operands: lhs = Expression(33, Add), rhs = Counter(5) -- expression 33 operands: lhs = Counter(0), rhs = Counter(4) +- expression 1 operands: lhs = Expression(9, Add), rhs = Expression(21, Add) +- expression 2 operands: lhs = Expression(20, Add), rhs = Zero +- expression 3 operands: lhs = Counter(0), rhs = Counter(7) +- expression 4 operands: lhs = Counter(4), rhs = Counter(6) +- expression 5 operands: lhs = Expression(9, Add), rhs = Counter(4) +- expression 6 operands: lhs = Expression(20, Add), rhs = Zero +- expression 7 operands: lhs = Counter(0), rhs = Counter(7) +- expression 8 operands: lhs = Expression(9, Add), rhs = Expression(21, Add) +- expression 9 operands: lhs = Expression(20, Add), rhs = Zero +- expression 10 operands: lhs = Counter(0), rhs = Counter(7) +- expression 11 operands: lhs = Counter(4), rhs = Counter(6) +- expression 12 operands: lhs = Expression(20, Add), rhs = Expression(21, Add) +- expression 13 operands: lhs = Counter(0), rhs = Counter(7) +- expression 14 operands: lhs = Counter(4), rhs = Counter(6) +- expression 15 operands: lhs = Expression(20, Add), rhs = Expression(17, Add) +- expression 16 operands: lhs = Counter(0), rhs = Counter(7) +- expression 17 operands: lhs = Expression(21, Add), rhs = Zero +- expression 18 operands: lhs = Counter(4), rhs = Counter(6) +- expression 19 operands: lhs = Expression(20, Add), rhs = Expression(21, Add) +- expression 20 operands: lhs = Counter(0), rhs = Counter(7) +- expression 21 operands: lhs = Counter(4), rhs = Counter(6) +- expression 22 operands: lhs = Expression(23, Add), rhs = Counter(6) +- expression 23 operands: lhs = Counter(4), rhs = Counter(5) Number of file 0 mappings: 20 - Code(Counter(0)) at (prev + 9, 5) to (start + 1, 16) - Code(Counter(1)) at (prev + 2, 16) to (start + 0, 21) @@ -47,57 +37,57 @@ Number of file 0 mappings: 20 - Code(Counter(1)) at (prev + 1, 13) to (start + 0, 30) - Code(Counter(4)) at (prev + 0, 30) to (start + 0, 31) - Code(Zero) at (prev + 1, 16) to (start + 1, 10) -- Code(Expression(10, Sub)) at (prev + 3, 13) to (start + 0, 14) - = ((((c0 + c5) + c6) + Zero) - (c1 + c8)) -- Code(Expression(6, Sub)) at (prev + 0, 18) to (start + 0, 23) - = ((((c0 + c5) + c6) + Zero) - c1) -- Code(Expression(10, Sub)) at (prev + 1, 16) to (start + 0, 20) - = ((((c0 + c5) + c6) + Zero) - (c1 + c8)) -- Code(Expression(24, Sub)) at (prev + 1, 20) to (start + 0, 25) - = (((c0 + c5) + c6) - (c1 + c8)) +- Code(Expression(8, Sub)) at (prev + 3, 13) to (start + 0, 14) + = (((c0 + c7) + Zero) - (c4 + c6)) +- Code(Expression(5, Sub)) at (prev + 0, 18) to (start + 0, 23) + = (((c0 + c7) + Zero) - c4) +- Code(Expression(8, Sub)) at (prev + 1, 16) to (start + 0, 20) + = (((c0 + c7) + Zero) - (c4 + c6)) +- Code(Expression(19, Sub)) at (prev + 1, 20) to (start + 0, 25) + = ((c0 + c7) - (c4 + c6)) - Code(Zero) at (prev + 1, 27) to (start + 0, 31) - Code(Zero) at (prev + 0, 32) to (start + 0, 34) -- Code(Expression(19, Sub)) at (prev + 1, 17) to (start + 0, 18) - = (((c0 + c5) + c6) - ((c1 + c8) + Zero)) -- Code(Expression(24, Sub)) at (prev + 1, 17) to (start + 0, 34) - = (((c0 + c5) + c6) - (c1 + c8)) -- Code(Expression(28, Sub)) at (prev + 0, 34) to (start + 0, 35) - = ((c0 + c5) - (c1 + c8)) +- Code(Expression(15, Sub)) at (prev + 1, 17) to (start + 0, 18) + = ((c0 + c7) - ((c4 + c6) + Zero)) +- Code(Expression(19, Sub)) at (prev + 1, 17) to (start + 0, 34) + = ((c0 + c7) - (c4 + c6)) +- Code(Counter(5)) at (prev + 0, 34) to (start + 0, 35) - Code(Zero) at (prev + 1, 20) to (start + 1, 14) -- Code(Counter(8)) at (prev + 3, 9) to (start + 0, 15) -- Code(Expression(31, Sub)) at (prev + 1, 5) to (start + 0, 6) - = (((c0 + c4) + c5) - c1) -Highest counter ID seen: c8 +- Code(Counter(6)) at (prev + 3, 9) to (start + 0, 15) +- Code(Expression(22, Add)) at (prev + 1, 5) to (start + 0, 6) + = ((c4 + c5) + c6) +Highest counter ID seen: c6 Function name: <loops_branches::DisplayTest as core::fmt::Display>::fmt -Raw bytes (152): 0x[01, 01, 18, 01, 00, 01, 00, 23, 15, 27, 11, 00, 0d, 27, 11, 00, 0d, 23, 15, 27, 11, 00, 0d, 4b, 15, 4f, 11, 00, 0d, 4b, 43, 4f, 11, 00, 0d, 15, 00, 4b, 15, 4f, 11, 00, 0d, 5f, 15, 00, 11, 5f, 21, 00, 11, 14, 01, 22, 05, 01, 11, 00, 01, 12, 01, 0a, 02, 02, 10, 00, 15, 00, 01, 17, 00, 1b, 00, 00, 1c, 00, 1e, 06, 01, 0d, 00, 0e, 02, 01, 0d, 00, 1e, 21, 00, 1e, 00, 1f, 1e, 02, 0d, 00, 0e, 23, 00, 12, 00, 17, 1e, 01, 10, 00, 15, 00, 00, 16, 01, 0e, 46, 02, 14, 00, 19, 00, 01, 1b, 00, 1f, 00, 00, 20, 00, 22, 36, 01, 11, 00, 12, 46, 01, 11, 00, 22, 52, 00, 22, 00, 23, 15, 03, 09, 00, 0f, 5b, 01, 05, 00, 06] +Raw bytes (154): 0x[01, 01, 19, 01, 00, 01, 00, 2b, 63, 2f, 0d, 01, 00, 11, 15, 2b, 11, 2f, 0d, 01, 00, 2b, 63, 2f, 0d, 01, 00, 11, 15, 57, 63, 01, 0d, 11, 15, 57, 4b, 01, 0d, 63, 00, 11, 15, 57, 63, 01, 0d, 11, 15, 63, 21, 11, 15, 14, 01, 22, 05, 01, 11, 00, 01, 12, 01, 0a, 02, 02, 10, 00, 15, 00, 01, 17, 00, 1b, 00, 00, 1c, 00, 1e, 06, 01, 0d, 00, 0e, 02, 01, 0d, 00, 1e, 11, 00, 1e, 00, 1f, 26, 02, 0d, 00, 0e, 1a, 00, 12, 00, 17, 26, 01, 10, 00, 15, 00, 00, 16, 01, 0e, 52, 02, 14, 00, 19, 00, 01, 1b, 00, 1f, 00, 00, 20, 00, 22, 42, 01, 11, 00, 12, 52, 01, 11, 00, 22, 21, 00, 22, 00, 23, 15, 03, 09, 00, 0f, 5f, 01, 05, 00, 06] Number of files: 1 - file 0 => global file 1 -Number of expressions: 24 +Number of expressions: 25 - expression 0 operands: lhs = Counter(0), rhs = Zero - expression 1 operands: lhs = Counter(0), rhs = Zero -- expression 2 operands: lhs = Expression(8, Add), rhs = Counter(5) -- expression 3 operands: lhs = Expression(9, Add), rhs = Counter(4) -- expression 4 operands: lhs = Zero, rhs = Counter(3) -- expression 5 operands: lhs = Expression(9, Add), rhs = Counter(4) -- expression 6 operands: lhs = Zero, rhs = Counter(3) -- expression 7 operands: lhs = Expression(8, Add), rhs = Counter(5) -- expression 8 operands: lhs = Expression(9, Add), rhs = Counter(4) -- expression 9 operands: lhs = Zero, rhs = Counter(3) -- expression 10 operands: lhs = Expression(18, Add), rhs = Counter(5) -- expression 11 operands: lhs = Expression(19, Add), rhs = Counter(4) -- expression 12 operands: lhs = Zero, rhs = Counter(3) -- expression 13 operands: lhs = Expression(18, Add), rhs = Expression(16, Add) -- expression 14 operands: lhs = Expression(19, Add), rhs = Counter(4) -- expression 15 operands: lhs = Zero, rhs = Counter(3) -- expression 16 operands: lhs = Counter(5), rhs = Zero -- expression 17 operands: lhs = Expression(18, Add), rhs = Counter(5) -- expression 18 operands: lhs = Expression(19, Add), rhs = Counter(4) -- expression 19 operands: lhs = Zero, rhs = Counter(3) -- expression 20 operands: lhs = Expression(23, Add), rhs = Counter(5) -- expression 21 operands: lhs = Zero, rhs = Counter(4) -- expression 22 operands: lhs = Expression(23, Add), rhs = Counter(8) -- expression 23 operands: lhs = Zero, rhs = Counter(4) +- expression 2 operands: lhs = Expression(10, Add), rhs = Expression(24, Add) +- expression 3 operands: lhs = Expression(11, Add), rhs = Counter(3) +- expression 4 operands: lhs = Counter(0), rhs = Zero +- expression 5 operands: lhs = Counter(4), rhs = Counter(5) +- expression 6 operands: lhs = Expression(10, Add), rhs = Counter(4) +- expression 7 operands: lhs = Expression(11, Add), rhs = Counter(3) +- expression 8 operands: lhs = Counter(0), rhs = Zero +- expression 9 operands: lhs = Expression(10, Add), rhs = Expression(24, Add) +- expression 10 operands: lhs = Expression(11, Add), rhs = Counter(3) +- expression 11 operands: lhs = Counter(0), rhs = Zero +- expression 12 operands: lhs = Counter(4), rhs = Counter(5) +- expression 13 operands: lhs = Expression(21, Add), rhs = Expression(24, Add) +- expression 14 operands: lhs = Counter(0), rhs = Counter(3) +- expression 15 operands: lhs = Counter(4), rhs = Counter(5) +- expression 16 operands: lhs = Expression(21, Add), rhs = Expression(18, Add) +- expression 17 operands: lhs = Counter(0), rhs = Counter(3) +- expression 18 operands: lhs = Expression(24, Add), rhs = Zero +- expression 19 operands: lhs = Counter(4), rhs = Counter(5) +- expression 20 operands: lhs = Expression(21, Add), rhs = Expression(24, Add) +- expression 21 operands: lhs = Counter(0), rhs = Counter(3) +- expression 22 operands: lhs = Counter(4), rhs = Counter(5) +- expression 23 operands: lhs = Expression(24, Add), rhs = Counter(8) +- expression 24 operands: lhs = Counter(4), rhs = Counter(5) Number of file 0 mappings: 20 - Code(Counter(0)) at (prev + 34, 5) to (start + 1, 17) - Code(Zero) at (prev + 1, 18) to (start + 1, 10) @@ -109,27 +99,26 @@ Number of file 0 mappings: 20 = (c0 - Zero) - Code(Expression(0, Sub)) at (prev + 1, 13) to (start + 0, 30) = (c0 - Zero) -- Code(Counter(8)) at (prev + 0, 30) to (start + 0, 31) -- Code(Expression(7, Sub)) at (prev + 2, 13) to (start + 0, 14) - = (((Zero + c3) + c4) - c5) -- Code(Expression(8, Add)) at (prev + 0, 18) to (start + 0, 23) - = ((Zero + c3) + c4) -- Code(Expression(7, Sub)) at (prev + 1, 16) to (start + 0, 21) - = (((Zero + c3) + c4) - c5) +- Code(Counter(4)) at (prev + 0, 30) to (start + 0, 31) +- Code(Expression(9, Sub)) at (prev + 2, 13) to (start + 0, 14) + = (((c0 + Zero) + c3) - (c4 + c5)) +- Code(Expression(6, Sub)) at (prev + 0, 18) to (start + 0, 23) + = (((c0 + Zero) + c3) - c4) +- Code(Expression(9, Sub)) at (prev + 1, 16) to (start + 0, 21) + = (((c0 + Zero) + c3) - (c4 + c5)) - Code(Zero) at (prev + 0, 22) to (start + 1, 14) -- Code(Expression(17, Sub)) at (prev + 2, 20) to (start + 0, 25) - = (((Zero + c3) + c4) - c5) +- Code(Expression(20, Sub)) at (prev + 2, 20) to (start + 0, 25) + = ((c0 + c3) - (c4 + c5)) - Code(Zero) at (prev + 1, 27) to (start + 0, 31) - Code(Zero) at (prev + 0, 32) to (start + 0, 34) -- Code(Expression(13, Sub)) at (prev + 1, 17) to (start + 0, 18) - = (((Zero + c3) + c4) - (c5 + Zero)) -- Code(Expression(17, Sub)) at (prev + 1, 17) to (start + 0, 34) - = (((Zero + c3) + c4) - c5) -- Code(Expression(20, Sub)) at (prev + 0, 34) to (start + 0, 35) - = ((Zero + c4) - c5) +- Code(Expression(16, Sub)) at (prev + 1, 17) to (start + 0, 18) + = ((c0 + c3) - ((c4 + c5) + Zero)) +- Code(Expression(20, Sub)) at (prev + 1, 17) to (start + 0, 34) + = ((c0 + c3) - (c4 + c5)) +- Code(Counter(8)) at (prev + 0, 34) to (start + 0, 35) - Code(Counter(5)) at (prev + 3, 9) to (start + 0, 15) -- Code(Expression(22, Add)) at (prev + 1, 5) to (start + 0, 6) - = ((Zero + c4) + c8) +- Code(Expression(23, Add)) at (prev + 1, 5) to (start + 0, 6) + = ((c4 + c5) + c8) Highest counter ID seen: c8 Function name: loops_branches::main diff --git a/tests/coverage/mcdc/condition-limit.cov-map b/tests/coverage/mcdc/condition-limit.cov-map index 19716878600..8ff5d6360f6 100644 --- a/tests/coverage/mcdc/condition-limit.cov-map +++ b/tests/coverage/mcdc/condition-limit.cov-map @@ -1,54 +1,16 @@ Function name: condition_limit::accept_7_conditions -Raw bytes (237): 0x[01, 01, 2e, 01, 05, 05, 09, 05, 09, 05, 7b, 09, 0d, 05, 7b, 09, 0d, 05, 77, 7b, 11, 09, 0d, 05, 77, 7b, 11, 09, 0d, 05, 73, 77, 15, 7b, 11, 09, 0d, 05, 73, 77, 15, 7b, 11, 09, 0d, 05, 6f, 73, 19, 77, 15, 7b, 11, 09, 0d, 05, 6f, 73, 19, 77, 15, 7b, 11, 09, 0d, 83, 01, 05, a7, 01, 21, ab, 01, 19, af, 01, 15, b3, 01, 11, b7, 01, 0d, 01, 09, 9f, 01, 05, a3, 01, 21, a7, 01, 1d, ab, 01, 19, af, 01, 15, b3, 01, 11, b7, 01, 0d, 01, 09, 12, 01, 07, 01, 02, 09, 28, 08, 07, 02, 08, 00, 27, 30, 05, 02, 01, 07, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 0a, 09, 07, 06, 00, 00, 0d, 00, 0e, 0a, 00, 12, 00, 13, 30, 16, 0d, 06, 05, 00, 00, 12, 00, 13, 16, 00, 17, 00, 18, 30, 2a, 11, 05, 04, 00, 00, 17, 00, 18, 2a, 00, 1c, 00, 1d, 30, 46, 15, 04, 03, 00, 00, 1c, 00, 1d, 46, 00, 21, 00, 22, 30, 6a, 19, 03, 02, 00, 00, 21, 00, 22, 6a, 00, 26, 00, 27, 30, 1d, 21, 02, 00, 00, 00, 26, 00, 27, 1d, 00, 28, 02, 06, 7e, 02, 05, 00, 06, 9a, 01, 01, 01, 00, 02] +Raw bytes (147): 0x[01, 01, 08, 01, 05, 05, 09, 09, 0d, 0d, 11, 11, 15, 15, 19, 19, 1d, 01, 1d, 12, 01, 07, 01, 02, 09, 28, 08, 07, 02, 08, 00, 27, 30, 05, 02, 01, 07, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 09, 06, 07, 06, 00, 00, 0d, 00, 0e, 09, 00, 12, 00, 13, 30, 0d, 0a, 06, 05, 00, 00, 12, 00, 13, 0d, 00, 17, 00, 18, 30, 11, 0e, 05, 04, 00, 00, 17, 00, 18, 11, 00, 1c, 00, 1d, 30, 15, 12, 04, 03, 00, 00, 1c, 00, 1d, 15, 00, 21, 00, 22, 30, 19, 16, 03, 02, 00, 00, 21, 00, 22, 19, 00, 26, 00, 27, 30, 1d, 1a, 02, 00, 00, 00, 26, 00, 27, 1d, 00, 28, 02, 06, 1e, 02, 05, 00, 06, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 -Number of expressions: 46 +Number of expressions: 8 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Counter(2) -- expression 2 operands: lhs = Counter(1), rhs = Counter(2) -- expression 3 operands: lhs = Counter(1), rhs = Expression(30, Add) -- expression 4 operands: lhs = Counter(2), rhs = Counter(3) -- expression 5 operands: lhs = Counter(1), rhs = Expression(30, Add) -- expression 6 operands: lhs = Counter(2), rhs = Counter(3) -- expression 7 operands: lhs = Counter(1), rhs = Expression(29, Add) -- expression 8 operands: lhs = Expression(30, Add), rhs = Counter(4) -- expression 9 operands: lhs = Counter(2), rhs = Counter(3) -- expression 10 operands: lhs = Counter(1), rhs = Expression(29, Add) -- expression 11 operands: lhs = Expression(30, Add), rhs = Counter(4) -- expression 12 operands: lhs = Counter(2), rhs = Counter(3) -- expression 13 operands: lhs = Counter(1), rhs = Expression(28, Add) -- expression 14 operands: lhs = Expression(29, Add), rhs = Counter(5) -- expression 15 operands: lhs = Expression(30, Add), rhs = Counter(4) -- expression 16 operands: lhs = Counter(2), rhs = Counter(3) -- expression 17 operands: lhs = Counter(1), rhs = Expression(28, Add) -- expression 18 operands: lhs = Expression(29, Add), rhs = Counter(5) -- expression 19 operands: lhs = Expression(30, Add), rhs = Counter(4) -- expression 20 operands: lhs = Counter(2), rhs = Counter(3) -- expression 21 operands: lhs = Counter(1), rhs = Expression(27, Add) -- expression 22 operands: lhs = Expression(28, Add), rhs = Counter(6) -- expression 23 operands: lhs = Expression(29, Add), rhs = Counter(5) -- expression 24 operands: lhs = Expression(30, Add), rhs = Counter(4) -- expression 25 operands: lhs = Counter(2), rhs = Counter(3) -- expression 26 operands: lhs = Counter(1), rhs = Expression(27, Add) -- expression 27 operands: lhs = Expression(28, Add), rhs = Counter(6) -- expression 28 operands: lhs = Expression(29, Add), rhs = Counter(5) -- expression 29 operands: lhs = Expression(30, Add), rhs = Counter(4) -- expression 30 operands: lhs = Counter(2), rhs = Counter(3) -- expression 31 operands: lhs = Expression(32, Add), rhs = Counter(1) -- expression 32 operands: lhs = Expression(41, Add), rhs = Counter(8) -- expression 33 operands: lhs = Expression(42, Add), rhs = Counter(6) -- expression 34 operands: lhs = Expression(43, Add), rhs = Counter(5) -- expression 35 operands: lhs = Expression(44, Add), rhs = Counter(4) -- expression 36 operands: lhs = Expression(45, Add), rhs = Counter(3) -- expression 37 operands: lhs = Counter(0), rhs = Counter(2) -- expression 38 operands: lhs = Expression(39, Add), rhs = Counter(1) -- expression 39 operands: lhs = Expression(40, Add), rhs = Counter(8) -- expression 40 operands: lhs = Expression(41, Add), rhs = Counter(7) -- expression 41 operands: lhs = Expression(42, Add), rhs = Counter(6) -- expression 42 operands: lhs = Expression(43, Add), rhs = Counter(5) -- expression 43 operands: lhs = Expression(44, Add), rhs = Counter(4) -- expression 44 operands: lhs = Expression(45, Add), rhs = Counter(3) -- expression 45 operands: lhs = Counter(0), rhs = Counter(2) +- expression 2 operands: lhs = Counter(2), rhs = Counter(3) +- expression 3 operands: lhs = Counter(3), rhs = Counter(4) +- expression 4 operands: lhs = Counter(4), rhs = Counter(5) +- expression 5 operands: lhs = Counter(5), rhs = Counter(6) +- expression 6 operands: lhs = Counter(6), rhs = Counter(7) +- expression 7 operands: lhs = Counter(0), rhs = Counter(7) Number of file 0 mappings: 18 - Code(Counter(0)) at (prev + 7, 1) to (start + 2, 9) - MCDCDecision { bitmap_idx: 8, conditions_num: 7 } at (prev + 2, 8) to (start + 0, 39) @@ -56,38 +18,32 @@ Number of file 0 mappings: 18 true = c1 false = (c0 - c1) - Code(Counter(1)) at (prev + 0, 13) to (start + 0, 14) -- MCDCBranch { true: Expression(2, Sub), false: Counter(2), condition_id: 7, true_next_id: 6, false_next_id: 0 } at (prev + 0, 13) to (start + 0, 14) - true = (c1 - c2) - false = c2 -- Code(Expression(2, Sub)) at (prev + 0, 18) to (start + 0, 19) - = (c1 - c2) -- MCDCBranch { true: Expression(5, Sub), false: Counter(3), condition_id: 6, true_next_id: 5, false_next_id: 0 } at (prev + 0, 18) to (start + 0, 19) - true = (c1 - (c2 + c3)) - false = c3 -- Code(Expression(5, Sub)) at (prev + 0, 23) to (start + 0, 24) - = (c1 - (c2 + c3)) -- MCDCBranch { true: Expression(10, Sub), false: Counter(4), condition_id: 5, true_next_id: 4, false_next_id: 0 } at (prev + 0, 23) to (start + 0, 24) - true = (c1 - ((c2 + c3) + c4)) - false = c4 -- Code(Expression(10, Sub)) at (prev + 0, 28) to (start + 0, 29) - = (c1 - ((c2 + c3) + c4)) -- MCDCBranch { true: Expression(17, Sub), false: Counter(5), condition_id: 4, true_next_id: 3, false_next_id: 0 } at (prev + 0, 28) to (start + 0, 29) - true = (c1 - (((c2 + c3) + c4) + c5)) - false = c5 -- Code(Expression(17, Sub)) at (prev + 0, 33) to (start + 0, 34) - = (c1 - (((c2 + c3) + c4) + c5)) -- MCDCBranch { true: Expression(26, Sub), false: Counter(6), condition_id: 3, true_next_id: 2, false_next_id: 0 } at (prev + 0, 33) to (start + 0, 34) - true = (c1 - ((((c2 + c3) + c4) + c5) + c6)) - false = c6 -- Code(Expression(26, Sub)) at (prev + 0, 38) to (start + 0, 39) - = (c1 - ((((c2 + c3) + c4) + c5) + c6)) -- MCDCBranch { true: Counter(7), false: Counter(8), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 38) to (start + 0, 39) +- MCDCBranch { true: Counter(2), false: Expression(1, Sub), condition_id: 7, true_next_id: 6, false_next_id: 0 } at (prev + 0, 13) to (start + 0, 14) + true = c2 + false = (c1 - c2) +- Code(Counter(2)) at (prev + 0, 18) to (start + 0, 19) +- MCDCBranch { true: Counter(3), false: Expression(2, Sub), condition_id: 6, true_next_id: 5, false_next_id: 0 } at (prev + 0, 18) to (start + 0, 19) + true = c3 + false = (c2 - c3) +- Code(Counter(3)) at (prev + 0, 23) to (start + 0, 24) +- MCDCBranch { true: Counter(4), false: Expression(3, Sub), condition_id: 5, true_next_id: 4, false_next_id: 0 } at (prev + 0, 23) to (start + 0, 24) + true = c4 + false = (c3 - c4) +- Code(Counter(4)) at (prev + 0, 28) to (start + 0, 29) +- MCDCBranch { true: Counter(5), false: Expression(4, Sub), condition_id: 4, true_next_id: 3, false_next_id: 0 } at (prev + 0, 28) to (start + 0, 29) + true = c5 + false = (c4 - c5) +- Code(Counter(5)) at (prev + 0, 33) to (start + 0, 34) +- MCDCBranch { true: Counter(6), false: Expression(5, Sub), condition_id: 3, true_next_id: 2, false_next_id: 0 } at (prev + 0, 33) to (start + 0, 34) + true = c6 + false = (c5 - c6) +- Code(Counter(6)) at (prev + 0, 38) to (start + 0, 39) +- MCDCBranch { true: Counter(7), false: Expression(6, Sub), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 38) to (start + 0, 39) true = c7 - false = c8 + false = (c6 - c7) - Code(Counter(7)) at (prev + 0, 40) to (start + 2, 6) -- Code(Expression(31, Sub)) at (prev + 2, 5) to (start + 0, 6) - = (((((((c0 + c2) + c3) + c4) + c5) + c6) + c8) - c1) -- Code(Expression(38, Sub)) at (prev + 1, 1) to (start + 0, 2) - = ((((((((c0 + c2) + c3) + c4) + c5) + c6) + c7) + c8) - c1) -Highest counter ID seen: c8 +- Code(Expression(7, Sub)) at (prev + 2, 5) to (start + 0, 6) + = (c0 - c7) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) +Highest counter ID seen: c7 diff --git a/tests/coverage/mcdc/if.cov-map b/tests/coverage/mcdc/if.cov-map index acb8aac63de..771351f649f 100644 --- a/tests/coverage/mcdc/if.cov-map +++ b/tests/coverage/mcdc/if.cov-map @@ -1,14 +1,11 @@ Function name: if::mcdc_check_a -Raw bytes (68): 0x[01, 01, 06, 01, 05, 0b, 05, 01, 0d, 13, 05, 17, 0d, 01, 09, 08, 01, 0f, 01, 01, 09, 28, 03, 02, 01, 08, 00, 0e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 09, 0d, 02, 00, 00, 00, 0d, 00, 0e, 09, 00, 0f, 02, 06, 06, 02, 0c, 02, 06, 0e, 03, 01, 00, 02] +Raw bytes (62): 0x[01, 01, 03, 01, 05, 05, 09, 01, 09, 08, 01, 0f, 01, 01, 09, 28, 03, 02, 01, 08, 00, 0e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 09, 06, 02, 00, 00, 00, 0d, 00, 0e, 09, 00, 0f, 02, 06, 0a, 02, 0c, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 - file 0 => global file 1 -Number of expressions: 6 +Number of expressions: 3 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -- expression 1 operands: lhs = Expression(2, Add), rhs = Counter(1) -- expression 2 operands: lhs = Counter(0), rhs = Counter(3) -- expression 3 operands: lhs = Expression(4, Add), rhs = Counter(1) -- expression 4 operands: lhs = Expression(5, Add), rhs = Counter(3) -- expression 5 operands: lhs = Counter(0), rhs = Counter(2) +- expression 1 operands: lhs = Counter(1), rhs = Counter(2) +- expression 2 operands: lhs = Counter(0), rhs = Counter(2) Number of file 0 mappings: 8 - Code(Counter(0)) at (prev + 15, 1) to (start + 1, 9) - MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 1, 8) to (start + 0, 14) @@ -16,27 +13,23 @@ Number of file 0 mappings: 8 true = c1 false = (c0 - c1) - Code(Counter(1)) at (prev + 0, 13) to (start + 0, 14) -- MCDCBranch { true: Counter(2), false: Counter(3), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 13) to (start + 0, 14) +- MCDCBranch { true: Counter(2), false: Expression(1, Sub), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 13) to (start + 0, 14) true = c2 - false = c3 + false = (c1 - c2) - Code(Counter(2)) at (prev + 0, 15) to (start + 2, 6) -- Code(Expression(1, Sub)) at (prev + 2, 12) to (start + 2, 6) - = ((c0 + c3) - c1) -- Code(Expression(3, Sub)) at (prev + 3, 1) to (start + 0, 2) - = (((c0 + c2) + c3) - c1) -Highest counter ID seen: c3 +- Code(Expression(2, Sub)) at (prev + 2, 12) to (start + 2, 6) + = (c0 - c2) +- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2) +Highest counter ID seen: c2 Function name: if::mcdc_check_b -Raw bytes (68): 0x[01, 01, 06, 01, 05, 0b, 05, 01, 0d, 13, 05, 17, 0d, 01, 09, 08, 01, 17, 01, 01, 09, 28, 03, 02, 01, 08, 00, 0e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 09, 0d, 02, 00, 00, 00, 0d, 00, 0e, 09, 00, 0f, 02, 06, 06, 02, 0c, 02, 06, 0e, 03, 01, 00, 02] +Raw bytes (62): 0x[01, 01, 03, 01, 05, 05, 09, 01, 09, 08, 01, 17, 01, 01, 09, 28, 03, 02, 01, 08, 00, 0e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 09, 06, 02, 00, 00, 00, 0d, 00, 0e, 09, 00, 0f, 02, 06, 0a, 02, 0c, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 - file 0 => global file 1 -Number of expressions: 6 +Number of expressions: 3 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -- expression 1 operands: lhs = Expression(2, Add), rhs = Counter(1) -- expression 2 operands: lhs = Counter(0), rhs = Counter(3) -- expression 3 operands: lhs = Expression(4, Add), rhs = Counter(1) -- expression 4 operands: lhs = Expression(5, Add), rhs = Counter(3) -- expression 5 operands: lhs = Counter(0), rhs = Counter(2) +- expression 1 operands: lhs = Counter(1), rhs = Counter(2) +- expression 2 operands: lhs = Counter(0), rhs = Counter(2) Number of file 0 mappings: 8 - Code(Counter(0)) at (prev + 23, 1) to (start + 1, 9) - MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 1, 8) to (start + 0, 14) @@ -44,27 +37,23 @@ Number of file 0 mappings: 8 true = c1 false = (c0 - c1) - Code(Counter(1)) at (prev + 0, 13) to (start + 0, 14) -- MCDCBranch { true: Counter(2), false: Counter(3), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 13) to (start + 0, 14) +- MCDCBranch { true: Counter(2), false: Expression(1, Sub), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 13) to (start + 0, 14) true = c2 - false = c3 + false = (c1 - c2) - Code(Counter(2)) at (prev + 0, 15) to (start + 2, 6) -- Code(Expression(1, Sub)) at (prev + 2, 12) to (start + 2, 6) - = ((c0 + c3) - c1) -- Code(Expression(3, Sub)) at (prev + 3, 1) to (start + 0, 2) - = (((c0 + c2) + c3) - c1) -Highest counter ID seen: c3 +- Code(Expression(2, Sub)) at (prev + 2, 12) to (start + 2, 6) + = (c0 - c2) +- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2) +Highest counter ID seen: c2 Function name: if::mcdc_check_both -Raw bytes (68): 0x[01, 01, 06, 01, 05, 0b, 05, 01, 0d, 13, 05, 17, 0d, 01, 09, 08, 01, 1f, 01, 01, 09, 28, 03, 02, 01, 08, 00, 0e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 09, 0d, 02, 00, 00, 00, 0d, 00, 0e, 09, 00, 0f, 02, 06, 06, 02, 0c, 02, 06, 0e, 03, 01, 00, 02] +Raw bytes (62): 0x[01, 01, 03, 01, 05, 05, 09, 01, 09, 08, 01, 1f, 01, 01, 09, 28, 03, 02, 01, 08, 00, 0e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 09, 06, 02, 00, 00, 00, 0d, 00, 0e, 09, 00, 0f, 02, 06, 0a, 02, 0c, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 - file 0 => global file 1 -Number of expressions: 6 +Number of expressions: 3 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -- expression 1 operands: lhs = Expression(2, Add), rhs = Counter(1) -- expression 2 operands: lhs = Counter(0), rhs = Counter(3) -- expression 3 operands: lhs = Expression(4, Add), rhs = Counter(1) -- expression 4 operands: lhs = Expression(5, Add), rhs = Counter(3) -- expression 5 operands: lhs = Counter(0), rhs = Counter(2) +- expression 1 operands: lhs = Counter(1), rhs = Counter(2) +- expression 2 operands: lhs = Counter(0), rhs = Counter(2) Number of file 0 mappings: 8 - Code(Counter(0)) at (prev + 31, 1) to (start + 1, 9) - MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 1, 8) to (start + 0, 14) @@ -72,27 +61,23 @@ Number of file 0 mappings: 8 true = c1 false = (c0 - c1) - Code(Counter(1)) at (prev + 0, 13) to (start + 0, 14) -- MCDCBranch { true: Counter(2), false: Counter(3), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 13) to (start + 0, 14) +- MCDCBranch { true: Counter(2), false: Expression(1, Sub), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 13) to (start + 0, 14) true = c2 - false = c3 + false = (c1 - c2) - Code(Counter(2)) at (prev + 0, 15) to (start + 2, 6) -- Code(Expression(1, Sub)) at (prev + 2, 12) to (start + 2, 6) - = ((c0 + c3) - c1) -- Code(Expression(3, Sub)) at (prev + 3, 1) to (start + 0, 2) - = (((c0 + c2) + c3) - c1) -Highest counter ID seen: c3 +- Code(Expression(2, Sub)) at (prev + 2, 12) to (start + 2, 6) + = (c0 - c2) +- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2) +Highest counter ID seen: c2 Function name: if::mcdc_check_neither -Raw bytes (68): 0x[01, 01, 06, 01, 05, 0b, 05, 01, 0d, 13, 05, 17, 0d, 01, 09, 08, 01, 07, 01, 01, 09, 28, 03, 02, 01, 08, 00, 0e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 09, 0d, 02, 00, 00, 00, 0d, 00, 0e, 09, 00, 0f, 02, 06, 06, 02, 0c, 02, 06, 0e, 03, 01, 00, 02] +Raw bytes (62): 0x[01, 01, 03, 01, 05, 05, 09, 01, 09, 08, 01, 07, 01, 01, 09, 28, 03, 02, 01, 08, 00, 0e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 09, 06, 02, 00, 00, 00, 0d, 00, 0e, 09, 00, 0f, 02, 06, 0a, 02, 0c, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 - file 0 => global file 1 -Number of expressions: 6 +Number of expressions: 3 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -- expression 1 operands: lhs = Expression(2, Add), rhs = Counter(1) -- expression 2 operands: lhs = Counter(0), rhs = Counter(3) -- expression 3 operands: lhs = Expression(4, Add), rhs = Counter(1) -- expression 4 operands: lhs = Expression(5, Add), rhs = Counter(3) -- expression 5 operands: lhs = Counter(0), rhs = Counter(2) +- expression 1 operands: lhs = Counter(1), rhs = Counter(2) +- expression 2 operands: lhs = Counter(0), rhs = Counter(2) Number of file 0 mappings: 8 - Code(Counter(0)) at (prev + 7, 1) to (start + 1, 9) - MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 1, 8) to (start + 0, 14) @@ -100,32 +85,27 @@ Number of file 0 mappings: 8 true = c1 false = (c0 - c1) - Code(Counter(1)) at (prev + 0, 13) to (start + 0, 14) -- MCDCBranch { true: Counter(2), false: Counter(3), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 13) to (start + 0, 14) +- MCDCBranch { true: Counter(2), false: Expression(1, Sub), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 13) to (start + 0, 14) true = c2 - false = c3 + false = (c1 - c2) - Code(Counter(2)) at (prev + 0, 15) to (start + 2, 6) -- Code(Expression(1, Sub)) at (prev + 2, 12) to (start + 2, 6) - = ((c0 + c3) - c1) -- Code(Expression(3, Sub)) at (prev + 3, 1) to (start + 0, 2) - = (((c0 + c2) + c3) - c1) -Highest counter ID seen: c3 +- Code(Expression(2, Sub)) at (prev + 2, 12) to (start + 2, 6) + = (c0 - c2) +- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2) +Highest counter ID seen: c2 Function name: if::mcdc_check_not_tree_decision -Raw bytes (93): 0x[01, 01, 0b, 01, 05, 01, 2b, 05, 09, 05, 09, 17, 2b, 01, 11, 05, 09, 23, 2b, 27, 11, 01, 0d, 05, 09, 0a, 01, 31, 01, 03, 0a, 28, 05, 03, 03, 08, 00, 15, 30, 05, 02, 01, 02, 03, 00, 09, 00, 0a, 02, 00, 0e, 00, 0f, 30, 09, 06, 03, 02, 00, 00, 0e, 00, 0f, 2b, 00, 14, 00, 15, 30, 0d, 11, 02, 00, 00, 00, 14, 00, 15, 0d, 00, 16, 02, 06, 12, 02, 0c, 02, 06, 1e, 03, 01, 00, 02] +Raw bytes (85): 0x[01, 01, 07, 01, 05, 01, 17, 05, 09, 05, 09, 17, 0d, 05, 09, 01, 0d, 0a, 01, 31, 01, 03, 0a, 28, 05, 03, 03, 08, 00, 15, 30, 05, 02, 01, 02, 03, 00, 09, 00, 0a, 02, 00, 0e, 00, 0f, 30, 09, 06, 03, 02, 00, 00, 0e, 00, 0f, 17, 00, 14, 00, 15, 30, 0d, 12, 02, 00, 00, 00, 14, 00, 15, 0d, 00, 16, 02, 06, 1a, 02, 0c, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 - file 0 => global file 1 -Number of expressions: 11 +Number of expressions: 7 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -- expression 1 operands: lhs = Counter(0), rhs = Expression(10, Add) +- expression 1 operands: lhs = Counter(0), rhs = Expression(5, Add) - expression 2 operands: lhs = Counter(1), rhs = Counter(2) - expression 3 operands: lhs = Counter(1), rhs = Counter(2) -- expression 4 operands: lhs = Expression(5, Add), rhs = Expression(10, Add) -- expression 5 operands: lhs = Counter(0), rhs = Counter(4) -- expression 6 operands: lhs = Counter(1), rhs = Counter(2) -- expression 7 operands: lhs = Expression(8, Add), rhs = Expression(10, Add) -- expression 8 operands: lhs = Expression(9, Add), rhs = Counter(4) -- expression 9 operands: lhs = Counter(0), rhs = Counter(3) -- expression 10 operands: lhs = Counter(1), rhs = Counter(2) +- expression 4 operands: lhs = Expression(5, Add), rhs = Counter(3) +- expression 5 operands: lhs = Counter(1), rhs = Counter(2) +- expression 6 operands: lhs = Counter(0), rhs = Counter(3) Number of file 0 mappings: 10 - Code(Counter(0)) at (prev + 49, 1) to (start + 3, 10) - MCDCDecision { bitmap_idx: 5, conditions_num: 3 } at (prev + 3, 8) to (start + 0, 21) @@ -137,33 +117,30 @@ Number of file 0 mappings: 10 - MCDCBranch { true: Counter(2), false: Expression(1, Sub), condition_id: 3, true_next_id: 2, false_next_id: 0 } at (prev + 0, 14) to (start + 0, 15) true = c2 false = (c0 - (c1 + c2)) -- Code(Expression(10, Add)) at (prev + 0, 20) to (start + 0, 21) +- Code(Expression(5, Add)) at (prev + 0, 20) to (start + 0, 21) = (c1 + c2) -- MCDCBranch { true: Counter(3), false: Counter(4), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 20) to (start + 0, 21) +- MCDCBranch { true: Counter(3), false: Expression(4, Sub), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 20) to (start + 0, 21) true = c3 - false = c4 + false = ((c1 + c2) - c3) - Code(Counter(3)) at (prev + 0, 22) to (start + 2, 6) -- Code(Expression(4, Sub)) at (prev + 2, 12) to (start + 2, 6) - = ((c0 + c4) - (c1 + c2)) -- Code(Expression(7, Sub)) at (prev + 3, 1) to (start + 0, 2) - = (((c0 + c3) + c4) - (c1 + c2)) -Highest counter ID seen: c4 +- Code(Expression(6, Sub)) at (prev + 2, 12) to (start + 2, 6) + = (c0 - c3) +- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2) +Highest counter ID seen: c3 Function name: if::mcdc_check_tree_decision -Raw bytes (91): 0x[01, 01, 0a, 01, 05, 05, 09, 05, 09, 09, 0d, 17, 05, 01, 11, 1f, 05, 23, 11, 27, 0d, 01, 09, 0a, 01, 27, 01, 03, 09, 28, 04, 03, 03, 08, 00, 15, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 05, 00, 0e, 00, 0f, 30, 09, 0a, 02, 00, 03, 00, 0e, 00, 0f, 0a, 00, 13, 00, 14, 30, 0d, 11, 03, 00, 00, 00, 13, 00, 14, 0f, 00, 16, 02, 06, 12, 02, 0c, 02, 06, 1a, 03, 01, 00, 02] +Raw bytes (87): 0x[01, 01, 08, 01, 05, 05, 09, 05, 09, 05, 1f, 09, 0d, 09, 0d, 01, 1f, 09, 0d, 0a, 01, 27, 01, 03, 09, 28, 04, 03, 03, 08, 00, 15, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 05, 00, 0e, 00, 0f, 30, 09, 0a, 02, 00, 03, 00, 0e, 00, 0f, 0a, 00, 13, 00, 14, 30, 0d, 0e, 03, 00, 00, 00, 13, 00, 14, 1f, 00, 16, 02, 06, 1a, 02, 0c, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 - file 0 => global file 1 -Number of expressions: 10 +Number of expressions: 8 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Counter(2) - expression 2 operands: lhs = Counter(1), rhs = Counter(2) -- expression 3 operands: lhs = Counter(2), rhs = Counter(3) -- expression 4 operands: lhs = Expression(5, Add), rhs = Counter(1) -- expression 5 operands: lhs = Counter(0), rhs = Counter(4) -- expression 6 operands: lhs = Expression(7, Add), rhs = Counter(1) -- expression 7 operands: lhs = Expression(8, Add), rhs = Counter(4) -- expression 8 operands: lhs = Expression(9, Add), rhs = Counter(3) -- expression 9 operands: lhs = Counter(0), rhs = Counter(2) +- expression 3 operands: lhs = Counter(1), rhs = Expression(7, Add) +- expression 4 operands: lhs = Counter(2), rhs = Counter(3) +- expression 5 operands: lhs = Counter(2), rhs = Counter(3) +- expression 6 operands: lhs = Counter(0), rhs = Expression(7, Add) +- expression 7 operands: lhs = Counter(2), rhs = Counter(3) Number of file 0 mappings: 10 - Code(Counter(0)) at (prev + 39, 1) to (start + 3, 9) - MCDCDecision { bitmap_idx: 4, conditions_num: 3 } at (prev + 3, 8) to (start + 0, 21) @@ -176,38 +153,32 @@ Number of file 0 mappings: 10 false = (c1 - c2) - Code(Expression(2, Sub)) at (prev + 0, 19) to (start + 0, 20) = (c1 - c2) -- MCDCBranch { true: Counter(3), false: Counter(4), condition_id: 3, true_next_id: 0, false_next_id: 0 } at (prev + 0, 19) to (start + 0, 20) +- MCDCBranch { true: Counter(3), false: Expression(3, Sub), condition_id: 3, true_next_id: 0, false_next_id: 0 } at (prev + 0, 19) to (start + 0, 20) true = c3 - false = c4 -- Code(Expression(3, Add)) at (prev + 0, 22) to (start + 2, 6) + false = (c1 - (c2 + c3)) +- Code(Expression(7, Add)) at (prev + 0, 22) to (start + 2, 6) = (c2 + c3) -- Code(Expression(4, Sub)) at (prev + 2, 12) to (start + 2, 6) - = ((c0 + c4) - c1) -- Code(Expression(6, Sub)) at (prev + 3, 1) to (start + 0, 2) - = ((((c0 + c2) + c3) + c4) - c1) -Highest counter ID seen: c4 +- Code(Expression(6, Sub)) at (prev + 2, 12) to (start + 2, 6) + = (c0 - (c2 + c3)) +- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2) +Highest counter ID seen: c3 Function name: if::mcdc_nested_if -Raw bytes (130): 0x[01, 01, 10, 01, 05, 01, 3f, 05, 09, 05, 09, 3f, 0d, 05, 09, 3f, 0d, 05, 09, 0d, 15, 01, 3f, 05, 09, 33, 3f, 37, 15, 3b, 11, 01, 0d, 05, 09, 0e, 01, 3b, 01, 01, 09, 28, 03, 02, 01, 08, 00, 0e, 30, 05, 02, 01, 00, 02, 00, 08, 00, 09, 02, 00, 0d, 00, 0e, 30, 09, 26, 02, 00, 00, 00, 0d, 00, 0e, 3f, 01, 09, 01, 0d, 28, 06, 02, 01, 0c, 00, 12, 30, 1a, 0d, 01, 02, 00, 00, 0c, 00, 0d, 1a, 00, 11, 00, 12, 30, 11, 15, 02, 00, 00, 00, 11, 00, 12, 11, 00, 13, 02, 0a, 23, 02, 09, 00, 0a, 26, 01, 0c, 02, 06, 2e, 03, 01, 00, 02] +Raw bytes (120): 0x[01, 01, 0b, 01, 05, 01, 2b, 05, 09, 05, 09, 2b, 0d, 05, 09, 0d, 11, 2b, 11, 05, 09, 01, 2b, 05, 09, 0e, 01, 3b, 01, 01, 09, 28, 03, 02, 01, 08, 00, 0e, 30, 05, 02, 01, 00, 02, 00, 08, 00, 09, 02, 00, 0d, 00, 0e, 30, 09, 26, 02, 00, 00, 00, 0d, 00, 0e, 2b, 01, 09, 01, 0d, 28, 06, 02, 01, 0c, 00, 12, 30, 0d, 12, 01, 02, 00, 00, 0c, 00, 0d, 0d, 00, 11, 00, 12, 30, 11, 1a, 02, 00, 00, 00, 11, 00, 12, 11, 00, 13, 02, 0a, 1e, 02, 09, 00, 0a, 26, 01, 0c, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 - file 0 => global file 1 -Number of expressions: 16 +Number of expressions: 11 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -- expression 1 operands: lhs = Counter(0), rhs = Expression(15, Add) +- expression 1 operands: lhs = Counter(0), rhs = Expression(10, Add) - expression 2 operands: lhs = Counter(1), rhs = Counter(2) - expression 3 operands: lhs = Counter(1), rhs = Counter(2) -- expression 4 operands: lhs = Expression(15, Add), rhs = Counter(3) +- expression 4 operands: lhs = Expression(10, Add), rhs = Counter(3) - expression 5 operands: lhs = Counter(1), rhs = Counter(2) -- expression 6 operands: lhs = Expression(15, Add), rhs = Counter(3) -- expression 7 operands: lhs = Counter(1), rhs = Counter(2) -- expression 8 operands: lhs = Counter(3), rhs = Counter(5) -- expression 9 operands: lhs = Counter(0), rhs = Expression(15, Add) +- expression 6 operands: lhs = Counter(3), rhs = Counter(4) +- expression 7 operands: lhs = Expression(10, Add), rhs = Counter(4) +- expression 8 operands: lhs = Counter(1), rhs = Counter(2) +- expression 9 operands: lhs = Counter(0), rhs = Expression(10, Add) - expression 10 operands: lhs = Counter(1), rhs = Counter(2) -- expression 11 operands: lhs = Expression(12, Add), rhs = Expression(15, Add) -- expression 12 operands: lhs = Expression(13, Add), rhs = Counter(5) -- expression 13 operands: lhs = Expression(14, Add), rhs = Counter(4) -- expression 14 operands: lhs = Counter(0), rhs = Counter(3) -- expression 15 operands: lhs = Counter(1), rhs = Counter(2) Number of file 0 mappings: 14 - Code(Counter(0)) at (prev + 59, 1) to (start + 1, 9) - MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 1, 8) to (start + 0, 14) @@ -219,23 +190,21 @@ Number of file 0 mappings: 14 - MCDCBranch { true: Counter(2), false: Expression(9, Sub), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 13) to (start + 0, 14) true = c2 false = (c0 - (c1 + c2)) -- Code(Expression(15, Add)) at (prev + 1, 9) to (start + 1, 13) +- Code(Expression(10, Add)) at (prev + 1, 9) to (start + 1, 13) = (c1 + c2) - MCDCDecision { bitmap_idx: 6, conditions_num: 2 } at (prev + 1, 12) to (start + 0, 18) -- MCDCBranch { true: Expression(6, Sub), false: Counter(3), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 12) to (start + 0, 13) - true = ((c1 + c2) - c3) - false = c3 -- Code(Expression(6, Sub)) at (prev + 0, 17) to (start + 0, 18) - = ((c1 + c2) - c3) -- MCDCBranch { true: Counter(4), false: Counter(5), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 17) to (start + 0, 18) +- MCDCBranch { true: Counter(3), false: Expression(4, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 12) to (start + 0, 13) + true = c3 + false = ((c1 + c2) - c3) +- Code(Counter(3)) at (prev + 0, 17) to (start + 0, 18) +- MCDCBranch { true: Counter(4), false: Expression(6, Sub), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 17) to (start + 0, 18) true = c4 - false = c5 + false = (c3 - c4) - Code(Counter(4)) at (prev + 0, 19) to (start + 2, 10) -- Code(Expression(8, Add)) at (prev + 2, 9) to (start + 0, 10) - = (c3 + c5) +- Code(Expression(7, Sub)) at (prev + 2, 9) to (start + 0, 10) + = ((c1 + c2) - c4) - Code(Expression(9, Sub)) at (prev + 1, 12) to (start + 2, 6) = (c0 - (c1 + c2)) -- Code(Expression(11, Sub)) at (prev + 3, 1) to (start + 0, 2) - = ((((c0 + c3) + c4) + c5) - (c1 + c2)) -Highest counter ID seen: c5 +- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2) +Highest counter ID seen: c4 diff --git a/tests/coverage/mcdc/inlined_expressions.cov-map b/tests/coverage/mcdc/inlined_expressions.cov-map index 92ec60dc23c..6a112b66e88 100644 --- a/tests/coverage/mcdc/inlined_expressions.cov-map +++ b/tests/coverage/mcdc/inlined_expressions.cov-map @@ -1,12 +1,10 @@ Function name: inlined_expressions::inlined_instance -Raw bytes (54): 0x[01, 01, 04, 01, 05, 0b, 05, 0f, 0d, 01, 09, 06, 01, 08, 01, 01, 06, 28, 03, 02, 01, 05, 00, 0b, 30, 05, 02, 01, 02, 00, 00, 05, 00, 06, 05, 00, 0a, 00, 0b, 30, 09, 0d, 02, 00, 00, 00, 0a, 00, 0b, 06, 01, 01, 00, 02] +Raw bytes (50): 0x[01, 01, 02, 01, 05, 05, 09, 06, 01, 08, 01, 01, 06, 28, 03, 02, 01, 05, 00, 0b, 30, 05, 02, 01, 02, 00, 00, 05, 00, 06, 05, 00, 0a, 00, 0b, 30, 09, 06, 02, 00, 00, 00, 0a, 00, 0b, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 -Number of expressions: 4 +Number of expressions: 2 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -- expression 1 operands: lhs = Expression(2, Add), rhs = Counter(1) -- expression 2 operands: lhs = Expression(3, Add), rhs = Counter(3) -- expression 3 operands: lhs = Counter(0), rhs = Counter(2) +- expression 1 operands: lhs = Counter(1), rhs = Counter(2) Number of file 0 mappings: 6 - Code(Counter(0)) at (prev + 8, 1) to (start + 1, 6) - MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 1, 5) to (start + 0, 11) @@ -14,10 +12,9 @@ Number of file 0 mappings: 6 true = c1 false = (c0 - c1) - Code(Counter(1)) at (prev + 0, 10) to (start + 0, 11) -- MCDCBranch { true: Counter(2), false: Counter(3), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 10) to (start + 0, 11) +- MCDCBranch { true: Counter(2), false: Expression(1, Sub), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 10) to (start + 0, 11) true = c2 - false = c3 -- Code(Expression(1, Sub)) at (prev + 1, 1) to (start + 0, 2) - = (((c0 + c2) + c3) - c1) -Highest counter ID seen: c3 + false = (c1 - c2) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) +Highest counter ID seen: c2 diff --git a/tests/coverage/mcdc/nested_if.cov-map b/tests/coverage/mcdc/nested_if.cov-map index 72daecabc77..72c7d68840d 100644 --- a/tests/coverage/mcdc/nested_if.cov-map +++ b/tests/coverage/mcdc/nested_if.cov-map @@ -1,24 +1,22 @@ Function name: nested_if::doubly_nested_if_in_condition -Raw bytes (172): 0x[01, 01, 10, 01, 05, 05, 09, 05, 09, 05, 27, 09, 19, 19, 1d, 19, 1d, 23, 27, 05, 1d, 09, 19, 09, 0d, 33, 05, 01, 15, 3b, 05, 3f, 15, 01, 11, 14, 01, 0f, 01, 01, 09, 28, 09, 02, 01, 08, 00, 4e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 30, 11, 15, 02, 00, 00, 00, 0d, 00, 4e, 05, 00, 10, 00, 11, 28, 06, 02, 00, 10, 00, 36, 30, 09, 0a, 01, 00, 02, 00, 10, 00, 11, 30, 0d, 21, 02, 00, 00, 00, 15, 00, 36, 0a, 00, 18, 00, 19, 28, 03, 02, 00, 18, 00, 1e, 30, 19, 0e, 01, 02, 00, 00, 18, 00, 19, 19, 00, 1d, 00, 1e, 30, 1a, 1d, 02, 00, 00, 00, 1d, 00, 1e, 1a, 00, 21, 00, 25, 1e, 00, 2f, 00, 34, 2b, 00, 39, 00, 3e, 21, 00, 48, 00, 4c, 11, 00, 4f, 02, 06, 2e, 02, 0c, 02, 06, 36, 03, 01, 00, 02] +Raw bytes (168): 0x[01, 01, 0e, 01, 05, 05, 09, 05, 09, 05, 13, 09, 19, 19, 1d, 05, 1f, 09, 1d, 09, 0d, 2b, 05, 01, 15, 33, 05, 37, 15, 01, 11, 14, 01, 0f, 01, 01, 09, 28, 09, 02, 01, 08, 00, 4e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 30, 11, 15, 02, 00, 00, 00, 0d, 00, 4e, 05, 00, 10, 00, 11, 28, 06, 02, 00, 10, 00, 36, 30, 09, 0a, 01, 00, 02, 00, 10, 00, 11, 30, 0d, 21, 02, 00, 00, 00, 15, 00, 36, 0a, 00, 18, 00, 19, 28, 03, 02, 00, 18, 00, 1e, 30, 19, 0e, 01, 02, 00, 00, 18, 00, 19, 19, 00, 1d, 00, 1e, 30, 1d, 16, 02, 00, 00, 00, 1d, 00, 1e, 1d, 00, 21, 00, 25, 1a, 00, 2f, 00, 34, 23, 00, 39, 00, 3e, 21, 00, 48, 00, 4c, 11, 00, 4f, 02, 06, 26, 02, 0c, 02, 06, 2e, 03, 01, 00, 02] Number of files: 1 - file 0 => global file 1 -Number of expressions: 16 +Number of expressions: 14 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Counter(2) - expression 2 operands: lhs = Counter(1), rhs = Counter(2) -- expression 3 operands: lhs = Counter(1), rhs = Expression(9, Add) +- expression 3 operands: lhs = Counter(1), rhs = Expression(4, Add) - expression 4 operands: lhs = Counter(2), rhs = Counter(6) - expression 5 operands: lhs = Counter(6), rhs = Counter(7) -- expression 6 operands: lhs = Counter(6), rhs = Counter(7) -- expression 7 operands: lhs = Expression(8, Add), rhs = Expression(9, Add) -- expression 8 operands: lhs = Counter(1), rhs = Counter(7) -- expression 9 operands: lhs = Counter(2), rhs = Counter(6) -- expression 10 operands: lhs = Counter(2), rhs = Counter(3) +- expression 6 operands: lhs = Counter(1), rhs = Expression(7, Add) +- expression 7 operands: lhs = Counter(2), rhs = Counter(7) +- expression 8 operands: lhs = Counter(2), rhs = Counter(3) +- expression 9 operands: lhs = Expression(10, Add), rhs = Counter(1) +- expression 10 operands: lhs = Counter(0), rhs = Counter(5) - expression 11 operands: lhs = Expression(12, Add), rhs = Counter(1) -- expression 12 operands: lhs = Counter(0), rhs = Counter(5) -- expression 13 operands: lhs = Expression(14, Add), rhs = Counter(1) -- expression 14 operands: lhs = Expression(15, Add), rhs = Counter(5) -- expression 15 operands: lhs = Counter(0), rhs = Counter(4) +- expression 12 operands: lhs = Expression(13, Add), rhs = Counter(5) +- expression 13 operands: lhs = Counter(0), rhs = Counter(4) Number of file 0 mappings: 20 - Code(Counter(0)) at (prev + 15, 1) to (start + 1, 9) - MCDCDecision { bitmap_idx: 9, conditions_num: 2 } at (prev + 1, 8) to (start + 0, 78) @@ -43,20 +41,19 @@ Number of file 0 mappings: 20 true = c6 false = (c1 - (c2 + c6)) - Code(Counter(6)) at (prev + 0, 29) to (start + 0, 30) -- MCDCBranch { true: Expression(6, Sub), false: Counter(7), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 29) to (start + 0, 30) - true = (c6 - c7) - false = c7 -- Code(Expression(6, Sub)) at (prev + 0, 33) to (start + 0, 37) - = (c6 - c7) -- Code(Expression(7, Sub)) at (prev + 0, 47) to (start + 0, 52) - = ((c1 + c7) - (c2 + c6)) -- Code(Expression(10, Add)) at (prev + 0, 57) to (start + 0, 62) +- MCDCBranch { true: Counter(7), false: Expression(5, Sub), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 29) to (start + 0, 30) + true = c7 + false = (c6 - c7) +- Code(Counter(7)) at (prev + 0, 33) to (start + 0, 37) +- Code(Expression(6, Sub)) at (prev + 0, 47) to (start + 0, 52) + = (c1 - (c2 + c7)) +- Code(Expression(8, Add)) at (prev + 0, 57) to (start + 0, 62) = (c2 + c3) - Code(Counter(8)) at (prev + 0, 72) to (start + 0, 76) - Code(Counter(4)) at (prev + 0, 79) to (start + 2, 6) -- Code(Expression(11, Sub)) at (prev + 2, 12) to (start + 2, 6) +- Code(Expression(9, Sub)) at (prev + 2, 12) to (start + 2, 6) = ((c0 + c5) - c1) -- Code(Expression(13, Sub)) at (prev + 3, 1) to (start + 0, 2) +- Code(Expression(11, Sub)) at (prev + 3, 1) to (start + 0, 2) = (((c0 + c4) + c5) - c1) Highest counter ID seen: c8 @@ -109,30 +106,28 @@ Number of file 0 mappings: 14 Highest counter ID seen: c5 Function name: nested_if::nested_in_then_block_in_condition -Raw bytes (180): 0x[01, 01, 14, 01, 05, 05, 09, 05, 09, 05, 3b, 09, 0d, 09, 0d, 3b, 11, 09, 0d, 11, 15, 11, 15, 2f, 11, 3b, 15, 09, 0d, 05, 3b, 09, 0d, 43, 05, 01, 1d, 4b, 05, 4f, 1d, 01, 19, 14, 01, 22, 01, 01, 09, 28, 09, 02, 01, 08, 00, 4b, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 30, 19, 1d, 02, 00, 00, 00, 0d, 00, 4b, 05, 00, 10, 00, 11, 28, 03, 02, 00, 10, 00, 16, 30, 09, 0a, 01, 00, 02, 00, 10, 00, 11, 0a, 00, 15, 00, 16, 30, 0d, 36, 02, 00, 00, 00, 15, 00, 16, 3b, 00, 1c, 00, 1d, 28, 06, 02, 00, 1c, 00, 22, 30, 11, 1a, 01, 02, 00, 00, 1c, 00, 1d, 11, 00, 21, 00, 22, 30, 26, 15, 02, 00, 00, 00, 21, 00, 22, 26, 00, 25, 00, 29, 2a, 00, 33, 00, 38, 36, 00, 44, 00, 49, 19, 00, 4c, 02, 06, 3e, 02, 0c, 02, 06, 46, 03, 01, 00, 02] +Raw bytes (176): 0x[01, 01, 12, 01, 05, 05, 09, 05, 09, 05, 33, 09, 0d, 09, 0d, 33, 11, 09, 0d, 11, 15, 33, 15, 09, 0d, 05, 33, 09, 0d, 3b, 05, 01, 1d, 43, 05, 47, 1d, 01, 19, 14, 01, 22, 01, 01, 09, 28, 09, 02, 01, 08, 00, 4b, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 30, 19, 1d, 02, 00, 00, 00, 0d, 00, 4b, 05, 00, 10, 00, 11, 28, 03, 02, 00, 10, 00, 16, 30, 09, 0a, 01, 00, 02, 00, 10, 00, 11, 0a, 00, 15, 00, 16, 30, 0d, 2e, 02, 00, 00, 00, 15, 00, 16, 33, 00, 1c, 00, 1d, 28, 06, 02, 00, 1c, 00, 22, 30, 11, 1a, 01, 02, 00, 00, 1c, 00, 1d, 11, 00, 21, 00, 22, 30, 15, 22, 02, 00, 00, 00, 21, 00, 22, 15, 00, 25, 00, 29, 26, 00, 33, 00, 38, 2e, 00, 44, 00, 49, 19, 00, 4c, 02, 06, 36, 02, 0c, 02, 06, 3e, 03, 01, 00, 02] Number of files: 1 - file 0 => global file 1 -Number of expressions: 20 +Number of expressions: 18 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Counter(2) - expression 2 operands: lhs = Counter(1), rhs = Counter(2) -- expression 3 operands: lhs = Counter(1), rhs = Expression(14, Add) +- expression 3 operands: lhs = Counter(1), rhs = Expression(12, Add) - expression 4 operands: lhs = Counter(2), rhs = Counter(3) - expression 5 operands: lhs = Counter(2), rhs = Counter(3) -- expression 6 operands: lhs = Expression(14, Add), rhs = Counter(4) +- expression 6 operands: lhs = Expression(12, Add), rhs = Counter(4) - expression 7 operands: lhs = Counter(2), rhs = Counter(3) - expression 8 operands: lhs = Counter(4), rhs = Counter(5) -- expression 9 operands: lhs = Counter(4), rhs = Counter(5) -- expression 10 operands: lhs = Expression(11, Add), rhs = Counter(4) -- expression 11 operands: lhs = Expression(14, Add), rhs = Counter(5) +- expression 9 operands: lhs = Expression(12, Add), rhs = Counter(5) +- expression 10 operands: lhs = Counter(2), rhs = Counter(3) +- expression 11 operands: lhs = Counter(1), rhs = Expression(12, Add) - expression 12 operands: lhs = Counter(2), rhs = Counter(3) -- expression 13 operands: lhs = Counter(1), rhs = Expression(14, Add) -- expression 14 operands: lhs = Counter(2), rhs = Counter(3) +- expression 13 operands: lhs = Expression(14, Add), rhs = Counter(1) +- expression 14 operands: lhs = Counter(0), rhs = Counter(7) - expression 15 operands: lhs = Expression(16, Add), rhs = Counter(1) -- expression 16 operands: lhs = Counter(0), rhs = Counter(7) -- expression 17 operands: lhs = Expression(18, Add), rhs = Counter(1) -- expression 18 operands: lhs = Expression(19, Add), rhs = Counter(7) -- expression 19 operands: lhs = Counter(0), rhs = Counter(6) +- expression 16 operands: lhs = Expression(17, Add), rhs = Counter(7) +- expression 17 operands: lhs = Counter(0), rhs = Counter(6) Number of file 0 mappings: 20 - Code(Counter(0)) at (prev + 34, 1) to (start + 1, 9) - MCDCDecision { bitmap_idx: 9, conditions_num: 2 } at (prev + 1, 8) to (start + 0, 75) @@ -149,29 +144,28 @@ Number of file 0 mappings: 20 false = (c1 - c2) - Code(Expression(2, Sub)) at (prev + 0, 21) to (start + 0, 22) = (c1 - c2) -- MCDCBranch { true: Counter(3), false: Expression(13, Sub), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 21) to (start + 0, 22) +- MCDCBranch { true: Counter(3), false: Expression(11, Sub), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 21) to (start + 0, 22) true = c3 false = (c1 - (c2 + c3)) -- Code(Expression(14, Add)) at (prev + 0, 28) to (start + 0, 29) +- Code(Expression(12, Add)) at (prev + 0, 28) to (start + 0, 29) = (c2 + c3) - MCDCDecision { bitmap_idx: 6, conditions_num: 2 } at (prev + 0, 28) to (start + 0, 34) - MCDCBranch { true: Counter(4), false: Expression(6, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 28) to (start + 0, 29) true = c4 false = ((c2 + c3) - c4) - Code(Counter(4)) at (prev + 0, 33) to (start + 0, 34) -- MCDCBranch { true: Expression(9, Sub), false: Counter(5), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 33) to (start + 0, 34) - true = (c4 - c5) - false = c5 -- Code(Expression(9, Sub)) at (prev + 0, 37) to (start + 0, 41) - = (c4 - c5) -- Code(Expression(10, Sub)) at (prev + 0, 51) to (start + 0, 56) - = (((c2 + c3) + c5) - c4) -- Code(Expression(13, Sub)) at (prev + 0, 68) to (start + 0, 73) +- MCDCBranch { true: Counter(5), false: Expression(8, Sub), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 33) to (start + 0, 34) + true = c5 + false = (c4 - c5) +- Code(Counter(5)) at (prev + 0, 37) to (start + 0, 41) +- Code(Expression(9, Sub)) at (prev + 0, 51) to (start + 0, 56) + = ((c2 + c3) - c5) +- Code(Expression(11, Sub)) at (prev + 0, 68) to (start + 0, 73) = (c1 - (c2 + c3)) - Code(Counter(6)) at (prev + 0, 76) to (start + 2, 6) -- Code(Expression(15, Sub)) at (prev + 2, 12) to (start + 2, 6) +- Code(Expression(13, Sub)) at (prev + 2, 12) to (start + 2, 6) = ((c0 + c7) - c1) -- Code(Expression(17, Sub)) at (prev + 3, 1) to (start + 0, 2) +- Code(Expression(15, Sub)) at (prev + 3, 1) to (start + 0, 2) = (((c0 + c6) + c7) - c1) Highest counter ID seen: c7 diff --git a/tests/coverage/mcdc/non_control_flow.cov-map b/tests/coverage/mcdc/non_control_flow.cov-map index 0edeff9a586..c282d53c5ac 100644 --- a/tests/coverage/mcdc/non_control_flow.cov-map +++ b/tests/coverage/mcdc/non_control_flow.cov-map @@ -1,124 +1,107 @@ Function name: non_control_flow::assign_3 -Raw bytes (89): 0x[01, 01, 09, 07, 11, 0b, 0d, 05, 09, 01, 05, 01, 05, 01, 23, 05, 11, 01, 23, 05, 11, 0a, 01, 16, 01, 00, 28, 03, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 04, 03, 00, 0d, 00, 18, 30, 05, 12, 01, 00, 02, 00, 0d, 00, 0e, 12, 00, 12, 00, 13, 30, 1e, 11, 02, 03, 00, 00, 12, 00, 13, 1e, 00, 17, 00, 18, 30, 09, 0d, 03, 00, 00, 00, 17, 00, 18, 03, 01, 05, 01, 02] +Raw bytes (79): 0x[01, 01, 04, 01, 05, 01, 0b, 05, 09, 09, 0d, 0a, 01, 16, 01, 00, 28, 01, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 04, 03, 00, 0d, 00, 18, 30, 05, 02, 01, 00, 02, 00, 0d, 00, 0e, 02, 00, 12, 00, 13, 30, 09, 06, 02, 03, 00, 00, 12, 00, 13, 09, 00, 17, 00, 18, 30, 0d, 0e, 03, 00, 00, 00, 17, 00, 18, 01, 01, 05, 01, 02] Number of files: 1 - file 0 => global file 1 -Number of expressions: 9 -- expression 0 operands: lhs = Expression(1, Add), rhs = Counter(4) -- expression 1 operands: lhs = Expression(2, Add), rhs = Counter(3) +Number of expressions: 4 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +- expression 1 operands: lhs = Counter(0), rhs = Expression(2, Add) - expression 2 operands: lhs = Counter(1), rhs = Counter(2) -- expression 3 operands: lhs = Counter(0), rhs = Counter(1) -- expression 4 operands: lhs = Counter(0), rhs = Counter(1) -- expression 5 operands: lhs = Counter(0), rhs = Expression(8, Add) -- expression 6 operands: lhs = Counter(1), rhs = Counter(4) -- expression 7 operands: lhs = Counter(0), rhs = Expression(8, Add) -- expression 8 operands: lhs = Counter(1), rhs = Counter(4) +- expression 3 operands: lhs = Counter(2), rhs = Counter(3) Number of file 0 mappings: 10 - Code(Counter(0)) at (prev + 22, 1) to (start + 0, 40) -- Code(Expression(0, Add)) at (prev + 1, 9) to (start + 0, 10) - = (((c1 + c2) + c3) + c4) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 10) - Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14) - MCDCDecision { bitmap_idx: 4, conditions_num: 3 } at (prev + 0, 13) to (start + 0, 24) -- MCDCBranch { true: Counter(1), false: Expression(4, Sub), condition_id: 1, true_next_id: 0, false_next_id: 2 } at (prev + 0, 13) to (start + 0, 14) +- MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 0, false_next_id: 2 } at (prev + 0, 13) to (start + 0, 14) true = c1 false = (c0 - c1) -- Code(Expression(4, Sub)) at (prev + 0, 18) to (start + 0, 19) +- Code(Expression(0, Sub)) at (prev + 0, 18) to (start + 0, 19) = (c0 - c1) -- MCDCBranch { true: Expression(7, Sub), false: Counter(4), condition_id: 2, true_next_id: 3, false_next_id: 0 } at (prev + 0, 18) to (start + 0, 19) - true = (c0 - (c1 + c4)) - false = c4 -- Code(Expression(7, Sub)) at (prev + 0, 23) to (start + 0, 24) - = (c0 - (c1 + c4)) -- MCDCBranch { true: Counter(2), false: Counter(3), condition_id: 3, true_next_id: 0, false_next_id: 0 } at (prev + 0, 23) to (start + 0, 24) +- MCDCBranch { true: Counter(2), false: Expression(1, Sub), condition_id: 2, true_next_id: 3, false_next_id: 0 } at (prev + 0, 18) to (start + 0, 19) true = c2 - false = c3 -- Code(Expression(0, Add)) at (prev + 1, 5) to (start + 1, 2) - = (((c1 + c2) + c3) + c4) -Highest counter ID seen: c4 + false = (c0 - (c1 + c2)) +- Code(Counter(2)) at (prev + 0, 23) to (start + 0, 24) +- MCDCBranch { true: Counter(3), false: Expression(3, Sub), condition_id: 3, true_next_id: 0, false_next_id: 0 } at (prev + 0, 23) to (start + 0, 24) + true = c3 + false = (c2 - c3) +- Code(Counter(0)) at (prev + 1, 5) to (start + 1, 2) +Highest counter ID seen: c3 Function name: non_control_flow::assign_3_bis -Raw bytes (81): 0x[01, 01, 05, 07, 11, 09, 0d, 01, 05, 05, 09, 01, 09, 0a, 01, 1b, 01, 00, 2c, 03, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 05, 03, 00, 0d, 00, 18, 30, 05, 0a, 01, 03, 02, 00, 0d, 00, 0e, 05, 00, 12, 00, 13, 30, 09, 0e, 03, 00, 02, 00, 12, 00, 13, 12, 00, 17, 00, 18, 30, 0d, 11, 02, 00, 00, 00, 17, 00, 18, 03, 01, 05, 01, 02] +Raw bytes (81): 0x[01, 01, 05, 01, 05, 05, 09, 01, 09, 01, 13, 09, 0d, 0a, 01, 1b, 01, 00, 2c, 01, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 05, 03, 00, 0d, 00, 18, 30, 05, 02, 01, 03, 02, 00, 0d, 00, 0e, 05, 00, 12, 00, 13, 30, 09, 06, 03, 00, 02, 00, 12, 00, 13, 0a, 00, 17, 00, 18, 30, 0d, 0e, 02, 00, 00, 00, 17, 00, 18, 01, 01, 05, 01, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 5 -- expression 0 operands: lhs = Expression(1, Add), rhs = Counter(4) -- expression 1 operands: lhs = Counter(2), rhs = Counter(3) -- expression 2 operands: lhs = Counter(0), rhs = Counter(1) -- expression 3 operands: lhs = Counter(1), rhs = Counter(2) -- expression 4 operands: lhs = Counter(0), rhs = Counter(2) +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +- expression 1 operands: lhs = Counter(1), rhs = Counter(2) +- expression 2 operands: lhs = Counter(0), rhs = Counter(2) +- expression 3 operands: lhs = Counter(0), rhs = Expression(4, Add) +- expression 4 operands: lhs = Counter(2), rhs = Counter(3) Number of file 0 mappings: 10 - Code(Counter(0)) at (prev + 27, 1) to (start + 0, 44) -- Code(Expression(0, Add)) at (prev + 1, 9) to (start + 0, 10) - = ((c2 + c3) + c4) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 10) - Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14) - MCDCDecision { bitmap_idx: 5, conditions_num: 3 } at (prev + 0, 13) to (start + 0, 24) -- MCDCBranch { true: Counter(1), false: Expression(2, Sub), condition_id: 1, true_next_id: 3, false_next_id: 2 } at (prev + 0, 13) to (start + 0, 14) +- MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 3, false_next_id: 2 } at (prev + 0, 13) to (start + 0, 14) true = c1 false = (c0 - c1) - Code(Counter(1)) at (prev + 0, 18) to (start + 0, 19) -- MCDCBranch { true: Counter(2), false: Expression(3, Sub), condition_id: 3, true_next_id: 0, false_next_id: 2 } at (prev + 0, 18) to (start + 0, 19) +- MCDCBranch { true: Counter(2), false: Expression(1, Sub), condition_id: 3, true_next_id: 0, false_next_id: 2 } at (prev + 0, 18) to (start + 0, 19) true = c2 false = (c1 - c2) -- Code(Expression(4, Sub)) at (prev + 0, 23) to (start + 0, 24) +- Code(Expression(2, Sub)) at (prev + 0, 23) to (start + 0, 24) = (c0 - c2) -- MCDCBranch { true: Counter(3), false: Counter(4), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 23) to (start + 0, 24) +- MCDCBranch { true: Counter(3), false: Expression(3, Sub), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 23) to (start + 0, 24) true = c3 - false = c4 -- Code(Expression(0, Add)) at (prev + 1, 5) to (start + 1, 2) - = ((c2 + c3) + c4) -Highest counter ID seen: c4 + false = (c0 - (c2 + c3)) +- Code(Counter(0)) at (prev + 1, 5) to (start + 1, 2) +Highest counter ID seen: c3 Function name: non_control_flow::assign_and -Raw bytes (64): 0x[01, 01, 04, 07, 05, 0b, 0d, 01, 09, 01, 05, 08, 01, 0c, 01, 00, 21, 02, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 03, 02, 00, 0d, 00, 13, 30, 05, 0e, 01, 02, 00, 00, 0d, 00, 0e, 05, 00, 12, 00, 13, 30, 09, 0d, 02, 00, 00, 00, 12, 00, 13, 02, 01, 05, 01, 02] +Raw bytes (60): 0x[01, 01, 02, 01, 05, 05, 09, 08, 01, 0c, 01, 00, 21, 01, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 03, 02, 00, 0d, 00, 13, 30, 05, 02, 01, 02, 00, 00, 0d, 00, 0e, 05, 00, 12, 00, 13, 30, 09, 06, 02, 00, 00, 00, 12, 00, 13, 01, 01, 05, 01, 02] Number of files: 1 - file 0 => global file 1 -Number of expressions: 4 -- expression 0 operands: lhs = Expression(1, Add), rhs = Counter(1) -- expression 1 operands: lhs = Expression(2, Add), rhs = Counter(3) -- expression 2 operands: lhs = Counter(0), rhs = Counter(2) -- expression 3 operands: lhs = Counter(0), rhs = Counter(1) +Number of expressions: 2 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +- expression 1 operands: lhs = Counter(1), rhs = Counter(2) Number of file 0 mappings: 8 - Code(Counter(0)) at (prev + 12, 1) to (start + 0, 33) -- Code(Expression(0, Sub)) at (prev + 1, 9) to (start + 0, 10) - = (((c0 + c2) + c3) - c1) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 10) - Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14) - MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 0, 13) to (start + 0, 19) -- MCDCBranch { true: Counter(1), false: Expression(3, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 13) to (start + 0, 14) +- MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 13) to (start + 0, 14) true = c1 false = (c0 - c1) - Code(Counter(1)) at (prev + 0, 18) to (start + 0, 19) -- MCDCBranch { true: Counter(2), false: Counter(3), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 18) to (start + 0, 19) +- MCDCBranch { true: Counter(2), false: Expression(1, Sub), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 18) to (start + 0, 19) true = c2 - false = c3 -- Code(Expression(0, Sub)) at (prev + 1, 5) to (start + 1, 2) - = (((c0 + c2) + c3) - c1) -Highest counter ID seen: c3 + false = (c1 - c2) +- Code(Counter(0)) at (prev + 1, 5) to (start + 1, 2) +Highest counter ID seen: c2 Function name: non_control_flow::assign_or -Raw bytes (64): 0x[01, 01, 04, 07, 0d, 05, 09, 01, 05, 01, 05, 08, 01, 11, 01, 00, 20, 03, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 03, 02, 00, 0d, 00, 13, 30, 05, 0e, 01, 00, 02, 00, 0d, 00, 0e, 0e, 00, 12, 00, 13, 30, 09, 0d, 02, 00, 00, 00, 12, 00, 13, 03, 01, 05, 01, 02] +Raw bytes (62): 0x[01, 01, 03, 01, 05, 01, 0b, 05, 09, 08, 01, 11, 01, 00, 20, 01, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 03, 02, 00, 0d, 00, 13, 30, 05, 02, 01, 00, 02, 00, 0d, 00, 0e, 02, 00, 12, 00, 13, 30, 09, 06, 02, 00, 00, 00, 12, 00, 13, 01, 01, 05, 01, 02] Number of files: 1 - file 0 => global file 1 -Number of expressions: 4 -- expression 0 operands: lhs = Expression(1, Add), rhs = Counter(3) -- expression 1 operands: lhs = Counter(1), rhs = Counter(2) -- expression 2 operands: lhs = Counter(0), rhs = Counter(1) -- expression 3 operands: lhs = Counter(0), rhs = Counter(1) +Number of expressions: 3 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +- expression 1 operands: lhs = Counter(0), rhs = Expression(2, Add) +- expression 2 operands: lhs = Counter(1), rhs = Counter(2) Number of file 0 mappings: 8 - Code(Counter(0)) at (prev + 17, 1) to (start + 0, 32) -- Code(Expression(0, Add)) at (prev + 1, 9) to (start + 0, 10) - = ((c1 + c2) + c3) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 10) - Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14) - MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 0, 13) to (start + 0, 19) -- MCDCBranch { true: Counter(1), false: Expression(3, Sub), condition_id: 1, true_next_id: 0, false_next_id: 2 } at (prev + 0, 13) to (start + 0, 14) +- MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 0, false_next_id: 2 } at (prev + 0, 13) to (start + 0, 14) true = c1 false = (c0 - c1) -- Code(Expression(3, Sub)) at (prev + 0, 18) to (start + 0, 19) +- Code(Expression(0, Sub)) at (prev + 0, 18) to (start + 0, 19) = (c0 - c1) -- MCDCBranch { true: Counter(2), false: Counter(3), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 18) to (start + 0, 19) +- MCDCBranch { true: Counter(2), false: Expression(1, Sub), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 18) to (start + 0, 19) true = c2 - false = c3 -- Code(Expression(0, Add)) at (prev + 1, 5) to (start + 1, 2) - = ((c1 + c2) + c3) -Highest counter ID seen: c3 + false = (c0 - (c1 + c2)) +- Code(Counter(0)) at (prev + 1, 5) to (start + 1, 2) +Highest counter ID seen: c2 Function name: non_control_flow::foo Raw bytes (9): 0x[01, 01, 00, 01, 01, 25, 01, 02, 02] @@ -130,14 +113,12 @@ Number of file 0 mappings: 1 Highest counter ID seen: c0 Function name: non_control_flow::func_call -Raw bytes (54): 0x[01, 01, 04, 01, 05, 0b, 05, 0f, 0d, 01, 09, 06, 01, 29, 01, 01, 0a, 28, 03, 02, 01, 09, 00, 0f, 30, 05, 02, 01, 02, 00, 00, 09, 00, 0a, 05, 00, 0e, 00, 0f, 30, 09, 0d, 02, 00, 00, 00, 0e, 00, 0f, 06, 01, 01, 00, 02] +Raw bytes (50): 0x[01, 01, 02, 01, 05, 05, 09, 06, 01, 29, 01, 01, 0a, 28, 03, 02, 01, 09, 00, 0f, 30, 05, 02, 01, 02, 00, 00, 09, 00, 0a, 05, 00, 0e, 00, 0f, 30, 09, 06, 02, 00, 00, 00, 0e, 00, 0f, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 -Number of expressions: 4 +Number of expressions: 2 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -- expression 1 operands: lhs = Expression(2, Add), rhs = Counter(1) -- expression 2 operands: lhs = Expression(3, Add), rhs = Counter(3) -- expression 3 operands: lhs = Counter(0), rhs = Counter(2) +- expression 1 operands: lhs = Counter(1), rhs = Counter(2) Number of file 0 mappings: 6 - Code(Counter(0)) at (prev + 41, 1) to (start + 1, 10) - MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 1, 9) to (start + 0, 15) @@ -145,66 +126,46 @@ Number of file 0 mappings: 6 true = c1 false = (c0 - c1) - Code(Counter(1)) at (prev + 0, 14) to (start + 0, 15) -- MCDCBranch { true: Counter(2), false: Counter(3), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 14) to (start + 0, 15) +- MCDCBranch { true: Counter(2), false: Expression(1, Sub), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 14) to (start + 0, 15) true = c2 - false = c3 -- Code(Expression(1, Sub)) at (prev + 1, 1) to (start + 0, 2) - = (((c0 + c2) + c3) - c1) -Highest counter ID seen: c3 + false = (c1 - c2) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) +Highest counter ID seen: c2 Function name: non_control_flow::right_comb_tree -Raw bytes (139): 0x[01, 01, 13, 07, 05, 0b, 19, 0f, 15, 13, 11, 17, 0d, 01, 09, 01, 05, 05, 09, 05, 09, 05, 4b, 09, 0d, 05, 4b, 09, 0d, 05, 47, 4b, 11, 09, 0d, 05, 47, 4b, 11, 09, 0d, 0e, 01, 20, 01, 00, 41, 02, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 06, 05, 00, 0d, 00, 2a, 30, 05, 1a, 01, 02, 00, 00, 0d, 00, 0e, 05, 00, 13, 00, 14, 30, 22, 09, 02, 03, 00, 00, 13, 00, 14, 22, 00, 19, 00, 1a, 30, 2e, 0d, 03, 04, 00, 00, 19, 00, 1a, 2e, 00, 1f, 00, 20, 30, 42, 11, 04, 05, 00, 00, 1f, 00, 20, 42, 00, 24, 00, 27, 30, 15, 19, 05, 00, 00, 00, 24, 00, 27, 02, 01, 05, 01, 02] +Raw bytes (111): 0x[01, 01, 05, 01, 05, 05, 09, 09, 0d, 0d, 11, 11, 15, 0e, 01, 20, 01, 00, 41, 01, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 06, 05, 00, 0d, 00, 2a, 30, 05, 02, 01, 02, 00, 00, 0d, 00, 0e, 05, 00, 13, 00, 14, 30, 09, 06, 02, 03, 00, 00, 13, 00, 14, 09, 00, 19, 00, 1a, 30, 0d, 0a, 03, 04, 00, 00, 19, 00, 1a, 0d, 00, 1f, 00, 20, 30, 11, 0e, 04, 05, 00, 00, 1f, 00, 20, 11, 00, 24, 00, 27, 30, 15, 12, 05, 00, 00, 00, 24, 00, 27, 01, 01, 05, 01, 02] Number of files: 1 - file 0 => global file 1 -Number of expressions: 19 -- expression 0 operands: lhs = Expression(1, Add), rhs = Counter(1) -- expression 1 operands: lhs = Expression(2, Add), rhs = Counter(6) -- expression 2 operands: lhs = Expression(3, Add), rhs = Counter(5) -- expression 3 operands: lhs = Expression(4, Add), rhs = Counter(4) -- expression 4 operands: lhs = Expression(5, Add), rhs = Counter(3) -- expression 5 operands: lhs = Counter(0), rhs = Counter(2) -- expression 6 operands: lhs = Counter(0), rhs = Counter(1) -- expression 7 operands: lhs = Counter(1), rhs = Counter(2) -- expression 8 operands: lhs = Counter(1), rhs = Counter(2) -- expression 9 operands: lhs = Counter(1), rhs = Expression(18, Add) -- expression 10 operands: lhs = Counter(2), rhs = Counter(3) -- expression 11 operands: lhs = Counter(1), rhs = Expression(18, Add) -- expression 12 operands: lhs = Counter(2), rhs = Counter(3) -- expression 13 operands: lhs = Counter(1), rhs = Expression(17, Add) -- expression 14 operands: lhs = Expression(18, Add), rhs = Counter(4) -- expression 15 operands: lhs = Counter(2), rhs = Counter(3) -- expression 16 operands: lhs = Counter(1), rhs = Expression(17, Add) -- expression 17 operands: lhs = Expression(18, Add), rhs = Counter(4) -- expression 18 operands: lhs = Counter(2), rhs = Counter(3) +Number of expressions: 5 +- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +- expression 1 operands: lhs = Counter(1), rhs = Counter(2) +- expression 2 operands: lhs = Counter(2), rhs = Counter(3) +- expression 3 operands: lhs = Counter(3), rhs = Counter(4) +- expression 4 operands: lhs = Counter(4), rhs = Counter(5) Number of file 0 mappings: 14 - Code(Counter(0)) at (prev + 32, 1) to (start + 0, 65) -- Code(Expression(0, Sub)) at (prev + 1, 9) to (start + 0, 10) - = ((((((c0 + c2) + c3) + c4) + c5) + c6) - c1) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 10) - Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14) - MCDCDecision { bitmap_idx: 6, conditions_num: 5 } at (prev + 0, 13) to (start + 0, 42) -- MCDCBranch { true: Counter(1), false: Expression(6, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 13) to (start + 0, 14) +- MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 13) to (start + 0, 14) true = c1 false = (c0 - c1) - Code(Counter(1)) at (prev + 0, 19) to (start + 0, 20) -- MCDCBranch { true: Expression(8, Sub), false: Counter(2), condition_id: 2, true_next_id: 3, false_next_id: 0 } at (prev + 0, 19) to (start + 0, 20) - true = (c1 - c2) - false = c2 -- Code(Expression(8, Sub)) at (prev + 0, 25) to (start + 0, 26) - = (c1 - c2) -- MCDCBranch { true: Expression(11, Sub), false: Counter(3), condition_id: 3, true_next_id: 4, false_next_id: 0 } at (prev + 0, 25) to (start + 0, 26) - true = (c1 - (c2 + c3)) - false = c3 -- Code(Expression(11, Sub)) at (prev + 0, 31) to (start + 0, 32) - = (c1 - (c2 + c3)) -- MCDCBranch { true: Expression(16, Sub), false: Counter(4), condition_id: 4, true_next_id: 5, false_next_id: 0 } at (prev + 0, 31) to (start + 0, 32) - true = (c1 - ((c2 + c3) + c4)) - false = c4 -- Code(Expression(16, Sub)) at (prev + 0, 36) to (start + 0, 39) - = (c1 - ((c2 + c3) + c4)) -- MCDCBranch { true: Counter(5), false: Counter(6), condition_id: 5, true_next_id: 0, false_next_id: 0 } at (prev + 0, 36) to (start + 0, 39) +- MCDCBranch { true: Counter(2), false: Expression(1, Sub), condition_id: 2, true_next_id: 3, false_next_id: 0 } at (prev + 0, 19) to (start + 0, 20) + true = c2 + false = (c1 - c2) +- Code(Counter(2)) at (prev + 0, 25) to (start + 0, 26) +- MCDCBranch { true: Counter(3), false: Expression(2, Sub), condition_id: 3, true_next_id: 4, false_next_id: 0 } at (prev + 0, 25) to (start + 0, 26) + true = c3 + false = (c2 - c3) +- Code(Counter(3)) at (prev + 0, 31) to (start + 0, 32) +- MCDCBranch { true: Counter(4), false: Expression(3, Sub), condition_id: 4, true_next_id: 5, false_next_id: 0 } at (prev + 0, 31) to (start + 0, 32) + true = c4 + false = (c3 - c4) +- Code(Counter(4)) at (prev + 0, 36) to (start + 0, 39) +- MCDCBranch { true: Counter(5), false: Expression(4, Sub), condition_id: 5, true_next_id: 0, false_next_id: 0 } at (prev + 0, 36) to (start + 0, 39) true = c5 - false = c6 -- Code(Expression(0, Sub)) at (prev + 1, 5) to (start + 1, 2) - = ((((((c0 + c2) + c3) + c4) + c5) + c6) - c1) -Highest counter ID seen: c6 + false = (c4 - c5) +- Code(Counter(0)) at (prev + 1, 5) to (start + 1, 2) +Highest counter ID seen: c5 diff --git a/tests/coverage/try_error_result.cov-map b/tests/coverage/try_error_result.cov-map index 7fbd2cc642e..f90b73592bd 100644 --- a/tests/coverage/try_error_result.cov-map +++ b/tests/coverage/try_error_result.cov-map @@ -55,18 +55,15 @@ Number of file 0 mappings: 4 Highest counter ID seen: c1 Function name: try_error_result::test1 -Raw bytes (75): 0x[01, 01, 08, 07, 09, 01, 00, 03, 0d, 03, 13, 0d, 11, 1b, 00, 1f, 00, 0d, 15, 0b, 01, 0d, 01, 02, 17, 03, 07, 09, 00, 0e, 0a, 02, 09, 04, 1a, 11, 06, 0d, 00, 29, 15, 00, 29, 00, 2a, 00, 01, 0d, 00, 2a, 00, 00, 2a, 00, 2b, 0e, 04, 0d, 00, 2a, 00, 00, 2a, 00, 2b, 0d, 03, 05, 00, 0b, 17, 01, 01, 00, 02] +Raw bytes (69): 0x[01, 01, 05, 07, 09, 01, 00, 03, 0d, 03, 13, 0d, 11, 0b, 01, 0d, 01, 02, 17, 03, 07, 09, 00, 0e, 0a, 02, 09, 04, 1a, 11, 06, 0d, 00, 29, 15, 00, 29, 00, 2a, 00, 01, 0d, 00, 2a, 00, 00, 2a, 00, 2b, 0e, 04, 0d, 00, 2a, 00, 00, 2a, 00, 2b, 0d, 03, 05, 00, 0b, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 -Number of expressions: 8 +Number of expressions: 5 - expression 0 operands: lhs = Expression(1, Add), rhs = Counter(2) - expression 1 operands: lhs = Counter(0), rhs = Zero - expression 2 operands: lhs = Expression(0, Add), rhs = Counter(3) - expression 3 operands: lhs = Expression(0, Add), rhs = Expression(4, Add) - expression 4 operands: lhs = Counter(3), rhs = Counter(4) -- expression 5 operands: lhs = Expression(6, Add), rhs = Zero -- expression 6 operands: lhs = Expression(7, Add), rhs = Zero -- expression 7 operands: lhs = Counter(3), rhs = Counter(5) Number of file 0 mappings: 11 - Code(Counter(0)) at (prev + 13, 1) to (start + 2, 23) - Code(Expression(0, Add)) at (prev + 7, 9) to (start + 0, 14) @@ -81,8 +78,7 @@ Number of file 0 mappings: 11 = (((c0 + Zero) + c2) - (c3 + c4)) - Code(Zero) at (prev + 0, 42) to (start + 0, 43) - Code(Counter(3)) at (prev + 3, 5) to (start + 0, 11) -- Code(Expression(5, Add)) at (prev + 1, 1) to (start + 0, 2) - = (((c3 + c5) + Zero) + Zero) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c5 Function name: try_error_result::test2 diff --git a/tests/coverage/unicode.cov-map b/tests/coverage/unicode.cov-map index 630ab4ce47e..0a4e367bb9e 100644 --- a/tests/coverage/unicode.cov-map +++ b/tests/coverage/unicode.cov-map @@ -1,14 +1,10 @@ Function name: unicode::main -Raw bytes (61): 0x[01, 01, 06, 01, 05, 0b, 09, 01, 11, 13, 09, 17, 11, 01, 0d, 09, 01, 0e, 01, 00, 0b, 05, 01, 09, 00, 0c, 03, 00, 10, 00, 1b, 05, 00, 1c, 00, 28, 01, 02, 08, 00, 25, 09, 00, 29, 00, 46, 0d, 00, 47, 02, 06, 06, 02, 05, 00, 06, 0e, 02, 05, 01, 02] +Raw bytes (53): 0x[01, 01, 02, 01, 05, 01, 0d, 09, 01, 0e, 01, 00, 0b, 05, 01, 09, 00, 0c, 03, 00, 10, 00, 1b, 05, 00, 1c, 00, 28, 01, 02, 08, 00, 25, 09, 00, 29, 00, 46, 0d, 00, 47, 02, 06, 06, 02, 05, 00, 06, 01, 02, 05, 01, 02] Number of files: 1 - file 0 => global file 1 -Number of expressions: 6 +Number of expressions: 2 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -- expression 1 operands: lhs = Expression(2, Add), rhs = Counter(2) -- expression 2 operands: lhs = Counter(0), rhs = Counter(4) -- expression 3 operands: lhs = Expression(4, Add), rhs = Counter(2) -- expression 4 operands: lhs = Expression(5, Add), rhs = Counter(4) -- expression 5 operands: lhs = Counter(0), rhs = Counter(3) +- expression 1 operands: lhs = Counter(0), rhs = Counter(3) Number of file 0 mappings: 9 - Code(Counter(0)) at (prev + 14, 1) to (start + 0, 11) - Code(Counter(1)) at (prev + 1, 9) to (start + 0, 12) @@ -19,9 +15,8 @@ Number of file 0 mappings: 9 - Code(Counter(2)) at (prev + 0, 41) to (start + 0, 70) - Code(Counter(3)) at (prev + 0, 71) to (start + 2, 6) - Code(Expression(1, Sub)) at (prev + 2, 5) to (start + 0, 6) - = ((c0 + c4) - c2) -- Code(Expression(3, Sub)) at (prev + 2, 5) to (start + 1, 2) - = (((c0 + c3) + c4) - c2) + = (c0 - c3) +- Code(Counter(0)) at (prev + 2, 5) to (start + 1, 2) Highest counter ID seen: c3 Function name: unicode::ä»– (unused) diff --git a/tests/coverage/while_early_ret.cov-map b/tests/coverage/while_early_ret.cov-map index ade770597e2..554056fa801 100644 --- a/tests/coverage/while_early_ret.cov-map +++ b/tests/coverage/while_early_ret.cov-map @@ -1,12 +1,12 @@ Function name: while_early_ret::main -Raw bytes (59): 0x[01, 01, 05, 01, 05, 03, 09, 01, 09, 13, 11, 09, 0d, 09, 01, 05, 01, 01, 1b, 03, 03, 09, 02, 0a, 06, 05, 0d, 02, 0e, 0a, 06, 15, 02, 16, 0d, 04, 15, 00, 1b, 11, 04, 15, 00, 1b, 05, 03, 0a, 03, 0a, 09, 06, 05, 00, 0b, 0f, 01, 01, 00, 02] +Raw bytes (59): 0x[01, 01, 05, 01, 05, 03, 09, 01, 09, 01, 13, 09, 0d, 09, 01, 05, 01, 01, 1b, 03, 03, 09, 02, 0a, 06, 05, 0d, 02, 0e, 0a, 06, 15, 02, 16, 0d, 04, 15, 00, 1b, 0e, 04, 15, 00, 1b, 05, 03, 0a, 03, 0a, 09, 06, 05, 00, 0b, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 5 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Expression(0, Add), rhs = Counter(2) - expression 2 operands: lhs = Counter(0), rhs = Counter(2) -- expression 3 operands: lhs = Expression(4, Add), rhs = Counter(4) +- expression 3 operands: lhs = Counter(0), rhs = Expression(4, Add) - expression 4 operands: lhs = Counter(2), rhs = Counter(3) Number of file 0 mappings: 9 - Code(Counter(0)) at (prev + 5, 1) to (start + 1, 27) @@ -17,10 +17,10 @@ Number of file 0 mappings: 9 - Code(Expression(2, Sub)) at (prev + 6, 21) to (start + 2, 22) = (c0 - c2) - Code(Counter(3)) at (prev + 4, 21) to (start + 0, 27) -- Code(Counter(4)) at (prev + 4, 21) to (start + 0, 27) +- Code(Expression(3, Sub)) at (prev + 4, 21) to (start + 0, 27) + = (c0 - (c2 + c3)) - Code(Counter(1)) at (prev + 3, 10) to (start + 3, 10) - Code(Counter(2)) at (prev + 6, 5) to (start + 0, 11) -- Code(Expression(3, Add)) at (prev + 1, 1) to (start + 0, 2) - = ((c2 + c3) + c4) -Highest counter ID seen: c4 +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) +Highest counter ID seen: c3 diff --git a/tests/coverage/yield.cov-map b/tests/coverage/yield.cov-map index e01ec8f9edb..868fec4b107 100644 --- a/tests/coverage/yield.cov-map +++ b/tests/coverage/yield.cov-map @@ -1,19 +1,13 @@ Function name: yield::main -Raw bytes (106): 0x[01, 01, 0b, 05, 00, 0d, 11, 0d, 23, 11, 15, 11, 15, 0d, 23, 11, 15, 0d, 23, 11, 15, 19, 1d, 25, 29, 10, 01, 07, 01, 01, 16, 01, 07, 0b, 00, 2e, 0d, 01, 27, 00, 29, 03, 01, 0e, 00, 34, 0d, 02, 0b, 00, 2e, 06, 01, 22, 00, 27, 1e, 00, 2c, 00, 2e, 23, 01, 0e, 00, 34, 1e, 03, 09, 00, 16, 1e, 08, 0b, 00, 2e, 21, 01, 27, 00, 29, 27, 01, 0e, 00, 34, 21, 02, 0b, 00, 2e, 2d, 01, 27, 00, 29, 2b, 01, 0e, 00, 34, 2d, 02, 01, 00, 02] +Raw bytes (94): 0x[01, 01, 05, 05, 00, 0d, 15, 0d, 11, 19, 1d, 25, 29, 10, 01, 07, 01, 01, 16, 01, 07, 0b, 00, 2e, 0d, 01, 27, 00, 29, 03, 01, 0e, 00, 34, 0d, 02, 0b, 00, 2e, 06, 01, 22, 00, 27, 11, 00, 2c, 00, 2e, 0a, 01, 0e, 00, 34, 11, 03, 09, 00, 16, 11, 08, 0b, 00, 2e, 21, 01, 27, 00, 29, 0f, 01, 0e, 00, 34, 21, 02, 0b, 00, 2e, 2d, 01, 27, 00, 29, 13, 01, 0e, 00, 34, 2d, 02, 01, 00, 02] Number of files: 1 - file 0 => global file 1 -Number of expressions: 11 +Number of expressions: 5 - expression 0 operands: lhs = Counter(1), rhs = Zero -- expression 1 operands: lhs = Counter(3), rhs = Counter(4) -- expression 2 operands: lhs = Counter(3), rhs = Expression(8, Add) -- expression 3 operands: lhs = Counter(4), rhs = Counter(5) -- expression 4 operands: lhs = Counter(4), rhs = Counter(5) -- expression 5 operands: lhs = Counter(3), rhs = Expression(8, Add) -- expression 6 operands: lhs = Counter(4), rhs = Counter(5) -- expression 7 operands: lhs = Counter(3), rhs = Expression(8, Add) -- expression 8 operands: lhs = Counter(4), rhs = Counter(5) -- expression 9 operands: lhs = Counter(6), rhs = Counter(7) -- expression 10 operands: lhs = Counter(9), rhs = Counter(10) +- expression 1 operands: lhs = Counter(3), rhs = Counter(5) +- expression 2 operands: lhs = Counter(3), rhs = Counter(4) +- expression 3 operands: lhs = Counter(6), rhs = Counter(7) +- expression 4 operands: lhs = Counter(9), rhs = Counter(10) Number of file 0 mappings: 16 - Code(Counter(0)) at (prev + 7, 1) to (start + 1, 22) - Code(Counter(0)) at (prev + 7, 11) to (start + 0, 46) @@ -22,21 +16,18 @@ Number of file 0 mappings: 16 = (c1 + Zero) - Code(Counter(3)) at (prev + 2, 11) to (start + 0, 46) - Code(Expression(1, Sub)) at (prev + 1, 34) to (start + 0, 39) + = (c3 - c5) +- Code(Counter(4)) at (prev + 0, 44) to (start + 0, 46) +- Code(Expression(2, Sub)) at (prev + 1, 14) to (start + 0, 52) = (c3 - c4) -- Code(Expression(7, Sub)) at (prev + 0, 44) to (start + 0, 46) - = (c3 - (c4 + c5)) -- Code(Expression(8, Add)) at (prev + 1, 14) to (start + 0, 52) - = (c4 + c5) -- Code(Expression(7, Sub)) at (prev + 3, 9) to (start + 0, 22) - = (c3 - (c4 + c5)) -- Code(Expression(7, Sub)) at (prev + 8, 11) to (start + 0, 46) - = (c3 - (c4 + c5)) +- Code(Counter(4)) at (prev + 3, 9) to (start + 0, 22) +- Code(Counter(4)) at (prev + 8, 11) to (start + 0, 46) - Code(Counter(8)) at (prev + 1, 39) to (start + 0, 41) -- Code(Expression(9, Add)) at (prev + 1, 14) to (start + 0, 52) +- Code(Expression(3, Add)) at (prev + 1, 14) to (start + 0, 52) = (c6 + c7) - Code(Counter(8)) at (prev + 2, 11) to (start + 0, 46) - Code(Counter(11)) at (prev + 1, 39) to (start + 0, 41) -- Code(Expression(10, Add)) at (prev + 1, 14) to (start + 0, 52) +- Code(Expression(4, Add)) at (prev + 1, 14) to (start + 0, 52) = (c9 + c10) - Code(Counter(11)) at (prev + 2, 1) to (start + 0, 2) Highest counter ID seen: c11 diff --git a/tests/crashes/124375.rs b/tests/crashes/124375.rs deleted file mode 100644 index 1d877caeb8b..00000000000 --- a/tests/crashes/124375.rs +++ /dev/null @@ -1,11 +0,0 @@ -//@ known-bug: #124375 -//@ compile-flags: -Zmir-opt-level=0 -//@ only-x86_64 -#![crate_type = "lib"] -#![feature(naked_functions)] -use std::arch::naked_asm; - -#[naked] -pub unsafe extern "C" fn naked_with_args_and_return(a: isize, b: isize) -> isize { - naked_asm!("lea rax, [rdi + rsi]", "ret"); -} diff --git a/tests/crashes/131227.rs b/tests/crashes/131227.rs deleted file mode 100644 index f46185b5b4a..00000000000 --- a/tests/crashes/131227.rs +++ /dev/null @@ -1,16 +0,0 @@ -//@ known-bug: #131227 -//@ compile-flags: -Zmir-opt-level=3 - -static mut G: () = (); - -fn myfunc() -> i32 { - let var = &raw mut G; - if var.is_null() { - return 0; - } - 0 -} - -fn main() { - myfunc(); -} diff --git a/tests/run-make/const-trait-stable-toolchain/const-super-trait-nightly-disabled.stderr b/tests/run-make/const-trait-stable-toolchain/const-super-trait-nightly-disabled.stderr new file mode 100644 index 00000000000..596f7c510be --- /dev/null +++ b/tests/run-make/const-trait-stable-toolchain/const-super-trait-nightly-disabled.stderr @@ -0,0 +1,66 @@ +error: `~const` is not allowed here + --> const-super-trait.rs:7:12 + | +LL | trait Bar: ~const Foo {} + | ^^^^^^ + | +note: this trait is not a `#[const_trait]`, so it cannot have `~const` trait bounds + --> const-super-trait.rs:7:1 + | +LL | trait Bar: ~const Foo {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0658]: const trait impls are experimental + --> const-super-trait.rs:7:12 + | +LL | trait Bar: ~const Foo {} + | ^^^^^^ + | + = note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information + = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: const trait impls are experimental + --> const-super-trait.rs:9:17 + | +LL | const fn foo<T: ~const Bar>(x: &T) { + | ^^^^^^ + | + = note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information + = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: `~const` can only be applied to `#[const_trait]` traits + --> const-super-trait.rs:7:12 + | +LL | trait Bar: ~const Foo {} + | ^^^^^^ can't be applied to `Foo` + | +help: enable `#![feature(const_trait_impl)]` in your crate and mark `Foo` as `#[const_trait]` to allow it to have `const` implementations + | +LL | #[const_trait] trait Foo { + | ++++++++++++++ + +error: `~const` can only be applied to `#[const_trait]` traits + --> const-super-trait.rs:9:17 + | +LL | const fn foo<T: ~const Bar>(x: &T) { + | ^^^^^^ can't be applied to `Bar` + | +help: enable `#![feature(const_trait_impl)]` in your crate and mark `Bar` as `#[const_trait]` to allow it to have `const` implementations + | +LL | #[const_trait] trait Bar: ~const Foo {} + | ++++++++++++++ + +error[E0015]: cannot call non-const fn `<T as Foo>::a` in constant functions + --> const-super-trait.rs:10:7 + | +LL | x.a(); + | ^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + +error: aborting due to 6 previous errors + +Some errors have detailed explanations: E0015, E0658. +For more information about an error, try `rustc --explain E0015`. diff --git a/tests/run-make/const-trait-stable-toolchain/const-super-trait-nightly-enabled.stderr b/tests/run-make/const-trait-stable-toolchain/const-super-trait-nightly-enabled.stderr new file mode 100644 index 00000000000..7235278d1bd --- /dev/null +++ b/tests/run-make/const-trait-stable-toolchain/const-super-trait-nightly-enabled.stderr @@ -0,0 +1,45 @@ +error: `~const` is not allowed here + --> const-super-trait.rs:7:12 + | +LL | trait Bar: ~const Foo {} + | ^^^^^^ + | +note: this trait is not a `#[const_trait]`, so it cannot have `~const` trait bounds + --> const-super-trait.rs:7:1 + | +LL | trait Bar: ~const Foo {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `~const` can only be applied to `#[const_trait]` traits + --> const-super-trait.rs:7:12 + | +LL | trait Bar: ~const Foo {} + | ^^^^^^ can't be applied to `Foo` + | +help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations + | +LL | #[const_trait] trait Foo { + | ++++++++++++++ + +error: `~const` can only be applied to `#[const_trait]` traits + --> const-super-trait.rs:9:17 + | +LL | const fn foo<T: ~const Bar>(x: &T) { + | ^^^^^^ can't be applied to `Bar` + | +help: mark `Bar` as `#[const_trait]` to allow it to have `const` implementations + | +LL | #[const_trait] trait Bar: ~const Foo {} + | ++++++++++++++ + +error[E0015]: cannot call non-const fn `<T as Foo>::a` in constant functions + --> const-super-trait.rs:10:7 + | +LL | x.a(); + | ^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0015`. diff --git a/tests/run-make/const-trait-stable-toolchain/const-super-trait-stable-disabled.stderr b/tests/run-make/const-trait-stable-toolchain/const-super-trait-stable-disabled.stderr new file mode 100644 index 00000000000..eacdaf5e369 --- /dev/null +++ b/tests/run-make/const-trait-stable-toolchain/const-super-trait-stable-disabled.stderr @@ -0,0 +1,64 @@ +error: `~const` is not allowed here + --> const-super-trait.rs:7:12 + | +7 | trait Bar: ~const Foo {} + | ^^^^^^ + | +note: this trait is not a `#[const_trait]`, so it cannot have `~const` trait bounds + --> const-super-trait.rs:7:1 + | +7 | trait Bar: ~const Foo {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0658]: const trait impls are experimental + --> const-super-trait.rs:7:12 + | +7 | trait Bar: ~const Foo {} + | ^^^^^^ + | + = note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information + +error[E0658]: const trait impls are experimental + --> const-super-trait.rs:9:17 + | +9 | const fn foo<T: ~const Bar>(x: &T) { + | ^^^^^^ + | + = note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information + +error: `~const` can only be applied to `#[const_trait]` traits + --> const-super-trait.rs:7:12 + | +7 | trait Bar: ~const Foo {} + | ^^^^^^ can't be applied to `Foo` + | +note: `Foo` can't be used with `~const` because it isn't annotated with `#[const_trait]` + --> const-super-trait.rs:3:1 + | +3 | trait Foo { + | ^^^^^^^^^ + +error: `~const` can only be applied to `#[const_trait]` traits + --> const-super-trait.rs:9:17 + | +9 | const fn foo<T: ~const Bar>(x: &T) { + | ^^^^^^ can't be applied to `Bar` + | +note: `Bar` can't be used with `~const` because it isn't annotated with `#[const_trait]` + --> const-super-trait.rs:7:1 + | +7 | trait Bar: ~const Foo {} + | ^^^^^^^^^^^^^^^^^^^^^ + +error[E0015]: cannot call non-const fn `<T as Foo>::a` in constant functions + --> const-super-trait.rs:10:7 + | +10 | x.a(); + | ^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + +error: aborting due to 6 previous errors + +Some errors have detailed explanations: E0015, E0658. +For more information about an error, try `rustc --explain E0015`. diff --git a/tests/run-make/const-trait-stable-toolchain/const-super-trait-stable-enabled.stderr b/tests/run-make/const-trait-stable-toolchain/const-super-trait-stable-enabled.stderr new file mode 100644 index 00000000000..9ddec6e422c --- /dev/null +++ b/tests/run-make/const-trait-stable-toolchain/const-super-trait-stable-enabled.stderr @@ -0,0 +1,54 @@ +error: `~const` is not allowed here + --> const-super-trait.rs:7:12 + | +7 | trait Bar: ~const Foo {} + | ^^^^^^ + | +note: this trait is not a `#[const_trait]`, so it cannot have `~const` trait bounds + --> const-super-trait.rs:7:1 + | +7 | trait Bar: ~const Foo {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0554]: `#![feature]` may not be used on the NIGHTLY release channel + --> const-super-trait.rs:1:30 + | +1 | #![cfg_attr(feature_enabled, feature(const_trait_impl))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `~const` can only be applied to `#[const_trait]` traits + --> const-super-trait.rs:7:12 + | +7 | trait Bar: ~const Foo {} + | ^^^^^^ can't be applied to `Foo` + | +note: `Foo` can't be used with `~const` because it isn't annotated with `#[const_trait]` + --> const-super-trait.rs:3:1 + | +3 | trait Foo { + | ^^^^^^^^^ + +error: `~const` can only be applied to `#[const_trait]` traits + --> const-super-trait.rs:9:17 + | +9 | const fn foo<T: ~const Bar>(x: &T) { + | ^^^^^^ can't be applied to `Bar` + | +note: `Bar` can't be used with `~const` because it isn't annotated with `#[const_trait]` + --> const-super-trait.rs:7:1 + | +7 | trait Bar: ~const Foo {} + | ^^^^^^^^^^^^^^^^^^^^^ + +error[E0015]: cannot call non-const fn `<T as Foo>::a` in constant functions + --> const-super-trait.rs:10:7 + | +10 | x.a(); + | ^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + +error: aborting due to 5 previous errors + +Some errors have detailed explanations: E0015, E0554. +For more information about an error, try `rustc --explain E0015`. diff --git a/tests/run-make/const-trait-stable-toolchain/const-super-trait.rs b/tests/run-make/const-trait-stable-toolchain/const-super-trait.rs new file mode 100644 index 00000000000..b2ee96d79f7 --- /dev/null +++ b/tests/run-make/const-trait-stable-toolchain/const-super-trait.rs @@ -0,0 +1,13 @@ +#![cfg_attr(feature_enabled, feature(const_trait_impl))] + +trait Foo { + fn a(&self); +} + +trait Bar: ~const Foo {} + +const fn foo<T: ~const Bar>(x: &T) { + x.a(); +} + +fn main() {} diff --git a/tests/run-make/const-trait-stable-toolchain/rmake.rs b/tests/run-make/const-trait-stable-toolchain/rmake.rs new file mode 100644 index 00000000000..241de11ed59 --- /dev/null +++ b/tests/run-make/const-trait-stable-toolchain/rmake.rs @@ -0,0 +1,59 @@ +// Test output of const super trait errors in both stable and nightly. +// We don't want to provide suggestions on stable that only make sense in nightly. + +use run_make_support::{diff, rustc}; + +fn main() { + let out = rustc() + .input("const-super-trait.rs") + .env("RUSTC_BOOTSTRAP", "-1") + .cfg("feature_enabled") + .run_fail() + .assert_stderr_not_contains( + "as `#[const_trait]` to allow it to have `const` implementations", + ) + .stderr_utf8(); + diff() + .expected_file("const-super-trait-stable-enabled.stderr") + .normalize( + "may not be used on the .* release channel", + "may not be used on the NIGHTLY release channel", + ) + .actual_text("(rustc)", &out) + .run(); + let out = rustc() + .input("const-super-trait.rs") + .cfg("feature_enabled") + .ui_testing() + .run_fail() + .assert_stderr_not_contains("enable `#![feature(const_trait_impl)]` in your crate and mark") + .assert_stderr_contains("as `#[const_trait]` to allow it to have `const` implementations") + .stderr_utf8(); + diff() + .expected_file("const-super-trait-nightly-enabled.stderr") + .actual_text("(rustc)", &out) + .run(); + let out = rustc() + .input("const-super-trait.rs") + .env("RUSTC_BOOTSTRAP", "-1") + .run_fail() + .assert_stderr_not_contains("enable `#![feature(const_trait_impl)]` in your crate and mark") + .assert_stderr_not_contains( + "as `#[const_trait]` to allow it to have `const` implementations", + ) + .stderr_utf8(); + diff() + .expected_file("const-super-trait-stable-disabled.stderr") + .actual_text("(rustc)", &out) + .run(); + let out = rustc() + .input("const-super-trait.rs") + .ui_testing() + .run_fail() + .assert_stderr_contains("enable `#![feature(const_trait_impl)]` in your crate and mark") + .stderr_utf8(); + diff() + .expected_file("const-super-trait-nightly-disabled.stderr") + .actual_text("(rustc)", &out) + .run(); +} diff --git a/tests/run-make/libs-through-symlinks/Makefile b/tests/run-make/libs-through-symlinks/Makefile index 592eae663a4..c6ff566a0e8 100644 --- a/tests/run-make/libs-through-symlinks/Makefile +++ b/tests/run-make/libs-through-symlinks/Makefile @@ -3,10 +3,20 @@ include ../tools.mk # ignore-windows +# The option -n for the AIX ln command has a different purpose than it does +# on Linux. On Linux, the -n option is used to treat the destination path as +# normal file if it is a symbolic link to a directory, which is the default +# behavior of the AIX ln command. +ifeq ($(UNAME),AIX) +LN_FLAGS := -sf +else +LN_FLAGS := -nsf +endif + NAME := $(shell $(RUSTC) --print file-names foo.rs) all: mkdir -p $(TMPDIR)/outdir $(RUSTC) foo.rs -o $(TMPDIR)/outdir/$(NAME) - ln -nsf outdir/$(NAME) $(TMPDIR) + ln $(LN_FLAGS) outdir/$(NAME) $(TMPDIR) RUSTC_LOG=rustc_metadata::loader $(RUSTC) bar.rs diff --git a/tests/run-make/link-args-order/rmake.rs b/tests/run-make/link-args-order/rmake.rs index b7ef8333267..fe0d02926ef 100644 --- a/tests/run-make/link-args-order/rmake.rs +++ b/tests/run-make/link-args-order/rmake.rs @@ -15,8 +15,9 @@ fn main() { .link_args("b c") .link_args("d e") .link_arg("f") + .arg("--print=link-args") .run_fail() - .assert_stderr_contains(r#""a" "b" "c" "d" "e" "f""#); + .assert_stdout_contains(r#""a" "b" "c" "d" "e" "f""#); rustc() .input("empty.rs") .linker_flavor(linker) @@ -24,6 +25,7 @@ fn main() { .arg("-Zpre-link-args=b c") .arg("-Zpre-link-args=d e") .arg("-Zpre-link-arg=f") + .arg("--print=link-args") .run_fail() - .assert_stderr_contains(r#""a" "b" "c" "d" "e" "f""#); + .assert_stdout_contains(r#""a" "b" "c" "d" "e" "f""#); } diff --git a/tests/run-make/link-dedup/rmake.rs b/tests/run-make/link-dedup/rmake.rs index 6075f310954..f38603dee8c 100644 --- a/tests/run-make/link-dedup/rmake.rs +++ b/tests/run-make/link-dedup/rmake.rs @@ -14,13 +14,13 @@ fn main() { rustc().input("depb.rs").run(); rustc().input("depc.rs").run(); - let output = rustc().input("empty.rs").cfg("bar").run_fail(); - output.assert_stderr_contains(needle_from_libs(&["testa", "testb", "testa"])); + let output = rustc().input("empty.rs").cfg("bar").arg("--print=link-args").run_fail(); + output.assert_stdout_contains(needle_from_libs(&["testa", "testb", "testa"])); - let output = rustc().input("empty.rs").run_fail(); - output.assert_stderr_contains(needle_from_libs(&["testa"])); - output.assert_stderr_not_contains(needle_from_libs(&["testb"])); - output.assert_stderr_not_contains(needle_from_libs(&["testa", "testa", "testa"])); + let output = rustc().input("empty.rs").arg("--print=link-args").run_fail(); + output.assert_stdout_contains(needle_from_libs(&["testa"])); + output.assert_stdout_not_contains(needle_from_libs(&["testb"])); + output.assert_stdout_not_contains(needle_from_libs(&["testa", "testa", "testa"])); // Adjacent identical native libraries are no longer deduplicated if // they come from different crates (https://github.com/rust-lang/rust/pull/103311) // so the following will fail: diff --git a/tests/run-make/linker-warning/fake-linker.rs b/tests/run-make/linker-warning/fake-linker.rs new file mode 100644 index 00000000000..30497eea2cc --- /dev/null +++ b/tests/run-make/linker-warning/fake-linker.rs @@ -0,0 +1,13 @@ +fn main() { + for arg in std::env::args() { + match &*arg { + "run_make_info" => println!("foo"), + "run_make_warn" => eprintln!("warning: bar"), + "run_make_error" => { + eprintln!("error: baz"); + std::process::exit(1); + } + _ => (), + } + } +} diff --git a/tests/run-make/linker-warning/main.rs b/tests/run-make/linker-warning/main.rs new file mode 100644 index 00000000000..f328e4d9d04 --- /dev/null +++ b/tests/run-make/linker-warning/main.rs @@ -0,0 +1 @@ +fn main() {} diff --git a/tests/run-make/linker-warning/rmake.rs b/tests/run-make/linker-warning/rmake.rs new file mode 100644 index 00000000000..4d21c5ea569 --- /dev/null +++ b/tests/run-make/linker-warning/rmake.rs @@ -0,0 +1,28 @@ +use run_make_support::{Rustc, rustc}; + +fn run_rustc() -> Rustc { + let mut rustc = rustc(); + rustc.arg("main.rs").output("main").linker("./fake-linker"); + rustc +} + +fn main() { + // first, compile our linker + rustc().arg("fake-linker.rs").output("fake-linker").run(); + + // Make sure we don't show the linker args unless `--verbose` is passed + run_rustc() + .link_arg("run_make_error") + .verbose() + .run_fail() + .assert_stderr_contains_regex("fake-linker.*run_make_error") + .assert_stderr_not_contains("object files omitted") + .assert_stderr_contains_regex(r"lib(/|\\\\)libstd"); + run_rustc() + .link_arg("run_make_error") + .run_fail() + .assert_stderr_contains("fake-linker") + .assert_stderr_contains("object files omitted") + .assert_stderr_contains_regex(r"\{") + .assert_stderr_not_contains_regex(r"lib(/|\\\\)libstd"); +} diff --git a/tests/rustdoc-ui/issues/issue-107918.rs b/tests/rustdoc-ui/issues/duplicate-panic-impl-107918.rs index 19d53f84cb6..ec35b52e33b 100644 --- a/tests/rustdoc-ui/issues/issue-107918.rs +++ b/tests/rustdoc-ui/issues/duplicate-panic-impl-107918.rs @@ -2,6 +2,7 @@ //@ compile-flags: --document-private-items //@ build-pass //@ only-linux +// https://github.com/rust-lang/rust/issues/107918 #![no_std] #![no_main] diff --git a/tests/rustdoc-ui/issues/issue-110900.rs b/tests/rustdoc-ui/issues/ice-associated-type-bounds-110900.rs index 5a896167083..4fa60f8878d 100644 --- a/tests/rustdoc-ui/issues/issue-110900.rs +++ b/tests/rustdoc-ui/issues/ice-associated-type-bounds-110900.rs @@ -1,4 +1,5 @@ //@ check-pass +// https://github.com/rust-lang/rust/issues/110900 #![crate_type="lib"] diff --git a/tests/rustdoc-ui/issues/issue-106213.rs b/tests/rustdoc-ui/issues/ice-bare-dyn-106213.rs index 5c3a8390252..c954162589d 100644 --- a/tests/rustdoc-ui/issues/issue-106213.rs +++ b/tests/rustdoc-ui/issues/ice-bare-dyn-106213.rs @@ -1,5 +1,6 @@ //@ compile-flags: --document-private-items //@ edition:2021 +// https://github.com/rust-lang/rust/issues/106213 fn use_avx() -> dyn { //~^ ERROR at least one trait is required for an object type diff --git a/tests/rustdoc-ui/issues/issue-106213.stderr b/tests/rustdoc-ui/issues/ice-bare-dyn-106213.stderr index fa79fe2e71c..b029fee510e 100644 --- a/tests/rustdoc-ui/issues/issue-106213.stderr +++ b/tests/rustdoc-ui/issues/ice-bare-dyn-106213.stderr @@ -1,5 +1,5 @@ error[E0224]: at least one trait is required for an object type - --> $DIR/issue-106213.rs:4:17 + --> $DIR/ice-bare-dyn-106213.rs:5:17 | LL | fn use_avx() -> dyn { | ^^^ diff --git a/tests/rustdoc-ui/issues/issue-105742.rs b/tests/rustdoc-ui/issues/ice-generic-type-alias-105742.rs index bd8ec4e8b58..027574923c7 100644 --- a/tests/rustdoc-ui/issues/issue-105742.rs +++ b/tests/rustdoc-ui/issues/ice-generic-type-alias-105742.rs @@ -1,4 +1,5 @@ //@ compile-flags: -Znormalize-docs +// https://github.com/rust-lang/rust/issues/105742 use std::ops::Index; pub fn next<'a, T>(s: &'a mut dyn SVec<Item = T, Output = T>) { diff --git a/tests/rustdoc-ui/issues/issue-105742.stderr b/tests/rustdoc-ui/issues/ice-generic-type-alias-105742.stderr index 0f09d637f38..06a1cf6b118 100644 --- a/tests/rustdoc-ui/issues/issue-105742.stderr +++ b/tests/rustdoc-ui/issues/ice-generic-type-alias-105742.stderr @@ -1,11 +1,11 @@ error[E0107]: missing generics for associated type `SVec::Item` - --> $DIR/issue-105742.rs:15:21 + --> $DIR/ice-generic-type-alias-105742.rs:16:21 | LL | <Self as SVec>::Item, | ^^^^ expected 1 lifetime argument | note: associated type defined here, with 1 lifetime parameter: `'a` - --> $DIR/issue-105742.rs:59:10 + --> $DIR/ice-generic-type-alias-105742.rs:60:10 | LL | type Item<'a, T>; | ^^^^ -- @@ -15,13 +15,13 @@ LL | <Self as SVec>::Item<'a>, | ++++ error[E0107]: missing generics for associated type `SVec::Item` - --> $DIR/issue-105742.rs:15:21 + --> $DIR/ice-generic-type-alias-105742.rs:16:21 | LL | <Self as SVec>::Item, | ^^^^ expected 1 generic argument | note: associated type defined here, with 1 generic parameter: `T` - --> $DIR/issue-105742.rs:59:10 + --> $DIR/ice-generic-type-alias-105742.rs:60:10 | LL | type Item<'a, T>; | ^^^^ - @@ -31,13 +31,13 @@ LL | <Self as SVec>::Item<T>, | +++ error[E0107]: missing generics for associated type `SVec::Item` - --> $DIR/issue-105742.rs:26:37 + --> $DIR/ice-generic-type-alias-105742.rs:27:37 | LL | Output = <Index<<Self as SVec>::Item, | ^^^^ expected 1 lifetime argument | note: associated type defined here, with 1 lifetime parameter: `'a` - --> $DIR/issue-105742.rs:59:10 + --> $DIR/ice-generic-type-alias-105742.rs:60:10 | LL | type Item<'a, T>; | ^^^^ -- @@ -47,13 +47,13 @@ LL | Output = <Index<<Self as SVec>::Item<'a>, | ++++ error[E0107]: missing generics for associated type `SVec::Item` - --> $DIR/issue-105742.rs:26:37 + --> $DIR/ice-generic-type-alias-105742.rs:27:37 | LL | Output = <Index<<Self as SVec>::Item, | ^^^^ expected 1 generic argument | note: associated type defined here, with 1 generic parameter: `T` - --> $DIR/issue-105742.rs:59:10 + --> $DIR/ice-generic-type-alias-105742.rs:60:10 | LL | type Item<'a, T>; | ^^^^ - @@ -63,13 +63,13 @@ LL | Output = <Index<<Self as SVec>::Item<T>, | +++ error[E0107]: missing generics for associated type `SVec::Item` - --> $DIR/issue-105742.rs:37:30 + --> $DIR/ice-generic-type-alias-105742.rs:38:30 | LL | Output = <Self as SVec>::Item> as SVec>::Item, | ^^^^ expected 1 lifetime argument | note: associated type defined here, with 1 lifetime parameter: `'a` - --> $DIR/issue-105742.rs:59:10 + --> $DIR/ice-generic-type-alias-105742.rs:60:10 | LL | type Item<'a, T>; | ^^^^ -- @@ -79,13 +79,13 @@ LL | Output = <Self as SVec>::Item<'a>> as SVec>::Item, | ++++ error[E0107]: missing generics for associated type `SVec::Item` - --> $DIR/issue-105742.rs:37:30 + --> $DIR/ice-generic-type-alias-105742.rs:38:30 | LL | Output = <Self as SVec>::Item> as SVec>::Item, | ^^^^ expected 1 generic argument | note: associated type defined here, with 1 generic parameter: `T` - --> $DIR/issue-105742.rs:59:10 + --> $DIR/ice-generic-type-alias-105742.rs:60:10 | LL | type Item<'a, T>; | ^^^^ - @@ -95,13 +95,13 @@ LL | Output = <Self as SVec>::Item<T>> as SVec>::Item, | +++ error[E0107]: missing generics for associated type `SVec::Item` - --> $DIR/issue-105742.rs:37:46 + --> $DIR/ice-generic-type-alias-105742.rs:38:46 | LL | Output = <Self as SVec>::Item> as SVec>::Item, | ^^^^ expected 1 lifetime argument | note: associated type defined here, with 1 lifetime parameter: `'a` - --> $DIR/issue-105742.rs:59:10 + --> $DIR/ice-generic-type-alias-105742.rs:60:10 | LL | type Item<'a, T>; | ^^^^ -- @@ -111,13 +111,13 @@ LL | Output = <Self as SVec>::Item> as SVec>::Item<'a>, | ++++ error[E0107]: missing generics for associated type `SVec::Item` - --> $DIR/issue-105742.rs:37:46 + --> $DIR/ice-generic-type-alias-105742.rs:38:46 | LL | Output = <Self as SVec>::Item> as SVec>::Item, | ^^^^ expected 1 generic argument | note: associated type defined here, with 1 generic parameter: `T` - --> $DIR/issue-105742.rs:59:10 + --> $DIR/ice-generic-type-alias-105742.rs:60:10 | LL | type Item<'a, T>; | ^^^^ - @@ -127,13 +127,13 @@ LL | Output = <Self as SVec>::Item> as SVec>::Item<T>, | +++ error[E0107]: missing generics for associated type `SVec::Item` - --> $DIR/issue-105742.rs:4:40 + --> $DIR/ice-generic-type-alias-105742.rs:5:40 | LL | pub fn next<'a, T>(s: &'a mut dyn SVec<Item = T, Output = T>) { | ^^^^ expected 1 lifetime argument | note: associated type defined here, with 1 lifetime parameter: `'a` - --> $DIR/issue-105742.rs:59:10 + --> $DIR/ice-generic-type-alias-105742.rs:60:10 | LL | type Item<'a, T>; | ^^^^ -- @@ -143,13 +143,13 @@ LL | pub fn next<'a, T>(s: &'a mut dyn SVec<Item<'_> = T, Output = T>) { | ++++ error[E0107]: missing generics for associated type `SVec::Item` - --> $DIR/issue-105742.rs:4:40 + --> $DIR/ice-generic-type-alias-105742.rs:5:40 | LL | pub fn next<'a, T>(s: &'a mut dyn SVec<Item = T, Output = T>) { | ^^^^ expected 1 generic argument | note: associated type defined here, with 1 generic parameter: `T` - --> $DIR/issue-105742.rs:59:10 + --> $DIR/ice-generic-type-alias-105742.rs:60:10 | LL | type Item<'a, T>; | ^^^^ - @@ -159,13 +159,13 @@ LL | pub fn next<'a, T>(s: &'a mut dyn SVec<Item<T> = T, Output = T>) { | +++ error[E0107]: missing generics for associated type `SVec::Item` - --> $DIR/issue-105742.rs:15:21 + --> $DIR/ice-generic-type-alias-105742.rs:16:21 | LL | <Self as SVec>::Item, | ^^^^ expected 1 lifetime argument | note: associated type defined here, with 1 lifetime parameter: `'a` - --> $DIR/issue-105742.rs:59:10 + --> $DIR/ice-generic-type-alias-105742.rs:60:10 | LL | type Item<'a, T>; | ^^^^ -- @@ -176,13 +176,13 @@ LL | <Self as SVec>::Item<'a>, | ++++ error[E0107]: missing generics for associated type `SVec::Item` - --> $DIR/issue-105742.rs:15:21 + --> $DIR/ice-generic-type-alias-105742.rs:16:21 | LL | <Self as SVec>::Item, | ^^^^ expected 1 generic argument | note: associated type defined here, with 1 generic parameter: `T` - --> $DIR/issue-105742.rs:59:10 + --> $DIR/ice-generic-type-alias-105742.rs:60:10 | LL | type Item<'a, T>; | ^^^^ - @@ -193,13 +193,13 @@ LL | <Self as SVec>::Item<T>, | +++ error[E0107]: missing generics for associated type `SVec::Item` - --> $DIR/issue-105742.rs:26:37 + --> $DIR/ice-generic-type-alias-105742.rs:27:37 | LL | Output = <Index<<Self as SVec>::Item, | ^^^^ expected 1 lifetime argument | note: associated type defined here, with 1 lifetime parameter: `'a` - --> $DIR/issue-105742.rs:59:10 + --> $DIR/ice-generic-type-alias-105742.rs:60:10 | LL | type Item<'a, T>; | ^^^^ -- @@ -210,13 +210,13 @@ LL | Output = <Index<<Self as SVec>::Item<'a>, | ++++ error[E0107]: missing generics for associated type `SVec::Item` - --> $DIR/issue-105742.rs:26:37 + --> $DIR/ice-generic-type-alias-105742.rs:27:37 | LL | Output = <Index<<Self as SVec>::Item, | ^^^^ expected 1 generic argument | note: associated type defined here, with 1 generic parameter: `T` - --> $DIR/issue-105742.rs:59:10 + --> $DIR/ice-generic-type-alias-105742.rs:60:10 | LL | type Item<'a, T>; | ^^^^ - @@ -227,13 +227,13 @@ LL | Output = <Index<<Self as SVec>::Item<T>, | +++ error[E0107]: missing generics for associated type `SVec::Item` - --> $DIR/issue-105742.rs:37:30 + --> $DIR/ice-generic-type-alias-105742.rs:38:30 | LL | Output = <Self as SVec>::Item> as SVec>::Item, | ^^^^ expected 1 lifetime argument | note: associated type defined here, with 1 lifetime parameter: `'a` - --> $DIR/issue-105742.rs:59:10 + --> $DIR/ice-generic-type-alias-105742.rs:60:10 | LL | type Item<'a, T>; | ^^^^ -- @@ -244,13 +244,13 @@ LL | Output = <Self as SVec>::Item<'a>> as SVec>::Item, | ++++ error[E0107]: missing generics for associated type `SVec::Item` - --> $DIR/issue-105742.rs:37:30 + --> $DIR/ice-generic-type-alias-105742.rs:38:30 | LL | Output = <Self as SVec>::Item> as SVec>::Item, | ^^^^ expected 1 generic argument | note: associated type defined here, with 1 generic parameter: `T` - --> $DIR/issue-105742.rs:59:10 + --> $DIR/ice-generic-type-alias-105742.rs:60:10 | LL | type Item<'a, T>; | ^^^^ - @@ -261,13 +261,13 @@ LL | Output = <Self as SVec>::Item<T>> as SVec>::Item, | +++ error[E0107]: missing generics for associated type `SVec::Item` - --> $DIR/issue-105742.rs:37:46 + --> $DIR/ice-generic-type-alias-105742.rs:38:46 | LL | Output = <Self as SVec>::Item> as SVec>::Item, | ^^^^ expected 1 lifetime argument | note: associated type defined here, with 1 lifetime parameter: `'a` - --> $DIR/issue-105742.rs:59:10 + --> $DIR/ice-generic-type-alias-105742.rs:60:10 | LL | type Item<'a, T>; | ^^^^ -- @@ -278,13 +278,13 @@ LL | Output = <Self as SVec>::Item> as SVec>::Item<'a>, | ++++ error[E0107]: missing generics for associated type `SVec::Item` - --> $DIR/issue-105742.rs:37:46 + --> $DIR/ice-generic-type-alias-105742.rs:38:46 | LL | Output = <Self as SVec>::Item> as SVec>::Item, | ^^^^ expected 1 generic argument | note: associated type defined here, with 1 generic parameter: `T` - --> $DIR/issue-105742.rs:59:10 + --> $DIR/ice-generic-type-alias-105742.rs:60:10 | LL | type Item<'a, T>; | ^^^^ - @@ -295,13 +295,13 @@ LL | Output = <Self as SVec>::Item> as SVec>::Item<T>, | +++ error[E0038]: the trait `SVec` cannot be made into an object - --> $DIR/issue-105742.rs:4:31 + --> $DIR/ice-generic-type-alias-105742.rs:5:31 | LL | pub fn next<'a, T>(s: &'a mut dyn SVec<Item = T, Output = T>) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `SVec` cannot be made into an object | note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> - --> $DIR/issue-105742.rs:14:17 + --> $DIR/ice-generic-type-alias-105742.rs:15:17 | LL | pub trait SVec: Index< | ____________----__^ @@ -329,13 +329,13 @@ LL | pub fn next<'a, T>(s: &'a mut impl SVec<Item = T, Output = T>) { | ~~~~ error[E0107]: missing generics for associated type `SVec::Item` - --> $DIR/issue-105742.rs:15:21 + --> $DIR/ice-generic-type-alias-105742.rs:16:21 | LL | <Self as SVec>::Item, | ^^^^ expected 1 lifetime argument | note: associated type defined here, with 1 lifetime parameter: `'a` - --> $DIR/issue-105742.rs:59:10 + --> $DIR/ice-generic-type-alias-105742.rs:60:10 | LL | type Item<'a, T>; | ^^^^ -- @@ -346,13 +346,13 @@ LL | <Self as SVec>::Item<'a>, | ++++ error[E0107]: missing generics for associated type `SVec::Item` - --> $DIR/issue-105742.rs:15:21 + --> $DIR/ice-generic-type-alias-105742.rs:16:21 | LL | <Self as SVec>::Item, | ^^^^ expected 1 generic argument | note: associated type defined here, with 1 generic parameter: `T` - --> $DIR/issue-105742.rs:59:10 + --> $DIR/ice-generic-type-alias-105742.rs:60:10 | LL | type Item<'a, T>; | ^^^^ - @@ -363,13 +363,13 @@ LL | <Self as SVec>::Item<T>, | +++ error[E0107]: missing generics for associated type `SVec::Item` - --> $DIR/issue-105742.rs:26:37 + --> $DIR/ice-generic-type-alias-105742.rs:27:37 | LL | Output = <Index<<Self as SVec>::Item, | ^^^^ expected 1 lifetime argument | note: associated type defined here, with 1 lifetime parameter: `'a` - --> $DIR/issue-105742.rs:59:10 + --> $DIR/ice-generic-type-alias-105742.rs:60:10 | LL | type Item<'a, T>; | ^^^^ -- @@ -380,13 +380,13 @@ LL | Output = <Index<<Self as SVec>::Item<'a>, | ++++ error[E0107]: missing generics for associated type `SVec::Item` - --> $DIR/issue-105742.rs:26:37 + --> $DIR/ice-generic-type-alias-105742.rs:27:37 | LL | Output = <Index<<Self as SVec>::Item, | ^^^^ expected 1 generic argument | note: associated type defined here, with 1 generic parameter: `T` - --> $DIR/issue-105742.rs:59:10 + --> $DIR/ice-generic-type-alias-105742.rs:60:10 | LL | type Item<'a, T>; | ^^^^ - @@ -397,13 +397,13 @@ LL | Output = <Index<<Self as SVec>::Item<T>, | +++ error[E0107]: missing generics for associated type `SVec::Item` - --> $DIR/issue-105742.rs:37:30 + --> $DIR/ice-generic-type-alias-105742.rs:38:30 | LL | Output = <Self as SVec>::Item> as SVec>::Item, | ^^^^ expected 1 lifetime argument | note: associated type defined here, with 1 lifetime parameter: `'a` - --> $DIR/issue-105742.rs:59:10 + --> $DIR/ice-generic-type-alias-105742.rs:60:10 | LL | type Item<'a, T>; | ^^^^ -- @@ -414,13 +414,13 @@ LL | Output = <Self as SVec>::Item<'a>> as SVec>::Item, | ++++ error[E0107]: missing generics for associated type `SVec::Item` - --> $DIR/issue-105742.rs:37:30 + --> $DIR/ice-generic-type-alias-105742.rs:38:30 | LL | Output = <Self as SVec>::Item> as SVec>::Item, | ^^^^ expected 1 generic argument | note: associated type defined here, with 1 generic parameter: `T` - --> $DIR/issue-105742.rs:59:10 + --> $DIR/ice-generic-type-alias-105742.rs:60:10 | LL | type Item<'a, T>; | ^^^^ - @@ -431,13 +431,13 @@ LL | Output = <Self as SVec>::Item<T>> as SVec>::Item, | +++ error[E0107]: missing generics for associated type `SVec::Item` - --> $DIR/issue-105742.rs:37:46 + --> $DIR/ice-generic-type-alias-105742.rs:38:46 | LL | Output = <Self as SVec>::Item> as SVec>::Item, | ^^^^ expected 1 lifetime argument | note: associated type defined here, with 1 lifetime parameter: `'a` - --> $DIR/issue-105742.rs:59:10 + --> $DIR/ice-generic-type-alias-105742.rs:60:10 | LL | type Item<'a, T>; | ^^^^ -- @@ -448,13 +448,13 @@ LL | Output = <Self as SVec>::Item> as SVec>::Item<'a>, | ++++ error[E0107]: missing generics for associated type `SVec::Item` - --> $DIR/issue-105742.rs:37:46 + --> $DIR/ice-generic-type-alias-105742.rs:38:46 | LL | Output = <Self as SVec>::Item> as SVec>::Item, | ^^^^ expected 1 generic argument | note: associated type defined here, with 1 generic parameter: `T` - --> $DIR/issue-105742.rs:59:10 + --> $DIR/ice-generic-type-alias-105742.rs:60:10 | LL | type Item<'a, T>; | ^^^^ - @@ -465,13 +465,13 @@ LL | Output = <Self as SVec>::Item> as SVec>::Item<T>, | +++ error[E0107]: missing generics for associated type `SVec::Item` - --> $DIR/issue-105742.rs:15:21 + --> $DIR/ice-generic-type-alias-105742.rs:16:21 | LL | <Self as SVec>::Item, | ^^^^ expected 1 lifetime argument | note: associated type defined here, with 1 lifetime parameter: `'a` - --> $DIR/issue-105742.rs:59:10 + --> $DIR/ice-generic-type-alias-105742.rs:60:10 | LL | type Item<'a, T>; | ^^^^ -- @@ -482,13 +482,13 @@ LL | <Self as SVec>::Item<'a>, | ++++ error[E0107]: missing generics for associated type `SVec::Item` - --> $DIR/issue-105742.rs:15:21 + --> $DIR/ice-generic-type-alias-105742.rs:16:21 | LL | <Self as SVec>::Item, | ^^^^ expected 1 generic argument | note: associated type defined here, with 1 generic parameter: `T` - --> $DIR/issue-105742.rs:59:10 + --> $DIR/ice-generic-type-alias-105742.rs:60:10 | LL | type Item<'a, T>; | ^^^^ - @@ -499,13 +499,13 @@ LL | <Self as SVec>::Item<T>, | +++ error[E0107]: missing generics for associated type `SVec::Item` - --> $DIR/issue-105742.rs:26:37 + --> $DIR/ice-generic-type-alias-105742.rs:27:37 | LL | Output = <Index<<Self as SVec>::Item, | ^^^^ expected 1 lifetime argument | note: associated type defined here, with 1 lifetime parameter: `'a` - --> $DIR/issue-105742.rs:59:10 + --> $DIR/ice-generic-type-alias-105742.rs:60:10 | LL | type Item<'a, T>; | ^^^^ -- @@ -516,13 +516,13 @@ LL | Output = <Index<<Self as SVec>::Item<'a>, | ++++ error[E0107]: missing generics for associated type `SVec::Item` - --> $DIR/issue-105742.rs:26:37 + --> $DIR/ice-generic-type-alias-105742.rs:27:37 | LL | Output = <Index<<Self as SVec>::Item, | ^^^^ expected 1 generic argument | note: associated type defined here, with 1 generic parameter: `T` - --> $DIR/issue-105742.rs:59:10 + --> $DIR/ice-generic-type-alias-105742.rs:60:10 | LL | type Item<'a, T>; | ^^^^ - @@ -533,13 +533,13 @@ LL | Output = <Index<<Self as SVec>::Item<T>, | +++ error[E0107]: missing generics for associated type `SVec::Item` - --> $DIR/issue-105742.rs:37:30 + --> $DIR/ice-generic-type-alias-105742.rs:38:30 | LL | Output = <Self as SVec>::Item> as SVec>::Item, | ^^^^ expected 1 lifetime argument | note: associated type defined here, with 1 lifetime parameter: `'a` - --> $DIR/issue-105742.rs:59:10 + --> $DIR/ice-generic-type-alias-105742.rs:60:10 | LL | type Item<'a, T>; | ^^^^ -- @@ -550,13 +550,13 @@ LL | Output = <Self as SVec>::Item<'a>> as SVec>::Item, | ++++ error[E0107]: missing generics for associated type `SVec::Item` - --> $DIR/issue-105742.rs:37:30 + --> $DIR/ice-generic-type-alias-105742.rs:38:30 | LL | Output = <Self as SVec>::Item> as SVec>::Item, | ^^^^ expected 1 generic argument | note: associated type defined here, with 1 generic parameter: `T` - --> $DIR/issue-105742.rs:59:10 + --> $DIR/ice-generic-type-alias-105742.rs:60:10 | LL | type Item<'a, T>; | ^^^^ - @@ -567,13 +567,13 @@ LL | Output = <Self as SVec>::Item<T>> as SVec>::Item, | +++ error[E0107]: missing generics for associated type `SVec::Item` - --> $DIR/issue-105742.rs:37:46 + --> $DIR/ice-generic-type-alias-105742.rs:38:46 | LL | Output = <Self as SVec>::Item> as SVec>::Item, | ^^^^ expected 1 lifetime argument | note: associated type defined here, with 1 lifetime parameter: `'a` - --> $DIR/issue-105742.rs:59:10 + --> $DIR/ice-generic-type-alias-105742.rs:60:10 | LL | type Item<'a, T>; | ^^^^ -- @@ -584,13 +584,13 @@ LL | Output = <Self as SVec>::Item> as SVec>::Item<'a>, | ++++ error[E0107]: missing generics for associated type `SVec::Item` - --> $DIR/issue-105742.rs:37:46 + --> $DIR/ice-generic-type-alias-105742.rs:38:46 | LL | Output = <Self as SVec>::Item> as SVec>::Item, | ^^^^ expected 1 generic argument | note: associated type defined here, with 1 generic parameter: `T` - --> $DIR/issue-105742.rs:59:10 + --> $DIR/ice-generic-type-alias-105742.rs:60:10 | LL | type Item<'a, T>; | ^^^^ - @@ -601,13 +601,13 @@ LL | Output = <Self as SVec>::Item> as SVec>::Item<T>, | +++ error[E0107]: missing generics for associated type `SVec::Item` - --> $DIR/issue-105742.rs:61:38 + --> $DIR/ice-generic-type-alias-105742.rs:62:38 | LL | fn len(&self) -> <Self as SVec>::Item; | ^^^^ expected 1 lifetime argument | note: associated type defined here, with 1 lifetime parameter: `'a` - --> $DIR/issue-105742.rs:59:10 + --> $DIR/ice-generic-type-alias-105742.rs:60:10 | LL | type Item<'a, T>; | ^^^^ -- @@ -617,13 +617,13 @@ LL | fn len(&self) -> <Self as SVec>::Item<'_>; | ++++ error[E0107]: missing generics for associated type `SVec::Item` - --> $DIR/issue-105742.rs:61:38 + --> $DIR/ice-generic-type-alias-105742.rs:62:38 | LL | fn len(&self) -> <Self as SVec>::Item; | ^^^^ expected 1 generic argument | note: associated type defined here, with 1 generic parameter: `T` - --> $DIR/issue-105742.rs:59:10 + --> $DIR/ice-generic-type-alias-105742.rs:60:10 | LL | type Item<'a, T>; | ^^^^ - diff --git a/tests/rustdoc-ui/issues/ice-impl-fn-generic-105737.rs b/tests/rustdoc-ui/issues/ice-impl-fn-generic-105737.rs new file mode 100644 index 00000000000..651fd9ab4b8 --- /dev/null +++ b/tests/rustdoc-ui/issues/ice-impl-fn-generic-105737.rs @@ -0,0 +1,5 @@ +// https://github.com/rust-lang/rust/issues/105737 +impl Vec<lol> {} +//~^ ERROR + +pub fn lol() {} diff --git a/tests/rustdoc-ui/issues/issue-105737.stderr b/tests/rustdoc-ui/issues/ice-impl-fn-generic-105737.stderr index 2c63c345e46..49cbebc91d9 100644 --- a/tests/rustdoc-ui/issues/issue-105737.stderr +++ b/tests/rustdoc-ui/issues/ice-impl-fn-generic-105737.stderr @@ -1,5 +1,5 @@ error[E0747]: constant provided when a type was expected - --> $DIR/issue-105737.rs:1:10 + --> $DIR/ice-impl-fn-generic-105737.rs:2:10 | LL | impl Vec<lol> {} | ^^^ diff --git a/tests/rustdoc-ui/issues/issue-101076.rs b/tests/rustdoc-ui/issues/ice-macro-hidden-exported-macro-defid-101076.rs index f9b93c408fd..0c9a8b9175b 100644 --- a/tests/rustdoc-ui/issues/issue-101076.rs +++ b/tests/rustdoc-ui/issues/ice-macro-hidden-exported-macro-defid-101076.rs @@ -1,4 +1,5 @@ //@ check-pass +// https://github.com/rust-lang/rust/issues/101076 const _: () = { #[macro_export] diff --git a/tests/rustdoc-ui/issues/issue-106226.rs b/tests/rustdoc-ui/issues/ice-placeholder-type-alias-106226.rs index 71b497a9adc..71b497a9adc 100644 --- a/tests/rustdoc-ui/issues/issue-106226.rs +++ b/tests/rustdoc-ui/issues/ice-placeholder-type-alias-106226.rs diff --git a/tests/rustdoc-ui/issues/issue-106226.stderr b/tests/rustdoc-ui/issues/ice-placeholder-type-alias-106226.stderr index 4d063b46188..e9080925450 100644 --- a/tests/rustdoc-ui/issues/issue-106226.stderr +++ b/tests/rustdoc-ui/issues/ice-placeholder-type-alias-106226.stderr @@ -1,5 +1,5 @@ error[E0121]: the placeholder `_` is not allowed within types on item signatures for type aliases - --> $DIR/issue-106226.rs:2:11 + --> $DIR/ice-placeholder-type-alias-106226.rs:2:11 | LL | type F = [_; ()]; | ^ not allowed in type signatures diff --git a/tests/rustdoc-ui/issues/ice-raw-str-105334.rs b/tests/rustdoc-ui/issues/ice-raw-str-105334.rs new file mode 100644 index 00000000000..f18f0456fdd --- /dev/null +++ b/tests/rustdoc-ui/issues/ice-raw-str-105334.rs @@ -0,0 +1,3 @@ +// https://github.com/rust-lang/rust/issues/105334 +impl Vec< br##"*.."## > {} +//~^ ERROR diff --git a/tests/rustdoc-ui/issues/issue-105334.stderr b/tests/rustdoc-ui/issues/ice-raw-str-105334.stderr index d992b219b3b..2096757fbb9 100644 --- a/tests/rustdoc-ui/issues/issue-105334.stderr +++ b/tests/rustdoc-ui/issues/ice-raw-str-105334.stderr @@ -1,5 +1,5 @@ error[E0747]: constant provided when a type was expected - --> $DIR/issue-105334.rs:1:11 + --> $DIR/ice-raw-str-105334.rs:2:11 | LL | impl Vec< br##"*.."## > {} | ^^^^^^^^^^^ diff --git a/tests/rustdoc-ui/issues/issue-102986.rs b/tests/rustdoc-ui/issues/ice-typeof-102986.rs index 001784ac285..8fcbfffe172 100644 --- a/tests/rustdoc-ui/issues/issue-102986.rs +++ b/tests/rustdoc-ui/issues/ice-typeof-102986.rs @@ -1,3 +1,4 @@ +// https://github.com/rust-lang/rust/issues/102986 struct Struct { y: (typeof("hey"),), //~^ `typeof` is a reserved keyword but unimplemented diff --git a/tests/rustdoc-ui/issues/issue-102986.stderr b/tests/rustdoc-ui/issues/ice-typeof-102986.stderr index d91f93f394a..20dbb2661bc 100644 --- a/tests/rustdoc-ui/issues/issue-102986.stderr +++ b/tests/rustdoc-ui/issues/ice-typeof-102986.stderr @@ -1,5 +1,5 @@ error[E0516]: `typeof` is a reserved keyword but unimplemented - --> $DIR/issue-102986.rs:2:9 + --> $DIR/ice-typeof-102986.rs:3:9 | LL | y: (typeof("hey"),), | ^^^^^^^^^^^^^ reserved keyword diff --git a/tests/rustdoc-ui/issues/issue-103997.rs b/tests/rustdoc-ui/issues/ice-unresolved-self-103997.rs index ebd1d2e4447..b6ba4e48cff 100644 --- a/tests/rustdoc-ui/issues/issue-103997.rs +++ b/tests/rustdoc-ui/issues/ice-unresolved-self-103997.rs @@ -1,4 +1,5 @@ //@ check-pass +// https://github.com/rust-lang/rust/issues/103997 pub fn foo() {} diff --git a/tests/rustdoc-ui/issues/issue-103997.stderr b/tests/rustdoc-ui/issues/ice-unresolved-self-103997.stderr index c06db91496f..9cb64079c61 100644 --- a/tests/rustdoc-ui/issues/issue-103997.stderr +++ b/tests/rustdoc-ui/issues/ice-unresolved-self-103997.stderr @@ -1,5 +1,5 @@ warning: unresolved link to `Self::foo` - --> $DIR/issue-103997.rs:5:13 + --> $DIR/ice-unresolved-self-103997.rs:6:13 | LL | /// [`foo`](Self::foo) | ^^^^^^^^^ no item named `Self` in scope diff --git a/tests/rustdoc-ui/issues/issue-105334.rs b/tests/rustdoc-ui/issues/issue-105334.rs deleted file mode 100644 index ee1adc6a029..00000000000 --- a/tests/rustdoc-ui/issues/issue-105334.rs +++ /dev/null @@ -1,2 +0,0 @@ -impl Vec< br##"*.."## > {} -//~^ ERROR diff --git a/tests/rustdoc-ui/issues/issue-105737.rs b/tests/rustdoc-ui/issues/issue-105737.rs deleted file mode 100644 index 154f069d8ff..00000000000 --- a/tests/rustdoc-ui/issues/issue-105737.rs +++ /dev/null @@ -1,4 +0,0 @@ -impl Vec<lol> {} -//~^ ERROR - -pub fn lol() {} diff --git a/tests/ui-fulldeps/lexer/unicode-version.rs b/tests/ui-fulldeps/lexer/unicode-version.rs new file mode 100644 index 00000000000..cd02b952895 --- /dev/null +++ b/tests/ui-fulldeps/lexer/unicode-version.rs @@ -0,0 +1,27 @@ +// This test is used to validate which version of Unicode is used for parsing +// identifiers. If the Unicode version changes, it should also be updated in +// the reference at +// https://github.com/rust-lang/reference/blob/HEAD/src/identifiers.md. + +//@ run-pass +//@ check-run-results +//@ ignore-cross-compile +//@ reference: ident.unicode +//@ reference: ident.normalization + +#![feature(rustc_private)] + +extern crate rustc_driver; +extern crate rustc_lexer; +extern crate rustc_parse; + +fn main() { + println!("Checking if Unicode version changed."); + println!( + "If the Unicode version changes are intentional, \ + it should also be updated in the reference at \ + https://github.com/rust-lang/reference/blob/HEAD/src/identifiers.md." + ); + println!("Unicode XID version is: {:?}", rustc_lexer::UNICODE_XID_VERSION); + println!("Unicode normalization version is: {:?}", rustc_parse::UNICODE_NORMALIZATION_VERSION); +} diff --git a/tests/ui-fulldeps/lexer/unicode-version.run.stdout b/tests/ui-fulldeps/lexer/unicode-version.run.stdout new file mode 100644 index 00000000000..f32c8365cdf --- /dev/null +++ b/tests/ui-fulldeps/lexer/unicode-version.run.stdout @@ -0,0 +1,4 @@ +Checking if Unicode version changed. +If the Unicode version changes are intentional, it should also be updated in the reference at https://github.com/rust-lang/reference/blob/HEAD/src/identifiers.md. +Unicode XID version is: (16, 0, 0) +Unicode normalization version is: (16, 0, 0) diff --git a/tests/ui/asm/aarch64/srcloc.new.stderr b/tests/ui/asm/aarch64/srcloc.new.stderr new file mode 100644 index 00000000000..b92a07e5fb1 --- /dev/null +++ b/tests/ui/asm/aarch64/srcloc.new.stderr @@ -0,0 +1,320 @@ +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:15:15 + | +LL | asm!("invalid_instruction"); + | ^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> <inline asm>:1:2 + | +LL | invalid_instruction + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:19:13 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> <inline asm>:2:13 + | +LL | invalid_instruction + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:24:13 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> <inline asm>:2:13 + | +LL | invalid_instruction + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:30:13 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> <inline asm>:3:13 + | +LL | invalid_instruction + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:37:13 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> <inline asm>:3:13 + | +LL | invalid_instruction + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:42:14 + | +LL | asm!(concat!("invalid", "_", "instruction")); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> <inline asm>:1:2 + | +LL | invalid_instruction + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:46:14 + | +LL | "invalid_instruction", + | ^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> <inline asm>:1:2 + | +LL | invalid_instruction + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:52:14 + | +LL | "invalid_instruction", + | ^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> <inline asm>:2:1 + | +LL | invalid_instruction + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:59:14 + | +LL | "invalid_instruction", + | ^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> <inline asm>:3:1 + | +LL | invalid_instruction + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:66:13 + | +LL | concat!("invalid", "_", "instruction"), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> <inline asm>:2:1 + | +LL | invalid_instruction + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:73:13 + | +LL | concat!("invalid", "_", "instruction"), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> <inline asm>:2:1 + | +LL | invalid_instruction + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:80:14 + | +LL | "invalid_instruction1", + | ^^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> <inline asm>:1:2 + | +LL | invalid_instruction1 + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:81:14 + | +LL | "invalid_instruction2", + | ^^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> <inline asm>:2:1 + | +LL | invalid_instruction2 + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:87:13 + | +LL | / concat!( +LL | | "invalid", "_", "instruction1", "\n", +LL | | "invalid", "_", "instruction2", +LL | | ), + | |_____________^ + | +note: instantiated into assembly here + --> <inline asm>:1:2 + | +LL | invalid_instruction1 + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:87:13 + | +LL | / concat!( +LL | | "invalid", "_", "instruction1", "\n", +LL | | "invalid", "_", "instruction2", +LL | | ), + | |_____________^ + | +note: instantiated into assembly here + --> <inline asm>:2:1 + | +LL | invalid_instruction2 + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:96:13 + | +LL | / concat!( +LL | | "invalid", "_", "instruction1", "\n", +LL | | "invalid", "_", "instruction2", +LL | | ), + | |_____________^ + | +note: instantiated into assembly here + --> <inline asm>:1:2 + | +LL | invalid_instruction1 + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:96:13 + | +LL | / concat!( +LL | | "invalid", "_", "instruction1", "\n", +LL | | "invalid", "_", "instruction2", +LL | | ), + | |_____________^ + | +note: instantiated into assembly here + --> <inline asm>:2:1 + | +LL | invalid_instruction2 + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:100:13 + | +LL | / concat!( +LL | | "invalid", "_", "instruction3", "\n", +LL | | "invalid", "_", "instruction4", +LL | | ), + | |_____________^ + | +note: instantiated into assembly here + --> <inline asm>:3:1 + | +LL | invalid_instruction3 + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:100:13 + | +LL | / concat!( +LL | | "invalid", "_", "instruction3", "\n", +LL | | "invalid", "_", "instruction4", +LL | | ), + | |_____________^ + | +note: instantiated into assembly here + --> <inline asm>:4:1 + | +LL | invalid_instruction4 + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:111:13 + | +LL | / concat!( +LL | | "invalid", "_", "instruction1", "\n", +LL | | "invalid", "_", "instruction2", "\n", +LL | | ), + | |_____________^ + | +note: instantiated into assembly here + --> <inline asm>:1:2 + | +LL | invalid_instruction1 + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:111:13 + | +LL | / concat!( +LL | | "invalid", "_", "instruction1", "\n", +LL | | "invalid", "_", "instruction2", "\n", +LL | | ), + | |_____________^ + | +note: instantiated into assembly here + --> <inline asm>:2:1 + | +LL | invalid_instruction2 + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:115:13 + | +LL | / concat!( +LL | | "invalid", "_", "instruction3", "\n", +LL | | "invalid", "_", "instruction4", "\n", +LL | | ), + | |_____________^ + | +note: instantiated into assembly here + --> <inline asm>:4:1 + | +LL | invalid_instruction3 + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:115:13 + | +LL | / concat!( +LL | | "invalid", "_", "instruction3", "\n", +LL | | "invalid", "_", "instruction4", "\n", +LL | | ), + | |_____________^ + | +note: instantiated into assembly here + --> <inline asm>:5:1 + | +LL | invalid_instruction4 + | ^ + +error: unrecognized instruction mnemonic + --> $DIR/srcloc.rs:128:14 + | +LL | "invalid_instruction" + | ^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> <inline asm>:4:1 + | +LL | invalid_instruction + | ^ + +error: aborting due to 24 previous errors + diff --git a/tests/ui/asm/aarch64/srcloc.stderr b/tests/ui/asm/aarch64/srcloc.old.stderr index 2e17b60b912..2a15e48f025 100644 --- a/tests/ui/asm/aarch64/srcloc.stderr +++ b/tests/ui/asm/aarch64/srcloc.old.stderr @@ -1,5 +1,5 @@ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:12:15 + --> $DIR/srcloc.rs:15:15 | LL | asm!("invalid_instruction"); | ^ @@ -11,7 +11,7 @@ LL | invalid_instruction | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:16:13 + --> $DIR/srcloc.rs:19:13 | LL | invalid_instruction | ^ @@ -23,7 +23,7 @@ LL | invalid_instruction | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:21:13 + --> $DIR/srcloc.rs:24:13 | LL | invalid_instruction | ^ @@ -35,7 +35,7 @@ LL | invalid_instruction | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:27:13 + --> $DIR/srcloc.rs:30:13 | LL | invalid_instruction | ^ @@ -47,7 +47,7 @@ LL | invalid_instruction | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:34:13 + --> $DIR/srcloc.rs:37:13 | LL | invalid_instruction | ^ @@ -59,7 +59,7 @@ LL | invalid_instruction | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:39:14 + --> $DIR/srcloc.rs:42:14 | LL | asm!(concat!("invalid", "_", "instruction")); | ^ @@ -71,7 +71,7 @@ LL | invalid_instruction | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:43:14 + --> $DIR/srcloc.rs:46:14 | LL | "invalid_instruction", | ^ @@ -83,7 +83,7 @@ LL | invalid_instruction | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:49:14 + --> $DIR/srcloc.rs:52:14 | LL | "invalid_instruction", | ^ @@ -95,7 +95,7 @@ LL | invalid_instruction | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:56:14 + --> $DIR/srcloc.rs:59:14 | LL | "invalid_instruction", | ^ @@ -107,7 +107,7 @@ LL | invalid_instruction | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:63:13 + --> $DIR/srcloc.rs:66:13 | LL | concat!("invalid", "_", "instruction"), | ^ @@ -119,7 +119,7 @@ LL | invalid_instruction | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:70:13 + --> $DIR/srcloc.rs:73:13 | LL | concat!("invalid", "_", "instruction"), | ^ @@ -131,7 +131,7 @@ LL | invalid_instruction | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:77:14 + --> $DIR/srcloc.rs:80:14 | LL | "invalid_instruction1", | ^ @@ -143,7 +143,7 @@ LL | invalid_instruction1 | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:78:14 + --> $DIR/srcloc.rs:81:14 | LL | "invalid_instruction2", | ^ @@ -155,7 +155,7 @@ LL | invalid_instruction2 | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:84:13 + --> $DIR/srcloc.rs:87:13 | LL | concat!( | ^ @@ -167,7 +167,7 @@ LL | invalid_instruction1 | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:84:13 + --> $DIR/srcloc.rs:87:13 | LL | concat!( | ^ @@ -179,7 +179,7 @@ LL | invalid_instruction2 | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:93:13 + --> $DIR/srcloc.rs:96:13 | LL | concat!( | ^ @@ -191,7 +191,7 @@ LL | invalid_instruction1 | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:93:13 + --> $DIR/srcloc.rs:96:13 | LL | concat!( | ^ @@ -203,7 +203,7 @@ LL | invalid_instruction2 | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:97:13 + --> $DIR/srcloc.rs:100:13 | LL | concat!( | ^ @@ -215,7 +215,7 @@ LL | invalid_instruction3 | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:97:13 + --> $DIR/srcloc.rs:100:13 | LL | concat!( | ^ @@ -227,7 +227,7 @@ LL | invalid_instruction4 | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:108:13 + --> $DIR/srcloc.rs:111:13 | LL | concat!( | ^ @@ -239,7 +239,7 @@ LL | invalid_instruction1 | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:108:13 + --> $DIR/srcloc.rs:111:13 | LL | concat!( | ^ @@ -251,7 +251,7 @@ LL | invalid_instruction2 | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:112:13 + --> $DIR/srcloc.rs:115:13 | LL | concat!( | ^ @@ -263,7 +263,7 @@ LL | invalid_instruction3 | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:112:13 + --> $DIR/srcloc.rs:115:13 | LL | concat!( | ^ @@ -275,7 +275,7 @@ LL | invalid_instruction4 | ^ error: unrecognized instruction mnemonic - --> $DIR/srcloc.rs:125:14 + --> $DIR/srcloc.rs:128:14 | LL | "invalid_instruction" | ^ diff --git a/tests/ui/asm/aarch64/srcloc.rs b/tests/ui/asm/aarch64/srcloc.rs index c635fa6ba70..9b92dfef056 100644 --- a/tests/ui/asm/aarch64/srcloc.rs +++ b/tests/ui/asm/aarch64/srcloc.rs @@ -1,7 +1,10 @@ +//@ revisions: old new //@ only-aarch64 //@ build-fail //@ needs-asm-support //@ compile-flags: -Ccodegen-units=1 +//@[old] ignore-llvm-version: 19 - 99 +//@[new] min-llvm-version: 19 use std::arch::asm; diff --git a/tests/ui/asm/inline-syntax.arm.stderr b/tests/ui/asm/inline-syntax.arm.stderr index 61e5078d6d9..e36ec125d13 100644 --- a/tests/ui/asm/inline-syntax.arm.stderr +++ b/tests/ui/asm/inline-syntax.arm.stderr @@ -15,10 +15,10 @@ LL | .intel_syntax noprefix | ^ error: unknown directive - --> $DIR/inline-syntax.rs:29:15 + --> $DIR/inline-syntax.rs:35:15 | LL | asm!(".intel_syntax noprefix", "nop"); - | ^ + | ^^^^^^^^^^^^^^^^^^^^^^ | note: instantiated into assembly here --> <inline asm>:1:2 @@ -27,10 +27,10 @@ LL | .intel_syntax noprefix | ^ error: unknown directive - --> $DIR/inline-syntax.rs:32:15 + --> $DIR/inline-syntax.rs:39:15 | LL | asm!(".intel_syntax aaa noprefix", "nop"); - | ^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: instantiated into assembly here --> <inline asm>:1:2 @@ -39,10 +39,10 @@ LL | .intel_syntax aaa noprefix | ^ error: unknown directive - --> $DIR/inline-syntax.rs:35:15 + --> $DIR/inline-syntax.rs:43:15 | LL | asm!(".att_syntax noprefix", "nop"); - | ^ + | ^^^^^^^^^^^^^^^^^^^^ | note: instantiated into assembly here --> <inline asm>:1:2 @@ -51,10 +51,10 @@ LL | .att_syntax noprefix | ^ error: unknown directive - --> $DIR/inline-syntax.rs:38:15 + --> $DIR/inline-syntax.rs:47:15 | LL | asm!(".att_syntax bbb noprefix", "nop"); - | ^ + | ^^^^^^^^^^^^^^^^^^^^^^^^ | note: instantiated into assembly here --> <inline asm>:1:2 @@ -63,10 +63,10 @@ LL | .att_syntax bbb noprefix | ^ error: unknown directive - --> $DIR/inline-syntax.rs:41:15 + --> $DIR/inline-syntax.rs:51:15 | LL | asm!(".intel_syntax noprefix; nop"); - | ^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: instantiated into assembly here --> <inline asm>:1:2 @@ -75,10 +75,10 @@ LL | .intel_syntax noprefix; nop | ^ error: unknown directive - --> $DIR/inline-syntax.rs:47:13 + --> $DIR/inline-syntax.rs:58:13 | LL | .intel_syntax noprefix - | ^ + | ^^^^^^^^^^^^^^^^^^^^^^ | note: instantiated into assembly here --> <inline asm>:2:13 diff --git a/tests/ui/asm/inline-syntax.arm_llvm_18.stderr b/tests/ui/asm/inline-syntax.arm_llvm_18.stderr new file mode 100644 index 00000000000..ada3f4891d3 --- /dev/null +++ b/tests/ui/asm/inline-syntax.arm_llvm_18.stderr @@ -0,0 +1,90 @@ +error: unknown directive + | +note: instantiated into assembly here + --> <inline asm>:1:1 + | +LL | .intel_syntax noprefix + | ^ + +error: unknown directive + | +note: instantiated into assembly here + --> <inline asm>:1:1 + | +LL | .intel_syntax noprefix + | ^ + +error: unknown directive + --> $DIR/inline-syntax.rs:35:15 + | +LL | asm!(".intel_syntax noprefix", "nop"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:2 + | +LL | .intel_syntax noprefix + | ^ + +error: unknown directive + --> $DIR/inline-syntax.rs:39:15 + | +LL | asm!(".intel_syntax aaa noprefix", "nop"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:2 + | +LL | .intel_syntax aaa noprefix + | ^ + +error: unknown directive + --> $DIR/inline-syntax.rs:43:15 + | +LL | asm!(".att_syntax noprefix", "nop"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:2 + | +LL | .att_syntax noprefix + | ^ + +error: unknown directive + --> $DIR/inline-syntax.rs:47:15 + | +LL | asm!(".att_syntax bbb noprefix", "nop"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:2 + | +LL | .att_syntax bbb noprefix + | ^ + +error: unknown directive + --> $DIR/inline-syntax.rs:51:15 + | +LL | asm!(".intel_syntax noprefix; nop"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:2 + | +LL | .intel_syntax noprefix; nop + | ^ + +error: unknown directive + --> $DIR/inline-syntax.rs:58:13 + | +LL | .intel_syntax noprefix + | ^ + | +note: instantiated into assembly here + --> <inline asm>:2:13 + | +LL | .intel_syntax noprefix + | ^ + +error: aborting due to 8 previous errors + diff --git a/tests/ui/asm/inline-syntax.rs b/tests/ui/asm/inline-syntax.rs index b8486527e6f..fda79b2afa3 100644 --- a/tests/ui/asm/inline-syntax.rs +++ b/tests/ui/asm/inline-syntax.rs @@ -1,10 +1,16 @@ -//@ revisions: x86_64 arm +//@ revisions: x86_64 arm_llvm_18 arm //@[x86_64] compile-flags: --target x86_64-unknown-linux-gnu //@[x86_64] check-pass //@[x86_64] needs-llvm-components: x86 +//@[arm_llvm_18] compile-flags: --target armv7-unknown-linux-gnueabihf +//@[arm_llvm_18] build-fail +//@[arm_llvm_18] needs-llvm-components: arm +//@[arm_llvm_18] ignore-llvm-version: 19 - 99 +// LLVM 19+ has full support for 64-bit cookies. //@[arm] compile-flags: --target armv7-unknown-linux-gnueabihf //@[arm] build-fail //@[arm] needs-llvm-components: arm +//@[arm] min-llvm-version: 19 //@ needs-asm-support #![feature(no_core, lang_items, rustc_attrs)] @@ -29,18 +35,23 @@ pub fn main() { asm!(".intel_syntax noprefix", "nop"); //[x86_64]~^ WARN avoid using `.intel_syntax` //[arm]~^^ ERROR unknown directive + //[arm_llvm_18]~^^^ ERROR unknown directive asm!(".intel_syntax aaa noprefix", "nop"); //[x86_64]~^ WARN avoid using `.intel_syntax` //[arm]~^^ ERROR unknown directive + //[arm_llvm_18]~^^^ ERROR unknown directive asm!(".att_syntax noprefix", "nop"); //[x86_64]~^ WARN avoid using `.att_syntax` //[arm]~^^ ERROR unknown directive + //[arm_llvm_18]~^^^ ERROR unknown directive asm!(".att_syntax bbb noprefix", "nop"); //[x86_64]~^ WARN avoid using `.att_syntax` //[arm]~^^ ERROR unknown directive + //[arm_llvm_18]~^^^ ERROR unknown directive asm!(".intel_syntax noprefix; nop"); //[x86_64]~^ WARN avoid using `.intel_syntax` //[arm]~^^ ERROR unknown directive + //[arm_llvm_18]~^^^ ERROR unknown directive asm!( r" @@ -49,9 +60,10 @@ pub fn main() { ); //[x86_64]~^^^ WARN avoid using `.intel_syntax` //[arm]~^^^^ ERROR unknown directive + //[arm_llvm_18]~^^^^^ ERROR unknown directive } } global_asm!(".intel_syntax noprefix", "nop"); //[x86_64]~^ WARN avoid using `.intel_syntax` -// Assembler errors don't have line numbers, so no error on ARM +// Global assembly errors don't have line numbers, so no error on ARM. diff --git a/tests/ui/asm/inline-syntax.x86_64.stderr b/tests/ui/asm/inline-syntax.x86_64.stderr index 59c95194322..66dc37f3089 100644 --- a/tests/ui/asm/inline-syntax.x86_64.stderr +++ b/tests/ui/asm/inline-syntax.x86_64.stderr @@ -1,5 +1,5 @@ warning: avoid using `.intel_syntax`, Intel syntax is the default - --> $DIR/inline-syntax.rs:55:14 + --> $DIR/inline-syntax.rs:67:14 | LL | global_asm!(".intel_syntax noprefix", "nop"); | ^^^^^^^^^^^^^^^^^^^^^^ @@ -7,37 +7,37 @@ LL | global_asm!(".intel_syntax noprefix", "nop"); = note: `#[warn(bad_asm_style)]` on by default warning: avoid using `.intel_syntax`, Intel syntax is the default - --> $DIR/inline-syntax.rs:29:15 + --> $DIR/inline-syntax.rs:35:15 | LL | asm!(".intel_syntax noprefix", "nop"); | ^^^^^^^^^^^^^^^^^^^^^^ warning: avoid using `.intel_syntax`, Intel syntax is the default - --> $DIR/inline-syntax.rs:32:15 + --> $DIR/inline-syntax.rs:39:15 | LL | asm!(".intel_syntax aaa noprefix", "nop"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: avoid using `.att_syntax`, prefer using `options(att_syntax)` instead - --> $DIR/inline-syntax.rs:35:15 + --> $DIR/inline-syntax.rs:43:15 | LL | asm!(".att_syntax noprefix", "nop"); | ^^^^^^^^^^^^^^^^^^^^ warning: avoid using `.att_syntax`, prefer using `options(att_syntax)` instead - --> $DIR/inline-syntax.rs:38:15 + --> $DIR/inline-syntax.rs:47:15 | LL | asm!(".att_syntax bbb noprefix", "nop"); | ^^^^^^^^^^^^^^^^^^^^^^^^ warning: avoid using `.intel_syntax`, Intel syntax is the default - --> $DIR/inline-syntax.rs:41:15 + --> $DIR/inline-syntax.rs:51:15 | LL | asm!(".intel_syntax noprefix; nop"); | ^^^^^^^^^^^^^^^^^^^^^^ warning: avoid using `.intel_syntax`, Intel syntax is the default - --> $DIR/inline-syntax.rs:47:13 + --> $DIR/inline-syntax.rs:58:13 | LL | .intel_syntax noprefix | ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/asm/naked-functions-instruction-set.rs b/tests/ui/asm/naked-functions-instruction-set.rs index 37c7b52c191..3a6e7a46ce5 100644 --- a/tests/ui/asm/naked-functions-instruction-set.rs +++ b/tests/ui/asm/naked-functions-instruction-set.rs @@ -24,7 +24,7 @@ unsafe extern "C" fn test_thumb() { #[no_mangle] #[naked] -#[instruction_set(arm::t32)] +#[instruction_set(arm::a32)] unsafe extern "C" fn test_arm() { naked_asm!("bx lr"); } diff --git a/tests/ui/asm/naked-functions.rs b/tests/ui/asm/naked-functions.rs index 5c58f1498cc..e7e5d84f2a5 100644 --- a/tests/ui/asm/naked-functions.rs +++ b/tests/ui/asm/naked-functions.rs @@ -219,7 +219,6 @@ pub unsafe extern "C" fn compatible_must_use_attributes() -> u64 { #[export_name = "exported_function_name"] #[link_section = ".custom_section"] -#[no_mangle] #[naked] pub unsafe extern "C" fn compatible_ffi_attributes_1() { naked_asm!("", options(raw)); diff --git a/tests/ui/asm/riscv/riscv32e-registers.riscv32e.stderr b/tests/ui/asm/riscv/riscv32e-registers.riscv32e.stderr index e7a86805b26..ac1373f0e2d 100644 --- a/tests/ui/asm/riscv/riscv32e-registers.riscv32e.stderr +++ b/tests/ui/asm/riscv/riscv32e-registers.riscv32e.stderr @@ -1,8 +1,8 @@ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:46:11 + --> $DIR/riscv32e-registers.rs:58:11 | LL | asm!("li x16, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> <inline asm>:1:5 @@ -11,10 +11,10 @@ LL | li x16, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:49:11 + --> $DIR/riscv32e-registers.rs:61:11 | LL | asm!("li x17, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> <inline asm>:1:5 @@ -23,10 +23,10 @@ LL | li x17, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:52:11 + --> $DIR/riscv32e-registers.rs:64:11 | LL | asm!("li x18, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> <inline asm>:1:5 @@ -35,10 +35,10 @@ LL | li x18, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:55:11 + --> $DIR/riscv32e-registers.rs:67:11 | LL | asm!("li x19, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> <inline asm>:1:5 @@ -47,10 +47,10 @@ LL | li x19, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:58:11 + --> $DIR/riscv32e-registers.rs:70:11 | LL | asm!("li x20, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> <inline asm>:1:5 @@ -59,10 +59,10 @@ LL | li x20, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:61:11 + --> $DIR/riscv32e-registers.rs:73:11 | LL | asm!("li x21, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> <inline asm>:1:5 @@ -71,10 +71,10 @@ LL | li x21, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:64:11 + --> $DIR/riscv32e-registers.rs:76:11 | LL | asm!("li x22, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> <inline asm>:1:5 @@ -83,10 +83,10 @@ LL | li x22, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:67:11 + --> $DIR/riscv32e-registers.rs:79:11 | LL | asm!("li x23, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> <inline asm>:1:5 @@ -95,10 +95,10 @@ LL | li x23, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:70:11 + --> $DIR/riscv32e-registers.rs:82:11 | LL | asm!("li x24, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> <inline asm>:1:5 @@ -107,10 +107,10 @@ LL | li x24, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:73:11 + --> $DIR/riscv32e-registers.rs:85:11 | LL | asm!("li x25, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> <inline asm>:1:5 @@ -119,10 +119,10 @@ LL | li x25, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:76:11 + --> $DIR/riscv32e-registers.rs:88:11 | LL | asm!("li x26, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> <inline asm>:1:5 @@ -131,10 +131,10 @@ LL | li x26, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:79:11 + --> $DIR/riscv32e-registers.rs:91:11 | LL | asm!("li x27, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> <inline asm>:1:5 @@ -143,10 +143,10 @@ LL | li x27, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:82:11 + --> $DIR/riscv32e-registers.rs:94:11 | LL | asm!("li x28, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> <inline asm>:1:5 @@ -155,10 +155,10 @@ LL | li x28, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:85:11 + --> $DIR/riscv32e-registers.rs:97:11 | LL | asm!("li x29, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> <inline asm>:1:5 @@ -167,10 +167,10 @@ LL | li x29, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:88:11 + --> $DIR/riscv32e-registers.rs:100:11 | LL | asm!("li x30, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> <inline asm>:1:5 @@ -179,10 +179,10 @@ LL | li x30, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:91:11 + --> $DIR/riscv32e-registers.rs:103:11 | LL | asm!("li x31, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> <inline asm>:1:5 diff --git a/tests/ui/asm/riscv/riscv32e-registers.riscv32e_llvm_18.stderr b/tests/ui/asm/riscv/riscv32e-registers.riscv32e_llvm_18.stderr new file mode 100644 index 00000000000..f140f54adc5 --- /dev/null +++ b/tests/ui/asm/riscv/riscv32e-registers.riscv32e_llvm_18.stderr @@ -0,0 +1,194 @@ +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:58:11 + | +LL | asm!("li x16, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x16, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:61:11 + | +LL | asm!("li x17, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x17, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:64:11 + | +LL | asm!("li x18, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x18, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:67:11 + | +LL | asm!("li x19, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x19, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:70:11 + | +LL | asm!("li x20, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x20, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:73:11 + | +LL | asm!("li x21, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x21, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:76:11 + | +LL | asm!("li x22, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x22, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:79:11 + | +LL | asm!("li x23, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x23, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:82:11 + | +LL | asm!("li x24, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x24, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:85:11 + | +LL | asm!("li x25, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x25, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:88:11 + | +LL | asm!("li x26, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x26, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:91:11 + | +LL | asm!("li x27, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x27, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:94:11 + | +LL | asm!("li x28, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x28, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:97:11 + | +LL | asm!("li x29, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x29, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:100:11 + | +LL | asm!("li x30, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x30, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:103:11 + | +LL | asm!("li x31, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x31, 0 + | ^ + +error: aborting due to 16 previous errors + diff --git a/tests/ui/asm/riscv/riscv32e-registers.riscv32em.stderr b/tests/ui/asm/riscv/riscv32e-registers.riscv32em.stderr index e7a86805b26..ac1373f0e2d 100644 --- a/tests/ui/asm/riscv/riscv32e-registers.riscv32em.stderr +++ b/tests/ui/asm/riscv/riscv32e-registers.riscv32em.stderr @@ -1,8 +1,8 @@ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:46:11 + --> $DIR/riscv32e-registers.rs:58:11 | LL | asm!("li x16, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> <inline asm>:1:5 @@ -11,10 +11,10 @@ LL | li x16, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:49:11 + --> $DIR/riscv32e-registers.rs:61:11 | LL | asm!("li x17, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> <inline asm>:1:5 @@ -23,10 +23,10 @@ LL | li x17, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:52:11 + --> $DIR/riscv32e-registers.rs:64:11 | LL | asm!("li x18, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> <inline asm>:1:5 @@ -35,10 +35,10 @@ LL | li x18, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:55:11 + --> $DIR/riscv32e-registers.rs:67:11 | LL | asm!("li x19, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> <inline asm>:1:5 @@ -47,10 +47,10 @@ LL | li x19, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:58:11 + --> $DIR/riscv32e-registers.rs:70:11 | LL | asm!("li x20, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> <inline asm>:1:5 @@ -59,10 +59,10 @@ LL | li x20, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:61:11 + --> $DIR/riscv32e-registers.rs:73:11 | LL | asm!("li x21, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> <inline asm>:1:5 @@ -71,10 +71,10 @@ LL | li x21, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:64:11 + --> $DIR/riscv32e-registers.rs:76:11 | LL | asm!("li x22, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> <inline asm>:1:5 @@ -83,10 +83,10 @@ LL | li x22, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:67:11 + --> $DIR/riscv32e-registers.rs:79:11 | LL | asm!("li x23, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> <inline asm>:1:5 @@ -95,10 +95,10 @@ LL | li x23, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:70:11 + --> $DIR/riscv32e-registers.rs:82:11 | LL | asm!("li x24, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> <inline asm>:1:5 @@ -107,10 +107,10 @@ LL | li x24, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:73:11 + --> $DIR/riscv32e-registers.rs:85:11 | LL | asm!("li x25, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> <inline asm>:1:5 @@ -119,10 +119,10 @@ LL | li x25, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:76:11 + --> $DIR/riscv32e-registers.rs:88:11 | LL | asm!("li x26, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> <inline asm>:1:5 @@ -131,10 +131,10 @@ LL | li x26, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:79:11 + --> $DIR/riscv32e-registers.rs:91:11 | LL | asm!("li x27, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> <inline asm>:1:5 @@ -143,10 +143,10 @@ LL | li x27, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:82:11 + --> $DIR/riscv32e-registers.rs:94:11 | LL | asm!("li x28, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> <inline asm>:1:5 @@ -155,10 +155,10 @@ LL | li x28, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:85:11 + --> $DIR/riscv32e-registers.rs:97:11 | LL | asm!("li x29, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> <inline asm>:1:5 @@ -167,10 +167,10 @@ LL | li x29, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:88:11 + --> $DIR/riscv32e-registers.rs:100:11 | LL | asm!("li x30, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> <inline asm>:1:5 @@ -179,10 +179,10 @@ LL | li x30, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:91:11 + --> $DIR/riscv32e-registers.rs:103:11 | LL | asm!("li x31, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> <inline asm>:1:5 diff --git a/tests/ui/asm/riscv/riscv32e-registers.riscv32em_llvm_18.stderr b/tests/ui/asm/riscv/riscv32e-registers.riscv32em_llvm_18.stderr new file mode 100644 index 00000000000..f140f54adc5 --- /dev/null +++ b/tests/ui/asm/riscv/riscv32e-registers.riscv32em_llvm_18.stderr @@ -0,0 +1,194 @@ +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:58:11 + | +LL | asm!("li x16, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x16, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:61:11 + | +LL | asm!("li x17, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x17, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:64:11 + | +LL | asm!("li x18, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x18, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:67:11 + | +LL | asm!("li x19, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x19, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:70:11 + | +LL | asm!("li x20, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x20, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:73:11 + | +LL | asm!("li x21, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x21, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:76:11 + | +LL | asm!("li x22, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x22, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:79:11 + | +LL | asm!("li x23, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x23, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:82:11 + | +LL | asm!("li x24, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x24, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:85:11 + | +LL | asm!("li x25, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x25, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:88:11 + | +LL | asm!("li x26, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x26, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:91:11 + | +LL | asm!("li x27, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x27, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:94:11 + | +LL | asm!("li x28, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x28, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:97:11 + | +LL | asm!("li x29, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x29, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:100:11 + | +LL | asm!("li x30, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x30, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:103:11 + | +LL | asm!("li x31, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x31, 0 + | ^ + +error: aborting due to 16 previous errors + diff --git a/tests/ui/asm/riscv/riscv32e-registers.riscv32emc.stderr b/tests/ui/asm/riscv/riscv32e-registers.riscv32emc.stderr index e7a86805b26..ac1373f0e2d 100644 --- a/tests/ui/asm/riscv/riscv32e-registers.riscv32emc.stderr +++ b/tests/ui/asm/riscv/riscv32e-registers.riscv32emc.stderr @@ -1,8 +1,8 @@ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:46:11 + --> $DIR/riscv32e-registers.rs:58:11 | LL | asm!("li x16, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> <inline asm>:1:5 @@ -11,10 +11,10 @@ LL | li x16, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:49:11 + --> $DIR/riscv32e-registers.rs:61:11 | LL | asm!("li x17, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> <inline asm>:1:5 @@ -23,10 +23,10 @@ LL | li x17, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:52:11 + --> $DIR/riscv32e-registers.rs:64:11 | LL | asm!("li x18, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> <inline asm>:1:5 @@ -35,10 +35,10 @@ LL | li x18, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:55:11 + --> $DIR/riscv32e-registers.rs:67:11 | LL | asm!("li x19, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> <inline asm>:1:5 @@ -47,10 +47,10 @@ LL | li x19, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:58:11 + --> $DIR/riscv32e-registers.rs:70:11 | LL | asm!("li x20, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> <inline asm>:1:5 @@ -59,10 +59,10 @@ LL | li x20, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:61:11 + --> $DIR/riscv32e-registers.rs:73:11 | LL | asm!("li x21, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> <inline asm>:1:5 @@ -71,10 +71,10 @@ LL | li x21, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:64:11 + --> $DIR/riscv32e-registers.rs:76:11 | LL | asm!("li x22, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> <inline asm>:1:5 @@ -83,10 +83,10 @@ LL | li x22, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:67:11 + --> $DIR/riscv32e-registers.rs:79:11 | LL | asm!("li x23, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> <inline asm>:1:5 @@ -95,10 +95,10 @@ LL | li x23, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:70:11 + --> $DIR/riscv32e-registers.rs:82:11 | LL | asm!("li x24, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> <inline asm>:1:5 @@ -107,10 +107,10 @@ LL | li x24, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:73:11 + --> $DIR/riscv32e-registers.rs:85:11 | LL | asm!("li x25, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> <inline asm>:1:5 @@ -119,10 +119,10 @@ LL | li x25, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:76:11 + --> $DIR/riscv32e-registers.rs:88:11 | LL | asm!("li x26, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> <inline asm>:1:5 @@ -131,10 +131,10 @@ LL | li x26, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:79:11 + --> $DIR/riscv32e-registers.rs:91:11 | LL | asm!("li x27, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> <inline asm>:1:5 @@ -143,10 +143,10 @@ LL | li x27, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:82:11 + --> $DIR/riscv32e-registers.rs:94:11 | LL | asm!("li x28, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> <inline asm>:1:5 @@ -155,10 +155,10 @@ LL | li x28, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:85:11 + --> $DIR/riscv32e-registers.rs:97:11 | LL | asm!("li x29, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> <inline asm>:1:5 @@ -167,10 +167,10 @@ LL | li x29, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:88:11 + --> $DIR/riscv32e-registers.rs:100:11 | LL | asm!("li x30, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> <inline asm>:1:5 @@ -179,10 +179,10 @@ LL | li x30, 0 | ^ error: invalid operand for instruction - --> $DIR/riscv32e-registers.rs:91:11 + --> $DIR/riscv32e-registers.rs:103:11 | LL | asm!("li x31, 0"); - | ^ + | ^^^^^^^^^ | note: instantiated into assembly here --> <inline asm>:1:5 diff --git a/tests/ui/asm/riscv/riscv32e-registers.riscv32emc_llvm_18.stderr b/tests/ui/asm/riscv/riscv32e-registers.riscv32emc_llvm_18.stderr new file mode 100644 index 00000000000..f140f54adc5 --- /dev/null +++ b/tests/ui/asm/riscv/riscv32e-registers.riscv32emc_llvm_18.stderr @@ -0,0 +1,194 @@ +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:58:11 + | +LL | asm!("li x16, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x16, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:61:11 + | +LL | asm!("li x17, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x17, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:64:11 + | +LL | asm!("li x18, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x18, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:67:11 + | +LL | asm!("li x19, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x19, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:70:11 + | +LL | asm!("li x20, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x20, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:73:11 + | +LL | asm!("li x21, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x21, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:76:11 + | +LL | asm!("li x22, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x22, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:79:11 + | +LL | asm!("li x23, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x23, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:82:11 + | +LL | asm!("li x24, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x24, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:85:11 + | +LL | asm!("li x25, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x25, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:88:11 + | +LL | asm!("li x26, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x26, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:91:11 + | +LL | asm!("li x27, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x27, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:94:11 + | +LL | asm!("li x28, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x28, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:97:11 + | +LL | asm!("li x29, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x29, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:100:11 + | +LL | asm!("li x30, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x30, 0 + | ^ + +error: invalid operand for instruction + --> $DIR/riscv32e-registers.rs:103:11 + | +LL | asm!("li x31, 0"); + | ^ + | +note: instantiated into assembly here + --> <inline asm>:1:5 + | +LL | li x31, 0 + | ^ + +error: aborting due to 16 previous errors + diff --git a/tests/ui/asm/riscv/riscv32e-registers.rs b/tests/ui/asm/riscv/riscv32e-registers.rs index 57b1e169a04..c3fe19991b0 100644 --- a/tests/ui/asm/riscv/riscv32e-registers.rs +++ b/tests/ui/asm/riscv/riscv32e-registers.rs @@ -1,15 +1,27 @@ // Test that loads into registers x16..=x31 are never generated for riscv32{e,em,emc} targets // //@ build-fail -//@ revisions: riscv32e riscv32em riscv32emc +//@ revisions: riscv32e riscv32em riscv32emc riscv32e_llvm_18 riscv32em_llvm_18 riscv32emc_llvm_18 // //@ compile-flags: --crate-type=rlib //@ [riscv32e] needs-llvm-components: riscv //@ [riscv32e] compile-flags: --target=riscv32e-unknown-none-elf +//@ [riscv32e] min-llvm-version: 19 //@ [riscv32em] needs-llvm-components: riscv //@ [riscv32em] compile-flags: --target=riscv32em-unknown-none-elf +//@ [riscv32em] min-llvm-version: 19 //@ [riscv32emc] needs-llvm-components: riscv //@ [riscv32emc] compile-flags: --target=riscv32emc-unknown-none-elf +//@ [riscv32emc] min-llvm-version: 19 +//@ [riscv32e_llvm_18] needs-llvm-components: riscv +//@ [riscv32e_llvm_18] compile-flags: --target=riscv32e-unknown-none-elf +//@ [riscv32e_llvm_18] ignore-llvm-version: 19 - 99 +//@ [riscv32em_llvm_18] needs-llvm-components: riscv +//@ [riscv32em_llvm_18] compile-flags: --target=riscv32em-unknown-none-elf +//@ [riscv32em_llvm_18] ignore-llvm-version: 19 - 99 +//@ [riscv32emc_llvm_18] needs-llvm-components: riscv +//@ [riscv32emc_llvm_18] compile-flags: --target=riscv32emc-unknown-none-elf +//@ [riscv32emc_llvm_18] ignore-llvm-version: 19 - 99 // Unlike bad-reg.rs, this tests if the assembler can reject invalid registers // usage in assembly code. diff --git a/tests/ui/asm/x86_64/srcloc.new.stderr b/tests/ui/asm/x86_64/srcloc.new.stderr new file mode 100644 index 00000000000..7211f1ab69d --- /dev/null +++ b/tests/ui/asm/x86_64/srcloc.new.stderr @@ -0,0 +1,332 @@ +error: invalid instruction mnemonic 'invalid_instruction' + --> $DIR/srcloc.rs:14:15 + | +LL | asm!("invalid_instruction"); + | ^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> <inline asm>:2:2 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction' + --> $DIR/srcloc.rs:18:13 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> <inline asm>:3:13 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction' + --> $DIR/srcloc.rs:23:13 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> <inline asm>:3:13 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction' + --> $DIR/srcloc.rs:29:13 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> <inline asm>:4:13 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction' + --> $DIR/srcloc.rs:36:13 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> <inline asm>:4:13 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction' + --> $DIR/srcloc.rs:41:14 + | +LL | asm!(concat!("invalid", "_", "instruction")); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> <inline asm>:2:2 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + +warning: scale factor without index register is ignored + --> $DIR/srcloc.rs:44:15 + | +LL | asm!("movaps %xmm3, (%esi, 2)", options(att_syntax)); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> <inline asm>:1:23 + | +LL | movaps %xmm3, (%esi, 2) + | ^ + +error: invalid instruction mnemonic 'invalid_instruction' + --> $DIR/srcloc.rs:48:14 + | +LL | "invalid_instruction", + | ^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> <inline asm>:2:2 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction' + --> $DIR/srcloc.rs:54:14 + | +LL | "invalid_instruction", + | ^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> <inline asm>:3:1 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction' + --> $DIR/srcloc.rs:61:14 + | +LL | "invalid_instruction", + | ^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> <inline asm>:4:1 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction' + --> $DIR/srcloc.rs:68:13 + | +LL | concat!("invalid", "_", "instruction"), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> <inline asm>:3:1 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction' + --> $DIR/srcloc.rs:75:13 + | +LL | concat!("invalid", "_", "instruction"), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> <inline asm>:3:1 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction1' + --> $DIR/srcloc.rs:82:14 + | +LL | "invalid_instruction1", + | ^^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> <inline asm>:2:2 + | +LL | invalid_instruction1 + | ^^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction2' + --> $DIR/srcloc.rs:83:14 + | +LL | "invalid_instruction2", + | ^^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> <inline asm>:3:1 + | +LL | invalid_instruction2 + | ^^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction1' + --> $DIR/srcloc.rs:89:13 + | +LL | / concat!( +LL | | "invalid", "_", "instruction1", "\n", +LL | | "invalid", "_", "instruction2", +LL | | ), + | |_____________^ + | +note: instantiated into assembly here + --> <inline asm>:2:2 + | +LL | invalid_instruction1 + | ^^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction2' + --> $DIR/srcloc.rs:89:13 + | +LL | / concat!( +LL | | "invalid", "_", "instruction1", "\n", +LL | | "invalid", "_", "instruction2", +LL | | ), + | |_____________^ + | +note: instantiated into assembly here + --> <inline asm>:3:1 + | +LL | invalid_instruction2 + | ^^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction1' + --> $DIR/srcloc.rs:98:13 + | +LL | / concat!( +LL | | "invalid", "_", "instruction1", "\n", +LL | | "invalid", "_", "instruction2", +LL | | ), + | |_____________^ + | +note: instantiated into assembly here + --> <inline asm>:2:2 + | +LL | invalid_instruction1 + | ^^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction2' + --> $DIR/srcloc.rs:98:13 + | +LL | / concat!( +LL | | "invalid", "_", "instruction1", "\n", +LL | | "invalid", "_", "instruction2", +LL | | ), + | |_____________^ + | +note: instantiated into assembly here + --> <inline asm>:3:1 + | +LL | invalid_instruction2 + | ^^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction3' + --> $DIR/srcloc.rs:102:13 + | +LL | / concat!( +LL | | "invalid", "_", "instruction3", "\n", +LL | | "invalid", "_", "instruction4", +LL | | ), + | |_____________^ + | +note: instantiated into assembly here + --> <inline asm>:4:1 + | +LL | invalid_instruction3 + | ^^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction4' + --> $DIR/srcloc.rs:102:13 + | +LL | / concat!( +LL | | "invalid", "_", "instruction3", "\n", +LL | | "invalid", "_", "instruction4", +LL | | ), + | |_____________^ + | +note: instantiated into assembly here + --> <inline asm>:5:1 + | +LL | invalid_instruction4 + | ^^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction1' + --> $DIR/srcloc.rs:113:13 + | +LL | / concat!( +LL | | "invalid", "_", "instruction1", "\n", +LL | | "invalid", "_", "instruction2", "\n", +LL | | ), + | |_____________^ + | +note: instantiated into assembly here + --> <inline asm>:2:2 + | +LL | invalid_instruction1 + | ^^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction2' + --> $DIR/srcloc.rs:113:13 + | +LL | / concat!( +LL | | "invalid", "_", "instruction1", "\n", +LL | | "invalid", "_", "instruction2", "\n", +LL | | ), + | |_____________^ + | +note: instantiated into assembly here + --> <inline asm>:3:1 + | +LL | invalid_instruction2 + | ^^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction3' + --> $DIR/srcloc.rs:117:13 + | +LL | / concat!( +LL | | "invalid", "_", "instruction3", "\n", +LL | | "invalid", "_", "instruction4", "\n", +LL | | ), + | |_____________^ + | +note: instantiated into assembly here + --> <inline asm>:5:1 + | +LL | invalid_instruction3 + | ^^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction4' + --> $DIR/srcloc.rs:117:13 + | +LL | / concat!( +LL | | "invalid", "_", "instruction3", "\n", +LL | | "invalid", "_", "instruction4", "\n", +LL | | ), + | |_____________^ + | +note: instantiated into assembly here + --> <inline asm>:6:1 + | +LL | invalid_instruction4 + | ^^^^^^^^^^^^^^^^^^^^ + +error: invalid instruction mnemonic 'invalid_instruction' + --> $DIR/srcloc.rs:130:14 + | +LL | "invalid_instruction" + | ^^^^^^^^^^^^^^^^^^^ + | +note: instantiated into assembly here + --> <inline asm>:5:1 + | +LL | invalid_instruction + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 24 previous errors; 1 warning emitted + diff --git a/tests/ui/asm/x86_64/srcloc.stderr b/tests/ui/asm/x86_64/srcloc.old.stderr index 8899c1b916b..edb9ee46812 100644 --- a/tests/ui/asm/x86_64/srcloc.stderr +++ b/tests/ui/asm/x86_64/srcloc.old.stderr @@ -1,5 +1,5 @@ error: invalid instruction mnemonic 'invalid_instruction' - --> $DIR/srcloc.rs:11:15 + --> $DIR/srcloc.rs:14:15 | LL | asm!("invalid_instruction"); | ^ @@ -11,7 +11,7 @@ LL | invalid_instruction | ^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction' - --> $DIR/srcloc.rs:15:13 + --> $DIR/srcloc.rs:18:13 | LL | invalid_instruction | ^ @@ -23,7 +23,7 @@ LL | invalid_instruction | ^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction' - --> $DIR/srcloc.rs:20:13 + --> $DIR/srcloc.rs:23:13 | LL | invalid_instruction | ^ @@ -35,7 +35,7 @@ LL | invalid_instruction | ^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction' - --> $DIR/srcloc.rs:26:13 + --> $DIR/srcloc.rs:29:13 | LL | invalid_instruction | ^ @@ -47,7 +47,7 @@ LL | invalid_instruction | ^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction' - --> $DIR/srcloc.rs:33:13 + --> $DIR/srcloc.rs:36:13 | LL | invalid_instruction | ^ @@ -59,7 +59,7 @@ LL | invalid_instruction | ^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction' - --> $DIR/srcloc.rs:38:14 + --> $DIR/srcloc.rs:41:14 | LL | asm!(concat!("invalid", "_", "instruction")); | ^ @@ -71,7 +71,7 @@ LL | invalid_instruction | ^^^^^^^^^^^^^^^^^^^ warning: scale factor without index register is ignored - --> $DIR/srcloc.rs:41:15 + --> $DIR/srcloc.rs:44:15 | LL | asm!("movaps %xmm3, (%esi, 2)", options(att_syntax)); | ^ @@ -83,7 +83,7 @@ LL | movaps %xmm3, (%esi, 2) | ^ error: invalid instruction mnemonic 'invalid_instruction' - --> $DIR/srcloc.rs:45:14 + --> $DIR/srcloc.rs:48:14 | LL | "invalid_instruction", | ^ @@ -95,7 +95,7 @@ LL | invalid_instruction | ^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction' - --> $DIR/srcloc.rs:51:14 + --> $DIR/srcloc.rs:54:14 | LL | "invalid_instruction", | ^ @@ -107,7 +107,7 @@ LL | invalid_instruction | ^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction' - --> $DIR/srcloc.rs:58:14 + --> $DIR/srcloc.rs:61:14 | LL | "invalid_instruction", | ^ @@ -119,7 +119,7 @@ LL | invalid_instruction | ^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction' - --> $DIR/srcloc.rs:65:13 + --> $DIR/srcloc.rs:68:13 | LL | concat!("invalid", "_", "instruction"), | ^ @@ -131,7 +131,7 @@ LL | invalid_instruction | ^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction' - --> $DIR/srcloc.rs:72:13 + --> $DIR/srcloc.rs:75:13 | LL | concat!("invalid", "_", "instruction"), | ^ @@ -143,7 +143,7 @@ LL | invalid_instruction | ^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction1' - --> $DIR/srcloc.rs:79:14 + --> $DIR/srcloc.rs:82:14 | LL | "invalid_instruction1", | ^ @@ -155,7 +155,7 @@ LL | invalid_instruction1 | ^^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction2' - --> $DIR/srcloc.rs:80:14 + --> $DIR/srcloc.rs:83:14 | LL | "invalid_instruction2", | ^ @@ -167,7 +167,7 @@ LL | invalid_instruction2 | ^^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction1' - --> $DIR/srcloc.rs:86:13 + --> $DIR/srcloc.rs:89:13 | LL | concat!( | ^ @@ -179,7 +179,7 @@ LL | invalid_instruction1 | ^^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction2' - --> $DIR/srcloc.rs:86:13 + --> $DIR/srcloc.rs:89:13 | LL | concat!( | ^ @@ -191,7 +191,7 @@ LL | invalid_instruction2 | ^^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction1' - --> $DIR/srcloc.rs:95:13 + --> $DIR/srcloc.rs:98:13 | LL | concat!( | ^ @@ -203,7 +203,7 @@ LL | invalid_instruction1 | ^^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction2' - --> $DIR/srcloc.rs:95:13 + --> $DIR/srcloc.rs:98:13 | LL | concat!( | ^ @@ -215,7 +215,7 @@ LL | invalid_instruction2 | ^^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction3' - --> $DIR/srcloc.rs:99:13 + --> $DIR/srcloc.rs:102:13 | LL | concat!( | ^ @@ -227,7 +227,7 @@ LL | invalid_instruction3 | ^^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction4' - --> $DIR/srcloc.rs:99:13 + --> $DIR/srcloc.rs:102:13 | LL | concat!( | ^ @@ -239,7 +239,7 @@ LL | invalid_instruction4 | ^^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction1' - --> $DIR/srcloc.rs:110:13 + --> $DIR/srcloc.rs:113:13 | LL | concat!( | ^ @@ -251,7 +251,7 @@ LL | invalid_instruction1 | ^^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction2' - --> $DIR/srcloc.rs:110:13 + --> $DIR/srcloc.rs:113:13 | LL | concat!( | ^ @@ -263,7 +263,7 @@ LL | invalid_instruction2 | ^^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction3' - --> $DIR/srcloc.rs:114:13 + --> $DIR/srcloc.rs:117:13 | LL | concat!( | ^ @@ -275,7 +275,7 @@ LL | invalid_instruction3 | ^^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction4' - --> $DIR/srcloc.rs:114:13 + --> $DIR/srcloc.rs:117:13 | LL | concat!( | ^ @@ -287,7 +287,7 @@ LL | invalid_instruction4 | ^^^^^^^^^^^^^^^^^^^^ error: invalid instruction mnemonic 'invalid_instruction' - --> $DIR/srcloc.rs:127:14 + --> $DIR/srcloc.rs:130:14 | LL | "invalid_instruction" | ^ diff --git a/tests/ui/asm/x86_64/srcloc.rs b/tests/ui/asm/x86_64/srcloc.rs index 2938bafe5e7..40fc66cbc92 100644 --- a/tests/ui/asm/x86_64/srcloc.rs +++ b/tests/ui/asm/x86_64/srcloc.rs @@ -1,6 +1,9 @@ +//@ revisions: old new //@ only-x86_64 //@ build-fail //@ compile-flags: -Ccodegen-units=1 +//@[old] ignore-llvm-version: 19 - 99 +//@[new] min-llvm-version: 19 use std::arch::asm; diff --git a/tests/ui/async-await/async-closures/call-once-deduction.rs b/tests/ui/async-await/async-closures/call-once-deduction.rs new file mode 100644 index 00000000000..41d92bc3d78 --- /dev/null +++ b/tests/ui/async-await/async-closures/call-once-deduction.rs @@ -0,0 +1,14 @@ +//@ edition: 2021 +//@ check-pass + +#![feature(async_closure, async_fn_traits, unboxed_closures)] + +fn bar<F, O>(_: F) +where + F: AsyncFnOnce<(), CallOnceFuture = O>, +{ +} + +fn main() { + bar(async move || {}); +} diff --git a/tests/ui/attributes/mixed_export_name_and_no_mangle.fixed b/tests/ui/attributes/mixed_export_name_and_no_mangle.fixed new file mode 100644 index 00000000000..7224d4289e3 --- /dev/null +++ b/tests/ui/attributes/mixed_export_name_and_no_mangle.fixed @@ -0,0 +1,14 @@ +// issue: rust-lang/rust#47446 +//@ run-rustfix +//@ check-pass + +#![warn(unused_attributes)] +//~^ WARN `#[no_mangle]` attribute may not be used in combination with `#[export_name]` [unused_attributes] +#[export_name = "foo"] +pub fn bar() {} + +//~^ WARN `#[unsafe(no_mangle)]` attribute may not be used in combination with `#[export_name]` [unused_attributes] +#[export_name = "baz"] +pub fn bak() {} + +fn main() {} diff --git a/tests/ui/attributes/mixed_export_name_and_no_mangle.rs b/tests/ui/attributes/mixed_export_name_and_no_mangle.rs new file mode 100644 index 00000000000..149a7904e1e --- /dev/null +++ b/tests/ui/attributes/mixed_export_name_and_no_mangle.rs @@ -0,0 +1,16 @@ +// issue: rust-lang/rust#47446 +//@ run-rustfix +//@ check-pass + +#![warn(unused_attributes)] +#[no_mangle] +//~^ WARN `#[no_mangle]` attribute may not be used in combination with `#[export_name]` [unused_attributes] +#[export_name = "foo"] +pub fn bar() {} + +#[unsafe(no_mangle)] +//~^ WARN `#[unsafe(no_mangle)]` attribute may not be used in combination with `#[export_name]` [unused_attributes] +#[export_name = "baz"] +pub fn bak() {} + +fn main() {} diff --git a/tests/ui/attributes/mixed_export_name_and_no_mangle.stderr b/tests/ui/attributes/mixed_export_name_and_no_mangle.stderr new file mode 100644 index 00000000000..ba63127ba2d --- /dev/null +++ b/tests/ui/attributes/mixed_export_name_and_no_mangle.stderr @@ -0,0 +1,39 @@ +warning: `#[no_mangle]` attribute may not be used in combination with `#[export_name]` + --> $DIR/mixed_export_name_and_no_mangle.rs:6:1 + | +LL | #[no_mangle] + | ^^^^^^^^^^^^ `#[no_mangle]` is ignored + | +note: `#[export_name]` takes precedence + --> $DIR/mixed_export_name_and_no_mangle.rs:8:1 + | +LL | #[export_name = "foo"] + | ^^^^^^^^^^^^^^^^^^^^^^ +note: the lint level is defined here + --> $DIR/mixed_export_name_and_no_mangle.rs:5:9 + | +LL | #![warn(unused_attributes)] + | ^^^^^^^^^^^^^^^^^ +help: remove the `#[no_mangle]` attribute + | +LL - #[no_mangle] + | + +warning: `#[unsafe(no_mangle)]` attribute may not be used in combination with `#[export_name]` + --> $DIR/mixed_export_name_and_no_mangle.rs:11:1 + | +LL | #[unsafe(no_mangle)] + | ^^^^^^^^^^^^^^^^^^^^ `#[unsafe(no_mangle)]` is ignored + | +note: `#[export_name]` takes precedence + --> $DIR/mixed_export_name_and_no_mangle.rs:13:1 + | +LL | #[export_name = "baz"] + | ^^^^^^^^^^^^^^^^^^^^^^ +help: remove the `#[unsafe(no_mangle)]` attribute + | +LL - #[unsafe(no_mangle)] + | + +warning: 2 warnings emitted + diff --git a/tests/ui/check-cfg/target_feature.stderr b/tests/ui/check-cfg/target_feature.stderr index 2674a97a551..3df1545cd4a 100644 --- a/tests/ui/check-cfg/target_feature.stderr +++ b/tests/ui/check-cfg/target_feature.stderr @@ -153,6 +153,7 @@ LL | cfg!(target_feature = "_UNEXPECTED_VALUE"); `popcnt` `power10-vector` `power8-altivec` +`power8-crypto` `power8-vector` `power9-altivec` `power9-vector` diff --git a/tests/ui/const-generics/generic_const_exprs/unevaluated-const-ice-119731.stderr b/tests/ui/const-generics/generic_const_exprs/unevaluated-const-ice-119731.stderr index 4eb374b2020..30a45ce377e 100644 --- a/tests/ui/const-generics/generic_const_exprs/unevaluated-const-ice-119731.stderr +++ b/tests/ui/const-generics/generic_const_exprs/unevaluated-const-ice-119731.stderr @@ -72,20 +72,6 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more LL + #![feature(adt_const_params)] | -note: erroneous constant encountered - --> $DIR/unevaluated-const-ice-119731.rs:22:19 - | -LL | impl v17<512, v0> { - | ^^ - -note: erroneous constant encountered - --> $DIR/unevaluated-const-ice-119731.rs:22:19 - | -LL | impl v17<512, v0> { - | ^^ - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - error: maximum number of nodes exceeded in constant v20::v17::<v10, v2>::{constant#0} --> $DIR/unevaluated-const-ice-119731.rs:28:37 | diff --git a/tests/ui/consts/const-integer-bool-ops.stderr b/tests/ui/consts/const-integer-bool-ops.stderr index d58a8e93ff6..4e503e5a5c0 100644 --- a/tests/ui/consts/const-integer-bool-ops.stderr +++ b/tests/ui/consts/const-integer-bool-ops.stderr @@ -16,12 +16,6 @@ error[E0308]: mismatched types LL | const X: usize = 42 && 39; | ^^^^^^^^ expected `usize`, found `bool` -note: erroneous constant encountered - --> $DIR/const-integer-bool-ops.rs:8:18 - | -LL | const ARR: [i32; X] = [99; 34]; - | ^ - error[E0308]: mismatched types --> $DIR/const-integer-bool-ops.rs:10:19 | @@ -40,12 +34,6 @@ error[E0308]: mismatched types LL | const X1: usize = 42 || 39; | ^^^^^^^^ expected `usize`, found `bool` -note: erroneous constant encountered - --> $DIR/const-integer-bool-ops.rs:17:19 - | -LL | const ARR1: [i32; X1] = [99; 47]; - | ^^ - error[E0308]: mismatched types --> $DIR/const-integer-bool-ops.rs:19:19 | @@ -64,12 +52,6 @@ error[E0308]: mismatched types LL | const X2: usize = -42 || -39; | ^^^^^^^^^^ expected `usize`, found `bool` -note: erroneous constant encountered - --> $DIR/const-integer-bool-ops.rs:26:19 - | -LL | const ARR2: [i32; X2] = [99; 18446744073709551607]; - | ^^ - error[E0308]: mismatched types --> $DIR/const-integer-bool-ops.rs:28:19 | @@ -88,84 +70,42 @@ error[E0308]: mismatched types LL | const X3: usize = -42 && -39; | ^^^^^^^^^^ expected `usize`, found `bool` -note: erroneous constant encountered - --> $DIR/const-integer-bool-ops.rs:35:19 - | -LL | const ARR3: [i32; X3] = [99; 6]; - | ^^ - error[E0308]: mismatched types --> $DIR/const-integer-bool-ops.rs:37:18 | LL | const Y: usize = 42.0 == 42.0; | ^^^^^^^^^^^^ expected `usize`, found `bool` -note: erroneous constant encountered - --> $DIR/const-integer-bool-ops.rs:40:19 - | -LL | const ARRR: [i32; Y] = [99; 1]; - | ^ - error[E0308]: mismatched types --> $DIR/const-integer-bool-ops.rs:42:19 | LL | const Y1: usize = 42.0 >= 42.0; | ^^^^^^^^^^^^ expected `usize`, found `bool` -note: erroneous constant encountered - --> $DIR/const-integer-bool-ops.rs:45:20 - | -LL | const ARRR1: [i32; Y1] = [99; 1]; - | ^^ - error[E0308]: mismatched types --> $DIR/const-integer-bool-ops.rs:47:19 | LL | const Y2: usize = 42.0 <= 42.0; | ^^^^^^^^^^^^ expected `usize`, found `bool` -note: erroneous constant encountered - --> $DIR/const-integer-bool-ops.rs:50:20 - | -LL | const ARRR2: [i32; Y2] = [99; 1]; - | ^^ - error[E0308]: mismatched types --> $DIR/const-integer-bool-ops.rs:52:19 | LL | const Y3: usize = 42.0 > 42.0; | ^^^^^^^^^^^ expected `usize`, found `bool` -note: erroneous constant encountered - --> $DIR/const-integer-bool-ops.rs:55:20 - | -LL | const ARRR3: [i32; Y3] = [99; 0]; - | ^^ - error[E0308]: mismatched types --> $DIR/const-integer-bool-ops.rs:57:19 | LL | const Y4: usize = 42.0 < 42.0; | ^^^^^^^^^^^ expected `usize`, found `bool` -note: erroneous constant encountered - --> $DIR/const-integer-bool-ops.rs:60:20 - | -LL | const ARRR4: [i32; Y4] = [99; 0]; - | ^^ - error[E0308]: mismatched types --> $DIR/const-integer-bool-ops.rs:62:19 | LL | const Y5: usize = 42.0 != 42.0; | ^^^^^^^^^^^^ expected `usize`, found `bool` -note: erroneous constant encountered - --> $DIR/const-integer-bool-ops.rs:65:20 - | -LL | const ARRR5: [i32; Y5] = [99; 0]; - | ^^ - error: aborting due to 18 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/consts/const-mut-refs/issue-76510.stderr b/tests/ui/consts/const-mut-refs/issue-76510.stderr index a63be676fda..aff86e83578 100644 --- a/tests/ui/consts/const-mut-refs/issue-76510.stderr +++ b/tests/ui/consts/const-mut-refs/issue-76510.stderr @@ -4,12 +4,6 @@ error[E0764]: mutable references are not allowed in the final value of constants LL | const S: &'static mut str = &mut " hello "; | ^^^^^^^^^^^^^^ -note: erroneous constant encountered - --> $DIR/issue-76510.rs:7:70 - | -LL | let s = transmute::<(*const u8, usize), &ManuallyDrop<str>>((S.as_ptr(), 3)); - | ^ - error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0764`. diff --git a/tests/ui/consts/const-try.stderr b/tests/ui/consts/const-try.stderr index abb03a74c82..4209ca1d526 100644 --- a/tests/ui/consts/const-try.stderr +++ b/tests/ui/consts/const-try.stderr @@ -2,7 +2,7 @@ error: const `impl` for trait `FromResidual` which is not marked with `#[const_t --> $DIR/const-try.rs:15:12 | LL | impl const FromResidual<Error> for TryMe { - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ this trait is not `const` | = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` = note: adding a non-const method body in the future would be a breaking change @@ -11,7 +11,7 @@ error: const `impl` for trait `Try` which is not marked with `#[const_trait]` --> $DIR/const-try.rs:22:12 | LL | impl const Try for TryMe { - | ^^^ + | ^^^ this trait is not `const` | = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` = note: adding a non-const method body in the future would be a breaking change diff --git a/tests/ui/consts/const-tup-index-span.stderr b/tests/ui/consts/const-tup-index-span.stderr index 2a3f0cfb06d..792e18aa8fd 100644 --- a/tests/ui/consts/const-tup-index-span.stderr +++ b/tests/ui/consts/const-tup-index-span.stderr @@ -11,12 +11,6 @@ help: use a trailing comma to create a tuple with one element LL | const TUP: (usize,) = (5usize << 64,); | + ++ -note: erroneous constant encountered - --> $DIR/const-tup-index-span.rs:6:18 - | -LL | const ARR: [i32; TUP.0] = []; - | ^^^ - error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/consts/fn_trait_refs.stderr b/tests/ui/consts/fn_trait_refs.stderr index bb7ff76b125..e0dbecff8e5 100644 --- a/tests/ui/consts/fn_trait_refs.stderr +++ b/tests/ui/consts/fn_trait_refs.stderr @@ -14,110 +14,145 @@ error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/fn_trait_refs.rs:14:8 | LL | T: ~const Fn<()> + ~const Destruct, - | ^^^^^^ + | ^^^^^^ can't be applied to `Fn` + | +note: `Fn` can't be used with `~const` because it isn't annotated with `#[const_trait]` + --> $SRC_DIR/core/src/ops/function.rs:LL:COL error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/fn_trait_refs.rs:14:8 | LL | T: ~const Fn<()> + ~const Destruct, - | ^^^^^^ + | ^^^^^^ can't be applied to `Fn` | +note: `Fn` can't be used with `~const` because it isn't annotated with `#[const_trait]` + --> $SRC_DIR/core/src/ops/function.rs:LL:COL = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/fn_trait_refs.rs:14:8 | LL | T: ~const Fn<()> + ~const Destruct, - | ^^^^^^ + | ^^^^^^ can't be applied to `Fn` | +note: `Fn` can't be used with `~const` because it isn't annotated with `#[const_trait]` + --> $SRC_DIR/core/src/ops/function.rs:LL:COL = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/fn_trait_refs.rs:21:8 | LL | T: ~const FnMut<()> + ~const Destruct, - | ^^^^^^ + | ^^^^^^ can't be applied to `FnMut` + | +note: `FnMut` can't be used with `~const` because it isn't annotated with `#[const_trait]` + --> $SRC_DIR/core/src/ops/function.rs:LL:COL error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/fn_trait_refs.rs:21:8 | LL | T: ~const FnMut<()> + ~const Destruct, - | ^^^^^^ + | ^^^^^^ can't be applied to `FnMut` | +note: `FnMut` can't be used with `~const` because it isn't annotated with `#[const_trait]` + --> $SRC_DIR/core/src/ops/function.rs:LL:COL = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/fn_trait_refs.rs:21:8 | LL | T: ~const FnMut<()> + ~const Destruct, - | ^^^^^^ + | ^^^^^^ can't be applied to `FnMut` | +note: `FnMut` can't be used with `~const` because it isn't annotated with `#[const_trait]` + --> $SRC_DIR/core/src/ops/function.rs:LL:COL = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/fn_trait_refs.rs:28:8 | LL | T: ~const FnOnce<()>, - | ^^^^^^ + | ^^^^^^ can't be applied to `FnOnce` + | +note: `FnOnce` can't be used with `~const` because it isn't annotated with `#[const_trait]` + --> $SRC_DIR/core/src/ops/function.rs:LL:COL error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/fn_trait_refs.rs:28:8 | LL | T: ~const FnOnce<()>, - | ^^^^^^ + | ^^^^^^ can't be applied to `FnOnce` | +note: `FnOnce` can't be used with `~const` because it isn't annotated with `#[const_trait]` + --> $SRC_DIR/core/src/ops/function.rs:LL:COL = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/fn_trait_refs.rs:28:8 | LL | T: ~const FnOnce<()>, - | ^^^^^^ + | ^^^^^^ can't be applied to `FnOnce` | +note: `FnOnce` can't be used with `~const` because it isn't annotated with `#[const_trait]` + --> $SRC_DIR/core/src/ops/function.rs:LL:COL = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/fn_trait_refs.rs:35:8 | LL | T: ~const Fn<()> + ~const Destruct, - | ^^^^^^ + | ^^^^^^ can't be applied to `Fn` + | +note: `Fn` can't be used with `~const` because it isn't annotated with `#[const_trait]` + --> $SRC_DIR/core/src/ops/function.rs:LL:COL error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/fn_trait_refs.rs:35:8 | LL | T: ~const Fn<()> + ~const Destruct, - | ^^^^^^ + | ^^^^^^ can't be applied to `Fn` | +note: `Fn` can't be used with `~const` because it isn't annotated with `#[const_trait]` + --> $SRC_DIR/core/src/ops/function.rs:LL:COL = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/fn_trait_refs.rs:35:8 | LL | T: ~const Fn<()> + ~const Destruct, - | ^^^^^^ + | ^^^^^^ can't be applied to `Fn` | +note: `Fn` can't be used with `~const` because it isn't annotated with `#[const_trait]` + --> $SRC_DIR/core/src/ops/function.rs:LL:COL = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/fn_trait_refs.rs:49:8 | LL | T: ~const FnMut<()> + ~const Destruct, - | ^^^^^^ + | ^^^^^^ can't be applied to `FnMut` + | +note: `FnMut` can't be used with `~const` because it isn't annotated with `#[const_trait]` + --> $SRC_DIR/core/src/ops/function.rs:LL:COL error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/fn_trait_refs.rs:49:8 | LL | T: ~const FnMut<()> + ~const Destruct, - | ^^^^^^ + | ^^^^^^ can't be applied to `FnMut` | +note: `FnMut` can't be used with `~const` because it isn't annotated with `#[const_trait]` + --> $SRC_DIR/core/src/ops/function.rs:LL:COL = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/fn_trait_refs.rs:49:8 | LL | T: ~const FnMut<()> + ~const Destruct, - | ^^^^^^ + | ^^^^^^ can't be applied to `FnMut` | +note: `FnMut` can't be used with `~const` because it isn't annotated with `#[const_trait]` + --> $SRC_DIR/core/src/ops/function.rs:LL:COL = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: the trait bound `fn() -> i32 {one}: const Destruct` is not satisfied diff --git a/tests/ui/consts/issue-54954.stderr b/tests/ui/consts/issue-54954.stderr index ed6aa9c44a3..b8c983eb7b8 100644 --- a/tests/ui/consts/issue-54954.stderr +++ b/tests/ui/consts/issue-54954.stderr @@ -19,24 +19,6 @@ LL | | core::mem::size_of::<T>() LL | | } | |_____- `Tt::const_val` defined here -note: erroneous constant encountered - --> $DIR/issue-54954.rs:11:15 - | -LL | fn f(z: [f32; ARR_LEN]) -> [f32; ARR_LEN] { - | ^^^^^^^ - -note: erroneous constant encountered - --> $DIR/issue-54954.rs:11:34 - | -LL | fn f(z: [f32; ARR_LEN]) -> [f32; ARR_LEN] { - | ^^^^^^^ - -note: erroneous constant encountered - --> $DIR/issue-54954.rs:16:22 - | -LL | let _ = f([1f32; ARR_LEN]); - | ^^^^^^^ - error: aborting due to 2 previous errors Some errors have detailed explanations: E0379, E0790. diff --git a/tests/ui/consts/missing_assoc_const_type2.stderr b/tests/ui/consts/missing_assoc_const_type2.stderr index 3279a077464..1255ca2d102 100644 --- a/tests/ui/consts/missing_assoc_const_type2.stderr +++ b/tests/ui/consts/missing_assoc_const_type2.stderr @@ -4,11 +4,5 @@ error: missing type for `const` item LL | const FIRST: = 10; | ^ help: provide a type for the associated constant: `u8` -note: erroneous constant encountered - --> $DIR/missing_assoc_const_type2.rs:18:5 - | -LL | TwoDigits::FIRST as usize - | ^^^^^^^^^^^^^^^^ - error: aborting due to 1 previous error diff --git a/tests/ui/consts/promoted-type-error-issue-133968.rs b/tests/ui/consts/promoted-type-error-issue-133968.rs new file mode 100644 index 00000000000..52c0d48ab5b --- /dev/null +++ b/tests/ui/consts/promoted-type-error-issue-133968.rs @@ -0,0 +1,7 @@ +struct B<T: ?Sized + Send + 'static> { + x: &'static T, +} +static STR: &'static [u8] = "a b"; //~ERROR: mismatched types +static C: &B<[u8]> = &B { x: STR }; + +fn main() {} diff --git a/tests/ui/consts/promoted-type-error-issue-133968.stderr b/tests/ui/consts/promoted-type-error-issue-133968.stderr new file mode 100644 index 00000000000..24f1268e4b6 --- /dev/null +++ b/tests/ui/consts/promoted-type-error-issue-133968.stderr @@ -0,0 +1,16 @@ +error[E0308]: mismatched types + --> $DIR/promoted-type-error-issue-133968.rs:4:29 + | +LL | static STR: &'static [u8] = "a b"; + | ^^^^^ expected `&[u8]`, found `&str` + | + = note: expected reference `&'static [u8]` + found reference `&'static str` +help: consider adding a leading `b` + | +LL | static STR: &'static [u8] = b"a b"; + | + + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/consts/rustc-impl-const-stability.stderr b/tests/ui/consts/rustc-impl-const-stability.stderr index 4a58b5c8603..19c6bb5907f 100644 --- a/tests/ui/consts/rustc-impl-const-stability.stderr +++ b/tests/ui/consts/rustc-impl-const-stability.stderr @@ -2,7 +2,7 @@ error: const `impl` for trait `Default` which is not marked with `#[const_trait] --> $DIR/rustc-impl-const-stability.rs:15:12 | LL | impl const Default for Data { - | ^^^^^^^ + | ^^^^^^^ this trait is not `const` | = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` = note: adding a non-const method body in the future would be a breaking change diff --git a/tests/ui/consts/unstable-const-fn-in-libcore.stderr b/tests/ui/consts/unstable-const-fn-in-libcore.stderr index f40c1871e90..32693edbfcb 100644 --- a/tests/ui/consts/unstable-const-fn-in-libcore.stderr +++ b/tests/ui/consts/unstable-const-fn-in-libcore.stderr @@ -2,14 +2,19 @@ error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/unstable-const-fn-in-libcore.rs:19:32 | LL | const fn unwrap_or_else<F: ~const FnOnce() -> T>(self, f: F) -> T { - | ^^^^^^ + | ^^^^^^ can't be applied to `FnOnce` + | +note: `FnOnce` can't be used with `~const` because it isn't annotated with `#[const_trait]` + --> $SRC_DIR/core/src/ops/function.rs:LL:COL error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/unstable-const-fn-in-libcore.rs:19:32 | LL | const fn unwrap_or_else<F: ~const FnOnce() -> T>(self, f: F) -> T { - | ^^^^^^ + | ^^^^^^ can't be applied to `FnOnce` | +note: `FnOnce` can't be used with `~const` because it isn't annotated with `#[const_trait]` + --> $SRC_DIR/core/src/ops/function.rs:LL:COL = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0015]: cannot call non-const closure in constant functions diff --git a/tests/ui/dataflow_const_prop/ptr-in-switch-int-issue-131227.rs b/tests/ui/dataflow_const_prop/ptr-in-switch-int-issue-131227.rs new file mode 100644 index 00000000000..7a55e13d0ee --- /dev/null +++ b/tests/ui/dataflow_const_prop/ptr-in-switch-int-issue-131227.rs @@ -0,0 +1,19 @@ +//! Issue: <https://github.com/rust-lang/rust/issues/131227> +//! Test that constant propagation in SwitchInt does not crash +//! when encountering a ptr-to-int transmute. + +//@ check-pass +//@ compile-flags: -Zmir-enable-passes=+InstSimplify-before-inline,+DataflowConstProp + +#![crate_type = "lib"] + +static mut G: i32 = 0; + +pub fn myfunc() -> i32 { + let var = &raw mut G; + let u: usize = unsafe { std::mem::transmute(var) }; + match u { + 0 => 0, + _ => 1, + } +} diff --git a/tests/ui/destructuring-assignment/struct_destructure_fail.stderr b/tests/ui/destructuring-assignment/struct_destructure_fail.stderr index 4c4f0663eeb..58f8e97dea0 100644 --- a/tests/ui/destructuring-assignment/struct_destructure_fail.stderr +++ b/tests/ui/destructuring-assignment/struct_destructure_fail.stderr @@ -12,17 +12,6 @@ error: functional record updates are not allowed in destructuring assignments LL | Struct { a, ..d } = Struct { a: 1, b: 2 }; | ^ help: consider removing the trailing pattern -error[E0797]: base expression required after `..` - --> $DIR/struct_destructure_fail.rs:15:19 - | -LL | Struct { a, .. }; - | ^ - | -help: add a base expression here - | -LL | Struct { a, ../* expr */ }; - | ++++++++++ - error[E0026]: struct `Struct` does not have a field named `c` --> $DIR/struct_destructure_fail.rs:10:20 | @@ -48,6 +37,17 @@ help: or always ignore missing fields here LL | Struct { a, .. } = Struct { a: 1, b: 2 }; | ~~~~~~ +error[E0797]: base expression required after `..` + --> $DIR/struct_destructure_fail.rs:15:19 + | +LL | Struct { a, .. }; + | ^ + | +help: add a base expression here + | +LL | Struct { a, ../* expr */ }; + | ++++++++++ + error: aborting due to 5 previous errors Some errors have detailed explanations: E0026, E0027, E0797. diff --git a/tests/ui/enum-discriminant/issue-41394.stderr b/tests/ui/enum-discriminant/issue-41394.stderr index 9bf4fc79b1b..e81562df04f 100644 --- a/tests/ui/enum-discriminant/issue-41394.stderr +++ b/tests/ui/enum-discriminant/issue-41394.stderr @@ -6,12 +6,6 @@ LL | A = "" + 1 | | | &str -note: erroneous constant encountered - --> $DIR/issue-41394.rs:7:9 - | -LL | A = Foo::A as isize - | ^^^^^^^^^^^^^^^ - error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0369`. diff --git a/tests/ui/extern/extern-C-non-FFI-safe-arg-ice-52334.stderr b/tests/ui/extern/extern-C-non-FFI-safe-arg-ice-52334.stderr index b5c718ec381..044c1ae2dd4 100644 --- a/tests/ui/extern/extern-C-non-FFI-safe-arg-ice-52334.stderr +++ b/tests/ui/extern/extern-C-non-FFI-safe-arg-ice-52334.stderr @@ -4,7 +4,6 @@ warning: `extern` fn uses type `CStr`, which is not FFI-safe LL | type Foo = extern "C" fn(::std::ffi::CStr); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe | - = note: the function pointer to `extern "C" fn(CStr)` is FFI-unsafe due to `CStr` = help: consider passing a `*const std::ffi::c_char` instead, and use `CStr::as_ptr()` = note: `CStr`/`CString` do not have a guaranteed layout = note: `#[warn(improper_ctypes_definitions)]` on by default @@ -15,7 +14,6 @@ warning: `extern` block uses type `CStr`, which is not FFI-safe LL | fn meh(blah: Foo); | ^^^ not FFI-safe | - = note: the function pointer to `extern "C" fn(CStr)` is FFI-unsafe due to `CStr` = help: consider passing a `*const std::ffi::c_char` instead, and use `CStr::as_ptr()` = note: `CStr`/`CString` do not have a guaranteed layout = note: `#[warn(improper_ctypes)]` on by default diff --git a/tests/ui/extern/extern-C-str-arg-ice-80125.stderr b/tests/ui/extern/extern-C-str-arg-ice-80125.stderr index f2ee21c3166..ebd6cec6ecd 100644 --- a/tests/ui/extern/extern-C-str-arg-ice-80125.stderr +++ b/tests/ui/extern/extern-C-str-arg-ice-80125.stderr @@ -4,7 +4,6 @@ warning: `extern` fn uses type `str`, which is not FFI-safe LL | type ExternCallback = extern "C" fn(*const u8, u32, str); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe | - = note: the function pointer to `extern "C" fn(*const u8, u32, str)` is FFI-unsafe due to `str` = help: consider using `*const u8` and a length instead = note: string slices have no C equivalent = note: `#[warn(improper_ctypes_definitions)]` on by default @@ -15,7 +14,6 @@ warning: `extern` fn uses type `str`, which is not FFI-safe LL | pub extern "C" fn register_something(bind: ExternCallback) -> Struct { | ^^^^^^^^^^^^^^ not FFI-safe | - = note: the function pointer to `extern "C" fn(*const u8, u32, str)` is FFI-unsafe due to `str` = help: consider using `*const u8` and a length instead = note: string slices have no C equivalent diff --git a/tests/ui/feature-gates/feature-gate-default-field-values.rs b/tests/ui/feature-gates/feature-gate-default-field-values.rs new file mode 100644 index 00000000000..d2e41a71602 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-default-field-values.rs @@ -0,0 +1,106 @@ +#![feature(generic_const_exprs)] +#![allow(unused_variables, dead_code, incomplete_features)] + +pub struct S; + +#[derive(Default)] +pub struct Foo { + pub bar: S = S, //~ ERROR default values on fields are experimental + pub baz: i32 = 42 + 3, //~ ERROR default values on fields are experimental +} + +#[derive(Default)] +pub enum Bar { + #[default] + Foo { //~ ERROR the `#[default]` attribute may only be used on unit enum variants + bar: S = S, //~ ERROR default values on fields are experimental + baz: i32 = 42 + 3, //~ ERROR default values on fields are experimental + } +} + +#[derive(Default)] +pub struct Qux<A, const C: i32> { + bar: S = Qux::<A, C>::S, //~ ERROR default values on fields are experimental + baz: i32 = foo(), //~ ERROR default values on fields are experimental + bat: i32 = <Qux<A, C> as T>::K, //~ ERROR default values on fields are experimental + bay: i32 = C, //~ ERROR default values on fields are experimental + bak: Vec<A> = Vec::new(), //~ ERROR default values on fields are experimental +} + +impl<A, const C: i32> Qux<A, C> { + const S: S = S; +} + +trait T { + const K: i32; +} + +impl<A, const C: i32> T for Qux<A, C> { + const K: i32 = 2; +} + +const fn foo() -> i32 { + 42 +} + +#[derive(Default)] +pub struct Opt { + mandatory: Option<()>, + optional: () = (), //~ ERROR default values on fields are experimental +} + +#[derive(Default)] +pub enum OptEnum { + #[default] + Variant { //~ ERROR the `#[default]` attribute may only be used on unit enum variants + mandatory: Option<()>, + optional: () = (), //~ ERROR default values on fields are experimental + } +} + +fn main () { + let x = Foo { .. }; //~ ERROR base expression required after `..` + let y = Foo::default(); + let z = Foo { baz: 1, .. }; //~ ERROR base expression required after `..` + + assert_eq!(45, x.baz); + assert_eq!(45, y.baz); + assert_eq!(1, z.baz); + + let x = Bar::Foo { .. }; //~ ERROR base expression required after `..` + let y = Bar::default(); + let z = Bar::Foo { baz: 1, .. }; //~ ERROR base expression required after `..` + + assert!(matches!(Bar::Foo { bar: S, baz: 45 }, x)); + assert!(matches!(Bar::Foo { bar: S, baz: 45 }, y)); + assert!(matches!(Bar::Foo { bar: S, baz: 1 }, z)); + + let x = Qux::<i32, 4> { .. }; //~ ERROR base expression required after `..` + assert!(matches!(Qux::<i32, 4> { bar: S, baz: 42, bat: 2, bay: 4, .. }, x)); + //~^ ERROR base expression required after `..` + assert!(x.bak.is_empty()); + let y = Opt { mandatory: None, .. }; + //~^ ERROR base expression required after `..` + assert!(matches!(Opt::default(), y)); + let z = Opt::default(); + assert!(matches!(Opt { mandatory: None, .. }, z)); + //~^ ERROR base expression required after `..` + assert!(matches!(Opt { .. }, z)); + //~^ ERROR base expression required after `..` + assert!(matches!(Opt { optional: (), .. }, z)); + //~^ ERROR base expression required after `..` + assert!(matches!(Opt { optional: (), mandatory: None, .. }, z)); + //~^ ERROR base expression required after `..` + let y = OptEnum::Variant { mandatory: None, .. }; + //~^ ERROR base expression required after `..` + assert!(matches!(OptEnum::default(), y)); + let z = OptEnum::default(); + assert!(matches!(OptEnum::Variant { mandatory: None, .. }, z)); + //~^ ERROR base expression required after `..` + assert!(matches!(OptEnum::Variant { .. }, z)); + //~^ ERROR base expression required after `..` + assert!(matches!(OptEnum::Variant { optional: (), .. }, z)); + //~^ ERROR base expression required after `..` + assert!(matches!(OptEnum::Variant { optional: (), mandatory: None, .. }, z)); + //~^ ERROR base expression required after `..` +} diff --git a/tests/ui/feature-gates/feature-gate-default-field-values.stderr b/tests/ui/feature-gates/feature-gate-default-field-values.stderr new file mode 100644 index 00000000000..d882c322c8e --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-default-field-values.stderr @@ -0,0 +1,318 @@ +error: the `#[default]` attribute may only be used on unit enum variants + --> $DIR/feature-gate-default-field-values.rs:15:5 + | +LL | Foo { + | ^^^ + | + = help: consider a manual implementation of `Default` + +error: the `#[default]` attribute may only be used on unit enum variants + --> $DIR/feature-gate-default-field-values.rs:55:5 + | +LL | Variant { + | ^^^^^^^ + | + = help: consider a manual implementation of `Default` + +error[E0658]: default values on fields are experimental + --> $DIR/feature-gate-default-field-values.rs:8:15 + | +LL | pub bar: S = S, + | ^^^^ + | + = note: see issue #132162 <https://github.com/rust-lang/rust/issues/132162> for more information + = help: add `#![feature(default_field_values)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: default values on fields are experimental + --> $DIR/feature-gate-default-field-values.rs:9:17 + | +LL | pub baz: i32 = 42 + 3, + | ^^^^^^^^^ + | + = note: see issue #132162 <https://github.com/rust-lang/rust/issues/132162> for more information + = help: add `#![feature(default_field_values)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: default values on fields are experimental + --> $DIR/feature-gate-default-field-values.rs:16:15 + | +LL | bar: S = S, + | ^^^^ + | + = note: see issue #132162 <https://github.com/rust-lang/rust/issues/132162> for more information + = help: add `#![feature(default_field_values)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: default values on fields are experimental + --> $DIR/feature-gate-default-field-values.rs:17:17 + | +LL | baz: i32 = 42 + 3, + | ^^^^^^^^^ + | + = note: see issue #132162 <https://github.com/rust-lang/rust/issues/132162> for more information + = help: add `#![feature(default_field_values)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: default values on fields are experimental + --> $DIR/feature-gate-default-field-values.rs:23:11 + | +LL | bar: S = Qux::<A, C>::S, + | ^^^^^^^^^^^^^^^^^ + | + = note: see issue #132162 <https://github.com/rust-lang/rust/issues/132162> for more information + = help: add `#![feature(default_field_values)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: default values on fields are experimental + --> $DIR/feature-gate-default-field-values.rs:24:13 + | +LL | baz: i32 = foo(), + | ^^^^^^^^ + | + = note: see issue #132162 <https://github.com/rust-lang/rust/issues/132162> for more information + = help: add `#![feature(default_field_values)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: default values on fields are experimental + --> $DIR/feature-gate-default-field-values.rs:25:13 + | +LL | bat: i32 = <Qux<A, C> as T>::K, + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #132162 <https://github.com/rust-lang/rust/issues/132162> for more information + = help: add `#![feature(default_field_values)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: default values on fields are experimental + --> $DIR/feature-gate-default-field-values.rs:26:13 + | +LL | bay: i32 = C, + | ^^^^ + | + = note: see issue #132162 <https://github.com/rust-lang/rust/issues/132162> for more information + = help: add `#![feature(default_field_values)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: default values on fields are experimental + --> $DIR/feature-gate-default-field-values.rs:27:16 + | +LL | bak: Vec<A> = Vec::new(), + | ^^^^^^^^^^^^^ + | + = note: see issue #132162 <https://github.com/rust-lang/rust/issues/132162> for more information + = help: add `#![feature(default_field_values)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: default values on fields are experimental + --> $DIR/feature-gate-default-field-values.rs:49:17 + | +LL | optional: () = (), + | ^^^^^ + | + = note: see issue #132162 <https://github.com/rust-lang/rust/issues/132162> for more information + = help: add `#![feature(default_field_values)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: default values on fields are experimental + --> $DIR/feature-gate-default-field-values.rs:57:21 + | +LL | optional: () = (), + | ^^^^^ + | + = note: see issue #132162 <https://github.com/rust-lang/rust/issues/132162> for more information + = help: add `#![feature(default_field_values)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0797]: base expression required after `..` + --> $DIR/feature-gate-default-field-values.rs:62:21 + | +LL | let x = Foo { .. }; + | ^ + | + = help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields +help: add a base expression here + | +LL | let x = Foo { ../* expr */ }; + | ++++++++++ + +error[E0797]: base expression required after `..` + --> $DIR/feature-gate-default-field-values.rs:64:29 + | +LL | let z = Foo { baz: 1, .. }; + | ^ + | + = help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields +help: add a base expression here + | +LL | let z = Foo { baz: 1, ../* expr */ }; + | ++++++++++ + +error[E0797]: base expression required after `..` + --> $DIR/feature-gate-default-field-values.rs:70:26 + | +LL | let x = Bar::Foo { .. }; + | ^ + | + = help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields +help: add a base expression here + | +LL | let x = Bar::Foo { ../* expr */ }; + | ++++++++++ + +error[E0797]: base expression required after `..` + --> $DIR/feature-gate-default-field-values.rs:72:34 + | +LL | let z = Bar::Foo { baz: 1, .. }; + | ^ + | + = help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields +help: add a base expression here + | +LL | let z = Bar::Foo { baz: 1, ../* expr */ }; + | ++++++++++ + +error[E0797]: base expression required after `..` + --> $DIR/feature-gate-default-field-values.rs:78:31 + | +LL | let x = Qux::<i32, 4> { .. }; + | ^ + | + = help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields +help: add a base expression here + | +LL | let x = Qux::<i32, 4> { ../* expr */ }; + | ++++++++++ + +error[E0797]: base expression required after `..` + --> $DIR/feature-gate-default-field-values.rs:79:73 + | +LL | assert!(matches!(Qux::<i32, 4> { bar: S, baz: 42, bat: 2, bay: 4, .. }, x)); + | ^ + | + = help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields +help: add a base expression here + | +LL | assert!(matches!(Qux::<i32, 4> { bar: S, baz: 42, bat: 2, bay: 4, ../* expr */ }, x)); + | ++++++++++ + +error[E0797]: base expression required after `..` + --> $DIR/feature-gate-default-field-values.rs:82:38 + | +LL | let y = Opt { mandatory: None, .. }; + | ^ + | + = help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields +help: add a base expression here + | +LL | let y = Opt { mandatory: None, ../* expr */ }; + | ++++++++++ + +error[E0797]: base expression required after `..` + --> $DIR/feature-gate-default-field-values.rs:86:47 + | +LL | assert!(matches!(Opt { mandatory: None, .. }, z)); + | ^ + | + = help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields +help: add a base expression here + | +LL | assert!(matches!(Opt { mandatory: None, ../* expr */ }, z)); + | ++++++++++ + +error[E0797]: base expression required after `..` + --> $DIR/feature-gate-default-field-values.rs:88:30 + | +LL | assert!(matches!(Opt { .. }, z)); + | ^ + | +help: add a base expression here + | +LL | assert!(matches!(Opt { ../* expr */ }, z)); + | ++++++++++ + +error[E0797]: base expression required after `..` + --> $DIR/feature-gate-default-field-values.rs:90:44 + | +LL | assert!(matches!(Opt { optional: (), .. }, z)); + | ^ + | +help: add a base expression here + | +LL | assert!(matches!(Opt { optional: (), ../* expr */ }, z)); + | ++++++++++ + +error[E0797]: base expression required after `..` + --> $DIR/feature-gate-default-field-values.rs:92:61 + | +LL | assert!(matches!(Opt { optional: (), mandatory: None, .. }, z)); + | ^ + | +help: remove the `..` as all the fields are already present + | +LL - assert!(matches!(Opt { optional: (), mandatory: None, .. }, z)); +LL + assert!(matches!(Opt { optional: (), mandatory: None, }, z)); + | + +error[E0797]: base expression required after `..` + --> $DIR/feature-gate-default-field-values.rs:94:51 + | +LL | let y = OptEnum::Variant { mandatory: None, .. }; + | ^ + | + = help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields +help: add a base expression here + | +LL | let y = OptEnum::Variant { mandatory: None, ../* expr */ }; + | ++++++++++ + +error[E0797]: base expression required after `..` + --> $DIR/feature-gate-default-field-values.rs:98:60 + | +LL | assert!(matches!(OptEnum::Variant { mandatory: None, .. }, z)); + | ^ + | + = help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields +help: add a base expression here + | +LL | assert!(matches!(OptEnum::Variant { mandatory: None, ../* expr */ }, z)); + | ++++++++++ + +error[E0797]: base expression required after `..` + --> $DIR/feature-gate-default-field-values.rs:100:43 + | +LL | assert!(matches!(OptEnum::Variant { .. }, z)); + | ^ + | +help: add a base expression here + | +LL | assert!(matches!(OptEnum::Variant { ../* expr */ }, z)); + | ++++++++++ + +error[E0797]: base expression required after `..` + --> $DIR/feature-gate-default-field-values.rs:102:57 + | +LL | assert!(matches!(OptEnum::Variant { optional: (), .. }, z)); + | ^ + | +help: add a base expression here + | +LL | assert!(matches!(OptEnum::Variant { optional: (), ../* expr */ }, z)); + | ++++++++++ + +error[E0797]: base expression required after `..` + --> $DIR/feature-gate-default-field-values.rs:104:74 + | +LL | assert!(matches!(OptEnum::Variant { optional: (), mandatory: None, .. }, z)); + | ^ + | +help: remove the `..` as all the fields are already present + | +LL - assert!(matches!(OptEnum::Variant { optional: (), mandatory: None, .. }, z)); +LL + assert!(matches!(OptEnum::Variant { optional: (), mandatory: None, }, z)); + | + +error: aborting due to 29 previous errors + +Some errors have detailed explanations: E0658, E0797. +For more information about an error, try `rustc --explain E0658`. diff --git a/tests/ui/impl-trait/normalize-tait-in-const.stderr b/tests/ui/impl-trait/normalize-tait-in-const.stderr index 1dd84f10ad8..0f79cefeaec 100644 --- a/tests/ui/impl-trait/normalize-tait-in-const.stderr +++ b/tests/ui/impl-trait/normalize-tait-in-const.stderr @@ -2,14 +2,19 @@ error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/normalize-tait-in-const.rs:26:35 | LL | const fn with_positive<F: for<'a> ~const Fn(&'a Alias<'a>) + ~const Destruct>(fun: F) { - | ^^^^^^ + | ^^^^^^ can't be applied to `Fn` + | +note: `Fn` can't be used with `~const` because it isn't annotated with `#[const_trait]` + --> $SRC_DIR/core/src/ops/function.rs:LL:COL error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/normalize-tait-in-const.rs:26:35 | LL | const fn with_positive<F: for<'a> ~const Fn(&'a Alias<'a>) + ~const Destruct>(fun: F) { - | ^^^^^^ + | ^^^^^^ can't be applied to `Fn` | +note: `Fn` can't be used with `~const` because it isn't annotated with `#[const_trait]` + --> $SRC_DIR/core/src/ops/function.rs:LL:COL = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: the trait bound `for<'a, 'b> fn(&'a foo::Alias<'b>) {foo}: const Destruct` is not satisfied diff --git a/tests/ui/impl-trait/precise-capturing/overcaptures-2024.fixed b/tests/ui/impl-trait/precise-capturing/overcaptures-2024.fixed index 1eb88c71d54..ef8dd055a8a 100644 --- a/tests/ui/impl-trait/precise-capturing/overcaptures-2024.fixed +++ b/tests/ui/impl-trait/precise-capturing/overcaptures-2024.fixed @@ -42,4 +42,8 @@ async fn async_fn<'a>(x: &'a ()) -> impl Sized + use<> {} //~^ ERROR `impl Sized` will capture more lifetimes than possibly intended in edition 2024 //~| WARN this changes meaning in Rust 2024 +pub fn parens(x: &i32) -> &(impl Clone + use<>) { x } +//~^ ERROR `impl Clone` will capture more lifetimes than possibly intended in edition 2024 +//~| WARN this changes meaning in Rust 2024 + fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/overcaptures-2024.rs b/tests/ui/impl-trait/precise-capturing/overcaptures-2024.rs index 6f1ef6a472f..ce1cfe1246f 100644 --- a/tests/ui/impl-trait/precise-capturing/overcaptures-2024.rs +++ b/tests/ui/impl-trait/precise-capturing/overcaptures-2024.rs @@ -42,4 +42,8 @@ async fn async_fn<'a>(x: &'a ()) -> impl Sized {} //~^ ERROR `impl Sized` will capture more lifetimes than possibly intended in edition 2024 //~| WARN this changes meaning in Rust 2024 +pub fn parens(x: &i32) -> &impl Clone { x } +//~^ ERROR `impl Clone` will capture more lifetimes than possibly intended in edition 2024 +//~| WARN this changes meaning in Rust 2024 + fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/overcaptures-2024.stderr b/tests/ui/impl-trait/precise-capturing/overcaptures-2024.stderr index 63c87cd46c8..965f8e7b672 100644 --- a/tests/ui/impl-trait/precise-capturing/overcaptures-2024.stderr +++ b/tests/ui/impl-trait/precise-capturing/overcaptures-2024.stderr @@ -146,5 +146,24 @@ help: use the precise capturing `use<...>` syntax to make the captures explicit LL | async fn async_fn<'a>(x: &'a ()) -> impl Sized + use<> {} | +++++++ -error: aborting due to 7 previous errors +error: `impl Clone` will capture more lifetimes than possibly intended in edition 2024 + --> $DIR/overcaptures-2024.rs:45:28 + | +LL | pub fn parens(x: &i32) -> &impl Clone { x } + | ^^^^^^^^^^ + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/rpit-lifetime-capture.html> +note: specifically, this lifetime is in scope but not mentioned in the type's bounds + --> $DIR/overcaptures-2024.rs:45:18 + | +LL | pub fn parens(x: &i32) -> &impl Clone { x } + | ^ + = note: all lifetimes in scope will be captured by `impl Trait`s in edition 2024 +help: use the precise capturing `use<...>` syntax to make the captures explicit + | +LL | pub fn parens(x: &i32) -> &(impl Clone + use<>) { x } + | + ++++++++ + +error: aborting due to 8 previous errors diff --git a/tests/ui/layout/base-layout-is-sized-ice-123078.stderr b/tests/ui/layout/base-layout-is-sized-ice-123078.stderr index ee7f5162552..455bd2cbf8b 100644 --- a/tests/ui/layout/base-layout-is-sized-ice-123078.stderr +++ b/tests/ui/layout/base-layout-is-sized-ice-123078.stderr @@ -25,12 +25,6 @@ LL | const C: S = unsafe { std::mem::transmute(()) }; = note: source type: `()` (0 bits) = note: target type: `S` (size can vary because of [u8]) -note: erroneous constant encountered - --> $DIR/base-layout-is-sized-ice-123078.rs:13:5 - | -LL | C; - | ^ - error: aborting due to 2 previous errors Some errors have detailed explanations: E0277, E0512. diff --git a/tests/ui/linkage-attr/auxiliary/link-cfg-works-transitive-dylib.rs b/tests/ui/link-native-libs/auxiliary/link-cfg-works-transitive-dylib.rs index 0d927117d81..0d927117d81 100644 --- a/tests/ui/linkage-attr/auxiliary/link-cfg-works-transitive-dylib.rs +++ b/tests/ui/link-native-libs/auxiliary/link-cfg-works-transitive-dylib.rs diff --git a/tests/ui/linkage-attr/auxiliary/link-cfg-works-transitive-rlib.rs b/tests/ui/link-native-libs/auxiliary/link-cfg-works-transitive-rlib.rs index 49a46b202e4..49a46b202e4 100644 --- a/tests/ui/linkage-attr/auxiliary/link-cfg-works-transitive-rlib.rs +++ b/tests/ui/link-native-libs/auxiliary/link-cfg-works-transitive-rlib.rs diff --git a/tests/ui/native-library-link-flags/empty-kind-1.rs b/tests/ui/link-native-libs/empty-kind-1.rs index d9b8d8a7f7d..d9b8d8a7f7d 100644 --- a/tests/ui/native-library-link-flags/empty-kind-1.rs +++ b/tests/ui/link-native-libs/empty-kind-1.rs diff --git a/tests/ui/native-library-link-flags/empty-kind-1.stderr b/tests/ui/link-native-libs/empty-kind-1.stderr index 3e5b0549339..3e5b0549339 100644 --- a/tests/ui/native-library-link-flags/empty-kind-1.stderr +++ b/tests/ui/link-native-libs/empty-kind-1.stderr diff --git a/tests/ui/native-library-link-flags/empty-kind-2.rs b/tests/ui/link-native-libs/empty-kind-2.rs index 16cb3b917e4..16cb3b917e4 100644 --- a/tests/ui/native-library-link-flags/empty-kind-2.rs +++ b/tests/ui/link-native-libs/empty-kind-2.rs diff --git a/tests/ui/native-library-link-flags/empty-kind-2.stderr b/tests/ui/link-native-libs/empty-kind-2.stderr index 3e5b0549339..3e5b0549339 100644 --- a/tests/ui/native-library-link-flags/empty-kind-2.stderr +++ b/tests/ui/link-native-libs/empty-kind-2.stderr diff --git a/tests/ui/linkage-attr/issue-109144.rs b/tests/ui/link-native-libs/issue-109144.rs index 2f740e55389..2f740e55389 100644 --- a/tests/ui/linkage-attr/issue-109144.rs +++ b/tests/ui/link-native-libs/issue-109144.rs diff --git a/tests/ui/linkage-attr/issue-109144.stderr b/tests/ui/link-native-libs/issue-109144.stderr index 0748d94189c..0748d94189c 100644 --- a/tests/ui/linkage-attr/issue-109144.stderr +++ b/tests/ui/link-native-libs/issue-109144.stderr diff --git a/tests/ui/issues/issue-43925.rs b/tests/ui/link-native-libs/issue-43925.rs index 1a210887154..1a210887154 100644 --- a/tests/ui/issues/issue-43925.rs +++ b/tests/ui/link-native-libs/issue-43925.rs diff --git a/tests/ui/issues/issue-43925.stderr b/tests/ui/link-native-libs/issue-43925.stderr index 7cc347c6163..7cc347c6163 100644 --- a/tests/ui/issues/issue-43925.stderr +++ b/tests/ui/link-native-libs/issue-43925.stderr diff --git a/tests/ui/issues/issue-43926.rs b/tests/ui/link-native-libs/issue-43926.rs index 6d3003552dc..6d3003552dc 100644 --- a/tests/ui/issues/issue-43926.rs +++ b/tests/ui/link-native-libs/issue-43926.rs diff --git a/tests/ui/issues/issue-43926.stderr b/tests/ui/link-native-libs/issue-43926.stderr index 7c5c50a38a9..7c5c50a38a9 100644 --- a/tests/ui/issues/issue-43926.stderr +++ b/tests/ui/link-native-libs/issue-43926.stderr diff --git a/tests/ui/issues/issue-70093/issue-70093-link-directives.rs b/tests/ui/link-native-libs/issue-70093/issue-70093-link-directives.rs index 9c60affbccd..9c60affbccd 100644 --- a/tests/ui/issues/issue-70093/issue-70093-link-directives.rs +++ b/tests/ui/link-native-libs/issue-70093/issue-70093-link-directives.rs diff --git a/tests/ui/issues/issue-70093/issue-70093.rs b/tests/ui/link-native-libs/issue-70093/issue-70093.rs index 86974239338..86974239338 100644 --- a/tests/ui/issues/issue-70093/issue-70093.rs +++ b/tests/ui/link-native-libs/issue-70093/issue-70093.rs diff --git a/tests/ui/linkage-attr/kind-framework.rs b/tests/ui/link-native-libs/kind-framework.rs index c2f90809e03..c2f90809e03 100644 --- a/tests/ui/linkage-attr/kind-framework.rs +++ b/tests/ui/link-native-libs/kind-framework.rs diff --git a/tests/ui/linkage-attr/kind-framework.stderr b/tests/ui/link-native-libs/kind-framework.stderr index 93dacd68e29..93dacd68e29 100644 --- a/tests/ui/linkage-attr/kind-framework.stderr +++ b/tests/ui/link-native-libs/kind-framework.stderr diff --git a/tests/ui/native-library-link-flags/link-arg-error.rs b/tests/ui/link-native-libs/link-arg-error.rs index 4defb108178..4defb108178 100644 --- a/tests/ui/native-library-link-flags/link-arg-error.rs +++ b/tests/ui/link-native-libs/link-arg-error.rs diff --git a/tests/ui/native-library-link-flags/link-arg-error.stderr b/tests/ui/link-native-libs/link-arg-error.stderr index e1d01e14152..e1d01e14152 100644 --- a/tests/ui/native-library-link-flags/link-arg-error.stderr +++ b/tests/ui/link-native-libs/link-arg-error.stderr diff --git a/tests/ui/native-library-link-flags/link-arg-from-rs.rs b/tests/ui/link-native-libs/link-arg-from-rs.rs index 4a6017fea33..4a6017fea33 100644 --- a/tests/ui/native-library-link-flags/link-arg-from-rs.rs +++ b/tests/ui/link-native-libs/link-arg-from-rs.rs diff --git a/tests/ui/native-library-link-flags/link-arg-from-rs.stderr b/tests/ui/link-native-libs/link-arg-from-rs.stderr index f31e15f1da6..f31e15f1da6 100644 --- a/tests/ui/native-library-link-flags/link-arg-from-rs.stderr +++ b/tests/ui/link-native-libs/link-arg-from-rs.stderr diff --git a/tests/ui/linkage-attr/link-attr-validation-early.rs b/tests/ui/link-native-libs/link-attr-validation-early.rs index b9a835fb5e9..b9a835fb5e9 100644 --- a/tests/ui/linkage-attr/link-attr-validation-early.rs +++ b/tests/ui/link-native-libs/link-attr-validation-early.rs diff --git a/tests/ui/linkage-attr/link-attr-validation-early.stderr b/tests/ui/link-native-libs/link-attr-validation-early.stderr index 24ad9d825f8..24ad9d825f8 100644 --- a/tests/ui/linkage-attr/link-attr-validation-early.stderr +++ b/tests/ui/link-native-libs/link-attr-validation-early.stderr diff --git a/tests/ui/linkage-attr/link-attr-validation-late.rs b/tests/ui/link-native-libs/link-attr-validation-late.rs index 34f720dd2d3..34f720dd2d3 100644 --- a/tests/ui/linkage-attr/link-attr-validation-late.rs +++ b/tests/ui/link-native-libs/link-attr-validation-late.rs diff --git a/tests/ui/linkage-attr/link-attr-validation-late.stderr b/tests/ui/link-native-libs/link-attr-validation-late.stderr index 1ad5fbaf7de..1ad5fbaf7de 100644 --- a/tests/ui/linkage-attr/link-attr-validation-late.stderr +++ b/tests/ui/link-native-libs/link-attr-validation-late.stderr diff --git a/tests/ui/linkage-attr/link-cfg-works.rs b/tests/ui/link-native-libs/link-cfg-works.rs index 7b936bc43b1..7b936bc43b1 100644 --- a/tests/ui/linkage-attr/link-cfg-works.rs +++ b/tests/ui/link-native-libs/link-cfg-works.rs diff --git a/tests/ui/manual/manual-link-bad-form.rs b/tests/ui/link-native-libs/manual-link-bad-form.rs index 0f5723adec9..0f5723adec9 100644 --- a/tests/ui/manual/manual-link-bad-form.rs +++ b/tests/ui/link-native-libs/manual-link-bad-form.rs diff --git a/tests/ui/manual/manual-link-bad-form.stderr b/tests/ui/link-native-libs/manual-link-bad-form.stderr index 7fd7a1066b4..7fd7a1066b4 100644 --- a/tests/ui/manual/manual-link-bad-form.stderr +++ b/tests/ui/link-native-libs/manual-link-bad-form.stderr diff --git a/tests/ui/manual/manual-link-bad-kind.rs b/tests/ui/link-native-libs/manual-link-bad-kind.rs index d070faa6574..d070faa6574 100644 --- a/tests/ui/manual/manual-link-bad-kind.rs +++ b/tests/ui/link-native-libs/manual-link-bad-kind.rs diff --git a/tests/ui/manual/manual-link-bad-kind.stderr b/tests/ui/link-native-libs/manual-link-bad-kind.stderr index 647c4c61e02..647c4c61e02 100644 --- a/tests/ui/manual/manual-link-bad-kind.stderr +++ b/tests/ui/link-native-libs/manual-link-bad-kind.stderr diff --git a/tests/ui/manual/manual-link-bad-search-path.rs b/tests/ui/link-native-libs/manual-link-bad-search-path.rs index c9ced4734fc..c9ced4734fc 100644 --- a/tests/ui/manual/manual-link-bad-search-path.rs +++ b/tests/ui/link-native-libs/manual-link-bad-search-path.rs diff --git a/tests/ui/manual/manual-link-bad-search-path.stderr b/tests/ui/link-native-libs/manual-link-bad-search-path.stderr index 2c0649ea152..2c0649ea152 100644 --- a/tests/ui/manual/manual-link-bad-search-path.stderr +++ b/tests/ui/link-native-libs/manual-link-bad-search-path.stderr diff --git a/tests/ui/manual/manual-link-framework.rs b/tests/ui/link-native-libs/manual-link-framework.rs index 43cdda0a4e6..43cdda0a4e6 100644 --- a/tests/ui/manual/manual-link-framework.rs +++ b/tests/ui/link-native-libs/manual-link-framework.rs diff --git a/tests/ui/manual/manual-link-framework.stderr b/tests/ui/link-native-libs/manual-link-framework.stderr index 38d2302a48d..38d2302a48d 100644 --- a/tests/ui/manual/manual-link-framework.stderr +++ b/tests/ui/link-native-libs/manual-link-framework.stderr diff --git a/tests/ui/manual/manual-link-unsupported-kind.rs b/tests/ui/link-native-libs/manual-link-unsupported-kind.rs index b5b9e3e6577..b5b9e3e6577 100644 --- a/tests/ui/manual/manual-link-unsupported-kind.rs +++ b/tests/ui/link-native-libs/manual-link-unsupported-kind.rs diff --git a/tests/ui/manual/manual-link-unsupported-kind.stderr b/tests/ui/link-native-libs/manual-link-unsupported-kind.stderr index ae4a1ec9a95..ae4a1ec9a95 100644 --- a/tests/ui/manual/manual-link-unsupported-kind.stderr +++ b/tests/ui/link-native-libs/manual-link-unsupported-kind.stderr diff --git a/tests/ui/native-library-link-flags/modifiers-bad.blank.stderr b/tests/ui/link-native-libs/modifiers-bad.blank.stderr index ea36af0b4cf..ea36af0b4cf 100644 --- a/tests/ui/native-library-link-flags/modifiers-bad.blank.stderr +++ b/tests/ui/link-native-libs/modifiers-bad.blank.stderr diff --git a/tests/ui/native-library-link-flags/modifiers-bad.no-prefix.stderr b/tests/ui/link-native-libs/modifiers-bad.no-prefix.stderr index ea36af0b4cf..ea36af0b4cf 100644 --- a/tests/ui/native-library-link-flags/modifiers-bad.no-prefix.stderr +++ b/tests/ui/link-native-libs/modifiers-bad.no-prefix.stderr diff --git a/tests/ui/native-library-link-flags/modifiers-bad.prefix-only.stderr b/tests/ui/link-native-libs/modifiers-bad.prefix-only.stderr index 1e701374688..1e701374688 100644 --- a/tests/ui/native-library-link-flags/modifiers-bad.prefix-only.stderr +++ b/tests/ui/link-native-libs/modifiers-bad.prefix-only.stderr diff --git a/tests/ui/native-library-link-flags/modifiers-bad.rs b/tests/ui/link-native-libs/modifiers-bad.rs index 185201e0d84..185201e0d84 100644 --- a/tests/ui/native-library-link-flags/modifiers-bad.rs +++ b/tests/ui/link-native-libs/modifiers-bad.rs diff --git a/tests/ui/native-library-link-flags/modifiers-bad.unknown.stderr b/tests/ui/link-native-libs/modifiers-bad.unknown.stderr index 75950ad9c64..75950ad9c64 100644 --- a/tests/ui/native-library-link-flags/modifiers-bad.unknown.stderr +++ b/tests/ui/link-native-libs/modifiers-bad.unknown.stderr diff --git a/tests/ui/native-library-link-flags/modifiers-override-2.rs b/tests/ui/link-native-libs/modifiers-override-2.rs index a462a741ac6..a462a741ac6 100644 --- a/tests/ui/native-library-link-flags/modifiers-override-2.rs +++ b/tests/ui/link-native-libs/modifiers-override-2.rs diff --git a/tests/ui/native-library-link-flags/modifiers-override-2.stderr b/tests/ui/link-native-libs/modifiers-override-2.stderr index aa5b59c5b6f..aa5b59c5b6f 100644 --- a/tests/ui/native-library-link-flags/modifiers-override-2.stderr +++ b/tests/ui/link-native-libs/modifiers-override-2.stderr diff --git a/tests/ui/native-library-link-flags/modifiers-override-3.rs b/tests/ui/link-native-libs/modifiers-override-3.rs index d05735ad616..d05735ad616 100644 --- a/tests/ui/native-library-link-flags/modifiers-override-3.rs +++ b/tests/ui/link-native-libs/modifiers-override-3.rs diff --git a/tests/ui/native-library-link-flags/modifiers-override-3.stderr b/tests/ui/link-native-libs/modifiers-override-3.stderr index 3eb9459f6f3..3eb9459f6f3 100644 --- a/tests/ui/native-library-link-flags/modifiers-override-3.stderr +++ b/tests/ui/link-native-libs/modifiers-override-3.stderr diff --git a/tests/ui/native-library-link-flags/modifiers-override.rs b/tests/ui/link-native-libs/modifiers-override.rs index cd2d003664a..cd2d003664a 100644 --- a/tests/ui/native-library-link-flags/modifiers-override.rs +++ b/tests/ui/link-native-libs/modifiers-override.rs diff --git a/tests/ui/native-library-link-flags/modifiers-override.stderr b/tests/ui/link-native-libs/modifiers-override.stderr index 64427651e9f..64427651e9f 100644 --- a/tests/ui/native-library-link-flags/modifiers-override.stderr +++ b/tests/ui/link-native-libs/modifiers-override.stderr diff --git a/tests/ui/native-library-link-flags/msvc-non-utf8-output.rs b/tests/ui/link-native-libs/msvc-non-utf8-output.rs index 659a832247a..659a832247a 100644 --- a/tests/ui/native-library-link-flags/msvc-non-utf8-output.rs +++ b/tests/ui/link-native-libs/msvc-non-utf8-output.rs diff --git a/tests/ui/native-library-link-flags/msvc-non-utf8-output.stderr b/tests/ui/link-native-libs/msvc-non-utf8-output.stderr index 7f3ef376447..7f3ef376447 100644 --- a/tests/ui/native-library-link-flags/msvc-non-utf8-output.stderr +++ b/tests/ui/link-native-libs/msvc-non-utf8-output.stderr diff --git a/tests/ui/native-library-link-flags/suggest-libname-only-1.rs b/tests/ui/link-native-libs/suggest-libname-only-1.rs index 328181fb5cb..328181fb5cb 100644 --- a/tests/ui/native-library-link-flags/suggest-libname-only-1.rs +++ b/tests/ui/link-native-libs/suggest-libname-only-1.rs diff --git a/tests/ui/native-library-link-flags/suggest-libname-only-1.stderr b/tests/ui/link-native-libs/suggest-libname-only-1.stderr index e142835a9d6..e142835a9d6 100644 --- a/tests/ui/native-library-link-flags/suggest-libname-only-1.stderr +++ b/tests/ui/link-native-libs/suggest-libname-only-1.stderr diff --git a/tests/ui/native-library-link-flags/suggest-libname-only-2.rs b/tests/ui/link-native-libs/suggest-libname-only-2.rs index 7ed106e4ab4..7ed106e4ab4 100644 --- a/tests/ui/native-library-link-flags/suggest-libname-only-2.rs +++ b/tests/ui/link-native-libs/suggest-libname-only-2.rs diff --git a/tests/ui/native-library-link-flags/suggest-libname-only-2.stderr b/tests/ui/link-native-libs/suggest-libname-only-2.stderr index 392d2f01f61..392d2f01f61 100644 --- a/tests/ui/native-library-link-flags/suggest-libname-only-2.stderr +++ b/tests/ui/link-native-libs/suggest-libname-only-2.stderr diff --git a/tests/ui/linkage-attr/uikit-framework.rs b/tests/ui/link-native-libs/uikit-framework.rs index fca0332384a..fca0332384a 100644 --- a/tests/ui/linkage-attr/uikit-framework.rs +++ b/tests/ui/link-native-libs/uikit-framework.rs diff --git a/tests/ui/lint/extern-C-fnptr-lints-slices.rs b/tests/ui/lint/extern-C-fnptr-lints-slices.rs index 4e3832ab1b6..0c35eb37a48 100644 --- a/tests/ui/lint/extern-C-fnptr-lints-slices.rs +++ b/tests/ui/lint/extern-C-fnptr-lints-slices.rs @@ -3,7 +3,7 @@ // It's an improper ctype (a slice) arg in an extern "C" fnptr. pub type F = extern "C" fn(&[u8]); -//~^ ERROR: `extern` fn uses type `&[u8]`, which is not FFI-safe +//~^ ERROR: `extern` fn uses type `[u8]`, which is not FFI-safe fn main() {} diff --git a/tests/ui/lint/extern-C-fnptr-lints-slices.stderr b/tests/ui/lint/extern-C-fnptr-lints-slices.stderr index c0923dd96c8..d13f93ca96f 100644 --- a/tests/ui/lint/extern-C-fnptr-lints-slices.stderr +++ b/tests/ui/lint/extern-C-fnptr-lints-slices.stderr @@ -1,12 +1,11 @@ -error: `extern` fn uses type `&[u8]`, which is not FFI-safe +error: `extern` fn uses type `[u8]`, which is not FFI-safe --> $DIR/extern-C-fnptr-lints-slices.rs:5:14 | LL | pub type F = extern "C" fn(&[u8]); | ^^^^^^^^^^^^^^^^^^^^ not FFI-safe | - = note: the function pointer to `for<'a> extern "C" fn(&'a [u8])` is FFI-unsafe due to `&[u8]` - = help: consider using a raw pointer to the slice's first element (and a length) instead - = note: this reference to an unsized type contains metadata, which makes it incompatible with a C pointer + = help: consider using a raw pointer instead + = note: slices have no C equivalent note: the lint level is defined here --> $DIR/extern-C-fnptr-lints-slices.rs:1:8 | diff --git a/tests/ui/lint/improper_ctypes_definitions_ice_134060.rs b/tests/ui/lint/improper_ctypes_definitions_ice_134060.rs new file mode 100644 index 00000000000..b30be996736 --- /dev/null +++ b/tests/ui/lint/improper_ctypes_definitions_ice_134060.rs @@ -0,0 +1,15 @@ +//! Regression test for <https://github.com/rust-lang/rust/issues/134060> due to impl bug from +//! <https://github.com/rust-lang/rust/pull/131669>. This test should be adjusted in favor of more +//! comprehensive coverage when the changes are to be relanded, as this is a basic sanity check to +//! check that the fuzzed example from #134060 doesn't ICE. + +//@ check-pass + +#![crate_type = "lib"] + +pub trait Foo { + extern "C" fn foo_(&self, _: ()) -> i64 { + //~^ WARN `extern` fn uses type `()`, which is not FFI-safe + 0 + } +} diff --git a/tests/ui/lint/improper_ctypes_definitions_ice_134060.stderr b/tests/ui/lint/improper_ctypes_definitions_ice_134060.stderr new file mode 100644 index 00000000000..f6ac9a92cd5 --- /dev/null +++ b/tests/ui/lint/improper_ctypes_definitions_ice_134060.stderr @@ -0,0 +1,12 @@ +warning: `extern` fn uses type `()`, which is not FFI-safe + --> $DIR/improper_ctypes_definitions_ice_134060.rs:11:34 + | +LL | extern "C" fn foo_(&self, _: ()) -> i64 { + | ^^ not FFI-safe + | + = help: consider using a struct instead + = note: tuples have unspecified layout + = note: `#[warn(improper_ctypes_definitions)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/lint/lint-ctypes-73249-2.stderr b/tests/ui/lint/lint-ctypes-73249-2.stderr index f035cdb213e..ef30a406969 100644 --- a/tests/ui/lint/lint-ctypes-73249-2.stderr +++ b/tests/ui/lint/lint-ctypes-73249-2.stderr @@ -4,7 +4,6 @@ error: `extern` block uses type `Qux`, which is not FFI-safe LL | fn lint_me() -> A<()>; | ^^^^^ not FFI-safe | - = note: this reference (`&Qux`) is ABI-compatible with a C pointer, but `Qux` itself does not have a C layout = note: opaque types have no C equivalent note: the lint level is defined here --> $DIR/lint-ctypes-73249-2.rs:2:9 diff --git a/tests/ui/lint/lint-ctypes-94223.stderr b/tests/ui/lint/lint-ctypes-94223.stderr index 4bebca69b7f..bd127cf6004 100644 --- a/tests/ui/lint/lint-ctypes-94223.stderr +++ b/tests/ui/lint/lint-ctypes-94223.stderr @@ -4,8 +4,7 @@ error: `extern` fn uses type `[u8]`, which is not FFI-safe LL | pub fn bad(f: extern "C" fn([u8])) {} | ^^^^^^^^^^^^^^^^^^^ not FFI-safe | - = note: the function pointer to `extern "C" fn([u8])` is FFI-unsafe due to `[u8]` - = help: consider using a raw pointer to the slice's first element (and a length) instead + = help: consider using a raw pointer instead = note: slices have no C equivalent note: the lint level is defined here --> $DIR/lint-ctypes-94223.rs:2:9 @@ -19,8 +18,7 @@ error: `extern` fn uses type `[u8]`, which is not FFI-safe LL | pub fn bad_twice(f: Result<extern "C" fn([u8]), extern "C" fn([u8])>) {} | ^^^^^^^^^^^^^^^^^^^ not FFI-safe | - = note: the function pointer to `extern "C" fn([u8])` is FFI-unsafe due to `[u8]` - = help: consider using a raw pointer to the slice's first element (and a length) instead + = help: consider using a raw pointer instead = note: slices have no C equivalent error: `extern` fn uses type `[u8]`, which is not FFI-safe @@ -29,8 +27,7 @@ error: `extern` fn uses type `[u8]`, which is not FFI-safe LL | pub fn bad_twice(f: Result<extern "C" fn([u8]), extern "C" fn([u8])>) {} | ^^^^^^^^^^^^^^^^^^^ not FFI-safe | - = note: the function pointer to `extern "C" fn([u8])` is FFI-unsafe due to `[u8]` - = help: consider using a raw pointer to the slice's first element (and a length) instead + = help: consider using a raw pointer instead = note: slices have no C equivalent error: `extern` fn uses type `[u8]`, which is not FFI-safe @@ -39,8 +36,7 @@ error: `extern` fn uses type `[u8]`, which is not FFI-safe LL | struct BadStruct(extern "C" fn([u8])); | ^^^^^^^^^^^^^^^^^^^ not FFI-safe | - = note: the function pointer to `extern "C" fn([u8])` is FFI-unsafe due to `[u8]` - = help: consider using a raw pointer to the slice's first element (and a length) instead + = help: consider using a raw pointer instead = note: slices have no C equivalent error: `extern` fn uses type `[u8]`, which is not FFI-safe @@ -49,8 +45,7 @@ error: `extern` fn uses type `[u8]`, which is not FFI-safe LL | A(extern "C" fn([u8])), | ^^^^^^^^^^^^^^^^^^^ not FFI-safe | - = note: the function pointer to `extern "C" fn([u8])` is FFI-unsafe due to `[u8]` - = help: consider using a raw pointer to the slice's first element (and a length) instead + = help: consider using a raw pointer instead = note: slices have no C equivalent error: `extern` fn uses type `[u8]`, which is not FFI-safe @@ -59,8 +54,7 @@ error: `extern` fn uses type `[u8]`, which is not FFI-safe LL | A(extern "C" fn([u8])), | ^^^^^^^^^^^^^^^^^^^ not FFI-safe | - = note: the function pointer to `extern "C" fn([u8])` is FFI-unsafe due to `[u8]` - = help: consider using a raw pointer to the slice's first element (and a length) instead + = help: consider using a raw pointer instead = note: slices have no C equivalent error: `extern` fn uses type `[u8]`, which is not FFI-safe @@ -69,8 +63,7 @@ error: `extern` fn uses type `[u8]`, which is not FFI-safe LL | type Foo = extern "C" fn([u8]); | ^^^^^^^^^^^^^^^^^^^ not FFI-safe | - = note: the function pointer to `extern "C" fn([u8])` is FFI-unsafe due to `[u8]` - = help: consider using a raw pointer to the slice's first element (and a length) instead + = help: consider using a raw pointer instead = note: slices have no C equivalent error: `extern` fn uses type `Option<&<T as FooTrait>::FooType>`, which is not FFI-safe @@ -79,7 +72,6 @@ error: `extern` fn uses type `Option<&<T as FooTrait>::FooType>`, which is not F LL | pub type Foo2<T> = extern "C" fn(Option<&<T as FooTrait>::FooType>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe | - = note: the function pointer to `for<'a> extern "C" fn(Option<&'a <T as FooTrait>::FooType>)` is FFI-unsafe due to `Option<&<T as FooTrait>::FooType>` = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum = note: enum has no representation hint @@ -89,7 +81,6 @@ error: `extern` fn uses type `FfiUnsafe`, which is not FFI-safe LL | pub static BAD: extern "C" fn(FfiUnsafe) = f; | ^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe | - = note: the function pointer to `extern "C" fn(FfiUnsafe)` is FFI-unsafe due to `FfiUnsafe` = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct = note: this struct has unspecified layout note: the type is defined here @@ -104,7 +95,6 @@ error: `extern` fn uses type `FfiUnsafe`, which is not FFI-safe LL | pub static BAD_TWICE: Result<extern "C" fn(FfiUnsafe), extern "C" fn(FfiUnsafe)> = Ok(f); | ^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe | - = note: the function pointer to `extern "C" fn(FfiUnsafe)` is FFI-unsafe due to `FfiUnsafe` = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct = note: this struct has unspecified layout note: the type is defined here @@ -119,7 +109,6 @@ error: `extern` fn uses type `FfiUnsafe`, which is not FFI-safe LL | pub static BAD_TWICE: Result<extern "C" fn(FfiUnsafe), extern "C" fn(FfiUnsafe)> = Ok(f); | ^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe | - = note: the function pointer to `extern "C" fn(FfiUnsafe)` is FFI-unsafe due to `FfiUnsafe` = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct = note: this struct has unspecified layout note: the type is defined here @@ -134,7 +123,6 @@ error: `extern` fn uses type `FfiUnsafe`, which is not FFI-safe LL | pub const BAD_CONST: extern "C" fn(FfiUnsafe) = f; | ^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe | - = note: the function pointer to `extern "C" fn(FfiUnsafe)` is FFI-unsafe due to `FfiUnsafe` = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct = note: this struct has unspecified layout note: the type is defined here diff --git a/tests/ui/lint/lint-ctypes-cstr.rs b/tests/ui/lint/lint-ctypes-cstr.rs index c4de5a44a96..b04decd0bca 100644 --- a/tests/ui/lint/lint-ctypes-cstr.rs +++ b/tests/ui/lint/lint-ctypes-cstr.rs @@ -8,7 +8,7 @@ extern "C" { //~^ ERROR `extern` block uses type `CStr`, which is not FFI-safe //~| HELP consider passing a `*const std::ffi::c_char` instead, and use `CStr::as_ptr()` fn take_cstr_ref(s: &CStr); - //~^ ERROR `extern` block uses type `&CStr`, which is not FFI-safe + //~^ ERROR `extern` block uses type `CStr`, which is not FFI-safe //~| HELP consider passing a `*const std::ffi::c_char` instead, and use `CStr::as_ptr()` fn take_cstring(s: CString); //~^ ERROR `extern` block uses type `CString`, which is not FFI-safe @@ -27,7 +27,7 @@ extern "C" { } extern "C" fn rust_take_cstr_ref(s: &CStr) {} -//~^ ERROR `extern` fn uses type `&CStr`, which is not FFI-safe +//~^ ERROR `extern` fn uses type `CStr`, which is not FFI-safe //~| HELP consider passing a `*const std::ffi::c_char` instead, and use `CStr::as_ptr()` extern "C" fn rust_take_cstring(s: CString) {} //~^ ERROR `extern` fn uses type `CString`, which is not FFI-safe diff --git a/tests/ui/lint/lint-ctypes-cstr.stderr b/tests/ui/lint/lint-ctypes-cstr.stderr index da15b748f21..8957758d577 100644 --- a/tests/ui/lint/lint-ctypes-cstr.stderr +++ b/tests/ui/lint/lint-ctypes-cstr.stderr @@ -12,14 +12,14 @@ note: the lint level is defined here LL | #![deny(improper_ctypes, improper_ctypes_definitions)] | ^^^^^^^^^^^^^^^ -error: `extern` block uses type `&CStr`, which is not FFI-safe +error: `extern` block uses type `CStr`, which is not FFI-safe --> $DIR/lint-ctypes-cstr.rs:10:25 | LL | fn take_cstr_ref(s: &CStr); | ^^^^^ not FFI-safe | = help: consider passing a `*const std::ffi::c_char` instead, and use `CStr::as_ptr()` - = note: this reference to an unsized type contains metadata, which makes it incompatible with a C pointer + = note: `CStr`/`CString` do not have a guaranteed layout error: `extern` block uses type `CString`, which is not FFI-safe --> $DIR/lint-ctypes-cstr.rs:13:24 @@ -36,7 +36,6 @@ error: `extern` block uses type `CString`, which is not FFI-safe LL | fn take_cstring_ref(s: &CString); | ^^^^^^^^ not FFI-safe | - = note: this reference (`&CString`) is ABI-compatible with a C pointer, but `CString` itself does not have a C layout = help: consider passing a `*const std::ffi::c_char` instead, and use `CStr::as_ptr()` = note: `CStr`/`CString` do not have a guaranteed layout @@ -46,7 +45,6 @@ error: `extern` block uses type `CString`, which is not FFI-safe LL | fn no_special_help_for_mut_cstring(s: *mut CString); | ^^^^^^^^^^^^ not FFI-safe | - = note: this reference (`*mut CString`) is ABI-compatible with a C pointer, but `CString` itself does not have a C layout = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct = note: this struct has unspecified layout @@ -56,18 +54,17 @@ error: `extern` block uses type `CString`, which is not FFI-safe LL | fn no_special_help_for_mut_cstring_ref(s: &mut CString); | ^^^^^^^^^^^^ not FFI-safe | - = note: this reference (`&mut CString`) is ABI-compatible with a C pointer, but `CString` itself does not have a C layout = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct = note: this struct has unspecified layout -error: `extern` fn uses type `&CStr`, which is not FFI-safe +error: `extern` fn uses type `CStr`, which is not FFI-safe --> $DIR/lint-ctypes-cstr.rs:29:37 | LL | extern "C" fn rust_take_cstr_ref(s: &CStr) {} | ^^^^^ not FFI-safe | = help: consider passing a `*const std::ffi::c_char` instead, and use `CStr::as_ptr()` - = note: this reference to an unsized type contains metadata, which makes it incompatible with a C pointer + = note: `CStr`/`CString` do not have a guaranteed layout note: the lint level is defined here --> $DIR/lint-ctypes-cstr.rs:2:26 | diff --git a/tests/ui/lint/lint-ctypes-fn.rs b/tests/ui/lint/lint-ctypes-fn.rs index e16ff9573fd..73820c86d1a 100644 --- a/tests/ui/lint/lint-ctypes-fn.rs +++ b/tests/ui/lint/lint-ctypes-fn.rs @@ -68,10 +68,10 @@ pub extern "C" fn ptr_unit(p: *const ()) { } pub extern "C" fn ptr_tuple(p: *const ((),)) { } pub extern "C" fn slice_type(p: &[u32]) { } -//~^ ERROR: uses type `&[u32]` +//~^ ERROR: uses type `[u32]` pub extern "C" fn str_type(p: &str) { } -//~^ ERROR: uses type `&str` +//~^ ERROR: uses type `str` pub extern "C" fn box_type(p: Box<u32>) { } @@ -124,7 +124,7 @@ pub extern "C" fn transparent_i128(p: TransparentI128) { } //~^ ERROR: uses type `i128` pub extern "C" fn transparent_str(p: TransparentStr) { } -//~^ ERROR: uses type `&str` +//~^ ERROR: uses type `str` pub extern "C" fn transparent_fn(p: TransparentBadFn) { } diff --git a/tests/ui/lint/lint-ctypes-fn.stderr b/tests/ui/lint/lint-ctypes-fn.stderr index c86c02c8006..a62533a4be1 100644 --- a/tests/ui/lint/lint-ctypes-fn.stderr +++ b/tests/ui/lint/lint-ctypes-fn.stderr @@ -1,25 +1,25 @@ -error: `extern` fn uses type `&[u32]`, which is not FFI-safe +error: `extern` fn uses type `[u32]`, which is not FFI-safe --> $DIR/lint-ctypes-fn.rs:70:33 | LL | pub extern "C" fn slice_type(p: &[u32]) { } | ^^^^^^ not FFI-safe | - = help: consider using a raw pointer to the slice's first element (and a length) instead - = note: this reference to an unsized type contains metadata, which makes it incompatible with a C pointer + = help: consider using a raw pointer instead + = note: slices have no C equivalent note: the lint level is defined here --> $DIR/lint-ctypes-fn.rs:2:9 | LL | #![deny(improper_ctypes_definitions)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: `extern` fn uses type `&str`, which is not FFI-safe +error: `extern` fn uses type `str`, which is not FFI-safe --> $DIR/lint-ctypes-fn.rs:73:31 | LL | pub extern "C" fn str_type(p: &str) { } | ^^^^ not FFI-safe | = help: consider using `*const u8` and a length instead - = note: this reference to an unsized type contains metadata, which makes it incompatible with a C pointer + = note: string slices have no C equivalent error: `extern` fn uses type `Box<[u8]>`, which is not FFI-safe --> $DIR/lint-ctypes-fn.rs:80:34 @@ -27,8 +27,7 @@ error: `extern` fn uses type `Box<[u8]>`, which is not FFI-safe LL | pub extern "C" fn boxed_slice(p: Box<[u8]>) { } | ^^^^^^^^^ not FFI-safe | - = help: consider using a raw pointer to the slice's first element (and a length) instead - = note: this box for an unsized type contains metadata, which makes it incompatible with a C pointer + = note: box cannot be represented as a single pointer error: `extern` fn uses type `Box<str>`, which is not FFI-safe --> $DIR/lint-ctypes-fn.rs:83:35 @@ -36,8 +35,7 @@ error: `extern` fn uses type `Box<str>`, which is not FFI-safe LL | pub extern "C" fn boxed_string(p: Box<str>) { } | ^^^^^^^^ not FFI-safe | - = help: consider using `*const u8` and a length instead - = note: this box for an unsized type contains metadata, which makes it incompatible with a C pointer + = note: box cannot be represented as a single pointer error: `extern` fn uses type `Box<dyn Trait>`, which is not FFI-safe --> $DIR/lint-ctypes-fn.rs:86:34 @@ -45,7 +43,7 @@ error: `extern` fn uses type `Box<dyn Trait>`, which is not FFI-safe LL | pub extern "C" fn boxed_trait(p: Box<dyn Trait>) { } | ^^^^^^^^^^^^^^ not FFI-safe | - = note: this box for an unsized type contains metadata, which makes it incompatible with a C pointer + = note: box cannot be represented as a single pointer error: `extern` fn uses type `char`, which is not FFI-safe --> $DIR/lint-ctypes-fn.rs:89:32 @@ -151,14 +149,14 @@ LL | pub extern "C" fn transparent_i128(p: TransparentI128) { } | = note: 128-bit integers don't currently have a known stable ABI -error: `extern` fn uses type `&str`, which is not FFI-safe +error: `extern` fn uses type `str`, which is not FFI-safe --> $DIR/lint-ctypes-fn.rs:126:38 | LL | pub extern "C" fn transparent_str(p: TransparentStr) { } | ^^^^^^^^^^^^^^ not FFI-safe | = help: consider using `*const u8` and a length instead - = note: this reference to an unsized type contains metadata, which makes it incompatible with a C pointer + = note: string slices have no C equivalent error: `extern` fn uses type `PhantomData<bool>`, which is not FFI-safe --> $DIR/lint-ctypes-fn.rs:172:43 diff --git a/tests/ui/lint/lint-ctypes.rs b/tests/ui/lint/lint-ctypes.rs index 8c516ab8428..dae07930aba 100644 --- a/tests/ui/lint/lint-ctypes.rs +++ b/tests/ui/lint/lint-ctypes.rs @@ -1,5 +1,4 @@ #![feature(rustc_private)] -#![feature(extern_types)] #![allow(private_interfaces)] #![deny(improper_ctypes)] @@ -7,9 +6,7 @@ use std::cell::UnsafeCell; use std::marker::PhantomData; use std::ffi::{c_int, c_uint}; -use std::fmt::Debug; -unsafe extern "C" {type UnsizedOpaque;} trait Bar { } trait Mirror { type It: ?Sized; } impl<T: ?Sized> Mirror for T { type It = Self; } @@ -23,7 +20,7 @@ pub type I32Pair = (i32, i32); #[repr(C)] pub struct ZeroSize; pub type RustFn = fn(); -pub type RustBoxRet = extern "C" fn() -> Box<u32>; +pub type RustBadRet = extern "C" fn() -> Box<u32>; pub type CVoidRet = (); pub struct Foo; #[repr(transparent)] @@ -31,7 +28,7 @@ pub struct TransparentI128(i128); #[repr(transparent)] pub struct TransparentStr(&'static str); #[repr(transparent)] -pub struct TransparentBoxFn(RustBoxRet); +pub struct TransparentBadFn(RustBadRet); #[repr(transparent)] pub struct TransparentInt(u32); #[repr(transparent)] @@ -42,16 +39,6 @@ pub struct TransparentLifetime<'a>(*const u8, PhantomData<&'a ()>); pub struct TransparentUnit<U>(f32, PhantomData<U>); #[repr(transparent)] pub struct TransparentCustomZst(i32, ZeroSize); -#[repr(C)] -pub struct UnsizedStructBecauseForeign { - sized: u32, - unszd: UnsizedOpaque, -} -#[repr(C)] -pub struct UnsizedStructBecauseDyn { - sized: u32, - unszd: dyn Debug, -} #[repr(C)] pub struct ZeroSizeWithPhantomData(::std::marker::PhantomData<i32>); @@ -61,14 +48,15 @@ extern "C" { pub fn ptr_type2(size: *const Foo); //~ ERROR: uses type `Foo` pub fn ptr_unit(p: *const ()); pub fn ptr_tuple(p: *const ((),)); //~ ERROR: uses type `((),)` - pub fn slice_type(p: &[u32]); //~ ERROR: uses type `&[u32]` - pub fn str_type(p: &str); //~ ERROR: uses type `&str` - pub fn box_type(p: Box<u32>); + pub fn slice_type(p: &[u32]); //~ ERROR: uses type `[u32]` + pub fn str_type(p: &str); //~ ERROR: uses type `str` + pub fn box_type(p: Box<u32>); //~ ERROR uses type `Box<u32>` pub fn opt_box_type(p: Option<Box<u32>>); + //~^ ERROR uses type `Option<Box<u32>>` pub fn char_type(p: char); //~ ERROR uses type `char` pub fn i128_type(p: i128); //~ ERROR uses type `i128` pub fn u128_type(p: u128); //~ ERROR uses type `u128` - pub fn trait_type(p: &dyn Bar); //~ ERROR uses type `&dyn Bar` + pub fn trait_type(p: &dyn Bar); //~ ERROR uses type `dyn Bar` pub fn tuple_type(p: (i32, i32)); //~ ERROR uses type `(i32, i32)` pub fn tuple_type2(p: I32Pair); //~ ERROR uses type `(i32, i32)` pub fn zero_size(p: ZeroSize); //~ ERROR uses type `ZeroSize` @@ -78,15 +66,12 @@ extern "C" { -> ::std::marker::PhantomData<bool>; //~ ERROR uses type `PhantomData<bool>` pub fn fn_type(p: RustFn); //~ ERROR uses type `fn()` pub fn fn_type2(p: fn()); //~ ERROR uses type `fn()` - pub fn fn_contained(p: RustBoxRet); + pub fn fn_contained(p: RustBadRet); //~ ERROR: uses type `Box<u32>` pub fn transparent_i128(p: TransparentI128); //~ ERROR: uses type `i128` - pub fn transparent_str(p: TransparentStr); //~ ERROR: uses type `&str` - pub fn transparent_fn(p: TransparentBoxFn); + pub fn transparent_str(p: TransparentStr); //~ ERROR: uses type `str` + pub fn transparent_fn(p: TransparentBadFn); //~ ERROR: uses type `Box<u32>` pub fn raw_array(arr: [u8; 8]); //~ ERROR: uses type `[u8; 8]` - pub fn struct_unsized_ptr_no_metadata(p: &UnsizedStructBecauseForeign); - pub fn struct_unsized_ptr_has_metadata(p: &UnsizedStructBecauseDyn); //~ ERROR uses type `&UnsizedStructBecauseDyn` - pub fn no_niche_a(a: Option<UnsafeCell<extern fn()>>); //~^ ERROR: uses type `Option<UnsafeCell<extern "C" fn()>>` pub fn no_niche_b(b: Option<UnsafeCell<&i32>>); diff --git a/tests/ui/lint/lint-ctypes.stderr b/tests/ui/lint/lint-ctypes.stderr index 8580a10b215..2c81c7b8e4b 100644 --- a/tests/ui/lint/lint-ctypes.stderr +++ b/tests/ui/lint/lint-ctypes.stderr @@ -1,68 +1,83 @@ error: `extern` block uses type `Foo`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:60:28 + --> $DIR/lint-ctypes.rs:47:28 | LL | pub fn ptr_type1(size: *const Foo); | ^^^^^^^^^^ not FFI-safe | - = note: this reference (`*const Foo`) is ABI-compatible with a C pointer, but `Foo` itself does not have a C layout = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct = note: this struct has unspecified layout note: the type is defined here - --> $DIR/lint-ctypes.rs:28:1 + --> $DIR/lint-ctypes.rs:25:1 | LL | pub struct Foo; | ^^^^^^^^^^^^^^ note: the lint level is defined here - --> $DIR/lint-ctypes.rs:5:9 + --> $DIR/lint-ctypes.rs:4:9 | LL | #![deny(improper_ctypes)] | ^^^^^^^^^^^^^^^ error: `extern` block uses type `Foo`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:61:28 + --> $DIR/lint-ctypes.rs:48:28 | LL | pub fn ptr_type2(size: *const Foo); | ^^^^^^^^^^ not FFI-safe | - = note: this reference (`*const Foo`) is ABI-compatible with a C pointer, but `Foo` itself does not have a C layout = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct = note: this struct has unspecified layout note: the type is defined here - --> $DIR/lint-ctypes.rs:28:1 + --> $DIR/lint-ctypes.rs:25:1 | LL | pub struct Foo; | ^^^^^^^^^^^^^^ error: `extern` block uses type `((),)`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:63:25 + --> $DIR/lint-ctypes.rs:50:25 | LL | pub fn ptr_tuple(p: *const ((),)); | ^^^^^^^^^^^^ not FFI-safe | - = note: this reference (`*const ((),)`) is ABI-compatible with a C pointer, but `((),)` itself does not have a C layout = help: consider using a struct instead = note: tuples have unspecified layout -error: `extern` block uses type `&[u32]`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:64:26 +error: `extern` block uses type `[u32]`, which is not FFI-safe + --> $DIR/lint-ctypes.rs:51:26 | LL | pub fn slice_type(p: &[u32]); | ^^^^^^ not FFI-safe | - = help: consider using a raw pointer to the slice's first element (and a length) instead - = note: this reference to an unsized type contains metadata, which makes it incompatible with a C pointer + = help: consider using a raw pointer instead + = note: slices have no C equivalent -error: `extern` block uses type `&str`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:65:24 +error: `extern` block uses type `str`, which is not FFI-safe + --> $DIR/lint-ctypes.rs:52:24 | LL | pub fn str_type(p: &str); | ^^^^ not FFI-safe | = help: consider using `*const u8` and a length instead - = note: this reference to an unsized type contains metadata, which makes it incompatible with a C pointer + = note: string slices have no C equivalent + +error: `extern` block uses type `Box<u32>`, which is not FFI-safe + --> $DIR/lint-ctypes.rs:53:24 + | +LL | pub fn box_type(p: Box<u32>); + | ^^^^^^^^ not FFI-safe + | + = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct + = note: this struct has unspecified layout + +error: `extern` block uses type `Option<Box<u32>>`, which is not FFI-safe + --> $DIR/lint-ctypes.rs:54:28 + | +LL | pub fn opt_box_type(p: Option<Box<u32>>); + | ^^^^^^^^^^^^^^^^ not FFI-safe + | + = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum + = note: enum has no representation hint error: `extern` block uses type `char`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:68:25 + --> $DIR/lint-ctypes.rs:56:25 | LL | pub fn char_type(p: char); | ^^^^ not FFI-safe @@ -71,7 +86,7 @@ LL | pub fn char_type(p: char); = note: the `char` type has no C equivalent error: `extern` block uses type `i128`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:69:25 + --> $DIR/lint-ctypes.rs:57:25 | LL | pub fn i128_type(p: i128); | ^^^^ not FFI-safe @@ -79,23 +94,23 @@ LL | pub fn i128_type(p: i128); = note: 128-bit integers don't currently have a known stable ABI error: `extern` block uses type `u128`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:70:25 + --> $DIR/lint-ctypes.rs:58:25 | LL | pub fn u128_type(p: u128); | ^^^^ not FFI-safe | = note: 128-bit integers don't currently have a known stable ABI -error: `extern` block uses type `&dyn Bar`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:71:26 +error: `extern` block uses type `dyn Bar`, which is not FFI-safe + --> $DIR/lint-ctypes.rs:59:26 | LL | pub fn trait_type(p: &dyn Bar); | ^^^^^^^^ not FFI-safe | - = note: this reference to an unsized type contains metadata, which makes it incompatible with a C pointer + = note: trait objects have no C equivalent error: `extern` block uses type `(i32, i32)`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:72:26 + --> $DIR/lint-ctypes.rs:60:26 | LL | pub fn tuple_type(p: (i32, i32)); | ^^^^^^^^^^ not FFI-safe @@ -104,7 +119,7 @@ LL | pub fn tuple_type(p: (i32, i32)); = note: tuples have unspecified layout error: `extern` block uses type `(i32, i32)`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:73:27 + --> $DIR/lint-ctypes.rs:61:27 | LL | pub fn tuple_type2(p: I32Pair); | ^^^^^^^ not FFI-safe @@ -113,7 +128,7 @@ LL | pub fn tuple_type2(p: I32Pair); = note: tuples have unspecified layout error: `extern` block uses type `ZeroSize`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:74:25 + --> $DIR/lint-ctypes.rs:62:25 | LL | pub fn zero_size(p: ZeroSize); | ^^^^^^^^ not FFI-safe @@ -121,26 +136,26 @@ LL | pub fn zero_size(p: ZeroSize); = help: consider adding a member to this struct = note: this struct has no fields note: the type is defined here - --> $DIR/lint-ctypes.rs:24:1 + --> $DIR/lint-ctypes.rs:21:1 | LL | pub struct ZeroSize; | ^^^^^^^^^^^^^^^^^^^ error: `extern` block uses type `ZeroSizeWithPhantomData`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:75:33 + --> $DIR/lint-ctypes.rs:63:33 | LL | pub fn zero_size_phantom(p: ZeroSizeWithPhantomData); | ^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe | = note: composed only of `PhantomData` note: the type is defined here - --> $DIR/lint-ctypes.rs:57:1 + --> $DIR/lint-ctypes.rs:44:1 | LL | pub struct ZeroSizeWithPhantomData(::std::marker::PhantomData<i32>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `extern` block uses type `PhantomData<bool>`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:78:12 + --> $DIR/lint-ctypes.rs:66:12 | LL | -> ::std::marker::PhantomData<bool>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -148,7 +163,7 @@ LL | -> ::std::marker::PhantomData<bool>; = note: composed only of `PhantomData` error: `extern` block uses type `fn()`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:79:23 + --> $DIR/lint-ctypes.rs:67:23 | LL | pub fn fn_type(p: RustFn); | ^^^^^^ not FFI-safe @@ -157,7 +172,7 @@ LL | pub fn fn_type(p: RustFn); = note: this function pointer has Rust-specific calling convention error: `extern` block uses type `fn()`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:80:24 + --> $DIR/lint-ctypes.rs:68:24 | LL | pub fn fn_type2(p: fn()); | ^^^^ not FFI-safe @@ -165,25 +180,43 @@ LL | pub fn fn_type2(p: fn()); = help: consider using an `extern fn(...) -> ...` function pointer instead = note: this function pointer has Rust-specific calling convention +error: `extern` block uses type `Box<u32>`, which is not FFI-safe + --> $DIR/lint-ctypes.rs:69:28 + | +LL | pub fn fn_contained(p: RustBadRet); + | ^^^^^^^^^^ not FFI-safe + | + = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct + = note: this struct has unspecified layout + error: `extern` block uses type `i128`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:82:32 + --> $DIR/lint-ctypes.rs:70:32 | LL | pub fn transparent_i128(p: TransparentI128); | ^^^^^^^^^^^^^^^ not FFI-safe | = note: 128-bit integers don't currently have a known stable ABI -error: `extern` block uses type `&str`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:83:31 +error: `extern` block uses type `str`, which is not FFI-safe + --> $DIR/lint-ctypes.rs:71:31 | LL | pub fn transparent_str(p: TransparentStr); | ^^^^^^^^^^^^^^ not FFI-safe | = help: consider using `*const u8` and a length instead - = note: this reference to an unsized type contains metadata, which makes it incompatible with a C pointer + = note: string slices have no C equivalent + +error: `extern` block uses type `Box<u32>`, which is not FFI-safe + --> $DIR/lint-ctypes.rs:72:30 + | +LL | pub fn transparent_fn(p: TransparentBadFn); + | ^^^^^^^^^^^^^^^^ not FFI-safe + | + = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct + = note: this struct has unspecified layout error: `extern` block uses type `[u8; 8]`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:85:27 + --> $DIR/lint-ctypes.rs:73:27 | LL | pub fn raw_array(arr: [u8; 8]); | ^^^^^^^ not FFI-safe @@ -191,16 +224,8 @@ LL | pub fn raw_array(arr: [u8; 8]); = help: consider passing a pointer to the array = note: passing raw arrays by value is not FFI-safe -error: `extern` block uses type `&UnsizedStructBecauseDyn`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:88:47 - | -LL | pub fn struct_unsized_ptr_has_metadata(p: &UnsizedStructBecauseDyn); - | ^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe - | - = note: this reference to an unsized type contains metadata, which makes it incompatible with a C pointer - error: `extern` block uses type `Option<UnsafeCell<extern "C" fn()>>`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:90:26 + --> $DIR/lint-ctypes.rs:75:26 | LL | pub fn no_niche_a(a: Option<UnsafeCell<extern fn()>>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -209,7 +234,7 @@ LL | pub fn no_niche_a(a: Option<UnsafeCell<extern fn()>>); = note: enum has no representation hint error: `extern` block uses type `Option<UnsafeCell<&i32>>`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:92:26 + --> $DIR/lint-ctypes.rs:77:26 | LL | pub fn no_niche_b(b: Option<UnsafeCell<&i32>>); | ^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -218,7 +243,7 @@ LL | pub fn no_niche_b(b: Option<UnsafeCell<&i32>>); = note: enum has no representation hint error: `extern` block uses type `u128`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:95:34 + --> $DIR/lint-ctypes.rs:80:34 | LL | pub static static_u128_type: u128; | ^^^^ not FFI-safe @@ -226,12 +251,12 @@ LL | pub static static_u128_type: u128; = note: 128-bit integers don't currently have a known stable ABI error: `extern` block uses type `u128`, which is not FFI-safe - --> $DIR/lint-ctypes.rs:96:40 + --> $DIR/lint-ctypes.rs:81:40 | LL | pub static static_u128_array_type: [u128; 16]; | ^^^^^^^^^^ not FFI-safe | = note: 128-bit integers don't currently have a known stable ABI -error: aborting due to 24 previous errors +error: aborting due to 27 previous errors diff --git a/tests/ui/never_type/never-in-range-pat.rs b/tests/ui/never_type/never-in-range-pat.rs new file mode 100644 index 00000000000..ae2d76c172e --- /dev/null +++ b/tests/ui/never_type/never-in-range-pat.rs @@ -0,0 +1,16 @@ +// Regression test for <https://github.com/rust-lang/rust/issues/133947>. + +// Make sure we don't ICE when there's `!` in a range pattern. +// +// This shouldn't be allowed anyways, but we only deny it during MIR +// building, so make sure we handle it semi-gracefully during typeck. + +#![feature(never_type)] + +fn main() { + let x: !; + match 1 { + 0..x => {} + //~^ ERROR only `char` and numeric types are allowed in range patterns + } +} diff --git a/tests/ui/never_type/never-in-range-pat.stderr b/tests/ui/never_type/never-in-range-pat.stderr new file mode 100644 index 00000000000..c78be5350e0 --- /dev/null +++ b/tests/ui/never_type/never-in-range-pat.stderr @@ -0,0 +1,11 @@ +error[E0029]: only `char` and numeric types are allowed in range patterns + --> $DIR/never-in-range-pat.rs:13:12 + | +LL | 0..x => {} + | - ^ this is of type `!` but it should be `char` or numeric + | | + | this is of type `{integer}` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0029`. diff --git a/tests/ui/parser/struct-default-values-and-missing-field-separator.fixed b/tests/ui/parser/struct-default-values-and-missing-field-separator.fixed deleted file mode 100644 index be6ed053c6e..00000000000 --- a/tests/ui/parser/struct-default-values-and-missing-field-separator.fixed +++ /dev/null @@ -1,35 +0,0 @@ -//@ run-rustfix -#![allow(dead_code)] - -enum E { - A, -} - -struct S { - field1: i32, //~ ERROR default values on `struct` fields aren't supported - field2: E, //~ ERROR default values on `struct` fields aren't supported - field3: i32, //~ ERROR default values on `struct` fields aren't supported - field4: i32, //~ ERROR default values on `struct` fields aren't supported - field5: E, //~ ERROR default values on `struct` fields aren't supported - field6: E, //~ ERROR default values on `struct` fields aren't supported -} - -struct S1 { - field1: i32, //~ ERROR expected `,`, or `}`, found `field2` - field2: E, //~ ERROR expected `,`, or `}`, found `field3` - field3: i32, //~ ERROR default values on `struct` fields aren't supported - field4: i32, //~ ERROR default values on `struct` fields aren't supported - field5: E, //~ ERROR default values on `struct` fields aren't supported - field6: E, //~ ERROR default values on `struct` fields aren't supported -} - -struct S2 { - field1 : i32, //~ ERROR expected `:`, found `=` - field2: E, //~ ERROR expected `:`, found `;` -} - -const fn foo(_: i32) -> E { - E::A -} - -fn main() {} diff --git a/tests/ui/parser/struct-default-values-and-missing-field-separator.rs b/tests/ui/parser/struct-default-values-and-missing-field-separator.rs index 7900d397a5d..bb9de98bddb 100644 --- a/tests/ui/parser/struct-default-values-and-missing-field-separator.rs +++ b/tests/ui/parser/struct-default-values-and-missing-field-separator.rs @@ -1,4 +1,3 @@ -//@ run-rustfix #![allow(dead_code)] enum E { @@ -6,21 +5,21 @@ enum E { } struct S { - field1: i32 = 42, //~ ERROR default values on `struct` fields aren't supported - field2: E = E::A, //~ ERROR default values on `struct` fields aren't supported - field3: i32 = 1 + 2, //~ ERROR default values on `struct` fields aren't supported - field4: i32 = { 1 + 2 }, //~ ERROR default values on `struct` fields aren't supported - field5: E = foo(42), //~ ERROR default values on `struct` fields aren't supported - field6: E = { foo(42) }, //~ ERROR default values on `struct` fields aren't supported + field1: i32 = 42, //~ ERROR default values on fields are experimental + field2: E = E::A, //~ ERROR default values on fields are experimental + field3: i32 = 1 + 2, //~ ERROR default values on fields are experimental + field4: i32 = { 1 + 2 }, //~ ERROR default values on fields are experimental + field5: E = foo(42), //~ ERROR default values on fields are experimental + field6: E = { foo(42) }, //~ ERROR default values on fields are experimental } struct S1 { field1: i32 //~ ERROR expected `,`, or `}`, found `field2` field2: E //~ ERROR expected `,`, or `}`, found `field3` - field3: i32 = 1 + 2, //~ ERROR default values on `struct` fields aren't supported - field4: i32 = { 1 + 2 }, //~ ERROR default values on `struct` fields aren't supported - field5: E = foo(42), //~ ERROR default values on `struct` fields aren't supported - field6: E = { foo(42) }, //~ ERROR default values on `struct` fields aren't supported + field3: i32 = 1 + 2, //~ ERROR default values on fields are experimental + field4: i32 = { 1 + 2 }, //~ ERROR default values on fields are experimental + field5: E = foo(42), //~ ERROR default values on fields are experimental + field6: E = { foo(42) }, //~ ERROR default values on fields are experimental } struct S2 { diff --git a/tests/ui/parser/struct-default-values-and-missing-field-separator.stderr b/tests/ui/parser/struct-default-values-and-missing-field-separator.stderr index 1fb57ab11f9..fdd9f0d6dce 100644 --- a/tests/ui/parser/struct-default-values-and-missing-field-separator.stderr +++ b/tests/ui/parser/struct-default-values-and-missing-field-separator.stderr @@ -1,152 +1,133 @@ -error: default values on `struct` fields aren't supported - --> $DIR/struct-default-values-and-missing-field-separator.rs:9:16 +error: expected `,`, or `}`, found `field2` + --> $DIR/struct-default-values-and-missing-field-separator.rs:17:16 | -LL | field1: i32 = 42, - | ^^^^^ +LL | field1: i32 + | ^ help: try adding a comma: `,` + +error: expected `,`, or `}`, found `field3` + --> $DIR/struct-default-values-and-missing-field-separator.rs:18:14 + | +LL | field2: E + | ^ help: try adding a comma: `,` + +error: expected `:`, found `=` + --> $DIR/struct-default-values-and-missing-field-separator.rs:26:12 + | +LL | field1 = i32, + | ^ + | | + | expected `:` + | help: field names and their types are separated with `:` + +error: expected `:`, found `;` + --> $DIR/struct-default-values-and-missing-field-separator.rs:27:11 | -help: remove this unsupported default value +LL | field2; E, + | ^ + | | + | expected `:` + | help: field names and their types are separated with `:` + +error[E0658]: default values on fields are experimental + --> $DIR/struct-default-values-and-missing-field-separator.rs:8:16 | -LL - field1: i32 = 42, -LL + field1: i32, +LL | field1: i32 = 42, + | ^^^^^ | + = note: see issue #132162 <https://github.com/rust-lang/rust/issues/132162> for more information + = help: add `#![feature(default_field_values)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: default values on `struct` fields aren't supported - --> $DIR/struct-default-values-and-missing-field-separator.rs:10:14 +error[E0658]: default values on fields are experimental + --> $DIR/struct-default-values-and-missing-field-separator.rs:9:14 | LL | field2: E = E::A, | ^^^^^^^ | -help: remove this unsupported default value - | -LL - field2: E = E::A, -LL + field2: E, - | + = note: see issue #132162 <https://github.com/rust-lang/rust/issues/132162> for more information + = help: add `#![feature(default_field_values)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: default values on `struct` fields aren't supported - --> $DIR/struct-default-values-and-missing-field-separator.rs:11:16 +error[E0658]: default values on fields are experimental + --> $DIR/struct-default-values-and-missing-field-separator.rs:10:16 | LL | field3: i32 = 1 + 2, | ^^^^^^^^ | -help: remove this unsupported default value - | -LL - field3: i32 = 1 + 2, -LL + field3: i32, - | + = note: see issue #132162 <https://github.com/rust-lang/rust/issues/132162> for more information + = help: add `#![feature(default_field_values)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: default values on `struct` fields aren't supported - --> $DIR/struct-default-values-and-missing-field-separator.rs:12:16 +error[E0658]: default values on fields are experimental + --> $DIR/struct-default-values-and-missing-field-separator.rs:11:16 | LL | field4: i32 = { 1 + 2 }, | ^^^^^^^^^^^^ | -help: remove this unsupported default value - | -LL - field4: i32 = { 1 + 2 }, -LL + field4: i32, - | + = note: see issue #132162 <https://github.com/rust-lang/rust/issues/132162> for more information + = help: add `#![feature(default_field_values)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: default values on `struct` fields aren't supported - --> $DIR/struct-default-values-and-missing-field-separator.rs:13:14 +error[E0658]: default values on fields are experimental + --> $DIR/struct-default-values-and-missing-field-separator.rs:12:14 | LL | field5: E = foo(42), | ^^^^^^^^^^ | -help: remove this unsupported default value - | -LL - field5: E = foo(42), -LL + field5: E, - | + = note: see issue #132162 <https://github.com/rust-lang/rust/issues/132162> for more information + = help: add `#![feature(default_field_values)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: default values on `struct` fields aren't supported - --> $DIR/struct-default-values-and-missing-field-separator.rs:14:14 +error[E0658]: default values on fields are experimental + --> $DIR/struct-default-values-and-missing-field-separator.rs:13:14 | LL | field6: E = { foo(42) }, | ^^^^^^^^^^^^^^ | -help: remove this unsupported default value - | -LL - field6: E = { foo(42) }, -LL + field6: E, - | - -error: expected `,`, or `}`, found `field2` - --> $DIR/struct-default-values-and-missing-field-separator.rs:18:16 - | -LL | field1: i32 - | ^ help: try adding a comma: `,` - -error: expected `,`, or `}`, found `field3` - --> $DIR/struct-default-values-and-missing-field-separator.rs:19:14 - | -LL | field2: E - | ^ help: try adding a comma: `,` + = note: see issue #132162 <https://github.com/rust-lang/rust/issues/132162> for more information + = help: add `#![feature(default_field_values)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: default values on `struct` fields aren't supported - --> $DIR/struct-default-values-and-missing-field-separator.rs:20:16 +error[E0658]: default values on fields are experimental + --> $DIR/struct-default-values-and-missing-field-separator.rs:19:16 | LL | field3: i32 = 1 + 2, | ^^^^^^^^ | -help: remove this unsupported default value - | -LL - field3: i32 = 1 + 2, -LL + field3: i32, - | + = note: see issue #132162 <https://github.com/rust-lang/rust/issues/132162> for more information + = help: add `#![feature(default_field_values)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: default values on `struct` fields aren't supported - --> $DIR/struct-default-values-and-missing-field-separator.rs:21:16 +error[E0658]: default values on fields are experimental + --> $DIR/struct-default-values-and-missing-field-separator.rs:20:16 | LL | field4: i32 = { 1 + 2 }, | ^^^^^^^^^^^^ | -help: remove this unsupported default value - | -LL - field4: i32 = { 1 + 2 }, -LL + field4: i32, - | + = note: see issue #132162 <https://github.com/rust-lang/rust/issues/132162> for more information + = help: add `#![feature(default_field_values)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: default values on `struct` fields aren't supported - --> $DIR/struct-default-values-and-missing-field-separator.rs:22:14 +error[E0658]: default values on fields are experimental + --> $DIR/struct-default-values-and-missing-field-separator.rs:21:14 | LL | field5: E = foo(42), | ^^^^^^^^^^ | -help: remove this unsupported default value - | -LL - field5: E = foo(42), -LL + field5: E, - | + = note: see issue #132162 <https://github.com/rust-lang/rust/issues/132162> for more information + = help: add `#![feature(default_field_values)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: default values on `struct` fields aren't supported - --> $DIR/struct-default-values-and-missing-field-separator.rs:23:14 +error[E0658]: default values on fields are experimental + --> $DIR/struct-default-values-and-missing-field-separator.rs:22:14 | LL | field6: E = { foo(42) }, | ^^^^^^^^^^^^^^ | -help: remove this unsupported default value - | -LL - field6: E = { foo(42) }, -LL + field6: E, - | - -error: expected `:`, found `=` - --> $DIR/struct-default-values-and-missing-field-separator.rs:27:12 - | -LL | field1 = i32, - | ^ - | | - | expected `:` - | help: field names and their types are separated with `:` - -error: expected `:`, found `;` - --> $DIR/struct-default-values-and-missing-field-separator.rs:28:11 - | -LL | field2; E, - | ^ - | | - | expected `:` - | help: field names and their types are separated with `:` + = note: see issue #132162 <https://github.com/rust-lang/rust/issues/132162> for more information + = help: add `#![feature(default_field_values)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error: aborting due to 14 previous errors +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/range/issue-54505-no-std.rs b/tests/ui/range/issue-54505-no-std.rs index a1595685372..0c913f766b7 100644 --- a/tests/ui/range/issue-54505-no-std.rs +++ b/tests/ui/range/issue-54505-no-std.rs @@ -38,6 +38,7 @@ fn main() { take_range(..); //~^ ERROR mismatched types [E0308] + //~| HELP you might have meant //~| HELP consider borrowing here //~| SUGGESTION &( diff --git a/tests/ui/range/issue-54505-no-std.stderr b/tests/ui/range/issue-54505-no-std.stderr index f15a0ae6138..2aa1d584046 100644 --- a/tests/ui/range/issue-54505-no-std.stderr +++ b/tests/ui/range/issue-54505-no-std.stderr @@ -53,13 +53,18 @@ note: function defined here | LL | fn take_range(_r: &impl RangeBounds<i8>) {} | ^^^^^^^^^^ ------------------------- +help: you might have meant to use `..` to skip providing a value for expected fields, but this is only supported on non-tuple struct literals when `#![feature(default_field_values)]` is enabled; it is instead interpreted as a `std::ops::RangeFull` literal + --> $DIR/issue-54505-no-std.rs:39:16 + | +LL | take_range(..); + | ^^ help: consider borrowing here | LL | take_range(&(..)); | ++ + error[E0308]: mismatched types - --> $DIR/issue-54505-no-std.rs:44:16 + --> $DIR/issue-54505-no-std.rs:45:16 | LL | take_range(0..=1); | ---------- ^^^^^ expected `&_`, found `RangeInclusive<{integer}>` @@ -79,7 +84,7 @@ LL | take_range(&(0..=1)); | ++ + error[E0308]: mismatched types - --> $DIR/issue-54505-no-std.rs:49:16 + --> $DIR/issue-54505-no-std.rs:50:16 | LL | take_range(..5); | ---------- ^^^ expected `&_`, found `RangeTo<{integer}>` @@ -99,7 +104,7 @@ LL | take_range(&(..5)); | ++ + error[E0308]: mismatched types - --> $DIR/issue-54505-no-std.rs:54:16 + --> $DIR/issue-54505-no-std.rs:55:16 | LL | take_range(..=42); | ---------- ^^^^^ expected `&_`, found `RangeToInclusive<{integer}>` diff --git a/tests/ui/range/issue-54505.fixed b/tests/ui/range/issue-54505.fixed index 054d3c2cf5e..08a2682140a 100644 --- a/tests/ui/range/issue-54505.fixed +++ b/tests/ui/range/issue-54505.fixed @@ -23,6 +23,7 @@ fn main() { take_range(&(..)); //~^ ERROR mismatched types [E0308] + //~| HELP you might have meant //~| HELP consider borrowing here //~| SUGGESTION &( diff --git a/tests/ui/range/issue-54505.rs b/tests/ui/range/issue-54505.rs index f5cec831760..0a9d7083e4f 100644 --- a/tests/ui/range/issue-54505.rs +++ b/tests/ui/range/issue-54505.rs @@ -23,6 +23,7 @@ fn main() { take_range(..); //~^ ERROR mismatched types [E0308] + //~| HELP you might have meant //~| HELP consider borrowing here //~| SUGGESTION &( diff --git a/tests/ui/range/issue-54505.stderr b/tests/ui/range/issue-54505.stderr index 0e959fc05e2..291e097e865 100644 --- a/tests/ui/range/issue-54505.stderr +++ b/tests/ui/range/issue-54505.stderr @@ -53,13 +53,18 @@ note: function defined here | LL | fn take_range(_r: &impl RangeBounds<i8>) {} | ^^^^^^^^^^ ------------------------- +help: you might have meant to use `..` to skip providing a value for expected fields, but this is only supported on non-tuple struct literals when `#![feature(default_field_values)]` is enabled; it is instead interpreted as a `std::ops::RangeFull` literal + --> $DIR/issue-54505.rs:24:16 + | +LL | take_range(..); + | ^^ help: consider borrowing here | LL | take_range(&(..)); | ++ + error[E0308]: mismatched types - --> $DIR/issue-54505.rs:29:16 + --> $DIR/issue-54505.rs:30:16 | LL | take_range(0..=1); | ---------- ^^^^^ expected `&_`, found `RangeInclusive<{integer}>` @@ -79,7 +84,7 @@ LL | take_range(&(0..=1)); | ++ + error[E0308]: mismatched types - --> $DIR/issue-54505.rs:34:16 + --> $DIR/issue-54505.rs:35:16 | LL | take_range(..5); | ---------- ^^^ expected `&_`, found `RangeTo<{integer}>` @@ -99,7 +104,7 @@ LL | take_range(&(..5)); | ++ + error[E0308]: mismatched types - --> $DIR/issue-54505.rs:39:16 + --> $DIR/issue-54505.rs:40:16 | LL | take_range(..=42); | ---------- ^^^^^ expected `&_`, found `RangeToInclusive<{integer}>` diff --git a/tests/ui/resolve/generic-params-from-outer-item-in-const-item.default.stderr b/tests/ui/resolve/generic-params-from-outer-item-in-const-item.default.stderr index c7e9df10d41..fbb9ede8aa1 100644 --- a/tests/ui/resolve/generic-params-from-outer-item-in-const-item.default.stderr +++ b/tests/ui/resolve/generic-params-from-outer-item-in-const-item.default.stderr @@ -29,20 +29,6 @@ LL | const _: u32 = T::C; | = note: a `const` is a separate item from the item that contains it -note: erroneous constant encountered - --> $DIR/generic-params-from-outer-item-in-const-item.rs:22:9 - | -LL | I - | ^ - -note: erroneous constant encountered - --> $DIR/generic-params-from-outer-item-in-const-item.rs:22:9 - | -LL | I - | ^ - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0401`. diff --git a/tests/ui/resolve/generic-params-from-outer-item-in-const-item.generic_const_items.stderr b/tests/ui/resolve/generic-params-from-outer-item-in-const-item.generic_const_items.stderr index 64c436d3ceb..60aa94038c3 100644 --- a/tests/ui/resolve/generic-params-from-outer-item-in-const-item.generic_const_items.stderr +++ b/tests/ui/resolve/generic-params-from-outer-item-in-const-item.generic_const_items.stderr @@ -35,20 +35,6 @@ LL | const _: u32 = T::C; | = note: a `const` is a separate item from the item that contains it -note: erroneous constant encountered - --> $DIR/generic-params-from-outer-item-in-const-item.rs:22:9 - | -LL | I - | ^ - -note: erroneous constant encountered - --> $DIR/generic-params-from-outer-item-in-const-item.rs:22:9 - | -LL | I - | ^ - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0401`. diff --git a/tests/ui/resolve/issue-50599.stderr b/tests/ui/resolve/issue-50599.stderr index 427dc9f2049..24fb3d580b8 100644 --- a/tests/ui/resolve/issue-50599.stderr +++ b/tests/ui/resolve/issue-50599.stderr @@ -20,12 +20,6 @@ LL - const M: usize = (f64::from(N) * std::f64::LOG10_2) as usize; LL + const M: usize = (f64::from(N) * LOG10_2) as usize; | -note: erroneous constant encountered - --> $DIR/issue-50599.rs:4:29 - | -LL | let mut digits = [0u32; M]; - | ^ - error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/avoid-invalid-mir.stderr b/tests/ui/rfcs/rfc-2497-if-let-chains/avoid-invalid-mir.stderr index eab2604d4c0..606f808f093 100644 --- a/tests/ui/rfcs/rfc-2497-if-let-chains/avoid-invalid-mir.stderr +++ b/tests/ui/rfcs/rfc-2497-if-let-chains/avoid-invalid-mir.stderr @@ -6,11 +6,5 @@ LL | !let y = 42; | = note: only supported directly in conditions of `if` and `while` expressions -note: erroneous constant encountered - --> $DIR/avoid-invalid-mir.rs:11:13 - | -LL | x: [(); N] - | ^ - error: aborting due to 1 previous error diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/invalid-dlltool.rs b/tests/ui/rfcs/rfc-2627-raw-dylib/invalid-dlltool.rs index bcf6dda7a44..057242246f0 100644 --- a/tests/ui/rfcs/rfc-2627-raw-dylib/invalid-dlltool.rs +++ b/tests/ui/rfcs/rfc-2627-raw-dylib/invalid-dlltool.rs @@ -1,7 +1,7 @@ // Tests that failing to run dlltool will raise an error. //@ needs-dlltool -//@ compile-flags: --crate-type lib --emit link -Cdlltool=does_not_exit.exe +//@ compile-flags: --crate-type lib --emit link -Cdlltool=does_not_exist.exe #[link(name = "foo", kind = "raw-dylib")] extern "C" { fn f(x: i32); diff --git a/tests/ui/rfcs/rfc-2627-raw-dylib/invalid-dlltool.stderr b/tests/ui/rfcs/rfc-2627-raw-dylib/invalid-dlltool.stderr index 9dbeee49f53..4bbad9b30a7 100644 --- a/tests/ui/rfcs/rfc-2627-raw-dylib/invalid-dlltool.stderr +++ b/tests/ui/rfcs/rfc-2627-raw-dylib/invalid-dlltool.stderr @@ -1,4 +1,4 @@ -error: Error calling dlltool 'does_not_exit.exe': program not found +error: Error calling dlltool 'does_not_exist.exe': program not found error: aborting due to 1 previous error diff --git a/tests/ui/runtime/on-broken-pipe/auxiliary/assert-sigpipe-disposition.rs b/tests/ui/runtime/on-broken-pipe/auxiliary/assert-sigpipe-disposition.rs index 117f6134b4e..229408fb724 100644 --- a/tests/ui/runtime/on-broken-pipe/auxiliary/assert-sigpipe-disposition.rs +++ b/tests/ui/runtime/on-broken-pipe/auxiliary/assert-sigpipe-disposition.rs @@ -25,7 +25,14 @@ fn start(argc: isize, argv: *const *const u8) -> isize { let actual = unsafe { let mut actual: libc::sigaction = std::mem::zeroed(); libc::sigaction(libc::SIGPIPE, std::ptr::null(), &mut actual); - actual.sa_sigaction + #[cfg(not(target_os = "aix"))] + { + actual.sa_sigaction + } + #[cfg(target_os = "aix")] + { + actual.sa_union.__su_sigaction as libc::sighandler_t + } }; assert_eq!(actual, expected, "actual and expected SIGPIPE disposition in child differs"); diff --git a/tests/ui/runtime/on-broken-pipe/auxiliary/sigpipe-utils.rs b/tests/ui/runtime/on-broken-pipe/auxiliary/sigpipe-utils.rs index 3d93d50ca3f..d16a2b4d8c8 100644 --- a/tests/ui/runtime/on-broken-pipe/auxiliary/sigpipe-utils.rs +++ b/tests/ui/runtime/on-broken-pipe/auxiliary/sigpipe-utils.rs @@ -20,7 +20,14 @@ pub fn assert_sigpipe_handler(expected_handler: SignalHandler) { let actual = unsafe { let mut actual: libc::sigaction = std::mem::zeroed(); libc::sigaction(libc::SIGPIPE, std::ptr::null(), &mut actual); - actual.sa_sigaction + #[cfg(not(target_os = "aix"))] + { + actual.sa_sigaction + } + #[cfg(target_os = "aix")] + { + actual.sa_union.__su_sigaction as libc::sighandler_t + } }; let expected = match expected_handler { diff --git a/tests/ui/runtime/signal-alternate-stack-cleanup.rs b/tests/ui/runtime/signal-alternate-stack-cleanup.rs index f2af86be0a5..8fce0928273 100644 --- a/tests/ui/runtime/signal-alternate-stack-cleanup.rs +++ b/tests/ui/runtime/signal-alternate-stack-cleanup.rs @@ -29,7 +29,14 @@ fn main() { // Install signal handler that runs on alternate signal stack. let mut action: sigaction = std::mem::zeroed(); action.sa_flags = (SA_ONSTACK | SA_SIGINFO) as _; - action.sa_sigaction = signal_handler as sighandler_t; + #[cfg(not(target_os = "aix"))] + { + action.sa_sigaction = signal_handler as sighandler_t; + } + #[cfg(target_os = "aix")] + { + action.sa_union.__su_sigaction = signal_handler as sighandler_t; + } sigaction(SIGWINCH, &action, std::ptr::null_mut()); // Send SIGWINCH on exit. diff --git a/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr b/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr index e4991823d28..cf4c219215e 100644 --- a/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr +++ b/tests/ui/self/arbitrary-self-from-method-substs-ice.stderr @@ -17,12 +17,6 @@ LL | const fn get<R: Deref<Target = Self>>(self: R) -> u32 { LL | } | - value is dropped here -note: erroneous constant encountered - --> $DIR/arbitrary-self-from-method-substs-ice.rs:24:5 - | -LL | FOO; - | ^^^ - error[E0801]: invalid generic `self` parameter type: `R` --> $DIR/arbitrary-self-from-method-substs-ice.rs:10:49 | diff --git a/tests/ui/specialization/const_trait_impl.stderr b/tests/ui/specialization/const_trait_impl.stderr index 607fc06823e..3e1260ff09c 100644 --- a/tests/ui/specialization/const_trait_impl.stderr +++ b/tests/ui/specialization/const_trait_impl.stderr @@ -2,42 +2,57 @@ error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/const_trait_impl.rs:34:9 | LL | impl<T: ~const Default> const A for T { - | ^^^^^^ + | ^^^^^^ can't be applied to `Default` + | +note: `Default` can't be used with `~const` because it isn't annotated with `#[const_trait]` + --> $SRC_DIR/core/src/default.rs:LL:COL error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/const_trait_impl.rs:40:9 | LL | impl<T: ~const Default + ~const Sup> const A for T { - | ^^^^^^ + | ^^^^^^ can't be applied to `Default` + | +note: `Default` can't be used with `~const` because it isn't annotated with `#[const_trait]` + --> $SRC_DIR/core/src/default.rs:LL:COL error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/const_trait_impl.rs:46:9 | LL | impl<T: ~const Default + ~const Sub> const A for T { - | ^^^^^^ + | ^^^^^^ can't be applied to `Default` + | +note: `Default` can't be used with `~const` because it isn't annotated with `#[const_trait]` + --> $SRC_DIR/core/src/default.rs:LL:COL error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/const_trait_impl.rs:40:9 | LL | impl<T: ~const Default + ~const Sup> const A for T { - | ^^^^^^ + | ^^^^^^ can't be applied to `Default` | +note: `Default` can't be used with `~const` because it isn't annotated with `#[const_trait]` + --> $SRC_DIR/core/src/default.rs:LL:COL = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/const_trait_impl.rs:34:9 | LL | impl<T: ~const Default> const A for T { - | ^^^^^^ + | ^^^^^^ can't be applied to `Default` | +note: `Default` can't be used with `~const` because it isn't annotated with `#[const_trait]` + --> $SRC_DIR/core/src/default.rs:LL:COL = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/const_trait_impl.rs:46:9 | LL | impl<T: ~const Default + ~const Sub> const A for T { - | ^^^^^^ + | ^^^^^^ can't be applied to `Default` | +note: `Default` can't be used with `~const` because it isn't annotated with `#[const_trait]` + --> $SRC_DIR/core/src/default.rs:LL:COL = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: aborting due to 6 previous errors diff --git a/tests/ui/stats/input-stats.stderr b/tests/ui/stats/input-stats.stderr index 2adbcfab612..e3bc68a2134 100644 --- a/tests/ui/stats/input-stats.stderr +++ b/tests/ui/stats/input-stats.stderr @@ -20,8 +20,8 @@ ast-stats-1 Stmt 160 ( 2.4%) 5 32 ast-stats-1 - Let 32 ( 0.5%) 1 ast-stats-1 - MacCall 32 ( 0.5%) 1 ast-stats-1 - Expr 96 ( 1.4%) 3 -ast-stats-1 FieldDef 176 ( 2.6%) 2 88 ast-stats-1 Block 192 ( 2.9%) 6 32 +ast-stats-1 FieldDef 208 ( 3.1%) 2 104 ast-stats-1 Variant 208 ( 3.1%) 2 104 ast-stats-1 AssocItem 352 ( 5.3%) 4 88 ast-stats-1 - Type 176 ( 2.6%) 2 @@ -29,7 +29,7 @@ ast-stats-1 - Fn 176 ( 2.6%) 2 ast-stats-1 GenericBound 352 ( 5.3%) 4 88 ast-stats-1 - Trait 352 ( 5.3%) 4 ast-stats-1 GenericParam 480 ( 7.2%) 5 96 -ast-stats-1 Pat 504 ( 7.6%) 7 72 +ast-stats-1 Pat 504 ( 7.5%) 7 72 ast-stats-1 - Struct 72 ( 1.1%) 1 ast-stats-1 - Wild 72 ( 1.1%) 1 ast-stats-1 - Ident 360 ( 5.4%) 5 @@ -39,13 +39,13 @@ ast-stats-1 - Match 72 ( 1.1%) 1 ast-stats-1 - Struct 72 ( 1.1%) 1 ast-stats-1 - Lit 144 ( 2.2%) 2 ast-stats-1 - Block 216 ( 3.2%) 3 -ast-stats-1 PathSegment 744 (11.2%) 31 24 +ast-stats-1 PathSegment 744 (11.1%) 31 24 ast-stats-1 Ty 896 (13.4%) 14 64 ast-stats-1 - Ref 64 ( 1.0%) 1 ast-stats-1 - Ptr 64 ( 1.0%) 1 ast-stats-1 - ImplicitSelf 128 ( 1.9%) 2 ast-stats-1 - Path 640 ( 9.6%) 10 -ast-stats-1 Item 1_224 (18.4%) 9 136 +ast-stats-1 Item 1_224 (18.3%) 9 136 ast-stats-1 - ForeignMod 136 ( 2.0%) 1 ast-stats-1 - Trait 136 ( 2.0%) 1 ast-stats-1 - Impl 136 ( 2.0%) 1 @@ -53,7 +53,7 @@ ast-stats-1 - Enum 136 ( 2.0%) 1 ast-stats-1 - Fn 272 ( 4.1%) 2 ast-stats-1 - Use 408 ( 6.1%) 3 ast-stats-1 ---------------------------------------------------------------- -ast-stats-1 Total 6_664 116 +ast-stats-1 Total 6_696 116 ast-stats-1 ast-stats-2 POST EXPANSION AST STATS ast-stats-2 Name Accumulated Size Count Item Size @@ -70,7 +70,7 @@ ast-stats-2 - Fn 88 ( 1.2%) 1 ast-stats-2 Arm 96 ( 1.3%) 2 48 ast-stats-2 FnDecl 120 ( 1.6%) 5 24 ast-stats-2 InlineAsm 120 ( 1.6%) 1 120 -ast-stats-2 Attribute 128 ( 1.8%) 4 32 +ast-stats-2 Attribute 128 ( 1.7%) 4 32 ast-stats-2 - DocComment 32 ( 0.4%) 1 ast-stats-2 - Normal 96 ( 1.3%) 3 ast-stats-2 Param 160 ( 2.2%) 4 40 @@ -78,33 +78,33 @@ ast-stats-2 Stmt 160 ( 2.2%) 5 32 ast-stats-2 - Let 32 ( 0.4%) 1 ast-stats-2 - Semi 32 ( 0.4%) 1 ast-stats-2 - Expr 96 ( 1.3%) 3 -ast-stats-2 FieldDef 176 ( 2.4%) 2 88 ast-stats-2 Block 192 ( 2.6%) 6 32 +ast-stats-2 FieldDef 208 ( 2.8%) 2 104 ast-stats-2 Variant 208 ( 2.8%) 2 104 ast-stats-2 AssocItem 352 ( 4.8%) 4 88 ast-stats-2 - Type 176 ( 2.4%) 2 ast-stats-2 - Fn 176 ( 2.4%) 2 ast-stats-2 GenericBound 352 ( 4.8%) 4 88 ast-stats-2 - Trait 352 ( 4.8%) 4 -ast-stats-2 GenericParam 480 ( 6.6%) 5 96 +ast-stats-2 GenericParam 480 ( 6.5%) 5 96 ast-stats-2 Pat 504 ( 6.9%) 7 72 ast-stats-2 - Struct 72 ( 1.0%) 1 ast-stats-2 - Wild 72 ( 1.0%) 1 ast-stats-2 - Ident 360 ( 4.9%) 5 -ast-stats-2 Expr 648 ( 8.9%) 9 72 +ast-stats-2 Expr 648 ( 8.8%) 9 72 ast-stats-2 - Path 72 ( 1.0%) 1 ast-stats-2 - Match 72 ( 1.0%) 1 ast-stats-2 - Struct 72 ( 1.0%) 1 ast-stats-2 - InlineAsm 72 ( 1.0%) 1 ast-stats-2 - Lit 144 ( 2.0%) 2 -ast-stats-2 - Block 216 ( 3.0%) 3 +ast-stats-2 - Block 216 ( 2.9%) 3 ast-stats-2 PathSegment 864 (11.8%) 36 24 -ast-stats-2 Ty 896 (12.3%) 14 64 +ast-stats-2 Ty 896 (12.2%) 14 64 ast-stats-2 - Ref 64 ( 0.9%) 1 ast-stats-2 - Ptr 64 ( 0.9%) 1 -ast-stats-2 - ImplicitSelf 128 ( 1.8%) 2 -ast-stats-2 - Path 640 ( 8.8%) 10 -ast-stats-2 Item 1_496 (20.5%) 11 136 +ast-stats-2 - ImplicitSelf 128 ( 1.7%) 2 +ast-stats-2 - Path 640 ( 8.7%) 10 +ast-stats-2 Item 1_496 (20.4%) 11 136 ast-stats-2 - Enum 136 ( 1.9%) 1 ast-stats-2 - Trait 136 ( 1.9%) 1 ast-stats-2 - Impl 136 ( 1.9%) 1 @@ -113,7 +113,7 @@ ast-stats-2 - ForeignMod 136 ( 1.9%) 1 ast-stats-2 - Fn 272 ( 3.7%) 2 ast-stats-2 - Use 544 ( 7.4%) 4 ast-stats-2 ---------------------------------------------------------------- -ast-stats-2 Total 7_312 127 +ast-stats-2 Total 7_344 127 ast-stats-2 hir-stats HIR STATS hir-stats Name Accumulated Size Count Item Size @@ -138,9 +138,9 @@ hir-stats Stmt 96 ( 1.1%) 3 32 hir-stats - Let 32 ( 0.4%) 1 hir-stats - Semi 32 ( 0.4%) 1 hir-stats - Expr 32 ( 0.4%) 1 -hir-stats FieldDef 112 ( 1.3%) 2 56 hir-stats FnDecl 120 ( 1.3%) 3 40 hir-stats Attribute 128 ( 1.4%) 4 32 +hir-stats FieldDef 128 ( 1.4%) 2 64 hir-stats GenericArgs 144 ( 1.6%) 3 48 hir-stats Variant 144 ( 1.6%) 2 72 hir-stats GenericBound 256 ( 2.9%) 4 64 @@ -163,7 +163,7 @@ hir-stats - Struct 64 ( 0.7%) 1 hir-stats - InlineAsm 64 ( 0.7%) 1 hir-stats - Lit 128 ( 1.4%) 2 hir-stats - Block 384 ( 4.3%) 6 -hir-stats Item 968 (10.9%) 11 88 +hir-stats Item 968 (10.8%) 11 88 hir-stats - Enum 88 ( 1.0%) 1 hir-stats - Trait 88 ( 1.0%) 1 hir-stats - Impl 88 ( 1.0%) 1 @@ -174,5 +174,5 @@ hir-stats - Use 352 ( 3.9%) 4 hir-stats Path 1_240 (13.9%) 31 40 hir-stats PathSegment 1_920 (21.5%) 40 48 hir-stats ---------------------------------------------------------------- -hir-stats Total 8_920 180 +hir-stats Total 8_936 180 hir-stats diff --git a/tests/ui/structs/auxiliary/struct_field_default.rs b/tests/ui/structs/auxiliary/struct_field_default.rs new file mode 100644 index 00000000000..b315df5dba2 --- /dev/null +++ b/tests/ui/structs/auxiliary/struct_field_default.rs @@ -0,0 +1,5 @@ +#![feature(default_field_values)] + +pub struct A { + pub a: isize = 42, +} diff --git a/tests/ui/structs/default-field-values-failures.rs b/tests/ui/structs/default-field-values-failures.rs new file mode 100644 index 00000000000..0ac071d91d6 --- /dev/null +++ b/tests/ui/structs/default-field-values-failures.rs @@ -0,0 +1,64 @@ +#![feature(default_field_values)] + +#[derive(Debug)] +pub struct S; + +#[derive(Debug, Default)] +pub struct Foo { + pub bar: S = S, + pub baz: i32 = 42 + 3, +} + +#[derive(Debug, Default)] +pub struct Bar { + pub bar: S, //~ ERROR the trait bound `S: Default` is not satisfied + pub baz: i32 = 42 + 3, +} + +#[derive(Default)] +pub struct Qux<const C: i32> { + bar: S = Self::S, //~ ERROR generic `Self` types are currently not permitted in anonymous constants + baz: i32 = foo(), + bat: i32 = <Qux<{ C }> as T>::K, //~ ERROR generic parameters may not be used in const operations + bay: i32 = C, +} + +pub struct Rak(i32 = 42); //~ ERROR default fields are not supported in tuple structs + +impl<const C: i32> Qux<C> { + const S: S = S; +} + +trait T { + const K: i32; +} + +impl<const C: i32> T for Qux<C> { + const K: i32 = 2; +} + +const fn foo() -> i32 { + 42 +} + +#[derive(Debug, Default)] +enum E { + #[default] + Variant {} //~ ERROR the `#[default]` attribute may only be used on unit enum variants +} + +fn main () { + let _ = Foo { .. }; // ok + let _ = Foo::default(); // ok + let _ = Bar { .. }; //~ ERROR mandatory field + let _ = Bar::default(); // silenced + let _ = Bar { bar: S, .. }; // ok + let _ = Qux::<4> { .. }; + let _ = Rak(..); //~ ERROR E0308 + //~^ you might have meant to use `..` to skip providing + let _ = Rak(0, ..); //~ ERROR E0061 + //~^ you might have meant to use `..` to skip providing + let _ = Rak(.., 0); //~ ERROR E0061 + //~^ you might have meant to use `..` to skip providing + let _ = Rak { .. }; // ok +} diff --git a/tests/ui/structs/default-field-values-failures.stderr b/tests/ui/structs/default-field-values-failures.stderr new file mode 100644 index 00000000000..5b9d2df5a5d --- /dev/null +++ b/tests/ui/structs/default-field-values-failures.stderr @@ -0,0 +1,118 @@ +error: the `#[default]` attribute may only be used on unit enum variants or variants where every field has a default value + --> $DIR/default-field-values-failures.rs:47:5 + | +LL | Variant {} + | ^^^^^^^ + | + = help: consider a manual implementation of `Default` + +error: generic parameters may not be used in const operations + --> $DIR/default-field-values-failures.rs:22:23 + | +LL | bat: i32 = <Qux<{ C }> as T>::K, + | ^ cannot perform const operation using `C` + | + = help: const parameters may only be used as standalone arguments, i.e. `C` + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions + +error: default fields are not supported in tuple structs + --> $DIR/default-field-values-failures.rs:26:22 + | +LL | pub struct Rak(i32 = 42); + | ^^ default fields are only supported on structs + +error: generic `Self` types are currently not permitted in anonymous constants + --> $DIR/default-field-values-failures.rs:20:14 + | +LL | bar: S = Self::S, + | ^^^^ + +error[E0277]: the trait bound `S: Default` is not satisfied + --> $DIR/default-field-values-failures.rs:14:5 + | +LL | #[derive(Debug, Default)] + | ------- in this derive macro expansion +LL | pub struct Bar { +LL | pub bar: S, + | ^^^^^^^^^^ the trait `Default` is not implemented for `S` + | + = note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider annotating `S` with `#[derive(Default)]` + | +LL + #[derive(Default)] +LL | pub struct S; + | + +error: missing mandatory field `bar` + --> $DIR/default-field-values-failures.rs:53:21 + | +LL | let _ = Bar { .. }; + | ^ + +error[E0308]: mismatched types + --> $DIR/default-field-values-failures.rs:57:17 + | +LL | let _ = Rak(..); + | --- ^^ expected `i32`, found `RangeFull` + | | + | arguments to this struct are incorrect + | +note: tuple struct defined here + --> $DIR/default-field-values-failures.rs:26:12 + | +LL | pub struct Rak(i32 = 42); + | ^^^ +help: you might have meant to use `..` to skip providing a value for expected fields, but this is only supported on non-tuple struct literals; it is instead interpreted as a `std::ops::RangeFull` literal + --> $DIR/default-field-values-failures.rs:57:17 + | +LL | let _ = Rak(..); + | ^^ + +error[E0061]: this struct takes 1 argument but 2 arguments were supplied + --> $DIR/default-field-values-failures.rs:59:13 + | +LL | let _ = Rak(0, ..); + | ^^^ -- unexpected argument #2 of type `RangeFull` + | +help: you might have meant to use `..` to skip providing a value for expected fields, but this is only supported on non-tuple struct literals; it is instead interpreted as a `std::ops::RangeFull` literal + --> $DIR/default-field-values-failures.rs:59:20 + | +LL | let _ = Rak(0, ..); + | ^^ +note: tuple struct defined here + --> $DIR/default-field-values-failures.rs:26:12 + | +LL | pub struct Rak(i32 = 42); + | ^^^ +help: remove the extra argument + | +LL - let _ = Rak(0, ..); +LL + let _ = Rak(0); + | + +error[E0061]: this struct takes 1 argument but 2 arguments were supplied + --> $DIR/default-field-values-failures.rs:61:13 + | +LL | let _ = Rak(.., 0); + | ^^^ -- unexpected argument #1 of type `RangeFull` + | +help: you might have meant to use `..` to skip providing a value for expected fields, but this is only supported on non-tuple struct literals; it is instead interpreted as a `std::ops::RangeFull` literal + --> $DIR/default-field-values-failures.rs:61:17 + | +LL | let _ = Rak(.., 0); + | ^^ +note: tuple struct defined here + --> $DIR/default-field-values-failures.rs:26:12 + | +LL | pub struct Rak(i32 = 42); + | ^^^ +help: remove the extra argument + | +LL - let _ = Rak(.., 0); +LL + let _ = Rak(0); + | + +error: aborting due to 9 previous errors + +Some errors have detailed explanations: E0061, E0277, E0308. +For more information about an error, try `rustc --explain E0061`. diff --git a/tests/ui/structs/default-field-values-invalid-const.rs b/tests/ui/structs/default-field-values-invalid-const.rs new file mode 100644 index 00000000000..203a712868b --- /dev/null +++ b/tests/ui/structs/default-field-values-invalid-const.rs @@ -0,0 +1,16 @@ +#![feature(default_field_values, generic_const_exprs)] +#![allow(incomplete_features)] + +pub struct Bat { + pub bax: u8 = panic!("asdf"), + //~^ ERROR evaluation of constant value failed +} + +pub struct Baz<const C: u8> { + pub bax: u8 = 130 + C, // ok + pub bat: u8 = 130 + 130, + //~^ ERROR evaluation of `Baz::<C>::bat::{constant#0}` failed + pub bay: u8 = 1, // ok +} + +fn main() {} diff --git a/tests/ui/structs/default-field-values-invalid-const.stderr b/tests/ui/structs/default-field-values-invalid-const.stderr new file mode 100644 index 00000000000..47f25a1f38e --- /dev/null +++ b/tests/ui/structs/default-field-values-invalid-const.stderr @@ -0,0 +1,17 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/default-field-values-invalid-const.rs:5:19 + | +LL | pub bax: u8 = panic!("asdf"), + | ^^^^^^^^^^^^^^ the evaluated program panicked at 'asdf', $DIR/default-field-values-invalid-const.rs:5:19 + | + = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of `Baz::<C>::bat::{constant#0}` failed + --> $DIR/default-field-values-invalid-const.rs:11:19 + | +LL | pub bat: u8 = 130 + 130, + | ^^^^^^^^^ attempt to compute `130_u8 + 130_u8`, which would overflow + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui/structs/default-field-values-support.rs b/tests/ui/structs/default-field-values-support.rs new file mode 100644 index 00000000000..8209d6dd4a0 --- /dev/null +++ b/tests/ui/structs/default-field-values-support.rs @@ -0,0 +1,100 @@ +// Exercise the `default_field_values` feature to confirm it interacts correctly with other nightly +// features. In particular, we want to verify that interaction with consts coming from different +// contexts are usable as a default field value. +//@ run-pass +//@ aux-build:struct_field_default.rs +#![feature(const_trait_impl, default_field_values, generic_const_exprs)] +#![allow(unused_variables, dead_code, incomplete_features)] + +extern crate struct_field_default as xc; + +pub struct S; + +// Basic expressions and `Default` expansion +#[derive(Default)] +pub struct Foo { + pub bar: S = S, + pub baz: i32 = 42 + 3, +} + +// Enum support for deriving `Default` when all fields have default values +#[derive(Default)] +pub enum Bar { + #[default] + Foo { + bar: S = S, + baz: i32 = 42 + 3, + } +} + +#[const_trait] pub trait ConstDefault { + fn value() -> Self; +} + +impl const ConstDefault for i32 { + fn value() -> i32 { + 101 + } +} + +pub struct Qux<A, const C: i32, X: const ConstDefault> { + bar: S = Qux::<A, C, X>::S, // Associated constant from inherent impl + baz: i32 = foo(), // Constant function + bat: i32 = <Qux<A, C, X> as T>::K, // Associated constant from explicit trait + baq: i32 = Self::K, // Associated constant from implicit trait + bay: i32 = C, // `const` parameter + bak: Vec<A> = Vec::new(), // Associated constant function + ban: X = X::value(), // Associated constant function from `const` trait parameter +} + +impl<A, const C: i32, X: const ConstDefault> Qux<A, C, X> { + const S: S = S; +} + +trait T { + const K: i32; +} + +impl<A, const C: i32, X: const ConstDefault> T for Qux<A, C, X> { + const K: i32 = 2; +} + +const fn foo() -> i32 { + 42 +} + +fn main () { + let x = Foo { .. }; + let y = Foo::default(); + let z = Foo { baz: 1, .. }; + + assert_eq!(45, x.baz); + assert_eq!(45, y.baz); + assert_eq!(1, z.baz); + + let x = Bar::Foo { .. }; + let y = Bar::default(); + let z = Bar::Foo { baz: 1, .. }; + + assert!(matches!(Bar::Foo { bar: S, baz: 45 }, x)); + assert!(matches!(Bar::Foo { bar: S, baz: 45 }, y)); + assert!(matches!(Bar::Foo { bar: S, baz: 1 }, z)); + + let x = Qux::<i32, 4, i32> { .. }; + assert!(matches!( + Qux::<i32, 4, i32> { + bar: S, + baz: 42, + bat: 2, + baq: 2, + bay: 4, + ban: 101, + .. + }, + x, + )); + assert!(x.bak.is_empty()); + + let x = xc::A { .. }; + assert!(matches!(xc::A { a: 42 }, x)); +} diff --git a/tests/ui/thir-print/thir-tree-match.stdout b/tests/ui/thir-print/thir-tree-match.stdout index d56f15fb221..916f296ccfc 100644 --- a/tests/ui/thir-print/thir-tree-match.stdout +++ b/tests/ui/thir-print/thir-tree-match.stdout @@ -92,7 +92,7 @@ body: adt_def: AdtDef { did: DefId(0:10 ~ thir_tree_match[fcf8]::Foo) - variants: [VariantDef { def_id: DefId(0:11 ~ thir_tree_match[fcf8]::Foo::FooOne), ctor: Some((Fn, DefId(0:12 ~ thir_tree_match[fcf8]::Foo::FooOne::{constructor#0}))), name: "FooOne", discr: Relative(0), fields: [FieldDef { did: DefId(0:13 ~ thir_tree_match[fcf8]::Foo::FooOne::0), name: "0", vis: Restricted(DefId(0:0 ~ thir_tree_match[fcf8])), safety: Safe }], tainted: None, flags: }, VariantDef { def_id: DefId(0:14 ~ thir_tree_match[fcf8]::Foo::FooTwo), ctor: Some((Const, DefId(0:15 ~ thir_tree_match[fcf8]::Foo::FooTwo::{constructor#0}))), name: "FooTwo", discr: Relative(1), fields: [], tainted: None, flags: }] + variants: [VariantDef { def_id: DefId(0:11 ~ thir_tree_match[fcf8]::Foo::FooOne), ctor: Some((Fn, DefId(0:12 ~ thir_tree_match[fcf8]::Foo::FooOne::{constructor#0}))), name: "FooOne", discr: Relative(0), fields: [FieldDef { did: DefId(0:13 ~ thir_tree_match[fcf8]::Foo::FooOne::0), name: "0", vis: Restricted(DefId(0:0 ~ thir_tree_match[fcf8])), safety: Safe, value: None }], tainted: None, flags: }, VariantDef { def_id: DefId(0:14 ~ thir_tree_match[fcf8]::Foo::FooTwo), ctor: Some((Const, DefId(0:15 ~ thir_tree_match[fcf8]::Foo::FooTwo::{constructor#0}))), name: "FooTwo", discr: Relative(1), fields: [], tainted: None, flags: }] flags: IS_ENUM repr: ReprOptions { int: None, align: None, pack: None, flags: , field_shuffle_seed: 3477539199540094892 } args: [] @@ -154,7 +154,7 @@ body: adt_def: AdtDef { did: DefId(0:10 ~ thir_tree_match[fcf8]::Foo) - variants: [VariantDef { def_id: DefId(0:11 ~ thir_tree_match[fcf8]::Foo::FooOne), ctor: Some((Fn, DefId(0:12 ~ thir_tree_match[fcf8]::Foo::FooOne::{constructor#0}))), name: "FooOne", discr: Relative(0), fields: [FieldDef { did: DefId(0:13 ~ thir_tree_match[fcf8]::Foo::FooOne::0), name: "0", vis: Restricted(DefId(0:0 ~ thir_tree_match[fcf8])), safety: Safe }], tainted: None, flags: }, VariantDef { def_id: DefId(0:14 ~ thir_tree_match[fcf8]::Foo::FooTwo), ctor: Some((Const, DefId(0:15 ~ thir_tree_match[fcf8]::Foo::FooTwo::{constructor#0}))), name: "FooTwo", discr: Relative(1), fields: [], tainted: None, flags: }] + variants: [VariantDef { def_id: DefId(0:11 ~ thir_tree_match[fcf8]::Foo::FooOne), ctor: Some((Fn, DefId(0:12 ~ thir_tree_match[fcf8]::Foo::FooOne::{constructor#0}))), name: "FooOne", discr: Relative(0), fields: [FieldDef { did: DefId(0:13 ~ thir_tree_match[fcf8]::Foo::FooOne::0), name: "0", vis: Restricted(DefId(0:0 ~ thir_tree_match[fcf8])), safety: Safe, value: None }], tainted: None, flags: }, VariantDef { def_id: DefId(0:14 ~ thir_tree_match[fcf8]::Foo::FooTwo), ctor: Some((Const, DefId(0:15 ~ thir_tree_match[fcf8]::Foo::FooTwo::{constructor#0}))), name: "FooTwo", discr: Relative(1), fields: [], tainted: None, flags: }] flags: IS_ENUM repr: ReprOptions { int: None, align: None, pack: None, flags: , field_shuffle_seed: 3477539199540094892 } args: [] @@ -206,7 +206,7 @@ body: adt_def: AdtDef { did: DefId(0:10 ~ thir_tree_match[fcf8]::Foo) - variants: [VariantDef { def_id: DefId(0:11 ~ thir_tree_match[fcf8]::Foo::FooOne), ctor: Some((Fn, DefId(0:12 ~ thir_tree_match[fcf8]::Foo::FooOne::{constructor#0}))), name: "FooOne", discr: Relative(0), fields: [FieldDef { did: DefId(0:13 ~ thir_tree_match[fcf8]::Foo::FooOne::0), name: "0", vis: Restricted(DefId(0:0 ~ thir_tree_match[fcf8])), safety: Safe }], tainted: None, flags: }, VariantDef { def_id: DefId(0:14 ~ thir_tree_match[fcf8]::Foo::FooTwo), ctor: Some((Const, DefId(0:15 ~ thir_tree_match[fcf8]::Foo::FooTwo::{constructor#0}))), name: "FooTwo", discr: Relative(1), fields: [], tainted: None, flags: }] + variants: [VariantDef { def_id: DefId(0:11 ~ thir_tree_match[fcf8]::Foo::FooOne), ctor: Some((Fn, DefId(0:12 ~ thir_tree_match[fcf8]::Foo::FooOne::{constructor#0}))), name: "FooOne", discr: Relative(0), fields: [FieldDef { did: DefId(0:13 ~ thir_tree_match[fcf8]::Foo::FooOne::0), name: "0", vis: Restricted(DefId(0:0 ~ thir_tree_match[fcf8])), safety: Safe, value: None }], tainted: None, flags: }, VariantDef { def_id: DefId(0:14 ~ thir_tree_match[fcf8]::Foo::FooTwo), ctor: Some((Const, DefId(0:15 ~ thir_tree_match[fcf8]::Foo::FooTwo::{constructor#0}))), name: "FooTwo", discr: Relative(1), fields: [], tainted: None, flags: }] flags: IS_ENUM repr: ReprOptions { int: None, align: None, pack: None, flags: , field_shuffle_seed: 3477539199540094892 } args: [] diff --git a/tests/ui/traits/const-traits/call-const-trait-method-pass.stderr b/tests/ui/traits/const-traits/call-const-trait-method-pass.stderr index 1e48a0331cc..ef494bde98c 100644 --- a/tests/ui/traits/const-traits/call-const-trait-method-pass.stderr +++ b/tests/ui/traits/const-traits/call-const-trait-method-pass.stderr @@ -2,7 +2,7 @@ error: const `impl` for trait `PartialEq` which is not marked with `#[const_trai --> $DIR/call-const-trait-method-pass.rs:15:12 | LL | impl const PartialEq for Int { - | ^^^^^^^^^ + | ^^^^^^^^^ this trait is not `const` | = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` = note: adding a non-const method body in the future would be a breaking change diff --git a/tests/ui/traits/const-traits/call-generic-in-impl.stderr b/tests/ui/traits/const-traits/call-generic-in-impl.stderr index 52ee04425b2..58d0997f5a3 100644 --- a/tests/ui/traits/const-traits/call-generic-in-impl.stderr +++ b/tests/ui/traits/const-traits/call-generic-in-impl.stderr @@ -2,14 +2,19 @@ error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/call-generic-in-impl.rs:10:9 | LL | impl<T: ~const PartialEq> const MyPartialEq for T { - | ^^^^^^ + | ^^^^^^ can't be applied to `PartialEq` + | +note: `PartialEq` can't be used with `~const` because it isn't annotated with `#[const_trait]` + --> $SRC_DIR/core/src/cmp.rs:LL:COL error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/call-generic-in-impl.rs:10:9 | LL | impl<T: ~const PartialEq> const MyPartialEq for T { - | ^^^^^^ + | ^^^^^^ can't be applied to `PartialEq` | +note: `PartialEq` can't be used with `~const` because it isn't annotated with `#[const_trait]` + --> $SRC_DIR/core/src/cmp.rs:LL:COL = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0015]: cannot call non-const fn `<T as PartialEq>::eq` in constant functions diff --git a/tests/ui/traits/const-traits/call-generic-method-chain.stderr b/tests/ui/traits/const-traits/call-generic-method-chain.stderr index 21fb19daad4..d7a2a186494 100644 --- a/tests/ui/traits/const-traits/call-generic-method-chain.stderr +++ b/tests/ui/traits/const-traits/call-generic-method-chain.stderr @@ -2,7 +2,7 @@ error: const `impl` for trait `PartialEq` which is not marked with `#[const_trai --> $DIR/call-generic-method-chain.rs:11:12 | LL | impl const PartialEq for S { - | ^^^^^^^^^ + | ^^^^^^^^^ this trait is not `const` | = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` = note: adding a non-const method body in the future would be a breaking change @@ -11,28 +11,38 @@ error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/call-generic-method-chain.rs:20:25 | LL | const fn equals_self<T: ~const PartialEq>(t: &T) -> bool { - | ^^^^^^ + | ^^^^^^ can't be applied to `PartialEq` + | +note: `PartialEq` can't be used with `~const` because it isn't annotated with `#[const_trait]` + --> $SRC_DIR/core/src/cmp.rs:LL:COL error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/call-generic-method-chain.rs:20:25 | LL | const fn equals_self<T: ~const PartialEq>(t: &T) -> bool { - | ^^^^^^ + | ^^^^^^ can't be applied to `PartialEq` | +note: `PartialEq` can't be used with `~const` because it isn't annotated with `#[const_trait]` + --> $SRC_DIR/core/src/cmp.rs:LL:COL = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/call-generic-method-chain.rs:24:33 | LL | const fn equals_self_wrapper<T: ~const PartialEq>(t: &T) -> bool { - | ^^^^^^ + | ^^^^^^ can't be applied to `PartialEq` + | +note: `PartialEq` can't be used with `~const` because it isn't annotated with `#[const_trait]` + --> $SRC_DIR/core/src/cmp.rs:LL:COL error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/call-generic-method-chain.rs:24:33 | LL | const fn equals_self_wrapper<T: ~const PartialEq>(t: &T) -> bool { - | ^^^^^^ + | ^^^^^^ can't be applied to `PartialEq` | +note: `PartialEq` can't be used with `~const` because it isn't annotated with `#[const_trait]` + --> $SRC_DIR/core/src/cmp.rs:LL:COL = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0015]: cannot call non-const operator in constant functions diff --git a/tests/ui/traits/const-traits/call-generic-method-dup-bound.stderr b/tests/ui/traits/const-traits/call-generic-method-dup-bound.stderr index 845949a38bf..90465d0a5b2 100644 --- a/tests/ui/traits/const-traits/call-generic-method-dup-bound.stderr +++ b/tests/ui/traits/const-traits/call-generic-method-dup-bound.stderr @@ -2,7 +2,7 @@ error: const `impl` for trait `PartialEq` which is not marked with `#[const_trai --> $DIR/call-generic-method-dup-bound.rs:9:12 | LL | impl const PartialEq for S { - | ^^^^^^^^^ + | ^^^^^^^^^ this trait is not `const` | = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` = note: adding a non-const method body in the future would be a breaking change @@ -11,28 +11,38 @@ error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/call-generic-method-dup-bound.rs:20:37 | LL | const fn equals_self<T: PartialEq + ~const PartialEq>(t: &T) -> bool { - | ^^^^^^ + | ^^^^^^ can't be applied to `PartialEq` + | +note: `PartialEq` can't be used with `~const` because it isn't annotated with `#[const_trait]` + --> $SRC_DIR/core/src/cmp.rs:LL:COL error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/call-generic-method-dup-bound.rs:20:37 | LL | const fn equals_self<T: PartialEq + ~const PartialEq>(t: &T) -> bool { - | ^^^^^^ + | ^^^^^^ can't be applied to `PartialEq` | +note: `PartialEq` can't be used with `~const` because it isn't annotated with `#[const_trait]` + --> $SRC_DIR/core/src/cmp.rs:LL:COL = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/call-generic-method-dup-bound.rs:27:30 | LL | const fn equals_self2<T: A + ~const PartialEq>(t: &T) -> bool { - | ^^^^^^ + | ^^^^^^ can't be applied to `PartialEq` + | +note: `PartialEq` can't be used with `~const` because it isn't annotated with `#[const_trait]` + --> $SRC_DIR/core/src/cmp.rs:LL:COL error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/call-generic-method-dup-bound.rs:27:30 | LL | const fn equals_self2<T: A + ~const PartialEq>(t: &T) -> bool { - | ^^^^^^ + | ^^^^^^ can't be applied to `PartialEq` | +note: `PartialEq` can't be used with `~const` because it isn't annotated with `#[const_trait]` + --> $SRC_DIR/core/src/cmp.rs:LL:COL = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0015]: cannot call non-const operator in constant functions diff --git a/tests/ui/traits/const-traits/call-generic-method-pass.stderr b/tests/ui/traits/const-traits/call-generic-method-pass.stderr index 0c0037e36b8..a7626a4e99d 100644 --- a/tests/ui/traits/const-traits/call-generic-method-pass.stderr +++ b/tests/ui/traits/const-traits/call-generic-method-pass.stderr @@ -2,7 +2,7 @@ error: const `impl` for trait `PartialEq` which is not marked with `#[const_trai --> $DIR/call-generic-method-pass.rs:11:12 | LL | impl const PartialEq for S { - | ^^^^^^^^^ + | ^^^^^^^^^ this trait is not `const` | = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` = note: adding a non-const method body in the future would be a breaking change @@ -11,14 +11,19 @@ error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/call-generic-method-pass.rs:20:25 | LL | const fn equals_self<T: ~const PartialEq>(t: &T) -> bool { - | ^^^^^^ + | ^^^^^^ can't be applied to `PartialEq` + | +note: `PartialEq` can't be used with `~const` because it isn't annotated with `#[const_trait]` + --> $SRC_DIR/core/src/cmp.rs:LL:COL error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/call-generic-method-pass.rs:20:25 | LL | const fn equals_self<T: ~const PartialEq>(t: &T) -> bool { - | ^^^^^^ + | ^^^^^^ can't be applied to `PartialEq` | +note: `PartialEq` can't be used with `~const` because it isn't annotated with `#[const_trait]` + --> $SRC_DIR/core/src/cmp.rs:LL:COL = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0015]: cannot call non-const operator in constant functions diff --git a/tests/ui/traits/const-traits/const-bounds-non-const-trait.stderr b/tests/ui/traits/const-traits/const-bounds-non-const-trait.stderr index 2436c97ccf2..f97d3a9181e 100644 --- a/tests/ui/traits/const-traits/const-bounds-non-const-trait.stderr +++ b/tests/ui/traits/const-traits/const-bounds-non-const-trait.stderr @@ -2,21 +2,35 @@ error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/const-bounds-non-const-trait.rs:6:21 | LL | const fn perform<T: ~const NonConst>() {} - | ^^^^^^ + | ^^^^^^ can't be applied to `NonConst` + | +help: mark `NonConst` as `#[const_trait]` to allow it to have `const` implementations + | +LL | #[const_trait] trait NonConst {} + | ++++++++++++++ error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/const-bounds-non-const-trait.rs:6:21 | LL | const fn perform<T: ~const NonConst>() {} - | ^^^^^^ + | ^^^^^^ can't be applied to `NonConst` | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: mark `NonConst` as `#[const_trait]` to allow it to have `const` implementations + | +LL | #[const_trait] trait NonConst {} + | ++++++++++++++ error: `const` can only be applied to `#[const_trait]` traits --> $DIR/const-bounds-non-const-trait.rs:10:15 | LL | fn operate<T: const NonConst>() {} - | ^^^^^ + | ^^^^^ can't be applied to `NonConst` + | +help: mark `NonConst` as `#[const_trait]` to allow it to have `const` implementations + | +LL | #[const_trait] trait NonConst {} + | ++++++++++++++ error: aborting due to 3 previous errors diff --git a/tests/ui/traits/const-traits/const-closure-parse-not-item.stderr b/tests/ui/traits/const-traits/const-closure-parse-not-item.stderr index 0970cd5225f..57afa2257b7 100644 --- a/tests/ui/traits/const-traits/const-closure-parse-not-item.stderr +++ b/tests/ui/traits/const-traits/const-closure-parse-not-item.stderr @@ -2,22 +2,29 @@ error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/const-closure-parse-not-item.rs:7:25 | LL | const fn test() -> impl ~const Fn() { - | ^^^^^^ + | ^^^^^^ can't be applied to `Fn` + | +note: `Fn` can't be used with `~const` because it isn't annotated with `#[const_trait]` + --> $SRC_DIR/core/src/ops/function.rs:LL:COL error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/const-closure-parse-not-item.rs:7:25 | LL | const fn test() -> impl ~const Fn() { - | ^^^^^^ + | ^^^^^^ can't be applied to `Fn` | +note: `Fn` can't be used with `~const` because it isn't annotated with `#[const_trait]` + --> $SRC_DIR/core/src/ops/function.rs:LL:COL = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/const-closure-parse-not-item.rs:7:25 | LL | const fn test() -> impl ~const Fn() { - | ^^^^^^ + | ^^^^^^ can't be applied to `Fn` | +note: `Fn` can't be used with `~const` because it isn't annotated with `#[const_trait]` + --> $SRC_DIR/core/src/ops/function.rs:LL:COL = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: aborting due to 3 previous errors diff --git a/tests/ui/traits/const-traits/const-closure-trait-method-fail.stderr b/tests/ui/traits/const-traits/const-closure-trait-method-fail.stderr index a76dc3e82af..2a97846ccb4 100644 --- a/tests/ui/traits/const-traits/const-closure-trait-method-fail.stderr +++ b/tests/ui/traits/const-traits/const-closure-trait-method-fail.stderr @@ -2,14 +2,19 @@ error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/const-closure-trait-method-fail.rs:14:32 | LL | const fn need_const_closure<T: ~const FnOnce(()) -> i32>(x: T) -> i32 { - | ^^^^^^ + | ^^^^^^ can't be applied to `FnOnce` + | +note: `FnOnce` can't be used with `~const` because it isn't annotated with `#[const_trait]` + --> $SRC_DIR/core/src/ops/function.rs:LL:COL error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/const-closure-trait-method-fail.rs:14:32 | LL | const fn need_const_closure<T: ~const FnOnce(()) -> i32>(x: T) -> i32 { - | ^^^^^^ + | ^^^^^^ can't be applied to `FnOnce` | +note: `FnOnce` can't be used with `~const` because it isn't annotated with `#[const_trait]` + --> $SRC_DIR/core/src/ops/function.rs:LL:COL = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0015]: cannot call non-const closure in constant functions diff --git a/tests/ui/traits/const-traits/const-closure-trait-method.stderr b/tests/ui/traits/const-traits/const-closure-trait-method.stderr index d37ff3d727c..9c63b7e63a6 100644 --- a/tests/ui/traits/const-traits/const-closure-trait-method.stderr +++ b/tests/ui/traits/const-traits/const-closure-trait-method.stderr @@ -2,14 +2,19 @@ error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/const-closure-trait-method.rs:14:32 | LL | const fn need_const_closure<T: ~const FnOnce(()) -> i32>(x: T) -> i32 { - | ^^^^^^ + | ^^^^^^ can't be applied to `FnOnce` + | +note: `FnOnce` can't be used with `~const` because it isn't annotated with `#[const_trait]` + --> $SRC_DIR/core/src/ops/function.rs:LL:COL error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/const-closure-trait-method.rs:14:32 | LL | const fn need_const_closure<T: ~const FnOnce(()) -> i32>(x: T) -> i32 { - | ^^^^^^ + | ^^^^^^ can't be applied to `FnOnce` | +note: `FnOnce` can't be used with `~const` because it isn't annotated with `#[const_trait]` + --> $SRC_DIR/core/src/ops/function.rs:LL:COL = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0015]: cannot call non-const closure in constant functions diff --git a/tests/ui/traits/const-traits/const-closures.stderr b/tests/ui/traits/const-traits/const-closures.stderr index 8ceaae16d8e..92f3ba20820 100644 --- a/tests/ui/traits/const-traits/const-closures.stderr +++ b/tests/ui/traits/const-traits/const-closures.stderr @@ -2,56 +2,76 @@ error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/const-closures.rs:8:12 | LL | F: ~const FnOnce() -> u8, - | ^^^^^^ + | ^^^^^^ can't be applied to `FnOnce` + | +note: `FnOnce` can't be used with `~const` because it isn't annotated with `#[const_trait]` + --> $SRC_DIR/core/src/ops/function.rs:LL:COL error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/const-closures.rs:9:12 | LL | F: ~const FnMut() -> u8, - | ^^^^^^ + | ^^^^^^ can't be applied to `FnMut` + | +note: `FnMut` can't be used with `~const` because it isn't annotated with `#[const_trait]` + --> $SRC_DIR/core/src/ops/function.rs:LL:COL error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/const-closures.rs:10:12 | LL | F: ~const Fn() -> u8, - | ^^^^^^ + | ^^^^^^ can't be applied to `Fn` + | +note: `Fn` can't be used with `~const` because it isn't annotated with `#[const_trait]` + --> $SRC_DIR/core/src/ops/function.rs:LL:COL error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/const-closures.rs:8:12 | LL | F: ~const FnOnce() -> u8, - | ^^^^^^ + | ^^^^^^ can't be applied to `FnOnce` | +note: `FnOnce` can't be used with `~const` because it isn't annotated with `#[const_trait]` + --> $SRC_DIR/core/src/ops/function.rs:LL:COL = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/const-closures.rs:9:12 | LL | F: ~const FnMut() -> u8, - | ^^^^^^ + | ^^^^^^ can't be applied to `FnMut` | +note: `FnMut` can't be used with `~const` because it isn't annotated with `#[const_trait]` + --> $SRC_DIR/core/src/ops/function.rs:LL:COL = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/const-closures.rs:10:12 | LL | F: ~const Fn() -> u8, - | ^^^^^^ + | ^^^^^^ can't be applied to `Fn` | +note: `Fn` can't be used with `~const` because it isn't annotated with `#[const_trait]` + --> $SRC_DIR/core/src/ops/function.rs:LL:COL = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/const-closures.rs:23:20 | LL | const fn answer<F: ~const Fn() -> u8>(f: &F) -> u8 { - | ^^^^^^ + | ^^^^^^ can't be applied to `Fn` + | +note: `Fn` can't be used with `~const` because it isn't annotated with `#[const_trait]` + --> $SRC_DIR/core/src/ops/function.rs:LL:COL error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/const-closures.rs:23:20 | LL | const fn answer<F: ~const Fn() -> u8>(f: &F) -> u8 { - | ^^^^^^ + | ^^^^^^ can't be applied to `Fn` | +note: `Fn` can't be used with `~const` because it isn't annotated with `#[const_trait]` + --> $SRC_DIR/core/src/ops/function.rs:LL:COL = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0015]: cannot call non-const closure in constant functions diff --git a/tests/ui/traits/const-traits/const-impl-requires-const-trait.stderr b/tests/ui/traits/const-traits/const-impl-requires-const-trait.stderr index bcaae381949..c728eda069e 100644 --- a/tests/ui/traits/const-traits/const-impl-requires-const-trait.stderr +++ b/tests/ui/traits/const-traits/const-impl-requires-const-trait.stderr @@ -1,14 +1,15 @@ error: const `impl` for trait `A` which is not marked with `#[const_trait]` --> $DIR/const-impl-requires-const-trait.rs:6:12 | -LL | pub trait A {} - | - help: mark `A` as const: `#[const_trait]` -LL | LL | impl const A for () {} - | ^ + | ^ this trait is not `const` | = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` = note: adding a non-const method body in the future would be a breaking change +help: mark `A` as `#[const_trait]` to allow it to have `const` implementations + | +LL | #[const_trait] pub trait A {} + | ++++++++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/traits/const-traits/const_derives/derive-const-gate.stderr b/tests/ui/traits/const-traits/const_derives/derive-const-gate.stderr index 95f6f32f21d..fae871a4c85 100644 --- a/tests/ui/traits/const-traits/const_derives/derive-const-gate.stderr +++ b/tests/ui/traits/const-traits/const_derives/derive-const-gate.stderr @@ -11,7 +11,7 @@ error: const `impl` for trait `Default` which is not marked with `#[const_trait] --> $DIR/derive-const-gate.rs:1:16 | LL | #[derive_const(Default)] - | ^^^^^^^ + | ^^^^^^^ this trait is not `const` | = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` = note: adding a non-const method body in the future would be a breaking change diff --git a/tests/ui/traits/const-traits/const_derives/derive-const-non-const-type.stderr b/tests/ui/traits/const-traits/const_derives/derive-const-non-const-type.stderr index 9492000a563..8a6401afcf1 100644 --- a/tests/ui/traits/const-traits/const_derives/derive-const-non-const-type.stderr +++ b/tests/ui/traits/const-traits/const_derives/derive-const-non-const-type.stderr @@ -2,7 +2,7 @@ error: const `impl` for trait `Default` which is not marked with `#[const_trait] --> $DIR/derive-const-non-const-type.rs:10:16 | LL | #[derive_const(Default)] - | ^^^^^^^ + | ^^^^^^^ this trait is not `const` | = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` = note: adding a non-const method body in the future would be a breaking change diff --git a/tests/ui/traits/const-traits/const_derives/derive-const-use.stderr b/tests/ui/traits/const-traits/const_derives/derive-const-use.stderr index 6f4fc90f636..3b06f4d801a 100644 --- a/tests/ui/traits/const-traits/const_derives/derive-const-use.stderr +++ b/tests/ui/traits/const-traits/const_derives/derive-const-use.stderr @@ -14,7 +14,7 @@ error: const `impl` for trait `Default` which is not marked with `#[const_trait] --> $DIR/derive-const-use.rs:7:12 | LL | impl const Default for A { - | ^^^^^^^ + | ^^^^^^^ this trait is not `const` | = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` = note: adding a non-const method body in the future would be a breaking change @@ -23,7 +23,7 @@ error: const `impl` for trait `Default` which is not marked with `#[const_trait] --> $DIR/derive-const-use.rs:15:16 | LL | #[derive_const(Default, PartialEq)] - | ^^^^^^^ + | ^^^^^^^ this trait is not `const` | = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` = note: adding a non-const method body in the future would be a breaking change @@ -33,7 +33,7 @@ error: const `impl` for trait `PartialEq` which is not marked with `#[const_trai --> $DIR/derive-const-use.rs:11:12 | LL | impl const PartialEq for A { - | ^^^^^^^^^ + | ^^^^^^^^^ this trait is not `const` | = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` = note: adding a non-const method body in the future would be a breaking change @@ -42,7 +42,7 @@ error: const `impl` for trait `PartialEq` which is not marked with `#[const_trai --> $DIR/derive-const-use.rs:15:25 | LL | #[derive_const(Default, PartialEq)] - | ^^^^^^^^^ + | ^^^^^^^^^ this trait is not `const` | = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` = note: adding a non-const method body in the future would be a breaking change diff --git a/tests/ui/traits/const-traits/const_derives/derive-const-with-params.stderr b/tests/ui/traits/const-traits/const_derives/derive-const-with-params.stderr index 21cf64f89ea..6b1405712ef 100644 --- a/tests/ui/traits/const-traits/const_derives/derive-const-with-params.stderr +++ b/tests/ui/traits/const-traits/const_derives/derive-const-with-params.stderr @@ -2,13 +2,16 @@ error: const `impl` for trait `PartialEq` which is not marked with `#[const_trai --> $DIR/derive-const-with-params.rs:7:16 | LL | #[derive_const(PartialEq)] - | ^^^^^^^^^ + | ^^^^^^^^^ this trait is not `const` | = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` = note: adding a non-const method body in the future would be a breaking change = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) error: `~const` can only be applied to `#[const_trait]` traits + | +note: `PartialEq` can't be used with `~const` because it isn't annotated with `#[const_trait]` + --> $SRC_DIR/core/src/cmp.rs:LL:COL error[E0015]: cannot call non-const operator in constant functions --> $DIR/derive-const-with-params.rs:8:23 diff --git a/tests/ui/traits/const-traits/dont-ice-on-const-pred-for-bounds.rs b/tests/ui/traits/const-traits/dont-ice-on-const-pred-for-bounds.rs new file mode 100644 index 00000000000..2295c2c3857 --- /dev/null +++ b/tests/ui/traits/const-traits/dont-ice-on-const-pred-for-bounds.rs @@ -0,0 +1,22 @@ +// Regression test for <https://github.com/rust-lang/rust/issues/133526>. + +// Ensures we don't ICE when we encounter a `HostEffectPredicate` when computing +// the "item super predicates" for `Assoc`. + +//@ compile-flags: -Znext-solver +//@ check-pass + +#![feature(const_trait_impl)] + +#[const_trait] +trait Trait { + type Assoc: const Trait; +} + +const fn needs_trait<T: ~const Trait>() {} + +fn test<T: Trait>() { + const { needs_trait::<T::Assoc>() }; +} + +fn main() {} diff --git a/tests/ui/traits/const-traits/effects/ice-112822-expected-type-for-param.stderr b/tests/ui/traits/const-traits/effects/ice-112822-expected-type-for-param.stderr index 879d966b1f9..280f8807f5f 100644 --- a/tests/ui/traits/const-traits/effects/ice-112822-expected-type-for-param.stderr +++ b/tests/ui/traits/const-traits/effects/ice-112822-expected-type-for-param.stderr @@ -12,22 +12,29 @@ error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/ice-112822-expected-type-for-param.rs:3:25 | LL | const fn test() -> impl ~const Fn() { - | ^^^^^^ + | ^^^^^^ can't be applied to `Fn` + | +note: `Fn` can't be used with `~const` because it isn't annotated with `#[const_trait]` + --> $SRC_DIR/core/src/ops/function.rs:LL:COL error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/ice-112822-expected-type-for-param.rs:3:25 | LL | const fn test() -> impl ~const Fn() { - | ^^^^^^ + | ^^^^^^ can't be applied to `Fn` | +note: `Fn` can't be used with `~const` because it isn't annotated with `#[const_trait]` + --> $SRC_DIR/core/src/ops/function.rs:LL:COL = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/ice-112822-expected-type-for-param.rs:3:25 | LL | const fn test() -> impl ~const Fn() { - | ^^^^^^ + | ^^^^^^ can't be applied to `Fn` | +note: `Fn` can't be used with `~const` because it isn't annotated with `#[const_trait]` + --> $SRC_DIR/core/src/ops/function.rs:LL:COL = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0015]: cannot call non-const operator in constant functions diff --git a/tests/ui/traits/const-traits/effects/spec-effectvar-ice.stderr b/tests/ui/traits/const-traits/effects/spec-effectvar-ice.stderr index 5659102c5e5..474d96698d5 100644 --- a/tests/ui/traits/const-traits/effects/spec-effectvar-ice.stderr +++ b/tests/ui/traits/const-traits/effects/spec-effectvar-ice.stderr @@ -1,32 +1,39 @@ error: const `impl` for trait `Foo` which is not marked with `#[const_trait]` --> $DIR/spec-effectvar-ice.rs:10:15 | -LL | trait Foo {} - | - help: mark `Foo` as const: `#[const_trait]` -LL | LL | impl<T> const Foo for T {} - | ^^^ + | ^^^ this trait is not `const` | = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` = note: adding a non-const method body in the future would be a breaking change +help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations + | +LL | #[const_trait] trait Foo {} + | ++++++++++++++ error: const `impl` for trait `Foo` which is not marked with `#[const_trait]` --> $DIR/spec-effectvar-ice.rs:13:15 | -LL | trait Foo {} - | - help: mark `Foo` as const: `#[const_trait]` -... LL | impl<T> const Foo for T where T: const Specialize {} - | ^^^ + | ^^^ this trait is not `const` | = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` = note: adding a non-const method body in the future would be a breaking change +help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations + | +LL | #[const_trait] trait Foo {} + | ++++++++++++++ error: `const` can only be applied to `#[const_trait]` traits --> $DIR/spec-effectvar-ice.rs:13:34 | LL | impl<T> const Foo for T where T: const Specialize {} - | ^^^^^ + | ^^^^^ can't be applied to `Specialize` + | +help: mark `Specialize` as `#[const_trait]` to allow it to have `const` implementations + | +LL | #[const_trait] trait Specialize {} + | ++++++++++++++ error: specialization impl does not specialize any associated items --> $DIR/spec-effectvar-ice.rs:13:1 diff --git a/tests/ui/traits/const-traits/ice-119717-constant-lifetime.stderr b/tests/ui/traits/const-traits/ice-119717-constant-lifetime.stderr index 9e22422ad3b..5af263de28c 100644 --- a/tests/ui/traits/const-traits/ice-119717-constant-lifetime.stderr +++ b/tests/ui/traits/const-traits/ice-119717-constant-lifetime.stderr @@ -2,7 +2,7 @@ error: const `impl` for trait `FromResidual` which is not marked with `#[const_t --> $DIR/ice-119717-constant-lifetime.rs:6:15 | LL | impl<T> const FromResidual for T { - | ^^^^^^^^^^^^ + | ^^^^^^^^^^^^ this trait is not `const` | = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` = note: adding a non-const method body in the future would be a breaking change diff --git a/tests/ui/traits/const-traits/ice-123664-unexpected-bound-var.stderr b/tests/ui/traits/const-traits/ice-123664-unexpected-bound-var.stderr index 1178c90fce5..821b257af88 100644 --- a/tests/ui/traits/const-traits/ice-123664-unexpected-bound-var.stderr +++ b/tests/ui/traits/const-traits/ice-123664-unexpected-bound-var.stderr @@ -2,14 +2,19 @@ error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/ice-123664-unexpected-bound-var.rs:4:27 | LL | const fn with_positive<F: ~const Fn()>() {} - | ^^^^^^ + | ^^^^^^ can't be applied to `Fn` + | +note: `Fn` can't be used with `~const` because it isn't annotated with `#[const_trait]` + --> $SRC_DIR/core/src/ops/function.rs:LL:COL error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/ice-123664-unexpected-bound-var.rs:4:27 | LL | const fn with_positive<F: ~const Fn()>() {} - | ^^^^^^ + | ^^^^^^ can't be applied to `Fn` | +note: `Fn` can't be used with `~const` because it isn't annotated with `#[const_trait]` + --> $SRC_DIR/core/src/ops/function.rs:LL:COL = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: aborting due to 2 previous errors diff --git a/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.stderr b/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.stderr index 9bd493e5fdb..41f99c2d375 100644 --- a/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.stderr +++ b/tests/ui/traits/const-traits/ice-126148-failed-to-normalize.stderr @@ -2,7 +2,7 @@ error: const `impl` for trait `FromResidual` which is not marked with `#[const_t --> $DIR/ice-126148-failed-to-normalize.rs:8:12 | LL | impl const FromResidual<Error> for TryMe {} - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ this trait is not `const` | = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` = note: adding a non-const method body in the future would be a breaking change @@ -19,7 +19,7 @@ error: const `impl` for trait `Try` which is not marked with `#[const_trait]` --> $DIR/ice-126148-failed-to-normalize.rs:12:12 | LL | impl const Try for TryMe { - | ^^^ + | ^^^ this trait is not `const` | = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` = note: adding a non-const method body in the future would be a breaking change diff --git a/tests/ui/traits/const-traits/non-const-op-in-closure-in-const.stderr b/tests/ui/traits/const-traits/non-const-op-in-closure-in-const.stderr index 837effb7ca4..4ddb1e8c5a9 100644 --- a/tests/ui/traits/const-traits/non-const-op-in-closure-in-const.stderr +++ b/tests/ui/traits/const-traits/non-const-op-in-closure-in-const.stderr @@ -2,14 +2,19 @@ error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/non-const-op-in-closure-in-const.rs:10:44 | LL | impl<A, B> const Convert<B> for A where B: ~const From<A> { - | ^^^^^^ + | ^^^^^^ can't be applied to `From` + | +note: `From` can't be used with `~const` because it isn't annotated with `#[const_trait]` + --> $SRC_DIR/core/src/convert/mod.rs:LL:COL error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/non-const-op-in-closure-in-const.rs:10:44 | LL | impl<A, B> const Convert<B> for A where B: ~const From<A> { - | ^^^^^^ + | ^^^^^^ can't be applied to `From` | +note: `From` can't be used with `~const` because it isn't annotated with `#[const_trait]` + --> $SRC_DIR/core/src/convert/mod.rs:LL:COL = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0015]: cannot call non-const fn `<B as From<A>>::from` in constant functions diff --git a/tests/ui/traits/const-traits/super-traits-fail-2.nn.stderr b/tests/ui/traits/const-traits/super-traits-fail-2.nn.stderr index e7f54b4c5bd..51b88cf8702 100644 --- a/tests/ui/traits/const-traits/super-traits-fail-2.nn.stderr +++ b/tests/ui/traits/const-traits/super-traits-fail-2.nn.stderr @@ -14,23 +14,36 @@ error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/super-traits-fail-2.rs:11:12 | LL | trait Bar: ~const Foo {} - | ^^^^^^ + | ^^^^^^ can't be applied to `Foo` + | +help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations + | +LL | #[const_trait] trait Foo { + | ++++++++++++++ error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/super-traits-fail-2.rs:11:12 | LL | trait Bar: ~const Foo {} - | ^^^^^^ + | ^^^^^^ can't be applied to `Foo` | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations + | +LL | #[const_trait] trait Foo { + | ++++++++++++++ error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/super-traits-fail-2.rs:11:12 | LL | trait Bar: ~const Foo {} - | ^^^^^^ + | ^^^^^^ can't be applied to `Foo` | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations + | +LL | #[const_trait] trait Foo { + | ++++++++++++++ error[E0015]: cannot call non-const fn `<T as Foo>::a` in constant functions --> $DIR/super-traits-fail-2.rs:20:7 diff --git a/tests/ui/traits/const-traits/super-traits-fail-2.ny.stderr b/tests/ui/traits/const-traits/super-traits-fail-2.ny.stderr index a09fe81f716..38fb6f05412 100644 --- a/tests/ui/traits/const-traits/super-traits-fail-2.ny.stderr +++ b/tests/ui/traits/const-traits/super-traits-fail-2.ny.stderr @@ -2,39 +2,60 @@ error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/super-traits-fail-2.rs:11:12 | LL | trait Bar: ~const Foo {} - | ^^^^^^ + | ^^^^^^ can't be applied to `Foo` + | +help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations + | +LL | #[const_trait] trait Foo { + | ++++++++++++++ error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/super-traits-fail-2.rs:11:12 | LL | trait Bar: ~const Foo {} - | ^^^^^^ + | ^^^^^^ can't be applied to `Foo` | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations + | +LL | #[const_trait] trait Foo { + | ++++++++++++++ error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/super-traits-fail-2.rs:11:12 | LL | trait Bar: ~const Foo {} - | ^^^^^^ + | ^^^^^^ can't be applied to `Foo` | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations + | +LL | #[const_trait] trait Foo { + | ++++++++++++++ error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/super-traits-fail-2.rs:11:12 | LL | trait Bar: ~const Foo {} - | ^^^^^^ + | ^^^^^^ can't be applied to `Foo` | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations + | +LL | #[const_trait] trait Foo { + | ++++++++++++++ error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/super-traits-fail-2.rs:11:12 | LL | trait Bar: ~const Foo {} - | ^^^^^^ + | ^^^^^^ can't be applied to `Foo` | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations + | +LL | #[const_trait] trait Foo { + | ++++++++++++++ error[E0015]: cannot call non-const fn `<T as Foo>::a` in constant functions --> $DIR/super-traits-fail-2.rs:20:7 diff --git a/tests/ui/traits/const-traits/super-traits-fail-3.nnn.stderr b/tests/ui/traits/const-traits/super-traits-fail-3.nnn.stderr new file mode 100644 index 00000000000..fd802fde5bd --- /dev/null +++ b/tests/ui/traits/const-traits/super-traits-fail-3.nnn.stderr @@ -0,0 +1,102 @@ +error: `~const` is not allowed here + --> $DIR/super-traits-fail-3.rs:23:12 + | +LL | trait Bar: ~const Foo {} + | ^^^^^^ + | +note: this trait is not a `#[const_trait]`, so it cannot have `~const` trait bounds + --> $DIR/super-traits-fail-3.rs:23:1 + | +LL | trait Bar: ~const Foo {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0658]: const trait impls are experimental + --> $DIR/super-traits-fail-3.rs:23:12 + | +LL | trait Bar: ~const Foo {} + | ^^^^^^ + | + = note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information + = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: const trait impls are experimental + --> $DIR/super-traits-fail-3.rs:32:17 + | +LL | const fn foo<T: ~const Bar>(x: &T) { + | ^^^^^^ + | + = note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information + = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/super-traits-fail-3.rs:23:12 + | +LL | trait Bar: ~const Foo {} + | ^^^^^^ can't be applied to `Foo` + | +help: enable `#![feature(const_trait_impl)]` in your crate and mark `Foo` as `#[const_trait]` to allow it to have `const` implementations + | +LL | #[const_trait] trait Foo { + | ++++++++++++++ + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/super-traits-fail-3.rs:23:12 + | +LL | trait Bar: ~const Foo {} + | ^^^^^^ can't be applied to `Foo` + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: enable `#![feature(const_trait_impl)]` in your crate and mark `Foo` as `#[const_trait]` to allow it to have `const` implementations + | +LL | #[const_trait] trait Foo { + | ++++++++++++++ + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/super-traits-fail-3.rs:23:12 + | +LL | trait Bar: ~const Foo {} + | ^^^^^^ can't be applied to `Foo` + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: enable `#![feature(const_trait_impl)]` in your crate and mark `Foo` as `#[const_trait]` to allow it to have `const` implementations + | +LL | #[const_trait] trait Foo { + | ++++++++++++++ + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/super-traits-fail-3.rs:32:17 + | +LL | const fn foo<T: ~const Bar>(x: &T) { + | ^^^^^^ can't be applied to `Bar` + | +help: enable `#![feature(const_trait_impl)]` in your crate and mark `Bar` as `#[const_trait]` to allow it to have `const` implementations + | +LL | #[const_trait] trait Bar: ~const Foo {} + | ++++++++++++++ + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/super-traits-fail-3.rs:32:17 + | +LL | const fn foo<T: ~const Bar>(x: &T) { + | ^^^^^^ can't be applied to `Bar` + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: enable `#![feature(const_trait_impl)]` in your crate and mark `Bar` as `#[const_trait]` to allow it to have `const` implementations + | +LL | #[const_trait] trait Bar: ~const Foo {} + | ++++++++++++++ + +error[E0015]: cannot call non-const fn `<T as Foo>::a` in constant functions + --> $DIR/super-traits-fail-3.rs:36:7 + | +LL | x.a(); + | ^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + +error: aborting due to 9 previous errors + +Some errors have detailed explanations: E0015, E0658. +For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/traits/const-traits/super-traits-fail-3.nny.stderr b/tests/ui/traits/const-traits/super-traits-fail-3.nny.stderr new file mode 100644 index 00000000000..fd802fde5bd --- /dev/null +++ b/tests/ui/traits/const-traits/super-traits-fail-3.nny.stderr @@ -0,0 +1,102 @@ +error: `~const` is not allowed here + --> $DIR/super-traits-fail-3.rs:23:12 + | +LL | trait Bar: ~const Foo {} + | ^^^^^^ + | +note: this trait is not a `#[const_trait]`, so it cannot have `~const` trait bounds + --> $DIR/super-traits-fail-3.rs:23:1 + | +LL | trait Bar: ~const Foo {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0658]: const trait impls are experimental + --> $DIR/super-traits-fail-3.rs:23:12 + | +LL | trait Bar: ~const Foo {} + | ^^^^^^ + | + = note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information + = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: const trait impls are experimental + --> $DIR/super-traits-fail-3.rs:32:17 + | +LL | const fn foo<T: ~const Bar>(x: &T) { + | ^^^^^^ + | + = note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information + = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/super-traits-fail-3.rs:23:12 + | +LL | trait Bar: ~const Foo {} + | ^^^^^^ can't be applied to `Foo` + | +help: enable `#![feature(const_trait_impl)]` in your crate and mark `Foo` as `#[const_trait]` to allow it to have `const` implementations + | +LL | #[const_trait] trait Foo { + | ++++++++++++++ + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/super-traits-fail-3.rs:23:12 + | +LL | trait Bar: ~const Foo {} + | ^^^^^^ can't be applied to `Foo` + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: enable `#![feature(const_trait_impl)]` in your crate and mark `Foo` as `#[const_trait]` to allow it to have `const` implementations + | +LL | #[const_trait] trait Foo { + | ++++++++++++++ + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/super-traits-fail-3.rs:23:12 + | +LL | trait Bar: ~const Foo {} + | ^^^^^^ can't be applied to `Foo` + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: enable `#![feature(const_trait_impl)]` in your crate and mark `Foo` as `#[const_trait]` to allow it to have `const` implementations + | +LL | #[const_trait] trait Foo { + | ++++++++++++++ + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/super-traits-fail-3.rs:32:17 + | +LL | const fn foo<T: ~const Bar>(x: &T) { + | ^^^^^^ can't be applied to `Bar` + | +help: enable `#![feature(const_trait_impl)]` in your crate and mark `Bar` as `#[const_trait]` to allow it to have `const` implementations + | +LL | #[const_trait] trait Bar: ~const Foo {} + | ++++++++++++++ + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/super-traits-fail-3.rs:32:17 + | +LL | const fn foo<T: ~const Bar>(x: &T) { + | ^^^^^^ can't be applied to `Bar` + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: enable `#![feature(const_trait_impl)]` in your crate and mark `Bar` as `#[const_trait]` to allow it to have `const` implementations + | +LL | #[const_trait] trait Bar: ~const Foo {} + | ++++++++++++++ + +error[E0015]: cannot call non-const fn `<T as Foo>::a` in constant functions + --> $DIR/super-traits-fail-3.rs:36:7 + | +LL | x.a(); + | ^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + +error: aborting due to 9 previous errors + +Some errors have detailed explanations: E0015, E0658. +For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/traits/const-traits/super-traits-fail-3.ny.stderr b/tests/ui/traits/const-traits/super-traits-fail-3.ny.stderr deleted file mode 100644 index a880c2a2206..00000000000 --- a/tests/ui/traits/const-traits/super-traits-fail-3.ny.stderr +++ /dev/null @@ -1,49 +0,0 @@ -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/super-traits-fail-3.rs:13:12 - | -LL | trait Bar: ~const Foo {} - | ^^^^^^ - -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/super-traits-fail-3.rs:13:12 - | -LL | trait Bar: ~const Foo {} - | ^^^^^^ - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/super-traits-fail-3.rs:13:12 - | -LL | trait Bar: ~const Foo {} - | ^^^^^^ - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/super-traits-fail-3.rs:13:12 - | -LL | trait Bar: ~const Foo {} - | ^^^^^^ - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/super-traits-fail-3.rs:13:12 - | -LL | trait Bar: ~const Foo {} - | ^^^^^^ - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error[E0015]: cannot call non-const fn `<T as Foo>::a` in constant functions - --> $DIR/super-traits-fail-3.rs:24:7 - | -LL | x.a(); - | ^^^ - | - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants - -error: aborting due to 6 previous errors - -For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/traits/const-traits/super-traits-fail-3.nyn.stderr b/tests/ui/traits/const-traits/super-traits-fail-3.nyn.stderr new file mode 100644 index 00000000000..8abda1c8f8a --- /dev/null +++ b/tests/ui/traits/const-traits/super-traits-fail-3.nyn.stderr @@ -0,0 +1,53 @@ +error[E0658]: const trait impls are experimental + --> $DIR/super-traits-fail-3.rs:23:12 + | +LL | trait Bar: ~const Foo {} + | ^^^^^^ + | + = note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information + = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: const trait impls are experimental + --> $DIR/super-traits-fail-3.rs:32:17 + | +LL | const fn foo<T: ~const Bar>(x: &T) { + | ^^^^^^ + | + = note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information + = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `const_trait` is a temporary placeholder for marking a trait that is suitable for `const` `impls` and all default bodies as `const`, which may be removed or renamed in the future. + --> $DIR/super-traits-fail-3.rs:15:37 + | +LL | #[cfg_attr(any(yyy, yyn, nyy, nyn), const_trait)] + | ^^^^^^^^^^^ + | + = note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information + = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `const_trait` is a temporary placeholder for marking a trait that is suitable for `const` `impls` and all default bodies as `const`, which may be removed or renamed in the future. + --> $DIR/super-traits-fail-3.rs:21:37 + | +LL | #[cfg_attr(any(yyy, yny, nyy, nyn), const_trait)] + | ^^^^^^^^^^^ + | + = note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information + = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: cannot call conditionally-const method `<T as Foo>::a` in constant functions + --> $DIR/super-traits-fail-3.rs:36:5 + | +LL | x.a(); + | ^^^^^ + | + = note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information + = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/traits/const-traits/super-traits-fail-3.nyy.stderr b/tests/ui/traits/const-traits/super-traits-fail-3.nyy.stderr new file mode 100644 index 00000000000..8abda1c8f8a --- /dev/null +++ b/tests/ui/traits/const-traits/super-traits-fail-3.nyy.stderr @@ -0,0 +1,53 @@ +error[E0658]: const trait impls are experimental + --> $DIR/super-traits-fail-3.rs:23:12 + | +LL | trait Bar: ~const Foo {} + | ^^^^^^ + | + = note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information + = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: const trait impls are experimental + --> $DIR/super-traits-fail-3.rs:32:17 + | +LL | const fn foo<T: ~const Bar>(x: &T) { + | ^^^^^^ + | + = note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information + = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `const_trait` is a temporary placeholder for marking a trait that is suitable for `const` `impls` and all default bodies as `const`, which may be removed or renamed in the future. + --> $DIR/super-traits-fail-3.rs:15:37 + | +LL | #[cfg_attr(any(yyy, yyn, nyy, nyn), const_trait)] + | ^^^^^^^^^^^ + | + = note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information + = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: `const_trait` is a temporary placeholder for marking a trait that is suitable for `const` `impls` and all default bodies as `const`, which may be removed or renamed in the future. + --> $DIR/super-traits-fail-3.rs:21:37 + | +LL | #[cfg_attr(any(yyy, yny, nyy, nyn), const_trait)] + | ^^^^^^^^^^^ + | + = note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information + = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: cannot call conditionally-const method `<T as Foo>::a` in constant functions + --> $DIR/super-traits-fail-3.rs:36:5 + | +LL | x.a(); + | ^^^^^ + | + = note: see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information + = help: add `#![feature(const_trait_impl)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/traits/const-traits/super-traits-fail-3.rs b/tests/ui/traits/const-traits/super-traits-fail-3.rs index bd95ae8d96a..aa27554e7f8 100644 --- a/tests/ui/traits/const-traits/super-traits-fail-3.rs +++ b/tests/ui/traits/const-traits/super-traits-fail-3.rs @@ -1,29 +1,42 @@ //@ compile-flags: -Znext-solver -#![feature(const_trait_impl)] +#![cfg_attr(any(yyy, yyn, yny, ynn), feature(const_trait_impl))] -//@ revisions: yy yn ny nn -//@[yy] check-pass +//@ revisions: yyy yyn yny ynn nyy nyn nny nnn +//@[yyy] check-pass +/// yyy: feature enabled, Foo is const, Bar is const +/// yyn: feature enabled, Foo is const, Bar is not const +/// yny: feature enabled, Foo is not const, Bar is const +/// ynn: feature enabled, Foo is not const, Bar is not const +/// nyy: feature not enabled, Foo is const, Bar is const +/// nyn: feature not enabled, Foo is const, Bar is not const +/// nny: feature not enabled, Foo is not const, Bar is const +/// nnn: feature not enabled, Foo is not const, Bar is not const -#[cfg_attr(any(yy, yn), const_trait)] +#[cfg_attr(any(yyy, yyn, nyy, nyn), const_trait)] +//[nyy,nyn]~^ ERROR: `const_trait` is a temporary placeholder for marking a trait that is suitable for `const` `impls` and all default bodies as `const`, which may be removed or renamed in the future trait Foo { fn a(&self); } -#[cfg_attr(any(yy, ny), const_trait)] +#[cfg_attr(any(yyy, yny, nyy, nyn), const_trait)] +//[nyy,nyn]~^ ERROR: `const_trait` is a temporary placeholder for marking a trait that is suitable for `const` `impls` and all default bodies as `const`, which may be removed or renamed in the future trait Bar: ~const Foo {} -//[ny,nn]~^ ERROR: `~const` can only be applied to `#[const_trait]` -//[ny,nn]~| ERROR: `~const` can only be applied to `#[const_trait]` -//[ny,nn]~| ERROR: `~const` can only be applied to `#[const_trait]` -//[ny]~| ERROR: `~const` can only be applied to `#[const_trait]` -//[ny]~| ERROR: `~const` can only be applied to `#[const_trait]` -//[yn,nn]~^^^^^^ ERROR: `~const` is not allowed here +//[yny,ynn,nny,nnn]~^ ERROR: `~const` can only be applied to `#[const_trait]` +//[yny,ynn,nny,nnn]~| ERROR: `~const` can only be applied to `#[const_trait]` +//[yny,ynn,nny,nnn]~| ERROR: `~const` can only be applied to `#[const_trait]` +//[yny]~^^^^ ERROR: `~const` can only be applied to `#[const_trait]` +//[yny]~| ERROR: `~const` can only be applied to `#[const_trait]` +//[yyn,ynn,nny,nnn]~^^^^^^ ERROR: `~const` is not allowed here +//[nyy,nyn,nny,nnn]~^^^^^^^ ERROR: const trait impls are experimental const fn foo<T: ~const Bar>(x: &T) { - //[yn,nn]~^ ERROR: `~const` can only be applied to `#[const_trait]` - //[yn,nn]~| ERROR: `~const` can only be applied to `#[const_trait]` + //[yyn,ynn,nny,nnn]~^ ERROR: `~const` can only be applied to `#[const_trait]` + //[yyn,ynn,nny,nnn]~| ERROR: `~const` can only be applied to `#[const_trait]` + //[nyy,nyn,nny,nnn]~^^^ ERROR: const trait impls are experimental x.a(); - //[yn]~^ ERROR: the trait bound `T: ~const Foo` is not satisfied - //[nn,ny]~^^ ERROR: cannot call non-const fn `<T as Foo>::a` in constant functions + //[yyn]~^ ERROR: the trait bound `T: ~const Foo` is not satisfied + //[ynn,yny,nny,nnn]~^^ ERROR: cannot call non-const fn `<T as Foo>::a` in constant functions + //[nyy,nyn]~^^^ ERROR: cannot call conditionally-const method `<T as Foo>::a` in constant functions } fn main() {} diff --git a/tests/ui/traits/const-traits/super-traits-fail-3.nn.stderr b/tests/ui/traits/const-traits/super-traits-fail-3.ynn.stderr index 599b8c826f7..16424696eeb 100644 --- a/tests/ui/traits/const-traits/super-traits-fail-3.nn.stderr +++ b/tests/ui/traits/const-traits/super-traits-fail-3.ynn.stderr @@ -1,53 +1,75 @@ error: `~const` is not allowed here - --> $DIR/super-traits-fail-3.rs:13:12 + --> $DIR/super-traits-fail-3.rs:23:12 | LL | trait Bar: ~const Foo {} | ^^^^^^ | note: this trait is not a `#[const_trait]`, so it cannot have `~const` trait bounds - --> $DIR/super-traits-fail-3.rs:13:1 + --> $DIR/super-traits-fail-3.rs:23:1 | LL | trait Bar: ~const Foo {} | ^^^^^^^^^^^^^^^^^^^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/super-traits-fail-3.rs:13:12 + --> $DIR/super-traits-fail-3.rs:23:12 | LL | trait Bar: ~const Foo {} - | ^^^^^^ + | ^^^^^^ can't be applied to `Foo` + | +help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations + | +LL | #[const_trait] trait Foo { + | ++++++++++++++ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/super-traits-fail-3.rs:13:12 + --> $DIR/super-traits-fail-3.rs:23:12 | LL | trait Bar: ~const Foo {} - | ^^^^^^ + | ^^^^^^ can't be applied to `Foo` | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations + | +LL | #[const_trait] trait Foo { + | ++++++++++++++ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/super-traits-fail-3.rs:13:12 + --> $DIR/super-traits-fail-3.rs:23:12 | LL | trait Bar: ~const Foo {} - | ^^^^^^ + | ^^^^^^ can't be applied to `Foo` | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations + | +LL | #[const_trait] trait Foo { + | ++++++++++++++ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/super-traits-fail-3.rs:21:17 + --> $DIR/super-traits-fail-3.rs:32:17 | LL | const fn foo<T: ~const Bar>(x: &T) { - | ^^^^^^ + | ^^^^^^ can't be applied to `Bar` + | +help: mark `Bar` as `#[const_trait]` to allow it to have `const` implementations + | +LL | #[const_trait] trait Bar: ~const Foo {} + | ++++++++++++++ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/super-traits-fail-3.rs:21:17 + --> $DIR/super-traits-fail-3.rs:32:17 | LL | const fn foo<T: ~const Bar>(x: &T) { - | ^^^^^^ + | ^^^^^^ can't be applied to `Bar` | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: mark `Bar` as `#[const_trait]` to allow it to have `const` implementations + | +LL | #[const_trait] trait Bar: ~const Foo {} + | ++++++++++++++ error[E0015]: cannot call non-const fn `<T as Foo>::a` in constant functions - --> $DIR/super-traits-fail-3.rs:24:7 + --> $DIR/super-traits-fail-3.rs:36:7 | LL | x.a(); | ^^^ diff --git a/tests/ui/traits/const-traits/super-traits-fail-3.yny.stderr b/tests/ui/traits/const-traits/super-traits-fail-3.yny.stderr new file mode 100644 index 00000000000..c81544c4bf5 --- /dev/null +++ b/tests/ui/traits/const-traits/super-traits-fail-3.yny.stderr @@ -0,0 +1,70 @@ +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/super-traits-fail-3.rs:23:12 + | +LL | trait Bar: ~const Foo {} + | ^^^^^^ can't be applied to `Foo` + | +help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations + | +LL | #[const_trait] trait Foo { + | ++++++++++++++ + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/super-traits-fail-3.rs:23:12 + | +LL | trait Bar: ~const Foo {} + | ^^^^^^ can't be applied to `Foo` + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations + | +LL | #[const_trait] trait Foo { + | ++++++++++++++ + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/super-traits-fail-3.rs:23:12 + | +LL | trait Bar: ~const Foo {} + | ^^^^^^ can't be applied to `Foo` + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations + | +LL | #[const_trait] trait Foo { + | ++++++++++++++ + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/super-traits-fail-3.rs:23:12 + | +LL | trait Bar: ~const Foo {} + | ^^^^^^ can't be applied to `Foo` + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations + | +LL | #[const_trait] trait Foo { + | ++++++++++++++ + +error: `~const` can only be applied to `#[const_trait]` traits + --> $DIR/super-traits-fail-3.rs:23:12 + | +LL | trait Bar: ~const Foo {} + | ^^^^^^ can't be applied to `Foo` + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: mark `Foo` as `#[const_trait]` to allow it to have `const` implementations + | +LL | #[const_trait] trait Foo { + | ++++++++++++++ + +error[E0015]: cannot call non-const fn `<T as Foo>::a` in constant functions + --> $DIR/super-traits-fail-3.rs:36:7 + | +LL | x.a(); + | ^^^ + | + = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/traits/const-traits/super-traits-fail-3.yn.stderr b/tests/ui/traits/const-traits/super-traits-fail-3.yyn.stderr index ecee348222d..3270611dace 100644 --- a/tests/ui/traits/const-traits/super-traits-fail-3.yn.stderr +++ b/tests/ui/traits/const-traits/super-traits-fail-3.yyn.stderr @@ -1,31 +1,40 @@ error: `~const` is not allowed here - --> $DIR/super-traits-fail-3.rs:13:12 + --> $DIR/super-traits-fail-3.rs:23:12 | LL | trait Bar: ~const Foo {} | ^^^^^^ | note: this trait is not a `#[const_trait]`, so it cannot have `~const` trait bounds - --> $DIR/super-traits-fail-3.rs:13:1 + --> $DIR/super-traits-fail-3.rs:23:1 | LL | trait Bar: ~const Foo {} | ^^^^^^^^^^^^^^^^^^^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/super-traits-fail-3.rs:21:17 + --> $DIR/super-traits-fail-3.rs:32:17 | LL | const fn foo<T: ~const Bar>(x: &T) { - | ^^^^^^ + | ^^^^^^ can't be applied to `Bar` + | +help: mark `Bar` as `#[const_trait]` to allow it to have `const` implementations + | +LL | #[const_trait] trait Bar: ~const Foo {} + | ++++++++++++++ error: `~const` can only be applied to `#[const_trait]` traits - --> $DIR/super-traits-fail-3.rs:21:17 + --> $DIR/super-traits-fail-3.rs:32:17 | LL | const fn foo<T: ~const Bar>(x: &T) { - | ^^^^^^ + | ^^^^^^ can't be applied to `Bar` | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: mark `Bar` as `#[const_trait]` to allow it to have `const` implementations + | +LL | #[const_trait] trait Bar: ~const Foo {} + | ++++++++++++++ error[E0277]: the trait bound `T: ~const Foo` is not satisfied - --> $DIR/super-traits-fail-3.rs:24:7 + --> $DIR/super-traits-fail-3.rs:36:7 | LL | x.a(); | ^ diff --git a/tests/ui/traits/const-traits/trait-default-body-stability.stderr b/tests/ui/traits/const-traits/trait-default-body-stability.stderr index b471cb81c3b..77b81211e81 100644 --- a/tests/ui/traits/const-traits/trait-default-body-stability.stderr +++ b/tests/ui/traits/const-traits/trait-default-body-stability.stderr @@ -2,7 +2,7 @@ error: const `impl` for trait `Try` which is not marked with `#[const_trait]` --> $DIR/trait-default-body-stability.rs:19:12 | LL | impl const Try for T { - | ^^^ + | ^^^ this trait is not `const` | = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` = note: adding a non-const method body in the future would be a breaking change @@ -11,7 +11,7 @@ error: const `impl` for trait `FromResidual` which is not marked with `#[const_t --> $DIR/trait-default-body-stability.rs:34:12 | LL | impl const FromResidual for T { - | ^^^^^^^^^^^^ + | ^^^^^^^^^^^^ this trait is not `const` | = note: marking a trait with `#[const_trait]` ensures all default method bodies are `const` = note: adding a non-const method body in the future would be a breaking change diff --git a/tests/ui/type/type-dependent-def-issue-49241.stderr b/tests/ui/type/type-dependent-def-issue-49241.stderr index 4e55618e5cb..cf372dc5968 100644 --- a/tests/ui/type/type-dependent-def-issue-49241.stderr +++ b/tests/ui/type/type-dependent-def-issue-49241.stderr @@ -9,12 +9,6 @@ help: consider using `let` instead of `const` LL | let l: usize = v.count(); | ~~~ -note: erroneous constant encountered - --> $DIR/type-dependent-def-issue-49241.rs:4:18 - | -LL | let s: [u32; l] = v.into_iter().collect(); - | ^ - error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0435`. diff --git a/tests/ui/unsafe-fields/copy-trait.rs b/tests/ui/unsafe-fields/copy-trait.rs new file mode 100644 index 00000000000..fb09ed02e3f --- /dev/null +++ b/tests/ui/unsafe-fields/copy-trait.rs @@ -0,0 +1,41 @@ +//@ compile-flags: --crate-type=lib + +#![feature(unsafe_fields)] +#![allow(incomplete_features)] +#![deny(missing_copy_implementations)] + +mod good_safe_impl { + enum SafeEnum { + Safe(u8), + } + + impl Copy for SafeEnum {} +} + +mod bad_safe_impl { + enum UnsafeEnum { + Safe(u8), + Unsafe { unsafe field: u8 }, + } + + impl Copy for UnsafeEnum {} + //~^ ERROR the trait `Copy` requires an `unsafe impl` declaration +} + +mod good_unsafe_impl { + enum UnsafeEnum { + Safe(u8), + Unsafe { unsafe field: u8 }, + } + + unsafe impl Copy for UnsafeEnum {} +} + +mod bad_unsafe_impl { + enum SafeEnum { + Safe(u8), + } + + unsafe impl Copy for SafeEnum {} + //~^ ERROR implementing the trait `Copy` is not unsafe +} diff --git a/tests/ui/unsafe-fields/copy-trait.stderr b/tests/ui/unsafe-fields/copy-trait.stderr new file mode 100644 index 00000000000..5952f8c89c1 --- /dev/null +++ b/tests/ui/unsafe-fields/copy-trait.stderr @@ -0,0 +1,28 @@ +error[E0200]: the trait `Copy` requires an `unsafe impl` declaration + --> $DIR/copy-trait.rs:21:5 + | +LL | impl Copy for UnsafeEnum {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the trait `Copy` cannot be safely implemented for `bad_safe_impl::UnsafeEnum` because it has unsafe fields. Review the invariants of those fields before adding an `unsafe impl` +help: add `unsafe` to this trait implementation + | +LL | unsafe impl Copy for UnsafeEnum {} + | ++++++ + +error[E0199]: implementing the trait `Copy` is not unsafe + --> $DIR/copy-trait.rs:39:5 + | +LL | unsafe impl Copy for SafeEnum {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove `unsafe` from this trait implementation + | +LL - unsafe impl Copy for SafeEnum {} +LL + impl Copy for SafeEnum {} + | + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0199, E0200. +For more information about an error, try `rustc --explain E0199`. diff --git a/triagebot.toml b/triagebot.toml index c5dbd538f6c..18bbbad234e 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -983,11 +983,19 @@ cc = ["@Zalathar"] [mentions."src/tools/opt-dist"] cc = ["@kobzol"] +[mentions."tests/ui-fulldeps/lexer/unicode-version.run.stdout"] +message = """If the Unicode version changes are intentional, +it should also be updated in the reference at +https://github.com/rust-lang/reference/blob/HEAD/src/identifiers.md. +""" +cc = ["@ehuss"] + [assign] warn_non_default_branch = true contributing_url = "https://rustc-dev-guide.rust-lang.org/getting-started.html" users_on_vacation = [ "jyn514", + "celinval", ] [assign.adhoc_groups] @@ -1004,9 +1012,10 @@ compiler = [ "@lcnr", "@Nadrieril", "@nnethercote", + "@Noratrieb", "@oli-obk", "@petrochenkov", - "@pnkfelix", + "@SparrowLii", "@wesleywiser", ] libs = [ @@ -1098,7 +1107,6 @@ types = [ ] borrowck = [ "@davidtwco", - "@pnkfelix", "@matthewjasper" ] ast_lowering = [ |
