diff options
638 files changed, 11233 insertions, 6174 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8266c03eaa7..f539b64d8c8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -117,12 +117,12 @@ jobs: with: fetch-depth: 2 - # Free up disk space on Linux and Windows by removing preinstalled components that + # Free up disk space on Linux by removing preinstalled components that # we do not need. We do this to enable some of the less resource # intensive jobs to run on free runners, which however also have # less disk space. - name: free up disk space - run: src/ci/scripts/free-disk-space.sh + run: src/ci/scripts/free-disk-space-linux.sh if: matrix.free_disk # If we don't need to free up disk space then just report how much space we have @@ -223,11 +223,6 @@ jobs: cd src/ci/citool CARGO_INCREMENTAL=0 CARGO_TARGET_DIR=../../../build/citool cargo build - - name: wait for Windows disk cleanup to finish - if: ${{ matrix.free_disk && startsWith(matrix.os, 'windows-') }} - run: | - python3 src/ci/scripts/free-disk-space-windows-wait.py - - name: run the build run: | set +e diff --git a/Cargo.lock b/Cargo.lock index 6f7a309894c..71ae559bd12 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -152,9 +152,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.98" +version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" +checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100" [[package]] name = "ar_archive_writer" @@ -204,7 +204,7 @@ dependencies = [ "rustc-hash 2.1.1", "serde", "serde_derive", - "syn 2.0.104", + "syn 2.0.106", ] [[package]] @@ -266,9 +266,9 @@ dependencies = [ [[package]] name = "bitflags" -version = "2.9.1" +version = "2.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" +checksum = "6a65b545ab31d687cff52899d4890855fec459eb6afe0da6417b8a18da87aa29" [[package]] name = "blake3" @@ -421,7 +421,7 @@ dependencies = [ "serde", "serde-untagged", "serde-value", - "thiserror 2.0.12", + "thiserror 2.0.15", "toml 0.8.23", "unicode-xid", "url", @@ -453,7 +453,7 @@ dependencies = [ "semver", "serde", "serde_json", - "thiserror 2.0.12", + "thiserror 2.0.15", ] [[package]] @@ -518,9 +518,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.43" +version = "4.5.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50fd97c9dc2399518aa331917ac6f274280ec5eb34e555dd291899745c48ec6f" +checksum = "1fc0e74a703892159f5ae7d3aac52c8e6c392f5ae5f359c70b5881d60aaac318" dependencies = [ "clap_builder", "clap_derive", @@ -538,9 +538,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.43" +version = "4.5.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c35b5830294e1fa0462034af85cc95225a4cb07092c088c55bda3147cfcd8f65" +checksum = "b3e7f4214277f3c7aa526a59dd3fbe306a370daee1f8b7b8c987069cd8e888a8" dependencies = [ "anstream", "anstyle", @@ -550,14 +550,14 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.41" +version = "4.5.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef4f52386a59ca4c860f7393bcf8abd8dfd91ecccc0f774635ff68e92eeef491" +checksum = "14cb31bb0a7d536caef2639baa7fad459e15c3144efefa6dbd1c84562c4739f6" dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.106", ] [[package]] @@ -720,7 +720,7 @@ dependencies = [ "nom", "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.106", ] [[package]] @@ -907,9 +907,9 @@ dependencies = [ [[package]] name = "curl" -version = "0.4.48" +version = "0.4.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e2d5c8f48d9c0c23250e52b55e82a6ab4fdba6650c931f5a0a57a43abda812b" +checksum = "79fc3b6dd0b87ba36e565715bf9a2ced221311db47bd18011676f24a6066edbc" dependencies = [ "curl-sys", "libc", @@ -922,9 +922,9 @@ dependencies = [ [[package]] name = "curl-sys" -version = "0.4.82+curl-8.14.1" +version = "0.4.83+curl-8.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4d63638b5ec65f1a4ae945287b3fd035be4554bbaf211901159c9a2a74fb5be" +checksum = "5830daf304027db10c82632a464879d46a3f7c4ba17a31592657ad16c719b483" dependencies = [ "cc", "libc", @@ -937,9 +937,9 @@ dependencies = [ [[package]] name = "cxx" -version = "1.0.166" +version = "1.0.168" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5287274dfdf7e7eaa3d97d460eb2a94922539e6af214bda423f292105011ee2" +checksum = "7aa144b12f11741f0dab5b4182896afad46faa0598b6a061f7b9d17a21837ba7" dependencies = [ "cc", "cxxbridge-cmd", @@ -951,9 +951,9 @@ dependencies = [ [[package]] name = "cxx-build" -version = "1.0.166" +version = "1.0.168" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65f3ce027a744135db10a1ebffa0863dab685aeef48f40a02c201f5e70c667d3" +checksum = "12d3cbb84fb003242941c231b45ca9417e786e66e94baa39584bd99df3a270b6" dependencies = [ "cc", "codespan-reporting", @@ -961,40 +961,40 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn 2.0.104", + "syn 2.0.106", ] [[package]] name = "cxxbridge-cmd" -version = "1.0.166" +version = "1.0.168" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a07dc23f2eea4774297f4c9a17ae4065fecb63127da556e6c9fadb0216d93595" +checksum = "3fa36b7b249d43f67a3f54bd65788e35e7afe64bbc671396387a48b3e8aaea94" dependencies = [ "clap", "codespan-reporting", "indexmap", "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.106", ] [[package]] name = "cxxbridge-flags" -version = "1.0.166" +version = "1.0.168" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7a4dbad6171f763c4066c83dcd27546b6e93c5c5ae2229f9813bda7233f571d" +checksum = "77707c70f6563edc5429618ca34a07241b75ebab35bd01d46697c75d58f8ddfe" [[package]] name = "cxxbridge-macro" -version = "1.0.166" +version = "1.0.168" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9be4b527950fc42db06163705e78e73eedc8fd723708e942afe3572a9a2c366" +checksum = "ede6c0fb7e318f0a11799b86ee29dcf17b9be2960bd379a6c38e1a96a6010fff" dependencies = [ "indexmap", "proc-macro2", "quote", "rustversion", - "syn 2.0.104", + "syn 2.0.106", ] [[package]] @@ -1018,7 +1018,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.104", + "syn 2.0.106", ] [[package]] @@ -1029,7 +1029,7 @@ checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ "darling_core", "quote", - "syn 2.0.104", + "syn 2.0.106", ] [[package]] @@ -1061,7 +1061,7 @@ checksum = "ef941ded77d15ca19b40374869ac6000af1c9f2a4c0f3d4c70926287e6364a8f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.106", ] [[package]] @@ -1082,7 +1082,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.106", ] [[package]] @@ -1092,7 +1092,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" dependencies = [ "derive_builder_core", - "syn 2.0.104", + "syn 2.0.106", ] [[package]] @@ -1104,7 +1104,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.106", ] [[package]] @@ -1194,7 +1194,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.106", ] [[package]] @@ -1379,7 +1379,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "54f0d287c53ffd184d04d8677f590f4ac5379785529e5e08b1c8083acdd5c198" dependencies = [ "memchr", - "thiserror 2.0.12", + "thiserror 2.0.15", ] [[package]] @@ -1539,9 +1539,9 @@ dependencies = [ [[package]] name = "glob" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" [[package]] name = "globset" @@ -1855,7 +1855,7 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.106", ] [[package]] @@ -2044,7 +2044,7 @@ checksum = "03343451ff899767262ec32146f6d559dd759fdadf42ff0e227c7c48f72594b4" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.106", ] [[package]] @@ -2102,7 +2102,7 @@ dependencies = [ "pest_derive", "regex", "serde_json", - "thiserror 2.0.12", + "thiserror 2.0.15", ] [[package]] @@ -2337,7 +2337,7 @@ checksum = "88a9689d8d44bf9964484516275f5cd4c9b59457a6940c1d5d0ecbb94510a36b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.106", ] [[package]] @@ -2643,9 +2643,9 @@ dependencies = [ [[package]] name = "object" -version = "0.37.2" +version = "0.37.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3e3d0a7419f081f4a808147e845310313a39f322d7ae1f996b7f001d6cbed04" +checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" dependencies = [ "crc32fast", "flate2", @@ -2653,7 +2653,7 @@ dependencies = [ "indexmap", "memchr", "ruzstd 0.8.1", - "wasmparser 0.236.0", + "wasmparser 0.236.1", ] [[package]] @@ -2834,7 +2834,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1db05f56d34358a8b1066f67cbb203ee3e7ed2ba674a6263a1d5ec6db2204323" dependencies = [ "memchr", - "thiserror 2.0.12", + "thiserror 2.0.15", "ucd-trie", ] @@ -2858,7 +2858,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.106", ] [[package]] @@ -3007,9 +3007,9 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" [[package]] name = "proc-macro2" -version = "1.0.95" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" dependencies = [ "unicode-ident", ] @@ -3147,9 +3147,9 @@ dependencies = [ [[package]] name = "rayon" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f" dependencies = [ "either", "rayon-core", @@ -3157,9 +3157,9 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.12.1" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" dependencies = [ "crossbeam-deque", "crossbeam-utils", @@ -3193,7 +3193,7 @@ checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" dependencies = [ "getrandom 0.2.16", "libredox", - "thiserror 2.0.12", + "thiserror 2.0.15", ] [[package]] @@ -3279,11 +3279,11 @@ dependencies = [ "build_helper", "gimli 0.32.0", "libc", - "object 0.37.2", + "object 0.37.3", "regex", "serde_json", "similar", - "wasmparser 0.236.0", + "wasmparser 0.236.1", ] [[package]] @@ -3459,7 +3459,6 @@ dependencies = [ "rustc_feature", "rustc_fluent_macro", "rustc_macros", - "rustc_parse", "rustc_session", "rustc_span", "rustc_target", @@ -3481,7 +3480,6 @@ dependencies = [ name = "rustc_attr_parsing" version = "0.0.0" dependencies = [ - "itertools", "rustc_abi", "rustc_ast", "rustc_ast_pretty", @@ -3491,6 +3489,7 @@ dependencies = [ "rustc_hir", "rustc_lexer", "rustc_macros", + "rustc_parse", "rustc_session", "rustc_span", "thin-vec", @@ -3571,7 +3570,7 @@ dependencies = [ "itertools", "libc", "measureme", - "object 0.37.2", + "object 0.37.3", "rustc-demangle", "rustc_abi", "rustc_ast", @@ -3609,7 +3608,7 @@ dependencies = [ "cc", "itertools", "libc", - "object 0.37.2", + "object 0.37.3", "pathdiff", "regex", "rustc_abi", @@ -3798,6 +3797,7 @@ dependencies = [ "annotate-snippets 0.11.5", "derive_setters", "rustc_abi", + "rustc_ast", "rustc_data_structures", "rustc_error_codes", "rustc_error_messages", @@ -3864,7 +3864,7 @@ dependencies = [ "fluent-syntax", "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.106", "unic-langid", ] @@ -4024,7 +4024,7 @@ version = "0.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.106", ] [[package]] @@ -4135,7 +4135,6 @@ dependencies = [ name = "rustc_lint_defs" version = "0.0.0" dependencies = [ - "rustc_abi", "rustc_ast", "rustc_data_structures", "rustc_error_messages", @@ -4170,7 +4169,7 @@ version = "0.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.106", "synstructure", ] @@ -4356,7 +4355,6 @@ dependencies = [ "rustc-literal-escaper", "rustc_ast", "rustc_ast_pretty", - "rustc_attr_parsing", "rustc_data_structures", "rustc_errors", "rustc_feature", @@ -4655,7 +4653,7 @@ name = "rustc_target" version = "0.0.0" dependencies = [ "bitflags", - "object 0.37.2", + "object 0.37.3", "rustc_abi", "rustc_data_structures", "rustc_error_messages", @@ -4793,7 +4791,7 @@ version = "0.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.106", "synstructure", ] @@ -4885,7 +4883,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.104", + "syn 2.0.106", ] [[package]] @@ -5022,9 +5020,9 @@ dependencies = [ [[package]] name = "serde-untagged" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "299d9c19d7d466db4ab10addd5703e4c615dec2a5a16dbbafe191045e87ee66e" +checksum = "34836a629bcbc6f1afdf0907a744870039b1e14c0561cb26094fa683b158eff3" dependencies = [ "erased-serde", "serde", @@ -5049,7 +5047,7 @@ checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.106", ] [[package]] @@ -5140,12 +5138,12 @@ checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "socket2" -version = "0.5.10" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" +checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -5285,9 +5283,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.104" +version = "2.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" dependencies = [ "proc-macro2", "quote", @@ -5302,7 +5300,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.106", ] [[package]] @@ -5420,11 +5418,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.12" +version = "2.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +checksum = "80d76d3f064b981389ecb4b6b7f45a0bf9fdac1d5b9204c7bd6714fecc302850" dependencies = [ - "thiserror-impl 2.0.12", + "thiserror-impl 2.0.15", ] [[package]] @@ -5435,18 +5433,18 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.106", ] [[package]] name = "thiserror-impl" -version = "2.0.12" +version = "2.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" +checksum = "44d29feb33e986b6ea906bd9c3559a856983f92371b3eaa5e83782a351623de0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.106", ] [[package]] @@ -5643,7 +5641,7 @@ checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.106", ] [[package]] @@ -5826,7 +5824,7 @@ checksum = "a1249a628de3ad34b821ecb1001355bca3940bcb2f88558f1a8bd82e977f75b5" dependencies = [ "proc-macro-hack", "quote", - "syn 2.0.104", + "syn 2.0.106", "unic-langid-impl", ] @@ -5958,9 +5956,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.17.0" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cf4199d1e5d15ddd86a694e4d0dffa9c323ce759fea589f00fef9d81cc1931d" +checksum = "f33196643e165781c20a5ead5582283a7dacbb87855d867fbc2df3f81eddc1be" dependencies = [ "getrandom 0.3.3", "js-sys", @@ -6038,7 +6036,7 @@ dependencies = [ "log", "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.106", "wasm-bindgen-shared", ] @@ -6060,7 +6058,7 @@ checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.106", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -6123,12 +6121,12 @@ dependencies = [ [[package]] name = "wasm-encoder" -version = "0.236.0" +version = "0.236.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3108979166ab0d3c7262d2e16a2190ffe784b2a5beb963edef154b5e8e07680b" +checksum = "724fccfd4f3c24b7e589d333fc0429c68042897a7e8a5f8694f31792471841e7" dependencies = [ "leb128fmt", - "wasmparser 0.236.0", + "wasmparser 0.236.1", ] [[package]] @@ -6168,9 +6166,9 @@ dependencies = [ [[package]] name = "wasmparser" -version = "0.236.0" +version = "0.236.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16d1eee846a705f6f3cb9d7b9f79b54583810f1fb57a1e3aea76d1742db2e3d2" +checksum = "a9b1e81f3eb254cf7404a82cee6926a4a3ccc5aad80cc3d43608a070c67aa1d7" dependencies = [ "bitflags", "indexmap", @@ -6179,22 +6177,22 @@ dependencies = [ [[package]] name = "wast" -version = "236.0.0" +version = "236.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11d6b6faeab519ba6fbf9b26add41617ca6f5553f99ebc33d876e591d2f4f3c6" +checksum = "d3bec4b4db9c6808d394632fd4b0cd4654c32c540bd3237f55ee6a40fff6e51f" dependencies = [ "bumpalo", "leb128fmt", "memchr", "unicode-width 0.2.1", - "wasm-encoder 0.236.0", + "wasm-encoder 0.236.1", ] [[package]] name = "wat" -version = "1.236.0" +version = "1.236.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc31704322400f461f7f31a5f9190d5488aaeafb63ae69ad2b5888d2704dcb08" +checksum = "64475e2f77d6071ce90624098fc236285ddafa8c3ea1fb386f2c4154b6c2bbdb" dependencies = [ "wast", ] @@ -6328,7 +6326,7 @@ checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.106", ] [[package]] @@ -6339,7 +6337,7 @@ checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.106", ] [[package]] @@ -6350,7 +6348,7 @@ checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.106", ] [[package]] @@ -6361,7 +6359,7 @@ checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.106", ] [[package]] @@ -6794,7 +6792,7 @@ checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.106", "synstructure", ] @@ -6806,7 +6804,7 @@ checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.106", "synstructure", ] @@ -6827,7 +6825,7 @@ checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.106", ] [[package]] @@ -6847,7 +6845,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.106", "synstructure", ] @@ -6892,7 +6890,7 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.106", ] [[package]] @@ -6903,5 +6901,5 @@ checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.106", ] diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index fc816f2cb79..ea98bebd305 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -7,6 +7,7 @@ pub use NtPatKind::*; pub use TokenKind::*; use rustc_macros::{Decodable, Encodable, HashStable_Generic}; use rustc_span::edition::Edition; +use rustc_span::symbol::IdentPrintMode; use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, kw, sym}; #[allow(clippy::useless_attribute)] // FIXME: following use of `hidden_glob_reexports` incorrectly triggers `useless_attribute` lint. #[allow(hidden_glob_reexports)] @@ -344,15 +345,24 @@ pub enum IdentIsRaw { Yes, } -impl From<bool> for IdentIsRaw { - fn from(b: bool) -> Self { - if b { Self::Yes } else { Self::No } +impl IdentIsRaw { + pub fn to_print_mode_ident(self) -> IdentPrintMode { + match self { + IdentIsRaw::No => IdentPrintMode::Normal, + IdentIsRaw::Yes => IdentPrintMode::RawIdent, + } + } + pub fn to_print_mode_lifetime(self) -> IdentPrintMode { + match self { + IdentIsRaw::No => IdentPrintMode::Normal, + IdentIsRaw::Yes => IdentPrintMode::RawLifetime, + } } } -impl From<IdentIsRaw> for bool { - fn from(is_raw: IdentIsRaw) -> bool { - matches!(is_raw, IdentIsRaw::Yes) +impl From<bool> for IdentIsRaw { + fn from(b: bool) -> Self { + if b { Self::Yes } else { Self::No } } } diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index cd0f9f2403e..bb559bd8921 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -1596,7 +1596,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let safety = self.lower_safety(h.safety, default_safety); // Treat safe `#[target_feature]` functions as unsafe, but also remember that we did so. - let safety = if find_attr!(attrs, AttributeKind::TargetFeature { .. }) + let safety = if find_attr!(attrs, AttributeKind::TargetFeature { was_forced: false, .. }) && safety.is_safe() && !self.tcx.sess.target.is_like_wasm { diff --git a/compiler/rustc_ast_passes/Cargo.toml b/compiler/rustc_ast_passes/Cargo.toml index 1940628b44a..3e04f8b11ec 100644 --- a/compiler/rustc_ast_passes/Cargo.toml +++ b/compiler/rustc_ast_passes/Cargo.toml @@ -15,7 +15,6 @@ rustc_errors = { path = "../rustc_errors" } rustc_feature = { path = "../rustc_feature" } rustc_fluent_macro = { path = "../rustc_fluent_macro" } rustc_macros = { path = "../rustc_macros" } -rustc_parse = { path = "../rustc_parse" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index c0679c1b8ff..a95f1443968 100644 --- a/compiler/rustc_ast_passes/messages.ftl +++ b/compiler/rustc_ast_passes/messages.ftl @@ -113,6 +113,10 @@ ast_passes_extern_without_abi = `extern` declarations without an explicit ABI ar .suggestion = specify an ABI .help = prior to Rust 2024, a default ABI was inferred +ast_passes_extern_without_abi_sugg = `extern` declarations without an explicit ABI are deprecated + .label = ABI should be specified here + .suggestion = explicitly specify the {$default_abi} ABI + ast_passes_feature_on_non_nightly = `#![feature]` may not be used on the {$channel} release channel .suggestion = remove the attribute .stable_since = the feature `{$name}` has been stable since `{$since}` and no longer requires an attribute to enable diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index ef4410566c5..6133cc3548b 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -25,16 +25,16 @@ use rustc_abi::{CanonAbi, ExternAbi, InterruptKind}; use rustc_ast::visit::{AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor, walk_list}; use rustc_ast::*; use rustc_ast_pretty::pprust::{self, State}; +use rustc_attr_parsing::validate_attr; use rustc_data_structures::fx::FxIndexMap; -use rustc_errors::DiagCtxtHandle; +use rustc_errors::{DiagCtxtHandle, LintBuffer}; use rustc_feature::Features; -use rustc_parse::validate_attr; use rustc_session::Session; +use rustc_session::lint::BuiltinLintDiag; use rustc_session::lint::builtin::{ DEPRECATED_WHERE_CLAUSE_LOCATION, MISSING_ABI, MISSING_UNSAFE_ON_EXTERN, PATTERNS_IN_FNS_WITHOUT_BODY, }; -use rustc_session::lint::{BuiltinLintDiag, LintBuffer}; use rustc_span::{Ident, Span, kw, sym}; use rustc_target::spec::{AbiMap, AbiMapping}; use thin_vec::thin_vec; @@ -876,7 +876,7 @@ impl<'a> AstValidator<'a> { MISSING_ABI, id, span, - BuiltinLintDiag::MissingAbi(span, ExternAbi::FALLBACK), + errors::MissingAbiSugg { span, default_abi: ExternAbi::FALLBACK }, ) } } diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index b9b2d271954..ae8f056cb4e 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -4,7 +4,7 @@ use rustc_abi::ExternAbi; use rustc_ast::ParamKindOrd; use rustc_errors::codes::*; use rustc_errors::{Applicability, Diag, EmissionGuarantee, Subdiagnostic}; -use rustc_macros::{Diagnostic, Subdiagnostic}; +use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_span::{Ident, Span, Symbol}; use crate::fluent_generated as fluent; @@ -815,6 +815,14 @@ pub(crate) struct MissingAbi { pub span: Span, } +#[derive(LintDiagnostic)] +#[diag(ast_passes_extern_without_abi_sugg)] +pub(crate) struct MissingAbiSugg { + #[suggestion(code = "extern {default_abi}", applicability = "machine-applicable")] + pub span: Span, + pub default_abi: ExternAbi, +} + #[derive(Diagnostic)] #[diag(ast_passes_abi_custom_safe_foreign_function)] pub(crate) struct AbiCustomSafeForeignFunction { diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index c9344a76a7b..e763c9d69fc 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -524,6 +524,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) { gate_all!(where_clause_attrs, "attributes in `where` clause are unstable"); gate_all!(super_let, "`super let` is experimental"); gate_all!(frontmatter, "frontmatters are experimental"); + gate_all!(coroutines, "coroutine syntax is experimental"); if !visitor.features.never_patterns() { if let Some(spans) = spans.get(&sym::never_patterns) { diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 85f76036df7..a056ce3e29d 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -10,7 +10,7 @@ use std::borrow::Cow; use std::sync::Arc; use rustc_ast::attr::AttrIdGenerator; -use rustc_ast::token::{self, CommentKind, Delimiter, IdentIsRaw, Token, TokenKind}; +use rustc_ast::token::{self, CommentKind, Delimiter, Token, TokenKind}; use rustc_ast::tokenstream::{Spacing, TokenStream, TokenTree}; use rustc_ast::util::classify; use rustc_ast::util::comments::{Comment, CommentStyle}; @@ -441,7 +441,7 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere fn print_generic_args(&mut self, args: &ast::GenericArgs, colons_before_params: bool); fn print_ident(&mut self, ident: Ident) { - self.word(IdentPrinter::for_ast_ident(ident, ident.is_raw_guess()).to_string()); + self.word(IdentPrinter::for_ast_ident(ident, ident.guess_print_mode()).to_string()); self.ann_post(ident) } @@ -1015,17 +1015,16 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere /* Name components */ token::Ident(name, is_raw) => { - IdentPrinter::new(name, is_raw.into(), convert_dollar_crate).to_string().into() + IdentPrinter::new(name, is_raw.to_print_mode_ident(), convert_dollar_crate) + .to_string() + .into() } token::NtIdent(ident, is_raw) => { - IdentPrinter::for_ast_ident(ident, is_raw.into()).to_string().into() + IdentPrinter::for_ast_ident(ident, is_raw.to_print_mode_ident()).to_string().into() } - token::Lifetime(name, IdentIsRaw::No) - | token::NtLifetime(Ident { name, .. }, IdentIsRaw::No) => name.to_string().into(), - token::Lifetime(name, IdentIsRaw::Yes) - | token::NtLifetime(Ident { name, .. }, IdentIsRaw::Yes) => { - format!("'r#{}", &name.as_str()[1..]).into() + token::Lifetime(name, is_raw) | token::NtLifetime(Ident { name, .. }, is_raw) => { + IdentPrinter::new(name, is_raw.to_print_mode_lifetime(), None).to_string().into() } /* Other */ diff --git a/compiler/rustc_attr_parsing/Cargo.toml b/compiler/rustc_attr_parsing/Cargo.toml index bac89373b67..fd8f7ffb2ed 100644 --- a/compiler/rustc_attr_parsing/Cargo.toml +++ b/compiler/rustc_attr_parsing/Cargo.toml @@ -5,7 +5,6 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -itertools = "0.12" rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } @@ -15,6 +14,7 @@ rustc_fluent_macro = { path = "../rustc_fluent_macro" } rustc_hir = { path = "../rustc_hir" } rustc_lexer = { path = "../rustc_lexer" } rustc_macros = { path = "../rustc_macros" } +rustc_parse = { path = "../rustc_parse" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } thin-vec = "0.2.12" diff --git a/compiler/rustc_attr_parsing/messages.ftl b/compiler/rustc_attr_parsing/messages.ftl index 067d95a0f48..40e9d597530 100644 --- a/compiler/rustc_attr_parsing/messages.ftl +++ b/compiler/rustc_attr_parsing/messages.ftl @@ -170,3 +170,22 @@ attr_parsing_unused_multiple = -attr_parsing_previously_accepted = this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +attr_parsing_meta_bad_delim = wrong meta list delimiters +attr_parsing_meta_bad_delim_suggestion = the delimiters should be `(` and `)` + +attr_parsing_unsafe_attr_outside_unsafe = unsafe attribute used without unsafe + .label = usage of unsafe attribute +attr_parsing_unsafe_attr_outside_unsafe_suggestion = wrap the attribute in `unsafe(...)` + +attr_parsing_invalid_attr_unsafe = `{$name}` is not an unsafe attribute + .label = this is not an unsafe attribute + .suggestion = remove the `unsafe(...)` + .note = extraneous unsafe is not allowed in attributes + +attr_parsing_invalid_meta_item = expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found {$descr} + .remove_neg_sugg = negative numbers are not literals, try removing the `-` sign + .quote_ident_sugg = surround the identifier with quotation marks to make it into a string literal + +attr_parsing_suffixed_literal_in_attribute = suffixed literals are not allowed in attributes + .help = instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.) diff --git a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs index 4d995027814..088fa73d742 100644 --- a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs +++ b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs @@ -1,14 +1,6 @@ use std::iter; -use rustc_feature::{AttributeTemplate, template}; -use rustc_hir::attrs::AttributeKind; -use rustc_hir::{MethodKind, Target}; -use rustc_span::{Span, Symbol, sym}; - -use super::{CombineAttributeParser, ConvertFn}; -use crate::context::MaybeWarn::{Allow, Warn}; -use crate::context::{AcceptContext, AllowedTargets, Stage}; -use crate::parser::ArgParser; +use super::prelude::*; use crate::session_diagnostics; pub(crate) struct AllowInternalUnstableParser; diff --git a/compiler/rustc_attr_parsing/src/attributes/body.rs b/compiler/rustc_attr_parsing/src/attributes/body.rs index 88540384621..a1492d76194 100644 --- a/compiler/rustc_attr_parsing/src/attributes/body.rs +++ b/compiler/rustc_attr_parsing/src/attributes/body.rs @@ -1,12 +1,6 @@ //! Attributes that can be found in function body. -use rustc_hir::Target; -use rustc_hir::attrs::AttributeKind; -use rustc_span::{Symbol, sym}; - -use super::{NoArgsAttributeParser, OnDuplicate}; -use crate::context::MaybeWarn::Allow; -use crate::context::{AllowedTargets, Stage}; +use super::prelude::*; pub(crate) struct CoroutineParser; diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index 6ea073896c2..91053811a0b 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -1,16 +1,7 @@ -use rustc_feature::{AttributeTemplate, template}; -use rustc_hir::attrs::{AttributeKind, CoverageAttrKind, OptimizeAttr, UsedBy}; -use rustc_hir::{MethodKind, Target}; +use rustc_hir::attrs::{CoverageAttrKind, OptimizeAttr, UsedBy}; use rustc_session::parse::feature_err; -use rustc_span::{Span, Symbol, sym}; - -use super::{ - AcceptMapping, AttributeOrder, AttributeParser, CombineAttributeParser, ConvertFn, - NoArgsAttributeParser, OnDuplicate, SingleAttributeParser, -}; -use crate::context::MaybeWarn::{Allow, Warn}; -use crate::context::{AcceptContext, AllowedTargets, FinalizeContext, Stage}; -use crate::parser::ArgParser; + +use super::prelude::*; use crate::session_diagnostics::{NakedFunctionIncompatibleAttribute, NullOnExport}; pub(crate) struct OptimizeParser; @@ -44,7 +35,7 @@ impl<S: Stage> SingleAttributeParser<S> for OptimizeParser { Some(sym::speed) => OptimizeAttr::Speed, Some(sym::none) => OptimizeAttr::DoNotOptimize, _ => { - cx.expected_specific_argument(single.span(), vec!["size", "speed", "none"]); + cx.expected_specific_argument(single.span(), &[sym::size, sym::speed, sym::none]); OptimizeAttr::Default } }; @@ -91,7 +82,7 @@ impl<S: Stage> SingleAttributeParser<S> for CoverageParser { fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> { let Some(args) = args.list() else { - cx.expected_specific_argument_and_list(cx.attr_span, vec!["on", "off"]); + cx.expected_specific_argument_and_list(cx.attr_span, &[sym::on, sym::off]); return None; }; @@ -100,7 +91,8 @@ impl<S: Stage> SingleAttributeParser<S> for CoverageParser { return None; }; - let fail_incorrect_argument = |span| cx.expected_specific_argument(span, vec!["on", "off"]); + let fail_incorrect_argument = + |span| cx.expected_specific_argument(span, &[sym::on, sym::off]); let Some(arg) = arg.meta_item() else { fail_incorrect_argument(args.span); @@ -352,7 +344,7 @@ impl<S: Stage> AttributeParser<S> for UsedParser { UsedBy::Linker } _ => { - cx.expected_specific_argument(l.span(), vec!["compiler", "linker"]); + cx.expected_specific_argument(l.span(), &[sym::compiler, sym::linker]); return; } } @@ -385,57 +377,68 @@ impl<S: Stage> AttributeParser<S> for UsedParser { } } +fn parse_tf_attribute<'c, S: Stage>( + cx: &'c mut AcceptContext<'_, '_, S>, + args: &'c ArgParser<'_>, +) -> impl IntoIterator<Item = (Symbol, Span)> + 'c { + let mut features = Vec::new(); + let ArgParser::List(list) = args else { + cx.expected_list(cx.attr_span); + return features; + }; + if list.is_empty() { + cx.warn_empty_attribute(cx.attr_span); + return features; + } + for item in list.mixed() { + let Some(name_value) = item.meta_item() else { + cx.expected_name_value(item.span(), Some(sym::enable)); + return features; + }; + + // Validate name + let Some(name) = name_value.path().word_sym() else { + cx.expected_name_value(name_value.path().span(), Some(sym::enable)); + return features; + }; + if name != sym::enable { + cx.expected_name_value(name_value.path().span(), Some(sym::enable)); + return features; + } + + // Use value + let Some(name_value) = name_value.args().name_value() else { + cx.expected_name_value(item.span(), Some(sym::enable)); + return features; + }; + let Some(value_str) = name_value.value_as_str() else { + cx.expected_string_literal(name_value.value_span, Some(name_value.value_as_lit())); + return features; + }; + for feature in value_str.as_str().split(",") { + features.push((Symbol::intern(feature), item.span())); + } + } + features +} + pub(crate) struct TargetFeatureParser; impl<S: Stage> CombineAttributeParser<S> for TargetFeatureParser { type Item = (Symbol, Span); const PATH: &[Symbol] = &[sym::target_feature]; - const CONVERT: ConvertFn<Self::Item> = |items, span| AttributeKind::TargetFeature(items, span); + const CONVERT: ConvertFn<Self::Item> = |items, span| AttributeKind::TargetFeature { + features: items, + attr_span: span, + was_forced: false, + }; const TEMPLATE: AttributeTemplate = template!(List: &["enable = \"feat1, feat2\""]); fn extend<'c>( cx: &'c mut AcceptContext<'_, '_, S>, args: &'c ArgParser<'_>, ) -> impl IntoIterator<Item = Self::Item> + 'c { - let mut features = Vec::new(); - let ArgParser::List(list) = args else { - cx.expected_list(cx.attr_span); - return features; - }; - if list.is_empty() { - cx.warn_empty_attribute(cx.attr_span); - return features; - } - for item in list.mixed() { - let Some(name_value) = item.meta_item() else { - cx.expected_name_value(item.span(), Some(sym::enable)); - return features; - }; - - // Validate name - let Some(name) = name_value.path().word_sym() else { - cx.expected_name_value(name_value.path().span(), Some(sym::enable)); - return features; - }; - if name != sym::enable { - cx.expected_name_value(name_value.path().span(), Some(sym::enable)); - return features; - } - - // Use value - let Some(name_value) = name_value.args().name_value() else { - cx.expected_name_value(item.span(), Some(sym::enable)); - return features; - }; - let Some(value_str) = name_value.value_as_str() else { - cx.expected_string_literal(name_value.value_span, Some(name_value.value_as_lit())); - return features; - }; - for feature in value_str.as_str().split(",") { - features.push((Symbol::intern(feature), item.span())); - } - } - features + parse_tf_attribute(cx, args) } const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ @@ -449,3 +452,30 @@ impl<S: Stage> CombineAttributeParser<S> for TargetFeatureParser { Warn(Target::MacroDef), ]); } + +pub(crate) struct ForceTargetFeatureParser; + +impl<S: Stage> CombineAttributeParser<S> for ForceTargetFeatureParser { + type Item = (Symbol, Span); + const PATH: &[Symbol] = &[sym::force_target_feature]; + const CONVERT: ConvertFn<Self::Item> = |items, span| AttributeKind::TargetFeature { + features: items, + attr_span: span, + was_forced: true, + }; + const TEMPLATE: AttributeTemplate = template!(List: &["enable = \"feat1, feat2\""]); + + fn extend<'c>( + cx: &'c mut AcceptContext<'_, '_, S>, + args: &'c ArgParser<'_>, + ) -> impl IntoIterator<Item = Self::Item> + 'c { + parse_tf_attribute(cx, args) + } + + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + Allow(Target::Fn), + Allow(Target::Method(MethodKind::Inherent)), + Allow(Target::Method(MethodKind::Trait { body: true })), + Allow(Target::Method(MethodKind::TraitImpl)), + ]); +} diff --git a/compiler/rustc_attr_parsing/src/attributes/confusables.rs b/compiler/rustc_attr_parsing/src/attributes/confusables.rs index 00f949c82c5..97e78dfb136 100644 --- a/compiler/rustc_attr_parsing/src/attributes/confusables.rs +++ b/compiler/rustc_attr_parsing/src/attributes/confusables.rs @@ -1,13 +1,6 @@ -use rustc_feature::template; -use rustc_hir::attrs::AttributeKind; -use rustc_hir::{MethodKind, Target}; -use rustc_span::{Span, Symbol, sym}; -use thin_vec::ThinVec; - -use super::{AcceptMapping, AttributeParser}; -use crate::context::MaybeWarn::Allow; -use crate::context::{AllowedTargets, FinalizeContext, Stage}; -use crate::session_diagnostics; +use super::prelude::*; +use crate::session_diagnostics::EmptyConfusables; + #[derive(Default)] pub(crate) struct ConfusablesParser { confusables: ThinVec<Symbol>, @@ -25,7 +18,7 @@ impl<S: Stage> AttributeParser<S> for ConfusablesParser { }; if list.is_empty() { - cx.emit_err(session_diagnostics::EmptyConfusables { span: cx.attr_span }); + cx.emit_err(EmptyConfusables { span: cx.attr_span }); } for param in list.mixed() { diff --git a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs index d3a61f3a653..31c698228ef 100644 --- a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs +++ b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs @@ -1,14 +1,11 @@ -use rustc_feature::{AttributeTemplate, template}; -use rustc_hir::attrs::{AttributeKind, DeprecatedSince, Deprecation}; -use rustc_hir::{MethodKind, Target}; -use rustc_span::{Span, Symbol, sym}; +use rustc_hir::attrs::{DeprecatedSince, Deprecation}; +use super::prelude::*; use super::util::parse_version; -use super::{AttributeOrder, OnDuplicate, SingleAttributeParser}; -use crate::context::MaybeWarn::{Allow, Error}; -use crate::context::{AcceptContext, AllowedTargets, Stage}; -use crate::parser::ArgParser; -use crate::session_diagnostics; +use crate::session_diagnostics::{ + DeprecatedItemSuggestion, InvalidSince, MissingNote, MissingSince, +}; + pub(crate) struct DeprecationParser; fn get<S: Stage>( @@ -102,7 +99,7 @@ impl<S: Stage> SingleAttributeParser<S> for DeprecationParser { } Some(name @ sym::suggestion) => { if !features.deprecated_suggestion() { - cx.emit_err(session_diagnostics::DeprecatedItemSuggestion { + cx.emit_err(DeprecatedItemSuggestion { span: param.span(), is_nightly: cx.sess().is_nightly_build(), details: (), @@ -144,18 +141,18 @@ impl<S: Stage> SingleAttributeParser<S> for DeprecationParser { } else if let Some(version) = parse_version(since) { DeprecatedSince::RustcVersion(version) } else { - cx.emit_err(session_diagnostics::InvalidSince { span: cx.attr_span }); + cx.emit_err(InvalidSince { span: cx.attr_span }); DeprecatedSince::Err } } else if is_rustc { - cx.emit_err(session_diagnostics::MissingSince { span: cx.attr_span }); + cx.emit_err(MissingSince { span: cx.attr_span }); DeprecatedSince::Err } else { DeprecatedSince::Unspecified }; if is_rustc && note.is_none() { - cx.emit_err(session_diagnostics::MissingNote { span: cx.attr_span }); + cx.emit_err(MissingNote { span: cx.attr_span }); return None; } diff --git a/compiler/rustc_attr_parsing/src/attributes/dummy.rs b/compiler/rustc_attr_parsing/src/attributes/dummy.rs index 85842b1b5c5..7293cee842c 100644 --- a/compiler/rustc_attr_parsing/src/attributes/dummy.rs +++ b/compiler/rustc_attr_parsing/src/attributes/dummy.rs @@ -3,8 +3,10 @@ use rustc_hir::attrs::AttributeKind; use rustc_span::{Symbol, sym}; use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser}; -use crate::context::{ALL_TARGETS, AcceptContext, AllowedTargets, Stage}; +use crate::context::{AcceptContext, Stage}; use crate::parser::ArgParser; +use crate::target_checking::{ALL_TARGETS, AllowedTargets}; + pub(crate) struct DummyParser; impl<S: Stage> SingleAttributeParser<S> for DummyParser { const PATH: &[Symbol] = &[sym::rustc_dummy]; diff --git a/compiler/rustc_attr_parsing/src/attributes/inline.rs b/compiler/rustc_attr_parsing/src/attributes/inline.rs index 33c21bad240..39d5ff85d9f 100644 --- a/compiler/rustc_attr_parsing/src/attributes/inline.rs +++ b/compiler/rustc_attr_parsing/src/attributes/inline.rs @@ -2,17 +2,10 @@ // note: need to model better how duplicate attr errors work when not using // SingleAttributeParser which is what we have two of here. -use rustc_feature::{AttributeTemplate, template}; use rustc_hir::attrs::{AttributeKind, InlineAttr}; -use rustc_hir::lints::AttributeLintKind; -use rustc_hir::{MethodKind, Target}; -use rustc_span::{Symbol, sym}; -use super::{AcceptContext, AttributeOrder, OnDuplicate}; -use crate::attributes::SingleAttributeParser; -use crate::context::MaybeWarn::{Allow, Warn}; -use crate::context::{AllowedTargets, Stage}; -use crate::parser::ArgParser; +use super::prelude::*; + pub(crate) struct InlineParser; impl<S: Stage> SingleAttributeParser<S> for InlineParser { @@ -56,7 +49,7 @@ impl<S: Stage> SingleAttributeParser<S> for InlineParser { Some(AttributeKind::Inline(InlineAttr::Never, cx.attr_span)) } _ => { - cx.expected_specific_argument(l.span(), vec!["always", "never"]); + cx.expected_specific_argument(l.span(), &[sym::always, sym::never]); return None; } } diff --git a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs index 552b9dfabc2..66b02697c77 100644 --- a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs @@ -1,16 +1,10 @@ -use rustc_feature::{AttributeTemplate, template}; use rustc_hir::attrs::AttributeKind::{LinkName, LinkOrdinal, LinkSection}; -use rustc_hir::attrs::{AttributeKind, Linkage}; -use rustc_hir::{MethodKind, Target}; -use rustc_span::{Span, Symbol, sym}; - -use crate::attributes::{ - AttributeOrder, NoArgsAttributeParser, OnDuplicate, SingleAttributeParser, -}; -use crate::context::MaybeWarn::Allow; -use crate::context::{ALL_TARGETS, AcceptContext, AllowedTargets, Stage, parse_single_integer}; -use crate::parser::ArgParser; +use rustc_hir::attrs::Linkage; + +use super::prelude::*; +use super::util::parse_single_integer; use crate::session_diagnostics::{LinkOrdinalOutOfRange, NullOnLinkSection}; + pub(crate) struct LinkNameParser; impl<S: Stage> SingleAttributeParser<S> for LinkNameParser { @@ -212,16 +206,16 @@ impl<S: Stage> SingleAttributeParser<S> for LinkageParser { _ => { cx.expected_specific_argument( name_value.value_span, - vec![ - "available_externally", - "common", - "extern_weak", - "external", - "internal", - "linkonce", - "linkonce_odr", - "weak", - "weak_odr", + &[ + sym::available_externally, + sym::common, + sym::extern_weak, + sym::external, + sym::internal, + sym::linkonce, + sym::linkonce_odr, + sym::weak, + sym::weak_odr, ], ); return None; diff --git a/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs b/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs index 2b586d4003c..63b0809d0d8 100644 --- a/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs +++ b/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs @@ -1,10 +1,5 @@ -use rustc_hir::attrs::AttributeKind; -use rustc_hir::{MethodKind, Target}; -use rustc_span::{Span, Symbol, sym}; +use super::prelude::*; -use crate::attributes::{NoArgsAttributeParser, OnDuplicate}; -use crate::context::MaybeWarn::{Allow, Error}; -use crate::context::{AllowedTargets, Stage}; pub(crate) struct AsPtrParser; impl<S: Stage> NoArgsAttributeParser<S> for AsPtrParser { const PATH: &[Symbol] = &[sym::rustc_as_ptr]; diff --git a/compiler/rustc_attr_parsing/src/attributes/loop_match.rs b/compiler/rustc_attr_parsing/src/attributes/loop_match.rs index 242e2f2c1bc..528090b8673 100644 --- a/compiler/rustc_attr_parsing/src/attributes/loop_match.rs +++ b/compiler/rustc_attr_parsing/src/attributes/loop_match.rs @@ -1,10 +1,5 @@ -use rustc_hir::Target; -use rustc_hir::attrs::AttributeKind; -use rustc_span::{Span, Symbol, sym}; +use super::prelude::*; -use crate::attributes::{NoArgsAttributeParser, OnDuplicate}; -use crate::context::MaybeWarn::Allow; -use crate::context::{AllowedTargets, Stage}; pub(crate) struct LoopMatchParser; impl<S: Stage> NoArgsAttributeParser<S> for LoopMatchParser { const PATH: &[Symbol] = &[sym::loop_match]; diff --git a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs index 8928129c201..180130c7be4 100644 --- a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs @@ -1,15 +1,9 @@ use rustc_errors::DiagArgValue; -use rustc_feature::{AttributeTemplate, template}; -use rustc_hir::Target; -use rustc_hir::attrs::{AttributeKind, MacroUseArgs}; -use rustc_span::{Span, Symbol, sym}; -use thin_vec::ThinVec; +use rustc_hir::attrs::MacroUseArgs; + +use super::prelude::*; +use crate::session_diagnostics::IllFormedAttributeInputLint; -use crate::attributes::{AcceptMapping, AttributeParser, NoArgsAttributeParser, OnDuplicate}; -use crate::context::MaybeWarn::{Allow, Error, Warn}; -use crate::context::{AcceptContext, AllowedTargets, FinalizeContext, Stage}; -use crate::parser::ArgParser; -use crate::session_diagnostics; pub(crate) struct MacroEscapeParser; impl<S: Stage> NoArgsAttributeParser<S> for MacroEscapeParser { const PATH: &[Symbol] = &[sym::macro_escape]; @@ -108,7 +102,7 @@ impl<S: Stage> AttributeParser<S> for MacroUseParser { } ArgParser::NameValue(_) => { let suggestions = MACRO_USE_TEMPLATE.suggestions(cx.attr_style, sym::macro_use); - cx.emit_err(session_diagnostics::IllFormedAttributeInputLint { + cx.emit_err(IllFormedAttributeInputLint { num_suggestions: suggestions.len(), suggestions: DiagArgValue::StrListSepByAnd( suggestions.into_iter().map(|s| format!("`{s}`").into()).collect(), diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index 3d6e26a24b8..b98678041d7 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -7,9 +7,9 @@ //! Specifically, you might not care about managing the state of your [`AttributeParser`] //! state machine yourself. In this case you can choose to implement: //! -//! - [`SingleAttributeParser`]: makes it easy to implement an attribute which should error if it +//! - [`SingleAttributeParser`](crate::attributes::SingleAttributeParser): makes it easy to implement an attribute which should error if it //! appears more than once in a list of attributes -//! - [`CombineAttributeParser`]: makes it easy to implement an attribute which should combine the +//! - [`CombineAttributeParser`](crate::attributes::CombineAttributeParser): makes it easy to implement an attribute which should combine the //! contents of attributes, if an attribute appear multiple times in a list //! //! Attributes should be added to `crate::context::ATTRIBUTE_PARSERS` to be parsed. @@ -21,9 +21,13 @@ use rustc_hir::attrs::AttributeKind; use rustc_span::{Span, Symbol}; use thin_vec::ThinVec; -use crate::context::{AcceptContext, AllowedTargets, FinalizeContext, Stage}; +use crate::context::{AcceptContext, FinalizeContext, Stage}; use crate::parser::ArgParser; use crate::session_diagnostics::UnusedMultiple; +use crate::target_checking::AllowedTargets; + +/// All the parsers require roughly the same imports, so this prelude has most of the often-needed ones. +mod prelude; pub(crate) mod allow_unstable; pub(crate) mod body; diff --git a/compiler/rustc_attr_parsing/src/attributes/must_use.rs b/compiler/rustc_attr_parsing/src/attributes/must_use.rs index eb2b39298bc..e6a5141d783 100644 --- a/compiler/rustc_attr_parsing/src/attributes/must_use.rs +++ b/compiler/rustc_attr_parsing/src/attributes/must_use.rs @@ -1,14 +1,8 @@ use rustc_errors::DiagArgValue; -use rustc_feature::{AttributeTemplate, template}; -use rustc_hir::attrs::AttributeKind; -use rustc_hir::{MethodKind, Target}; -use rustc_span::{Symbol, sym}; -use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser}; -use crate::context::MaybeWarn::{Allow, Error}; -use crate::context::{AcceptContext, AllowedTargets, Stage}; -use crate::parser::ArgParser; -use crate::session_diagnostics; +use super::prelude::*; +use crate::session_diagnostics::IllFormedAttributeInputLint; + pub(crate) struct MustUseParser; impl<S: Stage> SingleAttributeParser<S> for MustUseParser { @@ -53,7 +47,7 @@ impl<S: Stage> SingleAttributeParser<S> for MustUseParser { ArgParser::List(_) => { let suggestions = <Self as SingleAttributeParser<S>>::TEMPLATE .suggestions(cx.attr_style, "must_use"); - cx.emit_err(session_diagnostics::IllFormedAttributeInputLint { + cx.emit_err(IllFormedAttributeInputLint { num_suggestions: suggestions.len(), suggestions: DiagArgValue::StrListSepByAnd( suggestions.into_iter().map(|s| format!("`{s}`").into()).collect(), diff --git a/compiler/rustc_attr_parsing/src/attributes/no_implicit_prelude.rs b/compiler/rustc_attr_parsing/src/attributes/no_implicit_prelude.rs index 589faf38f73..40073ea0f46 100644 --- a/compiler/rustc_attr_parsing/src/attributes/no_implicit_prelude.rs +++ b/compiler/rustc_attr_parsing/src/attributes/no_implicit_prelude.rs @@ -1,10 +1,5 @@ -use rustc_hir::Target; -use rustc_hir::attrs::AttributeKind; -use rustc_span::{Span, sym}; +use super::prelude::*; -use crate::attributes::{NoArgsAttributeParser, OnDuplicate}; -use crate::context::MaybeWarn::Allow; -use crate::context::{AllowedTargets, Stage}; pub(crate) struct NoImplicitPreludeParser; impl<S: Stage> NoArgsAttributeParser<S> for NoImplicitPreludeParser { diff --git a/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs b/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs index 41e9ca4de41..4e6aec95e66 100644 --- a/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs +++ b/compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs @@ -3,8 +3,10 @@ use rustc_hir::attrs::AttributeKind; use rustc_span::{Span, Symbol, sym}; use crate::attributes::{NoArgsAttributeParser, OnDuplicate}; -use crate::context::MaybeWarn::{Allow, Warn}; -use crate::context::{AllowedTargets, Stage}; +use crate::context::Stage; +use crate::target_checking::AllowedTargets; +use crate::target_checking::Policy::{Allow, Warn}; + pub(crate) struct NonExhaustiveParser; impl<S: Stage> NoArgsAttributeParser<S> for NonExhaustiveParser { diff --git a/compiler/rustc_attr_parsing/src/attributes/path.rs b/compiler/rustc_attr_parsing/src/attributes/path.rs index f9191d1abed..e4cb806bb42 100644 --- a/compiler/rustc_attr_parsing/src/attributes/path.rs +++ b/compiler/rustc_attr_parsing/src/attributes/path.rs @@ -1,12 +1,5 @@ -use rustc_feature::{AttributeTemplate, template}; -use rustc_hir::Target; -use rustc_hir::attrs::AttributeKind; -use rustc_span::{Symbol, sym}; +use super::prelude::*; -use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser}; -use crate::context::MaybeWarn::{Allow, Error}; -use crate::context::{AcceptContext, AllowedTargets, Stage}; -use crate::parser::ArgParser; pub(crate) struct PathParser; impl<S: Stage> SingleAttributeParser<S> for PathParser { diff --git a/compiler/rustc_attr_parsing/src/attributes/prelude.rs b/compiler/rustc_attr_parsing/src/attributes/prelude.rs new file mode 100644 index 00000000000..2bcdee55c75 --- /dev/null +++ b/compiler/rustc_attr_parsing/src/attributes/prelude.rs @@ -0,0 +1,20 @@ +// parsing +// templates +pub(super) use rustc_feature::{AttributeTemplate, template}; +// data structures +pub(super) use rustc_hir::attrs::AttributeKind; +pub(super) use rustc_hir::lints::AttributeLintKind; +pub(super) use rustc_hir::{MethodKind, Target}; +pub(super) use rustc_span::{DUMMY_SP, Ident, Span, Symbol, sym}; +pub(super) use thin_vec::ThinVec; + +pub(super) use crate::attributes::{ + AcceptMapping, AttributeOrder, AttributeParser, CombineAttributeParser, ConvertFn, + NoArgsAttributeParser, OnDuplicate, SingleAttributeParser, +}; +// contexts +pub(super) use crate::context::{AcceptContext, FinalizeContext, Stage}; +pub(super) use crate::parser::*; +// target checking +pub(super) use crate::target_checking::Policy::{Allow, Error, Warn}; +pub(super) use crate::target_checking::{ALL_TARGETS, AllowedTargets}; diff --git a/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs index 4624fa36287..9ac18c04e32 100644 --- a/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs @@ -1,15 +1,5 @@ -use rustc_feature::{AttributeTemplate, template}; -use rustc_hir::Target; -use rustc_hir::attrs::AttributeKind; -use rustc_span::{Span, Symbol, sym}; -use thin_vec::ThinVec; +use super::prelude::*; -use crate::attributes::{ - AttributeOrder, NoArgsAttributeParser, OnDuplicate, SingleAttributeParser, -}; -use crate::context::MaybeWarn::{Allow, Warn}; -use crate::context::{AcceptContext, AllowedTargets, Stage}; -use crate::parser::ArgParser; pub(crate) struct ProcMacroParser; impl<S: Stage> NoArgsAttributeParser<S> for ProcMacroParser { const PATH: &[Symbol] = &[sym::proc_macro]; @@ -110,7 +100,7 @@ fn parse_derive_like<S: Stage>( return None; }; if !attr_list.path().word_is(sym::attributes) { - cx.expected_specific_argument(attrs.span(), vec!["attributes"]); + cx.expected_specific_argument(attrs.span(), &[sym::attributes]); return None; } let Some(attr_list) = attr_list.args().list() else { diff --git a/compiler/rustc_attr_parsing/src/attributes/prototype.rs b/compiler/rustc_attr_parsing/src/attributes/prototype.rs index fb1e47298b4..80fe82bf542 100644 --- a/compiler/rustc_attr_parsing/src/attributes/prototype.rs +++ b/compiler/rustc_attr_parsing/src/attributes/prototype.rs @@ -7,8 +7,10 @@ use rustc_span::{Span, Symbol, sym}; use super::{AttributeOrder, OnDuplicate}; use crate::attributes::SingleAttributeParser; -use crate::context::{AcceptContext, AllowedTargets, MaybeWarn, Stage}; +use crate::context::{AcceptContext, Stage}; use crate::parser::ArgParser; +use crate::target_checking::AllowedTargets; +use crate::target_checking::Policy::Allow; pub(crate) struct CustomMirParser; @@ -19,8 +21,7 @@ impl<S: Stage> SingleAttributeParser<S> for CustomMirParser { const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error; - const ALLOWED_TARGETS: AllowedTargets = - AllowedTargets::AllowList(&[MaybeWarn::Allow(Target::Fn)]); + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]); const TEMPLATE: AttributeTemplate = template!(List: &[r#"dialect = "...", phase = "...""#]); @@ -108,7 +109,7 @@ fn parse_dialect<S: Stage>( sym::runtime => MirDialect::Runtime, _ => { - cx.expected_specific_argument(span, vec!["analysis", "built", "runtime"]); + cx.expected_specific_argument(span, &[sym::analysis, sym::built, sym::runtime]); *failed = true; return None; } @@ -130,7 +131,7 @@ fn parse_phase<S: Stage>( sym::optimized => MirPhase::Optimized, _ => { - cx.expected_specific_argument(span, vec!["initial", "post-cleanup", "optimized"]); + cx.expected_specific_argument(span, &[sym::initial, sym::post_cleanup, sym::optimized]); *failed = true; return None; } diff --git a/compiler/rustc_attr_parsing/src/attributes/repr.rs b/compiler/rustc_attr_parsing/src/attributes/repr.rs index 7ab58ed9347..23aabd15597 100644 --- a/compiler/rustc_attr_parsing/src/attributes/repr.rs +++ b/compiler/rustc_attr_parsing/src/attributes/repr.rs @@ -1,16 +1,10 @@ use rustc_abi::Align; use rustc_ast::{IntTy, LitIntType, LitKind, UintTy}; -use rustc_feature::{AttributeTemplate, template}; -use rustc_hir::attrs::{AttributeKind, IntType, ReprAttr}; -use rustc_hir::{MethodKind, Target}; -use rustc_span::{DUMMY_SP, Span, Symbol, sym}; - -use super::{AcceptMapping, AttributeParser, CombineAttributeParser, ConvertFn, FinalizeContext}; -use crate::context::MaybeWarn::Allow; -use crate::context::{ALL_TARGETS, AcceptContext, AllowedTargets, Stage}; -use crate::parser::{ArgParser, MetaItemListParser, MetaItemParser}; -use crate::session_diagnostics; -use crate::session_diagnostics::IncorrectReprFormatGenericCause; +use rustc_hir::attrs::{IntType, ReprAttr}; + +use super::prelude::*; +use crate::session_diagnostics::{self, IncorrectReprFormatGenericCause}; + /// Parse #[repr(...)] forms. /// /// Valid repr contents: any of the primitive integral type names (see diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs index efd7b650e44..a995549fc7c 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs @@ -1,12 +1,6 @@ -use rustc_feature::{AttributeTemplate, template}; -use rustc_hir::Target; -use rustc_hir::attrs::AttributeKind; -use rustc_span::{Symbol, sym}; - -use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser}; -use crate::context::MaybeWarn::Allow; -use crate::context::{AcceptContext, AllowedTargets, Stage, parse_single_integer}; -use crate::parser::ArgParser; +use super::prelude::*; +use super::util::parse_single_integer; + pub(crate) struct RustcLayoutScalarValidRangeStart; impl<S: Stage> SingleAttributeParser<S> for RustcLayoutScalarValidRangeStart { diff --git a/compiler/rustc_attr_parsing/src/attributes/semantics.rs b/compiler/rustc_attr_parsing/src/attributes/semantics.rs index d4ad861a3a2..d7f62483297 100644 --- a/compiler/rustc_attr_parsing/src/attributes/semantics.rs +++ b/compiler/rustc_attr_parsing/src/attributes/semantics.rs @@ -1,8 +1,5 @@ -use rustc_hir::attrs::AttributeKind; -use rustc_span::{Span, Symbol, sym}; +use super::prelude::*; -use crate::attributes::{NoArgsAttributeParser, OnDuplicate}; -use crate::context::{ALL_TARGETS, AllowedTargets, Stage}; pub(crate) struct MayDangleParser; impl<S: Stage> NoArgsAttributeParser<S> for MayDangleParser { const PATH: &[Symbol] = &[sym::may_dangle]; diff --git a/compiler/rustc_attr_parsing/src/attributes/stability.rs b/compiler/rustc_attr_parsing/src/attributes/stability.rs index c7a809d7d88..b94e23477ff 100644 --- a/compiler/rustc_attr_parsing/src/attributes/stability.rs +++ b/compiler/rustc_attr_parsing/src/attributes/stability.rs @@ -1,20 +1,13 @@ use std::num::NonZero; use rustc_errors::ErrorGuaranteed; -use rustc_feature::template; -use rustc_hir::attrs::AttributeKind; use rustc_hir::{ DefaultBodyStability, MethodKind, PartialConstStability, Stability, StabilityLevel, StableSince, Target, UnstableReason, VERSION_PLACEHOLDER, }; -use rustc_span::{Ident, Span, Symbol, sym}; +use super::prelude::*; use super::util::parse_version; -use super::{AcceptMapping, AttributeParser, OnDuplicate}; -use crate::attributes::NoArgsAttributeParser; -use crate::context::MaybeWarn::Allow; -use crate::context::{AcceptContext, AllowedTargets, FinalizeContext, Stage}; -use crate::parser::{ArgParser, MetaItemParser}; use crate::session_diagnostics::{self, UnsupportedLiteralReason}; macro_rules! reject_outside_std { diff --git a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs index 164c680b8a8..510ff1ded49 100644 --- a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs @@ -1,13 +1,5 @@ -use rustc_feature::{AttributeTemplate, template}; -use rustc_hir::Target; -use rustc_hir::attrs::AttributeKind; -use rustc_hir::lints::AttributeLintKind; -use rustc_span::{Symbol, sym}; +use super::prelude::*; -use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser}; -use crate::context::MaybeWarn::{Allow, Error}; -use crate::context::{AcceptContext, AllowedTargets, Stage}; -use crate::parser::ArgParser; pub(crate) struct IgnoreParser; impl<S: Stage> SingleAttributeParser<S> for IgnoreParser { @@ -89,7 +81,7 @@ impl<S: Stage> SingleAttributeParser<S> for ShouldPanicParser { return None; }; if !single.path().word_is(sym::expected) { - cx.expected_specific_argument_strings(list.span, vec!["expected"]); + cx.expected_specific_argument_strings(list.span, &[sym::expected]); return None; } let Some(nv) = single.args().name_value() else { diff --git a/compiler/rustc_attr_parsing/src/attributes/traits.rs b/compiler/rustc_attr_parsing/src/attributes/traits.rs index ee9d7ba99cd..89ac1b07d16 100644 --- a/compiler/rustc_attr_parsing/src/attributes/traits.rs +++ b/compiler/rustc_attr_parsing/src/attributes/traits.rs @@ -1,16 +1,14 @@ -use core::mem; - -use rustc_feature::{AttributeTemplate, template}; -use rustc_hir::attrs::AttributeKind; -use rustc_hir::{MethodKind, Target}; -use rustc_span::{Span, Symbol, sym}; +use std::mem; +use super::prelude::*; use crate::attributes::{ AttributeOrder, NoArgsAttributeParser, OnDuplicate, SingleAttributeParser, }; -use crate::context::MaybeWarn::{Allow, Warn}; -use crate::context::{ALL_TARGETS, AcceptContext, AllowedTargets, Stage}; +use crate::context::{AcceptContext, Stage}; use crate::parser::ArgParser; +use crate::target_checking::Policy::{Allow, Warn}; +use crate::target_checking::{ALL_TARGETS, AllowedTargets}; + pub(crate) struct SkipDuringMethodDispatchParser; impl<S: Stage> SingleAttributeParser<S> for SkipDuringMethodDispatchParser { const PATH: &[Symbol] = &[sym::rustc_skip_during_method_dispatch]; @@ -44,7 +42,7 @@ impl<S: Stage> SingleAttributeParser<S> for SkipDuringMethodDispatchParser { Some(key @ sym::array) => (key, &mut array), Some(key @ sym::boxed_slice) => (key, &mut boxed_slice), _ => { - cx.expected_specific_argument(path.span(), vec!["array", "boxed_slice"]); + cx.expected_specific_argument(path.span(), &[sym::array, sym::boxed_slice]); continue; } }; diff --git a/compiler/rustc_attr_parsing/src/attributes/transparency.rs b/compiler/rustc_attr_parsing/src/attributes/transparency.rs index 0ffcf434b52..ea1f5549c4e 100644 --- a/compiler/rustc_attr_parsing/src/attributes/transparency.rs +++ b/compiler/rustc_attr_parsing/src/attributes/transparency.rs @@ -1,13 +1,7 @@ -use rustc_feature::{AttributeTemplate, template}; -use rustc_hir::Target; -use rustc_hir::attrs::AttributeKind; use rustc_span::hygiene::Transparency; -use rustc_span::{Symbol, sym}; -use super::{AttributeOrder, OnDuplicate, SingleAttributeParser}; -use crate::context::MaybeWarn::Allow; -use crate::context::{AcceptContext, AllowedTargets, Stage}; -use crate::parser::ArgParser; +use super::prelude::*; + pub(crate) struct TransparencyParser; // FIXME(jdonszelmann): make these proper diagnostics @@ -35,7 +29,7 @@ impl<S: Stage> SingleAttributeParser<S> for TransparencyParser { Some(_) => { cx.expected_specific_argument_strings( nv.value_span, - vec!["transparent", "semitransparent", "opaque"], + &[sym::transparent, sym::semitransparent, sym::opaque], ); None } diff --git a/compiler/rustc_attr_parsing/src/attributes/util.rs b/compiler/rustc_attr_parsing/src/attributes/util.rs index 10134915b27..ef9701cb7cb 100644 --- a/compiler/rustc_attr_parsing/src/attributes/util.rs +++ b/compiler/rustc_attr_parsing/src/attributes/util.rs @@ -1,8 +1,12 @@ +use rustc_ast::LitKind; use rustc_ast::attr::{AttributeExt, first_attr_value_str_by_name}; use rustc_feature::is_builtin_attr_name; use rustc_hir::RustcVersion; use rustc_span::{Symbol, sym}; +use crate::context::{AcceptContext, Stage}; +use crate::parser::ArgParser; + /// Parse a rustc version number written inside string literal in an attribute, /// like appears in `since = "1.0.0"`. Suffixes like "-dev" and "-nightly" are /// not accepted in this position, unlike when parsing CFG_RELEASE. @@ -56,3 +60,32 @@ pub fn is_doc_alias_attrs_contain_symbol<'tcx, T: AttributeExt + 'tcx>( } false } + +/// Parse a single integer. +/// +/// Used by attributes that take a single integer as argument, such as +/// `#[link_ordinal]` and `#[rustc_layout_scalar_valid_range_start]`. +/// `cx` is the context given to the attribute. +/// `args` is the parser for the attribute arguments. +pub(crate) fn parse_single_integer<S: Stage>( + cx: &mut AcceptContext<'_, '_, S>, + args: &ArgParser<'_>, +) -> Option<u128> { + let Some(list) = args.list() else { + cx.expected_list(cx.attr_span); + return None; + }; + let Some(single) = list.single() else { + cx.expected_single_argument(list.span); + return None; + }; + let Some(lit) = single.lit() else { + cx.expected_integer_literal(single.span()); + return None; + }; + let LitKind::Int(num, _ty) = lit.kind else { + cx.expected_integer_literal(single.span()); + return None; + }; + Some(num.0) +} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index c0d3bc99ba9..b9c415e8085 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -3,26 +3,24 @@ use std::collections::BTreeMap; use std::ops::{Deref, DerefMut}; use std::sync::LazyLock; -use itertools::Itertools; use private::Sealed; -use rustc_ast::{self as ast, AttrStyle, LitKind, MetaItemLit, NodeId}; -use rustc_errors::{DiagCtxtHandle, Diagnostic}; -use rustc_feature::{AttributeTemplate, Features}; +use rustc_ast::{AttrStyle, MetaItemLit, NodeId}; +use rustc_errors::Diagnostic; +use rustc_feature::AttributeTemplate; use rustc_hir::attrs::AttributeKind; use rustc_hir::lints::{AttributeLint, AttributeLintKind}; -use rustc_hir::{ - AttrArgs, AttrItem, AttrPath, Attribute, HashIgnoredAttrId, HirId, MethodKind, Target, -}; +use rustc_hir::{AttrPath, HirId}; use rustc_session::Session; -use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym}; +use rustc_span::{ErrorGuaranteed, Span, Symbol}; +use crate::AttributeParser; use crate::attributes::allow_unstable::{ AllowConstFnUnstableParser, AllowInternalUnstableParser, UnstableFeatureBoundParser, }; use crate::attributes::body::CoroutineParser; use crate::attributes::codegen_attrs::{ - ColdParser, CoverageParser, ExportNameParser, NakedParser, NoMangleParser, OptimizeParser, - TargetFeatureParser, TrackCallerParser, UsedParser, + ColdParser, CoverageParser, ExportNameParser, ForceTargetFeatureParser, NakedParser, + NoMangleParser, OptimizeParser, TargetFeatureParser, TrackCallerParser, UsedParser, }; use crate::attributes::confusables::ConfusablesParser; use crate::attributes::deprecation::DeprecationParser; @@ -65,23 +63,21 @@ use crate::attributes::traits::{ }; use crate::attributes::transparency::TransparencyParser; use crate::attributes::{AttributeParser as _, Combine, Single, WithoutArgs}; -use crate::context::MaybeWarn::{Allow, Error, Warn}; -use crate::parser::{ArgParser, MetaItemParser, PathParser}; -use crate::session_diagnostics::{ - AttributeParseError, AttributeParseErrorReason, InvalidTarget, UnknownMetaItem, -}; +use crate::parser::{ArgParser, PathParser}; +use crate::session_diagnostics::{AttributeParseError, AttributeParseErrorReason, UnknownMetaItem}; +use crate::target_checking::AllowedTargets; type GroupType<S> = LazyLock<GroupTypeInner<S>>; -struct GroupTypeInner<S: Stage> { - accepters: BTreeMap<&'static [Symbol], Vec<GroupTypeInnerAccept<S>>>, - finalizers: Vec<FinalizeFn<S>>, +pub(super) struct GroupTypeInner<S: Stage> { + pub(super) accepters: BTreeMap<&'static [Symbol], Vec<GroupTypeInnerAccept<S>>>, + pub(super) finalizers: Vec<FinalizeFn<S>>, } -struct GroupTypeInnerAccept<S: Stage> { - template: AttributeTemplate, - accept_fn: AcceptFn<S>, - allowed_targets: AllowedTargets, +pub(super) struct GroupTypeInnerAccept<S: Stage> { + pub(super) template: AttributeTemplate, + pub(super) accept_fn: AcceptFn<S>, + pub(super) allowed_targets: AllowedTargets, } type AcceptFn<S> = @@ -161,6 +157,7 @@ attribute_parsers!( // tidy-alphabetical-start Combine<AllowConstFnUnstableParser>, Combine<AllowInternalUnstableParser>, + Combine<ForceTargetFeatureParser>, Combine<ReprParser>, Combine<TargetFeatureParser>, Combine<UnstableFeatureBoundParser>, @@ -506,10 +503,11 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { }) } + /// produces an error along the lines of `expected one of [foo, meow]` pub(crate) fn expected_specific_argument( &self, span: Span, - possibilities: Vec<&'static str>, + possibilities: &[Symbol], ) -> ErrorGuaranteed { self.emit_err(AttributeParseError { span, @@ -525,10 +523,12 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { }) } + /// produces an error along the lines of `expected one of [foo, meow] as an argument`. + /// i.e. slightly different wording to [`expected_specific_argument`](Self::expected_specific_argument). pub(crate) fn expected_specific_argument_and_list( &self, span: Span, - possibilities: Vec<&'static str>, + possibilities: &[Symbol], ) -> ErrorGuaranteed { self.emit_err(AttributeParseError { span, @@ -544,10 +544,11 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { }) } + /// produces an error along the lines of `expected one of ["foo", "meow"]` pub(crate) fn expected_specific_argument_strings( &self, span: Span, - possibilities: Vec<&'static str>, + possibilities: &[Symbol], ) -> ErrorGuaranteed { self.emit_err(AttributeParseError { span, @@ -595,7 +596,7 @@ pub struct SharedContext<'p, 'sess, S: Stage> { /// The id ([`NodeId`] if `S` is `Early`, [`HirId`] if `S` is `Late`) of the syntactical component this attribute was applied to pub(crate) target_id: S::Id, - emit_lint: &'p mut dyn FnMut(AttributeLint<S::Id>), + pub(crate) emit_lint: &'p mut dyn FnMut(AttributeLint<S::Id>), } /// Context given to every attribute parser during finalization. @@ -666,557 +667,3 @@ impl ShouldEmit { } } } - -#[derive(Debug)] -pub(crate) enum AllowedTargets { - AllowList(&'static [MaybeWarn]), - AllowListWarnRest(&'static [MaybeWarn]), -} - -pub(crate) enum AllowedResult { - Allowed, - Warn, - Error, -} - -impl AllowedTargets { - pub(crate) fn is_allowed(&self, target: Target) -> AllowedResult { - match self { - AllowedTargets::AllowList(list) => { - if list.contains(&Allow(target)) { - AllowedResult::Allowed - } else if list.contains(&Warn(target)) { - AllowedResult::Warn - } else { - AllowedResult::Error - } - } - AllowedTargets::AllowListWarnRest(list) => { - if list.contains(&Allow(target)) { - AllowedResult::Allowed - } else if list.contains(&Error(target)) { - AllowedResult::Error - } else { - AllowedResult::Warn - } - } - } - } - - pub(crate) fn allowed_targets(&self) -> Vec<Target> { - match self { - AllowedTargets::AllowList(list) => list, - AllowedTargets::AllowListWarnRest(list) => list, - } - .iter() - .filter_map(|target| match target { - Allow(target) => Some(*target), - Warn(_) => None, - Error(_) => None, - }) - .collect() - } -} - -#[derive(Debug, Eq, PartialEq)] -pub(crate) enum MaybeWarn { - Allow(Target), - Warn(Target), - Error(Target), -} - -/// Context created once, for example as part of the ast lowering -/// context, through which all attributes can be lowered. -pub struct AttributeParser<'sess, S: Stage = Late> { - pub(crate) tools: Vec<Symbol>, - features: Option<&'sess Features>, - sess: &'sess Session, - stage: S, - - /// *Only* parse attributes with this symbol. - /// - /// Used in cases where we want the lowering infrastructure for parse just a single attribute. - parse_only: Option<Symbol>, -} - -impl<'sess> AttributeParser<'sess, Early> { - /// This method allows you to parse attributes *before* you have access to features or tools. - /// One example where this is necessary, is to parse `feature` attributes themselves for - /// example. - /// - /// Try to use this as little as possible. Attributes *should* be lowered during - /// `rustc_ast_lowering`. Some attributes require access to features to parse, which would - /// crash if you tried to do so through [`parse_limited`](Self::parse_limited). - /// - /// To make sure use is limited, supply a `Symbol` you'd like to parse. Only attributes with - /// that symbol are picked out of the list of instructions and parsed. Those are returned. - /// - /// No diagnostics will be emitted when parsing limited. Lints are not emitted at all, while - /// errors will be emitted as a delayed bugs. in other words, we *expect* attributes parsed - /// with `parse_limited` to be reparsed later during ast lowering where we *do* emit the errors - pub fn parse_limited( - sess: &'sess Session, - attrs: &[ast::Attribute], - sym: Symbol, - target_span: Span, - target_node_id: NodeId, - features: Option<&'sess Features>, - ) -> Option<Attribute> { - let mut p = Self { - features, - tools: Vec::new(), - parse_only: Some(sym), - sess, - stage: Early { emit_errors: ShouldEmit::Nothing }, - }; - let mut parsed = p.parse_attribute_list( - attrs, - target_span, - target_node_id, - Target::Crate, // Does not matter, we're not going to emit errors anyways - OmitDoc::Skip, - std::convert::identity, - |_lint| { - panic!("can't emit lints here for now (nothing uses this atm)"); - }, - ); - assert!(parsed.len() <= 1); - - parsed.pop() - } - - pub fn parse_single<T>( - sess: &'sess Session, - attr: &ast::Attribute, - target_span: Span, - target_node_id: NodeId, - features: Option<&'sess Features>, - emit_errors: ShouldEmit, - parse_fn: fn(cx: &mut AcceptContext<'_, '_, Early>, item: &ArgParser<'_>) -> T, - template: &AttributeTemplate, - ) -> T { - let mut parser = Self { - features, - tools: Vec::new(), - parse_only: None, - sess, - stage: Early { emit_errors }, - }; - let ast::AttrKind::Normal(normal_attr) = &attr.kind else { - panic!("parse_single called on a doc attr") - }; - let meta_parser = MetaItemParser::from_attr(normal_attr, parser.dcx()); - let path = meta_parser.path(); - let args = meta_parser.args(); - let mut cx: AcceptContext<'_, 'sess, Early> = AcceptContext { - shared: SharedContext { - cx: &mut parser, - target_span, - target_id: target_node_id, - emit_lint: &mut |_lint| { - panic!("can't emit lints here for now (nothing uses this atm)"); - }, - }, - attr_span: attr.span, - attr_style: attr.style, - template, - attr_path: path.get_attribute_path(), - }; - parse_fn(&mut cx, args) - } -} - -impl<'sess, S: Stage> AttributeParser<'sess, S> { - pub fn new( - sess: &'sess Session, - features: &'sess Features, - tools: Vec<Symbol>, - stage: S, - ) -> Self { - Self { features: Some(features), tools, parse_only: None, sess, stage } - } - - pub(crate) fn sess(&self) -> &'sess Session { - &self.sess - } - - pub(crate) fn features(&self) -> &'sess Features { - self.features.expect("features not available at this point in the compiler") - } - - pub(crate) fn features_option(&self) -> Option<&'sess Features> { - self.features - } - - pub(crate) fn dcx(&self) -> DiagCtxtHandle<'sess> { - self.sess().dcx() - } - - /// Parse a list of attributes. - /// - /// `target_span` is the span of the thing this list of attributes is applied to, - /// and when `omit_doc` is set, doc attributes are filtered out. - pub fn parse_attribute_list( - &mut self, - attrs: &[ast::Attribute], - target_span: Span, - target_id: S::Id, - target: Target, - omit_doc: OmitDoc, - - lower_span: impl Copy + Fn(Span) -> Span, - mut emit_lint: impl FnMut(AttributeLint<S::Id>), - ) -> Vec<Attribute> { - let mut attributes = Vec::new(); - let mut attr_paths = Vec::new(); - - for attr in attrs { - // If we're only looking for a single attribute, skip all the ones we don't care about. - if let Some(expected) = self.parse_only { - if !attr.has_name(expected) { - continue; - } - } - - // Sometimes, for example for `#![doc = include_str!("readme.md")]`, - // doc still contains a non-literal. You might say, when we're lowering attributes - // that's expanded right? But no, sometimes, when parsing attributes on macros, - // we already use the lowering logic and these are still there. So, when `omit_doc` - // is set we *also* want to ignore these. - if omit_doc == OmitDoc::Skip && attr.has_name(sym::doc) { - continue; - } - - match &attr.kind { - ast::AttrKind::DocComment(comment_kind, symbol) => { - if omit_doc == OmitDoc::Skip { - continue; - } - - attributes.push(Attribute::Parsed(AttributeKind::DocComment { - style: attr.style, - kind: *comment_kind, - span: lower_span(attr.span), - comment: *symbol, - })) - } - // // FIXME: make doc attributes go through a proper attribute parser - // ast::AttrKind::Normal(n) if n.has_name(sym::doc) => { - // let p = GenericMetaItemParser::from_attr(&n, self.dcx()); - // - // attributes.push(Attribute::Parsed(AttributeKind::DocComment { - // style: attr.style, - // kind: CommentKind::Line, - // span: attr.span, - // comment: p.args().name_value(), - // })) - // } - ast::AttrKind::Normal(n) => { - attr_paths.push(PathParser::Ast(&n.item.path)); - - let parser = MetaItemParser::from_attr(n, self.dcx()); - let path = parser.path(); - let args = parser.args(); - let parts = path.segments().map(|i| i.name).collect::<Vec<_>>(); - - if let Some(accepts) = S::parsers().accepters.get(parts.as_slice()) { - for accept in accepts { - let mut cx: AcceptContext<'_, 'sess, S> = AcceptContext { - shared: SharedContext { - cx: self, - target_span, - target_id, - emit_lint: &mut emit_lint, - }, - attr_span: lower_span(attr.span), - attr_style: attr.style, - template: &accept.template, - attr_path: path.get_attribute_path(), - }; - - (accept.accept_fn)(&mut cx, args); - - if self.stage.should_emit().should_emit() { - match accept.allowed_targets.is_allowed(target) { - AllowedResult::Allowed => {} - AllowedResult::Warn => { - let allowed_targets = - accept.allowed_targets.allowed_targets(); - let (applied, only) = allowed_targets_applied( - allowed_targets, - target, - self.features, - ); - emit_lint(AttributeLint { - id: target_id, - span: attr.span, - kind: AttributeLintKind::InvalidTarget { - name: parts[0], - target, - only: if only { "only " } else { "" }, - applied, - }, - }); - } - AllowedResult::Error => { - let allowed_targets = - accept.allowed_targets.allowed_targets(); - let (applied, only) = allowed_targets_applied( - allowed_targets, - target, - self.features, - ); - self.dcx().emit_err(InvalidTarget { - span: attr.span, - name: parts[0], - target: target.plural_name(), - only: if only { "only " } else { "" }, - applied, - }); - } - } - } - } - } else { - // If we're here, we must be compiling a tool attribute... Or someone - // forgot to parse their fancy new attribute. Let's warn them in any case. - // If you are that person, and you really think your attribute should - // remain unparsed, carefully read the documentation in this module and if - // you still think so you can add an exception to this assertion. - - // FIXME(jdonszelmann): convert other attributes, and check with this that - // we caught em all - // const FIXME_TEMPORARY_ATTR_ALLOWLIST: &[Symbol] = &[sym::cfg]; - // assert!( - // self.tools.contains(&parts[0]) || true, - // // || FIXME_TEMPORARY_ATTR_ALLOWLIST.contains(&parts[0]), - // "attribute {path} wasn't parsed and isn't a know tool attribute", - // ); - - attributes.push(Attribute::Unparsed(Box::new(AttrItem { - path: AttrPath::from_ast(&n.item.path), - args: self.lower_attr_args(&n.item.args, lower_span), - id: HashIgnoredAttrId { attr_id: attr.id }, - style: attr.style, - span: lower_span(attr.span), - }))); - } - } - } - } - - let mut parsed_attributes = Vec::new(); - for f in &S::parsers().finalizers { - if let Some(attr) = f(&mut FinalizeContext { - shared: SharedContext { - cx: self, - target_span, - target_id, - emit_lint: &mut emit_lint, - }, - all_attrs: &attr_paths, - }) { - parsed_attributes.push(Attribute::Parsed(attr)); - } - } - - attributes.extend(parsed_attributes); - - attributes - } - - /// Returns whether there is a parser for an attribute with this name - pub fn is_parsed_attribute(path: &[Symbol]) -> bool { - Late::parsers().accepters.contains_key(path) - } - - fn lower_attr_args(&self, args: &ast::AttrArgs, lower_span: impl Fn(Span) -> Span) -> AttrArgs { - match args { - ast::AttrArgs::Empty => AttrArgs::Empty, - ast::AttrArgs::Delimited(args) => AttrArgs::Delimited(args.clone()), - // This is an inert key-value attribute - it will never be visible to macros - // after it gets lowered to HIR. Therefore, we can extract literals to handle - // nonterminals in `#[doc]` (e.g. `#[doc = $e]`). - ast::AttrArgs::Eq { eq_span, expr } => { - // In valid code the value always ends up as a single literal. Otherwise, a dummy - // literal suffices because the error is handled elsewhere. - let lit = if let ast::ExprKind::Lit(token_lit) = expr.kind - && let Ok(lit) = - ast::MetaItemLit::from_token_lit(token_lit, lower_span(expr.span)) - { - lit - } else { - let guar = self.dcx().span_delayed_bug( - args.span().unwrap_or(DUMMY_SP), - "expr in place where literal is expected (builtin attr parsing)", - ); - ast::MetaItemLit { - symbol: sym::dummy, - suffix: None, - kind: ast::LitKind::Err(guar), - span: DUMMY_SP, - } - }; - AttrArgs::Eq { eq_span: lower_span(*eq_span), expr: lit } - } - } - } -} - -/// Takes a list of `allowed_targets` for an attribute, and the `target` the attribute was applied to. -/// Does some heuristic-based filtering to remove uninteresting targets, and formats the targets into a string -pub(crate) fn allowed_targets_applied( - mut allowed_targets: Vec<Target>, - target: Target, - features: Option<&Features>, -) -> (String, bool) { - // Remove unstable targets from `allowed_targets` if their features are not enabled - if let Some(features) = features { - if !features.fn_delegation() { - allowed_targets.retain(|t| !matches!(t, Target::Delegation { .. })); - } - if !features.stmt_expr_attributes() { - allowed_targets.retain(|t| !matches!(t, Target::Expression | Target::Statement)); - } - if !features.extern_types() { - allowed_targets.retain(|t| !matches!(t, Target::ForeignTy)); - } - } - - // We define groups of "similar" targets. - // If at least two of the targets are allowed, and the `target` is not in the group, - // we collapse the entire group to a single entry to simplify the target list - const FUNCTION_LIKE: &[Target] = &[ - Target::Fn, - Target::Closure, - Target::ForeignFn, - Target::Method(MethodKind::Inherent), - Target::Method(MethodKind::Trait { body: false }), - Target::Method(MethodKind::Trait { body: true }), - Target::Method(MethodKind::TraitImpl), - ]; - const METHOD_LIKE: &[Target] = &[ - Target::Method(MethodKind::Inherent), - Target::Method(MethodKind::Trait { body: false }), - Target::Method(MethodKind::Trait { body: true }), - Target::Method(MethodKind::TraitImpl), - ]; - const IMPL_LIKE: &[Target] = - &[Target::Impl { of_trait: false }, Target::Impl { of_trait: true }]; - const ADT_LIKE: &[Target] = &[Target::Struct, Target::Enum]; - - let mut added_fake_targets = Vec::new(); - filter_targets( - &mut allowed_targets, - FUNCTION_LIKE, - "functions", - target, - &mut added_fake_targets, - ); - filter_targets(&mut allowed_targets, METHOD_LIKE, "methods", target, &mut added_fake_targets); - filter_targets(&mut allowed_targets, IMPL_LIKE, "impl blocks", target, &mut added_fake_targets); - filter_targets(&mut allowed_targets, ADT_LIKE, "data types", target, &mut added_fake_targets); - - // If there is now only 1 target left, show that as the only possible target - ( - added_fake_targets - .iter() - .copied() - .chain(allowed_targets.iter().map(|t| t.plural_name())) - .join(", "), - allowed_targets.len() + added_fake_targets.len() == 1, - ) -} - -fn filter_targets( - allowed_targets: &mut Vec<Target>, - target_group: &'static [Target], - target_group_name: &'static str, - target: Target, - added_fake_targets: &mut Vec<&'static str>, -) { - if target_group.contains(&target) { - return; - } - if allowed_targets.iter().filter(|at| target_group.contains(at)).count() < 2 { - return; - } - allowed_targets.retain(|t| !target_group.contains(t)); - added_fake_targets.push(target_group_name); -} - -/// This is the list of all targets to which a attribute can be applied -/// This is used for: -/// - `rustc_dummy`, which can be applied to all targets -/// - Attributes that are not parted to the new target system yet can use this list as a placeholder -pub(crate) const ALL_TARGETS: &'static [MaybeWarn] = &[ - Allow(Target::ExternCrate), - Allow(Target::Use), - Allow(Target::Static), - Allow(Target::Const), - Allow(Target::Fn), - Allow(Target::Closure), - Allow(Target::Mod), - Allow(Target::ForeignMod), - Allow(Target::GlobalAsm), - Allow(Target::TyAlias), - Allow(Target::Enum), - Allow(Target::Variant), - Allow(Target::Struct), - Allow(Target::Field), - Allow(Target::Union), - Allow(Target::Trait), - Allow(Target::TraitAlias), - Allow(Target::Impl { of_trait: false }), - Allow(Target::Impl { of_trait: true }), - Allow(Target::Expression), - Allow(Target::Statement), - Allow(Target::Arm), - Allow(Target::AssocConst), - Allow(Target::Method(MethodKind::Inherent)), - Allow(Target::Method(MethodKind::Trait { body: false })), - Allow(Target::Method(MethodKind::Trait { body: true })), - Allow(Target::Method(MethodKind::TraitImpl)), - Allow(Target::AssocTy), - Allow(Target::ForeignFn), - Allow(Target::ForeignStatic), - Allow(Target::ForeignTy), - Allow(Target::MacroDef), - Allow(Target::Param), - Allow(Target::PatField), - Allow(Target::ExprField), - Allow(Target::WherePredicate), - Allow(Target::MacroCall), - Allow(Target::Crate), - Allow(Target::Delegation { mac: false }), - Allow(Target::Delegation { mac: true }), -]; - -/// Parse a single integer. -/// -/// Used by attributes that take a single integer as argument, such as -/// `#[link_ordinal]` and `#[rustc_layout_scalar_valid_range_start]`. -/// `cx` is the context given to the attribute. -/// `args` is the parser for the attribute arguments. -pub(crate) fn parse_single_integer<S: Stage>( - cx: &mut AcceptContext<'_, '_, S>, - args: &ArgParser<'_>, -) -> Option<u128> { - let Some(list) = args.list() else { - cx.expected_list(cx.attr_span); - return None; - }; - let Some(single) = list.single() else { - cx.expected_single_argument(list.span); - return None; - }; - let Some(lit) = single.lit() else { - cx.expected_integer_literal(single.span()); - return None; - }; - let LitKind::Int(num, _ty) = lit.kind else { - cx.expected_integer_literal(single.span()); - return None; - }; - Some(num.0) -} diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs new file mode 100644 index 00000000000..f652d39a708 --- /dev/null +++ b/compiler/rustc_attr_parsing/src/interface.rs @@ -0,0 +1,350 @@ +use std::borrow::Cow; + +use rustc_ast as ast; +use rustc_ast::NodeId; +use rustc_errors::DiagCtxtHandle; +use rustc_feature::{AttributeTemplate, Features}; +use rustc_hir::attrs::AttributeKind; +use rustc_hir::lints::AttributeLint; +use rustc_hir::{AttrArgs, AttrItem, AttrPath, Attribute, HashIgnoredAttrId, Target}; +use rustc_session::Session; +use rustc_span::{DUMMY_SP, Span, Symbol, sym}; + +use crate::context::{AcceptContext, FinalizeContext, SharedContext, Stage}; +use crate::parser::{ArgParser, MetaItemParser, PathParser}; +use crate::{Early, Late, OmitDoc, ShouldEmit}; + +/// Context created once, for example as part of the ast lowering +/// context, through which all attributes can be lowered. +pub struct AttributeParser<'sess, S: Stage = Late> { + pub(crate) tools: Vec<Symbol>, + pub(crate) features: Option<&'sess Features>, + pub(crate) sess: &'sess Session, + pub(crate) stage: S, + + /// *Only* parse attributes with this symbol. + /// + /// Used in cases where we want the lowering infrastructure for parse just a single attribute. + parse_only: Option<Symbol>, +} + +impl<'sess> AttributeParser<'sess, Early> { + /// This method allows you to parse attributes *before* you have access to features or tools. + /// One example where this is necessary, is to parse `feature` attributes themselves for + /// example. + /// + /// Try to use this as little as possible. Attributes *should* be lowered during + /// `rustc_ast_lowering`. Some attributes require access to features to parse, which would + /// crash if you tried to do so through [`parse_limited`](Self::parse_limited). + /// + /// To make sure use is limited, supply a `Symbol` you'd like to parse. Only attributes with + /// that symbol are picked out of the list of instructions and parsed. Those are returned. + /// + /// No diagnostics will be emitted when parsing limited. Lints are not emitted at all, while + /// errors will be emitted as a delayed bugs. in other words, we *expect* attributes parsed + /// with `parse_limited` to be reparsed later during ast lowering where we *do* emit the errors + pub fn parse_limited( + sess: &'sess Session, + attrs: &[ast::Attribute], + sym: Symbol, + target_span: Span, + target_node_id: NodeId, + features: Option<&'sess Features>, + ) -> Option<Attribute> { + let mut parsed = Self::parse_limited_all( + sess, + attrs, + Some(sym), + Target::Crate, // Does not matter, we're not going to emit errors anyways + target_span, + target_node_id, + features, + ShouldEmit::Nothing, + ); + assert!(parsed.len() <= 1); + parsed.pop() + } + + pub fn parse_limited_all( + sess: &'sess Session, + attrs: &[ast::Attribute], + parse_only: Option<Symbol>, + target: Target, + target_span: Span, + target_node_id: NodeId, + features: Option<&'sess Features>, + emit_errors: ShouldEmit, + ) -> Vec<Attribute> { + let mut p = + Self { features, tools: Vec::new(), parse_only, sess, stage: Early { emit_errors } }; + p.parse_attribute_list( + attrs, + target_span, + target_node_id, + target, + OmitDoc::Skip, + std::convert::identity, + |_lint| { + // FIXME: Can't emit lints here for now + // This branch can be hit when an attribute produces a warning during early parsing (such as attributes on macro calls) + }, + ) + } + + pub fn parse_single<T>( + sess: &'sess Session, + attr: &ast::Attribute, + target_span: Span, + target_node_id: NodeId, + features: Option<&'sess Features>, + emit_errors: ShouldEmit, + parse_fn: fn(cx: &mut AcceptContext<'_, '_, Early>, item: &ArgParser<'_>) -> Option<T>, + template: &AttributeTemplate, + ) -> Option<T> { + let mut parser = Self { + features, + tools: Vec::new(), + parse_only: None, + sess, + stage: Early { emit_errors }, + }; + let ast::AttrKind::Normal(normal_attr) = &attr.kind else { + panic!("parse_single called on a doc attr") + }; + let parts = + normal_attr.item.path.segments.iter().map(|seg| seg.ident.name).collect::<Vec<_>>(); + let meta_parser = MetaItemParser::from_attr(normal_attr, &parts, &sess.psess, emit_errors)?; + let path = meta_parser.path(); + let args = meta_parser.args(); + let mut cx: AcceptContext<'_, 'sess, Early> = AcceptContext { + shared: SharedContext { + cx: &mut parser, + target_span, + target_id: target_node_id, + emit_lint: &mut |_lint| { + panic!("can't emit lints here for now (nothing uses this atm)"); + }, + }, + attr_span: attr.span, + attr_style: attr.style, + template, + attr_path: path.get_attribute_path(), + }; + parse_fn(&mut cx, args) + } +} + +impl<'sess, S: Stage> AttributeParser<'sess, S> { + pub fn new( + sess: &'sess Session, + features: &'sess Features, + tools: Vec<Symbol>, + stage: S, + ) -> Self { + Self { features: Some(features), tools, parse_only: None, sess, stage } + } + + pub(crate) fn sess(&self) -> &'sess Session { + &self.sess + } + + pub(crate) fn features(&self) -> &'sess Features { + self.features.expect("features not available at this point in the compiler") + } + + pub(crate) fn features_option(&self) -> Option<&'sess Features> { + self.features + } + + pub(crate) fn dcx(&self) -> DiagCtxtHandle<'sess> { + self.sess().dcx() + } + + /// Parse a list of attributes. + /// + /// `target_span` is the span of the thing this list of attributes is applied to, + /// and when `omit_doc` is set, doc attributes are filtered out. + pub fn parse_attribute_list( + &mut self, + attrs: &[ast::Attribute], + target_span: Span, + target_id: S::Id, + target: Target, + omit_doc: OmitDoc, + + lower_span: impl Copy + Fn(Span) -> Span, + mut emit_lint: impl FnMut(AttributeLint<S::Id>), + ) -> Vec<Attribute> { + let mut attributes = Vec::new(); + let mut attr_paths = Vec::new(); + + for attr in attrs { + // If we're only looking for a single attribute, skip all the ones we don't care about. + if let Some(expected) = self.parse_only { + if !attr.has_name(expected) { + continue; + } + } + + // Sometimes, for example for `#![doc = include_str!("readme.md")]`, + // doc still contains a non-literal. You might say, when we're lowering attributes + // that's expanded right? But no, sometimes, when parsing attributes on macros, + // we already use the lowering logic and these are still there. So, when `omit_doc` + // is set we *also* want to ignore these. + if omit_doc == OmitDoc::Skip && attr.has_name(sym::doc) { + continue; + } + + match &attr.kind { + ast::AttrKind::DocComment(comment_kind, symbol) => { + if omit_doc == OmitDoc::Skip { + continue; + } + + attributes.push(Attribute::Parsed(AttributeKind::DocComment { + style: attr.style, + kind: *comment_kind, + span: lower_span(attr.span), + comment: *symbol, + })) + } + // // FIXME: make doc attributes go through a proper attribute parser + // ast::AttrKind::Normal(n) if n.has_name(sym::doc) => { + // let p = GenericMetaItemParser::from_attr(&n, self.dcx()); + // + // attributes.push(Attribute::Parsed(AttributeKind::DocComment { + // style: attr.style, + // kind: CommentKind::Line, + // span: attr.span, + // comment: p.args().name_value(), + // })) + // } + ast::AttrKind::Normal(n) => { + attr_paths.push(PathParser(Cow::Borrowed(&n.item.path))); + + let parts = + n.item.path.segments.iter().map(|seg| seg.ident.name).collect::<Vec<_>>(); + + if let Some(accepts) = S::parsers().accepters.get(parts.as_slice()) { + let Some(parser) = MetaItemParser::from_attr( + n, + &parts, + &self.sess.psess, + self.stage.should_emit(), + ) else { + continue; + }; + let path = parser.path(); + let args = parser.args(); + for accept in accepts { + let mut cx: AcceptContext<'_, 'sess, S> = AcceptContext { + shared: SharedContext { + cx: self, + target_span, + target_id, + emit_lint: &mut emit_lint, + }, + attr_span: lower_span(attr.span), + attr_style: attr.style, + template: &accept.template, + attr_path: path.get_attribute_path(), + }; + + (accept.accept_fn)(&mut cx, args); + + if self.stage.should_emit().should_emit() { + self.check_target( + path.get_attribute_path(), + attr.span, + &accept.allowed_targets, + target, + target_id, + &mut emit_lint, + ); + } + } + } else { + // If we're here, we must be compiling a tool attribute... Or someone + // forgot to parse their fancy new attribute. Let's warn them in any case. + // If you are that person, and you really think your attribute should + // remain unparsed, carefully read the documentation in this module and if + // you still think so you can add an exception to this assertion. + + // FIXME(jdonszelmann): convert other attributes, and check with this that + // we caught em all + // const FIXME_TEMPORARY_ATTR_ALLOWLIST: &[Symbol] = &[sym::cfg]; + // assert!( + // self.tools.contains(&parts[0]) || true, + // // || FIXME_TEMPORARY_ATTR_ALLOWLIST.contains(&parts[0]), + // "attribute {path} wasn't parsed and isn't a know tool attribute", + // ); + + attributes.push(Attribute::Unparsed(Box::new(AttrItem { + path: AttrPath::from_ast(&n.item.path), + args: self.lower_attr_args(&n.item.args, lower_span), + id: HashIgnoredAttrId { attr_id: attr.id }, + style: attr.style, + span: lower_span(attr.span), + }))); + } + } + } + } + + let mut parsed_attributes = Vec::new(); + for f in &S::parsers().finalizers { + if let Some(attr) = f(&mut FinalizeContext { + shared: SharedContext { + cx: self, + target_span, + target_id, + emit_lint: &mut emit_lint, + }, + all_attrs: &attr_paths, + }) { + parsed_attributes.push(Attribute::Parsed(attr)); + } + } + + attributes.extend(parsed_attributes); + + attributes + } + + /// Returns whether there is a parser for an attribute with this name + pub fn is_parsed_attribute(path: &[Symbol]) -> bool { + Late::parsers().accepters.contains_key(path) + } + + fn lower_attr_args(&self, args: &ast::AttrArgs, lower_span: impl Fn(Span) -> Span) -> AttrArgs { + match args { + ast::AttrArgs::Empty => AttrArgs::Empty, + ast::AttrArgs::Delimited(args) => AttrArgs::Delimited(args.clone()), + // This is an inert key-value attribute - it will never be visible to macros + // after it gets lowered to HIR. Therefore, we can extract literals to handle + // nonterminals in `#[doc]` (e.g. `#[doc = $e]`). + ast::AttrArgs::Eq { eq_span, expr } => { + // In valid code the value always ends up as a single literal. Otherwise, a dummy + // literal suffices because the error is handled elsewhere. + let lit = if let ast::ExprKind::Lit(token_lit) = expr.kind + && let Ok(lit) = + ast::MetaItemLit::from_token_lit(token_lit, lower_span(expr.span)) + { + lit + } else { + let guar = self.dcx().span_delayed_bug( + args.span().unwrap_or(DUMMY_SP), + "expr in place where literal is expected (builtin attr parsing)", + ); + ast::MetaItemLit { + symbol: sym::dummy, + suffix: None, + kind: ast::LitKind::Err(guar), + span: DUMMY_SP, + } + }; + AttrArgs::Eq { eq_span: lower_span(*eq_span), expr: lit } + } + } + } +} diff --git a/compiler/rustc_attr_parsing/src/lib.rs b/compiler/rustc_attr_parsing/src/lib.rs index fc1377e5314..969c24a4f89 100644 --- a/compiler/rustc_attr_parsing/src/lib.rs +++ b/compiler/rustc_attr_parsing/src/lib.rs @@ -84,18 +84,33 @@ // tidy-alphabetical-end #[macro_use] +/// All the individual attribute parsers for each of rustc's built-in attributes. mod attributes; + +/// All the important types given to attribute parsers when parsing pub(crate) mod context; -mod lints; + +/// Code that other crates interact with, to actually parse a list (or sometimes single) +/// attribute. +mod interface; + +/// Despite this entire module called attribute parsing and the term being a little overloaded, +/// in this module the code lives that actually breaks up tokenstreams into semantic pieces of attributes, +/// like lists or name-value pairs. pub mod parser; + +mod lints; mod session_diagnostics; +mod target_checking; +pub mod validate_attr; pub use attributes::cfg::{CFG_TEMPLATE, EvalConfigResult, eval_config_entry, parse_cfg_attr}; pub use attributes::cfg_old::*; pub use attributes::util::{ find_crate_name, is_builtin_attr, is_doc_alias_attrs_contain_symbol, parse_version, }; -pub use context::{AttributeParser, Early, Late, OmitDoc, ShouldEmit}; +pub use context::{Early, Late, OmitDoc, ShouldEmit}; +pub use interface::AttributeParser; pub use lints::emit_attribute_lint; rustc_fluent_macro::fluent_messages! { "../messages.ftl" } diff --git a/compiler/rustc_attr_parsing/src/lints.rs b/compiler/rustc_attr_parsing/src/lints.rs index 2813fef3148..7030f28f23c 100644 --- a/compiler/rustc_attr_parsing/src/lints.rs +++ b/compiler/rustc_attr_parsing/src/lints.rs @@ -1,3 +1,5 @@ +use std::borrow::Cow; + use rustc_errors::{DiagArgValue, LintEmitter}; use rustc_hir::lints::{AttributeLint, AttributeLintKind}; use rustc_hir::{HirId, Target}; @@ -35,12 +37,12 @@ pub fn emit_attribute_lint<L: LintEmitter>(lint: &AttributeLint<HirId>, lint_emi *first_span, session_diagnostics::EmptyAttributeList { attr_span: *first_span }, ), - &AttributeLintKind::InvalidTarget { name, target, ref applied, only } => lint_emitter + AttributeLintKind::InvalidTarget { name, target, applied, only } => lint_emitter .emit_node_span_lint( // This check is here because `deprecated` had its own lint group and removing this would be a breaking change - if name == sym::deprecated + if name.segments[0].name == sym::deprecated && ![Target::Closure, Target::Expression, Target::Statement, Target::Arm] - .contains(&target) + .contains(target) { rustc_session::lint::builtin::USELESS_DEPRECATED } else { @@ -51,7 +53,9 @@ pub fn emit_attribute_lint<L: LintEmitter>(lint: &AttributeLint<HirId>, lint_emi session_diagnostics::InvalidTargetLint { name, target: target.plural_name(), - applied: applied.clone(), + applied: DiagArgValue::StrListSepByAnd( + applied.into_iter().map(|i| Cow::Owned(i.to_string())).collect(), + ), only, attr_span: *span, }, diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs index aecaae947c9..364f8819d13 100644 --- a/compiler/rustc_attr_parsing/src/parser.rs +++ b/compiler/rustc_attr_parsing/src/parser.rs @@ -3,45 +3,30 @@ //! //! FIXME(jdonszelmann): delete `rustc_ast/attr/mod.rs` +use std::borrow::Cow; use std::fmt::{Debug, Display}; -use std::iter::Peekable; -use rustc_ast::token::{self, Delimiter, Token}; -use rustc_ast::tokenstream::{TokenStreamIter, TokenTree}; +use rustc_ast::token::{self, Delimiter, MetaVarKind}; +use rustc_ast::tokenstream::TokenStream; use rustc_ast::{AttrArgs, DelimArgs, Expr, ExprKind, LitKind, MetaItemLit, NormalAttr, Path}; use rustc_ast_pretty::pprust; -use rustc_errors::DiagCtxtHandle; +use rustc_errors::PResult; use rustc_hir::{self as hir, AttrPath}; -use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol, kw, sym}; - -pub struct SegmentIterator<'a> { - offset: usize, - path: &'a PathParser<'a>, -} - -impl<'a> Iterator for SegmentIterator<'a> { - type Item = &'a Ident; - - fn next(&mut self) -> Option<Self::Item> { - if self.offset >= self.path.len() { - return None; - } - - let res = match self.path { - PathParser::Ast(ast_path) => &ast_path.segments[self.offset].ident, - PathParser::Attr(attr_path) => &attr_path.segments[self.offset], - }; - - self.offset += 1; - Some(res) - } -} +use rustc_parse::exp; +use rustc_parse::parser::{Parser, PathStyle, token_descr}; +use rustc_session::errors::report_lit_error; +use rustc_session::parse::ParseSess; +use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol, sym}; +use thin_vec::ThinVec; + +use crate::ShouldEmit; +use crate::session_diagnostics::{ + InvalidMetaItem, InvalidMetaItemQuoteIdentSugg, InvalidMetaItemRemoveNegSugg, MetaBadDelim, + MetaBadDelimSugg, SuffixedLiteralInAttribute, +}; #[derive(Clone, Debug)] -pub enum PathParser<'a> { - Ast(&'a Path), - Attr(AttrPath), -} +pub struct PathParser<'a>(pub Cow<'a, Path>); impl<'a> PathParser<'a> { pub fn get_attribute_path(&self) -> hir::AttrPath { @@ -52,21 +37,15 @@ impl<'a> PathParser<'a> { } pub fn segments(&'a self) -> impl Iterator<Item = &'a Ident> { - SegmentIterator { offset: 0, path: self } + self.0.segments.iter().map(|seg| &seg.ident) } pub fn span(&self) -> Span { - match self { - PathParser::Ast(path) => path.span, - PathParser::Attr(attr_path) => attr_path.span, - } + self.0.span } pub fn len(&self) -> usize { - match self { - PathParser::Ast(path) => path.segments.len(), - PathParser::Attr(attr_path) => attr_path.segments.len(), - } + self.0.segments.len() } pub fn segments_is(&self, segments: &[Symbol]) -> bool { @@ -99,10 +78,7 @@ impl<'a> PathParser<'a> { impl Display for PathParser<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - PathParser::Ast(path) => write!(f, "{}", pprust::path_to_string(path)), - PathParser::Attr(attr_path) => write!(f, "{attr_path}"), - } + write!(f, "{}", pprust::path_to_string(&self.0)) } } @@ -123,21 +99,39 @@ impl<'a> ArgParser<'a> { } } - pub fn from_attr_args<'sess>(value: &'a AttrArgs, dcx: DiagCtxtHandle<'sess>) -> Self { - match value { + pub fn from_attr_args<'sess>( + value: &'a AttrArgs, + parts: &[Symbol], + psess: &'sess ParseSess, + should_emit: ShouldEmit, + ) -> Option<Self> { + Some(match value { AttrArgs::Empty => Self::NoArgs, - AttrArgs::Delimited(args) if args.delim == Delimiter::Parenthesis => { - Self::List(MetaItemListParser::new(args, dcx)) - } AttrArgs::Delimited(args) => { - Self::List(MetaItemListParser { sub_parsers: vec![], span: args.dspan.entire() }) + // The arguments of rustc_dummy are not validated if the arguments are delimited + if parts == &[sym::rustc_dummy] { + return Some(ArgParser::List(MetaItemListParser { + sub_parsers: ThinVec::new(), + span: args.dspan.entire(), + })); + } + + if args.delim != Delimiter::Parenthesis { + psess.dcx().emit_err(MetaBadDelim { + span: args.dspan.entire(), + sugg: MetaBadDelimSugg { open: args.dspan.open, close: args.dspan.close }, + }); + return None; + } + + Self::List(MetaItemListParser::new(args, psess, should_emit)?) } AttrArgs::Eq { eq_span, expr } => Self::NameValue(NameValueParser { eq_span: *eq_span, - value: expr_to_lit(dcx, &expr, *eq_span), + value: expr_to_lit(psess, &expr, expr.span, should_emit)?, value_span: expr.span, }), - } + }) } /// Asserts that this MetaItem is a list @@ -249,11 +243,16 @@ impl<'a> Debug for MetaItemParser<'a> { impl<'a> MetaItemParser<'a> { /// Create a new parser from a [`NormalAttr`], which is stored inside of any /// [`ast::Attribute`](rustc_ast::Attribute) - pub fn from_attr<'sess>(attr: &'a NormalAttr, dcx: DiagCtxtHandle<'sess>) -> Self { - Self { - path: PathParser::Ast(&attr.item.path), - args: ArgParser::from_attr_args(&attr.item.args, dcx), - } + pub fn from_attr<'sess>( + attr: &'a NormalAttr, + parts: &[Symbol], + psess: &'sess ParseSess, + should_emit: ShouldEmit, + ) -> Option<Self> { + Some(Self { + path: PathParser(Cow::Borrowed(&attr.item.path)), + args: ArgParser::from_attr_args(&attr.item.args, parts, psess, should_emit)?, + }) } } @@ -318,215 +317,232 @@ impl NameValueParser { } } -fn expr_to_lit(dcx: DiagCtxtHandle<'_>, expr: &Expr, span: Span) -> MetaItemLit { - // In valid code the value always ends up as a single literal. Otherwise, a dummy - // literal suffices because the error is handled elsewhere. - if let ExprKind::Lit(token_lit) = expr.kind - && let Ok(lit) = MetaItemLit::from_token_lit(token_lit, expr.span) - { - lit +fn expr_to_lit( + psess: &ParseSess, + expr: &Expr, + span: Span, + should_emit: ShouldEmit, +) -> Option<MetaItemLit> { + if let ExprKind::Lit(token_lit) = expr.kind { + let res = MetaItemLit::from_token_lit(token_lit, expr.span); + match res { + Ok(lit) => { + if token_lit.suffix.is_some() { + psess + .dcx() + .create_err(SuffixedLiteralInAttribute { span: lit.span }) + .emit_unless_delay(!should_emit.should_emit()); + None + } else { + if should_emit.should_emit() && !lit.kind.is_unsuffixed() { + // Emit error and continue, we can still parse the attribute as if the suffix isn't there + psess.dcx().emit_err(SuffixedLiteralInAttribute { span: lit.span }); + } + + Some(lit) + } + } + Err(err) => { + let guar = report_lit_error(psess, err, token_lit, expr.span); + let lit = MetaItemLit { + symbol: token_lit.symbol, + suffix: token_lit.suffix, + kind: LitKind::Err(guar), + span: expr.span, + }; + Some(lit) + } + } } else { - let guar = dcx.span_delayed_bug( - span, - "expr in place where literal is expected (builtin attr parsing)", - ); - MetaItemLit { symbol: sym::dummy, suffix: None, kind: LitKind::Err(guar), span } + // Example cases: + // - `#[foo = 1+1]`: results in `ast::ExprKind::BinOp`. + // - `#[foo = include_str!("nonexistent-file.rs")]`: + // results in `ast::ExprKind::Err`. In that case we delay + // the error because an earlier error will have already + // been reported. + let msg = "attribute value must be a literal"; + let mut err = psess.dcx().struct_span_err(span, msg); + if let ExprKind::Err(_) = expr.kind { + err.downgrade_to_delayed_bug(); + } + + err.emit_unless_delay(!should_emit.should_emit()); + None } } struct MetaItemListParserContext<'a, 'sess> { - // the tokens inside the delimiters, so `#[some::attr(a b c)]` would have `a b c` inside - inside_delimiters: Peekable<TokenStreamIter<'a>>, - dcx: DiagCtxtHandle<'sess>, + parser: &'a mut Parser<'sess>, + should_emit: ShouldEmit, } impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> { - fn done(&mut self) -> bool { - self.inside_delimiters.peek().is_none() - } - - fn next_path(&mut self) -> Option<AttrPath> { - // FIXME: Share code with `parse_path`. - let tt = self.inside_delimiters.next().map(|tt| TokenTree::uninterpolate(tt)); - - match tt.as_deref()? { - &TokenTree::Token( - Token { kind: ref kind @ (token::Ident(..) | token::PathSep), span }, - _, - ) => { - // here we have either an ident or pathsep `::`. - - let mut segments = if let &token::Ident(name, _) = kind { - // when we lookahead another pathsep, more path's coming - if let Some(TokenTree::Token(Token { kind: token::PathSep, .. }, _)) = - self.inside_delimiters.peek() - { - self.inside_delimiters.next(); - vec![Ident::new(name, span)] - } else { - // else we have a single identifier path, that's all - return Some(AttrPath { - segments: vec![Ident::new(name, span)].into_boxed_slice(), - span, - }); - } - } else { - // if `::` is all we get, we just got a path root - vec![Ident::new(kw::PathRoot, span)] - }; + fn parse_unsuffixed_meta_item_lit(&mut self) -> PResult<'sess, MetaItemLit> { + let uninterpolated_span = self.parser.token_uninterpolated_span(); + let Some(token_lit) = self.parser.eat_token_lit() else { + return self.parser.handle_missing_lit(Parser::mk_meta_item_lit_char); + }; - // one segment accepted. accept n more - loop { - // another ident? - if let Some(&TokenTree::Token(Token { kind: token::Ident(name, _), span }, _)) = - self.inside_delimiters - .next() - .map(|tt| TokenTree::uninterpolate(tt)) - .as_deref() - { - segments.push(Ident::new(name, span)); - } else { - return None; - } - // stop unless we see another `::` - if let Some(TokenTree::Token(Token { kind: token::PathSep, .. }, _)) = - self.inside_delimiters.peek() - { - self.inside_delimiters.next(); - } else { - break; - } - } - let span = span.with_hi(segments.last().unwrap().span.hi()); - Some(AttrPath { segments: segments.into_boxed_slice(), span }) - } - TokenTree::Token(Token { kind, .. }, _) if kind.is_delim() => None, - _ => { - // malformed attributes can get here. We can't crash, but somewhere else should've - // already warned for this. - None + let lit = match MetaItemLit::from_token_lit(token_lit, self.parser.prev_token.span) { + Ok(lit) => lit, + Err(err) => { + let guar = + report_lit_error(&self.parser.psess, err, token_lit, uninterpolated_span); + // Pack possible quotes and prefixes from the original literal into + // the error literal's symbol so they can be pretty-printed faithfully. + let suffixless_lit = token::Lit::new(token_lit.kind, token_lit.symbol, None); + let symbol = Symbol::intern(&suffixless_lit.to_string()); + let token_lit = token::Lit::new(token::Err(guar), symbol, token_lit.suffix); + MetaItemLit::from_token_lit(token_lit, uninterpolated_span).unwrap() } + }; + + if self.should_emit.should_emit() && !lit.kind.is_unsuffixed() { + // Emit error and continue, we can still parse the attribute as if the suffix isn't there + self.parser.dcx().emit_err(SuffixedLiteralInAttribute { span: lit.span }); } - } - fn value(&mut self) -> Option<MetaItemLit> { - match self.inside_delimiters.next() { - Some(TokenTree::Delimited(.., Delimiter::Invisible(_), inner_tokens)) => { - MetaItemListParserContext { - inside_delimiters: inner_tokens.iter().peekable(), - dcx: self.dcx, - } - .value() - } - Some(TokenTree::Token(token, _)) => MetaItemLit::from_token(token), - _ => None, + Ok(lit) + } + + fn parse_attr_item(&mut self) -> PResult<'sess, MetaItemParser<'static>> { + if let Some(MetaVarKind::Meta { has_meta_form }) = self.parser.token.is_metavar_seq() { + return if has_meta_form { + let attr_item = self + .parser + .eat_metavar_seq(MetaVarKind::Meta { has_meta_form: true }, |this| { + MetaItemListParserContext { parser: this, should_emit: self.should_emit } + .parse_attr_item() + }) + .unwrap(); + Ok(attr_item) + } else { + self.parser.unexpected_any() + }; } + + let path = self.parser.parse_path(PathStyle::Mod)?; + + // Check style of arguments that this meta item has + let args = if self.parser.check(exp!(OpenParen)) { + let start = self.parser.token.span; + let (sub_parsers, _) = self.parser.parse_paren_comma_seq(|parser| { + MetaItemListParserContext { parser, should_emit: self.should_emit } + .parse_meta_item_inner() + })?; + let end = self.parser.prev_token.span; + ArgParser::List(MetaItemListParser { sub_parsers, span: start.with_hi(end.hi()) }) + } else if self.parser.eat(exp!(Eq)) { + let eq_span = self.parser.prev_token.span; + let value = self.parse_unsuffixed_meta_item_lit()?; + + ArgParser::NameValue(NameValueParser { eq_span, value, value_span: value.span }) + } else { + ArgParser::NoArgs + }; + + Ok(MetaItemParser { path: PathParser(Cow::Owned(path)), args }) } - /// parses one element on the inside of a list attribute like `#[my_attr( <insides> )]` - /// - /// parses a path followed be either: - /// 1. nothing (a word attr) - /// 2. a parenthesized list - /// 3. an equals sign and a literal (name-value) - /// - /// Can also parse *just* a literal. This is for cases like as `#[my_attr("literal")]` - /// where no path is given before the literal - /// - /// Some exceptions too for interpolated attributes which are already pre-processed - fn next(&mut self) -> Option<MetaItemOrLitParser<'a>> { - // a list element is either a literal - if let Some(TokenTree::Token(token, _)) = self.inside_delimiters.peek() - && let Some(lit) = MetaItemLit::from_token(token) - { - self.inside_delimiters.next(); - return Some(MetaItemOrLitParser::Lit(lit)); - } else if let Some(TokenTree::Delimited(.., Delimiter::Invisible(_), inner_tokens)) = - self.inside_delimiters.peek() + fn parse_meta_item_inner(&mut self) -> PResult<'sess, MetaItemOrLitParser<'static>> { + match self.parse_unsuffixed_meta_item_lit() { + Ok(lit) => return Ok(MetaItemOrLitParser::Lit(lit)), + Err(err) => err.cancel(), // we provide a better error below + } + + match self.parse_attr_item() { + Ok(mi) => return Ok(MetaItemOrLitParser::MetaItemParser(mi)), + Err(err) => err.cancel(), // we provide a better error below + } + + let mut err = InvalidMetaItem { + span: self.parser.token.span, + descr: token_descr(&self.parser.token), + quote_ident_sugg: None, + remove_neg_sugg: None, + }; + + // Suggest quoting idents, e.g. in `#[cfg(key = value)]`. We don't use `Token::ident` and + // don't `uninterpolate` the token to avoid suggesting anything butchered or questionable + // when macro metavariables are involved. + if self.parser.prev_token == token::Eq + && let token::Ident(..) = self.parser.token.kind { - self.inside_delimiters.next(); - return MetaItemListParserContext { - inside_delimiters: inner_tokens.iter().peekable(), - dcx: self.dcx, + let before = self.parser.token.span.shrink_to_lo(); + while let token::Ident(..) = self.parser.token.kind { + self.parser.bump(); } - .next(); + err.quote_ident_sugg = Some(InvalidMetaItemQuoteIdentSugg { + before, + after: self.parser.prev_token.span.shrink_to_hi(), + }); } - // or a path. - let path = self.next_path()?; - - // Paths can be followed by: - // - `(more meta items)` (another list) - // - `= lit` (a name-value) - // - nothing - Some(MetaItemOrLitParser::MetaItemParser(match self.inside_delimiters.peek() { - Some(TokenTree::Delimited(dspan, _, Delimiter::Parenthesis, inner_tokens)) => { - self.inside_delimiters.next(); - - MetaItemParser { - path: PathParser::Attr(path), - args: ArgParser::List(MetaItemListParser::new_tts( - inner_tokens.iter(), - dspan.entire(), - self.dcx, - )), - } - } - Some(TokenTree::Delimited(_, ..)) => { - self.inside_delimiters.next(); - // self.dcx.span_delayed_bug(span.entire(), "wrong delimiters"); - return None; - } - Some(TokenTree::Token(Token { kind: token::Eq, span }, _)) => { - self.inside_delimiters.next(); - let value = self.value()?; - MetaItemParser { - path: PathParser::Attr(path), - args: ArgParser::NameValue(NameValueParser { - eq_span: *span, - value_span: value.span, - value, - }), - } - } - _ => MetaItemParser { path: PathParser::Attr(path), args: ArgParser::NoArgs }, - })) + if self.parser.token == token::Minus + && self + .parser + .look_ahead(1, |t| matches!(t.kind, rustc_ast::token::TokenKind::Literal { .. })) + { + err.remove_neg_sugg = + Some(InvalidMetaItemRemoveNegSugg { negative_sign: self.parser.token.span }); + self.parser.bump(); + self.parser.bump(); + } + + Err(self.parser.dcx().create_err(err)) } - fn parse(mut self, span: Span) -> MetaItemListParser<'a> { - let mut sub_parsers = Vec::new(); + fn parse( + tokens: TokenStream, + psess: &'sess ParseSess, + span: Span, + should_emit: ShouldEmit, + ) -> PResult<'sess, MetaItemListParser<'static>> { + let mut parser = Parser::new(psess, tokens, None); + let mut this = MetaItemListParserContext { parser: &mut parser, should_emit }; - while !self.done() { - let Some(n) = self.next() else { - continue; - }; - sub_parsers.push(n); + // Presumably, the majority of the time there will only be one attr. + let mut sub_parsers = ThinVec::with_capacity(1); + while this.parser.token != token::Eof { + sub_parsers.push(this.parse_meta_item_inner()?); - match self.inside_delimiters.peek() { - None | Some(TokenTree::Token(Token { kind: token::Comma, .. }, _)) => { - self.inside_delimiters.next(); - } - Some(_) => {} + if !this.parser.eat(exp!(Comma)) { + break; } } - MetaItemListParser { sub_parsers, span } + if parser.token != token::Eof { + parser.unexpected()?; + } + + Ok(MetaItemListParser { sub_parsers, span }) } } #[derive(Debug, Clone)] pub struct MetaItemListParser<'a> { - sub_parsers: Vec<MetaItemOrLitParser<'a>>, + sub_parsers: ThinVec<MetaItemOrLitParser<'a>>, pub span: Span, } impl<'a> MetaItemListParser<'a> { - fn new<'sess>(delim: &'a DelimArgs, dcx: DiagCtxtHandle<'sess>) -> Self { - MetaItemListParser::new_tts(delim.tokens.iter(), delim.dspan.entire(), dcx) - } - - fn new_tts<'sess>(tts: TokenStreamIter<'a>, span: Span, dcx: DiagCtxtHandle<'sess>) -> Self { - MetaItemListParserContext { inside_delimiters: tts.peekable(), dcx }.parse(span) + fn new<'sess>( + delim: &'a DelimArgs, + psess: &'sess ParseSess, + should_emit: ShouldEmit, + ) -> Option<Self> { + match MetaItemListParserContext::parse( + delim.tokens.clone(), + psess, + delim.dspan.entire(), + should_emit, + ) { + Ok(s) => Some(s), + Err(e) => { + e.emit_unless_delay(!should_emit.should_emit()); + None + } + } } /// Lets you pick and choose as what you want to parse each element in the list diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index aec970a3ce9..2192e8f8f83 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -1,6 +1,6 @@ use std::num::IntErrorKind; -use rustc_ast::{self as ast, AttrStyle}; +use rustc_ast::{self as ast, AttrStyle, Path}; use rustc_errors::codes::*; use rustc_errors::{ Applicability, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, @@ -484,10 +484,10 @@ pub(crate) struct EmptyAttributeList { #[diag(attr_parsing_invalid_target_lint)] #[warning] #[help] -pub(crate) struct InvalidTargetLint { - pub name: Symbol, - pub target: &'static str, - pub applied: String, +pub(crate) struct InvalidTargetLint<'a> { + pub name: &'a AttrPath, + pub target: &'a str, + pub applied: DiagArgValue, pub only: &'static str, #[suggestion(code = "", applicability = "machine-applicable", style = "tool-only")] pub attr_span: Span, @@ -500,9 +500,9 @@ pub(crate) struct InvalidTarget { #[primary_span] #[suggestion(code = "", applicability = "machine-applicable", style = "tool-only")] pub span: Span, - pub name: Symbol, + pub name: AttrPath, pub target: &'static str, - pub applied: String, + pub applied: DiagArgValue, pub only: &'static str, } @@ -558,7 +558,7 @@ pub(crate) struct LinkOrdinalOutOfRange { pub ordinal: u128, } -pub(crate) enum AttributeParseErrorReason { +pub(crate) enum AttributeParseErrorReason<'a> { ExpectedNoArgs, ExpectedStringLiteral { byte_string: Option<Span>, @@ -571,7 +571,7 @@ pub(crate) enum AttributeParseErrorReason { ExpectedNameValue(Option<Symbol>), DuplicateKey(Symbol), ExpectedSpecificArgument { - possibilities: Vec<&'static str>, + possibilities: &'a [Symbol], strings: bool, /// Should we tell the user to write a list when they didn't? list: bool, @@ -579,16 +579,16 @@ pub(crate) enum AttributeParseErrorReason { ExpectedIdentifier, } -pub(crate) struct AttributeParseError { +pub(crate) struct AttributeParseError<'a> { pub(crate) span: Span, pub(crate) attr_span: Span, pub(crate) attr_style: AttrStyle, pub(crate) template: AttributeTemplate, pub(crate) attribute: AttrPath, - pub(crate) reason: AttributeParseErrorReason, + pub(crate) reason: AttributeParseErrorReason<'a>, } -impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError { +impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError<'_> { fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { let name = self.attribute.to_string(); @@ -657,7 +657,7 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError { list: false, } => { let quote = if strings { '"' } else { '`' }; - match possibilities.as_slice() { + match possibilities { &[] => {} &[x] => { diag.span_label( @@ -687,7 +687,7 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError { list: true, } => { let quote = if strings { '"' } else { '`' }; - match possibilities.as_slice() { + match possibilities { &[] => {} &[x] => { diag.span_label( @@ -737,3 +737,92 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError { diag } } + +#[derive(Diagnostic)] +#[diag(attr_parsing_invalid_attr_unsafe)] +#[note] +pub(crate) struct InvalidAttrUnsafe { + #[primary_span] + #[label] + pub span: Span, + pub name: Path, +} + +#[derive(Diagnostic)] +#[diag(attr_parsing_unsafe_attr_outside_unsafe)] +pub(crate) struct UnsafeAttrOutsideUnsafe { + #[primary_span] + #[label] + pub span: Span, + #[subdiagnostic] + pub suggestion: UnsafeAttrOutsideUnsafeSuggestion, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion( + attr_parsing_unsafe_attr_outside_unsafe_suggestion, + applicability = "machine-applicable" +)] +pub(crate) struct UnsafeAttrOutsideUnsafeSuggestion { + #[suggestion_part(code = "unsafe(")] + pub left: Span, + #[suggestion_part(code = ")")] + pub right: Span, +} + +#[derive(Diagnostic)] +#[diag(attr_parsing_meta_bad_delim)] +pub(crate) struct MetaBadDelim { + #[primary_span] + pub span: Span, + #[subdiagnostic] + pub sugg: MetaBadDelimSugg, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion( + attr_parsing_meta_bad_delim_suggestion, + applicability = "machine-applicable" +)] +pub(crate) struct MetaBadDelimSugg { + #[suggestion_part(code = "(")] + pub open: Span, + #[suggestion_part(code = ")")] + pub close: Span, +} + +#[derive(Diagnostic)] +#[diag(attr_parsing_invalid_meta_item)] +pub(crate) struct InvalidMetaItem { + #[primary_span] + pub span: Span, + pub descr: String, + #[subdiagnostic] + pub quote_ident_sugg: Option<InvalidMetaItemQuoteIdentSugg>, + #[subdiagnostic] + pub remove_neg_sugg: Option<InvalidMetaItemRemoveNegSugg>, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion(attr_parsing_quote_ident_sugg, applicability = "machine-applicable")] +pub(crate) struct InvalidMetaItemQuoteIdentSugg { + #[suggestion_part(code = "\"")] + pub before: Span, + #[suggestion_part(code = "\"")] + pub after: Span, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion(attr_parsing_remove_neg_sugg, applicability = "machine-applicable")] +pub(crate) struct InvalidMetaItemRemoveNegSugg { + #[suggestion_part(code = "")] + pub negative_sign: Span, +} + +#[derive(Diagnostic)] +#[diag(attr_parsing_suffixed_literal_in_attribute)] +#[help] +pub(crate) struct SuffixedLiteralInAttribute { + #[primary_span] + pub span: Span, +} diff --git a/compiler/rustc_attr_parsing/src/target_checking.rs b/compiler/rustc_attr_parsing/src/target_checking.rs new file mode 100644 index 00000000000..9568b791b3f --- /dev/null +++ b/compiler/rustc_attr_parsing/src/target_checking.rs @@ -0,0 +1,247 @@ +use std::borrow::Cow; + +use rustc_errors::DiagArgValue; +use rustc_feature::Features; +use rustc_hir::lints::{AttributeLint, AttributeLintKind}; +use rustc_hir::{AttrPath, MethodKind, Target}; +use rustc_span::Span; + +use crate::AttributeParser; +use crate::context::Stage; +use crate::session_diagnostics::InvalidTarget; + +#[derive(Debug)] +pub(crate) enum AllowedTargets { + AllowList(&'static [Policy]), + AllowListWarnRest(&'static [Policy]), +} + +pub(crate) enum AllowedResult { + Allowed, + Warn, + Error, +} + +impl AllowedTargets { + pub(crate) fn is_allowed(&self, target: Target) -> AllowedResult { + match self { + AllowedTargets::AllowList(list) => { + if list.contains(&Policy::Allow(target)) { + AllowedResult::Allowed + } else if list.contains(&Policy::Warn(target)) { + AllowedResult::Warn + } else { + AllowedResult::Error + } + } + AllowedTargets::AllowListWarnRest(list) => { + if list.contains(&Policy::Allow(target)) { + AllowedResult::Allowed + } else if list.contains(&Policy::Error(target)) { + AllowedResult::Error + } else { + AllowedResult::Warn + } + } + } + } + + pub(crate) fn allowed_targets(&self) -> Vec<Target> { + match self { + AllowedTargets::AllowList(list) => list, + AllowedTargets::AllowListWarnRest(list) => list, + } + .iter() + .filter_map(|target| match target { + Policy::Allow(target) => Some(*target), + Policy::Warn(_) => None, + Policy::Error(_) => None, + }) + .collect() + } +} + +#[derive(Debug, Eq, PartialEq)] +pub(crate) enum Policy { + Allow(Target), + Warn(Target), + Error(Target), +} + +impl<S: Stage> AttributeParser<'_, S> { + pub(crate) fn check_target( + &self, + attr_name: AttrPath, + attr_span: Span, + allowed_targets: &AllowedTargets, + target: Target, + target_id: S::Id, + mut emit_lint: impl FnMut(AttributeLint<S::Id>), + ) { + match allowed_targets.is_allowed(target) { + AllowedResult::Allowed => {} + AllowedResult::Warn => { + let allowed_targets = allowed_targets.allowed_targets(); + let (applied, only) = + allowed_targets_applied(allowed_targets, target, self.features); + emit_lint(AttributeLint { + id: target_id, + span: attr_span, + kind: AttributeLintKind::InvalidTarget { + name: attr_name, + target, + only: if only { "only " } else { "" }, + applied, + }, + }); + } + AllowedResult::Error => { + let allowed_targets = allowed_targets.allowed_targets(); + let (applied, only) = + allowed_targets_applied(allowed_targets, target, self.features); + self.dcx().emit_err(InvalidTarget { + span: attr_span, + name: attr_name, + target: target.plural_name(), + only: if only { "only " } else { "" }, + applied: DiagArgValue::StrListSepByAnd( + applied.into_iter().map(Cow::Owned).collect(), + ), + }); + } + } + } +} + +/// Takes a list of `allowed_targets` for an attribute, and the `target` the attribute was applied to. +/// Does some heuristic-based filtering to remove uninteresting targets, and formats the targets into a string +pub(crate) fn allowed_targets_applied( + mut allowed_targets: Vec<Target>, + target: Target, + features: Option<&Features>, +) -> (Vec<String>, bool) { + // Remove unstable targets from `allowed_targets` if their features are not enabled + if let Some(features) = features { + if !features.fn_delegation() { + allowed_targets.retain(|t| !matches!(t, Target::Delegation { .. })); + } + if !features.stmt_expr_attributes() { + allowed_targets.retain(|t| !matches!(t, Target::Expression | Target::Statement)); + } + if !features.extern_types() { + allowed_targets.retain(|t| !matches!(t, Target::ForeignTy)); + } + } + + // We define groups of "similar" targets. + // If at least two of the targets are allowed, and the `target` is not in the group, + // we collapse the entire group to a single entry to simplify the target list + const FUNCTION_LIKE: &[Target] = &[ + Target::Fn, + Target::Closure, + Target::ForeignFn, + Target::Method(MethodKind::Inherent), + Target::Method(MethodKind::Trait { body: false }), + Target::Method(MethodKind::Trait { body: true }), + Target::Method(MethodKind::TraitImpl), + ]; + const METHOD_LIKE: &[Target] = &[ + Target::Method(MethodKind::Inherent), + Target::Method(MethodKind::Trait { body: false }), + Target::Method(MethodKind::Trait { body: true }), + Target::Method(MethodKind::TraitImpl), + ]; + const IMPL_LIKE: &[Target] = + &[Target::Impl { of_trait: false }, Target::Impl { of_trait: true }]; + const ADT_LIKE: &[Target] = &[Target::Struct, Target::Enum]; + + let mut added_fake_targets = Vec::new(); + filter_targets( + &mut allowed_targets, + FUNCTION_LIKE, + "functions", + target, + &mut added_fake_targets, + ); + filter_targets(&mut allowed_targets, METHOD_LIKE, "methods", target, &mut added_fake_targets); + filter_targets(&mut allowed_targets, IMPL_LIKE, "impl blocks", target, &mut added_fake_targets); + filter_targets(&mut allowed_targets, ADT_LIKE, "data types", target, &mut added_fake_targets); + + // If there is now only 1 target left, show that as the only possible target + ( + added_fake_targets + .iter() + .copied() + .chain(allowed_targets.iter().map(|t| t.plural_name())) + .map(|i| i.to_string()) + .collect(), + allowed_targets.len() + added_fake_targets.len() == 1, + ) +} + +fn filter_targets( + allowed_targets: &mut Vec<Target>, + target_group: &'static [Target], + target_group_name: &'static str, + target: Target, + added_fake_targets: &mut Vec<&'static str>, +) { + if target_group.contains(&target) { + return; + } + if allowed_targets.iter().filter(|at| target_group.contains(at)).count() < 2 { + return; + } + allowed_targets.retain(|t| !target_group.contains(t)); + added_fake_targets.push(target_group_name); +} + +/// This is the list of all targets to which a attribute can be applied +/// This is used for: +/// - `rustc_dummy`, which can be applied to all targets +/// - Attributes that are not parted to the new target system yet can use this list as a placeholder +pub(crate) const ALL_TARGETS: &'static [Policy] = { + use Policy::Allow; + &[ + Allow(Target::ExternCrate), + Allow(Target::Use), + Allow(Target::Static), + Allow(Target::Const), + Allow(Target::Fn), + Allow(Target::Closure), + Allow(Target::Mod), + Allow(Target::ForeignMod), + Allow(Target::GlobalAsm), + Allow(Target::TyAlias), + Allow(Target::Enum), + Allow(Target::Variant), + Allow(Target::Struct), + Allow(Target::Field), + Allow(Target::Union), + Allow(Target::Trait), + Allow(Target::TraitAlias), + Allow(Target::Impl { of_trait: false }), + Allow(Target::Impl { of_trait: true }), + Allow(Target::Expression), + Allow(Target::Statement), + Allow(Target::Arm), + Allow(Target::AssocConst), + Allow(Target::Method(MethodKind::Inherent)), + Allow(Target::Method(MethodKind::Trait { body: false })), + Allow(Target::Method(MethodKind::Trait { body: true })), + Allow(Target::Method(MethodKind::TraitImpl)), + Allow(Target::AssocTy), + Allow(Target::ForeignFn), + Allow(Target::ForeignStatic), + Allow(Target::ForeignTy), + Allow(Target::MacroDef), + Allow(Target::Param), + Allow(Target::PatField), + Allow(Target::ExprField), + Allow(Target::WherePredicate), + Allow(Target::MacroCall), + Allow(Target::Crate), + Allow(Target::Delegation { mac: false }), + Allow(Target::Delegation { mac: true }), + ] +}; diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_attr_parsing/src/validate_attr.rs index 68ef6d6f32c..7a7624893bd 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_attr_parsing/src/validate_attr.rs @@ -8,16 +8,16 @@ use rustc_ast::{ self as ast, AttrArgs, Attribute, DelimArgs, MetaItem, MetaItemInner, MetaItemKind, NodeId, Path, Safety, }; -use rustc_attr_parsing::{AttributeParser, Late}; use rustc_errors::{Applicability, DiagCtxtHandle, FatalError, PResult}; use rustc_feature::{AttributeSafety, AttributeTemplate, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute}; +use rustc_parse::parse_in; use rustc_session::errors::report_lit_error; use rustc_session::lint::BuiltinLintDiag; use rustc_session::lint::builtin::{ILL_FORMED_ATTRIBUTE_INPUT, UNSAFE_ATTR_OUTSIDE_UNSAFE}; use rustc_session::parse::ParseSess; use rustc_span::{Span, Symbol, sym}; -use crate::{errors, parse_in}; +use crate::{AttributeParser, Late, session_diagnostics as errors}; pub fn check_attr(psess: &ParseSess, attr: &Attribute, id: NodeId) { if attr.is_doc_comment() || attr.has_name(sym::cfg_trace) || attr.has_name(sym::cfg_attr_trace) @@ -33,7 +33,10 @@ pub fn check_attr(psess: &ParseSess, attr: &Attribute, id: NodeId) { // Check input tokens for built-in and key-value attributes. match builtin_attr_info { // `rustc_dummy` doesn't have any restrictions specific to built-in attributes. - Some(BuiltinAttribute { name, template, .. }) if *name != sym::rustc_dummy => { + Some(BuiltinAttribute { name, template, .. }) => { + if AttributeParser::<Late>::is_parsed_attribute(slice::from_ref(&name)) { + return; + } match parse_meta(psess, attr) { // Don't check safety again, we just did that Ok(meta) => { @@ -133,16 +136,6 @@ fn check_meta_bad_delim(psess: &ParseSess, span: DelimSpan, delim: Delimiter) { }); } -pub(super) fn check_cfg_attr_bad_delim(psess: &ParseSess, span: DelimSpan, delim: Delimiter) { - if let Delimiter::Parenthesis = delim { - return; - } - psess.dcx().emit_err(errors::CfgAttrBadDelim { - span: span.entire(), - sugg: errors::MetaBadDelimSugg { open: span.open, close: span.close }, - }); -} - /// Checks that the given meta-item is compatible with this `AttributeTemplate`. fn is_attr_template_compatible(template: &AttributeTemplate, meta: &ast::MetaItemKind) -> bool { let is_one_allowed_subword = |items: &[MetaItemInner]| match items { @@ -269,9 +262,6 @@ pub fn check_builtin_meta_item( ) { if !is_attr_template_compatible(&template, &meta.kind) { // attrs with new parsers are locally validated so excluded here - if AttributeParser::<Late>::is_parsed_attribute(slice::from_ref(&name)) { - return; - } emit_malformed_attribute(psess, style, meta.span, name, template); } diff --git a/compiler/rustc_builtin_macros/src/cfg_accessible.rs b/compiler/rustc_builtin_macros/src/cfg_accessible.rs index f7d8f4aa783..48d80004cdd 100644 --- a/compiler/rustc_builtin_macros/src/cfg_accessible.rs +++ b/compiler/rustc_builtin_macros/src/cfg_accessible.rs @@ -1,9 +1,9 @@ //! Implementation of the `#[cfg_accessible(path)]` attribute macro. use rustc_ast as ast; +use rustc_attr_parsing::validate_attr; use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt, Indeterminate, MultiItemModifier}; use rustc_feature::AttributeTemplate; -use rustc_parse::validate_attr; use rustc_span::{Span, sym}; use crate::errors; diff --git a/compiler/rustc_builtin_macros/src/derive.rs b/compiler/rustc_builtin_macros/src/derive.rs index a33eca43de5..09d827b0635 100644 --- a/compiler/rustc_builtin_macros/src/derive.rs +++ b/compiler/rustc_builtin_macros/src/derive.rs @@ -1,10 +1,10 @@ use rustc_ast as ast; use rustc_ast::{GenericParamKind, ItemKind, MetaItemInner, MetaItemKind, StmtKind}; +use rustc_attr_parsing::validate_attr; use rustc_expand::base::{ Annotatable, DeriveResolution, ExpandResult, ExtCtxt, Indeterminate, MultiItemModifier, }; use rustc_feature::AttributeTemplate; -use rustc_parse::validate_attr; use rustc_session::Session; use rustc_span::{ErrorGuaranteed, Ident, Span, sym}; diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index ec613b7b710..6415e55e0b0 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -10,11 +10,12 @@ use rustc_ast::{ }; use rustc_data_structures::fx::FxHashSet; use rustc_errors::{ - Applicability, Diag, MultiSpan, PResult, SingleLabelManySpans, listify, pluralize, + Applicability, BufferedEarlyLint, Diag, MultiSpan, PResult, SingleLabelManySpans, listify, + pluralize, }; use rustc_expand::base::*; use rustc_lint_defs::builtin::NAMED_ARGUMENTS_USED_POSITIONALLY; -use rustc_lint_defs::{BufferedEarlyLint, BuiltinLintDiag, LintId}; +use rustc_lint_defs::{BuiltinLintDiag, LintId}; use rustc_parse::exp; use rustc_parse_format as parse; use rustc_span::{BytePos, ErrorGuaranteed, Ident, InnerSpan, Span, Symbol}; @@ -595,7 +596,8 @@ fn make_format_args( named_arg_sp: arg_name.span, named_arg_name: arg_name.name.to_string(), is_formatting_arg: matches!(used_as, Width | Precision), - }, + } + .into(), }); } } diff --git a/compiler/rustc_builtin_macros/src/util.rs b/compiler/rustc_builtin_macros/src/util.rs index f00c170e485..3a4585d5be9 100644 --- a/compiler/rustc_builtin_macros/src/util.rs +++ b/compiler/rustc_builtin_macros/src/util.rs @@ -1,12 +1,13 @@ use rustc_ast::tokenstream::TokenStream; use rustc_ast::{self as ast, AttrStyle, Attribute, MetaItem, attr, token}; +use rustc_attr_parsing::validate_attr; use rustc_errors::{Applicability, Diag, ErrorGuaranteed}; use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt}; use rustc_expand::expand::AstFragment; use rustc_feature::AttributeTemplate; use rustc_lint_defs::BuiltinLintDiag; use rustc_lint_defs::builtin::DUPLICATE_MACRO_ATTRIBUTES; -use rustc_parse::{exp, parser, validate_attr}; +use rustc_parse::{exp, parser}; use rustc_session::errors::report_lit_error; use rustc_span::{BytePos, Span, Symbol}; diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 06c3d8ed6bc..49d3dedbeab 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -330,7 +330,7 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { _ => bug!(), }; let ptr = args[0].immediate(); - let locality = fn_args.const_at(1).to_value().valtree.unwrap_leaf().to_u32() as i32; + let locality = fn_args.const_at(1).to_value().valtree.unwrap_leaf().to_i32(); self.call_intrinsic( "llvm.prefetch", &[self.val_ty(ptr)], diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index c8690251bd0..23e2abd6de3 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -193,7 +193,7 @@ fn process_builtin_attrs( } } AttributeKind::Optimize(optimize, _) => codegen_fn_attrs.optimize = *optimize, - AttributeKind::TargetFeature(features, attr_span) => { + AttributeKind::TargetFeature { features, attr_span, was_forced } => { let Some(sig) = tcx.hir_node_by_def_id(did).fn_sig() else { tcx.dcx().span_delayed_bug(*attr_span, "target_feature applied to non-fn"); continue; @@ -201,7 +201,7 @@ fn process_builtin_attrs( let safe_target_features = matches!(sig.header.safety, hir::HeaderSafety::SafeTargetFeatures); codegen_fn_attrs.safe_target_features = safe_target_features; - if safe_target_features { + if safe_target_features && !was_forced { if tcx.sess.target.is_like_wasm || tcx.sess.opts.actually_rustdoc { // The `#[target_feature]` attribute is allowed on // WebAssembly targets on all functions. Prior to stabilizing @@ -232,6 +232,7 @@ fn process_builtin_attrs( tcx, did, features, + *was_forced, rust_target_features, &mut codegen_fn_attrs.target_features, ); @@ -462,7 +463,7 @@ fn check_result( .collect(), ) { let span = - find_attr!(tcx.get_all_attrs(did), AttributeKind::TargetFeature(_, span) => *span) + find_attr!(tcx.get_all_attrs(did), AttributeKind::TargetFeature{attr_span: span, ..} => *span) .unwrap_or_else(|| tcx.def_span(did)); tcx.dcx() diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index b5aa50f4851..54584999d61 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -3,7 +3,7 @@ use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_hir::attrs::InstructionSetAttr; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId}; -use rustc_middle::middle::codegen_fn_attrs::TargetFeature; +use rustc_middle::middle::codegen_fn_attrs::{TargetFeature, TargetFeatureKind}; use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_session::Session; @@ -22,6 +22,7 @@ pub(crate) fn from_target_feature_attr( tcx: TyCtxt<'_>, did: LocalDefId, features: &[(Symbol, Span)], + was_forced: bool, rust_target_features: &UnordMap<String, target_features::Stability>, target_features: &mut Vec<TargetFeature>, ) { @@ -88,7 +89,14 @@ pub(crate) fn from_target_feature_attr( } } } - target_features.push(TargetFeature { name, implied: name != feature }) + let kind = if name != feature { + TargetFeatureKind::Implied + } else if was_forced { + TargetFeatureKind::Forced + } else { + TargetFeatureKind::Enabled + }; + target_features.push(TargetFeature { name, kind }) } } } diff --git a/compiler/rustc_const_eval/src/util/type_name.rs b/compiler/rustc_const_eval/src/util/type_name.rs index 92096958f2b..2ae6655901b 100644 --- a/compiler/rustc_const_eval/src/util/type_name.rs +++ b/compiler/rustc_const_eval/src/util/type_name.rs @@ -164,12 +164,12 @@ impl<'tcx> Printer<'tcx> for TypeNamePrinter<'tcx> { } impl<'tcx> PrettyPrinter<'tcx> for TypeNamePrinter<'tcx> { - fn should_print_optional_region(&self, _region: ty::Region<'_>) -> bool { + fn should_print_optional_region(&self, region: ty::Region<'_>) -> bool { // Bound regions are always printed (as `'_`), which gives some idea that they are special, // even though the `for` is omitted by the pretty printer. // E.g. `for<'a, 'b> fn(&'a u32, &'b u32)` is printed as "fn(&'_ u32, &'_ u32)". - match _region.kind() { - ty::ReErased => false, + match region.kind() { + ty::ReErased | ty::ReEarlyParam(_) => false, ty::ReBound(..) => true, _ => unreachable!(), } diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index 53178d09348..17da3ea83c8 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -77,6 +77,7 @@ pub mod thinvec; pub mod thousands; pub mod transitive_relation; pub mod unhash; +pub mod union_find; pub mod unord; pub mod vec_cache; pub mod work_queue; diff --git a/compiler/rustc_mir_transform/src/coverage/counters/union_find.rs b/compiler/rustc_data_structures/src/union_find.rs index a826a953fa6..ef73cd7ab40 100644 --- a/compiler/rustc_mir_transform/src/coverage/counters/union_find.rs +++ b/compiler/rustc_data_structures/src/union_find.rs @@ -9,7 +9,7 @@ mod tests; /// Simple implementation of a union-find data structure, i.e. a disjoint-set /// forest. #[derive(Debug)] -pub(crate) struct UnionFind<Key: Idx> { +pub struct UnionFind<Key: Idx> { table: IndexVec<Key, UnionFindEntry<Key>>, } @@ -28,7 +28,7 @@ struct UnionFindEntry<Key> { impl<Key: Idx> UnionFind<Key> { /// Creates a new disjoint-set forest containing the keys `0..num_keys`. /// Initially, every key is part of its own one-element set. - pub(crate) fn new(num_keys: usize) -> Self { + pub fn new(num_keys: usize) -> Self { // Initially, every key is the root of its own set, so its parent is itself. Self { table: IndexVec::from_fn_n(|key| UnionFindEntry { parent: key, rank: 0 }, num_keys) } } @@ -38,7 +38,7 @@ impl<Key: Idx> UnionFind<Key> { /// /// Also updates internal data structures to make subsequent `find` /// operations faster. - pub(crate) fn find(&mut self, key: Key) -> Key { + pub fn find(&mut self, key: Key) -> Key { // Loop until we find a key that is its own parent. let mut curr = key; while let parent = self.table[curr].parent @@ -60,7 +60,7 @@ impl<Key: Idx> UnionFind<Key> { /// Merges the set containing `a` and the set containing `b` into one set. /// /// Returns the common root of both keys, after the merge. - pub(crate) fn unify(&mut self, a: Key, b: Key) -> Key { + pub fn unify(&mut self, a: Key, b: Key) -> Key { let mut a = self.find(a); let mut b = self.find(b); @@ -90,7 +90,7 @@ impl<Key: Idx> UnionFind<Key> { /// Takes a "snapshot" of the current state of this disjoint-set forest, in /// the form of a vector that directly maps each key to its current root. - pub(crate) fn snapshot(&mut self) -> IndexVec<Key, Key> { + pub fn snapshot(&mut self) -> IndexVec<Key, Key> { self.table.indices().map(|key| self.find(key)).collect() } } diff --git a/compiler/rustc_mir_transform/src/coverage/counters/union_find/tests.rs b/compiler/rustc_data_structures/src/union_find/tests.rs index 34a4e4f8e6e..34a4e4f8e6e 100644 --- a/compiler/rustc_mir_transform/src/coverage/counters/union_find/tests.rs +++ b/compiler/rustc_data_structures/src/union_find/tests.rs diff --git a/compiler/rustc_errors/Cargo.toml b/compiler/rustc_errors/Cargo.toml index ad6d29e21fc..f37b6fb748f 100644 --- a/compiler/rustc_errors/Cargo.toml +++ b/compiler/rustc_errors/Cargo.toml @@ -8,6 +8,7 @@ edition = "2024" annotate-snippets = "0.11" derive_setters = "0.1.6" rustc_abi = { path = "../rustc_abi" } +rustc_ast = { path = "../rustc_ast" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_error_codes = { path = "../rustc_error_codes" } rustc_error_messages = { path = "../rustc_error_messages" } diff --git a/compiler/rustc_errors/src/decorate_diag.rs b/compiler/rustc_errors/src/decorate_diag.rs new file mode 100644 index 00000000000..5aef26ccf97 --- /dev/null +++ b/compiler/rustc_errors/src/decorate_diag.rs @@ -0,0 +1,85 @@ +/// This module provides types and traits for buffering lints until later in compilation. +use rustc_ast::node_id::NodeId; +use rustc_data_structures::fx::FxIndexMap; +use rustc_error_messages::MultiSpan; +use rustc_lint_defs::{BuiltinLintDiag, Lint, LintId}; + +use crate::{DynSend, LintDiagnostic, LintDiagnosticBox}; + +/// We can't implement `LintDiagnostic` for `BuiltinLintDiag`, because decorating some of its +/// variants requires types we don't have yet. So, handle that case separately. +pub enum DecorateDiagCompat { + Dynamic(Box<dyn for<'a> LintDiagnosticBox<'a, ()> + DynSend + 'static>), + Builtin(BuiltinLintDiag), +} + +impl std::fmt::Debug for DecorateDiagCompat { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("DecorateDiagCompat").finish() + } +} + +impl !LintDiagnostic<'_, ()> for BuiltinLintDiag {} + +impl<D: for<'a> LintDiagnostic<'a, ()> + DynSend + 'static> From<D> for DecorateDiagCompat { + #[inline] + fn from(d: D) -> Self { + Self::Dynamic(Box::new(d)) + } +} + +impl From<BuiltinLintDiag> for DecorateDiagCompat { + #[inline] + fn from(b: BuiltinLintDiag) -> Self { + Self::Builtin(b) + } +} + +/// Lints that are buffered up early on in the `Session` before the +/// `LintLevels` is calculated. +#[derive(Debug)] +pub struct BufferedEarlyLint { + /// The span of code that we are linting on. + pub span: Option<MultiSpan>, + + /// The `NodeId` of the AST node that generated the lint. + pub node_id: NodeId, + + /// A lint Id that can be passed to + /// `rustc_lint::early::EarlyContextAndPass::check_id`. + pub lint_id: LintId, + + /// Customization of the `Diag<'_>` for the lint. + pub diagnostic: DecorateDiagCompat, +} + +#[derive(Default, Debug)] +pub struct LintBuffer { + pub map: FxIndexMap<NodeId, Vec<BufferedEarlyLint>>, +} + +impl LintBuffer { + pub fn add_early_lint(&mut self, early_lint: BufferedEarlyLint) { + self.map.entry(early_lint.node_id).or_default().push(early_lint); + } + + pub fn take(&mut self, id: NodeId) -> Vec<BufferedEarlyLint> { + // FIXME(#120456) - is `swap_remove` correct? + self.map.swap_remove(&id).unwrap_or_default() + } + + pub fn buffer_lint( + &mut self, + lint: &'static Lint, + node_id: NodeId, + span: impl Into<MultiSpan>, + decorate: impl Into<DecorateDiagCompat>, + ) { + self.add_early_lint(BufferedEarlyLint { + lint_id: LintId::of(lint), + node_id, + span: Some(span.into()), + diagnostic: decorate.into(), + }); + } +} diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 183dceddd2c..43ce886975c 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -138,10 +138,20 @@ where /// `#[derive(LintDiagnostic)]` -- see [rustc_macros::LintDiagnostic]. #[rustc_diagnostic_item = "LintDiagnostic"] pub trait LintDiagnostic<'a, G: EmissionGuarantee> { - /// Decorate and emit a lint. + /// Decorate a lint with the information from this type. fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, G>); } +pub trait LintDiagnosticBox<'a, G: EmissionGuarantee> { + fn decorate_lint_box<'b>(self: Box<Self>, diag: &'b mut Diag<'a, G>); +} + +impl<'a, G: EmissionGuarantee, D: LintDiagnostic<'a, G>> LintDiagnosticBox<'a, G> for D { + fn decorate_lint_box<'b>(self: Box<Self>, diag: &'b mut Diag<'a, G>) { + self.decorate_lint(diag); + } +} + #[derive(Clone, Debug, Encodable, Decodable)] pub(crate) struct DiagLocation { file: Cow<'static, str>, diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index a775b70dbee..38c5716348f 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -40,9 +40,10 @@ use std::{fmt, panic}; use Level::*; pub use codes::*; +pub use decorate_diag::{BufferedEarlyLint, DecorateDiagCompat, LintBuffer}; pub use diagnostic::{ BugAbort, Diag, DiagArgMap, DiagInner, DiagStyledString, Diagnostic, EmissionGuarantee, - FatalAbort, LintDiagnostic, StringPart, Subdiag, Subdiagnostic, + FatalAbort, LintDiagnostic, LintDiagnosticBox, StringPart, Subdiag, Subdiagnostic, }; pub use diagnostic_impls::{ DiagSymbolList, ElidedLifetimeInPathSubdiag, ExpectedLifetimeParameter, @@ -80,6 +81,7 @@ use crate::timings::TimingRecord; pub mod annotate_snippet_emitter_writer; pub mod codes; +mod decorate_diag; mod diagnostic; mod diagnostic_impls; pub mod emitter; diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index f2c15071532..8ff21509f4a 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -13,13 +13,13 @@ use rustc_ast::visit::{AssocCtxt, Visitor}; use rustc_ast::{self as ast, AttrVec, Attribute, HasAttrs, Item, NodeId, PatKind}; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_data_structures::sync; -use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed, PResult}; +use rustc_errors::{BufferedEarlyLint, DiagCtxtHandle, ErrorGuaranteed, PResult}; use rustc_feature::Features; use rustc_hir as hir; use rustc_hir::attrs::{AttributeKind, CfgEntry, Deprecation}; use rustc_hir::def::MacroKinds; use rustc_hir::{Stability, find_attr}; -use rustc_lint_defs::{BufferedEarlyLint, RegisteredTools}; +use rustc_lint_defs::RegisteredTools; use rustc_parse::MACRO_ARGUMENTS; use rustc_parse::parser::{ForceCollect, Parser}; use rustc_session::config::CollapseMacroDebuginfo; diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index 83a8d601afe..15419ab7423 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -11,8 +11,10 @@ use rustc_ast::{ NodeId, NormalAttr, }; use rustc_attr_parsing as attr; +use rustc_attr_parsing::validate_attr::deny_builtin_meta_unsafety; use rustc_attr_parsing::{ AttributeParser, CFG_TEMPLATE, EvalConfigResult, ShouldEmit, eval_config_entry, parse_cfg_attr, + validate_attr, }; use rustc_data_structures::flat_map_in_place::FlatMapInPlace; use rustc_feature::{ @@ -20,8 +22,6 @@ use rustc_feature::{ REMOVED_LANG_FEATURES, UNSTABLE_LANG_FEATURES, }; use rustc_lint_defs::BuiltinLintDiag; -use rustc_parse::validate_attr; -use rustc_parse::validate_attr::deny_builtin_meta_unsafety; use rustc_session::Session; use rustc_session::parse::feature_err; use rustc_span::{STDLIB_STABLE_CRATES, Span, Symbol, sym}; @@ -415,16 +415,6 @@ impl<'a> StripUnconfigured<'a> { node: NodeId, emit_errors: ShouldEmit, ) -> EvalConfigResult { - // We need to run this to do basic validation of the attribute, such as that lits are valid, etc - // FIXME(jdonszelmann) this should not be necessary in the future - match validate_attr::parse_meta(&self.sess.psess, attr) { - Ok(_) => {} - Err(err) => { - err.emit(); - return EvalConfigResult::True; - } - } - // Unsafety check needs to be done explicitly here because this attribute will be removed before the normal check deny_builtin_meta_unsafety( self.sess.dcx(), diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 755275d3cda..012bfe226f2 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -1,27 +1,28 @@ use std::path::PathBuf; use std::rc::Rc; use std::sync::Arc; -use std::{iter, mem}; +use std::{iter, mem, slice}; use rustc_ast::mut_visit::*; use rustc_ast::tokenstream::TokenStream; use rustc_ast::visit::{self, AssocCtxt, Visitor, VisitorResult, try_visit, walk_list}; use rustc_ast::{ - self as ast, AssocItemKind, AstNodeWrapper, AttrArgs, AttrStyle, AttrVec, DUMMY_NODE_ID, - ExprKind, ForeignItemKind, HasAttrs, HasNodeId, Inline, ItemKind, MacStmtStyle, MetaItemInner, - MetaItemKind, ModKind, NodeId, PatKind, StmtKind, TyKind, token, + self as ast, AssocItemKind, AstNodeWrapper, AttrArgs, AttrStyle, AttrVec, CRATE_NODE_ID, + DUMMY_NODE_ID, ExprKind, ForeignItemKind, HasAttrs, HasNodeId, Inline, ItemKind, MacStmtStyle, + MetaItemInner, MetaItemKind, ModKind, NodeId, PatKind, StmtKind, TyKind, token, }; use rustc_ast_pretty::pprust; -use rustc_attr_parsing::{EvalConfigResult, ShouldEmit}; +use rustc_attr_parsing::{AttributeParser, EvalConfigResult, ShouldEmit, validate_attr}; use rustc_data_structures::flat_map_in_place::FlatMapInPlace; +use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::PResult; use rustc_feature::Features; +use rustc_hir::Target; use rustc_hir::def::MacroKinds; use rustc_parse::parser::{ AttemptLocalParseRecovery, CommaRecoveryMode, ForceCollect, Parser, RecoverColon, RecoverComma, token_descr, }; -use rustc_parse::validate_attr; use rustc_session::lint::BuiltinLintDiag; use rustc_session::lint::builtin::{UNUSED_ATTRIBUTES, UNUSED_DOC_COMMENTS}; use rustc_session::parse::feature_err; @@ -2158,6 +2159,16 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { attr, self.cx.current_expansion.lint_node_id, ); + AttributeParser::parse_limited_all( + self.cx.sess, + slice::from_ref(attr), + None, + Target::MacroCall, + call.span(), + CRATE_NODE_ID, + Some(self.cx.ecfg.features), + ShouldEmit::ErrorsAndLints, + ); let current_span = if let Some(sp) = span { sp.to(attr.span) } else { attr.span }; span = Some(current_span); @@ -2469,7 +2480,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { if let Some(attr) = node.attrs.first() { self.cfg().maybe_emit_expr_attr_err(attr); } - self.visit_node(node) + ensure_sufficient_stack(|| self.visit_node(node)) } fn visit_method_receiver_expr(&mut self, node: &mut ast::Expr) { diff --git a/compiler/rustc_expand/src/module.rs b/compiler/rustc_expand/src/module.rs index 6666ea33cd3..19f3cdbc549 100644 --- a/compiler/rustc_expand/src/module.rs +++ b/compiler/rustc_expand/src/module.rs @@ -2,8 +2,9 @@ use std::iter::once; use std::path::{self, Path, PathBuf}; use rustc_ast::{AttrVec, Attribute, Inline, Item, ModSpans}; +use rustc_attr_parsing::validate_attr; use rustc_errors::{Diag, ErrorGuaranteed}; -use rustc_parse::{exp, new_parser_from_file, unwrap_or_emit_fatal, validate_attr}; +use rustc_parse::{exp, new_parser_from_file, unwrap_or_emit_fatal}; use rustc_session::Session; use rustc_session::parse::ParseSess; use rustc_span::{Ident, Span, sym}; diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs index fd71f2ce948..5b1d3d6d35b 100644 --- a/compiler/rustc_expand/src/proc_macro_server.rs +++ b/compiler/rustc_expand/src/proc_macro_server.rs @@ -250,12 +250,14 @@ impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> for Vec<TokenTree<TokenStre Question => op("?"), SingleQuote => op("'"), - Ident(sym, is_raw) => { - trees.push(TokenTree::Ident(Ident { sym, is_raw: is_raw.into(), span })) - } + Ident(sym, is_raw) => trees.push(TokenTree::Ident(Ident { + sym, + is_raw: matches!(is_raw, IdentIsRaw::Yes), + span, + })), NtIdent(ident, is_raw) => trees.push(TokenTree::Ident(Ident { sym: ident.name, - is_raw: is_raw.into(), + is_raw: matches!(is_raw, IdentIsRaw::Yes), span: ident.span, })), @@ -263,7 +265,11 @@ impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> for Vec<TokenTree<TokenStre let ident = rustc_span::Ident::new(name, span).without_first_quote(); trees.extend([ TokenTree::Punct(Punct { ch: b'\'', joint: true, span }), - TokenTree::Ident(Ident { sym: ident.name, is_raw: is_raw.into(), span }), + TokenTree::Ident(Ident { + sym: ident.name, + is_raw: matches!(is_raw, IdentIsRaw::Yes), + span, + }), ]); } NtLifetime(ident, is_raw) => { diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 8f632bcebc7..e81003b1897 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -745,6 +745,10 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ ErrorPreceding, EncodeCrossCrate::No ), gated!( + unsafe force_target_feature, Normal, template!(List: &[r#"enable = "name""#]), + DuplicatesOk, EncodeCrossCrate::No, effective_target_features, experimental!(force_target_feature) + ), + gated!( sanitize, Normal, template!(List: &[r#"address = "on|off""#, r#"kernel_address = "on|off""#, r#"cfi = "on|off""#, r#"hwaddress = "on|off""#, r#"kcfi = "on|off""#, r#"memory = "on|off""#, r#"memtag = "on|off""#, r#"shadow_call_stack = "on|off""#, r#"thread = "on|off""#]), ErrorPreceding, EncodeCrossCrate::No, sanitize, experimental!(sanitize), ), diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 746871982ce..92b435b4b01 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -480,6 +480,8 @@ declare_features! ( (unstable, doc_cfg_hide, "1.57.0", Some(43781)), /// Allows `#[doc(masked)]`. (unstable, doc_masked, "1.21.0", Some(44027)), + /// Allows features to allow target_feature to better interact with traits. + (incomplete, effective_target_features, "CURRENT_RUSTC_VERSION", Some(143352)), /// Allows the .use postfix syntax `x.use` and use closures `use |x| { ... }` (incomplete, ergonomic_clones, "1.87.0", Some(132290)), /// Allows exhaustive pattern matching on types that contain uninhabited types. @@ -614,6 +616,7 @@ declare_features! ( (unstable, proc_macro_hygiene, "1.30.0", Some(54727)), /// Allows the use of raw-dylibs on ELF platforms (incomplete, raw_dylib_elf, "1.87.0", Some(135694)), + (unstable, reborrow, "CURRENT_RUSTC_VERSION", Some(145612)), /// Makes `&` and `&mut` patterns eat only one layer of references in Rust 2024. (incomplete, ref_pat_eat_one_layer_2024, "1.79.0", Some(123076)), /// Makes `&` and `&mut` patterns eat only one layer of references in Rust 2024—structural variant diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index a17350f0392..2209b18df3f 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -524,8 +524,9 @@ pub enum AttributeKind { /// Represents `#[rustc_std_internal_symbol]`. StdInternalSymbol(Span), - /// Represents `#[target_feature(enable = "...")]` - TargetFeature(ThinVec<(Symbol, Span)>, Span), + /// Represents `#[target_feature(enable = "...")]` and + /// `#[unsafe(force_target_feature(enable = "...")]`. + TargetFeature { features: ThinVec<(Symbol, Span)>, attr_span: Span, was_forced: bool }, /// Represents `#[track_caller]` TrackCaller(Span), diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index defabdccc02..485ded3981f 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -78,7 +78,7 @@ impl AttributeKind { SpecializationTrait(..) => No, Stability { .. } => Yes, StdInternalSymbol(..) => No, - TargetFeature(..) => No, + TargetFeature { .. } => No, TrackCaller(..) => Yes, TypeConst(..) => Yes, UnsafeSpecializationMarker(..) => No, diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 39696f74d51..e397c286de2 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1161,6 +1161,12 @@ pub struct AttrPath { pub span: Span, } +impl IntoDiagArg for AttrPath { + fn into_diag_arg(self, path: &mut Option<std::path::PathBuf>) -> DiagArgValue { + self.to_string().into_diag_arg(path) + } +} + impl AttrPath { pub fn from_ast(path: &ast::Path) -> Self { AttrPath { diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 905b84a8cbe..0464665b41f 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -437,6 +437,9 @@ language_item_table! { DefaultTrait1, sym::default_trait1, default_trait1_trait, Target::Trait, GenericRequirement::None; ContractCheckEnsures, sym::contract_check_ensures, contract_check_ensures_fn, Target::Fn, GenericRequirement::None; + + // Reborrowing related lang-items + Reborrow, sym::reborrow, reborrow, Target::Trait, GenericRequirement::Exact(0); } /// The requirement imposed on the generics of a lang item diff --git a/compiler/rustc_hir/src/lints.rs b/compiler/rustc_hir/src/lints.rs index e3cde2d3bb6..061ec786dc8 100644 --- a/compiler/rustc_hir/src/lints.rs +++ b/compiler/rustc_hir/src/lints.rs @@ -1,8 +1,8 @@ use rustc_data_structures::fingerprint::Fingerprint; use rustc_macros::HashStable_Generic; -use rustc_span::{Span, Symbol}; +use rustc_span::Span; -use crate::{HirId, Target}; +use crate::{AttrPath, HirId, Target}; #[derive(Debug)] pub struct DelayedLints { @@ -34,5 +34,5 @@ pub enum AttributeLintKind { UnusedDuplicate { this: Span, other: Span, warning: bool }, IllFormedAttributeInput { suggestions: Vec<String> }, EmptyAttribute { first_span: Span }, - InvalidTarget { name: Symbol, target: Target, applied: String, only: &'static str }, + InvalidTarget { name: AttrPath, target: Target, applied: Vec<String>, only: &'static str }, } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index b80a2af3100..5aec50c8b53 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -83,14 +83,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { *self.deferred_cast_checks.borrow_mut() = deferred_cast_checks; } - pub(in super::super) fn check_transmutes(&self) { - let mut deferred_transmute_checks = self.deferred_transmute_checks.borrow_mut(); - debug!("FnCtxt::check_transmutes: {} deferred checks", deferred_transmute_checks.len()); - for (from, to, hir_id) in deferred_transmute_checks.drain(..) { - self.check_transmute(from, to, hir_id); - } - } - pub(in super::super) fn check_asms(&self) { let mut deferred_asm_checks = self.deferred_asm_checks.borrow_mut(); debug!("FnCtxt::check_asm: {} deferred checks", deferred_asm_checks.len()); diff --git a/compiler/rustc_hir_typeck/src/intrinsicck.rs b/compiler/rustc_hir_typeck/src/intrinsicck.rs index 194e420b606..7567f8ba348 100644 --- a/compiler/rustc_hir_typeck/src/intrinsicck.rs +++ b/compiler/rustc_hir_typeck/src/intrinsicck.rs @@ -7,11 +7,10 @@ use rustc_hir as hir; use rustc_index::Idx; use rustc_middle::bug; use rustc_middle::ty::layout::{LayoutError, SizeSkeleton}; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; +use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_span::def_id::LocalDefId; use tracing::trace; -use super::FnCtxt; - /// If the type is `Option<T>`, it will return `T`, otherwise /// the type itself. Works on most `Option`-like types. fn unpack_option_like<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { @@ -39,119 +38,117 @@ fn unpack_option_like<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { ty } -impl<'a, 'tcx> FnCtxt<'a, 'tcx> { - /// FIXME: Move this check out of typeck, since it'll easily cycle when revealing opaques, - /// and we shouldn't need to check anything here if the typeck results are tainted. - pub(crate) fn check_transmute(&self, from: Ty<'tcx>, to: Ty<'tcx>, hir_id: HirId) { - let tcx = self.tcx; - let dl = &tcx.data_layout; - let span = tcx.hir_span(hir_id); - let normalize = |ty| { - let ty = self.resolve_vars_if_possible(ty); - if let Ok(ty) = - self.tcx.try_normalize_erasing_regions(self.typing_env(self.param_env), ty) - { - ty +/// Try to display a sensible error with as much information as possible. +fn skeleton_string<'tcx>( + ty: Ty<'tcx>, + sk: Result<SizeSkeleton<'tcx>, &'tcx LayoutError<'tcx>>, +) -> String { + match sk { + Ok(SizeSkeleton::Pointer { tail, .. }) => format!("pointer to `{tail}`"), + Ok(SizeSkeleton::Known(size, _)) => { + if let Some(v) = u128::from(size.bytes()).checked_mul(8) { + format!("{v} bits") } else { - Ty::new_error_with_message( - tcx, - span, - "tried to normalize non-wf type in check_transmute", - ) + // `u128` should definitely be able to hold the size of different architectures + // larger sizes should be reported as error `are too big for the target architecture` + // otherwise we have a bug somewhere + bug!("{:?} overflow for u128", size) } - }; - let from = normalize(from); - let to = normalize(to); - trace!(?from, ?to); - if from.has_non_region_infer() || to.has_non_region_infer() { - // Note: this path is currently not reached in any test, so any - // example that triggers this would be worth minimizing and - // converting into a test. - self.dcx().span_bug(span, "argument to transmute has inference variables"); } - // Transmutes that are only changing lifetimes are always ok. - if from == to { - return; + Ok(SizeSkeleton::Generic(size)) => { + format!("generic size {size}") + } + Err(LayoutError::TooGeneric(bad)) => { + if *bad == ty { + "this type does not have a fixed size".to_owned() + } else { + format!("size can vary because of {bad}") + } + } + Err(err) => err.to_string(), + } +} + +fn check_transmute<'tcx>( + tcx: TyCtxt<'tcx>, + typing_env: ty::TypingEnv<'tcx>, + from: Ty<'tcx>, + to: Ty<'tcx>, + hir_id: HirId, +) { + let span = || tcx.hir_span(hir_id); + let normalize = |ty| { + if let Ok(ty) = tcx.try_normalize_erasing_regions(typing_env, ty) { + ty + } else { + Ty::new_error_with_message( + tcx, + span(), + format!("tried to normalize non-wf type {ty:#?} in check_transmute"), + ) } + }; - let skel = |ty| SizeSkeleton::compute(ty, tcx, self.typing_env(self.param_env)); - let sk_from = skel(from); - let sk_to = skel(to); - trace!(?sk_from, ?sk_to); + let from = normalize(from); + let to = normalize(to); + trace!(?from, ?to); - // Check for same size using the skeletons. - if let (Ok(sk_from), Ok(sk_to)) = (sk_from, sk_to) { - if sk_from.same_size(sk_to) { - return; - } + // Transmutes that are only changing lifetimes are always ok. + if from == to { + return; + } - // Special-case transmuting from `typeof(function)` and - // `Option<typeof(function)>` to present a clearer error. - let from = unpack_option_like(tcx, from); - if let (&ty::FnDef(..), SizeSkeleton::Known(size_to, _)) = (from.kind(), sk_to) - && size_to == Pointer(dl.instruction_address_space).size(&tcx) - { - struct_span_code_err!(self.dcx(), span, E0591, "can't transmute zero-sized type") - .with_note(format!("source type: {from}")) - .with_note(format!("target type: {to}")) - .with_help("cast with `as` to a pointer instead") - .emit(); - return; - } + let sk_from = SizeSkeleton::compute(from, tcx, typing_env); + let sk_to = SizeSkeleton::compute(to, tcx, typing_env); + trace!(?sk_from, ?sk_to); + + // Check for same size using the skeletons. + if let Ok(sk_from) = sk_from + && let Ok(sk_to) = sk_to + { + if sk_from.same_size(sk_to) { + return; } - // Try to display a sensible error with as much information as possible. - let skeleton_string = |ty: Ty<'tcx>, sk: Result<_, &_>| match sk { - Ok(SizeSkeleton::Pointer { tail, .. }) => format!("pointer to `{tail}`"), - Ok(SizeSkeleton::Known(size, _)) => { - if let Some(v) = u128::from(size.bytes()).checked_mul(8) { - format!("{v} bits") - } else { - // `u128` should definitely be able to hold the size of different architectures - // larger sizes should be reported as error `are too big for the target architecture` - // otherwise we have a bug somewhere - bug!("{:?} overflow for u128", size) - } - } - Ok(SizeSkeleton::Generic(size)) => { - if let Some(size) = - self.try_structurally_resolve_const(span, size).try_to_target_usize(tcx) - { - format!("{size} bytes") - } else { - format!("generic size {size}") - } - } - Err(LayoutError::TooGeneric(bad)) => { - if *bad == ty { - "this type does not have a fixed size".to_owned() - } else { - format!("size can vary because of {bad}") - } - } - Err(err) => err.to_string(), - }; - - let mut err = struct_span_code_err!( - self.dcx(), - span, - E0512, - "cannot transmute between types of different sizes, \ - or dependently-sized types" - ); - if from == to { - err.note(format!("`{from}` does not have a fixed size")); - err.emit(); - } else { - err.note(format!("source type: `{}` ({})", from, skeleton_string(from, sk_from))) - .note(format!("target type: `{}` ({})", to, skeleton_string(to, sk_to))); - if let Err(LayoutError::ReferencesError(_)) = sk_from { - err.delay_as_bug(); - } else if let Err(LayoutError::ReferencesError(_)) = sk_to { - err.delay_as_bug(); - } else { - err.emit(); - } + // Special-case transmuting from `typeof(function)` and + // `Option<typeof(function)>` to present a clearer error. + let from = unpack_option_like(tcx, from); + if let ty::FnDef(..) = from.kind() + && let SizeSkeleton::Known(size_to, _) = sk_to + && size_to == Pointer(tcx.data_layout.instruction_address_space).size(&tcx) + { + struct_span_code_err!(tcx.sess.dcx(), span(), E0591, "can't transmute zero-sized type") + .with_note(format!("source type: {from}")) + .with_note(format!("target type: {to}")) + .with_help("cast with `as` to a pointer instead") + .emit(); + return; } } + + let mut err = struct_span_code_err!( + tcx.sess.dcx(), + span(), + E0512, + "cannot transmute between types of different sizes, or dependently-sized types" + ); + if from == to { + err.note(format!("`{from}` does not have a fixed size")); + err.emit(); + } else { + err.note(format!("source type: `{}` ({})", from, skeleton_string(from, sk_from))); + err.note(format!("target type: `{}` ({})", to, skeleton_string(to, sk_to))); + err.emit(); + } +} + +pub(crate) fn check_transmutes(tcx: TyCtxt<'_>, owner: LocalDefId) { + assert!(!tcx.is_typeck_child(owner.to_def_id())); + let typeck_results = tcx.typeck(owner); + let None = typeck_results.tainted_by_errors else { return }; + + let typing_env = ty::TypingEnv::post_analysis(tcx, owner); + for &(from, to, hir_id) in &typeck_results.transmutes_to_check { + check_transmute(tcx, typing_env, from, to, hir_id); + } } diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index aae870f7ee3..ab4181f5293 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -251,10 +251,6 @@ fn typeck_with_inspect<'tcx>( fcx.report_ambiguity_errors(); } - if let None = fcx.infcx.tainted_by_errors() { - fcx.check_transmutes(); - } - fcx.check_asms(); let typeck_results = fcx.resolve_type_vars_in_body(body); @@ -555,6 +551,7 @@ pub fn provide(providers: &mut Providers) { method_autoderef_steps: method::probe::method_autoderef_steps, typeck, used_trait_imports, + check_transmutes: intrinsicck::check_transmutes, ..*providers }; } diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 824d592fa6c..c8f6c06b720 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -13,9 +13,7 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::sorted_map::SortedMap; use rustc_data_structures::unord::UnordSet; use rustc_errors::codes::*; -use rustc_errors::{ - Applicability, Diag, DiagStyledString, MultiSpan, StashKey, pluralize, struct_span_code_err, -}; +use rustc_errors::{Applicability, Diag, MultiSpan, StashKey, pluralize, struct_span_code_err}; use rustc_hir::attrs::AttributeKind; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::DefId; @@ -1560,11 +1558,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } - if rcvr_ty.is_numeric() && rcvr_ty.is_fresh() - || restrict_type_params - || suggested_derive - || self.lookup_alternative_tuple_impls(&mut err, &unsatisfied_predicates) - { + if rcvr_ty.is_numeric() && rcvr_ty.is_fresh() || restrict_type_params || suggested_derive { } else { self.suggest_traits_to_import( &mut err, @@ -1741,119 +1735,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.emit() } - /// If the predicate failure is caused by an unmet bound on a tuple, recheck if the bound would - /// succeed if all the types on the tuple had no borrows. This is a common problem for libraries - /// like Bevy and ORMs, which rely heavily on traits being implemented on tuples. - fn lookup_alternative_tuple_impls( - &self, - err: &mut Diag<'_>, - unsatisfied_predicates: &[( - ty::Predicate<'tcx>, - Option<ty::Predicate<'tcx>>, - Option<ObligationCause<'tcx>>, - )], - ) -> bool { - let mut found_tuple = false; - for (pred, root, _ob) in unsatisfied_predicates { - let mut preds = vec![pred]; - if let Some(root) = root { - // We will look at both the current predicate and the root predicate that caused it - // to be needed. If calling something like `<(A, &B)>::default()`, then `pred` is - // `&B: Default` and `root` is `(A, &B): Default`, which is the one we are checking - // for further down, so we check both. - preds.push(root); - } - for pred in preds { - if let Some(clause) = pred.as_clause() - && let Some(clause) = clause.as_trait_clause() - && let ty = clause.self_ty().skip_binder() - && let ty::Tuple(types) = ty.kind() - { - let path = clause.skip_binder().trait_ref.print_only_trait_path(); - let def_id = clause.def_id(); - let ty = Ty::new_tup( - self.tcx, - self.tcx.mk_type_list_from_iter(types.iter().map(|ty| ty.peel_refs())), - ); - let args = ty::GenericArgs::for_item(self.tcx, def_id, |param, _| { - if param.index == 0 { - ty.into() - } else { - self.infcx.var_for_def(DUMMY_SP, param) - } - }); - if self - .infcx - .type_implements_trait(def_id, args, self.param_env) - .must_apply_modulo_regions() - { - // "`Trait` is implemented for `(A, B)` but not for `(A, &B)`" - let mut msg = DiagStyledString::normal(format!("`{path}` ")); - msg.push_highlighted("is"); - msg.push_normal(" implemented for `("); - let len = types.len(); - for (i, t) in types.iter().enumerate() { - msg.push( - format!("{}", with_forced_trimmed_paths!(t.peel_refs())), - t.peel_refs() != t, - ); - if i < len - 1 { - msg.push_normal(", "); - } - } - msg.push_normal(")` but "); - msg.push_highlighted("not"); - msg.push_normal(" for `("); - for (i, t) in types.iter().enumerate() { - msg.push( - format!("{}", with_forced_trimmed_paths!(t)), - t.peel_refs() != t, - ); - if i < len - 1 { - msg.push_normal(", "); - } - } - msg.push_normal(")`"); - - // Find the span corresponding to the impl that was found to point at it. - if let Some(impl_span) = self - .tcx - .all_impls(def_id) - .filter(|&impl_def_id| { - let header = self.tcx.impl_trait_header(impl_def_id).unwrap(); - let trait_ref = header.trait_ref.instantiate( - self.tcx, - self.infcx.fresh_args_for_item(DUMMY_SP, impl_def_id), - ); - - let value = ty::fold_regions(self.tcx, ty, |_, _| { - self.tcx.lifetimes.re_erased - }); - // FIXME: Don't bother dealing with non-lifetime binders here... - if value.has_escaping_bound_vars() { - return false; - } - self.infcx.can_eq(ty::ParamEnv::empty(), trait_ref.self_ty(), value) - && header.polarity == ty::ImplPolarity::Positive - }) - .map(|impl_def_id| self.tcx.def_span(impl_def_id)) - .next() - { - err.highlighted_span_note(impl_span, msg.0); - } else { - err.highlighted_note(msg.0); - } - found_tuple = true; - } - // If `pred` was already on the tuple, we don't need to look at the root - // obligation too. - break; - } - } - } - found_tuple - } - /// If an appropriate error source is not found, check method chain for possible candidates fn lookup_segments_chain_for_no_match_method( &self, diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index 093de950d63..42736a07b2a 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -74,6 +74,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { wbcx.visit_user_provided_tys(); wbcx.visit_user_provided_sigs(); wbcx.visit_coroutine_interior(); + wbcx.visit_transmutes(); wbcx.visit_offset_of_container_types(); wbcx.typeck_results.rvalue_scopes = @@ -532,6 +533,18 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { } } + fn visit_transmutes(&mut self) { + let tcx = self.tcx(); + let fcx_typeck_results = self.fcx.typeck_results.borrow(); + assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner); + for &(from, to, hir_id) in self.fcx.deferred_transmute_checks.borrow().iter() { + let span = tcx.hir_span(hir_id); + let from = self.resolve(from, &span); + let to = self.resolve(to, &span); + self.typeck_results.transmutes_to_check.push((from, to, hir_id)); + } + } + #[instrument(skip(self), level = "debug")] fn visit_opaque_types(&mut self) { let tcx = self.tcx(); diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 3ba224723e3..90f7ae76387 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -6,6 +6,7 @@ use std::sync::{Arc, LazyLock, OnceLock}; use std::{env, fs, iter}; use rustc_ast as ast; +use rustc_attr_parsing::validate_attr; use rustc_codegen_ssa::traits::CodegenBackend; use rustc_data_structures::jobserver::Proxy; use rustc_data_structures::steal::Steal; @@ -25,9 +26,7 @@ use rustc_middle::arena::Arena; use rustc_middle::dep_graph::DepsType; use rustc_middle::ty::{self, CurrentGcx, GlobalCtxt, RegisteredTools, TyCtxt}; use rustc_middle::util::Providers; -use rustc_parse::{ - new_parser_from_file, new_parser_from_source_str, unwrap_or_emit_fatal, validate_attr, -}; +use rustc_parse::{new_parser_from_file, new_parser_from_source_str, unwrap_or_emit_fatal}; use rustc_passes::{abi_test, input_stats, layout_test}; use rustc_resolve::{Resolver, ResolverOutputs}; use rustc_session::config::{CrateType, Input, OutFileName, OutputFilenames, OutputType}; @@ -1081,7 +1080,8 @@ fn run_required_analyses(tcx: TyCtxt<'_>) { if !tcx.is_typeck_child(def_id.to_def_id()) { // Child unsafety and borrowck happens together with the parent tcx.ensure_ok().check_unsafety(def_id); - tcx.ensure_ok().mir_borrowck(def_id) + tcx.ensure_ok().mir_borrowck(def_id); + tcx.ensure_ok().check_transmutes(def_id); } tcx.ensure_ok().has_ffi_unwind_calls(def_id); diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index 0ca4fcc66ca..9a432a60819 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -5,14 +5,15 @@ use std::sync::{Arc, OnceLock}; use std::{env, thread}; use rustc_ast as ast; +use rustc_attr_parsing::validate_attr; use rustc_codegen_ssa::traits::CodegenBackend; use rustc_data_structures::jobserver::Proxy; use rustc_data_structures::sync; +use rustc_errors::LintBuffer; use rustc_metadata::{DylibError, load_symbol_from_dylib}; use rustc_middle::ty::CurrentGcx; -use rustc_parse::validate_attr; use rustc_session::config::{Cfg, OutFileName, OutputFilenames, OutputTypes, Sysroot, host_tuple}; -use rustc_session::lint::{self, BuiltinLintDiag, LintBuffer}; +use rustc_session::lint::{self, BuiltinLintDiag}; use rustc_session::output::{CRATE_TYPES, categorize_crate_type}; use rustc_session::{EarlyDiagCtxt, Session, filesearch}; use rustc_span::edit_distance::find_best_match_for_name; diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs index e80196ed567..483cc3e93dc 100644 --- a/compiler/rustc_lexer/src/lib.rs +++ b/compiler/rustc_lexer/src/lib.rs @@ -540,11 +540,11 @@ impl Cursor<'_> { // whitespace between the opening and the infostring. self.eat_while(|ch| ch != '\n' && is_whitespace(ch)); - // copied from `eat_identifier`, but allows `.` in infostring to allow something like + // copied from `eat_identifier`, but allows `-` and `.` in infostring to allow something like // `---Cargo.toml` as a valid opener if is_id_start(self.first()) { self.bump(); - self.eat_while(|c| is_id_continue(c) || c == '.'); + self.eat_while(|c| is_id_continue(c) || c == '-' || c == '.'); } self.eat_while(|ch| ch != '\n' && is_whitespace(ch)); diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index f26e5f05e1a..940a07c94df 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -205,8 +205,6 @@ lint_confusable_identifier_pair = found both `{$existing_sym}` and `{$sym}` as i .current_use = this identifier can be confused with `{$existing_sym}` .other_use = other identifier used here -lint_custom_inner_attribute_unstable = custom inner attributes are unstable - lint_dangling_pointers_from_locals = a dangling pointer will be produced because the local variable `{$local_var_name}` will be dropped .ret_ty = return type of the {$fn_kind} is `{$ret_ty}` .local_var = `{$local_var_name}` is part the {$fn_kind} and will be dropped at the end of the {$fn_kind} @@ -271,10 +269,6 @@ lint_expectation = this lint expectation is unfulfilled lint_extern_crate_not_idiomatic = `extern crate` is not idiomatic in the new edition .suggestion = convert it to a `use` -lint_extern_without_abi = `extern` declarations without an explicit ABI are deprecated - .label = ABI should be specified here - .suggestion = explicitly specify the {$default_abi} ABI - lint_for_loops_over_fallibles = for loop over {$article} `{$ref_prefix}{$ty}`. This is more readably written as an `if let` statement .suggestion = consider using `if let` to clear intent @@ -294,19 +288,6 @@ lint_hidden_glob_reexport = private item shadows public glob re-export lint_hidden_lifetime_parameters = hidden lifetime parameters in types are deprecated -lint_hidden_unicode_codepoints = unicode codepoint changing visible direction of text present in {$label} - .label = this {$label} contains {$count -> - [one] an invisible - *[other] invisible - } unicode text flow control {$count -> - [one] codepoint - *[other] codepoints - } - .note = these kind of unicode codepoints change the way text flows on applications that support them, but can cause confusion because they change the order of characters on the screen - .suggestion_remove = if their presence wasn't intentional, you can remove them - .suggestion_escape = if you want to keep them but make them visible in your source code, you can escape them - .no_suggestion_note_escape = if you want to keep them but make them visible in your source code, you can escape them: {$escaped} - lint_identifier_non_ascii_char = identifier contains non-ASCII characters lint_identifier_uncommon_codepoints = identifier contains {$codepoints_len -> @@ -431,8 +412,6 @@ lint_improper_ctypes_union_non_exhaustive = this union is non-exhaustive lint_incomplete_include = include macro expected single expression in source -lint_inner_macro_attribute_unstable = inner macro attributes are unstable - lint_invalid_asm_label_binary = avoid using labels containing only the digits `0` and `1` in inline assembly .label = use a different label that doesn't start with `0` or `1` .help = start numbering with `2` instead @@ -870,10 +849,6 @@ lint_undropped_manually_drops = calls to `std::mem::drop` with `std::mem::Manual .label = argument has type `{$arg_ty}` .suggestion = use `std::mem::ManuallyDrop::into_inner` to get the inner value -lint_unexpected_builtin_cfg = unexpected `--cfg {$cfg}` flag - .controlled_by = config `{$cfg_name}` is only supposed to be controlled by `{$controlled_by}` - .incoherent = manually setting a built-in cfg can and does create incoherent behaviors - lint_unexpected_cfg_add_build_rs_println = or consider adding `{$build_rs_println}` to the top of the `build.rs` lint_unexpected_cfg_add_cargo_feature = consider using a Cargo feature instead lint_unexpected_cfg_add_cargo_toml_lint_cfg = or consider adding in `Cargo.toml` the `check-cfg` lint config for the lint:{$cargo_toml_lint_cfg} diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index e9bd9dccdf1..0669da1a025 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -11,7 +11,7 @@ use rustc_ast::util::parser::ExprPrecedence; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::sync; use rustc_data_structures::unord::UnordMap; -use rustc_errors::{Diag, LintDiagnostic, MultiSpan}; +use rustc_errors::{Diag, LintBuffer, LintDiagnostic, MultiSpan}; use rustc_feature::Features; use rustc_hir::def::Res; use rustc_hir::def_id::{CrateNum, DefId}; @@ -23,7 +23,7 @@ use rustc_middle::middle::privacy::EffectiveVisibilities; use rustc_middle::ty::layout::{LayoutError, LayoutOfHelpers, TyAndLayout}; use rustc_middle::ty::print::{PrintError, PrintTraitRefExt as _, Printer, with_no_trimmed_paths}; use rustc_middle::ty::{self, GenericArg, RegisteredTools, Ty, TyCtxt, TypingEnv, TypingMode}; -use rustc_session::lint::{FutureIncompatibleInfo, Lint, LintBuffer, LintExpectationId, LintId}; +use rustc_session::lint::{FutureIncompatibleInfo, Lint, LintExpectationId, LintId}; use rustc_session::{DynLintStore, Session}; use rustc_span::edit_distance::find_best_match_for_names; use rustc_span::{Ident, Span, Symbol, sym}; diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs index 58205087def..dff1fc43670 100644 --- a/compiler/rustc_lint/src/early.rs +++ b/compiler/rustc_lint/src/early.rs @@ -7,10 +7,11 @@ use rustc_ast::visit::{self as ast_visit, Visitor, walk_list}; use rustc_ast::{self as ast, HasAttrs}; use rustc_data_structures::stack::ensure_sufficient_stack; +use rustc_errors::{BufferedEarlyLint, DecorateDiagCompat, LintBuffer}; use rustc_feature::Features; use rustc_middle::ty::{RegisteredTools, TyCtxt}; use rustc_session::Session; -use rustc_session::lint::{BufferedEarlyLint, LintBuffer, LintPass}; +use rustc_session::lint::LintPass; use rustc_span::{Ident, Span}; use tracing::debug; @@ -36,8 +37,11 @@ impl<'ecx, 'tcx, T: EarlyLintPass> EarlyContextAndPass<'ecx, 'tcx, T> { fn check_id(&mut self, id: ast::NodeId) { for early_lint in self.context.buffered.take(id) { let BufferedEarlyLint { span, node_id: _, lint_id, diagnostic } = early_lint; - self.context.opt_span_lint(lint_id.lint, span, |diag| { - diagnostics::decorate_builtin_lint(self.context.sess(), self.tcx, diagnostic, diag); + self.context.opt_span_lint(lint_id.lint, span, |diag| match diagnostic { + DecorateDiagCompat::Builtin(b) => { + diagnostics::decorate_builtin_lint(self.context.sess(), self.tcx, b, diag); + } + DecorateDiagCompat::Dynamic(d) => d.decorate_lint_box(diag), }); } } diff --git a/compiler/rustc_lint/src/early/diagnostics.rs b/compiler/rustc_lint/src/early/diagnostics.rs index 0e283ed923a..7300490b838 100644 --- a/compiler/rustc_lint/src/early/diagnostics.rs +++ b/compiler/rustc_lint/src/early/diagnostics.rs @@ -158,9 +158,6 @@ pub fn decorate_builtin_lint( } .decorate_lint(diag); } - BuiltinLintDiag::MissingAbi(label_span, default_abi) => { - lints::MissingAbi { span: label_span, default_abi }.decorate_lint(diag); - } BuiltinLintDiag::LegacyDeriveHelpers(label_span) => { lints::LegacyDeriveHelpers { span: label_span }.decorate_lint(diag); } @@ -186,27 +183,6 @@ pub fn decorate_builtin_lint( lints::ReservedMultihash { suggestion }.decorate_lint(diag); } } - BuiltinLintDiag::HiddenUnicodeCodepoints { - label, - count, - span_label, - labels, - escape, - spans, - } => { - lints::HiddenUnicodeCodepointsDiag { - label: &label, - count, - span_label, - labels: labels.map(|spans| lints::HiddenUnicodeCodepointsDiagLabels { spans }), - sub: if escape { - lints::HiddenUnicodeCodepointsDiagSub::Escape { spans } - } else { - lints::HiddenUnicodeCodepointsDiagSub::NoEscape { spans } - }, - } - .decorate_lint(diag); - } BuiltinLintDiag::UnusedBuiltinAttribute { attr_name, macro_name, @@ -466,17 +442,8 @@ pub fn decorate_builtin_lint( } .decorate_lint(diag) } - BuiltinLintDiag::InnerAttributeUnstable { is_macro } => if is_macro { - lints::InnerAttributeUnstable::InnerMacroAttribute - } else { - lints::InnerAttributeUnstable::CustomInnerAttribute - } - .decorate_lint(diag), BuiltinLintDiag::OutOfScopeMacroCalls { span, path, location } => { lints::OutOfScopeMacroCalls { span, path, location }.decorate_lint(diag) } - BuiltinLintDiag::UnexpectedBuiltinCfg { cfg, cfg_name, controlled_by } => { - lints::UnexpectedBuiltinCfg { cfg, cfg_name, controlled_by }.decorate_lint(diag) - } } } diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs index e1fbe39222b..929fc8207b0 100644 --- a/compiler/rustc_lint/src/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -4,7 +4,7 @@ use rustc_hir::def::Res; use rustc_hir::def_id::DefId; use rustc_hir::{Expr, ExprKind, HirId}; -use rustc_middle::ty::{self, ClauseKind, GenericArgsRef, PredicatePolarity, TraitPredicate, Ty}; +use rustc_middle::ty::{self, GenericArgsRef, PredicatePolarity, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::hygiene::{ExpnKind, MacroKind}; use rustc_span::{Span, sym}; @@ -129,18 +129,23 @@ fn has_unstable_into_iter_predicate<'tcx>( }; let predicates = cx.tcx.predicates_of(callee_def_id).instantiate(cx.tcx, generic_args); for (predicate, _) in predicates { - let ClauseKind::Trait(TraitPredicate { trait_ref, polarity: PredicatePolarity::Positive }) = - predicate.kind().skip_binder() - else { + let Some(trait_pred) = predicate.as_trait_clause() else { continue; }; - // Does the function or method require any of its arguments to implement `IntoIterator`? - if trait_ref.def_id != into_iterator_def_id { + if trait_pred.def_id() != into_iterator_def_id + || trait_pred.polarity() != PredicatePolarity::Positive + { continue; } - let Ok(Some(instance)) = - ty::Instance::try_resolve(cx.tcx, cx.typing_env(), into_iter_fn_def_id, trait_ref.args) - else { + // `IntoIterator::into_iter` has no additional method args. + let into_iter_fn_args = + cx.tcx.instantiate_bound_regions_with_erased(trait_pred).trait_ref.args; + let Ok(Some(instance)) = ty::Instance::try_resolve( + cx.tcx, + cx.typing_env(), + into_iter_fn_def_id, + into_iter_fn_args, + ) else { continue; }; // Does the input type's `IntoIterator` implementation have the diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index f06757b3c23..bdbac7fc4d1 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -133,10 +133,9 @@ pub use early::{EarlyCheckNode, check_ast_node}; pub use late::{check_crate, late_lint_mod, unerased_lint_store}; pub use levels::LintLevelsBuilder; pub use passes::{EarlyLintPass, LateLintPass}; +pub use rustc_errors::BufferedEarlyLint; pub use rustc_session::lint::Level::{self, *}; -pub use rustc_session::lint::{ - BufferedEarlyLint, FutureIncompatibleInfo, Lint, LintId, LintPass, LintVec, -}; +pub use rustc_session::lint::{FutureIncompatibleInfo, Lint, LintId, LintPass, LintVec}; rustc_fluent_macro::fluent_messages! { "../messages.ftl" } diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index a1e26bf1503..6c509734626 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -1,7 +1,6 @@ #![allow(rustc::untranslatable_diagnostic)] use std::num::NonZero; -use rustc_abi::ExternAbi; use rustc_errors::codes::*; use rustc_errors::{ Applicability, Diag, DiagArgValue, DiagMessage, DiagStyledString, ElidedLifetimeInPathSubdiag, @@ -816,80 +815,6 @@ pub(crate) enum InvalidReferenceCastingDiag<'tcx> { }, } -// hidden_unicode_codepoints.rs -#[derive(LintDiagnostic)] -#[diag(lint_hidden_unicode_codepoints)] -#[note] -pub(crate) struct HiddenUnicodeCodepointsDiag<'a> { - pub label: &'a str, - pub count: usize, - #[label] - pub span_label: Span, - #[subdiagnostic] - pub labels: Option<HiddenUnicodeCodepointsDiagLabels>, - #[subdiagnostic] - pub sub: HiddenUnicodeCodepointsDiagSub, -} - -pub(crate) struct HiddenUnicodeCodepointsDiagLabels { - pub spans: Vec<(char, Span)>, -} - -impl Subdiagnostic for HiddenUnicodeCodepointsDiagLabels { - fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) { - for (c, span) in self.spans { - diag.span_label(span, format!("{c:?}")); - } - } -} - -pub(crate) enum HiddenUnicodeCodepointsDiagSub { - Escape { spans: Vec<(char, Span)> }, - NoEscape { spans: Vec<(char, Span)> }, -} - -// Used because of multiple multipart_suggestion and note -impl Subdiagnostic for HiddenUnicodeCodepointsDiagSub { - fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) { - match self { - HiddenUnicodeCodepointsDiagSub::Escape { spans } => { - diag.multipart_suggestion_with_style( - fluent::lint_suggestion_remove, - spans.iter().map(|(_, span)| (*span, "".to_string())).collect(), - Applicability::MachineApplicable, - SuggestionStyle::HideCodeAlways, - ); - diag.multipart_suggestion( - fluent::lint_suggestion_escape, - spans - .into_iter() - .map(|(c, span)| { - let c = format!("{c:?}"); - (span, c[1..c.len() - 1].to_string()) - }) - .collect(), - Applicability::MachineApplicable, - ); - } - HiddenUnicodeCodepointsDiagSub::NoEscape { spans } => { - // FIXME: in other suggestions we've reversed the inner spans of doc comments. We - // should do the same here to provide the same good suggestions as we do for - // literals above. - diag.arg( - "escaped", - spans - .into_iter() - .map(|(c, _)| format!("{c:?}")) - .collect::<Vec<String>>() - .join(", "), - ); - diag.note(fluent::lint_suggestion_remove); - diag.note(fluent::lint_no_suggestion_note_escape); - } - } - } -} - // map_unit_fn.rs #[derive(LintDiagnostic)] #[diag(lint_map_unit_fn)] @@ -2567,16 +2492,6 @@ pub(crate) mod unexpected_cfg_value { } #[derive(LintDiagnostic)] -#[diag(lint_unexpected_builtin_cfg)] -#[note(lint_controlled_by)] -#[note(lint_incoherent)] -pub(crate) struct UnexpectedBuiltinCfg { - pub(crate) cfg: String, - pub(crate) cfg_name: Symbol, - pub(crate) controlled_by: &'static str, -} - -#[derive(LintDiagnostic)] #[diag(lint_macro_use_deprecated)] #[help] pub(crate) struct MacroUseDeprecated; @@ -2690,14 +2605,6 @@ pub(crate) struct IllFormedAttributeInput { } #[derive(LintDiagnostic)] -pub(crate) enum InnerAttributeUnstable { - #[diag(lint_inner_macro_attribute_unstable)] - InnerMacroAttribute, - #[diag(lint_custom_inner_attribute_unstable)] - CustomInnerAttribute, -} - -#[derive(LintDiagnostic)] #[diag(lint_unknown_diagnostic_attribute)] pub(crate) struct UnknownDiagnosticAttribute { #[subdiagnostic] @@ -2890,14 +2797,6 @@ pub(crate) struct PatternsInFnsWithoutBodySub { } #[derive(LintDiagnostic)] -#[diag(lint_extern_without_abi)] -pub(crate) struct MissingAbi { - #[suggestion(code = "extern {default_abi}", applicability = "machine-applicable")] - pub span: Span, - pub default_abi: ExternAbi, -} - -#[derive(LintDiagnostic)] #[diag(lint_legacy_derive_helpers)] pub(crate) struct LegacyDeriveHelpers { #[label] diff --git a/compiler/rustc_lint_defs/Cargo.toml b/compiler/rustc_lint_defs/Cargo.toml index 152eb4fb380..c8201d5ea8c 100644 --- a/compiler/rustc_lint_defs/Cargo.toml +++ b/compiler/rustc_lint_defs/Cargo.toml @@ -5,7 +5,6 @@ edition = "2024" [dependencies] # tidy-alphabetical-start -rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_error_messages = { path = "../rustc_error_messages" } diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index d1f5cc21277..2e84233e5a5 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -1,10 +1,8 @@ use std::borrow::Cow; -use rustc_abi::ExternAbi; use rustc_ast::AttrId; use rustc_ast::attr::AttributeExt; -use rustc_ast::node_id::NodeId; -use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; +use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::stable_hasher::{ HashStable, StableCompare, StableHasher, ToStableHashKey, }; @@ -648,7 +646,6 @@ pub enum BuiltinLintDiag { path: String, since_kind: DeprecatedSinceKind, }, - MissingAbi(Span, ExternAbi), UnusedDocComment(Span), UnusedBuiltinAttribute { attr_name: Symbol, @@ -671,14 +668,6 @@ pub enum BuiltinLintDiag { is_string: bool, suggestion: Span, }, - HiddenUnicodeCodepoints { - label: String, - count: usize, - span_label: Span, - labels: Option<Vec<(char, Span)>>, - escape: bool, - spans: Vec<(char, Span)>, - }, TrailingMacro(bool, Ident), BreakWithLabelAndLoop(Span), UnicodeTextFlow(Span, String), @@ -803,68 +792,11 @@ pub enum BuiltinLintDiag { suggestions: Vec<String>, docs: Option<&'static str>, }, - InnerAttributeUnstable { - is_macro: bool, - }, OutOfScopeMacroCalls { span: Span, path: String, location: String, }, - UnexpectedBuiltinCfg { - cfg: String, - cfg_name: Symbol, - controlled_by: &'static str, - }, -} - -/// Lints that are buffered up early on in the `Session` before the -/// `LintLevels` is calculated. -#[derive(Debug)] -pub struct BufferedEarlyLint { - /// The span of code that we are linting on. - pub span: Option<MultiSpan>, - - /// The `NodeId` of the AST node that generated the lint. - pub node_id: NodeId, - - /// A lint Id that can be passed to - /// `rustc_lint::early::EarlyContextAndPass::check_id`. - pub lint_id: LintId, - - /// Customization of the `Diag<'_>` for the lint. - pub diagnostic: BuiltinLintDiag, -} - -#[derive(Default, Debug)] -pub struct LintBuffer { - pub map: FxIndexMap<NodeId, Vec<BufferedEarlyLint>>, -} - -impl LintBuffer { - pub fn add_early_lint(&mut self, early_lint: BufferedEarlyLint) { - self.map.entry(early_lint.node_id).or_default().push(early_lint); - } - - pub fn take(&mut self, id: NodeId) -> Vec<BufferedEarlyLint> { - // FIXME(#120456) - is `swap_remove` correct? - self.map.swap_remove(&id).unwrap_or_default() - } - - pub fn buffer_lint( - &mut self, - lint: &'static Lint, - node_id: NodeId, - span: impl Into<MultiSpan>, - diagnostic: BuiltinLintDiag, - ) { - self.add_early_lint(BufferedEarlyLint { - lint_id: LintId::of(lint), - node_id, - span: Some(span.into()), - diagnostic, - }); - } } pub type RegisteredTools = FxIndexSet<Ident>; diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index e5cc23c213d..cf0549fa668 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -60,6 +60,7 @@ #![feature(try_trait_v2_residual)] #![feature(try_trait_v2_yeet)] #![feature(type_alias_impl_trait)] +#![feature(unwrap_infallible)] #![feature(yeet_expr)] #![recursion_limit = "256"] // tidy-alphabetical-end diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs index 347319b07c9..78cafe8566b 100644 --- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs +++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs @@ -72,13 +72,23 @@ pub struct CodegenFnAttrs { pub patchable_function_entry: Option<PatchableFunctionEntry>, } +#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable, PartialEq, Eq)] +pub enum TargetFeatureKind { + /// The feature is implied by another feature, rather than explicitly added by the + /// `#[target_feature]` attribute + Implied, + /// The feature is added by the regular `target_feature` attribute. + Enabled, + /// The feature is added by the unsafe `force_target_feature` attribute. + Forced, +} + #[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)] pub struct TargetFeature { /// The name of the target feature (e.g. "avx") pub name: Symbol, - /// The feature is implied by another feature, rather than explicitly added by the - /// `#[target_feature]` attribute - pub implied: bool, + /// The way this feature was enabled. + pub kind: TargetFeatureKind, } #[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)] diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index 4a19cf1563c..18520089e3e 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -4,7 +4,7 @@ use std::num::NonZero; use rustc_ast::NodeId; -use rustc_errors::{Applicability, Diag, EmissionGuarantee}; +use rustc_errors::{Applicability, Diag, EmissionGuarantee, LintBuffer}; use rustc_feature::GateIssue; use rustc_hir::attrs::{DeprecatedSince, Deprecation}; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -12,7 +12,7 @@ use rustc_hir::{self as hir, ConstStability, DefaultBodyStability, HirId, Stabil use rustc_macros::{Decodable, Encodable, HashStable, Subdiagnostic}; use rustc_session::Session; use rustc_session::lint::builtin::{DEPRECATED, DEPRECATED_IN_FUTURE, SOFT_UNSTABLE}; -use rustc_session::lint::{BuiltinLintDiag, DeprecatedSinceKind, Level, Lint, LintBuffer}; +use rustc_session::lint::{BuiltinLintDiag, DeprecatedSinceKind, Level, Lint}; use rustc_session::parse::feature_err_issue; use rustc_span::{Span, Symbol, sym}; use tracing::debug; diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index 0e6f797b1e4..533066bdef9 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -548,10 +548,27 @@ impl<'tcx> CodegenUnit<'tcx> { let mut items: Vec<_> = self.items().iter().map(|(&i, &data)| (i, data)).collect(); if !tcx.sess.opts.unstable_opts.codegen_source_order { - // It's already deterministic, so we can just use it. - return items; + // In this case, we do not need to keep the items in any specific order, as the input + // is already deterministic. + // + // However, it seems that moving related things (such as different + // monomorphizations of the same function) close to one another is actually beneficial + // for LLVM performance. + // LLVM will codegen the items in the order we pass them to it, and when it handles + // similar things in succession, it seems that it leads to better cache utilization, + // less branch mispredictions and in general to better performance. + // For example, if we have functions `a`, `c::<u32>`, `b`, `c::<i16>`, `d` and + // `c::<bool>`, it seems that it helps LLVM's performance to codegen the three `c` + // instantiations right after one another, as they will likely reference similar types, + // call similar functions, etc. + // + // See https://github.com/rust-lang/rust/pull/145358 for more details. + // + // Sorting by symbol name should not incur any new non-determinism. + items.sort_by_cached_key(|&(i, _)| i.symbol_name(tcx)); + } else { + items.sort_by_cached_key(|&(i, _)| item_sort_key(tcx, i)); } - items.sort_by_cached_key(|&(i, _)| item_sort_key(tcx, i)); items } diff --git a/compiler/rustc_middle/src/mir/statement.rs b/compiler/rustc_middle/src/mir/statement.rs index 683d7b48617..6e52bc775ef 100644 --- a/compiler/rustc_middle/src/mir/statement.rs +++ b/compiler/rustc_middle/src/mir/statement.rs @@ -160,7 +160,11 @@ impl<'tcx> PlaceTy<'tcx> { /// Convenience wrapper around `projection_ty_core` for `PlaceElem`, /// where we can just use the `Ty` that is already stored inline on /// field projection elems. - pub fn projection_ty(self, tcx: TyCtxt<'tcx>, elem: PlaceElem<'tcx>) -> PlaceTy<'tcx> { + pub fn projection_ty<V: ::std::fmt::Debug>( + self, + tcx: TyCtxt<'tcx>, + elem: ProjectionElem<V, Ty<'tcx>>, + ) -> PlaceTy<'tcx> { self.projection_ty_core(tcx, &elem, |ty| ty, |_, _, _, ty| ty, |ty| ty) } @@ -290,6 +294,36 @@ impl<V, T> ProjectionElem<V, T> { Self::UnwrapUnsafeBinder(..) => false, } } + + /// Returns the `ProjectionKind` associated to this projection. + pub fn kind(self) -> ProjectionKind { + self.try_map(|_| Some(()), |_| ()).unwrap() + } + + /// Apply functions to types and values in this projection and return the result. + pub fn try_map<V2, T2>( + self, + v: impl FnOnce(V) -> Option<V2>, + t: impl FnOnce(T) -> T2, + ) -> Option<ProjectionElem<V2, T2>> { + Some(match self { + ProjectionElem::Deref => ProjectionElem::Deref, + ProjectionElem::Downcast(name, read_variant) => { + ProjectionElem::Downcast(name, read_variant) + } + ProjectionElem::Field(f, ty) => ProjectionElem::Field(f, t(ty)), + ProjectionElem::ConstantIndex { offset, min_length, from_end } => { + ProjectionElem::ConstantIndex { offset, min_length, from_end } + } + ProjectionElem::Subslice { from, to, from_end } => { + ProjectionElem::Subslice { from, to, from_end } + } + ProjectionElem::OpaqueCast(ty) => ProjectionElem::OpaqueCast(t(ty)), + ProjectionElem::Subtype(ty) => ProjectionElem::Subtype(t(ty)), + ProjectionElem::UnwrapUnsafeBinder(ty) => ProjectionElem::UnwrapUnsafeBinder(t(ty)), + ProjectionElem::Index(val) => ProjectionElem::Index(v(val)?), + }) + } } /// Alias for projections as they appear in `UserTypeProjection`, where we diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 3bb8353f49e..d4f88c458a8 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1116,6 +1116,11 @@ rustc_queries! { } /// Unsafety-check this `LocalDefId`. + query check_transmutes(key: LocalDefId) { + desc { |tcx| "check transmute calls inside `{}`", tcx.def_path_str(key) } + } + + /// Unsafety-check this `LocalDefId`. query check_unsafety(key: LocalDefId) { desc { |tcx| "unsafety-checking `{}`", tcx.def_path_str(key) } } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index e70c98ab704..a7298af502e 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -32,7 +32,7 @@ use rustc_data_structures::intern::Interned; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::steal::Steal; use rustc_data_structures::unord::{UnordMap, UnordSet}; -use rustc_errors::{Diag, ErrorGuaranteed}; +use rustc_errors::{Diag, ErrorGuaranteed, LintBuffer}; use rustc_hir::attrs::{AttributeKind, StrippedCfgItem}; use rustc_hir::def::{CtorKind, CtorOf, DefKind, DocLinkResMap, LifetimeRes, Res}; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LocalDefIdMap}; @@ -46,7 +46,6 @@ use rustc_macros::{ }; use rustc_query_system::ich::StableHashingContext; use rustc_serialize::{Decodable, Encodable}; -use rustc_session::lint::LintBuffer; pub use rustc_session::lint::RegisteredTools; use rustc_span::hygiene::MacroKind; use rustc_span::{DUMMY_SP, ExpnId, ExpnKind, Ident, Span, Symbol, sym}; diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index 6b187c5325a..f42dbbd2ac3 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -210,6 +210,11 @@ pub struct TypeckResults<'tcx> { /// on closure size. pub closure_size_eval: LocalDefIdMap<ClosureSizeProfileData<'tcx>>, + /// Stores the types involved in calls to `transmute` intrinsic. These are meant to be checked + /// outside of typeck and borrowck to avoid cycles with opaque types and coroutine layout + /// computation. + pub transmutes_to_check: Vec<(Ty<'tcx>, Ty<'tcx>, HirId)>, + /// Container types and field indices of `offset_of!` expressions offset_of_data: ItemLocalMap<(Ty<'tcx>, Vec<(VariantIdx, FieldIdx)>)>, } @@ -241,6 +246,7 @@ impl<'tcx> TypeckResults<'tcx> { rvalue_scopes: Default::default(), coroutine_stalled_predicates: Default::default(), closure_size_eval: Default::default(), + transmutes_to_check: Default::default(), offset_of_data: Default::default(), } } diff --git a/compiler/rustc_mir_build/src/builder/coverageinfo.rs b/compiler/rustc_mir_build/src/builder/coverageinfo.rs index 14199c20921..091b9dad5bc 100644 --- a/compiler/rustc_mir_build/src/builder/coverageinfo.rs +++ b/compiler/rustc_mir_build/src/builder/coverageinfo.rs @@ -157,6 +157,21 @@ impl CoverageInfoBuilder { // if there's nothing interesting in it. Box::new(CoverageInfoHi { num_block_markers, branch_spans }) } + + pub(crate) fn as_done(&self) -> Box<CoverageInfoHi> { + let &Self { nots: _, markers: BlockMarkerGen { num_block_markers }, ref branch_info } = + self; + + let branch_spans = branch_info + .as_ref() + .map(|branch_info| branch_info.branch_spans.as_slice()) + .unwrap_or_default() + .to_owned(); + + // For simplicity, always return an info struct (without Option), even + // if there's nothing interesting in it. + Box::new(CoverageInfoHi { num_block_markers, branch_spans }) + } } impl<'tcx> Builder<'_, 'tcx> { diff --git a/compiler/rustc_mir_build/src/builder/mod.rs b/compiler/rustc_mir_build/src/builder/mod.rs index 9570760f943..6a8f0b21ee0 100644 --- a/compiler/rustc_mir_build/src/builder/mod.rs +++ b/compiler/rustc_mir_build/src/builder/mod.rs @@ -790,6 +790,28 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { builder } + #[allow(dead_code)] + fn dump_for_debugging(&self) { + let mut body = Body::new( + MirSource::item(self.def_id.to_def_id()), + self.cfg.basic_blocks.clone(), + self.source_scopes.clone(), + self.local_decls.clone(), + self.canonical_user_type_annotations.clone(), + self.arg_count.clone(), + self.var_debug_info.clone(), + self.fn_span.clone(), + self.coroutine.clone(), + None, + ); + body.coverage_info_hi = self.coverage_info.as_ref().map(|b| b.as_done()); + + use rustc_middle::mir::pretty; + let options = pretty::PrettyPrintMirOptions::from_cli(self.tcx); + pretty::write_mir_fn(self.tcx, &body, &mut |_, _| Ok(()), &mut std::io::stdout(), options) + .unwrap(); + } + fn finish(self) -> Body<'tcx> { let mut body = Body::new( MirSource::item(self.def_id.to_def_id()), diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index cdab785e842..b5e165c7517 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -8,7 +8,7 @@ use rustc_errors::DiagArgValue; use rustc_hir::attrs::AttributeKind; use rustc_hir::def::DefKind; use rustc_hir::{self as hir, BindingMode, ByRef, HirId, Mutability, find_attr}; -use rustc_middle::middle::codegen_fn_attrs::TargetFeature; +use rustc_middle::middle::codegen_fn_attrs::{TargetFeature, TargetFeatureKind}; use rustc_middle::mir::BorrowKind; use rustc_middle::span_bug; use rustc_middle::thir::visit::Visitor; @@ -522,7 +522,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { .iter() .copied() .filter(|feature| { - !feature.implied + feature.kind == TargetFeatureKind::Enabled && !self .body_target_features .iter() diff --git a/compiler/rustc_mir_dataflow/src/move_paths/abs_domain.rs b/compiler/rustc_mir_dataflow/src/move_paths/abs_domain.rs deleted file mode 100644 index d056ad3d4b4..00000000000 --- a/compiler/rustc_mir_dataflow/src/move_paths/abs_domain.rs +++ /dev/null @@ -1,38 +0,0 @@ -//! The move-analysis portion of borrowck needs to work in an abstract -//! domain of lifted `Place`s. Most of the `Place` variants fall into a -//! one-to-one mapping between the concrete and abstract (e.g., a -//! field-deref on a local variable, `x.field`, has the same meaning -//! in both domains). Indexed projections are the exception: `a[x]` -//! needs to be treated as mapping to the same move path as `a[y]` as -//! well as `a[13]`, etc. So we map these `x`/`y` values to `()`. -//! -//! (In theory, the analysis could be extended to work with sets of -//! paths, so that `a[0]` and `a[13]` could be kept distinct, while -//! `a[x]` would still overlap them both. But that is not this -//! representation does today.) - -use rustc_middle::mir::{PlaceElem, ProjectionElem, ProjectionKind}; - -pub(crate) trait Lift { - fn lift(&self) -> ProjectionKind; -} - -impl<'tcx> Lift for PlaceElem<'tcx> { - fn lift(&self) -> ProjectionKind { - match *self { - ProjectionElem::Deref => ProjectionElem::Deref, - ProjectionElem::Field(f, _ty) => ProjectionElem::Field(f, ()), - ProjectionElem::OpaqueCast(_ty) => ProjectionElem::OpaqueCast(()), - ProjectionElem::Index(_i) => ProjectionElem::Index(()), - ProjectionElem::Subslice { from, to, from_end } => { - ProjectionElem::Subslice { from, to, from_end } - } - ProjectionElem::ConstantIndex { offset, min_length, from_end } => { - ProjectionElem::ConstantIndex { offset, min_length, from_end } - } - ProjectionElem::Downcast(a, u) => ProjectionElem::Downcast(a, u), - ProjectionElem::Subtype(_ty) => ProjectionElem::Subtype(()), - ProjectionElem::UnwrapUnsafeBinder(_ty) => ProjectionElem::UnwrapUnsafeBinder(()), - } - } -} diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs index 8bbc89fdcec..48718cad597 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs @@ -7,7 +7,6 @@ use rustc_middle::{bug, span_bug}; use smallvec::{SmallVec, smallvec}; use tracing::debug; -use super::abs_domain::Lift; use super::{ Init, InitIndex, InitKind, InitLocation, LocationMap, LookupResult, MoveData, MoveOut, MoveOutIndex, MovePath, MovePathIndex, MovePathLookup, @@ -241,7 +240,7 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> { if union_path.is_none() { // inlined from add_move_path because of a borrowck conflict with the iterator base = - *data.rev_lookup.projections.entry((base, elem.lift())).or_insert_with(|| { + *data.rev_lookup.projections.entry((base, elem.kind())).or_insert_with(|| { new_move_path( &mut data.move_paths, &mut data.path_map, @@ -272,7 +271,7 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> { tcx, .. } = self; - *rev_lookup.projections.entry((base, elem.lift())).or_insert_with(move || { + *rev_lookup.projections.entry((base, elem.kind())).or_insert_with(move || { new_move_path(move_paths, path_map, init_path_map, Some(base), mk_place(*tcx)) }) } diff --git a/compiler/rustc_mir_dataflow/src/move_paths/mod.rs b/compiler/rustc_mir_dataflow/src/move_paths/mod.rs index 18985ba0da2..466416d63f5 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/mod.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/mod.rs @@ -1,3 +1,15 @@ +//! The move-analysis portion of borrowck needs to work in an abstract domain of lifted `Place`s. +//! Most of the `Place` variants fall into a one-to-one mapping between the concrete and abstract +//! (e.g., a field projection on a local variable, `x.field`, has the same meaning in both +//! domains). In other words, all field projections for the same field on the same local do not +//! have meaningfully different types if ever. Indexed projections are the exception: `a[x]` needs +//! to be treated as mapping to the same move path as `a[y]` as well as `a[13]`, etc. So we map +//! these `x`/`y` values to `()`. +//! +//! (In theory, the analysis could be extended to work with sets of paths, so that `a[0]` and +//! `a[13]` could be kept distinct, while `a[x]` would still overlap them both. But that is not +//! what this representation does today.) + use std::fmt; use std::ops::{Index, IndexMut}; @@ -8,11 +20,8 @@ use rustc_middle::ty::{Ty, TyCtxt}; use rustc_span::Span; use smallvec::SmallVec; -use self::abs_domain::Lift; use crate::un_derefer::UnDerefer; -mod abs_domain; - rustc_index::newtype_index! { #[orderable] #[debug_format = "mp{}"] @@ -324,7 +333,7 @@ impl<'tcx> MovePathLookup<'tcx> { }; for (_, elem) in self.un_derefer.iter_projections(place) { - if let Some(&subpath) = self.projections.get(&(result, elem.lift())) { + if let Some(&subpath) = self.projections.get(&(result, elem.kind())) { result = subpath; } else { return LookupResult::Parent(Some(result)); diff --git a/compiler/rustc_mir_transform/src/coverage/counters.rs b/compiler/rustc_mir_transform/src/coverage/counters.rs index 5568d42ab8f..879a20e771d 100644 --- a/compiler/rustc_mir_transform/src/coverage/counters.rs +++ b/compiler/rustc_mir_transform/src/coverage/counters.rs @@ -16,7 +16,6 @@ use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph}; mod balanced_flow; pub(crate) mod node_flow; -mod union_find; /// Struct containing the results of [`prepare_bcb_counters_data`]. pub(crate) struct BcbCountersData { diff --git a/compiler/rustc_mir_transform/src/coverage/counters/node_flow.rs b/compiler/rustc_mir_transform/src/coverage/counters/node_flow.rs index 91ed54b8b59..e063f75887b 100644 --- a/compiler/rustc_mir_transform/src/coverage/counters/node_flow.rs +++ b/compiler/rustc_mir_transform/src/coverage/counters/node_flow.rs @@ -7,13 +7,12 @@ //! (Knuth & Stevenson, 1973). use rustc_data_structures::graph; +use rustc_data_structures::union_find::UnionFind; use rustc_index::bit_set::DenseBitSet; use rustc_index::{Idx, IndexSlice, IndexVec}; pub(crate) use rustc_middle::mir::coverage::NodeFlowData; use rustc_middle::mir::coverage::Op; -use crate::coverage::counters::union_find::UnionFind; - #[cfg(test)] mod tests; diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 952da2cdf72..5a13394543b 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -447,26 +447,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { Projection(base, elem) => { let base = self.evaluated[base].as_ref()?; - let elem = match elem { - ProjectionElem::Deref => ProjectionElem::Deref, - ProjectionElem::Downcast(name, read_variant) => { - ProjectionElem::Downcast(name, read_variant) - } - ProjectionElem::Field(f, ()) => ProjectionElem::Field(f, ty.ty), - ProjectionElem::ConstantIndex { offset, min_length, from_end } => { - ProjectionElem::ConstantIndex { offset, min_length, from_end } - } - ProjectionElem::Subslice { from, to, from_end } => { - ProjectionElem::Subslice { from, to, from_end } - } - ProjectionElem::OpaqueCast(()) => ProjectionElem::OpaqueCast(ty.ty), - ProjectionElem::Subtype(()) => ProjectionElem::Subtype(ty.ty), - ProjectionElem::UnwrapUnsafeBinder(()) => { - ProjectionElem::UnwrapUnsafeBinder(ty.ty) - } - // This should have been replaced by a `ConstantIndex` earlier. - ProjectionElem::Index(_) => return None, - }; + // `Index` by constants should have been replaced by `ConstantIndex` by + // `simplify_place_projection`. + let elem = elem.try_map(|_| None, |()| ty.ty)?; self.ecx.project(base, elem).discard_err()? } Address { place, kind: _, provenance: _ } => { @@ -476,13 +459,11 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { let local = self.locals[place.local]?; let pointer = self.evaluated[local].as_ref()?; let mut mplace = self.ecx.deref_pointer(pointer).discard_err()?; - for proj in place.projection.iter().skip(1) { - // We have no call stack to associate a local with a value, so we cannot - // interpret indexing. - if matches!(proj, ProjectionElem::Index(_)) { - return None; - } - mplace = self.ecx.project(&mplace, proj).discard_err()?; + for elem in place.projection.iter().skip(1) { + // `Index` by constants should have been replaced by `ConstantIndex` by + // `simplify_place_projection`. + let elem = elem.try_map(|_| None, |ty| ty)?; + mplace = self.ecx.project(&mplace, elem).discard_err()?; } let pointer = mplace.to_ref(&self.ecx); ImmTy::from_immediate(pointer, ty).into() @@ -902,27 +883,14 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { proj: ProjectionElem<VnIndex, ()>, loc: Location, ) -> Option<PlaceElem<'tcx>> { - Some(match proj { - ProjectionElem::Deref => ProjectionElem::Deref, - ProjectionElem::Field(idx, ()) => ProjectionElem::Field(idx, ty), - ProjectionElem::Index(idx) => { - let Some(local) = self.try_as_local(idx, loc) else { - return None; - }; + proj.try_map( + |value| { + let local = self.try_as_local(value, loc)?; self.reused_locals.insert(local); - ProjectionElem::Index(local) - } - ProjectionElem::ConstantIndex { offset, min_length, from_end } => { - ProjectionElem::ConstantIndex { offset, min_length, from_end } - } - ProjectionElem::Subslice { from, to, from_end } => { - ProjectionElem::Subslice { from, to, from_end } - } - ProjectionElem::Downcast(symbol, idx) => ProjectionElem::Downcast(symbol, idx), - ProjectionElem::OpaqueCast(()) => ProjectionElem::OpaqueCast(ty), - ProjectionElem::Subtype(()) => ProjectionElem::Subtype(ty), - ProjectionElem::UnwrapUnsafeBinder(()) => ProjectionElem::UnwrapUnsafeBinder(ty), - }) + Some(local) + }, + |()| ty, + ) } fn simplify_aggregate_to_copy( diff --git a/compiler/rustc_mir_transform/src/ref_prop.rs b/compiler/rustc_mir_transform/src/ref_prop.rs index d1c2d6b508f..6f61215cee2 100644 --- a/compiler/rustc_mir_transform/src/ref_prop.rs +++ b/compiler/rustc_mir_transform/src/ref_prop.rs @@ -79,6 +79,7 @@ impl<'tcx> crate::MirPass<'tcx> for ReferencePropagation { #[instrument(level = "trace", skip(self, tcx, body))] fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { debug!(def_id = ?body.source.def_id()); + move_to_copy_pointers(tcx, body); while propagate_ssa(tcx, body) {} } @@ -87,11 +88,43 @@ impl<'tcx> crate::MirPass<'tcx> for ReferencePropagation { } } +/// The SSA analysis done by [`SsaLocals`] treats [`Operand::Move`] as a read, even though in +/// general [`Operand::Move`] represents pass-by-pointer where the callee can overwrite the +/// pointee (Miri always considers the place deinitialized). CopyProp has a similar trick to +/// turn [`Operand::Move`] into [`Operand::Copy`] when required for an optimization, but in this +/// pass we just turn all moves of pointers into copies because pointers should be by-value anyway. +fn move_to_copy_pointers<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + let mut visitor = MoveToCopyVisitor { tcx, local_decls: &body.local_decls }; + for (bb, data) in body.basic_blocks.as_mut_preserves_cfg().iter_enumerated_mut() { + visitor.visit_basic_block_data(bb, data); + } + + struct MoveToCopyVisitor<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + local_decls: &'a IndexVec<Local, LocalDecl<'tcx>>, + } + + impl<'a, 'tcx> MutVisitor<'tcx> for MoveToCopyVisitor<'a, 'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } + + fn visit_operand(&mut self, operand: &mut Operand<'tcx>, loc: Location) { + if let Operand::Move(place) = *operand { + if place.ty(self.local_decls, self.tcx).ty.is_any_ptr() { + *operand = Operand::Copy(place); + } + } + self.super_operand(operand, loc); + } + } +} + fn propagate_ssa<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> bool { let typing_env = body.typing_env(tcx); let ssa = SsaLocals::new(tcx, body, typing_env); - let mut replacer = compute_replacement(tcx, body, &ssa); + let mut replacer = compute_replacement(tcx, body, ssa); debug!(?replacer.targets); debug!(?replacer.allowed_replacements); debug!(?replacer.storage_to_remove); @@ -119,7 +152,7 @@ enum Value<'tcx> { fn compute_replacement<'tcx>( tcx: TyCtxt<'tcx>, body: &Body<'tcx>, - ssa: &SsaLocals, + ssa: SsaLocals, ) -> Replacer<'tcx> { let always_live_locals = always_storage_live_locals(body); @@ -138,7 +171,7 @@ fn compute_replacement<'tcx>( // reborrowed references. let mut storage_to_remove = DenseBitSet::new_empty(body.local_decls.len()); - let fully_replaceable_locals = fully_replaceable_locals(ssa); + let fully_replaceable_locals = fully_replaceable_locals(&ssa); // Returns true iff we can use `place` as a pointee. // diff --git a/compiler/rustc_parse/Cargo.toml b/compiler/rustc_parse/Cargo.toml index 0ae0b613fa2..6d738a10371 100644 --- a/compiler/rustc_parse/Cargo.toml +++ b/compiler/rustc_parse/Cargo.toml @@ -9,7 +9,6 @@ bitflags = "2.4.1" rustc-literal-escaper = "0.0.5" rustc_ast = { path = "../rustc_ast" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } -rustc_attr_parsing = { path = "../rustc_attr_parsing" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_feature = { path = "../rustc_feature" } diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index a107a682184..4ca2f57bd87 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -359,6 +359,20 @@ parse_generics_in_path = unexpected generic arguments in path parse_help_set_edition_cargo = set `edition = "{$edition}"` in `Cargo.toml` parse_help_set_edition_standalone = pass `--edition {$edition}` to `rustc` + +parse_hidden_unicode_codepoints = unicode codepoint changing visible direction of text present in {$label} + .label = this {$label} contains {$count -> + [one] an invisible + *[other] invisible + } unicode text flow control {$count -> + [one] codepoint + *[other] codepoints + } + .note = these kind of unicode codepoints change the way text flows on applications that support them, but can cause confusion because they change the order of characters on the screen + .suggestion_remove = if their presence wasn't intentional, you can remove them + .suggestion_escape = if you want to keep them but make them visible in your source code, you can escape them + .no_suggestion_note_escape = if you want to keep them but make them visible in your source code, you can escape them: {$escaped} + parse_if_expression_missing_condition = missing condition for `if` expression .condition_label = expected condition here .block_label = if this block is the condition of the `if` expression, then it must be followed by another block @@ -436,11 +450,6 @@ parse_inner_doc_comment_not_permitted = expected outer doc comment .label_does_not_annotate_this = the inner doc comment doesn't annotate this {$item} .sugg_change_inner_to_outer = to annotate the {$item}, change the doc comment from inner to outer style -parse_invalid_attr_unsafe = `{$name}` is not an unsafe attribute - .label = this is not an unsafe attribute - .suggestion = remove the `unsafe(...)` - .note = extraneous unsafe is not allowed in attributes - parse_invalid_block_macro_segment = cannot use a `block` macro fragment here .label = the `block` fragment is within this context .suggestion = wrap this in another block @@ -468,9 +477,6 @@ parse_invalid_dyn_keyword = invalid `dyn` keyword parse_invalid_expression_in_let_else = a `{$operator}` expression cannot be directly assigned in `let...else` parse_invalid_identifier_with_leading_number = identifiers cannot start with a number -parse_invalid_label = - invalid label name `{$name}` - parse_invalid_literal_suffix_on_tuple_index = suffixes on a tuple index are invalid .label = invalid suffix `{$suffix}` .tuple_exception_line_1 = `{$suffix}` is *temporarily* accepted on tuple index fields as it was incorrectly accepted on stable for a few releases @@ -500,6 +506,8 @@ parse_invalid_unicode_escape = invalid unicode character escape parse_invalid_variable_declaration = invalid variable declaration +parse_keyword_label = labels cannot use keyword names + parse_keyword_lifetime = lifetimes cannot use keyword names @@ -601,7 +609,6 @@ parse_maybe_report_ambiguous_plus = ambiguous `+` in a type .suggestion = use parentheses to disambiguate -parse_meta_bad_delim = wrong meta list delimiters parse_meta_bad_delim_suggestion = the delimiters should be `(` and `)` parse_mismatched_closing_delimiter = mismatched closing delimiter: `{$delimiter}` @@ -990,10 +997,6 @@ parse_unmatched_angle_brackets = {$num_extra_brackets -> *[other] remove extra angle brackets } -parse_unsafe_attr_outside_unsafe = unsafe attribute used without unsafe - .label = usage of unsafe attribute -parse_unsafe_attr_outside_unsafe_suggestion = wrap the attribute in `unsafe(...)` - parse_unskipped_whitespace = whitespace symbol '{$ch}' is not skipped .label = {parse_unskipped_whitespace} diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 2c046329e33..797d4830c2f 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -8,8 +8,9 @@ use rustc_ast::{Path, Visibility}; use rustc_errors::codes::*; use rustc_errors::{ Applicability, Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, Subdiagnostic, + SuggestionStyle, }; -use rustc_macros::{Diagnostic, Subdiagnostic}; +use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_session::errors::ExprParenthesesNeeded; use rustc_span::edition::{Edition, LATEST_STABLE_EDITION}; use rustc_span::{Ident, Span, Symbol}; @@ -2228,11 +2229,10 @@ pub(crate) struct KeywordLifetime { } #[derive(Diagnostic)] -#[diag(parse_invalid_label)] -pub(crate) struct InvalidLabel { +#[diag(parse_keyword_label)] +pub(crate) struct KeywordLabel { #[primary_span] pub span: Span, - pub name: Symbol, } #[derive(Diagnostic)] @@ -3346,15 +3346,6 @@ pub(crate) struct KwBadCase<'a> { } #[derive(Diagnostic)] -#[diag(parse_meta_bad_delim)] -pub(crate) struct MetaBadDelim { - #[primary_span] - pub span: Span, - #[subdiagnostic] - pub sugg: MetaBadDelimSugg, -} - -#[derive(Diagnostic)] #[diag(parse_cfg_attr_bad_delim)] pub(crate) struct CfgAttrBadDelim { #[primary_span] @@ -3494,38 +3485,6 @@ pub(crate) struct DotDotRangeAttribute { } #[derive(Diagnostic)] -#[diag(parse_invalid_attr_unsafe)] -#[note] -pub(crate) struct InvalidAttrUnsafe { - #[primary_span] - #[label] - pub span: Span, - pub name: Path, -} - -#[derive(Diagnostic)] -#[diag(parse_unsafe_attr_outside_unsafe)] -pub(crate) struct UnsafeAttrOutsideUnsafe { - #[primary_span] - #[label] - pub span: Span, - #[subdiagnostic] - pub suggestion: UnsafeAttrOutsideUnsafeSuggestion, -} - -#[derive(Subdiagnostic)] -#[multipart_suggestion( - parse_unsafe_attr_outside_unsafe_suggestion, - applicability = "machine-applicable" -)] -pub(crate) struct UnsafeAttrOutsideUnsafeSuggestion { - #[suggestion_part(code = "unsafe(")] - pub left: Span, - #[suggestion_part(code = ")")] - pub right: Span, -} - -#[derive(Diagnostic)] #[diag(parse_binder_before_modifiers)] pub(crate) struct BinderBeforeModifiers { #[primary_span] @@ -3643,3 +3602,76 @@ pub(crate) struct ExpectedRegisterClassOrExplicitRegister { #[primary_span] pub(crate) span: Span, } + +#[derive(LintDiagnostic)] +#[diag(parse_hidden_unicode_codepoints)] +#[note] +pub(crate) struct HiddenUnicodeCodepointsDiag { + pub label: String, + pub count: usize, + #[label] + pub span_label: Span, + #[subdiagnostic] + pub labels: Option<HiddenUnicodeCodepointsDiagLabels>, + #[subdiagnostic] + pub sub: HiddenUnicodeCodepointsDiagSub, +} + +pub(crate) struct HiddenUnicodeCodepointsDiagLabels { + pub spans: Vec<(char, Span)>, +} + +impl Subdiagnostic for HiddenUnicodeCodepointsDiagLabels { + fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) { + for (c, span) in self.spans { + diag.span_label(span, format!("{c:?}")); + } + } +} + +pub(crate) enum HiddenUnicodeCodepointsDiagSub { + Escape { spans: Vec<(char, Span)> }, + NoEscape { spans: Vec<(char, Span)> }, +} + +// Used because of multiple multipart_suggestion and note +impl Subdiagnostic for HiddenUnicodeCodepointsDiagSub { + fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) { + match self { + HiddenUnicodeCodepointsDiagSub::Escape { spans } => { + diag.multipart_suggestion_with_style( + fluent::parse_suggestion_remove, + spans.iter().map(|(_, span)| (*span, "".to_string())).collect(), + Applicability::MachineApplicable, + SuggestionStyle::HideCodeAlways, + ); + diag.multipart_suggestion( + fluent::parse_suggestion_escape, + spans + .into_iter() + .map(|(c, span)| { + let c = format!("{c:?}"); + (span, c[1..c.len() - 1].to_string()) + }) + .collect(), + Applicability::MachineApplicable, + ); + } + HiddenUnicodeCodepointsDiagSub::NoEscape { spans } => { + // FIXME: in other suggestions we've reversed the inner spans of doc comments. We + // should do the same here to provide the same good suggestions as we do for + // literals above. + diag.arg( + "escaped", + spans + .into_iter() + .map(|(c, _)| format!("{c:?}")) + .collect::<Vec<String>>() + .join(", "), + ); + diag.note(fluent::parse_suggestion_remove); + diag.note(fluent::parse_no_suggestion_note_escape); + } + } + } +} diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 7c7e7e50b27..9792240a548 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -543,21 +543,21 @@ impl<'psess, 'src> Lexer<'psess, 'src> { }) .collect(); + let label = label.to_string(); let count = spans.len(); - let labels = point_at_inner_spans.then_some(spans.clone()); + let labels = point_at_inner_spans + .then_some(errors::HiddenUnicodeCodepointsDiagLabels { spans: spans.clone() }); + let sub = if point_at_inner_spans && !spans.is_empty() { + errors::HiddenUnicodeCodepointsDiagSub::Escape { spans } + } else { + errors::HiddenUnicodeCodepointsDiagSub::NoEscape { spans } + }; self.psess.buffer_lint( TEXT_DIRECTION_CODEPOINT_IN_LITERAL, span, ast::CRATE_NODE_ID, - BuiltinLintDiag::HiddenUnicodeCodepoints { - label: label.to_string(), - count, - span_label: span, - labels, - escape: point_at_inner_spans && !spans.is_empty(), - spans, - }, + errors::HiddenUnicodeCodepointsDiag { label, count, span_label: span, labels, sub }, ); } diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index adad5751871..48289b2e8ab 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -16,7 +16,7 @@ use std::str::Utf8Error; use std::sync::Arc; use rustc_ast as ast; -use rustc_ast::tokenstream::TokenStream; +use rustc_ast::tokenstream::{DelimSpan, TokenStream}; use rustc_ast::{AttrItem, Attribute, MetaItemInner, token}; use rustc_ast_pretty::pprust; use rustc_errors::{Diag, EmissionGuarantee, FatalError, PResult, pluralize}; @@ -31,8 +31,9 @@ pub const MACRO_ARGUMENTS: Option<&str> = Some("macro arguments"); #[macro_use] pub mod parser; use parser::Parser; +use rustc_ast::token::Delimiter; + pub mod lexer; -pub mod validate_attr; mod errors; @@ -235,7 +236,7 @@ pub fn parse_cfg_attr( ast::AttrArgs::Delimited(ast::DelimArgs { dspan, delim, ref tokens }) if !tokens.is_empty() => { - crate::validate_attr::check_cfg_attr_bad_delim(psess, dspan, delim); + check_cfg_attr_bad_delim(psess, dspan, delim); match parse_in(psess, tokens.clone(), "`cfg_attr` input", |p| p.parse_cfg_attr()) { Ok(r) => return Some(r), Err(e) => { @@ -254,3 +255,13 @@ pub fn parse_cfg_attr( } None } + +fn check_cfg_attr_bad_delim(psess: &ParseSess, span: DelimSpan, delim: Delimiter) { + if let Delimiter::Parenthesis = delim { + return; + } + psess.dcx().emit_err(errors::CfgAttrBadDelim { + span: span.entire(), + sugg: errors::MetaBadDelimSugg { open: span.open, close: span.close }, + }); +} diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs index 7f6afeba28c..acd338156ce 100644 --- a/compiler/rustc_parse/src/parser/attr.rs +++ b/compiler/rustc_parse/src/parser/attr.rs @@ -399,7 +399,7 @@ impl<'a> Parser<'a> { } /// Matches `COMMASEP(meta_item_inner)`. - pub(crate) fn parse_meta_seq_top(&mut self) -> PResult<'a, ThinVec<ast::MetaItemInner>> { + pub fn parse_meta_seq_top(&mut self) -> PResult<'a, ThinVec<ast::MetaItemInner>> { // Presumably, the majority of the time there will only be one attr. let mut nmis = ThinVec::with_capacity(1); while self.token != token::Eof { diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index ea8cd3754a0..1499808966c 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -2077,7 +2077,7 @@ impl<'a> Parser<'a> { (token::Lit { symbol: name, suffix: None, kind: token::Char }, span) } - fn mk_meta_item_lit_char(name: Symbol, span: Span) -> MetaItemLit { + pub fn mk_meta_item_lit_char(name: Symbol, span: Span) -> MetaItemLit { ast::MetaItemLit { symbol: name, suffix: None, @@ -2086,7 +2086,7 @@ impl<'a> Parser<'a> { } } - fn handle_missing_lit<L>( + pub fn handle_missing_lit<L>( &mut self, mk_lit_char: impl FnOnce(Symbol, Span) -> L, ) -> PResult<'a, L> { @@ -2156,7 +2156,7 @@ impl<'a> Parser<'a> { /// Keep this in sync with `Token::can_begin_literal_maybe_minus` and /// `Lit::from_token` (excluding unary negation). - fn eat_token_lit(&mut self) -> Option<token::Lit> { + pub fn eat_token_lit(&mut self) -> Option<token::Lit> { let check_expr = |expr: Box<Expr>| { if let ast::ExprKind::Lit(token_lit) = expr.kind { Some(token_lit) @@ -2409,8 +2409,12 @@ impl<'a> Parser<'a> { let constness = self.parse_closure_constness(); - let movability = - if self.eat_keyword(exp!(Static)) { Movability::Static } else { Movability::Movable }; + let movability = if self.eat_keyword(exp!(Static)) { + self.psess.gated_spans.gate(sym::coroutines, self.prev_token.span); + Movability::Static + } else { + Movability::Movable + }; let coroutine_kind = if self.token_uninterpolated_span().at_least_rust_2018() { self.parse_coroutine_kind(Case::Sensitive) @@ -3090,7 +3094,7 @@ impl<'a> Parser<'a> { if let Some((ident, is_raw)) = self.token.lifetime() { // Disallow `'fn`, but with a better error message than `expect_lifetime`. if matches!(is_raw, IdentIsRaw::No) && ident.without_first_quote().is_reserved() { - self.dcx().emit_err(errors::InvalidLabel { span: ident.span, name: ident.name }); + self.dcx().emit_err(errors::KeywordLabel { span: ident.span }); } self.bump(); diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 21f42b54f21..d19114df812 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -24,7 +24,7 @@ pub use diagnostics::AttemptLocalParseRecovery; pub(crate) use expr::ForbiddenLetReason; pub(crate) use item::{FnContext, FnParseMode}; pub use pat::{CommaRecoveryMode, RecoverColon, RecoverComma}; -use path::PathStyle; +pub use path::PathStyle; use rustc_ast::token::{ self, IdentIsRaw, InvisibleOrigin, MetaVarKind, NtExprKind, NtPatKind, Token, TokenKind, }; @@ -285,7 +285,7 @@ pub enum FollowedByType { } #[derive(Copy, Clone, Debug)] -enum Trailing { +pub enum Trailing { No, Yes, } @@ -494,7 +494,7 @@ impl<'a> Parser<'a> { /// This method will automatically add `tok` to `expected_token_types` if `tok` is not /// encountered. #[inline] - fn check(&mut self, exp: ExpTokenPair<'_>) -> bool { + pub fn check(&mut self, exp: ExpTokenPair<'_>) -> bool { let is_present = self.token == *exp.tok; if !is_present { self.expected_token_types.insert(exp.token_type); @@ -633,7 +633,7 @@ impl<'a> Parser<'a> { } /// Consume a sequence produced by a metavar expansion, if present. - fn eat_metavar_seq<T>( + pub fn eat_metavar_seq<T>( &mut self, mv_kind: MetaVarKind, f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>, @@ -1094,7 +1094,7 @@ impl<'a> Parser<'a> { /// Parses a comma-separated sequence delimited by parentheses (e.g. `(x, y)`). /// The function `f` must consume tokens until reaching the next separator or /// closing bracket. - fn parse_paren_comma_seq<T>( + pub fn parse_paren_comma_seq<T>( &mut self, f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>, ) -> PResult<'a, (ThinVec<T>, Trailing)> { @@ -1355,7 +1355,8 @@ impl<'a> Parser<'a> { AttrArgs::Delimited(args) } else if self.eat(exp!(Eq)) { let eq_span = self.prev_token.span; - AttrArgs::Eq { eq_span, expr: self.parse_expr_force_collect()? } + let expr = self.parse_expr_force_collect()?; + AttrArgs::Eq { eq_span, expr } } else { AttrArgs::Empty }) diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 37fc723cd89..86045648859 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -26,7 +26,7 @@ use crate::parser::{ /// Specifies how to parse a path. #[derive(Copy, Clone, PartialEq)] -pub(super) enum PathStyle { +pub enum PathStyle { /// In some contexts, notably in expressions, paths with generic arguments are ambiguous /// with something else. For example, in expressions `segment < ....` can be interpreted /// as a comparison and `segment ( ....` can be interpreted as a function call. @@ -150,7 +150,7 @@ impl<'a> Parser<'a> { true } - pub(super) fn parse_path(&mut self, style: PathStyle) -> PResult<'a, Path> { + pub fn parse_path(&mut self, style: PathStyle) -> PResult<'a, Path> { self.parse_path_inner(style, None) } diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 899a43955ab..6168647183f 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -137,14 +137,37 @@ impl<'a> Parser<'a> { /// The difference from `parse_ty` is that this version allows `...` /// (`CVarArgs`) at the top level of the type. pub(super) fn parse_ty_for_param(&mut self) -> PResult<'a, Box<Ty>> { - self.parse_ty_common( + let ty = self.parse_ty_common( AllowPlus::Yes, AllowCVariadic::Yes, RecoverQPath::Yes, RecoverReturnSign::Yes, None, RecoverQuestionMark::Yes, - ) + )?; + + // Recover a trailing `= EXPR` if present. + if self.may_recover() + && self.check_noexpect(&token::Eq) + && self.look_ahead(1, |tok| tok.can_begin_expr()) + { + let snapshot = self.create_snapshot_for_diagnostic(); + self.bump(); + let eq_span = self.prev_token.span; + match self.parse_expr() { + Ok(e) => { + self.dcx() + .struct_span_err(eq_span.to(e.span), "parameter defaults are not supported") + .emit(); + } + Err(diag) => { + diag.cancel(); + self.restore_snapshot(snapshot); + } + } + } + + Ok(ty) } /// Parses a type in restricted contexts where `+` is not permitted. @@ -1479,8 +1502,7 @@ impl<'a> Parser<'a> { pub(super) fn expect_lifetime(&mut self) -> Lifetime { if let Some((ident, is_raw)) = self.token.lifetime() { if matches!(is_raw, IdentIsRaw::No) - && ident.without_first_quote().is_reserved() - && ![kw::UnderscoreLifetime, kw::StaticLifetime].contains(&ident.name) + && ident.without_first_quote().is_reserved_lifetime() { self.dcx().emit_err(errors::KeywordLifetime { span: ident.span }); } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 70eae82392c..077afd6dd23 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -167,7 +167,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { Attribute::Parsed(AttributeKind::Deprecation { .. }) => { self.check_deprecated(hir_id, attr, span, target) } - Attribute::Parsed(AttributeKind::TargetFeature(_, attr_span)) => { + Attribute::Parsed(AttributeKind::TargetFeature{ attr_span, ..}) => { self.check_target_feature(hir_id, *attr_span, target, attrs) } Attribute::Parsed(AttributeKind::RustcObjectLifetimeDefault) => { diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 08d06402000..10cd9df4816 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -8,7 +8,6 @@ use std::mem; use hir::def_id::{LocalDefIdMap, LocalDefIdSet}; use rustc_abi::FieldIdx; use rustc_data_structures::fx::FxIndexSet; -use rustc_data_structures::unord::UnordSet; use rustc_errors::MultiSpan; use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId}; @@ -79,7 +78,7 @@ struct MarkSymbolVisitor<'tcx> { worklist: Vec<(LocalDefId, ComesFromAllowExpect)>, tcx: TyCtxt<'tcx>, maybe_typeck_results: Option<&'tcx ty::TypeckResults<'tcx>>, - scanned: UnordSet<(LocalDefId, ComesFromAllowExpect)>, + scanned: LocalDefIdSet, live_symbols: LocalDefIdSet, repr_unconditionally_treats_fields_as_live: bool, repr_has_repr_simd: bool, @@ -321,18 +320,8 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { fn mark_live_symbols(&mut self) { while let Some(work) = self.worklist.pop() { - if !self.scanned.insert(work) { - continue; - } - let (mut id, comes_from_allow_expect) = work; - // Avoid accessing the HIR for the synthesized associated type generated for RPITITs. - if self.tcx.is_impl_trait_in_trait(id.to_def_id()) { - self.live_symbols.insert(id); - continue; - } - // in the case of tuple struct constructors we want to check the item, // not the generated tuple struct constructor function if let DefKind::Ctor(..) = self.tcx.def_kind(id) { @@ -360,9 +349,23 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { // this "duplication" is essential as otherwise a function with `#[expect]` // called from a `pub fn` may be falsely reported as not live, falsely // triggering the `unfulfilled_lint_expectations` lint. - if comes_from_allow_expect != ComesFromAllowExpect::Yes { + match comes_from_allow_expect { + ComesFromAllowExpect::Yes => {} + ComesFromAllowExpect::No => { + self.live_symbols.insert(id); + } + } + + if !self.scanned.insert(id) { + continue; + } + + // Avoid accessing the HIR for the synthesized associated type generated for RPITITs. + if self.tcx.is_impl_trait_in_trait(id.to_def_id()) { self.live_symbols.insert(id); + continue; } + self.visit_node(self.tcx.hir_node_by_def_id(id)); } } diff --git a/compiler/rustc_pattern_analysis/src/rustc/print.rs b/compiler/rustc_pattern_analysis/src/rustc/print.rs index 7649f72f868..cdf62c2553d 100644 --- a/compiler/rustc_pattern_analysis/src/rustc/print.rs +++ b/compiler/rustc_pattern_analysis/src/rustc/print.rs @@ -101,23 +101,11 @@ pub(crate) fn write_struct_like<'tcx>( let num_fields = variant_and_name.as_ref().map_or(subpatterns.len(), |(v, _)| v.fields.len()); if num_fields != 0 || variant_and_name.is_none() { write!(f, "(")?; - for i in 0..num_fields { - write!(f, "{}", start_or_comma())?; - - // Common case: the field is where we expect it. - if let Some(p) = subpatterns.get(i) { - if p.field.index() == i { - write!(f, "{}", p.pattern)?; - continue; - } - } - - // Otherwise, we have to go looking for it. - if let Some(p) = subpatterns.iter().find(|p| p.field.index() == i) { - write!(f, "{}", p.pattern)?; - } else { - write!(f, "_")?; - } + for FieldPat { pattern, .. } in subpatterns { + write!(f, "{}{pattern}", start_or_comma())?; + } + if matches!(ty.kind(), ty::Tuple(..)) && num_fields == 1 { + write!(f, ",")?; } write!(f, ")")?; } diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 64641ecc080..337e7d2dd86 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1020,11 +1020,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { &mut self, suggestions: &mut Vec<TypoSuggestion>, scope_set: ScopeSet<'ra>, - parent_scope: &ParentScope<'ra>, + ps: &ParentScope<'ra>, ctxt: SyntaxContext, filter_fn: &impl Fn(Res) -> bool, ) { - self.cm().visit_scopes(scope_set, parent_scope, ctxt, |this, scope, use_prelude, _| { + self.cm().visit_scopes(scope_set, ps, ctxt, None, |this, scope, use_prelude, _| { match scope { Scope::DeriveHelpers(expn_id) => { let res = Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper); @@ -1557,7 +1557,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }); } for ns in [Namespace::MacroNS, Namespace::TypeNS, Namespace::ValueNS] { - let Ok(binding) = self.cm().early_resolve_ident_in_lexical_scope( + let Ok(binding) = self.cm().resolve_ident_in_scope_set( ident, ScopeSet::All(ns), parent_scope, @@ -2371,7 +2371,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } else { self.cm() - .early_resolve_ident_in_lexical_scope( + .resolve_ident_in_scope_set( ident, ScopeSet::All(ns_to_try), parent_scope, @@ -2474,7 +2474,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }, ) }); - if let Ok(binding) = self.cm().early_resolve_ident_in_lexical_scope( + if let Ok(binding) = self.cm().resolve_ident_in_scope_set( ident, ScopeSet::All(ValueNS), parent_scope, diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 650154d586f..dae42645bec 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -19,7 +19,7 @@ use crate::{ AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, BindingKey, CmResolver, Determinacy, Finalize, ImportKind, LexicalScopeBinding, Module, ModuleKind, ModuleOrUniformRoot, NameBinding, NameBindingKind, ParentScope, PathResult, PrivacyError, Res, ResolutionError, - Resolver, Scope, ScopeSet, Segment, Used, Weak, errors, + Resolver, Scope, ScopeSet, Segment, Stage, Used, Weak, errors, }; #[derive(Copy, Clone)] @@ -49,6 +49,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { scope_set: ScopeSet<'ra>, parent_scope: &ParentScope<'ra>, ctxt: SyntaxContext, + derive_fallback_lint_id: Option<NodeId>, mut visitor: impl FnMut( &mut CmResolver<'r, 'ra, 'tcx>, Scope<'ra>, @@ -99,15 +100,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let rust_2015 = ctxt.edition().is_rust_2015(); let (ns, macro_kind) = match scope_set { - ScopeSet::All(ns) - | ScopeSet::ModuleAndExternPrelude(ns, _) - | ScopeSet::Late(ns, ..) => (ns, None), + ScopeSet::All(ns) | ScopeSet::ModuleAndExternPrelude(ns, _) => (ns, None), ScopeSet::ExternPrelude => (TypeNS, None), ScopeSet::Macro(macro_kind) => (MacroNS, Some(macro_kind)), }; let module = match scope_set { // Start with the specified module. - ScopeSet::Late(_, module, _) | ScopeSet::ModuleAndExternPrelude(_, module) => module, + ScopeSet::ModuleAndExternPrelude(_, module) => module, // Jump out of trait or enum modules, they do not act as scopes. _ => parent_scope.module.nearest_item_scope(), }; @@ -193,10 +192,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }, Scope::Module(module, prev_lint_id) => { use_prelude = !module.no_implicit_prelude; - let derive_fallback_lint_id = match scope_set { - ScopeSet::Late(.., lint_id) => lint_id, - _ => None, - }; match self.hygienic_lexical_parent(module, &mut ctxt, derive_fallback_lint_id) { Some((parent_module, lint_id)) => { Scope::Module(parent_module, lint_id.or(prev_lint_id)) @@ -349,11 +344,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { return Some(LexicalScopeBinding::Item(binding)); } else if let RibKind::Module(module) = rib.kind { // Encountered a module item, abandon ribs and look into that module and preludes. + let parent_scope = &ParentScope { module, ..*parent_scope }; + let finalize = finalize.map(|f| Finalize { stage: Stage::Late, ..f }); return self .cm() - .early_resolve_ident_in_lexical_scope( + .resolve_ident_in_scope_set( orig_ident, - ScopeSet::Late(ns, module, finalize.map(|finalize| finalize.node_id)), + ScopeSet::All(ns), parent_scope, finalize, finalize.is_some(), @@ -376,13 +373,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { unreachable!() } - /// Resolve an identifier in lexical scope. - /// This is a variation of `fn resolve_ident_in_lexical_scope` that can be run during - /// expansion and import resolution (perhaps they can be merged in the future). - /// The function is used for resolving initial segments of macro paths (e.g., `foo` in - /// `foo::bar!();` or `foo!();`) and also for import paths on 2018 edition. + /// Resolve an identifier in the specified set of scopes. #[instrument(level = "debug", skip(self))] - pub(crate) fn early_resolve_ident_in_lexical_scope<'r>( + pub(crate) fn resolve_ident_in_scope_set<'r>( self: CmResolver<'r, 'ra, 'tcx>, orig_ident: Ident, scope_set: ScopeSet<'ra>, @@ -411,9 +404,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } let (ns, macro_kind) = match scope_set { - ScopeSet::All(ns) - | ScopeSet::ModuleAndExternPrelude(ns, _) - | ScopeSet::Late(ns, ..) => (ns, None), + ScopeSet::All(ns) | ScopeSet::ModuleAndExternPrelude(ns, _) => (ns, None), ScopeSet::ExternPrelude => (TypeNS, None), ScopeSet::Macro(macro_kind) => (MacroNS, Some(macro_kind)), }; @@ -437,10 +428,15 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } // Go through all the scopes and try to resolve the name. + let derive_fallback_lint_id = match finalize { + Some(Finalize { node_id, stage: Stage::Late, .. }) => Some(node_id), + _ => None, + }; let break_result = self.visit_scopes( scope_set, parent_scope, orig_ident.span.ctxt(), + derive_fallback_lint_id, |this, scope, use_prelude, ctxt| { let ident = Ident::new(orig_ident.name, orig_ident.span.with_ctxt(ctxt)); let result = match scope { @@ -510,11 +506,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ident, ns, adjusted_parent_scope, - if matches!(scope_set, ScopeSet::Late(..)) { - Shadowing::Unrestricted - } else { - Shadowing::Restricted - }, + Shadowing::Restricted, adjusted_finalize, ignore_binding, ignore_import, @@ -643,7 +635,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { return None; } - if finalize.is_none() || matches!(scope_set, ScopeSet::Late(..)) { + // Below we report various ambiguity errors. + // We do not need to report them if we are either in speculative resolution, + // or in late resolution when everything is already imported and expanded + // and no ambiguities exist. + if matches!(finalize, None | Some(Finalize { stage: Stage::Late, .. })) { return Some(Ok(binding)); } @@ -811,7 +807,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ModuleOrUniformRoot::Module(module) => module, ModuleOrUniformRoot::ModuleAndExternPrelude(module) => { assert_eq!(shadowing, Shadowing::Unrestricted); - let binding = self.early_resolve_ident_in_lexical_scope( + let binding = self.resolve_ident_in_scope_set( ident, ScopeSet::ModuleAndExternPrelude(ns, module), parent_scope, @@ -827,7 +823,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { return if ns != TypeNS { Err((Determined, Weak::No)) } else { - let binding = self.early_resolve_ident_in_lexical_scope( + let binding = self.resolve_ident_in_scope_set( ident, ScopeSet::ExternPrelude, parent_scope, @@ -852,7 +848,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } - let binding = self.early_resolve_ident_in_lexical_scope( + let binding = self.resolve_ident_in_scope_set( ident, ScopeSet::All(ns), parent_scope, @@ -945,7 +941,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Now we are in situation when new item/import can appear only from a glob or a macro // expansion. With restricted shadowing names from globs and macro expansions cannot // shadow names from outer scopes, so we can freely fallback from module search to search - // in outer scopes. For `early_resolve_ident_in_lexical_scope` to continue search in outer + // in outer scopes. For `resolve_ident_in_scope_set` to continue search in outer // scopes we return `Undetermined` with `Weak::Yes`. // Check if one of unexpanded macros can still define the name, @@ -1040,6 +1036,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Forbid expanded shadowing to avoid time travel. if let Some(shadowed_glob) = shadowed_glob && shadowing == Shadowing::Restricted + && finalize.stage == Stage::Early && binding.expansion != LocalExpnId::ROOT && binding.res() != shadowed_glob.res() { @@ -1635,7 +1632,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { _ => Err(Determinacy::determined(finalize.is_some())), } } else { - self.reborrow().early_resolve_ident_in_lexical_scope( + self.reborrow().resolve_ident_in_scope_set( ident, ScopeSet::All(ns), parent_scope, diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index d3790394d2a..d7fc028287f 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -1446,7 +1446,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { return; } - match this.cm().early_resolve_ident_in_lexical_scope( + match this.cm().resolve_ident_in_scope_set( target, ScopeSet::All(ns), &import.parent_scope, diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 9b201e40d13..80b2095d8cc 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -38,8 +38,8 @@ use crate::late::{ }; use crate::ty::fast_reject::SimplifiedType; use crate::{ - Module, ModuleKind, ModuleOrUniformRoot, PathResult, PathSource, Resolver, ScopeSet, Segment, - errors, path_names_to_string, + Module, ModuleKind, ModuleOrUniformRoot, ParentScope, PathResult, PathSource, Resolver, + ScopeSet, Segment, errors, path_names_to_string, }; type Res = def::Res<ast::NodeId>; @@ -2460,10 +2460,11 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { self.r.add_module_candidates(module, &mut names, &filter_fn, Some(ctxt)); } else if let RibKind::Module(module) = rib.kind { // Encountered a module item, abandon ribs and look into that module and preludes. + let parent_scope = &ParentScope { module, ..self.parent_scope }; self.r.add_scope_set_candidates( &mut names, - ScopeSet::Late(ns, module, None), - &self.parent_scope, + ScopeSet::All(ns), + parent_scope, ctxt, filter_fn, ); @@ -3094,7 +3095,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { } else { self.suggest_introducing_lifetime( &mut err, - Some(lifetime_ref.ident.name.as_str()), + Some(lifetime_ref.ident), |err, _, span, message, suggestion, span_suggs| { err.multipart_suggestion_verbose( message, @@ -3112,7 +3113,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { fn suggest_introducing_lifetime( &self, err: &mut Diag<'_>, - name: Option<&str>, + name: Option<Ident>, suggest: impl Fn( &mut Diag<'_>, bool, @@ -3159,7 +3160,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { let mut rm_inner_binders: FxIndexSet<Span> = Default::default(); let (span, sugg) = if span.is_empty() { let mut binder_idents: FxIndexSet<Ident> = Default::default(); - binder_idents.insert(Ident::from_str(name.unwrap_or("'a"))); + binder_idents.insert(name.unwrap_or(Ident::from_str("'a"))); // We need to special case binders in the following situation: // Change `T: for<'a> Trait<T> + 'b` to `for<'a, 'b> T: Trait<T> + 'b` @@ -3189,16 +3190,11 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { } } - let binders_sugg = binder_idents.into_iter().enumerate().fold( - "".to_string(), - |mut binders, (i, x)| { - if i != 0 { - binders += ", "; - } - binders += x.as_str(); - binders - }, - ); + let binders_sugg: String = binder_idents + .into_iter() + .map(|ident| ident.to_string()) + .intersperse(", ".to_owned()) + .collect(); let sugg = format!( "{}<{}>{}", if higher_ranked { "for" } else { "" }, @@ -3214,7 +3210,8 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { .source_map() .span_through_char(span, '<') .shrink_to_hi(); - let sugg = format!("{}, ", name.unwrap_or("'a")); + let sugg = + format!("{}, ", name.map(|i| i.to_string()).as_deref().unwrap_or("'a")); (span, sugg) }; @@ -3222,7 +3219,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { let message = Cow::from(format!( "consider making the {} lifetime-generic with a new `{}` lifetime", kind.descr(), - name.unwrap_or("'a"), + name.map(|i| i.to_string()).as_deref().unwrap_or("'a"), )); should_continue = suggest( err, diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 2063c46124c..2afb52ef4d4 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -49,7 +49,7 @@ use rustc_data_structures::intern::Interned; use rustc_data_structures::steal::Steal; use rustc_data_structures::sync::{FreezeReadGuard, FreezeWriteGuard}; use rustc_data_structures::unord::{UnordMap, UnordSet}; -use rustc_errors::{Applicability, Diag, ErrCode, ErrorGuaranteed}; +use rustc_errors::{Applicability, Diag, ErrCode, ErrorGuaranteed, LintBuffer}; use rustc_expand::base::{DeriveResolution, SyntaxExtension, SyntaxExtensionKind}; use rustc_feature::BUILTIN_ATTRIBUTES; use rustc_hir::attrs::StrippedCfgItem; @@ -72,8 +72,8 @@ use rustc_middle::ty::{ ResolverGlobalCtxt, TyCtxt, TyCtxtFeed, Visibility, }; use rustc_query_system::ich::StableHashingContext; +use rustc_session::lint::BuiltinLintDiag; use rustc_session::lint::builtin::PRIVATE_MACRO_USE; -use rustc_session::lint::{BuiltinLintDiag, LintBuffer}; use rustc_span::hygiene::{ExpnId, LocalExpnId, MacroKind, SyntaxContext, Transparency}; use rustc_span::{DUMMY_SP, Ident, Macros20NormalizedIdent, Span, Symbol, kw, sym}; use smallvec::{SmallVec, smallvec}; @@ -156,11 +156,8 @@ enum ScopeSet<'ra> { ModuleAndExternPrelude(Namespace, Module<'ra>), /// Just two extern prelude scopes. ExternPrelude, - /// All scopes with macro namespace and the given macro kind restriction. + /// Same as `All(MacroNS)`, but with the given macro kind restriction. Macro(MacroKind), - /// All scopes with the given namespace, used for partially performing late resolution. - /// The node id enables lints and is used for reporting them. - Late(Namespace, Module<'ra>, Option<NodeId>), } /// Everything you need to know about a name's location to resolve it. @@ -1888,7 +1885,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } - self.cm().visit_scopes(ScopeSet::All(TypeNS), parent_scope, ctxt, |this, scope, _, _| { + let scope_set = ScopeSet::All(TypeNS); + self.cm().visit_scopes(scope_set, parent_scope, ctxt, None, |this, scope, _, _| { match scope { Scope::Module(module, _) => { this.get_mut().traits_in_module(module, assoc_item, &mut found_traits); @@ -2455,6 +2453,17 @@ fn module_to_string(mut module: Module<'_>) -> Option<String> { Some(names_to_string(names.iter().rev().copied())) } +#[derive(Copy, Clone, PartialEq, Debug)] +enum Stage { + /// Resolving an import or a macro. + /// Used when macro expansion is either not yet finished, or we are finalizing its results. + /// Used by default as a more restrictive variant that can produce additional errors. + Early, + /// Resolving something in late resolution when all imports are resolved + /// and all macros are expanded. + Late, +} + #[derive(Copy, Clone, Debug)] struct Finalize { /// Node ID for linting. @@ -2467,9 +2476,11 @@ struct Finalize { root_span: Span, /// Whether to report privacy errors or silently return "no resolution" for them, /// similarly to speculative resolution. - report_private: bool, + report_private: bool = true, /// Tracks whether an item is used in scope or used relatively to a module. - used: Used, + used: Used = Used::Other, + /// Finalizing early or late resolution. + stage: Stage = Stage::Early, } impl Finalize { @@ -2478,7 +2489,7 @@ impl Finalize { } fn with_root_span(node_id: NodeId, path_span: Span, root_span: Span) -> Finalize { - Finalize { node_id, path_span, root_span, report_private: true, used: Used::Other } + Finalize { node_id, path_span, root_span, .. } } } diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 72ed8990241..5fa87b4cd9b 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -789,7 +789,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { self.prohibit_imported_non_macro_attrs(None, res.ok(), path_span); res } else { - let binding = self.reborrow().early_resolve_ident_in_lexical_scope( + let binding = self.reborrow().resolve_ident_in_scope_set( path[0].ident, ScopeSet::Macro(kind), parent_scope, @@ -951,7 +951,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // FIXME: Should be an output of Speculative Resolution. let macro_resolutions = self.single_segment_macro_resolutions.take(); for (ident, kind, parent_scope, initial_binding, sugg_span) in macro_resolutions { - match self.cm().early_resolve_ident_in_lexical_scope( + match self.cm().resolve_ident_in_scope_set( ident, ScopeSet::Macro(kind), &parent_scope, @@ -1006,7 +1006,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let builtin_attrs = mem::take(&mut self.builtin_attrs); for (ident, parent_scope) in builtin_attrs { - let _ = self.cm().early_resolve_ident_in_lexical_scope( + let _ = self.cm().resolve_ident_in_scope_set( ident, ScopeSet::Macro(MacroKind::Attr), &parent_scope, @@ -1112,7 +1112,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // If such resolution is successful and gives the same result // (e.g. if the macro is re-imported), then silence the lint. let no_macro_rules = self.arenas.alloc_macro_rules_scope(MacroRulesScope::Empty); - let fallback_binding = self.reborrow().early_resolve_ident_in_lexical_scope( + let fallback_binding = self.reborrow().resolve_ident_in_scope_set( path.segments[0].ident, ScopeSet::Macro(MacroKind::Bang), &ParentScope { macro_rules: no_macro_rules, ..*parent_scope }, diff --git a/compiler/rustc_session/Cargo.toml b/compiler/rustc_session/Cargo.toml index 0516982aeab..60d56b1b808 100644 --- a/compiler/rustc_session/Cargo.toml +++ b/compiler/rustc_session/Cargo.toml @@ -27,8 +27,10 @@ tracing = "0.1" # tidy-alphabetical-end [target.'cfg(unix)'.dependencies] +# FIXME: Remove this pin once this rustix issue is resolved +# https://github.com/bytecodealliance/rustix/issues/1496 # tidy-alphabetical-start -libc = "0.2" +libc = "=0.2.174" # tidy-alphabetical-end [target.'cfg(windows)'.dependencies.windows] diff --git a/compiler/rustc_session/messages.ftl b/compiler/rustc_session/messages.ftl index 80754964c43..b46e8ab4fdc 100644 --- a/compiler/rustc_session/messages.ftl +++ b/compiler/rustc_session/messages.ftl @@ -131,6 +131,10 @@ session_target_small_data_threshold_not_supported = `-Z small-data-threshold` is session_target_stack_protector_not_supported = `-Z stack-protector={$stack_protector}` is not supported for target {$target_triple} and will be ignored +session_unexpected_builtin_cfg = unexpected `--cfg {$cfg}` flag + .controlled_by = config `{$cfg_name}` is only supposed to be controlled by `{$controlled_by}` + .incoherent = manually setting a built-in cfg can and does create incoherent behaviors + session_unleashed_feature_help_named = skipping check for `{$gate}` feature session_unleashed_feature_help_unnamed = skipping check that does not even have a feature gate diff --git a/compiler/rustc_session/src/config/cfg.rs b/compiler/rustc_session/src/config/cfg.rs index 62891eb4f26..8f63ce6f0ae 100644 --- a/compiler/rustc_session/src/config/cfg.rs +++ b/compiler/rustc_session/src/config/cfg.rs @@ -26,13 +26,12 @@ use std::iter; use rustc_abi::Align; use rustc_ast::ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; -use rustc_lint_defs::BuiltinLintDiag; use rustc_lint_defs::builtin::EXPLICIT_BUILTIN_CFGS_IN_FLAGS; use rustc_span::{Symbol, sym}; use rustc_target::spec::{PanicStrategy, RelocModel, SanitizerSet, Target}; -use crate::Session; use crate::config::{CrateType, FmtDebug}; +use crate::{Session, errors}; /// The parsed `--cfg` options that define the compilation environment of the /// crate, used to drive conditional compilation. @@ -99,7 +98,7 @@ pub(crate) fn disallow_cfgs(sess: &Session, user_cfgs: &Cfg) { EXPLICIT_BUILTIN_CFGS_IN_FLAGS, None, ast::CRATE_NODE_ID, - BuiltinLintDiag::UnexpectedBuiltinCfg { cfg, cfg_name, controlled_by }, + errors::UnexpectedBuiltinCfg { cfg, cfg_name, controlled_by }.into(), ) }; diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs index 9471807df01..34da54a20bf 100644 --- a/compiler/rustc_session/src/errors.rs +++ b/compiler/rustc_session/src/errors.rs @@ -7,7 +7,7 @@ use rustc_errors::{ Diag, DiagCtxtHandle, DiagMessage, Diagnostic, EmissionGuarantee, ErrorGuaranteed, Level, MultiSpan, }; -use rustc_macros::{Diagnostic, Subdiagnostic}; +use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_span::{Span, Symbol}; use rustc_target::spec::{SplitDebuginfo, StackProtector, TargetTuple}; @@ -505,3 +505,13 @@ pub(crate) struct SoftFloatIgnored; #[note] #[note(session_soft_float_deprecated_issue)] pub(crate) struct SoftFloatDeprecated; + +#[derive(LintDiagnostic)] +#[diag(session_unexpected_builtin_cfg)] +#[note(session_controlled_by)] +#[note(session_incoherent)] +pub(crate) struct UnexpectedBuiltinCfg { + pub(crate) cfg: String, + pub(crate) cfg_name: Symbol, + pub(crate) controlled_by: &'static str, +} diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index 426480f0dba..9048c51d5b4 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -11,8 +11,8 @@ use rustc_data_structures::sync::{AppendOnlyVec, Lock}; use rustc_errors::emitter::{FatalOnlyEmitter, HumanEmitter, stderr_destination}; use rustc_errors::translation::Translator; use rustc_errors::{ - ColorConfig, Diag, DiagCtxt, DiagCtxtHandle, DiagMessage, EmissionGuarantee, MultiSpan, - StashKey, + BufferedEarlyLint, ColorConfig, DecorateDiagCompat, Diag, DiagCtxt, DiagCtxtHandle, + DiagMessage, EmissionGuarantee, MultiSpan, StashKey, }; use rustc_feature::{GateIssue, UnstableFeatures, find_feature_issue}; use rustc_span::edition::Edition; @@ -27,7 +27,7 @@ use crate::errors::{ FeatureDiagnosticSuggestion, FeatureGateError, SuggestUpgradeCompiler, }; use crate::lint::builtin::UNSTABLE_SYNTAX_PRE_EXPANSION; -use crate::lint::{BufferedEarlyLint, BuiltinLintDiag, Lint, LintId}; +use crate::lint::{Lint, LintId}; /// Collected spans during parsing for places where a certain feature was /// used and should be feature gated accordingly in `check_crate`. @@ -342,17 +342,17 @@ impl ParseSess { lint: &'static Lint, span: impl Into<MultiSpan>, node_id: NodeId, - diagnostic: BuiltinLintDiag, + diagnostic: impl Into<DecorateDiagCompat>, ) { - self.opt_span_buffer_lint(lint, Some(span.into()), node_id, diagnostic) + self.opt_span_buffer_lint(lint, Some(span.into()), node_id, diagnostic.into()) } - pub fn opt_span_buffer_lint( + pub(crate) fn opt_span_buffer_lint( &self, lint: &'static Lint, span: Option<MultiSpan>, node_id: NodeId, - diagnostic: BuiltinLintDiag, + diagnostic: DecorateDiagCompat, ) { self.buffered_lints.with_lock(|buffered_lints| { buffered_lints.push(BufferedEarlyLint { diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index d9315149798..8270de1e917 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -911,12 +911,13 @@ impl SourceMap { /// Returns a new span representing just the last character of this span. pub fn end_point(&self, sp: Span) -> Span { - let pos = sp.hi().0; + let sp = sp.data(); + let pos = sp.hi.0; let width = self.find_width_of_character_at_span(sp, false); let corrected_end_position = pos.checked_sub(width).unwrap_or(pos); - let end_point = BytePos(cmp::max(corrected_end_position, sp.lo().0)); + let end_point = BytePos(cmp::max(corrected_end_position, sp.lo.0)); sp.with_lo(end_point) } @@ -930,8 +931,9 @@ impl SourceMap { if sp.is_dummy() { return sp; } - let start_of_next_point = sp.hi().0; + let sp = sp.data(); + let start_of_next_point = sp.hi.0; let width = self.find_width_of_character_at_span(sp, true); // If the width is 1, then the next span should only contain the next char besides current ending. // However, in the case of a multibyte character, where the width != 1, the next span should @@ -940,7 +942,7 @@ impl SourceMap { start_of_next_point.checked_add(width).unwrap_or(start_of_next_point); let end_of_next_point = BytePos(cmp::max(start_of_next_point + 1, end_of_next_point)); - Span::new(BytePos(start_of_next_point), end_of_next_point, sp.ctxt(), None) + Span::new(BytePos(start_of_next_point), end_of_next_point, sp.ctxt, None) } /// Check whether span is followed by some specified expected string in limit scope @@ -963,9 +965,7 @@ impl SourceMap { /// Finds the width of the character, either before or after the end of provided span, /// depending on the `forwards` parameter. #[instrument(skip(self, sp))] - fn find_width_of_character_at_span(&self, sp: Span, forwards: bool) -> u32 { - let sp = sp.data(); - + fn find_width_of_character_at_span(&self, sp: SpanData, forwards: bool) -> u32 { if sp.lo == sp.hi && !forwards { debug!("early return empty span"); return 1; diff --git a/compiler/rustc_span/src/span_encoding.rs b/compiler/rustc_span/src/span_encoding.rs index a4a47dc99b0..e34efa784de 100644 --- a/compiler/rustc_span/src/span_encoding.rs +++ b/compiler/rustc_span/src/span_encoding.rs @@ -74,9 +74,8 @@ use crate::{BytePos, SPAN_TRACK, SpanData}; /// because `parent` isn't currently used by default. /// /// In order to reliably use parented spans in incremental compilation, -/// the dependency to the parent definition's span. This is performed -/// using the callback `SPAN_TRACK` to access the query engine. -/// +/// accesses to `lo` and `hi` must introduce a dependency to the parent definition's span. +/// This is performed using the callback `SPAN_TRACK` to access the query engine. #[derive(Clone, Copy, Eq, PartialEq, Hash)] #[rustc_pass_by_value] pub struct Span { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index dcb1becc957..5d140cc6117 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -901,6 +901,7 @@ symbols! { dynamic_no_pic: "dynamic-no-pic", e, edition_panic, + effective_target_features, effects, eh_catch_typeinfo, eh_personality, @@ -1061,6 +1062,7 @@ symbols! { fn_ptr_addr, fn_ptr_trait, forbid, + force_target_feature, forget, format, format_args, @@ -1754,6 +1756,7 @@ symbols! { readonly, realloc, reason, + reborrow, receiver, receiver_target, recursion_limit, @@ -2533,10 +2536,16 @@ impl fmt::Debug for Ident { /// except that AST identifiers don't keep the rawness flag, so we have to guess it. impl fmt::Display for Ident { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(&IdentPrinter::new(self.name, self.is_raw_guess(), None), f) + fmt::Display::fmt(&IdentPrinter::new(self.name, self.guess_print_mode(), None), f) } } +pub enum IdentPrintMode { + Normal, + RawIdent, + RawLifetime, +} + /// The most general type to print identifiers. /// /// AST pretty-printer is used as a fallback for turning AST structures into token streams for @@ -2552,7 +2561,7 @@ impl fmt::Display for Ident { /// done for a token stream or a single token. pub struct IdentPrinter { symbol: Symbol, - is_raw: bool, + mode: IdentPrintMode, /// Span used for retrieving the crate name to which `$crate` refers to, /// if this field is `None` then the `$crate` conversion doesn't happen. convert_dollar_crate: Option<Span>, @@ -2560,32 +2569,51 @@ pub struct IdentPrinter { impl IdentPrinter { /// The most general `IdentPrinter` constructor. Do not use this. - pub fn new(symbol: Symbol, is_raw: bool, convert_dollar_crate: Option<Span>) -> IdentPrinter { - IdentPrinter { symbol, is_raw, convert_dollar_crate } + pub fn new( + symbol: Symbol, + mode: IdentPrintMode, + convert_dollar_crate: Option<Span>, + ) -> IdentPrinter { + IdentPrinter { symbol, mode, convert_dollar_crate } } /// This implementation is supposed to be used when printing identifiers /// as a part of pretty-printing for larger AST pieces. /// Do not use this either. - pub fn for_ast_ident(ident: Ident, is_raw: bool) -> IdentPrinter { - IdentPrinter::new(ident.name, is_raw, Some(ident.span)) + pub fn for_ast_ident(ident: Ident, mode: IdentPrintMode) -> IdentPrinter { + IdentPrinter::new(ident.name, mode, Some(ident.span)) } } impl fmt::Display for IdentPrinter { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if self.is_raw { - f.write_str("r#")?; - } else if self.symbol == kw::DollarCrate { - if let Some(span) = self.convert_dollar_crate { + let s = match self.mode { + IdentPrintMode::Normal + if self.symbol == kw::DollarCrate + && let Some(span) = self.convert_dollar_crate => + { let converted = span.ctxt().dollar_crate_name(); if !converted.is_path_segment_keyword() { f.write_str("::")?; } - return fmt::Display::fmt(&converted, f); + converted } - } - fmt::Display::fmt(&self.symbol, f) + IdentPrintMode::Normal => self.symbol, + IdentPrintMode::RawIdent => { + f.write_str("r#")?; + self.symbol + } + IdentPrintMode::RawLifetime => { + f.write_str("'r#")?; + let s = self + .symbol + .as_str() + .strip_prefix("'") + .expect("only lifetime idents should be passed with RawLifetime mode"); + Symbol::intern(s) + } + }; + s.fmt(f) } } @@ -3020,6 +3048,29 @@ impl Ident { self.name.can_be_raw() && self.is_reserved() } + /// Given the name of a lifetime without the first quote (`'`), + /// returns whether the lifetime name is reserved (therefore invalid) + pub fn is_reserved_lifetime(self) -> bool { + self.is_reserved() && ![kw::Underscore, kw::Static].contains(&self.name) + } + + pub fn is_raw_lifetime_guess(self) -> bool { + let name_without_apostrophe = self.without_first_quote(); + name_without_apostrophe.name != self.name + && name_without_apostrophe.name.can_be_raw() + && name_without_apostrophe.is_reserved_lifetime() + } + + pub fn guess_print_mode(self) -> IdentPrintMode { + if self.is_raw_lifetime_guess() { + IdentPrintMode::RawLifetime + } else if self.is_raw_guess() { + IdentPrintMode::RawIdent + } else { + IdentPrintMode::Normal + } + } + /// Whether this would be the identifier for a tuple field like `self.0`, as /// opposed to a named field like `self.thing`. pub fn is_numeric(self) -> bool { diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 399770022b2..a67795e3e93 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -2116,6 +2116,7 @@ supported_targets! { ("msp430-none-elf", msp430_none_elf), + ("aarch64_be-unknown-hermit", aarch64_be_unknown_hermit), ("aarch64-unknown-hermit", aarch64_unknown_hermit), ("riscv64gc-unknown-hermit", riscv64gc_unknown_hermit), ("x86_64-unknown-hermit", x86_64_unknown_hermit), diff --git a/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_hermit.rs b/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_hermit.rs new file mode 100644 index 00000000000..cad57abc2b1 --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_hermit.rs @@ -0,0 +1,25 @@ +use rustc_abi::Endian; + +use crate::spec::{StackProbeType, Target, TargetMetadata, TargetOptions, base}; + +pub(crate) fn target() -> Target { + Target { + llvm_target: "aarch64_be-unknown-hermit".into(), + metadata: TargetMetadata { + description: Some("ARM64 Hermit (big-endian)".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(true), + }, + pointer_width: 64, + arch: "aarch64".into(), + data_layout: "E-m:e-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), + options: TargetOptions { + features: "+v8a,+strict-align,+neon,+fp-armv8".into(), + max_atomic_width: Some(128), + stack_probes: StackProbeType::Inline, + endian: Endian::Big, + ..base::hermit::opts() + }, + } +} diff --git a/compiler/rustc_target/src/spec/targets/aarch64_nintendo_switch_freestanding.rs b/compiler/rustc_target/src/spec/targets/aarch64_nintendo_switch_freestanding.rs index 9b81362b27d..61e4cad3fa2 100644 --- a/compiler/rustc_target/src/spec/targets/aarch64_nintendo_switch_freestanding.rs +++ b/compiler/rustc_target/src/spec/targets/aarch64_nintendo_switch_freestanding.rs @@ -19,7 +19,7 @@ pub(crate) fn target() -> Target { data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), arch: "aarch64".into(), options: TargetOptions { - features: "+v8a".into(), + features: "+v8a,+neon,+crypto,+crc".into(), linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), linker: Some("rust-lld".into()), link_script: Some(LINKER_SCRIPT.into()), diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs index f31a85ec07a..40285e5d0e9 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs @@ -537,7 +537,7 @@ impl<T> Trait<T> for X { } } TypeError::TargetFeatureCast(def_id) => { - let target_spans = find_attr!(tcx.get_all_attrs(def_id), AttributeKind::TargetFeature(.., span) => *span); + let target_spans = find_attr!(tcx.get_all_attrs(def_id), AttributeKind::TargetFeature{attr_span: span, was_forced: false, ..} => *span); diag.note( "functions with `#[target_feature]` can only be coerced to `unsafe` function pointers" ); diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 214a6e86d39..d768e0bf63f 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -275,8 +275,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { *err.long_ty_path() = long_ty_file; let mut suggested = false; + let mut noted_missing_impl = false; if is_try_conversion || is_question_mark { - suggested = self.try_conversion_context(&obligation, main_trait_predicate, &mut err); + (suggested, noted_missing_impl) = self.try_conversion_context(&obligation, main_trait_predicate, &mut err); } if let Some(ret_span) = self.return_type_span(&obligation) { @@ -335,6 +336,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { return err.emit(); } + let ty_span = match leaf_trait_predicate.self_ty().skip_binder().kind() { + ty::Adt(def, _) if def.did().is_local() + && !self.can_suggest_derive(&obligation, leaf_trait_predicate) => self.tcx.def_span(def.did()), + _ => DUMMY_SP, + }; if let Some(s) = label { // If it has a custom `#[rustc_on_unimplemented]` // error message, let's display it as the label! @@ -347,15 +353,28 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // Don't say "the trait `FromResidual<Option<Infallible>>` is // not implemented for `Result<T, E>`". { - err.help(explanation); + // We do this just so that the JSON output's `help` position is the + // right one and not `file.rs:1:1`. The render is the same. + if ty_span == DUMMY_SP { + err.help(explanation); + } else { + err.span_help(ty_span, explanation); + } } } else if let Some(custom_explanation) = safe_transmute_explanation { err.span_label(span, custom_explanation); - } else if explanation.len() > self.tcx.sess.diagnostic_width() { + } else if (explanation.len() > self.tcx.sess.diagnostic_width() || ty_span != DUMMY_SP) && !noted_missing_impl { // Really long types don't look good as span labels, instead move it // to a `help`. err.span_label(span, "unsatisfied trait bound"); - err.help(explanation); + + // We do this just so that the JSON output's `help` position is the + // right one and not `file.rs:1:1`. The render is the same. + if ty_span == DUMMY_SP { + err.help(explanation); + } else { + err.span_help(ty_span, explanation); + } } else { err.span_label(span, explanation); } @@ -939,7 +958,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { obligation: &PredicateObligation<'tcx>, trait_pred: ty::PolyTraitPredicate<'tcx>, err: &mut Diag<'_>, - ) -> bool { + ) -> (bool, bool) { let span = obligation.cause.span; /// Look for the (direct) sub-expr of `?`, and return it if it's a `.` method call. struct FindMethodSubexprOfTry { @@ -959,21 +978,22 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } let hir_id = self.tcx.local_def_id_to_hir_id(obligation.cause.body_id); - let Some(body_id) = self.tcx.hir_node(hir_id).body_id() else { return false }; + let Some(body_id) = self.tcx.hir_node(hir_id).body_id() else { return (false, false) }; let ControlFlow::Break(expr) = (FindMethodSubexprOfTry { search_span: span }).visit_body(self.tcx.hir_body(body_id)) else { - return false; + return (false, false); }; let Some(typeck) = &self.typeck_results else { - return false; + return (false, false); }; let ObligationCauseCode::QuestionMark = obligation.cause.code().peel_derives() else { - return false; + return (false, false); }; let self_ty = trait_pred.skip_binder().self_ty(); let found_ty = trait_pred.skip_binder().trait_ref.args.get(1).and_then(|a| a.as_type()); - self.note_missing_impl_for_question_mark(err, self_ty, found_ty, trait_pred); + let noted_missing_impl = + self.note_missing_impl_for_question_mark(err, self_ty, found_ty, trait_pred); let mut prev_ty = self.resolve_vars_if_possible( typeck.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(self.tcx)), @@ -1137,7 +1157,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } prev = Some(err_ty); } - suggested + (suggested, noted_missing_impl) } fn note_missing_impl_for_question_mark( @@ -1146,7 +1166,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { self_ty: Ty<'_>, found_ty: Option<Ty<'_>>, trait_pred: ty::PolyTraitPredicate<'tcx>, - ) { + ) -> bool { match (self_ty.kind(), found_ty) { (ty::Adt(def, _), Some(ty)) if let ty::Adt(found, _) = ty.kind() @@ -1187,8 +1207,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { format!("`{ty}` needs to implement `Into<{self_ty}>`"), ); } - _ => {} + _ => return false, } + true } fn report_const_param_not_wf( diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 953449c6758..e31ff8b8729 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -3853,59 +3853,71 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } - pub fn suggest_derive( + pub fn can_suggest_derive( &self, obligation: &PredicateObligation<'tcx>, - err: &mut Diag<'_>, trait_pred: ty::PolyTraitPredicate<'tcx>, - ) { + ) -> bool { if trait_pred.polarity() == ty::PredicatePolarity::Negative { - return; + return false; } let Some(diagnostic_name) = self.tcx.get_diagnostic_name(trait_pred.def_id()) else { - return; + return false; }; let (adt, args) = match trait_pred.skip_binder().self_ty().kind() { ty::Adt(adt, args) if adt.did().is_local() => (adt, args), - _ => return, + _ => return false, }; - let can_derive = { - let is_derivable_trait = match diagnostic_name { - sym::Default => !adt.is_enum(), - sym::PartialEq | sym::PartialOrd => { - let rhs_ty = trait_pred.skip_binder().trait_ref.args.type_at(1); - trait_pred.skip_binder().self_ty() == rhs_ty - } - sym::Eq | sym::Ord | sym::Clone | sym::Copy | sym::Hash | sym::Debug => true, - _ => false, - }; - is_derivable_trait && - // Ensure all fields impl the trait. - adt.all_fields().all(|field| { - let field_ty = ty::GenericArg::from(field.ty(self.tcx, args)); - let trait_args = match diagnostic_name { - sym::PartialEq | sym::PartialOrd => { - Some(field_ty) - } - _ => None, - }; - let trait_pred = trait_pred.map_bound_ref(|tr| ty::TraitPredicate { - trait_ref: ty::TraitRef::new(self.tcx, - trait_pred.def_id(), - [field_ty].into_iter().chain(trait_args), - ), - ..*tr - }); - let field_obl = Obligation::new( - self.tcx, - obligation.cause.clone(), - obligation.param_env, - trait_pred, - ); - self.predicate_must_hold_modulo_regions(&field_obl) - }) + let is_derivable_trait = match diagnostic_name { + sym::Default => !adt.is_enum(), + sym::PartialEq | sym::PartialOrd => { + let rhs_ty = trait_pred.skip_binder().trait_ref.args.type_at(1); + trait_pred.skip_binder().self_ty() == rhs_ty + } + sym::Eq | sym::Ord | sym::Clone | sym::Copy | sym::Hash | sym::Debug => true, + _ => false, + }; + is_derivable_trait && + // Ensure all fields impl the trait. + adt.all_fields().all(|field| { + let field_ty = ty::GenericArg::from(field.ty(self.tcx, args)); + let trait_args = match diagnostic_name { + sym::PartialEq | sym::PartialOrd => { + Some(field_ty) + } + _ => None, + }; + let trait_pred = trait_pred.map_bound_ref(|tr| ty::TraitPredicate { + trait_ref: ty::TraitRef::new(self.tcx, + trait_pred.def_id(), + [field_ty].into_iter().chain(trait_args), + ), + ..*tr + }); + let field_obl = Obligation::new( + self.tcx, + obligation.cause.clone(), + obligation.param_env, + trait_pred, + ); + self.predicate_must_hold_modulo_regions(&field_obl) + }) + } + + pub fn suggest_derive( + &self, + obligation: &PredicateObligation<'tcx>, + err: &mut Diag<'_>, + trait_pred: ty::PolyTraitPredicate<'tcx>, + ) { + let Some(diagnostic_name) = self.tcx.get_diagnostic_name(trait_pred.def_id()) else { + return; + }; + let adt = match trait_pred.skip_binder().self_ty().kind() { + ty::Adt(adt, _) if adt.did().is_local() => adt, + _ => return, }; - if can_derive { + if self.can_suggest_derive(obligation, trait_pred) { err.span_suggestion_verbose( self.tcx.def_span(adt.did()).shrink_to_lo(), format!( diff --git a/compiler/rustc_type_ir/src/region_kind.rs b/compiler/rustc_type_ir/src/region_kind.rs index cca81dcb4a0..06048af0436 100644 --- a/compiler/rustc_type_ir/src/region_kind.rs +++ b/compiler/rustc_type_ir/src/region_kind.rs @@ -154,7 +154,7 @@ pub enum RegionKind<I: Interner> { /// parameters via `tcx.liberate_late_bound_regions`. They are then treated /// the same way as `ReEarlyParam` while inside of the function. /// - /// See <https://rustc-dev-guide.rust-lang.org/early-late-bound-params/early-late-bound-summary.html> for + /// See <https://rustc-dev-guide.rust-lang.org/early_late_parameters.html> for /// more info about early and late bound lifetime parameters. ReLateParam(I::LateParamRegion), diff --git a/library/Cargo.lock b/library/Cargo.lock index 418a5f78397..8b860f69492 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -140,9 +140,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.174" +version = "0.2.175" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" +checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543" dependencies = [ "rustc-std-workspace-core", ] @@ -169,9 +169,9 @@ dependencies = [ [[package]] name = "object" -version = "0.37.2" +version = "0.37.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3e3d0a7419f081f4a808147e845310313a39f322d7ae1f996b7f001d6cbed04" +checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" dependencies = [ "memchr", "rustc-std-workspace-alloc", @@ -192,7 +192,6 @@ name = "panic_unwind" version = "0.0.0" dependencies = [ "alloc", - "cfg-if", "libc", "rustc-std-workspace-core", "unwind", diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs index 7ee0962721f..985e669c92d 100644 --- a/library/core/src/char/methods.rs +++ b/library/core/src/char/methods.rs @@ -1872,28 +1872,33 @@ pub const unsafe fn encode_utf8_raw_unchecked(code: u32, dst: *mut u8) { // SAFETY: The caller must guarantee that the buffer pointed to by `dst` // is at least `len` bytes long. unsafe { - match len { - 1 => { - *dst = code as u8; - } - 2 => { - *dst = (code >> 6 & 0x1F) as u8 | TAG_TWO_B; - *dst.add(1) = (code & 0x3F) as u8 | TAG_CONT; - } - 3 => { - *dst = (code >> 12 & 0x0F) as u8 | TAG_THREE_B; - *dst.add(1) = (code >> 6 & 0x3F) as u8 | TAG_CONT; - *dst.add(2) = (code & 0x3F) as u8 | TAG_CONT; - } - 4 => { - *dst = (code >> 18 & 0x07) as u8 | TAG_FOUR_B; - *dst.add(1) = (code >> 12 & 0x3F) as u8 | TAG_CONT; - *dst.add(2) = (code >> 6 & 0x3F) as u8 | TAG_CONT; - *dst.add(3) = (code & 0x3F) as u8 | TAG_CONT; - } - // SAFETY: `char` always takes between 1 and 4 bytes to encode in UTF-8. - _ => crate::hint::unreachable_unchecked(), + if len == 1 { + *dst = code as u8; + return; + } + + let last1 = (code >> 0 & 0x3F) as u8 | TAG_CONT; + let last2 = (code >> 6 & 0x3F) as u8 | TAG_CONT; + let last3 = (code >> 12 & 0x3F) as u8 | TAG_CONT; + let last4 = (code >> 18 & 0x3F) as u8 | TAG_FOUR_B; + + if len == 2 { + *dst = last2 | TAG_TWO_B; + *dst.add(1) = last1; + return; } + + if len == 3 { + *dst = last3 | TAG_THREE_B; + *dst.add(1) = last2; + *dst.add(2) = last1; + return; + } + + *dst = last4; + *dst.add(1) = last3; + *dst.add(2) = last2; + *dst.add(3) = last1; } } diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 71abd707374..f69d6a98592 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -172,6 +172,7 @@ #![feature(no_core)] #![feature(optimize_attribute)] #![feature(prelude_import)] +#![feature(reborrow)] #![feature(repr_simd)] #![feature(rustc_allow_const_fn_unstable)] #![feature(rustc_attrs)] diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index ba00ee17b65..8ad58599c68 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -1365,3 +1365,11 @@ pub macro CoercePointee($item:item) { pub trait CoercePointeeValidated { /* compiler built-in */ } + +/// Allows value to be reborrowed as exclusive, creating a copy of the value +/// that disables the source for reads and writes for the lifetime of the copy. +#[lang = "reborrow"] +#[unstable(feature = "reborrow", issue = "145612")] +pub trait Reborrow { + // Empty. +} diff --git a/library/core/src/panic/location.rs b/library/core/src/panic/location.rs index 6ef7d5a22a3..cafdcfa2c2e 100644 --- a/library/core/src/panic/location.rs +++ b/library/core/src/panic/location.rs @@ -183,7 +183,7 @@ impl<'a> Location<'a> { #[must_use] #[stable(feature = "panic_hooks", since = "1.10.0")] #[rustc_const_stable(feature = "const_location_fields", since = "1.79.0")] - pub const fn file(&self) -> &str { + pub const fn file(&self) -> &'a str { // SAFETY: The filename is valid. unsafe { self.filename.as_ref() } } @@ -195,7 +195,7 @@ impl<'a> Location<'a> { #[must_use] #[unstable(feature = "file_with_nul", issue = "141727")] #[inline] - pub const fn file_with_nul(&self) -> &CStr { + pub const fn file_with_nul(&self) -> &'a CStr { let filename = self.filename.as_ptr(); // SAFETY: The filename is valid for `filename_len+1` bytes, so this addition can't diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs index ae360df80f6..98091e9fe83 100644 --- a/library/core/src/slice/index.rs +++ b/library/core/src/slice/index.rs @@ -34,53 +34,44 @@ where #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)] #[cfg_attr(feature = "panic_immediate_abort", inline)] #[track_caller] -const fn slice_start_index_len_fail(index: usize, len: usize) -> ! { - const_panic!( - "slice start index is out of range for slice", - "range start index {index} out of range for slice of length {len}", - index: usize, - len: usize, - ) -} +const fn slice_index_fail(start: usize, end: usize, len: usize) -> ! { + if start > len { + const_panic!( + "slice start index is out of range for slice", + "range start index {start} out of range for slice of length {len}", + start: usize, + len: usize, + ) + } -#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)] -#[cfg_attr(feature = "panic_immediate_abort", inline)] -#[track_caller] -const fn slice_end_index_len_fail(index: usize, len: usize) -> ! { - const_panic!( - "slice end index is out of range for slice", - "range end index {index} out of range for slice of length {len}", - index: usize, - len: usize, - ) -} + if end > len { + const_panic!( + "slice end index is out of range for slice", + "range end index {end} out of range for slice of length {len}", + end: usize, + len: usize, + ) + } -#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)] -#[cfg_attr(feature = "panic_immediate_abort", inline)] -#[track_caller] -const fn slice_index_order_fail(index: usize, end: usize) -> ! { + if start > end { + const_panic!( + "slice index start is larger than end", + "slice index starts at {start} but ends at {end}", + start: usize, + end: usize, + ) + } + + // Only reachable if the range was a `RangeInclusive` or a + // `RangeToInclusive`, with `end == len`. const_panic!( - "slice index start is larger than end", - "slice index starts at {index} but ends at {end}", - index: usize, + "slice end index is out of range for slice", + "range end index {end} out of range for slice of length {len}", end: usize, + len: usize, ) } -#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)] -#[cfg_attr(feature = "panic_immediate_abort", inline)] -#[track_caller] -const fn slice_start_index_overflow_fail() -> ! { - panic!("attempted to index slice from after maximum usize"); -} - -#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)] -#[cfg_attr(feature = "panic_immediate_abort", inline)] -#[track_caller] -const fn slice_end_index_overflow_fail() -> ! { - panic!("attempted to index slice up to maximum usize"); -} - // The UbChecks are great for catching bugs in the unsafe methods, but including // them in safe indexing is unnecessary and hurts inlining and debug runtime perf. // Both the safe and unsafe public methods share these helpers, @@ -341,7 +332,7 @@ unsafe impl<T> const SliceIndex<[T]> for ops::IndexRange { // SAFETY: `self` is checked to be valid and in bounds above. unsafe { &*get_offset_len_noubcheck(slice, self.start(), self.len()) } } else { - slice_end_index_len_fail(self.end(), slice.len()) + slice_index_fail(self.start(), self.end(), slice.len()) } } @@ -351,7 +342,7 @@ unsafe impl<T> const SliceIndex<[T]> for ops::IndexRange { // SAFETY: `self` is checked to be valid and in bounds above. unsafe { &mut *get_offset_len_mut_noubcheck(slice, self.start(), self.len()) } } else { - slice_end_index_len_fail(self.end(), slice.len()) + slice_index_fail(self.start(), self.end(), slice.len()) } } } @@ -436,26 +427,27 @@ unsafe impl<T> const SliceIndex<[T]> for ops::Range<usize> { #[inline(always)] fn index(self, slice: &[T]) -> &[T] { // Using checked_sub is a safe way to get `SubUnchecked` in MIR - let Some(new_len) = usize::checked_sub(self.end, self.start) else { - slice_index_order_fail(self.start, self.end) - }; - if self.end > slice.len() { - slice_end_index_len_fail(self.end, slice.len()); + if let Some(new_len) = usize::checked_sub(self.end, self.start) + && self.end <= slice.len() + { + // SAFETY: `self` is checked to be valid and in bounds above. + unsafe { &*get_offset_len_noubcheck(slice, self.start, new_len) } + } else { + slice_index_fail(self.start, self.end, slice.len()) } - // SAFETY: `self` is checked to be valid and in bounds above. - unsafe { &*get_offset_len_noubcheck(slice, self.start, new_len) } } #[inline] fn index_mut(self, slice: &mut [T]) -> &mut [T] { - let Some(new_len) = usize::checked_sub(self.end, self.start) else { - slice_index_order_fail(self.start, self.end) - }; - if self.end > slice.len() { - slice_end_index_len_fail(self.end, slice.len()); + // Using checked_sub is a safe way to get `SubUnchecked` in MIR + if let Some(new_len) = usize::checked_sub(self.end, self.start) + && self.end <= slice.len() + { + // SAFETY: `self` is checked to be valid and in bounds above. + unsafe { &mut *get_offset_len_mut_noubcheck(slice, self.start, new_len) } + } else { + slice_index_fail(self.start, self.end, slice.len()) } - // SAFETY: `self` is checked to be valid and in bounds above. - unsafe { &mut *get_offset_len_mut_noubcheck(slice, self.start, new_len) } } } @@ -567,7 +559,7 @@ unsafe impl<T> const SliceIndex<[T]> for ops::RangeFrom<usize> { #[inline] fn index(self, slice: &[T]) -> &[T] { if self.start > slice.len() { - slice_start_index_len_fail(self.start, slice.len()); + slice_index_fail(self.start, slice.len(), slice.len()) } // SAFETY: `self` is checked to be valid and in bounds above. unsafe { &*self.get_unchecked(slice) } @@ -576,7 +568,7 @@ unsafe impl<T> const SliceIndex<[T]> for ops::RangeFrom<usize> { #[inline] fn index_mut(self, slice: &mut [T]) -> &mut [T] { if self.start > slice.len() { - slice_start_index_len_fail(self.start, slice.len()); + slice_index_fail(self.start, slice.len(), slice.len()) } // SAFETY: `self` is checked to be valid and in bounds above. unsafe { &mut *self.get_unchecked_mut(slice) } @@ -690,18 +682,32 @@ unsafe impl<T> const SliceIndex<[T]> for ops::RangeInclusive<usize> { #[inline] fn index(self, slice: &[T]) -> &[T] { - if *self.end() == usize::MAX { - slice_end_index_overflow_fail(); + let Self { mut start, mut end, exhausted } = self; + let len = slice.len(); + if end < len { + end = end + 1; + start = if exhausted { end } else { start }; + if let Some(new_len) = usize::checked_sub(end, start) { + // SAFETY: `self` is checked to be valid and in bounds above. + unsafe { return &*get_offset_len_noubcheck(slice, start, new_len) } + } } - self.into_slice_range().index(slice) + slice_index_fail(start, end, slice.len()) } #[inline] fn index_mut(self, slice: &mut [T]) -> &mut [T] { - if *self.end() == usize::MAX { - slice_end_index_overflow_fail(); + let Self { mut start, mut end, exhausted } = self; + let len = slice.len(); + if end < len { + end = end + 1; + start = if exhausted { end } else { start }; + if let Some(new_len) = usize::checked_sub(end, start) { + // SAFETY: `self` is checked to be valid and in bounds above. + unsafe { return &mut *get_offset_len_mut_noubcheck(slice, start, new_len) } + } } - self.into_slice_range().index_mut(slice) + slice_index_fail(start, end, slice.len()) } } @@ -852,28 +858,26 @@ where { let len = bounds.end; - let start = match range.start_bound() { - ops::Bound::Included(&start) => start, - ops::Bound::Excluded(start) => { - start.checked_add(1).unwrap_or_else(|| slice_start_index_overflow_fail()) - } - ops::Bound::Unbounded => 0, - }; - let end = match range.end_bound() { - ops::Bound::Included(end) => { - end.checked_add(1).unwrap_or_else(|| slice_end_index_overflow_fail()) - } + ops::Bound::Included(&end) if end >= len => slice_index_fail(0, end, len), + // Cannot overflow because `end < len` implies `end < usize::MAX`. + ops::Bound::Included(&end) => end + 1, + + ops::Bound::Excluded(&end) if end > len => slice_index_fail(0, end, len), ops::Bound::Excluded(&end) => end, ops::Bound::Unbounded => len, }; - if start > end { - slice_index_order_fail(start, end); - } - if end > len { - slice_end_index_len_fail(end, len); - } + let start = match range.start_bound() { + ops::Bound::Excluded(&start) if start >= end => slice_index_fail(start, end, len), + // Cannot overflow because `start < end` implies `start < usize::MAX`. + ops::Bound::Excluded(&start) => start + 1, + + ops::Bound::Included(&start) if start > end => slice_index_fail(start, end, len), + ops::Bound::Included(&start) => start, + + ops::Bound::Unbounded => 0, + }; ops::Range { start, end } } @@ -982,25 +986,27 @@ pub(crate) fn into_slice_range( len: usize, (start, end): (ops::Bound<usize>, ops::Bound<usize>), ) -> ops::Range<usize> { - use ops::Bound; - let start = match start { - Bound::Included(start) => start, - Bound::Excluded(start) => { - start.checked_add(1).unwrap_or_else(|| slice_start_index_overflow_fail()) - } - Bound::Unbounded => 0, - }; - let end = match end { - Bound::Included(end) => { - end.checked_add(1).unwrap_or_else(|| slice_end_index_overflow_fail()) - } - Bound::Excluded(end) => end, - Bound::Unbounded => len, + ops::Bound::Included(end) if end >= len => slice_index_fail(0, end, len), + // Cannot overflow because `end < len` implies `end < usize::MAX`. + ops::Bound::Included(end) => end + 1, + + ops::Bound::Excluded(end) if end > len => slice_index_fail(0, end, len), + ops::Bound::Excluded(end) => end, + + ops::Bound::Unbounded => len, }; - // Don't bother with checking `start < end` and `end <= len` - // since these checks are handled by `Range` impls + let start = match start { + ops::Bound::Excluded(start) if start >= end => slice_index_fail(start, end, len), + // Cannot overflow because `start < end` implies `start < usize::MAX`. + ops::Bound::Excluded(start) => start + 1, + + ops::Bound::Included(start) if start > end => slice_index_fail(start, end, len), + ops::Bound::Included(start) => start, + + ops::Bound::Unbounded => 0, + }; start..end } diff --git a/library/coretests/tests/panic/location.rs b/library/coretests/tests/panic/location.rs index 910001bcc1c..a7db05a15c6 100644 --- a/library/coretests/tests/panic/location.rs +++ b/library/coretests/tests/panic/location.rs @@ -48,10 +48,18 @@ fn location_const_column() { } #[test] +fn location_file_lifetime<'x>() { + // Verify that the returned `&str`s lifetime is derived from the generic + // lifetime 'a, not the lifetime of `&self`, when calling `Location::file`. + // Test failure is indicated by a compile failure, not a runtime panic. + let _: for<'a> fn(&'a Location<'x>) -> &'x str = Location::file; +} + +#[test] fn location_debug() { let f = format!("{:?}", Location::caller()); assert!(f.contains(&format!("{:?}", file!()))); - assert!(f.contains("52")); + assert!(f.contains("60")); assert!(f.contains("29")); } diff --git a/library/coretests/tests/slice.rs b/library/coretests/tests/slice.rs index 992f24cb18f..110c4e5f3b4 100644 --- a/library/coretests/tests/slice.rs +++ b/library/coretests/tests/slice.rs @@ -1492,28 +1492,28 @@ mod slice_index { // note: using 0 specifically ensures that the result of overflowing is 0..0, // so that `get` doesn't simply return None for the wrong reason. bad: data[0 ..= usize::MAX]; - message: "maximum usize"; + message: "out of range"; } in mod rangetoinclusive_overflow { data: [0, 1]; bad: data[..= usize::MAX]; - message: "maximum usize"; + message: "out of range"; } in mod boundpair_overflow_end { data: [0; 1]; bad: data[(Bound::Unbounded, Bound::Included(usize::MAX))]; - message: "maximum usize"; + message: "out of range"; } in mod boundpair_overflow_start { data: [0; 1]; bad: data[(Bound::Excluded(usize::MAX), Bound::Unbounded)]; - message: "maximum usize"; + message: "out of range"; } } // panic_cases! } @@ -2008,7 +2008,7 @@ fn test_copy_within_panics_src_inverted() { bytes.copy_within(2..1, 0); } #[test] -#[should_panic(expected = "attempted to index slice up to maximum usize")] +#[should_panic(expected = "out of range")] fn test_copy_within_panics_src_out_of_bounds() { let mut bytes = *b"Hello, World!"; // an inclusive range ending at usize::MAX would make src_end overflow diff --git a/library/panic_unwind/Cargo.toml b/library/panic_unwind/Cargo.toml index 13d1a7160da..67fc919c42c 100644 --- a/library/panic_unwind/Cargo.toml +++ b/library/panic_unwind/Cargo.toml @@ -13,7 +13,6 @@ doc = false [dependencies] alloc = { path = "../alloc" } -cfg-if = { version = "1.0", features = ['rustc-dep-of-std'] } core = { path = "../rustc-std-workspace-core", package = "rustc-std-workspace-core" } unwind = { path = "../unwind" } diff --git a/library/panic_unwind/src/lib.rs b/library/panic_unwind/src/lib.rs index 50bd933aca2..83311f32380 100644 --- a/library/panic_unwind/src/lib.rs +++ b/library/panic_unwind/src/lib.rs @@ -15,6 +15,7 @@ #![unstable(feature = "panic_unwind", issue = "32837")] #![doc(issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/")] #![feature(cfg_emscripten_wasm_eh)] +#![feature(cfg_select)] #![feature(core_intrinsics)] #![feature(lang_items)] #![feature(panic_unwind)] @@ -33,18 +34,21 @@ use alloc::boxed::Box; use core::any::Any; use core::panic::PanicPayload; -cfg_if::cfg_if! { - if #[cfg(all(target_os = "emscripten", not(emscripten_wasm_eh)))] { +cfg_select! { + all(target_os = "emscripten", not(emscripten_wasm_eh)) => { #[path = "emcc.rs"] mod imp; - } else if #[cfg(target_os = "hermit")] { + } + target_os = "hermit" => { #[path = "hermit.rs"] mod imp; - } else if #[cfg(target_os = "l4re")] { + } + target_os = "l4re" => { // L4Re is unix family but does not yet support unwinding. #[path = "dummy.rs"] mod imp; - } else if #[cfg(any( + } + any( all(target_family = "windows", target_env = "gnu"), target_os = "psp", target_os = "xous", @@ -52,19 +56,22 @@ cfg_if::cfg_if! { all(target_family = "unix", not(any(target_os = "espidf", target_os = "nuttx"))), all(target_vendor = "fortanix", target_env = "sgx"), target_family = "wasm", - ))] { + ) => { #[path = "gcc.rs"] mod imp; - } else if #[cfg(miri)] { + } + miri => { // Use the Miri runtime on Windows as miri doesn't support funclet based unwinding, // only landingpad based unwinding. Also use the Miri runtime on unsupported platforms. #[path = "miri.rs"] mod imp; - } else if #[cfg(all(target_env = "msvc", not(target_arch = "arm")))] { + } + all(target_env = "msvc", not(target_arch = "arm")) => { // LLVM does not support unwinding on 32 bit ARM msvc (thumbv7a-pc-windows-msvc) #[path = "seh.rs"] mod imp; - } else { + } + _ => { // Targets that don't support unwinding. // - os=none ("bare metal" targets) // - os=uefi diff --git a/library/panic_unwind/src/seh.rs b/library/panic_unwind/src/seh.rs index 668e988abff..a5d67dbb6a9 100644 --- a/library/panic_unwind/src/seh.rs +++ b/library/panic_unwind/src/seh.rs @@ -289,10 +289,11 @@ macro_rules! define_cleanup { } } } -cfg_if::cfg_if! { - if #[cfg(target_arch = "x86")] { +cfg_select! { + target_arch = "x86" => { define_cleanup!("thiscall" "thiscall-unwind"); - } else { + } + _ => { define_cleanup!("C" "C-unwind"); } } diff --git a/library/std/src/sync/nonpoison.rs b/library/std/src/sync/nonpoison.rs index 2bbf226dc2c..b3ae376e70d 100644 --- a/library/std/src/sync/nonpoison.rs +++ b/library/std/src/sync/nonpoison.rs @@ -33,5 +33,10 @@ impl fmt::Display for WouldBlock { pub use self::mutex::MappedMutexGuard; #[unstable(feature = "nonpoison_mutex", issue = "134645")] pub use self::mutex::{Mutex, MutexGuard}; +#[unstable(feature = "mapped_lock_guards", issue = "117108")] +pub use self::rwlock::{MappedRwLockReadGuard, MappedRwLockWriteGuard}; +#[unstable(feature = "nonpoison_rwlock", issue = "134645")] +pub use self::rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard}; mod mutex; +mod rwlock; diff --git a/library/std/src/sync/nonpoison/rwlock.rs b/library/std/src/sync/nonpoison/rwlock.rs new file mode 100644 index 00000000000..eb0aef99cc1 --- /dev/null +++ b/library/std/src/sync/nonpoison/rwlock.rs @@ -0,0 +1,1081 @@ +use crate::cell::UnsafeCell; +use crate::fmt; +use crate::marker::PhantomData; +use crate::mem::{self, ManuallyDrop, forget}; +use crate::ops::{Deref, DerefMut}; +use crate::ptr::NonNull; +use crate::sync::nonpoison::{TryLockResult, WouldBlock}; +use crate::sys::sync as sys; + +/// A reader-writer lock that does not keep track of lock poisoning. +/// +/// For more information about reader-writer locks, check out the documentation for the poisoning +/// variant of this lock (which can be found at [`poison::RwLock`]). +/// +/// [`poison::RwLock`]: crate::sync::poison::RwLock +/// +/// # Examples +/// +/// ``` +/// #![feature(nonpoison_rwlock)] +/// +/// use std::sync::nonpoison::RwLock; +/// +/// let lock = RwLock::new(5); +/// +/// // many reader locks can be held at once +/// { +/// let r1 = lock.read(); +/// let r2 = lock.read(); +/// assert_eq!(*r1, 5); +/// assert_eq!(*r2, 5); +/// } // read locks are dropped at this point +/// +/// // only one write lock may be held, however +/// { +/// let mut w = lock.write(); +/// *w += 1; +/// assert_eq!(*w, 6); +/// } // write lock is dropped here +/// ``` +#[unstable(feature = "nonpoison_rwlock", issue = "134645")] +#[cfg_attr(not(test), rustc_diagnostic_item = "NonPoisonRwLock")] +pub struct RwLock<T: ?Sized> { + /// The inner [`sys::RwLock`] that synchronizes thread access to the protected data. + inner: sys::RwLock, + /// The lock-protected data. + data: UnsafeCell<T>, +} + +#[unstable(feature = "nonpoison_rwlock", issue = "134645")] +unsafe impl<T: ?Sized + Send> Send for RwLock<T> {} + +#[unstable(feature = "nonpoison_rwlock", issue = "134645")] +unsafe impl<T: ?Sized + Send + Sync> Sync for RwLock<T> {} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Guards +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/// RAII structure used to release the shared read access of a lock when +/// dropped. +/// +/// This structure is created by the [`read`] and [`try_read`] methods on +/// [`RwLock`]. +/// +/// [`read`]: RwLock::read +/// [`try_read`]: RwLock::try_read +#[must_use = "if unused the RwLock will immediately unlock"] +#[must_not_suspend = "holding a RwLockReadGuard across suspend \ + points can cause deadlocks, delays, \ + and cause Futures to not implement `Send`"] +#[unstable(feature = "nonpoison_rwlock", issue = "134645")] +#[clippy::has_significant_drop] +#[cfg_attr(not(test), rustc_diagnostic_item = "NonPoisonRwLockReadGuard")] +pub struct RwLockReadGuard<'rwlock, T: ?Sized + 'rwlock> { + /// A pointer to the data protected by the `RwLock`. Note that we use a pointer here instead of + /// `&'rwlock T` to avoid `noalias` violations, because a `RwLockReadGuard` instance only holds + /// immutability until it drops, not for its whole scope. + /// `NonNull` is preferable over `*const T` to allow for niche optimizations. `NonNull` is also + /// covariant over `T`, just like we would have with `&T`. + data: NonNull<T>, + /// A reference to the internal [`sys::RwLock`] that we have read-locked. + inner_lock: &'rwlock sys::RwLock, +} + +#[unstable(feature = "nonpoison_rwlock", issue = "134645")] +impl<T: ?Sized> !Send for RwLockReadGuard<'_, T> {} + +#[unstable(feature = "nonpoison_rwlock", issue = "134645")] +unsafe impl<T: ?Sized + Sync> Sync for RwLockReadGuard<'_, T> {} + +/// RAII structure used to release the exclusive write access of a lock when +/// dropped. +/// +/// This structure is created by the [`write`] and [`try_write`] methods +/// on [`RwLock`]. +/// +/// [`write`]: RwLock::write +/// [`try_write`]: RwLock::try_write +#[must_use = "if unused the RwLock will immediately unlock"] +#[must_not_suspend = "holding a RwLockWriteGuard across suspend \ + points can cause deadlocks, delays, \ + and cause Future's to not implement `Send`"] +#[unstable(feature = "nonpoison_rwlock", issue = "134645")] +#[clippy::has_significant_drop] +#[cfg_attr(not(test), rustc_diagnostic_item = "NonPoisonRwLockWriteGuard")] +pub struct RwLockWriteGuard<'rwlock, T: ?Sized + 'rwlock> { + /// A reference to the [`RwLock`] that we have write-locked. + lock: &'rwlock RwLock<T>, +} + +#[unstable(feature = "nonpoison_rwlock", issue = "134645")] +impl<T: ?Sized> !Send for RwLockWriteGuard<'_, T> {} + +#[unstable(feature = "nonpoison_rwlock", issue = "134645")] +unsafe impl<T: ?Sized + Sync> Sync for RwLockWriteGuard<'_, T> {} + +/// RAII structure used to release the shared read access of a lock when +/// dropped, which can point to a subfield of the protected data. +/// +/// This structure is created by the [`map`] and [`filter_map`] methods +/// on [`RwLockReadGuard`]. +/// +/// [`map`]: RwLockReadGuard::map +/// [`filter_map`]: RwLockReadGuard::filter_map +#[must_use = "if unused the RwLock will immediately unlock"] +#[must_not_suspend = "holding a MappedRwLockReadGuard across suspend \ + points can cause deadlocks, delays, \ + and cause Futures to not implement `Send`"] +#[unstable(feature = "mapped_lock_guards", issue = "117108")] +// #[unstable(feature = "nonpoison_rwlock", issue = "134645")] +#[clippy::has_significant_drop] +pub struct MappedRwLockReadGuard<'rwlock, T: ?Sized + 'rwlock> { + /// A pointer to the data protected by the `RwLock`. Note that we use a pointer here instead of + /// `&'rwlock T` to avoid `noalias` violations, because a `MappedRwLockReadGuard` instance only + /// holds immutability until it drops, not for its whole scope. + /// `NonNull` is preferable over `*const T` to allow for niche optimizations. `NonNull` is also + /// covariant over `T`, just like we would have with `&T`. + data: NonNull<T>, + /// A reference to the internal [`sys::RwLock`] that we have read-locked. + inner_lock: &'rwlock sys::RwLock, +} + +#[unstable(feature = "mapped_lock_guards", issue = "117108")] +// #[unstable(feature = "nonpoison_rwlock", issue = "134645")] +impl<T: ?Sized> !Send for MappedRwLockReadGuard<'_, T> {} + +#[unstable(feature = "mapped_lock_guards", issue = "117108")] +// #[unstable(feature = "nonpoison_rwlock", issue = "134645")] +unsafe impl<T: ?Sized + Sync> Sync for MappedRwLockReadGuard<'_, T> {} + +/// RAII structure used to release the exclusive write access of a lock when +/// dropped, which can point to a subfield of the protected data. +/// +/// This structure is created by the [`map`] and [`filter_map`] methods +/// on [`RwLockWriteGuard`]. +/// +/// [`map`]: RwLockWriteGuard::map +/// [`filter_map`]: RwLockWriteGuard::filter_map +#[must_use = "if unused the RwLock will immediately unlock"] +#[must_not_suspend = "holding a MappedRwLockWriteGuard across suspend \ + points can cause deadlocks, delays, \ + and cause Future's to not implement `Send`"] +#[unstable(feature = "mapped_lock_guards", issue = "117108")] +// #[unstable(feature = "nonpoison_rwlock", issue = "134645")] +#[clippy::has_significant_drop] +pub struct MappedRwLockWriteGuard<'rwlock, T: ?Sized + 'rwlock> { + /// A pointer to the data protected by the `RwLock`. Note that we use a pointer here instead of + /// `&'rwlock T` to avoid `noalias` violations, because a `MappedRwLockWriteGuard` instance only + /// holds uniquneness until it drops, not for its whole scope. + /// `NonNull` is preferable over `*const T` to allow for niche optimizations. + data: NonNull<T>, + /// `NonNull` is covariant over `T`, so we add a `PhantomData<&'rwlock mut T>` field here to + /// enforce the correct invariance over `T`. + _variance: PhantomData<&'rwlock mut T>, + /// A reference to the internal [`sys::RwLock`] that we have write-locked. + inner_lock: &'rwlock sys::RwLock, +} + +#[unstable(feature = "mapped_lock_guards", issue = "117108")] +// #[unstable(feature = "nonpoison_rwlock", issue = "134645")] +impl<T: ?Sized> !Send for MappedRwLockWriteGuard<'_, T> {} + +#[unstable(feature = "mapped_lock_guards", issue = "117108")] +// #[unstable(feature = "nonpoison_rwlock", issue = "134645")] +unsafe impl<T: ?Sized + Sync> Sync for MappedRwLockWriteGuard<'_, T> {} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Implementations +//////////////////////////////////////////////////////////////////////////////////////////////////// + +impl<T> RwLock<T> { + /// Creates a new instance of an `RwLock<T>` which is unlocked. + /// + /// # Examples + /// + /// ``` + /// #![feature(nonpoison_rwlock)] + /// + /// use std::sync::nonpoison::RwLock; + /// + /// let lock = RwLock::new(5); + /// ``` + #[unstable(feature = "nonpoison_rwlock", issue = "134645")] + #[inline] + pub const fn new(t: T) -> RwLock<T> { + RwLock { inner: sys::RwLock::new(), data: UnsafeCell::new(t) } + } + + /// Returns the contained value by cloning it. + /// + /// # Examples + /// + /// ``` + /// #![feature(nonpoison_rwlock)] + /// #![feature(lock_value_accessors)] + /// + /// use std::sync::nonpoison::RwLock; + /// + /// let mut lock = RwLock::new(7); + /// + /// assert_eq!(lock.get_cloned(), 7); + /// ``` + #[unstable(feature = "lock_value_accessors", issue = "133407")] + // #[unstable(feature = "nonpoison_rwlock", issue = "134645")] + pub fn get_cloned(&self) -> T + where + T: Clone, + { + self.read().clone() + } + + /// Sets the contained value. + /// + /// # Examples + /// + /// ``` + /// #![feature(nonpoison_rwlock)] + /// #![feature(lock_value_accessors)] + /// + /// use std::sync::nonpoison::RwLock; + /// + /// let mut lock = RwLock::new(7); + /// + /// assert_eq!(lock.get_cloned(), 7); + /// lock.set(11); + /// assert_eq!(lock.get_cloned(), 11); + /// ``` + #[unstable(feature = "lock_value_accessors", issue = "133407")] + // #[unstable(feature = "nonpoison_rwlock", issue = "134645")] + pub fn set(&self, value: T) { + if mem::needs_drop::<T>() { + // If the contained value has a non-trivial destructor, we + // call that destructor after the lock has been released. + drop(self.replace(value)) + } else { + *self.write() = value; + } + } + + /// Replaces the contained value with `value`, and returns the old contained value. + /// + /// # Examples + /// + /// ``` + /// #![feature(nonpoison_rwlock)] + /// #![feature(lock_value_accessors)] + /// + /// use std::sync::nonpoison::RwLock; + /// + /// let mut lock = RwLock::new(7); + /// + /// assert_eq!(lock.replace(11), 7); + /// assert_eq!(lock.get_cloned(), 11); + /// ``` + #[unstable(feature = "lock_value_accessors", issue = "133407")] + // #[unstable(feature = "nonpoison_rwlock", issue = "134645")] + pub fn replace(&self, value: T) -> T { + let mut guard = self.write(); + mem::replace(&mut *guard, value) + } +} + +impl<T: ?Sized> RwLock<T> { + /// Locks this `RwLock` with shared read access, blocking the current thread + /// until it can be acquired. + /// + /// The calling thread will be blocked until there are no more writers which + /// hold the lock. There may be other readers currently inside the lock when + /// this method returns. This method does not provide any guarantees with + /// respect to the ordering of whether contentious readers or writers will + /// acquire the lock first. + /// + /// Returns an RAII guard which will release this thread's shared access + /// once it is dropped. + /// + /// # Panics + /// + /// This function might panic when called if the lock is already held by the current thread. + /// + /// # Examples + /// + /// ``` + /// #![feature(nonpoison_rwlock)] + /// + /// use std::sync::Arc; + /// use std::sync::nonpoison::RwLock; + /// use std::thread; + /// + /// let lock = Arc::new(RwLock::new(1)); + /// let c_lock = Arc::clone(&lock); + /// + /// let n = lock.read(); + /// assert_eq!(*n, 1); + /// + /// thread::spawn(move || { + /// let r = c_lock.read(); + /// }).join().unwrap(); + /// ``` + #[inline] + #[unstable(feature = "nonpoison_rwlock", issue = "134645")] + pub fn read(&self) -> RwLockReadGuard<'_, T> { + unsafe { + self.inner.read(); + RwLockReadGuard::new(self) + } + } + + /// Attempts to acquire this `RwLock` with shared read access. + /// + /// If the access could not be granted at this time, then `Err` is returned. + /// Otherwise, an RAII guard is returned which will release the shared access + /// when it is dropped. + /// + /// This function does not block. + /// + /// This function does not provide any guarantees with respect to the ordering + /// of whether contentious readers or writers will acquire the lock first. + /// + /// # Errors + /// + /// This function will return the [`WouldBlock`] error if the `RwLock` could + /// not be acquired because it was already locked exclusively. + /// + /// # Examples + /// + /// ``` + /// #![feature(nonpoison_rwlock)] + /// + /// use std::sync::nonpoison::RwLock; + /// + /// let lock = RwLock::new(1); + /// + /// match lock.try_read() { + /// Ok(n) => assert_eq!(*n, 1), + /// Err(_) => unreachable!(), + /// }; + /// ``` + #[inline] + #[unstable(feature = "nonpoison_rwlock", issue = "134645")] + pub fn try_read(&self) -> TryLockResult<RwLockReadGuard<'_, T>> { + unsafe { + if self.inner.try_read() { Ok(RwLockReadGuard::new(self)) } else { Err(WouldBlock) } + } + } + + /// Locks this `RwLock` with exclusive write access, blocking the current + /// thread until it can be acquired. + /// + /// This function will not return while other writers or other readers + /// currently have access to the lock. + /// + /// Returns an RAII guard which will drop the write access of this `RwLock` + /// when dropped. + /// + /// # Panics + /// + /// This function might panic when called if the lock is already held by the current thread. + /// + /// # Examples + /// + /// ``` + /// #![feature(nonpoison_rwlock)] + /// + /// use std::sync::nonpoison::RwLock; + /// + /// let lock = RwLock::new(1); + /// + /// let mut n = lock.write(); + /// *n = 2; + /// + /// assert!(lock.try_read().is_err()); + /// ``` + #[inline] + #[unstable(feature = "nonpoison_rwlock", issue = "134645")] + pub fn write(&self) -> RwLockWriteGuard<'_, T> { + unsafe { + self.inner.write(); + RwLockWriteGuard::new(self) + } + } + + /// Attempts to lock this `RwLock` with exclusive write access. + /// + /// If the lock could not be acquired at this time, then `Err` is returned. + /// Otherwise, an RAII guard is returned which will release the lock when + /// it is dropped. + /// + /// This function does not block. + /// + /// This function does not provide any guarantees with respect to the ordering + /// of whether contentious readers or writers will acquire the lock first. + /// + /// # Errors + /// + /// This function will return the [`WouldBlock`] error if the `RwLock` could + /// not be acquired because it was already locked. + /// + /// [`WouldBlock`]: WouldBlock + /// + /// # Examples + /// + /// ``` + /// #![feature(nonpoison_rwlock)] + /// + /// use std::sync::nonpoison::RwLock; + /// + /// let lock = RwLock::new(1); + /// + /// let n = lock.read(); + /// assert_eq!(*n, 1); + /// + /// assert!(lock.try_write().is_err()); + /// ``` + #[inline] + #[unstable(feature = "nonpoison_rwlock", issue = "134645")] + pub fn try_write(&self) -> TryLockResult<RwLockWriteGuard<'_, T>> { + unsafe { + if self.inner.try_write() { Ok(RwLockWriteGuard::new(self)) } else { Err(WouldBlock) } + } + } + + /// Consumes this `RwLock`, returning the underlying data. + /// + /// # Examples + /// + /// ``` + /// #![feature(nonpoison_rwlock)] + /// + /// use std::sync::nonpoison::RwLock; + /// + /// let lock = RwLock::new(String::new()); + /// { + /// let mut s = lock.write(); + /// *s = "modified".to_owned(); + /// } + /// assert_eq!(lock.into_inner(), "modified"); + /// ``` + #[unstable(feature = "nonpoison_rwlock", issue = "134645")] + pub fn into_inner(self) -> T + where + T: Sized, + { + self.data.into_inner() + } + + /// Returns a mutable reference to the underlying data. + /// + /// Since this call borrows the `RwLock` mutably, no actual locking needs to + /// take place -- the mutable borrow statically guarantees no new locks can be acquired + /// while this reference exists. Note that this method does not clear any previously abandoned + /// locks (e.g., via [`forget()`] on a [`RwLockReadGuard`] or [`RwLockWriteGuard`]). + /// + /// # Examples + /// + /// ``` + /// #![feature(nonpoison_rwlock)] + /// + /// use std::sync::nonpoison::RwLock; + /// + /// let mut lock = RwLock::new(0); + /// *lock.get_mut() = 10; + /// assert_eq!(*lock.read(), 10); + /// ``` + #[unstable(feature = "nonpoison_rwlock", issue = "134645")] + pub fn get_mut(&mut self) -> &mut T { + self.data.get_mut() + } + + /// Returns a raw pointer to the underlying data. + /// + /// The returned pointer is always non-null and properly aligned, but it is + /// the user's responsibility to ensure that any reads and writes through it + /// are properly synchronized to avoid data races, and that it is not read + /// or written through after the lock is dropped. + #[unstable(feature = "rwlock_data_ptr", issue = "140368")] + // #[unstable(feature = "nonpoison_rwlock", issue = "134645")] + pub fn data_ptr(&self) -> *mut T { + self.data.get() + } +} + +#[unstable(feature = "nonpoison_rwlock", issue = "134645")] +impl<T: ?Sized + fmt::Debug> fmt::Debug for RwLock<T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut d = f.debug_struct("RwLock"); + match self.try_read() { + Ok(guard) => { + d.field("data", &&*guard); + } + Err(WouldBlock) => { + d.field("data", &format_args!("<locked>")); + } + } + d.finish_non_exhaustive() + } +} + +#[unstable(feature = "nonpoison_rwlock", issue = "134645")] +impl<T: Default> Default for RwLock<T> { + /// Creates a new `RwLock<T>`, with the `Default` value for T. + fn default() -> RwLock<T> { + RwLock::new(Default::default()) + } +} + +#[unstable(feature = "nonpoison_rwlock", issue = "134645")] +impl<T> From<T> for RwLock<T> { + /// Creates a new instance of an `RwLock<T>` which is unlocked. + /// This is equivalent to [`RwLock::new`]. + fn from(t: T) -> Self { + RwLock::new(t) + } +} + +impl<'rwlock, T: ?Sized> RwLockReadGuard<'rwlock, T> { + /// Creates a new instance of `RwLockReadGuard<T>` from a `RwLock<T>`. + /// + /// # Safety + /// + /// This function is safe if and only if the same thread has successfully and safely called + /// `lock.inner.read()`, `lock.inner.try_read()`, or `lock.inner.downgrade()` before + /// instantiating this object. + unsafe fn new(lock: &'rwlock RwLock<T>) -> RwLockReadGuard<'rwlock, T> { + RwLockReadGuard { + data: unsafe { NonNull::new_unchecked(lock.data.get()) }, + inner_lock: &lock.inner, + } + } + + /// Makes a [`MappedRwLockReadGuard`] for a component of the borrowed data, e.g. + /// an enum variant. + /// + /// The `RwLock` is already locked for reading, so this cannot fail. + /// + /// This is an associated function that needs to be used as + /// `RwLockReadGuard::map(...)`. A method would interfere with methods of + /// the same name on the contents of the `RwLockReadGuard` used through + /// `Deref`. + /// + /// # Panics + /// + /// If the closure panics, the guard will be dropped (unlocked). + #[unstable(feature = "mapped_lock_guards", issue = "117108")] + // #[unstable(feature = "nonpoison_rwlock", issue = "134645")] + pub fn map<U, F>(orig: Self, f: F) -> MappedRwLockReadGuard<'rwlock, U> + where + F: FnOnce(&T) -> &U, + U: ?Sized, + { + // SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when the original guard + // was created, and have been upheld throughout `map` and/or `filter_map`. + // The signature of the closure guarantees that it will not "leak" the lifetime of the + // reference passed to it. If the closure panics, the guard will be dropped. + let data = NonNull::from(f(unsafe { orig.data.as_ref() })); + let orig = ManuallyDrop::new(orig); + MappedRwLockReadGuard { data, inner_lock: &orig.inner_lock } + } + + /// Makes a [`MappedRwLockReadGuard`] for a component of the borrowed data. The + /// original guard is returned as an `Err(...)` if the closure returns + /// `None`. + /// + /// The `RwLock` is already locked for reading, so this cannot fail. + /// + /// This is an associated function that needs to be used as + /// `RwLockReadGuard::filter_map(...)`. A method would interfere with methods + /// of the same name on the contents of the `RwLockReadGuard` used through + /// `Deref`. + /// + /// # Panics + /// + /// If the closure panics, the guard will be dropped (unlocked). + #[unstable(feature = "mapped_lock_guards", issue = "117108")] + // #[unstable(feature = "nonpoison_rwlock", issue = "134645")] + pub fn filter_map<U, F>(orig: Self, f: F) -> Result<MappedRwLockReadGuard<'rwlock, U>, Self> + where + F: FnOnce(&T) -> Option<&U>, + U: ?Sized, + { + // SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when the original guard + // was created, and have been upheld throughout `map` and/or `filter_map`. + // The signature of the closure guarantees that it will not "leak" the lifetime of the + // reference passed to it. If the closure panics, the guard will be dropped. + match f(unsafe { orig.data.as_ref() }) { + Some(data) => { + let data = NonNull::from(data); + let orig = ManuallyDrop::new(orig); + Ok(MappedRwLockReadGuard { data, inner_lock: &orig.inner_lock }) + } + None => Err(orig), + } + } +} + +impl<'rwlock, T: ?Sized> RwLockWriteGuard<'rwlock, T> { + /// Creates a new instance of `RwLockWriteGuard<T>` from a `RwLock<T>`. + /// + /// # Safety + /// + /// This function is safe if and only if the same thread has successfully and safely called + /// `lock.inner.write()`, `lock.inner.try_write()`, or `lock.inner.try_upgrade` before + /// instantiating this object. + unsafe fn new(lock: &'rwlock RwLock<T>) -> RwLockWriteGuard<'rwlock, T> { + RwLockWriteGuard { lock } + } + + /// Downgrades a write-locked `RwLockWriteGuard` into a read-locked [`RwLockReadGuard`]. + /// + /// Since we have the `RwLockWriteGuard`, the [`RwLock`] must already be locked for writing, so + /// this method cannot fail. + /// + /// After downgrading, other readers will be allowed to read the protected data. + /// + /// # Examples + /// + /// `downgrade` takes ownership of the `RwLockWriteGuard` and returns a [`RwLockReadGuard`]. + /// + /// ``` + /// #![feature(nonpoison_rwlock)] + /// #![feature(rwlock_downgrade)] + /// + /// use std::sync::nonpoison::{RwLock, RwLockWriteGuard}; + /// + /// let rw = RwLock::new(0); + /// + /// let mut write_guard = rw.write(); + /// *write_guard = 42; + /// + /// let read_guard = RwLockWriteGuard::downgrade(write_guard); + /// assert_eq!(42, *read_guard); + /// ``` + /// + /// `downgrade` will _atomically_ change the state of the [`RwLock`] from exclusive mode into + /// shared mode. This means that it is impossible for another writing thread to get in between a + /// thread calling `downgrade` and any reads it performs after downgrading. + /// + /// ``` + /// #![feature(nonpoison_rwlock)] + /// #![feature(rwlock_downgrade)] + /// + /// use std::sync::Arc; + /// use std::sync::nonpoison::{RwLock, RwLockWriteGuard}; + /// + /// let rw = Arc::new(RwLock::new(1)); + /// + /// // Put the lock in write mode. + /// let mut main_write_guard = rw.write(); + /// + /// let rw_clone = rw.clone(); + /// let evil_handle = std::thread::spawn(move || { + /// // This will not return until the main thread drops the `main_read_guard`. + /// let mut evil_guard = rw_clone.write(); + /// + /// assert_eq!(*evil_guard, 2); + /// *evil_guard = 3; + /// }); + /// + /// *main_write_guard = 2; + /// + /// // Atomically downgrade the write guard into a read guard. + /// let main_read_guard = RwLockWriteGuard::downgrade(main_write_guard); + /// + /// // Since `downgrade` is atomic, the writer thread cannot have changed the protected data. + /// assert_eq!(*main_read_guard, 2, "`downgrade` was not atomic"); + /// # + /// # drop(main_read_guard); + /// # evil_handle.join().unwrap(); + /// # + /// # let final_check = rw.read(); + /// # assert_eq!(*final_check, 3); + /// ``` + #[unstable(feature = "rwlock_downgrade", issue = "128203")] + // #[unstable(feature = "nonpoison_rwlock", issue = "134645")] + pub fn downgrade(s: Self) -> RwLockReadGuard<'rwlock, T> { + let lock = s.lock; + + // We don't want to call the destructor since that calls `write_unlock`. + forget(s); + + // SAFETY: We take ownership of a write guard, so we must already have the `RwLock` in write + // mode, satisfying the `downgrade` contract. + unsafe { lock.inner.downgrade() }; + + // SAFETY: We have just successfully called `downgrade`, so we fulfill the safety contract. + unsafe { RwLockReadGuard::new(lock) } + } + + /// Makes a [`MappedRwLockWriteGuard`] for a component of the borrowed data, e.g. + /// an enum variant. + /// + /// The `RwLock` is already locked for writing, so this cannot fail. + /// + /// This is an associated function that needs to be used as + /// `RwLockWriteGuard::map(...)`. A method would interfere with methods of + /// the same name on the contents of the `RwLockWriteGuard` used through + /// `Deref`. + /// + /// # Panics + /// + /// If the closure panics, the guard will be dropped (unlocked). + #[unstable(feature = "mapped_lock_guards", issue = "117108")] + // #[unstable(feature = "nonpoison_rwlock", issue = "134645")] + pub fn map<U, F>(orig: Self, f: F) -> MappedRwLockWriteGuard<'rwlock, U> + where + F: FnOnce(&mut T) -> &mut U, + U: ?Sized, + { + // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when the original guard + // was created, and have been upheld throughout `map` and/or `filter_map`. + // The signature of the closure guarantees that it will not "leak" the lifetime of the + // reference passed to it. If the closure panics, the guard will be dropped. + let data = NonNull::from(f(unsafe { &mut *orig.lock.data.get() })); + let orig = ManuallyDrop::new(orig); + MappedRwLockWriteGuard { data, inner_lock: &orig.lock.inner, _variance: PhantomData } + } + + /// Makes a [`MappedRwLockWriteGuard`] for a component of the borrowed data. The + /// original guard is returned as an `Err(...)` if the closure returns + /// `None`. + /// + /// The `RwLock` is already locked for writing, so this cannot fail. + /// + /// This is an associated function that needs to be used as + /// `RwLockWriteGuard::filter_map(...)`. A method would interfere with methods + /// of the same name on the contents of the `RwLockWriteGuard` used through + /// `Deref`. + /// + /// # Panics + /// + /// If the closure panics, the guard will be dropped (unlocked). + #[unstable(feature = "mapped_lock_guards", issue = "117108")] + // #[unstable(feature = "nonpoison_rwlock", issue = "134645")] + pub fn filter_map<U, F>(orig: Self, f: F) -> Result<MappedRwLockWriteGuard<'rwlock, U>, Self> + where + F: FnOnce(&mut T) -> Option<&mut U>, + U: ?Sized, + { + // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when the original guard + // was created, and have been upheld throughout `map` and/or `filter_map`. + // The signature of the closure guarantees that it will not "leak" the lifetime of the + // reference passed to it. If the closure panics, the guard will be dropped. + match f(unsafe { &mut *orig.lock.data.get() }) { + Some(data) => { + let data = NonNull::from(data); + let orig = ManuallyDrop::new(orig); + Ok(MappedRwLockWriteGuard { + data, + inner_lock: &orig.lock.inner, + _variance: PhantomData, + }) + } + None => Err(orig), + } + } +} + +impl<'rwlock, T: ?Sized> MappedRwLockReadGuard<'rwlock, T> { + /// Makes a [`MappedRwLockReadGuard`] for a component of the borrowed data, + /// e.g. an enum variant. + /// + /// The `RwLock` is already locked for reading, so this cannot fail. + /// + /// This is an associated function that needs to be used as + /// `MappedRwLockReadGuard::map(...)`. A method would interfere with + /// methods of the same name on the contents of the `MappedRwLockReadGuard` + /// used through `Deref`. + /// + /// # Panics + /// + /// If the closure panics, the guard will be dropped (unlocked). + #[unstable(feature = "mapped_lock_guards", issue = "117108")] + // #[unstable(feature = "nonpoison_rwlock", issue = "134645")] + pub fn map<U, F>(orig: Self, f: F) -> MappedRwLockReadGuard<'rwlock, U> + where + F: FnOnce(&T) -> &U, + U: ?Sized, + { + // SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when the original guard + // was created, and have been upheld throughout `map` and/or `filter_map`. + // The signature of the closure guarantees that it will not "leak" the lifetime of the + // reference passed to it. If the closure panics, the guard will be dropped. + let data = NonNull::from(f(unsafe { orig.data.as_ref() })); + let orig = ManuallyDrop::new(orig); + MappedRwLockReadGuard { data, inner_lock: &orig.inner_lock } + } + + /// Makes a [`MappedRwLockReadGuard`] for a component of the borrowed data. + /// The original guard is returned as an `Err(...)` if the closure returns + /// `None`. + /// + /// The `RwLock` is already locked for reading, so this cannot fail. + /// + /// This is an associated function that needs to be used as + /// `MappedRwLockReadGuard::filter_map(...)`. A method would interfere with + /// methods of the same name on the contents of the `MappedRwLockReadGuard` + /// used through `Deref`. + /// + /// # Panics + /// + /// If the closure panics, the guard will be dropped (unlocked). + #[unstable(feature = "mapped_lock_guards", issue = "117108")] + // #[unstable(feature = "nonpoison_rwlock", issue = "134645")] + pub fn filter_map<U, F>(orig: Self, f: F) -> Result<MappedRwLockReadGuard<'rwlock, U>, Self> + where + F: FnOnce(&T) -> Option<&U>, + U: ?Sized, + { + // SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when the original guard + // was created, and have been upheld throughout `map` and/or `filter_map`. + // The signature of the closure guarantees that it will not "leak" the lifetime of the + // reference passed to it. If the closure panics, the guard will be dropped. + match f(unsafe { orig.data.as_ref() }) { + Some(data) => { + let data = NonNull::from(data); + let orig = ManuallyDrop::new(orig); + Ok(MappedRwLockReadGuard { data, inner_lock: &orig.inner_lock }) + } + None => Err(orig), + } + } +} + +impl<'rwlock, T: ?Sized> MappedRwLockWriteGuard<'rwlock, T> { + /// Makes a [`MappedRwLockWriteGuard`] for a component of the borrowed data, + /// e.g. an enum variant. + /// + /// The `RwLock` is already locked for writing, so this cannot fail. + /// + /// This is an associated function that needs to be used as + /// `MappedRwLockWriteGuard::map(...)`. A method would interfere with + /// methods of the same name on the contents of the `MappedRwLockWriteGuard` + /// used through `Deref`. + /// + /// # Panics + /// + /// If the closure panics, the guard will be dropped (unlocked). + #[unstable(feature = "mapped_lock_guards", issue = "117108")] + // #[unstable(feature = "nonpoison_rwlock", issue = "134645")] + pub fn map<U, F>(mut orig: Self, f: F) -> MappedRwLockWriteGuard<'rwlock, U> + where + F: FnOnce(&mut T) -> &mut U, + U: ?Sized, + { + // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when the original guard + // was created, and have been upheld throughout `map` and/or `filter_map`. + // The signature of the closure guarantees that it will not "leak" the lifetime of the + // reference passed to it. If the closure panics, the guard will be dropped. + let data = NonNull::from(f(unsafe { orig.data.as_mut() })); + let orig = ManuallyDrop::new(orig); + MappedRwLockWriteGuard { data, inner_lock: orig.inner_lock, _variance: PhantomData } + } + + /// Makes a [`MappedRwLockWriteGuard`] for a component of the borrowed data. + /// The original guard is returned as an `Err(...)` if the closure returns + /// `None`. + /// + /// The `RwLock` is already locked for writing, so this cannot fail. + /// + /// This is an associated function that needs to be used as + /// `MappedRwLockWriteGuard::filter_map(...)`. A method would interfere with + /// methods of the same name on the contents of the `MappedRwLockWriteGuard` + /// used through `Deref`. + /// + /// # Panics + /// + /// If the closure panics, the guard will be dropped (unlocked). + #[unstable(feature = "mapped_lock_guards", issue = "117108")] + // #[unstable(feature = "nonpoison_rwlock", issue = "134645")] + pub fn filter_map<U, F>( + mut orig: Self, + f: F, + ) -> Result<MappedRwLockWriteGuard<'rwlock, U>, Self> + where + F: FnOnce(&mut T) -> Option<&mut U>, + U: ?Sized, + { + // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when the original guard + // was created, and have been upheld throughout `map` and/or `filter_map`. + // The signature of the closure guarantees that it will not "leak" the lifetime of the + // reference passed to it. If the closure panics, the guard will be dropped. + match f(unsafe { orig.data.as_mut() }) { + Some(data) => { + let data = NonNull::from(data); + let orig = ManuallyDrop::new(orig); + Ok(MappedRwLockWriteGuard { + data, + inner_lock: orig.inner_lock, + _variance: PhantomData, + }) + } + None => Err(orig), + } + } +} + +#[unstable(feature = "nonpoison_rwlock", issue = "134645")] +impl<T: ?Sized> Drop for RwLockReadGuard<'_, T> { + fn drop(&mut self) { + // SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when created. + unsafe { + self.inner_lock.read_unlock(); + } + } +} + +#[unstable(feature = "nonpoison_rwlock", issue = "134645")] +impl<T: ?Sized> Drop for RwLockWriteGuard<'_, T> { + fn drop(&mut self) { + // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when created. + unsafe { + self.lock.inner.write_unlock(); + } + } +} + +#[unstable(feature = "mapped_lock_guards", issue = "117108")] +// #[unstable(feature = "nonpoison_rwlock", issue = "134645")] +impl<T: ?Sized> Drop for MappedRwLockReadGuard<'_, T> { + fn drop(&mut self) { + // SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when the original guard + // was created, and have been upheld throughout `map` and/or `filter_map`. + unsafe { + self.inner_lock.read_unlock(); + } + } +} + +#[unstable(feature = "mapped_lock_guards", issue = "117108")] +// #[unstable(feature = "nonpoison_rwlock", issue = "134645")] +impl<T: ?Sized> Drop for MappedRwLockWriteGuard<'_, T> { + fn drop(&mut self) { + // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when the original guard + // was created, and have been upheld throughout `map` and/or `filter_map`. + unsafe { + self.inner_lock.write_unlock(); + } + } +} + +#[unstable(feature = "nonpoison_rwlock", issue = "134645")] +impl<T: ?Sized> Deref for RwLockReadGuard<'_, T> { + type Target = T; + + fn deref(&self) -> &T { + // SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when created. + unsafe { self.data.as_ref() } + } +} + +#[unstable(feature = "nonpoison_rwlock", issue = "134645")] +impl<T: ?Sized> Deref for RwLockWriteGuard<'_, T> { + type Target = T; + + fn deref(&self) -> &T { + // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when created. + unsafe { &*self.lock.data.get() } + } +} + +#[unstable(feature = "nonpoison_rwlock", issue = "134645")] +impl<T: ?Sized> DerefMut for RwLockWriteGuard<'_, T> { + fn deref_mut(&mut self) -> &mut T { + // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when created. + unsafe { &mut *self.lock.data.get() } + } +} + +#[unstable(feature = "mapped_lock_guards", issue = "117108")] +// #[unstable(feature = "nonpoison_rwlock", issue = "134645")] +impl<T: ?Sized> Deref for MappedRwLockReadGuard<'_, T> { + type Target = T; + + fn deref(&self) -> &T { + // SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when the original guard + // was created, and have been upheld throughout `map` and/or `filter_map`. + unsafe { self.data.as_ref() } + } +} + +#[unstable(feature = "mapped_lock_guards", issue = "117108")] +// #[unstable(feature = "nonpoison_rwlock", issue = "134645")] +impl<T: ?Sized> Deref for MappedRwLockWriteGuard<'_, T> { + type Target = T; + + fn deref(&self) -> &T { + // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when the original guard + // was created, and have been upheld throughout `map` and/or `filter_map`. + unsafe { self.data.as_ref() } + } +} + +#[unstable(feature = "mapped_lock_guards", issue = "117108")] +// #[unstable(feature = "nonpoison_rwlock", issue = "134645")] +impl<T: ?Sized> DerefMut for MappedRwLockWriteGuard<'_, T> { + fn deref_mut(&mut self) -> &mut T { + // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when the original guard + // was created, and have been upheld throughout `map` and/or `filter_map`. + unsafe { self.data.as_mut() } + } +} + +#[unstable(feature = "nonpoison_rwlock", issue = "134645")] +impl<T: ?Sized + fmt::Debug> fmt::Debug for RwLockReadGuard<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (**self).fmt(f) + } +} + +#[unstable(feature = "nonpoison_rwlock", issue = "134645")] +impl<T: ?Sized + fmt::Display> fmt::Display for RwLockReadGuard<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (**self).fmt(f) + } +} + +#[unstable(feature = "nonpoison_rwlock", issue = "134645")] +impl<T: ?Sized + fmt::Debug> fmt::Debug for RwLockWriteGuard<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (**self).fmt(f) + } +} + +#[unstable(feature = "nonpoison_rwlock", issue = "134645")] +impl<T: ?Sized + fmt::Display> fmt::Display for RwLockWriteGuard<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (**self).fmt(f) + } +} + +#[unstable(feature = "mapped_lock_guards", issue = "117108")] +// #[unstable(feature = "nonpoison_rwlock", issue = "134645")] +impl<T: ?Sized + fmt::Debug> fmt::Debug for MappedRwLockReadGuard<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (**self).fmt(f) + } +} + +#[unstable(feature = "mapped_lock_guards", issue = "117108")] +// #[unstable(feature = "nonpoison_rwlock", issue = "134645")] +impl<T: ?Sized + fmt::Display> fmt::Display for MappedRwLockReadGuard<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (**self).fmt(f) + } +} + +#[unstable(feature = "mapped_lock_guards", issue = "117108")] +// #[unstable(feature = "nonpoison_rwlock", issue = "134645")] +impl<T: ?Sized + fmt::Debug> fmt::Debug for MappedRwLockWriteGuard<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (**self).fmt(f) + } +} + +#[unstable(feature = "mapped_lock_guards", issue = "117108")] +// #[unstable(feature = "nonpoison_rwlock", issue = "134645")] +impl<T: ?Sized + fmt::Display> fmt::Display for MappedRwLockWriteGuard<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (**self).fmt(f) + } +} diff --git a/library/std/src/sync/poison/rwlock.rs b/library/std/src/sync/poison/rwlock.rs index 2c92602bc87..0a463f3f9c7 100644 --- a/library/std/src/sync/poison/rwlock.rs +++ b/library/std/src/sync/poison/rwlock.rs @@ -80,16 +80,24 @@ use crate::sys::sync as sys; #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "RwLock")] pub struct RwLock<T: ?Sized> { + /// The inner [`sys::RwLock`] that synchronizes thread access to the protected data. inner: sys::RwLock, + /// A flag denoting if this `RwLock` has been poisoned. poison: poison::Flag, + /// The lock-protected data. data: UnsafeCell<T>, } #[stable(feature = "rust1", since = "1.0.0")] unsafe impl<T: ?Sized + Send> Send for RwLock<T> {} + #[stable(feature = "rust1", since = "1.0.0")] unsafe impl<T: ?Sized + Send + Sync> Sync for RwLock<T> {} +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Guards +//////////////////////////////////////////////////////////////////////////////////////////////////// + /// RAII structure used to release the shared read access of a lock when /// dropped. /// @@ -105,13 +113,15 @@ unsafe impl<T: ?Sized + Send + Sync> Sync for RwLock<T> {} #[stable(feature = "rust1", since = "1.0.0")] #[clippy::has_significant_drop] #[cfg_attr(not(test), rustc_diagnostic_item = "RwLockReadGuard")] -pub struct RwLockReadGuard<'a, T: ?Sized + 'a> { - // NB: we use a pointer instead of `&'a T` to avoid `noalias` violations, because a - // `RwLockReadGuard` argument doesn't hold immutability for its whole scope, only until it drops. - // `NonNull` is also covariant over `T`, just like we would have with `&T`. `NonNull` - // is preferable over `const* T` to allow for niche optimization. +pub struct RwLockReadGuard<'rwlock, T: ?Sized + 'rwlock> { + /// A pointer to the data protected by the `RwLock`. Note that we use a pointer here instead of + /// `&'rwlock T` to avoid `noalias` violations, because a `RwLockReadGuard` instance only holds + /// immutability until it drops, not for its whole scope. + /// `NonNull` is preferable over `*const T` to allow for niche optimizations. `NonNull` is also + /// covariant over `T`, just like we would have with `&T`. data: NonNull<T>, - inner_lock: &'a sys::RwLock, + /// A reference to the internal [`sys::RwLock`] that we have read-locked. + inner_lock: &'rwlock sys::RwLock, } #[stable(feature = "rust1", since = "1.0.0")] @@ -135,8 +145,10 @@ unsafe impl<T: ?Sized + Sync> Sync for RwLockReadGuard<'_, T> {} #[stable(feature = "rust1", since = "1.0.0")] #[clippy::has_significant_drop] #[cfg_attr(not(test), rustc_diagnostic_item = "RwLockWriteGuard")] -pub struct RwLockWriteGuard<'a, T: ?Sized + 'a> { - lock: &'a RwLock<T>, +pub struct RwLockWriteGuard<'rwlock, T: ?Sized + 'rwlock> { + /// A reference to the [`RwLock`] that we have write-locked. + lock: &'rwlock RwLock<T>, + /// The poison guard. See the [`poison`] module for more information. poison: poison::Guard, } @@ -160,13 +172,15 @@ unsafe impl<T: ?Sized + Sync> Sync for RwLockWriteGuard<'_, T> {} and cause Futures to not implement `Send`"] #[unstable(feature = "mapped_lock_guards", issue = "117108")] #[clippy::has_significant_drop] -pub struct MappedRwLockReadGuard<'a, T: ?Sized + 'a> { - // NB: we use a pointer instead of `&'a T` to avoid `noalias` violations, because a - // `MappedRwLockReadGuard` argument doesn't hold immutability for its whole scope, only until it drops. - // `NonNull` is also covariant over `T`, just like we would have with `&T`. `NonNull` - // is preferable over `const* T` to allow for niche optimization. +pub struct MappedRwLockReadGuard<'rwlock, T: ?Sized + 'rwlock> { + /// A pointer to the data protected by the `RwLock`. Note that we use a pointer here instead of + /// `&'rwlock T` to avoid `noalias` violations, because a `MappedRwLockReadGuard` instance only + /// holds immutability until it drops, not for its whole scope. + /// `NonNull` is preferable over `*const T` to allow for niche optimizations. `NonNull` is also + /// covariant over `T`, just like we would have with `&T`. data: NonNull<T>, - inner_lock: &'a sys::RwLock, + /// A reference to the internal [`sys::RwLock`] that we have read-locked. + inner_lock: &'rwlock sys::RwLock, } #[unstable(feature = "mapped_lock_guards", issue = "117108")] @@ -189,16 +203,21 @@ unsafe impl<T: ?Sized + Sync> Sync for MappedRwLockReadGuard<'_, T> {} and cause Future's to not implement `Send`"] #[unstable(feature = "mapped_lock_guards", issue = "117108")] #[clippy::has_significant_drop] -pub struct MappedRwLockWriteGuard<'a, T: ?Sized + 'a> { - // NB: we use a pointer instead of `&'a mut T` to avoid `noalias` violations, because a - // `MappedRwLockWriteGuard` argument doesn't hold uniqueness for its whole scope, only until it drops. - // `NonNull` is covariant over `T`, so we add a `PhantomData<&'a mut T>` field - // below for the correct variance over `T` (invariance). +pub struct MappedRwLockWriteGuard<'rwlock, T: ?Sized + 'rwlock> { + /// A pointer to the data protected by the `RwLock`. Note that we use a pointer here instead of + /// `&'rwlock T` to avoid `noalias` violations, because a `MappedRwLockWriteGuard` instance only + /// holds uniquneness until it drops, not for its whole scope. + /// `NonNull` is preferable over `*const T` to allow for niche optimizations. data: NonNull<T>, - inner_lock: &'a sys::RwLock, - poison_flag: &'a poison::Flag, - poison: poison::Guard, - _variance: PhantomData<&'a mut T>, + /// `NonNull` is covariant over `T`, so we add a `PhantomData<&'rwlock mut T>` field here to + /// enforce the correct invariance over `T`. + _variance: PhantomData<&'rwlock mut T>, + /// A reference to the internal [`sys::RwLock`] that we have write-locked. + inner_lock: &'rwlock sys::RwLock, + /// A reference to the original `RwLock`'s poison state. + poison_flag: &'rwlock poison::Flag, + /// The poison guard. See the [`poison`] module for more information. + poison_guard: poison::Guard, } #[unstable(feature = "mapped_lock_guards", issue = "117108")] @@ -207,6 +226,10 @@ impl<T: ?Sized> !Send for MappedRwLockWriteGuard<'_, T> {} #[unstable(feature = "mapped_lock_guards", issue = "117108")] unsafe impl<T: ?Sized + Sync> Sync for MappedRwLockWriteGuard<'_, T> {} +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Implementations +//////////////////////////////////////////////////////////////////////////////////////////////////// + impl<T> RwLock<T> { /// Creates a new instance of an `RwLock<T>` which is unlocked. /// @@ -611,8 +634,8 @@ impl<T: ?Sized> RwLock<T> { /// /// Since this call borrows the `RwLock` mutably, no actual locking needs to /// take place -- the mutable borrow statically guarantees no new locks can be acquired - /// while this reference exists. Note that this method does not clear any previously abandoned locks - /// (e.g., via [`forget()`] on a [`RwLockReadGuard`] or [`RwLockWriteGuard`]). + /// while this reference exists. Note that this method does not clear any previously abandoned + /// locks (e.g., via [`forget()`] on a [`RwLockReadGuard`] or [`RwLockWriteGuard`]). /// /// # Errors /// @@ -700,177 +723,7 @@ impl<'rwlock, T: ?Sized> RwLockReadGuard<'rwlock, T> { inner_lock: &lock.inner, }) } -} - -impl<'rwlock, T: ?Sized> RwLockWriteGuard<'rwlock, T> { - /// Creates a new instance of `RwLockWriteGuard<T>` from a `RwLock<T>`. - // SAFETY: if and only if `lock.inner.write()` (or `lock.inner.try_write()`) has been - // successfully called from the same thread before instantiating this object. - unsafe fn new(lock: &'rwlock RwLock<T>) -> LockResult<RwLockWriteGuard<'rwlock, T>> { - poison::map_result(lock.poison.guard(), |guard| RwLockWriteGuard { lock, poison: guard }) - } -} - -#[stable(feature = "std_debug", since = "1.16.0")] -impl<T: ?Sized + fmt::Debug> fmt::Debug for RwLockReadGuard<'_, T> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - (**self).fmt(f) - } -} - -#[stable(feature = "std_guard_impls", since = "1.20.0")] -impl<T: ?Sized + fmt::Display> fmt::Display for RwLockReadGuard<'_, T> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - (**self).fmt(f) - } -} - -#[stable(feature = "std_debug", since = "1.16.0")] -impl<T: ?Sized + fmt::Debug> fmt::Debug for RwLockWriteGuard<'_, T> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - (**self).fmt(f) - } -} - -#[stable(feature = "std_guard_impls", since = "1.20.0")] -impl<T: ?Sized + fmt::Display> fmt::Display for RwLockWriteGuard<'_, T> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - (**self).fmt(f) - } -} - -#[unstable(feature = "mapped_lock_guards", issue = "117108")] -impl<T: ?Sized + fmt::Debug> fmt::Debug for MappedRwLockReadGuard<'_, T> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - (**self).fmt(f) - } -} - -#[unstable(feature = "mapped_lock_guards", issue = "117108")] -impl<T: ?Sized + fmt::Display> fmt::Display for MappedRwLockReadGuard<'_, T> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - (**self).fmt(f) - } -} - -#[unstable(feature = "mapped_lock_guards", issue = "117108")] -impl<T: ?Sized + fmt::Debug> fmt::Debug for MappedRwLockWriteGuard<'_, T> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - (**self).fmt(f) - } -} - -#[unstable(feature = "mapped_lock_guards", issue = "117108")] -impl<T: ?Sized + fmt::Display> fmt::Display for MappedRwLockWriteGuard<'_, T> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - (**self).fmt(f) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<T: ?Sized> Deref for RwLockReadGuard<'_, T> { - type Target = T; - - fn deref(&self) -> &T { - // SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when created. - unsafe { self.data.as_ref() } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<T: ?Sized> Deref for RwLockWriteGuard<'_, T> { - type Target = T; - - fn deref(&self) -> &T { - // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when created. - unsafe { &*self.lock.data.get() } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<T: ?Sized> DerefMut for RwLockWriteGuard<'_, T> { - fn deref_mut(&mut self) -> &mut T { - // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when created. - unsafe { &mut *self.lock.data.get() } - } -} - -#[unstable(feature = "mapped_lock_guards", issue = "117108")] -impl<T: ?Sized> Deref for MappedRwLockReadGuard<'_, T> { - type Target = T; - - fn deref(&self) -> &T { - // SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when the original guard - // was created, and have been upheld throughout `map` and/or `filter_map`. - unsafe { self.data.as_ref() } - } -} - -#[unstable(feature = "mapped_lock_guards", issue = "117108")] -impl<T: ?Sized> Deref for MappedRwLockWriteGuard<'_, T> { - type Target = T; - - fn deref(&self) -> &T { - // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when the original guard - // was created, and have been upheld throughout `map` and/or `filter_map`. - unsafe { self.data.as_ref() } - } -} - -#[unstable(feature = "mapped_lock_guards", issue = "117108")] -impl<T: ?Sized> DerefMut for MappedRwLockWriteGuard<'_, T> { - fn deref_mut(&mut self) -> &mut T { - // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when the original guard - // was created, and have been upheld throughout `map` and/or `filter_map`. - unsafe { self.data.as_mut() } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<T: ?Sized> Drop for RwLockReadGuard<'_, T> { - fn drop(&mut self) { - // SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when created. - unsafe { - self.inner_lock.read_unlock(); - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<T: ?Sized> Drop for RwLockWriteGuard<'_, T> { - fn drop(&mut self) { - self.lock.poison.done(&self.poison); - // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when created. - unsafe { - self.lock.inner.write_unlock(); - } - } -} - -#[unstable(feature = "mapped_lock_guards", issue = "117108")] -impl<T: ?Sized> Drop for MappedRwLockReadGuard<'_, T> { - fn drop(&mut self) { - // SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when the original guard - // was created, and have been upheld throughout `map` and/or `filter_map`. - unsafe { - self.inner_lock.read_unlock(); - } - } -} - -#[unstable(feature = "mapped_lock_guards", issue = "117108")] -impl<T: ?Sized> Drop for MappedRwLockWriteGuard<'_, T> { - fn drop(&mut self) { - self.poison_flag.done(&self.poison); - // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when the original guard - // was created, and have been upheld throughout `map` and/or `filter_map`. - unsafe { - self.inner_lock.write_unlock(); - } - } -} -impl<'a, T: ?Sized> RwLockReadGuard<'a, T> { /// Makes a [`MappedRwLockReadGuard`] for a component of the borrowed data, e.g. /// an enum variant. /// @@ -883,17 +736,18 @@ impl<'a, T: ?Sized> RwLockReadGuard<'a, T> { /// /// # Panics /// - /// If the closure panics, the guard will be dropped (unlocked) and the RwLock will not be poisoned. + /// If the closure panics, the guard will be dropped (unlocked) and the RwLock will not be + /// poisoned. #[unstable(feature = "mapped_lock_guards", issue = "117108")] - pub fn map<U, F>(orig: Self, f: F) -> MappedRwLockReadGuard<'a, U> + pub fn map<U, F>(orig: Self, f: F) -> MappedRwLockReadGuard<'rwlock, U> where F: FnOnce(&T) -> &U, U: ?Sized, { // SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when the original guard // was created, and have been upheld throughout `map` and/or `filter_map`. - // The signature of the closure guarantees that it will not "leak" the lifetime of the reference - // passed to it. If the closure panics, the guard will be dropped. + // The signature of the closure guarantees that it will not "leak" the lifetime of the + // reference passed to it. If the closure panics, the guard will be dropped. let data = NonNull::from(f(unsafe { orig.data.as_ref() })); let orig = ManuallyDrop::new(orig); MappedRwLockReadGuard { data, inner_lock: &orig.inner_lock } @@ -912,17 +766,18 @@ impl<'a, T: ?Sized> RwLockReadGuard<'a, T> { /// /// # Panics /// - /// If the closure panics, the guard will be dropped (unlocked) and the RwLock will not be poisoned. + /// If the closure panics, the guard will be dropped (unlocked) and the RwLock will not be + /// poisoned. #[unstable(feature = "mapped_lock_guards", issue = "117108")] - pub fn filter_map<U, F>(orig: Self, f: F) -> Result<MappedRwLockReadGuard<'a, U>, Self> + pub fn filter_map<U, F>(orig: Self, f: F) -> Result<MappedRwLockReadGuard<'rwlock, U>, Self> where F: FnOnce(&T) -> Option<&U>, U: ?Sized, { // SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when the original guard // was created, and have been upheld throughout `map` and/or `filter_map`. - // The signature of the closure guarantees that it will not "leak" the lifetime of the reference - // passed to it. If the closure panics, the guard will be dropped. + // The signature of the closure guarantees that it will not "leak" the lifetime of the + // reference passed to it. If the closure panics, the guard will be dropped. match f(unsafe { orig.data.as_ref() }) { Some(data) => { let data = NonNull::from(data); @@ -934,71 +789,95 @@ impl<'a, T: ?Sized> RwLockReadGuard<'a, T> { } } -impl<'a, T: ?Sized> MappedRwLockReadGuard<'a, T> { - /// Makes a [`MappedRwLockReadGuard`] for a component of the borrowed data, - /// e.g. an enum variant. - /// - /// The `RwLock` is already locked for reading, so this cannot fail. - /// - /// This is an associated function that needs to be used as - /// `MappedRwLockReadGuard::map(...)`. A method would interfere with - /// methods of the same name on the contents of the `MappedRwLockReadGuard` - /// used through `Deref`. +impl<'rwlock, T: ?Sized> RwLockWriteGuard<'rwlock, T> { + /// Creates a new instance of `RwLockWriteGuard<T>` from a `RwLock<T>`. /// - /// # Panics + /// # Safety /// - /// If the closure panics, the guard will be dropped (unlocked) and the RwLock will not be poisoned. - #[unstable(feature = "mapped_lock_guards", issue = "117108")] - pub fn map<U, F>(orig: Self, f: F) -> MappedRwLockReadGuard<'a, U> - where - F: FnOnce(&T) -> &U, - U: ?Sized, - { - // SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when the original guard - // was created, and have been upheld throughout `map` and/or `filter_map`. - // The signature of the closure guarantees that it will not "leak" the lifetime of the reference - // passed to it. If the closure panics, the guard will be dropped. - let data = NonNull::from(f(unsafe { orig.data.as_ref() })); - let orig = ManuallyDrop::new(orig); - MappedRwLockReadGuard { data, inner_lock: &orig.inner_lock } + /// This function is safe if and only if the same thread has successfully and safely called + /// `lock.inner.write()`, `lock.inner.try_write()`, or `lock.inner.try_upgrade` before + /// instantiating this object. + unsafe fn new(lock: &'rwlock RwLock<T>) -> LockResult<RwLockWriteGuard<'rwlock, T>> { + poison::map_result(lock.poison.guard(), |guard| RwLockWriteGuard { lock, poison: guard }) } - /// Makes a [`MappedRwLockReadGuard`] for a component of the borrowed data. - /// The original guard is returned as an `Err(...)` if the closure returns - /// `None`. + /// Downgrades a write-locked `RwLockWriteGuard` into a read-locked [`RwLockReadGuard`]. /// - /// The `RwLock` is already locked for reading, so this cannot fail. + /// Since we have the `RwLockWriteGuard`, the [`RwLock`] must already be locked for writing, so + /// this method cannot fail. /// - /// This is an associated function that needs to be used as - /// `MappedRwLockReadGuard::filter_map(...)`. A method would interfere with - /// methods of the same name on the contents of the `MappedRwLockReadGuard` - /// used through `Deref`. + /// After downgrading, other readers will be allowed to read the protected data. /// - /// # Panics + /// # Examples /// - /// If the closure panics, the guard will be dropped (unlocked) and the RwLock will not be poisoned. - #[unstable(feature = "mapped_lock_guards", issue = "117108")] - pub fn filter_map<U, F>(orig: Self, f: F) -> Result<MappedRwLockReadGuard<'a, U>, Self> - where - F: FnOnce(&T) -> Option<&U>, - U: ?Sized, - { - // SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when the original guard - // was created, and have been upheld throughout `map` and/or `filter_map`. - // The signature of the closure guarantees that it will not "leak" the lifetime of the reference - // passed to it. If the closure panics, the guard will be dropped. - match f(unsafe { orig.data.as_ref() }) { - Some(data) => { - let data = NonNull::from(data); - let orig = ManuallyDrop::new(orig); - Ok(MappedRwLockReadGuard { data, inner_lock: &orig.inner_lock }) - } - None => Err(orig), - } + /// `downgrade` takes ownership of the `RwLockWriteGuard` and returns a [`RwLockReadGuard`]. + /// + /// ``` + /// #![feature(rwlock_downgrade)] + /// + /// use std::sync::{RwLock, RwLockWriteGuard}; + /// + /// let rw = RwLock::new(0); + /// + /// let mut write_guard = rw.write().unwrap(); + /// *write_guard = 42; + /// + /// let read_guard = RwLockWriteGuard::downgrade(write_guard); + /// assert_eq!(42, *read_guard); + /// ``` + /// + /// `downgrade` will _atomically_ change the state of the [`RwLock`] from exclusive mode into + /// shared mode. This means that it is impossible for another writing thread to get in between a + /// thread calling `downgrade` and any reads it performs after downgrading. + /// + /// ``` + /// #![feature(rwlock_downgrade)] + /// + /// use std::sync::{Arc, RwLock, RwLockWriteGuard}; + /// + /// let rw = Arc::new(RwLock::new(1)); + /// + /// // Put the lock in write mode. + /// let mut main_write_guard = rw.write().unwrap(); + /// + /// let rw_clone = rw.clone(); + /// let evil_handle = std::thread::spawn(move || { + /// // This will not return until the main thread drops the `main_read_guard`. + /// let mut evil_guard = rw_clone.write().unwrap(); + /// + /// assert_eq!(*evil_guard, 2); + /// *evil_guard = 3; + /// }); + /// + /// *main_write_guard = 2; + /// + /// // Atomically downgrade the write guard into a read guard. + /// let main_read_guard = RwLockWriteGuard::downgrade(main_write_guard); + /// + /// // Since `downgrade` is atomic, the writer thread cannot have changed the protected data. + /// assert_eq!(*main_read_guard, 2, "`downgrade` was not atomic"); + /// # + /// # drop(main_read_guard); + /// # evil_handle.join().unwrap(); + /// # + /// # let final_check = rw.read().unwrap(); + /// # assert_eq!(*final_check, 3); + /// ``` + #[unstable(feature = "rwlock_downgrade", issue = "128203")] + pub fn downgrade(s: Self) -> RwLockReadGuard<'rwlock, T> { + let lock = s.lock; + + // We don't want to call the destructor since that calls `write_unlock`. + forget(s); + + // SAFETY: We take ownership of a write guard, so we must already have the `RwLock` in write + // mode, satisfying the `downgrade` contract. + unsafe { lock.inner.downgrade() }; + + // SAFETY: We have just successfully called `downgrade`, so we fulfill the safety contract. + unsafe { RwLockReadGuard::new(lock).unwrap_or_else(PoisonError::into_inner) } } -} -impl<'a, T: ?Sized> RwLockWriteGuard<'a, T> { /// Makes a [`MappedRwLockWriteGuard`] for a component of the borrowed data, e.g. /// an enum variant. /// @@ -1013,22 +892,22 @@ impl<'a, T: ?Sized> RwLockWriteGuard<'a, T> { /// /// If the closure panics, the guard will be dropped (unlocked) and the RwLock will be poisoned. #[unstable(feature = "mapped_lock_guards", issue = "117108")] - pub fn map<U, F>(orig: Self, f: F) -> MappedRwLockWriteGuard<'a, U> + pub fn map<U, F>(orig: Self, f: F) -> MappedRwLockWriteGuard<'rwlock, U> where F: FnOnce(&mut T) -> &mut U, U: ?Sized, { // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when the original guard // was created, and have been upheld throughout `map` and/or `filter_map`. - // The signature of the closure guarantees that it will not "leak" the lifetime of the reference - // passed to it. If the closure panics, the guard will be dropped. + // The signature of the closure guarantees that it will not "leak" the lifetime of the + // reference passed to it. If the closure panics, the guard will be dropped. let data = NonNull::from(f(unsafe { &mut *orig.lock.data.get() })); let orig = ManuallyDrop::new(orig); MappedRwLockWriteGuard { data, inner_lock: &orig.lock.inner, poison_flag: &orig.lock.poison, - poison: orig.poison.clone(), + poison_guard: orig.poison.clone(), _variance: PhantomData, } } @@ -1048,15 +927,15 @@ impl<'a, T: ?Sized> RwLockWriteGuard<'a, T> { /// /// If the closure panics, the guard will be dropped (unlocked) and the RwLock will be poisoned. #[unstable(feature = "mapped_lock_guards", issue = "117108")] - pub fn filter_map<U, F>(orig: Self, f: F) -> Result<MappedRwLockWriteGuard<'a, U>, Self> + pub fn filter_map<U, F>(orig: Self, f: F) -> Result<MappedRwLockWriteGuard<'rwlock, U>, Self> where F: FnOnce(&mut T) -> Option<&mut U>, U: ?Sized, { // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when the original guard // was created, and have been upheld throughout `map` and/or `filter_map`. - // The signature of the closure guarantees that it will not "leak" the lifetime of the reference - // passed to it. If the closure panics, the guard will be dropped. + // The signature of the closure guarantees that it will not "leak" the lifetime of the + // reference passed to it. If the closure panics, the guard will be dropped. match f(unsafe { &mut *orig.lock.data.get() }) { Some(data) => { let data = NonNull::from(data); @@ -1065,78 +944,82 @@ impl<'a, T: ?Sized> RwLockWriteGuard<'a, T> { data, inner_lock: &orig.lock.inner, poison_flag: &orig.lock.poison, - poison: orig.poison.clone(), + poison_guard: orig.poison.clone(), _variance: PhantomData, }) } None => Err(orig), } } +} - /// Downgrades a write-locked `RwLockWriteGuard` into a read-locked [`RwLockReadGuard`]. - /// - /// This method will atomically change the state of the [`RwLock`] from exclusive mode into - /// shared mode. This means that it is impossible for a writing thread to get in between a - /// thread calling `downgrade` and the same thread reading whatever it wrote while it had the - /// [`RwLock`] in write mode. - /// - /// Note that since we have the `RwLockWriteGuard`, we know that the [`RwLock`] is already - /// locked for writing, so this method cannot fail. - /// - /// # Example - /// - /// ``` - /// #![feature(rwlock_downgrade)] - /// use std::sync::{Arc, RwLock, RwLockWriteGuard}; - /// - /// // The inner value starts as 0. - /// let rw = Arc::new(RwLock::new(0)); +impl<'rwlock, T: ?Sized> MappedRwLockReadGuard<'rwlock, T> { + /// Makes a [`MappedRwLockReadGuard`] for a component of the borrowed data, + /// e.g. an enum variant. /// - /// // Put the lock in write mode. - /// let mut main_write_guard = rw.write().unwrap(); + /// The `RwLock` is already locked for reading, so this cannot fail. /// - /// let evil = rw.clone(); - /// let handle = std::thread::spawn(move || { - /// // This will not return until the main thread drops the `main_read_guard`. - /// let mut evil_guard = evil.write().unwrap(); + /// This is an associated function that needs to be used as + /// `MappedRwLockReadGuard::map(...)`. A method would interfere with + /// methods of the same name on the contents of the `MappedRwLockReadGuard` + /// used through `Deref`. /// - /// assert_eq!(*evil_guard, 1); - /// *evil_guard = 2; - /// }); + /// # Panics /// - /// // After spawning the writer thread, set the inner value to 1. - /// *main_write_guard = 1; + /// If the closure panics, the guard will be dropped (unlocked) and the RwLock will not be + /// poisoned. + #[unstable(feature = "mapped_lock_guards", issue = "117108")] + pub fn map<U, F>(orig: Self, f: F) -> MappedRwLockReadGuard<'rwlock, U> + where + F: FnOnce(&T) -> &U, + U: ?Sized, + { + // SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when the original guard + // was created, and have been upheld throughout `map` and/or `filter_map`. + // The signature of the closure guarantees that it will not "leak" the lifetime of the + // reference passed to it. If the closure panics, the guard will be dropped. + let data = NonNull::from(f(unsafe { orig.data.as_ref() })); + let orig = ManuallyDrop::new(orig); + MappedRwLockReadGuard { data, inner_lock: &orig.inner_lock } + } + + /// Makes a [`MappedRwLockReadGuard`] for a component of the borrowed data. + /// The original guard is returned as an `Err(...)` if the closure returns + /// `None`. /// - /// // Atomically downgrade the write guard into a read guard. - /// let main_read_guard = RwLockWriteGuard::downgrade(main_write_guard); + /// The `RwLock` is already locked for reading, so this cannot fail. /// - /// // Since `downgrade` is atomic, the writer thread cannot have set the inner value to 2. - /// assert_eq!(*main_read_guard, 1, "`downgrade` was not atomic"); + /// This is an associated function that needs to be used as + /// `MappedRwLockReadGuard::filter_map(...)`. A method would interfere with + /// methods of the same name on the contents of the `MappedRwLockReadGuard` + /// used through `Deref`. /// - /// // Clean up everything now - /// drop(main_read_guard); - /// handle.join().unwrap(); + /// # Panics /// - /// let final_check = rw.read().unwrap(); - /// assert_eq!(*final_check, 2); - /// ``` - #[unstable(feature = "rwlock_downgrade", issue = "128203")] - pub fn downgrade(s: Self) -> RwLockReadGuard<'a, T> { - let lock = s.lock; - - // We don't want to call the destructor since that calls `write_unlock`. - forget(s); - - // SAFETY: We take ownership of a write guard, so we must already have the `RwLock` in write - // mode, satisfying the `downgrade` contract. - unsafe { lock.inner.downgrade() }; - - // SAFETY: We have just successfully called `downgrade`, so we fulfill the safety contract. - unsafe { RwLockReadGuard::new(lock).unwrap_or_else(PoisonError::into_inner) } + /// If the closure panics, the guard will be dropped (unlocked) and the RwLock will not be + /// poisoned. + #[unstable(feature = "mapped_lock_guards", issue = "117108")] + pub fn filter_map<U, F>(orig: Self, f: F) -> Result<MappedRwLockReadGuard<'rwlock, U>, Self> + where + F: FnOnce(&T) -> Option<&U>, + U: ?Sized, + { + // SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when the original guard + // was created, and have been upheld throughout `map` and/or `filter_map`. + // The signature of the closure guarantees that it will not "leak" the lifetime of the + // reference passed to it. If the closure panics, the guard will be dropped. + match f(unsafe { orig.data.as_ref() }) { + Some(data) => { + let data = NonNull::from(data); + let orig = ManuallyDrop::new(orig); + Ok(MappedRwLockReadGuard { data, inner_lock: &orig.inner_lock }) + } + None => Err(orig), + } } } -impl<'a, T: ?Sized> MappedRwLockWriteGuard<'a, T> { +impl<'rwlock, T: ?Sized> MappedRwLockWriteGuard<'rwlock, T> { /// Makes a [`MappedRwLockWriteGuard`] for a component of the borrowed data, /// e.g. an enum variant. /// @@ -1151,22 +1034,22 @@ impl<'a, T: ?Sized> MappedRwLockWriteGuard<'a, T> { /// /// If the closure panics, the guard will be dropped (unlocked) and the RwLock will be poisoned. #[unstable(feature = "mapped_lock_guards", issue = "117108")] - pub fn map<U, F>(mut orig: Self, f: F) -> MappedRwLockWriteGuard<'a, U> + pub fn map<U, F>(mut orig: Self, f: F) -> MappedRwLockWriteGuard<'rwlock, U> where F: FnOnce(&mut T) -> &mut U, U: ?Sized, { // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when the original guard // was created, and have been upheld throughout `map` and/or `filter_map`. - // The signature of the closure guarantees that it will not "leak" the lifetime of the reference - // passed to it. If the closure panics, the guard will be dropped. + // The signature of the closure guarantees that it will not "leak" the lifetime of the + // reference passed to it. If the closure panics, the guard will be dropped. let data = NonNull::from(f(unsafe { orig.data.as_mut() })); let orig = ManuallyDrop::new(orig); MappedRwLockWriteGuard { data, inner_lock: orig.inner_lock, poison_flag: orig.poison_flag, - poison: orig.poison.clone(), + poison_guard: orig.poison_guard.clone(), _variance: PhantomData, } } @@ -1186,15 +1069,18 @@ impl<'a, T: ?Sized> MappedRwLockWriteGuard<'a, T> { /// /// If the closure panics, the guard will be dropped (unlocked) and the RwLock will be poisoned. #[unstable(feature = "mapped_lock_guards", issue = "117108")] - pub fn filter_map<U, F>(mut orig: Self, f: F) -> Result<MappedRwLockWriteGuard<'a, U>, Self> + pub fn filter_map<U, F>( + mut orig: Self, + f: F, + ) -> Result<MappedRwLockWriteGuard<'rwlock, U>, Self> where F: FnOnce(&mut T) -> Option<&mut U>, U: ?Sized, { // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when the original guard // was created, and have been upheld throughout `map` and/or `filter_map`. - // The signature of the closure guarantees that it will not "leak" the lifetime of the reference - // passed to it. If the closure panics, the guard will be dropped. + // The signature of the closure guarantees that it will not "leak" the lifetime of the + // reference passed to it. If the closure panics, the guard will be dropped. match f(unsafe { orig.data.as_mut() }) { Some(data) => { let data = NonNull::from(data); @@ -1203,7 +1089,7 @@ impl<'a, T: ?Sized> MappedRwLockWriteGuard<'a, T> { data, inner_lock: orig.inner_lock, poison_flag: orig.poison_flag, - poison: orig.poison.clone(), + poison_guard: orig.poison_guard.clone(), _variance: PhantomData, }) } @@ -1211,3 +1097,162 @@ impl<'a, T: ?Sized> MappedRwLockWriteGuard<'a, T> { } } } + +#[stable(feature = "rust1", since = "1.0.0")] +impl<T: ?Sized> Drop for RwLockReadGuard<'_, T> { + fn drop(&mut self) { + // SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when created. + unsafe { + self.inner_lock.read_unlock(); + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<T: ?Sized> Drop for RwLockWriteGuard<'_, T> { + fn drop(&mut self) { + self.lock.poison.done(&self.poison); + // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when created. + unsafe { + self.lock.inner.write_unlock(); + } + } +} + +#[unstable(feature = "mapped_lock_guards", issue = "117108")] +impl<T: ?Sized> Drop for MappedRwLockReadGuard<'_, T> { + fn drop(&mut self) { + // SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when the original guard + // was created, and have been upheld throughout `map` and/or `filter_map`. + unsafe { + self.inner_lock.read_unlock(); + } + } +} + +#[unstable(feature = "mapped_lock_guards", issue = "117108")] +impl<T: ?Sized> Drop for MappedRwLockWriteGuard<'_, T> { + fn drop(&mut self) { + self.poison_flag.done(&self.poison_guard); + // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when the original guard + // was created, and have been upheld throughout `map` and/or `filter_map`. + unsafe { + self.inner_lock.write_unlock(); + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<T: ?Sized> Deref for RwLockReadGuard<'_, T> { + type Target = T; + + fn deref(&self) -> &T { + // SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when created. + unsafe { self.data.as_ref() } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<T: ?Sized> Deref for RwLockWriteGuard<'_, T> { + type Target = T; + + fn deref(&self) -> &T { + // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when created. + unsafe { &*self.lock.data.get() } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<T: ?Sized> DerefMut for RwLockWriteGuard<'_, T> { + fn deref_mut(&mut self) -> &mut T { + // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when created. + unsafe { &mut *self.lock.data.get() } + } +} + +#[unstable(feature = "mapped_lock_guards", issue = "117108")] +impl<T: ?Sized> Deref for MappedRwLockReadGuard<'_, T> { + type Target = T; + + fn deref(&self) -> &T { + // SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when the original guard + // was created, and have been upheld throughout `map` and/or `filter_map`. + unsafe { self.data.as_ref() } + } +} + +#[unstable(feature = "mapped_lock_guards", issue = "117108")] +impl<T: ?Sized> Deref for MappedRwLockWriteGuard<'_, T> { + type Target = T; + + fn deref(&self) -> &T { + // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when the original guard + // was created, and have been upheld throughout `map` and/or `filter_map`. + unsafe { self.data.as_ref() } + } +} + +#[unstable(feature = "mapped_lock_guards", issue = "117108")] +impl<T: ?Sized> DerefMut for MappedRwLockWriteGuard<'_, T> { + fn deref_mut(&mut self) -> &mut T { + // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when the original guard + // was created, and have been upheld throughout `map` and/or `filter_map`. + unsafe { self.data.as_mut() } + } +} + +#[stable(feature = "std_debug", since = "1.16.0")] +impl<T: ?Sized + fmt::Debug> fmt::Debug for RwLockReadGuard<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (**self).fmt(f) + } +} + +#[stable(feature = "std_guard_impls", since = "1.20.0")] +impl<T: ?Sized + fmt::Display> fmt::Display for RwLockReadGuard<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (**self).fmt(f) + } +} + +#[stable(feature = "std_debug", since = "1.16.0")] +impl<T: ?Sized + fmt::Debug> fmt::Debug for RwLockWriteGuard<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (**self).fmt(f) + } +} + +#[stable(feature = "std_guard_impls", since = "1.20.0")] +impl<T: ?Sized + fmt::Display> fmt::Display for RwLockWriteGuard<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (**self).fmt(f) + } +} + +#[unstable(feature = "mapped_lock_guards", issue = "117108")] +impl<T: ?Sized + fmt::Debug> fmt::Debug for MappedRwLockReadGuard<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (**self).fmt(f) + } +} + +#[unstable(feature = "mapped_lock_guards", issue = "117108")] +impl<T: ?Sized + fmt::Display> fmt::Display for MappedRwLockReadGuard<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (**self).fmt(f) + } +} + +#[unstable(feature = "mapped_lock_guards", issue = "117108")] +impl<T: ?Sized + fmt::Debug> fmt::Debug for MappedRwLockWriteGuard<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (**self).fmt(f) + } +} + +#[unstable(feature = "mapped_lock_guards", issue = "117108")] +impl<T: ?Sized + fmt::Display> fmt::Display for MappedRwLockWriteGuard<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (**self).fmt(f) + } +} diff --git a/library/std/src/sys/fd/unix.rs b/library/std/src/sys/fd/unix.rs index cdca73cdca1..a12f692e754 100644 --- a/library/std/src/sys/fd/unix.rs +++ b/library/std/src/sys/fd/unix.rs @@ -37,10 +37,10 @@ pub struct FileDesc(OwnedFd); // // On Apple targets however, apparently the 64-bit libc is either buggy or // intentionally showing odd behavior by rejecting any read with a size -// larger than or equal to INT_MAX. To handle both of these the read -// size is capped on both platforms. +// larger than INT_MAX. To handle both of these the read size is capped on +// both platforms. const READ_LIMIT: usize = if cfg!(target_vendor = "apple") { - libc::c_int::MAX as usize - 1 + libc::c_int::MAX as usize } else { libc::ssize_t::MAX as usize }; diff --git a/library/std/src/sys/pal/unix/mod.rs b/library/std/src/sys/pal/unix/mod.rs index fede3673eb6..aef7ab55088 100644 --- a/library/std/src/sys/pal/unix/mod.rs +++ b/library/std/src/sys/pal/unix/mod.rs @@ -59,6 +59,30 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) { } unsafe fn sanitize_standard_fds() { + #[allow(dead_code, unused_variables, unused_mut)] + let mut opened_devnull = -1; + #[allow(dead_code, unused_variables, unused_mut)] + let mut open_devnull = || { + #[cfg(not(all(target_os = "linux", target_env = "gnu")))] + use libc::open; + #[cfg(all(target_os = "linux", target_env = "gnu"))] + use libc::open64 as open; + + if opened_devnull != -1 { + if libc::dup(opened_devnull) != -1 { + return; + } + } + opened_devnull = open(c"/dev/null".as_ptr(), libc::O_RDWR, 0); + if opened_devnull == -1 { + // If the stream is closed but we failed to reopen it, abort the + // process. Otherwise we wouldn't preserve the safety of + // operations on the corresponding Rust object Stdin, Stdout, or + // Stderr. + libc::abort(); + } + }; + // fast path with a single syscall for systems with poll() #[cfg(not(any( miri, @@ -74,11 +98,6 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) { target_vendor = "apple", )))] 'poll: { - #[cfg(not(all(target_os = "linux", target_env = "gnu")))] - use libc::open as open64; - #[cfg(all(target_os = "linux", target_env = "gnu"))] - use libc::open64; - use crate::sys::os::errno; let pfds: &mut [_] = &mut [ libc::pollfd { fd: 0, events: 0, revents: 0 }, @@ -106,13 +125,7 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) { if pfd.revents & libc::POLLNVAL == 0 { continue; } - if open64(c"/dev/null".as_ptr(), libc::O_RDWR, 0) == -1 { - // If the stream is closed but we failed to reopen it, abort the - // process. Otherwise we wouldn't preserve the safety of - // operations on the corresponding Rust object Stdin, Stdout, or - // Stderr. - libc::abort(); - } + open_devnull(); } return; } @@ -129,21 +142,10 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) { target_os = "vita", )))] { - #[cfg(not(all(target_os = "linux", target_env = "gnu")))] - use libc::open as open64; - #[cfg(all(target_os = "linux", target_env = "gnu"))] - use libc::open64; - use crate::sys::os::errno; for fd in 0..3 { if libc::fcntl(fd, libc::F_GETFD) == -1 && errno() == libc::EBADF { - if open64(c"/dev/null".as_ptr(), libc::O_RDWR, 0) == -1 { - // If the stream is closed but we failed to reopen it, abort the - // process. Otherwise we wouldn't preserve the safety of - // operations on the corresponding Rust object Stdin, Stdout, or - // Stderr. - libc::abort(); - } + open_devnull(); } } } diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs index 0ad014ccd3e..797feeb2bbb 100644 --- a/library/std/src/thread/local.rs +++ b/library/std/src/thread/local.rs @@ -8,8 +8,8 @@ use crate::fmt; /// A thread local storage (TLS) key which owns its contents. /// -/// This key uses the fastest possible implementation available to it for the -/// target platform. It is instantiated with the [`thread_local!`] macro and the +/// This key uses the fastest implementation available on the target platform. +/// It is instantiated with the [`thread_local!`] macro and the /// primary method is the [`with`] method, though there are helpers to make /// working with [`Cell`] types easier. /// @@ -24,10 +24,10 @@ use crate::fmt; /// [`with`]) within a thread, and values that implement [`Drop`] get /// destructed when a thread exits. Some platform-specific caveats apply, which /// are explained below. -/// Note that, should the destructor panics, the whole process will be [aborted]. +/// Note that if the destructor panics, the whole process will be [aborted]. /// /// A `LocalKey`'s initializer cannot recursively depend on itself. Using a -/// `LocalKey` in this way may cause panics, aborts or infinite recursion on +/// `LocalKey` in this way may cause panics, aborts, or infinite recursion on /// the first call to `with`. /// /// [aborted]: crate::process::abort diff --git a/library/std/tests/sync/lib.rs b/library/std/tests/sync/lib.rs index 94f1fe96b6a..f874c2ba389 100644 --- a/library/std/tests/sync/lib.rs +++ b/library/std/tests/sync/lib.rs @@ -8,6 +8,7 @@ #![feature(std_internals)] #![feature(sync_nonpoison)] #![feature(nonpoison_mutex)] +#![feature(nonpoison_rwlock)] #![allow(internal_features)] #![feature(macro_metavar_expr_concat)] // For concatenating identifiers in macros. diff --git a/library/std/tests/sync/rwlock.rs b/library/std/tests/sync/rwlock.rs index 1d55a176948..eca15d2a4ad 100644 --- a/library/std/tests/sync/rwlock.rs +++ b/library/std/tests/sync/rwlock.rs @@ -29,239 +29,457 @@ fn test_needs_drop() { assert!(mem::needs_drop::<NonCopyNeedsDrop>()); } -#[derive(Clone, Eq, PartialEq, Debug)] -struct Cloneable(i32); - -#[test] -fn smoke() { - let l = RwLock::new(()); - drop(l.read().unwrap()); - drop(l.write().unwrap()); - drop((l.read().unwrap(), l.read().unwrap())); - drop(l.write().unwrap()); -} +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Non-poison & Poison Tests +//////////////////////////////////////////////////////////////////////////////////////////////////// +use super::nonpoison_and_poison_unwrap_test; + +nonpoison_and_poison_unwrap_test!( + name: smoke, + test_body: { + use locks::RwLock; + + let l = RwLock::new(()); + drop(maybe_unwrap(l.read())); + drop(maybe_unwrap(l.write())); + drop((maybe_unwrap(l.read()), maybe_unwrap(l.read()))); + drop(maybe_unwrap(l.write())); + } +); -#[test] // FIXME: On macOS we use a provenance-incorrect implementation and Miri // catches that issue with a chance of around 1/1000. // See <https://github.com/rust-lang/rust/issues/121950> for details. #[cfg_attr(all(miri, target_os = "macos"), ignore)] -fn frob() { - const N: u32 = 10; - const M: usize = if cfg!(miri) { 100 } else { 1000 }; +nonpoison_and_poison_unwrap_test!( + name: frob, + test_body: { + use locks::RwLock; - let r = Arc::new(RwLock::new(())); + const N: u32 = 10; + const M: usize = if cfg!(miri) { 100 } else { 1000 }; - let (tx, rx) = channel::<()>(); - for _ in 0..N { - let tx = tx.clone(); - let r = r.clone(); - thread::spawn(move || { - let mut rng = crate::common::test_rng(); - for _ in 0..M { - if rng.random_bool(1.0 / (N as f64)) { - drop(r.write().unwrap()); - } else { - drop(r.read().unwrap()); + let r = Arc::new(RwLock::new(())); + + let (tx, rx) = channel::<()>(); + for _ in 0..N { + let tx = tx.clone(); + let r = r.clone(); + thread::spawn(move || { + let mut rng = crate::common::test_rng(); + for _ in 0..M { + if rng.random_bool(1.0 / (N as f64)) { + drop(maybe_unwrap(r.write())); + } else { + drop(maybe_unwrap(r.read())); + } } + drop(tx); + }); + } + drop(tx); + let _ = rx.recv(); + } +); + +nonpoison_and_poison_unwrap_test!( + name: test_rw_arc, + test_body: { + use locks::RwLock; + + let arc = Arc::new(RwLock::new(0)); + let arc2 = arc.clone(); + let (tx, rx) = channel(); + + thread::spawn(move || { + let mut lock = maybe_unwrap(arc2.write()); + for _ in 0..10 { + let tmp = *lock; + *lock = -1; + thread::yield_now(); + *lock = tmp + 1; } - drop(tx); + tx.send(()).unwrap(); }); + + // Readers try to catch the writer in the act + let mut children = Vec::new(); + for _ in 0..5 { + let arc3 = arc.clone(); + children.push(thread::spawn(move || { + let lock = maybe_unwrap(arc3.read()); + assert!(*lock >= 0); + })); + } + + // Wait for children to pass their asserts + for r in children { + assert!(r.join().is_ok()); + } + + // Wait for writer to finish + rx.recv().unwrap(); + let lock = maybe_unwrap(arc.read()); + assert_eq!(*lock, 10); } - drop(tx); - let _ = rx.recv(); -} +); -#[test] #[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] -fn test_rw_arc_poison_wr() { - let arc = Arc::new(RwLock::new(1)); - let arc2 = arc.clone(); - let _: Result<(), _> = thread::spawn(move || { - let _lock = arc2.write().unwrap(); - panic!(); - }) - .join(); - assert!(arc.read().is_err()); -} +nonpoison_and_poison_unwrap_test!( + name: test_rw_arc_access_in_unwind, + test_body: { + use locks::RwLock; + + let arc = Arc::new(RwLock::new(1)); + let arc2 = arc.clone(); + let _ = thread::spawn(move || -> () { + struct Unwinder { + i: Arc<RwLock<isize>>, + } + impl Drop for Unwinder { + fn drop(&mut self) { + let mut lock = maybe_unwrap(self.i.write()); + *lock += 1; + } + } + let _u = Unwinder { i: arc2 }; + panic!(); + }) + .join(); + let lock = maybe_unwrap(arc.read()); + assert_eq!(*lock, 2); + } +); + +nonpoison_and_poison_unwrap_test!( + name: test_rwlock_unsized, + test_body: { + use locks::RwLock; + + let rw: &RwLock<[i32]> = &RwLock::new([1, 2, 3]); + { + let b = &mut *maybe_unwrap(rw.write()); + b[0] = 4; + b[2] = 5; + } + let comp: &[i32] = &[4, 2, 5]; + assert_eq!(&*maybe_unwrap(rw.read()), comp); + } +); -#[test] -#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] -fn test_rw_arc_poison_mapped_w_r() { - let arc = Arc::new(RwLock::new(1)); - let arc2 = arc.clone(); - let _: Result<(), _> = thread::spawn(move || { - let lock = arc2.write().unwrap(); - let _lock = RwLockWriteGuard::map(lock, |val| val); - panic!(); - }) - .join(); - assert!(arc.read().is_err()); -} +nonpoison_and_poison_unwrap_test!( + name: test_into_inner, + test_body: { + use locks::RwLock; -#[test] -#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] -fn test_rw_arc_poison_ww() { - let arc = Arc::new(RwLock::new(1)); - assert!(!arc.is_poisoned()); - let arc2 = arc.clone(); - let _: Result<(), _> = thread::spawn(move || { - let _lock = arc2.write().unwrap(); - panic!(); - }) - .join(); - assert!(arc.write().is_err()); - assert!(arc.is_poisoned()); -} + let m = RwLock::new(NonCopy(10)); + assert_eq!(maybe_unwrap(m.into_inner()), NonCopy(10)); + } +); -#[test] -#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] -fn test_rw_arc_poison_mapped_w_w() { - let arc = Arc::new(RwLock::new(1)); - let arc2 = arc.clone(); - let _: Result<(), _> = thread::spawn(move || { - let lock = arc2.write().unwrap(); - let _lock = RwLockWriteGuard::map(lock, |val| val); - panic!(); - }) - .join(); - assert!(arc.write().is_err()); - assert!(arc.is_poisoned()); -} +nonpoison_and_poison_unwrap_test!( + name: test_into_inner_drop, + test_body: { + use locks::RwLock; -#[test] -#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] -fn test_rw_arc_no_poison_rr() { - let arc = Arc::new(RwLock::new(1)); - let arc2 = arc.clone(); - let _: Result<(), _> = thread::spawn(move || { - let _lock = arc2.read().unwrap(); - panic!(); - }) - .join(); - let lock = arc.read().unwrap(); - assert_eq!(*lock, 1); -} + struct Foo(Arc<AtomicUsize>); + impl Drop for Foo { + fn drop(&mut self) { + self.0.fetch_add(1, Ordering::SeqCst); + } + } -#[test] -#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] -fn test_rw_arc_no_poison_mapped_r_r() { - let arc = Arc::new(RwLock::new(1)); - let arc2 = arc.clone(); - let _: Result<(), _> = thread::spawn(move || { - let lock = arc2.read().unwrap(); - let _lock = RwLockReadGuard::map(lock, |val| val); - panic!(); - }) - .join(); - let lock = arc.read().unwrap(); - assert_eq!(*lock, 1); -} + let num_drops = Arc::new(AtomicUsize::new(0)); + let m = RwLock::new(Foo(num_drops.clone())); + assert_eq!(num_drops.load(Ordering::SeqCst), 0); + { + let _inner = maybe_unwrap(m.into_inner()); + assert_eq!(num_drops.load(Ordering::SeqCst), 0); + } + assert_eq!(num_drops.load(Ordering::SeqCst), 1); + } +); -#[test] -#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] -fn test_rw_arc_no_poison_rw() { - let arc = Arc::new(RwLock::new(1)); - let arc2 = arc.clone(); - let _: Result<(), _> = thread::spawn(move || { - let _lock = arc2.read().unwrap(); - panic!() - }) - .join(); - let lock = arc.write().unwrap(); - assert_eq!(*lock, 1); -} +nonpoison_and_poison_unwrap_test!( + name: test_get_cloned, + test_body: { + use locks::RwLock; -#[test] -#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] -fn test_rw_arc_no_poison_mapped_r_w() { - let arc = Arc::new(RwLock::new(1)); - let arc2 = arc.clone(); - let _: Result<(), _> = thread::spawn(move || { - let lock = arc2.read().unwrap(); - let _lock = RwLockReadGuard::map(lock, |val| val); - panic!(); - }) - .join(); - let lock = arc.write().unwrap(); - assert_eq!(*lock, 1); -} + #[derive(Clone, Eq, PartialEq, Debug)] + struct Cloneable(i32); -#[test] -fn test_rw_arc() { - let arc = Arc::new(RwLock::new(0)); - let arc2 = arc.clone(); - let (tx, rx) = channel(); - - thread::spawn(move || { - let mut lock = arc2.write().unwrap(); - for _ in 0..10 { - let tmp = *lock; - *lock = -1; - thread::yield_now(); - *lock = tmp + 1; + let m = RwLock::new(Cloneable(10)); + + assert_eq!(maybe_unwrap(m.get_cloned()), Cloneable(10)); + } +); + +nonpoison_and_poison_unwrap_test!( + name: test_get_mut, + test_body: { + use locks::RwLock; + + let mut m = RwLock::new(NonCopy(10)); + *maybe_unwrap(m.get_mut()) = NonCopy(20); + assert_eq!(maybe_unwrap(m.into_inner()), NonCopy(20)); + } +); + +nonpoison_and_poison_unwrap_test!( + name: test_set, + test_body: { + use locks::RwLock; + + fn inner<T>(mut init: impl FnMut() -> T, mut value: impl FnMut() -> T) + where + T: Debug + Eq, + { + let m = RwLock::new(init()); + + assert_eq!(*maybe_unwrap(m.read()), init()); + maybe_unwrap(m.set(value())); + assert_eq!(*maybe_unwrap(m.read()), value()); + } + + inner(|| NonCopy(10), || NonCopy(20)); + inner(|| NonCopyNeedsDrop(10), || NonCopyNeedsDrop(20)); + } +); + +nonpoison_and_poison_unwrap_test!( + name: test_replace, + test_body: { + use locks::RwLock; + + fn inner<T>(mut init: impl FnMut() -> T, mut value: impl FnMut() -> T) + where + T: Debug + Eq, + { + let m = RwLock::new(init()); + + assert_eq!(*maybe_unwrap(m.read()), init()); + assert_eq!(maybe_unwrap(m.replace(value())), init()); + assert_eq!(*maybe_unwrap(m.read()), value()); } - tx.send(()).unwrap(); - }); - // Readers try to catch the writer in the act - let mut children = Vec::new(); - for _ in 0..5 { - let arc3 = arc.clone(); - children.push(thread::spawn(move || { - let lock = arc3.read().unwrap(); - assert!(*lock >= 0); - })); + inner(|| NonCopy(10), || NonCopy(20)); + inner(|| NonCopyNeedsDrop(10), || NonCopyNeedsDrop(20)); + } +); + +nonpoison_and_poison_unwrap_test!( + name: test_read_guard_covariance, + test_body: { + use locks::{RwLock, RwLockReadGuard}; + + fn do_stuff<'a>(_: RwLockReadGuard<'_, &'a i32>, _: &'a i32) {} + let j: i32 = 5; + let lock = RwLock::new(&j); + { + let i = 6; + do_stuff(maybe_unwrap(lock.read()), &i); + } + drop(lock); } +); + +nonpoison_and_poison_unwrap_test!( + name: test_mapped_read_guard_covariance, + test_body: { + use locks::{RwLock, RwLockReadGuard, MappedRwLockReadGuard}; + + fn do_stuff<'a>(_: MappedRwLockReadGuard<'_, &'a i32>, _: &'a i32) {} + let j: i32 = 5; + let lock = RwLock::new((&j, &j)); + { + let i = 6; + let guard = maybe_unwrap(lock.read()); + let guard = RwLockReadGuard::map(guard, |(val, _val)| val); + do_stuff(guard, &i); + } + drop(lock); + } +); + +nonpoison_and_poison_unwrap_test!( + name: test_downgrade_basic, + test_body: { + use locks::{RwLock, RwLockWriteGuard}; + + let r = RwLock::new(()); - // Wait for children to pass their asserts - for r in children { - assert!(r.join().is_ok()); + let write_guard = maybe_unwrap(r.write()); + let _read_guard = RwLockWriteGuard::downgrade(write_guard); } +); - // Wait for writer to finish - rx.recv().unwrap(); - let lock = arc.read().unwrap(); - assert_eq!(*lock, 10); -} +// FIXME: On macOS we use a provenance-incorrect implementation and Miri catches that issue. +// See <https://github.com/rust-lang/rust/issues/121950> for details. +#[cfg_attr(all(miri, target_os = "macos"), ignore)] +nonpoison_and_poison_unwrap_test!( + name: test_downgrade_observe, + test_body: { + use locks::{RwLock, RwLockWriteGuard}; + + // Inspired by the test `test_rwlock_downgrade` from: + // https://github.com/Amanieu/parking_lot/blob/master/src/rwlock.rs + + const W: usize = 20; + const N: usize = if cfg!(miri) { 40 } else { 100 }; + + // This test spawns `W` writer threads, where each will increment a counter `N` times, + // ensuring that the value they wrote has not changed after downgrading. + + let rw = Arc::new(RwLock::new(0)); + + // Spawn the writers that will do `W * N` operations and checks. + let handles: Vec<_> = (0..W) + .map(|_| { + let rw = rw.clone(); + thread::spawn(move || { + for _ in 0..N { + // Increment the counter. + let mut write_guard = maybe_unwrap(rw.write()); + *write_guard += 1; + let cur_val = *write_guard; + + // Downgrade the lock to read mode, where the value protected cannot be + // modified. + let read_guard = RwLockWriteGuard::downgrade(write_guard); + assert_eq!(cur_val, *read_guard); + } + }) + }) + .collect(); -#[test] -#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] -fn test_rw_arc_access_in_unwind() { - let arc = Arc::new(RwLock::new(1)); - let arc2 = arc.clone(); - let _ = thread::spawn(move || -> () { - struct Unwinder { - i: Arc<RwLock<isize>>, + for handle in handles { + handle.join().unwrap(); } - impl Drop for Unwinder { - fn drop(&mut self) { - let mut lock = self.i.write().unwrap(); - *lock += 1; - } + + assert_eq!(*maybe_unwrap(rw.read()), W * N); + } +); + +// FIXME: On macOS we use a provenance-incorrect implementation and Miri catches that issue. +// See <https://github.com/rust-lang/rust/issues/121950> for details. +#[cfg_attr(all(miri, target_os = "macos"), ignore)] +nonpoison_and_poison_unwrap_test!( + name: test_downgrade_atomic, + test_body: { + use locks::{RwLock, RwLockWriteGuard}; + + const NEW_VALUE: i32 = -1; + + // This test checks that `downgrade` is atomic, meaning as soon as a write lock has been + // downgraded, the lock must be in read mode and no other threads can take the write lock to + // modify the protected value. + + // `W` is the number of evil writer threads. + const W: usize = 20; + let rwlock = Arc::new(RwLock::new(0)); + + // Spawns many evil writer threads that will try and write to the locked value before the + // initial writer (who has the exclusive lock) can read after it downgrades. + // If the `RwLock` behaves correctly, then the initial writer should read the value it wrote + // itself as no other thread should be able to mutate the protected value. + + // Put the lock in write mode, causing all future threads trying to access this go to sleep. + let mut main_write_guard = maybe_unwrap(rwlock.write()); + + // Spawn all of the evil writer threads. They will each increment the protected value by 1. + let handles: Vec<_> = (0..W) + .map(|_| { + let rwlock = rwlock.clone(); + thread::spawn(move || { + // Will go to sleep since the main thread initially has the write lock. + let mut evil_guard = maybe_unwrap(rwlock.write()); + *evil_guard += 1; + }) + }) + .collect(); + + // Wait for a good amount of time so that evil threads go to sleep. + // Note: this is not strictly necessary... + let eternity = std::time::Duration::from_millis(42); + thread::sleep(eternity); + + // Once everyone is asleep, set the value to `NEW_VALUE`. + *main_write_guard = NEW_VALUE; + + // Atomically downgrade the write guard into a read guard. + let main_read_guard = RwLockWriteGuard::downgrade(main_write_guard); + + // If the above is not atomic, then it would be possible for an evil thread to get in front + // of this read and change the value to be non-negative. + assert_eq!(*main_read_guard, NEW_VALUE, "`downgrade` was not atomic"); + + // Drop the main read guard and allow the evil writer threads to start incrementing. + drop(main_read_guard); + + for handle in handles { + handle.join().unwrap(); } - let _u = Unwinder { i: arc2 }; - panic!(); - }) - .join(); - let lock = arc.read().unwrap(); - assert_eq!(*lock, 2); -} + + let final_check = maybe_unwrap(rwlock.read()); + assert_eq!(*final_check, W as i32 + NEW_VALUE); + } +); + +nonpoison_and_poison_unwrap_test!( + name: test_mapping_mapped_guard, + test_body: { + use locks::{ + RwLock, RwLockReadGuard, RwLockWriteGuard, MappedRwLockReadGuard, MappedRwLockWriteGuard + }; + + let arr = [0; 4]; + let mut lock = RwLock::new(arr); + let guard = maybe_unwrap(lock.write()); + let guard = RwLockWriteGuard::map(guard, |arr| &mut arr[..2]); + let mut guard = MappedRwLockWriteGuard::map(guard, |slice| &mut slice[1..]); + assert_eq!(guard.len(), 1); + guard[0] = 42; + drop(guard); + assert_eq!(*maybe_unwrap(lock.get_mut()), [0, 42, 0, 0]); + + let guard = maybe_unwrap(lock.read()); + let guard = RwLockReadGuard::map(guard, |arr| &arr[..2]); + let guard = MappedRwLockReadGuard::map(guard, |slice| &slice[1..]); + assert_eq!(*guard, [42]); + drop(guard); + assert_eq!(*maybe_unwrap(lock.get_mut()), [0, 42, 0, 0]); + } +); #[test] -fn test_rwlock_unsized() { - let rw: &RwLock<[i32]> = &RwLock::new([1, 2, 3]); - { - let b = &mut *rw.write().unwrap(); - b[0] = 4; - b[2] = 5; +fn nonpoison_test_rwlock_try_write() { + use std::sync::nonpoison::{RwLock, RwLockReadGuard, WouldBlock}; + + let lock = RwLock::new(0isize); + let read_guard = lock.read(); + + let write_result = lock.try_write(); + match write_result { + Err(WouldBlock) => (), + Ok(_) => assert!(false, "try_write should not succeed while read_guard is in scope"), + } + + drop(read_guard); + let mapped_read_guard = RwLockReadGuard::map(lock.read(), |_| &()); + + let write_result = lock.try_write(); + match write_result { + Err(WouldBlock) => (), + Ok(_) => assert!(false, "try_write should not succeed while mapped_read_guard is in scope"), } - let comp: &[i32] = &[4, 2, 5]; - assert_eq!(&*rw.read().unwrap(), comp); + + drop(mapped_read_guard); } #[test] -fn test_rwlock_try_write() { +fn poison_test_rwlock_try_write() { + use std::sync::poison::{RwLock, RwLockReadGuard, TryLockError}; + let lock = RwLock::new(0isize); let read_guard = lock.read().unwrap(); @@ -285,6 +503,11 @@ fn test_rwlock_try_write() { drop(mapped_read_guard); } +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Poison Tests +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/// Creates a rwlock that is immediately poisoned. fn new_poisoned_rwlock<T>(value: T) -> RwLock<T> { let lock = RwLock::new(value); @@ -301,30 +524,6 @@ fn new_poisoned_rwlock<T>(value: T) -> RwLock<T> { } #[test] -fn test_into_inner() { - let m = RwLock::new(NonCopy(10)); - assert_eq!(m.into_inner().unwrap(), NonCopy(10)); -} - -#[test] -fn test_into_inner_drop() { - struct Foo(Arc<AtomicUsize>); - impl Drop for Foo { - fn drop(&mut self) { - self.0.fetch_add(1, Ordering::SeqCst); - } - } - let num_drops = Arc::new(AtomicUsize::new(0)); - let m = RwLock::new(Foo(num_drops.clone())); - assert_eq!(num_drops.load(Ordering::SeqCst), 0); - { - let _inner = m.into_inner().unwrap(); - assert_eq!(num_drops.load(Ordering::SeqCst), 0); - } - assert_eq!(num_drops.load(Ordering::SeqCst), 1); -} - -#[test] #[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_into_inner_poison() { let m = new_poisoned_rwlock(NonCopy(10)); @@ -336,15 +535,11 @@ fn test_into_inner_poison() { } #[test] -fn test_get_cloned() { - let m = RwLock::new(Cloneable(10)); - - assert_eq!(m.get_cloned().unwrap(), Cloneable(10)); -} - -#[test] #[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_get_cloned_poison() { + #[derive(Clone, Eq, PartialEq, Debug)] + struct Cloneable(i32); + let m = new_poisoned_rwlock(Cloneable(10)); match m.get_cloned() { @@ -354,13 +549,6 @@ fn test_get_cloned_poison() { } #[test] -fn test_get_mut() { - let mut m = RwLock::new(NonCopy(10)); - *m.get_mut().unwrap() = NonCopy(20); - assert_eq!(m.into_inner().unwrap(), NonCopy(20)); -} - -#[test] #[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_get_mut_poison() { let mut m = new_poisoned_rwlock(NonCopy(10)); @@ -372,23 +560,6 @@ fn test_get_mut_poison() { } #[test] -fn test_set() { - fn inner<T>(mut init: impl FnMut() -> T, mut value: impl FnMut() -> T) - where - T: Debug + Eq, - { - let m = RwLock::new(init()); - - assert_eq!(*m.read().unwrap(), init()); - m.set(value()).unwrap(); - assert_eq!(*m.read().unwrap(), value()); - } - - inner(|| NonCopy(10), || NonCopy(20)); - inner(|| NonCopyNeedsDrop(10), || NonCopyNeedsDrop(20)); -} - -#[test] #[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_set_poison() { fn inner<T>(mut init: impl FnMut() -> T, mut value: impl FnMut() -> T) @@ -411,23 +582,6 @@ fn test_set_poison() { } #[test] -fn test_replace() { - fn inner<T>(mut init: impl FnMut() -> T, mut value: impl FnMut() -> T) - where - T: Debug + Eq, - { - let m = RwLock::new(init()); - - assert_eq!(*m.read().unwrap(), init()); - assert_eq!(m.replace(value()).unwrap(), init()); - assert_eq!(*m.read().unwrap(), value()); - } - - inner(|| NonCopy(10), || NonCopy(20)); - inner(|| NonCopyNeedsDrop(10), || NonCopyNeedsDrop(20)); -} - -#[test] #[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_replace_poison() { fn inner<T>(mut init: impl FnMut() -> T, mut value: impl FnMut() -> T) @@ -450,49 +604,118 @@ fn test_replace_poison() { } #[test] -fn test_read_guard_covariance() { - fn do_stuff<'a>(_: RwLockReadGuard<'_, &'a i32>, _: &'a i32) {} - let j: i32 = 5; - let lock = RwLock::new(&j); - { - let i = 6; - do_stuff(lock.read().unwrap(), &i); - } - drop(lock); +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] +fn test_rw_arc_poison_wr() { + let arc = Arc::new(RwLock::new(1)); + let arc2 = arc.clone(); + let _: Result<(), _> = thread::spawn(move || { + let _lock = arc2.write().unwrap(); + panic!(); + }) + .join(); + assert!(arc.read().is_err()); } #[test] -fn test_mapped_read_guard_covariance() { - fn do_stuff<'a>(_: MappedRwLockReadGuard<'_, &'a i32>, _: &'a i32) {} - let j: i32 = 5; - let lock = RwLock::new((&j, &j)); - { - let i = 6; - let guard = lock.read().unwrap(); - let guard = RwLockReadGuard::map(guard, |(val, _val)| val); - do_stuff(guard, &i); - } - drop(lock); +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] +fn test_rw_arc_poison_mapped_w_r() { + let arc = Arc::new(RwLock::new(1)); + let arc2 = arc.clone(); + let _: Result<(), _> = thread::spawn(move || { + let lock = arc2.write().unwrap(); + let _lock = RwLockWriteGuard::map(lock, |val| val); + panic!(); + }) + .join(); + assert!(arc.read().is_err()); } #[test] -fn test_mapping_mapped_guard() { - let arr = [0; 4]; - let mut lock = RwLock::new(arr); - let guard = lock.write().unwrap(); - let guard = RwLockWriteGuard::map(guard, |arr| &mut arr[..2]); - let mut guard = MappedRwLockWriteGuard::map(guard, |slice| &mut slice[1..]); - assert_eq!(guard.len(), 1); - guard[0] = 42; - drop(guard); - assert_eq!(*lock.get_mut().unwrap(), [0, 42, 0, 0]); - - let guard = lock.read().unwrap(); - let guard = RwLockReadGuard::map(guard, |arr| &arr[..2]); - let guard = MappedRwLockReadGuard::map(guard, |slice| &slice[1..]); - assert_eq!(*guard, [42]); - drop(guard); - assert_eq!(*lock.get_mut().unwrap(), [0, 42, 0, 0]); +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] +fn test_rw_arc_poison_ww() { + let arc = Arc::new(RwLock::new(1)); + assert!(!arc.is_poisoned()); + let arc2 = arc.clone(); + let _: Result<(), _> = thread::spawn(move || { + let _lock = arc2.write().unwrap(); + panic!(); + }) + .join(); + assert!(arc.write().is_err()); + assert!(arc.is_poisoned()); +} + +#[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] +fn test_rw_arc_poison_mapped_w_w() { + let arc = Arc::new(RwLock::new(1)); + let arc2 = arc.clone(); + let _: Result<(), _> = thread::spawn(move || { + let lock = arc2.write().unwrap(); + let _lock = RwLockWriteGuard::map(lock, |val| val); + panic!(); + }) + .join(); + assert!(arc.write().is_err()); + assert!(arc.is_poisoned()); +} + +#[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] +fn test_rw_arc_no_poison_rr() { + let arc = Arc::new(RwLock::new(1)); + let arc2 = arc.clone(); + let _: Result<(), _> = thread::spawn(move || { + let _lock = arc2.read().unwrap(); + panic!(); + }) + .join(); + let lock = arc.read().unwrap(); + assert_eq!(*lock, 1); +} + +#[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] +fn test_rw_arc_no_poison_mapped_r_r() { + let arc = Arc::new(RwLock::new(1)); + let arc2 = arc.clone(); + let _: Result<(), _> = thread::spawn(move || { + let lock = arc2.read().unwrap(); + let _lock = RwLockReadGuard::map(lock, |val| val); + panic!(); + }) + .join(); + let lock = arc.read().unwrap(); + assert_eq!(*lock, 1); +} + +#[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] +fn test_rw_arc_no_poison_rw() { + let arc = Arc::new(RwLock::new(1)); + let arc2 = arc.clone(); + let _: Result<(), _> = thread::spawn(move || { + let _lock = arc2.read().unwrap(); + panic!() + }) + .join(); + let lock = arc.write().unwrap(); + assert_eq!(*lock, 1); +} + +#[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] +fn test_rw_arc_no_poison_mapped_r_w() { + let arc = Arc::new(RwLock::new(1)); + let arc2 = arc.clone(); + let _: Result<(), _> = thread::spawn(move || { + let lock = arc2.read().unwrap(); + let _lock = RwLockReadGuard::map(lock, |val| val); + panic!(); + }) + .join(); + let lock = arc.write().unwrap(); + assert_eq!(*lock, 1); } #[test] @@ -638,114 +861,3 @@ fn panic_while_mapping_write_unlocked_poison() { drop(lock); } - -#[test] -fn test_downgrade_basic() { - let r = RwLock::new(()); - - let write_guard = r.write().unwrap(); - let _read_guard = RwLockWriteGuard::downgrade(write_guard); -} - -#[test] -// FIXME: On macOS we use a provenance-incorrect implementation and Miri catches that issue. -// See <https://github.com/rust-lang/rust/issues/121950> for details. -#[cfg_attr(all(miri, target_os = "macos"), ignore)] -fn test_downgrade_observe() { - // Taken from the test `test_rwlock_downgrade` from: - // https://github.com/Amanieu/parking_lot/blob/master/src/rwlock.rs - - const W: usize = 20; - const N: usize = if cfg!(miri) { 40 } else { 100 }; - - // This test spawns `W` writer threads, where each will increment a counter `N` times, ensuring - // that the value they wrote has not changed after downgrading. - - let rw = Arc::new(RwLock::new(0)); - - // Spawn the writers that will do `W * N` operations and checks. - let handles: Vec<_> = (0..W) - .map(|_| { - let rw = rw.clone(); - thread::spawn(move || { - for _ in 0..N { - // Increment the counter. - let mut write_guard = rw.write().unwrap(); - *write_guard += 1; - let cur_val = *write_guard; - - // Downgrade the lock to read mode, where the value protected cannot be modified. - let read_guard = RwLockWriteGuard::downgrade(write_guard); - assert_eq!(cur_val, *read_guard); - } - }) - }) - .collect(); - - for handle in handles { - handle.join().unwrap(); - } - - assert_eq!(*rw.read().unwrap(), W * N); -} - -#[test] -// FIXME: On macOS we use a provenance-incorrect implementation and Miri catches that issue. -// See <https://github.com/rust-lang/rust/issues/121950> for details. -#[cfg_attr(all(miri, target_os = "macos"), ignore)] -fn test_downgrade_atomic() { - const NEW_VALUE: i32 = -1; - - // This test checks that `downgrade` is atomic, meaning as soon as a write lock has been - // downgraded, the lock must be in read mode and no other threads can take the write lock to - // modify the protected value. - - // `W` is the number of evil writer threads. - const W: usize = 20; - let rwlock = Arc::new(RwLock::new(0)); - - // Spawns many evil writer threads that will try and write to the locked value before the - // initial writer (who has the exclusive lock) can read after it downgrades. - // If the `RwLock` behaves correctly, then the initial writer should read the value it wrote - // itself as no other thread should be able to mutate the protected value. - - // Put the lock in write mode, causing all future threads trying to access this go to sleep. - let mut main_write_guard = rwlock.write().unwrap(); - - // Spawn all of the evil writer threads. They will each increment the protected value by 1. - let handles: Vec<_> = (0..W) - .map(|_| { - let rwlock = rwlock.clone(); - thread::spawn(move || { - // Will go to sleep since the main thread initially has the write lock. - let mut evil_guard = rwlock.write().unwrap(); - *evil_guard += 1; - }) - }) - .collect(); - - // Wait for a good amount of time so that evil threads go to sleep. - // Note: this is not strictly necessary... - let eternity = std::time::Duration::from_millis(42); - thread::sleep(eternity); - - // Once everyone is asleep, set the value to `NEW_VALUE`. - *main_write_guard = NEW_VALUE; - - // Atomically downgrade the write guard into a read guard. - let main_read_guard = RwLockWriteGuard::downgrade(main_write_guard); - - // If the above is not atomic, then it would be possible for an evil thread to get in front of - // this read and change the value to be non-negative. - assert_eq!(*main_read_guard, NEW_VALUE, "`downgrade` was not atomic"); - - // Drop the main read guard and allow the evil writer threads to start incrementing. - drop(main_read_guard); - - for handle in handles { - handle.join().unwrap(); - } - - let final_check = rwlock.read().unwrap(); - assert_eq!(*final_check, W as i32 + NEW_VALUE); -} diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index be09cfa41af..6ca32aca345 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -1394,8 +1394,8 @@ fn rustc_llvm_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetSelect if builder.config.llvm_enzyme { cargo.env("LLVM_ENZYME", "1"); } - let llvm::LlvmResult { llvm_config, .. } = builder.ensure(llvm::Llvm { target }); - cargo.env("LLVM_CONFIG", &llvm_config); + let llvm::LlvmResult { host_llvm_config, .. } = builder.ensure(llvm::Llvm { target }); + cargo.env("LLVM_CONFIG", &host_llvm_config); // Some LLVM linker flags (-L and -l) may be needed to link `rustc_llvm`. Its build script // expects these to be passed via the `LLVM_LINKER_FLAGS` env variable, separated by @@ -2001,14 +2001,52 @@ impl Step for Assemble { if builder.config.llvm_enabled(target_compiler.host) { trace!("target_compiler.host" = ?target_compiler.host, "LLVM enabled"); - let llvm::LlvmResult { llvm_config, .. } = - builder.ensure(llvm::Llvm { target: target_compiler.host }); + let target = target_compiler.host; + let llvm::LlvmResult { host_llvm_config, .. } = builder.ensure(llvm::Llvm { target }); if !builder.config.dry_run() && builder.config.llvm_tools_enabled { trace!("LLVM tools enabled"); - let llvm_bin_dir = - command(llvm_config).arg("--bindir").run_capture_stdout(builder).stdout(); - let llvm_bin_dir = Path::new(llvm_bin_dir.trim()); + let host_llvm_bin_dir = command(&host_llvm_config) + .arg("--bindir") + .run_capture_stdout(builder) + .stdout() + .trim() + .to_string(); + + let llvm_bin_dir = if target == builder.host_target { + PathBuf::from(host_llvm_bin_dir) + } else { + // If we're cross-compiling, we cannot run the target llvm-config in order to + // figure out where binaries are located. We thus have to guess. + let external_llvm_config = builder + .config + .target_config + .get(&target) + .and_then(|t| t.llvm_config.clone()); + if let Some(external_llvm_config) = external_llvm_config { + // If we have an external LLVM, just hope that the bindir is the directory + // where the LLVM config is located + external_llvm_config.parent().unwrap().to_path_buf() + } else { + // If we have built LLVM locally, then take the path of the host bindir + // relative to its output build directory, and then apply it to the target + // LLVM output build directory. + let host_llvm_out = builder.llvm_out(builder.host_target); + let target_llvm_out = builder.llvm_out(target); + if let Ok(relative_path) = + Path::new(&host_llvm_bin_dir).strip_prefix(host_llvm_out) + { + target_llvm_out.join(relative_path) + } else { + // This is the most desperate option, just replace the host target with + // the actual target in the directory path... + PathBuf::from( + host_llvm_bin_dir + .replace(&*builder.host_target.triple, &target.triple), + ) + } + } + }; // Since we've already built the LLVM tools, install them to the sysroot. // This is the equivalent of installing the `llvm-tools-preview` component via diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index beb71e70035..daac75c03e2 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -2230,11 +2230,12 @@ fn maybe_install_llvm( builder.install(&llvm_dylib_path, dst_libdir, FileType::NativeLibrary); } !builder.config.dry_run() - } else if let llvm::LlvmBuildStatus::AlreadyBuilt(llvm::LlvmResult { llvm_config, .. }) = - llvm::prebuilt_llvm_config(builder, target, true) + } else if let llvm::LlvmBuildStatus::AlreadyBuilt(llvm::LlvmResult { + host_llvm_config, .. + }) = llvm::prebuilt_llvm_config(builder, target, true) { trace!("LLVM already built, installing LLVM files"); - let mut cmd = command(llvm_config); + let mut cmd = command(host_llvm_config); cmd.arg("--libfiles"); builder.verbose(|| println!("running {cmd:?}")); let files = cmd.run_capture_stdout(builder).stdout(); diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index 260108292e0..70259f0d1d7 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -29,7 +29,7 @@ use crate::{CLang, GitRepo, Kind, trace}; pub struct LlvmResult { /// Path to llvm-config binary. /// NB: This is always the host llvm-config! - pub llvm_config: PathBuf, + pub host_llvm_config: PathBuf, /// Path to LLVM cmake directory for the target. pub llvm_cmake_dir: PathBuf, } @@ -109,14 +109,14 @@ pub fn prebuilt_llvm_config( && let Some(ref s) = config.llvm_config { check_llvm_version(builder, s); - let llvm_config = s.to_path_buf(); - let mut llvm_cmake_dir = llvm_config.clone(); + let host_llvm_config = s.to_path_buf(); + let mut llvm_cmake_dir = host_llvm_config.clone(); llvm_cmake_dir.pop(); llvm_cmake_dir.pop(); llvm_cmake_dir.push("lib"); llvm_cmake_dir.push("cmake"); llvm_cmake_dir.push("llvm"); - return LlvmBuildStatus::AlreadyBuilt(LlvmResult { llvm_config, llvm_cmake_dir }); + return LlvmBuildStatus::AlreadyBuilt(LlvmResult { host_llvm_config, llvm_cmake_dir }); } if handle_submodule_when_needed { @@ -141,7 +141,7 @@ pub fn prebuilt_llvm_config( }; let llvm_cmake_dir = out_dir.join("lib/cmake/llvm"); - let res = LlvmResult { llvm_config: build_llvm_config, llvm_cmake_dir }; + let res = LlvmResult { host_llvm_config: build_llvm_config, llvm_cmake_dir }; static STAMP_HASH_MEMO: OnceLock<String> = OnceLock::new(); let smart_stamp_hash = STAMP_HASH_MEMO.get_or_init(|| { @@ -220,10 +220,6 @@ pub(crate) fn is_ci_llvm_available_for_target( ("armv7-unknown-linux-gnueabihf", false), ("loongarch64-unknown-linux-gnu", false), ("loongarch64-unknown-linux-musl", false), - ("mips-unknown-linux-gnu", false), - ("mips64-unknown-linux-gnuabi64", false), - ("mips64el-unknown-linux-gnuabi64", false), - ("mipsel-unknown-linux-gnu", false), ("powerpc-unknown-linux-gnu", false), ("powerpc64-unknown-linux-gnu", false), ("powerpc64le-unknown-linux-gnu", false), @@ -487,11 +483,11 @@ impl Step for Llvm { // https://llvm.org/docs/HowToCrossCompileLLVM.html if !builder.config.is_host_target(target) { - let LlvmResult { llvm_config, .. } = + let LlvmResult { host_llvm_config, .. } = builder.ensure(Llvm { target: builder.config.host_target }); if !builder.config.dry_run() { let llvm_bindir = - command(&llvm_config).arg("--bindir").run_capture_stdout(builder).stdout(); + command(&host_llvm_config).arg("--bindir").run_capture_stdout(builder).stdout(); let host_bin = Path::new(llvm_bindir.trim()); cfg.define( "LLVM_TABLEGEN", @@ -500,7 +496,7 @@ impl Step for Llvm { // LLVM_NM is required for cross compiling using MSVC cfg.define("LLVM_NM", host_bin.join("llvm-nm").with_extension(EXE_EXTENSION)); } - cfg.define("LLVM_CONFIG_PATH", llvm_config); + cfg.define("LLVM_CONFIG_PATH", host_llvm_config); if builder.config.llvm_clang { let build_bin = builder.llvm_out(builder.config.host_target).join("build").join("bin"); @@ -542,7 +538,7 @@ impl Step for Llvm { // Helper to find the name of LLVM's shared library on darwin and linux. let find_llvm_lib_name = |extension| { - let major = get_llvm_version_major(builder, &res.llvm_config); + let major = get_llvm_version_major(builder, &res.host_llvm_config); match &llvm_version_suffix { Some(version_suffix) => format!("libLLVM-{major}{version_suffix}.{extension}"), None => format!("libLLVM-{major}.{extension}"), @@ -919,7 +915,7 @@ impl Step for Enzyme { } let target = self.target; - let LlvmResult { llvm_config, .. } = builder.ensure(Llvm { target: self.target }); + let LlvmResult { host_llvm_config, .. } = builder.ensure(Llvm { target: self.target }); static STAMP_HASH_MEMO: OnceLock<String> = OnceLock::new(); let smart_stamp_hash = STAMP_HASH_MEMO.get_or_init(|| { @@ -973,7 +969,7 @@ impl Step for Enzyme { cfg.out_dir(&out_dir) .profile(profile) - .env("LLVM_CONFIG_REAL", &llvm_config) + .env("LLVM_CONFIG_REAL", &host_llvm_config) .define("LLVM_ENABLE_ASSERTIONS", "ON") .define("ENZYME_EXTERNAL_SHARED_LIB", "ON") .define("ENZYME_BC_LOADER", "OFF") @@ -1010,13 +1006,13 @@ impl Step for Lld { } let target = self.target; - let LlvmResult { llvm_config, llvm_cmake_dir } = builder.ensure(Llvm { target }); + let LlvmResult { host_llvm_config, llvm_cmake_dir } = builder.ensure(Llvm { target }); // The `dist` step packages LLD next to LLVM's binaries for download-ci-llvm. The root path // we usually expect here is `./build/$triple/ci-llvm/`, with the binaries in its `bin` // subfolder. We check if that's the case, and if LLD's binary already exists there next to // `llvm-config`: if so, we can use it instead of building LLVM/LLD from source. - let ci_llvm_bin = llvm_config.parent().unwrap(); + let ci_llvm_bin = host_llvm_config.parent().unwrap(); if ci_llvm_bin.is_dir() && ci_llvm_bin.file_name().unwrap() == "bin" { let lld_path = ci_llvm_bin.join(exe("lld", target)); if lld_path.exists() { @@ -1099,7 +1095,7 @@ impl Step for Lld { // Use the host llvm-tblgen binary. cfg.define( "LLVM_TABLEGEN_EXE", - llvm_config.with_file_name("llvm-tblgen").with_extension(EXE_EXTENSION), + host_llvm_config.with_file_name("llvm-tblgen").with_extension(EXE_EXTENSION), ); } @@ -1140,7 +1136,7 @@ impl Step for Sanitizers { return runtimes; } - let LlvmResult { llvm_config, .. } = + let LlvmResult { host_llvm_config, .. } = builder.ensure(Llvm { target: builder.config.host_target }); static STAMP_HASH_MEMO: OnceLock<String> = OnceLock::new(); @@ -1180,7 +1176,7 @@ impl Step for Sanitizers { cfg.define("COMPILER_RT_BUILD_XRAY", "OFF"); cfg.define("COMPILER_RT_DEFAULT_TARGET_ONLY", "ON"); cfg.define("COMPILER_RT_USE_LIBCXX", "OFF"); - cfg.define("LLVM_CONFIG_PATH", &llvm_config); + cfg.define("LLVM_CONFIG_PATH", &host_llvm_config); if self.target.contains("ohos") { cfg.define("COMPILER_RT_USE_BUILTINS_LIBRARY", "ON"); diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 56e7582a6ff..269e7da8d7b 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -2038,12 +2038,14 @@ HELP: You can add it into `bootstrap.toml` in `rust.codegen-backends = [{name:?} let mut llvm_components_passed = false; let mut copts_passed = false; if builder.config.llvm_enabled(compiler.host) { - let llvm::LlvmResult { llvm_config, .. } = + let llvm::LlvmResult { host_llvm_config, .. } = builder.ensure(llvm::Llvm { target: builder.config.host_target }); if !builder.config.dry_run() { - let llvm_version = get_llvm_version(builder, &llvm_config); - let llvm_components = - command(&llvm_config).arg("--components").run_capture_stdout(builder).stdout(); + let llvm_version = get_llvm_version(builder, &host_llvm_config); + let llvm_components = command(&host_llvm_config) + .arg("--components") + .run_capture_stdout(builder) + .stdout(); // Remove trailing newline from llvm-config output. cmd.arg("--llvm-version") .arg(llvm_version.trim()) @@ -2061,7 +2063,7 @@ HELP: You can add it into `bootstrap.toml` in `rust.codegen-backends = [{name:?} // rustc args as a workaround. if !builder.config.dry_run() && suite.ends_with("fulldeps") { let llvm_libdir = - command(&llvm_config).arg("--libdir").run_capture_stdout(builder).stdout(); + command(&host_llvm_config).arg("--libdir").run_capture_stdout(builder).stdout(); let link_llvm = if target.is_msvc() { format!("-Clink-arg=-LIBPATH:{llvm_libdir}") } else { @@ -2075,7 +2077,7 @@ HELP: You can add it into `bootstrap.toml` in `rust.codegen-backends = [{name:?} // tools. Pass the path to run-make tests so they can use them. // (The coverage-run tests also need these tools to process // coverage reports.) - let llvm_bin_path = llvm_config + let llvm_bin_path = host_llvm_config .parent() .expect("Expected llvm-config to be contained in directory"); assert!(llvm_bin_path.is_dir()); diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index 043cb1c2666..40460bf168d 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -1647,11 +1647,15 @@ You have to build a stage1 compiler for `{}` first, and then use it to build a s /// /// Note that this returns `None` if LLVM is disabled, or if we're in a /// check build or dry-run, where there's no need to build all of LLVM. + /// + /// FIXME(@kobzol) + /// **WARNING**: This actually returns the **HOST** LLVM config, not LLVM config for the given + /// *target*. pub fn llvm_config(&self, target: TargetSelection) -> Option<PathBuf> { if self.config.llvm_enabled(target) && self.kind != Kind::Check && !self.config.dry_run() { - let llvm::LlvmResult { llvm_config, .. } = self.ensure(llvm::Llvm { target }); - if llvm_config.is_file() { - return Some(llvm_config); + let llvm::LlvmResult { host_llvm_config, .. } = self.ensure(llvm::Llvm { target }); + if host_llvm_config.is_file() { + return Some(host_llvm_config); } } None diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index a2fe546c60a..2afba25ae59 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -434,14 +434,14 @@ fn test_prebuilt_llvm_config_path_resolution() { false, ) .llvm_result() - .llvm_config + .host_llvm_config .clone(); let actual = drop_win_disk_prefix_if_present(actual); assert_eq!(expected, actual); let actual = prebuilt_llvm_config(&builder, builder.config.host_target, false) .llvm_result() - .llvm_config + .host_llvm_config .clone(); let actual = drop_win_disk_prefix_if_present(actual); assert_eq!(expected, actual); @@ -459,7 +459,7 @@ fn test_prebuilt_llvm_config_path_resolution() { let actual = prebuilt_llvm_config(&builder, builder.config.host_target, false) .llvm_result() - .llvm_config + .host_llvm_config .clone(); let expected = builder .out @@ -482,7 +482,7 @@ fn test_prebuilt_llvm_config_path_resolution() { let actual = prebuilt_llvm_config(&builder, builder.config.host_target, false) .llvm_result() - .llvm_config + .host_llvm_config .clone(); let expected = builder .out diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index d0647537e56..f579bdd847f 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -13,7 +13,6 @@ //! and the `bootstrap.toml` file—merging them, applying defaults, and performing //! cross-component validation. The main `parse_inner` function and its supporting //! helpers reside here, transforming raw `Toml` data into the structured `Config` type. - use std::cell::Cell; use std::collections::{BTreeSet, HashMap, HashSet}; use std::io::IsTerminal; @@ -48,7 +47,7 @@ use crate::core::config::toml::rust::{ use crate::core::config::toml::target::Target; use crate::core::config::{ DebuginfoLevel, DryRun, GccCiMode, LlvmLibunwind, Merge, ReplaceOpt, RustcLto, SplitDebuginfo, - StringOrBool, set, threads_from_config, + StringOrBool, threads_from_config, }; use crate::core::download::{ DownloadContext, download_beta_toolchain, is_download_ci_available, maybe_download_rustfmt, @@ -463,35 +462,29 @@ impl Config { "flags.exclude" = ?flags_exclude ); - // First initialize the bare minimum that we need for further operation - source directory - // and execution context. - let mut config = Config::default_opts(); - let exec_ctx = ExecutionContext::new(flags_verbose, flags_cmd.fail_fast()); - - config.exec_ctx = exec_ctx; + // Set config values based on flags. + let mut exec_ctx = ExecutionContext::new(flags_verbose, flags_cmd.fail_fast()); + exec_ctx.set_dry_run(if flags_dry_run { DryRun::UserSelected } else { DryRun::Disabled }); + let mut src = { + let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + // Undo `src/bootstrap` + manifest_dir.parent().unwrap().parent().unwrap().to_owned() + }; - if let Some(src) = compute_src_directory(flags_src, &config.exec_ctx) { - config.src = src; + if let Some(src_) = compute_src_directory(flags_src, &exec_ctx) { + src = src_; } // Now load the TOML config, as soon as possible - let (mut toml, toml_path) = load_toml_config(&config.src, flags_config, &get_toml); - config.config = toml_path.clone(); - - postprocess_toml( - &mut toml, - &config.src, - toml_path, - config.exec_ctx(), - &flags_set, - &get_toml, - ); + let (mut toml, toml_path) = load_toml_config(&src, flags_config, &get_toml); + + postprocess_toml(&mut toml, &src, toml_path.clone(), &exec_ctx, &flags_set, &get_toml); // Now override TOML values with flags, to make sure that we won't later override flags with // TOML values by accident instead, because flags have higher priority. let Build { description: build_description, - build: mut build_build, + build: build_build, host: build_host, target: build_target, build_dir: build_build_dir, @@ -538,7 +531,7 @@ impl Config { metrics: _, android_ndk: build_android_ndk, optimized_compiler_builtins: build_optimized_compiler_builtins, - jobs: mut build_jobs, + jobs: build_jobs, compiletest_diff_tool: build_compiletest_diff_tool, compiletest_use_stage0_libtest: build_compiletest_use_stage0_libtest, tidy_extra_checks: build_tidy_extra_checks, @@ -656,6 +649,58 @@ impl Config { let Gcc { download_ci_gcc: gcc_download_ci_gcc } = toml.gcc.unwrap_or_default(); + if rust_optimize.as_ref().is_some_and(|v| matches!(v, RustOptimize::Bool(false))) { + eprintln!( + "WARNING: setting `optimize` to `false` is known to cause errors and \ + should be considered unsupported. Refer to `bootstrap.example.toml` \ + for more details." + ); + } + + // Prefer CLI verbosity flags if set (`flags_verbose` > 0), otherwise take the value from + // TOML. + exec_ctx.set_verbosity(cmp::max(build_verbose.unwrap_or_default() as u8, flags_verbose)); + + let stage0_metadata = build_helper::stage0_parser::parse_stage0_file(); + let path_modification_cache = Arc::new(Mutex::new(HashMap::new())); + + let host_target = flags_build + .or(build_build) + .map(|build| TargetSelection::from_user(&build)) + .unwrap_or_else(get_host_target); + let hosts = flags_host + .map(|TargetSelectionList(hosts)| hosts) + .or_else(|| { + build_host.map(|h| h.iter().map(|t| TargetSelection::from_user(t)).collect()) + }) + .unwrap_or_else(|| vec![host_target]); + + let llvm_assertions = llvm_assertions.unwrap_or(false); + let mut target_config = HashMap::new(); + let mut channel = "dev".to_string(); + let out = flags_build_dir.or(build_build_dir.map(PathBuf::from)).unwrap_or_else(|| { + if cfg!(test) { + // Use the build directory of the original x.py invocation, so that we can set `initial_rustc` properly. + Path::new( + &env::var_os("CARGO_TARGET_DIR").expect("cargo test directly is not supported"), + ) + .parent() + .unwrap() + .to_path_buf() + } else { + PathBuf::from("build") + } + }); + + // NOTE: Bootstrap spawns various commands with different working directories. + // To avoid writing to random places on the file system, `config.out` needs to be an absolute path. + let mut out = if !out.is_absolute() { + // `canonicalize` requires the path to already exist. Use our vendored copy of `absolute` instead. + absolute(&out).expect("can't make empty path absolute") + } else { + out + }; + if cfg!(test) { // When configuring bootstrap for tests, make sure to set the rustc and Cargo to the // same ones used to call the tests (if custom ones are not defined in the toml). If we @@ -666,118 +711,13 @@ impl Config { build_cargo = build_cargo.take().or(std::env::var_os("CARGO").map(|p| p.into())); } - build_jobs = flags_jobs.or(build_jobs); - build_build = flags_build.or(build_build); - - let build_dir = flags_build_dir.or(build_build_dir.map(PathBuf::from)); - let host = if let Some(TargetSelectionList(hosts)) = flags_host { - Some(hosts) - } else { - build_host - .map(|file_host| file_host.iter().map(|h| TargetSelection::from_user(h)).collect()) - }; - let target = if let Some(TargetSelectionList(targets)) = flags_target { - Some(targets) - } else { - build_target.map(|file_target| { - file_target.iter().map(|h| TargetSelection::from_user(h)).collect() - }) - }; - - if let Some(rustc) = &build_rustc - && !flags_skip_stage0_validation - { - check_stage0_version(rustc, "rustc", &config.src, config.exec_ctx()); - } - if let Some(cargo) = &build_cargo - && !flags_skip_stage0_validation - { - check_stage0_version(cargo, "cargo", &config.src, config.exec_ctx()); - } - - // Prefer CLI verbosity flags if set (`flags_verbose` > 0), otherwise take the value from - // TOML. - config - .exec_ctx - .set_verbosity(cmp::max(build_verbose.unwrap_or_default() as u8, flags_verbose)); - - let mut paths: Vec<PathBuf> = flags_skip.into_iter().chain(flags_exclude).collect(); - if let Some(exclude) = build_exclude { - paths.extend(exclude); - } - - // Set config values based on flags. - config.paths = flags_paths; - config.include_default_paths = flags_include_default_paths; - config.rustc_error_format = flags_rustc_error_format; - config.json_output = flags_json_output; - config.compile_time_deps = flags_compile_time_deps; - config.on_fail = flags_on_fail; - config.cmd = flags_cmd; - config.incremental = flags_incremental; - config.set_dry_run(if flags_dry_run { DryRun::UserSelected } else { DryRun::Disabled }); - config.dump_bootstrap_shims = flags_dump_bootstrap_shims; - config.keep_stage = flags_keep_stage; - config.keep_stage_std = flags_keep_stage_std; - config.color = flags_color; - config.free_args = flags_free_args; - config.llvm_profile_use = flags_llvm_profile_use; - config.llvm_profile_generate = flags_llvm_profile_generate; - config.enable_bolt_settings = flags_enable_bolt_settings; - config.bypass_bootstrap_lock = flags_bypass_bootstrap_lock; - config.is_running_on_ci = flags_ci.unwrap_or(CiEnv::is_ci()); - config.skip_std_check_if_no_download_rustc = flags_skip_std_check_if_no_download_rustc; - - // Infer the rest of the configuration. - - if cfg!(test) { - // Use the build directory of the original x.py invocation, so that we can set `initial_rustc` properly. - config.out = Path::new( - &env::var_os("CARGO_TARGET_DIR").expect("cargo test directly is not supported"), - ) - .parent() - .unwrap() - .to_path_buf(); - } - - config.compiletest_allow_stage0 = build_compiletest_allow_stage0.unwrap_or(false); - config.stage0_metadata = build_helper::stage0_parser::parse_stage0_file(); - - config.change_id = toml.change_id.inner; - - config.skip = paths - .into_iter() - .map(|p| { - // Never return top-level path here as it would break `--skip` - // logic on rustc's internal test framework which is utilized - // by compiletest. - if cfg!(windows) { - PathBuf::from(p.to_str().unwrap().replace('/', "\\")) - } else { - p - } - }) - .collect(); - - #[cfg(feature = "tracing")] - span!( - target: "CONFIG_HANDLING", - tracing::Level::TRACE, - "normalizing and combining `flag.skip`/`flag.exclude` paths", - "config.skip" = ?config.skip, - ); - - config.jobs = Some(threads_from_config(build_jobs.unwrap_or(0))); - if let Some(build) = build_build { - config.host_target = TargetSelection::from_user(&build); - } - - set(&mut config.out, build_dir); - // NOTE: Bootstrap spawns various commands with different working directories. - // To avoid writing to random places on the file system, `config.out` needs to be an absolute path. - if !config.out.is_absolute() { - // `canonicalize` requires the path to already exist. Use our vendored copy of `absolute` instead. - config.out = absolute(&config.out).expect("can't make empty path absolute"); + if !flags_skip_stage0_validation { + if let Some(rustc) = &build_rustc { + check_stage0_version(rustc, "rustc", &src, &exec_ctx); + } + if let Some(cargo) = &build_cargo { + check_stage0_version(cargo, "cargo", &src, &exec_ctx); + } } if build_cargo_clippy.is_some() && build_rustc.is_none() { @@ -786,146 +726,68 @@ impl Config { ); } - config.initial_rustc = if let Some(rustc) = build_rustc { - rustc - } else { - let dwn_ctx = DownloadContext::from(&config); - download_beta_toolchain(dwn_ctx); - config - .out - .join(config.host_target) - .join("stage0") - .join("bin") - .join(exe("rustc", config.host_target)) + let is_running_on_ci = flags_ci.unwrap_or(CiEnv::is_ci()); + let dwn_ctx = DownloadContext { + path_modification_cache: path_modification_cache.clone(), + src: &src, + submodules: &build_submodules, + host_target, + patch_binaries_for_nix: build_patch_binaries_for_nix, + exec_ctx: &exec_ctx, + stage0_metadata: &stage0_metadata, + llvm_assertions, + bootstrap_cache_path: &build_bootstrap_cache_path, + is_running_on_ci, }; - config.initial_sysroot = t!(PathBuf::from_str( - command(&config.initial_rustc) + let initial_rustc = build_rustc.unwrap_or_else(|| { + download_beta_toolchain(&dwn_ctx, &out); + out.join(host_target).join("stage0").join("bin").join(exe("rustc", host_target)) + }); + + let initial_sysroot = t!(PathBuf::from_str( + command(&initial_rustc) .args(["--print", "sysroot"]) .run_in_dry_run() - .run_capture_stdout(&config) + .run_capture_stdout(&exec_ctx) .stdout() .trim() )); - config.initial_cargo_clippy = build_cargo_clippy; - - config.initial_cargo = if let Some(cargo) = build_cargo { - cargo - } else { - let dwn_ctx = DownloadContext::from(&config); - download_beta_toolchain(dwn_ctx); - config.initial_sysroot.join("bin").join(exe("cargo", config.host_target)) - }; + let initial_cargo = build_cargo.unwrap_or_else(|| { + download_beta_toolchain(&dwn_ctx, &out); + initial_sysroot.join("bin").join(exe("cargo", host_target)) + }); // NOTE: it's important this comes *after* we set `initial_rustc` just above. - if config.dry_run() { - let dir = config.out.join("tmp-dry-run"); - t!(fs::create_dir_all(&dir)); - config.out = dir; + if exec_ctx.dry_run() { + out = out.join("tmp-dry-run"); + fs::create_dir_all(&out).expect("Failed to create dry-run directory"); } - config.hosts = if let Some(hosts) = host { hosts } else { vec![config.host_target] }; - config.targets = if let Some(targets) = target { - targets - } else { - // If target is *not* configured, then default to the host - // toolchains. - config.hosts.clone() - }; - - config.nodejs = build_nodejs.map(PathBuf::from); - config.npm = build_npm.map(PathBuf::from); - config.gdb = build_gdb.map(PathBuf::from); - config.lldb = build_lldb.map(PathBuf::from); - config.python = build_python.map(PathBuf::from); - config.reuse = build_reuse.map(PathBuf::from); - config.submodules = build_submodules; - config.android_ndk = build_android_ndk; - config.bootstrap_cache_path = build_bootstrap_cache_path; - set(&mut config.low_priority, build_low_priority); - set(&mut config.compiler_docs, build_compiler_docs); - set(&mut config.library_docs_private_items, build_library_docs_private_items); - set(&mut config.docs_minification, build_docs_minification); - set(&mut config.docs, build_docs); - set(&mut config.locked_deps, build_locked_deps); - set(&mut config.full_bootstrap, build_full_bootstrap); - set(&mut config.extended, build_extended); - config.tools = build_tools; - set(&mut config.tool, build_tool); - set(&mut config.sanitizers, build_sanitizers); - set(&mut config.profiler, build_profiler); - set(&mut config.cargo_native_static, build_cargo_native_static); - set(&mut config.configure_args, build_configure_args); - set(&mut config.local_rebuild, build_local_rebuild); - set(&mut config.print_step_timings, build_print_step_timings); - set(&mut config.print_step_rusage, build_print_step_rusage); - config.patch_binaries_for_nix = build_patch_binaries_for_nix; - - // Verbose flag is a good default for `rust.verbose-tests`. - config.verbose_tests = config.is_verbose(); - - config.prefix = install_prefix.map(PathBuf::from); - config.sysconfdir = install_sysconfdir.map(PathBuf::from); - config.datadir = install_datadir.map(PathBuf::from); - config.docdir = install_docdir.map(PathBuf::from); - set(&mut config.bindir, install_bindir.map(PathBuf::from)); - config.libdir = install_libdir.map(PathBuf::from); - config.mandir = install_mandir.map(PathBuf::from); - - config.llvm_assertions = llvm_assertions.unwrap_or(false); - - let file_content = t!(fs::read_to_string(config.src.join("src/ci/channel"))); + let file_content = t!(fs::read_to_string(src.join("src/ci/channel"))); let ci_channel = file_content.trim_end(); let is_user_configured_rust_channel = match rust_channel { - Some(channel) if channel == "auto-detect" => { - config.channel = ci_channel.into(); + Some(channel_) if channel_ == "auto-detect" => { + channel = ci_channel.into(); true } - Some(channel) => { - config.channel = channel; + Some(channel_) => { + channel = channel_; true } None => false, }; - let default = config.channel == "dev"; - config.omit_git_hash = rust_omit_git_hash.unwrap_or(default); + let omit_git_hash = rust_omit_git_hash.unwrap_or(channel == "dev"); - config.rust_info = git_info(&config.exec_ctx, config.omit_git_hash, &config.src); - config.cargo_info = - git_info(&config.exec_ctx, config.omit_git_hash, &config.src.join("src/tools/cargo")); - config.rust_analyzer_info = git_info( - &config.exec_ctx, - config.omit_git_hash, - &config.src.join("src/tools/rust-analyzer"), - ); - config.clippy_info = - git_info(&config.exec_ctx, config.omit_git_hash, &config.src.join("src/tools/clippy")); - config.miri_info = - git_info(&config.exec_ctx, config.omit_git_hash, &config.src.join("src/tools/miri")); - config.rustfmt_info = - git_info(&config.exec_ctx, config.omit_git_hash, &config.src.join("src/tools/rustfmt")); - config.enzyme_info = - git_info(&config.exec_ctx, config.omit_git_hash, &config.src.join("src/tools/enzyme")); - config.in_tree_llvm_info = - git_info(&config.exec_ctx, false, &config.src.join("src/llvm-project")); - config.in_tree_gcc_info = git_info(&config.exec_ctx, false, &config.src.join("src/gcc")); - - config.vendor = build_vendor.unwrap_or( - config.rust_info.is_from_tarball() - && config.src.join("vendor").exists() - && config.src.join(".cargo/config.toml").exists(), - ); + let rust_info = git_info(&exec_ctx, omit_git_hash, &src); - if !is_user_configured_rust_channel && config.rust_info.is_from_tarball() { - config.channel = ci_channel.into(); + if !is_user_configured_rust_channel && rust_info.is_from_tarball() { + channel = ci_channel.into(); } - config.rust_profile_use = flags_rust_profile_use; - config.rust_profile_generate = flags_rust_profile_generate; - // FIXME(#133381): alt rustc builds currently do *not* have rustc debug assertions // enabled. We should not download a CI alt rustc if we need rustc to have debug // assertions (e.g. for crashes test suite). This can be changed once something like @@ -951,17 +813,32 @@ impl Config { ); } - let dwn_ctx = DownloadContext::from(&config); - config.download_rustc_commit = - download_ci_rustc_commit(dwn_ctx, rust_download_rustc, config.llvm_assertions); + let mut download_rustc_commit = + download_ci_rustc_commit(&dwn_ctx, &rust_info, rust_download_rustc, llvm_assertions); - if debug_assertions_requested && config.download_rustc_commit.is_some() { + if debug_assertions_requested && download_rustc_commit.is_some() { eprintln!( "WARN: `rust.debug-assertions = true` will prevent downloading CI rustc as alt CI \ rustc is not currently built with debug assertions." ); // We need to put this later down_ci_rustc_commit. - config.download_rustc_commit = None; + download_rustc_commit = None; + } + + // We need to override `rust.channel` if it's manually specified when using the CI rustc. + // This is because if the compiler uses a different channel than the one specified in bootstrap.toml, + // tests may fail due to using a different channel than the one used by the compiler during tests. + if let Some(commit) = &download_rustc_commit + && is_user_configured_rust_channel + { + println!( + "WARNING: `rust.download-rustc` is enabled. The `rust.channel` option will be overridden by the CI rustc's channel." + ); + + channel = + read_file_by_commit(&dwn_ctx, &rust_info, Path::new("src/ci/channel"), commit) + .trim() + .to_owned(); } if let Some(t) = toml.target { @@ -969,24 +846,22 @@ impl Config { let mut target = Target::from_triple(&triple); if let Some(ref s) = cfg.llvm_config { - if config.download_rustc_commit.is_some() - && triple == *config.host_target.triple - { + if download_rustc_commit.is_some() && triple == *host_target.triple { panic!( "setting llvm_config for the host is incompatible with download-rustc" ); } - target.llvm_config = Some(config.src.join(s)); + target.llvm_config = Some(src.join(s)); } if let Some(patches) = cfg.llvm_has_rust_patches { assert!( - config.submodules == Some(false) || cfg.llvm_config.is_some(), + build_submodules == Some(false) || cfg.llvm_config.is_some(), "use of `llvm-has-rust-patches` is restricted to cases where either submodules are disabled or llvm-config been provided" ); target.llvm_has_rust_patches = Some(patches); } if let Some(ref s) = cfg.llvm_filecheck { - target.llvm_filecheck = Some(config.src.join(s)); + target.llvm_filecheck = Some(src.join(s)); } target.llvm_libunwind = cfg.llvm_libunwind.as_ref().map(|v| { v.parse().unwrap_or_else(|_| { @@ -1023,82 +898,18 @@ impl Config { }) }); - config.target_config.insert(TargetSelection::from_user(&triple), target); + target_config.insert(TargetSelection::from_user(&triple), target); } } - if rust_optimize.as_ref().is_some_and(|v| matches!(v, RustOptimize::Bool(false))) { - eprintln!( - "WARNING: setting `optimize` to `false` is known to cause errors and \ - should be considered unsupported. Refer to `bootstrap.example.toml` \ - for more details." - ); - } - - config.rust_new_symbol_mangling = rust_new_symbol_mangling; - set(&mut config.rust_optimize_tests, rust_optimize_tests); - set(&mut config.codegen_tests, rust_codegen_tests); - set(&mut config.rust_rpath, rust_rpath); - set(&mut config.rust_strip, rust_strip); - set(&mut config.rust_frame_pointers, rust_frame_pointers); - config.rust_stack_protector = rust_stack_protector; - set(&mut config.jemalloc, rust_jemalloc); - set(&mut config.test_compare_mode, rust_test_compare_mode); - set(&mut config.backtrace, rust_backtrace); - set(&mut config.rust_dist_src, rust_dist_src); - set(&mut config.verbose_tests, rust_verbose_tests); - // in the case "false" is set explicitly, do not overwrite the command line args - if let Some(true) = rust_incremental { - config.incremental = true; - } - set(&mut config.lld_mode, rust_lld_mode); - set(&mut config.llvm_bitcode_linker_enabled, rust_llvm_bitcode_linker); - - config.rust_randomize_layout = rust_randomize_layout.unwrap_or_default(); - config.llvm_tools_enabled = rust_llvm_tools.unwrap_or(true); - - config.llvm_enzyme = config.channel == "dev" || config.channel == "nightly"; - config.rustc_default_linker = rust_default_linker; - config.musl_root = rust_musl_root.map(PathBuf::from); - config.save_toolstates = rust_save_toolstates.map(PathBuf::from); - set( - &mut config.deny_warnings, - match flags_warnings { - Warnings::Deny => Some(true), - Warnings::Warn => Some(false), - Warnings::Default => rust_deny_warnings, - }, - ); - set(&mut config.backtrace_on_ice, rust_backtrace_on_ice); - set(&mut config.rust_verify_llvm_ir, rust_verify_llvm_ir); - config.rust_thin_lto_import_instr_limit = rust_thin_lto_import_instr_limit; - set(&mut config.rust_remap_debuginfo, rust_remap_debuginfo); - set(&mut config.control_flow_guard, rust_control_flow_guard); - set(&mut config.ehcont_guard, rust_ehcont_guard); - config.llvm_libunwind_default = - rust_llvm_libunwind.map(|v| v.parse().expect("failed to parse rust.llvm-libunwind")); - set( - &mut config.rust_codegen_backends, - rust_codegen_backends.map(|backends| parse_codegen_backends(backends, "rust")), + let llvm_from_ci = parse_download_ci_llvm( + &dwn_ctx, + &rust_info, + &download_rustc_commit, + llvm_download_ci_llvm, + llvm_assertions, ); - config.rust_codegen_units = rust_codegen_units.map(threads_from_config); - config.rust_codegen_units_std = rust_codegen_units_std.map(threads_from_config); - - if config.rust_profile_use.is_none() { - config.rust_profile_use = rust_profile_use; - } - - if config.rust_profile_generate.is_none() { - config.rust_profile_generate = rust_profile_generate; - } - - config.rust_lto = - rust_lto.as_deref().map(|value| RustcLto::from_str(value).unwrap()).unwrap_or_default(); - config.rust_validate_mir_opts = rust_validate_mir_opts; - - config.rust_optimize = rust_optimize.unwrap_or(RustOptimize::Bool(true)); - // We make `x86_64-unknown-linux-gnu` use the self-contained linker by default, so we will // build our internal lld and use it as the default linker, by setting the `rust.lld` config // to true by default: @@ -1111,105 +922,17 @@ impl Config { // thus, disabled // - similarly, lld will not be built nor used by default when explicitly asked not to, e.g. // when the config sets `rust.lld = false` - if default_lld_opt_in_targets().contains(&config.host_target.triple.to_string()) - && config.hosts == [config.host_target] + let lld_enabled = if default_lld_opt_in_targets().contains(&host_target.triple.to_string()) + && hosts == [host_target] { - let no_llvm_config = config - .target_config - .get(&config.host_target) - .is_none_or(|target_config| target_config.llvm_config.is_none()); - let enable_lld = config.llvm_from_ci || no_llvm_config; - // Prefer the config setting in case an explicit opt-out is needed. - config.lld_enabled = rust_lld_enabled.unwrap_or(enable_lld); + let no_llvm_config = + target_config.get(&host_target).is_none_or(|config| config.llvm_config.is_none()); + rust_lld_enabled.unwrap_or(llvm_from_ci || no_llvm_config) } else { - set(&mut config.lld_enabled, rust_lld_enabled); - } - - let default_std_features = BTreeSet::from([String::from("panic-unwind")]); - config.rust_std_features = rust_std_features.unwrap_or(default_std_features); - - let default = rust_debug == Some(true); - config.rustc_debug_assertions = rust_rustc_debug_assertions.unwrap_or(default); - config.std_debug_assertions = - rust_std_debug_assertions.unwrap_or(config.rustc_debug_assertions); - config.tools_debug_assertions = - rust_tools_debug_assertions.unwrap_or(config.rustc_debug_assertions); - config.rust_overflow_checks = rust_overflow_checks.unwrap_or(default); - config.rust_overflow_checks_std = - rust_overflow_checks_std.unwrap_or(config.rust_overflow_checks); - - config.rust_debug_logging = rust_debug_logging.unwrap_or(config.rustc_debug_assertions); - - let with_defaults = |debuginfo_level_specific: Option<_>| { - debuginfo_level_specific.or(rust_debuginfo_level).unwrap_or( - if rust_debug == Some(true) { - DebuginfoLevel::Limited - } else { - DebuginfoLevel::None - }, - ) + rust_lld_enabled.unwrap_or(false) }; - config.rust_debuginfo_level_rustc = with_defaults(rust_debuginfo_level_rustc); - config.rust_debuginfo_level_std = with_defaults(rust_debuginfo_level_std); - config.rust_debuginfo_level_tools = with_defaults(rust_debuginfo_level_tools); - config.rust_debuginfo_level_tests = - rust_debuginfo_level_tests.unwrap_or(DebuginfoLevel::None); - - config.reproducible_artifacts = flags_reproducible_artifact; - config.description = build_description; - - // We need to override `rust.channel` if it's manually specified when using the CI rustc. - // This is because if the compiler uses a different channel than the one specified in bootstrap.toml, - // 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 - && is_user_configured_rust_channel - { - println!( - "WARNING: `rust.download-rustc` is enabled. The `rust.channel` option will be overridden by the CI rustc's channel." - ); - - let dwn_ctx = DownloadContext::from(&config); - let channel = - read_file_by_commit(dwn_ctx, Path::new("src/ci/channel"), commit).trim().to_owned(); - - config.channel = channel; - } - set(&mut config.ninja_in_file, llvm_ninja); - set(&mut config.llvm_optimize, llvm_optimize); - set(&mut config.llvm_thin_lto, llvm_thin_lto); - set(&mut config.llvm_release_debuginfo, llvm_release_debuginfo); - set(&mut config.llvm_static_stdcpp, llvm_static_libstdcpp); - set(&mut config.llvm_libzstd, llvm_libzstd); - if let Some(v) = llvm_link_shared { - config.llvm_link_shared.set(Some(v)); - } - config.llvm_targets.clone_from(&llvm_targets); - config.llvm_experimental_targets.clone_from(&llvm_experimental_targets); - config.llvm_link_jobs = llvm_link_jobs; - config.llvm_version_suffix.clone_from(&llvm_version_suffix); - config.llvm_clang_cl.clone_from(&llvm_clang_cl); - config.llvm_tests = llvm_tests.unwrap_or_default(); - config.llvm_enzyme = llvm_enzyme.unwrap_or_default(); - config.llvm_plugins = llvm_plugin.unwrap_or_default(); - - config.llvm_cflags.clone_from(&llvm_cflags); - config.llvm_cxxflags.clone_from(&llvm_cxxflags); - config.llvm_ldflags.clone_from(&llvm_ldflags); - set(&mut config.llvm_use_libcxx, llvm_use_libcxx); - config.llvm_use_linker.clone_from(&llvm_use_linker); - config.llvm_allow_old_toolchain = llvm_allow_old_toolchain.unwrap_or(false); - config.llvm_offload = llvm_offload.unwrap_or(false); - config.llvm_polly = llvm_polly.unwrap_or(false); - config.llvm_clang = llvm_clang.unwrap_or(false); - config.llvm_enable_warnings = llvm_enable_warnings.unwrap_or(false); - config.llvm_build_config = llvm_build_config.clone().unwrap_or(Default::default()); - - let dwn_ctx = DownloadContext::from(&config); - config.llvm_from_ci = - parse_download_ci_llvm(dwn_ctx, llvm_download_ci_llvm, config.llvm_assertions); - - if config.llvm_from_ci { + if llvm_from_ci { let warn = |option: &str| { println!( "WARNING: `{option}` will only be used on `compiler/rustc_llvm` build, not for the LLVM build." @@ -1244,66 +967,21 @@ impl Config { } } - if !config.llvm_from_ci && config.llvm_thin_lto && llvm_link_shared.is_none() { - // If we're building with ThinLTO on, by default we want to link - // to LLVM shared, to avoid re-doing ThinLTO (which happens in - // the link step) with each stage. - config.llvm_link_shared.set(Some(true)); - } - - config.gcc_ci_mode = match gcc_download_ci_gcc { - Some(value) => match value { - true => GccCiMode::DownloadFromCi, - false => GccCiMode::BuildLocally, - }, - None => GccCiMode::default(), - }; - - match build_ccache { - Some(StringOrBool::String(ref s)) => config.ccache = Some(s.to_string()), - Some(StringOrBool::Bool(true)) => { - config.ccache = Some("ccache".to_string()); - } - Some(StringOrBool::Bool(false)) | None => {} - } - - if config.llvm_from_ci { - let triple = &config.host_target.triple; - let dwn_ctx = DownloadContext::from(&config); - let ci_llvm_bin = ci_llvm_root(dwn_ctx).join("bin"); - let build_target = config - .target_config - .entry(config.host_target) - .or_insert_with(|| Target::from_triple(triple)); - + if llvm_from_ci { + let triple = &host_target.triple; + let ci_llvm_bin = ci_llvm_root(&dwn_ctx, llvm_from_ci, &out).join("bin"); + let build_target = + target_config.entry(host_target).or_insert_with(|| Target::from_triple(triple)); check_ci_llvm!(build_target.llvm_config); check_ci_llvm!(build_target.llvm_filecheck); - build_target.llvm_config = - Some(ci_llvm_bin.join(exe("llvm-config", config.host_target))); - build_target.llvm_filecheck = - Some(ci_llvm_bin.join(exe("FileCheck", config.host_target))); + build_target.llvm_config = Some(ci_llvm_bin.join(exe("llvm-config", host_target))); + build_target.llvm_filecheck = Some(ci_llvm_bin.join(exe("FileCheck", host_target))); } - config.dist_sign_folder = dist_sign_folder.map(PathBuf::from); - config.dist_upload_addr = dist_upload_addr; - config.dist_compression_formats = dist_compression_formats; - set(&mut config.dist_compression_profile, dist_compression_profile); - set(&mut config.rust_dist_src, dist_src_tarball); - set(&mut config.dist_include_mingw_linker, dist_include_mingw_linker); - config.dist_vendor = dist_vendor.unwrap_or_else(|| { - // If we're building from git or tarball sources, enable it by default. - config.rust_info.is_managed_git_subrepository() || config.rust_info.is_from_tarball() - }); - - config.initial_rustfmt = if let Some(r) = build_rustfmt { - Some(r) - } else { - let dwn_ctx = DownloadContext::from(&config); - maybe_download_rustfmt(dwn_ctx) - }; + let initial_rustfmt = build_rustfmt.or_else(|| maybe_download_rustfmt(&dwn_ctx, &out)); - if matches!(config.lld_mode, LldMode::SelfContained) - && !config.lld_enabled + if matches!(rust_lld_mode.unwrap_or_default(), LldMode::SelfContained) + && !lld_enabled && flags_stage.unwrap_or(0) > 0 { panic!( @@ -1311,29 +989,13 @@ impl Config { ); } - let dwn_ctx = DownloadContext::from(&config); - if config.lld_enabled && is_system_llvm(dwn_ctx, config.host_target) { + if lld_enabled && is_system_llvm(&dwn_ctx, &target_config, llvm_from_ci, host_target) { panic!("Cannot enable LLD with `rust.lld = true` when using external llvm-config."); } - config.optimized_compiler_builtins = - build_optimized_compiler_builtins.unwrap_or(config.channel != "dev"); - config.compiletest_diff_tool = build_compiletest_diff_tool; - config.compiletest_use_stage0_libtest = - build_compiletest_use_stage0_libtest.unwrap_or(true); - config.tidy_extra_checks = build_tidy_extra_checks; + let download_rustc = download_rustc_commit.is_some(); - let download_rustc = config.download_rustc_commit.is_some(); - config.explicit_stage_from_cli = flags_stage.is_some(); - config.explicit_stage_from_config = build_test_stage.is_some() - || build_build_stage.is_some() - || build_doc_stage.is_some() - || build_dist_stage.is_some() - || build_install_stage.is_some() - || build_check_stage.is_some() - || build_bench_stage.is_some(); - - config.stage = match config.cmd { + let stage = match flags_cmd { Subcommand::Check { .. } => flags_stage.or(build_check_stage).unwrap_or(1), Subcommand::Clippy { .. } | Subcommand::Fix => { flags_stage.or(build_check_stage).unwrap_or(1) @@ -1362,7 +1024,7 @@ impl Config { }; // Now check that the selected stage makes sense, and if not, print a warning and end - match (config.stage, &config.cmd) { + match (stage, &flags_cmd) { (0, Subcommand::Build { .. }) => { eprintln!("ERROR: cannot build anything on stage 0. Use at least stage 1."); exit!(1); @@ -1382,7 +1044,7 @@ impl Config { _ => {} } - if config.compile_time_deps && !matches!(config.cmd, Subcommand::Check { .. }) { + if flags_compile_time_deps && !matches!(flags_cmd, Subcommand::Check { .. }) { eprintln!( "WARNING: Can't use --compile-time-deps with any subcommand other than check." ); @@ -1391,8 +1053,8 @@ impl Config { // CI should always run stage 2 builds, unless it specifically states otherwise #[cfg(not(test))] - if flags_stage.is_none() && config.is_running_on_ci { - match config.cmd { + if flags_stage.is_none() && is_running_on_ci { + match flags_cmd { Subcommand::Test { .. } | Subcommand::Miri { .. } | Subcommand::Doc { .. } @@ -1401,9 +1063,8 @@ impl Config { | Subcommand::Dist | Subcommand::Install => { assert_eq!( - config.stage, 2, - "x.py should be run with `--stage 2` on CI, but was run with `--stage {}`", - config.stage, + stage, 2, + "x.py should be run with `--stage 2` on CI, but was run with `--stage {stage}`", ); } Subcommand::Clean { .. } @@ -1418,7 +1079,296 @@ impl Config { } } - config + let with_defaults = |debuginfo_level_specific: Option<_>| { + debuginfo_level_specific.or(rust_debuginfo_level).unwrap_or( + if rust_debug == Some(true) { + DebuginfoLevel::Limited + } else { + DebuginfoLevel::None + }, + ) + }; + + let ccache = match build_ccache { + Some(StringOrBool::String(s)) => Some(s), + Some(StringOrBool::Bool(true)) => Some("ccache".to_string()), + _ => None, + }; + + let explicit_stage_from_config = build_test_stage.is_some() + || build_build_stage.is_some() + || build_doc_stage.is_some() + || build_dist_stage.is_some() + || build_install_stage.is_some() + || build_check_stage.is_some() + || build_bench_stage.is_some(); + + let deny_warnings = match flags_warnings { + Warnings::Deny => true, + Warnings::Warn => false, + Warnings::Default => rust_deny_warnings.unwrap_or(true), + }; + + let gcc_ci_mode = match gcc_download_ci_gcc { + Some(value) => match value { + true => GccCiMode::DownloadFromCi, + false => GccCiMode::BuildLocally, + }, + None => GccCiMode::default(), + }; + + let targets = flags_target + .map(|TargetSelectionList(targets)| targets) + .or_else(|| { + build_target.map(|t| t.iter().map(|t| TargetSelection::from_user(t)).collect()) + }) + .unwrap_or_else(|| hosts.clone()); + + #[allow(clippy::map_identity)] + let skip = flags_skip + .into_iter() + .chain(flags_exclude) + .chain(build_exclude.unwrap_or_default()) + .map(|p| { + // Never return top-level path here as it would break `--skip` + // logic on rustc's internal test framework which is utilized by compiletest. + #[cfg(windows)] + { + PathBuf::from(p.to_string_lossy().replace('/', "\\")) + } + #[cfg(not(windows))] + { + p + } + }) + .collect(); + + let cargo_info = git_info(&exec_ctx, omit_git_hash, &src.join("src/tools/cargo")); + let clippy_info = git_info(&exec_ctx, omit_git_hash, &src.join("src/tools/clippy")); + let in_tree_gcc_info = git_info(&exec_ctx, false, &src.join("src/gcc")); + let in_tree_llvm_info = git_info(&exec_ctx, false, &src.join("src/llvm-project")); + let enzyme_info = git_info(&exec_ctx, omit_git_hash, &src.join("src/tools/enzyme")); + let miri_info = git_info(&exec_ctx, omit_git_hash, &src.join("src/tools/miri")); + let rust_analyzer_info = + git_info(&exec_ctx, omit_git_hash, &src.join("src/tools/rust-analyzer")); + let rustfmt_info = git_info(&exec_ctx, omit_git_hash, &src.join("src/tools/rustfmt")); + + let optimized_compiler_builtins = + build_optimized_compiler_builtins.unwrap_or(channel != "dev"); + let vendor = build_vendor.unwrap_or( + rust_info.is_from_tarball() + && src.join("vendor").exists() + && src.join(".cargo/config.toml").exists(), + ); + let verbose_tests = rust_verbose_tests.unwrap_or(exec_ctx.is_verbose()); + + Config { + // tidy-alphabetical-start + android_ndk: build_android_ndk, + backtrace: rust_backtrace.unwrap_or(true), + backtrace_on_ice: rust_backtrace_on_ice.unwrap_or(false), + bindir: install_bindir.map(PathBuf::from).unwrap_or("bin".into()), + bootstrap_cache_path: build_bootstrap_cache_path, + bypass_bootstrap_lock: flags_bypass_bootstrap_lock, + cargo_info, + cargo_native_static: build_cargo_native_static.unwrap_or(false), + ccache, + change_id: toml.change_id.inner, + channel, + clippy_info, + cmd: flags_cmd, + codegen_tests: rust_codegen_tests.unwrap_or(true), + color: flags_color, + compile_time_deps: flags_compile_time_deps, + compiler_docs: build_compiler_docs.unwrap_or(false), + compiletest_allow_stage0: build_compiletest_allow_stage0.unwrap_or(false), + compiletest_diff_tool: build_compiletest_diff_tool, + compiletest_use_stage0_libtest: build_compiletest_use_stage0_libtest.unwrap_or(true), + config: toml_path, + configure_args: build_configure_args.unwrap_or_default(), + control_flow_guard: rust_control_flow_guard.unwrap_or(false), + datadir: install_datadir.map(PathBuf::from), + deny_warnings, + description: build_description, + dist_compression_formats, + dist_compression_profile: dist_compression_profile.unwrap_or("fast".into()), + dist_include_mingw_linker: dist_include_mingw_linker.unwrap_or(true), + dist_sign_folder: dist_sign_folder.map(PathBuf::from), + dist_upload_addr, + dist_vendor: dist_vendor.unwrap_or_else(|| { + // If we're building from git or tarball sources, enable it by default. + rust_info.is_managed_git_subrepository() || rust_info.is_from_tarball() + }), + docdir: install_docdir.map(PathBuf::from), + docs: build_docs.unwrap_or(true), + docs_minification: build_docs_minification.unwrap_or(true), + download_rustc_commit, + dump_bootstrap_shims: flags_dump_bootstrap_shims, + ehcont_guard: rust_ehcont_guard.unwrap_or(false), + enable_bolt_settings: flags_enable_bolt_settings, + enzyme_info, + exec_ctx, + explicit_stage_from_cli: flags_stage.is_some(), + explicit_stage_from_config, + extended: build_extended.unwrap_or(false), + free_args: flags_free_args, + full_bootstrap: build_full_bootstrap.unwrap_or(false), + gcc_ci_mode, + gdb: build_gdb.map(PathBuf::from), + host_target, + hosts, + in_tree_gcc_info, + in_tree_llvm_info, + include_default_paths: flags_include_default_paths, + incremental: flags_incremental || rust_incremental == Some(true), + initial_cargo, + initial_cargo_clippy: build_cargo_clippy, + initial_rustc, + initial_rustfmt, + initial_sysroot, + is_running_on_ci, + jemalloc: rust_jemalloc.unwrap_or(false), + jobs: Some(threads_from_config(flags_jobs.or(build_jobs).unwrap_or(0))), + json_output: flags_json_output, + keep_stage: flags_keep_stage, + keep_stage_std: flags_keep_stage_std, + libdir: install_libdir.map(PathBuf::from), + library_docs_private_items: build_library_docs_private_items.unwrap_or(false), + lld_enabled, + lld_mode: rust_lld_mode.unwrap_or_default(), + lldb: build_lldb.map(PathBuf::from), + llvm_allow_old_toolchain: llvm_allow_old_toolchain.unwrap_or(false), + llvm_assertions, + llvm_bitcode_linker_enabled: rust_llvm_bitcode_linker.unwrap_or(false), + llvm_build_config: llvm_build_config.clone().unwrap_or(Default::default()), + llvm_cflags, + llvm_clang: llvm_clang.unwrap_or(false), + llvm_clang_cl, + llvm_cxxflags, + llvm_enable_warnings: llvm_enable_warnings.unwrap_or(false), + llvm_enzyme: llvm_enzyme.unwrap_or(false), + llvm_experimental_targets, + llvm_from_ci, + llvm_ldflags, + llvm_libunwind_default: rust_llvm_libunwind + .map(|v| v.parse().expect("failed to parse rust.llvm-libunwind")), + llvm_libzstd: llvm_libzstd.unwrap_or(false), + llvm_link_jobs, + // If we're building with ThinLTO on, by default we want to link + // to LLVM shared, to avoid re-doing ThinLTO (which happens in + // the link step) with each stage. + llvm_link_shared: Cell::new( + llvm_link_shared + .or((!llvm_from_ci && llvm_thin_lto.unwrap_or(false)).then_some(true)), + ), + llvm_offload: llvm_offload.unwrap_or(false), + llvm_optimize: llvm_optimize.unwrap_or(true), + llvm_plugins: llvm_plugin.unwrap_or(false), + llvm_polly: llvm_polly.unwrap_or(false), + llvm_profile_generate: flags_llvm_profile_generate, + llvm_profile_use: flags_llvm_profile_use, + llvm_release_debuginfo: llvm_release_debuginfo.unwrap_or(false), + llvm_static_stdcpp: llvm_static_libstdcpp.unwrap_or(false), + llvm_targets, + llvm_tests: llvm_tests.unwrap_or(false), + llvm_thin_lto: llvm_thin_lto.unwrap_or(false), + llvm_tools_enabled: rust_llvm_tools.unwrap_or(true), + llvm_use_libcxx: llvm_use_libcxx.unwrap_or(false), + llvm_use_linker, + llvm_version_suffix, + local_rebuild: build_local_rebuild.unwrap_or(false), + locked_deps: build_locked_deps.unwrap_or(false), + low_priority: build_low_priority.unwrap_or(false), + mandir: install_mandir.map(PathBuf::from), + miri_info, + musl_root: rust_musl_root.map(PathBuf::from), + ninja_in_file: llvm_ninja.unwrap_or(true), + nodejs: build_nodejs.map(PathBuf::from), + npm: build_npm.map(PathBuf::from), + omit_git_hash, + on_fail: flags_on_fail, + optimized_compiler_builtins, + out, + patch_binaries_for_nix: build_patch_binaries_for_nix, + path_modification_cache, + paths: flags_paths, + prefix: install_prefix.map(PathBuf::from), + print_step_rusage: build_print_step_rusage.unwrap_or(false), + print_step_timings: build_print_step_timings.unwrap_or(false), + profiler: build_profiler.unwrap_or(false), + python: build_python.map(PathBuf::from), + reproducible_artifacts: flags_reproducible_artifact, + reuse: build_reuse.map(PathBuf::from), + rust_analyzer_info, + rust_codegen_backends: rust_codegen_backends + .map(|backends| parse_codegen_backends(backends, "rust")) + .unwrap_or(vec![CodegenBackendKind::Llvm]), + rust_codegen_units: rust_codegen_units.map(threads_from_config), + rust_codegen_units_std: rust_codegen_units_std.map(threads_from_config), + rust_debug_logging: rust_debug_logging + .or(rust_rustc_debug_assertions) + .unwrap_or(rust_debug == Some(true)), + rust_debuginfo_level_rustc: with_defaults(rust_debuginfo_level_rustc), + rust_debuginfo_level_std: with_defaults(rust_debuginfo_level_std), + rust_debuginfo_level_tests: rust_debuginfo_level_tests.unwrap_or(DebuginfoLevel::None), + rust_debuginfo_level_tools: with_defaults(rust_debuginfo_level_tools), + rust_dist_src: dist_src_tarball.unwrap_or_else(|| rust_dist_src.unwrap_or(true)), + rust_frame_pointers: rust_frame_pointers.unwrap_or(false), + rust_info, + rust_lto: rust_lto + .as_deref() + .map(|value| RustcLto::from_str(value).unwrap()) + .unwrap_or_default(), + rust_new_symbol_mangling, + rust_optimize: rust_optimize.unwrap_or(RustOptimize::Bool(true)), + rust_optimize_tests: rust_optimize_tests.unwrap_or(true), + rust_overflow_checks: rust_overflow_checks.unwrap_or(rust_debug == Some(true)), + rust_overflow_checks_std: rust_overflow_checks_std + .or(rust_overflow_checks) + .unwrap_or(rust_debug == Some(true)), + rust_profile_generate: flags_rust_profile_generate.or(rust_profile_generate), + rust_profile_use: flags_rust_profile_use.or(rust_profile_use), + rust_randomize_layout: rust_randomize_layout.unwrap_or(false), + rust_remap_debuginfo: rust_remap_debuginfo.unwrap_or(false), + rust_rpath: rust_rpath.unwrap_or(true), + rust_stack_protector, + rust_std_features: rust_std_features + .unwrap_or(BTreeSet::from([String::from("panic-unwind")])), + rust_strip: rust_strip.unwrap_or(false), + rust_thin_lto_import_instr_limit, + rust_validate_mir_opts, + rust_verify_llvm_ir: rust_verify_llvm_ir.unwrap_or(false), + rustc_debug_assertions: rust_rustc_debug_assertions.unwrap_or(rust_debug == Some(true)), + rustc_default_linker: rust_default_linker, + rustc_error_format: flags_rustc_error_format, + rustfmt_info, + sanitizers: build_sanitizers.unwrap_or(false), + save_toolstates: rust_save_toolstates.map(PathBuf::from), + skip, + skip_std_check_if_no_download_rustc: flags_skip_std_check_if_no_download_rustc, + src, + stage, + stage0_metadata, + std_debug_assertions: rust_std_debug_assertions + .or(rust_rustc_debug_assertions) + .unwrap_or(rust_debug == Some(true)), + stderr_is_tty: std::io::stderr().is_terminal(), + stdout_is_tty: std::io::stdout().is_terminal(), + submodules: build_submodules, + sysconfdir: install_sysconfdir.map(PathBuf::from), + target_config, + targets, + test_compare_mode: rust_test_compare_mode.unwrap_or(false), + tidy_extra_checks: build_tidy_extra_checks, + tool: build_tool.unwrap_or_default(), + tools: build_tools, + tools_debug_assertions: rust_tools_debug_assertions + .or(rust_rustc_debug_assertions) + .unwrap_or(rust_debug == Some(true)), + vendor, + verbose_tests, + // tidy-alphabetical-end + } } pub fn dry_run(&self) -> bool { @@ -1456,7 +1406,7 @@ impl Config { /// Returns the content of the given file at a specific commit. pub(crate) fn read_file_by_commit(&self, file: &Path, commit: &str) -> String { let dwn_ctx = DownloadContext::from(self); - read_file_by_commit(dwn_ctx, file, commit) + read_file_by_commit(dwn_ctx, &self.rust_info, file, commit) } /// Bootstrap embeds a version number into the name of shared libraries it uploads in CI. @@ -1528,7 +1478,7 @@ impl Config { /// The absolute path to the downloaded LLVM artifacts. pub(crate) fn ci_llvm_root(&self) -> PathBuf { let dwn_ctx = DownloadContext::from(self); - ci_llvm_root(dwn_ctx) + ci_llvm_root(dwn_ctx, self.llvm_from_ci, &self.out) } /// Directory where the extracted `rustc-dev` component is stored. @@ -1692,7 +1642,7 @@ impl Config { )] pub(crate) fn update_submodule(&self, relative_path: &str) { let dwn_ctx = DownloadContext::from(self); - update_submodule(dwn_ctx, relative_path); + update_submodule(dwn_ctx, &self.rust_info, relative_path); } /// Returns true if any of the `paths` have been modified locally. @@ -1808,7 +1758,7 @@ impl Config { /// NOTE: this is not the same as `!is_rust_llvm` when `llvm_has_patches` is set. pub fn is_system_llvm(&self, target: TargetSelection) -> bool { let dwn_ctx = DownloadContext::from(self); - is_system_llvm(dwn_ctx, target) + is_system_llvm(dwn_ctx, &self.target_config, self.llvm_from_ci, target) } /// Returns `true` if this is our custom, patched, version of LLVM. @@ -2102,6 +2052,7 @@ pub fn check_stage0_version( pub fn download_ci_rustc_commit<'a>( dwn_ctx: impl AsRef<DownloadContext<'a>>, + rust_info: &channel::GitInfo, download_rustc: Option<StringOrBool>, llvm_assertions: bool, ) -> Option<String> { @@ -2121,7 +2072,7 @@ pub fn download_ci_rustc_commit<'a>( None | Some(StringOrBool::Bool(false)) => return None, Some(StringOrBool::Bool(true)) => false, Some(StringOrBool::String(s)) if s == "if-unchanged" => { - if !dwn_ctx.rust_info.is_managed_git_subrepository() { + if !rust_info.is_managed_git_subrepository() { println!( "ERROR: `download-rustc=if-unchanged` is only compatible with Git managed sources." ); @@ -2135,7 +2086,7 @@ pub fn download_ci_rustc_commit<'a>( } }; - let commit = if dwn_ctx.rust_info.is_managed_git_subrepository() { + let commit = if rust_info.is_managed_git_subrepository() { // Look for a version to compare to based on the current commit. // Only commits merged by bors will have CI artifacts. let freshness = check_path_modifications_(dwn_ctx, RUSTC_IF_UNCHANGED_ALLOWED_PATHS); @@ -2209,6 +2160,8 @@ pub fn git_config(stage0_metadata: &build_helper::stage0_parser::Stage0) -> GitC pub fn parse_download_ci_llvm<'a>( dwn_ctx: impl AsRef<DownloadContext<'a>>, + rust_info: &channel::GitInfo, + download_rustc_commit: &Option<String>, download_ci_llvm: Option<StringOrBool>, asserts: bool, ) -> bool { @@ -2224,7 +2177,7 @@ pub fn parse_download_ci_llvm<'a>( let download_ci_llvm = download_ci_llvm.unwrap_or(default); let if_unchanged = || { - if dwn_ctx.rust_info.is_from_tarball() { + if rust_info.is_from_tarball() { // Git is needed for running "if-unchanged" logic. println!("ERROR: 'if-unchanged' is only compatible with Git managed sources."); crate::exit!(1); @@ -2232,7 +2185,7 @@ pub fn parse_download_ci_llvm<'a>( // Fetching the LLVM submodule is unnecessary for self-tests. #[cfg(not(test))] - update_submodule(dwn_ctx, "src/llvm-project"); + update_submodule(dwn_ctx, rust_info, "src/llvm-project"); // Check for untracked changes in `src/llvm-project` and other important places. let has_changes = has_changes_from_upstream(dwn_ctx, LLVM_INVALIDATION_PATHS); @@ -2247,7 +2200,7 @@ pub fn parse_download_ci_llvm<'a>( match download_ci_llvm { StringOrBool::Bool(b) => { - if !b && dwn_ctx.download_rustc_commit.is_some() { + if !b && download_rustc_commit.is_some() { panic!( "`llvm.download-ci-llvm` cannot be set to `false` if `rust.download-rustc` is set to `true` or `if-unchanged`." ); @@ -2290,9 +2243,13 @@ pub fn has_changes_from_upstream<'a>( fields(relative_path = ?relative_path), ), )] -pub(crate) fn update_submodule<'a>(dwn_ctx: impl AsRef<DownloadContext<'a>>, relative_path: &str) { +pub(crate) fn update_submodule<'a>( + dwn_ctx: impl AsRef<DownloadContext<'a>>, + rust_info: &channel::GitInfo, + relative_path: &str, +) { let dwn_ctx = dwn_ctx.as_ref(); - if dwn_ctx.rust_info.is_from_tarball() || !submodules_(dwn_ctx.submodules, dwn_ctx.rust_info) { + if rust_info.is_from_tarball() || !submodules_(dwn_ctx.submodules, rust_info) { return; } @@ -2421,12 +2378,14 @@ pub fn submodules_(submodules: &Option<bool>, rust_info: &channel::GitInfo) -> b /// NOTE: this is not the same as `!is_rust_llvm` when `llvm_has_patches` is set. pub fn is_system_llvm<'a>( dwn_ctx: impl AsRef<DownloadContext<'a>>, + target_config: &HashMap<TargetSelection, Target>, + llvm_from_ci: bool, target: TargetSelection, ) -> bool { let dwn_ctx = dwn_ctx.as_ref(); - match dwn_ctx.target_config.get(&target) { + match target_config.get(&target) { Some(Target { llvm_config: Some(_), .. }) => { - let ci_llvm = dwn_ctx.llvm_from_ci && is_host_target(&dwn_ctx.host_target, &target); + let ci_llvm = llvm_from_ci && is_host_target(&dwn_ctx.host_target, &target); !ci_llvm } // We're building from the in-tree src/llvm-project sources. @@ -2439,21 +2398,26 @@ pub fn is_host_target(host_target: &TargetSelection, target: &TargetSelection) - host_target == target } -pub(crate) fn ci_llvm_root<'a>(dwn_ctx: impl AsRef<DownloadContext<'a>>) -> PathBuf { +pub(crate) fn ci_llvm_root<'a>( + dwn_ctx: impl AsRef<DownloadContext<'a>>, + llvm_from_ci: bool, + out: &Path, +) -> PathBuf { let dwn_ctx = dwn_ctx.as_ref(); - assert!(dwn_ctx.llvm_from_ci); - dwn_ctx.out.join(dwn_ctx.host_target).join("ci-llvm") + assert!(llvm_from_ci); + out.join(dwn_ctx.host_target).join("ci-llvm") } /// Returns the content of the given file at a specific commit. pub(crate) fn read_file_by_commit<'a>( dwn_ctx: impl AsRef<DownloadContext<'a>>, + rust_info: &channel::GitInfo, file: &Path, commit: &str, ) -> String { let dwn_ctx = dwn_ctx.as_ref(); assert!( - dwn_ctx.rust_info.is_managed_git_subrepository(), + rust_info.is_managed_git_subrepository(), "`Config::read_file_by_commit` is not supported in non-git sources." ); diff --git a/src/bootstrap/src/core/config/mod.rs b/src/bootstrap/src/core/config/mod.rs index 8c5f9037251..dbd05fd2519 100644 --- a/src/bootstrap/src/core/config/mod.rs +++ b/src/bootstrap/src/core/config/mod.rs @@ -402,12 +402,6 @@ pub enum GccCiMode { DownloadFromCi, } -pub fn set<T>(field: &mut T, val: Option<T>) { - if let Some(v) = val { - *field = v; - } -} - pub fn threads_from_config(v: u32) -> u32 { match v { 0 => std::thread::available_parallelism().map_or(1, std::num::NonZeroUsize::get) as u32, diff --git a/src/bootstrap/src/core/download.rs b/src/bootstrap/src/core/download.rs index 5ded44cef14..2f3c80559c0 100644 --- a/src/bootstrap/src/core/download.rs +++ b/src/bootstrap/src/core/download.rs @@ -9,9 +9,8 @@ use std::sync::{Arc, Mutex, OnceLock}; use build_helper::git::PathFreshness; use xz2::bufread::XzDecoder; -use crate::core::config::{BUILDER_CONFIG_FILENAME, Target, TargetSelection}; +use crate::core::config::{BUILDER_CONFIG_FILENAME, TargetSelection}; use crate::utils::build_stamp::BuildStamp; -use crate::utils::channel; use crate::utils::exec::{ExecutionContext, command}; use crate::utils::helpers::{exe, hex_encode, move_file}; use crate::{Config, t}; @@ -73,7 +72,7 @@ impl Config { fn download_file(&self, url: &str, dest_path: &Path, help_on_error: &str) { let dwn_ctx: DownloadContext<'_> = self.into(); - download_file(dwn_ctx, url, dest_path, help_on_error); + download_file(dwn_ctx, &self.out, url, dest_path, help_on_error); } fn unpack(&self, tarball: &Path, dst: &Path, pattern: &str) { @@ -238,7 +237,7 @@ impl Config { destination: &str, ) { let dwn_ctx: DownloadContext<'_> = self.into(); - download_component(dwn_ctx, mode, filename, prefix, key, destination); + download_component(dwn_ctx, &self.out, mode, filename, prefix, key, destination); } #[cfg(test)] @@ -403,13 +402,8 @@ impl Config { pub(crate) struct DownloadContext<'a> { pub path_modification_cache: Arc<Mutex<HashMap<Vec<&'static str>, PathFreshness>>>, pub src: &'a Path, - pub rust_info: &'a channel::GitInfo, pub submodules: &'a Option<bool>, - pub download_rustc_commit: &'a Option<String>, pub host_target: TargetSelection, - pub llvm_from_ci: bool, - pub target_config: &'a HashMap<TargetSelection, Target>, - pub out: &'a Path, pub patch_binaries_for_nix: Option<bool>, pub exec_ctx: &'a ExecutionContext, pub stage0_metadata: &'a build_helper::stage0_parser::Stage0, @@ -430,12 +424,7 @@ impl<'a> From<&'a Config> for DownloadContext<'a> { path_modification_cache: value.path_modification_cache.clone(), src: &value.src, host_target: value.host_target, - rust_info: &value.rust_info, - download_rustc_commit: &value.download_rustc_commit, submodules: &value.submodules, - llvm_from_ci: value.llvm_from_ci, - target_config: &value.target_config, - out: &value.out, patch_binaries_for_nix: value.patch_binaries_for_nix, exec_ctx: &value.exec_ctx, stage0_metadata: &value.stage0_metadata, @@ -495,6 +484,7 @@ pub(crate) fn is_download_ci_available(target_triple: &str, llvm_assertions: boo #[cfg(test)] pub(crate) fn maybe_download_rustfmt<'a>( dwn_ctx: impl AsRef<DownloadContext<'a>>, + out: &Path, ) -> Option<PathBuf> { Some(PathBuf::new()) } @@ -504,6 +494,7 @@ pub(crate) fn maybe_download_rustfmt<'a>( #[cfg(not(test))] pub(crate) fn maybe_download_rustfmt<'a>( dwn_ctx: impl AsRef<DownloadContext<'a>>, + out: &Path, ) -> Option<PathBuf> { use build_helper::stage0_parser::VersionMetadata; @@ -517,7 +508,7 @@ pub(crate) fn maybe_download_rustfmt<'a>( let channel = format!("{version}-{date}"); let host = dwn_ctx.host_target; - let bin_root = dwn_ctx.out.join(host).join("rustfmt"); + let bin_root = out.join(host).join("rustfmt"); let rustfmt_path = bin_root.join("bin").join(exe("rustfmt", host)); let rustfmt_stamp = BuildStamp::new(&bin_root).with_prefix("rustfmt").add_stamp(channel); if rustfmt_path.exists() && rustfmt_stamp.is_up_to_date() { @@ -526,6 +517,7 @@ pub(crate) fn maybe_download_rustfmt<'a>( download_component( dwn_ctx, + out, DownloadSource::Dist, format!("rustfmt-{version}-{build}.tar.xz", build = host.triple), "rustfmt-preview", @@ -535,6 +527,7 @@ pub(crate) fn maybe_download_rustfmt<'a>( download_component( dwn_ctx, + out, DownloadSource::Dist, format!("rustc-{version}-{build}.tar.xz", build = host.triple), "rustc", @@ -543,13 +536,13 @@ pub(crate) fn maybe_download_rustfmt<'a>( ); if should_fix_bins_and_dylibs(dwn_ctx.patch_binaries_for_nix, dwn_ctx.exec_ctx) { - fix_bin_or_dylib(dwn_ctx.out, &bin_root.join("bin").join("rustfmt"), dwn_ctx.exec_ctx); - fix_bin_or_dylib(dwn_ctx.out, &bin_root.join("bin").join("cargo-fmt"), dwn_ctx.exec_ctx); + fix_bin_or_dylib(out, &bin_root.join("bin").join("rustfmt"), dwn_ctx.exec_ctx); + fix_bin_or_dylib(out, &bin_root.join("bin").join("cargo-fmt"), dwn_ctx.exec_ctx); let lib_dir = bin_root.join("lib"); for lib in t!(fs::read_dir(&lib_dir), lib_dir.display().to_string()) { let lib = t!(lib); if path_is_dylib(&lib.path()) { - fix_bin_or_dylib(dwn_ctx.out, &lib.path(), dwn_ctx.exec_ctx); + fix_bin_or_dylib(out, &lib.path(), dwn_ctx.exec_ctx); } } } @@ -559,10 +552,10 @@ pub(crate) fn maybe_download_rustfmt<'a>( } #[cfg(test)] -pub(crate) fn download_beta_toolchain<'a>(dwn_ctx: impl AsRef<DownloadContext<'a>>) {} +pub(crate) fn download_beta_toolchain<'a>(dwn_ctx: impl AsRef<DownloadContext<'a>>, out: &Path) {} #[cfg(not(test))] -pub(crate) fn download_beta_toolchain<'a>(dwn_ctx: impl AsRef<DownloadContext<'a>>) { +pub(crate) fn download_beta_toolchain<'a>(dwn_ctx: impl AsRef<DownloadContext<'a>>, out: &Path) { let dwn_ctx = dwn_ctx.as_ref(); dwn_ctx.exec_ctx.verbose(|| { println!("downloading stage0 beta artifacts"); @@ -574,6 +567,7 @@ pub(crate) fn download_beta_toolchain<'a>(dwn_ctx: impl AsRef<DownloadContext<'a let sysroot = "stage0"; download_toolchain( dwn_ctx, + out, &version, sysroot, &date, @@ -583,8 +577,10 @@ pub(crate) fn download_beta_toolchain<'a>(dwn_ctx: impl AsRef<DownloadContext<'a ); } +#[allow(clippy::too_many_arguments)] fn download_toolchain<'a>( dwn_ctx: impl AsRef<DownloadContext<'a>>, + out: &Path, version: &str, sysroot: &str, stamp_key: &str, @@ -594,7 +590,7 @@ fn download_toolchain<'a>( ) { let dwn_ctx = dwn_ctx.as_ref(); let host = dwn_ctx.host_target.triple; - let bin_root = dwn_ctx.out.join(host).join(sysroot); + let bin_root = out.join(host).join(sysroot); let rustc_stamp = BuildStamp::new(&bin_root).with_prefix("rustc").add_stamp(stamp_key); if !bin_root.join("bin").join(exe("rustc", dwn_ctx.host_target)).exists() @@ -605,20 +601,28 @@ fn download_toolchain<'a>( } let filename = format!("rust-std-{version}-{host}.tar.xz"); let pattern = format!("rust-std-{host}"); - download_component(dwn_ctx, mode.clone(), filename, &pattern, stamp_key, destination); + download_component(dwn_ctx, out, mode.clone(), filename, &pattern, stamp_key, destination); let filename = format!("rustc-{version}-{host}.tar.xz"); - download_component(dwn_ctx, mode.clone(), filename, "rustc", stamp_key, destination); + download_component(dwn_ctx, out, mode.clone(), filename, "rustc", stamp_key, destination); for component in extra_components { let filename = format!("{component}-{version}-{host}.tar.xz"); - download_component(dwn_ctx, mode.clone(), filename, component, stamp_key, destination); + download_component( + dwn_ctx, + out, + mode.clone(), + filename, + component, + stamp_key, + destination, + ); } if should_fix_bins_and_dylibs(dwn_ctx.patch_binaries_for_nix, dwn_ctx.exec_ctx) { - fix_bin_or_dylib(dwn_ctx.out, &bin_root.join("bin").join("rustc"), dwn_ctx.exec_ctx); - fix_bin_or_dylib(dwn_ctx.out, &bin_root.join("bin").join("rustdoc"), dwn_ctx.exec_ctx); + fix_bin_or_dylib(out, &bin_root.join("bin").join("rustc"), dwn_ctx.exec_ctx); + fix_bin_or_dylib(out, &bin_root.join("bin").join("rustdoc"), dwn_ctx.exec_ctx); fix_bin_or_dylib( - dwn_ctx.out, + out, &bin_root.join("libexec").join("rust-analyzer-proc-macro-srv"), dwn_ctx.exec_ctx, ); @@ -626,7 +630,7 @@ fn download_toolchain<'a>( for lib in t!(fs::read_dir(&lib_dir), lib_dir.display().to_string()) { let lib = t!(lib); if path_is_dylib(&lib.path()) { - fix_bin_or_dylib(dwn_ctx.out, &lib.path(), dwn_ctx.exec_ctx); + fix_bin_or_dylib(out, &lib.path(), dwn_ctx.exec_ctx); } } } @@ -750,6 +754,7 @@ fn should_fix_bins_and_dylibs( fn download_component<'a>( dwn_ctx: impl AsRef<DownloadContext<'a>>, + out: &Path, mode: DownloadSource, filename: String, prefix: &str, @@ -763,14 +768,14 @@ fn download_component<'a>( } let cache_dst = - dwn_ctx.bootstrap_cache_path.as_ref().cloned().unwrap_or_else(|| dwn_ctx.out.join("cache")); + dwn_ctx.bootstrap_cache_path.as_ref().cloned().unwrap_or_else(|| out.join("cache")); let cache_dir = cache_dst.join(key); if !cache_dir.exists() { t!(fs::create_dir_all(&cache_dir)); } - let bin_root = dwn_ctx.out.join(dwn_ctx.host_target).join(destination); + let bin_root = out.join(dwn_ctx.host_target).join(destination); let tarball = cache_dir.join(&filename); let (base_url, url, should_verify) = match mode { DownloadSource::CI => { @@ -835,7 +840,7 @@ HELP: if trying to compile an old commit of rustc, disable `download-rustc` in b download-rustc = false "; } - download_file(dwn_ctx, &format!("{base_url}/{url}"), &tarball, help_on_error); + download_file(dwn_ctx, out, &format!("{base_url}/{url}"), &tarball, help_on_error); if let Some(sha256) = checksum && !verify(dwn_ctx.exec_ctx, &tarball, sha256) { @@ -953,6 +958,7 @@ fn unpack(exec_ctx: &ExecutionContext, tarball: &Path, dst: &Path, pattern: &str fn download_file<'a>( dwn_ctx: impl AsRef<DownloadContext<'a>>, + out: &Path, url: &str, dest_path: &Path, help_on_error: &str, @@ -963,7 +969,7 @@ fn download_file<'a>( println!("download {url}"); }); // Use a temporary file in case we crash while downloading, to avoid a corrupt download in cache/. - let tempfile = tempdir(dwn_ctx.out).join(dest_path.file_name().unwrap()); + let tempfile = tempdir(out).join(dest_path.file_name().unwrap()); // While bootstrap itself only supports http and https downloads, downstream forks might // need to download components from other protocols. The match allows them adding more // protocols without worrying about merge conflicts if we change the HTTP implementation. diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs index bd02131b7fe..de7cada93f2 100644 --- a/src/bootstrap/src/core/sanity.rs +++ b/src/bootstrap/src/core/sanity.rs @@ -35,6 +35,7 @@ pub struct Finder { const STAGE0_MISSING_TARGETS: &[&str] = &[ "armv7a-vex-v5", // just a dummy comment so the list doesn't get onelined + "aarch64_be-unknown-hermit", "aarch64_be-unknown-none-softfloat", ]; @@ -327,6 +328,23 @@ than building it. .entry(*target) .or_insert_with(|| Target::from_triple(&target.triple)); + // compiler-rt c fallbacks for wasm cannot be built with gcc + if target.contains("wasm") + && (build.config.optimized_compiler_builtins(*target) + || build.config.rust_std_features.contains("compiler-builtins-c")) + { + let cc_tool = build.cc_tool(*target); + if !cc_tool.is_like_clang() && !cc_tool.path().ends_with("emcc") { + // emcc works as well + panic!( + "Clang is required to build C code for Wasm targets, got `{}` instead\n\ + this is because compiler-builtins is configured to build C source. Either \ + ensure Clang is used, or adjust this configuration.", + cc_tool.path().display() + ); + } + } + if (target.contains("-none-") || target.contains("nvptx")) && build.no_std(*target) == Some(false) { diff --git a/src/ci/docker/host-x86_64/dist-various-1/Dockerfile b/src/ci/docker/host-x86_64/dist-various-1/Dockerfile index 5c459e5cd18..4d5980027ca 100644 --- a/src/ci/docker/host-x86_64/dist-various-1/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-various-1/Dockerfile @@ -55,6 +55,12 @@ RUN ./install-riscv64-none-elf.sh COPY host-x86_64/dist-various-1/install-riscv32-none-elf.sh /build RUN ./install-riscv32-none-elf.sh +COPY host-x86_64/dist-various-1/install-emscripten.sh /build +RUN ./install-emscripten.sh + +# Add Emscripten to PATH +ENV PATH="/build/emsdk:/build/emsdk/upstream/emscripten:/build/emsdk/node/current/bin:${PATH}" + # Suppress some warnings in the openwrt toolchains we downloaded ENV STAGING_DIR=/tmp diff --git a/src/ci/docker/host-x86_64/dist-various-1/install-emscripten.sh b/src/ci/docker/host-x86_64/dist-various-1/install-emscripten.sh new file mode 100755 index 00000000000..eeb54ca67f7 --- /dev/null +++ b/src/ci/docker/host-x86_64/dist-various-1/install-emscripten.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +set -ex + +apt-get update +apt-get install -y --no-install-recommends \ + nodejs \ + default-jre + +git clone https://github.com/emscripten-core/emsdk.git +cd emsdk +./emsdk install latest +./emsdk activate latest diff --git a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile index 0855ea222a3..33d55123936 100644 --- a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile @@ -59,6 +59,10 @@ ENV \ CXX_i686_unknown_uefi=clang++-11 \ CC_x86_64_unknown_uefi=clang-11 \ CXX_x86_64_unknown_uefi=clang++-11 \ + CC_wasm32_unknown_unknown=clang-11 \ + CXX_wasm32_unknown_unknown=clang++-11 \ + CC_wasm32v1_none=clang-11 \ + CXX_wasm32v1_none=clang++-11 \ CC=gcc-9 \ CXX=g++-9 diff --git a/src/ci/docker/host-x86_64/test-various/Dockerfile b/src/ci/docker/host-x86_64/test-various/Dockerfile index 82a820c859d..6ff529c9e71 100644 --- a/src/ci/docker/host-x86_64/test-various/Dockerfile +++ b/src/ci/docker/host-x86_64/test-various/Dockerfile @@ -4,6 +4,7 @@ ARG DEBIAN_FRONTEND=noninteractive RUN apt-get update && apt-get install -y --no-install-recommends \ clang-11 \ llvm-11 \ + gcc-multilib \ g++ \ make \ ninja-build \ @@ -59,8 +60,8 @@ RUN curl -L https://github.com/bytecodealliance/wasmtime/releases/download/v19.0 tar -xJ ENV PATH "$PATH:/wasmtime-v19.0.0-x86_64-linux" -ENV WASM_TARGETS=wasm32-wasip1 -ENV WASM_SCRIPT python3 /checkout/x.py --stage 2 test --host='' --target $WASM_TARGETS \ +ENV WASM_WASIP_TARGET=wasm32-wasip1 +ENV WASM_WASIP_SCRIPT python3 /checkout/x.py --stage 2 test --host='' --target $WASM_WASIP_TARGET \ tests/run-make \ tests/ui \ tests/mir-opt \ @@ -91,4 +92,4 @@ ENV UEFI_SCRIPT python3 /checkout/x.py --stage 2 build --host='' --target $UEFI_ python3 /checkout/x.py --stage 2 test tests/run-make/uefi-qemu/rmake.rs --target i686-unknown-uefi && \ python3 /checkout/x.py --stage 2 test tests/run-make/uefi-qemu/rmake.rs --target x86_64-unknown-uefi -ENV SCRIPT $WASM_SCRIPT && $NVPTX_SCRIPT && $MUSL_SCRIPT && $UEFI_SCRIPT +ENV SCRIPT $WASM_WASIP_SCRIPT && $NVPTX_SCRIPT && $MUSL_SCRIPT && $UEFI_SCRIPT diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 8cfcc0c5b15..409d2cba821 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -28,7 +28,6 @@ runners: - &job-windows os: windows-2025 - free_disk: true <<: *base-job - &job-windows-8c diff --git a/src/ci/scripts/free-disk-space-windows-start.py b/src/ci/scripts/free-disk-space-windows-start.py deleted file mode 100644 index fbaad722bff..00000000000 --- a/src/ci/scripts/free-disk-space-windows-start.py +++ /dev/null @@ -1,72 +0,0 @@ -""" -Start freeing disk space on Windows in the background by launching -the PowerShell cleanup script, and recording the PID in a file, -so later steps can wait for completion. -""" - -import subprocess -from pathlib import Path -from free_disk_space_windows_util import get_pid_file, get_log_file, run_main - - -def get_cleanup_script() -> Path: - script_dir = Path(__file__).resolve().parent - cleanup_script = script_dir / "free-disk-space-windows.ps1" - if not cleanup_script.exists(): - raise Exception(f"Cleanup script '{cleanup_script}' not found") - return cleanup_script - - -def write_pid(pid: int): - pid_file = get_pid_file() - if pid_file.exists(): - raise Exception(f"Pid file '{pid_file}' already exists") - pid_file.write_text(str(pid)) - print(f"wrote pid {pid} in file {pid_file}") - - -def launch_cleanup_process(): - cleanup_script = get_cleanup_script() - log_file_path = get_log_file() - # Launch the PowerShell cleanup in the background and redirect logs. - try: - with open(log_file_path, "w", encoding="utf-8") as log_file: - proc = subprocess.Popen( - [ - "pwsh", - # Suppress PowerShell startup banner/logo for cleaner logs. - "-NoLogo", - # Don't load user/system profiles. Ensures a clean, predictable environment. - "-NoProfile", - # Disable interactive prompts. Required for CI to avoid hangs. - "-NonInteractive", - # Execute the specified script file (next argument). - "-File", - str(cleanup_script), - ], - # Write child stdout to the log file. - stdout=log_file, - # Merge stderr into stdout for a single, ordered log stream. - stderr=subprocess.STDOUT, - ) - print( - f"Started free-disk-space cleanup in background. " - f"pid={proc.pid}; log_file={log_file_path}" - ) - return proc - except FileNotFoundError as e: - raise Exception("pwsh not found on PATH; cannot start disk cleanup.") from e - - -def main() -> int: - proc = launch_cleanup_process() - - # Write pid of the process to a file, so that later steps can read it and wait - # until the process completes. - write_pid(proc.pid) - - return 0 - - -if __name__ == "__main__": - run_main(main) diff --git a/src/ci/scripts/free-disk-space-windows-wait.py b/src/ci/scripts/free-disk-space-windows-wait.py deleted file mode 100644 index d510781d534..00000000000 --- a/src/ci/scripts/free-disk-space-windows-wait.py +++ /dev/null @@ -1,92 +0,0 @@ -""" -Wait for the background Windows disk cleanup process. -""" - -import ctypes -import time -from free_disk_space_windows_util import get_pid_file, get_log_file, run_main - - -def is_process_running(pid: int) -> bool: - PROCESS_QUERY_LIMITED_INFORMATION = 0x1000 - processHandle = ctypes.windll.kernel32.OpenProcess( - PROCESS_QUERY_LIMITED_INFORMATION, 0, pid - ) - if processHandle == 0: - # The process is not running. - # If you don't have the sufficient rights to check if a process is running, - # zero is also returned. But in GitHub Actions we have these rights. - return False - else: - ctypes.windll.kernel32.CloseHandle(processHandle) - return True - - -def print_logs(): - """Print the logs from the cleanup script.""" - log_file = get_log_file() - if log_file.exists(): - print("free-disk-space logs:") - # Print entire log; replace undecodable bytes to avoid exceptions. - try: - with open(log_file, "r", encoding="utf-8", errors="replace") as f: - print(f.read()) - except Exception as e: - raise Exception(f"Failed to read log file '{log_file}'") from e - else: - print(f"::warning::Log file '{log_file}' not found") - - -def read_pid_from_file() -> int: - """Read the PID from the pid file.""" - - pid_file = get_pid_file() - if not pid_file.exists(): - raise Exception( - f"No background free-disk-space process to wait for: pid file {pid_file} not found" - ) - - pid_file_content = pid_file.read_text().strip() - - # Delete the file if it exists - pid_file.unlink(missing_ok=True) - - try: - # Read the first line and convert to int. - pid = int(pid_file_content.splitlines()[0]) - return pid - except Exception as e: - raise Exception( - f"Error while parsing the pid file with content '{pid_file_content!r}'" - ) from e - - -def wait_for_process(pid: int): - timeout_duration_seconds = 5 * 60 - interval_seconds = 3 - max_attempts = timeout_duration_seconds / interval_seconds - attempts = 0 - - # Poll until process exits - while is_process_running(pid): - if attempts >= max_attempts: - print( - "::warning::Timeout expired while waiting for the disk cleanup process to finish." - ) - break - time.sleep(interval_seconds) - attempts += 1 - - -def main() -> int: - pid = read_pid_from_file() - - wait_for_process(pid) - - print_logs() - - return 0 - - -if __name__ == "__main__": - run_main(main) diff --git a/src/ci/scripts/free-disk-space-windows.ps1 b/src/ci/scripts/free-disk-space-windows.ps1 deleted file mode 100644 index 8a4677bd2ab..00000000000 --- a/src/ci/scripts/free-disk-space-windows.ps1 +++ /dev/null @@ -1,35 +0,0 @@ -# Free disk space on Windows GitHub action runners. - -$ErrorActionPreference = 'Stop' - -Get-Volume | Out-String | Write-Output - -$available = $(Get-Volume C).SizeRemaining - -$dirs = 'C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\Llvm', -'C:\rtools45', 'C:\ghcup', 'C:\Program Files (x86)\Android', -'C:\Program Files\Google\Chrome', 'C:\Program Files (x86)\Microsoft\Edge', -'C:\Program Files\Mozilla Firefox', 'C:\Program Files\MySQL', 'C:\Julia', -'C:\Program Files\MongoDB', 'C:\Program Files\Azure Cosmos DB Emulator', -'C:\Program Files\PostgreSQL', 'C:\Program Files\Unity Hub', -'C:\Strawberry', 'C:\hostedtoolcache\windows\Java_Temurin-Hotspot_jdk' - -foreach ($dir in $dirs) { - Start-ThreadJob -InputObject $dir { - Remove-Item -Recurse -Force -LiteralPath $input - } | Out-Null -} - -foreach ($job in Get-Job) { - Wait-Job $job | Out-Null - if ($job.Error) { - Write-Output "::warning file=$PSCommandPath::$($job.Error)" - } - Remove-Job $job -} - -Get-Volume | Out-String | Write-Output - -$saved = ($(Get-Volume C).SizeRemaining - $available) / 1gb -$savedRounded = [math]::Round($saved, 3) -Write-Output "total space saved: $savedRounded GB" diff --git a/src/ci/scripts/free-disk-space.sh b/src/ci/scripts/free-disk-space.sh deleted file mode 100755 index 9264fe4de6d..00000000000 --- a/src/ci/scripts/free-disk-space.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash -set -euo pipefail - -script_dir=$(dirname "$0") - -if [[ "${RUNNER_OS:-}" == "Windows" ]]; then - python3 "$script_dir/free-disk-space-windows-start.py" -else - $script_dir/free-disk-space-linux.sh -fi diff --git a/src/ci/scripts/free_disk_space_windows_util.py b/src/ci/scripts/free_disk_space_windows_util.py deleted file mode 100644 index 488187864c2..00000000000 --- a/src/ci/scripts/free_disk_space_windows_util.py +++ /dev/null @@ -1,29 +0,0 @@ -""" -Utilities for Windows disk space cleanup scripts. -""" - -import os -from pathlib import Path -import sys - - -def get_temp_dir() -> Path: - """Get the temporary directory set by GitHub Actions.""" - return Path(os.environ.get("RUNNER_TEMP")) - - -def get_pid_file() -> Path: - return get_temp_dir() / "free-disk-space.pid" - - -def get_log_file() -> Path: - return get_temp_dir() / "free-disk-space.log" - - -def run_main(main_fn): - exit_code = 1 - try: - exit_code = main_fn() - except Exception as e: - print(f"::error::{e}") - sys.exit(exit_code) diff --git a/src/doc/rustc-dev-guide/src/autodiff/internals.md b/src/doc/rustc-dev-guide/src/autodiff/internals.md index c1b31a0e4bd..c8e304f814b 100644 --- a/src/doc/rustc-dev-guide/src/autodiff/internals.md +++ b/src/doc/rustc-dev-guide/src/autodiff/internals.md @@ -17,7 +17,7 @@ fn main() { The detailed documentation for the `std::autodiff` module is available at [std::autodiff](https://doc.rust-lang.org/std/autodiff/index.html). -Differentiable programing is used in various fields like numerical computing, [solid mechanics][ratel], [computational chemistry][molpipx], [fluid dynamics][waterlily] or for Neural Network training via Backpropagation, [ODE solver][diffsol], [differentiable rendering][libigl], [quantum computing][catalyst], and climate simulations. +Differentiable programming is used in various fields like numerical computing, [solid mechanics][ratel], [computational chemistry][molpipx], [fluid dynamics][waterlily] or for Neural Network training via Backpropagation, [ODE solver][diffsol], [differentiable rendering][libigl], [quantum computing][catalyst], and climate simulations. [ratel]: https://gitlab.com/micromorph/ratel [molpipx]: https://arxiv.org/abs/2411.17011v diff --git a/src/doc/rustc-dev-guide/src/solve/candidate-preference.md b/src/doc/rustc-dev-guide/src/solve/candidate-preference.md index 89605294735..8b28f56760a 100644 --- a/src/doc/rustc-dev-guide/src/solve/candidate-preference.md +++ b/src/doc/rustc-dev-guide/src/solve/candidate-preference.md @@ -95,7 +95,7 @@ fn overflow<T: Trait>() { ``` This preference causes a lot of issues. See [#24066]. Most of the -issues are caused by prefering where-bounds over impls even if the where-bound guides type inference: +issues are caused by preferring where-bounds over impls even if the where-bound guides type inference: ```rust trait Trait<T> { fn call_me(&self, x: T) {} diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index c039517a970..3bf87994297 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -270,6 +270,7 @@ target | std | host | notes [`aarch64-unknown-trusty`](platform-support/trusty.md) | ✓ | | [`aarch64-uwp-windows-msvc`](platform-support/uwp-windows-msvc.md) | ✓ | | [`aarch64-wrs-vxworks`](platform-support/vxworks.md) | ✓ | | ARM64 VxWorks OS +[`aarch64_be-unknown-hermit`](platform-support/hermit.md) | ✓ | | ARM64 Hermit (big-endian) `aarch64_be-unknown-linux-gnu` | ✓ | ✓ | ARM64 Linux (big-endian) `aarch64_be-unknown-linux-gnu_ilp32` | ✓ | ✓ | ARM64 Linux (big-endian, ILP32 ABI) [`aarch64_be-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | ARM64 NetBSD (big-endian) diff --git a/src/doc/rustc/src/platform-support/hermit.md b/src/doc/rustc/src/platform-support/hermit.md index 069c253bd38..8362d6f55fd 100644 --- a/src/doc/rustc/src/platform-support/hermit.md +++ b/src/doc/rustc/src/platform-support/hermit.md @@ -10,6 +10,7 @@ Target triplets available so far: - `x86_64-unknown-hermit` - `aarch64-unknown-hermit` +- `aarch64_be-unknown-hermit` - `riscv64gc-unknown-hermit` ## Target maintainers @@ -42,6 +43,7 @@ target = [ "<HOST_TARGET>", "x86_64-unknown-hermit", "aarch64-unknown-hermit", + "aarch64_be-unknown-hermit", "riscv64gc-unknown-hermit", ] diff --git a/src/doc/rustc/src/platform-support/wasm32-wali-linux.md b/src/doc/rustc/src/platform-support/wasm32-wali-linux.md index 3213e2b0c8f..001159b0d32 100644 --- a/src/doc/rustc/src/platform-support/wasm32-wali-linux.md +++ b/src/doc/rustc/src/platform-support/wasm32-wali-linux.md @@ -31,7 +31,7 @@ This target is cross-compiled and requires an installation of the [WALI compiler > **Note**: Users can expect that new enabled-by-default Wasm features for LLVM are transitively incorporatable into this target -- see [wasm32-unknown-unknown](wasm32-unknown-unknown.md) for detailed information on WebAssembly features. -> **Note**: The WALI ABI is similar to default Clang wasm32 ABIs but *not identical*. The primary difference is 64-bit `long` types as opposed to 32-bit for wasm32. This is required to mantain minimum source code changes for 64-bit host platforms currently supported. This may change in the future as the spec evolves. +> **Note**: The WALI ABI is similar to default Clang wasm32 ABIs but *not identical*. The primary difference is 64-bit `long` types as opposed to 32-bit for wasm32. This is required to maintain minimum source code changes for 64-bit host platforms currently supported. This may change in the future as the spec evolves. ### Execution Running generated WALI binaries also requires a supported compliant engine implementation -- a working implementation in the [WebAssembly Micro-Runtime (WAMR)](https://github.com/arjunr2/WALI) is included in the repo. diff --git a/src/doc/unstable-book/src/compiler-flags/randomize-layout.md b/src/doc/unstable-book/src/compiler-flags/randomize-layout.md index 84c6712bc23..81da0503d7f 100644 --- a/src/doc/unstable-book/src/compiler-flags/randomize-layout.md +++ b/src/doc/unstable-book/src/compiler-flags/randomize-layout.md @@ -7,7 +7,7 @@ The tracking issue for this feature is: [#106764](https://github.com/rust-lang/r The `-Zrandomize-layout` flag changes the layout algorithm for `repr(Rust)` types defined in the current crate from its normal optimization goals to pseudorandomly rearranging fields within the degrees of freedom provided by the largely unspecified default representation. This also affects type sizes and padding. -Downstream intantiations of generic types defined in a crate with randomization enabled will also be randomized. +Downstream instantiations of generic types defined in a crate with randomization enabled will also be randomized. It can be used to find unsafe code that accidentally relies on unspecified behavior. diff --git a/src/etc/lldb_lookup.py b/src/etc/lldb_lookup.py index f4ea904b7f5..f43d2c6a725 100644 --- a/src/etc/lldb_lookup.py +++ b/src/etc/lldb_lookup.py @@ -10,6 +10,9 @@ def is_hashbrown_hashmap(hash_map: lldb.SBValue) -> bool: def classify_rust_type(type: lldb.SBType) -> str: + if type.IsPointerType(): + type = type.GetPointeeType() + type_class = type.GetTypeClass() if type_class == lldb.eTypeClassStruct: return classify_struct(type.name, type.fields) diff --git a/src/etc/lldb_providers.py b/src/etc/lldb_providers.py index 98426e42423..65f18baa937 100644 --- a/src/etc/lldb_providers.py +++ b/src/etc/lldb_providers.py @@ -1,4 +1,5 @@ from __future__ import annotations +import re import sys from typing import List, TYPE_CHECKING @@ -410,6 +411,16 @@ class MSVCStrSyntheticProvider: return "&str" +def _getVariantName(variant) -> str: + """ + Since the enum variant's type name is in the form `TheEnumName::TheVariantName$Variant`, + we can extract `TheVariantName` from it for display purpose. + """ + s = variant.GetType().GetName() + match = re.search(r"::([^:]+)\$Variant$", s) + return match.group(1) if match else "" + + class ClangEncodedEnumProvider: """Pretty-printer for 'clang-encoded' enums support implemented in LLDB""" @@ -424,37 +435,25 @@ class ClangEncodedEnumProvider: return True def num_children(self) -> int: - if self.is_default: - return 1 - return 2 + return 1 - def get_child_index(self, name: str) -> int: - if name == ClangEncodedEnumProvider.VALUE_MEMBER_NAME: - return 0 - if name == ClangEncodedEnumProvider.DISCRIMINANT_MEMBER_NAME: - return 1 + def get_child_index(self, _name: str) -> int: return -1 def get_child_at_index(self, index: int) -> SBValue: if index == 0: - return self.variant.GetChildMemberWithName( + value = self.variant.GetChildMemberWithName( ClangEncodedEnumProvider.VALUE_MEMBER_NAME ) - if index == 1: - return self.variant.GetChildMemberWithName( - ClangEncodedEnumProvider.DISCRIMINANT_MEMBER_NAME + return value.CreateChildAtOffset( + _getVariantName(self.variant), 0, value.GetType() ) + return None def update(self): all_variants = self.valobj.GetChildAtIndex(0) index = self._getCurrentVariantIndex(all_variants) self.variant = all_variants.GetChildAtIndex(index) - self.is_default = ( - self.variant.GetIndexOfChildWithName( - ClangEncodedEnumProvider.DISCRIMINANT_MEMBER_NAME - ) - == -1 - ) def _getCurrentVariantIndex(self, all_variants: SBValue) -> int: default_index = 0 diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 46aaa0068de..92bd4a498ca 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1087,7 +1087,8 @@ pub(crate) fn extract_cfg_from_attrs<'a, I: Iterator<Item = &'a hir::Attribute> // treat #[target_feature(enable = "feat")] attributes as if they were // #[doc(cfg(target_feature = "feat"))] attributes as well - if let Some(features) = find_attr!(attrs, AttributeKind::TargetFeature(features, _) => features) + if let Some(features) = + find_attr!(attrs, AttributeKind::TargetFeature { features, .. } => features) { for (feature, _) in features { cfg &= Cfg::Cfg(sym::target_feature, Some(*feature)); diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs index 41657e290ea..dddc087d124 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -1494,7 +1494,9 @@ pub(crate) fn build_index( let search_unbox = match id { RenderTypeId::Mut => false, RenderTypeId::DefId(defid) => utils::has_doc_flag(tcx, defid, sym::search_unbox), - RenderTypeId::Primitive(PrimitiveType::Reference | PrimitiveType::Tuple) => true, + RenderTypeId::Primitive( + PrimitiveType::Reference | PrimitiveType::RawPointer | PrimitiveType::Tuple, + ) => true, RenderTypeId::Primitive(..) => false, RenderTypeId::AssociatedType(..) => false, // this bool is only used by `insert_into_map`, so it doesn't matter what we set here @@ -1855,7 +1857,7 @@ fn get_index_type_id( } clean::Primitive(p) => Some(RenderTypeId::Primitive(p)), clean::BorrowedRef { .. } => Some(RenderTypeId::Primitive(clean::PrimitiveType::Reference)), - clean::RawPointer(_, ref type_) => get_index_type_id(type_, rgen), + clean::RawPointer { .. } => Some(RenderTypeId::Primitive(clean::PrimitiveType::RawPointer)), // The type parameters are converted to generics in `simplify_fn_type` clean::Slice(_) => Some(RenderTypeId::Primitive(clean::PrimitiveType::Slice)), clean::Array(_, _) => Some(RenderTypeId::Primitive(clean::PrimitiveType::Array)), @@ -2113,7 +2115,8 @@ fn simplify_fn_type<'a, 'tcx>( generics: Some(ty_generics), }); } - Type::BorrowedRef { lifetime: _, mutability, ref type_ } => { + Type::BorrowedRef { lifetime: _, mutability, ref type_ } + | Type::RawPointer(mutability, ref type_) => { let mut ty_generics = Vec::new(); if mutability.is_mut() { ty_generics.push(RenderType { diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index 20fc6b75d37..4fcba5f120b 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -407,9 +407,7 @@ function preLoadCss(cssUrl) { function loadSearch() { if (!searchLoaded) { searchLoaded = true; - // @ts-expect-error window.rr_ = data => { - // @ts-expect-error window.searchIndex = data; }; if (!window.StringdexOnload) { @@ -1277,13 +1275,11 @@ function preLoadCss(cssUrl) { } window.addEventListener("resize", () => { - // @ts-expect-error if (window.CURRENT_TOOLTIP_ELEMENT) { // As a workaround to the behavior of `contains: layout` used in doc togglers, // tooltip popovers are positioned using javascript. // // This means when the window is resized, we need to redo the layout. - // @ts-expect-error const base = window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE; const force_visible = base.TOOLTIP_FORCE_VISIBLE; hideTooltip(false); @@ -1329,11 +1325,9 @@ function preLoadCss(cssUrl) { */ function showTooltip(e) { const notable_ty = e.getAttribute("data-notable-ty"); - // @ts-expect-error if (!window.NOTABLE_TRAITS && notable_ty) { const data = document.getElementById("notable-traits-data"); if (data) { - // @ts-expect-error window.NOTABLE_TRAITS = JSON.parse(data.innerText); } else { throw new Error("showTooltip() called with notable without any notable traits!"); @@ -1341,14 +1335,15 @@ function preLoadCss(cssUrl) { } // Make this function idempotent. If the tooltip is already shown, avoid doing extra work // and leave it alone. - // @ts-expect-error if (window.CURRENT_TOOLTIP_ELEMENT && window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE === e) { - // @ts-expect-error clearTooltipHoverTimeout(window.CURRENT_TOOLTIP_ELEMENT); return; } window.hideAllModals(false); - const wrapper = document.createElement("div"); + // use Object.assign to make sure the object has the correct type + // with all of the correct fields before it is assigned to a variable, + // as typescript has no way to change the type of a variable once it is initialized. + const wrapper = Object.assign(document.createElement("div"), {TOOLTIP_BASE: e}); if (notable_ty) { wrapper.innerHTML = "<div class=\"content\">" + // @ts-expect-error @@ -1394,11 +1389,7 @@ function preLoadCss(cssUrl) { ); } wrapper.style.visibility = ""; - // @ts-expect-error window.CURRENT_TOOLTIP_ELEMENT = wrapper; - // @ts-expect-error - window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE = e; - // @ts-expect-error clearTooltipHoverTimeout(window.CURRENT_TOOLTIP_ELEMENT); wrapper.onpointerenter = ev => { // If this is a synthetic touch event, ignore it. A click event will be along shortly. @@ -1433,19 +1424,15 @@ function preLoadCss(cssUrl) { */ function setTooltipHoverTimeout(element, show) { clearTooltipHoverTimeout(element); - // @ts-expect-error if (!show && !window.CURRENT_TOOLTIP_ELEMENT) { // To "hide" an already hidden element, just cancel its timeout. return; } - // @ts-expect-error if (show && window.CURRENT_TOOLTIP_ELEMENT) { // To "show" an already visible element, just cancel its timeout. return; } - // @ts-expect-error if (window.CURRENT_TOOLTIP_ELEMENT && - // @ts-expect-error window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE !== element) { // Don't do anything if another tooltip is already visible. return; @@ -1468,24 +1455,20 @@ function preLoadCss(cssUrl) { */ function clearTooltipHoverTimeout(element) { if (element.TOOLTIP_HOVER_TIMEOUT !== undefined) { - // @ts-expect-error removeClass(window.CURRENT_TOOLTIP_ELEMENT, "fade-out"); clearTimeout(element.TOOLTIP_HOVER_TIMEOUT); delete element.TOOLTIP_HOVER_TIMEOUT; } } - // @ts-expect-error + /** + * @param {Event & { relatedTarget: Node }} event + */ function tooltipBlurHandler(event) { - // @ts-expect-error if (window.CURRENT_TOOLTIP_ELEMENT && - // @ts-expect-error !window.CURRENT_TOOLTIP_ELEMENT.contains(document.activeElement) && - // @ts-expect-error !window.CURRENT_TOOLTIP_ELEMENT.contains(event.relatedTarget) && - // @ts-expect-error !window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE.contains(document.activeElement) && - // @ts-expect-error !window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE.contains(event.relatedTarget) ) { // Work around a difference in the focus behaviour between Firefox, Chrome, and Safari. @@ -1507,30 +1490,22 @@ function preLoadCss(cssUrl) { * If set to `false`, leave keyboard focus alone. */ function hideTooltip(focus) { - // @ts-expect-error if (window.CURRENT_TOOLTIP_ELEMENT) { - // @ts-expect-error if (window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE.TOOLTIP_FORCE_VISIBLE) { if (focus) { - // @ts-expect-error window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE.focus(); } - // @ts-expect-error window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE.TOOLTIP_FORCE_VISIBLE = false; } - // @ts-expect-error document.body.removeChild(window.CURRENT_TOOLTIP_ELEMENT); - // @ts-expect-error clearTooltipHoverTimeout(window.CURRENT_TOOLTIP_ELEMENT); - // @ts-expect-error - window.CURRENT_TOOLTIP_ELEMENT = null; + window.CURRENT_TOOLTIP_ELEMENT = undefined; } } onEachLazy(document.getElementsByClassName("tooltip"), e => { e.onclick = () => { e.TOOLTIP_FORCE_VISIBLE = e.TOOLTIP_FORCE_VISIBLE ? false : true; - // @ts-expect-error if (window.CURRENT_TOOLTIP_ELEMENT && !e.TOOLTIP_FORCE_VISIBLE) { hideTooltip(true); } else { @@ -1566,9 +1541,7 @@ function preLoadCss(cssUrl) { if (ev.pointerType !== "mouse") { return; } - // @ts-expect-error if (!e.TOOLTIP_FORCE_VISIBLE && window.CURRENT_TOOLTIP_ELEMENT && - // @ts-expect-error !window.CURRENT_TOOLTIP_ELEMENT.contains(ev.relatedTarget)) { // Tooltip pointer leave gesture: // @@ -1601,7 +1574,6 @@ function preLoadCss(cssUrl) { // * https://www.nngroup.com/articles/tooltip-guidelines/ // * https://bjk5.com/post/44698559168/breaking-down-amazons-mega-dropdown setTooltipHoverTimeout(e, false); - // @ts-expect-error addClass(window.CURRENT_TOOLTIP_ELEMENT, "fade-out"); } }; @@ -1707,8 +1679,7 @@ function preLoadCss(cssUrl) { if (isHelpPage) { const help_section = document.createElement("section"); help_section.appendChild(container); - // @ts-expect-error - document.getElementById("main-content").appendChild(help_section); + nonnull(document.getElementById("main-content")).appendChild(help_section); } else { onEachLazy(document.getElementsByClassName("help-menu"), menu => { if (menu.offsetWidth !== 0) { @@ -1854,8 +1825,7 @@ function preLoadCss(cssUrl) { sidebarButton.addEventListener("click", e => { removeClass(document.documentElement, "hide-sidebar"); updateLocalStorage("hide-sidebar", "false"); - if (document.querySelector(".rustdoc.src")) { - // @ts-expect-error + if (window.rustdocToggleSrcSidebar) { window.rustdocToggleSrcSidebar(); } e.preventDefault(); diff --git a/src/librustdoc/html/static/js/rustdoc.d.ts b/src/librustdoc/html/static/js/rustdoc.d.ts index 28852125fe1..3ac10742e41 100644 --- a/src/librustdoc/html/static/js/rustdoc.d.ts +++ b/src/librustdoc/html/static/js/rustdoc.d.ts @@ -28,6 +28,9 @@ declare global { currentTheme: HTMLLinkElement|null; /** Generated in `render/context.rs` */ SIDEBAR_ITEMS?: { [key: string]: string[] }; + /** Notable trait data */ + NOTABLE_TRAITS?: { [key: string]: string }; + CURRENT_TOOLTIP_ELEMENT?: HTMLElement & { TOOLTIP_BASE: HTMLElement }; /** Used by the popover tooltip code. */ RUSTDOC_TOOLTIP_HOVER_MS: number; /** Used by the popover tooltip code. */ @@ -93,6 +96,10 @@ declare global { pending_type_impls?: rustdoc.TypeImpls, rustdoc_add_line_numbers_to_examples?: function(), rustdoc_remove_line_numbers_from_examples?: function(), + /** JSON-encoded raw search index */ + searchIndex: string, + /** Used in search index shards in order to load data into the in-memory database */ + rr_: function(string), } interface HTMLElement { /** Used by the popover tooltip code. */ diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index 42b87d56252..3fb4db3a89c 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -587,6 +587,45 @@ function getNextElem(query, parserState, elems, isInGenerics) { /** @type {rustdoc.ParserQueryElement[]} */ const generics = []; + /** @type {function(string, string): void} */ + const handleRefOrPtr = (chr, name) => { + if (parserState.typeFilter !== null && parserState.typeFilter !== "primitive") { + throw [ + "Invalid search type: primitive ", + chr, + " and ", + parserState.typeFilter, + " both specified", + ]; + } + parserState.typeFilter = null; + parserState.pos += 1; + let c = parserState.userQuery[parserState.pos]; + while (c === " " && parserState.pos < parserState.length) { + parserState.pos += 1; + c = parserState.userQuery[parserState.pos]; + } + const generics = []; + const pos = parserState.pos; + if (parserState.userQuery.slice(pos, pos + 3) === "mut") { + generics.push(makePrimitiveElement("mut", { typeFilter: "keyword" })); + parserState.pos += 3; + c = parserState.userQuery[parserState.pos]; + } else if (chr === "*" && parserState.userQuery.slice(pos, pos + 5) === "const") { + // make *const T parse the same as *T + parserState.pos += 5; + c = parserState.userQuery[parserState.pos]; + } + while (c === " " && parserState.pos < parserState.length) { + parserState.pos += 1; + c = parserState.userQuery[parserState.pos]; + } + if (!isEndCharacter(c) && parserState.pos < parserState.length) { + getFilteredNextElem(query, parserState, generics, isInGenerics); + } + elems.push(makePrimitiveElement(name, { generics })); + }; + skipWhitespace(parserState); let start = parserState.pos; let end; @@ -636,36 +675,9 @@ function getNextElem(query, parserState, elems, isInGenerics) { elems.push(makePrimitiveElement(name, { bindingName, generics })); } } else if (parserState.userQuery[parserState.pos] === "&") { - if (parserState.typeFilter !== null && parserState.typeFilter !== "primitive") { - throw [ - "Invalid search type: primitive ", - "&", - " and ", - parserState.typeFilter, - " both specified", - ]; - } - parserState.typeFilter = null; - parserState.pos += 1; - let c = parserState.userQuery[parserState.pos]; - while (c === " " && parserState.pos < parserState.length) { - parserState.pos += 1; - c = parserState.userQuery[parserState.pos]; - } - const generics = []; - if (parserState.userQuery.slice(parserState.pos, parserState.pos + 3) === "mut") { - generics.push(makePrimitiveElement("mut", { typeFilter: "keyword" })); - parserState.pos += 3; - c = parserState.userQuery[parserState.pos]; - } - while (c === " " && parserState.pos < parserState.length) { - parserState.pos += 1; - c = parserState.userQuery[parserState.pos]; - } - if (!isEndCharacter(c) && parserState.pos < parserState.length) { - getFilteredNextElem(query, parserState, generics, isInGenerics); - } - elems.push(makePrimitiveElement("reference", { generics })); + handleRefOrPtr("&", "reference"); + } else if (parserState.userQuery[parserState.pos] === "*") { + handleRefOrPtr("*", "pointer"); } else { const isStringElem = parserState.userQuery[start] === "\""; // We handle the strings on their own mostly to make code easier to follow. @@ -1185,6 +1197,7 @@ class DocSearch { this.typeNameIdOfUnit = -1; this.typeNameIdOfTupleOrUnit = -1; this.typeNameIdOfReference = -1; + this.typeNameIdOfPointer = -1; this.typeNameIdOfHof = -1; this.utf8decoder = new TextDecoder(); @@ -1224,6 +1237,7 @@ class DocSearch { tupleOrUnit, // reference matches `&` reference, + pointer, // never matches `!` never, ] = await Promise.all([ @@ -1239,6 +1253,7 @@ class DocSearch { nn.search("unit"), nn.search("()"), nn.search("reference"), + nn.search("pointer"), nn.search("never"), ]); /** @@ -1270,6 +1285,7 @@ class DocSearch { this.typeNameIdOfUnit = await first(unit, TY_PRIMITIVE, ""); this.typeNameIdOfTupleOrUnit = await first(tupleOrUnit, TY_PRIMITIVE, ""); this.typeNameIdOfReference = await first(reference, TY_PRIMITIVE, ""); + this.typeNameIdOfPointer = await first(pointer, TY_PRIMITIVE, ""); this.typeNameIdOfHof = await first(hof, TY_PRIMITIVE, ""); this.typeNameIdOfNever = await first(never, TY_PRIMITIVE, ""); } @@ -2309,6 +2325,25 @@ class DocSearch { }, result), ); return true; + } else if (fnType.id === this.typeNameIdOfPointer) { + pushText({ name: "*", highlighted: fnType.highlighted }, result); + if (fnType.generics.length < 2) { + pushText({ name: "const ", highlighted: fnType.highlighted }, result); + } + let prevHighlighted = false; + await onEachBtwnAsync( + fnType.generics, + async value => { + prevHighlighted = !!value.highlighted; + await writeFn(value, result); + }, + // @ts-expect-error + value => pushText({ + name: " ", + highlighted: prevHighlighted && value.highlighted, + }, result), + ); + return true; } else if ( fnType.id === this.typeNameIdOfFn || fnType.id === this.typeNameIdOfFnMut || @@ -5244,9 +5279,7 @@ if (typeof window !== "undefined") { // search.index/root is loaded by main.js, so // this script doesn't need to launch it, but // must pick it up - // @ts-ignore if (window.searchIndex) { - // @ts-ignore window.rr_(window.searchIndex); } }, diff --git a/src/librustdoc/html/static/js/storage.js b/src/librustdoc/html/static/js/storage.js index c055eb0f808..40ab8be03c9 100644 --- a/src/librustdoc/html/static/js/storage.js +++ b/src/librustdoc/html/static/js/storage.js @@ -117,7 +117,7 @@ function addClass(elem, className) { * Remove a class from a DOM Element. If `elem` is null, * does nothing. This function is idempotent. * - * @param {Element|null} elem + * @param {Element|null|undefined} elem * @param {string} className */ // eslint-disable-next-line no-unused-vars diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index f966d926562..5fab8ad2a4b 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -930,7 +930,7 @@ fn maybe_from_hir_attr( ), AK::ExportName { name, span: _ } => Attribute::ExportName(name.to_string()), AK::LinkSection { name, span: _ } => Attribute::LinkSection(name.to_string()), - AK::TargetFeature(features, _span) => Attribute::TargetFeature { + AK::TargetFeature { features, .. } => Attribute::TargetFeature { enable: features.iter().map(|(feat, _span)| feat.to_string()).collect(), }, diff --git a/src/tools/cargo b/src/tools/cargo -Subproject 71eb84f21aef43c07580c6aed6f806a6299f504 +Subproject 623d536836b4cde09ce38609232a024d5b25da8 diff --git a/src/tools/clippy/.github/workflows/clippy_dev.yml b/src/tools/clippy/.github/workflows/clippy_dev.yml index d6534fbaff9..d530eb6c73a 100644 --- a/src/tools/clippy/.github/workflows/clippy_dev.yml +++ b/src/tools/clippy/.github/workflows/clippy_dev.yml @@ -16,7 +16,7 @@ jobs: steps: # Setup - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: # Unsetting this would make so that any malicious package could get our Github Token persist-credentials: false diff --git a/src/tools/clippy/.github/workflows/clippy_mq.yml b/src/tools/clippy/.github/workflows/clippy_mq.yml index 07d5a08304e..0bcb7135935 100644 --- a/src/tools/clippy/.github/workflows/clippy_mq.yml +++ b/src/tools/clippy/.github/workflows/clippy_mq.yml @@ -36,7 +36,7 @@ jobs: steps: # Setup - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: persist-credentials: false @@ -96,7 +96,7 @@ jobs: steps: # Setup - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: persist-credentials: false @@ -114,7 +114,7 @@ jobs: steps: # Setup - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: persist-credentials: false @@ -170,7 +170,7 @@ jobs: steps: # Setup - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: persist-credentials: false diff --git a/src/tools/clippy/.github/workflows/clippy_pr.yml b/src/tools/clippy/.github/workflows/clippy_pr.yml index 880ebd6e5d5..d91c638a8fb 100644 --- a/src/tools/clippy/.github/workflows/clippy_pr.yml +++ b/src/tools/clippy/.github/workflows/clippy_pr.yml @@ -24,7 +24,7 @@ jobs: steps: # Setup - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: # Unsetting this would make so that any malicious package could get our Github Token persist-credentials: false diff --git a/src/tools/clippy/.github/workflows/deploy.yml b/src/tools/clippy/.github/workflows/deploy.yml index ede19c11257..48c5bd36dbc 100644 --- a/src/tools/clippy/.github/workflows/deploy.yml +++ b/src/tools/clippy/.github/workflows/deploy.yml @@ -25,13 +25,13 @@ jobs: steps: # Setup - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: # Unsetting this would make so that any malicious package could get our Github Token persist-credentials: false - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: ref: ${{ env.TARGET_BRANCH }} path: 'out' diff --git a/src/tools/clippy/.github/workflows/feature_freeze.yml b/src/tools/clippy/.github/workflows/feature_freeze.yml index ec59be3e7f6..5b139e76700 100644 --- a/src/tools/clippy/.github/workflows/feature_freeze.yml +++ b/src/tools/clippy/.github/workflows/feature_freeze.yml @@ -16,7 +16,7 @@ jobs: permissions: pull-requests: write - # Do not in any case add code that runs anything coming from the the content + # Do not in any case add code that runs anything coming from the content # of the pull request, as malicious code would be able to access the private # GitHub token. steps: diff --git a/src/tools/clippy/.github/workflows/lintcheck.yml b/src/tools/clippy/.github/workflows/lintcheck.yml index 003d0395739..390d6a0f747 100644 --- a/src/tools/clippy/.github/workflows/lintcheck.yml +++ b/src/tools/clippy/.github/workflows/lintcheck.yml @@ -24,7 +24,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: fetch-depth: 2 # Unsetting this would make so that any malicious package could get our Github Token @@ -80,7 +80,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: # Unsetting this would make so that any malicious package could get our Github Token persist-credentials: false @@ -113,7 +113,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: # Unsetting this would make so that any malicious package could get our Github Token persist-credentials: false diff --git a/src/tools/clippy/.github/workflows/remark.yml b/src/tools/clippy/.github/workflows/remark.yml index 7e7e26818c0..c9d350ee0b3 100644 --- a/src/tools/clippy/.github/workflows/remark.yml +++ b/src/tools/clippy/.github/workflows/remark.yml @@ -11,7 +11,7 @@ jobs: steps: # Setup - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: # Unsetting this would make so that any malicious package could get our Github Token persist-credentials: false diff --git a/src/tools/clippy/CONTRIBUTING.md b/src/tools/clippy/CONTRIBUTING.md index 42ed624ec21..f7f0a1ce249 100644 --- a/src/tools/clippy/CONTRIBUTING.md +++ b/src/tools/clippy/CONTRIBUTING.md @@ -17,7 +17,7 @@ All contributors are expected to follow the [Rust Code of Conduct]. - [High level approach](#high-level-approach) - [Finding something to fix/improve](#finding-something-to-fiximprove) - [Getting code-completion for rustc internals to work](#getting-code-completion-for-rustc-internals-to-work) - - [IntelliJ Rust](#intellij-rust) + - [RustRover](#rustrover) - [Rust Analyzer](#rust-analyzer) - [How Clippy works](#how-clippy-works) - [Issue and PR triage](#issue-and-pr-triage) @@ -92,22 +92,22 @@ an AST expression). ## Getting code-completion for rustc internals to work -### IntelliJ Rust -Unfortunately, [`IntelliJ Rust`][IntelliJ_rust_homepage] does not (yet?) understand how Clippy uses compiler-internals +### RustRover +Unfortunately, [`RustRover`][RustRover_homepage] does not (yet?) understand how Clippy uses compiler-internals using `extern crate` and it also needs to be able to read the source files of the rustc-compiler which are not available via a `rustup` component at the time of writing. To work around this, you need to have a copy of the [rustc-repo][rustc_repo] available which can be obtained via `git clone https://github.com/rust-lang/rust/`. Then you can run a `cargo dev` command to automatically make Clippy use the rustc-repo via path-dependencies -which `IntelliJ Rust` will be able to understand. +which `RustRover` will be able to understand. Run `cargo dev setup intellij --repo-path <repo-path>` where `<repo-path>` is a path to the rustc repo you just cloned. The command will add path-dependencies pointing towards rustc-crates inside the rustc repo to -Clippy's `Cargo.toml`s and should allow `IntelliJ Rust` to understand most of the types that Clippy uses. +Clippy's `Cargo.toml`s and should allow `RustRover` to understand most of the types that Clippy uses. Just make sure to remove the dependencies again before finally making a pull request! [rustc_repo]: https://github.com/rust-lang/rust/ -[IntelliJ_rust_homepage]: https://intellij-rust.github.io/ +[RustRover_homepage]: https://www.jetbrains.com/rust/ ### Rust Analyzer For [`rust-analyzer`][ra_homepage] to work correctly make sure that in the `rust-analyzer` configuration you set diff --git a/src/tools/clippy/Cargo.toml b/src/tools/clippy/Cargo.toml index daf1c98cdc9..2add525b7e8 100644 --- a/src/tools/clippy/Cargo.toml +++ b/src/tools/clippy/Cargo.toml @@ -64,3 +64,14 @@ harness = false [[test]] name = "dogfood" harness = false + +# quine-mc_cluskey makes up a significant part of the runtime in dogfood +# due to the number of conditions in the clippy_lints crate +# and enabling optimizations for that specific dependency helps a bit +# without increasing total build times. +[profile.dev.package.quine-mc_cluskey] +opt-level = 3 + +[lints.rust.unexpected_cfgs] +level = "warn" +check-cfg = ['cfg(bootstrap)'] diff --git a/src/tools/clippy/book/src/continuous_integration/github_actions.md b/src/tools/clippy/book/src/continuous_integration/github_actions.md index b588c8f0f02..62d32446d92 100644 --- a/src/tools/clippy/book/src/continuous_integration/github_actions.md +++ b/src/tools/clippy/book/src/continuous_integration/github_actions.md @@ -15,7 +15,7 @@ jobs: clippy_check: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Run Clippy run: cargo clippy --all-targets --all-features ``` diff --git a/src/tools/clippy/book/src/development/basics.md b/src/tools/clippy/book/src/development/basics.md index fc405249bcf..19f626ab804 100644 --- a/src/tools/clippy/book/src/development/basics.md +++ b/src/tools/clippy/book/src/development/basics.md @@ -95,7 +95,7 @@ cargo dev new_lint cargo dev deprecate # automatically formatting all code before each commit cargo dev setup git-hook -# (experimental) Setup Clippy to work with IntelliJ-Rust +# (experimental) Setup Clippy to work with RustRover cargo dev setup intellij # runs the `dogfood` tests cargo dev dogfood @@ -103,7 +103,7 @@ cargo dev dogfood More about [intellij] command usage and reasons. -[intellij]: https://github.com/rust-lang/rust-clippy/blob/master/CONTRIBUTING.md#intellij-rust +[intellij]: https://github.com/rust-lang/rust-clippy/blob/master/CONTRIBUTING.md#rustrover ## lintcheck diff --git a/src/tools/clippy/book/src/development/common_tools_writing_lints.md b/src/tools/clippy/book/src/development/common_tools_writing_lints.md index e23b32039c9..3bec3ce33af 100644 --- a/src/tools/clippy/book/src/development/common_tools_writing_lints.md +++ b/src/tools/clippy/book/src/development/common_tools_writing_lints.md @@ -141,7 +141,7 @@ impl LateLintPass<'_> for MyStructLint { // we are looking for the `DefId` of `Drop` trait in lang items .drop_trait() // then we use it with our type `ty` by calling `implements_trait` from Clippy's utils - .map_or(false, |id| implements_trait(cx, ty, id, &[])) { + .is_some_and(|id| implements_trait(cx, ty, id, &[])) { // `expr` implements `Drop` trait } } diff --git a/src/tools/clippy/book/src/lint_configuration.md b/src/tools/clippy/book/src/lint_configuration.md index 7f16f3a9810..05590ff7b1c 100644 --- a/src/tools/clippy/book/src/lint_configuration.md +++ b/src/tools/clippy/book/src/lint_configuration.md @@ -555,7 +555,7 @@ default configuration of Clippy. By default, any configuration will replace the * `doc-valid-idents = ["ClipPy"]` would replace the default list with `["ClipPy"]`. * `doc-valid-idents = ["ClipPy", ".."]` would append `ClipPy` to the default list. -**Default Value:** `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "MHz", "GHz", "THz", "AccessKit", "CoAP", "CoreFoundation", "CoreGraphics", "CoreText", "DevOps", "Direct2D", "Direct3D", "DirectWrite", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PostScript", "PureScript", "TypeScript", "WebAssembly", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenAL", "OpenDNS", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenTelemetry", "OpenType", "WebGL", "WebGL2", "WebGPU", "WebRTC", "WebSocket", "WebTransport", "WebP", "OpenExr", "YCbCr", "sRGB", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "NetBSD", "OpenBSD", "NixOS", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]` +**Default Value:** `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "MHz", "GHz", "THz", "AccessKit", "CoAP", "CoreFoundation", "CoreGraphics", "CoreText", "DevOps", "Direct2D", "Direct3D", "DirectWrite", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PostScript", "PureScript", "TypeScript", "PowerPC", "WebAssembly", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenAL", "OpenDNS", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenTelemetry", "OpenType", "WebGL", "WebGL2", "WebGPU", "WebRTC", "WebSocket", "WebTransport", "WebP", "OpenExr", "YCbCr", "sRGB", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "NetBSD", "OpenBSD", "NixOS", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]` --- **Affected lints:** diff --git a/src/tools/clippy/clippy_config/src/conf.rs b/src/tools/clippy/clippy_config/src/conf.rs index 8167d75583e..2ad3f2efcdd 100644 --- a/src/tools/clippy/clippy_config/src/conf.rs +++ b/src/tools/clippy/clippy_config/src/conf.rs @@ -34,7 +34,7 @@ const DEFAULT_DOC_VALID_IDENTS: &[&str] = &[ "GitHub", "GitLab", "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PostScript", "PureScript", "TypeScript", - "WebAssembly", + "PowerPC", "WebAssembly", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", diff --git a/src/tools/clippy/clippy_dev/src/dogfood.rs b/src/tools/clippy/clippy_dev/src/dogfood.rs index 7e9d92458d0..d0fca952b93 100644 --- a/src/tools/clippy/clippy_dev/src/dogfood.rs +++ b/src/tools/clippy/clippy_dev/src/dogfood.rs @@ -1,35 +1,28 @@ -use crate::utils::exit_if_err; -use std::process::Command; +use crate::utils::{cargo_cmd, run_exit_on_err}; +use itertools::Itertools; /// # Panics /// /// Panics if unable to run the dogfood test #[allow(clippy::fn_params_excessive_bools)] pub fn dogfood(fix: bool, allow_dirty: bool, allow_staged: bool, allow_no_vcs: bool) { - let mut cmd = Command::new("cargo"); - - cmd.args(["test", "--test", "dogfood"]) - .args(["--features", "internal"]) - .args(["--", "dogfood_clippy", "--nocapture"]); - - let mut dogfood_args = Vec::new(); - if fix { - dogfood_args.push("--fix"); - } - - if allow_dirty { - dogfood_args.push("--allow-dirty"); - } - - if allow_staged { - dogfood_args.push("--allow-staged"); - } - - if allow_no_vcs { - dogfood_args.push("--allow-no-vcs"); - } - - cmd.env("__CLIPPY_DOGFOOD_ARGS", dogfood_args.join(" ")); - - exit_if_err(cmd.status()); + run_exit_on_err( + "cargo test", + cargo_cmd() + .args(["test", "--test", "dogfood"]) + .args(["--features", "internal"]) + .args(["--", "dogfood_clippy", "--nocapture"]) + .env( + "__CLIPPY_DOGFOOD_ARGS", + [ + if fix { "--fix" } else { "" }, + if allow_dirty { "--allow-dirty" } else { "" }, + if allow_staged { "--allow-staged" } else { "" }, + if allow_no_vcs { "--allow-no-vcs" } else { "" }, + ] + .iter() + .filter(|x| !x.is_empty()) + .join(" "), + ), + ); } diff --git a/src/tools/clippy/clippy_dev/src/lib.rs b/src/tools/clippy/clippy_dev/src/lib.rs index 40aadf4589a..16f413e0c86 100644 --- a/src/tools/clippy/clippy_dev/src/lib.rs +++ b/src/tools/clippy/clippy_dev/src/lib.rs @@ -15,8 +15,7 @@ )] #![allow(clippy::missing_panics_doc)] -// The `rustc_driver` crate seems to be required in order to use the `rust_lexer` crate. -#[allow(unused_extern_crates)] +#[expect(unused_extern_crates, reason = "required to link to rustc crates")] extern crate rustc_driver; extern crate rustc_lexer; extern crate rustc_literal_escaper; @@ -32,4 +31,6 @@ pub mod serve; pub mod setup; pub mod sync; pub mod update_lints; -pub mod utils; + +mod utils; +pub use utils::{ClippyInfo, UpdateMode}; diff --git a/src/tools/clippy/clippy_dev/src/lint.rs b/src/tools/clippy/clippy_dev/src/lint.rs index 0d66f167a38..2d9f563cdae 100644 --- a/src/tools/clippy/clippy_dev/src/lint.rs +++ b/src/tools/clippy/clippy_dev/src/lint.rs @@ -1,19 +1,18 @@ -use crate::utils::{cargo_clippy_path, exit_if_err}; -use std::process::{self, Command}; +use crate::utils::{ErrAction, cargo_cmd, expect_action, run_exit_on_err}; +use std::process::Command; use std::{env, fs}; -pub fn run<'a>(path: &str, edition: &str, args: impl Iterator<Item = &'a String>) { - let is_file = match fs::metadata(path) { - Ok(metadata) => metadata.is_file(), - Err(e) => { - eprintln!("Failed to read {path}: {e:?}"); - process::exit(1); - }, - }; +#[cfg(not(windows))] +static CARGO_CLIPPY_EXE: &str = "cargo-clippy"; +#[cfg(windows)] +static CARGO_CLIPPY_EXE: &str = "cargo-clippy.exe"; +pub fn run<'a>(path: &str, edition: &str, args: impl Iterator<Item = &'a String>) { + let is_file = expect_action(fs::metadata(path), ErrAction::Read, path).is_file(); if is_file { - exit_if_err( - Command::new(env::var("CARGO").unwrap_or_else(|_| "cargo".into())) + run_exit_on_err( + "cargo run", + cargo_cmd() .args(["run", "--bin", "clippy-driver", "--"]) .args(["-L", "./target/debug"]) .args(["-Z", "no-codegen"]) @@ -21,24 +20,25 @@ pub fn run<'a>(path: &str, edition: &str, args: impl Iterator<Item = &'a String> .arg(path) .args(args) // Prevent rustc from creating `rustc-ice-*` files the console output is enough. - .env("RUSTC_ICE", "0") - .status(), + .env("RUSTC_ICE", "0"), ); } else { - exit_if_err( - Command::new(env::var("CARGO").unwrap_or_else(|_| "cargo".into())) - .arg("build") - .status(), - ); - - let status = Command::new(cargo_clippy_path()) - .arg("clippy") - .args(args) - // Prevent rustc from creating `rustc-ice-*` files the console output is enough. - .env("RUSTC_ICE", "0") - .current_dir(path) - .status(); + // Ideally this would just be `cargo run`, but the working directory needs to be + // set to clippy's directory when building, and the target project's directory + // when running clippy. `cargo` can only set a single working directory for both + // when using `run`. + run_exit_on_err("cargo build", cargo_cmd().arg("build")); - exit_if_err(status); + let mut exe = env::current_exe().expect("failed to get current executable name"); + exe.set_file_name(CARGO_CLIPPY_EXE); + run_exit_on_err( + "cargo clippy", + Command::new(exe) + .arg("clippy") + .args(args) + // Prevent rustc from creating `rustc-ice-*` files the console output is enough. + .env("RUSTC_ICE", "0") + .current_dir(path), + ); } } diff --git a/src/tools/clippy/clippy_dev/src/main.rs b/src/tools/clippy/clippy_dev/src/main.rs index 26aa269fb63..5fef231f6ca 100644 --- a/src/tools/clippy/clippy_dev/src/main.rs +++ b/src/tools/clippy/clippy_dev/src/main.rs @@ -4,14 +4,15 @@ use clap::{Args, Parser, Subcommand}; use clippy_dev::{ - deprecate_lint, dogfood, fmt, lint, new_lint, release, rename_lint, serve, setup, sync, update_lints, utils, + ClippyInfo, UpdateMode, deprecate_lint, dogfood, fmt, lint, new_lint, release, rename_lint, serve, setup, sync, + update_lints, }; use std::convert::Infallible; use std::env; fn main() { let dev = Dev::parse(); - let clippy = utils::ClippyInfo::search_for_manifest(); + let clippy = ClippyInfo::search_for_manifest(); if let Err(e) = env::set_current_dir(&clippy.path) { panic!("error setting current directory to `{}`: {e}", clippy.path.display()); } @@ -26,8 +27,8 @@ fn main() { allow_staged, allow_no_vcs, } => dogfood::dogfood(fix, allow_dirty, allow_staged, allow_no_vcs), - DevCommand::Fmt { check } => fmt::run(utils::UpdateMode::from_check(check)), - DevCommand::UpdateLints { check } => update_lints::update(utils::UpdateMode::from_check(check)), + DevCommand::Fmt { check } => fmt::run(UpdateMode::from_check(check)), + DevCommand::UpdateLints { check } => update_lints::update(UpdateMode::from_check(check)), DevCommand::NewLint { pass, name, @@ -35,7 +36,7 @@ fn main() { r#type, msrv, } => match new_lint::create(clippy.version, pass, &name, &category, r#type.as_deref(), msrv) { - Ok(()) => update_lints::update(utils::UpdateMode::Change), + Ok(()) => update_lints::update(UpdateMode::Change), Err(e) => eprintln!("Unable to create lint: {e}"), }, DevCommand::Setup(SetupCommand { subcommand }) => match subcommand { diff --git a/src/tools/clippy/clippy_dev/src/serve.rs b/src/tools/clippy/clippy_dev/src/serve.rs index 498ffeba9d6..d9e01813381 100644 --- a/src/tools/clippy/clippy_dev/src/serve.rs +++ b/src/tools/clippy/clippy_dev/src/serve.rs @@ -1,7 +1,11 @@ +use crate::utils::{ErrAction, cargo_cmd, expect_action}; +use core::fmt::Display; +use core::mem; use std::path::Path; use std::process::Command; use std::time::{Duration, SystemTime}; -use std::{env, thread}; +use std::{fs, thread}; +use walkdir::WalkDir; #[cfg(windows)] const PYTHON: &str = "python"; @@ -18,56 +22,83 @@ pub fn run(port: u16, lint: Option<String>) -> ! { Some(lint) => format!("http://localhost:{port}/#{lint}"), }); + let mut last_update = mtime("util/gh-pages/index.html"); loop { - let index_time = mtime("util/gh-pages/index.html"); - let times = [ - "clippy_lints/src", - "util/gh-pages/index_template.html", - "tests/compile-test.rs", - ] - .map(mtime); - - if times.iter().any(|&time| index_time < time) { - Command::new(env::var("CARGO").unwrap_or_else(|_| "cargo".into())) - .arg("collect-metadata") - .spawn() - .unwrap() - .wait() - .unwrap(); + if is_metadata_outdated(mem::replace(&mut last_update, SystemTime::now())) { + // Ignore the command result; we'll fall back to displaying the old metadata. + let _ = expect_action( + cargo_cmd().arg("collect-metadata").status(), + ErrAction::Run, + "cargo collect-metadata", + ); + last_update = SystemTime::now(); } + + // Only start the web server the first time around. if let Some(url) = url.take() { thread::spawn(move || { - let mut child = Command::new(PYTHON) - .arg("-m") - .arg("http.server") - .arg(port.to_string()) - .current_dir("util/gh-pages") - .spawn() - .unwrap(); + let mut child = expect_action( + Command::new(PYTHON) + .args(["-m", "http.server", port.to_string().as_str()]) + .current_dir("util/gh-pages") + .spawn(), + ErrAction::Run, + "python -m http.server", + ); // Give some time for python to start thread::sleep(Duration::from_millis(500)); // Launch browser after first export.py has completed and http.server is up let _result = opener::open(url); - child.wait().unwrap(); + expect_action(child.wait(), ErrAction::Run, "python -m http.server"); }); } + + // Delay to avoid updating the metadata too aggressively. thread::sleep(Duration::from_millis(1000)); } } -fn mtime(path: impl AsRef<Path>) -> SystemTime { - let path = path.as_ref(); - if path.is_dir() { - path.read_dir() - .into_iter() - .flatten() - .flatten() - .map(|entry| mtime(entry.path())) - .max() - .unwrap_or(SystemTime::UNIX_EPOCH) - } else { - path.metadata() - .and_then(|metadata| metadata.modified()) - .unwrap_or(SystemTime::UNIX_EPOCH) +fn log_err_and_continue<T>(res: Result<T, impl Display>, path: &Path) -> Option<T> { + match res { + Ok(x) => Some(x), + Err(ref e) => { + eprintln!("error reading `{}`: {e}", path.display()); + None + }, } } + +fn mtime(path: &str) -> SystemTime { + log_err_and_continue(fs::metadata(path), path.as_ref()) + .and_then(|metadata| log_err_and_continue(metadata.modified(), path.as_ref())) + .unwrap_or(SystemTime::UNIX_EPOCH) +} + +fn is_metadata_outdated(time: SystemTime) -> bool { + // Ignore all IO errors here. We don't want to stop them from hosting the server. + if time < mtime("util/gh-pages/index_template.html") || time < mtime("tests/compile-test.rs") { + return true; + } + let Some(dir) = log_err_and_continue(fs::read_dir("."), ".".as_ref()) else { + return false; + }; + dir.map_while(|e| log_err_and_continue(e, ".".as_ref())).any(|e| { + let name = e.file_name(); + let name_bytes = name.as_encoded_bytes(); + if (name_bytes.starts_with(b"clippy_lints") && name_bytes != b"clippy_lints_internal") + || name_bytes == b"clippy_config" + { + WalkDir::new(&name) + .into_iter() + .map_while(|e| log_err_and_continue(e, name.as_ref())) + .filter(|e| e.file_type().is_file()) + .filter_map(|e| { + log_err_and_continue(e.metadata(), e.path()) + .and_then(|m| log_err_and_continue(m.modified(), e.path())) + }) + .any(|ftime| time < ftime) + } else { + false + } + }) +} diff --git a/src/tools/clippy/clippy_dev/src/setup/git_hook.rs b/src/tools/clippy/clippy_dev/src/setup/git_hook.rs index c7c53bc69d0..c5a1e8264c7 100644 --- a/src/tools/clippy/clippy_dev/src/setup/git_hook.rs +++ b/src/tools/clippy/clippy_dev/src/setup/git_hook.rs @@ -1,8 +1,6 @@ use std::fs; use std::path::Path; -use super::verify_inside_clippy_dir; - /// Rusts setup uses `git rev-parse --git-common-dir` to get the root directory of the repo. /// I've decided against this for the sake of simplicity and to make sure that it doesn't install /// the hook if `clippy_dev` would be used in the rust tree. The hook also references this tool @@ -35,10 +33,6 @@ pub fn install_hook(force_override: bool) { } fn check_precondition(force_override: bool) -> bool { - if !verify_inside_clippy_dir() { - return false; - } - // Make sure that we can find the git repository let git_path = Path::new(REPO_GIT_DIR); if !git_path.exists() || !git_path.is_dir() { diff --git a/src/tools/clippy/clippy_dev/src/setup/mod.rs b/src/tools/clippy/clippy_dev/src/setup/mod.rs index b0d31814639..5e938fff126 100644 --- a/src/tools/clippy/clippy_dev/src/setup/mod.rs +++ b/src/tools/clippy/clippy_dev/src/setup/mod.rs @@ -2,23 +2,3 @@ pub mod git_hook; pub mod intellij; pub mod toolchain; pub mod vscode; - -use std::path::Path; - -const CLIPPY_DEV_DIR: &str = "clippy_dev"; - -/// This function verifies that the tool is being executed in the clippy directory. -/// This is useful to ensure that setups only modify Clippy's resources. The verification -/// is done by checking that `clippy_dev` is a sub directory of the current directory. -/// -/// It will print an error message and return `false` if the directory could not be -/// verified. -fn verify_inside_clippy_dir() -> bool { - let path = Path::new(CLIPPY_DEV_DIR); - if path.exists() && path.is_dir() { - true - } else { - eprintln!("error: unable to verify that the working directory is clippy's directory"); - false - } -} diff --git a/src/tools/clippy/clippy_dev/src/setup/toolchain.rs b/src/tools/clippy/clippy_dev/src/setup/toolchain.rs index ecd80215f7e..c64ae4ef3c3 100644 --- a/src/tools/clippy/clippy_dev/src/setup/toolchain.rs +++ b/src/tools/clippy/clippy_dev/src/setup/toolchain.rs @@ -1,20 +1,12 @@ +use crate::utils::{cargo_cmd, run_exit_on_err}; use std::env::consts::EXE_SUFFIX; use std::env::current_dir; use std::ffi::OsStr; use std::fs; use std::path::{Path, PathBuf}; -use std::process::Command; use walkdir::WalkDir; -use crate::utils::exit_if_err; - -use super::verify_inside_clippy_dir; - pub fn create(standalone: bool, force: bool, release: bool, name: &str) { - if !verify_inside_clippy_dir() { - return; - } - let rustup_home = std::env::var("RUSTUP_HOME").unwrap(); let toolchain = std::env::var("RUSTUP_TOOLCHAIN").unwrap(); @@ -51,11 +43,10 @@ pub fn create(standalone: bool, force: bool, release: bool, name: &str) { } } - let status = Command::new("cargo") - .arg("build") - .args(release.then_some("--release")) - .status(); - exit_if_err(status); + run_exit_on_err( + "cargo build", + cargo_cmd().arg("build").args(release.then_some("--release")), + ); install_bin("cargo-clippy", &dest, standalone, release); install_bin("clippy-driver", &dest, standalone, release); diff --git a/src/tools/clippy/clippy_dev/src/setup/vscode.rs b/src/tools/clippy/clippy_dev/src/setup/vscode.rs index a37c873eed4..a24aef65991 100644 --- a/src/tools/clippy/clippy_dev/src/setup/vscode.rs +++ b/src/tools/clippy/clippy_dev/src/setup/vscode.rs @@ -1,8 +1,6 @@ use std::fs; use std::path::Path; -use super::verify_inside_clippy_dir; - const VSCODE_DIR: &str = ".vscode"; const TASK_SOURCE_FILE: &str = "util/etc/vscode-tasks.json"; const TASK_TARGET_FILE: &str = ".vscode/tasks.json"; @@ -22,10 +20,6 @@ pub fn install_tasks(force_override: bool) { } fn check_install_precondition(force_override: bool) -> bool { - if !verify_inside_clippy_dir() { - return false; - } - let vs_dir_path = Path::new(VSCODE_DIR); if vs_dir_path.exists() { // verify the target will be valid diff --git a/src/tools/clippy/clippy_dev/src/utils.rs b/src/tools/clippy/clippy_dev/src/utils.rs index 89962a11034..057951d0e33 100644 --- a/src/tools/clippy/clippy_dev/src/utils.rs +++ b/src/tools/clippy/clippy_dev/src/utils.rs @@ -8,15 +8,10 @@ use std::ffi::OsStr; use std::fs::{self, OpenOptions}; use std::io::{self, Read as _, Seek as _, SeekFrom, Write}; use std::path::{Path, PathBuf}; -use std::process::{self, Command, ExitStatus, Stdio}; +use std::process::{self, Command, Stdio}; use std::{env, thread}; use walkdir::WalkDir; -#[cfg(not(windows))] -static CARGO_CLIPPY_EXE: &str = "cargo-clippy"; -#[cfg(windows)] -static CARGO_CLIPPY_EXE: &str = "cargo-clippy.exe"; - #[derive(Clone, Copy)] pub enum ErrAction { Open, @@ -118,16 +113,14 @@ impl<'a> File<'a> { } } -/// Returns the path to the `cargo-clippy` binary -/// -/// # Panics -/// -/// Panics if the path of current executable could not be retrieved. +/// Creates a `Command` for running cargo. #[must_use] -pub fn cargo_clippy_path() -> PathBuf { - let mut path = env::current_exe().expect("failed to get current executable name"); - path.set_file_name(CARGO_CLIPPY_EXE); - path +pub fn cargo_cmd() -> Command { + if let Some(path) = env::var_os("CARGO") { + Command::new(path) + } else { + Command::new("cargo") + } } #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] @@ -288,19 +281,6 @@ impl ClippyInfo { } } -/// # Panics -/// Panics if given command result was failed. -pub fn exit_if_err(status: io::Result<ExitStatus>) { - match status.expect("failed to run command").code() { - Some(0) => {}, - Some(n) => process::exit(n), - None => { - eprintln!("Killed by signal"); - process::exit(1); - }, - } -} - #[derive(Clone, Copy)] pub enum UpdateStatus { Unchanged, @@ -341,6 +321,7 @@ pub struct FileUpdater { dst_buf: String, } impl FileUpdater { + #[track_caller] fn update_file_checked_inner( &mut self, tool: &str, @@ -364,6 +345,7 @@ impl FileUpdater { } } + #[track_caller] fn update_file_inner(&mut self, path: &Path, update: &mut dyn FnMut(&Path, &str, &mut String) -> UpdateStatus) { let mut file = File::open(path, OpenOptions::new().read(true).write(true)); file.read_to_cleared_string(&mut self.src_buf); @@ -373,6 +355,7 @@ impl FileUpdater { } } + #[track_caller] pub fn update_file_checked( &mut self, tool: &str, @@ -383,6 +366,7 @@ impl FileUpdater { self.update_file_checked_inner(tool, mode, path.as_ref(), update); } + #[track_caller] pub fn update_file( &mut self, path: impl AsRef<Path>, @@ -450,7 +434,6 @@ pub enum Token<'a> { OpenParen, Pound, Semi, - Slash, } pub struct RustSearcher<'txt> { @@ -528,7 +511,6 @@ impl<'txt> RustSearcher<'txt> { | (Token::OpenParen, lexer::TokenKind::OpenParen) | (Token::Pound, lexer::TokenKind::Pound) | (Token::Semi, lexer::TokenKind::Semi) - | (Token::Slash, lexer::TokenKind::Slash) | ( Token::LitStr, lexer::TokenKind::Literal { @@ -601,7 +583,7 @@ impl<'txt> RustSearcher<'txt> { } } -#[expect(clippy::must_use_candidate)] +#[track_caller] pub fn try_rename_file(old_name: &Path, new_name: &Path) -> bool { match OpenOptions::new().create_new(true).write(true).open(new_name) { Ok(file) => drop(file), @@ -623,7 +605,7 @@ pub fn try_rename_file(old_name: &Path, new_name: &Path) -> bool { } } -#[expect(clippy::must_use_candidate)] +#[track_caller] pub fn try_rename_dir(old_name: &Path, new_name: &Path) -> bool { match fs::create_dir(new_name) { Ok(()) => {}, @@ -649,10 +631,19 @@ pub fn try_rename_dir(old_name: &Path, new_name: &Path) -> bool { } } -pub fn write_file(path: &Path, contents: &str) { - expect_action(fs::write(path, contents), ErrAction::Write, path); +#[track_caller] +pub fn run_exit_on_err(path: &(impl AsRef<Path> + ?Sized), cmd: &mut Command) { + match expect_action(cmd.status(), ErrAction::Run, path.as_ref()).code() { + Some(0) => {}, + Some(n) => process::exit(n), + None => { + eprintln!("{} killed by signal", path.as_ref().display()); + process::exit(1); + }, + } } +#[track_caller] #[must_use] pub fn run_with_output(path: &(impl AsRef<Path> + ?Sized), cmd: &mut Command) -> Vec<u8> { fn f(path: &Path, cmd: &mut Command) -> Vec<u8> { @@ -738,7 +729,7 @@ pub fn split_args_for_threads( } } -#[expect(clippy::must_use_candidate)] +#[track_caller] pub fn delete_file_if_exists(path: &Path) -> bool { match fs::remove_file(path) { Ok(()) => true, @@ -747,6 +738,7 @@ pub fn delete_file_if_exists(path: &Path) -> bool { } } +#[track_caller] pub fn delete_dir_if_exists(path: &Path) { match fs::remove_dir_all(path) { Ok(()) => {}, diff --git a/src/tools/clippy/clippy_lints/src/casts/borrow_as_ptr.rs b/src/tools/clippy/clippy_lints/src/casts/borrow_as_ptr.rs index e3b125a8d5b..eb75d5576f5 100644 --- a/src/tools/clippy/clippy_lints/src/casts/borrow_as_ptr.rs +++ b/src/tools/clippy/clippy_lints/src/casts/borrow_as_ptr.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::msrvs::Msrv; use clippy_utils::source::{snippet_with_applicability, snippet_with_context}; use clippy_utils::sugg::has_enclosing_paren; -use clippy_utils::{get_parent_expr, is_expr_temporary_value, is_lint_allowed, msrvs, std_or_core}; +use clippy_utils::{get_parent_expr, is_expr_temporary_value, is_from_proc_macro, is_lint_allowed, msrvs, std_or_core}; use rustc_errors::Applicability; use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, Ty, TyKind}; use rustc_lint::LateContext; @@ -22,13 +22,12 @@ pub(super) fn check<'tcx>( && !matches!(target.ty.kind, TyKind::TraitObject(..)) && let ExprKind::AddrOf(BorrowKind::Ref, mutability, e) = cast_expr.kind && !is_lint_allowed(cx, BORROW_AS_PTR, expr.hir_id) + // Fix #9884 + && !is_expr_temporary_value(cx, e) + && !is_from_proc_macro(cx, expr) { let mut app = Applicability::MachineApplicable; let snip = snippet_with_context(cx, e.span, cast_expr.span.ctxt(), "..", &mut app).0; - // Fix #9884 - if is_expr_temporary_value(cx, e) { - return false; - } let (suggestion, span) = if msrv.meets(cx, msrvs::RAW_REF_OP) { // Make sure that the span to be replaced doesn't include parentheses, that could break the diff --git a/src/tools/clippy/clippy_lints/src/casts/char_lit_as_u8.rs b/src/tools/clippy/clippy_lints/src/casts/char_lit_as_u8.rs index a7d3868f76c..964eaf2a0a2 100644 --- a/src/tools/clippy/clippy_lints/src/casts/char_lit_as_u8.rs +++ b/src/tools/clippy/clippy_lints/src/casts/char_lit_as_u8.rs @@ -4,18 +4,17 @@ use rustc_ast::LitKind; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; -use rustc_middle::ty::{self, UintTy}; +use rustc_middle::ty::{self, Ty, UintTy}; use super::CHAR_LIT_AS_U8; -pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { - if let ExprKind::Cast(e, _) = &expr.kind - && let ExprKind::Lit(l) = &e.kind +pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from_expr: &Expr<'_>, cast_to: Ty<'_>) { + if let ExprKind::Lit(l) = &cast_from_expr.kind && let LitKind::Char(c) = l.node - && ty::Uint(UintTy::U8) == *cx.typeck_results().expr_ty(expr).kind() + && ty::Uint(UintTy::U8) == *cast_to.kind() { let mut applicability = Applicability::MachineApplicable; - let snippet = snippet_with_applicability(cx, e.span, "'x'", &mut applicability); + let snippet = snippet_with_applicability(cx, cast_from_expr.span, "'x'", &mut applicability); span_lint_and_then( cx, diff --git a/src/tools/clippy/clippy_lints/src/casts/mod.rs b/src/tools/clippy/clippy_lints/src/casts/mod.rs index dcc439a272c..e25df9dd249 100644 --- a/src/tools/clippy/clippy_lints/src/casts/mod.rs +++ b/src/tools/clippy/clippy_lints/src/casts/mod.rs @@ -871,6 +871,7 @@ impl<'tcx> LateLintPass<'tcx> for Casts { if !expr.span.from_expansion() && unnecessary_cast::check(cx, expr, cast_from_expr, cast_from, cast_to) { return; } + char_lit_as_u8::check(cx, expr, cast_from_expr, cast_to); cast_slice_from_raw_parts::check(cx, expr, cast_from_expr, cast_to, self.msrv); ptr_cast_constness::check(cx, expr, cast_from_expr, cast_from, cast_to, self.msrv); as_ptr_cast_mut::check(cx, expr, cast_from_expr, cast_to); @@ -911,7 +912,6 @@ impl<'tcx> LateLintPass<'tcx> for Casts { borrow_as_ptr::check_implicit_cast(cx, expr); } cast_ptr_alignment::check(cx, expr); - char_lit_as_u8::check(cx, expr); ptr_as_ptr::check(cx, expr, self.msrv); cast_slice_different_sizes::check(cx, expr, self.msrv); ptr_cast_constness::check_null_ptr_cast_method(cx, expr); diff --git a/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs b/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs index ee0f3fa81c6..89075409098 100644 --- a/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs +++ b/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs @@ -1,4 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_from_proc_macro; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::sugg::Sugg; @@ -25,7 +26,7 @@ impl OmitFollowedCastReason<'_> { } } -pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: Msrv) { +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, msrv: Msrv) { if let ExprKind::Cast(cast_expr, cast_to_hir_ty) = expr.kind && let (cast_from, cast_to) = (cx.typeck_results().expr_ty(cast_expr), cx.typeck_results().expr_ty(expr)) && let ty::RawPtr(_, from_mutbl) = cast_from.kind() @@ -36,6 +37,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: Msrv) { // as explained here: https://github.com/rust-lang/rust/issues/60602. && to_pointee_ty.is_sized(cx.tcx, cx.typing_env()) && msrv.meets(cx, msrvs::POINTER_CAST) + && !is_from_proc_macro(cx, expr) { let mut app = Applicability::MachineApplicable; let turbofish = match &cast_to_hir_ty.kind { diff --git a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs index 8f1c0296524..8f95c63a854 100644 --- a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs +++ b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs @@ -56,7 +56,7 @@ impl_lint_pass!(CognitiveComplexity => [COGNITIVE_COMPLEXITY]); impl CognitiveComplexity { fn check<'tcx>( - &mut self, + &self, cx: &LateContext<'tcx>, kind: FnKind<'tcx>, decl: &'tcx FnDecl<'_>, diff --git a/src/tools/clippy/clippy_lints/src/collapsible_if.rs b/src/tools/clippy/clippy_lints/src/collapsible_if.rs index e3103e2d301..ad610fbd8d2 100644 --- a/src/tools/clippy/clippy_lints/src/collapsible_if.rs +++ b/src/tools/clippy/clippy_lints/src/collapsible_if.rs @@ -5,7 +5,7 @@ use clippy_utils::source::{IntoSpan as _, SpanRangeExt, snippet, snippet_block_w use clippy_utils::{span_contains_non_whitespace, tokenize_with_text}; use rustc_ast::BinOpKind; use rustc_errors::Applicability; -use rustc_hir::{Block, Expr, ExprKind, Stmt, StmtKind}; +use rustc_hir::{Block, Expr, ExprKind, StmtKind}; use rustc_lexer::TokenKind; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; @@ -141,11 +141,7 @@ impl CollapsibleIf { // Prevent "elseif" // Check that the "else" is followed by whitespace - let requires_space = if let Some(c) = snippet(cx, up_to_else, "..").chars().last() { - !c.is_whitespace() - } else { - false - }; + let requires_space = snippet(cx, up_to_else, "..").ends_with(|c: char| !c.is_whitespace()); let mut applicability = Applicability::MachineApplicable; diag.span_suggestion( else_block.span, @@ -173,8 +169,7 @@ impl CollapsibleIf { && cx.tcx.hir_attrs(inner.hir_id).is_empty() && let ExprKind::If(check_inner, _, None) = &inner.kind && self.eligible_condition(cx, check_inner) - && let ctxt = expr.span.ctxt() - && inner.span.ctxt() == ctxt + && expr.span.eq_ctxt(inner.span) && !block_starts_with_significant_tokens(cx, then, inner, self.lint_commented_code) { span_lint_and_then( @@ -262,14 +257,9 @@ fn block_starts_with_significant_tokens( /// If `block` is a block with either one expression or a statement containing an expression, /// return the expression. We don't peel blocks recursively, as extra blocks might be intentional. fn expr_block<'tcx>(block: &Block<'tcx>) -> Option<&'tcx Expr<'tcx>> { - match block.stmts { - [] => block.expr, - [ - Stmt { - kind: StmtKind::Semi(expr), - .. - }, - ] if block.expr.is_none() => Some(expr), + match (block.stmts, block.expr) { + ([], expr) => expr, + ([stmt], None) if let StmtKind::Semi(expr) = stmt.kind => Some(expr), _ => None, } } diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs index e1cb08e361c..e67e8d9070f 100644 --- a/src/tools/clippy/clippy_lints/src/declared_lints.rs +++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs @@ -187,6 +187,7 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[ crate::from_raw_with_void_ptr::FROM_RAW_WITH_VOID_PTR_INFO, crate::from_str_radix_10::FROM_STR_RADIX_10_INFO, crate::functions::DOUBLE_MUST_USE_INFO, + crate::functions::DUPLICATE_UNDERSCORE_ARGUMENT_INFO, crate::functions::IMPL_TRAIT_IN_PARAMS_INFO, crate::functions::MISNAMED_GETTERS_INFO, crate::functions::MUST_USE_CANDIDATE_INFO, @@ -505,7 +506,6 @@ pub static LINTS: &[&::declare_clippy_lint::LintInfo] = &[ crate::misc::USED_UNDERSCORE_BINDING_INFO, crate::misc::USED_UNDERSCORE_ITEMS_INFO, crate::misc_early::BUILTIN_TYPE_SHADOW_INFO, - crate::misc_early::DUPLICATE_UNDERSCORE_ARGUMENT_INFO, crate::misc_early::MIXED_CASE_HEX_LITERALS_INFO, crate::misc_early::REDUNDANT_AT_REST_PATTERN_INFO, crate::misc_early::REDUNDANT_PATTERN_INFO, diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs index 995a1209595..9aa2f3cf0a5 100644 --- a/src/tools/clippy/clippy_lints/src/dereference.rs +++ b/src/tools/clippy/clippy_lints/src/dereference.rs @@ -1,12 +1,11 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then}; use clippy_utils::source::{snippet_with_applicability, snippet_with_context}; use clippy_utils::sugg::has_enclosing_paren; -use clippy_utils::ty::{implements_trait, is_manually_drop}; +use clippy_utils::ty::{adjust_derefs_manually_drop, implements_trait, is_manually_drop}; use clippy_utils::{ DefinedTy, ExprUseNode, expr_use_ctxt, get_parent_expr, is_block_like, is_lint_allowed, path_to_local, peel_middle_ty_refs, }; -use core::mem; use rustc_ast::util::parser::ExprPrecedence; use rustc_data_structures::fx::FxIndexMap; use rustc_errors::Applicability; @@ -707,14 +706,6 @@ fn try_parse_ref_op<'tcx>( )) } -// Checks if the adjustments contains a deref of `ManuallyDrop<_>` -fn adjust_derefs_manually_drop<'tcx>(adjustments: &'tcx [Adjustment<'tcx>], mut ty: Ty<'tcx>) -> bool { - adjustments.iter().any(|a| { - let ty = mem::replace(&mut ty, a.target); - matches!(a.kind, Adjust::Deref(Some(ref op)) if op.mutbl == Mutability::Mut) && is_manually_drop(ty) - }) -} - // Checks whether the type for a deref call actually changed the type, not just the mutability of // the reference. fn deref_method_same_type<'tcx>(result_ty: Ty<'tcx>, arg_ty: Ty<'tcx>) -> bool { diff --git a/src/tools/clippy/clippy_lints/src/doc/mod.rs b/src/tools/clippy/clippy_lints/src/doc/mod.rs index d27d68d3866..eca3bc390d7 100644 --- a/src/tools/clippy/clippy_lints/src/doc/mod.rs +++ b/src/tools/clippy/clippy_lints/src/doc/mod.rs @@ -1139,12 +1139,12 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize None, "a backtick may be missing a pair", ); + text_to_check.clear(); } else { - for (text, range, assoc_code_level) in text_to_check { + for (text, range, assoc_code_level) in text_to_check.drain(..) { markdown::check(cx, valid_idents, &text, &fragments, range, assoc_code_level, blockquote_level); } } - text_to_check = Vec::new(); }, Start(FootnoteDefinition(..)) => in_footnote_definition = true, End(TagEnd::FootnoteDefinition) => in_footnote_definition = false, diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs index e467246741c..0eefc2f6109 100644 --- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs +++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs @@ -231,9 +231,13 @@ fn check_closure<'tcx>(cx: &LateContext<'tcx>, outer_receiver: Option<&Expr<'tcx _ => (), } } + let replace_with = match callee_ty_adjusted.kind() { + ty::FnDef(def, _) => cx.tcx.def_descr(*def), + _ => "function", + }; diag.span_suggestion( expr.span, - "replace the closure with the function itself", + format!("replace the closure with the {replace_with} itself"), snippet, Applicability::MachineApplicable, ); diff --git a/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs b/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs index b816963cc82..d5873b3f85a 100644 --- a/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs +++ b/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::sugg::Sugg; -use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item}; +use clippy_utils::ty::is_type_lang_item; use clippy_utils::{is_in_const_context, is_integer_literal, sym}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, LangItem, PrimTy, QPath, TyKind, def}; @@ -89,5 +89,5 @@ impl<'tcx> LateLintPass<'tcx> for FromStrRadix10 { /// Checks if a Ty is `String` or `&str` fn is_ty_stringish(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { - is_type_lang_item(cx, ty, LangItem::String) || is_type_diagnostic_item(cx, ty, sym::str) + is_type_lang_item(cx, ty, LangItem::String) || ty.peel_refs().is_str() } diff --git a/src/tools/clippy/clippy_lints/src/functions/duplicate_underscore_argument.rs b/src/tools/clippy/clippy_lints/src/functions/duplicate_underscore_argument.rs new file mode 100644 index 00000000000..b15d1b1bb79 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/functions/duplicate_underscore_argument.rs @@ -0,0 +1,34 @@ +use clippy_utils::diagnostics::span_lint; +use rustc_ast::PatKind; +use rustc_ast::visit::FnKind; +use rustc_data_structures::fx::FxHashMap; +use rustc_lint::EarlyContext; +use rustc_span::Span; + +use super::DUPLICATE_UNDERSCORE_ARGUMENT; + +pub(super) fn check(cx: &EarlyContext<'_>, fn_kind: FnKind<'_>) { + let mut registered_names: FxHashMap<String, Span> = FxHashMap::default(); + + for arg in &fn_kind.decl().inputs { + if let PatKind::Ident(_, ident, None) = arg.pat.kind { + let arg_name = ident.to_string(); + + if let Some(arg_name) = arg_name.strip_prefix('_') { + if let Some(correspondence) = registered_names.get(arg_name) { + span_lint( + cx, + DUPLICATE_UNDERSCORE_ARGUMENT, + *correspondence, + format!( + "`{arg_name}` already exists, having another argument having almost the same \ + name makes code comprehension and documentation more difficult" + ), + ); + } + } else { + registered_names.insert(arg_name, arg.pat.span); + } + } + } +} diff --git a/src/tools/clippy/clippy_lints/src/functions/mod.rs b/src/tools/clippy/clippy_lints/src/functions/mod.rs index 6051dc9479b..ca5ea901814 100644 --- a/src/tools/clippy/clippy_lints/src/functions/mod.rs +++ b/src/tools/clippy/clippy_lints/src/functions/mod.rs @@ -1,3 +1,4 @@ +mod duplicate_underscore_argument; mod impl_trait_in_params; mod misnamed_getters; mod must_use; @@ -11,16 +12,40 @@ mod too_many_lines; use clippy_config::Conf; use clippy_utils::msrvs::Msrv; use clippy_utils::paths::{PathNS, lookup_path_str}; +use rustc_ast::{self as ast, visit}; use rustc_hir as hir; use rustc_hir::intravisit; -use rustc_lint::{LateContext, LateLintPass}; +use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass}; use rustc_middle::ty::TyCtxt; -use rustc_session::impl_lint_pass; +use rustc_session::{declare_lint_pass, impl_lint_pass}; use rustc_span::Span; use rustc_span::def_id::{DefIdSet, LocalDefId}; declare_clippy_lint! { /// ### What it does + /// Checks for function arguments having the similar names + /// differing by an underscore. + /// + /// ### Why is this bad? + /// It affects code readability. + /// + /// ### Example + /// ```no_run + /// fn foo(a: i32, _a: i32) {} + /// ``` + /// + /// Use instead: + /// ```no_run + /// fn bar(a: i32, _b: i32) {} + /// ``` + #[clippy::version = "pre 1.29.0"] + pub DUPLICATE_UNDERSCORE_ARGUMENT, + style, + "function arguments having names which only differ by an underscore" +} + +declare_clippy_lint! { + /// ### What it does /// Checks for functions with too many parameters. /// /// ### Why is this bad? @@ -448,6 +473,14 @@ declare_clippy_lint! { "function signature uses `&Option<T>` instead of `Option<&T>`" } +declare_lint_pass!(EarlyFunctions => [DUPLICATE_UNDERSCORE_ARGUMENT]); + +impl EarlyLintPass for EarlyFunctions { + fn check_fn(&mut self, cx: &EarlyContext<'_>, fn_kind: visit::FnKind<'_>, _: Span, _: ast::NodeId) { + duplicate_underscore_argument::check(cx, fn_kind); + } +} + pub struct Functions { too_many_arguments_threshold: u64, too_many_lines_threshold: u64, @@ -503,7 +536,7 @@ impl<'tcx> LateLintPass<'tcx> for Functions { ) { let hir_id = cx.tcx.local_def_id_to_hir_id(def_id); too_many_arguments::check_fn(cx, kind, decl, span, hir_id, self.too_many_arguments_threshold); - too_many_lines::check_fn(cx, kind, span, body, self.too_many_lines_threshold); + too_many_lines::check_fn(cx, kind, body, span, def_id, self.too_many_lines_threshold); not_unsafe_ptr_arg_deref::check_fn(cx, kind, decl, body, def_id); misnamed_getters::check_fn(cx, kind, decl, body, span); impl_trait_in_params::check_fn(cx, &kind, body, hir_id); diff --git a/src/tools/clippy/clippy_lints/src/functions/renamed_function_params.rs b/src/tools/clippy/clippy_lints/src/functions/renamed_function_params.rs index 0a7c6e9d5f8..f8e8f5544b9 100644 --- a/src/tools/clippy/clippy_lints/src/functions/renamed_function_params.rs +++ b/src/tools/clippy/clippy_lints/src/functions/renamed_function_params.rs @@ -6,6 +6,7 @@ use rustc_hir::{Impl, ImplItem, ImplItemKind, ItemKind, Node, TraitRef}; use rustc_lint::LateContext; use rustc_span::Span; use rustc_span::symbol::{Ident, kw}; +use std::iter; use super::RENAMED_FUNCTION_PARAMS; @@ -58,16 +59,11 @@ impl RenamedFnArgs { let mut renamed: Vec<(Span, String)> = vec![]; debug_assert!(default_idents.size_hint() == current_idents.size_hint()); - while let (Some(default_ident), Some(current_ident)) = (default_idents.next(), current_idents.next()) { + for (default_ident, current_ident) in iter::zip(default_idents, current_idents) { let has_name_to_check = |ident: Option<Ident>| { - if let Some(ident) = ident - && ident.name != kw::Underscore - && !ident.name.as_str().starts_with('_') - { - Some(ident) - } else { - None - } + ident + .filter(|ident| ident.name != kw::Underscore) + .filter(|ident| !ident.name.as_str().starts_with('_')) }; if let Some(default_ident) = has_name_to_check(default_ident) @@ -97,8 +93,7 @@ fn trait_item_def_id_of_impl(cx: &LateContext<'_>, target: OwnerId) -> Option<De } fn is_from_ignored_trait(of_trait: &TraitRef<'_>, ignored_traits: &DefIdSet) -> bool { - let Some(trait_did) = of_trait.trait_def_id() else { - return false; - }; - ignored_traits.contains(&trait_did) + of_trait + .trait_def_id() + .is_some_and(|trait_did| ignored_traits.contains(&trait_did)) } diff --git a/src/tools/clippy/clippy_lints/src/functions/result.rs b/src/tools/clippy/clippy_lints/src/functions/result.rs index bb98ae82611..1f2fce687ed 100644 --- a/src/tools/clippy/clippy_lints/src/functions/result.rs +++ b/src/tools/clippy/clippy_lints/src/functions/result.rs @@ -97,11 +97,7 @@ fn check_result_unit_err(cx: &LateContext<'_>, err_ty: Ty<'_>, fn_header_span: S fn check_result_large_err<'tcx>(cx: &LateContext<'tcx>, err_ty: Ty<'tcx>, hir_ty_span: Span, large_err_threshold: u64) { if let ty::Adt(adt, subst) = err_ty.kind() - && let Some(local_def_id) = err_ty - .ty_adt_def() - .expect("already checked this is adt") - .did() - .as_local() + && let Some(local_def_id) = adt.did().as_local() && let hir::Node::Item(item) = cx.tcx.hir_node_by_def_id(local_def_id) && let hir::ItemKind::Enum(_, _, ref def) = item.kind { diff --git a/src/tools/clippy/clippy_lints/src/functions/too_many_lines.rs b/src/tools/clippy/clippy_lints/src/functions/too_many_lines.rs index 4f90d9655b4..33eede8e65a 100644 --- a/src/tools/clippy/clippy_lints/src/functions/too_many_lines.rs +++ b/src/tools/clippy/clippy_lints/src/functions/too_many_lines.rs @@ -1,6 +1,7 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::source::SpanRangeExt; use rustc_hir as hir; +use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::FnKind; use rustc_lint::{LateContext, LintContext}; use rustc_span::Span; @@ -10,8 +11,9 @@ use super::TOO_MANY_LINES; pub(super) fn check_fn( cx: &LateContext<'_>, kind: FnKind<'_>, - span: Span, body: &hir::Body<'_>, + span: Span, + def_id: LocalDefId, too_many_lines_threshold: u64, ) { // Closures must be contained in a parent body, which will be checked for `too_many_lines`. @@ -74,7 +76,7 @@ pub(super) fn check_fn( span_lint( cx, TOO_MANY_LINES, - span, + cx.tcx.def_span(def_id), format!("this function has too many lines ({line_count}/{too_many_lines_threshold})"), ); } diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs index 6beddc1be14..57deb011f2b 100644 --- a/src/tools/clippy/clippy_lints/src/len_zero.rs +++ b/src/tools/clippy/clippy_lints/src/len_zero.rs @@ -176,12 +176,11 @@ impl<'tcx> LateLintPass<'tcx> for LenZero { if let ExprKind::Let(lt) = expr.kind && match lt.pat.kind { PatKind::Slice([], None, []) => true, - PatKind::Expr(lit) => match lit.kind { - PatExprKind::Lit { lit, .. } => match lit.node { - LitKind::Str(lit, _) => lit.as_str().is_empty(), - _ => false, - }, - _ => false, + PatKind::Expr(lit) + if let PatExprKind::Lit { lit, .. } = lit.kind + && let LitKind::Str(lit, _) = lit.node => + { + lit.as_str().is_empty() }, _ => false, } @@ -336,33 +335,23 @@ fn extract_future_output<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<& } fn is_first_generic_integral<'tcx>(segment: &'tcx PathSegment<'tcx>) -> bool { - if let Some(generic_args) = segment.args { - if generic_args.args.is_empty() { - return false; - } - let arg = &generic_args.args[0]; - if let GenericArg::Type(rustc_hir::Ty { - kind: TyKind::Path(QPath::Resolved(_, path)), - .. - }) = arg - { - let segments = &path.segments; - let segment = &segments[0]; - let res = &segment.res; - if matches!(res, Res::PrimTy(PrimTy::Uint(_))) || matches!(res, Res::PrimTy(PrimTy::Int(_))) { - return true; - } - } + if let Some(generic_args) = segment.args + && let [GenericArg::Type(ty), ..] = &generic_args.args + && let TyKind::Path(QPath::Resolved(_, path)) = ty.kind + && let [segment, ..] = &path.segments + && matches!(segment.res, Res::PrimTy(PrimTy::Uint(_) | PrimTy::Int(_))) + { + true + } else { + false } - - false } fn parse_len_output<'tcx>(cx: &LateContext<'tcx>, sig: FnSig<'tcx>) -> Option<LenOutput> { if let Some(segment) = extract_future_output(cx, sig.output()) { let res = segment.res; - if matches!(res, Res::PrimTy(PrimTy::Uint(_))) || matches!(res, Res::PrimTy(PrimTy::Int(_))) { + if matches!(res, Res::PrimTy(PrimTy::Uint(_) | PrimTy::Int(_))) { return Some(LenOutput::Integral); } diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index 844bc1b0e39..d468993e744 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs @@ -556,6 +556,7 @@ pub fn register_lint_passes(store: &mut rustc_lint::LintStore, conf: &'static Co store.register_late_pass(|_| Box::new(panicking_overflow_checks::PanickingOverflowChecks)); store.register_late_pass(|_| Box::<new_without_default::NewWithoutDefault>::default()); store.register_late_pass(move |_| Box::new(disallowed_names::DisallowedNames::new(conf))); + store.register_early_pass(|| Box::new(functions::EarlyFunctions)); store.register_late_pass(move |tcx| Box::new(functions::Functions::new(tcx, conf))); store.register_late_pass(move |_| Box::new(doc::Documentation::new(conf))); store.register_early_pass(move || Box::new(doc::Documentation::new(conf))); @@ -600,7 +601,7 @@ pub fn register_lint_passes(store: &mut rustc_lint::LintStore, conf: &'static Co store.register_late_pass(move |_| Box::new(trait_bounds::TraitBounds::new(conf))); store.register_late_pass(|_| Box::new(comparison_chain::ComparisonChain)); store.register_late_pass(move |tcx| Box::new(mut_key::MutableKeyType::new(tcx, conf))); - store.register_early_pass(|| Box::new(reference::DerefAddrOf)); + store.register_late_pass(|_| Box::new(reference::DerefAddrOf)); store.register_early_pass(|| Box::new(double_parens::DoubleParens)); let format_args = format_args_storage.clone(); store.register_late_pass(move |_| Box::new(format_impl::FormatImpl::new(format_args.clone()))); diff --git a/src/tools/clippy/clippy_lints/src/loops/infinite_loop.rs b/src/tools/clippy/clippy_lints/src/loops/infinite_loop.rs index 797ff1f3986..a71e6963f8c 100644 --- a/src/tools/clippy/clippy_lints/src/loops/infinite_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/infinite_loop.rs @@ -1,10 +1,11 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::{fn_def_id, is_from_proc_macro, is_lint_allowed}; use hir::intravisit::{Visitor, walk_expr}; -use hir::{Expr, ExprKind, FnRetTy, FnSig, Node, TyKind}; use rustc_ast::Label; use rustc_errors::Applicability; -use rustc_hir as hir; +use rustc_hir::{ + self as hir, Closure, ClosureKind, CoroutineDesugaring, CoroutineKind, Expr, ExprKind, FnRetTy, FnSig, Node, TyKind, +}; use rustc_lint::{LateContext, LintContext}; use rustc_span::sym; @@ -29,6 +30,10 @@ pub(super) fn check<'tcx>( return; } + if is_inside_unawaited_async_block(cx, expr) { + return; + } + if expr.span.in_external_macro(cx.sess().source_map()) || is_from_proc_macro(cx, expr) { return; } @@ -60,6 +65,39 @@ pub(super) fn check<'tcx>( } } +/// Check if the given expression is inside an async block that is not being awaited. +/// This helps avoid false positives when async blocks are spawned or assigned to variables. +fn is_inside_unawaited_async_block(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { + let current_hir_id = expr.hir_id; + for (_, parent_node) in cx.tcx.hir_parent_iter(current_hir_id) { + if let Node::Expr(Expr { + kind: + ExprKind::Closure(Closure { + kind: ClosureKind::Coroutine(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)), + .. + }), + .. + }) = parent_node + { + return !is_async_block_awaited(cx, expr); + } + } + false +} + +fn is_async_block_awaited(cx: &LateContext<'_>, async_expr: &Expr<'_>) -> bool { + for (_, parent_node) in cx.tcx.hir_parent_iter(async_expr.hir_id) { + if let Node::Expr(Expr { + kind: ExprKind::Match(_, _, hir::MatchSource::AwaitDesugar), + .. + }) = parent_node + { + return true; + } + } + false +} + fn get_parent_fn_ret_ty<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> Option<FnRetTy<'tcx>> { for (_, parent_node) in cx.tcx.hir_parent_iter(expr.hir_id) { match parent_node { @@ -67,8 +105,8 @@ fn get_parent_fn_ret_ty<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> Option // This is because we still need to backtrack one parent node to get the `OpaqueDef` ty. Node::Expr(Expr { kind: - ExprKind::Closure(hir::Closure { - kind: hir::ClosureKind::Coroutine(_), + ExprKind::Closure(Closure { + kind: ClosureKind::Coroutine(_), .. }), .. @@ -90,7 +128,7 @@ fn get_parent_fn_ret_ty<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> Option .. }) | Node::Expr(Expr { - kind: ExprKind::Closure(hir::Closure { fn_decl: decl, .. }), + kind: ExprKind::Closure(Closure { fn_decl: decl, .. }), .. }) => return Some(decl.output), _ => (), diff --git a/src/tools/clippy/clippy_lints/src/manual_let_else.rs b/src/tools/clippy/clippy_lints/src/manual_let_else.rs index 1f9a943f13d..5a7967bbf94 100644 --- a/src/tools/clippy/clippy_lints/src/manual_let_else.rs +++ b/src/tools/clippy/clippy_lints/src/manual_let_else.rs @@ -49,7 +49,7 @@ declare_clippy_lint! { } impl<'tcx> QuestionMark { - pub(crate) fn check_manual_let_else(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'tcx>) { + pub(crate) fn check_manual_let_else(&self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'tcx>) { if let StmtKind::Let(local) = stmt.kind && let Some(init) = local.init && local.els.is_none() diff --git a/src/tools/clippy/clippy_lints/src/matches/match_bool.rs b/src/tools/clippy/clippy_lints/src/matches/match_bool.rs index b90cf6357c5..a2c8741f4f7 100644 --- a/src/tools/clippy/clippy_lints/src/matches/match_bool.rs +++ b/src/tools/clippy/clippy_lints/src/matches/match_bool.rs @@ -12,7 +12,11 @@ use super::MATCH_BOOL; pub(crate) fn check(cx: &LateContext<'_>, scrutinee: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>) { // Type of expression is `bool`. - if *cx.typeck_results().expr_ty(scrutinee).kind() == ty::Bool { + if *cx.typeck_results().expr_ty(scrutinee).kind() == ty::Bool + && arms + .iter() + .all(|arm| arm.pat.walk_short(|p| !matches!(p.kind, PatKind::Binding(..)))) + { span_lint_and_then( cx, MATCH_BOOL, diff --git a/src/tools/clippy/clippy_lints/src/matches/match_ref_pats.rs b/src/tools/clippy/clippy_lints/src/matches/match_ref_pats.rs index 5445ee1f042..5934ec40993 100644 --- a/src/tools/clippy/clippy_lints/src/matches/match_ref_pats.rs +++ b/src/tools/clippy/clippy_lints/src/matches/match_ref_pats.rs @@ -17,6 +17,11 @@ where return; } + // `!` cannot be deref-ed + if cx.typeck_results().expr_ty(scrutinee).is_never() { + return; + } + let (first_sugg, msg, title); let ctxt = expr.span.ctxt(); let mut app = Applicability::Unspecified; diff --git a/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs b/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs index 8b4c1700051..eb8b16e1561 100644 --- a/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs +++ b/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs @@ -54,7 +54,7 @@ impl<'tcx> Visitor<'tcx> for MatchExprVisitor<'_, 'tcx> { } impl MatchExprVisitor<'_, '_> { - fn case_altered(&mut self, segment_ident: Symbol, receiver: &Expr<'_>) -> ControlFlow<CaseMethod> { + fn case_altered(&self, segment_ident: Symbol, receiver: &Expr<'_>) -> ControlFlow<CaseMethod> { if let Some(case_method) = get_case_method(segment_ident) { let ty = self.cx.typeck_results().expr_ty(receiver).peel_refs(); diff --git a/src/tools/clippy/clippy_lints/src/methods/double_ended_iterator_last.rs b/src/tools/clippy/clippy_lints/src/methods/double_ended_iterator_last.rs index 6d841853fbe..578865c3291 100644 --- a/src/tools/clippy/clippy_lints/src/methods/double_ended_iterator_last.rs +++ b/src/tools/clippy/clippy_lints/src/methods/double_ended_iterator_last.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::ty::{has_non_owning_mutable_access, implements_trait}; -use clippy_utils::{is_mutable, is_trait_method, path_to_local, sym}; +use clippy_utils::{is_mutable, is_trait_method, path_to_local_with_projections, sym}; use rustc_errors::Applicability; use rustc_hir::{Expr, Node, PatKind}; use rustc_lint::LateContext; @@ -37,7 +37,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &'_ Expr<'_>, self_expr: &'_ Exp // TODO: Change this to lint only when the referred iterator is not used later. If it is used later, // changing to `next_back()` may change its behavior. if !(is_mutable(cx, self_expr) || self_type.is_ref()) { - if let Some(hir_id) = path_to_local(self_expr) + if let Some(hir_id) = path_to_local_with_projections(self_expr) && let Node::Pat(pat) = cx.tcx.hir_node(hir_id) && let PatKind::Binding(_, _, ident, _) = pat.kind { diff --git a/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs b/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs index 6e5da5bda8c..818e26f8aa1 100644 --- a/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs +++ b/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs @@ -15,7 +15,6 @@ use std::ops::ControlFlow; use super::EXPECT_FUN_CALL; /// Checks for the `EXPECT_FUN_CALL` lint. -#[allow(clippy::too_many_lines)] pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, format_args_storage: &FormatArgsStorage, @@ -25,43 +24,6 @@ pub(super) fn check<'tcx>( receiver: &'tcx hir::Expr<'tcx>, args: &'tcx [hir::Expr<'tcx>], ) { - // Strip `{}`, `&`, `as_ref()` and `as_str()` off `arg` until we're left with either a `String` or - // `&str` - fn get_arg_root<'a>(cx: &LateContext<'_>, arg: &'a hir::Expr<'a>) -> &'a hir::Expr<'a> { - let mut arg_root = peel_blocks(arg); - loop { - arg_root = match &arg_root.kind { - hir::ExprKind::AddrOf(hir::BorrowKind::Ref, _, expr) => expr, - hir::ExprKind::MethodCall(method_name, receiver, [], ..) => { - if (method_name.ident.name == sym::as_str || method_name.ident.name == sym::as_ref) && { - let arg_type = cx.typeck_results().expr_ty(receiver); - let base_type = arg_type.peel_refs(); - base_type.is_str() || is_type_lang_item(cx, base_type, hir::LangItem::String) - } { - receiver - } else { - break; - } - }, - _ => break, - }; - } - arg_root - } - - fn contains_call<'a>(cx: &LateContext<'a>, arg: &'a hir::Expr<'a>) -> bool { - for_each_expr(cx, arg, |expr| { - if matches!(expr.kind, hir::ExprKind::MethodCall { .. } | hir::ExprKind::Call { .. }) - && !is_inside_always_const_context(cx.tcx, expr.hir_id) - { - ControlFlow::Break(()) - } else { - ControlFlow::Continue(()) - } - }) - .is_some() - } - if name == sym::expect && let [arg] = args && let arg_root = get_arg_root(cx, arg) @@ -114,3 +76,40 @@ pub(super) fn check<'tcx>( ); } } + +/// Strip `{}`, `&`, `as_ref()` and `as_str()` off `arg` until we're left with either a `String` or +/// `&str` +fn get_arg_root<'a>(cx: &LateContext<'_>, arg: &'a hir::Expr<'a>) -> &'a hir::Expr<'a> { + let mut arg_root = peel_blocks(arg); + loop { + arg_root = match &arg_root.kind { + hir::ExprKind::AddrOf(hir::BorrowKind::Ref, _, expr) => expr, + hir::ExprKind::MethodCall(method_name, receiver, [], ..) => { + if (method_name.ident.name == sym::as_str || method_name.ident.name == sym::as_ref) && { + let arg_type = cx.typeck_results().expr_ty(receiver); + let base_type = arg_type.peel_refs(); + base_type.is_str() || is_type_lang_item(cx, base_type, hir::LangItem::String) + } { + receiver + } else { + break; + } + }, + _ => break, + }; + } + arg_root +} + +fn contains_call<'a>(cx: &LateContext<'a>, arg: &'a hir::Expr<'a>) -> bool { + for_each_expr(cx, arg, |expr| { + if matches!(expr.kind, hir::ExprKind::MethodCall { .. } | hir::ExprKind::Call { .. }) + && !is_inside_always_const_context(cx.tcx, expr.hir_id) + { + ControlFlow::Break(()) + } else { + ControlFlow::Continue(()) + } + }) + .is_some() +} diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs index 4dd54cf1974..5b8457bdd16 100644 --- a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs +++ b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs @@ -106,7 +106,7 @@ enum CheckResult<'tcx> { impl<'tcx> OffendingFilterExpr<'tcx> { pub fn check_map_call( - &mut self, + &self, cx: &LateContext<'tcx>, map_body: &'tcx Body<'tcx>, map_param_id: HirId, @@ -413,7 +413,7 @@ fn is_find_or_filter<'a>( } && let PatKind::Binding(_, filter_param_id, _, None) = filter_pat.kind - && let Some(mut offending_expr) = OffendingFilterExpr::hir(cx, filter_body.value, filter_param_id) + && let Some(offending_expr) = OffendingFilterExpr::hir(cx, filter_body.value, filter_param_id) && let ExprKind::Closure(&Closure { body: map_body_id, .. }) = map_arg.kind && let map_body = cx.tcx.hir_body(map_body_id) diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_next.rs b/src/tools/clippy/clippy_lints/src/methods/filter_next.rs index 6c1a14fc882..72f83b245a0 100644 --- a/src/tools/clippy/clippy_lints/src/methods/filter_next.rs +++ b/src/tools/clippy/clippy_lints/src/methods/filter_next.rs @@ -1,4 +1,5 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; +use clippy_utils::path_to_local_with_projections; use clippy_utils::source::snippet; use clippy_utils::ty::implements_trait; use rustc_ast::{BindingMode, Mutability}; @@ -9,21 +10,6 @@ use rustc_span::sym; use super::FILTER_NEXT; -fn path_to_local(expr: &hir::Expr<'_>) -> Option<hir::HirId> { - match expr.kind { - hir::ExprKind::Field(f, _) => path_to_local(f), - hir::ExprKind::Index(recv, _, _) => path_to_local(recv), - hir::ExprKind::Path(hir::QPath::Resolved( - _, - hir::Path { - res: rustc_hir::def::Res::Local(local), - .. - }, - )) => Some(*local), - _ => None, - } -} - /// lint use of `filter().next()` for `Iterators` pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, @@ -44,7 +30,7 @@ pub(super) fn check<'tcx>( let iter_snippet = snippet(cx, recv.span, ".."); // add note if not multi-line span_lint_and_then(cx, FILTER_NEXT, expr.span, msg, |diag| { - let (applicability, pat) = if let Some(id) = path_to_local(recv) + let (applicability, pat) = if let Some(id) = path_to_local_with_projections(recv) && let hir::Node::Pat(pat) = cx.tcx.hir_node(id) && let hir::PatKind::Binding(BindingMode(_, Mutability::Not), _, ident, _) = pat.kind { diff --git a/src/tools/clippy/clippy_lints/src/misc_early/mod.rs b/src/tools/clippy/clippy_lints/src/misc_early/mod.rs index f880f1f329f..f988323a8c1 100644 --- a/src/tools/clippy/clippy_lints/src/misc_early/mod.rs +++ b/src/tools/clippy/clippy_lints/src/misc_early/mod.rs @@ -7,12 +7,9 @@ mod unneeded_field_pattern; mod unneeded_wildcard_pattern; mod zero_prefixed_literal; -use clippy_utils::diagnostics::span_lint; use clippy_utils::source::snippet_opt; -use rustc_ast::ast::{Expr, ExprKind, Generics, LitFloatType, LitIntType, LitKind, NodeId, Pat, PatKind}; +use rustc_ast::ast::{Expr, ExprKind, Generics, LitFloatType, LitIntType, LitKind, Pat}; use rustc_ast::token; -use rustc_ast::visit::FnKind; -use rustc_data_structures::fx::FxHashMap; use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; use rustc_session::declare_lint_pass; use rustc_span::Span; @@ -62,29 +59,6 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for function arguments having the similar names - /// differing by an underscore. - /// - /// ### Why is this bad? - /// It affects code readability. - /// - /// ### Example - /// ```no_run - /// fn foo(a: i32, _a: i32) {} - /// ``` - /// - /// Use instead: - /// ```no_run - /// fn bar(a: i32, _b: i32) {} - /// ``` - #[clippy::version = "pre 1.29.0"] - pub DUPLICATE_UNDERSCORE_ARGUMENT, - style, - "function arguments having names which only differ by an underscore" -} - -declare_clippy_lint! { - /// ### What it does /// Warns on hexadecimal literals with mixed-case letter /// digits. /// @@ -330,7 +304,6 @@ declare_clippy_lint! { declare_lint_pass!(MiscEarlyLints => [ UNNEEDED_FIELD_PATTERN, - DUPLICATE_UNDERSCORE_ARGUMENT, MIXED_CASE_HEX_LITERALS, UNSEPARATED_LITERAL_SUFFIX, SEPARATED_LITERAL_SUFFIX, @@ -359,32 +332,6 @@ impl EarlyLintPass for MiscEarlyLints { unneeded_wildcard_pattern::check(cx, pat); } - fn check_fn(&mut self, cx: &EarlyContext<'_>, fn_kind: FnKind<'_>, _: Span, _: NodeId) { - let mut registered_names: FxHashMap<String, Span> = FxHashMap::default(); - - for arg in &fn_kind.decl().inputs { - if let PatKind::Ident(_, ident, None) = arg.pat.kind { - let arg_name = ident.to_string(); - - if let Some(arg_name) = arg_name.strip_prefix('_') { - if let Some(correspondence) = registered_names.get(arg_name) { - span_lint( - cx, - DUPLICATE_UNDERSCORE_ARGUMENT, - *correspondence, - format!( - "`{arg_name}` already exists, having another argument having almost the same \ - name makes code comprehension and documentation more difficult" - ), - ); - } - } else { - registered_names.insert(arg_name, arg.pat.span); - } - } - } - } - fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { if expr.span.in_external_macro(cx.sess().source_map()) { return; @@ -404,7 +351,7 @@ impl MiscEarlyLints { // See <https://github.com/rust-lang/rust-clippy/issues/4507> for a regression. // FIXME: Find a better way to detect those cases. let lit_snip = match snippet_opt(cx, span) { - Some(snip) if snip.chars().next().is_some_and(|c| c.is_ascii_digit()) => snip, + Some(snip) if snip.starts_with(|c: char| c.is_ascii_digit()) => snip, _ => return, }; diff --git a/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs b/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs index a489c0a4a5a..3b44d4b60d3 100644 --- a/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs +++ b/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs @@ -134,7 +134,7 @@ impl<'tcx> DivergenceVisitor<'_, 'tcx> { } } - fn report_diverging_sub_expr(&mut self, e: &Expr<'_>) { + fn report_diverging_sub_expr(&self, e: &Expr<'_>) { if let Some(macro_call) = root_macro_call_first_node(self.cx, e) && self.cx.tcx.is_diagnostic_item(sym::todo_macro, macro_call.def_id) { diff --git a/src/tools/clippy/clippy_lints/src/needless_bool.rs b/src/tools/clippy/clippy_lints/src/needless_bool.rs index fa5afcc0087..6ae26156bc4 100644 --- a/src/tools/clippy/clippy_lints/src/needless_bool.rs +++ b/src/tools/clippy/clippy_lints/src/needless_bool.rs @@ -166,7 +166,9 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBool { applicability, ); }; - if let Some((a, b)) = fetch_bool_block(then).and_then(|a| Some((a, fetch_bool_block(else_expr)?))) { + if let Some(a) = fetch_bool_block(then) + && let Some(b) = fetch_bool_block(else_expr) + { match (a, b) { (RetBool(true), RetBool(true)) | (Bool(true), Bool(true)) => { span_lint( diff --git a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs index 120a4b98a65..c7c4976aeb7 100644 --- a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs +++ b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs @@ -59,7 +59,7 @@ declare_clippy_lint! { pub struct NeedlessBorrowsForGenericArgs<'tcx> { /// Stack of (body owner, `PossibleBorrowerMap`) pairs. Used by - /// `needless_borrow_impl_arg_position` to determine when a borrowed expression can instead + /// [`needless_borrow_count`] to determine when a borrowed expression can instead /// be moved. possible_borrowers: Vec<(LocalDefId, PossibleBorrowerMap<'tcx, 'tcx>)>, diff --git a/src/tools/clippy/clippy_lints/src/no_effect.rs b/src/tools/clippy/clippy_lints/src/no_effect.rs index 72e6503e7e4..0d6666eed45 100644 --- a/src/tools/clippy/clippy_lints/src/no_effect.rs +++ b/src/tools/clippy/clippy_lints/src/no_effect.rs @@ -305,11 +305,12 @@ fn check_unnecessary_operation(cx: &LateContext<'_>, stmt: &Stmt<'_>) { for e in reduced { if let Some(snip) = e.span.get_source_text(cx) { snippet.push_str(&snip); - snippet.push(';'); + snippet.push_str("; "); } else { return; } } + snippet.pop(); // remove the last space span_lint_hir_and_then( cx, UNNECESSARY_OPERATION, 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 8a5a6f4a4dc..2fffc4244a7 100644 --- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs +++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs @@ -92,7 +92,7 @@ declare_clippy_lint! { /// ``` #[clippy::version = "pre 1.29.0"] pub DECLARE_INTERIOR_MUTABLE_CONST, - style, + suspicious, "declaring `const` with interior mutability" } diff --git a/src/tools/clippy/clippy_lints/src/non_expressive_names.rs b/src/tools/clippy/clippy_lints/src/non_expressive_names.rs index c5873589b26..1961ac1516d 100644 --- a/src/tools/clippy/clippy_lints/src/non_expressive_names.rs +++ b/src/tools/clippy/clippy_lints/src/non_expressive_names.rs @@ -248,6 +248,11 @@ impl SimilarNamesNameVisitor<'_, '_, '_> { continue; } + // Skip similarity check if both names are exactly 3 characters + if count == 3 && existing_name.len == 3 { + continue; + } + let dissimilar = match existing_name.len.cmp(&count) { Ordering::Greater => existing_name.len - count != 1 || levenstein_not_1(interned_name, existing_str), Ordering::Less => count - existing_name.len != 1 || levenstein_not_1(existing_str, interned_name), diff --git a/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs b/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs index ba8f6354d97..a42763172f5 100644 --- a/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs +++ b/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs @@ -173,7 +173,7 @@ impl Params { } /// Sets the `apply_lint` flag on each parameter. - fn flag_for_linting(&mut self) { + fn flag_for_linting(&self) { // Stores the list of parameters currently being resolved. Needed to avoid cycles. let mut eval_stack = Vec::new(); for param in &self.params { diff --git a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs index 466beb04b07..ea5b81aec31 100644 --- a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs +++ b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs @@ -325,7 +325,7 @@ impl ArithmeticSideEffects { self.issue_lint(cx, expr); } - fn should_skip_expr<'tcx>(&mut self, cx: &LateContext<'tcx>, expr: &hir::Expr<'tcx>) -> bool { + fn should_skip_expr<'tcx>(&self, cx: &LateContext<'tcx>, expr: &hir::Expr<'tcx>) -> bool { is_lint_allowed(cx, ARITHMETIC_SIDE_EFFECTS, expr.hir_id) || self.expr_span.is_some() || self.const_span.is_some_and(|sp| sp.contains(expr.span)) diff --git a/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs b/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs index e6be536ca0f..9b1b063c473 100644 --- a/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs +++ b/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs @@ -13,7 +13,7 @@ pub struct Context { const_span: Option<Span>, } impl Context { - fn skip_expr(&mut self, e: &hir::Expr<'_>) -> bool { + fn skip_expr(&self, e: &hir::Expr<'_>) -> bool { self.expr_id.is_some() || self.const_span.is_some_and(|span| span.contains(e.span)) } diff --git a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs index d7b4a03aa53..1b1e77bbea8 100644 --- a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs +++ b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs @@ -120,7 +120,7 @@ impl PassByRefOrValue { } } - fn check_poly_fn(&mut self, cx: &LateContext<'_>, def_id: LocalDefId, decl: &FnDecl<'_>, span: Option<Span>) { + fn check_poly_fn(&self, cx: &LateContext<'_>, def_id: LocalDefId, decl: &FnDecl<'_>, span: Option<Span>) { if self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(def_id) { return; } diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs index b3058c51afd..9eed46460a6 100644 --- a/src/tools/clippy/clippy_lints/src/ptr.rs +++ b/src/tools/clippy/clippy_lints/src/ptr.rs @@ -237,7 +237,7 @@ impl<'tcx> LateLintPass<'tcx> for Ptr { .collect(); let results = check_ptr_arg_usage(cx, body, &lint_args); - for (result, args) in results.iter().zip(lint_args.iter()).filter(|(r, _)| !r.skip) { + for (result, args) in iter::zip(&results, &lint_args).filter(|(r, _)| !r.skip) { span_lint_hir_and_then(cx, PTR_ARG, args.emission_id, args.span, args.build_msg(), |diag| { diag.multipart_suggestion( "change this to", @@ -386,7 +386,6 @@ impl<'tcx> DerefTy<'tcx> { } } -#[expect(clippy::too_many_lines)] fn check_fn_args<'cx, 'tcx: 'cx>( cx: &'cx LateContext<'tcx>, fn_sig: ty::FnSig<'tcx>, @@ -413,13 +412,13 @@ fn check_fn_args<'cx, 'tcx: 'cx>( Some(sym::Vec) => ( [(sym::clone, ".to_owned()")].as_slice(), DerefTy::Slice( - name.args.and_then(|args| args.args.first()).and_then(|arg| { - if let GenericArg::Type(ty) = arg { - Some(ty.span) - } else { - None - } - }), + if let Some(name_args) = name.args + && let [GenericArg::Type(ty), ..] = name_args.args + { + Some(ty.span) + } else { + None + }, args.type_at(0), ), ), @@ -432,33 +431,29 @@ fn check_fn_args<'cx, 'tcx: 'cx>( DerefTy::Path, ), Some(sym::Cow) if mutability == Mutability::Not => { - if let Some((lifetime, ty)) = name.args.and_then(|args| { - if let [GenericArg::Lifetime(lifetime), ty] = args.args { - return Some((lifetime, ty)); - } - None - }) { + if let Some(name_args) = name.args + && let [GenericArg::Lifetime(lifetime), ty] = name_args.args + { if let LifetimeKind::Param(param_def_id) = lifetime.kind && !lifetime.is_anonymous() && fn_sig .output() .walk() - .filter_map(|arg| { - arg.as_region().and_then(|lifetime| match lifetime.kind() { - ty::ReEarlyParam(r) => Some( - cx.tcx - .generics_of(cx.tcx.parent(param_def_id.to_def_id())) - .region_param(r, cx.tcx) - .def_id, - ), - ty::ReBound(_, r) => r.kind.get_id(), - ty::ReLateParam(r) => r.kind.get_id(), - ty::ReStatic - | ty::ReVar(_) - | ty::RePlaceholder(_) - | ty::ReErased - | ty::ReError(_) => None, - }) + .filter_map(ty::GenericArg::as_region) + .filter_map(|lifetime| match lifetime.kind() { + ty::ReEarlyParam(r) => Some( + cx.tcx + .generics_of(cx.tcx.parent(param_def_id.to_def_id())) + .region_param(r, cx.tcx) + .def_id, + ), + ty::ReBound(_, r) => r.kind.get_id(), + ty::ReLateParam(r) => r.kind.get_id(), + ty::ReStatic + | ty::ReVar(_) + | ty::RePlaceholder(_) + | ty::ReErased + | ty::ReError(_) => None, }) .any(|def_id| def_id.as_local().is_some_and(|def_id| def_id == param_def_id)) { @@ -627,12 +622,16 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &Body<'tcx>, args: &[ } } + // If the expression's type gets adjusted down to the deref type, we might as + // well have started with that deref type -- the lint should fire let deref_ty = args.deref_ty.ty(self.cx); let adjusted_ty = self.cx.typeck_results().expr_ty_adjusted(e).peel_refs(); if adjusted_ty == deref_ty { return; } + // If the expression's type is constrained by `dyn Trait`, see if the deref + // type implements the trait(s) as well, and if so, the lint should fire if let ty::Dynamic(preds, ..) = adjusted_ty.kind() && matches_preds(self.cx, deref_ty, preds) { diff --git a/src/tools/clippy/clippy_lints/src/raw_strings.rs b/src/tools/clippy/clippy_lints/src/raw_strings.rs index 6a79cae32a5..943e662479e 100644 --- a/src/tools/clippy/clippy_lints/src/raw_strings.rs +++ b/src/tools/clippy/clippy_lints/src/raw_strings.rs @@ -103,15 +103,7 @@ impl EarlyLintPass for RawStrings { } impl RawStrings { - fn check_raw_string( - &mut self, - cx: &EarlyContext<'_>, - str: &str, - lit_span: Span, - prefix: &str, - max: u8, - descr: &str, - ) { + fn check_raw_string(&self, cx: &EarlyContext<'_>, str: &str, lit_span: Span, prefix: &str, max: u8, descr: &str) { if !str.contains(['\\', '"']) { span_lint_and_then( cx, diff --git a/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs b/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs index 902e8af7ec4..0c1c664f111 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs @@ -88,8 +88,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantPubCrate { // We ignore macro exports. And `ListStem` uses, which aren't interesting. fn is_ignorable_export<'tcx>(item: &'tcx Item<'tcx>) -> bool { if let ItemKind::Use(path, kind) = item.kind { - let ignore = matches!(path.res.macro_ns, Some(Res::Def(DefKind::Macro(_), _))) - || kind == UseKind::ListStem; + let ignore = matches!(path.res.macro_ns, Some(Res::Def(DefKind::Macro(_), _))) || kind == UseKind::ListStem; if ignore { return true; } diff --git a/src/tools/clippy/clippy_lints/src/reference.rs b/src/tools/clippy/clippy_lints/src/reference.rs index 4bff37216ed..3bbcad12a31 100644 --- a/src/tools/clippy/clippy_lints/src/reference.rs +++ b/src/tools/clippy/clippy_lints/src/reference.rs @@ -1,10 +1,11 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::source::{SpanRangeExt, snippet_with_applicability}; -use rustc_ast::ast::{Expr, ExprKind, Mutability, UnOp}; +use clippy_utils::source::snippet; +use clippy_utils::sugg::{Sugg, has_enclosing_paren}; +use clippy_utils::ty::adjust_derefs_manually_drop; use rustc_errors::Applicability; -use rustc_lint::{EarlyContext, EarlyLintPass}; +use rustc_hir::{Expr, ExprKind, HirId, Node, UnOp}; +use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::{BytePos, Span}; declare_clippy_lint! { /// ### What it does @@ -37,17 +38,12 @@ declare_clippy_lint! { declare_lint_pass!(DerefAddrOf => [DEREF_ADDROF]); -fn without_parens(mut e: &Expr) -> &Expr { - while let ExprKind::Paren(ref child_e) = e.kind { - e = child_e; - } - e -} - -impl EarlyLintPass for DerefAddrOf { - fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &Expr) { - if let ExprKind::Unary(UnOp::Deref, ref deref_target) = e.kind - && let ExprKind::AddrOf(_, ref mutability, ref addrof_target) = without_parens(deref_target).kind +impl LateLintPass<'_> for DerefAddrOf { + fn check_expr(&mut self, cx: &LateContext<'_>, e: &Expr<'_>) { + if !e.span.from_expansion() + && let ExprKind::Unary(UnOp::Deref, deref_target) = e.kind + && !deref_target.span.from_expansion() + && let ExprKind::AddrOf(_, _, addrof_target) = deref_target.kind // NOTE(tesuji): `*&` forces rustc to const-promote the array to `.rodata` section. // See #12854 for details. && !matches!(addrof_target.kind, ExprKind::Array(_)) @@ -55,57 +51,82 @@ impl EarlyLintPass for DerefAddrOf { && !addrof_target.span.from_expansion() { let mut applicability = Applicability::MachineApplicable; - let sugg = if e.span.from_expansion() { - if let Some(macro_source) = e.span.get_source_text(cx) { - // Remove leading whitespace from the given span - // e.g: ` $visitor` turns into `$visitor` - let trim_leading_whitespaces = |span: Span| { - span.get_source_text(cx) - .and_then(|snip| { - #[expect(clippy::cast_possible_truncation)] - snip.find(|c: char| !c.is_whitespace()) - .map(|pos| span.lo() + BytePos(pos as u32)) - }) - .map_or(span, |start_no_whitespace| e.span.with_lo(start_no_whitespace)) - }; + let mut sugg = || Sugg::hir_with_applicability(cx, addrof_target, "_", &mut applicability); - let mut generate_snippet = |pattern: &str| { - #[expect(clippy::cast_possible_truncation)] - macro_source.rfind(pattern).map(|pattern_pos| { - let rpos = pattern_pos + pattern.len(); - let span_after_ref = e.span.with_lo(BytePos(e.span.lo().0 + rpos as u32)); - let span = trim_leading_whitespaces(span_after_ref); - snippet_with_applicability(cx, span, "_", &mut applicability) - }) - }; + // If this expression is an explicit `DerefMut` of a `ManuallyDrop` reached through a + // union, we may remove the reference if we are at the point where the implicit + // dereference would take place. Otherwise, we should not lint. + let sugg = match is_manually_drop_through_union(cx, e.hir_id, addrof_target) { + ManuallyDropThroughUnion::Directly => sugg().deref(), + ManuallyDropThroughUnion::Indirect => return, + ManuallyDropThroughUnion::No => sugg(), + }; + + let sugg = if has_enclosing_paren(snippet(cx, e.span, "")) { + sugg.maybe_paren() + } else { + sugg + }; + + span_lint_and_sugg( + cx, + DEREF_ADDROF, + e.span, + "immediately dereferencing a reference", + "try", + sugg.to_string(), + applicability, + ); + } + } +} + +/// Is this a `ManuallyDrop` reached through a union, and when is `DerefMut` called on it? +enum ManuallyDropThroughUnion { + /// `ManuallyDrop` reached through a union and immediately explicitely dereferenced + Directly, + /// `ManuallyDrop` reached through a union, and dereferenced later on + Indirect, + /// Any other situation + No, +} - if *mutability == Mutability::Mut { - generate_snippet("mut") +/// Check if `addrof_target` is part of an access to a `ManuallyDrop` entity reached through a +/// union, and when it is dereferenced using `DerefMut` starting from `expr_id` and going up. +fn is_manually_drop_through_union( + cx: &LateContext<'_>, + expr_id: HirId, + addrof_target: &Expr<'_>, +) -> ManuallyDropThroughUnion { + if is_reached_through_union(cx, addrof_target) { + let typeck = cx.typeck_results(); + for (idx, id) in std::iter::once(expr_id) + .chain(cx.tcx.hir_parent_id_iter(expr_id)) + .enumerate() + { + if let Node::Expr(expr) = cx.tcx.hir_node(id) { + if adjust_derefs_manually_drop(typeck.expr_adjustments(expr), typeck.expr_ty(expr)) { + return if idx == 0 { + ManuallyDropThroughUnion::Directly } else { - generate_snippet("&") - } - } else { - Some(snippet_with_applicability(cx, e.span, "_", &mut applicability)) + ManuallyDropThroughUnion::Indirect + }; } } else { - Some(snippet_with_applicability( - cx, - addrof_target.span, - "_", - &mut applicability, - )) - }; - if let Some(sugg) = sugg { - span_lint_and_sugg( - cx, - DEREF_ADDROF, - e.span, - "immediately dereferencing a reference", - "try", - sugg.to_string(), - applicability, - ); + break; } } } + ManuallyDropThroughUnion::No +} + +/// Checks whether `expr` denotes an object reached through a union +fn is_reached_through_union(cx: &LateContext<'_>, mut expr: &Expr<'_>) -> bool { + while let ExprKind::Field(parent, _) | ExprKind::Index(parent, _, _) = expr.kind { + if cx.typeck_results().expr_ty_adjusted(parent).is_union() { + return true; + } + expr = parent; + } + false } diff --git a/src/tools/clippy/clippy_lints/src/swap.rs b/src/tools/clippy/clippy_lints/src/swap.rs index 5ecbb56925e..76ab3cdae22 100644 --- a/src/tools/clippy/clippy_lints/src/swap.rs +++ b/src/tools/clippy/clippy_lints/src/swap.rs @@ -380,7 +380,7 @@ impl<'tcx> IndexBinding<'_, 'tcx> { } } - fn is_used_other_than_swapping(&mut self, idx_ident: Ident) -> bool { + fn is_used_other_than_swapping(&self, idx_ident: Ident) -> bool { if Self::is_used_slice_indexed(self.swap1_idx, idx_ident) || Self::is_used_slice_indexed(self.swap2_idx, idx_ident) { @@ -389,7 +389,7 @@ impl<'tcx> IndexBinding<'_, 'tcx> { self.is_used_after_swap(idx_ident) } - fn is_used_after_swap(&mut self, idx_ident: Ident) -> bool { + fn is_used_after_swap(&self, idx_ident: Ident) -> bool { let mut v = IndexBindingVisitor { idx: idx_ident, suggest_span: self.suggest_span, diff --git a/src/tools/clippy/clippy_lints/src/transmute/eager_transmute.rs b/src/tools/clippy/clippy_lints/src/transmute/eager_transmute.rs index 535c044f49e..97e68b3df94 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/eager_transmute.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/eager_transmute.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::{eq_expr_value, path_to_local, sym}; +use clippy_utils::{eq_expr_value, path_to_local_with_projections, sym}; use rustc_abi::WrappingRange; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, Node}; @@ -63,11 +63,7 @@ fn binops_with_local(cx: &LateContext<'_>, local_expr: &Expr<'_>, expr: &Expr<'_ /// Checks if an expression is a path to a local variable (with optional projections), e.g. /// `x.field[0].field2` would return true. fn is_local_with_projections(expr: &Expr<'_>) -> bool { - match expr.kind { - ExprKind::Path(_) => path_to_local(expr).is_some(), - ExprKind::Field(expr, _) | ExprKind::Index(expr, ..) => is_local_with_projections(expr), - _ => false, - } + path_to_local_with_projections(expr).is_some() } pub(super) fn check<'tcx>( diff --git a/src/tools/clippy/clippy_lints/src/transmute/mod.rs b/src/tools/clippy/clippy_lints/src/transmute/mod.rs index d5112e2c3f9..1c7bb4314dd 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/mod.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/mod.rs @@ -105,7 +105,7 @@ declare_clippy_lint! { /// ``` #[clippy::version = "pre 1.29.0"] pub CROSSPOINTER_TRANSMUTE, - complexity, + suspicious, "transmutes that have to or from types that are a pointer to the other" } diff --git a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs index 1c52de52619..ba0d4de5f3b 100644 --- a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs +++ b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs @@ -202,79 +202,41 @@ impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks { }; let item_has_safety_comment = item_has_safety_comment(cx, item); - match (&item.kind, item_has_safety_comment) { - // lint unsafe impl without safety comment - (ItemKind::Impl(Impl { of_trait: Some(of_trait), .. }), HasSafetyComment::No) if of_trait.safety.is_unsafe() => { - if !is_lint_allowed(cx, UNDOCUMENTED_UNSAFE_BLOCKS, item.hir_id()) - && !is_unsafe_from_proc_macro(cx, item.span) - { - let source_map = cx.tcx.sess.source_map(); - let span = if source_map.is_multiline(item.span) { - source_map.span_until_char(item.span, '\n') - } else { - item.span - }; - - #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")] - span_lint_and_then( - cx, - UNDOCUMENTED_UNSAFE_BLOCKS, - span, - "unsafe impl missing a safety comment", - |diag| { - diag.help("consider adding a safety comment on the preceding line"); - }, - ); - } - }, - // lint safe impl with unnecessary safety comment - (ItemKind::Impl(Impl { of_trait: Some(of_trait), .. }), HasSafetyComment::Yes(pos)) if of_trait.safety.is_safe() => { - if !is_lint_allowed(cx, UNNECESSARY_SAFETY_COMMENT, item.hir_id()) { - let (span, help_span) = mk_spans(pos); - - span_lint_and_then( - cx, - UNNECESSARY_SAFETY_COMMENT, - span, - "impl has unnecessary safety comment", - |diag| { - diag.span_help(help_span, "consider removing the safety comment"); - }, - ); - } - }, - (ItemKind::Impl(_), _) => {}, - // const and static items only need a safety comment if their body is an unsafe block, lint otherwise - (&ItemKind::Const(.., body) | &ItemKind::Static(.., body), HasSafetyComment::Yes(pos)) => { - if !is_lint_allowed(cx, UNNECESSARY_SAFETY_COMMENT, body.hir_id) { - let body = cx.tcx.hir_body(body); - if !matches!( - body.value.kind, hir::ExprKind::Block(block, _) - if block.rules == BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided) - ) { - let (span, help_span) = mk_spans(pos); - - span_lint_and_then( - cx, - UNNECESSARY_SAFETY_COMMENT, - span, - format!( - "{} has unnecessary safety comment", - cx.tcx.def_descr(item.owner_id.to_def_id()), - ), - |diag| { - diag.span_help(help_span, "consider removing the safety comment"); - }, - ); - } - } - }, - // Aside from unsafe impls and consts/statics with an unsafe block, items in general - // do not have safety invariants that need to be documented, so lint those. - (_, HasSafetyComment::Yes(pos)) => { - if !is_lint_allowed(cx, UNNECESSARY_SAFETY_COMMENT, item.hir_id()) { - let (span, help_span) = mk_spans(pos); + match item_has_safety_comment { + HasSafetyComment::Yes(pos) => check_has_safety_comment(cx, item, mk_spans(pos)), + HasSafetyComment::No => check_has_no_safety_comment(cx, item), + HasSafetyComment::Maybe => {}, + } + } +} +fn check_has_safety_comment(cx: &LateContext<'_>, item: &hir::Item<'_>, (span, help_span): (Span, Span)) { + match &item.kind { + ItemKind::Impl(Impl { + of_trait: Some(of_trait), + .. + }) if of_trait.safety.is_safe() => { + if !is_lint_allowed(cx, UNNECESSARY_SAFETY_COMMENT, item.hir_id()) { + span_lint_and_then( + cx, + UNNECESSARY_SAFETY_COMMENT, + span, + "impl has unnecessary safety comment", + |diag| { + diag.span_help(help_span, "consider removing the safety comment"); + }, + ); + } + }, + ItemKind::Impl(_) => {}, + // const and static items only need a safety comment if their body is an unsafe block, lint otherwise + &ItemKind::Const(.., body) | &ItemKind::Static(.., body) => { + if !is_lint_allowed(cx, UNNECESSARY_SAFETY_COMMENT, body.hir_id) { + let body = cx.tcx.hir_body(body); + if !matches!( + body.value.kind, hir::ExprKind::Block(block, _) + if block.rules == BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided) + ) { span_lint_and_then( cx, UNNECESSARY_SAFETY_COMMENT, @@ -288,12 +250,56 @@ impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks { }, ); } - }, - _ => (), - } + } + }, + // Aside from unsafe impls and consts/statics with an unsafe block, items in general + // do not have safety invariants that need to be documented, so lint those. + _ => { + if !is_lint_allowed(cx, UNNECESSARY_SAFETY_COMMENT, item.hir_id()) { + span_lint_and_then( + cx, + UNNECESSARY_SAFETY_COMMENT, + span, + format!( + "{} has unnecessary safety comment", + cx.tcx.def_descr(item.owner_id.to_def_id()), + ), + |diag| { + diag.span_help(help_span, "consider removing the safety comment"); + }, + ); + } + }, } } +fn check_has_no_safety_comment(cx: &LateContext<'_>, item: &hir::Item<'_>) { + if let ItemKind::Impl(Impl { + of_trait: Some(of_trait), + .. + }) = item.kind + && of_trait.safety.is_unsafe() + && !is_lint_allowed(cx, UNDOCUMENTED_UNSAFE_BLOCKS, item.hir_id()) + && !is_unsafe_from_proc_macro(cx, item.span) + { + let source_map = cx.tcx.sess.source_map(); + let span = if source_map.is_multiline(item.span) { + source_map.span_until_char(item.span, '\n') + } else { + item.span + }; + #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")] + span_lint_and_then( + cx, + UNDOCUMENTED_UNSAFE_BLOCKS, + span, + "unsafe impl missing a safety comment", + |diag| { + diag.help("consider adding a safety comment on the preceding line"); + }, + ); + } +} fn expr_has_unnecessary_safety_comment<'tcx>( cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>, @@ -505,7 +511,8 @@ fn item_has_safety_comment(cx: &LateContext<'_>, item: &hir::Item<'_>) -> HasSaf }, Node::Stmt(stmt) => { if let Node::Block(block) = cx.tcx.parent_hir_node(stmt.hir_id) { - walk_span_to_context(block.span, SyntaxContext::root()).map(Span::lo) + walk_span_to_context(block.span, SyntaxContext::root()) + .map(|sp| CommentStartBeforeItem::Offset(sp.lo())) } else { // Problem getting the parent node. Pretend a comment was found. return HasSafetyComment::Maybe; @@ -518,10 +525,12 @@ fn item_has_safety_comment(cx: &LateContext<'_>, item: &hir::Item<'_>) -> HasSaf }; let source_map = cx.sess().source_map(); + // If the comment is in the first line of the file, there is no preceding line if let Some(comment_start) = comment_start && let Ok(unsafe_line) = source_map.lookup_line(item.span.lo()) - && let Ok(comment_start_line) = source_map.lookup_line(comment_start) - && Arc::ptr_eq(&unsafe_line.sf, &comment_start_line.sf) + && let Ok(comment_start_line) = source_map.lookup_line(comment_start.into()) + && let include_first_line_of_file = matches!(comment_start, CommentStartBeforeItem::Start) + && (include_first_line_of_file || Arc::ptr_eq(&unsafe_line.sf, &comment_start_line.sf)) && let Some(src) = unsafe_line.sf.src.as_deref() { return if comment_start_line.line >= unsafe_line.line { @@ -529,7 +538,8 @@ fn item_has_safety_comment(cx: &LateContext<'_>, item: &hir::Item<'_>) -> HasSaf } else { match text_has_safety_comment( src, - &unsafe_line.sf.lines()[comment_start_line.line + 1..=unsafe_line.line], + &unsafe_line.sf.lines() + [(comment_start_line.line + usize::from(!include_first_line_of_file))..=unsafe_line.line], unsafe_line.sf.start_pos, ) { Some(b) => HasSafetyComment::Yes(b), @@ -592,12 +602,27 @@ fn stmt_has_safety_comment( HasSafetyComment::Maybe } +#[derive(Clone, Copy, Debug)] +enum CommentStartBeforeItem { + Offset(BytePos), + Start, +} + +impl From<CommentStartBeforeItem> for BytePos { + fn from(value: CommentStartBeforeItem) -> Self { + match value { + CommentStartBeforeItem::Offset(loc) => loc, + CommentStartBeforeItem::Start => BytePos(0), + } + } +} + fn comment_start_before_item_in_mod( cx: &LateContext<'_>, parent_mod: &hir::Mod<'_>, parent_mod_span: Span, item: &hir::Item<'_>, -) -> Option<BytePos> { +) -> Option<CommentStartBeforeItem> { parent_mod.item_ids.iter().enumerate().find_map(|(idx, item_id)| { if *item_id == item.item_id() { if idx == 0 { @@ -605,15 +630,18 @@ fn comment_start_before_item_in_mod( // ^------------------------------------------^ returns the start of this span // ^---------------------^ finally checks comments in this range if let Some(sp) = walk_span_to_context(parent_mod_span, SyntaxContext::root()) { - return Some(sp.lo()); + return Some(CommentStartBeforeItem::Offset(sp.lo())); } } else { // some_item /* comment */ unsafe impl T {} // ^-------^ returns the end of this span // ^---------------^ finally checks comments in this range let prev_item = cx.tcx.hir_item(parent_mod.item_ids[idx - 1]); + if prev_item.span.is_dummy() { + return Some(CommentStartBeforeItem::Start); + } if let Some(sp) = walk_span_to_context(prev_item.span, SyntaxContext::root()) { - return Some(sp.hi()); + return Some(CommentStartBeforeItem::Offset(sp.hi())); } } } @@ -668,7 +696,7 @@ fn get_body_search_span(cx: &LateContext<'_>) -> Option<Span> { }) => { return maybe_mod_item .and_then(|item| comment_start_before_item_in_mod(cx, mod_, *span, &item)) - .map(|comment_start| mod_.spans.inner_span.with_lo(comment_start)) + .map(|comment_start| mod_.spans.inner_span.with_lo(comment_start.into())) .or(Some(*span)); }, node if let Some((span, _)) = span_and_hid_of_item_alike_node(&node) diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs b/src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs index 2b7d3dc0c90..6e3e41f08ee 100644 --- a/src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs +++ b/src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs @@ -55,7 +55,7 @@ impl UnnecessaryBoxReturns { } } - fn check_fn_item(&mut self, cx: &LateContext<'_>, decl: &FnDecl<'_>, def_id: LocalDefId, name: Symbol) { + fn check_fn_item(&self, cx: &LateContext<'_>, decl: &FnDecl<'_>, def_id: LocalDefId, name: Symbol) { // we don't want to tell someone to break an exported function if they ask us not to if self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(def_id) { return; diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_semicolon.rs b/src/tools/clippy/clippy_lints/src/unnecessary_semicolon.rs index f1d1a76d0c2..76e24b6bf80 100644 --- a/src/tools/clippy/clippy_lints/src/unnecessary_semicolon.rs +++ b/src/tools/clippy/clippy_lints/src/unnecessary_semicolon.rs @@ -86,7 +86,9 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessarySemicolon { expr.kind, ExprKind::If(..) | ExprKind::Match(_, _, MatchSource::Normal | MatchSource::Postfix) ) - && cx.typeck_results().expr_ty(expr) == cx.tcx.types.unit + && cx.typeck_results().expr_ty(expr).is_unit() + // if a stmt has attrs, then turning it into an expr will break the code, since attrs aren't allowed on exprs + && cx.tcx.hir_attrs(stmt.hir_id).is_empty() { if let Some(block_is_unit) = self.is_last_in_block(stmt) { if cx.tcx.sess.edition() <= Edition2021 && leaks_droppable_temporary_with_limited_lifetime(cx, expr) { diff --git a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs index e9ad578da2f..8b278d98a30 100644 --- a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs +++ b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs @@ -284,14 +284,14 @@ fn transform_with_focus_on_idx(alternatives: &mut ThinVec<Box<Pat>>, focus_idx: |k, ps1, idx| matches!( k, TupleStruct(qself2, path2, ps2) - if eq_maybe_qself(qself1.as_ref(), qself2.as_ref()) + if eq_maybe_qself(qself1.as_deref(), qself2.as_deref()) && eq_path(path1, path2) && eq_pre_post(ps1, ps2, idx) ), |k| always_pat!(k, TupleStruct(_, _, ps) => ps), ), // Transform a record pattern `S { fp_0, ..., fp_n }`. Struct(qself1, path1, fps1, rest1) => { - extend_with_struct_pat(qself1.as_ref(), path1, fps1, *rest1, start, alternatives) + extend_with_struct_pat(qself1.as_deref(), path1, fps1, *rest1, start, alternatives) }, }; @@ -304,7 +304,7 @@ fn transform_with_focus_on_idx(alternatives: &mut ThinVec<Box<Pat>>, focus_idx: /// So when we fixate on some `ident_k: pat_k`, we try to find `ident_k` in the other pattern /// and check that all `fp_i` where `i ∈ ((0...n) \ k)` between two patterns are equal. fn extend_with_struct_pat( - qself1: Option<&Box<ast::QSelf>>, + qself1: Option<&ast::QSelf>, path1: &ast::Path, fps1: &mut [ast::PatField], rest1: ast::PatFieldsRest, @@ -319,7 +319,7 @@ fn extend_with_struct_pat( |k| { matches!(k, Struct(qself2, path2, fps2, rest2) if rest1 == *rest2 // If one struct pattern has `..` so must the other. - && eq_maybe_qself(qself1, qself2.as_ref()) + && eq_maybe_qself(qself1, qself2.as_deref()) && eq_path(path1, path2) && fps1.len() == fps2.len() && fps1.iter().enumerate().all(|(idx_1, fp1)| { diff --git a/src/tools/clippy/clippy_lints/src/unwrap.rs b/src/tools/clippy/clippy_lints/src/unwrap.rs index c641d4e55b9..490da4f1e03 100644 --- a/src/tools/clippy/clippy_lints/src/unwrap.rs +++ b/src/tools/clippy/clippy_lints/src/unwrap.rs @@ -141,43 +141,45 @@ fn collect_unwrap_info<'tcx>( is_type_diagnostic_item(cx, ty, sym::Result) && matches!(method_name, sym::is_err | sym::is_ok) } - if let ExprKind::Binary(op, left, right) = &expr.kind { - match (invert, op.node) { - (false, BinOpKind::And | BinOpKind::BitAnd) | (true, BinOpKind::Or | BinOpKind::BitOr) => { - let mut unwrap_info = collect_unwrap_info(cx, if_expr, left, branch, invert, false); - unwrap_info.append(&mut collect_unwrap_info(cx, if_expr, right, branch, invert, false)); - return unwrap_info; - }, - _ => (), - } - } else if let ExprKind::Unary(UnOp::Not, expr) = &expr.kind { - return collect_unwrap_info(cx, if_expr, expr, branch, !invert, false); - } else if let ExprKind::MethodCall(method_name, receiver, [], _) = &expr.kind - && let Some(local_id) = path_to_local(receiver) - && let ty = cx.typeck_results().expr_ty(receiver) - && let name = method_name.ident.name - && (is_relevant_option_call(cx, ty, name) || is_relevant_result_call(cx, ty, name)) - { - let unwrappable = matches!(name, sym::is_some | sym::is_ok); - let safe_to_unwrap = unwrappable != invert; - let kind = if is_type_diagnostic_item(cx, ty, sym::Option) { - UnwrappableKind::Option - } else { - UnwrappableKind::Result - }; + match expr.kind { + ExprKind::Binary(op, left, right) + if matches!( + (invert, op.node), + (false, BinOpKind::And | BinOpKind::BitAnd) | (true, BinOpKind::Or | BinOpKind::BitOr) + ) => + { + let mut unwrap_info = collect_unwrap_info(cx, if_expr, left, branch, invert, false); + unwrap_info.extend(collect_unwrap_info(cx, if_expr, right, branch, invert, false)); + unwrap_info + }, + ExprKind::Unary(UnOp::Not, expr) => collect_unwrap_info(cx, if_expr, expr, branch, !invert, false), + ExprKind::MethodCall(method_name, receiver, [], _) + if let Some(local_id) = path_to_local(receiver) + && let ty = cx.typeck_results().expr_ty(receiver) + && let name = method_name.ident.name + && (is_relevant_option_call(cx, ty, name) || is_relevant_result_call(cx, ty, name)) => + { + let unwrappable = matches!(name, sym::is_some | sym::is_ok); + let safe_to_unwrap = unwrappable != invert; + let kind = if is_type_diagnostic_item(cx, ty, sym::Option) { + UnwrappableKind::Option + } else { + UnwrappableKind::Result + }; - return vec![UnwrapInfo { - local_id, - if_expr, - check: expr, - check_name: name, - branch, - safe_to_unwrap, - kind, - is_entire_condition, - }]; + vec![UnwrapInfo { + local_id, + if_expr, + check: expr, + check_name: name, + branch, + safe_to_unwrap, + kind, + is_entire_condition, + }] + }, + _ => vec![], } - Vec::new() } /// A HIR visitor delegate that checks if a local variable of type `Option` or `Result` is mutated, diff --git a/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs b/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs index 1550872bca2..f1572fd65bb 100644 --- a/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs +++ b/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs @@ -56,6 +56,9 @@ impl LateLintPass<'_> for ZeroSizedMapValues { // cannot check if it is `Sized` or not, such as an incomplete associated type in a // type alias. See an example in `issue14822()` of `tests/ui/zero_sized_hashmap_values.rs`. && !ty.has_non_region_param() + // Ensure that no region escapes to avoid an assertion error when computing the layout. + // See an example in `issue15429()` of `tests/ui/zero_sized_hashmap_values.rs`. + && !ty.has_escaping_bound_vars() && let Ok(layout) = cx.layout_of(ty) && layout.is_zst() { diff --git a/src/tools/clippy/clippy_lints_internal/src/derive_deserialize_allowing_unknown.rs b/src/tools/clippy/clippy_lints_internal/src/derive_deserialize_allowing_unknown.rs index 5e6a40ac2eb..0fd1e11b033 100644 --- a/src/tools/clippy/clippy_lints_internal/src/derive_deserialize_allowing_unknown.rs +++ b/src/tools/clippy/clippy_lints_internal/src/derive_deserialize_allowing_unknown.rs @@ -6,7 +6,8 @@ use rustc_hir::attrs::AttributeKind; use rustc_hir::def::Res; use rustc_hir::def_id::LocalDefId; use rustc_hir::{ - AttrArgs, AttrItem, AttrPath, Attribute, HirId, Impl, Item, ItemKind, Path, QPath, TraitRef, Ty, TyKind, find_attr, + AttrArgs, AttrItem, AttrPath, Attribute, HirId, Impl, Item, ItemKind, Path, QPath, TraitImplHeader, TraitRef, Ty, + TyKind, find_attr, }; use rustc_lint::{LateContext, LateLintPass}; use rustc_lint_defs::declare_tool_lint; @@ -56,10 +57,14 @@ impl<'tcx> LateLintPass<'tcx> for DeriveDeserializeAllowingUnknown { // Is this an `impl` (of a certain form)? let ItemKind::Impl(Impl { of_trait: - Some(TraitRef { - path: - Path { - res: Res::Def(_, trait_def_id), + Some(TraitImplHeader { + trait_ref: + TraitRef { + path: + Path { + res: Res::Def(_, trait_def_id), + .. + }, .. }, .. diff --git a/src/tools/clippy/clippy_test_deps/Cargo.lock b/src/tools/clippy/clippy_test_deps/Cargo.lock index 2f987c0137c..b22cf9d107d 100644 --- a/src/tools/clippy/clippy_test_deps/Cargo.lock +++ b/src/tools/clippy/clippy_test_deps/Cargo.lock @@ -377,9 +377,9 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.10" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04dc19736151f35336d325007ac991178d504a119863a2fcb3758cdb5e52c50d" +checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" [[package]] name = "smallvec" diff --git a/src/tools/clippy/clippy_utils/README.md b/src/tools/clippy/clippy_utils/README.md index 6d8dd92d55d..2dfe28953d0 100644 --- a/src/tools/clippy/clippy_utils/README.md +++ b/src/tools/clippy/clippy_utils/README.md @@ -8,7 +8,7 @@ This crate is only guaranteed to build with this `nightly` toolchain: <!-- begin autogenerated nightly --> ``` -nightly-2025-08-07 +nightly-2025-08-22 ``` <!-- end autogenerated nightly --> diff --git a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs index d80a9d9dd07..40c00568a3b 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs @@ -41,21 +41,23 @@ pub fn eq_pat(l: &Pat, r: &Pat) -> bool { b1 == b2 && eq_id(*i1, *i2) && both(s1.as_deref(), s2.as_deref(), eq_pat) }, (Range(lf, lt, le), Range(rf, rt, re)) => { - eq_expr_opt(lf.as_ref(), rf.as_ref()) - && eq_expr_opt(lt.as_ref(), rt.as_ref()) + eq_expr_opt(lf.as_deref(), rf.as_deref()) + && eq_expr_opt(lt.as_deref(), rt.as_deref()) && eq_range_end(&le.node, &re.node) }, (Box(l), Box(r)) | (Ref(l, Mutability::Not), Ref(r, Mutability::Not)) | (Ref(l, Mutability::Mut), Ref(r, Mutability::Mut)) => eq_pat(l, r), (Tuple(l), Tuple(r)) | (Slice(l), Slice(r)) => over(l, r, |l, r| eq_pat(l, r)), - (Path(lq, lp), Path(rq, rp)) => both(lq.as_ref(), rq.as_ref(), eq_qself) && eq_path(lp, rp), + (Path(lq, lp), Path(rq, rp)) => both(lq.as_deref(), rq.as_deref(), eq_qself) && eq_path(lp, rp), (TupleStruct(lqself, lp, lfs), TupleStruct(rqself, rp, rfs)) => { - eq_maybe_qself(lqself.as_ref(), rqself.as_ref()) && eq_path(lp, rp) && over(lfs, rfs, |l, r| eq_pat(l, r)) + eq_maybe_qself(lqself.as_deref(), rqself.as_deref()) + && eq_path(lp, rp) + && over(lfs, rfs, |l, r| eq_pat(l, r)) }, (Struct(lqself, lp, lfs, lr), Struct(rqself, rp, rfs, rr)) => { lr == rr - && eq_maybe_qself(lqself.as_ref(), rqself.as_ref()) + && eq_maybe_qself(lqself.as_deref(), rqself.as_deref()) && eq_path(lp, rp) && unordered_over(lfs, rfs, eq_field_pat) }, @@ -82,11 +84,11 @@ pub fn eq_field_pat(l: &PatField, r: &PatField) -> bool { && over(&l.attrs, &r.attrs, eq_attr) } -pub fn eq_qself(l: &Box<QSelf>, r: &Box<QSelf>) -> bool { +pub fn eq_qself(l: &QSelf, r: &QSelf) -> bool { l.position == r.position && eq_ty(&l.ty, &r.ty) } -pub fn eq_maybe_qself(l: Option<&Box<QSelf>>, r: Option<&Box<QSelf>>) -> bool { +pub fn eq_maybe_qself(l: Option<&QSelf>, r: Option<&QSelf>) -> bool { match (l, r) { (Some(l), Some(r)) => eq_qself(l, r), (None, None) => true, @@ -129,8 +131,8 @@ pub fn eq_generic_arg(l: &GenericArg, r: &GenericArg) -> bool { } } -pub fn eq_expr_opt(l: Option<&Box<Expr>>, r: Option<&Box<Expr>>) -> bool { - both(l, r, |l, r| eq_expr(l, r)) +pub fn eq_expr_opt(l: Option<&Expr>, r: Option<&Expr>) -> bool { + both(l, r, eq_expr) } pub fn eq_struct_rest(l: &StructRest, r: &StructRest) -> bool { @@ -177,7 +179,7 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool { (Cast(l, lt), Cast(r, rt)) | (Type(l, lt), Type(r, rt)) => eq_expr(l, r) && eq_ty(lt, rt), (Let(lp, le, _, _), Let(rp, re, _, _)) => eq_pat(lp, rp) && eq_expr(le, re), (If(lc, lt, le), If(rc, rt, re)) => { - eq_expr(lc, rc) && eq_block(lt, rt) && eq_expr_opt(le.as_ref(), re.as_ref()) + eq_expr(lc, rc) && eq_block(lt, rt) && eq_expr_opt(le.as_deref(), re.as_deref()) }, (While(lc, lt, ll), While(rc, rt, rl)) => { eq_label(ll.as_ref(), rl.as_ref()) && eq_expr(lc, rc) && eq_block(lt, rt) @@ -201,9 +203,11 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool { (Loop(lt, ll, _), Loop(rt, rl, _)) => eq_label(ll.as_ref(), rl.as_ref()) && eq_block(lt, rt), (Block(lb, ll), Block(rb, rl)) => eq_label(ll.as_ref(), rl.as_ref()) && eq_block(lb, rb), (TryBlock(l), TryBlock(r)) => eq_block(l, r), - (Yield(l), Yield(r)) => eq_expr_opt(l.expr(), r.expr()) && l.same_kind(r), - (Ret(l), Ret(r)) => eq_expr_opt(l.as_ref(), r.as_ref()), - (Break(ll, le), Break(rl, re)) => eq_label(ll.as_ref(), rl.as_ref()) && eq_expr_opt(le.as_ref(), re.as_ref()), + (Yield(l), Yield(r)) => eq_expr_opt(l.expr().map(Box::as_ref), r.expr().map(Box::as_ref)) && l.same_kind(r), + (Ret(l), Ret(r)) => eq_expr_opt(l.as_deref(), r.as_deref()), + (Break(ll, le), Break(rl, re)) => { + eq_label(ll.as_ref(), rl.as_ref()) && eq_expr_opt(le.as_deref(), re.as_deref()) + }, (Continue(ll), Continue(rl)) => eq_label(ll.as_ref(), rl.as_ref()), (Assign(l1, l2, _), Assign(r1, r2, _)) | (Index(l1, l2, _), Index(r1, r2, _)) => { eq_expr(l1, r1) && eq_expr(l2, r2) @@ -240,13 +244,13 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool { }, (Gen(lc, lb, lk, _), Gen(rc, rb, rk, _)) => lc == rc && eq_block(lb, rb) && lk == rk, (Range(lf, lt, ll), Range(rf, rt, rl)) => { - ll == rl && eq_expr_opt(lf.as_ref(), rf.as_ref()) && eq_expr_opt(lt.as_ref(), rt.as_ref()) + ll == rl && eq_expr_opt(lf.as_deref(), rf.as_deref()) && eq_expr_opt(lt.as_deref(), rt.as_deref()) }, (AddrOf(lbk, lm, le), AddrOf(rbk, rm, re)) => lbk == rbk && lm == rm && eq_expr(le, re), - (Path(lq, lp), Path(rq, rp)) => both(lq.as_ref(), rq.as_ref(), eq_qself) && eq_path(lp, rp), + (Path(lq, lp), Path(rq, rp)) => both(lq.as_deref(), rq.as_deref(), eq_qself) && eq_path(lp, rp), (MacCall(l), MacCall(r)) => eq_mac_call(l, r), (Struct(lse), Struct(rse)) => { - eq_maybe_qself(lse.qself.as_ref(), rse.qself.as_ref()) + eq_maybe_qself(lse.qself.as_deref(), rse.qself.as_deref()) && eq_path(&lse.path, &rse.path) && eq_struct_rest(&lse.rest, &rse.rest) && unordered_over(&lse.fields, &rse.fields, eq_field) @@ -278,8 +282,8 @@ pub fn eq_field(l: &ExprField, r: &ExprField) -> bool { pub fn eq_arm(l: &Arm, r: &Arm) -> bool { l.is_placeholder == r.is_placeholder && eq_pat(&l.pat, &r.pat) - && eq_expr_opt(l.body.as_ref(), r.body.as_ref()) - && eq_expr_opt(l.guard.as_ref(), r.guard.as_ref()) + && eq_expr_opt(l.body.as_deref(), r.body.as_deref()) + && eq_expr_opt(l.guard.as_deref(), r.guard.as_deref()) && over(&l.attrs, &r.attrs, eq_attr) } @@ -324,7 +328,7 @@ pub fn eq_item<K>(l: &Item<K>, r: &Item<K>, mut eq_kind: impl FnMut(&K, &K) -> b over(&l.attrs, &r.attrs, eq_attr) && eq_vis(&l.vis, &r.vis) && eq_kind(&l.kind, &r.kind) } -#[expect(clippy::similar_names, clippy::too_many_lines)] // Just a big match statement +#[expect(clippy::too_many_lines)] // Just a big match statement pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { use ItemKind::*; match (l, r) { @@ -347,7 +351,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { safety: rs, define_opaque: _, }), - ) => eq_id(*li, *ri) && lm == rm && ls == rs && eq_ty(lt, rt) && eq_expr_opt(le.as_ref(), re.as_ref()), + ) => eq_id(*li, *ri) && lm == rm && ls == rs && eq_ty(lt, rt) && eq_expr_opt(le.as_deref(), re.as_deref()), ( Const(box ConstItem { defaultness: ld, @@ -370,7 +374,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool { && eq_id(*li, *ri) && eq_generics(lg, rg) && eq_ty(lt, rt) - && eq_expr_opt(le.as_ref(), re.as_ref()) + && eq_expr_opt(le.as_deref(), re.as_deref()) }, ( Fn(box ast::Fn { @@ -525,7 +529,7 @@ pub fn eq_foreign_item_kind(l: &ForeignItemKind, r: &ForeignItemKind) -> bool { safety: rs, define_opaque: _, }), - ) => eq_id(*li, *ri) && eq_ty(lt, rt) && lm == rm && eq_expr_opt(le.as_ref(), re.as_ref()) && ls == rs, + ) => eq_id(*li, *ri) && eq_ty(lt, rt) && lm == rm && eq_expr_opt(le.as_deref(), re.as_deref()) && ls == rs, ( Fn(box ast::Fn { defaultness: ld, @@ -607,7 +611,7 @@ pub fn eq_assoc_item_kind(l: &AssocItemKind, r: &AssocItemKind) -> bool { && eq_id(*li, *ri) && eq_generics(lg, rg) && eq_ty(lt, rt) - && eq_expr_opt(le.as_ref(), re.as_ref()) + && eq_expr_opt(le.as_deref(), re.as_deref()) }, ( Fn(box ast::Fn { @@ -723,7 +727,8 @@ pub fn eq_fn_header(l: &FnHeader, r: &FnHeader) -> bool { pub fn eq_opt_fn_contract(l: &Option<Box<FnContract>>, r: &Option<Box<FnContract>>) -> bool { match (l, r) { (Some(l), Some(r)) => { - eq_expr_opt(l.requires.as_ref(), r.requires.as_ref()) && eq_expr_opt(l.ensures.as_ref(), r.ensures.as_ref()) + eq_expr_opt(l.requires.as_deref(), r.requires.as_deref()) + && eq_expr_opt(l.ensures.as_deref(), r.ensures.as_deref()) }, (None, None) => true, (Some(_), None) | (None, Some(_)) => false, @@ -841,7 +846,7 @@ pub fn eq_ty(l: &Ty, r: &Ty) -> bool { && eq_fn_decl(&l.decl, &r.decl) }, (Tup(l), Tup(r)) => over(l, r, |l, r| eq_ty(l, r)), - (Path(lq, lp), Path(rq, rp)) => both(lq.as_ref(), rq.as_ref(), eq_qself) && eq_path(lp, rp), + (Path(lq, lp), Path(rq, rp)) => both(lq.as_deref(), rq.as_deref(), eq_qself) && eq_path(lp, rp), (TraitObject(lg, ls), TraitObject(rg, rs)) => ls == rs && over(lg, rg, eq_generic_bound), (ImplTrait(_, lg), ImplTrait(_, rg)) => over(lg, rg, eq_generic_bound), (Typeof(l), Typeof(r)) => eq_expr(&l.value, &r.value), diff --git a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs index e0c1b9d445a..c4a759e919b 100644 --- a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs +++ b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs @@ -19,8 +19,8 @@ use rustc_ast::token::CommentKind; use rustc_hir::intravisit::FnKind; use rustc_hir::{ Block, BlockCheckMode, Body, Closure, Destination, Expr, ExprKind, FieldDef, FnHeader, FnRetTy, HirId, Impl, - ImplItem, ImplItemKind, TraitImplHeader, IsAuto, Item, ItemKind, Lit, LoopSource, MatchSource, MutTy, Node, Path, - QPath, Safety, TraitItem, TraitItemKind, Ty, TyKind, UnOp, UnsafeSource, Variant, VariantData, YieldSource, + ImplItem, ImplItemKind, IsAuto, Item, ItemKind, Lit, LoopSource, MatchSource, MutTy, Node, Path, QPath, Safety, + TraitImplHeader, TraitItem, TraitItemKind, Ty, TyKind, UnOp, UnsafeSource, Variant, VariantData, YieldSource, }; use rustc_lint::{EarlyContext, LateContext, LintContext}; use rustc_middle::ty::TyCtxt; @@ -254,7 +254,10 @@ fn item_search_pat(item: &Item<'_>) -> (Pat, Pat) { ItemKind::Union(..) => (Pat::Str("union"), Pat::Str("}")), ItemKind::Trait(_, _, Safety::Unsafe, ..) | ItemKind::Impl(Impl { - of_trait: Some(TraitImplHeader { safety: Safety::Unsafe, .. }), .. + of_trait: Some(TraitImplHeader { + safety: Safety::Unsafe, .. + }), + .. }) => (Pat::Str("unsafe"), Pat::Str("}")), ItemKind::Trait(_, IsAuto::Yes, ..) => (Pat::Str("auto"), Pat::Str("}")), ItemKind::Trait(..) => (Pat::Str("trait"), Pat::Str("}")), diff --git a/src/tools/clippy/clippy_utils/src/diagnostics.rs b/src/tools/clippy/clippy_utils/src/diagnostics.rs index 625e1eead21..8a19039a7fe 100644 --- a/src/tools/clippy/clippy_utils/src/diagnostics.rs +++ b/src/tools/clippy/clippy_utils/src/diagnostics.rs @@ -22,13 +22,14 @@ fn docs_link(diag: &mut Diag<'_, ()>, lint: &'static Lint) { { diag.help(format!( "for further information visit https://rust-lang.github.io/rust-clippy/{}/index.html#{lint}", - &option_env!("RUST_RELEASE_NUM").map_or_else( - || "master".to_string(), - |n| { - // extract just major + minor version and ignore patch versions - format!("rust-{}", n.rsplit_once('.').unwrap().1) - } - ) + match option_env!("CFG_RELEASE_CHANNEL") { + // Clippy version is 0.1.xx + // + // Always use .0 because we do not generate separate lint doc pages for rust patch releases + Some("stable") => concat!("rust-1.", env!("CARGO_PKG_VERSION_PATCH"), ".0"), + Some("beta") => "beta", + _ => "master", + } )); } } diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index f0d7fb89c44..8160443f413 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -258,7 +258,7 @@ impl HirEqInterExpr<'_, '_, '_> { }) } - fn should_ignore(&mut self, expr: &Expr<'_>) -> bool { + fn should_ignore(&self, expr: &Expr<'_>) -> bool { macro_backtrace(expr.span).last().is_some_and(|macro_call| { matches!( self.inner.cx.tcx.get_diagnostic_name(macro_call.def_id), diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index fcc120656e3..8533fa85541 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -460,6 +460,23 @@ pub fn path_to_local_id(expr: &Expr<'_>, id: HirId) -> bool { path_to_local(expr) == Some(id) } +/// If the expression is a path to a local (with optional projections), +/// returns the canonical `HirId` of the local. +/// +/// For example, `x.field[0].field2` would return the `HirId` of `x`. +pub fn path_to_local_with_projections(expr: &Expr<'_>) -> Option<HirId> { + match expr.kind { + ExprKind::Field(recv, _) | ExprKind::Index(recv, _, _) => path_to_local_with_projections(recv), + ExprKind::Path(QPath::Resolved( + _, + Path { + res: Res::Local(local), .. + }, + )) => Some(*local), + _ => None, + } +} + pub trait MaybePath<'hir> { fn hir_id(&self) -> HirId; fn qpath_opt(&self) -> Option<&QPath<'hir>>; diff --git a/src/tools/clippy/clippy_utils/src/msrvs.rs b/src/tools/clippy/clippy_utils/src/msrvs.rs index 89a83e2c48f..896d607fbcd 100644 --- a/src/tools/clippy/clippy_utils/src/msrvs.rs +++ b/src/tools/clippy/clippy_utils/src/msrvs.rs @@ -189,25 +189,25 @@ impl MsrvStack { fn parse_attrs(sess: &Session, attrs: &[impl AttributeExt]) -> Option<RustcVersion> { let mut msrv_attrs = attrs.iter().filter(|attr| attr.path_matches(&[sym::clippy, sym::msrv])); - if let Some(msrv_attr) = msrv_attrs.next() { - if let Some(duplicate) = msrv_attrs.next_back() { - sess.dcx() - .struct_span_err(duplicate.span(), "`clippy::msrv` is defined multiple times") - .with_span_note(msrv_attr.span(), "first definition found here") - .emit(); - } - - if let Some(msrv) = msrv_attr.value_str() { - if let Some(version) = parse_version(msrv) { - return Some(version); - } + let msrv_attr = msrv_attrs.next()?; - sess.dcx() - .span_err(msrv_attr.span(), format!("`{msrv}` is not a valid Rust version")); - } else { - sess.dcx().span_err(msrv_attr.span(), "bad clippy attribute"); - } + if let Some(duplicate) = msrv_attrs.next_back() { + sess.dcx() + .struct_span_err(duplicate.span(), "`clippy::msrv` is defined multiple times") + .with_span_note(msrv_attr.span(), "first definition found here") + .emit(); } - None + let Some(msrv) = msrv_attr.value_str() else { + sess.dcx().span_err(msrv_attr.span(), "bad clippy attribute"); + return None; + }; + + let Some(version) = parse_version(msrv) else { + sess.dcx() + .span_err(msrv_attr.span(), format!("`{msrv}` is not a valid Rust version")); + return None; + }; + + Some(version) } diff --git a/src/tools/clippy/clippy_utils/src/ty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/mod.rs index d79773f8321..fafc1d07e51 100644 --- a/src/tools/clippy/clippy_utils/src/ty/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ty/mod.rs @@ -18,6 +18,7 @@ use rustc_lint::LateContext; use rustc_middle::mir::ConstValue; use rustc_middle::mir::interpret::Scalar; use rustc_middle::traits::EvaluationResult; +use rustc_middle::ty::adjustment::{Adjust, Adjustment}; use rustc_middle::ty::layout::ValidityRequirement; use rustc_middle::ty::{ self, AdtDef, AliasTy, AssocItem, AssocTag, Binder, BoundRegion, FnSig, GenericArg, GenericArgKind, GenericArgsRef, @@ -31,7 +32,7 @@ use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt; use rustc_trait_selection::traits::{Obligation, ObligationCause}; use std::assert_matches::debug_assert_matches; use std::collections::hash_map::Entry; -use std::iter; +use std::{iter, mem}; use crate::path_res; use crate::paths::{PathNS, lookup_path_str}; @@ -1382,7 +1383,6 @@ pub fn is_slice_like<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { || matches!(ty.kind(), ty::Adt(adt_def, _) if cx.tcx.is_diagnostic_item(sym::Vec, adt_def.did())) } -/// Gets the index of a field by name. pub fn get_field_idx_by_name(ty: Ty<'_>, name: Symbol) -> Option<usize> { match *ty.kind() { ty::Adt(def, _) if def.is_union() || def.is_struct() => { @@ -1392,3 +1392,11 @@ pub fn get_field_idx_by_name(ty: Ty<'_>, name: Symbol) -> Option<usize> { _ => None, } } + +/// Checks if the adjustments contain a mutable dereference of a `ManuallyDrop<_>`. +pub fn adjust_derefs_manually_drop<'tcx>(adjustments: &'tcx [Adjustment<'tcx>], mut ty: Ty<'tcx>) -> bool { + adjustments.iter().any(|a| { + let ty = mem::replace(&mut ty, a.target); + matches!(a.kind, Adjust::Deref(Some(op)) if op.mutbl == Mutability::Mut) && is_manually_drop(ty) + }) +} diff --git a/src/tools/clippy/rust-toolchain.toml b/src/tools/clippy/rust-toolchain.toml index ac51ec2d61b..5497e77e8ad 100644 --- a/src/tools/clippy/rust-toolchain.toml +++ b/src/tools/clippy/rust-toolchain.toml @@ -1,6 +1,6 @@ [toolchain] # begin autogenerated nightly -channel = "nightly-2025-08-07" +channel = "nightly-2025-08-22" # end autogenerated nightly components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] profile = "minimal" diff --git a/src/tools/clippy/tests/ui-cargo/undocumented_unsafe_blocks/fail/Cargo.stderr b/src/tools/clippy/tests/ui-cargo/undocumented_unsafe_blocks/fail/Cargo.stderr new file mode 100644 index 00000000000..59a7146ac90 --- /dev/null +++ b/src/tools/clippy/tests/ui-cargo/undocumented_unsafe_blocks/fail/Cargo.stderr @@ -0,0 +1,26 @@ +error: module has unnecessary safety comment + --> src/main.rs:2:1 + | +2 | mod x {} + | ^^^^^^^^ + | +help: consider removing the safety comment + --> src/main.rs:1:1 + | +1 | // SAFETY: ... + | ^^^^^^^^^^^^^^ + = note: requested on the command line with `-D clippy::unnecessary-safety-comment` + +error: module has unnecessary safety comment + --> src/main.rs:5:1 + | +5 | mod y {} + | ^^^^^^^^ + | +help: consider removing the safety comment + --> src/main.rs:4:1 + | +4 | // SAFETY: ... + | ^^^^^^^^^^^^^^ + +error: could not compile `undocumented_unsafe_blocks` (bin "undocumented_unsafe_blocks") due to 2 previous errors diff --git a/src/tools/clippy/tests/ui-cargo/undocumented_unsafe_blocks/fail/Cargo.toml b/src/tools/clippy/tests/ui-cargo/undocumented_unsafe_blocks/fail/Cargo.toml new file mode 100644 index 00000000000..36bb3472df0 --- /dev/null +++ b/src/tools/clippy/tests/ui-cargo/undocumented_unsafe_blocks/fail/Cargo.toml @@ -0,0 +1,12 @@ +# Reproducing #14553 requires the `# Safety` comment to be in the first line of +# the file. Since `unnecessary_safety_comment` is not enabled by default, we +# will set it up here. + +[package] +name = "undocumented_unsafe_blocks" +edition = "2024" +publish = false +version = "0.1.0" + +[lints.clippy] +unnecessary_safety_comment = "deny" diff --git a/src/tools/clippy/tests/ui-cargo/undocumented_unsafe_blocks/fail/src/main.rs b/src/tools/clippy/tests/ui-cargo/undocumented_unsafe_blocks/fail/src/main.rs new file mode 100644 index 00000000000..5cafcff99dd --- /dev/null +++ b/src/tools/clippy/tests/ui-cargo/undocumented_unsafe_blocks/fail/src/main.rs @@ -0,0 +1,7 @@ +// SAFETY: ... +mod x {} + +// SAFETY: ... +mod y {} + +fn main() {} diff --git a/src/tools/clippy/tests/ui-toml/functions_maxlines/test.stderr b/src/tools/clippy/tests/ui-toml/functions_maxlines/test.stderr index 14a49cb76c1..e856963c87d 100644 --- a/src/tools/clippy/tests/ui-toml/functions_maxlines/test.stderr +++ b/src/tools/clippy/tests/ui-toml/functions_maxlines/test.stderr @@ -1,12 +1,8 @@ error: this function has too many lines (2/1) --> tests/ui-toml/functions_maxlines/test.rs:19:1 | -LL | / fn too_many_lines() { -LL | | -LL | | println!("This is bad."); -LL | | println!("This is bad."); -LL | | } - | |_^ +LL | fn too_many_lines() { + | ^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::too-many-lines` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::too_many_lines)]` @@ -14,35 +10,20 @@ LL | | } error: this function has too many lines (4/1) --> tests/ui-toml/functions_maxlines/test.rs:26:1 | -LL | / async fn async_too_many_lines() { -LL | | -LL | | println!("This is bad."); -LL | | println!("This is bad."); -LL | | } - | |_^ +LL | async fn async_too_many_lines() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this function has too many lines (4/1) --> tests/ui-toml/functions_maxlines/test.rs:33:1 | -LL | / fn closure_too_many_lines() { -LL | | -LL | | let _ = { -LL | | println!("This is bad."); -LL | | println!("This is bad."); -LL | | }; -LL | | } - | |_^ +LL | fn closure_too_many_lines() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this function has too many lines (2/1) --> tests/ui-toml/functions_maxlines/test.rs:56:1 | -LL | / fn comment_before_code() { -LL | | -LL | | let _ = "test"; -LL | | /* This comment extends to the front of -LL | | the code but this line should still count. */ let _ = 5; -LL | | } - | |_^ +LL | fn comment_before_code() { + | ^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 4 previous errors diff --git a/src/tools/clippy/tests/ui/as_ptr_cast_mut.fixed b/src/tools/clippy/tests/ui/as_ptr_cast_mut.fixed new file mode 100644 index 00000000000..fe9c5dca5ba --- /dev/null +++ b/src/tools/clippy/tests/ui/as_ptr_cast_mut.fixed @@ -0,0 +1,38 @@ +#![allow(unused)] +#![warn(clippy::as_ptr_cast_mut)] +#![allow(clippy::wrong_self_convention, clippy::unnecessary_cast)] + +struct MutPtrWrapper(Vec<u8>); +impl MutPtrWrapper { + fn as_ptr(&mut self) -> *const u8 { + self.0.as_mut_ptr() as *const u8 + } +} + +struct Covariant<T>(*const T); +impl<T> Covariant<T> { + fn as_ptr(self) -> *const T { + self.0 + } +} + +fn main() { + let mut string = String::new(); + let _ = string.as_mut_ptr(); + //~^ as_ptr_cast_mut + + let _ = string.as_ptr() as *const i8; + let _ = string.as_mut_ptr(); + let _ = string.as_mut_ptr() as *mut u8; + let _ = string.as_mut_ptr() as *const u8; + + let nn = std::ptr::NonNull::new(4 as *mut u8).unwrap(); + let _ = nn.as_ptr() as *mut u8; + + let mut wrap = MutPtrWrapper(Vec::new()); + let _ = wrap.as_ptr() as *mut u8; + + let mut local = 4; + let ref_with_write_perm = Covariant(std::ptr::addr_of_mut!(local) as *const _); + let _ = ref_with_write_perm.as_ptr() as *mut u8; +} diff --git a/src/tools/clippy/tests/ui/as_ptr_cast_mut.rs b/src/tools/clippy/tests/ui/as_ptr_cast_mut.rs index baf7279adc4..3f22c2058d0 100644 --- a/src/tools/clippy/tests/ui/as_ptr_cast_mut.rs +++ b/src/tools/clippy/tests/ui/as_ptr_cast_mut.rs @@ -1,7 +1,6 @@ #![allow(unused)] #![warn(clippy::as_ptr_cast_mut)] #![allow(clippy::wrong_self_convention, clippy::unnecessary_cast)] -//@no-rustfix: incorrect suggestion struct MutPtrWrapper(Vec<u8>); impl MutPtrWrapper { @@ -22,9 +21,6 @@ fn main() { let _ = string.as_ptr() as *mut u8; //~^ as_ptr_cast_mut - let _: *mut i8 = string.as_ptr() as *mut _; - //~^ as_ptr_cast_mut - let _ = string.as_ptr() as *const i8; let _ = string.as_mut_ptr(); let _ = string.as_mut_ptr() as *mut u8; diff --git a/src/tools/clippy/tests/ui/as_ptr_cast_mut.stderr b/src/tools/clippy/tests/ui/as_ptr_cast_mut.stderr index b3fc223ccdb..fa9fb23e2d0 100644 --- a/src/tools/clippy/tests/ui/as_ptr_cast_mut.stderr +++ b/src/tools/clippy/tests/ui/as_ptr_cast_mut.stderr @@ -1,5 +1,5 @@ error: casting the result of `as_ptr` to *mut u8 - --> tests/ui/as_ptr_cast_mut.rs:22:13 + --> tests/ui/as_ptr_cast_mut.rs:21:13 | LL | let _ = string.as_ptr() as *mut u8; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `string.as_mut_ptr()` @@ -7,11 +7,5 @@ LL | let _ = string.as_ptr() as *mut u8; = note: `-D clippy::as-ptr-cast-mut` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::as_ptr_cast_mut)]` -error: casting the result of `as_ptr` to *mut i8 - --> tests/ui/as_ptr_cast_mut.rs:25:22 - | -LL | let _: *mut i8 = string.as_ptr() as *mut _; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `string.as_mut_ptr()` - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error diff --git a/src/tools/clippy/tests/ui/as_ptr_cast_mut_unfixable.rs b/src/tools/clippy/tests/ui/as_ptr_cast_mut_unfixable.rs new file mode 100644 index 00000000000..a8f6b06bd4f --- /dev/null +++ b/src/tools/clippy/tests/ui/as_ptr_cast_mut_unfixable.rs @@ -0,0 +1,16 @@ +//@no-rustfix +#![allow(unused)] +#![warn(clippy::as_ptr_cast_mut)] + +fn main() { + let mut string = String::new(); + + // the `*mut _` is actually necessary since it does two things at once: + // - changes the mutability (caught by the lint) + // - changes the type + // + // and so replacing this with `as_mut_ptr` removes the second thing, + // resulting in a type mismatch + let _: *mut i8 = string.as_ptr() as *mut _; + //~^ as_ptr_cast_mut +} diff --git a/src/tools/clippy/tests/ui/as_ptr_cast_mut_unfixable.stderr b/src/tools/clippy/tests/ui/as_ptr_cast_mut_unfixable.stderr new file mode 100644 index 00000000000..c5bcad6f4df --- /dev/null +++ b/src/tools/clippy/tests/ui/as_ptr_cast_mut_unfixable.stderr @@ -0,0 +1,11 @@ +error: casting the result of `as_ptr` to *mut i8 + --> tests/ui/as_ptr_cast_mut_unfixable.rs:14:22 + | +LL | let _: *mut i8 = string.as_ptr() as *mut _; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `string.as_mut_ptr()` + | + = note: `-D clippy::as-ptr-cast-mut` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::as_ptr_cast_mut)]` + +error: aborting due to 1 previous error + diff --git a/src/tools/clippy/tests/ui/borrow_as_ptr.fixed b/src/tools/clippy/tests/ui/borrow_as_ptr.fixed index 3f6e5245b87..bfe826508f3 100644 --- a/src/tools/clippy/tests/ui/borrow_as_ptr.fixed +++ b/src/tools/clippy/tests/ui/borrow_as_ptr.fixed @@ -1,6 +1,9 @@ +//@aux-build:proc_macros.rs #![warn(clippy::borrow_as_ptr)] #![allow(clippy::useless_vec)] +extern crate proc_macros; + fn a() -> i32 { 0 } @@ -53,3 +56,12 @@ fn issue_15141() { // Don't lint cast to dyn trait pointers let b = &a as *const dyn std::any::Any; } + +fn issue15389() { + proc_macros::with_span! { + span + let var = 0u32; + // Don't lint in proc-macros + let _ = &var as *const u32; + }; +} diff --git a/src/tools/clippy/tests/ui/borrow_as_ptr.rs b/src/tools/clippy/tests/ui/borrow_as_ptr.rs index 20f4f40e001..ce248f157c6 100644 --- a/src/tools/clippy/tests/ui/borrow_as_ptr.rs +++ b/src/tools/clippy/tests/ui/borrow_as_ptr.rs @@ -1,6 +1,9 @@ +//@aux-build:proc_macros.rs #![warn(clippy::borrow_as_ptr)] #![allow(clippy::useless_vec)] +extern crate proc_macros; + fn a() -> i32 { 0 } @@ -53,3 +56,12 @@ fn issue_15141() { // Don't lint cast to dyn trait pointers let b = &a as *const dyn std::any::Any; } + +fn issue15389() { + proc_macros::with_span! { + span + let var = 0u32; + // Don't lint in proc-macros + let _ = &var as *const u32; + }; +} diff --git a/src/tools/clippy/tests/ui/borrow_as_ptr.stderr b/src/tools/clippy/tests/ui/borrow_as_ptr.stderr index b1fcce49403..b371b477a50 100644 --- a/src/tools/clippy/tests/ui/borrow_as_ptr.stderr +++ b/src/tools/clippy/tests/ui/borrow_as_ptr.stderr @@ -1,5 +1,5 @@ error: borrow as raw pointer - --> tests/ui/borrow_as_ptr.rs:11:14 + --> tests/ui/borrow_as_ptr.rs:14:14 | LL | let _p = &val as *const i32; | ^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::addr_of!(val)` @@ -8,25 +8,25 @@ LL | let _p = &val as *const i32; = help: to override `-D warnings` add `#[allow(clippy::borrow_as_ptr)]` error: borrow as raw pointer - --> tests/ui/borrow_as_ptr.rs:19:18 + --> tests/ui/borrow_as_ptr.rs:22:18 | LL | let _p_mut = &mut val_mut as *mut i32; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::addr_of_mut!(val_mut)` error: borrow as raw pointer - --> tests/ui/borrow_as_ptr.rs:23:16 + --> tests/ui/borrow_as_ptr.rs:26:16 | LL | let _raw = (&mut x[1] as *mut i32).wrapping_offset(-1); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::addr_of_mut!(x[1])` error: borrow as raw pointer - --> tests/ui/borrow_as_ptr.rs:29:17 + --> tests/ui/borrow_as_ptr.rs:32:17 | LL | let _raw = (&mut x[1] as *mut i32).wrapping_offset(-1); | ^^^^^^^^^^^^^^^^^^^^^ help: try: `&raw mut x[1]` error: implicit borrow as raw pointer - --> tests/ui/borrow_as_ptr.rs:35:25 + --> tests/ui/borrow_as_ptr.rs:38:25 | LL | let p: *const i32 = &val; | ^^^^ @@ -37,7 +37,7 @@ LL | let p: *const i32 = &raw const val; | +++++++++ error: implicit borrow as raw pointer - --> tests/ui/borrow_as_ptr.rs:39:23 + --> tests/ui/borrow_as_ptr.rs:42:23 | LL | let p: *mut i32 = &mut val; | ^^^^^^^^ @@ -48,7 +48,7 @@ LL | let p: *mut i32 = &raw mut val; | +++ error: implicit borrow as raw pointer - --> tests/ui/borrow_as_ptr.rs:44:19 + --> tests/ui/borrow_as_ptr.rs:47:19 | LL | core::ptr::eq(&val, &1); | ^^^^ diff --git a/src/tools/clippy/tests/ui/char_lit_as_u8_suggestions.fixed b/src/tools/clippy/tests/ui/char_lit_as_u8.fixed index 64aacedfd36..64aacedfd36 100644 --- a/src/tools/clippy/tests/ui/char_lit_as_u8_suggestions.fixed +++ b/src/tools/clippy/tests/ui/char_lit_as_u8.fixed diff --git a/src/tools/clippy/tests/ui/char_lit_as_u8.rs b/src/tools/clippy/tests/ui/char_lit_as_u8.rs index c8774c7f309..a8f39e27605 100644 --- a/src/tools/clippy/tests/ui/char_lit_as_u8.rs +++ b/src/tools/clippy/tests/ui/char_lit_as_u8.rs @@ -1,7 +1,12 @@ #![warn(clippy::char_lit_as_u8)] fn main() { - // no suggestion, since a byte literal won't work. - let _ = '❤' as u8; + let _ = 'a' as u8; + //~^ char_lit_as_u8 + let _ = '\n' as u8; + //~^ char_lit_as_u8 + let _ = '\0' as u8; + //~^ char_lit_as_u8 + let _ = '\x01' as u8; //~^ char_lit_as_u8 } diff --git a/src/tools/clippy/tests/ui/char_lit_as_u8.stderr b/src/tools/clippy/tests/ui/char_lit_as_u8.stderr index ec02f1341c0..9bcded7b0ff 100644 --- a/src/tools/clippy/tests/ui/char_lit_as_u8.stderr +++ b/src/tools/clippy/tests/ui/char_lit_as_u8.stderr @@ -1,12 +1,36 @@ error: casting a character literal to `u8` truncates - --> tests/ui/char_lit_as_u8.rs:5:13 + --> tests/ui/char_lit_as_u8.rs:4:13 | -LL | let _ = '❤' as u8; - | ^^^^^^^^^ +LL | let _ = 'a' as u8; + | ^^^^^^^^^ help: use a byte literal instead: `b'a'` | = note: `char` is four bytes wide, but `u8` is a single byte = note: `-D clippy::char-lit-as-u8` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::char_lit_as_u8)]` -error: aborting due to 1 previous error +error: casting a character literal to `u8` truncates + --> tests/ui/char_lit_as_u8.rs:6:13 + | +LL | let _ = '\n' as u8; + | ^^^^^^^^^^ help: use a byte literal instead: `b'\n'` + | + = note: `char` is four bytes wide, but `u8` is a single byte + +error: casting a character literal to `u8` truncates + --> tests/ui/char_lit_as_u8.rs:8:13 + | +LL | let _ = '\0' as u8; + | ^^^^^^^^^^ help: use a byte literal instead: `b'\0'` + | + = note: `char` is four bytes wide, but `u8` is a single byte + +error: casting a character literal to `u8` truncates + --> tests/ui/char_lit_as_u8.rs:10:13 + | +LL | let _ = '\x01' as u8; + | ^^^^^^^^^^^^ help: use a byte literal instead: `b'\x01'` + | + = note: `char` is four bytes wide, but `u8` is a single byte + +error: aborting due to 4 previous errors diff --git a/src/tools/clippy/tests/ui/char_lit_as_u8_suggestions.rs b/src/tools/clippy/tests/ui/char_lit_as_u8_suggestions.rs deleted file mode 100644 index a8f39e27605..00000000000 --- a/src/tools/clippy/tests/ui/char_lit_as_u8_suggestions.rs +++ /dev/null @@ -1,12 +0,0 @@ -#![warn(clippy::char_lit_as_u8)] - -fn main() { - let _ = 'a' as u8; - //~^ char_lit_as_u8 - let _ = '\n' as u8; - //~^ char_lit_as_u8 - let _ = '\0' as u8; - //~^ char_lit_as_u8 - let _ = '\x01' as u8; - //~^ char_lit_as_u8 -} diff --git a/src/tools/clippy/tests/ui/char_lit_as_u8_suggestions.stderr b/src/tools/clippy/tests/ui/char_lit_as_u8_suggestions.stderr deleted file mode 100644 index 158dfd6bed2..00000000000 --- a/src/tools/clippy/tests/ui/char_lit_as_u8_suggestions.stderr +++ /dev/null @@ -1,36 +0,0 @@ -error: casting a character literal to `u8` truncates - --> tests/ui/char_lit_as_u8_suggestions.rs:4:13 - | -LL | let _ = 'a' as u8; - | ^^^^^^^^^ help: use a byte literal instead: `b'a'` - | - = note: `char` is four bytes wide, but `u8` is a single byte - = note: `-D clippy::char-lit-as-u8` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::char_lit_as_u8)]` - -error: casting a character literal to `u8` truncates - --> tests/ui/char_lit_as_u8_suggestions.rs:6:13 - | -LL | let _ = '\n' as u8; - | ^^^^^^^^^^ help: use a byte literal instead: `b'\n'` - | - = note: `char` is four bytes wide, but `u8` is a single byte - -error: casting a character literal to `u8` truncates - --> tests/ui/char_lit_as_u8_suggestions.rs:8:13 - | -LL | let _ = '\0' as u8; - | ^^^^^^^^^^ help: use a byte literal instead: `b'\0'` - | - = note: `char` is four bytes wide, but `u8` is a single byte - -error: casting a character literal to `u8` truncates - --> tests/ui/char_lit_as_u8_suggestions.rs:10:13 - | -LL | let _ = '\x01' as u8; - | ^^^^^^^^^^^^ help: use a byte literal instead: `b'\x01'` - | - = note: `char` is four bytes wide, but `u8` is a single byte - -error: aborting due to 4 previous errors - diff --git a/src/tools/clippy/tests/ui/char_lit_as_u8_unfixable.rs b/src/tools/clippy/tests/ui/char_lit_as_u8_unfixable.rs new file mode 100644 index 00000000000..e5c094f158e --- /dev/null +++ b/src/tools/clippy/tests/ui/char_lit_as_u8_unfixable.rs @@ -0,0 +1,8 @@ +//@no-rustfix +#![warn(clippy::char_lit_as_u8)] + +fn main() { + // no suggestion, since a byte literal won't work. + let _ = '❤' as u8; + //~^ char_lit_as_u8 +} diff --git a/src/tools/clippy/tests/ui/char_lit_as_u8_unfixable.stderr b/src/tools/clippy/tests/ui/char_lit_as_u8_unfixable.stderr new file mode 100644 index 00000000000..49e555ae638 --- /dev/null +++ b/src/tools/clippy/tests/ui/char_lit_as_u8_unfixable.stderr @@ -0,0 +1,12 @@ +error: casting a character literal to `u8` truncates + --> tests/ui/char_lit_as_u8_unfixable.rs:6:13 + | +LL | let _ = '❤' as u8; + | ^^^^^^^^^ + | + = note: `char` is four bytes wide, but `u8` is a single byte + = note: `-D clippy::char-lit-as-u8` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::char_lit_as_u8)]` + +error: aborting due to 1 previous error + diff --git a/src/tools/clippy/tests/ui/deref_addrof.fixed b/src/tools/clippy/tests/ui/deref_addrof.fixed index 35dbd790e89..ffe7f7d1440 100644 --- a/src/tools/clippy/tests/ui/deref_addrof.fixed +++ b/src/tools/clippy/tests/ui/deref_addrof.fixed @@ -1,11 +1,11 @@ -//@aux-build:proc_macros.rs - -#![allow(clippy::return_self_not_must_use, clippy::useless_vec)] +#![allow( + dangerous_implicit_autorefs, + clippy::explicit_auto_deref, + clippy::return_self_not_must_use, + clippy::useless_vec +)] #![warn(clippy::deref_addrof)] -extern crate proc_macros; -use proc_macros::inline_macros; - fn get_number() -> usize { 10 } @@ -56,19 +56,75 @@ fn main() { //~^ deref_addrof // do NOT lint for array as semantic differences with/out `*&`. let _arr = *&[0, 1, 2, 3, 4]; + + // Do not lint when text comes from macro + macro_rules! mac { + (dr) => { + *&0 + }; + (dr $e:expr) => { + *&$e + }; + (r $e:expr) => { + &$e + }; + } + let b = mac!(dr); + let b = mac!(dr a); + let b = *mac!(r a); } -#[derive(Copy, Clone)] -pub struct S; -#[inline_macros] -impl S { - pub fn f(&self) -> &Self { - inline!($(@expr self)) - //~^ deref_addrof +fn issue14386() { + use std::mem::ManuallyDrop; + + #[derive(Copy, Clone)] + struct Data { + num: u64, } - #[allow(unused_mut)] // mut will be unused, once the macro is fixed - pub fn f_mut(mut self) -> Self { - inline!($(@expr self)) + + #[derive(Clone, Copy)] + struct M { + md: ManuallyDrop<[u8; 4]>, + } + + union DataWithPadding<'lt> { + data: ManuallyDrop<Data>, + prim: ManuallyDrop<u64>, + padding: [u8; size_of::<Data>()], + tup: (ManuallyDrop<Data>, ()), + indirect: M, + indirect_arr: [M; 2], + indirect_ref: &'lt mut M, + } + + let mut a = DataWithPadding { + padding: [0; size_of::<DataWithPadding>()], + }; + unsafe { + a.padding = [1; size_of::<DataWithPadding>()]; //~^ deref_addrof + a.tup.1 = (); + //~^ deref_addrof + *a.prim = 0; + //~^ deref_addrof + + (*a.data).num = 42; + //~^ deref_addrof + (*a.indirect.md)[3] = 1; + //~^ deref_addrof + (*a.indirect_arr[1].md)[3] = 1; + //~^ deref_addrof + (*a.indirect_ref.md)[3] = 1; + //~^ deref_addrof + + // Check that raw pointers are properly considered as well + *a.prim = 0; + //~^ deref_addrof + (*a.data).num = 42; + //~^ deref_addrof + + // Do not lint, as the dereference happens later, we cannot + // just remove `&mut` + (*&mut a.tup).0.num = 42; } } diff --git a/src/tools/clippy/tests/ui/deref_addrof.rs b/src/tools/clippy/tests/ui/deref_addrof.rs index 96d1b92ef7b..bc253716aff 100644 --- a/src/tools/clippy/tests/ui/deref_addrof.rs +++ b/src/tools/clippy/tests/ui/deref_addrof.rs @@ -1,11 +1,11 @@ -//@aux-build:proc_macros.rs - -#![allow(clippy::return_self_not_must_use, clippy::useless_vec)] +#![allow( + dangerous_implicit_autorefs, + clippy::explicit_auto_deref, + clippy::return_self_not_must_use, + clippy::useless_vec +)] #![warn(clippy::deref_addrof)] -extern crate proc_macros; -use proc_macros::inline_macros; - fn get_number() -> usize { 10 } @@ -56,19 +56,75 @@ fn main() { //~^ deref_addrof // do NOT lint for array as semantic differences with/out `*&`. let _arr = *&[0, 1, 2, 3, 4]; + + // Do not lint when text comes from macro + macro_rules! mac { + (dr) => { + *&0 + }; + (dr $e:expr) => { + *&$e + }; + (r $e:expr) => { + &$e + }; + } + let b = mac!(dr); + let b = mac!(dr a); + let b = *mac!(r a); } -#[derive(Copy, Clone)] -pub struct S; -#[inline_macros] -impl S { - pub fn f(&self) -> &Self { - inline!(*& $(@expr self)) - //~^ deref_addrof +fn issue14386() { + use std::mem::ManuallyDrop; + + #[derive(Copy, Clone)] + struct Data { + num: u64, } - #[allow(unused_mut)] // mut will be unused, once the macro is fixed - pub fn f_mut(mut self) -> Self { - inline!(*&mut $(@expr self)) + + #[derive(Clone, Copy)] + struct M { + md: ManuallyDrop<[u8; 4]>, + } + + union DataWithPadding<'lt> { + data: ManuallyDrop<Data>, + prim: ManuallyDrop<u64>, + padding: [u8; size_of::<Data>()], + tup: (ManuallyDrop<Data>, ()), + indirect: M, + indirect_arr: [M; 2], + indirect_ref: &'lt mut M, + } + + let mut a = DataWithPadding { + padding: [0; size_of::<DataWithPadding>()], + }; + unsafe { + (*&mut a.padding) = [1; size_of::<DataWithPadding>()]; //~^ deref_addrof + (*&mut a.tup).1 = (); + //~^ deref_addrof + **&mut a.prim = 0; + //~^ deref_addrof + + (*&mut a.data).num = 42; + //~^ deref_addrof + (*&mut a.indirect.md)[3] = 1; + //~^ deref_addrof + (*&mut a.indirect_arr[1].md)[3] = 1; + //~^ deref_addrof + (*&mut a.indirect_ref.md)[3] = 1; + //~^ deref_addrof + + // Check that raw pointers are properly considered as well + **&raw mut a.prim = 0; + //~^ deref_addrof + (*&raw mut a.data).num = 42; + //~^ deref_addrof + + // Do not lint, as the dereference happens later, we cannot + // just remove `&mut` + (*&mut a.tup).0.num = 42; } } diff --git a/src/tools/clippy/tests/ui/deref_addrof.stderr b/src/tools/clippy/tests/ui/deref_addrof.stderr index 81414b625b2..65dd904a8f7 100644 --- a/src/tools/clippy/tests/ui/deref_addrof.stderr +++ b/src/tools/clippy/tests/ui/deref_addrof.stderr @@ -56,20 +56,58 @@ LL | let _repeat = *&[0; 64]; | ^^^^^^^^^ help: try: `[0; 64]` error: immediately dereferencing a reference - --> tests/ui/deref_addrof.rs:66:17 + --> tests/ui/deref_addrof.rs:104:9 | -LL | inline!(*& $(@expr self)) - | ^^^^^^^^^^^^^^^^ help: try: `$(@expr self)` +LL | (*&mut a.padding) = [1; size_of::<DataWithPadding>()]; + | ^^^^^^^^^^^^^^^^^ help: try: `a.padding` + +error: immediately dereferencing a reference + --> tests/ui/deref_addrof.rs:106:9 + | +LL | (*&mut a.tup).1 = (); + | ^^^^^^^^^^^^^ help: try: `a.tup` + +error: immediately dereferencing a reference + --> tests/ui/deref_addrof.rs:108:10 | - = note: this error originates in the macro `__inline_mac_impl` (in Nightly builds, run with -Z macro-backtrace for more info) +LL | **&mut a.prim = 0; + | ^^^^^^^^^^^^ help: try: `a.prim` error: immediately dereferencing a reference - --> tests/ui/deref_addrof.rs:71:17 + --> tests/ui/deref_addrof.rs:111:9 | -LL | inline!(*&mut $(@expr self)) - | ^^^^^^^^^^^^^^^^^^^ help: try: `$(@expr self)` +LL | (*&mut a.data).num = 42; + | ^^^^^^^^^^^^^^ help: try: `(*a.data)` + +error: immediately dereferencing a reference + --> tests/ui/deref_addrof.rs:113:9 + | +LL | (*&mut a.indirect.md)[3] = 1; + | ^^^^^^^^^^^^^^^^^^^^^ help: try: `(*a.indirect.md)` + +error: immediately dereferencing a reference + --> tests/ui/deref_addrof.rs:115:9 + | +LL | (*&mut a.indirect_arr[1].md)[3] = 1; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(*a.indirect_arr[1].md)` + +error: immediately dereferencing a reference + --> tests/ui/deref_addrof.rs:117:9 + | +LL | (*&mut a.indirect_ref.md)[3] = 1; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(*a.indirect_ref.md)` + +error: immediately dereferencing a reference + --> tests/ui/deref_addrof.rs:121:10 + | +LL | **&raw mut a.prim = 0; + | ^^^^^^^^^^^^^^^^ help: try: `a.prim` + +error: immediately dereferencing a reference + --> tests/ui/deref_addrof.rs:123:9 | - = note: this error originates in the macro `__inline_mac_impl` (in Nightly builds, run with -Z macro-backtrace for more info) +LL | (*&raw mut a.data).num = 42; + | ^^^^^^^^^^^^^^^^^^ help: try: `(*a.data)` -error: aborting due to 11 previous errors +error: aborting due to 18 previous errors diff --git a/src/tools/clippy/tests/ui/doc/doc-fixable.fixed b/src/tools/clippy/tests/ui/doc/doc-fixable.fixed index bbbd5973036..423a73734da 100644 --- a/src/tools/clippy/tests/ui/doc/doc-fixable.fixed +++ b/src/tools/clippy/tests/ui/doc/doc-fixable.fixed @@ -74,7 +74,7 @@ fn test_units() { /// GitHub GitLab /// IPv4 IPv6 /// ClojureScript CoffeeScript JavaScript PostScript PureScript TypeScript -/// WebAssembly +/// PowerPC WebAssembly /// NaN NaNs /// OAuth GraphQL /// OCaml diff --git a/src/tools/clippy/tests/ui/doc/doc-fixable.rs b/src/tools/clippy/tests/ui/doc/doc-fixable.rs index 1077d3580d3..8deffb4210e 100644 --- a/src/tools/clippy/tests/ui/doc/doc-fixable.rs +++ b/src/tools/clippy/tests/ui/doc/doc-fixable.rs @@ -74,7 +74,7 @@ fn test_units() { /// GitHub GitLab /// IPv4 IPv6 /// ClojureScript CoffeeScript JavaScript PostScript PureScript TypeScript -/// WebAssembly +/// PowerPC WebAssembly /// NaN NaNs /// OAuth GraphQL /// OCaml diff --git a/src/tools/clippy/tests/ui/double_ended_iterator_last.fixed b/src/tools/clippy/tests/ui/double_ended_iterator_last.fixed index be31ee5fb48..180a513d0f8 100644 --- a/src/tools/clippy/tests/ui/double_ended_iterator_last.fixed +++ b/src/tools/clippy/tests/ui/double_ended_iterator_last.fixed @@ -81,6 +81,11 @@ fn issue_14139() { let (subindex, _) = (index.by_ref().take(3), 42); let _ = subindex.last(); let _ = index.next(); + + let mut index = [true, true, false, false, false, true].iter(); + let subindex = (index.by_ref().take(3), 42); + let _ = subindex.0.last(); + let _ = index.next(); } fn drop_order() { @@ -108,6 +113,12 @@ fn drop_order() { let mut v = DropDeIterator(v.into_iter()); println!("Last element is {}", v.next_back().unwrap().0); //~^ ERROR: called `Iterator::last` on a `DoubleEndedIterator` + + let v = vec![S("four"), S("five"), S("six")]; + let mut v = (DropDeIterator(v.into_iter()), 42); + println!("Last element is {}", v.0.next_back().unwrap().0); + //~^ ERROR: called `Iterator::last` on a `DoubleEndedIterator` + println!("Done"); } diff --git a/src/tools/clippy/tests/ui/double_ended_iterator_last.rs b/src/tools/clippy/tests/ui/double_ended_iterator_last.rs index 30864e15bce..3dd72cfeaac 100644 --- a/src/tools/clippy/tests/ui/double_ended_iterator_last.rs +++ b/src/tools/clippy/tests/ui/double_ended_iterator_last.rs @@ -81,6 +81,11 @@ fn issue_14139() { let (subindex, _) = (index.by_ref().take(3), 42); let _ = subindex.last(); let _ = index.next(); + + let mut index = [true, true, false, false, false, true].iter(); + let subindex = (index.by_ref().take(3), 42); + let _ = subindex.0.last(); + let _ = index.next(); } fn drop_order() { @@ -108,6 +113,12 @@ fn drop_order() { let v = DropDeIterator(v.into_iter()); println!("Last element is {}", v.last().unwrap().0); //~^ ERROR: called `Iterator::last` on a `DoubleEndedIterator` + + let v = vec![S("four"), S("five"), S("six")]; + let v = (DropDeIterator(v.into_iter()), 42); + println!("Last element is {}", v.0.last().unwrap().0); + //~^ ERROR: called `Iterator::last` on a `DoubleEndedIterator` + println!("Done"); } diff --git a/src/tools/clippy/tests/ui/double_ended_iterator_last.stderr b/src/tools/clippy/tests/ui/double_ended_iterator_last.stderr index 72a6ead47a9..0f0056be376 100644 --- a/src/tools/clippy/tests/ui/double_ended_iterator_last.stderr +++ b/src/tools/clippy/tests/ui/double_ended_iterator_last.stderr @@ -18,7 +18,7 @@ LL | let _ = DeIterator.last(); | help: try: `next_back()` error: called `Iterator::last` on a `DoubleEndedIterator`; this will needlessly iterate the entire iterator - --> tests/ui/double_ended_iterator_last.rs:109:36 + --> tests/ui/double_ended_iterator_last.rs:114:36 | LL | println!("Last element is {}", v.last().unwrap().0); | ^^^^^^^^ @@ -30,5 +30,18 @@ LL ~ let mut v = DropDeIterator(v.into_iter()); LL ~ println!("Last element is {}", v.next_back().unwrap().0); | -error: aborting due to 3 previous errors +error: called `Iterator::last` on a `DoubleEndedIterator`; this will needlessly iterate the entire iterator + --> tests/ui/double_ended_iterator_last.rs:119:36 + | +LL | println!("Last element is {}", v.0.last().unwrap().0); + | ^^^^^^^^^^ + | + = note: this change will alter drop order which may be undesirable +help: try + | +LL ~ let mut v = (DropDeIterator(v.into_iter()), 42); +LL ~ println!("Last element is {}", v.0.next_back().unwrap().0); + | + +error: aborting due to 4 previous errors diff --git a/src/tools/clippy/tests/ui/double_ended_iterator_last_unfixable.rs b/src/tools/clippy/tests/ui/double_ended_iterator_last_unfixable.rs deleted file mode 100644 index 73f62ac1246..00000000000 --- a/src/tools/clippy/tests/ui/double_ended_iterator_last_unfixable.rs +++ /dev/null @@ -1,39 +0,0 @@ -//@no-rustfix: requires manual changes -#![warn(clippy::double_ended_iterator_last)] - -// Should not be linted because applying the lint would move the original iterator. This can only be -// linted if the iterator is used thereafter. -fn main() { - let mut index = [true, true, false, false, false, true].iter(); - let subindex = (index.by_ref().take(3), 42); - let _ = subindex.0.last(); - let _ = index.next(); -} - -fn drop_order() { - struct DropDeIterator(std::vec::IntoIter<S>); - impl Iterator for DropDeIterator { - type Item = S; - fn next(&mut self) -> Option<Self::Item> { - self.0.next() - } - } - impl DoubleEndedIterator for DropDeIterator { - fn next_back(&mut self) -> Option<Self::Item> { - self.0.next_back() - } - } - - struct S(&'static str); - impl std::ops::Drop for S { - fn drop(&mut self) { - println!("Dropping {}", self.0); - } - } - - let v = vec![S("one"), S("two"), S("three")]; - let v = (DropDeIterator(v.into_iter()), 42); - println!("Last element is {}", v.0.last().unwrap().0); - //~^ ERROR: called `Iterator::last` on a `DoubleEndedIterator` - println!("Done"); -} diff --git a/src/tools/clippy/tests/ui/double_ended_iterator_last_unfixable.stderr b/src/tools/clippy/tests/ui/double_ended_iterator_last_unfixable.stderr deleted file mode 100644 index e330a22a354..00000000000 --- a/src/tools/clippy/tests/ui/double_ended_iterator_last_unfixable.stderr +++ /dev/null @@ -1,19 +0,0 @@ -error: called `Iterator::last` on a `DoubleEndedIterator`; this will needlessly iterate the entire iterator - --> tests/ui/double_ended_iterator_last_unfixable.rs:36:36 - | -LL | println!("Last element is {}", v.0.last().unwrap().0); - | ^^^^------ - | | - | help: try: `next_back()` - | - = note: this change will alter drop order which may be undesirable -note: this must be made mutable to use `.next_back()` - --> tests/ui/double_ended_iterator_last_unfixable.rs:36:36 - | -LL | println!("Last element is {}", v.0.last().unwrap().0); - | ^^^ - = note: `-D clippy::double-ended-iterator-last` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::double_ended_iterator_last)]` - -error: aborting due to 1 previous error - diff --git a/src/tools/clippy/tests/ui/eta.fixed b/src/tools/clippy/tests/ui/eta.fixed index c93b83f53ec..3d2b41b8fb8 100644 --- a/src/tools/clippy/tests/ui/eta.fixed +++ b/src/tools/clippy/tests/ui/eta.fixed @@ -1,3 +1,6 @@ +// we have some HELP annotations -- don't complain about them not being present everywhere +//@require-annotations-for-level: ERROR + #![warn(clippy::redundant_closure, clippy::redundant_closure_for_method_calls)] #![allow(unused)] #![allow( @@ -561,3 +564,29 @@ fn issue_14789() { std::convert::identity, ); } + +fn issue8817() { + fn f(_: u32) -> u32 { + todo!() + } + let g = |_: u32| -> u32 { todo!() }; + struct S(u32); + enum MyError { + A(S), + } + + Some(5) + .map(f) + //~^ redundant_closure + //~| HELP: replace the closure with the function itself + .map(g) + //~^ redundant_closure + //~| HELP: replace the closure with the function itself + .map(S) + //~^ redundant_closure + //~| HELP: replace the closure with the tuple struct itself + .map(MyError::A) + //~^ redundant_closure + //~| HELP: replace the closure with the tuple variant itself + .unwrap(); // just for nicer formatting +} diff --git a/src/tools/clippy/tests/ui/eta.rs b/src/tools/clippy/tests/ui/eta.rs index 273c8b21f4a..79d1103410d 100644 --- a/src/tools/clippy/tests/ui/eta.rs +++ b/src/tools/clippy/tests/ui/eta.rs @@ -1,3 +1,6 @@ +// we have some HELP annotations -- don't complain about them not being present everywhere +//@require-annotations-for-level: ERROR + #![warn(clippy::redundant_closure, clippy::redundant_closure_for_method_calls)] #![allow(unused)] #![allow( @@ -561,3 +564,29 @@ fn issue_14789() { std::convert::identity, ); } + +fn issue8817() { + fn f(_: u32) -> u32 { + todo!() + } + let g = |_: u32| -> u32 { todo!() }; + struct S(u32); + enum MyError { + A(S), + } + + Some(5) + .map(|n| f(n)) + //~^ redundant_closure + //~| HELP: replace the closure with the function itself + .map(|n| g(n)) + //~^ redundant_closure + //~| HELP: replace the closure with the function itself + .map(|n| S(n)) + //~^ redundant_closure + //~| HELP: replace the closure with the tuple struct itself + .map(|n| MyError::A(n)) + //~^ redundant_closure + //~| HELP: replace the closure with the tuple variant itself + .unwrap(); // just for nicer formatting +} diff --git a/src/tools/clippy/tests/ui/eta.stderr b/src/tools/clippy/tests/ui/eta.stderr index 8bc08add2fa..aa32ed1a38e 100644 --- a/src/tools/clippy/tests/ui/eta.stderr +++ b/src/tools/clippy/tests/ui/eta.stderr @@ -1,5 +1,5 @@ error: redundant closure - --> tests/ui/eta.rs:31:27 + --> tests/ui/eta.rs:34:27 | LL | let a = Some(1u8).map(|a| foo(a)); | ^^^^^^^^^^ help: replace the closure with the function itself: `foo` @@ -8,31 +8,31 @@ LL | let a = Some(1u8).map(|a| foo(a)); = help: to override `-D warnings` add `#[allow(clippy::redundant_closure)]` error: redundant closure - --> tests/ui/eta.rs:36:40 + --> tests/ui/eta.rs:39:40 | LL | let _: Option<Vec<u8>> = true.then(|| vec![]); // special case vec! | ^^^^^^^^^ help: replace the closure with `Vec::new`: `std::vec::Vec::new` error: redundant closure - --> tests/ui/eta.rs:39:35 + --> tests/ui/eta.rs:42:35 | LL | let d = Some(1u8).map(|a| foo((|b| foo2(b))(a))); //is adjusted? | ^^^^^^^^^^^^^ help: replace the closure with the function itself: `foo2` error: redundant closure - --> tests/ui/eta.rs:42:26 + --> tests/ui/eta.rs:45:26 | LL | all(&[1, 2, 3], &&2, |x, y| below(x, y)); //is adjusted | ^^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `below` error: redundant closure - --> tests/ui/eta.rs:51:27 + --> tests/ui/eta.rs:54:27 | LL | let e = Some(1u8).map(|a| generic(a)); | ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `generic` error: redundant closure - --> tests/ui/eta.rs:104:51 + --> tests/ui/eta.rs:107:51 | LL | let e = Some(TestStruct { some_ref: &i }).map(|a| a.foo()); | ^^^^^^^^^^^ help: replace the closure with the method itself: `TestStruct::foo` @@ -41,178 +41,202 @@ LL | let e = Some(TestStruct { some_ref: &i }).map(|a| a.foo()); = help: to override `-D warnings` add `#[allow(clippy::redundant_closure_for_method_calls)]` error: redundant closure - --> tests/ui/eta.rs:106:51 + --> tests/ui/eta.rs:109:51 | LL | let e = Some(TestStruct { some_ref: &i }).map(|a| a.trait_foo()); | ^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `TestTrait::trait_foo` error: redundant closure - --> tests/ui/eta.rs:109:42 + --> tests/ui/eta.rs:112:42 | LL | let e = Some(&mut vec![1, 2, 3]).map(|v| v.clear()); | ^^^^^^^^^^^^^ help: replace the closure with the method itself: `std::vec::Vec::clear` error: redundant closure - --> tests/ui/eta.rs:114:29 + --> tests/ui/eta.rs:117:29 | LL | let e = Some("str").map(|s| s.to_string()); | ^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `std::string::ToString::to_string` error: redundant closure - --> tests/ui/eta.rs:116:27 + --> tests/ui/eta.rs:119:27 | LL | let e = Some('a').map(|s| s.to_uppercase()); | ^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `char::to_uppercase` error: redundant closure - --> tests/ui/eta.rs:119:65 + --> tests/ui/eta.rs:122:65 | LL | let e: std::vec::Vec<char> = vec!['a', 'b', 'c'].iter().map(|c| c.to_ascii_uppercase()).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `char::to_ascii_uppercase` error: redundant closure - --> tests/ui/eta.rs:136:23 + --> tests/ui/eta.rs:139:23 | LL | let _ = x.map(|x| x.parse::<i16>()); | ^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `str::parse::<i16>` error: redundant closure - --> tests/ui/eta.rs:189:22 + --> tests/ui/eta.rs:192:22 | LL | requires_fn_once(|| x()); | ^^^^^^ help: replace the closure with the function itself: `x` error: redundant closure - --> tests/ui/eta.rs:197:27 + --> tests/ui/eta.rs:200:27 | LL | let a = Some(1u8).map(|a| foo_ptr(a)); | ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `foo_ptr` error: redundant closure - --> tests/ui/eta.rs:203:27 + --> tests/ui/eta.rs:206:27 | LL | let a = Some(1u8).map(|a| closure(a)); | ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `closure` error: redundant closure - --> tests/ui/eta.rs:236:28 + --> tests/ui/eta.rs:239:28 | LL | x.into_iter().for_each(|x| add_to_res(x)); | ^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut add_to_res` error: redundant closure - --> tests/ui/eta.rs:238:28 + --> tests/ui/eta.rs:241:28 | LL | y.into_iter().for_each(|x| add_to_res(x)); | ^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut add_to_res` error: redundant closure - --> tests/ui/eta.rs:240:28 + --> tests/ui/eta.rs:243:28 | LL | z.into_iter().for_each(|x| add_to_res(x)); | ^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `add_to_res` error: redundant closure - --> tests/ui/eta.rs:248:21 + --> tests/ui/eta.rs:251:21 | LL | Some(1).map(|n| closure(n)); | ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut closure` error: redundant closure - --> tests/ui/eta.rs:253:21 + --> tests/ui/eta.rs:256:21 | LL | Some(1).map(|n| in_loop(n)); | ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `in_loop` error: redundant closure - --> tests/ui/eta.rs:347:18 + --> tests/ui/eta.rs:350:18 | LL | takes_fn_mut(|| f()); | ^^^^^^ help: replace the closure with the function itself: `&mut f` error: redundant closure - --> tests/ui/eta.rs:351:19 + --> tests/ui/eta.rs:354:19 | LL | takes_fn_once(|| f()); | ^^^^^^ help: replace the closure with the function itself: `&mut f` error: redundant closure - --> tests/ui/eta.rs:356:26 + --> tests/ui/eta.rs:359:26 | LL | move || takes_fn_mut(|| f_used_once()) | ^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut f_used_once` error: redundant closure - --> tests/ui/eta.rs:369:19 + --> tests/ui/eta.rs:372:19 | LL | array_opt.map(|a| a.as_slice()); | ^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `<[u8; 3]>::as_slice` error: redundant closure - --> tests/ui/eta.rs:373:19 + --> tests/ui/eta.rs:376:19 | LL | slice_opt.map(|s| s.len()); | ^^^^^^^^^^^ help: replace the closure with the method itself: `<[u8]>::len` error: redundant closure - --> tests/ui/eta.rs:377:17 + --> tests/ui/eta.rs:380:17 | LL | ptr_opt.map(|p| p.is_null()); | ^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `<*const usize>::is_null` error: redundant closure - --> tests/ui/eta.rs:382:17 + --> tests/ui/eta.rs:385:17 | LL | dyn_opt.map(|d| d.method_on_dyn()); | ^^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `<dyn TestTrait>::method_on_dyn` error: redundant closure - --> tests/ui/eta.rs:443:19 + --> tests/ui/eta.rs:446:19 | LL | let _ = f(&0, |x, y| f2(x, y)); | ^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `f2` error: redundant closure - --> tests/ui/eta.rs:472:22 + --> tests/ui/eta.rs:475:22 | LL | test.map(|t| t.method()) | ^^^^^^^^^^^^^^ help: replace the closure with the method itself: `Test::method` error: redundant closure - --> tests/ui/eta.rs:477:22 + --> tests/ui/eta.rs:480:22 | LL | test.map(|t| t.method()) | ^^^^^^^^^^^^^^ help: replace the closure with the method itself: `super::Outer::method` error: redundant closure - --> tests/ui/eta.rs:491:18 + --> tests/ui/eta.rs:494:18 | LL | test.map(|t| t.method()) | ^^^^^^^^^^^^^^ help: replace the closure with the method itself: `test_mod::Test::method` error: redundant closure - --> tests/ui/eta.rs:499:30 + --> tests/ui/eta.rs:502:30 | LL | test.map(|t| t.method()) | ^^^^^^^^^^^^^^ help: replace the closure with the method itself: `crate::issue_10854::d::Test::method` error: redundant closure - --> tests/ui/eta.rs:519:38 + --> tests/ui/eta.rs:522:38 | LL | let x = Box::new(|| None.map(|x| f(x))); | ^^^^^^^^ help: replace the closure with the function itself: `&f` error: redundant closure - --> tests/ui/eta.rs:524:38 + --> tests/ui/eta.rs:527:38 | LL | let x = Box::new(|| None.map(|x| f(x))); | ^^^^^^^^ help: replace the closure with the function itself: `f` error: redundant closure - --> tests/ui/eta.rs:542:35 + --> tests/ui/eta.rs:545:35 | LL | let _field = bind.or_else(|| get_default()).unwrap(); | ^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `get_default` -error: aborting due to 35 previous errors +error: redundant closure + --> tests/ui/eta.rs:588:14 + | +LL | .map(|n| MyError::A(n)) + | ^^^^^^^^^^^^^^^^^ help: replace the closure with the tuple variant itself: `MyError::A` + +error: redundant closure + --> tests/ui/eta.rs:585:14 + | +LL | .map(|n| S(n)) + | ^^^^^^^^ help: replace the closure with the tuple struct itself: `S` + +error: redundant closure + --> tests/ui/eta.rs:582:14 + | +LL | .map(|n| g(n)) + | ^^^^^^^^ help: replace the closure with the function itself: `g` + +error: redundant closure + --> tests/ui/eta.rs:579:14 + | +LL | .map(|n| f(n)) + | ^^^^^^^^ help: replace the closure with the function itself: `f` + +error: aborting due to 39 previous errors diff --git a/src/tools/clippy/tests/ui/from_str_radix_10.fixed b/src/tools/clippy/tests/ui/from_str_radix_10.fixed index 4b8fd778685..47d24167e56 100644 --- a/src/tools/clippy/tests/ui/from_str_radix_10.fixed +++ b/src/tools/clippy/tests/ui/from_str_radix_10.fixed @@ -74,3 +74,13 @@ fn issue_12731() { let _ = u32::from_str_radix("123", 10); } } + +fn fix_str_ref_check() { + #![allow(clippy::needless_borrow)] + let s = "1"; + let _ = s.parse::<u32>().unwrap(); + //~^ from_str_radix_10 + let s_ref = &s; + let _ = s_ref.parse::<u32>().unwrap(); + //~^ from_str_radix_10 +} diff --git a/src/tools/clippy/tests/ui/from_str_radix_10.rs b/src/tools/clippy/tests/ui/from_str_radix_10.rs index 89002b11a99..952e19b57a0 100644 --- a/src/tools/clippy/tests/ui/from_str_radix_10.rs +++ b/src/tools/clippy/tests/ui/from_str_radix_10.rs @@ -74,3 +74,13 @@ fn issue_12731() { let _ = u32::from_str_radix("123", 10); } } + +fn fix_str_ref_check() { + #![allow(clippy::needless_borrow)] + let s = "1"; + let _ = u32::from_str_radix(&s, 10).unwrap(); + //~^ from_str_radix_10 + let s_ref = &s; + let _ = u32::from_str_radix(&s_ref, 10).unwrap(); + //~^ from_str_radix_10 +} diff --git a/src/tools/clippy/tests/ui/from_str_radix_10.stderr b/src/tools/clippy/tests/ui/from_str_radix_10.stderr index c693e8f50ff..d4e6c3657f2 100644 --- a/src/tools/clippy/tests/ui/from_str_radix_10.stderr +++ b/src/tools/clippy/tests/ui/from_str_radix_10.stderr @@ -49,5 +49,17 @@ error: this call to `from_str_radix` can be replaced with a call to `str::parse` LL | i32::from_str_radix(&stringier, 10)?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `stringier.parse::<i32>()` -error: aborting due to 8 previous errors +error: this call to `from_str_radix` can be replaced with a call to `str::parse` + --> tests/ui/from_str_radix_10.rs:81:13 + | +LL | let _ = u32::from_str_radix(&s, 10).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `s.parse::<u32>()` + +error: this call to `from_str_radix` can be replaced with a call to `str::parse` + --> tests/ui/from_str_radix_10.rs:84:13 + | +LL | let _ = u32::from_str_radix(&s_ref, 10).unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `s_ref.parse::<u32>()` + +error: aborting due to 10 previous errors diff --git a/src/tools/clippy/tests/ui/functions_maxlines.rs b/src/tools/clippy/tests/ui/functions_maxlines.rs index e0990dadaaa..b0714552461 100644 --- a/src/tools/clippy/tests/ui/functions_maxlines.rs +++ b/src/tools/clippy/tests/ui/functions_maxlines.rs @@ -1,3 +1,4 @@ +#![allow(clippy::unused_unit, clippy::missing_safety_doc)] #![warn(clippy::too_many_lines)] fn good_lines() { @@ -55,7 +56,8 @@ fn good_lines() { println!("This is good."); } -fn bad_lines() { +#[allow(unused)] // the attr shouldn't get included in the highlight +pub async unsafe extern "Rust" fn bad_lines() -> () { //~^ too_many_lines println!("Dont get confused by braces: {{}}"); @@ -162,4 +164,115 @@ fn bad_lines() { println!("This is bad."); } +struct Foo; +impl Foo { + #[allow(unused)] // the attr shouldn't get included in the highlight + pub async unsafe extern "Rust" fn bad_lines() -> () { + //~^ too_many_lines + + println!("Dont get confused by braces: {{}}"); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + println!("This is bad."); + } +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/functions_maxlines.stderr b/src/tools/clippy/tests/ui/functions_maxlines.stderr index f42a2b2a22a..4c3faf45c47 100644 --- a/src/tools/clippy/tests/ui/functions_maxlines.stderr +++ b/src/tools/clippy/tests/ui/functions_maxlines.stderr @@ -1,17 +1,17 @@ -error: this function has too many lines (102/100) - --> tests/ui/functions_maxlines.rs:58:1 +error: this function has too many lines (104/100) + --> tests/ui/functions_maxlines.rs:60:1 | -LL | / fn bad_lines() { -LL | | -LL | | -LL | | println!("Dont get confused by braces: {{}}"); -... | -LL | | println!("This is bad."); -LL | | } - | |_^ +LL | pub async unsafe extern "Rust" fn bad_lines() -> () { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::too-many-lines` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::too_many_lines)]` -error: aborting due to 1 previous error +error: this function has too many lines (104/100) + --> tests/ui/functions_maxlines.rs:170:5 + | +LL | pub async unsafe extern "Rust" fn bad_lines() -> () { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors diff --git a/src/tools/clippy/tests/ui/infinite_loops.rs b/src/tools/clippy/tests/ui/infinite_loops.rs index fcd1f795fff..9b8c3933197 100644 --- a/src/tools/clippy/tests/ui/infinite_loops.rs +++ b/src/tools/clippy/tests/ui/infinite_loops.rs @@ -450,4 +450,75 @@ mod issue_12338 { } } +#[allow(clippy::let_underscore_future, clippy::empty_loop)] +mod issue_14000 { + use super::do_something; + + async fn foo() { + let _ = async move { + loop { + //~^ infinite_loop + do_something(); + } + } + .await; + let _ = async move { + loop { + //~^ infinite_loop + continue; + } + } + .await; + } + + fn bar() { + let _ = async move { + loop { + do_something(); + } + }; + + let _ = async move { + loop { + continue; + } + }; + } +} + +#[allow(clippy::let_underscore_future)] +mod tokio_spawn_test { + use super::do_something; + + fn install_ticker() { + // This should NOT trigger the lint because the async block is spawned, not awaited + std::thread::spawn(move || { + async move { + loop { + // This loop should not trigger infinite_loop lint + do_something(); + } + } + }); + } + + fn spawn_async_block() { + // This should NOT trigger the lint because the async block is not awaited + let _handle = async move { + loop { + do_something(); + } + }; + } + + fn await_async_block() { + // This SHOULD trigger the lint because the async block is awaited + let _ = async move { + loop { + do_something(); + } + }; + } +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/infinite_loops.stderr b/src/tools/clippy/tests/ui/infinite_loops.stderr index 4d02636ef4a..4c6b6f725f1 100644 --- a/src/tools/clippy/tests/ui/infinite_loops.stderr +++ b/src/tools/clippy/tests/ui/infinite_loops.stderr @@ -311,5 +311,27 @@ help: if this is intentional, consider specifying `!` as function return LL | fn continue_outer() -> ! { | ++++ -error: aborting due to 21 previous errors +error: infinite loop detected + --> tests/ui/infinite_loops.rs:459:13 + | +LL | / loop { +LL | | +LL | | do_something(); +LL | | } + | |_____________^ + | + = help: if this is not intended, try adding a `break` or `return` condition in the loop + +error: infinite loop detected + --> tests/ui/infinite_loops.rs:466:13 + | +LL | / loop { +LL | | +LL | | continue; +LL | | } + | |_____________^ + | + = help: if this is not intended, try adding a `break` or `return` condition in the loop + +error: aborting due to 23 previous errors diff --git a/src/tools/clippy/tests/ui/match_bool.fixed b/src/tools/clippy/tests/ui/match_bool.fixed index 1dfb82db120..876ae935afd 100644 --- a/src/tools/clippy/tests/ui/match_bool.fixed +++ b/src/tools/clippy/tests/ui/match_bool.fixed @@ -61,4 +61,17 @@ fn issue14099() { } } } +fn issue15351() { + let mut d = false; + match d { + false => println!("foo"), + ref mut d => *d = false, + } + + match d { + false => println!("foo"), + e => println!("{e}"), + } +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/match_bool.rs b/src/tools/clippy/tests/ui/match_bool.rs index 719b4e51eb6..a134ad8346e 100644 --- a/src/tools/clippy/tests/ui/match_bool.rs +++ b/src/tools/clippy/tests/ui/match_bool.rs @@ -113,4 +113,17 @@ fn issue14099() { } } +fn issue15351() { + let mut d = false; + match d { + false => println!("foo"), + ref mut d => *d = false, + } + + match d { + false => println!("foo"), + e => println!("{e}"), + } +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/match_ref_pats.fixed b/src/tools/clippy/tests/ui/match_ref_pats.fixed index 8add3da0c99..f727546838b 100644 --- a/src/tools/clippy/tests/ui/match_ref_pats.fixed +++ b/src/tools/clippy/tests/ui/match_ref_pats.fixed @@ -1,6 +1,12 @@ #![warn(clippy::match_ref_pats)] #![allow(dead_code, unused_variables)] -#![allow(clippy::enum_variant_names, clippy::equatable_if_let, clippy::uninlined_format_args)] +#![allow( + clippy::enum_variant_names, + clippy::equatable_if_let, + clippy::uninlined_format_args, + clippy::empty_loop, + clippy::diverging_sub_expression +)] fn ref_pats() { { @@ -120,4 +126,32 @@ mod issue_7740 { } } +mod issue15378 { + fn never_in_match() { + match unimplemented!() { + &_ => {}, + &&&42 => { + todo!() + }, + _ => {}, + } + + match panic!() { + &_ => {}, + &&&42 => { + todo!() + }, + _ => {}, + } + + match loop {} { + &_ => {}, + &&&42 => { + todo!() + }, + _ => {}, + } + } +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/match_ref_pats.rs b/src/tools/clippy/tests/ui/match_ref_pats.rs index 07889b0dfc2..eca4d584acd 100644 --- a/src/tools/clippy/tests/ui/match_ref_pats.rs +++ b/src/tools/clippy/tests/ui/match_ref_pats.rs @@ -1,6 +1,12 @@ #![warn(clippy::match_ref_pats)] #![allow(dead_code, unused_variables)] -#![allow(clippy::enum_variant_names, clippy::equatable_if_let, clippy::uninlined_format_args)] +#![allow( + clippy::enum_variant_names, + clippy::equatable_if_let, + clippy::uninlined_format_args, + clippy::empty_loop, + clippy::diverging_sub_expression +)] fn ref_pats() { { @@ -120,4 +126,32 @@ mod issue_7740 { } } +mod issue15378 { + fn never_in_match() { + match unimplemented!() { + &_ => {}, + &&&42 => { + todo!() + }, + _ => {}, + } + + match panic!() { + &_ => {}, + &&&42 => { + todo!() + }, + _ => {}, + } + + match loop {} { + &_ => {}, + &&&42 => { + todo!() + }, + _ => {}, + } + } +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/match_ref_pats.stderr b/src/tools/clippy/tests/ui/match_ref_pats.stderr index f81b290b32c..ecb08e6972d 100644 --- a/src/tools/clippy/tests/ui/match_ref_pats.stderr +++ b/src/tools/clippy/tests/ui/match_ref_pats.stderr @@ -1,5 +1,5 @@ error: you don't need to add `&` to all patterns - --> tests/ui/match_ref_pats.rs:8:9 + --> tests/ui/match_ref_pats.rs:14:9 | LL | / match v { LL | | @@ -19,7 +19,7 @@ LL ~ None => println!("none"), | error: you don't need to add `&` to both the expression and the patterns - --> tests/ui/match_ref_pats.rs:26:5 + --> tests/ui/match_ref_pats.rs:32:5 | LL | / match &w { LL | | @@ -37,7 +37,7 @@ LL ~ None => println!("none"), | error: redundant pattern matching, consider using `is_none()` - --> tests/ui/match_ref_pats.rs:39:12 + --> tests/ui/match_ref_pats.rs:45:12 | LL | if let &None = a { | -------^^^^^---- help: try: `if a.is_none()` @@ -46,13 +46,13 @@ LL | if let &None = a { = help: to override `-D warnings` add `#[allow(clippy::redundant_pattern_matching)]` error: redundant pattern matching, consider using `is_none()` - --> tests/ui/match_ref_pats.rs:45:12 + --> tests/ui/match_ref_pats.rs:51:12 | LL | if let &None = &b { | -------^^^^^----- help: try: `if b.is_none()` error: you don't need to add `&` to all patterns - --> tests/ui/match_ref_pats.rs:106:9 + --> tests/ui/match_ref_pats.rs:112:9 | LL | / match foobar_variant!(0) { LL | | diff --git a/src/tools/clippy/tests/ui/ptr_as_ptr.fixed b/src/tools/clippy/tests/ui/ptr_as_ptr.fixed index 71fea6144e7..78e1ceb480a 100644 --- a/src/tools/clippy/tests/ui/ptr_as_ptr.fixed +++ b/src/tools/clippy/tests/ui/ptr_as_ptr.fixed @@ -2,8 +2,8 @@ #![warn(clippy::ptr_as_ptr)] -#[macro_use] extern crate proc_macros; +use proc_macros::{external, inline_macros, with_span}; mod issue_11278_a { #[derive(Debug)] @@ -53,11 +53,13 @@ fn main() { //~^ ptr_as_ptr // Make sure the lint is triggered inside a macro - let _ = inline!($ptr.cast::<i32>()); - //~^ ptr_as_ptr + // FIXME: `is_from_proc_macro` incorrectly stops the lint from firing here + let _ = inline!($ptr as *const i32); // Do not lint inside macros from external crates let _ = external!($ptr as *const i32); + + let _ = with_span!(expr $ptr as *const i32); } #[clippy::msrv = "1.37"] diff --git a/src/tools/clippy/tests/ui/ptr_as_ptr.rs b/src/tools/clippy/tests/ui/ptr_as_ptr.rs index 4d507592a1e..70732cf0a6c 100644 --- a/src/tools/clippy/tests/ui/ptr_as_ptr.rs +++ b/src/tools/clippy/tests/ui/ptr_as_ptr.rs @@ -2,8 +2,8 @@ #![warn(clippy::ptr_as_ptr)] -#[macro_use] extern crate proc_macros; +use proc_macros::{external, inline_macros, with_span}; mod issue_11278_a { #[derive(Debug)] @@ -53,11 +53,13 @@ fn main() { //~^ ptr_as_ptr // Make sure the lint is triggered inside a macro + // FIXME: `is_from_proc_macro` incorrectly stops the lint from firing here let _ = inline!($ptr as *const i32); - //~^ ptr_as_ptr // Do not lint inside macros from external crates let _ = external!($ptr as *const i32); + + let _ = with_span!(expr $ptr as *const i32); } #[clippy::msrv = "1.37"] diff --git a/src/tools/clippy/tests/ui/ptr_as_ptr.stderr b/src/tools/clippy/tests/ui/ptr_as_ptr.stderr index adad159bb0f..c0a2a4b6d20 100644 --- a/src/tools/clippy/tests/ui/ptr_as_ptr.stderr +++ b/src/tools/clippy/tests/ui/ptr_as_ptr.stderr @@ -38,174 +38,166 @@ LL | let _: *mut i32 = mut_ptr as _; | ^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `mut_ptr.cast()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:56:21 - | -LL | let _ = inline!($ptr as *const i32); - | ^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `$ptr.cast::<i32>()` - | - = note: this error originates in the macro `__inline_mac_fn_main` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:78:13 + --> tests/ui/ptr_as_ptr.rs:80:13 | LL | let _ = ptr as *const i32; | ^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `ptr.cast::<i32>()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:80:13 + --> tests/ui/ptr_as_ptr.rs:82:13 | LL | let _ = mut_ptr as *mut i32; | ^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `mut_ptr.cast::<i32>()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:88:9 + --> tests/ui/ptr_as_ptr.rs:90:9 | LL | ptr::null_mut() as *mut u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut::<u32>()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:93:9 + --> tests/ui/ptr_as_ptr.rs:95:9 | LL | std::ptr::null_mut() as *mut u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null_mut::<u32>()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:99:9 + --> tests/ui/ptr_as_ptr.rs:101:9 | LL | ptr::null_mut() as *mut u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut::<u32>()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:104:9 + --> tests/ui/ptr_as_ptr.rs:106:9 | LL | core::ptr::null_mut() as *mut u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null_mut::<u32>()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:110:9 + --> tests/ui/ptr_as_ptr.rs:112:9 | LL | ptr::null() as *const u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null::<u32>()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:115:9 + --> tests/ui/ptr_as_ptr.rs:117:9 | LL | std::ptr::null() as *const u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null::<u32>()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:121:9 + --> tests/ui/ptr_as_ptr.rs:123:9 | LL | ptr::null() as *const u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null::<u32>()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:126:9 + --> tests/ui/ptr_as_ptr.rs:128:9 | LL | core::ptr::null() as *const u32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null::<u32>()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:134:9 + --> tests/ui/ptr_as_ptr.rs:136:9 | LL | ptr::null_mut() as *mut _ | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:139:9 + --> tests/ui/ptr_as_ptr.rs:141:9 | LL | std::ptr::null_mut() as *mut _ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null_mut()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:145:9 + --> tests/ui/ptr_as_ptr.rs:147:9 | LL | ptr::null_mut() as *mut _ | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:150:9 + --> tests/ui/ptr_as_ptr.rs:152:9 | LL | core::ptr::null_mut() as *mut _ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null_mut()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:156:9 + --> tests/ui/ptr_as_ptr.rs:158:9 | LL | ptr::null() as *const _ | ^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:161:9 + --> tests/ui/ptr_as_ptr.rs:163:9 | LL | std::ptr::null() as *const _ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:167:9 + --> tests/ui/ptr_as_ptr.rs:169:9 | LL | ptr::null() as *const _ | ^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:172:9 + --> tests/ui/ptr_as_ptr.rs:174:9 | LL | core::ptr::null() as *const _ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:180:9 + --> tests/ui/ptr_as_ptr.rs:182:9 | LL | ptr::null_mut() as _ | ^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:185:9 + --> tests/ui/ptr_as_ptr.rs:187:9 | LL | std::ptr::null_mut() as _ | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null_mut()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:191:9 + --> tests/ui/ptr_as_ptr.rs:193:9 | LL | ptr::null_mut() as _ | ^^^^^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null_mut()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:196:9 + --> tests/ui/ptr_as_ptr.rs:198:9 | LL | core::ptr::null_mut() as _ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null_mut()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:202:9 + --> tests/ui/ptr_as_ptr.rs:204:9 | LL | ptr::null() as _ | ^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:207:9 + --> tests/ui/ptr_as_ptr.rs:209:9 | LL | std::ptr::null() as _ | ^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:213:9 + --> tests/ui/ptr_as_ptr.rs:215:9 | LL | ptr::null() as _ | ^^^^^^^^^^^^^^^^ help: try call directly: `ptr::null()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:218:9 + --> tests/ui/ptr_as_ptr.rs:220:9 | LL | core::ptr::null() as _ | ^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `core::ptr::null()` error: `as` casting between raw pointers without changing their constness - --> tests/ui/ptr_as_ptr.rs:226:43 + --> tests/ui/ptr_as_ptr.rs:228:43 | LL | let _: fn() = std::mem::transmute(std::ptr::null::<()>() as *const u8); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try call directly: `std::ptr::null::<u8>()` -error: aborting due to 34 previous errors +error: aborting due to 33 previous errors diff --git a/src/tools/clippy/tests/ui/similar_names.rs b/src/tools/clippy/tests/ui/similar_names.rs index 69b6ab6220b..55a141209f0 100644 --- a/src/tools/clippy/tests/ui/similar_names.rs +++ b/src/tools/clippy/tests/ui/similar_names.rs @@ -89,6 +89,10 @@ fn main() { let iter: i32; let item: i32; + + // 3 letter names are allowed to be similar + let kta: i32; + let ktv: i32; } fn foo() { diff --git a/src/tools/clippy/tests/ui/similar_names.stderr b/src/tools/clippy/tests/ui/similar_names.stderr index 8d722fb8b56..c226f73d4db 100644 --- a/src/tools/clippy/tests/ui/similar_names.stderr +++ b/src/tools/clippy/tests/ui/similar_names.stderr @@ -49,13 +49,13 @@ LL | let parser: i32; | ^^^^^^ error: binding's name is too similar to existing binding - --> tests/ui/similar_names.rs:98:16 + --> tests/ui/similar_names.rs:102:16 | LL | bpple: sprang, | ^^^^^^ | note: existing binding defined here - --> tests/ui/similar_names.rs:97:16 + --> tests/ui/similar_names.rs:101:16 | LL | apple: spring, | ^^^^^^ diff --git a/src/tools/clippy/tests/ui/unnecessary_operation.fixed b/src/tools/clippy/tests/ui/unnecessary_operation.fixed index ac9fa4de20a..db5409bc491 100644 --- a/src/tools/clippy/tests/ui/unnecessary_operation.fixed +++ b/src/tools/clippy/tests/ui/unnecessary_operation.fixed @@ -78,25 +78,25 @@ fn main() { //~^ unnecessary_operation get_number(); //~^ unnecessary_operation - 5;get_number(); + 5; get_number(); //~^ unnecessary_operation get_number(); //~^ unnecessary_operation get_number(); //~^ unnecessary_operation - 5;6;get_number(); + 5; 6; get_number(); //~^ unnecessary_operation get_number(); //~^ unnecessary_operation get_number(); //~^ unnecessary_operation - 5;get_number(); + 5; get_number(); //~^ unnecessary_operation - 42;get_number(); + 42; get_number(); //~^ unnecessary_operation assert!([42, 55].len() > get_usize()); //~^ unnecessary_operation - 42;get_number(); + 42; get_number(); //~^ unnecessary_operation get_number(); //~^ unnecessary_operation diff --git a/src/tools/clippy/tests/ui/unnecessary_operation.stderr b/src/tools/clippy/tests/ui/unnecessary_operation.stderr index 0fda1dfde19..3439ba2e33e 100644 --- a/src/tools/clippy/tests/ui/unnecessary_operation.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_operation.stderr @@ -35,7 +35,7 @@ error: unnecessary operation --> tests/ui/unnecessary_operation.rs:81:5 | LL | 5 + get_number(); - | ^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `5;get_number();` + | ^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `5; get_number();` error: unnecessary operation --> tests/ui/unnecessary_operation.rs:83:5 @@ -53,7 +53,7 @@ error: unnecessary operation --> tests/ui/unnecessary_operation.rs:87:5 | LL | (5, 6, get_number()); - | ^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `5;6;get_number();` + | ^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `5; 6; get_number();` error: unnecessary operation --> tests/ui/unnecessary_operation.rs:89:5 @@ -71,13 +71,13 @@ error: unnecessary operation --> tests/ui/unnecessary_operation.rs:93:5 | LL | 5..get_number(); - | ^^^^^^^^^^^^^^^^ help: statement can be reduced to: `5;get_number();` + | ^^^^^^^^^^^^^^^^ help: statement can be reduced to: `5; get_number();` error: unnecessary operation --> tests/ui/unnecessary_operation.rs:95:5 | LL | [42, get_number()]; - | ^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `42;get_number();` + | ^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `42; get_number();` error: unnecessary operation --> tests/ui/unnecessary_operation.rs:97:5 @@ -89,7 +89,7 @@ error: unnecessary operation --> tests/ui/unnecessary_operation.rs:99:5 | LL | (42, get_number()).1; - | ^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `42;get_number();` + | ^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `42; get_number();` error: unnecessary operation --> tests/ui/unnecessary_operation.rs:101:5 diff --git a/src/tools/clippy/tests/ui/unnecessary_semicolon.edition2021.fixed b/src/tools/clippy/tests/ui/unnecessary_semicolon.edition2021.fixed index f10d804c8cc..797f1505f49 100644 --- a/src/tools/clippy/tests/ui/unnecessary_semicolon.edition2021.fixed +++ b/src/tools/clippy/tests/ui/unnecessary_semicolon.edition2021.fixed @@ -63,3 +63,12 @@ fn issue14100() -> bool { // cast into the `bool` function return type. if return true {}; } + +fn issue15426(x: u32) { + // removing the `;` would turn the stmt into an expr, but attrs aren't allowed on exprs + #[rustfmt::skip] + match x { + 0b00 => {} 0b01 => {} + 0b11 => {} _ => {} + }; +} diff --git a/src/tools/clippy/tests/ui/unnecessary_semicolon.edition2024.fixed b/src/tools/clippy/tests/ui/unnecessary_semicolon.edition2024.fixed index 32a3bb9b408..d2609cea000 100644 --- a/src/tools/clippy/tests/ui/unnecessary_semicolon.edition2024.fixed +++ b/src/tools/clippy/tests/ui/unnecessary_semicolon.edition2024.fixed @@ -63,3 +63,12 @@ fn issue14100() -> bool { // cast into the `bool` function return type. if return true {}; } + +fn issue15426(x: u32) { + // removing the `;` would turn the stmt into an expr, but attrs aren't allowed on exprs + #[rustfmt::skip] + match x { + 0b00 => {} 0b01 => {} + 0b11 => {} _ => {} + }; +} diff --git a/src/tools/clippy/tests/ui/unnecessary_semicolon.rs b/src/tools/clippy/tests/ui/unnecessary_semicolon.rs index 91b28218022..55f1ec84cb0 100644 --- a/src/tools/clippy/tests/ui/unnecessary_semicolon.rs +++ b/src/tools/clippy/tests/ui/unnecessary_semicolon.rs @@ -63,3 +63,12 @@ fn issue14100() -> bool { // cast into the `bool` function return type. if return true {}; } + +fn issue15426(x: u32) { + // removing the `;` would turn the stmt into an expr, but attrs aren't allowed on exprs + #[rustfmt::skip] + match x { + 0b00 => {} 0b01 => {} + 0b11 => {} _ => {} + }; +} diff --git a/src/tools/clippy/tests/ui/zero_sized_hashmap_values.rs b/src/tools/clippy/tests/ui/zero_sized_hashmap_values.rs index dcbfd16843d..ee2fd19b5ee 100644 --- a/src/tools/clippy/tests/ui/zero_sized_hashmap_values.rs +++ b/src/tools/clippy/tests/ui/zero_sized_hashmap_values.rs @@ -92,6 +92,14 @@ fn issue14822() { //~^ zero_sized_map_values } +fn issue15429() { + struct E<'a>(&'a [E<'a>]); + + // The assertion error happens when the type being evaluated has escaping bound vars + // as it cannot be wrapped in a dummy binder during size computation. + type F = dyn for<'a> FnOnce(HashMap<u32, E<'a>>) -> u32; +} + fn main() { let _: HashMap<String, ()> = HashMap::new(); //~^ zero_sized_map_values diff --git a/src/tools/clippy/tests/ui/zero_sized_hashmap_values.stderr b/src/tools/clippy/tests/ui/zero_sized_hashmap_values.stderr index d29491fa05c..52ffef280c1 100644 --- a/src/tools/clippy/tests/ui/zero_sized_hashmap_values.stderr +++ b/src/tools/clippy/tests/ui/zero_sized_hashmap_values.stderr @@ -89,7 +89,7 @@ LL | type D = HashMap<u32, S<E>>; = help: consider using a set instead error: map with zero-sized value type - --> tests/ui/zero_sized_hashmap_values.rs:96:34 + --> tests/ui/zero_sized_hashmap_values.rs:104:34 | LL | let _: HashMap<String, ()> = HashMap::new(); | ^^^^^^^ @@ -97,7 +97,7 @@ LL | let _: HashMap<String, ()> = HashMap::new(); = help: consider using a set instead error: map with zero-sized value type - --> tests/ui/zero_sized_hashmap_values.rs:96:12 + --> tests/ui/zero_sized_hashmap_values.rs:104:12 | LL | let _: HashMap<String, ()> = HashMap::new(); | ^^^^^^^^^^^^^^^^^^^ @@ -105,7 +105,7 @@ LL | let _: HashMap<String, ()> = HashMap::new(); = help: consider using a set instead error: map with zero-sized value type - --> tests/ui/zero_sized_hashmap_values.rs:102:12 + --> tests/ui/zero_sized_hashmap_values.rs:110:12 | LL | let _: HashMap<_, _> = std::iter::empty::<(String, ())>().collect(); | ^^^^^^^^^^^^^ diff --git a/src/tools/compiletest/src/directives/directive_names.rs b/src/tools/compiletest/src/directives/directive_names.rs index f7955429d83..59690ff2602 100644 --- a/src/tools/compiletest/src/directives/directive_names.rs +++ b/src/tools/compiletest/src/directives/directive_names.rs @@ -194,6 +194,7 @@ pub(crate) const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "only-bpf", "only-cdb", "only-dist", + "only-eabihf", "only-elf", "only-emscripten", "only-gnu", diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index 52c4bd142c6..0b2ce900414 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -16,6 +16,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; #[allow(unused)] use rustc_data_structures::static_assert_size; use rustc_hir::attrs::InlineAttr; +use rustc_middle::middle::codegen_fn_attrs::TargetFeatureKind; use rustc_middle::mir; use rustc_middle::query::TyCtxtAt; use rustc_middle::ty::layout::{ @@ -1076,7 +1077,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { .target_features .iter() .filter(|&feature| { - !feature.implied && !ecx.tcx.sess.target_features.contains(&feature.name) + feature.kind != TargetFeatureKind::Implied && !ecx.tcx.sess.target_features.contains(&feature.name) }) .fold(String::new(), |mut s, feature| { if !s.is_empty() { diff --git a/src/tools/miri/tests/panic/oob_subslice.stderr b/src/tools/miri/tests/panic/oob_subslice.stderr index f8270f4ad4d..e1e5bd33d31 100644 --- a/src/tools/miri/tests/panic/oob_subslice.stderr +++ b/src/tools/miri/tests/panic/oob_subslice.stderr @@ -1,5 +1,5 @@ thread 'main' ($TID) panicked at tests/panic/oob_subslice.rs:LL:CC: -range end index 5 out of range for slice of length 4 +range end index 4 out of range for slice of length 4 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace note: in Miri, you may have to set `MIRIFLAGS=-Zmiri-env-forward=RUST_BACKTRACE` for the environment variable to have an effect diff --git a/src/tools/opt-dist/src/exec.rs b/src/tools/opt-dist/src/exec.rs index a8d4c93d160..a3935f98359 100644 --- a/src/tools/opt-dist/src/exec.rs +++ b/src/tools/opt-dist/src/exec.rs @@ -189,6 +189,12 @@ impl Bootstrap { self } + /// Rebuild rustc in case of statically linked LLVM + pub fn rustc_rebuild(mut self) -> Self { + self.cmd = self.cmd.arg("--keep-stage").arg("0"); + self + } + pub fn run(self, timer: &mut TimerSection) -> anyhow::Result<()> { self.cmd.run()?; let metrics = load_metrics(&self.metrics_path)?; diff --git a/src/tools/opt-dist/src/main.rs b/src/tools/opt-dist/src/main.rs index 19706b4a4f0..339c25552ad 100644 --- a/src/tools/opt-dist/src/main.rs +++ b/src/tools/opt-dist/src/main.rs @@ -375,8 +375,14 @@ fn execute_pipeline( let mut dist = Bootstrap::dist(env, &dist_args) .llvm_pgo_optimize(llvm_pgo_profile.as_ref()) - .rustc_pgo_optimize(&rustc_pgo_profile) - .avoid_rustc_rebuild(); + .rustc_pgo_optimize(&rustc_pgo_profile); + + // if LLVM is not built we'll have PGO optimized rustc + dist = if env.supports_shared_llvm() || !env.build_llvm() { + dist.avoid_rustc_rebuild() + } else { + dist.rustc_rebuild() + }; for bolt_profile in bolt_profiles { dist = dist.with_bolt_profile(bolt_profile); diff --git a/src/tools/rustbook/Cargo.lock b/src/tools/rustbook/Cargo.lock index e42f266391e..cd7ee6fb4fe 100644 --- a/src/tools/rustbook/Cargo.lock +++ b/src/tools/rustbook/Cargo.lock @@ -97,9 +97,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.98" +version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" +checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100" [[package]] name = "autocfg" @@ -124,9 +124,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.9.1" +version = "2.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" +checksum = "6a65b545ab31d687cff52899d4890855fec459eb6afe0da6417b8a18da87aa29" [[package]] name = "block-buffer" @@ -156,9 +156,9 @@ checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" [[package]] name = "cc" -version = "1.2.32" +version = "1.2.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2352e5597e9c544d5e6d9c95190d5d27738ade584fa8db0a16e130e5c2b5296e" +checksum = "3ee0f8803222ba5a7e2777dd72ca451868909b1ac410621b676adf07280e9b5f" dependencies = [ "shlex", ] @@ -185,9 +185,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.43" +version = "4.5.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50fd97c9dc2399518aa331917ac6f274280ec5eb34e555dd291899745c48ec6f" +checksum = "1fc0e74a703892159f5ae7d3aac52c8e6c392f5ae5f359c70b5881d60aaac318" dependencies = [ "clap_builder", "clap_derive", @@ -195,9 +195,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.43" +version = "4.5.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c35b5830294e1fa0462034af85cc95225a4cb07092c088c55bda3147cfcd8f65" +checksum = "b3e7f4214277f3c7aa526a59dd3fbe306a370daee1f8b7b8c987069cd8e888a8" dependencies = [ "anstream", "anstyle", @@ -208,18 +208,18 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.5.56" +version = "4.5.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67e4efcbb5da11a92e8a609233aa1e8a7d91e38de0be865f016d14700d45a7fd" +checksum = "4d9501bd3f5f09f7bbee01da9a511073ed30a80cd7a509f1214bb74eadea71ad" dependencies = [ "clap", ] [[package]] name = "clap_derive" -version = "4.5.41" +version = "4.5.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef4f52386a59ca4c860f7393bcf8abd8dfd91ecccc0f774635ff68e92eeef491" +checksum = "14cb31bb0a7d536caef2639baa7fad459e15c3144efefa6dbd1c84562c4739f6" dependencies = [ "heck", "proc-macro2", @@ -559,7 +559,7 @@ dependencies = [ "pest_derive", "serde", "serde_json", - "thiserror 2.0.12", + "thiserror 2.0.15", ] [[package]] @@ -1035,7 +1035,7 @@ version = "6.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "336b9c63443aceef14bea841b899035ae3abe89b7c486aaf4c5bd8aafedac3f0" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.2", "libc", "once_cell", "onig_sys", @@ -1104,7 +1104,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1db05f56d34358a8b1066f67cbb203ee3e7ed2ba674a6263a1d5ec6db2204323" dependencies = [ "memchr", - "thiserror 2.0.12", + "thiserror 2.0.15", "ucd-trie", ] @@ -1240,9 +1240,9 @@ checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" [[package]] name = "proc-macro2" -version = "1.0.95" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" dependencies = [ "unicode-ident", ] @@ -1253,7 +1253,7 @@ version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76979bea66e7875e7509c4ec5300112b316af87fa7a252ca91c448b32dfe3993" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.2", "memchr", "pulldown-cmark-escape 0.10.1", "unicase", @@ -1265,7 +1265,7 @@ version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f86ba2052aebccc42cbbb3ed234b8b13ce76f75c3551a303cb2bcffcff12bb14" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.2", "getopts", "memchr", "pulldown-cmark-escape 0.11.0", @@ -1347,7 +1347,7 @@ version = "0.5.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.2", ] [[package]] @@ -1385,6 +1385,7 @@ version = "0.1.0" dependencies = [ "clap", "env_logger", + "libc", "mdbook", "mdbook-i18n-helpers", "mdbook-spec", @@ -1397,7 +1398,7 @@ version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "11181fbabf243db407ef8df94a6ce0b2f9a733bd8be4ad02b4eda9602296cac8" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.2", "errno", "libc", "linux-raw-sys", @@ -1546,9 +1547,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" -version = "2.0.104" +version = "2.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" dependencies = [ "proc-macro2", "quote", @@ -1612,12 +1613,12 @@ dependencies = [ [[package]] name = "terminal_size" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45c6481c4829e4cc63825e62c49186a34538b7b2750b73b266581ffb612fb5ed" +checksum = "60b8cb979cb11c32ce1603f8137b22262a9d131aaa5c37b5678025f22b8becd0" dependencies = [ "rustix", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -1637,11 +1638,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.12" +version = "2.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +checksum = "80d76d3f064b981389ecb4b6b7f45a0bf9fdac1d5b9204c7bd6714fecc302850" dependencies = [ - "thiserror-impl 2.0.12", + "thiserror-impl 2.0.15", ] [[package]] @@ -1657,9 +1658,9 @@ dependencies = [ [[package]] name = "thiserror-impl" -version = "2.0.12" +version = "2.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" +checksum = "44d29feb33e986b6ea906bd9c3559a856983f92371b3eaa5e83782a351623de0" dependencies = [ "proc-macro2", "quote", @@ -2116,7 +2117,7 @@ version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.9.2", ] [[package]] diff --git a/src/tools/rustbook/Cargo.toml b/src/tools/rustbook/Cargo.toml index c7c6e39f157..b34c39c225d 100644 --- a/src/tools/rustbook/Cargo.toml +++ b/src/tools/rustbook/Cargo.toml @@ -10,6 +10,9 @@ edition = "2021" [dependencies] clap = "4.0.32" env_logger = "0.11" +# FIXME: Remove this pin once this rustix issue is resolved +# https://github.com/bytecodealliance/rustix/issues/1496 +libc = "=0.2.174" mdbook-trpl = { path = "../../doc/book/packages/mdbook-trpl" } mdbook-i18n-helpers = "0.3.3" mdbook-spec = { path = "../../doc/reference/mdbook-spec" } diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 858b058cb7d..80b6d54ce1c 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -592,6 +592,8 @@ pub fn check(root: &Path, cargo: &Path, bless: bool, bad: &mut bool) { if workspace == "library" { check_runtime_license_exceptions(&metadata, bad); + check_runtime_no_duplicate_dependencies(&metadata, bad); + check_runtime_no_proc_macros(&metadata, bad); checked_runtime_licenses = true; } } @@ -790,6 +792,37 @@ fn check_license_exceptions( } } +fn check_runtime_no_duplicate_dependencies(metadata: &Metadata, bad: &mut bool) { + let mut seen_pkgs = HashSet::new(); + for pkg in &metadata.packages { + if pkg.source.is_none() { + continue; + } + + if !seen_pkgs.insert(&*pkg.name) { + tidy_error!( + bad, + "duplicate package `{}` is not allowed for the standard library", + pkg.name + ); + } + } +} + +fn check_runtime_no_proc_macros(metadata: &Metadata, bad: &mut bool) { + for pkg in &metadata.packages { + if pkg.targets.iter().any(|target| target.is_proc_macro()) { + tidy_error!( + bad, + "proc macro `{}` is not allowed as standard library dependency.\n\ + Using proc macros in the standard library would break cross-compilation \ + as proc-macros don't get shipped for the host tuple.", + pkg.name + ); + } + } +} + /// Checks the dependency of `restricted_dependency_crates` at the given path. Changes `bad` to /// `true` if a check failed. /// diff --git a/tests/assembly-llvm/asm/mips-types.rs b/tests/assembly-llvm/asm/mips-types.rs index 00e8ce0b874..1dd345ff8fe 100644 --- a/tests/assembly-llvm/asm/mips-types.rs +++ b/tests/assembly-llvm/asm/mips-types.rs @@ -94,7 +94,6 @@ check!(reg_f32, f32, freg, "mov.s"); // CHECK: #APP // CHECK: mov.s $f0, $f0 // CHECK: #NO_APP -#[no_mangle] check_reg!(f0_f32, f32, "$f0", "mov.s"); // CHECK-LABEL: reg_f32_64: @@ -107,21 +106,18 @@ check!(reg_f32_64, f32, freg, "mov.d"); // CHECK: #APP // CHECK: mov.d $f0, $f0 // CHECK: #NO_APP -#[no_mangle] check_reg!(f0_f32_64, f32, "$f0", "mov.d"); // CHECK-LABEL: reg_f64: // CHECK: #APP // CHECK: mov.d $f{{[0-9]+}}, $f{{[0-9]+}} // CHECK: #NO_APP -#[no_mangle] check!(reg_f64, f64, freg, "mov.d"); // CHECK-LABEL: f0_f64: // CHECK: #APP // CHECK: mov.d $f0, $f0 // CHECK: #NO_APP -#[no_mangle] check_reg!(f0_f64, f64, "$f0", "mov.d"); // CHECK-LABEL: reg_ptr: diff --git a/tests/assembly-llvm/force-target-feature.rs b/tests/assembly-llvm/force-target-feature.rs new file mode 100644 index 00000000000..c11060d8d6d --- /dev/null +++ b/tests/assembly-llvm/force-target-feature.rs @@ -0,0 +1,33 @@ +//@ only-x86_64 +//@ assembly-output: emit-asm +//@ compile-flags: -C opt-level=3 -C target-feature=-avx2 +//@ ignore-sgx Tests incompatible with LVI mitigations + +#![feature(effective_target_features)] + +use std::arch::x86_64::{__m256i, _mm256_add_epi32, _mm256_setzero_si256}; +use std::ops::Add; + +#[derive(Clone, Copy)] +struct AvxU32(__m256i); + +impl Add<AvxU32> for AvxU32 { + type Output = Self; + + #[no_mangle] + #[inline(never)] + #[unsafe(force_target_feature(enable = "avx2"))] + fn add(self, oth: AvxU32) -> AvxU32 { + // CHECK-LABEL: add: + // CHECK-NOT: callq + // CHECK: vpaddd + // CHECK: retq + Self(_mm256_add_epi32(self.0, oth.0)) + } +} + +fn main() { + assert!(is_x86_feature_detected!("avx2")); + let v = AvxU32(unsafe { _mm256_setzero_si256() }); + v + v; +} diff --git a/tests/assembly-llvm/s390x-vector-abi.rs b/tests/assembly-llvm/s390x-vector-abi.rs index fcf42664034..c9c3266a18f 100644 --- a/tests/assembly-llvm/s390x-vector-abi.rs +++ b/tests/assembly-llvm/s390x-vector-abi.rs @@ -1,4 +1,5 @@ //@ revisions: z10 z10_vector z13 z13_no_vector +//@ add-core-stubs // ignore-tidy-linelength //@ assembly-output: emit-asm //@ compile-flags: -Copt-level=3 -Z merge-functions=disabled @@ -18,24 +19,8 @@ // Cases where vector feature is disabled are rejected. // See tests/ui/simd-abi-checks-s390x.rs for test for them. -#[lang = "pointee_sized"] -pub trait PointeeSized {} - -#[lang = "meta_sized"] -pub trait MetaSized: PointeeSized {} - -#[lang = "sized"] -pub trait Sized: MetaSized {} -#[lang = "copy"] -pub trait Copy {} -#[lang = "freeze"] -pub trait Freeze {} - -impl<T: Copy, const N: usize> Copy for [T; N] {} - -#[lang = "phantom_data"] -pub struct PhantomData<T: ?Sized>; -impl<T: ?Sized> Copy for PhantomData<T> {} +extern crate minicore; +use minicore::*; #[repr(simd)] pub struct i8x8([i8; 8]); @@ -52,8 +37,6 @@ pub struct WrapperWithZst<T>(T, PhantomData<()>); #[repr(transparent)] pub struct TransparentWrapper<T>(T); -impl Copy for i8 {} -impl Copy for i64 {} impl Copy for i8x8 {} impl Copy for i8x16 {} impl Copy for i8x32 {} @@ -221,7 +204,7 @@ unsafe extern "C" fn vector_transparent_wrapper_ret_large( #[cfg_attr(no_vector, target_feature(enable = "vector"))] #[no_mangle] unsafe extern "C" fn vector_arg_small(x: i8x8) -> i64 { - unsafe { *(&x as *const i8x8 as *const i64) } + unsafe { *(&raw const x as *const i64) } } // CHECK-LABEL: vector_arg: // CHECK: vlgvg %r2, %v24, 0 @@ -229,7 +212,7 @@ unsafe extern "C" fn vector_arg_small(x: i8x8) -> i64 { #[cfg_attr(no_vector, target_feature(enable = "vector"))] #[no_mangle] unsafe extern "C" fn vector_arg(x: i8x16) -> i64 { - unsafe { *(&x as *const i8x16 as *const i64) } + unsafe { *(&raw const x as *const i64) } } // CHECK-LABEL: vector_arg_large: // CHECK: lg %r2, 0(%r2) @@ -237,7 +220,7 @@ unsafe extern "C" fn vector_arg(x: i8x16) -> i64 { #[cfg_attr(no_vector, target_feature(enable = "vector"))] #[no_mangle] unsafe extern "C" fn vector_arg_large(x: i8x32) -> i64 { - unsafe { *(&x as *const i8x32 as *const i64) } + unsafe { *(&raw const x as *const i64) } } // CHECK-LABEL: vector_wrapper_arg_small: @@ -246,7 +229,7 @@ unsafe extern "C" fn vector_arg_large(x: i8x32) -> i64 { #[cfg_attr(no_vector, target_feature(enable = "vector"))] #[no_mangle] unsafe extern "C" fn vector_wrapper_arg_small(x: Wrapper<i8x8>) -> i64 { - unsafe { *(&x as *const Wrapper<i8x8> as *const i64) } + unsafe { *(&raw const x as *const i64) } } // CHECK-LABEL: vector_wrapper_arg: // CHECK: vlgvg %r2, %v24, 0 @@ -254,7 +237,7 @@ unsafe extern "C" fn vector_wrapper_arg_small(x: Wrapper<i8x8>) -> i64 { #[cfg_attr(no_vector, target_feature(enable = "vector"))] #[no_mangle] unsafe extern "C" fn vector_wrapper_arg(x: Wrapper<i8x16>) -> i64 { - unsafe { *(&x as *const Wrapper<i8x16> as *const i64) } + unsafe { *(&raw const x as *const i64) } } // CHECK-LABEL: vector_wrapper_arg_large: // CHECK: lg %r2, 0(%r2) @@ -262,7 +245,7 @@ unsafe extern "C" fn vector_wrapper_arg(x: Wrapper<i8x16>) -> i64 { #[cfg_attr(no_vector, target_feature(enable = "vector"))] #[no_mangle] unsafe extern "C" fn vector_wrapper_arg_large(x: Wrapper<i8x32>) -> i64 { - unsafe { *(&x as *const Wrapper<i8x32> as *const i64) } + unsafe { *(&raw const x as *const i64) } } // https://github.com/rust-lang/rust/pull/131586#discussion_r1837071121 @@ -272,7 +255,7 @@ unsafe extern "C" fn vector_wrapper_arg_large(x: Wrapper<i8x32>) -> i64 { #[cfg_attr(no_vector, target_feature(enable = "vector"))] #[no_mangle] unsafe extern "C" fn vector_wrapper_padding_arg(x: WrapperAlign16<i8x8>) -> i64 { - unsafe { *(&x as *const WrapperAlign16<i8x8> as *const i64) } + unsafe { *(&raw const x as *const i64) } } // CHECK-LABEL: vector_wrapper_with_zst_arg_small: @@ -282,7 +265,7 @@ unsafe extern "C" fn vector_wrapper_padding_arg(x: WrapperAlign16<i8x8>) -> i64 #[cfg_attr(no_vector, target_feature(enable = "vector"))] #[no_mangle] unsafe extern "C" fn vector_wrapper_with_zst_arg_small(x: WrapperWithZst<i8x8>) -> i64 { - unsafe { *(&x as *const WrapperWithZst<i8x8> as *const i64) } + unsafe { *(&raw const x as *const i64) } } // CHECK-LABEL: vector_wrapper_with_zst_arg: // CHECK: lg %r2, 0(%r2) @@ -290,7 +273,7 @@ unsafe extern "C" fn vector_wrapper_with_zst_arg_small(x: WrapperWithZst<i8x8>) #[cfg_attr(no_vector, target_feature(enable = "vector"))] #[no_mangle] unsafe extern "C" fn vector_wrapper_with_zst_arg(x: WrapperWithZst<i8x16>) -> i64 { - unsafe { *(&x as *const WrapperWithZst<i8x16> as *const i64) } + unsafe { *(&raw const x as *const i64) } } // CHECK-LABEL: vector_wrapper_with_zst_arg_large: // CHECK: lg %r2, 0(%r2) @@ -298,7 +281,7 @@ unsafe extern "C" fn vector_wrapper_with_zst_arg(x: WrapperWithZst<i8x16>) -> i6 #[cfg_attr(no_vector, target_feature(enable = "vector"))] #[no_mangle] unsafe extern "C" fn vector_wrapper_with_zst_arg_large(x: WrapperWithZst<i8x32>) -> i64 { - unsafe { *(&x as *const WrapperWithZst<i8x32> as *const i64) } + unsafe { *(&raw const x as *const i64) } } // CHECK-LABEL: vector_transparent_wrapper_arg_small: @@ -307,7 +290,7 @@ unsafe extern "C" fn vector_wrapper_with_zst_arg_large(x: WrapperWithZst<i8x32>) #[cfg_attr(no_vector, target_feature(enable = "vector"))] #[no_mangle] unsafe extern "C" fn vector_transparent_wrapper_arg_small(x: TransparentWrapper<i8x8>) -> i64 { - unsafe { *(&x as *const TransparentWrapper<i8x8> as *const i64) } + unsafe { *(&raw const x as *const i64) } } // CHECK-LABEL: vector_transparent_wrapper_arg: // CHECK: vlgvg %r2, %v24, 0 @@ -315,7 +298,7 @@ unsafe extern "C" fn vector_transparent_wrapper_arg_small(x: TransparentWrapper< #[cfg_attr(no_vector, target_feature(enable = "vector"))] #[no_mangle] unsafe extern "C" fn vector_transparent_wrapper_arg(x: TransparentWrapper<i8x16>) -> i64 { - unsafe { *(&x as *const TransparentWrapper<i8x16> as *const i64) } + unsafe { *(&raw const x as *const i64) } } // CHECK-LABEL: vector_transparent_wrapper_arg_large: // CHECK: lg %r2, 0(%r2) @@ -323,5 +306,5 @@ unsafe extern "C" fn vector_transparent_wrapper_arg(x: TransparentWrapper<i8x16> #[cfg_attr(no_vector, target_feature(enable = "vector"))] #[no_mangle] unsafe extern "C" fn vector_transparent_wrapper_arg_large(x: TransparentWrapper<i8x32>) -> i64 { - unsafe { *(&x as *const TransparentWrapper<i8x32> as *const i64) } + unsafe { *(&raw const x as *const i64) } } diff --git a/tests/assembly-llvm/targets/targets-elf.rs b/tests/assembly-llvm/targets/targets-elf.rs index a1d759ede2b..79347d0bbf6 100644 --- a/tests/assembly-llvm/targets/targets-elf.rs +++ b/tests/assembly-llvm/targets/targets-elf.rs @@ -1,6 +1,9 @@ //@ add-core-stubs //@ assembly-output: emit-asm // ignore-tidy-linelength +//@ revisions: aarch64_be_unknown_hermit +//@ [aarch64_be_unknown_hermit] compile-flags: --target aarch64_be-unknown-hermit +//@ [aarch64_be_unknown_hermit] needs-llvm-components: aarch64 //@ revisions: aarch64_be_unknown_linux_gnu //@ [aarch64_be_unknown_linux_gnu] compile-flags: --target aarch64_be-unknown-linux-gnu //@ [aarch64_be_unknown_linux_gnu] needs-llvm-components: aarch64 diff --git a/tests/codegen-llvm/binary-search-index-no-bound-check.rs b/tests/codegen-llvm/binary-search-index-no-bound-check.rs index d59c0beec64..8322c4179bd 100644 --- a/tests/codegen-llvm/binary-search-index-no-bound-check.rs +++ b/tests/codegen-llvm/binary-search-index-no-bound-check.rs @@ -8,8 +8,7 @@ #[no_mangle] pub fn binary_search_index_no_bounds_check(s: &[u8]) -> u8 { // CHECK-NOT: panic - // CHECK-NOT: slice_start_index_len_fail - // CHECK-NOT: slice_end_index_len_fail + // CHECK-NOT: slice_index_fail // CHECK-NOT: panic_bounds_check if let Ok(idx) = s.binary_search(&b'\\') { s[idx] } else { 42 } } diff --git a/tests/codegen-llvm/integer-overflow.rs b/tests/codegen-llvm/integer-overflow.rs index 80362247a86..df7845be06d 100644 --- a/tests/codegen-llvm/integer-overflow.rs +++ b/tests/codegen-llvm/integer-overflow.rs @@ -10,7 +10,7 @@ pub struct S1<'a> { // CHECK-LABEL: @slice_no_index_order #[no_mangle] pub fn slice_no_index_order<'a>(s: &'a mut S1, n: usize) -> &'a [u8] { - // CHECK-NOT: slice_index_order_fail + // CHECK-COUNT-1: slice_index_fail let d = &s.data[s.position..s.position + n]; s.position += n; return d; @@ -19,6 +19,6 @@ pub fn slice_no_index_order<'a>(s: &'a mut S1, n: usize) -> &'a [u8] { // CHECK-LABEL: @test_check #[no_mangle] pub fn test_check<'a>(s: &'a mut S1, x: usize, y: usize) -> &'a [u8] { - // CHECK: slice_index_order_fail + // CHECK-COUNT-1: slice_index_fail &s.data[x..y] } diff --git a/tests/codegen-llvm/issues/and-masked-comparison-131162.rs b/tests/codegen-llvm/issues/and-masked-comparison-131162.rs new file mode 100644 index 00000000000..bdf021092fd --- /dev/null +++ b/tests/codegen-llvm/issues/and-masked-comparison-131162.rs @@ -0,0 +1,17 @@ +//@ compile-flags: -Copt-level=3 +//@ min-llvm-version: 20 + +#![crate_type = "lib"] + +// CHECK-LABEL: @issue_131162 +#[no_mangle] +pub fn issue_131162(a1: usize, a2: usize) -> bool { + const MASK: usize = 1; + + // CHECK-NOT: xor + // CHECK-NOT: trunc + // CHECK-NOT: and i1 + // CHECK: icmp + // CHECK-NEXT: ret + (a1 & !MASK) == (a2 & !MASK) && (a1 & MASK) == (a2 & MASK) +} diff --git a/tests/codegen-llvm/issues/assert-for-loop-bounds-check-71997.rs b/tests/codegen-llvm/issues/assert-for-loop-bounds-check-71997.rs new file mode 100644 index 00000000000..a0c64d607a8 --- /dev/null +++ b/tests/codegen-llvm/issues/assert-for-loop-bounds-check-71997.rs @@ -0,0 +1,18 @@ +// Tests that there's no bounds check within for-loop after asserting that +// the range start and end are within bounds. + +//@ compile-flags: -Copt-level=3 + +#![crate_type = "lib"] + +// CHECK-LABEL: @no_bounds_check_after_assert +#[no_mangle] +fn no_bounds_check_after_assert(slice: &[u64], start: usize, end: usize) -> u64 { + // CHECK-NOT: panic_bounds_check + let mut total = 0; + assert!(start < end && start < slice.len() && end <= slice.len()); + for i in start..end { + total += slice[i]; + } + total +} diff --git a/tests/codegen-llvm/issues/elided-division-by-zero-check-74917.rs b/tests/codegen-llvm/issues/elided-division-by-zero-check-74917.rs new file mode 100644 index 00000000000..9e890e14852 --- /dev/null +++ b/tests/codegen-llvm/issues/elided-division-by-zero-check-74917.rs @@ -0,0 +1,13 @@ +// Tests that there is no check for dividing by zero since the +// denominator, `(x - y)`, will always be greater than 0 since `x > y`. + +//@ compile-flags: -Copt-level=3 + +#![crate_type = "lib"] + +// CHECK-LABEL: @issue_74917 +#[no_mangle] +pub fn issue_74917(x: u16, y: u16) -> u16 { + // CHECK-NOT: panic + if x > y { 100 / (x - y) } else { 100 } +} diff --git a/tests/codegen-llvm/issues/for-loop-inner-assert-91109.rs b/tests/codegen-llvm/issues/for-loop-inner-assert-91109.rs new file mode 100644 index 00000000000..bffbcd7d069 --- /dev/null +++ b/tests/codegen-llvm/issues/for-loop-inner-assert-91109.rs @@ -0,0 +1,18 @@ +// Tests that there's no bounds check for the inner loop after the assert. + +//@ compile-flags: -Copt-level=3 + +#![crate_type = "lib"] + +// CHECK-LABEL: @zero +#[no_mangle] +pub fn zero(d: &mut [Vec<i32>]) { + // CHECK-NOT: panic_bounds_check + let n = d.len(); + for i in 0..n { + assert!(d[i].len() == n); + for j in 0..n { + d[i][j] = 0; + } + } +} diff --git a/tests/codegen-llvm/issues/issue-113757-bounds-check-after-cmp-max.rs b/tests/codegen-llvm/issues/issue-113757-bounds-check-after-cmp-max.rs index d495adf9980..0db8a5220ec 100644 --- a/tests/codegen-llvm/issues/issue-113757-bounds-check-after-cmp-max.rs +++ b/tests/codegen-llvm/issues/issue-113757-bounds-check-after-cmp-max.rs @@ -5,7 +5,7 @@ use std::cmp::max; // CHECK-LABEL: @foo -// CHECK-NOT: slice_start_index_len_fail +// CHECK-NOT: slice_index_fail // CHECK-NOT: unreachable #[no_mangle] pub fn foo(v: &mut Vec<u8>, size: usize) -> Option<&mut [u8]> { diff --git a/tests/codegen-llvm/issues/issue-27130.rs b/tests/codegen-llvm/issues/issue-27130.rs index 594e02af097..3e53c5cffd6 100644 --- a/tests/codegen-llvm/issues/issue-27130.rs +++ b/tests/codegen-llvm/issues/issue-27130.rs @@ -6,7 +6,7 @@ #[no_mangle] pub fn trim_in_place(a: &mut &[u8]) { while a.first() == Some(&42) { - // CHECK-NOT: slice_index_order_fail + // CHECK-NOT: slice_index_fail *a = &a[1..]; } } @@ -15,7 +15,7 @@ pub fn trim_in_place(a: &mut &[u8]) { #[no_mangle] pub fn trim_in_place2(a: &mut &[u8]) { while let Some(&42) = a.first() { - // CHECK-NOT: slice_index_order_fail + // CHECK-COUNT-1: slice_index_fail *a = &a[2..]; } } diff --git a/tests/codegen-llvm/issues/issue-69101-bounds-check.rs b/tests/codegen-llvm/issues/issue-69101-bounds-check.rs index 953b79aa263..f1857a9ce89 100644 --- a/tests/codegen-llvm/issues/issue-69101-bounds-check.rs +++ b/tests/codegen-llvm/issues/issue-69101-bounds-check.rs @@ -10,7 +10,7 @@ // CHECK-LABEL: @already_sliced_no_bounds_check #[no_mangle] pub fn already_sliced_no_bounds_check(a: &[u8], b: &[u8], c: &mut [u8]) { - // CHECK: slice_end_index_len_fail + // CHECK: slice_index_fail // CHECK-NOT: panic_bounds_check let _ = (&a[..2048], &b[..2048], &mut c[..2048]); for i in 0..1024 { @@ -21,7 +21,7 @@ pub fn already_sliced_no_bounds_check(a: &[u8], b: &[u8], c: &mut [u8]) { // CHECK-LABEL: @already_sliced_no_bounds_check_exact #[no_mangle] pub fn already_sliced_no_bounds_check_exact(a: &[u8], b: &[u8], c: &mut [u8]) { - // CHECK: slice_end_index_len_fail + // CHECK: slice_index_fail // CHECK-NOT: panic_bounds_check let _ = (&a[..1024], &b[..1024], &mut c[..1024]); for i in 0..1024 { @@ -33,7 +33,7 @@ pub fn already_sliced_no_bounds_check_exact(a: &[u8], b: &[u8], c: &mut [u8]) { // CHECK-LABEL: @already_sliced_bounds_check #[no_mangle] pub fn already_sliced_bounds_check(a: &[u8], b: &[u8], c: &mut [u8]) { - // CHECK: slice_end_index_len_fail + // CHECK: slice_index_fail // CHECK: panic_bounds_check let _ = (&a[..1023], &b[..2048], &mut c[..2048]); for i in 0..1024 { diff --git a/tests/codegen-llvm/issues/issue-73396-bounds-check-after-position.rs b/tests/codegen-llvm/issues/issue-73396-bounds-check-after-position.rs index 1e2c25babe0..8a2200478aa 100644 --- a/tests/codegen-llvm/issues/issue-73396-bounds-check-after-position.rs +++ b/tests/codegen-llvm/issues/issue-73396-bounds-check-after-position.rs @@ -8,8 +8,7 @@ #[no_mangle] pub fn position_slice_to_no_bounds_check(s: &[u8]) -> &[u8] { // CHECK-NOT: panic - // CHECK-NOT: slice_start_index_len_fail - // CHECK-NOT: slice_end_index_len_fail + // CHECK-NOT: slice_index_fail // CHECK-NOT: panic_bounds_check // CHECK-NOT: unreachable if let Some(idx) = s.iter().position(|b| *b == b'\\') { &s[..idx] } else { s } @@ -19,8 +18,7 @@ pub fn position_slice_to_no_bounds_check(s: &[u8]) -> &[u8] { #[no_mangle] pub fn position_slice_from_no_bounds_check(s: &[u8]) -> &[u8] { // CHECK-NOT: panic - // CHECK-NOT: slice_start_index_len_fail - // CHECK-NOT: slice_end_index_len_fail + // CHECK-NOT: slice_index_fail // CHECK-NOT: panic_bounds_check // CHECK-NOT: unreachable if let Some(idx) = s.iter().position(|b| *b == b'\\') { &s[idx..] } else { s } @@ -30,8 +28,7 @@ pub fn position_slice_from_no_bounds_check(s: &[u8]) -> &[u8] { #[no_mangle] pub fn position_index_no_bounds_check(s: &[u8]) -> u8 { // CHECK-NOT: panic - // CHECK-NOT: slice_start_index_len_fail - // CHECK-NOT: slice_end_index_len_fail + // CHECK-NOT: slice_index_fail // CHECK-NOT: panic_bounds_check // CHECK-NOT: unreachable if let Some(idx) = s.iter().position(|b| *b == b'\\') { s[idx] } else { 42 } @@ -40,8 +37,7 @@ pub fn position_index_no_bounds_check(s: &[u8]) -> u8 { #[no_mangle] pub fn rposition_slice_to_no_bounds_check(s: &[u8]) -> &[u8] { // CHECK-NOT: panic - // CHECK-NOT: slice_start_index_len_fail - // CHECK-NOT: slice_end_index_len_fail + // CHECK-NOT: slice_index_fail // CHECK-NOT: panic_bounds_check // CHECK-NOT: unreachable if let Some(idx) = s.iter().rposition(|b| *b == b'\\') { &s[..idx] } else { s } @@ -51,8 +47,7 @@ pub fn rposition_slice_to_no_bounds_check(s: &[u8]) -> &[u8] { #[no_mangle] pub fn rposition_slice_from_no_bounds_check(s: &[u8]) -> &[u8] { // CHECK-NOT: panic - // CHECK-NOT: slice_start_index_len_fail - // CHECK-NOT: slice_end_index_len_fail + // CHECK-NOT: slice_index_fail // CHECK-NOT: panic_bounds_check // CHECK-NOT: unreachable if let Some(idx) = s.iter().rposition(|b| *b == b'\\') { &s[idx..] } else { s } @@ -62,8 +57,7 @@ pub fn rposition_slice_from_no_bounds_check(s: &[u8]) -> &[u8] { #[no_mangle] pub fn rposition_index_no_bounds_check(s: &[u8]) -> u8 { // CHECK-NOT: panic - // CHECK-NOT: slice_start_index_len_fail - // CHECK-NOT: slice_end_index_len_fail + // CHECK-NOT: slice_index_fail // CHECK-NOT: panic_bounds_check // CHECK-NOT: unreachable if let Some(idx) = s.iter().rposition(|b| *b == b'\\') { s[idx] } else { 42 } diff --git a/tests/codegen-llvm/issues/iter-max-no-unwrap-failed-129583.rs b/tests/codegen-llvm/issues/iter-max-no-unwrap-failed-129583.rs new file mode 100644 index 00000000000..4d3fa4993ef --- /dev/null +++ b/tests/codegen-llvm/issues/iter-max-no-unwrap-failed-129583.rs @@ -0,0 +1,31 @@ +// Tests that `unwrap` is optimized out when the slice has a known length. +// The iterator may unroll for values smaller than a certain threshold so we +// use a larger value to prevent unrolling. + +//@ compile-flags: -Copt-level=3 +//@ min-llvm-version: 20 + +#![crate_type = "lib"] + +// CHECK-LABEL: @infallible_max_not_unrolled +#[no_mangle] +pub fn infallible_max_not_unrolled(x: &[u8; 1024]) -> u8 { + // CHECK-NOT: panic + // CHECK-NOT: unwrap_failed + *x.iter().max().unwrap() +} + +// CHECK-LABEL: @infallible_max_unrolled +#[no_mangle] +pub fn infallible_max_unrolled(x: &[u8; 10]) -> u8 { + // CHECK-NOT: panic + // CHECK-NOT: unwrap_failed + *x.iter().max().unwrap() +} + +// CHECK-LABEL: @may_panic_max +#[no_mangle] +pub fn may_panic_max(x: &[u8]) -> u8 { + // CHECK: unwrap_failed + *x.iter().max().unwrap() +} diff --git a/tests/codegen-llvm/issues/matches-logical-or-141497.rs b/tests/codegen-llvm/issues/matches-logical-or-141497.rs new file mode 100644 index 00000000000..348f62096a5 --- /dev/null +++ b/tests/codegen-llvm/issues/matches-logical-or-141497.rs @@ -0,0 +1,25 @@ +// Tests that `matches!` optimizes the same as +// `f == FrameType::Inter || f == FrameType::Switch`. + +//@ compile-flags: -Copt-level=3 +//@ min-llvm-version: 21 + +#![crate_type = "lib"] + +#[derive(Clone, Copy, PartialEq, Eq)] +pub enum FrameType { + Key = 0, + Inter = 1, + Intra = 2, + Switch = 3, +} + +// CHECK-LABEL: @is_inter_or_switch +#[no_mangle] +pub fn is_inter_or_switch(f: FrameType) -> bool { + // CHECK-NEXT: start: + // CHECK-NEXT: and i8 + // CHECK-NEXT: icmp + // CHECK-NEXT: ret + matches!(f, FrameType::Inter | FrameType::Switch) +} diff --git a/tests/codegen-llvm/issues/no-bounds-check-after-assert-110971.rs b/tests/codegen-llvm/issues/no-bounds-check-after-assert-110971.rs new file mode 100644 index 00000000000..aa4002f176d --- /dev/null +++ b/tests/codegen-llvm/issues/no-bounds-check-after-assert-110971.rs @@ -0,0 +1,14 @@ +// Tests that the slice access for `j` doesn't have a bounds check panic after +// being asserted as less than half of the slice length. + +//@ compile-flags: -Copt-level=3 + +#![crate_type = "lib"] + +// CHECK-LABEL: @check_only_assert_panic +#[no_mangle] +pub fn check_only_assert_panic(arr: &[u32], j: usize) -> u32 { + // CHECK-NOT: panic_bounds_check + assert!(j < arr.len() / 2); + arr[j] +} diff --git a/tests/codegen-llvm/issues/no-panic-for-pop-after-assert-71257.rs b/tests/codegen-llvm/issues/no-panic-for-pop-after-assert-71257.rs new file mode 100644 index 00000000000..68877c28d6c --- /dev/null +++ b/tests/codegen-llvm/issues/no-panic-for-pop-after-assert-71257.rs @@ -0,0 +1,19 @@ +// Tests that the `unwrap` branch is optimized out from the `pop` since the +// length has already been validated. + +//@ compile-flags: -Copt-level=3 + +#![crate_type = "lib"] + +pub enum Foo { + First(usize), + Second(usize), +} + +// CHECK-LABEL: @check_only_one_panic +#[no_mangle] +pub fn check_only_one_panic(v: &mut Vec<Foo>) -> Foo { + // CHECK-COUNT-1: call{{.+}}panic + assert!(v.len() == 1); + v.pop().unwrap() +} diff --git a/tests/codegen-llvm/issues/num-is-digit-to-digit-59352.rs b/tests/codegen-llvm/issues/num-is-digit-to-digit-59352.rs new file mode 100644 index 00000000000..1d23eb2cdf9 --- /dev/null +++ b/tests/codegen-llvm/issues/num-is-digit-to-digit-59352.rs @@ -0,0 +1,14 @@ +// Tests that there's no panic on unwrapping `to_digit` call after checking +// with `is_digit`. + +//@ compile-flags: -Copt-level=3 + +#![crate_type = "lib"] + +// CHECK-LABEL: @num_to_digit_slow +#[no_mangle] +pub fn num_to_digit_slow(num: char) -> u32 { + // CHECK-NOT: br + // CHECK-NOT: panic + if num.is_digit(8) { num.to_digit(8).unwrap() } else { 0 } +} diff --git a/tests/codegen-llvm/issues/slice-index-bounds-check-80075.rs b/tests/codegen-llvm/issues/slice-index-bounds-check-80075.rs new file mode 100644 index 00000000000..ecb5eb787c7 --- /dev/null +++ b/tests/codegen-llvm/issues/slice-index-bounds-check-80075.rs @@ -0,0 +1,13 @@ +// Tests that no bounds check panic is generated for `j` since +// `j <= i < data.len()`. + +//@ compile-flags: -Copt-level=3 + +#![crate_type = "lib"] + +// CHECK-LABEL: @issue_80075 +#[no_mangle] +pub fn issue_80075(data: &[u8], i: usize, j: usize) -> u8 { + // CHECK-NOT: panic_bounds_check + if i < data.len() && j <= i { data[j] } else { 0 } +} diff --git a/tests/codegen-llvm/s390x-simd.rs b/tests/codegen-llvm/s390x-simd.rs index ac39357519e..464c1be11f1 100644 --- a/tests/codegen-llvm/s390x-simd.rs +++ b/tests/codegen-llvm/s390x-simd.rs @@ -6,7 +6,7 @@ #![crate_type = "rlib"] #![feature(no_core, asm_experimental_arch)] -#![feature(s390x_target_feature, simd_ffi, link_llvm_intrinsics, repr_simd)] +#![feature(s390x_target_feature, simd_ffi, intrinsics, repr_simd)] #![no_core] extern crate minicore; @@ -30,16 +30,20 @@ struct f32x4([f32; 4]); #[repr(simd)] struct f64x2([f64; 2]); -#[allow(improper_ctypes)] -extern "C" { - #[link_name = "llvm.smax.v16i8"] - fn vmxb(a: i8x16, b: i8x16) -> i8x16; - #[link_name = "llvm.smax.v8i16"] - fn vmxh(a: i16x8, b: i16x8) -> i16x8; - #[link_name = "llvm.smax.v4i32"] - fn vmxf(a: i32x4, b: i32x4) -> i32x4; - #[link_name = "llvm.smax.v2i64"] - fn vmxg(a: i64x2, b: i64x2) -> i64x2; +impl Copy for i8x16 {} +impl Copy for i16x8 {} +impl Copy for i32x4 {} +impl Copy for i64x2 {} + +#[rustc_intrinsic] +unsafe fn simd_ge<T, U>(x: T, y: T) -> U; + +#[rustc_intrinsic] +unsafe fn simd_select<M, V>(mask: M, a: V, b: V) -> V; + +#[inline(always)] +unsafe fn simd_max<T: Copy>(a: T, b: T) -> T { + simd_select(simd_ge::<T, T>(a, b), a, b) } // CHECK-LABEL: define <16 x i8> @max_i8x16 @@ -48,7 +52,7 @@ extern "C" { #[no_mangle] #[target_feature(enable = "vector")] pub unsafe extern "C" fn max_i8x16(a: i8x16, b: i8x16) -> i8x16 { - vmxb(a, b) + simd_max(a, b) } // CHECK-LABEL: define <8 x i16> @max_i16x8 @@ -57,7 +61,7 @@ pub unsafe extern "C" fn max_i8x16(a: i8x16, b: i8x16) -> i8x16 { #[no_mangle] #[target_feature(enable = "vector")] pub unsafe extern "C" fn max_i16x8(a: i16x8, b: i16x8) -> i16x8 { - vmxh(a, b) + simd_max(a, b) } // CHECK-LABEL: define <4 x i32> @max_i32x4 @@ -66,7 +70,7 @@ pub unsafe extern "C" fn max_i16x8(a: i16x8, b: i16x8) -> i16x8 { #[no_mangle] #[target_feature(enable = "vector")] pub unsafe extern "C" fn max_i32x4(a: i32x4, b: i32x4) -> i32x4 { - vmxf(a, b) + simd_max(a, b) } // CHECK-LABEL: define <2 x i64> @max_i64x2 @@ -75,7 +79,7 @@ pub unsafe extern "C" fn max_i32x4(a: i32x4, b: i32x4) -> i32x4 { #[no_mangle] #[target_feature(enable = "vector")] pub unsafe extern "C" fn max_i64x2(a: i64x2, b: i64x2) -> i64x2 { - vmxg(a, b) + simd_max(a, b) } // CHECK-LABEL: define <4 x float> @choose_f32x4 @@ -108,7 +112,7 @@ pub unsafe extern "C" fn max_wrapper_i8x16(a: Wrapper<i8x16>, b: Wrapper<i8x16>) // CHECK: call <16 x i8> @llvm.smax.v16i8 // CHECK-SAME: <16 x i8> // CHECK-SAME: <16 x i8> - Wrapper(vmxb(a.0, b.0)) + Wrapper(simd_max(a.0, b.0)) } #[no_mangle] @@ -122,7 +126,7 @@ pub unsafe extern "C" fn max_wrapper_i64x2(a: Wrapper<i64x2>, b: Wrapper<i64x2>) // CHECK: call <2 x i64> @llvm.smax.v2i64 // CHECK-SAME: <2 x i64> // CHECK-SAME: <2 x i64> - Wrapper(vmxg(a.0, b.0)) + Wrapper(simd_max(a.0, b.0)) } #[no_mangle] diff --git a/tests/codegen-llvm/slice-last-elements-optimization.rs b/tests/codegen-llvm/slice-last-elements-optimization.rs index b90f91d7b17..d982cda709d 100644 --- a/tests/codegen-llvm/slice-last-elements-optimization.rs +++ b/tests/codegen-llvm/slice-last-elements-optimization.rs @@ -1,19 +1,18 @@ //@ compile-flags: -Copt-level=3 -//@ only-x86_64 //@ min-llvm-version: 20 #![crate_type = "lib"] // This test verifies that LLVM 20 properly optimizes the bounds check // when accessing the last few elements of a slice with proper conditions. // Previously, this would generate an unreachable branch to -// slice_start_index_len_fail even when the bounds check was provably safe. +// slice_index_fail even when the bounds check was provably safe. // CHECK-LABEL: @last_four_initial( #[no_mangle] pub fn last_four_initial(s: &[u8]) -> &[u8] { - // Previously this would generate a branch to slice_start_index_len_fail + // Previously this would generate a branch to slice_index_fail // that is unreachable. The LLVM 20 fix should eliminate this branch. - // CHECK-NOT: slice_start_index_len_fail + // CHECK-NOT: slice_index_fail // CHECK-NOT: unreachable let start = if s.len() <= 4 { 0 } else { s.len() - 4 }; &s[start..] @@ -23,7 +22,7 @@ pub fn last_four_initial(s: &[u8]) -> &[u8] { #[no_mangle] pub fn last_four_optimized(s: &[u8]) -> &[u8] { // This version was already correctly optimized before the fix in LLVM 20. - // CHECK-NOT: slice_start_index_len_fail + // CHECK-NOT: slice_index_fail // CHECK-NOT: unreachable if s.len() <= 4 { &s[0..] } else { &s[s.len() - 4..] } } @@ -32,6 +31,6 @@ pub fn last_four_optimized(s: &[u8]) -> &[u8] { // CHECK-LABEL: @test_bounds_check_happens( #[no_mangle] pub fn test_bounds_check_happens(s: &[u8], i: usize) -> &[u8] { - // CHECK: slice_start_index_len_fail + // CHECK: slice_index_fail &s[i..] } diff --git a/tests/codegen-llvm/slice-reverse.rs b/tests/codegen-llvm/slice-reverse.rs index e58d1c1d9d8..c31cff5010b 100644 --- a/tests/codegen-llvm/slice-reverse.rs +++ b/tests/codegen-llvm/slice-reverse.rs @@ -8,10 +8,10 @@ #[no_mangle] pub fn slice_reverse_u8(slice: &mut [u8]) { // CHECK-NOT: panic_bounds_check - // CHECK-NOT: slice_end_index_len_fail + // CHECK-NOT: slice_index_fail // CHECK: shufflevector <{{[0-9]+}} x i8> // CHECK-NOT: panic_bounds_check - // CHECK-NOT: slice_end_index_len_fail + // CHECK-NOT: slice_index_fail slice.reverse(); } @@ -19,9 +19,9 @@ pub fn slice_reverse_u8(slice: &mut [u8]) { #[no_mangle] pub fn slice_reverse_i32(slice: &mut [i32]) { // CHECK-NOT: panic_bounds_check - // CHECK-NOT: slice_end_index_len_fail + // CHECK-NOT: slice_index_fail // CHECK: shufflevector <{{[0-9]+}} x i32> // CHECK-NOT: panic_bounds_check - // CHECK-NOT: slice_end_index_len_fail + // CHECK-NOT: slice_index_fail slice.reverse(); } diff --git a/tests/debuginfo/basic-stepping.rs b/tests/debuginfo/basic-stepping.rs index 6e1344d22a5..e7a70c8b087 100644 --- a/tests/debuginfo/basic-stepping.rs +++ b/tests/debuginfo/basic-stepping.rs @@ -3,6 +3,7 @@ //! Regression test for <https://github.com/rust-lang/rust/issues/33013>. //@ ignore-aarch64: Doesn't work yet. +//@ ignore-loongarch64: Doesn't work yet. //@ compile-flags: -g // gdb-command: run diff --git a/tests/debuginfo/borrowed-enum.rs b/tests/debuginfo/borrowed-enum.rs index 517b439ff15..893dd777bcd 100644 --- a/tests/debuginfo/borrowed-enum.rs +++ b/tests/debuginfo/borrowed-enum.rs @@ -22,11 +22,11 @@ // lldb-command:run // lldb-command:v *the_a_ref -// lldb-check:(borrowed_enum::ABC) *the_a_ref = { value = { x = 0 y = 8970181431921507452 } $discr$ = 0 } +// lldb-check:(borrowed_enum::ABC) *the_a_ref = { TheA = { x = 0 y = 8970181431921507452 } } // lldb-command:v *the_b_ref -// lldb-check:(borrowed_enum::ABC) *the_b_ref = { value = { 0 = 0 1 = 286331153 2 = 286331153 } $discr$ = 1 } +// lldb-check:(borrowed_enum::ABC) *the_b_ref = { TheB = { 0 = 0 1 = 286331153 2 = 286331153 } } // lldb-command:v *univariant_ref -// lldb-check:(borrowed_enum::Univariant) *univariant_ref = { value = { 0 = 4820353753753434 } } +// lldb-check:(borrowed_enum::Univariant) *univariant_ref = { TheOnlyCase = { 0 = 4820353753753434 } } #![allow(unused_variables)] diff --git a/tests/mir-opt/building/index_array_and_slice.rs b/tests/mir-opt/building/index_array_and_slice.rs index f91b37567f7..42ede66d92b 100644 --- a/tests/mir-opt/building/index_array_and_slice.rs +++ b/tests/mir-opt/building/index_array_and_slice.rs @@ -55,7 +55,7 @@ struct WithSliceTail(f64, [i32]); fn index_custom(custom: &WithSliceTail, index: usize) -> &i32 { // CHECK: bb0: // CHECK: [[PTR:_.+]] = &raw const (fake) ((*_1).1: [i32]); - // CHECK: [[LEN:_.+]] = PtrMetadata(move [[PTR]]); + // CHECK: [[LEN:_.+]] = PtrMetadata(copy [[PTR]]); // CHECK: [[LT:_.+]] = Lt(copy _2, copy [[LEN]]); // CHECK: assert(move [[LT]], "index out of bounds{{.+}}", move [[LEN]], copy _2) -> [success: bb1, diff --git a/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.32bit.panic-abort.diff b/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.32bit.panic-abort.diff index 25ffff619e6..f203b80e477 100644 --- a/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.32bit.panic-abort.diff +++ b/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.32bit.panic-abort.diff @@ -112,7 +112,7 @@ StorageDead(_17); StorageDead(_16); StorageDead(_14); - _3 = ShallowInitBox(move _13, ()); + _3 = ShallowInitBox(copy _13, ()); StorageDead(_13); StorageDead(_12); StorageDead(_11); diff --git a/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.64bit.panic-abort.diff b/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.64bit.panic-abort.diff index 839b53e3b0b..f072eb6ef8b 100644 --- a/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.64bit.panic-abort.diff +++ b/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.64bit.panic-abort.diff @@ -112,7 +112,7 @@ StorageDead(_17); StorageDead(_16); StorageDead(_14); - _3 = ShallowInitBox(move _13, ()); + _3 = ShallowInitBox(copy _13, ()); StorageDead(_13); StorageDead(_12); StorageDead(_11); diff --git a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-abort.diff b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-abort.diff index c2d144c98c3..3f854b6cbcf 100644 --- a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-abort.diff +++ b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-abort.diff @@ -103,7 +103,7 @@ StorageDead(_6); _4 = copy _5 as *mut [u8] (Transmute); StorageDead(_5); - _3 = move _4 as *mut u8 (PtrToPtr); + _3 = copy _4 as *mut u8 (PtrToPtr); StorageDead(_4); StorageDead(_3); - StorageDead(_1); diff --git a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-unwind.diff b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-unwind.diff index 88bd4628c29..15a9d9e39c4 100644 --- a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-unwind.diff +++ b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.32bit.panic-unwind.diff @@ -46,7 +46,7 @@ StorageDead(_6); _4 = copy _5 as *mut [u8] (Transmute); StorageDead(_5); - _3 = move _4 as *mut u8 (PtrToPtr); + _3 = copy _4 as *mut u8 (PtrToPtr); StorageDead(_4); StorageDead(_3); - StorageDead(_1); diff --git a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-abort.diff b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-abort.diff index 8641d2d6fa8..1dbe9394e70 100644 --- a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-abort.diff +++ b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-abort.diff @@ -103,7 +103,7 @@ StorageDead(_6); _4 = copy _5 as *mut [u8] (Transmute); StorageDead(_5); - _3 = move _4 as *mut u8 (PtrToPtr); + _3 = copy _4 as *mut u8 (PtrToPtr); StorageDead(_4); StorageDead(_3); - StorageDead(_1); diff --git a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-unwind.diff b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-unwind.diff index 0c52f1e0583..df008ececae 100644 --- a/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-unwind.diff +++ b/tests/mir-opt/pre-codegen/issue_117368_print_invalid_constant.main.GVN.64bit.panic-unwind.diff @@ -46,7 +46,7 @@ StorageDead(_6); _4 = copy _5 as *mut [u8] (Transmute); StorageDead(_5); - _3 = move _4 as *mut u8 (PtrToPtr); + _3 = copy _4 as *mut u8 (PtrToPtr); StorageDead(_4); StorageDead(_3); - StorageDead(_1); diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.panic-abort.mir index d1b1e3d7dd7..ebe8b23354b 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.panic-abort.mir @@ -30,7 +30,7 @@ fn slice_get_mut_usize(_1: &mut [u32], _2: usize) -> Option<&mut u32> { StorageDead(_3); StorageLive(_5); _5 = &mut (*_1)[_2]; - _0 = Option::<&mut u32>::Some(move _5); + _0 = Option::<&mut u32>::Some(copy _5); StorageDead(_5); goto -> bb3; } diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.panic-unwind.mir index d1b1e3d7dd7..ebe8b23354b 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.panic-unwind.mir @@ -30,7 +30,7 @@ fn slice_get_mut_usize(_1: &mut [u32], _2: usize) -> Option<&mut u32> { StorageDead(_3); StorageLive(_5); _5 = &mut (*_1)[_2]; - _0 = Option::<&mut u32>::Some(move _5); + _0 = Option::<&mut u32>::Some(copy _5); StorageDead(_5); goto -> bb3; } diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_index_range.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_index.slice_index_range.PreCodegen.after.panic-abort.mir index 731f6438a6e..2df2c4b85b8 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_index_range.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_index_range.PreCodegen.after.panic-abort.mir @@ -4,14 +4,81 @@ fn slice_index_range(_1: &[u32], _2: std::ops::Range<usize>) -> &[u32] { debug slice => _1; debug index => _2; let mut _0: &[u32]; + let mut _3: usize; + let mut _4: usize; scope 1 (inlined #[track_caller] core::slice::index::<impl Index<std::ops::Range<usize>> for [u32]>::index) { + scope 2 (inlined #[track_caller] <std::ops::Range<usize> as SliceIndex<[u32]>>::index) { + let mut _7: usize; + let mut _8: bool; + let mut _9: *const [u32]; + let _12: *const [u32]; + let mut _13: usize; + let mut _14: !; + scope 3 (inlined core::num::<impl usize>::checked_sub) { + let mut _5: bool; + let mut _6: usize; + } + scope 4 (inlined core::slice::index::get_offset_len_noubcheck::<u32>) { + let _10: *const u32; + scope 5 { + let _11: *const u32; + scope 6 { + } + } + } + } } bb0: { - _0 = <std::ops::Range<usize> as SliceIndex<[u32]>>::index(move _2, move _1) -> [return: bb1, unwind unreachable]; + _3 = move (_2.0: usize); + _4 = move (_2.1: usize); + StorageLive(_5); + _5 = Lt(copy _4, copy _3); + switchInt(move _5) -> [0: bb1, otherwise: bb4]; } bb1: { + _6 = SubUnchecked(copy _4, copy _3); + StorageDead(_5); + StorageLive(_8); + StorageLive(_7); + _7 = PtrMetadata(copy _1); + _8 = Le(copy _4, move _7); + switchInt(move _8) -> [0: bb2, otherwise: bb3]; + } + + bb2: { + StorageDead(_7); + goto -> bb5; + } + + bb3: { + StorageDead(_7); + StorageLive(_12); + StorageLive(_9); + _9 = &raw const (*_1); + StorageLive(_10); + StorageLive(_11); + _10 = copy _9 as *const u32 (PtrToPtr); + _11 = Offset(copy _10, copy _3); + _12 = *const [u32] from (copy _11, copy _6); + StorageDead(_11); + StorageDead(_10); + StorageDead(_9); + _0 = &(*_12); + StorageDead(_12); + StorageDead(_8); return; } + + bb4: { + StorageDead(_5); + goto -> bb5; + } + + bb5: { + StorageLive(_13); + _13 = PtrMetadata(copy _1); + _14 = core::slice::index::slice_index_fail(move _3, move _4, move _13) -> unwind unreachable; + } } diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_index_range.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_index.slice_index_range.PreCodegen.after.panic-unwind.mir index d879d06bb4e..d4b86b9633a 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_index_range.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_index_range.PreCodegen.after.panic-unwind.mir @@ -4,14 +4,81 @@ fn slice_index_range(_1: &[u32], _2: std::ops::Range<usize>) -> &[u32] { debug slice => _1; debug index => _2; let mut _0: &[u32]; + let mut _3: usize; + let mut _4: usize; scope 1 (inlined #[track_caller] core::slice::index::<impl Index<std::ops::Range<usize>> for [u32]>::index) { + scope 2 (inlined #[track_caller] <std::ops::Range<usize> as SliceIndex<[u32]>>::index) { + let mut _7: usize; + let mut _8: bool; + let mut _9: *const [u32]; + let _12: *const [u32]; + let mut _13: usize; + let mut _14: !; + scope 3 (inlined core::num::<impl usize>::checked_sub) { + let mut _5: bool; + let mut _6: usize; + } + scope 4 (inlined core::slice::index::get_offset_len_noubcheck::<u32>) { + let _10: *const u32; + scope 5 { + let _11: *const u32; + scope 6 { + } + } + } + } } bb0: { - _0 = <std::ops::Range<usize> as SliceIndex<[u32]>>::index(move _2, move _1) -> [return: bb1, unwind continue]; + _3 = move (_2.0: usize); + _4 = move (_2.1: usize); + StorageLive(_5); + _5 = Lt(copy _4, copy _3); + switchInt(move _5) -> [0: bb1, otherwise: bb4]; } bb1: { + _6 = SubUnchecked(copy _4, copy _3); + StorageDead(_5); + StorageLive(_8); + StorageLive(_7); + _7 = PtrMetadata(copy _1); + _8 = Le(copy _4, move _7); + switchInt(move _8) -> [0: bb2, otherwise: bb3]; + } + + bb2: { + StorageDead(_7); + goto -> bb5; + } + + bb3: { + StorageDead(_7); + StorageLive(_12); + StorageLive(_9); + _9 = &raw const (*_1); + StorageLive(_10); + StorageLive(_11); + _10 = copy _9 as *const u32 (PtrToPtr); + _11 = Offset(copy _10, copy _3); + _12 = *const [u32] from (copy _11, copy _6); + StorageDead(_11); + StorageDead(_10); + StorageDead(_9); + _0 = &(*_12); + StorageDead(_12); + StorageDead(_8); return; } + + bb4: { + StorageDead(_5); + goto -> bb5; + } + + bb5: { + StorageLive(_13); + _13 = PtrMetadata(copy _1); + _14 = core::slice::index::slice_index_fail(move _3, move _4, move _13) -> unwind continue; + } } diff --git a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir index d389e4069d0..72b39a7f6a8 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir @@ -143,7 +143,7 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { _4 = &raw const (*_1); StorageLive(_5); _5 = copy _4 as *const T (PtrToPtr); - _6 = NonNull::<T> { pointer: move _5 }; + _6 = NonNull::<T> { pointer: copy _5 }; StorageDead(_5); StorageLive(_9); switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb1, otherwise: bb2]; @@ -155,7 +155,7 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { _7 = copy _4 as *mut T (PtrToPtr); _8 = Offset(copy _7, copy _3); StorageDead(_7); - _9 = move _8 as *const T (PtrToPtr); + _9 = copy _8 as *const T (PtrToPtr); StorageDead(_8); goto -> bb3; } @@ -202,7 +202,7 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { _17 = copy _14 as *mut T (Transmute); StorageLive(_18); _18 = copy _16 as *mut T (Transmute); - _19 = Eq(move _17, move _18); + _19 = Eq(copy _17, copy _18); StorageDead(_18); StorageDead(_17); switchInt(move _19) -> [0: bb6, otherwise: bb7]; @@ -214,9 +214,9 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { StorageLive(_21); StorageLive(_20); _20 = copy _14 as *const T (Transmute); - _21 = Offset(move _20, const 1_usize); + _21 = Offset(copy _20, const 1_usize); StorageDead(_20); - _22 = NonNull::<T> { pointer: move _21 }; + _22 = NonNull::<T> { pointer: copy _21 }; StorageDead(_21); _11 = move _22; StorageDead(_22); @@ -282,7 +282,7 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { StorageDead(_23); StorageDead(_15); StorageDead(_14); - _28 = move ((_27 as Some).0: &T); + _28 = copy ((_27 as Some).0: &T); StorageDead(_27); _29 = copy _13; _30 = AddWithOverflow(copy _13, const 1_usize); diff --git a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir index 8c5fbda6392..42aa152ec99 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir @@ -70,7 +70,7 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { _4 = &raw const (*_1); StorageLive(_5); _5 = copy _4 as *const T (PtrToPtr); - _6 = NonNull::<T> { pointer: move _5 }; + _6 = NonNull::<T> { pointer: copy _5 }; StorageDead(_5); StorageLive(_9); switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb1, otherwise: bb2]; @@ -82,7 +82,7 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { _7 = copy _4 as *mut T (PtrToPtr); _8 = Offset(copy _7, copy _3); StorageDead(_7); - _9 = move _8 as *const T (PtrToPtr); + _9 = copy _8 as *const T (PtrToPtr); StorageDead(_8); goto -> bb3; } @@ -95,7 +95,7 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { bb3: { StorageLive(_10); _10 = copy _9; - _11 = std::slice::Iter::<'_, T> { ptr: copy _6, end_or_len: move _10, _marker: const ZeroSized: PhantomData<&T> }; + _11 = std::slice::Iter::<'_, T> { ptr: copy _6, end_or_len: copy _10, _marker: const ZeroSized: PhantomData<&T> }; StorageDead(_10); StorageDead(_9); StorageDead(_4); diff --git a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir index 216e05ec5b7..0d65640ec9b 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir @@ -110,7 +110,7 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { _4 = &raw const (*_1); StorageLive(_5); _5 = copy _4 as *const T (PtrToPtr); - _6 = NonNull::<T> { pointer: move _5 }; + _6 = NonNull::<T> { pointer: copy _5 }; StorageDead(_5); StorageLive(_9); switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb1, otherwise: bb2]; @@ -122,7 +122,7 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { _7 = copy _4 as *mut T (PtrToPtr); _8 = Offset(copy _7, copy _3); StorageDead(_7); - _9 = move _8 as *const T (PtrToPtr); + _9 = copy _8 as *const T (PtrToPtr); StorageDead(_8); goto -> bb3; } @@ -164,7 +164,7 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { _16 = copy _13 as *mut T (Transmute); StorageLive(_17); _17 = copy _15 as *mut T (Transmute); - _18 = Eq(move _16, move _17); + _18 = Eq(copy _16, copy _17); StorageDead(_17); StorageDead(_16); switchInt(move _18) -> [0: bb6, otherwise: bb7]; @@ -176,9 +176,9 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { StorageLive(_20); StorageLive(_19); _19 = copy _13 as *const T (Transmute); - _20 = Offset(move _19, const 1_usize); + _20 = Offset(copy _19, const 1_usize); StorageDead(_19); - _21 = NonNull::<T> { pointer: move _20 }; + _21 = NonNull::<T> { pointer: copy _20 }; StorageDead(_20); _11 = move _21; StorageDead(_21); diff --git a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir index 00102391980..02efb193474 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir @@ -110,7 +110,7 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { _4 = &raw const (*_1); StorageLive(_5); _5 = copy _4 as *const T (PtrToPtr); - _6 = NonNull::<T> { pointer: move _5 }; + _6 = NonNull::<T> { pointer: copy _5 }; StorageDead(_5); StorageLive(_9); switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb1, otherwise: bb2]; @@ -122,7 +122,7 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { _7 = copy _4 as *mut T (PtrToPtr); _8 = Offset(copy _7, copy _3); StorageDead(_7); - _9 = move _8 as *const T (PtrToPtr); + _9 = copy _8 as *const T (PtrToPtr); StorageDead(_8); goto -> bb3; } @@ -164,7 +164,7 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { _16 = copy _13 as *mut T (Transmute); StorageLive(_17); _17 = copy _15 as *mut T (Transmute); - _18 = Eq(move _16, move _17); + _18 = Eq(copy _16, copy _17); StorageDead(_17); StorageDead(_16); switchInt(move _18) -> [0: bb6, otherwise: bb7]; @@ -176,9 +176,9 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { StorageLive(_20); StorageLive(_19); _19 = copy _13 as *const T (Transmute); - _20 = Offset(move _19, const 1_usize); + _20 = Offset(copy _19, const 1_usize); StorageDead(_19); - _21 = NonNull::<T> { pointer: move _20 }; + _21 = NonNull::<T> { pointer: copy _20 }; StorageDead(_20); _11 = move _21; StorageDead(_21); diff --git a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir index b09e3622344..ee638be7d7a 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir @@ -70,7 +70,7 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { _4 = &raw const (*_1); StorageLive(_5); _5 = copy _4 as *const T (PtrToPtr); - _6 = NonNull::<T> { pointer: move _5 }; + _6 = NonNull::<T> { pointer: copy _5 }; StorageDead(_5); StorageLive(_9); switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb1, otherwise: bb2]; @@ -82,7 +82,7 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { _7 = copy _4 as *mut T (PtrToPtr); _8 = Offset(copy _7, copy _3); StorageDead(_7); - _9 = move _8 as *const T (PtrToPtr); + _9 = copy _8 as *const T (PtrToPtr); StorageDead(_8); goto -> bb3; } @@ -95,7 +95,7 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { bb3: { StorageLive(_10); _10 = copy _9; - _11 = std::slice::Iter::<'_, T> { ptr: copy _6, end_or_len: move _10, _marker: const ZeroSized: PhantomData<&T> }; + _11 = std::slice::Iter::<'_, T> { ptr: copy _6, end_or_len: copy _10, _marker: const ZeroSized: PhantomData<&T> }; StorageDead(_10); StorageDead(_9); StorageDead(_4); diff --git a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir index 12b54b57b84..aee29d4d4fe 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir @@ -70,7 +70,7 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { _4 = &raw const (*_1); StorageLive(_5); _5 = copy _4 as *const T (PtrToPtr); - _6 = NonNull::<T> { pointer: move _5 }; + _6 = NonNull::<T> { pointer: copy _5 }; StorageDead(_5); StorageLive(_9); switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb1, otherwise: bb2]; @@ -82,7 +82,7 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { _7 = copy _4 as *mut T (PtrToPtr); _8 = Offset(copy _7, copy _3); StorageDead(_7); - _9 = move _8 as *const T (PtrToPtr); + _9 = copy _8 as *const T (PtrToPtr); StorageDead(_8); goto -> bb3; } @@ -95,7 +95,7 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { bb3: { StorageLive(_10); _10 = copy _9; - _11 = std::slice::Iter::<'_, T> { ptr: copy _6, end_or_len: move _10, _marker: const ZeroSized: PhantomData<&T> }; + _11 = std::slice::Iter::<'_, T> { ptr: copy _6, end_or_len: copy _10, _marker: const ZeroSized: PhantomData<&T> }; StorageDead(_10); StorageDead(_9); StorageDead(_4); diff --git a/tests/mir-opt/pre-codegen/slice_iter.slice_iter_generic_is_empty.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.slice_iter_generic_is_empty.PreCodegen.after.panic-abort.mir index 38d00cfbabd..9b510380b10 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.slice_iter_generic_is_empty.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.slice_iter_generic_is_empty.PreCodegen.after.panic-abort.mir @@ -39,7 +39,7 @@ fn slice_iter_generic_is_empty(_1: &std::slice::Iter<'_, T>) -> bool { bb1: { StorageLive(_2); _2 = copy ((*_1).1: *const T); - _3 = move _2 as std::ptr::NonNull<T> (Transmute); + _3 = copy _2 as std::ptr::NonNull<T> (Transmute); StorageDead(_2); StorageLive(_5); StorageLive(_4); @@ -48,7 +48,7 @@ fn slice_iter_generic_is_empty(_1: &std::slice::Iter<'_, T>) -> bool { StorageDead(_4); StorageLive(_6); _6 = copy _3 as *mut T (Transmute); - _0 = Eq(move _5, move _6); + _0 = Eq(copy _5, copy _6); StorageDead(_6); StorageDead(_5); goto -> bb3; diff --git a/tests/mir-opt/pre-codegen/slice_iter.slice_iter_generic_is_empty.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.slice_iter_generic_is_empty.PreCodegen.after.panic-unwind.mir index 38d00cfbabd..9b510380b10 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.slice_iter_generic_is_empty.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.slice_iter_generic_is_empty.PreCodegen.after.panic-unwind.mir @@ -39,7 +39,7 @@ fn slice_iter_generic_is_empty(_1: &std::slice::Iter<'_, T>) -> bool { bb1: { StorageLive(_2); _2 = copy ((*_1).1: *const T); - _3 = move _2 as std::ptr::NonNull<T> (Transmute); + _3 = copy _2 as std::ptr::NonNull<T> (Transmute); StorageDead(_2); StorageLive(_5); StorageLive(_4); @@ -48,7 +48,7 @@ fn slice_iter_generic_is_empty(_1: &std::slice::Iter<'_, T>) -> bool { StorageDead(_4); StorageLive(_6); _6 = copy _3 as *mut T (Transmute); - _0 = Eq(move _5, move _6); + _0 = Eq(copy _5, copy _6); StorageDead(_6); StorageDead(_5); goto -> bb3; diff --git a/tests/mir-opt/pre-codegen/slice_iter.slice_iter_next.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.slice_iter_next.PreCodegen.after.panic-abort.mir index c0ed0aea1e2..cc0fce26149 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.slice_iter_next.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.slice_iter_next.PreCodegen.after.panic-abort.mir @@ -72,7 +72,7 @@ fn slice_iter_next(_1: &mut std::slice::Iter<'_, T>) -> Option<&T> { _5 = copy _2 as *mut T (Transmute); StorageLive(_6); _6 = copy _4 as *mut T (Transmute); - _7 = Eq(move _5, move _6); + _7 = Eq(copy _5, copy _6); StorageDead(_6); StorageDead(_5); switchInt(move _7) -> [0: bb2, otherwise: bb3]; @@ -84,9 +84,9 @@ fn slice_iter_next(_1: &mut std::slice::Iter<'_, T>) -> Option<&T> { StorageLive(_9); StorageLive(_8); _8 = copy _2 as *const T (Transmute); - _9 = Offset(move _8, const 1_usize); + _9 = Offset(copy _8, const 1_usize); StorageDead(_8); - _10 = NonNull::<T> { pointer: move _9 }; + _10 = NonNull::<T> { pointer: copy _9 }; StorageDead(_9); ((*_1).0: std::ptr::NonNull<T>) = move _10; StorageDead(_10); diff --git a/tests/mir-opt/pre-codegen/slice_iter.slice_iter_next.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.slice_iter_next.PreCodegen.after.panic-unwind.mir index c0ed0aea1e2..cc0fce26149 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.slice_iter_next.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.slice_iter_next.PreCodegen.after.panic-unwind.mir @@ -72,7 +72,7 @@ fn slice_iter_next(_1: &mut std::slice::Iter<'_, T>) -> Option<&T> { _5 = copy _2 as *mut T (Transmute); StorageLive(_6); _6 = copy _4 as *mut T (Transmute); - _7 = Eq(move _5, move _6); + _7 = Eq(copy _5, copy _6); StorageDead(_6); StorageDead(_5); switchInt(move _7) -> [0: bb2, otherwise: bb3]; @@ -84,9 +84,9 @@ fn slice_iter_next(_1: &mut std::slice::Iter<'_, T>) -> Option<&T> { StorageLive(_9); StorageLive(_8); _8 = copy _2 as *const T (Transmute); - _9 = Offset(move _8, const 1_usize); + _9 = Offset(copy _8, const 1_usize); StorageDead(_8); - _10 = NonNull::<T> { pointer: move _9 }; + _10 = NonNull::<T> { pointer: copy _9 }; StorageDead(_9); ((*_1).0: std::ptr::NonNull<T>) = move _10; StorageDead(_10); diff --git a/tests/mir-opt/reference_prop.debuginfo.ReferencePropagation.diff b/tests/mir-opt/reference_prop.debuginfo.ReferencePropagation.diff index 05ad9dbf3cc..3da795b61f9 100644 --- a/tests/mir-opt/reference_prop.debuginfo.ReferencePropagation.diff +++ b/tests/mir-opt/reference_prop.debuginfo.ReferencePropagation.diff @@ -99,7 +99,8 @@ _13 = &(*_26); StorageLive(_15); _15 = RangeFull; - _12 = <[i32; 10] as Index<RangeFull>>::index(move _13, move _15) -> [return: bb5, unwind continue]; +- _12 = <[i32; 10] as Index<RangeFull>>::index(move _13, move _15) -> [return: bb5, unwind continue]; ++ _12 = <[i32; 10] as Index<RangeFull>>::index(copy _13, move _15) -> [return: bb5, unwind continue]; } bb5: { diff --git a/tests/mir-opt/reference_prop.reference_propagation.ReferencePropagation.diff b/tests/mir-opt/reference_prop.reference_propagation.ReferencePropagation.diff index 3c6a9a9614c..0f90cc40a3d 100644 --- a/tests/mir-opt/reference_prop.reference_propagation.ReferencePropagation.diff +++ b/tests/mir-opt/reference_prop.reference_propagation.ReferencePropagation.diff @@ -218,8 +218,9 @@ - StorageLive(_14); - _14 = &_11; - _13 = &(*_14); +- _12 = move _13; + _13 = &_11; - _12 = move _13; ++ _12 = copy _13; StorageDead(_13); - StorageDead(_14); StorageLive(_15); @@ -252,7 +253,8 @@ StorageLive(_23); StorageLive(_24); _24 = copy _21; - _23 = opaque::<&&usize>(move _24) -> [return: bb3, unwind continue]; +- _23 = opaque::<&&usize>(move _24) -> [return: bb3, unwind continue]; ++ _23 = opaque::<&&usize>(copy _24) -> [return: bb3, unwind continue]; } bb3: { @@ -276,7 +278,8 @@ StorageLive(_30); StorageLive(_31); _31 = copy _28; - _30 = opaque::<*mut &usize>(move _31) -> [return: bb4, unwind continue]; +- _30 = opaque::<*mut &usize>(move _31) -> [return: bb4, unwind continue]; ++ _30 = opaque::<*mut &usize>(copy _31) -> [return: bb4, unwind continue]; } bb4: { @@ -299,7 +302,8 @@ StorageLive(_36); StorageLive(_37); _37 = copy _34; - _36 = opaque::<&usize>(move _37) -> [return: bb5, unwind continue]; +- _36 = opaque::<&usize>(move _37) -> [return: bb5, unwind continue]; ++ _36 = opaque::<&usize>(copy _37) -> [return: bb5, unwind continue]; } bb5: { @@ -328,7 +332,8 @@ StorageLive(_45); StorageLive(_46); _46 = copy _44; - _45 = opaque::<&usize>(move _46) -> [return: bb6, unwind continue]; +- _45 = opaque::<&usize>(move _46) -> [return: bb6, unwind continue]; ++ _45 = opaque::<&usize>(copy _46) -> [return: bb6, unwind continue]; } bb6: { @@ -368,8 +373,9 @@ - StorageLive(_55); - _55 = &(*_1); - _54 = &(*_55); +- _2 = move _54; + _54 = &(*_1); - _2 = move _54; ++ _2 = copy _54; StorageDead(_54); - StorageDead(_55); StorageLive(_56); diff --git a/tests/mir-opt/reference_prop.reference_propagation_const_ptr.ReferencePropagation.diff b/tests/mir-opt/reference_prop.reference_propagation_const_ptr.ReferencePropagation.diff index 75fe99de938..99ef07a212c 100644 --- a/tests/mir-opt/reference_prop.reference_propagation_const_ptr.ReferencePropagation.diff +++ b/tests/mir-opt/reference_prop.reference_propagation_const_ptr.ReferencePropagation.diff @@ -233,7 +233,8 @@ _12 = &raw const _10; StorageLive(_13); _13 = &raw const _11; - _12 = move _13; +- _12 = move _13; ++ _12 = copy _13; StorageDead(_13); StorageLive(_14); _14 = copy (*_12); @@ -265,7 +266,8 @@ StorageLive(_22); StorageLive(_23); _23 = copy _20; - _22 = opaque::<&*const usize>(move _23) -> [return: bb3, unwind continue]; +- _22 = opaque::<&*const usize>(move _23) -> [return: bb3, unwind continue]; ++ _22 = opaque::<&*const usize>(copy _23) -> [return: bb3, unwind continue]; } bb3: { @@ -289,7 +291,8 @@ StorageLive(_29); StorageLive(_30); _30 = copy _27; - _29 = opaque::<*mut *const usize>(move _30) -> [return: bb4, unwind continue]; +- _29 = opaque::<*mut *const usize>(move _30) -> [return: bb4, unwind continue]; ++ _29 = opaque::<*mut *const usize>(copy _30) -> [return: bb4, unwind continue]; } bb4: { @@ -312,7 +315,8 @@ StorageLive(_35); StorageLive(_36); _36 = copy _33; - _35 = opaque::<*const usize>(move _36) -> [return: bb5, unwind continue]; +- _35 = opaque::<*const usize>(move _36) -> [return: bb5, unwind continue]; ++ _35 = opaque::<*const usize>(copy _36) -> [return: bb5, unwind continue]; } bb5: { @@ -341,7 +345,8 @@ StorageLive(_44); StorageLive(_45); _45 = copy _43; - _44 = opaque::<*const usize>(move _45) -> [return: bb6, unwind continue]; +- _44 = opaque::<*const usize>(move _45) -> [return: bb6, unwind continue]; ++ _44 = opaque::<*const usize>(copy _45) -> [return: bb6, unwind continue]; } bb6: { @@ -379,7 +384,8 @@ _52 = &raw const (*_2); StorageLive(_53); _53 = &raw const (*_1); - _2 = move _53; +- _2 = move _53; ++ _2 = copy _53; StorageDead(_53); StorageLive(_54); _54 = copy (*_52); diff --git a/tests/mir-opt/reference_prop.reference_propagation_mut.ReferencePropagation.diff b/tests/mir-opt/reference_prop.reference_propagation_mut.ReferencePropagation.diff index f35b4974d6e..e2fab8a5f2e 100644 --- a/tests/mir-opt/reference_prop.reference_propagation_mut.ReferencePropagation.diff +++ b/tests/mir-opt/reference_prop.reference_propagation_mut.ReferencePropagation.diff @@ -218,8 +218,9 @@ - StorageLive(_14); - _14 = &mut _11; - _13 = &mut (*_14); +- _12 = move _13; + _13 = &mut _11; - _12 = move _13; ++ _12 = copy _13; StorageDead(_13); - StorageDead(_14); StorageLive(_15); @@ -251,7 +252,8 @@ StorageLive(_23); StorageLive(_24); _24 = copy _21; - _23 = opaque::<&&mut usize>(move _24) -> [return: bb3, unwind continue]; +- _23 = opaque::<&&mut usize>(move _24) -> [return: bb3, unwind continue]; ++ _23 = opaque::<&&mut usize>(copy _24) -> [return: bb3, unwind continue]; } bb3: { @@ -275,7 +277,8 @@ StorageLive(_30); StorageLive(_31); _31 = copy _28; - _30 = opaque::<*mut &mut usize>(move _31) -> [return: bb4, unwind continue]; +- _30 = opaque::<*mut &mut usize>(move _31) -> [return: bb4, unwind continue]; ++ _30 = opaque::<*mut &mut usize>(copy _31) -> [return: bb4, unwind continue]; } bb4: { @@ -296,8 +299,10 @@ _35 = copy (*_34); StorageLive(_36); StorageLive(_37); - _37 = move _34; - _36 = opaque::<&mut usize>(move _37) -> [return: bb5, unwind continue]; +- _37 = move _34; +- _36 = opaque::<&mut usize>(move _37) -> [return: bb5, unwind continue]; ++ _37 = copy _34; ++ _36 = opaque::<&mut usize>(copy _37) -> [return: bb5, unwind continue]; } bb5: { @@ -316,15 +321,19 @@ StorageLive(_41); _41 = copy (*_40); StorageLive(_42); - _42 = move _40; +- _42 = move _40; ++ _42 = copy _40; StorageLive(_43); _43 = copy (*_42); StorageLive(_44); - _44 = move _42; +- _44 = move _42; ++ _44 = copy _42; StorageLive(_45); StorageLive(_46); - _46 = move _44; - _45 = opaque::<&mut usize>(move _46) -> [return: bb6, unwind continue]; +- _46 = move _44; +- _45 = opaque::<&mut usize>(move _46) -> [return: bb6, unwind continue]; ++ _46 = copy _44; ++ _45 = opaque::<&mut usize>(copy _46) -> [return: bb6, unwind continue]; } bb6: { @@ -364,8 +373,9 @@ - StorageLive(_55); - _55 = &mut (*_1); - _54 = &mut (*_55); +- _2 = move _54; + _54 = &mut (*_1); - _2 = move _54; ++ _2 = copy _54; StorageDead(_54); - StorageDead(_55); StorageLive(_56); diff --git a/tests/mir-opt/reference_prop.reference_propagation_mut_ptr.ReferencePropagation.diff b/tests/mir-opt/reference_prop.reference_propagation_mut_ptr.ReferencePropagation.diff index 21b322b7218..c49254ee6c6 100644 --- a/tests/mir-opt/reference_prop.reference_propagation_mut_ptr.ReferencePropagation.diff +++ b/tests/mir-opt/reference_prop.reference_propagation_mut_ptr.ReferencePropagation.diff @@ -214,7 +214,8 @@ _12 = &raw mut _10; StorageLive(_13); _13 = &raw mut _11; - _12 = move _13; +- _12 = move _13; ++ _12 = copy _13; StorageDead(_13); StorageLive(_14); _14 = copy (*_12); @@ -245,7 +246,8 @@ StorageLive(_22); StorageLive(_23); _23 = copy _20; - _22 = opaque::<&*mut usize>(move _23) -> [return: bb3, unwind continue]; +- _22 = opaque::<&*mut usize>(move _23) -> [return: bb3, unwind continue]; ++ _22 = opaque::<&*mut usize>(copy _23) -> [return: bb3, unwind continue]; } bb3: { @@ -269,7 +271,8 @@ StorageLive(_29); StorageLive(_30); _30 = copy _27; - _29 = opaque::<*mut *mut usize>(move _30) -> [return: bb4, unwind continue]; +- _29 = opaque::<*mut *mut usize>(move _30) -> [return: bb4, unwind continue]; ++ _29 = opaque::<*mut *mut usize>(copy _30) -> [return: bb4, unwind continue]; } bb4: { @@ -291,7 +294,8 @@ StorageLive(_35); StorageLive(_36); _36 = copy _33; - _35 = opaque::<*mut usize>(move _36) -> [return: bb5, unwind continue]; +- _35 = opaque::<*mut usize>(move _36) -> [return: bb5, unwind continue]; ++ _35 = opaque::<*mut usize>(copy _36) -> [return: bb5, unwind continue]; } bb5: { @@ -318,7 +322,8 @@ StorageLive(_44); StorageLive(_45); _45 = copy _43; - _44 = opaque::<*mut usize>(move _45) -> [return: bb6, unwind continue]; +- _44 = opaque::<*mut usize>(move _45) -> [return: bb6, unwind continue]; ++ _44 = opaque::<*mut usize>(copy _45) -> [return: bb6, unwind continue]; } bb6: { @@ -356,7 +361,8 @@ _52 = &raw mut (*_2); StorageLive(_53); _53 = &raw mut (*_1); - _2 = move _53; +- _2 = move _53; ++ _2 = copy _53; StorageDead(_53); StorageLive(_54); _54 = copy (*_52); diff --git a/tests/mir-opt/reference_prop.rs b/tests/mir-opt/reference_prop.rs index 00d48938071..c4b63b6313c 100644 --- a/tests/mir-opt/reference_prop.rs +++ b/tests/mir-opt/reference_prop.rs @@ -30,7 +30,7 @@ fn reference_propagation<'a, T: Copy>(single: &'a T, mut multiple: &'a T) { // CHECK: [[a2:_.*]] = const 7_usize; // CHECK: [[b:_.*]] = &[[a]]; // CHECK: [[btmp:_.*]] = &[[a2]]; - // CHECK: [[b]] = move [[btmp]]; + // CHECK: [[b]] = copy [[btmp]]; // CHECK: [[c:_.*]] = copy (*[[b]]); let a = 5_usize; @@ -122,7 +122,7 @@ fn reference_propagation<'a, T: Copy>(single: &'a T, mut multiple: &'a T) { // CHECK: bb7: { // CHECK: [[a:_.*]] = &(*_2); // CHECK: [[tmp:_.*]] = &(*_1); - // CHECK: _2 = move [[tmp]]; + // CHECK: _2 = copy [[tmp]]; // CHECK: [[b:_.*]] = copy (*[[a]]); let a = &*multiple; @@ -186,7 +186,7 @@ fn reference_propagation_mut<'a, T: Copy>(single: &'a mut T, mut multiple: &'a m // CHECK: [[a2:_.*]] = const 7_usize; // CHECK: [[b:_.*]] = &mut [[a]]; // CHECK: [[btmp:_.*]] = &mut [[a2]]; - // CHECK: [[b]] = move [[btmp]]; + // CHECK: [[b]] = copy [[btmp]]; // CHECK: [[c:_.*]] = copy (*[[b]]); let mut a = 5_usize; @@ -247,9 +247,9 @@ fn reference_propagation_mut<'a, T: Copy>(single: &'a mut T, mut multiple: &'a m // CHECK: [[a:_.*]] = const 7_usize; // CHECK: [[b1:_.*]] = &mut [[a]]; // CHECK: [[c:_.*]] = copy (*[[b1]]); - // CHECK: [[b2:_.*]] = move [[b1]]; + // CHECK: [[b2:_.*]] = copy [[b1]]; // CHECK: [[c2:_.*]] = copy (*[[b2]]); - // CHECK: [[b3:_.*]] = move [[b2]]; + // CHECK: [[b3:_.*]] = copy [[b2]]; let mut a = 7_usize; let b1 = &mut a; @@ -278,7 +278,7 @@ fn reference_propagation_mut<'a, T: Copy>(single: &'a mut T, mut multiple: &'a m // CHECK: bb7: { // CHECK: [[a:_.*]] = &mut (*_2); // CHECK: [[tmp:_.*]] = &mut (*_1); - // CHECK: _2 = move [[tmp]]; + // CHECK: _2 = copy [[tmp]]; // CHECK: [[b:_.*]] = copy (*[[a]]); let a = &mut *multiple; @@ -343,7 +343,7 @@ fn reference_propagation_const_ptr<T: Copy>(single: *const T, mut multiple: *con // CHECK: [[a2:_.*]] = const 7_usize; // CHECK: [[b:_.*]] = &raw const [[a]]; // CHECK: [[btmp:_.*]] = &raw const [[a2]]; - // CHECK: [[b]] = move [[btmp]]; + // CHECK: [[b]] = copy [[btmp]]; // CHECK: [[c:_.*]] = copy (*[[b]]); let a = 5_usize; @@ -435,7 +435,7 @@ fn reference_propagation_const_ptr<T: Copy>(single: *const T, mut multiple: *con // CHECK: bb7: { // CHECK: [[a:_.*]] = &raw const (*_2); // CHECK: [[tmp:_.*]] = &raw const (*_1); - // CHECK: _2 = move [[tmp]]; + // CHECK: _2 = copy [[tmp]]; // CHECK: [[b:_.*]] = copy (*[[a]]); let a = &raw const *multiple; @@ -514,7 +514,7 @@ fn reference_propagation_mut_ptr<T: Copy>(single: *mut T, mut multiple: *mut T) // CHECK: [[a2:_.*]] = const 7_usize; // CHECK: [[b:_.*]] = &raw mut [[a]]; // CHECK: [[btmp:_.*]] = &raw mut [[a2]]; - // CHECK: [[b]] = move [[btmp]]; + // CHECK: [[b]] = copy [[btmp]]; // CHECK: [[c:_.*]] = copy (*[[b]]); let mut a = 5_usize; @@ -606,7 +606,7 @@ fn reference_propagation_mut_ptr<T: Copy>(single: *mut T, mut multiple: *mut T) // CHECK: bb7: { // CHECK: [[a:_.*]] = &raw mut (*_2); // CHECK: [[tmp:_.*]] = &raw mut (*_1); - // CHECK: _2 = move [[tmp]]; + // CHECK: _2 = copy [[tmp]]; // CHECK: [[b:_.*]] = copy (*[[a]]); let a = &raw mut *multiple; diff --git a/tests/mir-opt/reference_prop_do_not_reuse_move.rs b/tests/mir-opt/reference_prop_do_not_reuse_move.rs new file mode 100644 index 00000000000..8859d30aed1 --- /dev/null +++ b/tests/mir-opt/reference_prop_do_not_reuse_move.rs @@ -0,0 +1,44 @@ +//@ test-mir-pass: ReferencePropagation + +#![feature(custom_mir, core_intrinsics)] +#![allow(internal_features)] +#![crate_type = "lib"] + +use std::intrinsics::mir::*; + +#[inline(never)] +fn opaque(_: impl Sized, _: impl Sized) {} + +#[custom_mir(dialect = "runtime")] +pub fn fn0() { + // CHECK-LABEL: fn0 + // CHECK: _9 = opaque::<&u8, &u64>(copy (_2.1: &u8), copy _6) -> [return: bb1, unwind unreachable]; + mir! { + let _1: (u8, u8); + let _2: (u64, &u8); + let _3: (u8, &&u64); + let _4: u64; + let _5: &u64; + let _6: &u64; + let _7: &u64; + let _8: u64; + let n: (); + { + _3.0 = 0; + _1 = (0, _3.0); + _4 = 0; + _2.1 = &_1.0; + _8 = 0; + _5 = &_8; + _5 = &_4; + _6 = _5; + _7 = _6; + _3.1 = &_6; + Call(n = opaque(_2.1, Move(_6)), ReturnTo(bb1), UnwindUnreachable()) + } + bb1 = { + _2.0 = *_7; + Return() + } + } +} diff --git a/tests/mir-opt/uninhabited_not_read.main.SimplifyLocals-final.after.mir b/tests/mir-opt/uninhabited_not_read.main.SimplifyLocals-final.after.mir index 6bf4be652be..89f4cbc2ede 100644 --- a/tests/mir-opt/uninhabited_not_read.main.SimplifyLocals-final.after.mir +++ b/tests/mir-opt/uninhabited_not_read.main.SimplifyLocals-final.after.mir @@ -31,7 +31,7 @@ fn main() -> () { StorageLive(_2); StorageLive(_3); _3 = &raw const _1; - _2 = move _3 as *const ! (PtrToPtr); + _2 = copy _3 as *const ! (PtrToPtr); StorageDead(_3); StorageDead(_2); StorageDead(_1); @@ -40,7 +40,7 @@ fn main() -> () { StorageLive(_5); StorageLive(_6); _6 = &raw const _4; - _5 = move _6 as *const ! (PtrToPtr); + _5 = copy _6 as *const ! (PtrToPtr); StorageDead(_6); StorageDead(_5); StorageDead(_4); diff --git a/tests/rustdoc-gui/utils.goml b/tests/rustdoc-gui/utils.goml index 10439309402..e13aef6712f 100644 --- a/tests/rustdoc-gui/utils.goml +++ b/tests/rustdoc-gui/utils.goml @@ -39,6 +39,13 @@ define-function: ( "perform-search", [query], block { + // Block requests with doubled `//`. + // Amazon S3 doesn't support them, but other web hosts do, + // and so do file:/// URLs, which means we need to block + // it here if we want to avoid breaking the main docs site. + // https://github.com/rust-lang/rust/issues/145646 + block-network-request: "file://*//*" + // Perform search click: "#search-button" wait-for: ".search-input" write-into: (".search-input", |query|) diff --git a/tests/rustdoc-js-std/parser-errors.js b/tests/rustdoc-js-std/parser-errors.js index 49150cbd570..6e11dda8532 100644 --- a/tests/rustdoc-js-std/parser-errors.js +++ b/tests/rustdoc-js-std/parser-errors.js @@ -16,14 +16,6 @@ const PARSED = [ error: "Found generics without a path", }, { - query: '-> *', - elems: [], - foundElems: 0, - userQuery: "-> *", - returned: [], - error: "Unexpected `*` after ` ` (not a valid identifier)", - }, - { query: 'a<"P">', elems: [], foundElems: 0, diff --git a/tests/rustdoc-js/pointer.js b/tests/rustdoc-js/pointer.js new file mode 100644 index 00000000000..b2b556858fd --- /dev/null +++ b/tests/rustdoc-js/pointer.js @@ -0,0 +1,240 @@ +// exact-check + +const EXPECTED = [ + // pinkie with explicit names + { + 'query': 'usize, usize -> ()', + 'others': [ + { 'path': 'pointer', 'name': 'pinky' }, + ], + }, + { + 'query': 'pointer<usize>, usize -> ()', + 'others': [ + { 'path': 'pointer', 'name': 'pinky' }, + ], + }, + { + 'query': 'pointer<usize>, pointer<usize> -> ()', + 'others': [], + }, + { + 'query': 'pointer<mut, usize>, usize -> ()', + 'others': [], + }, + // thumb with explicit names + { + 'query': 'thumb, thumb -> ()', + 'others': [ + { 'path': 'pointer::Thumb', 'name': 'up' }, + ], + }, + { + 'query': 'pointer<thumb>, thumb -> ()', + 'others': [ + { 'path': 'pointer::Thumb', 'name': 'up' }, + ], + }, + { + 'query': 'pointer<thumb>, pointer<thumb> -> ()', + 'others': [], + }, + { + 'query': 'pointer<mut, thumb>, thumb -> ()', + 'others': [], + }, + // index with explicit names + { + 'query': 'index, index -> ()', + 'others': [ + { 'path': 'pointer::Index', 'name': 'point' }, + ], + }, + { + 'query': 'pointer<index>, index -> ()', + 'others': [ + { 'path': 'pointer::Index', 'name': 'point' }, + ], + }, + { + 'query': 'pointer<index>, pointer<index> -> ()', + 'others': [], + }, + { + 'query': 'pointer<mut, index>, index -> ()', + 'others': [], + }, + // ring with explicit names + { + 'query': 'ring, ring -> ()', + 'others': [ + { 'path': 'pointer::Ring', 'name': 'wear' }, + ], + }, + { + 'query': 'pointer<ring>, ring -> ()', + 'others': [ + { 'path': 'pointer::Ring', 'name': 'wear' }, + ], + }, + { + 'query': 'pointer<ring>, pointer<ring> -> ()', + // can't leave out the `mut`, because can't reorder like that + 'others': [], + }, + { + 'query': 'pointer<mut, ring>, pointer<ring> -> ()', + 'others': [ + { 'path': 'pointer::Ring', 'name': 'wear' }, + ], + }, + { + 'query': 'pointer<mut, ring>, pointer<mut, ring> -> ()', + 'others': [], + }, + // middle with explicit names + { + 'query': 'middle, middle -> ()', + 'others': [ + { 'path': 'pointer', 'name': 'show' }, + ], + }, + { + 'query': 'pointer<middle>, pointer<middle> -> ()', + // can't leave out the mut + 'others': [], + }, + { + 'query': 'pointer<mut, middle>, pointer<mut, middle> -> ()', + 'others': [ + { 'path': 'pointer', 'name': 'show' }, + ], + }, + { + 'query': 'pointer<pointer<mut, middle>>, pointer<mut, pointer<middle>> -> ()', + 'others': [ + { 'path': 'pointer', 'name': 'show' }, + ], + }, + { + 'query': 'pointer<mut, pointer<middle>>, pointer<pointer<mut, middle>> -> ()', + 'others': [ + { 'path': 'pointer', 'name': 'show' }, + ], + }, + { + 'query': 'pointer<pointer<mut, middle>>, pointer<pointer<mut, middle>> -> ()', + 'others': [], + }, + { + 'query': 'pointer<mut, pointer<middle>>, pointer<mut, pointer<middle>> -> ()', + 'others': [], + }, + // pinkie with shorthand + { + 'query': '*const usize, usize -> ()', + 'others': [ + { 'path': 'pointer', 'name': 'pinky' }, + ], + }, + // you can omit the `const`, if you want. + { + 'query': '*usize, usize -> ()', + 'others': [ + { 'path': 'pointer', 'name': 'pinky' }, + ], + }, + { + 'query': '*const usize, *const usize -> ()', + 'others': [], + }, + { + 'query': '*mut usize, usize -> ()', + 'others': [], + }, + // thumb with shorthand + { + 'query': '*const thumb, thumb -> ()', + 'others': [ + { 'path': 'pointer::Thumb', 'name': 'up' }, + ], + }, + { + 'query': '*const thumb, *const thumb -> ()', + 'others': [], + }, + { + 'query': '*mut thumb, thumb -> ()', + 'others': [], + }, + // index with explicit names + { + 'query': '*const index, index -> ()', + 'others': [ + { 'path': 'pointer::Index', 'name': 'point' }, + ], + }, + { + 'query': '*const index, *const index -> ()', + 'others': [], + }, + { + 'query': '*mut index, index -> ()', + 'others': [], + }, + // ring with shorthand + { + 'query': '*const ring, ring -> ()', + 'others': [ + { 'path': 'pointer::Ring', 'name': 'wear' }, + ], + }, + { + 'query': '*const ring, ring -> ()', + 'others': [ + { 'path': 'pointer::Ring', 'name': 'wear' }, + ], + }, + { + 'query': '*mut ring, *const ring -> ()', + 'others': [ + { 'path': 'pointer::Ring', 'name': 'wear' }, + ], + }, + { + 'query': '*mut ring, *mut ring -> ()', + 'others': [], + }, + // middle with shorthand + { + 'query': '*const middle, *const middle -> ()', + // can't leave out the mut + 'others': [], + }, + { + 'query': '*mut middle, *mut middle -> ()', + 'others': [ + { 'path': 'pointer', 'name': 'show' }, + ], + }, + { + 'query': '*const *mut middle, *mut *const middle -> ()', + 'others': [ + { 'path': 'pointer', 'name': 'show' }, + ], + }, + { + 'query': '*mut *const middle, *const *mut middle -> ()', + 'others': [ + { 'path': 'pointer', 'name': 'show' }, + ], + }, + { + 'query': '*const *mut middle, *const *mut middle -> ()', + 'others': [], + }, + { + 'query': '*mut *const middle, *mut *const middle -> ()', + 'others': [], + }, +]; diff --git a/tests/rustdoc-js/pointer.rs b/tests/rustdoc-js/pointer.rs new file mode 100644 index 00000000000..8375a174303 --- /dev/null +++ b/tests/rustdoc-js/pointer.rs @@ -0,0 +1,40 @@ +#![feature(extern_types)] + +pub fn pinky(input: *const usize, manage: usize) { + unimplemented!() +} + +pub struct Thumb; + +impl Thumb { + pub fn up(this: *const Self, finger: Thumb) { + unimplemented!() + } +} + +pub enum Index {} + +impl Index { + pub fn point(self, data: *const Index) { + unimplemented!() + } +} + +pub union Ring { + magic: u32, + marriage: f32, +} + +impl Ring { + pub fn wear(this: *mut Self, extra: *const Ring) { + unimplemented!() + } +} + +extern "C" { + pub type Middle; +} + +pub fn show(left: *const *mut Middle, right: *mut *const Middle) { + unimplemented!() +} diff --git a/tests/rustdoc-ui/issues/issue-79494.rs b/tests/rustdoc-ui/issues/issue-79494.rs index 28ef82dac0f..737c00a0269 100644 --- a/tests/rustdoc-ui/issues/issue-79494.rs +++ b/tests/rustdoc-ui/issues/issue-79494.rs @@ -1,5 +1,6 @@ -//@ only-x86_64-unknown-linux-gnu +//@ only-64bit #![feature(const_transmute)] -pub const ZST: &[u8] = unsafe { std::mem::transmute(1usize) }; //~ ERROR cannot transmute between types of different sizes, or dependently-sized types +pub const ZST: &[u8] = unsafe { std::mem::transmute(1usize) }; +//~^ ERROR transmuting from 8-byte type to 16-byte type diff --git a/tests/rustdoc-ui/issues/issue-79494.stderr b/tests/rustdoc-ui/issues/issue-79494.stderr index 20e568d8eab..fa797bfd50a 100644 --- a/tests/rustdoc-ui/issues/issue-79494.stderr +++ b/tests/rustdoc-ui/issues/issue-79494.stderr @@ -1,12 +1,9 @@ -error[E0512]: cannot transmute between types of different sizes, or dependently-sized types +error[E0080]: transmuting from 8-byte type to 16-byte type: `usize` -> `&[u8]` --> $DIR/issue-79494.rs:5:33 | LL | pub const ZST: &[u8] = unsafe { std::mem::transmute(1usize) }; - | ^^^^^^^^^^^^^^^^^^^ - | - = note: source type: `usize` (64 bits) - = note: target type: `&[u8]` (128 bits) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `ZST` failed here error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0512`. +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/ui-fulldeps/rustc-dev-remap.only-remap.stderr b/tests/ui-fulldeps/rustc-dev-remap.only-remap.stderr index 0c969b9c6d8..b8de9291d65 100644 --- a/tests/ui-fulldeps/rustc-dev-remap.only-remap.stderr +++ b/tests/ui-fulldeps/rustc-dev-remap.only-remap.stderr @@ -2,8 +2,13 @@ error[E0277]: the trait bound `NotAValidResultType: VisitorResult` is not satisf --> $DIR/rustc-dev-remap.rs:LL:COL | LL | type Result = NotAValidResultType; - | ^^^^^^^^^^^^^^^^^^^ the trait `VisitorResult` is not implemented for `NotAValidResultType` + | ^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound | +help: the trait `VisitorResult` is not implemented for `NotAValidResultType` + --> $DIR/rustc-dev-remap.rs:LL:COL + | +LL | struct NotAValidResultType; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: the following other types implement trait `VisitorResult`: () ControlFlow<T> diff --git a/tests/ui-fulldeps/rustc-dev-remap.remap-unremap.stderr b/tests/ui-fulldeps/rustc-dev-remap.remap-unremap.stderr index 6ac8c3046f6..29b43c819d0 100644 --- a/tests/ui-fulldeps/rustc-dev-remap.remap-unremap.stderr +++ b/tests/ui-fulldeps/rustc-dev-remap.remap-unremap.stderr @@ -2,8 +2,13 @@ error[E0277]: the trait bound `NotAValidResultType: VisitorResult` is not satisf --> $DIR/rustc-dev-remap.rs:LL:COL | LL | type Result = NotAValidResultType; - | ^^^^^^^^^^^^^^^^^^^ the trait `VisitorResult` is not implemented for `NotAValidResultType` + | ^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound | +help: the trait `VisitorResult` is not implemented for `NotAValidResultType` + --> $DIR/rustc-dev-remap.rs:LL:COL + | +LL | struct NotAValidResultType; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: the following other types implement trait `VisitorResult`: () ControlFlow<T> diff --git a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.stderr b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.stderr index 7377b0dfd0a..8b6c4b181c0 100644 --- a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.stderr +++ b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.stderr @@ -5,8 +5,13 @@ LL | #[derive(Diagnostic)] | ---------- required by a bound introduced by this call ... LL | arg: NotIntoDiagArg, - | ^^^^^^^^^^^^^^ the trait `IntoDiagArg` is not implemented for `NotIntoDiagArg` + | ^^^^^^^^^^^^^^ unsatisfied trait bound | +help: the trait `IntoDiagArg` is not implemented for `NotIntoDiagArg` + --> $DIR/diagnostic-derive-doc-comment-field.rs:28:1 + | +LL | struct NotIntoDiagArg; + | ^^^^^^^^^^^^^^^^^^^^^ = help: normalized in stderr note: required by a bound in `Diag::<'a, G>::arg` --> $COMPILER_DIR/rustc_errors/src/diagnostic.rs:LL:CC @@ -19,8 +24,13 @@ LL | #[derive(Subdiagnostic)] | ------------- required by a bound introduced by this call ... LL | arg: NotIntoDiagArg, - | ^^^^^^^^^^^^^^ the trait `IntoDiagArg` is not implemented for `NotIntoDiagArg` + | ^^^^^^^^^^^^^^ unsatisfied trait bound + | +help: the trait `IntoDiagArg` is not implemented for `NotIntoDiagArg` + --> $DIR/diagnostic-derive-doc-comment-field.rs:28:1 | +LL | struct NotIntoDiagArg; + | ^^^^^^^^^^^^^^^^^^^^^ = help: normalized in stderr note: required by a bound in `Diag::<'a, G>::arg` --> $COMPILER_DIR/rustc_errors/src/diagnostic.rs:LL:CC diff --git a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr index 396abb001ce..59b48e9f0ec 100644 --- a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr +++ b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr @@ -637,8 +637,13 @@ LL | #[derive(Diagnostic)] | ---------- required by a bound introduced by this call ... LL | other: Hello, - | ^^^^^ the trait `IntoDiagArg` is not implemented for `Hello` + | ^^^^^ unsatisfied trait bound | +help: the trait `IntoDiagArg` is not implemented for `Hello` + --> $DIR/diagnostic-derive.rs:40:1 + | +LL | struct Hello {} + | ^^^^^^^^^^^^ = help: normalized in stderr note: required by a bound in `Diag::<'a, G>::arg` --> $COMPILER_DIR/rustc_errors/src/diagnostic.rs:LL:CC diff --git a/tests/ui/abi/debug.generic.stderr b/tests/ui/abi/debug.generic.stderr index 8375de3e817..0fec35dabdd 100644 --- a/tests/ui/abi/debug.generic.stderr +++ b/tests/ui/abi/debug.generic.stderr @@ -89,7 +89,7 @@ error: fn_abi_of(test) = FnAbi { conv: Rust, can_unwind: $SOME_BOOL, } - --> $DIR/debug.rs:27:1 + --> $DIR/debug.rs:30:1 | LL | fn test(_x: u8) -> bool { | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -185,7 +185,7 @@ error: fn_abi_of(TestFnPtr) = FnAbi { conv: Rust, can_unwind: $SOME_BOOL, } - --> $DIR/debug.rs:33:1 + --> $DIR/debug.rs:36:1 | LL | type TestFnPtr = fn(bool) -> u8; | ^^^^^^^^^^^^^^ @@ -263,13 +263,13 @@ error: fn_abi_of(test_generic) = FnAbi { conv: Rust, can_unwind: $SOME_BOOL, } - --> $DIR/debug.rs:36:1 + --> $DIR/debug.rs:39:1 | LL | fn test_generic<T>(_x: *const T) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `#[rustc_abi]` can only be applied to function items, type aliases, and associated functions - --> $DIR/debug.rs:39:1 + --> $DIR/debug.rs:42:1 | LL | const C: () = (); | ^^^^^^^^^^^ @@ -419,7 +419,7 @@ error: ABIs are not compatible conv: Rust, can_unwind: $SOME_BOOL, } - --> $DIR/debug.rs:55:1 + --> $DIR/debug.rs:58:1 | LL | type TestAbiNe = (fn(u8), fn(u32)); | ^^^^^^^^^^^^^^ @@ -571,7 +571,7 @@ error: ABIs are not compatible conv: Rust, can_unwind: $SOME_BOOL, } - --> $DIR/debug.rs:58:1 + --> $DIR/debug.rs:61:1 | LL | type TestAbiNeLarger = (fn([u8; 32]), fn([u32; 32])); | ^^^^^^^^^^^^^^^^^^^^ @@ -720,7 +720,7 @@ error: ABIs are not compatible conv: Rust, can_unwind: $SOME_BOOL, } - --> $DIR/debug.rs:61:1 + --> $DIR/debug.rs:64:1 | LL | type TestAbiNeFloat = (fn(f32), fn(u32)); | ^^^^^^^^^^^^^^^^^^^ @@ -870,13 +870,13 @@ error: ABIs are not compatible conv: Rust, can_unwind: $SOME_BOOL, } - --> $DIR/debug.rs:65:1 + --> $DIR/debug.rs:68:1 | LL | type TestAbiNeSign = (fn(i32), fn(u32)); | ^^^^^^^^^^^^^^^^^^ error[E0277]: the size for values of type `str` cannot be known at compilation time - --> $DIR/debug.rs:68:46 + --> $DIR/debug.rs:71:46 | LL | type TestAbiEqNonsense = (fn((str, str)), fn((str, str))); | ^^^^^^^^^^ doesn't have a size known at compile-time @@ -885,13 +885,13 @@ LL | type TestAbiEqNonsense = (fn((str, str)), fn((str, str))); = note: only the last element of a tuple may have a dynamically sized type error: unrecognized argument - --> $DIR/debug.rs:70:13 + --> $DIR/debug.rs:73:13 | LL | #[rustc_abi("assert_eq")] | ^^^^^^^^^^^ error: `#[rustc_abi]` can only be applied to function items, type aliases, and associated functions - --> $DIR/debug.rs:43:5 + --> $DIR/debug.rs:46:5 | LL | const C: () = (); | ^^^^^^^^^^^ @@ -981,7 +981,7 @@ error: fn_abi_of(assoc_test) = FnAbi { conv: Rust, can_unwind: $SOME_BOOL, } - --> $DIR/debug.rs:48:5 + --> $DIR/debug.rs:51:5 | LL | fn assoc_test(&self) {} | ^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/abi/debug.loongarch64.stderr b/tests/ui/abi/debug.loongarch64.stderr new file mode 100644 index 00000000000..ce8bd41f045 --- /dev/null +++ b/tests/ui/abi/debug.loongarch64.stderr @@ -0,0 +1,991 @@ +error: fn_abi_of(test) = FnAbi { + args: [ + ArgAbi { + layout: TyAndLayout { + ty: u8, + layout: Layout { + size: Size(1 bytes), + align: AbiAlign { + abi: $SOME_ALIGN, + }, + backend_repr: Scalar( + Initialized { + value: Int( + I8, + false, + ), + valid_range: 0..=255, + }, + ), + fields: Primitive, + largest_niche: None, + uninhabited: false, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: $SOME_ALIGN, + randomization_seed: $SEED, + }, + }, + mode: Direct( + ArgAttributes { + regular: NoUndef, + arg_ext: Zext, + pointee_size: Size(0 bytes), + pointee_align: None, + }, + ), + }, + ], + ret: ArgAbi { + layout: TyAndLayout { + ty: bool, + layout: Layout { + size: Size(1 bytes), + align: AbiAlign { + abi: $SOME_ALIGN, + }, + backend_repr: Scalar( + Initialized { + value: Int( + I8, + false, + ), + valid_range: 0..=1, + }, + ), + fields: Primitive, + largest_niche: Some( + Niche { + offset: Size(0 bytes), + value: Int( + I8, + false, + ), + valid_range: 0..=1, + }, + ), + uninhabited: false, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: $SOME_ALIGN, + randomization_seed: $SEED, + }, + }, + mode: Direct( + ArgAttributes { + regular: NoUndef, + arg_ext: Zext, + pointee_size: Size(0 bytes), + pointee_align: None, + }, + ), + }, + c_variadic: false, + fixed_count: 1, + conv: Rust, + can_unwind: $SOME_BOOL, + } + --> $DIR/debug.rs:30:1 + | +LL | fn test(_x: u8) -> bool { + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: fn_abi_of(TestFnPtr) = FnAbi { + args: [ + ArgAbi { + layout: TyAndLayout { + ty: bool, + layout: Layout { + size: Size(1 bytes), + align: AbiAlign { + abi: $SOME_ALIGN, + }, + backend_repr: Scalar( + Initialized { + value: Int( + I8, + false, + ), + valid_range: 0..=1, + }, + ), + fields: Primitive, + largest_niche: Some( + Niche { + offset: Size(0 bytes), + value: Int( + I8, + false, + ), + valid_range: 0..=1, + }, + ), + uninhabited: false, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: $SOME_ALIGN, + randomization_seed: $SEED, + }, + }, + mode: Direct( + ArgAttributes { + regular: NoUndef, + arg_ext: Zext, + pointee_size: Size(0 bytes), + pointee_align: None, + }, + ), + }, + ], + ret: ArgAbi { + layout: TyAndLayout { + ty: u8, + layout: Layout { + size: Size(1 bytes), + align: AbiAlign { + abi: $SOME_ALIGN, + }, + backend_repr: Scalar( + Initialized { + value: Int( + I8, + false, + ), + valid_range: 0..=255, + }, + ), + fields: Primitive, + largest_niche: None, + uninhabited: false, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: $SOME_ALIGN, + randomization_seed: $SEED, + }, + }, + mode: Direct( + ArgAttributes { + regular: NoUndef, + arg_ext: None, + pointee_size: Size(0 bytes), + pointee_align: None, + }, + ), + }, + c_variadic: false, + fixed_count: 1, + conv: Rust, + can_unwind: $SOME_BOOL, + } + --> $DIR/debug.rs:36:1 + | +LL | type TestFnPtr = fn(bool) -> u8; + | ^^^^^^^^^^^^^^ + +error: fn_abi_of(test_generic) = FnAbi { + args: [ + ArgAbi { + layout: TyAndLayout { + ty: *const T, + layout: Layout { + size: $SOME_SIZE, + align: AbiAlign { + abi: $SOME_ALIGN, + }, + backend_repr: Scalar( + Initialized { + value: Pointer( + AddressSpace( + 0, + ), + ), + valid_range: $FULL, + }, + ), + fields: Primitive, + largest_niche: None, + uninhabited: false, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: $SOME_ALIGN, + randomization_seed: $SEED, + }, + }, + mode: Direct( + ArgAttributes { + regular: NoUndef, + arg_ext: None, + pointee_size: Size(0 bytes), + pointee_align: None, + }, + ), + }, + ], + ret: ArgAbi { + layout: TyAndLayout { + ty: (), + layout: Layout { + size: Size(0 bytes), + align: AbiAlign { + abi: $SOME_ALIGN, + }, + backend_repr: Memory { + sized: true, + }, + fields: Arbitrary { + offsets: [], + memory_index: [], + }, + largest_niche: None, + uninhabited: false, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: $SOME_ALIGN, + randomization_seed: $SEED, + }, + }, + mode: Ignore, + }, + c_variadic: false, + fixed_count: 1, + conv: Rust, + can_unwind: $SOME_BOOL, + } + --> $DIR/debug.rs:39:1 + | +LL | fn test_generic<T>(_x: *const T) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `#[rustc_abi]` can only be applied to function items, type aliases, and associated functions + --> $DIR/debug.rs:42:1 + | +LL | const C: () = (); + | ^^^^^^^^^^^ + +error: ABIs are not compatible + left ABI = FnAbi { + args: [ + ArgAbi { + layout: TyAndLayout { + ty: u8, + layout: Layout { + size: Size(1 bytes), + align: AbiAlign { + abi: $SOME_ALIGN, + }, + backend_repr: Scalar( + Initialized { + value: Int( + I8, + false, + ), + valid_range: 0..=255, + }, + ), + fields: Primitive, + largest_niche: None, + uninhabited: false, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: $SOME_ALIGN, + randomization_seed: $SEED, + }, + }, + mode: Direct( + ArgAttributes { + regular: NoUndef, + arg_ext: Zext, + pointee_size: Size(0 bytes), + pointee_align: None, + }, + ), + }, + ], + ret: ArgAbi { + layout: TyAndLayout { + ty: (), + layout: Layout { + size: Size(0 bytes), + align: AbiAlign { + abi: $SOME_ALIGN, + }, + backend_repr: Memory { + sized: true, + }, + fields: Arbitrary { + offsets: [], + memory_index: [], + }, + largest_niche: None, + uninhabited: false, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: $SOME_ALIGN, + randomization_seed: $SEED, + }, + }, + mode: Ignore, + }, + c_variadic: false, + fixed_count: 1, + conv: Rust, + can_unwind: $SOME_BOOL, + } + right ABI = FnAbi { + args: [ + ArgAbi { + layout: TyAndLayout { + ty: u32, + layout: Layout { + size: $SOME_SIZE, + align: AbiAlign { + abi: $SOME_ALIGN, + }, + backend_repr: Scalar( + Initialized { + value: Int( + I32, + false, + ), + valid_range: $FULL, + }, + ), + fields: Primitive, + largest_niche: None, + uninhabited: false, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: $SOME_ALIGN, + randomization_seed: $SEED, + }, + }, + mode: Direct( + ArgAttributes { + regular: NoUndef, + arg_ext: Sext, + pointee_size: Size(0 bytes), + pointee_align: None, + }, + ), + }, + ], + ret: ArgAbi { + layout: TyAndLayout { + ty: (), + layout: Layout { + size: Size(0 bytes), + align: AbiAlign { + abi: $SOME_ALIGN, + }, + backend_repr: Memory { + sized: true, + }, + fields: Arbitrary { + offsets: [], + memory_index: [], + }, + largest_niche: None, + uninhabited: false, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: $SOME_ALIGN, + randomization_seed: $SEED, + }, + }, + mode: Ignore, + }, + c_variadic: false, + fixed_count: 1, + conv: Rust, + can_unwind: $SOME_BOOL, + } + --> $DIR/debug.rs:58:1 + | +LL | type TestAbiNe = (fn(u8), fn(u32)); + | ^^^^^^^^^^^^^^ + +error: ABIs are not compatible + left ABI = FnAbi { + args: [ + ArgAbi { + layout: TyAndLayout { + ty: [u8; 32], + layout: Layout { + size: Size(32 bytes), + align: AbiAlign { + abi: $SOME_ALIGN, + }, + backend_repr: Memory { + sized: true, + }, + fields: Array { + stride: Size(1 bytes), + count: 32, + }, + largest_niche: None, + uninhabited: false, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: $SOME_ALIGN, + randomization_seed: $SEED, + }, + }, + mode: Indirect { + attrs: ArgAttributes { + regular: NoAlias | NoCapture | NonNull | NoUndef, + arg_ext: None, + pointee_size: Size(32 bytes), + pointee_align: Some( + Align(1 bytes), + ), + }, + meta_attrs: None, + on_stack: false, + }, + }, + ], + ret: ArgAbi { + layout: TyAndLayout { + ty: (), + layout: Layout { + size: Size(0 bytes), + align: AbiAlign { + abi: $SOME_ALIGN, + }, + backend_repr: Memory { + sized: true, + }, + fields: Arbitrary { + offsets: [], + memory_index: [], + }, + largest_niche: None, + uninhabited: false, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: $SOME_ALIGN, + randomization_seed: $SEED, + }, + }, + mode: Ignore, + }, + c_variadic: false, + fixed_count: 1, + conv: Rust, + can_unwind: $SOME_BOOL, + } + right ABI = FnAbi { + args: [ + ArgAbi { + layout: TyAndLayout { + ty: [u32; 32], + layout: Layout { + size: Size(128 bytes), + align: AbiAlign { + abi: $SOME_ALIGN, + }, + backend_repr: Memory { + sized: true, + }, + fields: Array { + stride: Size(4 bytes), + count: 32, + }, + largest_niche: None, + uninhabited: false, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: $SOME_ALIGN, + randomization_seed: $SEED, + }, + }, + mode: Indirect { + attrs: ArgAttributes { + regular: NoAlias | NoCapture | NonNull | NoUndef, + arg_ext: None, + pointee_size: Size(128 bytes), + pointee_align: Some( + Align(4 bytes), + ), + }, + meta_attrs: None, + on_stack: false, + }, + }, + ], + ret: ArgAbi { + layout: TyAndLayout { + ty: (), + layout: Layout { + size: Size(0 bytes), + align: AbiAlign { + abi: $SOME_ALIGN, + }, + backend_repr: Memory { + sized: true, + }, + fields: Arbitrary { + offsets: [], + memory_index: [], + }, + largest_niche: None, + uninhabited: false, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: $SOME_ALIGN, + randomization_seed: $SEED, + }, + }, + mode: Ignore, + }, + c_variadic: false, + fixed_count: 1, + conv: Rust, + can_unwind: $SOME_BOOL, + } + --> $DIR/debug.rs:61:1 + | +LL | type TestAbiNeLarger = (fn([u8; 32]), fn([u32; 32])); + | ^^^^^^^^^^^^^^^^^^^^ + +error: ABIs are not compatible + left ABI = FnAbi { + args: [ + ArgAbi { + layout: TyAndLayout { + ty: f32, + layout: Layout { + size: $SOME_SIZE, + align: AbiAlign { + abi: $SOME_ALIGN, + }, + backend_repr: Scalar( + Initialized { + value: Float( + F32, + ), + valid_range: $FULL, + }, + ), + fields: Primitive, + largest_niche: None, + uninhabited: false, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: $SOME_ALIGN, + randomization_seed: $SEED, + }, + }, + mode: Direct( + ArgAttributes { + regular: NoUndef, + arg_ext: None, + pointee_size: Size(0 bytes), + pointee_align: None, + }, + ), + }, + ], + ret: ArgAbi { + layout: TyAndLayout { + ty: (), + layout: Layout { + size: Size(0 bytes), + align: AbiAlign { + abi: $SOME_ALIGN, + }, + backend_repr: Memory { + sized: true, + }, + fields: Arbitrary { + offsets: [], + memory_index: [], + }, + largest_niche: None, + uninhabited: false, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: $SOME_ALIGN, + randomization_seed: $SEED, + }, + }, + mode: Ignore, + }, + c_variadic: false, + fixed_count: 1, + conv: Rust, + can_unwind: $SOME_BOOL, + } + right ABI = FnAbi { + args: [ + ArgAbi { + layout: TyAndLayout { + ty: u32, + layout: Layout { + size: $SOME_SIZE, + align: AbiAlign { + abi: $SOME_ALIGN, + }, + backend_repr: Scalar( + Initialized { + value: Int( + I32, + false, + ), + valid_range: $FULL, + }, + ), + fields: Primitive, + largest_niche: None, + uninhabited: false, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: $SOME_ALIGN, + randomization_seed: $SEED, + }, + }, + mode: Direct( + ArgAttributes { + regular: NoUndef, + arg_ext: Sext, + pointee_size: Size(0 bytes), + pointee_align: None, + }, + ), + }, + ], + ret: ArgAbi { + layout: TyAndLayout { + ty: (), + layout: Layout { + size: Size(0 bytes), + align: AbiAlign { + abi: $SOME_ALIGN, + }, + backend_repr: Memory { + sized: true, + }, + fields: Arbitrary { + offsets: [], + memory_index: [], + }, + largest_niche: None, + uninhabited: false, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: $SOME_ALIGN, + randomization_seed: $SEED, + }, + }, + mode: Ignore, + }, + c_variadic: false, + fixed_count: 1, + conv: Rust, + can_unwind: $SOME_BOOL, + } + --> $DIR/debug.rs:64:1 + | +LL | type TestAbiNeFloat = (fn(f32), fn(u32)); + | ^^^^^^^^^^^^^^^^^^^ + +error: ABIs are not compatible + left ABI = FnAbi { + args: [ + ArgAbi { + layout: TyAndLayout { + ty: i32, + layout: Layout { + size: $SOME_SIZE, + align: AbiAlign { + abi: $SOME_ALIGN, + }, + backend_repr: Scalar( + Initialized { + value: Int( + I32, + true, + ), + valid_range: $FULL, + }, + ), + fields: Primitive, + largest_niche: None, + uninhabited: false, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: $SOME_ALIGN, + randomization_seed: $SEED, + }, + }, + mode: Direct( + ArgAttributes { + regular: NoUndef, + arg_ext: Sext, + pointee_size: Size(0 bytes), + pointee_align: None, + }, + ), + }, + ], + ret: ArgAbi { + layout: TyAndLayout { + ty: (), + layout: Layout { + size: Size(0 bytes), + align: AbiAlign { + abi: $SOME_ALIGN, + }, + backend_repr: Memory { + sized: true, + }, + fields: Arbitrary { + offsets: [], + memory_index: [], + }, + largest_niche: None, + uninhabited: false, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: $SOME_ALIGN, + randomization_seed: $SEED, + }, + }, + mode: Ignore, + }, + c_variadic: false, + fixed_count: 1, + conv: Rust, + can_unwind: $SOME_BOOL, + } + right ABI = FnAbi { + args: [ + ArgAbi { + layout: TyAndLayout { + ty: u32, + layout: Layout { + size: $SOME_SIZE, + align: AbiAlign { + abi: $SOME_ALIGN, + }, + backend_repr: Scalar( + Initialized { + value: Int( + I32, + false, + ), + valid_range: $FULL, + }, + ), + fields: Primitive, + largest_niche: None, + uninhabited: false, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: $SOME_ALIGN, + randomization_seed: $SEED, + }, + }, + mode: Direct( + ArgAttributes { + regular: NoUndef, + arg_ext: Sext, + pointee_size: Size(0 bytes), + pointee_align: None, + }, + ), + }, + ], + ret: ArgAbi { + layout: TyAndLayout { + ty: (), + layout: Layout { + size: Size(0 bytes), + align: AbiAlign { + abi: $SOME_ALIGN, + }, + backend_repr: Memory { + sized: true, + }, + fields: Arbitrary { + offsets: [], + memory_index: [], + }, + largest_niche: None, + uninhabited: false, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: $SOME_ALIGN, + randomization_seed: $SEED, + }, + }, + mode: Ignore, + }, + c_variadic: false, + fixed_count: 1, + conv: Rust, + can_unwind: $SOME_BOOL, + } + --> $DIR/debug.rs:68:1 + | +LL | type TestAbiNeSign = (fn(i32), fn(u32)); + | ^^^^^^^^^^^^^^^^^^ + +error[E0277]: the size for values of type `str` cannot be known at compilation time + --> $DIR/debug.rs:71:46 + | +LL | type TestAbiEqNonsense = (fn((str, str)), fn((str, str))); + | ^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `str` + = note: only the last element of a tuple may have a dynamically sized type + +error: unrecognized argument + --> $DIR/debug.rs:73:13 + | +LL | #[rustc_abi("assert_eq")] + | ^^^^^^^^^^^ + +error: `#[rustc_abi]` can only be applied to function items, type aliases, and associated functions + --> $DIR/debug.rs:46:5 + | +LL | const C: () = (); + | ^^^^^^^^^^^ + +error: fn_abi_of(assoc_test) = FnAbi { + args: [ + ArgAbi { + layout: TyAndLayout { + ty: &S, + layout: Layout { + size: $SOME_SIZE, + align: AbiAlign { + abi: $SOME_ALIGN, + }, + backend_repr: Scalar( + Initialized { + value: Pointer( + AddressSpace( + 0, + ), + ), + valid_range: $NON_NULL, + }, + ), + fields: Primitive, + largest_niche: Some( + Niche { + offset: Size(0 bytes), + value: Pointer( + AddressSpace( + 0, + ), + ), + valid_range: $NON_NULL, + }, + ), + uninhabited: false, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: $SOME_ALIGN, + randomization_seed: $SEED, + }, + }, + mode: Direct( + ArgAttributes { + regular: NoAlias | NonNull | ReadOnly | NoUndef | CapturesReadOnly, + arg_ext: None, + pointee_size: Size(2 bytes), + pointee_align: Some( + Align(2 bytes), + ), + }, + ), + }, + ], + ret: ArgAbi { + layout: TyAndLayout { + ty: (), + layout: Layout { + size: Size(0 bytes), + align: AbiAlign { + abi: $SOME_ALIGN, + }, + backend_repr: Memory { + sized: true, + }, + fields: Arbitrary { + offsets: [], + memory_index: [], + }, + largest_niche: None, + uninhabited: false, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: $SOME_ALIGN, + randomization_seed: $SEED, + }, + }, + mode: Ignore, + }, + c_variadic: false, + fixed_count: 1, + conv: Rust, + can_unwind: $SOME_BOOL, + } + --> $DIR/debug.rs:51:5 + | +LL | fn assoc_test(&self) {} + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 12 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/abi/debug.riscv64.stderr b/tests/ui/abi/debug.riscv64.stderr index bddf0aea3d7..ce8bd41f045 100644 --- a/tests/ui/abi/debug.riscv64.stderr +++ b/tests/ui/abi/debug.riscv64.stderr @@ -89,7 +89,7 @@ error: fn_abi_of(test) = FnAbi { conv: Rust, can_unwind: $SOME_BOOL, } - --> $DIR/debug.rs:27:1 + --> $DIR/debug.rs:30:1 | LL | fn test(_x: u8) -> bool { | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -185,7 +185,7 @@ error: fn_abi_of(TestFnPtr) = FnAbi { conv: Rust, can_unwind: $SOME_BOOL, } - --> $DIR/debug.rs:33:1 + --> $DIR/debug.rs:36:1 | LL | type TestFnPtr = fn(bool) -> u8; | ^^^^^^^^^^^^^^ @@ -263,13 +263,13 @@ error: fn_abi_of(test_generic) = FnAbi { conv: Rust, can_unwind: $SOME_BOOL, } - --> $DIR/debug.rs:36:1 + --> $DIR/debug.rs:39:1 | LL | fn test_generic<T>(_x: *const T) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `#[rustc_abi]` can only be applied to function items, type aliases, and associated functions - --> $DIR/debug.rs:39:1 + --> $DIR/debug.rs:42:1 | LL | const C: () = (); | ^^^^^^^^^^^ @@ -419,7 +419,7 @@ error: ABIs are not compatible conv: Rust, can_unwind: $SOME_BOOL, } - --> $DIR/debug.rs:55:1 + --> $DIR/debug.rs:58:1 | LL | type TestAbiNe = (fn(u8), fn(u32)); | ^^^^^^^^^^^^^^ @@ -571,7 +571,7 @@ error: ABIs are not compatible conv: Rust, can_unwind: $SOME_BOOL, } - --> $DIR/debug.rs:58:1 + --> $DIR/debug.rs:61:1 | LL | type TestAbiNeLarger = (fn([u8; 32]), fn([u32; 32])); | ^^^^^^^^^^^^^^^^^^^^ @@ -720,7 +720,7 @@ error: ABIs are not compatible conv: Rust, can_unwind: $SOME_BOOL, } - --> $DIR/debug.rs:61:1 + --> $DIR/debug.rs:64:1 | LL | type TestAbiNeFloat = (fn(f32), fn(u32)); | ^^^^^^^^^^^^^^^^^^^ @@ -870,13 +870,13 @@ error: ABIs are not compatible conv: Rust, can_unwind: $SOME_BOOL, } - --> $DIR/debug.rs:65:1 + --> $DIR/debug.rs:68:1 | LL | type TestAbiNeSign = (fn(i32), fn(u32)); | ^^^^^^^^^^^^^^^^^^ error[E0277]: the size for values of type `str` cannot be known at compilation time - --> $DIR/debug.rs:68:46 + --> $DIR/debug.rs:71:46 | LL | type TestAbiEqNonsense = (fn((str, str)), fn((str, str))); | ^^^^^^^^^^ doesn't have a size known at compile-time @@ -885,13 +885,13 @@ LL | type TestAbiEqNonsense = (fn((str, str)), fn((str, str))); = note: only the last element of a tuple may have a dynamically sized type error: unrecognized argument - --> $DIR/debug.rs:70:13 + --> $DIR/debug.rs:73:13 | LL | #[rustc_abi("assert_eq")] | ^^^^^^^^^^^ error: `#[rustc_abi]` can only be applied to function items, type aliases, and associated functions - --> $DIR/debug.rs:43:5 + --> $DIR/debug.rs:46:5 | LL | const C: () = (); | ^^^^^^^^^^^ @@ -981,7 +981,7 @@ error: fn_abi_of(assoc_test) = FnAbi { conv: Rust, can_unwind: $SOME_BOOL, } - --> $DIR/debug.rs:48:5 + --> $DIR/debug.rs:51:5 | LL | fn assoc_test(&self) {} | ^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/abi/debug.rs b/tests/ui/abi/debug.rs index cc1589d8621..59c0908041d 100644 --- a/tests/ui/abi/debug.rs +++ b/tests/ui/abi/debug.rs @@ -8,10 +8,13 @@ //@ normalize-stderr: "(valid_range): [1-9]\.\.=(429496729[0-9]|1844674407370955161[0-9])" -> "$1: $$NON_NULL" // Some attributes are only computed for release builds: //@ compile-flags: -O -//@ revisions: generic riscv64 +//@ revisions: generic riscv64 loongarch64 //@ [riscv64] compile-flags: --target riscv64gc-unknown-linux-gnu //@ [riscv64] needs-llvm-components: riscv +//@ [loongarch64] compile-flags: --target loongarch64-unknown-linux-gnu +//@ [loongarch64] needs-llvm-components: loongarch //@ [generic] ignore-riscv64 +//@ [generic] ignore-loongarch64 #![feature(rustc_attrs)] #![crate_type = "lib"] #![feature(no_core)] diff --git a/tests/ui/abi/simd-abi-checks-s390x.rs b/tests/ui/abi/simd-abi-checks-s390x.rs index 2d4eb7a350f..877a25e8b08 100644 --- a/tests/ui/abi/simd-abi-checks-s390x.rs +++ b/tests/ui/abi/simd-abi-checks-s390x.rs @@ -110,47 +110,47 @@ extern "C" fn vector_transparent_wrapper_ret_large( #[no_mangle] extern "C" fn vector_arg_small(x: i8x8) -> i64 { //~^ ERROR requires the `vector` target feature, which is not enabled - unsafe { *(&x as *const i8x8 as *const i64) } + unsafe { *(&raw const x as *const i64) } } #[no_mangle] extern "C" fn vector_arg(x: i8x16) -> i64 { //~^ ERROR requires the `vector` target feature, which is not enabled - unsafe { *(&x as *const i8x16 as *const i64) } + unsafe { *(&raw const x as *const i64) } } #[no_mangle] extern "C" fn vector_arg_large(x: i8x32) -> i64 { // Ok - unsafe { *(&x as *const i8x32 as *const i64) } + unsafe { *(&raw const x as *const i64) } } #[no_mangle] extern "C" fn vector_wrapper_arg_small(x: Wrapper<i8x8>) -> i64 { //~^ ERROR requires the `vector` target feature, which is not enabled - unsafe { *(&x as *const Wrapper<i8x8> as *const i64) } + unsafe { *(&raw const x as *const i64) } } #[no_mangle] extern "C" fn vector_wrapper_arg(x: Wrapper<i8x16>) -> i64 { //~^ ERROR requires the `vector` target feature, which is not enabled - unsafe { *(&x as *const Wrapper<i8x16> as *const i64) } + unsafe { *(&raw const x as *const i64) } } #[no_mangle] extern "C" fn vector_wrapper_arg_large(x: Wrapper<i8x32>) -> i64 { // Ok - unsafe { *(&x as *const Wrapper<i8x32> as *const i64) } + unsafe { *(&raw const x as *const i64) } } #[no_mangle] extern "C" fn vector_transparent_wrapper_arg_small(x: TransparentWrapper<i8x8>) -> i64 { //~^ ERROR requires the `vector` target feature, which is not enabled - unsafe { *(&x as *const TransparentWrapper<i8x8> as *const i64) } + unsafe { *(&raw const x as *const i64) } } #[no_mangle] extern "C" fn vector_transparent_wrapper_arg(x: TransparentWrapper<i8x16>) -> i64 { //~^ ERROR requires the `vector` target feature, which is not enabled - unsafe { *(&x as *const TransparentWrapper<i8x16> as *const i64) } + unsafe { *(&raw const x as *const i64) } } #[no_mangle] extern "C" fn vector_transparent_wrapper_arg_large(x: TransparentWrapper<i8x32>) -> i64 { // Ok - unsafe { *(&x as *const TransparentWrapper<i8x32> as *const i64) } + unsafe { *(&raw const x as *const i64) } } diff --git a/tests/ui/asm/naked-invalid-attr.stderr b/tests/ui/asm/naked-invalid-attr.stderr index 936a36cd92e..33bbfc885da 100644 --- a/tests/ui/asm/naked-invalid-attr.stderr +++ b/tests/ui/asm/naked-invalid-attr.stderr @@ -18,7 +18,7 @@ error: `#[naked]` attribute cannot be used on foreign functions LL | #[unsafe(naked)] | ^^^^^^^^^^^^^^^^ | - = help: `#[naked]` can be applied to methods, functions + = help: `#[naked]` can be applied to methods and functions error: `#[naked]` attribute cannot be used on structs --> $DIR/naked-invalid-attr.rs:13:1 @@ -42,7 +42,7 @@ error: `#[naked]` attribute cannot be used on required trait methods LL | #[unsafe(naked)] | ^^^^^^^^^^^^^^^^ | - = help: `#[naked]` can be applied to functions, inherent methods, provided trait methods, trait methods in impl blocks + = help: `#[naked]` can be applied to functions, inherent methods, provided trait methods, and trait methods in impl blocks error: `#[naked]` attribute cannot be used on closures --> $DIR/naked-invalid-attr.rs:51:5 @@ -50,7 +50,7 @@ error: `#[naked]` attribute cannot be used on closures LL | #[unsafe(naked)] | ^^^^^^^^^^^^^^^^ | - = help: `#[naked]` can be applied to methods, functions + = help: `#[naked]` can be applied to methods and functions error[E0736]: attribute incompatible with `#[unsafe(naked)]` --> $DIR/naked-invalid-attr.rs:56:3 diff --git a/tests/ui/associated-consts/issue-105330.stderr b/tests/ui/associated-consts/issue-105330.stderr index 72527193555..5d6dc48e36c 100644 --- a/tests/ui/associated-consts/issue-105330.stderr +++ b/tests/ui/associated-consts/issue-105330.stderr @@ -53,8 +53,13 @@ error[E0277]: the trait bound `Demo: TraitWAssocConst` is not satisfied --> $DIR/issue-105330.rs:12:11 | LL | foo::<Demo>()(); - | ^^^^ the trait `TraitWAssocConst` is not implemented for `Demo` + | ^^^^ unsatisfied trait bound | +help: the trait `TraitWAssocConst` is not implemented for `Demo` + --> $DIR/issue-105330.rs:4:1 + | +LL | pub struct Demo {} + | ^^^^^^^^^^^^^^^ note: required by a bound in `foo` --> $DIR/issue-105330.rs:11:11 | @@ -75,8 +80,13 @@ error[E0277]: the trait bound `Demo: TraitWAssocConst` is not satisfied --> $DIR/issue-105330.rs:20:11 | LL | foo::<Demo>(); - | ^^^^ the trait `TraitWAssocConst` is not implemented for `Demo` + | ^^^^ unsatisfied trait bound + | +help: the trait `TraitWAssocConst` is not implemented for `Demo` + --> $DIR/issue-105330.rs:4:1 | +LL | pub struct Demo {} + | ^^^^^^^^^^^^^^^ note: required by a bound in `foo` --> $DIR/issue-105330.rs:11:11 | diff --git a/tests/ui/associated-types/defaults-suitability.current.stderr b/tests/ui/associated-types/defaults-suitability.current.stderr index 5e19674250f..0018181f480 100644 --- a/tests/ui/associated-types/defaults-suitability.current.stderr +++ b/tests/ui/associated-types/defaults-suitability.current.stderr @@ -73,8 +73,13 @@ error[E0277]: the trait bound `NotClone: IsU8<NotClone>` is not satisfied --> $DIR/defaults-suitability.rs:59:18 | LL | type Assoc = NotClone; - | ^^^^^^^^ the trait `IsU8<NotClone>` is not implemented for `NotClone` + | ^^^^^^^^ unsatisfied trait bound | +help: the trait `IsU8<NotClone>` is not implemented for `NotClone` + --> $DIR/defaults-suitability.rs:12:1 + | +LL | struct NotClone; + | ^^^^^^^^^^^^^^^ note: required by a bound in `D::Assoc` --> $DIR/defaults-suitability.rs:56:18 | diff --git a/tests/ui/associated-types/defaults-suitability.next.stderr b/tests/ui/associated-types/defaults-suitability.next.stderr index 5e19674250f..0018181f480 100644 --- a/tests/ui/associated-types/defaults-suitability.next.stderr +++ b/tests/ui/associated-types/defaults-suitability.next.stderr @@ -73,8 +73,13 @@ error[E0277]: the trait bound `NotClone: IsU8<NotClone>` is not satisfied --> $DIR/defaults-suitability.rs:59:18 | LL | type Assoc = NotClone; - | ^^^^^^^^ the trait `IsU8<NotClone>` is not implemented for `NotClone` + | ^^^^^^^^ unsatisfied trait bound | +help: the trait `IsU8<NotClone>` is not implemented for `NotClone` + --> $DIR/defaults-suitability.rs:12:1 + | +LL | struct NotClone; + | ^^^^^^^^^^^^^^^ note: required by a bound in `D::Assoc` --> $DIR/defaults-suitability.rs:56:18 | diff --git a/tests/ui/associated-types/issue-64855.stderr b/tests/ui/associated-types/issue-64855.stderr index d8ba1a9d07e..4358ab47365 100644 --- a/tests/ui/associated-types/issue-64855.stderr +++ b/tests/ui/associated-types/issue-64855.stderr @@ -2,8 +2,13 @@ error[E0277]: the trait bound `Bar<T>: Foo` is not satisfied --> $DIR/issue-64855.rs:9:19 | LL | pub struct Bar<T>(<Self as Foo>::Type) where Self: ; - | ^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `Bar<T>` + | ^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound | +help: the trait `Foo` is not implemented for `Bar<T>` + --> $DIR/issue-64855.rs:9:1 + | +LL | pub struct Bar<T>(<Self as Foo>::Type) where Self: ; + | ^^^^^^^^^^^^^^^^^ help: this trait has no implementations, consider adding one --> $DIR/issue-64855.rs:5:1 | diff --git a/tests/ui/associated-types/issue-65774-1.stderr b/tests/ui/associated-types/issue-65774-1.stderr index 9c77a25c432..3c8da092158 100644 --- a/tests/ui/associated-types/issue-65774-1.stderr +++ b/tests/ui/associated-types/issue-65774-1.stderr @@ -2,8 +2,13 @@ error[E0277]: the trait bound `T: MyDisplay` is not satisfied --> $DIR/issue-65774-1.rs:10:33 | LL | type MpuConfig: MyDisplay = T; - | ^ the trait `MyDisplay` is not implemented for `T` + | ^ unsatisfied trait bound | +help: the trait `MyDisplay` is not implemented for `T` + --> $DIR/issue-65774-1.rs:7:1 + | +LL | struct T; + | ^^^^^^^^ = help: the trait `MyDisplay` is implemented for `&'a mut T` note: required by a bound in `MPU::MpuConfig` --> $DIR/issue-65774-1.rs:10:21 @@ -15,8 +20,13 @@ error[E0277]: the trait bound `T: MyDisplay` is not satisfied --> $DIR/issue-65774-1.rs:44:76 | LL | let closure = |config: &mut <S as MPU>::MpuConfig| writer.my_write(&config); - | ^^^^^^^ the trait `MyDisplay` is not implemented for `T` + | ^^^^^^^ unsatisfied trait bound + | +help: the trait `MyDisplay` is not implemented for `T` + --> $DIR/issue-65774-1.rs:7:1 | +LL | struct T; + | ^^^^^^^^ = help: the trait `MyDisplay` is implemented for `&'a mut T` note: required for `&mut T` to implement `MyDisplay` --> $DIR/issue-65774-1.rs:5:24 diff --git a/tests/ui/associated-types/issue-65774-2.stderr b/tests/ui/associated-types/issue-65774-2.stderr index ca8a727f0fe..82210b84992 100644 --- a/tests/ui/associated-types/issue-65774-2.stderr +++ b/tests/ui/associated-types/issue-65774-2.stderr @@ -2,8 +2,13 @@ error[E0277]: the trait bound `T: MyDisplay` is not satisfied --> $DIR/issue-65774-2.rs:10:33 | LL | type MpuConfig: MyDisplay = T; - | ^ the trait `MyDisplay` is not implemented for `T` + | ^ unsatisfied trait bound | +help: the trait `MyDisplay` is not implemented for `T` + --> $DIR/issue-65774-2.rs:7:1 + | +LL | struct T; + | ^^^^^^^^ = help: the trait `MyDisplay` is implemented for `&'a mut T` note: required by a bound in `MPU::MpuConfig` --> $DIR/issue-65774-2.rs:10:21 @@ -15,8 +20,13 @@ error[E0277]: the trait bound `T: MyDisplay` is not satisfied --> $DIR/issue-65774-2.rs:39:25 | LL | writer.my_write(valref) - | ^^^^^^ the trait `MyDisplay` is not implemented for `T` + | ^^^^^^ unsatisfied trait bound + | +help: the trait `MyDisplay` is not implemented for `T` + --> $DIR/issue-65774-2.rs:7:1 | +LL | struct T; + | ^^^^^^^^ = help: the trait `MyDisplay` is implemented for `&'a mut T` = note: required for the cast from `&mut T` to `&dyn MyDisplay` diff --git a/tests/ui/async-await/async-fn/impl-header.stderr b/tests/ui/async-await/async-fn/impl-header.stderr index 2fc7a900a1e..d0cf0d822f2 100644 --- a/tests/ui/async-await/async-fn/impl-header.stderr +++ b/tests/ui/async-await/async-fn/impl-header.stderr @@ -36,7 +36,11 @@ error[E0277]: expected a `FnMut()` closure, found `F` LL | impl async Fn<()> for F {} | ^ expected an `FnMut()` closure, found `F` | - = help: the trait `FnMut()` is not implemented for `F` +help: the trait `FnMut()` is not implemented for `F` + --> $DIR/impl-header.rs:3:1 + | +LL | struct F; + | ^^^^^^^^ = note: wrap the `F` in a closure with no arguments: `|| { /* code */ }` note: required by a bound in `Fn` --> $SRC_DIR/core/src/ops/function.rs:LL:COL diff --git a/tests/ui/async-await/issue-61076.rs b/tests/ui/async-await/issue-61076.rs index f78abfd6d0f..0a679a95970 100644 --- a/tests/ui/async-await/issue-61076.rs +++ b/tests/ui/async-await/issue-61076.rs @@ -4,7 +4,7 @@ use core::future::Future; use core::pin::Pin; use core::task::{Context, Poll}; -struct T; +struct T; //~ HELP the trait `Try` is not implemented for `T` struct Tuple(i32); @@ -61,11 +61,9 @@ async fn baz() -> Result<(), ()> { let t = T; t?; //~ ERROR the `?` operator can only be applied to values that implement `Try` //~^ NOTE the `?` operator cannot be applied to type `T` - //~| HELP the trait `Try` is not implemented for `T` //~| HELP consider `await`ing on the `Future` //~| NOTE in this expansion of desugaring of operator `?` //~| NOTE in this expansion of desugaring of operator `?` - //~| NOTE in this expansion of desugaring of operator `?` let _: i32 = tuple().0; //~ ERROR no field `0` diff --git a/tests/ui/async-await/issue-61076.stderr b/tests/ui/async-await/issue-61076.stderr index b8478c8d138..7d46abe4a66 100644 --- a/tests/ui/async-await/issue-61076.stderr +++ b/tests/ui/async-await/issue-61076.stderr @@ -16,14 +16,18 @@ error[E0277]: the `?` operator can only be applied to values that implement `Try LL | t?; | ^^ the `?` operator cannot be applied to type `T` | - = help: the trait `Try` is not implemented for `T` +help: the trait `Try` is not implemented for `T` + --> $DIR/issue-61076.rs:7:1 + | +LL | struct T; + | ^^^^^^^^ help: consider `await`ing on the `Future` | LL | t.await?; | ++++++ error[E0609]: no field `0` on type `impl Future<Output = Tuple>` - --> $DIR/issue-61076.rs:71:26 + --> $DIR/issue-61076.rs:69:26 | LL | let _: i32 = tuple().0; | ^ field not available in `impl Future`, but it is available in its `Output` @@ -34,7 +38,7 @@ LL | let _: i32 = tuple().await.0; | ++++++ error[E0609]: no field `a` on type `impl Future<Output = Struct>` - --> $DIR/issue-61076.rs:75:28 + --> $DIR/issue-61076.rs:73:28 | LL | let _: i32 = struct_().a; | ^ field not available in `impl Future`, but it is available in its `Output` @@ -45,7 +49,7 @@ LL | let _: i32 = struct_().await.a; | ++++++ error[E0599]: no method named `method` found for opaque type `impl Future<Output = Struct>` in the current scope - --> $DIR/issue-61076.rs:79:15 + --> $DIR/issue-61076.rs:77:15 | LL | struct_().method(); | ^^^^^^ method not found in `impl Future<Output = Struct>` @@ -56,7 +60,7 @@ LL | struct_().await.method(); | ++++++ error[E0308]: mismatched types - --> $DIR/issue-61076.rs:88:9 + --> $DIR/issue-61076.rs:86:9 | LL | match tuple() { | ------- this expression has type `impl Future<Output = Tuple>` diff --git a/tests/ui/async-await/issue-64130-1-sync.stderr b/tests/ui/async-await/issue-64130-1-sync.stderr index 5428d7ef71b..6bc4810daad 100644 --- a/tests/ui/async-await/issue-64130-1-sync.stderr +++ b/tests/ui/async-await/issue-64130-1-sync.stderr @@ -4,7 +4,11 @@ error: future cannot be shared between threads safely LL | is_sync(bar()); | ^^^^^ future returned by `bar` is not `Sync` | - = help: within `impl Future<Output = ()>`, the trait `Sync` is not implemented for `Foo` +help: within `impl Future<Output = ()>`, the trait `Sync` is not implemented for `Foo` + --> $DIR/issue-64130-1-sync.rs:7:1 + | +LL | struct Foo; + | ^^^^^^^^^^ note: future is not `Sync` as this value is used across an await --> $DIR/issue-64130-1-sync.rs:15:11 | diff --git a/tests/ui/async-await/issue-64130-2-send.stderr b/tests/ui/async-await/issue-64130-2-send.stderr index f05e954d2d7..99c249843b8 100644 --- a/tests/ui/async-await/issue-64130-2-send.stderr +++ b/tests/ui/async-await/issue-64130-2-send.stderr @@ -4,7 +4,11 @@ error: future cannot be sent between threads safely LL | is_send(bar()); | ^^^^^ future returned by `bar` is not `Send` | - = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Foo` +help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Foo` + --> $DIR/issue-64130-2-send.rs:7:1 + | +LL | struct Foo; + | ^^^^^^^^^^ note: future is not `Send` as this value is used across an await --> $DIR/issue-64130-2-send.rs:15:11 | diff --git a/tests/ui/async-await/issue-64130-3-other.stderr b/tests/ui/async-await/issue-64130-3-other.stderr index 3ac30bdc23e..d683366ed47 100644 --- a/tests/ui/async-await/issue-64130-3-other.stderr +++ b/tests/ui/async-await/issue-64130-3-other.stderr @@ -5,8 +5,13 @@ LL | async fn bar() { | -------------- within this `impl Future<Output = ()>` ... LL | is_qux(bar()); - | ^^^^^ within `impl Future<Output = ()>`, the trait `Qux` is not implemented for `Foo` + | ^^^^^ unsatisfied trait bound | +help: within `impl Future<Output = ()>`, the trait `Qux` is not implemented for `Foo` + --> $DIR/issue-64130-3-other.rs:10:1 + | +LL | struct Foo; + | ^^^^^^^^^^ note: future does not implement `Qux` as this value is used across an await --> $DIR/issue-64130-3-other.rs:18:11 | diff --git a/tests/ui/async-await/partial-drop-partial-reinit.stderr b/tests/ui/async-await/partial-drop-partial-reinit.stderr index 042ed18984e..cef835f7aed 100644 --- a/tests/ui/async-await/partial-drop-partial-reinit.stderr +++ b/tests/ui/async-await/partial-drop-partial-reinit.stderr @@ -9,7 +9,11 @@ LL | gimme_send(foo()); LL | async fn foo() { | -------------- within this `impl Future<Output = ()>` | - = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `NotSend` +help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `NotSend` + --> $DIR/partial-drop-partial-reinit.rs:19:1 + | +LL | struct NotSend {} + | ^^^^^^^^^^^^^^ = note: required because it appears within the type `(NotSend,)` note: required because it's used within this `async` fn body --> $DIR/partial-drop-partial-reinit.rs:27:16 diff --git a/tests/ui/attributes/key-value-expansion.stderr b/tests/ui/attributes/key-value-expansion.stderr index 54d79c5bebb..d785bf97819 100644 --- a/tests/ui/attributes/key-value-expansion.stderr +++ b/tests/ui/attributes/key-value-expansion.stderr @@ -1,10 +1,4 @@ error: attribute value must be a literal - --> $DIR/key-value-expansion.rs:21:6 - | -LL | bug!((column!())); - | ^^^^^^^^^^^ - -error: attribute value must be a literal --> $DIR/key-value-expansion.rs:27:14 | LL | bug!("bug" + stringify!(found)); @@ -26,5 +20,11 @@ LL | some_macro!(u8); | = note: this error originates in the macro `some_macro` (in Nightly builds, run with -Z macro-backtrace for more info) +error: attribute value must be a literal + --> $DIR/key-value-expansion.rs:21:6 + | +LL | bug!((column!())); + | ^^^^^^^^^^^ + error: aborting due to 3 previous errors diff --git a/tests/ui/attributes/linkage.stderr b/tests/ui/attributes/linkage.stderr index 2e7ff0e7936..d2aee384058 100644 --- a/tests/ui/attributes/linkage.stderr +++ b/tests/ui/attributes/linkage.stderr @@ -4,7 +4,7 @@ error: `#[linkage]` attribute cannot be used on type aliases LL | #[linkage = "weak"] | ^^^^^^^^^^^^^^^^^^^ | - = help: `#[linkage]` can be applied to functions, statics, foreign statics + = help: `#[linkage]` can be applied to functions, statics, and foreign statics error: `#[linkage]` attribute cannot be used on modules --> $DIR/linkage.rs:9:1 @@ -12,7 +12,7 @@ error: `#[linkage]` attribute cannot be used on modules LL | #[linkage = "weak"] | ^^^^^^^^^^^^^^^^^^^ | - = help: `#[linkage]` can be applied to functions, statics, foreign statics + = help: `#[linkage]` can be applied to functions, statics, and foreign statics error: `#[linkage]` attribute cannot be used on structs --> $DIR/linkage.rs:12:1 @@ -20,7 +20,7 @@ error: `#[linkage]` attribute cannot be used on structs LL | #[linkage = "weak"] | ^^^^^^^^^^^^^^^^^^^ | - = help: `#[linkage]` can be applied to functions, statics, foreign statics + = help: `#[linkage]` can be applied to functions, statics, and foreign statics error: `#[linkage]` attribute cannot be used on inherent impl blocks --> $DIR/linkage.rs:15:1 @@ -28,7 +28,7 @@ error: `#[linkage]` attribute cannot be used on inherent impl blocks LL | #[linkage = "weak"] | ^^^^^^^^^^^^^^^^^^^ | - = help: `#[linkage]` can be applied to functions, statics, foreign statics + = help: `#[linkage]` can be applied to functions, statics, and foreign statics error: `#[linkage]` attribute cannot be used on expressions --> $DIR/linkage.rs:23:5 @@ -36,7 +36,7 @@ error: `#[linkage]` attribute cannot be used on expressions LL | #[linkage = "weak"] | ^^^^^^^^^^^^^^^^^^^ | - = help: `#[linkage]` can be applied to functions, statics, foreign statics + = help: `#[linkage]` can be applied to functions, statics, and foreign statics error: `#[linkage]` attribute cannot be used on closures --> $DIR/linkage.rs:39:13 @@ -44,7 +44,7 @@ error: `#[linkage]` attribute cannot be used on closures LL | let _ = #[linkage = "weak"] | ^^^^^^^^^^^^^^^^^^^ | - = help: `#[linkage]` can be applied to methods, functions, statics, foreign statics, foreign functions + = help: `#[linkage]` can be applied to methods, functions, statics, foreign statics, and foreign functions error: aborting due to 6 previous errors diff --git a/tests/ui/attributes/malformed-fn-align.rs b/tests/ui/attributes/malformed-fn-align.rs index adce84763ab..c76eda65a75 100644 --- a/tests/ui/attributes/malformed-fn-align.rs +++ b/tests/ui/attributes/malformed-fn-align.rs @@ -26,7 +26,7 @@ fn f3() {} #[repr(align(16))] //~ ERROR `#[repr(align(...))]` is not supported on functions fn f4() {} -#[rustc_align(-1)] //~ ERROR expected unsuffixed literal, found `-` +#[rustc_align(-1)] //~ ERROR expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `-` fn f5() {} #[rustc_align(3)] //~ ERROR invalid alignment value: not a power of two diff --git a/tests/ui/attributes/malformed-fn-align.stderr b/tests/ui/attributes/malformed-fn-align.stderr index 346fe2b4b7f..33f789b6269 100644 --- a/tests/ui/attributes/malformed-fn-align.stderr +++ b/tests/ui/attributes/malformed-fn-align.stderr @@ -1,17 +1,3 @@ -error: expected unsuffixed literal, found `-` - --> $DIR/malformed-fn-align.rs:29:15 - | -LL | #[rustc_align(-1)] - | ^ - -error: suffixed literals are not allowed in attributes - --> $DIR/malformed-fn-align.rs:35:15 - | -LL | #[rustc_align(4usize)] - | ^^^^^^ - | - = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.) - error[E0539]: malformed `rustc_align` attribute input --> $DIR/malformed-fn-align.rs:10:5 | @@ -51,12 +37,32 @@ error[E0589]: invalid alignment value: not a power of two LL | #[rustc_align(0)] | ^ +error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `-` + --> $DIR/malformed-fn-align.rs:29:15 + | +LL | #[rustc_align(-1)] + | ^ + | +help: negative numbers are not literals, try removing the `-` sign + | +LL - #[rustc_align(-1)] +LL + #[rustc_align(1)] + | + error[E0589]: invalid alignment value: not a power of two --> $DIR/malformed-fn-align.rs:32:15 | LL | #[rustc_align(3)] | ^ +error: suffixed literals are not allowed in attributes + --> $DIR/malformed-fn-align.rs:35:15 + | +LL | #[rustc_align(4usize)] + | ^^^^^^ + | + = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.) + error[E0589]: invalid alignment value: not an unsuffixed integer --> $DIR/malformed-fn-align.rs:35:15 | diff --git a/tests/ui/attributes/nonterminal-expansion.rs b/tests/ui/attributes/nonterminal-expansion.rs index 004a8a23fd6..ff2b36f7d27 100644 --- a/tests/ui/attributes/nonterminal-expansion.rs +++ b/tests/ui/attributes/nonterminal-expansion.rs @@ -5,7 +5,7 @@ macro_rules! pass_nonterminal { ($n:expr) => { #[repr(align($n))] - //~^ ERROR expected unsuffixed literal, found `expr` metavariable + //~^ ERROR expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `expr` metavariable struct S; }; } @@ -15,6 +15,5 @@ macro_rules! n { } pass_nonterminal!(n!()); -//~^ ERROR incorrect `repr(align)` attribute format: `align` expects a literal integer as argument [E0693] fn main() {} diff --git a/tests/ui/attributes/nonterminal-expansion.stderr b/tests/ui/attributes/nonterminal-expansion.stderr index 9c6cb98f619..21912de2106 100644 --- a/tests/ui/attributes/nonterminal-expansion.stderr +++ b/tests/ui/attributes/nonterminal-expansion.stderr @@ -1,4 +1,4 @@ -error: expected unsuffixed literal, found `expr` metavariable +error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `expr` metavariable --> $DIR/nonterminal-expansion.rs:7:22 | LL | #[repr(align($n))] @@ -9,12 +9,5 @@ LL | pass_nonterminal!(n!()); | = note: this error originates in the macro `pass_nonterminal` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0693]: incorrect `repr(align)` attribute format: `align` expects a literal integer as argument - --> $DIR/nonterminal-expansion.rs:17:19 - | -LL | pass_nonterminal!(n!()); - | ^ - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0693`. diff --git a/tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr b/tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr index 107e053ae0c..94edb263a6a 100644 --- a/tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr +++ b/tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr @@ -28,17 +28,6 @@ LL | #[unsafe(proc_macro_derive(Foo))] | = note: extraneous unsafe is not allowed in attributes -error: expected identifier, found keyword `unsafe` - --> $DIR/proc-unsafe-attributes.rs:12:21 - | -LL | #[proc_macro_derive(unsafe(Foo))] - | ^^^^^^ expected identifier, found keyword - | -help: escape `unsafe` to use it as an identifier - | -LL | #[proc_macro_derive(r#unsafe(Foo))] - | ++ - error: `proc_macro_attribute` is not an unsafe attribute --> $DIR/proc-unsafe-attributes.rs:18:3 | @@ -114,6 +103,17 @@ LL | #[unsafe(allow(unsafe(dead_code)))] | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +error: expected identifier, found keyword `unsafe` + --> $DIR/proc-unsafe-attributes.rs:12:21 + | +LL | #[proc_macro_derive(unsafe(Foo))] + | ^^^^^^ expected identifier, found keyword + | +help: escape `unsafe` to use it as an identifier + | +LL | #[proc_macro_derive(r#unsafe(Foo))] + | ++ + error[E0565]: malformed `proc_macro_derive` attribute input --> $DIR/proc-unsafe-attributes.rs:12:1 | diff --git a/tests/ui/auto-traits/issue-83857-ub.stderr b/tests/ui/auto-traits/issue-83857-ub.stderr index 3536450c75b..9bfdecf6f54 100644 --- a/tests/ui/auto-traits/issue-83857-ub.stderr +++ b/tests/ui/auto-traits/issue-83857-ub.stderr @@ -4,7 +4,11 @@ error[E0277]: `Foo<T, U>` cannot be sent between threads safely LL | fn generic<T, U>(v: Foo<T, U>, f: fn(<Foo<T, U> as WithAssoc>::Output) -> i32) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Foo<T, U>` cannot be sent between threads safely | - = help: the trait `Send` is not implemented for `Foo<T, U>` +help: the trait `Send` is not implemented for `Foo<T, U>` + --> $DIR/issue-83857-ub.rs:6:1 + | +LL | struct Foo<T, U>(Always<T, U>); + | ^^^^^^^^^^^^^^^^ note: required for `Foo<T, U>` to implement `WithAssoc` --> $DIR/issue-83857-ub.rs:14:15 | @@ -23,7 +27,11 @@ error[E0277]: `Foo<T, U>` cannot be sent between threads safely LL | fn generic<T, U>(v: Foo<T, U>, f: fn(<Foo<T, U> as WithAssoc>::Output) -> i32) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Foo<T, U>` cannot be sent between threads safely | - = help: the trait `Send` is not implemented for `Foo<T, U>` +help: the trait `Send` is not implemented for `Foo<T, U>` + --> $DIR/issue-83857-ub.rs:6:1 + | +LL | struct Foo<T, U>(Always<T, U>); + | ^^^^^^^^^^^^^^^^ note: required for `Foo<T, U>` to implement `WithAssoc` --> $DIR/issue-83857-ub.rs:14:15 | @@ -44,7 +52,11 @@ LL | f(foo(v)); | | | required by a bound introduced by this call | - = help: the trait `Send` is not implemented for `Foo<T, U>` +help: the trait `Send` is not implemented for `Foo<T, U>` + --> $DIR/issue-83857-ub.rs:6:1 + | +LL | struct Foo<T, U>(Always<T, U>); + | ^^^^^^^^^^^^^^^^ note: required by a bound in `foo` --> $DIR/issue-83857-ub.rs:28:11 | diff --git a/tests/ui/auto-traits/typeck-default-trait-impl-constituent-types-2.stderr b/tests/ui/auto-traits/typeck-default-trait-impl-constituent-types-2.stderr index aa5585a5371..c948e1b1051 100644 --- a/tests/ui/auto-traits/typeck-default-trait-impl-constituent-types-2.stderr +++ b/tests/ui/auto-traits/typeck-default-trait-impl-constituent-types-2.stderr @@ -2,8 +2,13 @@ error[E0277]: the trait bound `MyS2: MyTrait` is not satisfied in `(MyS2, MyS)` --> $DIR/typeck-default-trait-impl-constituent-types-2.rs:17:18 | LL | is_mytrait::<(MyS2, MyS)>(); - | ^^^^^^^^^^^ within `(MyS2, MyS)`, the trait `MyTrait` is not implemented for `MyS2` + | ^^^^^^^^^^^ unsatisfied trait bound | +help: within `(MyS2, MyS)`, the trait `MyTrait` is not implemented for `MyS2` + --> $DIR/typeck-default-trait-impl-constituent-types-2.rs:8:1 + | +LL | struct MyS2; + | ^^^^^^^^^^^ = note: required because it appears within the type `(MyS2, MyS)` note: required by a bound in `is_mytrait` --> $DIR/typeck-default-trait-impl-constituent-types-2.rs:12:18 diff --git a/tests/ui/auto-traits/typeck-default-trait-impl-constituent-types.stderr b/tests/ui/auto-traits/typeck-default-trait-impl-constituent-types.stderr index 668cbc8aeb4..ae33aeff6e2 100644 --- a/tests/ui/auto-traits/typeck-default-trait-impl-constituent-types.stderr +++ b/tests/ui/auto-traits/typeck-default-trait-impl-constituent-types.stderr @@ -2,8 +2,13 @@ error[E0277]: the trait bound `MyS2: MyTrait` is not satisfied --> $DIR/typeck-default-trait-impl-constituent-types.rs:21:18 | LL | is_mytrait::<MyS2>(); - | ^^^^ the trait `MyTrait` is not implemented for `MyS2` + | ^^^^ unsatisfied trait bound | +help: the trait `MyTrait` is not implemented for `MyS2` + --> $DIR/typeck-default-trait-impl-constituent-types.rs:10:1 + | +LL | struct MyS2; + | ^^^^^^^^^^^ note: required by a bound in `is_mytrait` --> $DIR/typeck-default-trait-impl-constituent-types.rs:16:18 | diff --git a/tests/ui/auto-traits/typeck-default-trait-impl-negation.stderr b/tests/ui/auto-traits/typeck-default-trait-impl-negation.stderr index fa8dd41da23..4b10262c2e2 100644 --- a/tests/ui/auto-traits/typeck-default-trait-impl-negation.stderr +++ b/tests/ui/auto-traits/typeck-default-trait-impl-negation.stderr @@ -2,8 +2,13 @@ error[E0277]: the trait bound `ThisImplsUnsafeTrait: MyTrait` is not satisfied --> $DIR/typeck-default-trait-impl-negation.rs:22:19 | LL | is_my_trait::<ThisImplsUnsafeTrait>(); - | ^^^^^^^^^^^^^^^^^^^^ the trait `MyTrait` is not implemented for `ThisImplsUnsafeTrait` + | ^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound | +help: the trait `MyTrait` is not implemented for `ThisImplsUnsafeTrait` + --> $DIR/typeck-default-trait-impl-negation.rs:13:1 + | +LL | struct ThisImplsUnsafeTrait; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: required by a bound in `is_my_trait` --> $DIR/typeck-default-trait-impl-negation.rs:17:19 | @@ -14,8 +19,13 @@ error[E0277]: the trait bound `ThisImplsTrait: MyUnsafeTrait` is not satisfied --> $DIR/typeck-default-trait-impl-negation.rs:25:26 | LL | is_my_unsafe_trait::<ThisImplsTrait>(); - | ^^^^^^^^^^^^^^ the trait `MyUnsafeTrait` is not implemented for `ThisImplsTrait` + | ^^^^^^^^^^^^^^ unsatisfied trait bound + | +help: the trait `MyUnsafeTrait` is not implemented for `ThisImplsTrait` + --> $DIR/typeck-default-trait-impl-negation.rs:8:1 | +LL | struct ThisImplsTrait; + | ^^^^^^^^^^^^^^^^^^^^^ note: required by a bound in `is_my_unsafe_trait` --> $DIR/typeck-default-trait-impl-negation.rs:18:26 | diff --git a/tests/ui/c-variadic/same-program-multiple-abis-arm.rs b/tests/ui/c-variadic/same-program-multiple-abis-arm.rs new file mode 100644 index 00000000000..1b0bdecabfb --- /dev/null +++ b/tests/ui/c-variadic/same-program-multiple-abis-arm.rs @@ -0,0 +1,77 @@ +#![feature(extended_varargs_abi_support)] +//@ run-pass +//@ only-arm +//@ ignore-thumb (this test uses arm assembly) +//@ only-eabihf (the assembly below requires float hardware support) + +// Check that multiple c-variadic calling conventions can be used in the same program. +// +// Clang and gcc reject defining functions with a non-default calling convention and a variable +// argument list, so C programs that use multiple c-variadic calling conventions are unlikely +// to come up. Here we validate that our codegen backends do in fact generate correct code. + +extern "C" { + fn variadic_c(_: f64, _: ...) -> f64; +} + +extern "aapcs" { + fn variadic_aapcs(_: f64, _: ...) -> f64; +} + +fn main() { + unsafe { + assert_eq!(variadic_c(1.0, 2.0, 3.0), 1.0 + 2.0 + 3.0); + assert_eq!(variadic_aapcs(1.0, 2.0, 3.0), 1.0 + 2.0 + 3.0); + } +} + +// This assembly was generated using https://godbolt.org/z/xcW6a1Tj5, and corresponds to the +// following code compiled for the `armv7-unknown-linux-gnueabihf` target: +// +// ```rust +// #![feature(c_variadic)] +// +// #[unsafe(no_mangle)] +// unsafe extern "C" fn variadic(a: f64, mut args: ...) -> f64 { +// let b = args.arg::<f64>(); +// let c = args.arg::<f64>(); +// +// a + b + c +// } +// ``` +// +// This function uses floats (and passes one normal float argument) because the aapcs and C calling +// conventions differ in how floats are passed, e.g. https://godbolt.org/z/sz799f51x. However, for +// c-variadic functions, both ABIs actually behave the same, based on: +// +// https://github.com/ARM-software/abi-aa/blob/main/aapcs32/aapcs32.rst#65parameter-passing +// +// > A variadic function is always marshaled as for the base standard. +// +// https://github.com/ARM-software/abi-aa/blob/main/aapcs32/aapcs32.rst#7the-standard-variants +// +// > This section applies only to non-variadic functions. For a variadic function the base standard +// > is always used both for argument passing and result return. +core::arch::global_asm!( + r#" +{variadic_c}: +{variadic_aapcs}: + sub sp, sp, #12 + stmib sp, {{r2, r3}} + vmov d0, r0, r1 + add r0, sp, #4 + vldr d1, [sp, #4] + add r0, r0, #15 + bic r0, r0, #7 + vadd.f64 d0, d0, d1 + add r1, r0, #8 + str r1, [sp] + vldr d1, [r0] + vadd.f64 d0, d0, d1 + vmov r0, r1, d0 + add sp, sp, #12 + bx lr + "#, + variadic_c = sym variadic_c, + variadic_aapcs = sym variadic_aapcs, +); diff --git a/tests/ui/c-variadic/same-program-multiple-abis.rs b/tests/ui/c-variadic/same-program-multiple-abis-x86_64.rs index b21accb999e..b21accb999e 100644 --- a/tests/ui/c-variadic/same-program-multiple-abis.rs +++ b/tests/ui/c-variadic/same-program-multiple-abis-x86_64.rs diff --git a/tests/ui/closures/issue-52437.rs b/tests/ui/closures/issue-52437.rs index 6ac5380a5aa..98b04d179af 100644 --- a/tests/ui/closures/issue-52437.rs +++ b/tests/ui/closures/issue-52437.rs @@ -1,5 +1,5 @@ fn main() { [(); &(&'static: loop { |x| {}; }) as *const _ as usize] - //~^ ERROR: invalid label name `'static` + //~^ ERROR: labels cannot use keyword names //~| ERROR: type annotations needed } diff --git a/tests/ui/closures/issue-52437.stderr b/tests/ui/closures/issue-52437.stderr index 9ba24c7a886..8c6fa097ec5 100644 --- a/tests/ui/closures/issue-52437.stderr +++ b/tests/ui/closures/issue-52437.stderr @@ -1,4 +1,4 @@ -error: invalid label name `'static` +error: labels cannot use keyword names --> $DIR/issue-52437.rs:2:13 | LL | [(); &(&'static: loop { |x| {}; }) as *const _ as usize] diff --git a/tests/ui/coherence/fuzzing/best-obligation-ICE.stderr b/tests/ui/coherence/fuzzing/best-obligation-ICE.stderr index fe28f4ff136..dedc8951041 100644 --- a/tests/ui/coherence/fuzzing/best-obligation-ICE.stderr +++ b/tests/ui/coherence/fuzzing/best-obligation-ICE.stderr @@ -11,8 +11,13 @@ error[E0277]: the trait bound `W<W<T>>: Trait` is not satisfied --> $DIR/best-obligation-ICE.rs:10:19 | LL | impl<T> Trait for W<W<W<T>>> {} - | ^^^^^^^^^^ the trait `Trait` is not implemented for `W<W<T>>` + | ^^^^^^^^^^ unsatisfied trait bound | +help: the trait `Trait` is not implemented for `W<W<T>>` + --> $DIR/best-obligation-ICE.rs:9:1 + | +LL | struct W<T: Trait>(*mut T); + | ^^^^^^^^^^^^^^^^^^ note: required by a bound in `W` --> $DIR/best-obligation-ICE.rs:9:13 | @@ -27,8 +32,13 @@ error[E0277]: the trait bound `W<T>: Trait` is not satisfied --> $DIR/best-obligation-ICE.rs:10:19 | LL | impl<T> Trait for W<W<W<T>>> {} - | ^^^^^^^^^^ the trait `Trait` is not implemented for `W<T>` + | ^^^^^^^^^^ unsatisfied trait bound | +help: the trait `Trait` is not implemented for `W<T>` + --> $DIR/best-obligation-ICE.rs:9:1 + | +LL | struct W<T: Trait>(*mut T); + | ^^^^^^^^^^^^^^^^^^ note: required by a bound in `W` --> $DIR/best-obligation-ICE.rs:9:13 | diff --git a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs index 126a534dc6f..2c84a966f90 100644 --- a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs +++ b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs @@ -43,7 +43,7 @@ struct S9; macro_rules! generate_s10 { ($expr: expr) => { #[cfg(feature = $expr)] - //~^ ERROR expected unsuffixed literal, found `expr` metavariable + //~^ ERROR expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `expr` metavariable struct S10; } } diff --git a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr index 6acde758ea5..59ff611e066 100644 --- a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr +++ b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr @@ -81,7 +81,7 @@ LL | #[cfg(a = b"hi")] | = note: expected a normal string literal, not a byte string literal -error: expected unsuffixed literal, found `expr` metavariable +error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `expr` metavariable --> $DIR/cfg-attr-syntax-validation.rs:45:25 | LL | #[cfg(feature = $expr)] diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_bad_empty_array.stderr b/tests/ui/const-generics/adt_const_params/const_param_ty_bad_empty_array.stderr index 9220cd1f94e..373ac9435da 100644 --- a/tests/ui/const-generics/adt_const_params/const_param_ty_bad_empty_array.stderr +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_bad_empty_array.stderr @@ -2,8 +2,13 @@ error[E0277]: `NotParam` can't be used as a const parameter type --> $DIR/const_param_ty_bad_empty_array.rs:10:13 | LL | check::<[NotParam; 0]>(); - | ^^^^^^^^^^^^^ the trait `ConstParamTy_` is not implemented for `NotParam` + | ^^^^^^^^^^^^^ unsatisfied trait bound | +help: the trait `ConstParamTy_` is not implemented for `NotParam` + --> $DIR/const_param_ty_bad_empty_array.rs:5:1 + | +LL | struct NotParam; + | ^^^^^^^^^^^^^^^ = note: required for `[NotParam; 0]` to implement `ConstParamTy_` note: required by a bound in `check` --> $DIR/const_param_ty_bad_empty_array.rs:7:13 diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_generic_bounds_do_not_hold.stderr b/tests/ui/const-generics/adt_const_params/const_param_ty_generic_bounds_do_not_hold.stderr index d01aaffe8ae..158e76630f3 100644 --- a/tests/ui/const-generics/adt_const_params/const_param_ty_generic_bounds_do_not_hold.stderr +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_generic_bounds_do_not_hold.stderr @@ -2,8 +2,13 @@ error[E0277]: `NotParam` can't be used as a const parameter type --> $DIR/const_param_ty_generic_bounds_do_not_hold.rs:10:13 | LL | check::<&NotParam>(); - | ^^^^^^^^^ the trait `UnsizedConstParamTy` is not implemented for `NotParam` + | ^^^^^^^^^ unsatisfied trait bound | +help: the trait `UnsizedConstParamTy` is not implemented for `NotParam` + --> $DIR/const_param_ty_generic_bounds_do_not_hold.rs:5:1 + | +LL | struct NotParam; + | ^^^^^^^^^^^^^^^ = note: required for `&NotParam` to implement `UnsizedConstParamTy` note: required by a bound in `check` --> $DIR/const_param_ty_generic_bounds_do_not_hold.rs:7:13 @@ -15,8 +20,13 @@ error[E0277]: `NotParam` can't be used as a const parameter type --> $DIR/const_param_ty_generic_bounds_do_not_hold.rs:11:13 | LL | check::<[NotParam]>(); - | ^^^^^^^^^^ the trait `UnsizedConstParamTy` is not implemented for `NotParam` + | ^^^^^^^^^^ unsatisfied trait bound + | +help: the trait `UnsizedConstParamTy` is not implemented for `NotParam` + --> $DIR/const_param_ty_generic_bounds_do_not_hold.rs:5:1 | +LL | struct NotParam; + | ^^^^^^^^^^^^^^^ = note: required for `[NotParam]` to implement `UnsizedConstParamTy` note: required by a bound in `check` --> $DIR/const_param_ty_generic_bounds_do_not_hold.rs:7:13 @@ -28,8 +38,13 @@ error[E0277]: `NotParam` can't be used as a const parameter type --> $DIR/const_param_ty_generic_bounds_do_not_hold.rs:12:13 | LL | check::<[NotParam; 17]>(); - | ^^^^^^^^^^^^^^ the trait `UnsizedConstParamTy` is not implemented for `NotParam` + | ^^^^^^^^^^^^^^ unsatisfied trait bound + | +help: the trait `UnsizedConstParamTy` is not implemented for `NotParam` + --> $DIR/const_param_ty_generic_bounds_do_not_hold.rs:5:1 | +LL | struct NotParam; + | ^^^^^^^^^^^^^^^ = note: required for `[NotParam; 17]` to implement `UnsizedConstParamTy` note: required by a bound in `check` --> $DIR/const_param_ty_generic_bounds_do_not_hold.rs:7:13 diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.stderr b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.stderr index b651cca3216..d3141381db8 100644 --- a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.stderr +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.stderr @@ -16,8 +16,13 @@ error[E0277]: the type `CantParam` does not `#[derive(PartialEq)]` --> $DIR/const_param_ty_impl_no_structural_eq.rs:10:43 | LL | impl std::marker::UnsizedConstParamTy for CantParam {} - | ^^^^^^^^^ the trait `StructuralPartialEq` is not implemented for `CantParam` + | ^^^^^^^^^ unsatisfied trait bound | +help: the trait `StructuralPartialEq` is not implemented for `CantParam` + --> $DIR/const_param_ty_impl_no_structural_eq.rs:8:1 + | +LL | struct CantParam(ImplementsConstParamTy); + | ^^^^^^^^^^^^^^^^ note: required by a bound in `UnsizedConstParamTy` --> $SRC_DIR/core/src/marker.rs:LL:COL @@ -39,8 +44,13 @@ error[E0277]: the type `CantParamDerive` does not `#[derive(PartialEq)]` --> $DIR/const_param_ty_impl_no_structural_eq.rs:14:10 | LL | #[derive(std::marker::UnsizedConstParamTy)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `StructuralPartialEq` is not implemented for `CantParamDerive` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound | +help: the trait `StructuralPartialEq` is not implemented for `CantParamDerive` + --> $DIR/const_param_ty_impl_no_structural_eq.rs:17:1 + | +LL | struct CantParamDerive(ImplementsConstParamTy); + | ^^^^^^^^^^^^^^^^^^^^^^ note: required by a bound in `UnsizedConstParamTy` --> $SRC_DIR/core/src/marker.rs:LL:COL diff --git a/tests/ui/const-generics/defaults/rp_impl_trait_fail.stderr b/tests/ui/const-generics/defaults/rp_impl_trait_fail.stderr index e36f645b263..65c480d7c49 100644 --- a/tests/ui/const-generics/defaults/rp_impl_trait_fail.stderr +++ b/tests/ui/const-generics/defaults/rp_impl_trait_fail.stderr @@ -2,11 +2,16 @@ error[E0277]: the trait bound `Uwu<10, 12>: Trait` is not satisfied --> $DIR/rp_impl_trait_fail.rs:6:14 | LL | fn rawr() -> impl Trait { - | ^^^^^^^^^^ the trait `Trait` is not implemented for `Uwu<10, 12>` + | ^^^^^^^^^^ unsatisfied trait bound LL | LL | Uwu::<10, 12> | ------------- return type was inferred to be `Uwu<10, 12>` here | +help: the trait `Trait` is not implemented for `Uwu<10, 12>` + --> $DIR/rp_impl_trait_fail.rs:1:1 + | +LL | struct Uwu<const N: u32 = 1, const M: u32 = N>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = help: the trait `Trait` is implemented for `Uwu<N>` error[E0277]: the trait bound `u32: Traitor<N>` is not satisfied diff --git a/tests/ui/const-generics/occurs-check/unused-substs-1.stderr b/tests/ui/const-generics/occurs-check/unused-substs-1.stderr index 07e86aa17f2..70fc71c99b9 100644 --- a/tests/ui/const-generics/occurs-check/unused-substs-1.stderr +++ b/tests/ui/const-generics/occurs-check/unused-substs-1.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `A<_>: Bar<_>` is not satisfied --> $DIR/unused-substs-1.rs:12:13 | LL | let _ = A; - | ^ the trait `Bar<_>` is not implemented for `A<_>` + | ^ unsatisfied trait bound | = help: the trait `Bar<_>` is not implemented for `A<_>` but it is implemented for `A<{ 6 + 1 }>` diff --git a/tests/ui/const-generics/transmute-fail.stderr b/tests/ui/const-generics/transmute-fail.stderr index 0e26daa3a0f..953119a8c34 100644 --- a/tests/ui/const-generics/transmute-fail.stderr +++ b/tests/ui/const-generics/transmute-fail.stderr @@ -6,6 +6,14 @@ LL | fn bar<const W: bool, const H: usize>(v: [[u32; H]; W]) -> [[u32; W]; H] { | = note: the length of array `[[u32; H]; W]` must be type `usize` +error: the constant `W` is not of type `usize` + --> $DIR/transmute-fail.rs:19:9 + | +LL | std::mem::transmute(v) + | ^^^^^^^^^^^^^^^^^^^ expected `usize`, found `bool` + | + = note: the length of array `[[u32; H]; W]` must be type `usize` + error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> $DIR/transmute-fail.rs:11:9 | @@ -15,14 +23,6 @@ LL | std::mem::transmute(v) = note: source type: `[[u32; H + 1]; W]` (size can vary because of [u32; H + 1]) = note: target type: `[[u32; W + 1]; H]` (size can vary because of [u32; W + 1]) -error: the constant `W` is not of type `usize` - --> $DIR/transmute-fail.rs:19:9 - | -LL | std::mem::transmute(v) - | ^^^^^^^^^^^^^^^^^^^ expected `usize`, found `bool` - | - = note: the length of array `[[u32; H]; W]` must be type `usize` - error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> $DIR/transmute-fail.rs:26:9 | diff --git a/tests/ui/consts/transmute-size-mismatch-before-typeck.rs b/tests/ui/consts/transmute-size-mismatch-before-typeck.rs index ffb143da2d4..4e0b12b9021 100644 --- a/tests/ui/consts/transmute-size-mismatch-before-typeck.rs +++ b/tests/ui/consts/transmute-size-mismatch-before-typeck.rs @@ -1,5 +1,9 @@ +//@ normalize-stderr-64bit: "8-byte" -> "word size" +//@ normalize-stderr-32bit: "4-byte" -> "word size" //@ normalize-stderr-64bit: "64 bits" -> "word size" //@ normalize-stderr-32bit: "32 bits" -> "word size" +//@ normalize-stderr-64bit: "16-byte" -> "2 * word size" +//@ normalize-stderr-32bit: "8-byte" -> "2 * word size" //@ normalize-stderr-64bit: "128 bits" -> "2 * word size" //@ normalize-stderr-32bit: "64 bits" -> "2 * word size" @@ -10,4 +14,5 @@ fn main() { } const ZST: &[u8] = unsafe { std::mem::transmute(1usize) }; -//~^ ERROR cannot transmute between types of different sizes +//~^ ERROR transmuting from +//~| ERROR cannot transmute between types of different sizes diff --git a/tests/ui/consts/transmute-size-mismatch-before-typeck.stderr b/tests/ui/consts/transmute-size-mismatch-before-typeck.stderr index 6bc7e7203aa..bb847f79ace 100644 --- a/tests/ui/consts/transmute-size-mismatch-before-typeck.stderr +++ b/tests/ui/consts/transmute-size-mismatch-before-typeck.stderr @@ -1,5 +1,11 @@ +error[E0080]: transmuting from word size type to 2 * word size type: `usize` -> `&[u8]` + --> $DIR/transmute-size-mismatch-before-typeck.rs:16:29 + | +LL | const ZST: &[u8] = unsafe { std::mem::transmute(1usize) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `ZST` failed here + error[E0512]: cannot transmute between types of different sizes, or dependently-sized types - --> $DIR/transmute-size-mismatch-before-typeck.rs:12:29 + --> $DIR/transmute-size-mismatch-before-typeck.rs:16:29 | LL | const ZST: &[u8] = unsafe { std::mem::transmute(1usize) }; | ^^^^^^^^^^^^^^^^^^^ @@ -7,6 +13,7 @@ LL | const ZST: &[u8] = unsafe { std::mem::transmute(1usize) }; = note: source type: `usize` (word size) = note: target type: `&[u8]` (2 * word size) -error: aborting due to 1 previous error +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0512`. +Some errors have detailed explanations: E0080, E0512. +For more information about an error, try `rustc --explain E0080`. diff --git a/tests/ui/coroutine/drop-tracking-parent-expression.stderr b/tests/ui/coroutine/drop-tracking-parent-expression.stderr index 2f5fe882f6e..fe8c17c1294 100644 --- a/tests/ui/coroutine/drop-tracking-parent-expression.stderr +++ b/tests/ui/coroutine/drop-tracking-parent-expression.stderr @@ -12,7 +12,11 @@ LL | | }; LL | | ); | |_____- in this macro invocation | - = help: within `{coroutine@$DIR/drop-tracking-parent-expression.rs:19:34: 19:41}`, the trait `Send` is not implemented for `derived_drop::Client` +help: within `{coroutine@$DIR/drop-tracking-parent-expression.rs:19:34: 19:41}`, the trait `Send` is not implemented for `derived_drop::Client` + --> $DIR/drop-tracking-parent-expression.rs:51:46 + | +LL | derived_drop => { #[derive(Default)] pub struct Client { pub nickname: String } }; + | ^^^^^^^^^^^^^^^^^ note: coroutine is not `Send` as this value is used across a yield --> $DIR/drop-tracking-parent-expression.rs:23:22 | @@ -50,7 +54,11 @@ LL | | }; LL | | ); | |_____- in this macro invocation | - = help: within `{coroutine@$DIR/drop-tracking-parent-expression.rs:19:34: 19:41}`, the trait `Send` is not implemented for `significant_drop::Client` +help: within `{coroutine@$DIR/drop-tracking-parent-expression.rs:19:34: 19:41}`, the trait `Send` is not implemented for `significant_drop::Client` + --> $DIR/drop-tracking-parent-expression.rs:55:13 + | +LL | pub struct Client; + | ^^^^^^^^^^^^^^^^^ note: coroutine is not `Send` as this value is used across a yield --> $DIR/drop-tracking-parent-expression.rs:23:22 | @@ -88,7 +96,11 @@ LL | | }; LL | | ); | |_____- in this macro invocation | - = help: within `{coroutine@$DIR/drop-tracking-parent-expression.rs:19:34: 19:41}`, the trait `Send` is not implemented for `insignificant_dtor::Client` +help: within `{coroutine@$DIR/drop-tracking-parent-expression.rs:19:34: 19:41}`, the trait `Send` is not implemented for `insignificant_dtor::Client` + --> $DIR/drop-tracking-parent-expression.rs:64:13 + | +LL | pub struct Client; + | ^^^^^^^^^^^^^^^^^ note: coroutine is not `Send` as this value is used across a yield --> $DIR/drop-tracking-parent-expression.rs:23:22 | diff --git a/tests/ui/coroutine/drop-yield-twice.stderr b/tests/ui/coroutine/drop-yield-twice.stderr index c5da35d9736..5ac2b471cb6 100644 --- a/tests/ui/coroutine/drop-yield-twice.stderr +++ b/tests/ui/coroutine/drop-yield-twice.stderr @@ -9,7 +9,11 @@ LL | | yield; LL | | }) | |______^ coroutine is not `Send` | - = help: within `{coroutine@$DIR/drop-yield-twice.rs:7:30: 7:32}`, the trait `Send` is not implemented for `Foo` +help: within `{coroutine@$DIR/drop-yield-twice.rs:7:30: 7:32}`, the trait `Send` is not implemented for `Foo` + --> $DIR/drop-yield-twice.rs:3:1 + | +LL | struct Foo(i32); + | ^^^^^^^^^^ note: coroutine is not `Send` as this value is used across a yield --> $DIR/drop-yield-twice.rs:9:9 | diff --git a/tests/ui/coroutine/not-send-sync.stderr b/tests/ui/coroutine/not-send-sync.stderr index c6d2ac0a557..16277edd66a 100644 --- a/tests/ui/coroutine/not-send-sync.stderr +++ b/tests/ui/coroutine/not-send-sync.stderr @@ -9,7 +9,11 @@ LL | | drop(a); LL | | }); | |______^ coroutine is not `Sync` | - = help: within `{coroutine@$DIR/not-send-sync.rs:14:30: 14:32}`, the trait `Sync` is not implemented for `NotSync` +help: within `{coroutine@$DIR/not-send-sync.rs:14:30: 14:32}`, the trait `Sync` is not implemented for `NotSync` + --> $DIR/not-send-sync.rs:5:1 + | +LL | struct NotSync; + | ^^^^^^^^^^^^^^ note: coroutine is not `Sync` as this value is used across a yield --> $DIR/not-send-sync.rs:17:9 | @@ -34,7 +38,11 @@ LL | | drop(a); LL | | }); | |______^ coroutine is not `Send` | - = help: within `{coroutine@$DIR/not-send-sync.rs:21:30: 21:32}`, the trait `Send` is not implemented for `NotSend` +help: within `{coroutine@$DIR/not-send-sync.rs:21:30: 21:32}`, the trait `Send` is not implemented for `NotSend` + --> $DIR/not-send-sync.rs:4:1 + | +LL | struct NotSend; + | ^^^^^^^^^^^^^^ note: coroutine is not `Send` as this value is used across a yield --> $DIR/not-send-sync.rs:24:9 | diff --git a/tests/ui/coroutine/parent-expression.stderr b/tests/ui/coroutine/parent-expression.stderr index f14bf05ed09..0dd97c538a8 100644 --- a/tests/ui/coroutine/parent-expression.stderr +++ b/tests/ui/coroutine/parent-expression.stderr @@ -12,7 +12,11 @@ LL | | }; LL | | ); | |_____- in this macro invocation | - = help: within `{coroutine@$DIR/parent-expression.rs:19:34: 19:41}`, the trait `Send` is not implemented for `derived_drop::Client` +help: within `{coroutine@$DIR/parent-expression.rs:19:34: 19:41}`, the trait `Send` is not implemented for `derived_drop::Client` + --> $DIR/parent-expression.rs:51:46 + | +LL | derived_drop => { #[derive(Default)] pub struct Client { pub nickname: String } }; + | ^^^^^^^^^^^^^^^^^ note: coroutine is not `Send` as this value is used across a yield --> $DIR/parent-expression.rs:23:22 | @@ -50,7 +54,11 @@ LL | | }; LL | | ); | |_____- in this macro invocation | - = help: within `{coroutine@$DIR/parent-expression.rs:19:34: 19:41}`, the trait `Send` is not implemented for `significant_drop::Client` +help: within `{coroutine@$DIR/parent-expression.rs:19:34: 19:41}`, the trait `Send` is not implemented for `significant_drop::Client` + --> $DIR/parent-expression.rs:55:13 + | +LL | pub struct Client; + | ^^^^^^^^^^^^^^^^^ note: coroutine is not `Send` as this value is used across a yield --> $DIR/parent-expression.rs:23:22 | @@ -88,7 +96,11 @@ LL | | }; LL | | ); | |_____- in this macro invocation | - = help: within `{coroutine@$DIR/parent-expression.rs:19:34: 19:41}`, the trait `Send` is not implemented for `insignificant_dtor::Client` +help: within `{coroutine@$DIR/parent-expression.rs:19:34: 19:41}`, the trait `Send` is not implemented for `insignificant_dtor::Client` + --> $DIR/parent-expression.rs:64:13 + | +LL | pub struct Client; + | ^^^^^^^^^^^^^^^^^ note: coroutine is not `Send` as this value is used across a yield --> $DIR/parent-expression.rs:23:22 | diff --git a/tests/ui/coroutine/print/coroutine-print-verbose-2.stderr b/tests/ui/coroutine/print/coroutine-print-verbose-2.stderr index 11b78e3bcf8..d27660c67d9 100644 --- a/tests/ui/coroutine/print/coroutine-print-verbose-2.stderr +++ b/tests/ui/coroutine/print/coroutine-print-verbose-2.stderr @@ -9,7 +9,11 @@ LL | | drop(a); LL | | }); | |______^ coroutine is not `Sync` | - = help: within `{main::{closure#0} upvar_tys=() resume_ty=() yield_ty=() return_ty=()}`, the trait `Sync` is not implemented for `NotSync` +help: within `{main::{closure#0} upvar_tys=() resume_ty=() yield_ty=() return_ty=()}`, the trait `Sync` is not implemented for `NotSync` + --> $DIR/coroutine-print-verbose-2.rs:8:1 + | +LL | struct NotSync; + | ^^^^^^^^^^^^^^ note: coroutine is not `Sync` as this value is used across a yield --> $DIR/coroutine-print-verbose-2.rs:20:9 | @@ -34,7 +38,11 @@ LL | | drop(a); LL | | }); | |______^ coroutine is not `Send` | - = help: within `{main::{closure#1} upvar_tys=() resume_ty=() yield_ty=() return_ty=()}`, the trait `Send` is not implemented for `NotSend` +help: within `{main::{closure#1} upvar_tys=() resume_ty=() yield_ty=() return_ty=()}`, the trait `Send` is not implemented for `NotSend` + --> $DIR/coroutine-print-verbose-2.rs:7:1 + | +LL | struct NotSend; + | ^^^^^^^^^^^^^^ note: coroutine is not `Send` as this value is used across a yield --> $DIR/coroutine-print-verbose-2.rs:27:9 | diff --git a/tests/ui/coroutine/static-closure-unexpanded.rs b/tests/ui/coroutine/static-closure-unexpanded.rs new file mode 100644 index 00000000000..7cf24774ded --- /dev/null +++ b/tests/ui/coroutine/static-closure-unexpanded.rs @@ -0,0 +1,10 @@ +// Tests that static closures are not stable in the parser grammar unless the +// coroutine feature is enabled. + +#[cfg(any())] +fn foo() { + let _ = static || {}; + //~^ ERROR coroutine syntax is experimental +} + +fn main() {} diff --git a/tests/ui/coroutine/static-closure-unexpanded.stderr b/tests/ui/coroutine/static-closure-unexpanded.stderr new file mode 100644 index 00000000000..f08bafd368f --- /dev/null +++ b/tests/ui/coroutine/static-closure-unexpanded.stderr @@ -0,0 +1,13 @@ +error[E0658]: coroutine syntax is experimental + --> $DIR/static-closure-unexpanded.rs:6:13 + | +LL | let _ = static || {}; + | ^^^^^^ + | + = note: see issue #43122 <https://github.com/rust-lang/rust/issues/43122> for more information + = help: add `#![feature(coroutines)]` 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 1 previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/coverage-attr/allowed-positions.stderr b/tests/ui/coverage-attr/allowed-positions.stderr index aaef3ad0203..1690d089a8c 100644 --- a/tests/ui/coverage-attr/allowed-positions.stderr +++ b/tests/ui/coverage-attr/allowed-positions.stderr @@ -14,7 +14,7 @@ error: `#[coverage]` attribute cannot be used on type aliases LL | #[coverage(off)] | ^^^^^^^^^^^^^^^^ | - = help: `#[coverage]` can be applied to functions, impl blocks, modules, crates + = help: `#[coverage]` can be applied to functions, impl blocks, modules, and crates error: `#[coverage]` attribute cannot be used on traits --> $DIR/allowed-positions.rs:17:1 @@ -22,7 +22,7 @@ error: `#[coverage]` attribute cannot be used on traits LL | #[coverage(off)] | ^^^^^^^^^^^^^^^^ | - = help: `#[coverage]` can be applied to functions, impl blocks, modules, crates + = help: `#[coverage]` can be applied to functions, impl blocks, modules, and crates error: `#[coverage]` attribute cannot be used on associated consts --> $DIR/allowed-positions.rs:19:5 @@ -30,7 +30,7 @@ error: `#[coverage]` attribute cannot be used on associated consts LL | #[coverage(off)] | ^^^^^^^^^^^^^^^^ | - = help: `#[coverage]` can be applied to functions, impl blocks, modules, crates + = help: `#[coverage]` can be applied to functions, impl blocks, modules, and crates error: `#[coverage]` attribute cannot be used on associated types --> $DIR/allowed-positions.rs:22:5 @@ -38,7 +38,7 @@ error: `#[coverage]` attribute cannot be used on associated types LL | #[coverage(off)] | ^^^^^^^^^^^^^^^^ | - = help: `#[coverage]` can be applied to functions, impl blocks, modules, crates + = help: `#[coverage]` can be applied to functions, impl blocks, modules, and crates error: `#[coverage]` attribute cannot be used on required trait methods --> $DIR/allowed-positions.rs:25:5 @@ -46,7 +46,7 @@ error: `#[coverage]` attribute cannot be used on required trait methods LL | #[coverage(off)] | ^^^^^^^^^^^^^^^^ | - = help: `#[coverage]` can be applied to impl blocks, functions, closures, provided trait methods, trait methods in impl blocks, inherent methods, modules, crates + = help: `#[coverage]` can be applied to impl blocks, functions, closures, provided trait methods, trait methods in impl blocks, inherent methods, modules, and crates error: `#[coverage]` attribute cannot be used on required trait methods --> $DIR/allowed-positions.rs:31:5 @@ -54,7 +54,7 @@ error: `#[coverage]` attribute cannot be used on required trait methods LL | #[coverage(off)] | ^^^^^^^^^^^^^^^^ | - = help: `#[coverage]` can be applied to impl blocks, functions, closures, provided trait methods, trait methods in impl blocks, inherent methods, modules, crates + = help: `#[coverage]` can be applied to impl blocks, functions, closures, provided trait methods, trait methods in impl blocks, inherent methods, modules, and crates error: `#[coverage]` attribute cannot be used on associated types --> $DIR/allowed-positions.rs:39:5 @@ -62,7 +62,7 @@ error: `#[coverage]` attribute cannot be used on associated types LL | #[coverage(off)] | ^^^^^^^^^^^^^^^^ | - = help: `#[coverage]` can be applied to functions, impl blocks, modules, crates + = help: `#[coverage]` can be applied to functions, impl blocks, modules, and crates error: `#[coverage]` attribute cannot be used on associated types --> $DIR/allowed-positions.rs:56:5 @@ -70,7 +70,7 @@ error: `#[coverage]` attribute cannot be used on associated types LL | #[coverage(off)] | ^^^^^^^^^^^^^^^^ | - = help: `#[coverage]` can be applied to functions, impl blocks, modules, crates + = help: `#[coverage]` can be applied to functions, impl blocks, modules, and crates error: `#[coverage]` attribute cannot be used on structs --> $DIR/allowed-positions.rs:61:1 @@ -78,7 +78,7 @@ error: `#[coverage]` attribute cannot be used on structs LL | #[coverage(off)] | ^^^^^^^^^^^^^^^^ | - = help: `#[coverage]` can be applied to functions, impl blocks, modules, crates + = help: `#[coverage]` can be applied to functions, impl blocks, modules, and crates error: `#[coverage]` attribute cannot be used on struct fields --> $DIR/allowed-positions.rs:63:5 @@ -86,7 +86,7 @@ error: `#[coverage]` attribute cannot be used on struct fields LL | #[coverage(off)] | ^^^^^^^^^^^^^^^^ | - = help: `#[coverage]` can be applied to functions, impl blocks, modules, crates + = help: `#[coverage]` can be applied to functions, impl blocks, modules, and crates error: `#[coverage]` attribute cannot be used on foreign statics --> $DIR/allowed-positions.rs:76:5 @@ -94,7 +94,7 @@ error: `#[coverage]` attribute cannot be used on foreign statics LL | #[coverage(off)] | ^^^^^^^^^^^^^^^^ | - = help: `#[coverage]` can be applied to functions, impl blocks, modules, crates + = help: `#[coverage]` can be applied to functions, impl blocks, modules, and crates error: `#[coverage]` attribute cannot be used on foreign types --> $DIR/allowed-positions.rs:79:5 @@ -102,7 +102,7 @@ error: `#[coverage]` attribute cannot be used on foreign types LL | #[coverage(off)] | ^^^^^^^^^^^^^^^^ | - = help: `#[coverage]` can be applied to functions, impl blocks, modules, crates + = help: `#[coverage]` can be applied to functions, impl blocks, modules, and crates error: `#[coverage]` attribute cannot be used on foreign functions --> $DIR/allowed-positions.rs:82:5 @@ -110,7 +110,7 @@ error: `#[coverage]` attribute cannot be used on foreign functions LL | #[coverage(off)] | ^^^^^^^^^^^^^^^^ | - = help: `#[coverage]` can be applied to methods, impl blocks, functions, closures, modules, crates + = help: `#[coverage]` can be applied to methods, impl blocks, functions, closures, modules, and crates error: `#[coverage]` attribute cannot be used on statements --> $DIR/allowed-positions.rs:88:5 @@ -118,7 +118,7 @@ error: `#[coverage]` attribute cannot be used on statements LL | #[coverage(off)] | ^^^^^^^^^^^^^^^^ | - = help: `#[coverage]` can be applied to functions, impl blocks, modules, crates + = help: `#[coverage]` can be applied to functions, impl blocks, modules, and crates error: `#[coverage]` attribute cannot be used on statements --> $DIR/allowed-positions.rs:94:5 @@ -126,7 +126,7 @@ error: `#[coverage]` attribute cannot be used on statements LL | #[coverage(off)] | ^^^^^^^^^^^^^^^^ | - = help: `#[coverage]` can be applied to functions, impl blocks, modules, crates + = help: `#[coverage]` can be applied to functions, impl blocks, modules, and crates error: `#[coverage]` attribute cannot be used on match arms --> $DIR/allowed-positions.rs:110:9 @@ -134,7 +134,7 @@ error: `#[coverage]` attribute cannot be used on match arms LL | #[coverage(off)] | ^^^^^^^^^^^^^^^^ | - = help: `#[coverage]` can be applied to functions, impl blocks, modules, crates + = help: `#[coverage]` can be applied to functions, impl blocks, modules, and crates error: `#[coverage]` attribute cannot be used on expressions --> $DIR/allowed-positions.rs:114:5 @@ -142,7 +142,7 @@ error: `#[coverage]` attribute cannot be used on expressions LL | #[coverage(off)] | ^^^^^^^^^^^^^^^^ | - = help: `#[coverage]` can be applied to functions, impl blocks, modules, crates + = help: `#[coverage]` can be applied to functions, impl blocks, modules, and crates error: aborting due to 18 previous errors diff --git a/tests/ui/coverage-attr/bad-syntax.stderr b/tests/ui/coverage-attr/bad-syntax.stderr index 927f61da08d..ecf3ed83bca 100644 --- a/tests/ui/coverage-attr/bad-syntax.stderr +++ b/tests/ui/coverage-attr/bad-syntax.stderr @@ -1,15 +1,3 @@ -error: expected identifier, found `,` - --> $DIR/bad-syntax.rs:44:12 - | -LL | #[coverage(,off)] - | ^ expected identifier - | -help: remove this comma - | -LL - #[coverage(,off)] -LL + #[coverage(off)] - | - error: multiple `coverage` attributes --> $DIR/bad-syntax.rs:9:1 | @@ -162,6 +150,18 @@ LL - #[coverage(off, bogus)] LL + #[coverage(on)] | +error: expected identifier, found `,` + --> $DIR/bad-syntax.rs:44:12 + | +LL | #[coverage(,off)] + | ^ expected identifier + | +help: remove this comma + | +LL - #[coverage(,off)] +LL + #[coverage(off)] + | + error: aborting due to 11 previous errors Some errors have detailed explanations: E0539, E0805. diff --git a/tests/ui/coverage-attr/name-value.stderr b/tests/ui/coverage-attr/name-value.stderr index d1527ec810c..77abaa42e31 100644 --- a/tests/ui/coverage-attr/name-value.stderr +++ b/tests/ui/coverage-attr/name-value.stderr @@ -49,7 +49,7 @@ error: `#[coverage]` attribute cannot be used on structs LL | #[coverage = "off"] | ^^^^^^^^^^^^^^^^^^^ | - = help: `#[coverage]` can be applied to functions, impl blocks, modules, crates + = help: `#[coverage]` can be applied to functions, impl blocks, modules, and crates error[E0539]: malformed `coverage` attribute input --> $DIR/name-value.rs:26:1 @@ -87,7 +87,7 @@ error: `#[coverage]` attribute cannot be used on associated consts LL | #[coverage = "off"] | ^^^^^^^^^^^^^^^^^^^ | - = help: `#[coverage]` can be applied to functions, impl blocks, modules, crates + = help: `#[coverage]` can be applied to functions, impl blocks, modules, and crates error[E0539]: malformed `coverage` attribute input --> $DIR/name-value.rs:35:1 @@ -110,7 +110,7 @@ error: `#[coverage]` attribute cannot be used on traits LL | #[coverage = "off"] | ^^^^^^^^^^^^^^^^^^^ | - = help: `#[coverage]` can be applied to functions, impl blocks, modules, crates + = help: `#[coverage]` can be applied to functions, impl blocks, modules, and crates error[E0539]: malformed `coverage` attribute input --> $DIR/name-value.rs:39:5 @@ -133,7 +133,7 @@ error: `#[coverage]` attribute cannot be used on associated consts LL | #[coverage = "off"] | ^^^^^^^^^^^^^^^^^^^ | - = help: `#[coverage]` can be applied to functions, impl blocks, modules, crates + = help: `#[coverage]` can be applied to functions, impl blocks, modules, and crates error[E0539]: malformed `coverage` attribute input --> $DIR/name-value.rs:44:5 @@ -156,7 +156,7 @@ error: `#[coverage]` attribute cannot be used on associated types LL | #[coverage = "off"] | ^^^^^^^^^^^^^^^^^^^ | - = help: `#[coverage]` can be applied to functions, impl blocks, modules, crates + = help: `#[coverage]` can be applied to functions, impl blocks, modules, and crates error[E0539]: malformed `coverage` attribute input --> $DIR/name-value.rs:50:1 @@ -194,7 +194,7 @@ error: `#[coverage]` attribute cannot be used on associated consts LL | #[coverage = "off"] | ^^^^^^^^^^^^^^^^^^^ | - = help: `#[coverage]` can be applied to functions, impl blocks, modules, crates + = help: `#[coverage]` can be applied to functions, impl blocks, modules, and crates error[E0539]: malformed `coverage` attribute input --> $DIR/name-value.rs:58:5 @@ -217,7 +217,7 @@ error: `#[coverage]` attribute cannot be used on associated types LL | #[coverage = "off"] | ^^^^^^^^^^^^^^^^^^^ | - = help: `#[coverage]` can be applied to functions, impl blocks, modules, crates + = help: `#[coverage]` can be applied to functions, impl blocks, modules, and crates error[E0539]: malformed `coverage` attribute input --> $DIR/name-value.rs:64:1 diff --git a/tests/ui/coverage-attr/word-only.stderr b/tests/ui/coverage-attr/word-only.stderr index 880ad080953..5fcffacc7fa 100644 --- a/tests/ui/coverage-attr/word-only.stderr +++ b/tests/ui/coverage-attr/word-only.stderr @@ -43,7 +43,7 @@ error: `#[coverage]` attribute cannot be used on structs LL | #[coverage] | ^^^^^^^^^^^ | - = help: `#[coverage]` can be applied to functions, impl blocks, modules, crates + = help: `#[coverage]` can be applied to functions, impl blocks, modules, and crates error[E0539]: malformed `coverage` attribute input --> $DIR/word-only.rs:26:1 @@ -77,7 +77,7 @@ error: `#[coverage]` attribute cannot be used on associated consts LL | #[coverage] | ^^^^^^^^^^^ | - = help: `#[coverage]` can be applied to functions, impl blocks, modules, crates + = help: `#[coverage]` can be applied to functions, impl blocks, modules, and crates error[E0539]: malformed `coverage` attribute input --> $DIR/word-only.rs:35:1 @@ -98,7 +98,7 @@ error: `#[coverage]` attribute cannot be used on traits LL | #[coverage] | ^^^^^^^^^^^ | - = help: `#[coverage]` can be applied to functions, impl blocks, modules, crates + = help: `#[coverage]` can be applied to functions, impl blocks, modules, and crates error[E0539]: malformed `coverage` attribute input --> $DIR/word-only.rs:39:5 @@ -119,7 +119,7 @@ error: `#[coverage]` attribute cannot be used on associated consts LL | #[coverage] | ^^^^^^^^^^^ | - = help: `#[coverage]` can be applied to functions, impl blocks, modules, crates + = help: `#[coverage]` can be applied to functions, impl blocks, modules, and crates error[E0539]: malformed `coverage` attribute input --> $DIR/word-only.rs:44:5 @@ -140,7 +140,7 @@ error: `#[coverage]` attribute cannot be used on associated types LL | #[coverage] | ^^^^^^^^^^^ | - = help: `#[coverage]` can be applied to functions, impl blocks, modules, crates + = help: `#[coverage]` can be applied to functions, impl blocks, modules, and crates error[E0539]: malformed `coverage` attribute input --> $DIR/word-only.rs:50:1 @@ -174,7 +174,7 @@ error: `#[coverage]` attribute cannot be used on associated consts LL | #[coverage] | ^^^^^^^^^^^ | - = help: `#[coverage]` can be applied to functions, impl blocks, modules, crates + = help: `#[coverage]` can be applied to functions, impl blocks, modules, and crates error[E0539]: malformed `coverage` attribute input --> $DIR/word-only.rs:58:5 @@ -195,7 +195,7 @@ error: `#[coverage]` attribute cannot be used on associated types LL | #[coverage] | ^^^^^^^^^^^ | - = help: `#[coverage]` can be applied to functions, impl blocks, modules, crates + = help: `#[coverage]` can be applied to functions, impl blocks, modules, and crates error[E0539]: malformed `coverage` attribute input --> $DIR/word-only.rs:64:1 diff --git a/tests/ui/delegation/explicit-paths.stderr b/tests/ui/delegation/explicit-paths.stderr index 8098ea8c54f..29f87cf1457 100644 --- a/tests/ui/delegation/explicit-paths.stderr +++ b/tests/ui/delegation/explicit-paths.stderr @@ -89,8 +89,13 @@ error[E0277]: the trait bound `S2: Trait` is not satisfied --> $DIR/explicit-paths.rs:76:16 | LL | reuse <S2 as Trait>::foo1; - | ^^ the trait `Trait` is not implemented for `S2` + | ^^ unsatisfied trait bound | +help: the trait `Trait` is not implemented for `S2` + --> $DIR/explicit-paths.rs:73:5 + | +LL | struct S2; + | ^^^^^^^^^ = help: the following other types implement trait `Trait`: F S diff --git a/tests/ui/delegation/generics/impl-to-trait-method.stderr b/tests/ui/delegation/generics/impl-to-trait-method.stderr index aeba30de043..2c0b466dba3 100644 --- a/tests/ui/delegation/generics/impl-to-trait-method.stderr +++ b/tests/ui/delegation/generics/impl-to-trait-method.stderr @@ -2,8 +2,13 @@ error[E0277]: the trait bound `bounds::S: Trait0` is not satisfied --> $DIR/impl-to-trait-method.rs:12:19 | LL | Self: Trait0, - | ^^^^^^ the trait `Trait0` is not implemented for `bounds::S` + | ^^^^^^ unsatisfied trait bound | +help: the trait `Trait0` is not implemented for `bounds::S` + --> $DIR/impl-to-trait-method.rs:21:5 + | +LL | struct S(F); + | ^^^^^^^^ help: this trait has no implementations, consider adding one --> $DIR/impl-to-trait-method.rs:5:5 | @@ -19,10 +24,15 @@ error[E0277]: the trait bound `bounds::F: Trait0` is not satisfied --> $DIR/impl-to-trait-method.rs:24:34 | LL | reuse Trait1::<T>::foo { &self.0 } - | --- ^^^^^^^ the trait `Trait0` is not implemented for `bounds::F` + | --- ^^^^^^^ unsatisfied trait bound | | | required by a bound introduced by this call | +help: the trait `Trait0` is not implemented for `bounds::F` + --> $DIR/impl-to-trait-method.rs:18:5 + | +LL | struct F; + | ^^^^^^^^ help: this trait has no implementations, consider adding one --> $DIR/impl-to-trait-method.rs:5:5 | diff --git a/tests/ui/delegation/ice-issue-122550.stderr b/tests/ui/delegation/ice-issue-122550.stderr index 1a01bee3e1e..01355c8ad92 100644 --- a/tests/ui/delegation/ice-issue-122550.stderr +++ b/tests/ui/delegation/ice-issue-122550.stderr @@ -8,8 +8,13 @@ error[E0277]: the trait bound `S: Trait` is not satisfied --> $DIR/ice-issue-122550.rs:13:12 | LL | reuse <S as Trait>::description { &self.0 } - | ^ the trait `Trait` is not implemented for `S` + | ^ unsatisfied trait bound | +help: the trait `Trait` is not implemented for `S` + --> $DIR/ice-issue-122550.rs:10:1 + | +LL | struct S(F); + | ^^^^^^^^ help: this trait has no implementations, consider adding one --> $DIR/ice-issue-122550.rs:4:1 | diff --git a/tests/ui/deprecation/deprecation-sanity.stderr b/tests/ui/deprecation/deprecation-sanity.stderr index 57af76d8f24..ea021b71e14 100644 --- a/tests/ui/deprecation/deprecation-sanity.stderr +++ b/tests/ui/deprecation/deprecation-sanity.stderr @@ -177,7 +177,7 @@ LL | #[deprecated = "hello"] | ^^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[deprecated]` can be applied to functions, data types, modules, unions, constants, statics, macro defs, type aliases, use statements, foreign statics, struct fields, traits, associated types, associated consts, enum variants, inherent impl blocks, crates + = help: `#[deprecated]` can be applied to functions, data types, modules, unions, constants, statics, macro defs, type aliases, use statements, foreign statics, struct fields, traits, associated types, associated consts, enum variants, inherent impl blocks, and crates = note: `#[deny(useless_deprecated)]` on by default error: aborting due to 10 previous errors diff --git a/tests/ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.rs b/tests/ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.rs index c5433151a8f..378d0a3e723 100644 --- a/tests/ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.rs +++ b/tests/ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.rs @@ -3,9 +3,9 @@ // was a well-formed `MetaItem`. fn main() { - foo() //~ WARNING use of deprecated function `foo` + foo() } #[deprecated(note = test)] -//~^ ERROR expected unsuffixed literal, found `test` +//~^ ERROR expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `test` fn foo() {} diff --git a/tests/ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.stderr b/tests/ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.stderr index 2ff8534b276..cd985ab5a18 100644 --- a/tests/ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.stderr +++ b/tests/ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.stderr @@ -1,4 +1,4 @@ -error: expected unsuffixed literal, found `test` +error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `test` --> $DIR/issue-66340-deprecated-attr-non-meta-grammar.rs:9:21 | LL | #[deprecated(note = test)] @@ -9,13 +9,5 @@ help: surround the identifier with quotation marks to make it into a string lite LL | #[deprecated(note = "test")] | + + -warning: use of deprecated function `foo` - --> $DIR/issue-66340-deprecated-attr-non-meta-grammar.rs:6:5 - | -LL | foo() - | ^^^ - | - = note: `#[warn(deprecated)]` on by default - -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error diff --git a/tests/ui/did_you_mean/issue-21659-show-relevant-trait-impls-1.stderr b/tests/ui/did_you_mean/issue-21659-show-relevant-trait-impls-1.stderr index 9d335b391eb..b754bafb344 100644 --- a/tests/ui/did_you_mean/issue-21659-show-relevant-trait-impls-1.stderr +++ b/tests/ui/did_you_mean/issue-21659-show-relevant-trait-impls-1.stderr @@ -2,10 +2,15 @@ error[E0277]: the trait bound `Bar: Foo<usize>` is not satisfied --> $DIR/issue-21659-show-relevant-trait-impls-1.rs:24:12 | LL | f1.foo(1usize); - | --- ^^^^^^ the trait `Foo<usize>` is not implemented for `Bar` + | --- ^^^^^^ unsatisfied trait bound | | | required by a bound introduced by this call | +help: the trait `Foo<usize>` is not implemented for `Bar` + --> $DIR/issue-21659-show-relevant-trait-impls-1.rs:13:1 + | +LL | struct Bar; + | ^^^^^^^^^^ = help: the following other types implement trait `Foo<A>`: `Bar` implements `Foo<i32>` `Bar` implements `Foo<u8>` diff --git a/tests/ui/did_you_mean/issue-21659-show-relevant-trait-impls-2.stderr b/tests/ui/did_you_mean/issue-21659-show-relevant-trait-impls-2.stderr index f9d71807960..8d1c05e7b54 100644 --- a/tests/ui/did_you_mean/issue-21659-show-relevant-trait-impls-2.stderr +++ b/tests/ui/did_you_mean/issue-21659-show-relevant-trait-impls-2.stderr @@ -2,10 +2,15 @@ error[E0277]: the trait bound `Bar: Foo<usize>` is not satisfied --> $DIR/issue-21659-show-relevant-trait-impls-2.rs:28:12 | LL | f1.foo(1usize); - | --- ^^^^^^ the trait `Foo<usize>` is not implemented for `Bar` + | --- ^^^^^^ unsatisfied trait bound | | | required by a bound introduced by this call | +help: the trait `Foo<usize>` is not implemented for `Bar` + --> $DIR/issue-21659-show-relevant-trait-impls-2.rs:13:1 + | +LL | struct Bar; + | ^^^^^^^^^^ = help: the following other types implement trait `Foo<A>`: `Bar` implements `Foo<i16>` `Bar` implements `Foo<i32>` diff --git a/tests/ui/drop/dropck-normalize-errors.nll.stderr b/tests/ui/drop/dropck-normalize-errors.nll.stderr index b008daa51a3..39ec4033eab 100644 --- a/tests/ui/drop/dropck-normalize-errors.nll.stderr +++ b/tests/ui/drop/dropck-normalize-errors.nll.stderr @@ -2,8 +2,13 @@ error[E0277]: the trait bound `NonImplementedStruct: NonImplementedTrait` is not --> $DIR/dropck-normalize-errors.rs:19:28 | LL | fn make_a_decoder<'a>() -> ADecoder<'a> { - | ^^^^^^^^^^^^ within `ADecoder<'a>`, the trait `NonImplementedTrait` is not implemented for `NonImplementedStruct` + | ^^^^^^^^^^^^ unsatisfied trait bound | +help: within `ADecoder<'a>`, the trait `NonImplementedTrait` is not implemented for `NonImplementedStruct` + --> $DIR/dropck-normalize-errors.rs:14:1 + | +LL | struct NonImplementedStruct; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: this trait has no implementations, consider adding one --> $DIR/dropck-normalize-errors.rs:11:1 | @@ -25,8 +30,13 @@ error[E0277]: the trait bound `NonImplementedStruct: NonImplementedTrait` is not --> $DIR/dropck-normalize-errors.rs:27:20 | LL | type Decoder = BDecoder; - | ^^^^^^^^ within `BDecoder`, the trait `NonImplementedTrait` is not implemented for `NonImplementedStruct` + | ^^^^^^^^ unsatisfied trait bound + | +help: within `BDecoder`, the trait `NonImplementedTrait` is not implemented for `NonImplementedStruct` + --> $DIR/dropck-normalize-errors.rs:14:1 | +LL | struct NonImplementedStruct; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: this trait has no implementations, consider adding one --> $DIR/dropck-normalize-errors.rs:11:1 | @@ -51,8 +61,13 @@ error[E0277]: the trait bound `NonImplementedStruct: NonImplementedTrait` is not --> $DIR/dropck-normalize-errors.rs:31:22 | LL | non_implemented: <NonImplementedStruct as NonImplementedTrait>::Assoc, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `NonImplementedTrait` is not implemented for `NonImplementedStruct` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound | +help: the trait `NonImplementedTrait` is not implemented for `NonImplementedStruct` + --> $DIR/dropck-normalize-errors.rs:14:1 + | +LL | struct NonImplementedStruct; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: this trait has no implementations, consider adding one --> $DIR/dropck-normalize-errors.rs:11:1 | @@ -63,8 +78,13 @@ error[E0277]: the trait bound `NonImplementedStruct: NonImplementedTrait` is not --> $DIR/dropck-normalize-errors.rs:19:28 | LL | fn make_a_decoder<'a>() -> ADecoder<'a> { - | ^^^^^^^^^^^^ the trait `NonImplementedTrait` is not implemented for `NonImplementedStruct` + | ^^^^^^^^^^^^ unsatisfied trait bound + | +help: the trait `NonImplementedTrait` is not implemented for `NonImplementedStruct` + --> $DIR/dropck-normalize-errors.rs:14:1 | +LL | struct NonImplementedStruct; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: this trait has no implementations, consider adding one --> $DIR/dropck-normalize-errors.rs:11:1 | diff --git a/tests/ui/drop/dropck-normalize-errors.polonius.stderr b/tests/ui/drop/dropck-normalize-errors.polonius.stderr index f8674b8e34a..3d72801b343 100644 --- a/tests/ui/drop/dropck-normalize-errors.polonius.stderr +++ b/tests/ui/drop/dropck-normalize-errors.polonius.stderr @@ -2,8 +2,13 @@ error[E0277]: the trait bound `NonImplementedStruct: NonImplementedTrait` is not --> $DIR/dropck-normalize-errors.rs:19:28 | LL | fn make_a_decoder<'a>() -> ADecoder<'a> { - | ^^^^^^^^^^^^ within `ADecoder<'a>`, the trait `NonImplementedTrait` is not implemented for `NonImplementedStruct` + | ^^^^^^^^^^^^ unsatisfied trait bound | +help: within `ADecoder<'a>`, the trait `NonImplementedTrait` is not implemented for `NonImplementedStruct` + --> $DIR/dropck-normalize-errors.rs:14:1 + | +LL | struct NonImplementedStruct; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: this trait has no implementations, consider adding one --> $DIR/dropck-normalize-errors.rs:11:1 | @@ -25,8 +30,13 @@ error[E0277]: the trait bound `NonImplementedStruct: NonImplementedTrait` is not --> $DIR/dropck-normalize-errors.rs:27:20 | LL | type Decoder = BDecoder; - | ^^^^^^^^ within `BDecoder`, the trait `NonImplementedTrait` is not implemented for `NonImplementedStruct` + | ^^^^^^^^ unsatisfied trait bound + | +help: within `BDecoder`, the trait `NonImplementedTrait` is not implemented for `NonImplementedStruct` + --> $DIR/dropck-normalize-errors.rs:14:1 | +LL | struct NonImplementedStruct; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: this trait has no implementations, consider adding one --> $DIR/dropck-normalize-errors.rs:11:1 | @@ -51,8 +61,13 @@ error[E0277]: the trait bound `NonImplementedStruct: NonImplementedTrait` is not --> $DIR/dropck-normalize-errors.rs:31:22 | LL | non_implemented: <NonImplementedStruct as NonImplementedTrait>::Assoc, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `NonImplementedTrait` is not implemented for `NonImplementedStruct` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound + | +help: the trait `NonImplementedTrait` is not implemented for `NonImplementedStruct` + --> $DIR/dropck-normalize-errors.rs:14:1 | +LL | struct NonImplementedStruct; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: this trait has no implementations, consider adding one --> $DIR/dropck-normalize-errors.rs:11:1 | diff --git a/tests/ui/dst/dst-bad-coerce1.stderr b/tests/ui/dst/dst-bad-coerce1.stderr index 68456b8642c..223bf9ce08a 100644 --- a/tests/ui/dst/dst-bad-coerce1.stderr +++ b/tests/ui/dst/dst-bad-coerce1.stderr @@ -13,8 +13,13 @@ error[E0277]: the trait bound `Foo: Bar` is not satisfied --> $DIR/dst-bad-coerce1.rs:20:29 | LL | let f3: &Fat<dyn Bar> = f2; - | ^^ the trait `Bar` is not implemented for `Foo` + | ^^ unsatisfied trait bound | +help: the trait `Bar` is not implemented for `Foo` + --> $DIR/dst-bad-coerce1.rs:7:1 + | +LL | struct Foo; + | ^^^^^^^^^^ help: this trait has no implementations, consider adding one --> $DIR/dst-bad-coerce1.rs:8:1 | diff --git a/tests/ui/errors/remap-path-prefix-diagnostics.not-diag-in-deps.stderr b/tests/ui/errors/remap-path-prefix-diagnostics.not-diag-in-deps.stderr index 229bfbe59e5..234e251b2ad 100644 --- a/tests/ui/errors/remap-path-prefix-diagnostics.not-diag-in-deps.stderr +++ b/tests/ui/errors/remap-path-prefix-diagnostics.not-diag-in-deps.stderr @@ -2,8 +2,13 @@ error[E0277]: `A` doesn't implement `std::fmt::Display` --> remapped/errors/remap-path-prefix-diagnostics.rs:LL:COL | LL | impl r#trait::Trait for A {} - | ^ the trait `std::fmt::Display` is not implemented for `A` + | ^ unsatisfied trait bound | +help: the trait `std::fmt::Display` is not implemented for `A` + --> remapped/errors/remap-path-prefix-diagnostics.rs:LL:COL + | +LL | struct A; + | ^^^^^^^^ note: required by a bound in `Trait` --> $DIR/auxiliary/trait.rs:LL:COL | diff --git a/tests/ui/errors/remap-path-prefix-diagnostics.only-debuginfo-in-deps.stderr b/tests/ui/errors/remap-path-prefix-diagnostics.only-debuginfo-in-deps.stderr index a59af3b6a82..3b0d66e75e8 100644 --- a/tests/ui/errors/remap-path-prefix-diagnostics.only-debuginfo-in-deps.stderr +++ b/tests/ui/errors/remap-path-prefix-diagnostics.only-debuginfo-in-deps.stderr @@ -2,8 +2,13 @@ error[E0277]: `A` doesn't implement `std::fmt::Display` --> $DIR/remap-path-prefix-diagnostics.rs:LL:COL | LL | impl r#trait::Trait for A {} - | ^ the trait `std::fmt::Display` is not implemented for `A` + | ^ unsatisfied trait bound | +help: the trait `std::fmt::Display` is not implemented for `A` + --> $DIR/remap-path-prefix-diagnostics.rs:LL:COL + | +LL | struct A; + | ^^^^^^^^ note: required by a bound in `Trait` --> $DIR/auxiliary/trait-debuginfo.rs:LL:COL | diff --git a/tests/ui/errors/remap-path-prefix-diagnostics.only-diag-in-deps.stderr b/tests/ui/errors/remap-path-prefix-diagnostics.only-diag-in-deps.stderr index 18fb9afcf39..e77c0e5f68d 100644 --- a/tests/ui/errors/remap-path-prefix-diagnostics.only-diag-in-deps.stderr +++ b/tests/ui/errors/remap-path-prefix-diagnostics.only-diag-in-deps.stderr @@ -2,8 +2,13 @@ error[E0277]: `A` doesn't implement `std::fmt::Display` --> $DIR/remap-path-prefix-diagnostics.rs:LL:COL | LL | impl r#trait::Trait for A {} - | ^ the trait `std::fmt::Display` is not implemented for `A` + | ^ unsatisfied trait bound | +help: the trait `std::fmt::Display` is not implemented for `A` + --> $DIR/remap-path-prefix-diagnostics.rs:LL:COL + | +LL | struct A; + | ^^^^^^^^ note: required by a bound in `Trait` --> $DIR/auxiliary/trait-diag.rs:LL:COL | diff --git a/tests/ui/errors/remap-path-prefix-diagnostics.only-macro-in-deps.stderr b/tests/ui/errors/remap-path-prefix-diagnostics.only-macro-in-deps.stderr index 9e770f07fba..91c9cd90152 100644 --- a/tests/ui/errors/remap-path-prefix-diagnostics.only-macro-in-deps.stderr +++ b/tests/ui/errors/remap-path-prefix-diagnostics.only-macro-in-deps.stderr @@ -2,8 +2,13 @@ error[E0277]: `A` doesn't implement `std::fmt::Display` --> $DIR/remap-path-prefix-diagnostics.rs:LL:COL | LL | impl r#trait::Trait for A {} - | ^ the trait `std::fmt::Display` is not implemented for `A` + | ^ unsatisfied trait bound | +help: the trait `std::fmt::Display` is not implemented for `A` + --> $DIR/remap-path-prefix-diagnostics.rs:LL:COL + | +LL | struct A; + | ^^^^^^^^ note: required by a bound in `Trait` --> $DIR/auxiliary/trait-macro.rs:LL:COL | diff --git a/tests/ui/errors/remap-path-prefix-diagnostics.with-debuginfo-in-deps.stderr b/tests/ui/errors/remap-path-prefix-diagnostics.with-debuginfo-in-deps.stderr index a59af3b6a82..3b0d66e75e8 100644 --- a/tests/ui/errors/remap-path-prefix-diagnostics.with-debuginfo-in-deps.stderr +++ b/tests/ui/errors/remap-path-prefix-diagnostics.with-debuginfo-in-deps.stderr @@ -2,8 +2,13 @@ error[E0277]: `A` doesn't implement `std::fmt::Display` --> $DIR/remap-path-prefix-diagnostics.rs:LL:COL | LL | impl r#trait::Trait for A {} - | ^ the trait `std::fmt::Display` is not implemented for `A` + | ^ unsatisfied trait bound | +help: the trait `std::fmt::Display` is not implemented for `A` + --> $DIR/remap-path-prefix-diagnostics.rs:LL:COL + | +LL | struct A; + | ^^^^^^^^ note: required by a bound in `Trait` --> $DIR/auxiliary/trait-debuginfo.rs:LL:COL | diff --git a/tests/ui/errors/remap-path-prefix-diagnostics.with-diag-in-deps.stderr b/tests/ui/errors/remap-path-prefix-diagnostics.with-diag-in-deps.stderr index ca6f2b1697a..00a647df61f 100644 --- a/tests/ui/errors/remap-path-prefix-diagnostics.with-diag-in-deps.stderr +++ b/tests/ui/errors/remap-path-prefix-diagnostics.with-diag-in-deps.stderr @@ -2,8 +2,13 @@ error[E0277]: `A` doesn't implement `std::fmt::Display` --> remapped/errors/remap-path-prefix-diagnostics.rs:LL:COL | LL | impl r#trait::Trait for A {} - | ^ the trait `std::fmt::Display` is not implemented for `A` + | ^ unsatisfied trait bound | +help: the trait `std::fmt::Display` is not implemented for `A` + --> remapped/errors/remap-path-prefix-diagnostics.rs:LL:COL + | +LL | struct A; + | ^^^^^^^^ note: required by a bound in `Trait` --> remapped/errors/auxiliary/trait-diag.rs:LL:COL | diff --git a/tests/ui/errors/remap-path-prefix-diagnostics.with-macro-in-deps.stderr b/tests/ui/errors/remap-path-prefix-diagnostics.with-macro-in-deps.stderr index 9e770f07fba..91c9cd90152 100644 --- a/tests/ui/errors/remap-path-prefix-diagnostics.with-macro-in-deps.stderr +++ b/tests/ui/errors/remap-path-prefix-diagnostics.with-macro-in-deps.stderr @@ -2,8 +2,13 @@ error[E0277]: `A` doesn't implement `std::fmt::Display` --> $DIR/remap-path-prefix-diagnostics.rs:LL:COL | LL | impl r#trait::Trait for A {} - | ^ the trait `std::fmt::Display` is not implemented for `A` + | ^ unsatisfied trait bound | +help: the trait `std::fmt::Display` is not implemented for `A` + --> $DIR/remap-path-prefix-diagnostics.rs:LL:COL + | +LL | struct A; + | ^^^^^^^^ note: required by a bound in `Trait` --> $DIR/auxiliary/trait-macro.rs:LL:COL | diff --git a/tests/ui/extern/extern-no-mangle.stderr b/tests/ui/extern/extern-no-mangle.stderr index b07cf0d4b4d..69c4fbb935d 100644 --- a/tests/ui/extern/extern-no-mangle.stderr +++ b/tests/ui/extern/extern-no-mangle.stderr @@ -5,7 +5,7 @@ LL | #[no_mangle] | ^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[no_mangle]` can be applied to functions, statics + = help: `#[no_mangle]` can be applied to functions and statics note: the lint level is defined here --> $DIR/extern-no-mangle.rs:1:9 | @@ -19,7 +19,7 @@ LL | #[no_mangle] | ^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[no_mangle]` can be applied to methods, functions, statics + = help: `#[no_mangle]` can be applied to methods, functions, and statics warning: `#[no_mangle]` attribute cannot be used on statements --> $DIR/extern-no-mangle.rs:24:5 @@ -28,7 +28,7 @@ LL | #[no_mangle] | ^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[no_mangle]` can be applied to functions, statics + = help: `#[no_mangle]` can be applied to functions and statics warning: 3 warnings emitted diff --git a/tests/ui/extern/issue-47725.stderr b/tests/ui/extern/issue-47725.stderr index 43362ea655b..27da18df37c 100644 --- a/tests/ui/extern/issue-47725.stderr +++ b/tests/ui/extern/issue-47725.stderr @@ -13,7 +13,7 @@ LL | #[link_name = "foo"] | ^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[link_name]` can be applied to foreign functions, foreign statics + = help: `#[link_name]` can be applied to foreign functions and foreign statics note: the lint level is defined here --> $DIR/issue-47725.rs:1:9 | @@ -27,7 +27,7 @@ LL | #[link_name = "foobar"] | ^^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[link_name]` can be applied to foreign functions, foreign statics + = help: `#[link_name]` can be applied to foreign functions and foreign statics warning: `#[link_name]` attribute cannot be used on foreign modules --> $DIR/issue-47725.rs:19:1 @@ -36,7 +36,7 @@ LL | #[link_name] | ^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[link_name]` can be applied to foreign functions, foreign statics + = help: `#[link_name]` can be applied to foreign functions and foreign statics error: aborting due to 1 previous error; 3 warnings emitted diff --git a/tests/ui/feature-gates/feature-gate-allow-internal-unstable-struct.stderr b/tests/ui/feature-gates/feature-gate-allow-internal-unstable-struct.stderr index cb8cf29e99d..42141b891ae 100644 --- a/tests/ui/feature-gates/feature-gate-allow-internal-unstable-struct.stderr +++ b/tests/ui/feature-gates/feature-gate-allow-internal-unstable-struct.stderr @@ -13,7 +13,7 @@ error: `#[allow_internal_unstable]` attribute cannot be used on structs LL | #[allow_internal_unstable(something)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: `#[allow_internal_unstable]` can be applied to macro defs, functions + = help: `#[allow_internal_unstable]` can be applied to macro defs and functions error: aborting due to 2 previous errors diff --git a/tests/ui/feature-gates/feature-gate-effective-target-features.default.stderr b/tests/ui/feature-gates/feature-gate-effective-target-features.default.stderr new file mode 100644 index 00000000000..34a56fe342e --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-effective-target-features.default.stderr @@ -0,0 +1,37 @@ +error[E0658]: the `#[force_target_feature]` attribute is an experimental feature + --> $DIR/feature-gate-effective-target-features.rs:13:5 + | +LL | #[unsafe(force_target_feature(enable = "avx2"))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #143352 <https://github.com/rust-lang/rust/issues/143352> for more information + = help: add `#![feature(effective_target_features)]` 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: `#[target_feature(..)]` cannot be applied to safe trait method + --> $DIR/feature-gate-effective-target-features.rs:21:5 + | +LL | #[target_feature(enable = "avx2")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot be applied to safe trait method +LL | +LL | fn foo(&self) {} + | ------------- not an `unsafe` function + +error[E0053]: method `foo` has an incompatible type for trait + --> $DIR/feature-gate-effective-target-features.rs:23:5 + | +LL | fn foo(&self) {} + | ^^^^^^^^^^^^^ expected safe fn, found unsafe fn + | +note: type in trait + --> $DIR/feature-gate-effective-target-features.rs:7:5 + | +LL | fn foo(&self); + | ^^^^^^^^^^^^^^ + = note: expected signature `fn(&Bar2)` + found signature `#[target_features] fn(&Bar2)` + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0053, E0658. +For more information about an error, try `rustc --explain E0053`. diff --git a/tests/ui/feature-gates/feature-gate-effective-target-features.feature.stderr b/tests/ui/feature-gates/feature-gate-effective-target-features.feature.stderr new file mode 100644 index 00000000000..d51956fa4d2 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-effective-target-features.feature.stderr @@ -0,0 +1,35 @@ +warning: the feature `effective_target_features` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/feature-gate-effective-target-features.rs:3:30 + | +LL | #![cfg_attr(feature, feature(effective_target_features))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #143352 <https://github.com/rust-lang/rust/issues/143352> for more information + = note: `#[warn(incomplete_features)]` on by default + +error: `#[target_feature(..)]` cannot be applied to safe trait method + --> $DIR/feature-gate-effective-target-features.rs:21:5 + | +LL | #[target_feature(enable = "avx2")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot be applied to safe trait method +LL | +LL | fn foo(&self) {} + | ------------- not an `unsafe` function + +error[E0053]: method `foo` has an incompatible type for trait + --> $DIR/feature-gate-effective-target-features.rs:23:5 + | +LL | fn foo(&self) {} + | ^^^^^^^^^^^^^ expected safe fn, found unsafe fn + | +note: type in trait + --> $DIR/feature-gate-effective-target-features.rs:7:5 + | +LL | fn foo(&self); + | ^^^^^^^^^^^^^^ + = note: expected signature `fn(&Bar2)` + found signature `#[target_features] fn(&Bar2)` + +error: aborting due to 2 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0053`. diff --git a/tests/ui/feature-gates/feature-gate-effective-target-features.rs b/tests/ui/feature-gates/feature-gate-effective-target-features.rs new file mode 100644 index 00000000000..d383897e438 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-effective-target-features.rs @@ -0,0 +1,27 @@ +//@ revisions: default feature +//@ only-x86_64 +#![cfg_attr(feature, feature(effective_target_features))] +//[feature]~^ WARN the feature `effective_target_features` is incomplete and may not be safe to use and/or cause compiler crashes + +trait Foo { + fn foo(&self); +} + +struct Bar; + +impl Foo for Bar { + #[unsafe(force_target_feature(enable = "avx2"))] + //[default]~^ ERROR the `#[force_target_feature]` attribute is an experimental feature + fn foo(&self) {} +} + +struct Bar2; + +impl Foo for Bar2 { + #[target_feature(enable = "avx2")] + //~^ ERROR `#[target_feature(..)]` cannot be applied to safe trait method + fn foo(&self) {} + //~^ ERROR method `foo` has an incompatible type for trait +} + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-reborrow.rs b/tests/ui/feature-gates/feature-gate-reborrow.rs new file mode 100644 index 00000000000..f016f6c6bfa --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-reborrow.rs @@ -0,0 +1,3 @@ +use std::marker::Reborrow; //~ ERROR use of unstable library feature `reborrow` + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-reborrow.stderr b/tests/ui/feature-gates/feature-gate-reborrow.stderr new file mode 100644 index 00000000000..5e3033f3bf1 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-reborrow.stderr @@ -0,0 +1,13 @@ +error[E0658]: use of unstable library feature `reborrow` + --> $DIR/feature-gate-reborrow.rs:1:5 + | +LL | use std::marker::Reborrow; + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #145612 <https://github.com/rust-lang/rust/issues/145612> for more information + = help: add `#![feature(reborrow)]` 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 1 previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.stderr b/tests/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.stderr index 334bc63b7ee..b2a2eba9ad1 100644 --- a/tests/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.stderr +++ b/tests/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.stderr @@ -93,7 +93,11 @@ error[E0277]: expected a `FnMut()` closure, found `Foo` LL | impl Fn<()> for Foo { | ^^^ expected an `FnMut()` closure, found `Foo` | - = help: the trait `FnMut()` is not implemented for `Foo` +help: the trait `FnMut()` is not implemented for `Foo` + --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:8:1 + | +LL | struct Foo; + | ^^^^^^^^^^ = note: wrap the `Foo` in a closure with no arguments: `|| { /* code */ }` note: required by a bound in `Fn` --> $SRC_DIR/core/src/ops/function.rs:LL:COL @@ -163,7 +167,11 @@ error[E0277]: expected a `FnOnce()` closure, found `Bar` LL | impl FnMut<()> for Bar { | ^^^ expected an `FnOnce()` closure, found `Bar` | - = help: the trait `FnOnce()` is not implemented for `Bar` +help: the trait `FnOnce()` is not implemented for `Bar` + --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:25:1 + | +LL | struct Bar; + | ^^^^^^^^^^ = note: wrap the `Bar` in a closure with no arguments: `|| { /* code */ }` note: required by a bound in `FnMut` --> $SRC_DIR/core/src/ops/function.rs:LL:COL diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr index 14122d466c4..3b010c3e312 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr +++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr @@ -30,7 +30,7 @@ error: `#[export_name]` attribute cannot be used on crates LL | #![export_name = "2200"] | ^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: `#[export_name]` can be applied to functions, statics + = help: `#[export_name]` can be applied to functions and statics error: `#[inline]` attribute cannot be used on crates --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:28:1 @@ -86,7 +86,7 @@ error: `#[export_name]` attribute cannot be used on modules LL | #[export_name = "2200"] | ^^^^^^^^^^^^^^^^^^^^^^^ | - = help: `#[export_name]` can be applied to functions, statics + = help: `#[export_name]` can be applied to functions and statics error: `#[export_name]` attribute cannot be used on modules --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:85:17 @@ -94,7 +94,7 @@ error: `#[export_name]` attribute cannot be used on modules LL | mod inner { #![export_name="2200"] } | ^^^^^^^^^^^^^^^^^^^^^^ | - = help: `#[export_name]` can be applied to functions, statics + = help: `#[export_name]` can be applied to functions and statics error: `#[export_name]` attribute cannot be used on structs --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:90:5 @@ -102,7 +102,7 @@ error: `#[export_name]` attribute cannot be used on structs LL | #[export_name = "2200"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^ | - = help: `#[export_name]` can be applied to functions, statics + = help: `#[export_name]` can be applied to functions and statics error: `#[export_name]` attribute cannot be used on type aliases --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:93:5 @@ -110,7 +110,7 @@ error: `#[export_name]` attribute cannot be used on type aliases LL | #[export_name = "2200"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^ | - = help: `#[export_name]` can be applied to functions, statics + = help: `#[export_name]` can be applied to functions and statics error: `#[export_name]` attribute cannot be used on inherent impl blocks --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:96:5 @@ -118,7 +118,7 @@ error: `#[export_name]` attribute cannot be used on inherent impl blocks LL | #[export_name = "2200"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^ | - = help: `#[export_name]` can be applied to functions, statics + = help: `#[export_name]` can be applied to functions and statics error: `#[export_name]` attribute cannot be used on required trait methods --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:100:9 @@ -126,7 +126,7 @@ error: `#[export_name]` attribute cannot be used on required trait methods LL | #[export_name = "2200"] fn foo(); | ^^^^^^^^^^^^^^^^^^^^^^^ | - = help: `#[export_name]` can be applied to statics, functions, inherent methods, provided trait methods, trait methods in impl blocks + = help: `#[export_name]` can be applied to statics, functions, inherent methods, provided trait methods, and trait methods in impl blocks error: attribute should be applied to an `extern crate` item --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:56:1 diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr index a633ac0aadb..7488c68b59f 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr +++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr @@ -675,7 +675,7 @@ LL | #[macro_use] fn f() { } | ^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[macro_use]` can be applied to modules, extern crates, crates + = help: `#[macro_use]` can be applied to modules, extern crates, and crates warning: `#[macro_use]` attribute cannot be used on structs --> $DIR/issue-43106-gating-of-builtin-attrs.rs:197:5 @@ -684,7 +684,7 @@ LL | #[macro_use] struct S; | ^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[macro_use]` can be applied to modules, extern crates, crates + = help: `#[macro_use]` can be applied to modules, extern crates, and crates warning: `#[macro_use]` attribute cannot be used on type aliases --> $DIR/issue-43106-gating-of-builtin-attrs.rs:203:5 @@ -693,7 +693,7 @@ LL | #[macro_use] type T = S; | ^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[macro_use]` can be applied to modules, extern crates, crates + = help: `#[macro_use]` can be applied to modules, extern crates, and crates warning: `#[macro_use]` attribute cannot be used on inherent impl blocks --> $DIR/issue-43106-gating-of-builtin-attrs.rs:209:5 @@ -702,7 +702,7 @@ LL | #[macro_use] impl S { } | ^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[macro_use]` can be applied to modules, extern crates, crates + = help: `#[macro_use]` can be applied to modules, extern crates, and crates warning: `#[path]` attribute cannot be used on functions --> $DIR/issue-43106-gating-of-builtin-attrs.rs:271:5 @@ -810,7 +810,7 @@ LL | #[no_mangle] | ^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[no_mangle]` can be applied to functions, statics + = help: `#[no_mangle]` can be applied to functions and statics warning: `#[no_mangle]` attribute cannot be used on modules --> $DIR/issue-43106-gating-of-builtin-attrs.rs:347:17 @@ -819,7 +819,7 @@ LL | mod inner { #![no_mangle] } | ^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[no_mangle]` can be applied to functions, statics + = help: `#[no_mangle]` can be applied to functions and statics warning: `#[no_mangle]` attribute cannot be used on structs --> $DIR/issue-43106-gating-of-builtin-attrs.rs:355:5 @@ -828,7 +828,7 @@ LL | #[no_mangle] struct S; | ^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[no_mangle]` can be applied to functions, statics + = help: `#[no_mangle]` can be applied to functions and statics warning: `#[no_mangle]` attribute cannot be used on type aliases --> $DIR/issue-43106-gating-of-builtin-attrs.rs:361:5 @@ -837,7 +837,7 @@ LL | #[no_mangle] type T = S; | ^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[no_mangle]` can be applied to functions, statics + = help: `#[no_mangle]` can be applied to functions and statics warning: `#[no_mangle]` attribute cannot be used on inherent impl blocks --> $DIR/issue-43106-gating-of-builtin-attrs.rs:367:5 @@ -846,7 +846,7 @@ LL | #[no_mangle] impl S { } | ^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[no_mangle]` can be applied to functions, statics + = help: `#[no_mangle]` can be applied to functions and statics warning: `#[no_mangle]` attribute cannot be used on required trait methods --> $DIR/issue-43106-gating-of-builtin-attrs.rs:374:9 @@ -855,7 +855,7 @@ LL | #[no_mangle] fn foo(); | ^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[no_mangle]` can be applied to functions, statics, inherent methods, trait methods in impl blocks + = help: `#[no_mangle]` can be applied to functions, statics, inherent methods, and trait methods in impl blocks warning: `#[no_mangle]` attribute cannot be used on provided trait methods --> $DIR/issue-43106-gating-of-builtin-attrs.rs:380:9 @@ -864,7 +864,7 @@ LL | #[no_mangle] fn bar() {} | ^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[no_mangle]` can be applied to functions, statics, inherent methods, trait methods in impl blocks + = help: `#[no_mangle]` can be applied to functions, statics, inherent methods, and trait methods in impl blocks warning: `#[should_panic]` attribute cannot be used on modules --> $DIR/issue-43106-gating-of-builtin-attrs.rs:388:1 @@ -963,7 +963,7 @@ LL | #[no_implicit_prelude] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[no_implicit_prelude]` can be applied to modules, crates + = help: `#[no_implicit_prelude]` can be applied to modules and crates warning: `#[no_implicit_prelude]` attribute cannot be used on structs --> $DIR/issue-43106-gating-of-builtin-attrs.rs:464:5 @@ -972,7 +972,7 @@ LL | #[no_implicit_prelude] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[no_implicit_prelude]` can be applied to modules, crates + = help: `#[no_implicit_prelude]` can be applied to modules and crates warning: `#[no_implicit_prelude]` attribute cannot be used on type aliases --> $DIR/issue-43106-gating-of-builtin-attrs.rs:470:5 @@ -981,7 +981,7 @@ LL | #[no_implicit_prelude] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[no_implicit_prelude]` can be applied to modules, crates + = help: `#[no_implicit_prelude]` can be applied to modules and crates warning: `#[no_implicit_prelude]` attribute cannot be used on inherent impl blocks --> $DIR/issue-43106-gating-of-builtin-attrs.rs:476:5 @@ -990,7 +990,7 @@ LL | #[no_implicit_prelude] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[no_implicit_prelude]` can be applied to modules, crates + = help: `#[no_implicit_prelude]` can be applied to modules and crates warning: `#[macro_escape]` attribute cannot be used on functions --> $DIR/issue-43106-gating-of-builtin-attrs.rs:510:5 @@ -999,7 +999,7 @@ LL | #[macro_escape] fn f() { } | ^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[macro_escape]` can be applied to modules, extern crates, crates + = help: `#[macro_escape]` can be applied to modules, extern crates, and crates warning: `#[macro_escape]` attribute cannot be used on structs --> $DIR/issue-43106-gating-of-builtin-attrs.rs:516:5 @@ -1008,7 +1008,7 @@ LL | #[macro_escape] struct S; | ^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[macro_escape]` can be applied to modules, extern crates, crates + = help: `#[macro_escape]` can be applied to modules, extern crates, and crates warning: `#[macro_escape]` attribute cannot be used on type aliases --> $DIR/issue-43106-gating-of-builtin-attrs.rs:522:5 @@ -1017,7 +1017,7 @@ LL | #[macro_escape] type T = S; | ^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[macro_escape]` can be applied to modules, extern crates, crates + = help: `#[macro_escape]` can be applied to modules, extern crates, and crates warning: `#[macro_escape]` attribute cannot be used on inherent impl blocks --> $DIR/issue-43106-gating-of-builtin-attrs.rs:528:5 @@ -1026,7 +1026,7 @@ LL | #[macro_escape] impl S { } | ^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[macro_escape]` can be applied to modules, extern crates, crates + = help: `#[macro_escape]` can be applied to modules, extern crates, and crates warning: `#[cold]` attribute cannot be used on modules --> $DIR/issue-43106-gating-of-builtin-attrs.rs:571:1 @@ -1080,7 +1080,7 @@ LL | #[link_name = "1900"] | ^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[link_name]` can be applied to foreign functions, foreign statics + = help: `#[link_name]` can be applied to foreign functions and foreign statics warning: `#[link_name]` attribute cannot be used on foreign modules --> $DIR/issue-43106-gating-of-builtin-attrs.rs:611:5 @@ -1089,7 +1089,7 @@ LL | #[link_name = "1900"] | ^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[link_name]` can be applied to foreign functions, foreign statics + = help: `#[link_name]` can be applied to foreign functions and foreign statics warning: `#[link_name]` attribute cannot be used on modules --> $DIR/issue-43106-gating-of-builtin-attrs.rs:618:17 @@ -1098,7 +1098,7 @@ LL | mod inner { #![link_name="1900"] } | ^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[link_name]` can be applied to foreign functions, foreign statics + = help: `#[link_name]` can be applied to foreign functions and foreign statics warning: `#[link_name]` attribute cannot be used on functions --> $DIR/issue-43106-gating-of-builtin-attrs.rs:624:5 @@ -1107,7 +1107,7 @@ LL | #[link_name = "1900"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[link_name]` can be applied to foreign functions, foreign statics + = help: `#[link_name]` can be applied to foreign functions and foreign statics warning: `#[link_name]` attribute cannot be used on structs --> $DIR/issue-43106-gating-of-builtin-attrs.rs:630:5 @@ -1116,7 +1116,7 @@ LL | #[link_name = "1900"] struct S; | ^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[link_name]` can be applied to foreign functions, foreign statics + = help: `#[link_name]` can be applied to foreign functions and foreign statics warning: `#[link_name]` attribute cannot be used on type aliases --> $DIR/issue-43106-gating-of-builtin-attrs.rs:636:5 @@ -1125,7 +1125,7 @@ LL | #[link_name = "1900"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[link_name]` can be applied to foreign functions, foreign statics + = help: `#[link_name]` can be applied to foreign functions and foreign statics warning: `#[link_name]` attribute cannot be used on inherent impl blocks --> $DIR/issue-43106-gating-of-builtin-attrs.rs:642:5 @@ -1134,7 +1134,7 @@ LL | #[link_name = "1900"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[link_name]` can be applied to foreign functions, foreign statics + = help: `#[link_name]` can be applied to foreign functions and foreign statics warning: `#[link_section]` attribute cannot be used on modules --> $DIR/issue-43106-gating-of-builtin-attrs.rs:649:1 @@ -1143,7 +1143,7 @@ LL | #[link_section = "1800"] | ^^^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[link_section]` can be applied to statics, functions + = help: `#[link_section]` can be applied to statics and functions warning: `#[link_section]` attribute cannot be used on modules --> $DIR/issue-43106-gating-of-builtin-attrs.rs:655:17 @@ -1152,7 +1152,7 @@ LL | mod inner { #![link_section="1800"] } | ^^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[link_section]` can be applied to statics, functions + = help: `#[link_section]` can be applied to statics and functions warning: `#[link_section]` attribute cannot be used on structs --> $DIR/issue-43106-gating-of-builtin-attrs.rs:663:5 @@ -1161,7 +1161,7 @@ LL | #[link_section = "1800"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[link_section]` can be applied to statics, functions + = help: `#[link_section]` can be applied to statics and functions warning: `#[link_section]` attribute cannot be used on type aliases --> $DIR/issue-43106-gating-of-builtin-attrs.rs:669:5 @@ -1170,7 +1170,7 @@ LL | #[link_section = "1800"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[link_section]` can be applied to statics, functions + = help: `#[link_section]` can be applied to statics and functions warning: `#[link_section]` attribute cannot be used on inherent impl blocks --> $DIR/issue-43106-gating-of-builtin-attrs.rs:675:5 @@ -1179,7 +1179,7 @@ LL | #[link_section = "1800"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[link_section]` can be applied to statics, functions + = help: `#[link_section]` can be applied to statics and functions warning: `#[must_use]` attribute cannot be used on modules --> $DIR/issue-43106-gating-of-builtin-attrs.rs:736:1 @@ -1188,7 +1188,7 @@ LL | #[must_use] | ^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[must_use]` can be applied to functions, data types, unions, traits + = help: `#[must_use]` can be applied to functions, data types, unions, and traits warning: `#[must_use]` attribute cannot be used on modules --> $DIR/issue-43106-gating-of-builtin-attrs.rs:741:17 @@ -1197,7 +1197,7 @@ LL | mod inner { #![must_use] } | ^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[must_use]` can be applied to functions, data types, unions, traits + = help: `#[must_use]` can be applied to functions, data types, unions, and traits warning: `#[must_use]` attribute cannot be used on type aliases --> $DIR/issue-43106-gating-of-builtin-attrs.rs:750:5 @@ -1206,7 +1206,7 @@ LL | #[must_use] type T = S; | ^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[must_use]` can be applied to functions, data types, unions, traits + = help: `#[must_use]` can be applied to functions, data types, unions, and traits warning: `#[must_use]` attribute cannot be used on inherent impl blocks --> $DIR/issue-43106-gating-of-builtin-attrs.rs:755:5 @@ -1215,7 +1215,7 @@ LL | #[must_use] impl S { } | ^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[must_use]` can be applied to functions, data types, unions, traits + = help: `#[must_use]` can be applied to functions, data types, unions, and traits warning: `#[should_panic]` attribute cannot be used on crates --> $DIR/issue-43106-gating-of-builtin-attrs.rs:50:1 @@ -1260,7 +1260,7 @@ LL | #![link_name = "1900"] | ^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[link_name]` can be applied to foreign functions, foreign statics + = help: `#[link_name]` can be applied to foreign functions and foreign statics warning: `#[link_section]` attribute cannot be used on crates --> $DIR/issue-43106-gating-of-builtin-attrs.rs:79:1 @@ -1269,7 +1269,7 @@ LL | #![link_section = "1800"] | ^^^^^^^^^^^^^^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[link_section]` can be applied to statics, functions + = help: `#[link_section]` can be applied to statics and functions warning: `#[must_use]` attribute cannot be used on crates --> $DIR/issue-43106-gating-of-builtin-attrs.rs:84:1 @@ -1278,7 +1278,7 @@ LL | #![must_use] | ^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[must_use]` can be applied to functions, data types, unions, traits + = help: `#[must_use]` can be applied to functions, data types, unions, and traits warning: 173 warnings emitted diff --git a/tests/ui/fmt/non-source-literals.stderr b/tests/ui/fmt/non-source-literals.stderr index 5f8a6200dab..5f042e1e631 100644 --- a/tests/ui/fmt/non-source-literals.stderr +++ b/tests/ui/fmt/non-source-literals.stderr @@ -4,7 +4,11 @@ error[E0277]: `NonDisplay` doesn't implement `std::fmt::Display` LL | let _ = format!(concat!("{", "}"), NonDisplay); | ^^^^^^^^^^ `NonDisplay` cannot be formatted with the default formatter | - = help: the trait `std::fmt::Display` is not implemented for `NonDisplay` +help: the trait `std::fmt::Display` is not implemented for `NonDisplay` + --> $DIR/non-source-literals.rs:5:1 + | +LL | pub struct NonDisplay; + | ^^^^^^^^^^^^^^^^^^^^^ = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead = note: this error originates in the macro `$crate::__export::format_args` which comes from the expansion of the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -14,7 +18,11 @@ error[E0277]: `NonDisplay` doesn't implement `std::fmt::Display` LL | let _ = format!(concat!("{", "0", "}"), NonDisplay); | ^^^^^^^^^^ `NonDisplay` cannot be formatted with the default formatter | - = help: the trait `std::fmt::Display` is not implemented for `NonDisplay` +help: the trait `std::fmt::Display` is not implemented for `NonDisplay` + --> $DIR/non-source-literals.rs:5:1 + | +LL | pub struct NonDisplay; + | ^^^^^^^^^^^^^^^^^^^^^ = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead = note: this error originates in the macro `$crate::__export::format_args` which comes from the expansion of the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/fn/issue-39259.stderr b/tests/ui/fn/issue-39259.stderr index 90e305ca17a..fc5c8282503 100644 --- a/tests/ui/fn/issue-39259.stderr +++ b/tests/ui/fn/issue-39259.stderr @@ -24,7 +24,11 @@ error[E0277]: expected a `FnMut(u32)` closure, found `S` LL | impl Fn(u32) -> u32 for S { | ^ expected an `FnMut(u32)` closure, found `S` | - = help: the trait `FnMut(u32)` is not implemented for `S` +help: the trait `FnMut(u32)` is not implemented for `S` + --> $DIR/issue-39259.rs:4:1 + | +LL | struct S; + | ^^^^^^^^ note: required by a bound in `Fn` --> $SRC_DIR/core/src/ops/function.rs:LL:COL diff --git a/tests/ui/for/for-loop-bogosity.stderr b/tests/ui/for/for-loop-bogosity.stderr index 194a2fa08ce..f4d99671f8e 100644 --- a/tests/ui/for/for-loop-bogosity.stderr +++ b/tests/ui/for/for-loop-bogosity.stderr @@ -4,7 +4,11 @@ error[E0277]: `MyStruct` is not an iterator LL | for x in bogus { | ^^^^^ `MyStruct` is not an iterator | - = help: the trait `Iterator` is not implemented for `MyStruct` +help: the trait `Iterator` is not implemented for `MyStruct` + --> $DIR/for-loop-bogosity.rs:1:1 + | +LL | struct MyStruct { + | ^^^^^^^^^^^^^^^ = note: required for `MyStruct` to implement `IntoIterator` error: aborting due to 1 previous error diff --git a/tests/ui/frontmatter/hyphen-in-infostring-leading.rs b/tests/ui/frontmatter/hyphen-in-infostring-leading.rs new file mode 100644 index 00000000000..8652fd76ad5 --- /dev/null +++ b/tests/ui/frontmatter/hyphen-in-infostring-leading.rs @@ -0,0 +1,9 @@ +--- -toml +//~^ ERROR: invalid infostring for frontmatter +--- + +// infostrings cannot have leading hyphens + +#![feature(frontmatter)] + +fn main() {} diff --git a/tests/ui/frontmatter/hyphen-in-infostring-leading.stderr b/tests/ui/frontmatter/hyphen-in-infostring-leading.stderr new file mode 100644 index 00000000000..167b537d62b --- /dev/null +++ b/tests/ui/frontmatter/hyphen-in-infostring-leading.stderr @@ -0,0 +1,10 @@ +error: invalid infostring for frontmatter + --> $DIR/hyphen-in-infostring-leading.rs:1:4 + | +LL | --- -toml + | ^^^^^^ + | + = note: frontmatter infostrings must be a single identifier immediately following the opening + +error: aborting due to 1 previous error + diff --git a/tests/ui/frontmatter/hyphen-in-infostring-non-leading.rs b/tests/ui/frontmatter/hyphen-in-infostring-non-leading.rs new file mode 100644 index 00000000000..35e7b96ff87 --- /dev/null +++ b/tests/ui/frontmatter/hyphen-in-infostring-non-leading.rs @@ -0,0 +1,9 @@ +--- Cargo-toml +--- + +// infostrings can contain hyphens as long as a hyphen isn't the first character. +//@ check-pass + +#![feature(frontmatter)] + +fn main() {} diff --git a/tests/ui/impl-trait/diagnostics/highlight-difference-between-expected-trait-and-found-trait.svg b/tests/ui/impl-trait/diagnostics/highlight-difference-between-expected-trait-and-found-trait.svg index 9832e28e008..73acb072ac5 100644 --- a/tests/ui/impl-trait/diagnostics/highlight-difference-between-expected-trait-and-found-trait.svg +++ b/tests/ui/impl-trait/diagnostics/highlight-difference-between-expected-trait-and-found-trait.svg @@ -1,4 +1,4 @@ -<svg width="1028px" height="398px" xmlns="http://www.w3.org/2000/svg"> +<svg width="1188px" height="398px" xmlns="http://www.w3.org/2000/svg"> <style> .fg { fill: #AAAAAA } .bg { background: #000000 } @@ -29,7 +29,7 @@ </tspan> <tspan x="10px" y="82px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> fn foo() -> impl Foo<i32> {</tspan> </tspan> - <tspan x="10px" y="100px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">^^^^^^^^^^^^^</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">the trait `Bar<i32>` is not implemented for `Struct`</tspan> + <tspan x="10px" y="100px"><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">^^^^^^^^^^^^^</tspan><tspan> </tspan><tspan class="fg-ansi256-009 bold">unsatisfied trait bound</tspan> </tspan> <tspan x="10px" y="118px"><tspan class="fg-ansi256-012 bold">LL</tspan><tspan> </tspan><tspan class="fg-ansi256-012 bold">|</tspan><tspan> Struct</tspan> </tspan> diff --git a/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.stderr b/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.stderr index a16e0160223..374176f041a 100644 --- a/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.stderr +++ b/tests/ui/impl-trait/in-trait/return-dont-satisfy-bounds.stderr @@ -24,7 +24,7 @@ error[E0277]: the trait bound `Bar: Foo<u8>` is not satisfied --> $DIR/return-dont-satisfy-bounds.rs:8:34 | LL | fn foo<F2: Foo<u8>>(self) -> impl Foo<u8> { - | ^^^^^^^^^^^^ the trait `Foo<u8>` is not implemented for `Bar` + | ^^^^^^^^^^^^ unsatisfied trait bound ... LL | self | ---- return type was inferred to be `Bar` here diff --git a/tests/ui/impl-trait/issues/issue-62742.stderr b/tests/ui/impl-trait/issues/issue-62742.stderr index ee4eb98f4ea..7ded3519d85 100644 --- a/tests/ui/impl-trait/issues/issue-62742.stderr +++ b/tests/ui/impl-trait/issues/issue-62742.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `RawImpl<_>: Raw<_>` is not satisfied --> $DIR/issue-62742.rs:4:5 | LL | WrongImpl::foo(0i32); - | ^^^^^^^^^ the trait `Raw<_>` is not implemented for `RawImpl<_>` + | ^^^^^^^^^ unsatisfied trait bound | = help: the trait `Raw<_>` is not implemented for `RawImpl<_>` but trait `Raw<[_]>` is implemented for it @@ -41,7 +41,7 @@ error[E0277]: the trait bound `RawImpl<()>: Raw<()>` is not satisfied --> $DIR/issue-62742.rs:10:5 | LL | WrongImpl::<()>::foo(0i32); - | ^^^^^^^^^^^^^^^ the trait `Raw<()>` is not implemented for `RawImpl<()>` + | ^^^^^^^^^^^^^^^ unsatisfied trait bound | = help: the trait `Raw<()>` is not implemented for `RawImpl<()>` but trait `Raw<[()]>` is implemented for it diff --git a/tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration.stderr b/tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration.stderr index a9a5483caa9..da196ae0433 100644 --- a/tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration.stderr +++ b/tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration.stderr @@ -7,7 +7,11 @@ LL | LL | Bar | --- return type was inferred to be `Bar` here | - = help: the trait `PartialEq<(Foo, i32)>` is not implemented for `Bar` +help: the trait `PartialEq<(Foo, i32)>` is not implemented for `Bar` + --> $DIR/recursive-type-alias-impl-trait-declaration.rs:5:1 + | +LL | struct Bar; + | ^^^^^^^^^^ = help: the trait `PartialEq<(Bar, i32)>` is implemented for `Bar` error: aborting due to 1 previous error diff --git a/tests/ui/impl-trait/transmute/in-defining-scope.rs b/tests/ui/impl-trait/transmute/in-defining-scope.rs index 4c8e1852a91..d9eafcc553c 100644 --- a/tests/ui/impl-trait/transmute/in-defining-scope.rs +++ b/tests/ui/impl-trait/transmute/in-defining-scope.rs @@ -1,11 +1,12 @@ -// This causes a query cycle due to using `TypingEnv::PostAnalysis`, +// Used to cause a query cycle due to using `TypingEnv::PostAnalysis`, // in #119821 const eval was changed to always use this mode. // -// See that PR for more details. +//@ check-pass + use std::mem::transmute; + fn foo() -> impl Sized { - //~^ ERROR cycle detected when computing type of - //~| WARN function cannot return without recursing + //~^ WARN function cannot return without recursing unsafe { transmute::<_, u8>(foo()); } diff --git a/tests/ui/impl-trait/transmute/in-defining-scope.stderr b/tests/ui/impl-trait/transmute/in-defining-scope.stderr index 31535695178..015a39d6670 100644 --- a/tests/ui/impl-trait/transmute/in-defining-scope.stderr +++ b/tests/ui/impl-trait/transmute/in-defining-scope.stderr @@ -1,56 +1,5 @@ -error[E0391]: cycle detected when computing type of `foo::{opaque#0}` - --> $DIR/in-defining-scope.rs:6:13 - | -LL | fn foo() -> impl Sized { - | ^^^^^^^^^^ - | -note: ...which requires computing type of opaque `foo::{opaque#0}`... - --> $DIR/in-defining-scope.rs:6:13 - | -LL | fn foo() -> impl Sized { - | ^^^^^^^^^^ -note: ...which requires borrow-checking `foo`... - --> $DIR/in-defining-scope.rs:6:1 - | -LL | fn foo() -> impl Sized { - | ^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires promoting constants in MIR for `foo`... - --> $DIR/in-defining-scope.rs:6:1 - | -LL | fn foo() -> impl Sized { - | ^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires checking if `foo` contains FFI-unwind calls... - --> $DIR/in-defining-scope.rs:6:1 - | -LL | fn foo() -> impl Sized { - | ^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires building MIR for `foo`... - --> $DIR/in-defining-scope.rs:6:1 - | -LL | fn foo() -> impl Sized { - | ^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires match-checking `foo`... - --> $DIR/in-defining-scope.rs:6:1 - | -LL | fn foo() -> impl Sized { - | ^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires type-checking `foo`... - --> $DIR/in-defining-scope.rs:6:1 - | -LL | fn foo() -> impl Sized { - | ^^^^^^^^^^^^^^^^^^^^^^ - = note: ...which requires computing layout of `foo::{opaque#0}`... - = note: ...which requires normalizing `foo::{opaque#0}`... - = note: ...which again requires computing type of `foo::{opaque#0}`, completing the cycle -note: cycle used when checking that `foo::{opaque#0}` is well-formed - --> $DIR/in-defining-scope.rs:6:13 - | -LL | fn foo() -> impl Sized { - | ^^^^^^^^^^ - = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information - warning: function cannot return without recursing - --> $DIR/in-defining-scope.rs:6:1 + --> $DIR/in-defining-scope.rs:8:1 | LL | fn foo() -> impl Sized { | ^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing @@ -61,6 +10,5 @@ LL | transmute::<_, u8>(foo()); = help: a `loop` may express intention better if this is on purpose = note: `#[warn(unconditional_recursion)]` on by default -error: aborting due to 1 previous error; 1 warning emitted +warning: 1 warning emitted -For more information about this error, try `rustc --explain E0391`. diff --git a/tests/ui/intrinsics/non-integer-atomic.stderr b/tests/ui/intrinsics/non-integer-atomic.stderr index 330d313639d..c27013c0de2 100644 --- a/tests/ui/intrinsics/non-integer-atomic.stderr +++ b/tests/ui/intrinsics/non-integer-atomic.stderr @@ -4,20 +4,20 @@ error[E0511]: invalid monomorphization of `atomic_load` intrinsic: expected basi LL | intrinsics::atomic_load::<_, { SeqCst }>(p); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +error[E0511]: invalid monomorphization of `atomic_xchg` intrinsic: expected basic integer or pointer type, found `&dyn Fn()` + --> $DIR/non-integer-atomic.rs:65:5 + | +LL | intrinsics::atomic_xchg::<_, { SeqCst }>(p, v); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error[E0511]: invalid monomorphization of `atomic_load` intrinsic: expected basic integer or pointer type, found `Foo` --> $DIR/non-integer-atomic.rs:35:5 | LL | intrinsics::atomic_load::<_, { SeqCst }>(p); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `atomic_store` intrinsic: expected basic integer or pointer type, found `&dyn Fn()` - --> $DIR/non-integer-atomic.rs:60:5 - | -LL | intrinsics::atomic_store::<_, { SeqCst }>(p, v); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0511]: invalid monomorphization of `atomic_xchg` intrinsic: expected basic integer or pointer type, found `[u8; 100]` - --> $DIR/non-integer-atomic.rs:85:5 +error[E0511]: invalid monomorphization of `atomic_xchg` intrinsic: expected basic integer or pointer type, found `Foo` + --> $DIR/non-integer-atomic.rs:45:5 | LL | intrinsics::atomic_xchg::<_, { SeqCst }>(p, v); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -28,71 +28,71 @@ error[E0511]: invalid monomorphization of `atomic_cxchg` intrinsic: expected bas LL | intrinsics::atomic_cxchg::<_, { SeqCst }, { SeqCst }>(p, v, v); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `atomic_store` intrinsic: expected basic integer or pointer type, found `Foo` - --> $DIR/non-integer-atomic.rs:40:5 +error[E0511]: invalid monomorphization of `atomic_store` intrinsic: expected basic integer or pointer type, found `&dyn Fn()` + --> $DIR/non-integer-atomic.rs:60:5 | LL | intrinsics::atomic_store::<_, { SeqCst }>(p, v); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `atomic_cxchg` intrinsic: expected basic integer or pointer type, found `[u8; 100]` - --> $DIR/non-integer-atomic.rs:90:5 +error[E0511]: invalid monomorphization of `atomic_cxchg` intrinsic: expected basic integer or pointer type, found `Foo` + --> $DIR/non-integer-atomic.rs:50:5 | LL | intrinsics::atomic_cxchg::<_, { SeqCst }, { SeqCst }>(p, v, v); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `atomic_store` intrinsic: expected basic integer or pointer type, found `[u8; 100]` - --> $DIR/non-integer-atomic.rs:80:5 - | -LL | intrinsics::atomic_store::<_, { SeqCst }>(p, v); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0511]: invalid monomorphization of `atomic_store` intrinsic: expected basic integer or pointer type, found `bool` - --> $DIR/non-integer-atomic.rs:20:5 +error[E0511]: invalid monomorphization of `atomic_store` intrinsic: expected basic integer or pointer type, found `Foo` + --> $DIR/non-integer-atomic.rs:40:5 | LL | intrinsics::atomic_store::<_, { SeqCst }>(p, v); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `atomic_xchg` intrinsic: expected basic integer or pointer type, found `&dyn Fn()` - --> $DIR/non-integer-atomic.rs:65:5 - | -LL | intrinsics::atomic_xchg::<_, { SeqCst }>(p, v); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - error[E0511]: invalid monomorphization of `atomic_load` intrinsic: expected basic integer or pointer type, found `[u8; 100]` --> $DIR/non-integer-atomic.rs:75:5 | LL | intrinsics::atomic_load::<_, { SeqCst }>(p); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +error[E0511]: invalid monomorphization of `atomic_xchg` intrinsic: expected basic integer or pointer type, found `[u8; 100]` + --> $DIR/non-integer-atomic.rs:85:5 + | +LL | intrinsics::atomic_xchg::<_, { SeqCst }>(p, v); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error[E0511]: invalid monomorphization of `atomic_load` intrinsic: expected basic integer or pointer type, found `bool` --> $DIR/non-integer-atomic.rs:15:5 | LL | intrinsics::atomic_load::<_, { SeqCst }>(p); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `atomic_cxchg` intrinsic: expected basic integer or pointer type, found `bool` - --> $DIR/non-integer-atomic.rs:30:5 +error[E0511]: invalid monomorphization of `atomic_xchg` intrinsic: expected basic integer or pointer type, found `bool` + --> $DIR/non-integer-atomic.rs:25:5 | -LL | intrinsics::atomic_cxchg::<_, { SeqCst }, { SeqCst }>(p, v, v); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | intrinsics::atomic_xchg::<_, { SeqCst }>(p, v); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `atomic_cxchg` intrinsic: expected basic integer or pointer type, found `Foo` - --> $DIR/non-integer-atomic.rs:50:5 +error[E0511]: invalid monomorphization of `atomic_cxchg` intrinsic: expected basic integer or pointer type, found `[u8; 100]` + --> $DIR/non-integer-atomic.rs:90:5 | LL | intrinsics::atomic_cxchg::<_, { SeqCst }, { SeqCst }>(p, v, v); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `atomic_xchg` intrinsic: expected basic integer or pointer type, found `Foo` - --> $DIR/non-integer-atomic.rs:45:5 +error[E0511]: invalid monomorphization of `atomic_store` intrinsic: expected basic integer or pointer type, found `[u8; 100]` + --> $DIR/non-integer-atomic.rs:80:5 | -LL | intrinsics::atomic_xchg::<_, { SeqCst }>(p, v); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | intrinsics::atomic_store::<_, { SeqCst }>(p, v); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `atomic_xchg` intrinsic: expected basic integer or pointer type, found `bool` - --> $DIR/non-integer-atomic.rs:25:5 +error[E0511]: invalid monomorphization of `atomic_cxchg` intrinsic: expected basic integer or pointer type, found `bool` + --> $DIR/non-integer-atomic.rs:30:5 | -LL | intrinsics::atomic_xchg::<_, { SeqCst }>(p, v); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | intrinsics::atomic_cxchg::<_, { SeqCst }, { SeqCst }>(p, v, v); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `atomic_store` intrinsic: expected basic integer or pointer type, found `bool` + --> $DIR/non-integer-atomic.rs:20:5 + | +LL | intrinsics::atomic_store::<_, { SeqCst }>(p, v); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 16 previous errors diff --git a/tests/ui/issues/issue-32782.rs b/tests/ui/issues/issue-32782.rs index e3aa9f3bf2f..1e99a25cec3 100644 --- a/tests/ui/issues/issue-32782.rs +++ b/tests/ui/issues/issue-32782.rs @@ -4,7 +4,9 @@ macro_rules! bar ( macro_rules! foo ( () => ( - #[allow_internal_unstable] //~ ERROR allow_internal_unstable side-steps + #[allow_internal_unstable()] + //~^ ERROR allow_internal_unstable side-steps + //~| ERROR `#[allow_internal_unstable]` attribute cannot be used on macro calls bar!(); ); ); diff --git a/tests/ui/issues/issue-32782.stderr b/tests/ui/issues/issue-32782.stderr index 830d83f6e57..96cd0489b2a 100644 --- a/tests/ui/issues/issue-32782.stderr +++ b/tests/ui/issues/issue-32782.stderr @@ -1,8 +1,8 @@ error[E0658]: allow_internal_unstable side-steps feature gating and stability checks --> $DIR/issue-32782.rs:7:9 | -LL | #[allow_internal_unstable] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[allow_internal_unstable()] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ... LL | foo!(); | ------ in this macro invocation @@ -11,6 +11,18 @@ LL | foo!(); = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 1 previous error +error: `#[allow_internal_unstable]` attribute cannot be used on macro calls + --> $DIR/issue-32782.rs:7:9 + | +LL | #[allow_internal_unstable()] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | foo!(); + | ------ in this macro invocation + | + = help: `#[allow_internal_unstable]` can be applied to macro defs and functions + = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/issues/issue-45801.stderr b/tests/ui/issues/issue-45801.stderr index 940c1865fa3..9f7c822f165 100644 --- a/tests/ui/issues/issue-45801.stderr +++ b/tests/ui/issues/issue-45801.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `Params: Plugin<i32>` is not satisfied --> $DIR/issue-45801.rs:21:9 | LL | req.get_ref::<Params>(); - | ^^^^^^^ the trait `Plugin<i32>` is not implemented for `Params` + | ^^^^^^^ unsatisfied trait bound | = help: the trait `Plugin<i32>` is not implemented for `Params` but trait `Plugin<Foo>` is implemented for it diff --git a/tests/ui/issues/issue-46311.rs b/tests/ui/issues/issue-46311.rs index 1233a49c582..24435665501 100644 --- a/tests/ui/issues/issue-46311.rs +++ b/tests/ui/issues/issue-46311.rs @@ -1,4 +1,4 @@ fn main() { - 'break: loop { //~ ERROR invalid label name `'break` + 'break: loop { //~ ERROR labels cannot use keyword names } } diff --git a/tests/ui/issues/issue-46311.stderr b/tests/ui/issues/issue-46311.stderr index 86a3602899a..f040ba2c026 100644 --- a/tests/ui/issues/issue-46311.stderr +++ b/tests/ui/issues/issue-46311.stderr @@ -1,4 +1,4 @@ -error: invalid label name `'break` +error: labels cannot use keyword names --> $DIR/issue-46311.rs:2:5 | LL | 'break: loop { diff --git a/tests/ui/kindck/kindck-copy.stderr b/tests/ui/kindck/kindck-copy.stderr index aee2aa98a60..f5623ddd4f7 100644 --- a/tests/ui/kindck/kindck-copy.stderr +++ b/tests/ui/kindck/kindck-copy.stderr @@ -120,8 +120,13 @@ error[E0277]: the trait bound `MyNoncopyStruct: Copy` is not satisfied --> $DIR/kindck-copy.rs:64:19 | LL | assert_copy::<MyNoncopyStruct>(); - | ^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `MyNoncopyStruct` + | ^^^^^^^^^^^^^^^ unsatisfied trait bound | +help: the trait `Copy` is not implemented for `MyNoncopyStruct` + --> $DIR/kindck-copy.rs:15:1 + | +LL | struct MyNoncopyStruct { + | ^^^^^^^^^^^^^^^^^^^^^^ note: required by a bound in `assert_copy` --> $DIR/kindck-copy.rs:5:18 | diff --git a/tests/ui/label/label-static.rs b/tests/ui/label/label-static.rs index 95e764d0187..ef06658506a 100644 --- a/tests/ui/label/label-static.rs +++ b/tests/ui/label/label-static.rs @@ -1,5 +1,5 @@ fn main() { - 'static: loop { //~ ERROR invalid label name `'static` - break 'static //~ ERROR invalid label name `'static` + 'static: loop { //~ ERROR labels cannot use keyword names + break 'static //~ ERROR labels cannot use keyword names } } diff --git a/tests/ui/label/label-static.stderr b/tests/ui/label/label-static.stderr index 1d3251d1b5f..f6ae8b44c08 100644 --- a/tests/ui/label/label-static.stderr +++ b/tests/ui/label/label-static.stderr @@ -1,10 +1,10 @@ -error: invalid label name `'static` +error: labels cannot use keyword names --> $DIR/label-static.rs:2:5 | LL | 'static: loop { | ^^^^^^^ -error: invalid label name `'static` +error: labels cannot use keyword names --> $DIR/label-static.rs:3:15 | LL | break 'static diff --git a/tests/ui/label/label-underscore.rs b/tests/ui/label/label-underscore.rs index de67f3d2c3e..8f1f90fe7c0 100644 --- a/tests/ui/label/label-underscore.rs +++ b/tests/ui/label/label-underscore.rs @@ -1,5 +1,5 @@ fn main() { - '_: loop { //~ ERROR invalid label name `'_` - break '_ //~ ERROR invalid label name `'_` + '_: loop { //~ ERROR labels cannot use keyword names + break '_ //~ ERROR labels cannot use keyword names } } diff --git a/tests/ui/label/label-underscore.stderr b/tests/ui/label/label-underscore.stderr index 4558ec4cb41..c0eb178d0f0 100644 --- a/tests/ui/label/label-underscore.stderr +++ b/tests/ui/label/label-underscore.stderr @@ -1,10 +1,10 @@ -error: invalid label name `'_` +error: labels cannot use keyword names --> $DIR/label-underscore.rs:2:5 | LL | '_: loop { | ^^ -error: invalid label name `'_` +error: labels cannot use keyword names --> $DIR/label-underscore.rs:3:15 | LL | break '_ diff --git a/tests/ui/layout/base-layout-is-sized-ice-123078.rs b/tests/ui/layout/base-layout-is-sized-ice-123078.rs index b1c33e15075..bbe32b2022a 100644 --- a/tests/ui/layout/base-layout-is-sized-ice-123078.rs +++ b/tests/ui/layout/base-layout-is-sized-ice-123078.rs @@ -8,7 +8,9 @@ struct S { } const C: S = unsafe { std::mem::transmute(()) }; -//~^ ERROR cannot transmute between types of different sizes, or dependently-sized types +//~^ ERROR the type `S` has an unknown layout +//~| ERROR cannot transmute between types of different sizes, or dependently-sized types + const _: [(); { C; 0 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 d8743d4e6d6..d6cebd3e7ae 100644 --- a/tests/ui/layout/base-layout-is-sized-ice-123078.stderr +++ b/tests/ui/layout/base-layout-is-sized-ice-123078.stderr @@ -16,6 +16,12 @@ help: the `Box` type always has a statically known size and allocates its conten LL | a: Box<[u8]>, | ++++ + +error[E0080]: the type `S` has an unknown layout + --> $DIR/base-layout-is-sized-ice-123078.rs:10:1 + | +LL | const C: S = unsafe { std::mem::transmute(()) }; + | ^^^^^^^^^^ evaluation of `C` failed here + error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> $DIR/base-layout-is-sized-ice-123078.rs:10:23 | @@ -25,7 +31,7 @@ LL | const C: S = unsafe { std::mem::transmute(()) }; = note: source type: `()` (0 bits) = note: target type: `S` (the type `S` has an unknown layout) -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors -Some errors have detailed explanations: E0277, E0512. -For more information about an error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0080, E0277, E0512. +For more information about an error, try `rustc --explain E0080`. diff --git a/tests/ui/layout/normalization-failure.rs b/tests/ui/layout/normalization-failure.rs index c0f8710c03c..a0195224d8c 100644 --- a/tests/ui/layout/normalization-failure.rs +++ b/tests/ui/layout/normalization-failure.rs @@ -49,8 +49,8 @@ fn check<T: Project1>() { unsafe { std::mem::transmute::<_, ()>(opaque::<T>().get()); //~^ ERROR: cannot transmute - //~| NOTE: (unable to determine layout for `<impl Project2 as Project2>::Assoc2` because `<impl Project2 as Project2>::Assoc2` cannot be normalized) - //~| NOTE: (0 bits) + //~| NOTE: source type: `{type error}` (the type has an unknown layout) + //~| NOTE: target type: `()` (0 bits) } } diff --git a/tests/ui/layout/normalization-failure.stderr b/tests/ui/layout/normalization-failure.stderr index 5fe38d4403a..1c78fc6ac41 100644 --- a/tests/ui/layout/normalization-failure.stderr +++ b/tests/ui/layout/normalization-failure.stderr @@ -4,7 +4,7 @@ error[E0512]: cannot transmute between types of different sizes, or dependently- LL | std::mem::transmute::<_, ()>(opaque::<T>().get()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: source type: `<impl Project2 as Project2>::Assoc2` (unable to determine layout for `<impl Project2 as Project2>::Assoc2` because `<impl Project2 as Project2>::Assoc2` cannot be normalized) + = note: source type: `{type error}` (the type has an unknown layout) = note: target type: `()` (0 bits) error: aborting due to 1 previous error diff --git a/tests/ui/layout/transmute-to-tail-with-err.rs b/tests/ui/layout/transmute-to-tail-with-err.rs index 6753ce15ed1..614c1ac756e 100644 --- a/tests/ui/layout/transmute-to-tail-with-err.rs +++ b/tests/ui/layout/transmute-to-tail-with-err.rs @@ -5,4 +5,5 @@ struct Bar(Box<dyn Trait<T>>); fn main() { let x: Bar = unsafe { std::mem::transmute(()) }; + //~^ ERROR cannot transmute between types of different size } diff --git a/tests/ui/layout/transmute-to-tail-with-err.stderr b/tests/ui/layout/transmute-to-tail-with-err.stderr index 433c6b38d0b..cff40812717 100644 --- a/tests/ui/layout/transmute-to-tail-with-err.stderr +++ b/tests/ui/layout/transmute-to-tail-with-err.stderr @@ -9,6 +9,16 @@ help: you might be missing a type parameter LL | struct Bar<T>(Box<dyn Trait<T>>); | +++ -error: aborting due to 1 previous error +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> $DIR/transmute-to-tail-with-err.rs:7:27 + | +LL | let x: Bar = unsafe { std::mem::transmute(()) }; + | ^^^^^^^^^^^^^^^^^^^ + | + = note: source type: `()` (0 bits) + = note: target type: `Bar` (the type has an unknown layout) + +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0412`. +Some errors have detailed explanations: E0412, E0512. +For more information about an error, try `rustc --explain E0412`. diff --git a/tests/ui/lifetimes/issue-95023.stderr b/tests/ui/lifetimes/issue-95023.stderr index dffa033fb17..013bc51ff78 100644 --- a/tests/ui/lifetimes/issue-95023.stderr +++ b/tests/ui/lifetimes/issue-95023.stderr @@ -46,7 +46,11 @@ error[E0277]: expected a `FnMut(&isize)` closure, found `Error` LL | impl Fn(&isize) for Error { | ^^^^^ expected an `FnMut(&isize)` closure, found `Error` | - = help: the trait `FnMut(&isize)` is not implemented for `Error` +help: the trait `FnMut(&isize)` is not implemented for `Error` + --> $DIR/issue-95023.rs:2:1 + | +LL | struct Error(ErrorKind); + | ^^^^^^^^^^^^ note: required by a bound in `Fn` --> $SRC_DIR/core/src/ops/function.rs:LL:COL diff --git a/tests/ui/lifetimes/raw/use-of-undeclared-raw-lifetimes.rs b/tests/ui/lifetimes/raw/use-of-undeclared-raw-lifetimes.rs new file mode 100644 index 00000000000..69461cfb200 --- /dev/null +++ b/tests/ui/lifetimes/raw/use-of-undeclared-raw-lifetimes.rs @@ -0,0 +1,21 @@ +// Check that we properly suggest `r#fn` if we use it undeclared. +// https://github.com/rust-lang/rust/issues/143150 +// +//@ edition: 2021 + +fn a(_: dyn Trait + 'r#fn) { + //~^ ERROR use of undeclared lifetime name `'r#fn` [E0261] +} + +trait Trait {} + +struct Test { + a: &'r#fn str, + //~^ ERROR use of undeclared lifetime name `'r#fn` [E0261] +} + +trait Trait1<T> + where T: for<'a> Trait1<T> + 'r#fn { } +//~^ ERROR use of undeclared lifetime name `'r#fn` [E0261] + +fn main() {} diff --git a/tests/ui/lifetimes/raw/use-of-undeclared-raw-lifetimes.stderr b/tests/ui/lifetimes/raw/use-of-undeclared-raw-lifetimes.stderr new file mode 100644 index 00000000000..8a17ce53dcf --- /dev/null +++ b/tests/ui/lifetimes/raw/use-of-undeclared-raw-lifetimes.stderr @@ -0,0 +1,42 @@ +error[E0261]: use of undeclared lifetime name `'r#fn` + --> $DIR/use-of-undeclared-raw-lifetimes.rs:6:21 + | +LL | fn a(_: dyn Trait + 'r#fn) { + | ^^^^^ undeclared lifetime + | +help: consider introducing lifetime `'r#fn` here + | +LL | fn a<'r#fn>(_: dyn Trait + 'r#fn) { + | +++++++ + +error[E0261]: use of undeclared lifetime name `'r#fn` + --> $DIR/use-of-undeclared-raw-lifetimes.rs:13:9 + | +LL | a: &'r#fn str, + | ^^^^^ undeclared lifetime + | +help: consider introducing lifetime `'r#fn` here + | +LL | struct Test<'r#fn> { + | +++++++ + +error[E0261]: use of undeclared lifetime name `'r#fn` + --> $DIR/use-of-undeclared-raw-lifetimes.rs:18:32 + | +LL | where T: for<'a> Trait1<T> + 'r#fn { } + | ^^^^^ undeclared lifetime + | + = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html +help: consider making the bound lifetime-generic with a new `'r#fn` lifetime + | +LL - where T: for<'a> Trait1<T> + 'r#fn { } +LL + where for<'r#fn, 'a> T: Trait1<T> + 'r#fn { } + | +help: consider introducing lifetime `'r#fn` here + | +LL | trait Trait1<'r#fn, T> + | ++++++ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0261`. diff --git a/tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-not-foreign-fn.stderr b/tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-not-foreign-fn.stderr index c561373db77..0f7fb8e6d3b 100644 --- a/tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-not-foreign-fn.stderr +++ b/tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-not-foreign-fn.stderr @@ -4,7 +4,7 @@ error: `#[link_ordinal]` attribute cannot be used on structs LL | #[link_ordinal(123)] | ^^^^^^^^^^^^^^^^^^^^ | - = help: `#[link_ordinal]` can be applied to foreign functions, foreign statics + = help: `#[link_ordinal]` can be applied to foreign functions and foreign statics error: `#[link_ordinal]` attribute cannot be used on functions --> $DIR/link-ordinal-not-foreign-fn.rs:5:1 @@ -12,7 +12,7 @@ error: `#[link_ordinal]` attribute cannot be used on functions LL | #[link_ordinal(123)] | ^^^^^^^^^^^^^^^^^^^^ | - = help: `#[link_ordinal]` can be applied to foreign functions, foreign statics + = help: `#[link_ordinal]` can be applied to foreign functions and foreign statics error: `#[link_ordinal]` attribute cannot be used on statics --> $DIR/link-ordinal-not-foreign-fn.rs:9:1 @@ -20,7 +20,7 @@ error: `#[link_ordinal]` attribute cannot be used on statics LL | #[link_ordinal(42)] | ^^^^^^^^^^^^^^^^^^^ | - = help: `#[link_ordinal]` can be applied to foreign functions, foreign statics + = help: `#[link_ordinal]` can be applied to foreign functions and foreign statics error: aborting due to 3 previous errors diff --git a/tests/ui/lint/inert-attr-macro.rs b/tests/ui/lint/inert-attr-macro.rs index f2d50e30aec..d345cbc0f07 100644 --- a/tests/ui/lint/inert-attr-macro.rs +++ b/tests/ui/lint/inert-attr-macro.rs @@ -1,5 +1,6 @@ //@ check-pass +#![feature(rustc_attrs)] #![warn(unused)] macro_rules! foo { @@ -7,16 +8,16 @@ macro_rules! foo { } fn main() { - #[inline] foo!(); //~ WARN unused attribute `inline` + #[rustc_dummy] foo!(); //~ WARN unused attribute `rustc_dummy` // This does nothing, since `#[allow(warnings)]` is itself // an inert attribute on a macro call - #[allow(warnings)] #[inline] foo!(); //~ WARN unused attribute `allow` - //~^ WARN unused attribute `inline` + #[allow(warnings)] #[rustc_dummy] foo!(); //~ WARN unused attribute `allow` + //~^ WARN unused attribute `rustc_dummy` // This does work, since the attribute is on a parent // of the macro invocation. - #[allow(warnings)] { #[inline] foo!(); } + #[allow(warnings)] { #[rustc_dummy] foo!(); } // Ok, `cfg` and `cfg_attr` are expanded eagerly and do not warn. #[cfg(true)] foo!(); diff --git a/tests/ui/lint/inert-attr-macro.stderr b/tests/ui/lint/inert-attr-macro.stderr index 5ccb4ffe792..fc02ee34ae6 100644 --- a/tests/ui/lint/inert-attr-macro.stderr +++ b/tests/ui/lint/inert-attr-macro.stderr @@ -1,44 +1,44 @@ -warning: unused attribute `inline` - --> $DIR/inert-attr-macro.rs:10:5 +warning: unused attribute `rustc_dummy` + --> $DIR/inert-attr-macro.rs:11:5 | -LL | #[inline] foo!(); - | ^^^^^^^^^ +LL | #[rustc_dummy] foo!(); + | ^^^^^^^^^^^^^^ | -note: the built-in attribute `inline` will be ignored, since it's applied to the macro invocation `foo` - --> $DIR/inert-attr-macro.rs:10:15 +note: the built-in attribute `rustc_dummy` will be ignored, since it's applied to the macro invocation `foo` + --> $DIR/inert-attr-macro.rs:11:20 | -LL | #[inline] foo!(); - | ^^^ +LL | #[rustc_dummy] foo!(); + | ^^^ note: the lint level is defined here - --> $DIR/inert-attr-macro.rs:3:9 + --> $DIR/inert-attr-macro.rs:4:9 | LL | #![warn(unused)] | ^^^^^^ = note: `#[warn(unused_attributes)]` implied by `#[warn(unused)]` warning: unused attribute `allow` - --> $DIR/inert-attr-macro.rs:14:5 + --> $DIR/inert-attr-macro.rs:15:5 | -LL | #[allow(warnings)] #[inline] foo!(); +LL | #[allow(warnings)] #[rustc_dummy] foo!(); | ^^^^^^^^^^^^^^^^^^ | note: the built-in attribute `allow` will be ignored, since it's applied to the macro invocation `foo` - --> $DIR/inert-attr-macro.rs:14:34 + --> $DIR/inert-attr-macro.rs:15:39 | -LL | #[allow(warnings)] #[inline] foo!(); - | ^^^ +LL | #[allow(warnings)] #[rustc_dummy] foo!(); + | ^^^ -warning: unused attribute `inline` - --> $DIR/inert-attr-macro.rs:14:24 +warning: unused attribute `rustc_dummy` + --> $DIR/inert-attr-macro.rs:15:24 | -LL | #[allow(warnings)] #[inline] foo!(); - | ^^^^^^^^^ +LL | #[allow(warnings)] #[rustc_dummy] foo!(); + | ^^^^^^^^^^^^^^ | -note: the built-in attribute `inline` will be ignored, since it's applied to the macro invocation `foo` - --> $DIR/inert-attr-macro.rs:14:34 +note: the built-in attribute `rustc_dummy` will be ignored, since it's applied to the macro invocation `foo` + --> $DIR/inert-attr-macro.rs:15:39 | -LL | #[allow(warnings)] #[inline] foo!(); - | ^^^ +LL | #[allow(warnings)] #[rustc_dummy] foo!(); + | ^^^ warning: 3 warnings emitted diff --git a/tests/ui/lint/internal/higher-ranked-query-instability.rs b/tests/ui/lint/internal/higher-ranked-query-instability.rs new file mode 100644 index 00000000000..4407baac0c6 --- /dev/null +++ b/tests/ui/lint/internal/higher-ranked-query-instability.rs @@ -0,0 +1,11 @@ +//@ check-pass +//@ compile-flags: -Zunstable-options + +// Make sure we don't try to resolve instances for trait refs that have escaping +// bound vars when computing the query instability lint. + +fn foo<T>() where for<'a> &'a [T]: IntoIterator<Item = &'a T> {} + +fn main() { + foo::<()>(); +} diff --git a/tests/ui/lint/unused/unused-attr-macro-rules.stderr b/tests/ui/lint/unused/unused-attr-macro-rules.stderr index 0c55ae678e9..9d61120463c 100644 --- a/tests/ui/lint/unused/unused-attr-macro-rules.stderr +++ b/tests/ui/lint/unused/unused-attr-macro-rules.stderr @@ -17,7 +17,7 @@ LL | #[macro_use] | ^^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[macro_use]` can be applied to modules, extern crates, crates + = help: `#[macro_use]` can be applied to modules, extern crates, and crates error: `#[path]` attribute cannot be used on macro defs --> $DIR/unused-attr-macro-rules.rs:9:1 diff --git a/tests/ui/lint/unused/unused_attributes-must_use.stderr b/tests/ui/lint/unused/unused_attributes-must_use.stderr index 12cc2ea56be..03baea3a004 100644 --- a/tests/ui/lint/unused/unused_attributes-must_use.stderr +++ b/tests/ui/lint/unused/unused_attributes-must_use.stderr @@ -22,7 +22,7 @@ LL | #[must_use] | ^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[must_use]` can be applied to functions, data types, unions, traits + = help: `#[must_use]` can be applied to functions, data types, unions, and traits error: `#[must_use]` attribute cannot be used on modules --> $DIR/unused_attributes-must_use.rs:11:1 @@ -31,7 +31,7 @@ LL | #[must_use] | ^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[must_use]` can be applied to functions, data types, unions, traits + = help: `#[must_use]` can be applied to functions, data types, unions, and traits error: `#[must_use]` attribute cannot be used on use statements --> $DIR/unused_attributes-must_use.rs:15:1 @@ -40,7 +40,7 @@ LL | #[must_use] | ^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[must_use]` can be applied to functions, data types, unions, traits + = help: `#[must_use]` can be applied to functions, data types, unions, and traits error: `#[must_use]` attribute cannot be used on constants --> $DIR/unused_attributes-must_use.rs:19:1 @@ -49,7 +49,7 @@ LL | #[must_use] | ^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[must_use]` can be applied to functions, data types, unions, traits + = help: `#[must_use]` can be applied to functions, data types, unions, and traits error: `#[must_use]` attribute cannot be used on statics --> $DIR/unused_attributes-must_use.rs:22:1 @@ -58,7 +58,7 @@ LL | #[must_use] | ^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[must_use]` can be applied to functions, data types, unions, traits + = help: `#[must_use]` can be applied to functions, data types, unions, and traits error: `#[must_use]` attribute cannot be used on inherent impl blocks --> $DIR/unused_attributes-must_use.rs:40:1 @@ -67,7 +67,7 @@ LL | #[must_use] | ^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[must_use]` can be applied to functions, data types, unions, traits + = help: `#[must_use]` can be applied to functions, data types, unions, and traits error: `#[must_use]` attribute cannot be used on foreign modules --> $DIR/unused_attributes-must_use.rs:55:1 @@ -76,7 +76,7 @@ LL | #[must_use] | ^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[must_use]` can be applied to functions, data types, unions, traits + = help: `#[must_use]` can be applied to functions, data types, unions, and traits error: `#[must_use]` attribute cannot be used on foreign statics --> $DIR/unused_attributes-must_use.rs:59:5 @@ -85,7 +85,7 @@ LL | #[must_use] | ^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[must_use]` can be applied to functions, data types, unions, traits + = help: `#[must_use]` can be applied to functions, data types, unions, and traits error: `#[must_use]` attribute cannot be used on type aliases --> $DIR/unused_attributes-must_use.rs:71:1 @@ -94,7 +94,7 @@ LL | #[must_use] | ^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[must_use]` can be applied to functions, data types, unions, traits + = help: `#[must_use]` can be applied to functions, data types, unions, and traits error: `#[must_use]` attribute cannot be used on function params --> $DIR/unused_attributes-must_use.rs:75:8 @@ -103,7 +103,7 @@ LL | fn qux<#[must_use] T>(_: T) {} | ^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[must_use]` can be applied to functions, data types, unions, traits + = help: `#[must_use]` can be applied to functions, data types, unions, and traits error: `#[must_use]` attribute cannot be used on associated consts --> $DIR/unused_attributes-must_use.rs:80:5 @@ -112,7 +112,7 @@ LL | #[must_use] | ^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[must_use]` can be applied to functions, data types, unions, traits + = help: `#[must_use]` can be applied to functions, data types, unions, and traits error: `#[must_use]` attribute cannot be used on associated types --> $DIR/unused_attributes-must_use.rs:83:5 @@ -121,7 +121,7 @@ LL | #[must_use] | ^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[must_use]` can be applied to functions, data types, unions, traits + = help: `#[must_use]` can be applied to functions, data types, unions, and traits error: `#[must_use]` attribute cannot be used on trait impl blocks --> $DIR/unused_attributes-must_use.rs:93:1 @@ -130,7 +130,7 @@ LL | #[must_use] | ^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[must_use]` can be applied to functions, data types, unions, traits + = help: `#[must_use]` can be applied to functions, data types, unions, and traits error: `#[must_use]` attribute cannot be used on trait methods in impl blocks --> $DIR/unused_attributes-must_use.rs:98:5 @@ -139,7 +139,7 @@ LL | #[must_use] | ^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[must_use]` can be applied to data types, functions, unions, required trait methods, provided trait methods, inherent methods, foreign functions, traits + = help: `#[must_use]` can be applied to data types, functions, unions, required trait methods, provided trait methods, inherent methods, foreign functions, and traits error: `#[must_use]` attribute cannot be used on trait aliases --> $DIR/unused_attributes-must_use.rs:105:1 @@ -148,7 +148,7 @@ LL | #[must_use] | ^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[must_use]` can be applied to functions, data types, unions, traits + = help: `#[must_use]` can be applied to functions, data types, unions, and traits error: `#[must_use]` attribute cannot be used on macro defs --> $DIR/unused_attributes-must_use.rs:109:1 @@ -157,7 +157,7 @@ LL | #[must_use] | ^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[must_use]` can be applied to functions, data types, unions, traits + = help: `#[must_use]` can be applied to functions, data types, unions, and traits error: `#[must_use]` attribute cannot be used on statements --> $DIR/unused_attributes-must_use.rs:118:5 @@ -166,7 +166,7 @@ LL | #[must_use] | ^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[must_use]` can be applied to functions, data types, unions, traits + = help: `#[must_use]` can be applied to functions, data types, unions, and traits error: `#[must_use]` attribute cannot be used on closures --> $DIR/unused_attributes-must_use.rs:123:13 @@ -175,7 +175,7 @@ LL | let x = #[must_use] | ^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[must_use]` can be applied to methods, data types, functions, unions, foreign functions, traits + = help: `#[must_use]` can be applied to methods, data types, functions, unions, foreign functions, and traits error: `#[must_use]` attribute cannot be used on match arms --> $DIR/unused_attributes-must_use.rs:146:9 @@ -184,7 +184,7 @@ LL | #[must_use] | ^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[must_use]` can be applied to functions, data types, unions, traits + = help: `#[must_use]` can be applied to functions, data types, unions, and traits error: `#[must_use]` attribute cannot be used on struct fields --> $DIR/unused_attributes-must_use.rs:155:28 @@ -193,7 +193,7 @@ LL | let s = PatternField { #[must_use] foo: 123 }; | ^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[must_use]` can be applied to functions, data types, unions, traits + = help: `#[must_use]` can be applied to functions, data types, unions, and traits error: `#[must_use]` attribute cannot be used on pattern fields --> $DIR/unused_attributes-must_use.rs:157:24 @@ -202,7 +202,7 @@ LL | let PatternField { #[must_use] foo } = s; | ^^^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[must_use]` can be applied to functions, data types, unions, traits + = help: `#[must_use]` can be applied to functions, data types, unions, and traits error: unused `X` that must be used --> $DIR/unused_attributes-must_use.rs:128:5 diff --git a/tests/ui/lint/warn-unused-inline-on-fn-prototypes.stderr b/tests/ui/lint/warn-unused-inline-on-fn-prototypes.stderr index 336366042f9..fcce1db7a9a 100644 --- a/tests/ui/lint/warn-unused-inline-on-fn-prototypes.stderr +++ b/tests/ui/lint/warn-unused-inline-on-fn-prototypes.stderr @@ -5,7 +5,7 @@ LL | #[inline] | ^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[inline]` can be applied to functions, inherent methods, provided trait methods, trait methods in impl blocks, closures + = help: `#[inline]` can be applied to functions, inherent methods, provided trait methods, trait methods in impl blocks, and closures note: the lint level is defined here --> $DIR/warn-unused-inline-on-fn-prototypes.rs:1:9 | @@ -19,7 +19,7 @@ LL | #[inline] | ^^^^^^^^^ | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = help: `#[inline]` can be applied to methods, functions, closures + = help: `#[inline]` can be applied to methods, functions, and closures error: aborting due to 2 previous errors diff --git a/tests/ui/macros/issue-68060.stderr b/tests/ui/macros/issue-68060.stderr index c701e50f054..4699594a2b0 100644 --- a/tests/ui/macros/issue-68060.stderr +++ b/tests/ui/macros/issue-68060.stderr @@ -4,7 +4,7 @@ error: `#[target_feature]` attribute cannot be used on closures LL | #[target_feature(enable = "")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: `#[target_feature]` can be applied to methods, functions + = help: `#[target_feature]` can be applied to methods and functions error[E0658]: `#[track_caller]` on closures is currently unstable --> $DIR/issue-68060.rs:6:13 diff --git a/tests/ui/marker_trait_attr/overlap-marker-trait.stderr b/tests/ui/marker_trait_attr/overlap-marker-trait.stderr index cdad382d11c..5516d034488 100644 --- a/tests/ui/marker_trait_attr/overlap-marker-trait.stderr +++ b/tests/ui/marker_trait_attr/overlap-marker-trait.stderr @@ -2,8 +2,13 @@ error[E0277]: the trait bound `NotDebugOrDisplay: Marker` is not satisfied --> $DIR/overlap-marker-trait.rs:28:17 | LL | is_marker::<NotDebugOrDisplay>(); - | ^^^^^^^^^^^^^^^^^ the trait `Marker` is not implemented for `NotDebugOrDisplay` + | ^^^^^^^^^^^^^^^^^ unsatisfied trait bound | +help: the trait `Marker` is not implemented for `NotDebugOrDisplay` + --> $DIR/overlap-marker-trait.rs:18:1 + | +LL | struct NotDebugOrDisplay; + | ^^^^^^^^^^^^^^^^^^^^^^^^ note: required by a bound in `is_marker` --> $DIR/overlap-marker-trait.rs:16:17 | diff --git a/tests/ui/methods/inherent-bound-in-probe.stderr b/tests/ui/methods/inherent-bound-in-probe.stderr index b7751ca4714..6502752bcb4 100644 --- a/tests/ui/methods/inherent-bound-in-probe.stderr +++ b/tests/ui/methods/inherent-bound-in-probe.stderr @@ -4,7 +4,11 @@ error[E0277]: `Helper<'a, T>` is not an iterator LL | type IntoIter = Helper<'a, T>; | ^^^^^^^^^^^^^ `Helper<'a, T>` is not an iterator | - = help: the trait `Iterator` is not implemented for `Helper<'a, T>` +help: the trait `Iterator` is not implemented for `Helper<'a, T>` + --> $DIR/inherent-bound-in-probe.rs:15:1 + | +LL | struct Helper<'a, T> + | ^^^^^^^^^^^^^^^^^^^^ note: required by a bound in `std::iter::IntoIterator::IntoIter` --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL diff --git a/tests/ui/methods/missing-bound-on-tuple.rs b/tests/ui/methods/missing-bound-on-tuple.rs deleted file mode 100644 index 25deabf5926..00000000000 --- a/tests/ui/methods/missing-bound-on-tuple.rs +++ /dev/null @@ -1,39 +0,0 @@ -trait WorksOnDefault { - fn do_something() {} -} - -impl<T: Default> WorksOnDefault for T {} -//~^ NOTE the following trait bounds were not satisfied -//~| NOTE unsatisfied trait bound introduced here - -trait Foo {} - -trait WorksOnFoo { - fn do_be_do() {} -} - -impl<T: Foo> WorksOnFoo for T {} -//~^ NOTE the following trait bounds were not satisfied -//~| NOTE unsatisfied trait bound introduced here - -impl<A: Foo, B: Foo, C: Foo> Foo for (A, B, C) {} -//~^ NOTE `Foo` is implemented for `(i32, u32, String)` -impl Foo for i32 {} -impl Foo for &i32 {} -impl Foo for u32 {} -impl Foo for String {} - -fn main() { - let _success = <(i32, u32, String)>::do_something(); - let _failure = <(i32, &u32, String)>::do_something(); //~ ERROR E0599 - //~^ NOTE `Default` is implemented for `(i32, u32, String)` - //~| NOTE function or associated item cannot be called on - let _success = <(i32, u32, String)>::do_be_do(); - let _failure = <(i32, &u32, String)>::do_be_do(); //~ ERROR E0599 - //~^ NOTE function or associated item cannot be called on - let _success = <(i32, u32, String)>::default(); - let _failure = <(i32, &u32, String)>::default(); //~ ERROR E0599 - //~^ NOTE `Default` is implemented for `(i32, u32, String)` - //~| NOTE function or associated item cannot be called on - //~| NOTE the following trait bounds were not satisfied -} diff --git a/tests/ui/methods/missing-bound-on-tuple.stderr b/tests/ui/methods/missing-bound-on-tuple.stderr deleted file mode 100644 index f3e0897e5e6..00000000000 --- a/tests/ui/methods/missing-bound-on-tuple.stderr +++ /dev/null @@ -1,58 +0,0 @@ -error[E0599]: the function or associated item `do_something` exists for tuple `(i32, &u32, String)`, but its trait bounds were not satisfied - --> $DIR/missing-bound-on-tuple.rs:28:43 - | -LL | let _failure = <(i32, &u32, String)>::do_something(); - | ^^^^^^^^^^^^ function or associated item cannot be called on `(i32, &u32, String)` due to unsatisfied trait bounds - | -note: the following trait bounds were not satisfied: - `&(i32, &u32, String): Default` - `&mut (i32, &u32, String): Default` - `(i32, &u32, String): Default` - --> $DIR/missing-bound-on-tuple.rs:5:9 - | -LL | impl<T: Default> WorksOnDefault for T {} - | ^^^^^^^ -------------- - - | | - | unsatisfied trait bound introduced here -note: `Default` is implemented for `(i32, u32, String)` but not for `(i32, &u32, String)` - --> $SRC_DIR/core/src/tuple.rs:LL:COL - = note: this error originates in the macro `tuple_impls` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0599]: the function or associated item `do_be_do` exists for tuple `(i32, &u32, String)`, but its trait bounds were not satisfied - --> $DIR/missing-bound-on-tuple.rs:32:43 - | -LL | let _failure = <(i32, &u32, String)>::do_be_do(); - | ^^^^^^^^ function or associated item cannot be called on `(i32, &u32, String)` due to unsatisfied trait bounds - | -note: the following trait bounds were not satisfied: - `&(i32, &u32, String): Foo` - `&mut (i32, &u32, String): Foo` - `(i32, &u32, String): Foo` - --> $DIR/missing-bound-on-tuple.rs:15:9 - | -LL | impl<T: Foo> WorksOnFoo for T {} - | ^^^ ---------- - - | | - | unsatisfied trait bound introduced here -note: `Foo` is implemented for `(i32, u32, String)` but not for `(i32, &u32, String)` - --> $DIR/missing-bound-on-tuple.rs:19:1 - | -LL | impl<A: Foo, B: Foo, C: Foo> Foo for (A, B, C) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0599]: the function or associated item `default` exists for tuple `(i32, &u32, String)`, but its trait bounds were not satisfied - --> $DIR/missing-bound-on-tuple.rs:35:43 - | -LL | let _failure = <(i32, &u32, String)>::default(); - | ^^^^^^^ function or associated item cannot be called on `(i32, &u32, String)` due to unsatisfied trait bounds - | - = note: the following trait bounds were not satisfied: - `&u32: Default` - which is required by `(i32, &u32, String): Default` -note: `Default` is implemented for `(i32, u32, String)` but not for `(i32, &u32, String)` - --> $SRC_DIR/core/src/tuple.rs:LL:COL - = note: this error originates in the macro `tuple_impls` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/methods/tuple-suggestions-issue-142488.rs b/tests/ui/methods/tuple-suggestions-issue-142488.rs new file mode 100644 index 00000000000..f6c58fce9a1 --- /dev/null +++ b/tests/ui/methods/tuple-suggestions-issue-142488.rs @@ -0,0 +1,48 @@ +// Regression test for issue #142488, a diagnostics ICE when trying to suggest missing methods +// present in similar tuple types. +// This is a few of the MCVEs from the issues and its many duplicates. + +// 1 +fn main() { + for a in x { + //~^ ERROR: cannot find value `x` in this scope + (a,).to_string() + //~^ ERROR: the method `to_string` exists for tuple + } +} + +// 2 +trait Trait { + fn meth(self); +} + +impl<T, U: Trait> Trait for (T, U) { + fn meth(self) {} +} + +fn mcve2() { + ((), std::collections::HashMap::new()).meth() + //~^ ERROR: the method `meth` exists for tuple +} + +// 3 +trait I {} + +struct Struct; +impl I for Struct {} + +trait Tr { + fn f<A>(self) -> (A,) + where + Self: Sized, + { + loop {} + } +} + +impl<T> Tr for T where T: I {} + +fn mcve3() { + Struct.f().f(); + //~^ ERROR: the method `f` exists for tuple +} diff --git a/tests/ui/methods/tuple-suggestions-issue-142488.stderr b/tests/ui/methods/tuple-suggestions-issue-142488.stderr new file mode 100644 index 00000000000..f9363bb216f --- /dev/null +++ b/tests/ui/methods/tuple-suggestions-issue-142488.stderr @@ -0,0 +1,61 @@ +error[E0425]: cannot find value `x` in this scope + --> $DIR/tuple-suggestions-issue-142488.rs:7:14 + | +LL | for a in x { + | ^ not found in this scope + +error[E0599]: the method `to_string` exists for tuple `(_,)`, but its trait bounds were not satisfied + --> $DIR/tuple-suggestions-issue-142488.rs:9:14 + | +LL | (a,).to_string() + | ^^^^^^^^^ method cannot be called on `(_,)` due to unsatisfied trait bounds + | + = note: the following trait bounds were not satisfied: + `(_,): std::fmt::Display` + which is required by `(_,): ToString` + +error[E0599]: the method `meth` exists for tuple `((), HashMap<_, _>)`, but its trait bounds were not satisfied + --> $DIR/tuple-suggestions-issue-142488.rs:24:44 + | +LL | ((), std::collections::HashMap::new()).meth() + | ^^^^ method cannot be called on `((), HashMap<_, _>)` due to unsatisfied trait bounds + | +note: trait bound `HashMap<_, _>: Trait` was not satisfied + --> $DIR/tuple-suggestions-issue-142488.rs:19:12 + | +LL | impl<T, U: Trait> Trait for (T, U) { + | ^^^^^ ----- ------ + | | + | unsatisfied trait bound introduced here + = help: items from traits can only be used if the trait is implemented and in scope +note: `Trait` defines an item `meth`, perhaps you need to implement it + --> $DIR/tuple-suggestions-issue-142488.rs:15:1 + | +LL | trait Trait { + | ^^^^^^^^^^^ + +error[E0599]: the method `f` exists for tuple `(_,)`, but its trait bounds were not satisfied + --> $DIR/tuple-suggestions-issue-142488.rs:46:16 + | +LL | Struct.f().f(); + | ^ method cannot be called on `(_,)` due to unsatisfied trait bounds + | +note: the following trait bounds were not satisfied: + `&(_,): I` + `&mut (_,): I` + `(_,): I` + --> $DIR/tuple-suggestions-issue-142488.rs:43:27 + | +LL | impl<T> Tr for T where T: I {} + | -- - ^ unsatisfied trait bound introduced here + = help: items from traits can only be used if the trait is implemented and in scope +note: `Tr` defines an item `f`, perhaps you need to implement it + --> $DIR/tuple-suggestions-issue-142488.rs:34:1 + | +LL | trait Tr { + | ^^^^^^^^ + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0425, E0599. +For more information about an error, try `rustc --explain E0425`. diff --git a/tests/ui/mut/mutable-enum-indirect.stderr b/tests/ui/mut/mutable-enum-indirect.stderr index 0b7783b3318..b15492357f5 100644 --- a/tests/ui/mut/mutable-enum-indirect.stderr +++ b/tests/ui/mut/mutable-enum-indirect.stderr @@ -6,7 +6,11 @@ LL | bar(&x); | | | required by a bound introduced by this call | - = help: within `&Foo`, the trait `Sync` is not implemented for `NoSync` +help: within `&Foo`, the trait `Sync` is not implemented for `NoSync` + --> $DIR/mutable-enum-indirect.rs:8:1 + | +LL | struct NoSync; + | ^^^^^^^^^^^^^ note: required because it appears within the type `Foo` --> $DIR/mutable-enum-indirect.rs:11:6 | diff --git a/tests/ui/namespace/namespace-mix.stderr b/tests/ui/namespace/namespace-mix.stderr index 200d31cc710..7c889f34e91 100644 --- a/tests/ui/namespace/namespace-mix.stderr +++ b/tests/ui/namespace/namespace-mix.stderr @@ -106,10 +106,15 @@ error[E0277]: the trait bound `c::Item: Impossible` is not satisfied --> $DIR/namespace-mix.rs:33:11 | LL | check(m1::S{}); - | ----- ^^^^^^^ the trait `Impossible` is not implemented for `c::Item` + | ----- ^^^^^^^ unsatisfied trait bound | | | required by a bound introduced by this call | +help: the trait `Impossible` is not implemented for `c::Item` + --> $DIR/namespace-mix.rs:16:5 + | +LL | pub struct Item; + | ^^^^^^^^^^^^^^^ help: this trait has no implementations, consider adding one --> $DIR/namespace-mix.rs:20:1 | @@ -125,10 +130,15 @@ error[E0277]: the trait bound `c::S: Impossible` is not satisfied --> $DIR/namespace-mix.rs:35:11 | LL | check(m2::S{}); - | ----- ^^^^^^^ the trait `Impossible` is not implemented for `c::S` + | ----- ^^^^^^^ unsatisfied trait bound | | | required by a bound introduced by this call | +help: the trait `Impossible` is not implemented for `c::S` + --> $DIR/namespace-mix.rs:7:5 + | +LL | pub struct S {} + | ^^^^^^^^^^^^ help: this trait has no implementations, consider adding one --> $DIR/namespace-mix.rs:20:1 | @@ -144,10 +154,15 @@ error[E0277]: the trait bound `c::Item: Impossible` is not satisfied --> $DIR/namespace-mix.rs:36:11 | LL | check(m2::S); - | ----- ^^^^^ the trait `Impossible` is not implemented for `c::Item` + | ----- ^^^^^ unsatisfied trait bound | | | required by a bound introduced by this call | +help: the trait `Impossible` is not implemented for `c::Item` + --> $DIR/namespace-mix.rs:16:5 + | +LL | pub struct Item; + | ^^^^^^^^^^^^^^^ help: this trait has no implementations, consider adding one --> $DIR/namespace-mix.rs:20:1 | @@ -220,10 +235,15 @@ error[E0277]: the trait bound `c::Item: Impossible` is not satisfied --> $DIR/namespace-mix.rs:55:11 | LL | check(m3::TS{}); - | ----- ^^^^^^^^ the trait `Impossible` is not implemented for `c::Item` + | ----- ^^^^^^^^ unsatisfied trait bound | | | required by a bound introduced by this call | +help: the trait `Impossible` is not implemented for `c::Item` + --> $DIR/namespace-mix.rs:16:5 + | +LL | pub struct Item; + | ^^^^^^^^^^^^^^^ help: this trait has no implementations, consider adding one --> $DIR/namespace-mix.rs:20:1 | @@ -258,10 +278,15 @@ error[E0277]: the trait bound `c::TS: Impossible` is not satisfied --> $DIR/namespace-mix.rs:57:11 | LL | check(m4::TS{}); - | ----- ^^^^^^^^ the trait `Impossible` is not implemented for `c::TS` + | ----- ^^^^^^^^ unsatisfied trait bound | | | required by a bound introduced by this call | +help: the trait `Impossible` is not implemented for `c::TS` + --> $DIR/namespace-mix.rs:8:5 + | +LL | pub struct TS(); + | ^^^^^^^^^^^^^ help: this trait has no implementations, consider adding one --> $DIR/namespace-mix.rs:20:1 | @@ -277,10 +302,15 @@ error[E0277]: the trait bound `c::Item: Impossible` is not satisfied --> $DIR/namespace-mix.rs:58:11 | LL | check(m4::TS); - | ----- ^^^^^^ the trait `Impossible` is not implemented for `c::Item` + | ----- ^^^^^^ unsatisfied trait bound | | | required by a bound introduced by this call | +help: the trait `Impossible` is not implemented for `c::Item` + --> $DIR/namespace-mix.rs:16:5 + | +LL | pub struct Item; + | ^^^^^^^^^^^^^^^ help: this trait has no implementations, consider adding one --> $DIR/namespace-mix.rs:20:1 | @@ -372,10 +402,15 @@ error[E0277]: the trait bound `c::Item: Impossible` is not satisfied --> $DIR/namespace-mix.rs:77:11 | LL | check(m5::US{}); - | ----- ^^^^^^^^ the trait `Impossible` is not implemented for `c::Item` + | ----- ^^^^^^^^ unsatisfied trait bound | | | required by a bound introduced by this call | +help: the trait `Impossible` is not implemented for `c::Item` + --> $DIR/namespace-mix.rs:16:5 + | +LL | pub struct Item; + | ^^^^^^^^^^^^^^^ help: this trait has no implementations, consider adding one --> $DIR/namespace-mix.rs:20:1 | @@ -391,10 +426,15 @@ error[E0277]: the trait bound `c::US: Impossible` is not satisfied --> $DIR/namespace-mix.rs:78:11 | LL | check(m5::US); - | ----- ^^^^^^ the trait `Impossible` is not implemented for `c::US` + | ----- ^^^^^^ unsatisfied trait bound | | | required by a bound introduced by this call | +help: the trait `Impossible` is not implemented for `c::US` + --> $DIR/namespace-mix.rs:9:5 + | +LL | pub struct US; + | ^^^^^^^^^^^^^ help: this trait has no implementations, consider adding one --> $DIR/namespace-mix.rs:20:1 | @@ -410,10 +450,15 @@ error[E0277]: the trait bound `c::US: Impossible` is not satisfied --> $DIR/namespace-mix.rs:79:11 | LL | check(m6::US{}); - | ----- ^^^^^^^^ the trait `Impossible` is not implemented for `c::US` + | ----- ^^^^^^^^ unsatisfied trait bound | | | required by a bound introduced by this call | +help: the trait `Impossible` is not implemented for `c::US` + --> $DIR/namespace-mix.rs:9:5 + | +LL | pub struct US; + | ^^^^^^^^^^^^^ help: this trait has no implementations, consider adding one --> $DIR/namespace-mix.rs:20:1 | @@ -429,10 +474,15 @@ error[E0277]: the trait bound `c::Item: Impossible` is not satisfied --> $DIR/namespace-mix.rs:80:11 | LL | check(m6::US); - | ----- ^^^^^^ the trait `Impossible` is not implemented for `c::Item` + | ----- ^^^^^^ unsatisfied trait bound | | | required by a bound introduced by this call | +help: the trait `Impossible` is not implemented for `c::Item` + --> $DIR/namespace-mix.rs:16:5 + | +LL | pub struct Item; + | ^^^^^^^^^^^^^^^ help: this trait has no implementations, consider adding one --> $DIR/namespace-mix.rs:20:1 | @@ -524,10 +574,15 @@ error[E0277]: the trait bound `c::Item: Impossible` is not satisfied --> $DIR/namespace-mix.rs:99:11 | LL | check(m7::V{}); - | ----- ^^^^^^^ the trait `Impossible` is not implemented for `c::Item` + | ----- ^^^^^^^ unsatisfied trait bound | | | required by a bound introduced by this call | +help: the trait `Impossible` is not implemented for `c::Item` + --> $DIR/namespace-mix.rs:16:5 + | +LL | pub struct Item; + | ^^^^^^^^^^^^^^^ help: this trait has no implementations, consider adding one --> $DIR/namespace-mix.rs:20:1 | @@ -543,10 +598,15 @@ error[E0277]: the trait bound `c::E: Impossible` is not satisfied --> $DIR/namespace-mix.rs:101:11 | LL | check(m8::V{}); - | ----- ^^^^^^^ the trait `Impossible` is not implemented for `c::E` + | ----- ^^^^^^^ unsatisfied trait bound | | | required by a bound introduced by this call | +help: the trait `Impossible` is not implemented for `c::E` + --> $DIR/namespace-mix.rs:10:5 + | +LL | pub enum E { + | ^^^^^^^^^^ help: this trait has no implementations, consider adding one --> $DIR/namespace-mix.rs:20:1 | @@ -562,10 +622,15 @@ error[E0277]: the trait bound `c::Item: Impossible` is not satisfied --> $DIR/namespace-mix.rs:102:11 | LL | check(m8::V); - | ----- ^^^^^ the trait `Impossible` is not implemented for `c::Item` + | ----- ^^^^^ unsatisfied trait bound | | | required by a bound introduced by this call | +help: the trait `Impossible` is not implemented for `c::Item` + --> $DIR/namespace-mix.rs:16:5 + | +LL | pub struct Item; + | ^^^^^^^^^^^^^^^ help: this trait has no implementations, consider adding one --> $DIR/namespace-mix.rs:20:1 | @@ -638,10 +703,15 @@ error[E0277]: the trait bound `c::Item: Impossible` is not satisfied --> $DIR/namespace-mix.rs:121:11 | LL | check(m9::TV{}); - | ----- ^^^^^^^^ the trait `Impossible` is not implemented for `c::Item` + | ----- ^^^^^^^^ unsatisfied trait bound | | | required by a bound introduced by this call | +help: the trait `Impossible` is not implemented for `c::Item` + --> $DIR/namespace-mix.rs:16:5 + | +LL | pub struct Item; + | ^^^^^^^^^^^^^^^ help: this trait has no implementations, consider adding one --> $DIR/namespace-mix.rs:20:1 | @@ -676,10 +746,15 @@ error[E0277]: the trait bound `c::E: Impossible` is not satisfied --> $DIR/namespace-mix.rs:123:11 | LL | check(mA::TV{}); - | ----- ^^^^^^^^ the trait `Impossible` is not implemented for `c::E` + | ----- ^^^^^^^^ unsatisfied trait bound | | | required by a bound introduced by this call | +help: the trait `Impossible` is not implemented for `c::E` + --> $DIR/namespace-mix.rs:10:5 + | +LL | pub enum E { + | ^^^^^^^^^^ help: this trait has no implementations, consider adding one --> $DIR/namespace-mix.rs:20:1 | @@ -695,10 +770,15 @@ error[E0277]: the trait bound `c::Item: Impossible` is not satisfied --> $DIR/namespace-mix.rs:124:11 | LL | check(mA::TV); - | ----- ^^^^^^ the trait `Impossible` is not implemented for `c::Item` + | ----- ^^^^^^ unsatisfied trait bound | | | required by a bound introduced by this call | +help: the trait `Impossible` is not implemented for `c::Item` + --> $DIR/namespace-mix.rs:16:5 + | +LL | pub struct Item; + | ^^^^^^^^^^^^^^^ help: this trait has no implementations, consider adding one --> $DIR/namespace-mix.rs:20:1 | @@ -790,10 +870,15 @@ error[E0277]: the trait bound `c::Item: Impossible` is not satisfied --> $DIR/namespace-mix.rs:143:11 | LL | check(mB::UV{}); - | ----- ^^^^^^^^ the trait `Impossible` is not implemented for `c::Item` + | ----- ^^^^^^^^ unsatisfied trait bound | | | required by a bound introduced by this call | +help: the trait `Impossible` is not implemented for `c::Item` + --> $DIR/namespace-mix.rs:16:5 + | +LL | pub struct Item; + | ^^^^^^^^^^^^^^^ help: this trait has no implementations, consider adding one --> $DIR/namespace-mix.rs:20:1 | @@ -809,10 +894,15 @@ error[E0277]: the trait bound `c::E: Impossible` is not satisfied --> $DIR/namespace-mix.rs:144:11 | LL | check(mB::UV); - | ----- ^^^^^^ the trait `Impossible` is not implemented for `c::E` + | ----- ^^^^^^ unsatisfied trait bound | | | required by a bound introduced by this call | +help: the trait `Impossible` is not implemented for `c::E` + --> $DIR/namespace-mix.rs:10:5 + | +LL | pub enum E { + | ^^^^^^^^^^ help: this trait has no implementations, consider adding one --> $DIR/namespace-mix.rs:20:1 | @@ -828,10 +918,15 @@ error[E0277]: the trait bound `c::E: Impossible` is not satisfied --> $DIR/namespace-mix.rs:145:11 | LL | check(mC::UV{}); - | ----- ^^^^^^^^ the trait `Impossible` is not implemented for `c::E` + | ----- ^^^^^^^^ unsatisfied trait bound | | | required by a bound introduced by this call | +help: the trait `Impossible` is not implemented for `c::E` + --> $DIR/namespace-mix.rs:10:5 + | +LL | pub enum E { + | ^^^^^^^^^^ help: this trait has no implementations, consider adding one --> $DIR/namespace-mix.rs:20:1 | @@ -847,10 +942,15 @@ error[E0277]: the trait bound `c::Item: Impossible` is not satisfied --> $DIR/namespace-mix.rs:146:11 | LL | check(mC::UV); - | ----- ^^^^^^ the trait `Impossible` is not implemented for `c::Item` + | ----- ^^^^^^ unsatisfied trait bound | | | required by a bound introduced by this call | +help: the trait `Impossible` is not implemented for `c::Item` + --> $DIR/namespace-mix.rs:16:5 + | +LL | pub struct Item; + | ^^^^^^^^^^^^^^^ help: this trait has no implementations, consider adding one --> $DIR/namespace-mix.rs:20:1 | diff --git a/tests/ui/never_type/from_infer_breaking_with_unit_fallback.unit.stderr b/tests/ui/never_type/from_infer_breaking_with_unit_fallback.unit.stderr index 9eacab9a0b7..891b6ea8046 100644 --- a/tests/ui/never_type/from_infer_breaking_with_unit_fallback.unit.stderr +++ b/tests/ui/never_type/from_infer_breaking_with_unit_fallback.unit.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `E: From<()>` is not satisfied --> $DIR/from_infer_breaking_with_unit_fallback.rs:25:6 | LL | <E as From<_>>::from(never); // Should the inference fail? - | ^ the trait `From<()>` is not implemented for `E` + | ^ unsatisfied trait bound | = help: the trait `From<()>` is not implemented for `E` but trait `From<!>` is implemented for it diff --git a/tests/ui/never_type/never-value-fallback-issue-66757.nofallback.stderr b/tests/ui/never_type/never-value-fallback-issue-66757.nofallback.stderr index d6234c8e7e1..cd34cd9e88e 100644 --- a/tests/ui/never_type/never-value-fallback-issue-66757.nofallback.stderr +++ b/tests/ui/never_type/never-value-fallback-issue-66757.nofallback.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `E: From<()>` is not satisfied --> $DIR/never-value-fallback-issue-66757.rs:28:6 | LL | <E as From<_>>::from(never); - | ^ the trait `From<()>` is not implemented for `E` + | ^ unsatisfied trait bound | = help: the trait `From<()>` is not implemented for `E` but trait `From<!>` is implemented for it diff --git a/tests/ui/on-unimplemented/no-debug.stderr b/tests/ui/on-unimplemented/no-debug.stderr index 5b0b060d40e..1e6fa7d52fa 100644 --- a/tests/ui/on-unimplemented/no-debug.stderr +++ b/tests/ui/on-unimplemented/no-debug.stderr @@ -34,7 +34,11 @@ LL | println!("{} {}", Foo, Bar); | | | required by this formatting parameter | - = help: the trait `std::fmt::Display` is not implemented for `Foo` +help: the trait `std::fmt::Display` is not implemented for `Foo` + --> $DIR/no-debug.rs:7:1 + | +LL | struct Foo; + | ^^^^^^^^^^ = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/on-unimplemented/parent-label.stderr b/tests/ui/on-unimplemented/parent-label.stderr index 101a41512d2..1160b24e325 100644 --- a/tests/ui/on-unimplemented/parent-label.stderr +++ b/tests/ui/on-unimplemented/parent-label.stderr @@ -4,10 +4,15 @@ error[E0277]: the trait bound `Foo: Trait` is not satisfied LL | let x = || { | -- in this scope LL | f(Foo {}); - | - ^^^^^^ the trait `Trait` is not implemented for `Foo` + | - ^^^^^^ unsatisfied trait bound | | | required by a bound introduced by this call | +help: the trait `Trait` is not implemented for `Foo` + --> $DIR/parent-label.rs:8:1 + | +LL | struct Foo; + | ^^^^^^^^^^ help: this trait has no implementations, consider adding one --> $DIR/parent-label.rs:6:1 | @@ -25,10 +30,15 @@ error[E0277]: the trait bound `Foo: Trait` is not satisfied LL | let y = || { | -- in this scope LL | f(Foo {}); - | - ^^^^^^ the trait `Trait` is not implemented for `Foo` + | - ^^^^^^ unsatisfied trait bound | | | required by a bound introduced by this call | +help: the trait `Trait` is not implemented for `Foo` + --> $DIR/parent-label.rs:8:1 + | +LL | struct Foo; + | ^^^^^^^^^^ help: this trait has no implementations, consider adding one --> $DIR/parent-label.rs:6:1 | @@ -47,10 +57,15 @@ LL | fn main() { | --------- in this scope ... LL | f(Foo {}); - | - ^^^^^^ the trait `Trait` is not implemented for `Foo` + | - ^^^^^^ unsatisfied trait bound | | | required by a bound introduced by this call | +help: the trait `Trait` is not implemented for `Foo` + --> $DIR/parent-label.rs:8:1 + | +LL | struct Foo; + | ^^^^^^^^^^ help: this trait has no implementations, consider adding one --> $DIR/parent-label.rs:6:1 | @@ -69,10 +84,15 @@ LL | fn main() { | --------- in this scope ... LL | f(Foo {}); - | - ^^^^^^ the trait `Trait` is not implemented for `Foo` + | - ^^^^^^ unsatisfied trait bound | | | required by a bound introduced by this call | +help: the trait `Trait` is not implemented for `Foo` + --> $DIR/parent-label.rs:8:1 + | +LL | struct Foo; + | ^^^^^^^^^^ help: this trait has no implementations, consider adding one --> $DIR/parent-label.rs:6:1 | diff --git a/tests/ui/on-unimplemented/suggest_tuple_wrap_root_obligation.rs b/tests/ui/on-unimplemented/suggest_tuple_wrap_root_obligation.rs index e0036d30187..0c195a58d57 100644 --- a/tests/ui/on-unimplemented/suggest_tuple_wrap_root_obligation.rs +++ b/tests/ui/on-unimplemented/suggest_tuple_wrap_root_obligation.rs @@ -1,4 +1,4 @@ -struct Tuple; +struct Tuple; //~ HELP the trait `From<u8>` is not implemented for `Tuple` impl From<(u8,)> for Tuple { fn from(_: (u8,)) -> Self { diff --git a/tests/ui/on-unimplemented/suggest_tuple_wrap_root_obligation.stderr b/tests/ui/on-unimplemented/suggest_tuple_wrap_root_obligation.stderr index 6ee08d2cd1b..c4156e1f128 100644 --- a/tests/ui/on-unimplemented/suggest_tuple_wrap_root_obligation.stderr +++ b/tests/ui/on-unimplemented/suggest_tuple_wrap_root_obligation.stderr @@ -2,10 +2,15 @@ error[E0277]: the trait bound `Tuple: From<u8>` is not satisfied --> $DIR/suggest_tuple_wrap_root_obligation.rs:22:24 | LL | convert_into_tuple(42_u8); - | ------------------ ^^^^^ the trait `From<u8>` is not implemented for `Tuple` + | ------------------ ^^^^^ unsatisfied trait bound | | | required by a bound introduced by this call | +help: the trait `From<u8>` is not implemented for `Tuple` + --> $DIR/suggest_tuple_wrap_root_obligation.rs:1:1 + | +LL | struct Tuple; + | ^^^^^^^^^^^^ = help: the following other types implement trait `From<T>`: `Tuple` implements `From<(u8, u8)>` `Tuple` implements `From<(u8, u8, u8)>` diff --git a/tests/ui/or-patterns/exhaustiveness-non-exhaustive.rs b/tests/ui/or-patterns/exhaustiveness-non-exhaustive.rs index 5999e04e0e2..9c0b2648384 100644 --- a/tests/ui/or-patterns/exhaustiveness-non-exhaustive.rs +++ b/tests/ui/or-patterns/exhaustiveness-non-exhaustive.rs @@ -7,11 +7,11 @@ fn main() { (0 | 1, 2 | 3) => {} } match ((0u8,),) { - //~^ ERROR non-exhaustive patterns: `((4_u8..=u8::MAX))` + //~^ ERROR non-exhaustive patterns: `((4_u8..=u8::MAX,),)` ((0 | 1,) | (2 | 3,),) => {} } match (Some(0u8),) { - //~^ ERROR non-exhaustive patterns: `(Some(2_u8..=u8::MAX))` + //~^ ERROR non-exhaustive patterns: `(Some(2_u8..=u8::MAX),)` (None | Some(0 | 1),) => {} } } diff --git a/tests/ui/or-patterns/exhaustiveness-non-exhaustive.stderr b/tests/ui/or-patterns/exhaustiveness-non-exhaustive.stderr index 9f691aea8a7..fe3a4aa2afc 100644 --- a/tests/ui/or-patterns/exhaustiveness-non-exhaustive.stderr +++ b/tests/ui/or-patterns/exhaustiveness-non-exhaustive.stderr @@ -11,30 +11,30 @@ LL ~ (0 | 1, 2 | 3) => {}, LL + (2_u8..=u8::MAX, _) => todo!() | -error[E0004]: non-exhaustive patterns: `((4_u8..=u8::MAX))` not covered +error[E0004]: non-exhaustive patterns: `((4_u8..=u8::MAX,),)` not covered --> $DIR/exhaustiveness-non-exhaustive.rs:9:11 | LL | match ((0u8,),) { - | ^^^^^^^^^ pattern `((4_u8..=u8::MAX))` not covered + | ^^^^^^^^^ pattern `((4_u8..=u8::MAX,),)` not covered | = note: the matched value is of type `((u8,),)` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL ~ ((0 | 1,) | (2 | 3,),) => {}, -LL + ((4_u8..=u8::MAX)) => todo!() +LL + ((4_u8..=u8::MAX,),) => todo!() | -error[E0004]: non-exhaustive patterns: `(Some(2_u8..=u8::MAX))` not covered +error[E0004]: non-exhaustive patterns: `(Some(2_u8..=u8::MAX),)` not covered --> $DIR/exhaustiveness-non-exhaustive.rs:13:11 | LL | match (Some(0u8),) { - | ^^^^^^^^^^^^ pattern `(Some(2_u8..=u8::MAX))` not covered + | ^^^^^^^^^^^^ pattern `(Some(2_u8..=u8::MAX),)` not covered | = note: the matched value is of type `(Option<u8>,)` help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL ~ (None | Some(0 | 1),) => {}, -LL + (Some(2_u8..=u8::MAX)) => todo!() +LL + (Some(2_u8..=u8::MAX),) => todo!() | error: aborting due to 3 previous errors diff --git a/tests/ui/parser/attribute/attr-bad-meta-4.rs b/tests/ui/parser/attribute/attr-bad-meta-4.rs index 937390a6da5..606b41e89a5 100644 --- a/tests/ui/parser/attribute/attr-bad-meta-4.rs +++ b/tests/ui/parser/attribute/attr-bad-meta-4.rs @@ -1,7 +1,7 @@ macro_rules! mac { ($attr_item: meta) => { #[cfg($attr_item)] - //~^ ERROR expected unsuffixed literal, found `meta` metavariable + //~^ ERROR expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `meta` metavariable struct S; } } @@ -9,7 +9,7 @@ macro_rules! mac { mac!(an(arbitrary token stream)); #[cfg(feature = -1)] -//~^ ERROR expected unsuffixed literal, found `-` +//~^ ERROR expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `-` fn handler() {} fn main() {} diff --git a/tests/ui/parser/attribute/attr-bad-meta-4.stderr b/tests/ui/parser/attribute/attr-bad-meta-4.stderr index 9c6ab5adadf..1d939942fb9 100644 --- a/tests/ui/parser/attribute/attr-bad-meta-4.stderr +++ b/tests/ui/parser/attribute/attr-bad-meta-4.stderr @@ -1,10 +1,16 @@ -error: expected unsuffixed literal, found `-` +error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `-` --> $DIR/attr-bad-meta-4.rs:11:17 | LL | #[cfg(feature = -1)] | ^ + | +help: negative numbers are not literals, try removing the `-` sign + | +LL - #[cfg(feature = -1)] +LL + #[cfg(feature = 1)] + | -error: expected unsuffixed literal, found `meta` metavariable +error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `meta` metavariable --> $DIR/attr-bad-meta-4.rs:3:15 | LL | #[cfg($attr_item)] diff --git a/tests/ui/parser/attribute/attr-incomplete.rs b/tests/ui/parser/attribute/attr-incomplete.rs new file mode 100644 index 00000000000..49cb66e5f59 --- /dev/null +++ b/tests/ui/parser/attribute/attr-incomplete.rs @@ -0,0 +1,17 @@ +#[cfg(target-os = "windows")] +//~^ ERROR expected one of `(`, `,`, `::`, or `=`, found `-` +pub fn test1() { } + +#[cfg(target_os = %)] +//~^ ERROR expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `%` +pub fn test2() { } + +#[cfg(target_os?)] +//~^ ERROR expected one of `(`, `,`, `::`, or `=`, found `?` +pub fn test3() { } + +#[cfg[target_os]] +//~^ ERROR wrong meta list delimiters +pub fn test4() { } + +pub fn main() {} diff --git a/tests/ui/parser/attribute/attr-incomplete.stderr b/tests/ui/parser/attribute/attr-incomplete.stderr new file mode 100644 index 00000000000..5909820cef3 --- /dev/null +++ b/tests/ui/parser/attribute/attr-incomplete.stderr @@ -0,0 +1,32 @@ +error: expected one of `(`, `,`, `::`, or `=`, found `-` + --> $DIR/attr-incomplete.rs:1:13 + | +LL | #[cfg(target-os = "windows")] + | ^ expected one of `(`, `,`, `::`, or `=` + +error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `%` + --> $DIR/attr-incomplete.rs:5:19 + | +LL | #[cfg(target_os = %)] + | ^ + +error: expected one of `(`, `,`, `::`, or `=`, found `?` + --> $DIR/attr-incomplete.rs:9:16 + | +LL | #[cfg(target_os?)] + | ^ expected one of `(`, `,`, `::`, or `=` + +error: wrong meta list delimiters + --> $DIR/attr-incomplete.rs:13:6 + | +LL | #[cfg[target_os]] + | ^^^^^^^^^^^ + | +help: the delimiters should be `(` and `)` + | +LL - #[cfg[target_os]] +LL + #[cfg(target_os)] + | + +error: aborting due to 4 previous errors + diff --git a/tests/ui/parser/attribute/attr-unquoted-ident.rs b/tests/ui/parser/attribute/attr-unquoted-ident.rs index 396265f715e..8a0c65b783a 100644 --- a/tests/ui/parser/attribute/attr-unquoted-ident.rs +++ b/tests/ui/parser/attribute/attr-unquoted-ident.rs @@ -4,13 +4,13 @@ fn main() { #[cfg(key=foo)] - //~^ ERROR expected unsuffixed literal, found `foo` + //~^ ERROR expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `foo` //~| HELP surround the identifier with quotation marks to make it into a string literal println!(); #[cfg(key="bar")] println!(); #[cfg(key=foo bar baz)] - //~^ ERROR expected unsuffixed literal, found `foo` + //~^ ERROR expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `foo` //~| HELP surround the identifier with quotation marks to make it into a string literal println!(); } diff --git a/tests/ui/parser/attribute/attr-unquoted-ident.stderr b/tests/ui/parser/attribute/attr-unquoted-ident.stderr index 2d7997f1aea..8a2785280ad 100644 --- a/tests/ui/parser/attribute/attr-unquoted-ident.stderr +++ b/tests/ui/parser/attribute/attr-unquoted-ident.stderr @@ -1,4 +1,4 @@ -error: expected unsuffixed literal, found `foo` +error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `foo` --> $DIR/attr-unquoted-ident.rs:6:15 | LL | #[cfg(key=foo)] @@ -9,7 +9,7 @@ help: surround the identifier with quotation marks to make it into a string lite LL | #[cfg(key="foo")] | + + -error: expected unsuffixed literal, found `foo` +error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `foo` --> $DIR/attr-unquoted-ident.rs:12:15 | LL | #[cfg(key=foo bar baz)] diff --git a/tests/ui/parser/bad-lit-suffixes.stderr b/tests/ui/parser/bad-lit-suffixes.stderr index 9a51cf70960..e1a8a6834f4 100644 --- a/tests/ui/parser/bad-lit-suffixes.stderr +++ b/tests/ui/parser/bad-lit-suffixes.stderr @@ -11,31 +11,11 @@ LL | "C"suffix | ^^^^^^^^^ invalid suffix `suffix` error: suffixes on string literals are invalid - --> $DIR/bad-lit-suffixes.rs:30:17 - | -LL | #[rustc_dummy = "string"suffix] - | ^^^^^^^^^^^^^^ invalid suffix `suffix` - -error: suffixes on string literals are invalid - --> $DIR/bad-lit-suffixes.rs:34:14 - | -LL | #[must_use = "string"suffix] - | ^^^^^^^^^^^^^^ invalid suffix `suffix` - -error: suffixes on string literals are invalid --> $DIR/bad-lit-suffixes.rs:39:15 | LL | #[link(name = "string"suffix)] | ^^^^^^^^^^^^^^ invalid suffix `suffix` -error: invalid suffix `suffix` for number literal - --> $DIR/bad-lit-suffixes.rs:43:41 - | -LL | #[rustc_layout_scalar_valid_range_start(0suffix)] - | ^^^^^^^ invalid suffix `suffix` - | - = help: the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.) - warning: `extern` declarations without an explicit ABI are deprecated --> $DIR/bad-lit-suffixes.rs:3:1 | @@ -150,6 +130,18 @@ LL | 1.0e10suffix; | = help: valid suffixes are `f32` and `f64` +error: suffixes on string literals are invalid + --> $DIR/bad-lit-suffixes.rs:30:17 + | +LL | #[rustc_dummy = "string"suffix] + | ^^^^^^^^^^^^^^ invalid suffix `suffix` + +error: suffixes on string literals are invalid + --> $DIR/bad-lit-suffixes.rs:34:14 + | +LL | #[must_use = "string"suffix] + | ^^^^^^^^^^^^^^ invalid suffix `suffix` + error[E0539]: malformed `must_use` attribute input --> $DIR/bad-lit-suffixes.rs:34:1 | @@ -168,16 +160,23 @@ LL - #[must_use = "string"suffix] LL + #[must_use] | -error[E0805]: malformed `rustc_layout_scalar_valid_range_start` attribute input +error: invalid suffix `suffix` for number literal + --> $DIR/bad-lit-suffixes.rs:43:41 + | +LL | #[rustc_layout_scalar_valid_range_start(0suffix)] + | ^^^^^^^ invalid suffix `suffix` + | + = help: the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.) + +error[E0539]: malformed `rustc_layout_scalar_valid_range_start` attribute input --> $DIR/bad-lit-suffixes.rs:43:1 | LL | #[rustc_layout_scalar_valid_range_start(0suffix)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---------^ - | | | - | | expected a single argument here + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-------^^ + | | | + | | expected an integer literal here | help: must be of the form: `#[rustc_layout_scalar_valid_range_start(start)]` error: aborting due to 22 previous errors; 2 warnings emitted -Some errors have detailed explanations: E0539, E0805. -For more information about an error, try `rustc --explain E0539`. +For more information about this error, try `rustc --explain E0539`. diff --git a/tests/ui/parser/recover/param-default.rs b/tests/ui/parser/recover/param-default.rs new file mode 100644 index 00000000000..5311d4dfae6 --- /dev/null +++ b/tests/ui/parser/recover/param-default.rs @@ -0,0 +1,5 @@ +fn foo(x: i32 = 1) {} //~ ERROR parameter defaults are not supported + +type Foo = fn(i32 = 0); //~ ERROR parameter defaults are not supported + +fn main() {} diff --git a/tests/ui/parser/recover/param-default.stderr b/tests/ui/parser/recover/param-default.stderr new file mode 100644 index 00000000000..93dea427daf --- /dev/null +++ b/tests/ui/parser/recover/param-default.stderr @@ -0,0 +1,14 @@ +error: parameter defaults are not supported + --> $DIR/param-default.rs:1:15 + | +LL | fn foo(x: i32 = 1) {} + | ^^^ + +error: parameter defaults are not supported + --> $DIR/param-default.rs:3:19 + | +LL | type Foo = fn(i32 = 0); + | ^^^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/parser/require-parens-for-chained-comparison.rs b/tests/ui/parser/require-parens-for-chained-comparison.rs index 21a908923f2..6152fff6c03 100644 --- a/tests/ui/parser/require-parens-for-chained-comparison.rs +++ b/tests/ui/parser/require-parens-for-chained-comparison.rs @@ -24,14 +24,14 @@ fn main() { //~| HELP use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments //~| ERROR expected //~| HELP add `'` to close the char literal - //~| ERROR invalid label name + //~| ERROR labels cannot use keyword names f<'_>(); //~^ ERROR comparison operators cannot be chained //~| HELP use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments //~| ERROR expected //~| HELP add `'` to close the char literal - //~| ERROR invalid label name + //~| ERROR labels cannot use keyword names let _ = f<u8>; //~^ ERROR comparison operators cannot be chained diff --git a/tests/ui/parser/require-parens-for-chained-comparison.stderr b/tests/ui/parser/require-parens-for-chained-comparison.stderr index 857c4a55788..9edfae36250 100644 --- a/tests/ui/parser/require-parens-for-chained-comparison.stderr +++ b/tests/ui/parser/require-parens-for-chained-comparison.stderr @@ -53,7 +53,7 @@ help: use `::<...>` instead of `<...>` to specify lifetime, type, or const argum LL | let _ = f::<u8, i8>(); | ++ -error: invalid label name `'_` +error: labels cannot use keyword names --> $DIR/require-parens-for-chained-comparison.rs:22:15 | LL | let _ = f<'_, i8>(); @@ -81,7 +81,7 @@ help: use `::<...>` instead of `<...>` to specify lifetime, type, or const argum LL | let _ = f::<'_, i8>(); | ++ -error: invalid label name `'_` +error: labels cannot use keyword names --> $DIR/require-parens-for-chained-comparison.rs:29:7 | LL | f<'_>(); diff --git a/tests/ui/pattern/deref-patterns/recursion-limit.stderr b/tests/ui/pattern/deref-patterns/recursion-limit.stderr index 9a83d1eb5a4..f6aa92b23ad 100644 --- a/tests/ui/pattern/deref-patterns/recursion-limit.stderr +++ b/tests/ui/pattern/deref-patterns/recursion-limit.stderr @@ -10,7 +10,13 @@ error[E0277]: the trait bound `Cyclic: DerefPure` is not satisfied --> $DIR/recursion-limit.rs:18:9 | LL | () => {} - | ^^ the trait `DerefPure` is not implemented for `Cyclic` + | ^^ unsatisfied trait bound + | +help: the trait `DerefPure` is not implemented for `Cyclic` + --> $DIR/recursion-limit.rs:8:1 + | +LL | struct Cyclic; + | ^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/tests/ui/pattern/deref-patterns/unsatisfied-bounds.stderr b/tests/ui/pattern/deref-patterns/unsatisfied-bounds.stderr index 983ce27865c..0b1e8ef4978 100644 --- a/tests/ui/pattern/deref-patterns/unsatisfied-bounds.stderr +++ b/tests/ui/pattern/deref-patterns/unsatisfied-bounds.stderr @@ -2,7 +2,13 @@ error[E0277]: the trait bound `MyPointer: DerefPure` is not satisfied --> $DIR/unsatisfied-bounds.rs:17:9 | LL | () => {} - | ^^ the trait `DerefPure` is not implemented for `MyPointer` + | ^^ unsatisfied trait bound + | +help: the trait `DerefPure` is not implemented for `MyPointer` + --> $DIR/unsatisfied-bounds.rs:4:1 + | +LL | struct MyPointer; + | ^^^^^^^^^^^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/privacy/sealed-traits/false-sealed-traits-note.stderr b/tests/ui/privacy/sealed-traits/false-sealed-traits-note.stderr index df8016565da..c3cfaed3e43 100644 --- a/tests/ui/privacy/sealed-traits/false-sealed-traits-note.stderr +++ b/tests/ui/privacy/sealed-traits/false-sealed-traits-note.stderr @@ -2,8 +2,13 @@ error[E0277]: the trait bound `Struct: TraitA` is not satisfied --> $DIR/false-sealed-traits-note.rs:12:24 | LL | impl inner::TraitB for Struct {} - | ^^^^^^ the trait `TraitA` is not implemented for `Struct` + | ^^^^^^ unsatisfied trait bound | +help: the trait `TraitA` is not implemented for `Struct` + --> $DIR/false-sealed-traits-note.rs:10:1 + | +LL | struct Struct; + | ^^^^^^^^^^^^^ help: this trait has no implementations, consider adding one --> $DIR/false-sealed-traits-note.rs:5:5 | @@ -19,8 +24,13 @@ error[E0277]: the trait bound `C: A` is not satisfied --> $DIR/false-sealed-traits-note.rs:20:16 | LL | impl B for C {} - | ^ the trait `A` is not implemented for `C` + | ^ unsatisfied trait bound + | +help: the trait `A` is not implemented for `C` + --> $DIR/false-sealed-traits-note.rs:19:5 | +LL | pub struct C; + | ^^^^^^^^^^^^ help: this trait has no implementations, consider adding one --> $DIR/false-sealed-traits-note.rs:16:5 | diff --git a/tests/ui/privacy/sealed-traits/sealed-trait-local.stderr b/tests/ui/privacy/sealed-traits/sealed-trait-local.stderr index a7f77a1c0c0..4d00d067d75 100644 --- a/tests/ui/privacy/sealed-traits/sealed-trait-local.stderr +++ b/tests/ui/privacy/sealed-traits/sealed-trait-local.stderr @@ -2,8 +2,13 @@ error[E0277]: the trait bound `S: b::Hidden` is not satisfied --> $DIR/sealed-trait-local.rs:52:20 | LL | impl a::Sealed for S {} - | ^ the trait `b::Hidden` is not implemented for `S` + | ^ unsatisfied trait bound | +help: the trait `b::Hidden` is not implemented for `S` + --> $DIR/sealed-trait-local.rs:51:1 + | +LL | struct S; + | ^^^^^^^^ note: required by a bound in `a::Sealed` --> $DIR/sealed-trait-local.rs:3:23 | @@ -17,8 +22,13 @@ error[E0277]: the trait bound `S: d::Hidden` is not satisfied --> $DIR/sealed-trait-local.rs:53:20 | LL | impl c::Sealed for S {} - | ^ the trait `d::Hidden` is not implemented for `S` + | ^ unsatisfied trait bound + | +help: the trait `d::Hidden` is not implemented for `S` + --> $DIR/sealed-trait-local.rs:51:1 | +LL | struct S; + | ^^^^^^^^ note: required by a bound in `c::Sealed` --> $DIR/sealed-trait-local.rs:17:23 | @@ -33,8 +43,13 @@ error[E0277]: the trait bound `S: f::Hidden` is not satisfied --> $DIR/sealed-trait-local.rs:54:20 | LL | impl e::Sealed for S {} - | ^ the trait `f::Hidden` is not implemented for `S` + | ^ unsatisfied trait bound + | +help: the trait `f::Hidden` is not implemented for `S` + --> $DIR/sealed-trait-local.rs:51:1 | +LL | struct S; + | ^^^^^^^^ note: required by a bound in `e::Sealed` --> $DIR/sealed-trait-local.rs:35:23 | diff --git a/tests/ui/proc-macro/issue-104884-trait-impl-sugg-err.stderr b/tests/ui/proc-macro/issue-104884-trait-impl-sugg-err.stderr index c12c8d03361..f3ed9e5761d 100644 --- a/tests/ui/proc-macro/issue-104884-trait-impl-sugg-err.stderr +++ b/tests/ui/proc-macro/issue-104884-trait-impl-sugg-err.stderr @@ -4,7 +4,11 @@ error[E0277]: can't compare `PriorityQueue<T>` with `PriorityQueue<T>` LL | #[derive(PartialOrd, AddImpl)] | ^^^^^^^^^^ no implementation for `PriorityQueue<T> == PriorityQueue<T>` | - = help: the trait `PartialEq` is not implemented for `PriorityQueue<T>` +help: the trait `PartialEq` is not implemented for `PriorityQueue<T>` + --> $DIR/issue-104884-trait-impl-sugg-err.rs:20:1 + | +LL | struct PriorityQueue<T>(BinaryHeap<PriorityQueueEntry<T>>); + | ^^^^^^^^^^^^^^^^^^^^^^^ note: required by a bound in `PartialOrd` --> $SRC_DIR/core/src/cmp.rs:LL:COL @@ -12,8 +16,13 @@ error[E0277]: the trait bound `PriorityQueue<T>: Eq` is not satisfied --> $DIR/issue-104884-trait-impl-sugg-err.rs:13:22 | LL | #[derive(PartialOrd, AddImpl)] - | ^^^^^^^ the trait `Eq` is not implemented for `PriorityQueue<T>` + | ^^^^^^^ unsatisfied trait bound | +help: the trait `Eq` is not implemented for `PriorityQueue<T>` + --> $DIR/issue-104884-trait-impl-sugg-err.rs:20:1 + | +LL | struct PriorityQueue<T>(BinaryHeap<PriorityQueueEntry<T>>); + | ^^^^^^^^^^^^^^^^^^^^^^^ note: required by a bound in `Ord` --> $SRC_DIR/core/src/cmp.rs:LL:COL = note: this error originates in the derive macro `AddImpl` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/resolve/path-attr-in-const-block.rs b/tests/ui/resolve/path-attr-in-const-block.rs index 69be65bda3f..076511d26d6 100644 --- a/tests/ui/resolve/path-attr-in-const-block.rs +++ b/tests/ui/resolve/path-attr-in-const-block.rs @@ -5,6 +5,5 @@ fn main() { const { #![path = foo!()] //~^ ERROR: cannot find macro `foo` in this scope - //~| ERROR malformed `path` attribute input } } diff --git a/tests/ui/resolve/path-attr-in-const-block.stderr b/tests/ui/resolve/path-attr-in-const-block.stderr index 23f4e319c6d..8f9e58157c8 100644 --- a/tests/ui/resolve/path-attr-in-const-block.stderr +++ b/tests/ui/resolve/path-attr-in-const-block.stderr @@ -4,17 +4,5 @@ error: cannot find macro `foo` in this scope LL | #![path = foo!()] | ^^^ -error[E0539]: malformed `path` attribute input - --> $DIR/path-attr-in-const-block.rs:6:9 - | -LL | #![path = foo!()] - | ^^^^^^^^^^------^ - | | | - | | expected a string literal here - | help: must be of the form: `#![path = "file"]` - | - = note: for more information, visit <https://doc.rust-lang.org/reference/items/modules.html#the-path-attribute> - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0539`. diff --git a/tests/ui/rfcs/rfc-1937-termination-trait/issue-103052-1.stderr b/tests/ui/rfcs/rfc-1937-termination-trait/issue-103052-1.stderr index 6c3d576cfba..7baa09b02b8 100644 --- a/tests/ui/rfcs/rfc-1937-termination-trait/issue-103052-1.stderr +++ b/tests/ui/rfcs/rfc-1937-termination-trait/issue-103052-1.stderr @@ -2,10 +2,15 @@ error[E0277]: the trait bound `Something: Termination` is not satisfied --> $DIR/issue-103052-1.rs:10:13 | LL | receive(Something); - | ------- ^^^^^^^^^ the trait `Termination` is not implemented for `Something` + | ------- ^^^^^^^^^ unsatisfied trait bound | | | required by a bound introduced by this call | +help: the trait `Termination` is not implemented for `Something` + --> $DIR/issue-103052-1.rs:7:1 + | +LL | struct Something; + | ^^^^^^^^^^^^^^^^ note: required by a bound in `receive` --> $DIR/issue-103052-1.rs:5:20 | diff --git a/tests/ui/rfcs/rfc-1937-termination-trait/issue-103052-2.stderr b/tests/ui/rfcs/rfc-1937-termination-trait/issue-103052-2.stderr index 99fd83e7b6f..643e3d3b680 100644 --- a/tests/ui/rfcs/rfc-1937-termination-trait/issue-103052-2.stderr +++ b/tests/ui/rfcs/rfc-1937-termination-trait/issue-103052-2.stderr @@ -2,8 +2,13 @@ error[E0277]: the trait bound `Something: Termination` is not satisfied --> $DIR/issue-103052-2.rs:9:22 | LL | fn main() -> Something { - | ^^^^^^^^^ the trait `Termination` is not implemented for `Something` + | ^^^^^^^^^ unsatisfied trait bound | +help: the trait `Termination` is not implemented for `Something` + --> $DIR/issue-103052-2.rs:6:5 + | +LL | struct Something; + | ^^^^^^^^^^^^^^^^ note: required by a bound in `Main::main::{anon_assoc#0}` --> $DIR/issue-103052-2.rs:3:27 | diff --git a/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-not-satisfied.stderr b/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-not-satisfied.stderr index 1b842c206ee..e799ba3f1b9 100644 --- a/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-not-satisfied.stderr +++ b/tests/ui/rfcs/rfc-1937-termination-trait/termination-trait-not-satisfied.stderr @@ -4,7 +4,11 @@ error[E0277]: `main` has invalid return type `ReturnType` LL | fn main() -> ReturnType { | ^^^^^^^^^^ `main` can only return types that implement `Termination` | - = help: consider using `()`, or a `Result` +help: consider using `()`, or a `Result` + --> $DIR/termination-trait-not-satisfied.rs:1:1 + | +LL | struct ReturnType {} + | ^^^^^^^^^^^^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/invalid-attribute.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/invalid-attribute.stderr index 3522c459977..98e8f1235e6 100644 --- a/tests/ui/rfcs/rfc-2008-non-exhaustive/invalid-attribute.stderr +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/invalid-attribute.stderr @@ -13,7 +13,7 @@ error: `#[non_exhaustive]` attribute cannot be used on traits LL | #[non_exhaustive] | ^^^^^^^^^^^^^^^^^ | - = help: `#[non_exhaustive]` can be applied to data types, enum variants + = help: `#[non_exhaustive]` can be applied to data types and enum variants error: `#[non_exhaustive]` attribute cannot be used on unions --> $DIR/invalid-attribute.rs:9:1 @@ -21,7 +21,7 @@ error: `#[non_exhaustive]` attribute cannot be used on unions LL | #[non_exhaustive] | ^^^^^^^^^^^^^^^^^ | - = help: `#[non_exhaustive]` can be applied to data types, enum variants + = help: `#[non_exhaustive]` can be applied to data types and enum variants error: aborting due to 3 previous errors diff --git a/tests/ui/span/issue-71363.stderr b/tests/ui/span/issue-71363.stderr index 31069914daa..d2f780bdbcb 100644 --- a/tests/ui/span/issue-71363.stderr +++ b/tests/ui/span/issue-71363.stderr @@ -2,8 +2,13 @@ error[E0277]: `MyError` doesn't implement `std::fmt::Display` --> $DIR/issue-71363.rs:4:28 | 4 | impl std::error::Error for MyError {} - | ^^^^^^^ the trait `std::fmt::Display` is not implemented for `MyError` + | ^^^^^^^ unsatisfied trait bound | +help: the trait `std::fmt::Display` is not implemented for `MyError` + --> $DIR/issue-71363.rs:3:1 + | +3 | struct MyError; + | ^^^^^^^^^^^^^^ note: required by a bound in `std::error::Error` --> $SRC_DIR/core/src/error.rs:LL:COL diff --git a/tests/ui/static/static-closures.rs b/tests/ui/static/static-closures.rs index 1bd518d6ffe..e836f1b85eb 100644 --- a/tests/ui/static/static-closures.rs +++ b/tests/ui/static/static-closures.rs @@ -1,4 +1,5 @@ fn main() { static || {}; //~^ ERROR closures cannot be static + //~| ERROR coroutine syntax is experimental } diff --git a/tests/ui/static/static-closures.stderr b/tests/ui/static/static-closures.stderr index b11c0b5a530..ecc961cc1e4 100644 --- a/tests/ui/static/static-closures.stderr +++ b/tests/ui/static/static-closures.stderr @@ -1,9 +1,20 @@ +error[E0658]: coroutine syntax is experimental + --> $DIR/static-closures.rs:2:5 + | +LL | static || {}; + | ^^^^^^ + | + = note: see issue #43122 <https://github.com/rust-lang/rust/issues/43122> for more information + = help: add `#![feature(coroutines)]` 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[E0697]: closures cannot be static --> $DIR/static-closures.rs:2:5 | LL | static || {}; | ^^^^^^^^^ -error: aborting due to 1 previous error +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0697`. +Some errors have detailed explanations: E0658, E0697. +For more information about an error, try `rustc --explain E0658`. diff --git a/tests/ui/statics/issue-17718-static-sync.stderr b/tests/ui/statics/issue-17718-static-sync.stderr index 96f894146c5..3a6e3becbad 100644 --- a/tests/ui/statics/issue-17718-static-sync.stderr +++ b/tests/ui/statics/issue-17718-static-sync.stderr @@ -4,7 +4,11 @@ error[E0277]: `Foo` cannot be shared between threads safely LL | static BAR: Foo = Foo; | ^^^ `Foo` cannot be shared between threads safely | - = help: the trait `Sync` is not implemented for `Foo` +help: the trait `Sync` is not implemented for `Foo` + --> $DIR/issue-17718-static-sync.rs:5:1 + | +LL | struct Foo; + | ^^^^^^^^^^ = note: shared static variables must have a type that implements `Sync` error: aborting due to 1 previous error diff --git a/tests/ui/suggestions/dont-suggest-borrowing-existing-borrow.stderr b/tests/ui/suggestions/dont-suggest-borrowing-existing-borrow.stderr index c2e2fe941a6..86d9a745b87 100644 --- a/tests/ui/suggestions/dont-suggest-borrowing-existing-borrow.stderr +++ b/tests/ui/suggestions/dont-suggest-borrowing-existing-borrow.stderr @@ -20,8 +20,13 @@ error[E0277]: the trait bound `S: Trait` is not satisfied --> $DIR/dont-suggest-borrowing-existing-borrow.rs:17:18 | LL | let _ = &mut S::foo(); - | ^ the trait `Trait` is not implemented for `S` + | ^ unsatisfied trait bound | +help: the trait `Trait` is not implemented for `S` + --> $DIR/dont-suggest-borrowing-existing-borrow.rs:3:1 + | +LL | struct S; + | ^^^^^^^^ = help: the trait `Trait` is implemented for `&mut S` help: you likely meant to call the associated function `foo` for type `&mut S`, but the code as written calls associated function `foo` on type `S` | @@ -32,8 +37,13 @@ error[E0277]: the trait bound `S: Trait` is not satisfied --> $DIR/dont-suggest-borrowing-existing-borrow.rs:19:14 | LL | let _ = &S::foo(); - | ^ the trait `Trait` is not implemented for `S` + | ^ unsatisfied trait bound + | +help: the trait `Trait` is not implemented for `S` + --> $DIR/dont-suggest-borrowing-existing-borrow.rs:3:1 | +LL | struct S; + | ^^^^^^^^ = help: the trait `Trait` is implemented for `&mut S` help: you likely meant to call the associated function `foo` for type `&S`, but the code as written calls associated function `foo` on type `S` | @@ -56,8 +66,13 @@ error[E0277]: the trait bound `S: Trait2` is not satisfied --> $DIR/dont-suggest-borrowing-existing-borrow.rs:23:18 | LL | let _ = &mut S::bar(); - | ^ the trait `Trait2` is not implemented for `S` + | ^ unsatisfied trait bound | +help: the trait `Trait2` is not implemented for `S` + --> $DIR/dont-suggest-borrowing-existing-borrow.rs:3:1 + | +LL | struct S; + | ^^^^^^^^ = help: the following other types implement trait `Trait2`: &S &mut S @@ -70,8 +85,13 @@ error[E0277]: the trait bound `S: Trait2` is not satisfied --> $DIR/dont-suggest-borrowing-existing-borrow.rs:25:14 | LL | let _ = &S::bar(); - | ^ the trait `Trait2` is not implemented for `S` + | ^ unsatisfied trait bound + | +help: the trait `Trait2` is not implemented for `S` + --> $DIR/dont-suggest-borrowing-existing-borrow.rs:3:1 | +LL | struct S; + | ^^^^^^^^ = help: the following other types implement trait `Trait2`: &S &mut S diff --git a/tests/ui/suggestions/inner_type.fixed b/tests/ui/suggestions/inner_type.fixed index 8174f8e204e..8671c43226c 100644 --- a/tests/ui/suggestions/inner_type.fixed +++ b/tests/ui/suggestions/inner_type.fixed @@ -31,10 +31,10 @@ fn main() { let another_item = std::sync::RwLock::new(Struct { p: 42_u32 }); another_item.read().unwrap().method(); - //~^ ERROR no method named `method` found for struct `RwLock<T>` in the current scope [E0599] + //~^ ERROR no method named `method` found for struct `std::sync::RwLock<T>` in the current scope [E0599] //~| HELP use `.read().unwrap()` to borrow the `Struct<u32>`, blocking the current thread until it can be acquired another_item.write().unwrap().some_mutable_method(); - //~^ ERROR no method named `some_mutable_method` found for struct `RwLock<T>` in the current scope [E0599] + //~^ ERROR no method named `some_mutable_method` found for struct `std::sync::RwLock<T>` in the current scope [E0599] //~| HELP use `.write().unwrap()` to mutably borrow the `Struct<u32>`, blocking the current thread until it can be acquired } diff --git a/tests/ui/suggestions/inner_type.rs b/tests/ui/suggestions/inner_type.rs index e4eaf07ca8b..793372c7deb 100644 --- a/tests/ui/suggestions/inner_type.rs +++ b/tests/ui/suggestions/inner_type.rs @@ -31,10 +31,10 @@ fn main() { let another_item = std::sync::RwLock::new(Struct { p: 42_u32 }); another_item.method(); - //~^ ERROR no method named `method` found for struct `RwLock<T>` in the current scope [E0599] + //~^ ERROR no method named `method` found for struct `std::sync::RwLock<T>` in the current scope [E0599] //~| HELP use `.read().unwrap()` to borrow the `Struct<u32>`, blocking the current thread until it can be acquired another_item.some_mutable_method(); - //~^ ERROR no method named `some_mutable_method` found for struct `RwLock<T>` in the current scope [E0599] + //~^ ERROR no method named `some_mutable_method` found for struct `std::sync::RwLock<T>` in the current scope [E0599] //~| HELP use `.write().unwrap()` to mutably borrow the `Struct<u32>`, blocking the current thread until it can be acquired } diff --git a/tests/ui/suggestions/inner_type.stderr b/tests/ui/suggestions/inner_type.stderr index 017ddb5ad6d..d2f7fa92bc6 100644 --- a/tests/ui/suggestions/inner_type.stderr +++ b/tests/ui/suggestions/inner_type.stderr @@ -46,11 +46,11 @@ help: use `.lock().unwrap()` to borrow the `Struct<u32>`, blocking the current t LL | another_item.lock().unwrap().method(); | ++++++++++++++++ -error[E0599]: no method named `method` found for struct `RwLock<T>` in the current scope +error[E0599]: no method named `method` found for struct `std::sync::RwLock<T>` in the current scope --> $DIR/inner_type.rs:33:18 | LL | another_item.method(); - | ^^^^^^ method not found in `RwLock<Struct<u32>>` + | ^^^^^^ method not found in `std::sync::RwLock<Struct<u32>>` | note: the method `method` exists on the type `Struct<u32>` --> $DIR/inner_type.rs:9:5 @@ -62,11 +62,11 @@ help: use `.read().unwrap()` to borrow the `Struct<u32>`, blocking the current t LL | another_item.read().unwrap().method(); | ++++++++++++++++ -error[E0599]: no method named `some_mutable_method` found for struct `RwLock<T>` in the current scope +error[E0599]: no method named `some_mutable_method` found for struct `std::sync::RwLock<T>` in the current scope --> $DIR/inner_type.rs:37:18 | LL | another_item.some_mutable_method(); - | ^^^^^^^^^^^^^^^^^^^ method not found in `RwLock<Struct<u32>>` + | ^^^^^^^^^^^^^^^^^^^ method not found in `std::sync::RwLock<Struct<u32>>` | note: the method `some_mutable_method` exists on the type `Struct<u32>` --> $DIR/inner_type.rs:11:5 diff --git a/tests/ui/suggestions/issue-96223.stderr b/tests/ui/suggestions/issue-96223.stderr index a54a4e7b3be..89dd094276a 100644 --- a/tests/ui/suggestions/issue-96223.stderr +++ b/tests/ui/suggestions/issue-96223.stderr @@ -2,10 +2,15 @@ error[E0277]: the trait bound `for<'de> EmptyBis<'de>: Foo<'_>` is not satisfied --> $DIR/issue-96223.rs:49:17 | LL | icey_bounds(&p); - | ----------- ^^ the trait `for<'de> Foo<'_>` is not implemented for `EmptyBis<'de>` + | ----------- ^^ unsatisfied trait bound | | | required by a bound introduced by this call | +help: the trait `for<'de> Foo<'_>` is not implemented for `EmptyBis<'de>` + --> $DIR/issue-96223.rs:33:1 + | +LL | pub struct EmptyBis<'a>(&'a [u8]); + | ^^^^^^^^^^^^^^^^^^^^^^^ = help: the trait `Foo<'de>` is implemented for `Baz<T>` note: required for `Baz<EmptyBis<'de>>` to implement `for<'de> Foo<'de>` --> $DIR/issue-96223.rs:16:14 diff --git a/tests/ui/target-feature/invalid-attribute.stderr b/tests/ui/target-feature/invalid-attribute.stderr index a0117649a57..7b75367b48c 100644 --- a/tests/ui/target-feature/invalid-attribute.stderr +++ b/tests/ui/target-feature/invalid-attribute.stderr @@ -143,7 +143,7 @@ error: `#[target_feature]` attribute cannot be used on closures LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: `#[target_feature]` can be applied to methods, functions + = help: `#[target_feature]` can be applied to methods and functions error: cannot use `#[inline(always)]` with `#[target_feature]` --> $DIR/invalid-attribute.rs:62:1 diff --git a/tests/ui/trait-bounds/trait-bound-adt-issue-145611.stderr b/tests/ui/trait-bounds/trait-bound-adt-issue-145611.stderr index 21a2cce20cb..9f47f9bc02a 100644 --- a/tests/ui/trait-bounds/trait-bound-adt-issue-145611.stderr +++ b/tests/ui/trait-bounds/trait-bound-adt-issue-145611.stderr @@ -2,8 +2,13 @@ error[E0277]: the trait bound `SomeType: LocalTrait` is not satisfied --> $DIR/trait-bound-adt-issue-145611.rs:8:19 | LL | impls_trait::<SomeType>(); - | ^^^^^^^^ the trait `LocalTrait` is not implemented for `SomeType` + | ^^^^^^^^ unsatisfied trait bound | +help: the trait `LocalTrait` is not implemented for `SomeType` + --> $DIR/trait-bound-adt-issue-145611.rs:5:1 + | +LL | struct SomeType; + | ^^^^^^^^^^^^^^^ help: this trait has no implementations, consider adding one --> $DIR/trait-bound-adt-issue-145611.rs:4:1 | diff --git a/tests/ui/traits/coercion-generic-bad.stderr b/tests/ui/traits/coercion-generic-bad.stderr index c0553ea62c5..6af96b9daf7 100644 --- a/tests/ui/traits/coercion-generic-bad.stderr +++ b/tests/ui/traits/coercion-generic-bad.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `Struct: Trait<isize>` is not satisfied --> $DIR/coercion-generic-bad.rs:16:36 | LL | let s: Box<dyn Trait<isize>> = Box::new(Struct { person: "Fred" }); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait<isize>` is not implemented for `Struct` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound | = help: the trait `Trait<isize>` is not implemented for `Struct` but trait `Trait<&'static str>` is implemented for it diff --git a/tests/ui/traits/default_auto_traits/default-bounds.stderr b/tests/ui/traits/default_auto_traits/default-bounds.stderr index 318fc57fc9c..ae1b0e842ff 100644 --- a/tests/ui/traits/default_auto_traits/default-bounds.stderr +++ b/tests/ui/traits/default_auto_traits/default-bounds.stderr @@ -2,10 +2,15 @@ error[E0277]: the trait bound `Forbidden: SyncDrop` is not satisfied --> $DIR/default-bounds.rs:43:9 | LL | bar(Forbidden); - | --- ^^^^^^^^^ the trait `SyncDrop` is not implemented for `Forbidden` + | --- ^^^^^^^^^ unsatisfied trait bound | | | required by a bound introduced by this call | +help: the trait `SyncDrop` is not implemented for `Forbidden` + --> $DIR/default-bounds.rs:32:1 + | +LL | struct Forbidden; + | ^^^^^^^^^^^^^^^^ note: required by a bound in `bar` --> $DIR/default-bounds.rs:39:8 | @@ -16,10 +21,15 @@ error[E0277]: the trait bound `Forbidden: Leak` is not satisfied --> $DIR/default-bounds.rs:43:9 | LL | bar(Forbidden); - | --- ^^^^^^^^^ the trait `Leak` is not implemented for `Forbidden` + | --- ^^^^^^^^^ unsatisfied trait bound | | | required by a bound introduced by this call | +help: the trait `Leak` is not implemented for `Forbidden` + --> $DIR/default-bounds.rs:32:1 + | +LL | struct Forbidden; + | ^^^^^^^^^^^^^^^^ note: required by a bound in `bar` --> $DIR/default-bounds.rs:39:11 | diff --git a/tests/ui/traits/default_auto_traits/maybe-bounds-in-dyn-traits.stderr b/tests/ui/traits/default_auto_traits/maybe-bounds-in-dyn-traits.stderr index 350233b7cbe..b19c082a1b8 100644 --- a/tests/ui/traits/default_auto_traits/maybe-bounds-in-dyn-traits.stderr +++ b/tests/ui/traits/default_auto_traits/maybe-bounds-in-dyn-traits.stderr @@ -2,8 +2,13 @@ error[E0277]: the trait bound `NonLeakS: Leak` is not satisfied --> $DIR/maybe-bounds-in-dyn-traits.rs:59:25 | LL | let _: &dyn Trait = &NonLeakS; - | ^^^^^^^^^ the trait `Leak` is not implemented for `NonLeakS` + | ^^^^^^^^^ unsatisfied trait bound | +help: the trait `Leak` is not implemented for `NonLeakS` + --> $DIR/maybe-bounds-in-dyn-traits.rs:46:1 + | +LL | struct NonLeakS; + | ^^^^^^^^^^^^^^^ = note: required for the cast from `&NonLeakS` to `&dyn Trait + Leak` error[E0277]: the trait bound `dyn Trait: Leak` is not satisfied diff --git a/tests/ui/traits/default_auto_traits/maybe-bounds-in-traits.stderr b/tests/ui/traits/default_auto_traits/maybe-bounds-in-traits.stderr index bc797c9d976..372bf817600 100644 --- a/tests/ui/traits/default_auto_traits/maybe-bounds-in-traits.stderr +++ b/tests/ui/traits/default_auto_traits/maybe-bounds-in-traits.stderr @@ -2,8 +2,13 @@ error[E0277]: the trait bound `NonLeakS: Leak` is not satisfied --> $DIR/maybe-bounds-in-traits.rs:67:22 | LL | type Leak2 = NonLeakS; - | ^^^^^^^^ the trait `Leak` is not implemented for `NonLeakS` + | ^^^^^^^^ unsatisfied trait bound | +help: the trait `Leak` is not implemented for `NonLeakS` + --> $DIR/maybe-bounds-in-traits.rs:34:1 + | +LL | struct NonLeakS; + | ^^^^^^^^^^^^^^^ note: required by a bound in `Test3::Leak2` --> $DIR/maybe-bounds-in-traits.rs:67:9 | @@ -57,8 +62,13 @@ error[E0277]: the trait bound `NonLeakS: Leak` is not satisfied --> $DIR/maybe-bounds-in-traits.rs:115:18 | LL | NonLeakS.leak_foo(); - | ^^^^^^^^ the trait `Leak` is not implemented for `NonLeakS` + | ^^^^^^^^ unsatisfied trait bound + | +help: the trait `Leak` is not implemented for `NonLeakS` + --> $DIR/maybe-bounds-in-traits.rs:34:1 | +LL | struct NonLeakS; + | ^^^^^^^^^^^^^^^ note: required by a bound in `methods::Trait::leak_foo` --> $DIR/maybe-bounds-in-traits.rs:101:9 | diff --git a/tests/ui/traits/enum-negative-send-impl.stderr b/tests/ui/traits/enum-negative-send-impl.stderr index 1992becccf4..2aad2265797 100644 --- a/tests/ui/traits/enum-negative-send-impl.stderr +++ b/tests/ui/traits/enum-negative-send-impl.stderr @@ -6,7 +6,11 @@ LL | requires_send(container); | | | required by a bound introduced by this call | - = help: within `Container`, the trait `Send` is not implemented for `NoSend` +help: within `Container`, the trait `Send` is not implemented for `NoSend` + --> $DIR/enum-negative-send-impl.rs:9:1 + | +LL | struct NoSend; + | ^^^^^^^^^^^^^ note: required because it appears within the type `Container` --> $DIR/enum-negative-send-impl.rs:12:6 | diff --git a/tests/ui/traits/enum-negative-sync-impl.stderr b/tests/ui/traits/enum-negative-sync-impl.stderr index a97b7a36a7b..b4ab69afb42 100644 --- a/tests/ui/traits/enum-negative-sync-impl.stderr +++ b/tests/ui/traits/enum-negative-sync-impl.stderr @@ -6,7 +6,11 @@ LL | requires_sync(container); | | | required by a bound introduced by this call | - = help: within `Container`, the trait `Sync` is not implemented for `NoSync` +help: within `Container`, the trait `Sync` is not implemented for `NoSync` + --> $DIR/enum-negative-sync-impl.rs:9:1 + | +LL | struct NoSync; + | ^^^^^^^^^^^^^ note: required because it appears within the type `Container` --> $DIR/enum-negative-sync-impl.rs:12:6 | diff --git a/tests/ui/traits/issue-87558.stderr b/tests/ui/traits/issue-87558.stderr index dc5bd6ece36..ca908a3062d 100644 --- a/tests/ui/traits/issue-87558.stderr +++ b/tests/ui/traits/issue-87558.stderr @@ -38,7 +38,11 @@ error[E0277]: expected a `FnMut(&isize)` closure, found `Error` LL | impl Fn(&isize) for Error { | ^^^^^ expected an `FnMut(&isize)` closure, found `Error` | - = help: the trait `FnMut(&isize)` is not implemented for `Error` +help: the trait `FnMut(&isize)` is not implemented for `Error` + --> $DIR/issue-87558.rs:2:1 + | +LL | struct Error(ErrorKind); + | ^^^^^^^^^^^^ note: required by a bound in `Fn` --> $SRC_DIR/core/src/ops/function.rs:LL:COL diff --git a/tests/ui/traits/issue-91594.stderr b/tests/ui/traits/issue-91594.stderr index 13568179e81..04abd02aac4 100644 --- a/tests/ui/traits/issue-91594.stderr +++ b/tests/ui/traits/issue-91594.stderr @@ -2,8 +2,13 @@ error[E0277]: the trait bound `Foo: HasComponent<()>` is not satisfied --> $DIR/issue-91594.rs:10:19 | LL | impl HasComponent<<Foo as Component<Foo>>::Interface> for Foo {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `HasComponent<()>` is not implemented for `Foo` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound | +help: the trait `HasComponent<()>` is not implemented for `Foo` + --> $DIR/issue-91594.rs:8:1 + | +LL | struct Foo; + | ^^^^^^^^^^ = help: the trait `HasComponent<<Foo as Component<Foo>>::Interface>` is implemented for `Foo` note: required for `Foo` to implement `Component<Foo>` --> $DIR/issue-91594.rs:13:27 diff --git a/tests/ui/traits/negative-bounds/on-unimplemented.stderr b/tests/ui/traits/negative-bounds/on-unimplemented.stderr index 8a295611010..008ff865018 100644 --- a/tests/ui/traits/negative-bounds/on-unimplemented.stderr +++ b/tests/ui/traits/negative-bounds/on-unimplemented.stderr @@ -2,10 +2,16 @@ error[E0277]: the trait bound `NotFoo: !Foo` is not satisfied --> $DIR/on-unimplemented.rs:9:15 | LL | fn hello() -> impl !Foo { - | ^^^^^^^^^ the trait bound `NotFoo: !Foo` is not satisfied + | ^^^^^^^^^ unsatisfied trait bound LL | LL | NotFoo | ------ return type was inferred to be `NotFoo` here + | +help: the trait bound `NotFoo: !Foo` is not satisfied + --> $DIR/on-unimplemented.rs:7:1 + | +LL | struct NotFoo; + | ^^^^^^^^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/traits/negative-bounds/simple.stderr b/tests/ui/traits/negative-bounds/simple.stderr index 499c19bb854..5b204c47d9c 100644 --- a/tests/ui/traits/negative-bounds/simple.stderr +++ b/tests/ui/traits/negative-bounds/simple.stderr @@ -26,8 +26,13 @@ error[E0277]: the trait bound `Copyable: !Copy` is not satisfied --> $DIR/simple.rs:30:16 | LL | not_copy::<Copyable>(); - | ^^^^^^^^ the trait bound `Copyable: !Copy` is not satisfied + | ^^^^^^^^ unsatisfied trait bound | +help: the trait bound `Copyable: !Copy` is not satisfied + --> $DIR/simple.rs:27:1 + | +LL | struct Copyable; + | ^^^^^^^^^^^^^^^ note: required by a bound in `not_copy` --> $DIR/simple.rs:3:16 | @@ -38,8 +43,13 @@ error[E0277]: the trait bound `NotNecessarilyCopyable: !Copy` is not satisfied --> $DIR/simple.rs:37:16 | LL | not_copy::<NotNecessarilyCopyable>(); - | ^^^^^^^^^^^^^^^^^^^^^^ the trait bound `NotNecessarilyCopyable: !Copy` is not satisfied + | ^^^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound + | +help: the trait bound `NotNecessarilyCopyable: !Copy` is not satisfied + --> $DIR/simple.rs:34:1 | +LL | struct NotNecessarilyCopyable; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: required by a bound in `not_copy` --> $DIR/simple.rs:3:16 | diff --git a/tests/ui/traits/negative-impls/negated-auto-traits-error.stderr b/tests/ui/traits/negative-impls/negated-auto-traits-error.stderr index 8f5b937e586..f450f786f60 100644 --- a/tests/ui/traits/negative-impls/negated-auto-traits-error.stderr +++ b/tests/ui/traits/negative-impls/negated-auto-traits-error.stderr @@ -6,7 +6,11 @@ LL | Outer(TestType); | | | required by a bound introduced by this call | - = help: the trait `Send` is not implemented for `dummy::TestType` +help: the trait `Send` is not implemented for `dummy::TestType` + --> $DIR/negated-auto-traits-error.rs:20:5 + | +LL | struct TestType; + | ^^^^^^^^^^^^^^^ note: required by a bound in `Outer` --> $DIR/negated-auto-traits-error.rs:10:17 | @@ -19,7 +23,11 @@ error[E0277]: `dummy::TestType` cannot be sent between threads safely LL | Outer(TestType); | ^^^^^^^^^^^^^^^ `dummy::TestType` cannot be sent between threads safely | - = help: the trait `Send` is not implemented for `dummy::TestType` +help: the trait `Send` is not implemented for `dummy::TestType` + --> $DIR/negated-auto-traits-error.rs:20:5 + | +LL | struct TestType; + | ^^^^^^^^^^^^^^^ note: required by a bound in `Outer` --> $DIR/negated-auto-traits-error.rs:10:17 | @@ -34,7 +42,11 @@ LL | is_send(TestType); | | | required by a bound introduced by this call | - = help: the trait `Send` is not implemented for `dummy1b::TestType` +help: the trait `Send` is not implemented for `dummy1b::TestType` + --> $DIR/negated-auto-traits-error.rs:29:5 + | +LL | struct TestType; + | ^^^^^^^^^^^^^^^ note: required by a bound in `is_send` --> $DIR/negated-auto-traits-error.rs:16:15 | @@ -49,7 +61,11 @@ LL | is_send((8, TestType)); | | | required by a bound introduced by this call | - = help: within `({integer}, dummy1c::TestType)`, the trait `Send` is not implemented for `dummy1c::TestType` +help: within `({integer}, dummy1c::TestType)`, the trait `Send` is not implemented for `dummy1c::TestType` + --> $DIR/negated-auto-traits-error.rs:37:5 + | +LL | struct TestType; + | ^^^^^^^^^^^^^^^ = note: required because it appears within the type `({integer}, dummy1c::TestType)` note: required by a bound in `is_send` --> $DIR/negated-auto-traits-error.rs:16:15 @@ -87,7 +103,11 @@ LL | is_send(Box::new(Outer2(TestType))); | | | required by a bound introduced by this call | - = help: within `Outer2<dummy3::TestType>`, the trait `Send` is not implemented for `dummy3::TestType` +help: within `Outer2<dummy3::TestType>`, the trait `Send` is not implemented for `dummy3::TestType` + --> $DIR/negated-auto-traits-error.rs:53:5 + | +LL | struct TestType; + | ^^^^^^^^^^^^^^^ note: required because it appears within the type `Outer2<dummy3::TestType>` --> $DIR/negated-auto-traits-error.rs:12:8 | @@ -110,7 +130,11 @@ LL | is_sync(Outer2(TestType)); | | | required by a bound introduced by this call | - = help: the trait `Send` is not implemented for `main::TestType` +help: the trait `Send` is not implemented for `main::TestType` + --> $DIR/negated-auto-traits-error.rs:61:5 + | +LL | struct TestType; + | ^^^^^^^^^^^^^^^ note: required for `Outer2<main::TestType>` to implement `Sync` --> $DIR/negated-auto-traits-error.rs:14:22 | diff --git a/tests/ui/traits/next-solver/auto-with-drop_tracking_mir.fail.stderr b/tests/ui/traits/next-solver/auto-with-drop_tracking_mir.fail.stderr index 55f52181ec9..0375e64ac66 100644 --- a/tests/ui/traits/next-solver/auto-with-drop_tracking_mir.fail.stderr +++ b/tests/ui/traits/next-solver/auto-with-drop_tracking_mir.fail.stderr @@ -4,7 +4,11 @@ error: future cannot be sent between threads safely LL | is_send(foo()); | ^^^^^ future returned by `foo` is not `Send` | - = help: the trait `Sync` is not implemented for `NotSync` +help: the trait `Sync` is not implemented for `NotSync` + --> $DIR/auto-with-drop_tracking_mir.rs:8:1 + | +LL | struct NotSync; + | ^^^^^^^^^^^^^^ note: future is not `Send` as this value is used across an await --> $DIR/auto-with-drop_tracking_mir.rs:16:11 | diff --git a/tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.with.stderr b/tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.with.stderr index d27104de541..8cad9408810 100644 --- a/tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.with.stderr +++ b/tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.with.stderr @@ -2,8 +2,13 @@ error[E0277]: the trait bound `A<X>: Trait<_, _, _>` is not satisfied --> $DIR/incompleteness-unstable-result.rs:66:19 | LL | impls_trait::<A<X>, _, _, _>(); - | ^^^^ the trait `Trait<_, _, _>` is not implemented for `A<X>` + | ^^^^ unsatisfied trait bound | +help: the trait `Trait<_, _, _>` is not implemented for `A<X>` + --> $DIR/incompleteness-unstable-result.rs:22:1 + | +LL | struct A<T>(*const T); + | ^^^^^^^^^^^ = help: the trait `Trait<U, V, D>` is implemented for `A<T>` note: required for `A<X>` to implement `Trait<_, _, _>` --> $DIR/incompleteness-unstable-result.rs:34:18 diff --git a/tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.without.stderr b/tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.without.stderr index d27104de541..8cad9408810 100644 --- a/tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.without.stderr +++ b/tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.without.stderr @@ -2,8 +2,13 @@ error[E0277]: the trait bound `A<X>: Trait<_, _, _>` is not satisfied --> $DIR/incompleteness-unstable-result.rs:66:19 | LL | impls_trait::<A<X>, _, _, _>(); - | ^^^^ the trait `Trait<_, _, _>` is not implemented for `A<X>` + | ^^^^ unsatisfied trait bound | +help: the trait `Trait<_, _, _>` is not implemented for `A<X>` + --> $DIR/incompleteness-unstable-result.rs:22:1 + | +LL | struct A<T>(*const T); + | ^^^^^^^^^^^ = help: the trait `Trait<U, V, D>` is implemented for `A<T>` note: required for `A<X>` to implement `Trait<_, _, _>` --> $DIR/incompleteness-unstable-result.rs:34:18 diff --git a/tests/ui/traits/next-solver/cycles/inductive-cycle-but-err.stderr b/tests/ui/traits/next-solver/cycles/inductive-cycle-but-err.stderr index 7895a263634..12a26a1bf60 100644 --- a/tests/ui/traits/next-solver/cycles/inductive-cycle-but-err.stderr +++ b/tests/ui/traits/next-solver/cycles/inductive-cycle-but-err.stderr @@ -14,8 +14,13 @@ error[E0277]: the trait bound `MultipleCandidates: Trait` is not satisfied --> $DIR/inductive-cycle-but-err.rs:54:19 | LL | impls_trait::<MultipleCandidates>(); - | ^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `MultipleCandidates` + | ^^^^^^^^^^^^^^^^^^ unsatisfied trait bound | +help: the trait `Trait` is not implemented for `MultipleCandidates` + --> $DIR/inductive-cycle-but-err.rs:18:1 + | +LL | struct MultipleCandidates; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ = help: the trait `Trait` is implemented for `MultipleCandidates` note: required by a bound in `impls_trait` --> $DIR/inductive-cycle-but-err.rs:51:19 diff --git a/tests/ui/traits/next-solver/cycles/normalizes-to-is-not-productive.stderr b/tests/ui/traits/next-solver/cycles/normalizes-to-is-not-productive.stderr index 8901805a20f..4934d8bf6fa 100644 --- a/tests/ui/traits/next-solver/cycles/normalizes-to-is-not-productive.stderr +++ b/tests/ui/traits/next-solver/cycles/normalizes-to-is-not-productive.stderr @@ -2,8 +2,13 @@ error[E0277]: the trait bound `Foo: Bound` is not satisfied --> $DIR/normalizes-to-is-not-productive.rs:42:31 | LL | <Foo as Trait<T>>::Assoc: Bound, - | ^^^^^ the trait `Bound` is not implemented for `Foo` + | ^^^^^ unsatisfied trait bound | +help: the trait `Bound` is not implemented for `Foo` + --> $DIR/normalizes-to-is-not-productive.rs:18:1 + | +LL | struct Foo; + | ^^^^^^^^^^ = help: the trait `Bound` is implemented for `u32` note: required for `Foo` to implement `Trait<T>` --> $DIR/normalizes-to-is-not-productive.rs:23:19 @@ -17,8 +22,13 @@ error[E0277]: the trait bound `Foo: Bound` is not satisfied --> $DIR/normalizes-to-is-not-productive.rs:47:19 | LL | impls_bound::<Foo>(); - | ^^^ the trait `Bound` is not implemented for `Foo` + | ^^^ unsatisfied trait bound + | +help: the trait `Bound` is not implemented for `Foo` + --> $DIR/normalizes-to-is-not-productive.rs:18:1 | +LL | struct Foo; + | ^^^^^^^^^^ = help: the trait `Bound` is implemented for `u32` note: required by a bound in `impls_bound` --> $DIR/normalizes-to-is-not-productive.rs:27:19 diff --git a/tests/ui/traits/next-solver/diagnostics/dont-pick-fnptr-bound-as-leaf.current.stderr b/tests/ui/traits/next-solver/diagnostics/dont-pick-fnptr-bound-as-leaf.current.stderr index a863886181c..6aa02879e7d 100644 --- a/tests/ui/traits/next-solver/diagnostics/dont-pick-fnptr-bound-as-leaf.current.stderr +++ b/tests/ui/traits/next-solver/diagnostics/dont-pick-fnptr-bound-as-leaf.current.stderr @@ -2,10 +2,15 @@ error[E0277]: the trait bound `Foo: Trait` is not satisfied --> $DIR/dont-pick-fnptr-bound-as-leaf.rs:24:20 | LL | requires_trait(Foo); - | -------------- ^^^ the trait `Trait` is not implemented for `Foo` + | -------------- ^^^ unsatisfied trait bound | | | required by a bound introduced by this call | +help: the trait `Trait` is not implemented for `Foo` + --> $DIR/dont-pick-fnptr-bound-as-leaf.rs:17:1 + | +LL | struct Foo; + | ^^^^^^^^^^ note: required by a bound in `requires_trait` --> $DIR/dont-pick-fnptr-bound-as-leaf.rs:19:22 | diff --git a/tests/ui/traits/next-solver/diagnostics/dont-pick-fnptr-bound-as-leaf.next.stderr b/tests/ui/traits/next-solver/diagnostics/dont-pick-fnptr-bound-as-leaf.next.stderr index a863886181c..6aa02879e7d 100644 --- a/tests/ui/traits/next-solver/diagnostics/dont-pick-fnptr-bound-as-leaf.next.stderr +++ b/tests/ui/traits/next-solver/diagnostics/dont-pick-fnptr-bound-as-leaf.next.stderr @@ -2,10 +2,15 @@ error[E0277]: the trait bound `Foo: Trait` is not satisfied --> $DIR/dont-pick-fnptr-bound-as-leaf.rs:24:20 | LL | requires_trait(Foo); - | -------------- ^^^ the trait `Trait` is not implemented for `Foo` + | -------------- ^^^ unsatisfied trait bound | | | required by a bound introduced by this call | +help: the trait `Trait` is not implemented for `Foo` + --> $DIR/dont-pick-fnptr-bound-as-leaf.rs:17:1 + | +LL | struct Foo; + | ^^^^^^^^^^ note: required by a bound in `requires_trait` --> $DIR/dont-pick-fnptr-bound-as-leaf.rs:19:22 | diff --git a/tests/ui/traits/next-solver/diagnostics/dont-pick-fnptr-bound-as-leaf.rs b/tests/ui/traits/next-solver/diagnostics/dont-pick-fnptr-bound-as-leaf.rs index 995f2c9fbee..0da7bb17a58 100644 --- a/tests/ui/traits/next-solver/diagnostics/dont-pick-fnptr-bound-as-leaf.rs +++ b/tests/ui/traits/next-solver/diagnostics/dont-pick-fnptr-bound-as-leaf.rs @@ -14,7 +14,7 @@ trait Trait {} impl<T: FnPtr> Trait for T {} -struct Foo; +struct Foo; //~ HELP: the trait `Trait` is not implemented for `Foo` fn requires_trait<T: Trait>(_: T) {} //~^ NOTE: required by a bound in `requires_trait` @@ -23,6 +23,6 @@ fn requires_trait<T: Trait>(_: T) {} fn main() { requires_trait(Foo); //~^ ERROR: the trait bound `Foo: Trait` is not satisfied - //~| NOTE: the trait `Trait` is not implemented for `Foo` + //~| NOTE: unsatisfied trait bound //~| NOTE: required by a bound introduced by this call } diff --git a/tests/ui/traits/no_send-struct.stderr b/tests/ui/traits/no_send-struct.stderr index fb7f26bb766..6b4a011280e 100644 --- a/tests/ui/traits/no_send-struct.stderr +++ b/tests/ui/traits/no_send-struct.stderr @@ -6,7 +6,11 @@ LL | bar(x); | | | required by a bound introduced by this call | - = help: the trait `Send` is not implemented for `Foo` +help: the trait `Send` is not implemented for `Foo` + --> $DIR/no_send-struct.rs:5:1 + | +LL | struct Foo { + | ^^^^^^^^^^ note: required by a bound in `bar` --> $DIR/no_send-struct.rs:11:11 | diff --git a/tests/ui/traits/struct-negative-sync-impl.stderr b/tests/ui/traits/struct-negative-sync-impl.stderr index c5fd13f42e5..cfb74d54ea3 100644 --- a/tests/ui/traits/struct-negative-sync-impl.stderr +++ b/tests/ui/traits/struct-negative-sync-impl.stderr @@ -6,7 +6,11 @@ LL | requires_sync(not_sync); | | | required by a bound introduced by this call | - = help: the trait `Sync` is not implemented for `NotSync` +help: the trait `Sync` is not implemented for `NotSync` + --> $DIR/struct-negative-sync-impl.rs:9:1 + | +LL | struct NotSync { + | ^^^^^^^^^^^^^^ note: required by a bound in `requires_sync` --> $DIR/struct-negative-sync-impl.rs:15:21 | diff --git a/tests/ui/traits/suggest-dereferences/deref-argument.stderr b/tests/ui/traits/suggest-dereferences/deref-argument.stderr index 3dc92fd6ab6..fd57e1f37c3 100644 --- a/tests/ui/traits/suggest-dereferences/deref-argument.stderr +++ b/tests/ui/traits/suggest-dereferences/deref-argument.stderr @@ -2,10 +2,15 @@ error[E0277]: the trait bound `MyRef: Test` is not satisfied --> $DIR/deref-argument.rs:29:18 | LL | consume_test(my_ref); - | ------------ ^^^^^^ the trait `Test` is not implemented for `MyRef` + | ------------ ^^^^^^ unsatisfied trait bound | | | required by a bound introduced by this call | +help: the trait `Test` is not implemented for `MyRef` + --> $DIR/deref-argument.rs:14:1 + | +LL | struct MyRef(u32); + | ^^^^^^^^^^^^ note: required by a bound in `consume_test` --> $DIR/deref-argument.rs:9:25 | diff --git a/tests/ui/traits/suggest-dereferences/issue-39029.stderr b/tests/ui/traits/suggest-dereferences/issue-39029.stderr index fd45fa3cf74..279d616c264 100644 --- a/tests/ui/traits/suggest-dereferences/issue-39029.stderr +++ b/tests/ui/traits/suggest-dereferences/issue-39029.stderr @@ -2,10 +2,15 @@ error[E0277]: the trait bound `NoToSocketAddrs: ToSocketAddrs` is not satisfied --> $DIR/issue-39029.rs:16:38 | LL | let _errors = TcpListener::bind(&bad); - | ----------------- ^^^ the trait `ToSocketAddrs` is not implemented for `NoToSocketAddrs` + | ----------------- ^^^ unsatisfied trait bound | | | required by a bound introduced by this call | +help: the trait `ToSocketAddrs` is not implemented for `NoToSocketAddrs` + --> $DIR/issue-39029.rs:4:1 + | +LL | struct NoToSocketAddrs(String); + | ^^^^^^^^^^^^^^^^^^^^^^ = note: required for `&NoToSocketAddrs` to implement `ToSocketAddrs` note: required by a bound in `TcpListener::bind` --> $SRC_DIR/std/src/net/tcp.rs:LL:COL diff --git a/tests/ui/traits/suggest-dereferences/suggest-dereferencing-receiver-argument.stderr b/tests/ui/traits/suggest-dereferences/suggest-dereferencing-receiver-argument.stderr index d6033bc6baa..6045224b11e 100644 --- a/tests/ui/traits/suggest-dereferences/suggest-dereferencing-receiver-argument.stderr +++ b/tests/ui/traits/suggest-dereferences/suggest-dereferencing-receiver-argument.stderr @@ -2,8 +2,13 @@ error[E0277]: the trait bound `TargetStruct: From<&{integer}>` is not satisfied --> $DIR/suggest-dereferencing-receiver-argument.rs:13:30 | LL | let _b: TargetStruct = a.into(); - | ^^^^ the trait `From<&{integer}>` is not implemented for `TargetStruct` + | ^^^^ unsatisfied trait bound | +help: the trait `From<&{integer}>` is not implemented for `TargetStruct` + --> $DIR/suggest-dereferencing-receiver-argument.rs:3:1 + | +LL | struct TargetStruct; + | ^^^^^^^^^^^^^^^^^^^ = note: required for `&{integer}` to implement `Into<TargetStruct>` help: consider dereferencing here | diff --git a/tests/ui/traits/suggest-where-clause.stderr b/tests/ui/traits/suggest-where-clause.stderr index 08f3a8dc23d..d01cd26730c 100644 --- a/tests/ui/traits/suggest-where-clause.stderr +++ b/tests/ui/traits/suggest-where-clause.stderr @@ -63,7 +63,13 @@ error[E0277]: the trait bound `Misc<_>: From<T>` is not satisfied --> $DIR/suggest-where-clause.rs:23:6 | LL | <Misc<_> as From<T>>::from; - | ^^^^^^^ the trait `From<T>` is not implemented for `Misc<_>` + | ^^^^^^^ unsatisfied trait bound + | +help: the trait `From<T>` is not implemented for `Misc<_>` + --> $DIR/suggest-where-clause.rs:3:1 + | +LL | struct Misc<T:?Sized>(T); + | ^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the size for values of type `[T]` cannot be known at compilation time --> $DIR/suggest-where-clause.rs:28:20 diff --git a/tests/ui/tuple/builtin-fail.stderr b/tests/ui/tuple/builtin-fail.stderr index ccbc5ae2b75..44e79578f4c 100644 --- a/tests/ui/tuple/builtin-fail.stderr +++ b/tests/ui/tuple/builtin-fail.stderr @@ -42,8 +42,13 @@ error[E0277]: `TupleStruct` is not a tuple --> $DIR/builtin-fail.rs:17:23 | LL | assert_is_tuple::<TupleStruct>(); - | ^^^^^^^^^^^ the trait `Tuple` is not implemented for `TupleStruct` + | ^^^^^^^^^^^ unsatisfied trait bound | +help: the trait `Tuple` is not implemented for `TupleStruct` + --> $DIR/builtin-fail.rs:5:1 + | +LL | struct TupleStruct(i32, i32); + | ^^^^^^^^^^^^^^^^^^ note: required by a bound in `assert_is_tuple` --> $DIR/builtin-fail.rs:3:23 | diff --git a/tests/ui/type-alias-impl-trait/constrain_in_projection.current.stderr b/tests/ui/type-alias-impl-trait/constrain_in_projection.current.stderr index c4c55d8e092..955ba69d3b6 100644 --- a/tests/ui/type-alias-impl-trait/constrain_in_projection.current.stderr +++ b/tests/ui/type-alias-impl-trait/constrain_in_projection.current.stderr @@ -2,7 +2,7 @@ error[E0277]: the trait bound `Foo: Trait<Bar>` is not satisfied --> $DIR/constrain_in_projection.rs:25:14 | LL | let x = <Foo as Trait<Bar>>::Assoc::default(); - | ^^^ the trait `Trait<Bar>` is not implemented for `Foo` + | ^^^ unsatisfied trait bound | = help: the trait `Trait<Bar>` is not implemented for `Foo` but trait `Trait<()>` is implemented for it @@ -11,7 +11,7 @@ error[E0277]: the trait bound `Foo: Trait<Bar>` is not satisfied --> $DIR/constrain_in_projection.rs:25:13 | LL | let x = <Foo as Trait<Bar>>::Assoc::default(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait<Bar>` is not implemented for `Foo` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound | = help: the trait `Trait<Bar>` is not implemented for `Foo` but trait `Trait<()>` is implemented for it diff --git a/tests/ui/type-alias-impl-trait/constrain_in_projection2.current.stderr b/tests/ui/type-alias-impl-trait/constrain_in_projection2.current.stderr index d7fb6e67ad2..4e7788bf113 100644 --- a/tests/ui/type-alias-impl-trait/constrain_in_projection2.current.stderr +++ b/tests/ui/type-alias-impl-trait/constrain_in_projection2.current.stderr @@ -2,8 +2,13 @@ error[E0277]: the trait bound `Foo: Trait<Bar>` is not satisfied --> $DIR/constrain_in_projection2.rs:28:14 | LL | let x = <Foo as Trait<Bar>>::Assoc::default(); - | ^^^ the trait `Trait<Bar>` is not implemented for `Foo` + | ^^^ unsatisfied trait bound | +help: the trait `Trait<Bar>` is not implemented for `Foo` + --> $DIR/constrain_in_projection2.rs:10:1 + | +LL | struct Foo; + | ^^^^^^^^^^ = help: the following other types implement trait `Trait<T>`: `Foo` implements `Trait<()>` `Foo` implements `Trait<u32>` @@ -12,8 +17,13 @@ error[E0277]: the trait bound `Foo: Trait<Bar>` is not satisfied --> $DIR/constrain_in_projection2.rs:28:13 | LL | let x = <Foo as Trait<Bar>>::Assoc::default(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait<Bar>` is not implemented for `Foo` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound + | +help: the trait `Trait<Bar>` is not implemented for `Foo` + --> $DIR/constrain_in_projection2.rs:10:1 | +LL | struct Foo; + | ^^^^^^^^^^ = help: the following other types implement trait `Trait<T>`: `Foo` implements `Trait<()>` `Foo` implements `Trait<u32>` diff --git a/tests/ui/type-alias-impl-trait/issue-53092-2.rs b/tests/ui/type-alias-impl-trait/issue-53092-2.rs index 1a530d27971..4ddb06e40ff 100644 --- a/tests/ui/type-alias-impl-trait/issue-53092-2.rs +++ b/tests/ui/type-alias-impl-trait/issue-53092-2.rs @@ -2,11 +2,11 @@ #![allow(dead_code)] type Bug<T, U> = impl Fn(T) -> U + Copy; -//~^ ERROR cycle detected when computing type of `Bug::{opaque#0}` #[define_opaque(Bug)] const CONST_BUG: Bug<u8, ()> = unsafe { std::mem::transmute(|_: u8| ()) }; //~^ ERROR item does not constrain `Bug::{opaque#0}` +//~| ERROR: cannot transmute between types of different sizes, or dependently-sized types #[define_opaque(Bug)] fn make_bug<T, U: From<T>>() -> Bug<T, U> { diff --git a/tests/ui/type-alias-impl-trait/issue-53092-2.stderr b/tests/ui/type-alias-impl-trait/issue-53092-2.stderr index c8db9fdfc57..689f7a733cb 100644 --- a/tests/ui/type-alias-impl-trait/issue-53092-2.stderr +++ b/tests/ui/type-alias-impl-trait/issue-53092-2.stderr @@ -1,56 +1,5 @@ -error[E0391]: cycle detected when computing type of `Bug::{opaque#0}` - --> $DIR/issue-53092-2.rs:4:18 - | -LL | type Bug<T, U> = impl Fn(T) -> U + Copy; - | ^^^^^^^^^^^^^^^^^^^^^^ - | -note: ...which requires computing type of opaque `Bug::{opaque#0}`... - --> $DIR/issue-53092-2.rs:4:18 - | -LL | type Bug<T, U> = impl Fn(T) -> U + Copy; - | ^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires borrow-checking `CONST_BUG`... - --> $DIR/issue-53092-2.rs:8:1 - | -LL | const CONST_BUG: Bug<u8, ()> = unsafe { std::mem::transmute(|_: u8| ()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires promoting constants in MIR for `CONST_BUG`... - --> $DIR/issue-53092-2.rs:8:1 - | -LL | const CONST_BUG: Bug<u8, ()> = unsafe { std::mem::transmute(|_: u8| ()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires const checking `CONST_BUG`... - --> $DIR/issue-53092-2.rs:8:1 - | -LL | const CONST_BUG: Bug<u8, ()> = unsafe { std::mem::transmute(|_: u8| ()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires building MIR for `CONST_BUG`... - --> $DIR/issue-53092-2.rs:8:1 - | -LL | const CONST_BUG: Bug<u8, ()> = unsafe { std::mem::transmute(|_: u8| ()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires match-checking `CONST_BUG`... - --> $DIR/issue-53092-2.rs:8:1 - | -LL | const CONST_BUG: Bug<u8, ()> = unsafe { std::mem::transmute(|_: u8| ()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires type-checking `CONST_BUG`... - --> $DIR/issue-53092-2.rs:8:1 - | -LL | const CONST_BUG: Bug<u8, ()> = unsafe { std::mem::transmute(|_: u8| ()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: ...which requires computing layout of `Bug<u8, ()>`... - = note: ...which requires normalizing `Bug<u8, ()>`... - = note: ...which again requires computing type of `Bug::{opaque#0}`, completing the cycle -note: cycle used when checking that `Bug::{opaque#0}` is well-formed - --> $DIR/issue-53092-2.rs:4:18 - | -LL | type Bug<T, U> = impl Fn(T) -> U + Copy; - | ^^^^^^^^^^^^^^^^^^^^^^ - = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information - error: item does not constrain `Bug::{opaque#0}` - --> $DIR/issue-53092-2.rs:8:7 + --> $DIR/issue-53092-2.rs:7:7 | LL | const CONST_BUG: Bug<u8, ()> = unsafe { std::mem::transmute(|_: u8| ()) }; | ^^^^^^^^^ @@ -62,6 +11,15 @@ note: this opaque type is supposed to be constrained LL | type Bug<T, U> = impl Fn(T) -> U + Copy; | ^^^^^^^^^^^^^^^^^^^^^^ +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> $DIR/issue-53092-2.rs:7:41 + | +LL | const CONST_BUG: Bug<u8, ()> = unsafe { std::mem::transmute(|_: u8| ()) }; + | ^^^^^^^^^^^^^^^^^^^ + | + = note: source type: `{closure@$DIR/issue-53092-2.rs:7:61: 7:68}` (0 bits) + = note: target type: `{type error}` (the type has an unknown layout) + error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0391`. +For more information about this error, try `rustc --explain E0512`. diff --git a/tests/ui/type-alias-impl-trait/no_inferrable_concrete_type.rs b/tests/ui/type-alias-impl-trait/no_inferrable_concrete_type.rs index 8e5e4719415..bd1d6651859 100644 --- a/tests/ui/type-alias-impl-trait/no_inferrable_concrete_type.rs +++ b/tests/ui/type-alias-impl-trait/no_inferrable_concrete_type.rs @@ -15,5 +15,6 @@ pub fn bar(x: Foo) -> Foo { fn main() { unsafe { let _: Foo = std::mem::transmute(0u8); + //~^ ERROR: cannot transmute between types of different sizes, or dependently-sized types } } diff --git a/tests/ui/type-alias-impl-trait/no_inferrable_concrete_type.stderr b/tests/ui/type-alias-impl-trait/no_inferrable_concrete_type.stderr index a57793d5a77..c9646a4e9a4 100644 --- a/tests/ui/type-alias-impl-trait/no_inferrable_concrete_type.stderr +++ b/tests/ui/type-alias-impl-trait/no_inferrable_concrete_type.stderr @@ -11,5 +11,15 @@ note: this opaque type is supposed to be constrained LL | pub type Foo = impl Copy; | ^^^^^^^^^ -error: aborting due to 1 previous error +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> $DIR/no_inferrable_concrete_type.rs:17:22 + | +LL | let _: Foo = std::mem::transmute(0u8); + | ^^^^^^^^^^^^^^^^^^^ + | + = note: source type: `u8` (8 bits) + = note: target type: `{type error}` (the type has an unknown layout) + +error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0512`. diff --git a/tests/ui/type/pattern_types/or_patterns_invalid.rs b/tests/ui/type/pattern_types/or_patterns_invalid.rs index d341927601d..a99667c5412 100644 --- a/tests/ui/type/pattern_types/or_patterns_invalid.rs +++ b/tests/ui/type/pattern_types/or_patterns_invalid.rs @@ -13,14 +13,18 @@ use std::pat::pattern_type; fn main() { //~? ERROR: only non-overlapping pattern type ranges are allowed at present let not_adjacent: pattern_type!(i8 is -127..0 | 1..) = unsafe { std::mem::transmute(0) }; + //~^ ERROR: cannot transmute between types of different sizes, or dependently-sized types //~? ERROR: one pattern needs to end at `i8::MAX`, but was 29 instead let not_wrapping: pattern_type!(i8 is 10..20 | 20..30) = unsafe { std::mem::transmute(0) }; + //~^ ERROR: cannot transmute between types of different sizes, or dependently-sized types //~? ERROR: only signed integer base types are allowed for or-pattern pattern types let not_signed: pattern_type!(u8 is 10.. | 0..5) = unsafe { std::mem::transmute(0) }; + //~^ ERROR: cannot transmute between types of different sizes, or dependently-sized types //~? ERROR: allowed are two range patterns that are directly connected let not_simple_enough_for_mvp: pattern_type!(i8 is ..0 | 1..10 | 10..) = unsafe { std::mem::transmute(0) }; + //~^ ERROR: cannot transmute between types of different sizes, or dependently-sized types } diff --git a/tests/ui/type/pattern_types/or_patterns_invalid.stderr b/tests/ui/type/pattern_types/or_patterns_invalid.stderr index 6964788a6c2..e229c11386d 100644 --- a/tests/ui/type/pattern_types/or_patterns_invalid.stderr +++ b/tests/ui/type/pattern_types/or_patterns_invalid.stderr @@ -1,10 +1,47 @@ error: only non-overlapping pattern type ranges are allowed at present +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> $DIR/or_patterns_invalid.rs:15:69 + | +LL | let not_adjacent: pattern_type!(i8 is -127..0 | 1..) = unsafe { std::mem::transmute(0) }; + | ^^^^^^^^^^^^^^^^^^^ + | + = note: source type: `i32` (32 bits) + = note: target type: `(i8) is (-127..=-1 | 1..)` (the type has an unknown layout) + error: one pattern needs to end at `i8::MAX`, but was 29 instead +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> $DIR/or_patterns_invalid.rs:19:71 + | +LL | let not_wrapping: pattern_type!(i8 is 10..20 | 20..30) = unsafe { std::mem::transmute(0) }; + | ^^^^^^^^^^^^^^^^^^^ + | + = note: source type: `i32` (32 bits) + = note: target type: `(i8) is (10..=19 | 20..=29)` (the type has an unknown layout) + error: only signed integer base types are allowed for or-pattern pattern types at present +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> $DIR/or_patterns_invalid.rs:23:65 + | +LL | let not_signed: pattern_type!(u8 is 10.. | 0..5) = unsafe { std::mem::transmute(0) }; + | ^^^^^^^^^^^^^^^^^^^ + | + = note: source type: `i32` (32 bits) + = note: target type: `(u8) is (10.. | 0..=4)` (the type has an unknown layout) + error: the only or-pattern types allowed are two range patterns that are directly connected at their overflow site -error: aborting due to 4 previous errors +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> $DIR/or_patterns_invalid.rs:28:18 + | +LL | unsafe { std::mem::transmute(0) }; + | ^^^^^^^^^^^^^^^^^^^ + | + = note: source type: `i32` (32 bits) + = note: target type: `(i8) is (i8::MIN..=-1 | 1..=9 | 10..)` (the type has an unknown layout) + +error: aborting due to 8 previous errors +For more information about this error, try `rustc --explain E0512`. diff --git a/tests/ui/type/type-name-basic.rs b/tests/ui/type/type-name-basic.rs index e1310e1f365..343bcae175a 100644 --- a/tests/ui/type/type-name-basic.rs +++ b/tests/ui/type/type-name-basic.rs @@ -5,7 +5,7 @@ #![allow(dead_code)] -use std::any::type_name; +use std::any::{Any, type_name, type_name_of_val}; use std::borrow::Cow; struct Foo<T>(T); @@ -29,6 +29,12 @@ macro_rules! t { } } +macro_rules! v { + ($v:expr, $str:literal) => { + assert_eq!(type_name_of_val(&$v), $str); + } +} + pub fn main() { t!(bool, "bool"); t!(char, "char"); @@ -91,4 +97,14 @@ pub fn main() { } } S::<u32>::test(); + + struct Wrap<T>(T); + impl Wrap<&()> { + fn get(&self) -> impl Any { + struct Info; + Info + } + } + let a = Wrap(&()).get(); + v!(a, "type_name_basic::main::Wrap<&()>::get::Info"); } diff --git a/tests/ui/typeck/typeck-default-trait-impl-negation-send.stderr b/tests/ui/typeck/typeck-default-trait-impl-negation-send.stderr index 771272ad10b..761277775f3 100644 --- a/tests/ui/typeck/typeck-default-trait-impl-negation-send.stderr +++ b/tests/ui/typeck/typeck-default-trait-impl-negation-send.stderr @@ -4,7 +4,11 @@ error[E0277]: `MyNotSendable` cannot be sent between threads safely LL | is_send::<MyNotSendable>(); | ^^^^^^^^^^^^^ `MyNotSendable` cannot be sent between threads safely | - = help: the trait `Send` is not implemented for `MyNotSendable` +help: the trait `Send` is not implemented for `MyNotSendable` + --> $DIR/typeck-default-trait-impl-negation-send.rs:9:1 + | +LL | struct MyNotSendable { + | ^^^^^^^^^^^^^^^^^^^^ note: required by a bound in `is_send` --> $DIR/typeck-default-trait-impl-negation-send.rs:15:15 | diff --git a/tests/ui/typeck/typeck-default-trait-impl-negation-sync.stderr b/tests/ui/typeck/typeck-default-trait-impl-negation-sync.stderr index b9fca1a1b54..92629704c89 100644 --- a/tests/ui/typeck/typeck-default-trait-impl-negation-sync.stderr +++ b/tests/ui/typeck/typeck-default-trait-impl-negation-sync.stderr @@ -4,7 +4,11 @@ error[E0277]: `MyNotSync` cannot be shared between threads safely LL | is_sync::<MyNotSync>(); | ^^^^^^^^^ `MyNotSync` cannot be shared between threads safely | - = help: the trait `Sync` is not implemented for `MyNotSync` +help: the trait `Sync` is not implemented for `MyNotSync` + --> $DIR/typeck-default-trait-impl-negation-sync.rs:15:1 + | +LL | struct MyNotSync { + | ^^^^^^^^^^^^^^^^ note: required by a bound in `is_sync` --> $DIR/typeck-default-trait-impl-negation-sync.rs:29:15 | @@ -35,7 +39,11 @@ error[E0277]: `Managed` cannot be shared between threads safely LL | is_sync::<MyTypeManaged>(); | ^^^^^^^^^^^^^ `Managed` cannot be shared between threads safely | - = help: within `MyTypeManaged`, the trait `Sync` is not implemented for `Managed` +help: within `MyTypeManaged`, the trait `Sync` is not implemented for `Managed` + --> $DIR/typeck-default-trait-impl-negation-sync.rs:3:1 + | +LL | struct Managed; + | ^^^^^^^^^^^^^^ note: required because it appears within the type `MyTypeManaged` --> $DIR/typeck-default-trait-impl-negation-sync.rs:25:8 | diff --git a/tests/ui/typeck/typeck-unsafe-always-share.stderr b/tests/ui/typeck/typeck-unsafe-always-share.stderr index 154e504996b..c680c6ee27b 100644 --- a/tests/ui/typeck/typeck-unsafe-always-share.stderr +++ b/tests/ui/typeck/typeck-unsafe-always-share.stderr @@ -56,7 +56,11 @@ LL | test(NoSync); | | | required by a bound introduced by this call | - = help: the trait `Sync` is not implemented for `NoSync` +help: the trait `Sync` is not implemented for `NoSync` + --> $DIR/typeck-unsafe-always-share.rs:12:1 + | +LL | struct NoSync; + | ^^^^^^^^^^^^^ note: required by a bound in `test` --> $DIR/typeck-unsafe-always-share.rs:15:12 | diff --git a/tests/ui/unboxed-closures/unboxed-closures-fnmut-as-fn.stderr b/tests/ui/unboxed-closures/unboxed-closures-fnmut-as-fn.stderr index 9c5d824185b..0dd6dcfe6a3 100644 --- a/tests/ui/unboxed-closures/unboxed-closures-fnmut-as-fn.stderr +++ b/tests/ui/unboxed-closures/unboxed-closures-fnmut-as-fn.stderr @@ -6,7 +6,11 @@ LL | let x = call_it(&S, 22); | | | required by a bound introduced by this call | - = help: the trait `Fn(isize)` is not implemented for `S` +help: the trait `Fn(isize)` is not implemented for `S` + --> $DIR/unboxed-closures-fnmut-as-fn.rs:8:1 + | +LL | struct S; + | ^^^^^^^^ = note: `S` implements `FnMut`, but it must implement `Fn`, which is more general note: required by a bound in `call_it` --> $DIR/unboxed-closures-fnmut-as-fn.rs:22:14 diff --git a/tests/ui/unpretty/exhaustive.expanded.stdout b/tests/ui/unpretty/exhaustive.expanded.stdout index 0327ad5f92b..a12ea0786f9 100644 --- a/tests/ui/unpretty/exhaustive.expanded.stdout +++ b/tests/ui/unpretty/exhaustive.expanded.stdout @@ -13,6 +13,7 @@ #![feature(box_patterns)] #![feature(builtin_syntax)] #![feature(const_trait_impl)] +#![feature(coroutines)] #![feature(decl_macro)] #![feature(deref_patterns)] #![feature(explicit_tail_calls)] diff --git a/tests/ui/unpretty/exhaustive.hir.stderr b/tests/ui/unpretty/exhaustive.hir.stderr index aa411ce81eb..eb5c186bd2c 100644 --- a/tests/ui/unpretty/exhaustive.hir.stderr +++ b/tests/ui/unpretty/exhaustive.hir.stderr @@ -1,17 +1,17 @@ error[E0697]: closures cannot be static - --> $DIR/exhaustive.rs:209:9 + --> $DIR/exhaustive.rs:210:9 | LL | static || value; | ^^^^^^^^^ error[E0697]: closures cannot be static - --> $DIR/exhaustive.rs:210:9 + --> $DIR/exhaustive.rs:211:9 | LL | static move || value; | ^^^^^^^^^^^^^^ error[E0728]: `await` is only allowed inside `async` functions and blocks - --> $DIR/exhaustive.rs:239:13 + --> $DIR/exhaustive.rs:240:13 | LL | fn expr_await() { | --------------- this is not `async` @@ -20,19 +20,19 @@ LL | fut.await; | ^^^^^ only allowed inside `async` functions and blocks error: in expressions, `_` can only be used on the left-hand side of an assignment - --> $DIR/exhaustive.rs:288:9 + --> $DIR/exhaustive.rs:289:9 | LL | _; | ^ `_` not allowed here error[E0214]: parenthesized type parameters may only be used with a `Fn` trait - --> $DIR/exhaustive.rs:298:9 + --> $DIR/exhaustive.rs:299:9 | LL | x::(); | ^^^^^ only `Fn` traits may use parentheses error[E0214]: parenthesized type parameters may only be used with a `Fn` trait - --> $DIR/exhaustive.rs:299:9 + --> $DIR/exhaustive.rs:300:9 | LL | x::(T, T) -> T; | ^^^^^^^^^^^^^^ only `Fn` traits may use parentheses @@ -44,31 +44,31 @@ LL + x::<T, T> -> T; | error[E0214]: parenthesized type parameters may only be used with a `Fn` trait - --> $DIR/exhaustive.rs:300:9 + --> $DIR/exhaustive.rs:301:9 | LL | crate::() -> ()::expressions::() -> ()::expr_path; | ^^^^^^^^^^^^^^^ only `Fn` traits may use parentheses error[E0214]: parenthesized type parameters may only be used with a `Fn` trait - --> $DIR/exhaustive.rs:300:26 + --> $DIR/exhaustive.rs:301:26 | LL | crate::() -> ()::expressions::() -> ()::expr_path; | ^^^^^^^^^^^^^^^^^^^^^ only `Fn` traits may use parentheses error[E0214]: parenthesized type parameters may only be used with a `Fn` trait - --> $DIR/exhaustive.rs:303:9 + --> $DIR/exhaustive.rs:304:9 | LL | core::()::marker::()::PhantomData; | ^^^^^^^^ only `Fn` traits may use parentheses error[E0214]: parenthesized type parameters may only be used with a `Fn` trait - --> $DIR/exhaustive.rs:303:19 + --> $DIR/exhaustive.rs:304:19 | LL | core::()::marker::()::PhantomData; | ^^^^^^^^^^ only `Fn` traits may use parentheses error: `yield` can only be used in `#[coroutine]` closures, or `gen` blocks - --> $DIR/exhaustive.rs:390:9 + --> $DIR/exhaustive.rs:391:9 | LL | yield; | ^^^^^ @@ -79,7 +79,7 @@ LL | #[coroutine] fn expr_yield() { | ++++++++++++ error[E0703]: invalid ABI: found `C++` - --> $DIR/exhaustive.rs:470:23 + --> $DIR/exhaustive.rs:471:23 | LL | unsafe extern "C++" {} | ^^^^^ invalid ABI @@ -87,7 +87,7 @@ LL | unsafe extern "C++" {} = note: invoke `rustc --print=calling-conventions` for a full list of supported calling conventions error: `..` patterns are not allowed here - --> $DIR/exhaustive.rs:677:13 + --> $DIR/exhaustive.rs:678:13 | LL | let ..; | ^^ @@ -95,13 +95,13 @@ LL | let ..; = note: only allowed in tuple, tuple struct, and slice patterns error[E0214]: parenthesized type parameters may only be used with a `Fn` trait - --> $DIR/exhaustive.rs:792:16 + --> $DIR/exhaustive.rs:793:16 | LL | let _: T() -> !; | ^^^^^^^^ only `Fn` traits may use parentheses error[E0562]: `impl Trait` is not allowed in the type of variable bindings - --> $DIR/exhaustive.rs:806:16 + --> $DIR/exhaustive.rs:807:16 | LL | let _: impl Send; | ^^^^^^^^^ @@ -112,7 +112,7 @@ LL | let _: impl Send; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0562]: `impl Trait` is not allowed in the type of variable bindings - --> $DIR/exhaustive.rs:807:16 + --> $DIR/exhaustive.rs:808:16 | LL | let _: impl Send + 'static; | ^^^^^^^^^^^^^^^^^^^ @@ -123,7 +123,7 @@ LL | let _: impl Send + 'static; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0562]: `impl Trait` is not allowed in the type of variable bindings - --> $DIR/exhaustive.rs:808:16 + --> $DIR/exhaustive.rs:809:16 | LL | let _: impl 'static + Send; | ^^^^^^^^^^^^^^^^^^^ @@ -134,7 +134,7 @@ LL | let _: impl 'static + Send; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0562]: `impl Trait` is not allowed in the type of variable bindings - --> $DIR/exhaustive.rs:809:16 + --> $DIR/exhaustive.rs:810:16 | LL | let _: impl ?Sized; | ^^^^^^^^^^^ @@ -145,7 +145,7 @@ LL | let _: impl ?Sized; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0562]: `impl Trait` is not allowed in the type of variable bindings - --> $DIR/exhaustive.rs:810:16 + --> $DIR/exhaustive.rs:811:16 | LL | let _: impl [const] Clone; | ^^^^^^^^^^^^^^^^^^ @@ -156,7 +156,7 @@ LL | let _: impl [const] Clone; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0562]: `impl Trait` is not allowed in the type of variable bindings - --> $DIR/exhaustive.rs:811:16 + --> $DIR/exhaustive.rs:812:16 | LL | let _: impl for<'a> Send; | ^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/unpretty/exhaustive.hir.stdout b/tests/ui/unpretty/exhaustive.hir.stdout index 68356a33c9e..924fb98ae18 100644 --- a/tests/ui/unpretty/exhaustive.hir.stdout +++ b/tests/ui/unpretty/exhaustive.hir.stdout @@ -12,6 +12,7 @@ #![feature(box_patterns)] #![feature(builtin_syntax)] #![feature(const_trait_impl)] +#![feature(coroutines)] #![feature(decl_macro)] #![feature(deref_patterns)] #![feature(explicit_tail_calls)] diff --git a/tests/ui/unpretty/exhaustive.rs b/tests/ui/unpretty/exhaustive.rs index b19d4f9fe2c..0983a0a7e43 100644 --- a/tests/ui/unpretty/exhaustive.rs +++ b/tests/ui/unpretty/exhaustive.rs @@ -12,6 +12,7 @@ #![feature(box_patterns)] #![feature(builtin_syntax)] #![feature(const_trait_impl)] +#![feature(coroutines)] #![feature(decl_macro)] #![feature(deref_patterns)] #![feature(explicit_tail_calls)] diff --git a/tests/ui/unsafe-fields/auto-traits.current.stderr b/tests/ui/unsafe-fields/auto-traits.current.stderr index 53a97458b7c..2483556b139 100644 --- a/tests/ui/unsafe-fields/auto-traits.current.stderr +++ b/tests/ui/unsafe-fields/auto-traits.current.stderr @@ -2,10 +2,15 @@ error[E0277]: the trait bound `UnsafeEnum: UnsafeAuto` is not satisfied --> $DIR/auto-traits.rs:24:22 | LL | impl_unsafe_auto(UnsafeEnum::Safe(42)); - | ---------------- ^^^^^^^^^^^^^^^^^^^^ the trait `UnsafeAuto` is not implemented for `UnsafeEnum` + | ---------------- ^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound | | | required by a bound introduced by this call | +help: the trait `UnsafeAuto` is not implemented for `UnsafeEnum` + --> $DIR/auto-traits.rs:9:1 + | +LL | enum UnsafeEnum { + | ^^^^^^^^^^^^^^^ note: required by a bound in `impl_unsafe_auto` --> $DIR/auto-traits.rs:20:29 | diff --git a/tests/ui/unsafe-fields/auto-traits.next.stderr b/tests/ui/unsafe-fields/auto-traits.next.stderr index 53a97458b7c..2483556b139 100644 --- a/tests/ui/unsafe-fields/auto-traits.next.stderr +++ b/tests/ui/unsafe-fields/auto-traits.next.stderr @@ -2,10 +2,15 @@ error[E0277]: the trait bound `UnsafeEnum: UnsafeAuto` is not satisfied --> $DIR/auto-traits.rs:24:22 | LL | impl_unsafe_auto(UnsafeEnum::Safe(42)); - | ---------------- ^^^^^^^^^^^^^^^^^^^^ the trait `UnsafeAuto` is not implemented for `UnsafeEnum` + | ---------------- ^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound | | | required by a bound introduced by this call | +help: the trait `UnsafeAuto` is not implemented for `UnsafeEnum` + --> $DIR/auto-traits.rs:9:1 + | +LL | enum UnsafeEnum { + | ^^^^^^^^^^^^^^^ note: required by a bound in `impl_unsafe_auto` --> $DIR/auto-traits.rs:20:29 | diff --git a/tests/ui/unsized/issue-75707.stderr b/tests/ui/unsized/issue-75707.stderr index f5f2f7192aa..7bdb65500a9 100644 --- a/tests/ui/unsized/issue-75707.stderr +++ b/tests/ui/unsized/issue-75707.stderr @@ -2,8 +2,13 @@ error[E0277]: the trait bound `MyCall: Callback` is not satisfied --> $DIR/issue-75707.rs:15:9 | LL | f::<dyn Processing<Call = MyCall>>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Callback` is not implemented for `MyCall` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound | +help: the trait `Callback` is not implemented for `MyCall` + --> $DIR/issue-75707.rs:14:5 + | +LL | struct MyCall; + | ^^^^^^^^^^^^^ help: this trait has no implementations, consider adding one --> $DIR/issue-75707.rs:1:1 | diff --git a/tests/ui/unstable-feature-bound/unstable_inherent_method.stderr b/tests/ui/unstable-feature-bound/unstable_inherent_method.stderr index 2a1ae936cfe..3438e84079d 100644 --- a/tests/ui/unstable-feature-bound/unstable_inherent_method.stderr +++ b/tests/ui/unstable-feature-bound/unstable_inherent_method.stderr @@ -4,7 +4,7 @@ error: `#[unstable_feature_bound]` attribute cannot be used on required trait me LL | #[unstable_feature_bound(foo)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: `#[unstable_feature_bound]` can be applied to functions, trait impl blocks, traits + = help: `#[unstable_feature_bound]` can be applied to functions, trait impl blocks, and traits error: `#[unstable_feature_bound]` attribute cannot be used on trait methods in impl blocks --> $DIR/unstable_inherent_method.rs:18:5 @@ -12,7 +12,7 @@ error: `#[unstable_feature_bound]` attribute cannot be used on trait methods in LL | #[unstable_feature_bound(foo)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: `#[unstable_feature_bound]` can be applied to functions, trait impl blocks, traits + = help: `#[unstable_feature_bound]` can be applied to functions, trait impl blocks, and traits error: aborting due to 2 previous errors diff --git a/tests/ui/wf/hir-wf-canonicalized.stderr b/tests/ui/wf/hir-wf-canonicalized.stderr index 8938801ce3d..51db0e39de0 100644 --- a/tests/ui/wf/hir-wf-canonicalized.stderr +++ b/tests/ui/wf/hir-wf-canonicalized.stderr @@ -2,8 +2,13 @@ error[E0277]: the trait bound `Bar<'a, T>: Foo` is not satisfied --> $DIR/hir-wf-canonicalized.rs:10:15 | LL | callback: Box<dyn Callback<dyn Callback<Bar<'a, T>>>>, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `Bar<'a, T>` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound | +help: the trait `Foo` is not implemented for `Bar<'a, T>` + --> $DIR/hir-wf-canonicalized.rs:9:1 + | +LL | struct Bar<'a, T> { + | ^^^^^^^^^^^^^^^^^ help: this trait has no implementations, consider adding one --> $DIR/hir-wf-canonicalized.rs:3:1 | diff --git a/tests/ui/wf/wf-packed-on-proj-of-type-as-unimpl-trait.stderr b/tests/ui/wf/wf-packed-on-proj-of-type-as-unimpl-trait.stderr index 8e3088c6f4a..3d066487654 100644 --- a/tests/ui/wf/wf-packed-on-proj-of-type-as-unimpl-trait.stderr +++ b/tests/ui/wf/wf-packed-on-proj-of-type-as-unimpl-trait.stderr @@ -2,8 +2,13 @@ error[E0277]: the trait bound `DefaultAllocator: Allocator` is not satisfied --> $DIR/wf-packed-on-proj-of-type-as-unimpl-trait.rs:28:12 | LL | struct Foo(Matrix<<DefaultAllocator as Allocator>::Buffer>); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Allocator` is not implemented for `DefaultAllocator` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound | +help: the trait `Allocator` is not implemented for `DefaultAllocator` + --> $DIR/wf-packed-on-proj-of-type-as-unimpl-trait.rs:21:1 + | +LL | pub struct DefaultAllocator; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: this trait has no implementations, consider adding one --> $DIR/wf-packed-on-proj-of-type-as-unimpl-trait.rs:23:1 | diff --git a/tests/ui/where-clauses/unsupported_attribute.stderr b/tests/ui/where-clauses/unsupported_attribute.stderr index cdd6e82b98d..42a8a1350d2 100644 --- a/tests/ui/where-clauses/unsupported_attribute.stderr +++ b/tests/ui/where-clauses/unsupported_attribute.stderr @@ -48,7 +48,7 @@ error: `#[macro_use]` attribute cannot be used on where predicates LL | #[macro_use] T: Trait, | ^^^^^^^^^^^^ | - = help: `#[macro_use]` can be applied to modules, extern crates, crates + = help: `#[macro_use]` can be applied to modules, extern crates, and crates error: `#[macro_use]` attribute cannot be used on where predicates --> $DIR/unsupported_attribute.rs:21:5 @@ -56,7 +56,7 @@ error: `#[macro_use]` attribute cannot be used on where predicates LL | #[macro_use] 'a: 'static, | ^^^^^^^^^^^^ | - = help: `#[macro_use]` can be applied to modules, extern crates, crates + = help: `#[macro_use]` can be applied to modules, extern crates, and crates error: `#[deprecated]` attribute cannot be used on where predicates --> $DIR/unsupported_attribute.rs:24:5 @@ -64,7 +64,7 @@ error: `#[deprecated]` attribute cannot be used on where predicates LL | #[deprecated] T: Trait, | ^^^^^^^^^^^^^ | - = help: `#[deprecated]` can be applied to functions, data types, modules, unions, constants, statics, macro defs, type aliases, use statements, foreign statics, struct fields, traits, associated types, associated consts, enum variants, inherent impl blocks, crates + = help: `#[deprecated]` can be applied to functions, data types, modules, unions, constants, statics, macro defs, type aliases, use statements, foreign statics, struct fields, traits, associated types, associated consts, enum variants, inherent impl blocks, and crates error: `#[deprecated]` attribute cannot be used on where predicates --> $DIR/unsupported_attribute.rs:25:5 @@ -72,7 +72,7 @@ error: `#[deprecated]` attribute cannot be used on where predicates LL | #[deprecated] 'a: 'static, | ^^^^^^^^^^^^^ | - = help: `#[deprecated]` can be applied to functions, data types, modules, unions, constants, statics, macro defs, type aliases, use statements, foreign statics, struct fields, traits, associated types, associated consts, enum variants, inherent impl blocks, crates + = help: `#[deprecated]` can be applied to functions, data types, modules, unions, constants, statics, macro defs, type aliases, use statements, foreign statics, struct fields, traits, associated types, associated consts, enum variants, inherent impl blocks, and crates error: `#[automatically_derived]` attribute cannot be used on where predicates --> $DIR/unsupported_attribute.rs:26:5 diff --git a/tests/ui/where-clauses/where-clause-method-substituion.stderr b/tests/ui/where-clauses/where-clause-method-substituion.stderr index 1a1d9c13ab8..73aac3d54a3 100644 --- a/tests/ui/where-clauses/where-clause-method-substituion.stderr +++ b/tests/ui/where-clauses/where-clause-method-substituion.stderr @@ -2,8 +2,13 @@ error[E0277]: the trait bound `X: Foo<X>` is not satisfied --> $DIR/where-clause-method-substituion.rs:20:16 | LL | 1.method::<X>(); - | ^ the trait `Foo<X>` is not implemented for `X` + | ^ unsatisfied trait bound | +help: the trait `Foo<X>` is not implemented for `X` + --> $DIR/where-clause-method-substituion.rs:10:1 + | +LL | struct X; + | ^^^^^^^^ help: this trait has no implementations, consider adding one --> $DIR/where-clause-method-substituion.rs:1:1 | diff --git a/triagebot.toml b/triagebot.toml index 955b0ba2b05..3b7b216c0d2 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1438,9 +1438,8 @@ fallback = [ ] style-team = [ "@calebcartwright", - "@compiler-errors", "@joshtriplett", - "@yaahc", + "@traviscross", ] project-const-traits = [ "@compiler-errors", |
