diff --git a/.github/workflows/post-merge.yml b/.github/workflows/post-merge.yml index 94553608a2f4..ca088ba31fdf 100644 --- a/.github/workflows/post-merge.yml +++ b/.github/workflows/post-merge.yml @@ -25,12 +25,19 @@ jobs: env: GH_TOKEN: ${{ github.token }} run: | + # Give GitHub some time to propagate the information that the PR was merged + sleep 60 + # Get closest bors merge commit PARENT_COMMIT=`git rev-list --author='bors ' -n1 --first-parent HEAD^1` echo "Parent: ${PARENT_COMMIT}" # Find PR for the current commit HEAD_PR=`gh pr list --search "${{ github.sha }}" --state merged --json number --jq '.[0].number'` + if [ -z "${HEAD_PR}" ]; then + echo "PR for commit SHA ${{ github.sha }} not found, exiting" + exit 1 + fi echo "HEAD: ${{ github.sha }} (#${HEAD_PR})" cd src/ci/citool diff --git a/Cargo.lock b/Cargo.lock index 361d237b3af8..83d7a6a9ab13 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -158,12 +158,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.97" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f" -dependencies = [ - "backtrace", -] +checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" [[package]] name = "ar_archive_writer" @@ -188,9 +185,9 @@ checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" [[package]] name = "askama" -version = "0.13.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a4e46abb203e00ef226442d452769233142bbfdd79c3941e84c8e61c4112543" +checksum = "5d4744ed2eef2645831b441d8f5459689ade2ab27c854488fbab1fbe94fce1a7" dependencies = [ "askama_derive", "itoa", @@ -201,9 +198,9 @@ dependencies = [ [[package]] name = "askama_derive" -version = "0.13.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54398906821fd32c728135f7b351f0c7494ab95ae421d41b6f5a020e158f28a6" +checksum = "d661e0f57be36a5c14c48f78d09011e67e0cb618f269cca9f2fd8d15b68c46ac" dependencies = [ "askama_parser", "basic-toml", @@ -213,7 +210,7 @@ dependencies = [ "rustc-hash 2.1.1", "serde", "serde_derive", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -225,7 +222,7 @@ dependencies = [ "memchr", "serde", "serde_derive", - "winnow 0.7.6", + "winnow 0.7.9", ] [[package]] @@ -281,9 +278,9 @@ checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" [[package]] name = "blake3" -version = "1.8.1" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "389a099b34312839e16420d499a9cad9650541715937ffbdd40d36f49e77eeb3" +checksum = "3888aaa89e4b2a40fca9848e400f6a658a5a3978de7be858e209cafa8be9a4a0" dependencies = [ "arrayref", "arrayvec", @@ -452,9 +449,9 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "chrono" -version = "0.4.40" +version = "0.4.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c" +checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" dependencies = [ "android-tzdata", "iana-time-zone", @@ -496,9 +493,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.36" +version = "4.5.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2df961d8c8a0d08aa9945718ccf584145eee3f3aa06cddbeac12933781102e04" +checksum = "eccb054f56cbd38340b380d4a8e69ef1f02f1af43db2f0cc817a4774d80ae071" dependencies = [ "clap_builder", "clap_derive", @@ -516,9 +513,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.36" +version = "4.5.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "132dbda40fb6753878316a489d5a1242a8ef2f0d9e47ba01c951ea8aa7d013a5" +checksum = "efd9466fac8543255d3b1fcad4762c5e116ffe808c8a3043d4263cd4fd4862a2" dependencies = [ "anstream", "anstyle", @@ -535,7 +532,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -561,13 +558,13 @@ dependencies = [ "if_chain", "itertools", "parking_lot", - "pulldown-cmark 0.11.3", + "pulldown-cmark", "quote", "regex", "rustc_tools_util 0.4.2", "serde", "serde_json", - "syn 2.0.100", + "syn 2.0.101", "tempfile", "termize", "tokio", @@ -653,16 +650,16 @@ dependencies = [ [[package]] name = "color-eyre" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55146f5e46f237f7423d74111267d4597b59b0dad0ffaf7303bce9945d843ad5" +checksum = "e6e1761c0e16f8883bbbb8ce5990867f4f06bf11a0253da6495a04ce4b6ef0ec" dependencies = [ "backtrace", "color-spantrace", "eyre", "indenter", "once_cell", - "owo-colors", + "owo-colors 4.2.0", "tracing-error", ] @@ -684,17 +681,17 @@ dependencies = [ "nom", "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] name = "color-spantrace" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd6be1b2a7e382e2b98b43b2adcca6bb0e465af0bdd38123873ae61eb17a72c2" +checksum = "2ddd8d5bfda1e11a501d0a7303f3bfed9aa632ebdb859be40d0fd70478ed70d5" dependencies = [ "once_cell", - "owo-colors", + "owo-colors 4.2.0", "tracing-core", "tracing-error", ] @@ -780,6 +777,7 @@ name = "coverage-dump" version = "0.1.0" dependencies = [ "anyhow", + "itertools", "leb128", "md-5", "miniz_oxide 0.7.4", @@ -910,7 +908,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -921,7 +919,7 @@ checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ "darling_core", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -943,13 +941,13 @@ dependencies = [ [[package]] name = "derive-where" -version = "1.2.7" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62d671cc41a825ebabc75757b62d3d168c577f9149b2d49ece1dad1f72119d25" +checksum = "e73f2692d4bd3cac41dca28934a39894200c9fabf49586d77d0e5954af1d7902" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -970,7 +968,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -980,7 +978,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" dependencies = [ "derive_builder_core", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -992,7 +990,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -1082,7 +1080,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -1361,7 +1359,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -1434,9 +1432,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ "cfg-if", "libc", @@ -1502,9 +1500,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.2" +version = "0.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3" dependencies = [ "allocator-api2", "equivalent", @@ -1761,7 +1759,7 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -1919,9 +1917,9 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "jiff" -version = "0.2.6" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f33145a5cbea837164362c7bd596106eb7c5198f97d1ba6f6ebb3223952e488" +checksum = "d07d8d955d798e7a4d6f9c58cd1f1916e790b42b092758a9ef6e16fef9f1b3fd" dependencies = [ "jiff-static", "log", @@ -1932,13 +1930,13 @@ dependencies = [ [[package]] name = "jiff-static" -version = "0.2.6" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43ce13c40ec6956157a3635d97a1ee2df323b263f09ea14165131289cb0f5c19" +checksum = "f244cfe006d98d26f859c7abd1318d85327e1882dc9cef80f62daeeb0adcf300" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -2071,14 +2069,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" dependencies = [ "cfg-if", - "windows-targets 0.52.6", + "windows-targets 0.48.5", ] [[package]] name = "libm" -version = "0.2.11" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" +checksum = "c9627da5196e5d8ed0b0495e61e518847578da83483c37288316d9b2e03a7f72" [[package]] name = "libredox" @@ -2202,7 +2200,7 @@ checksum = "88a9689d8d44bf9964484516275f5cd4c9b59457a6940c1d5d0ecbb94510a36b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -2307,7 +2305,7 @@ dependencies = [ "libffi", "libloading", "measureme", - "rand 0.9.0", + "rand 0.9.1", "regex", "rustc_version", "smallvec", @@ -2466,6 +2464,25 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" +[[package]] +name = "objc2-core-foundation" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c10c2894a6fed806ade6027bcd50662746363a9589d3ec9d9bef30a4e4bc166" +dependencies = [ + "bitflags", +] + +[[package]] +name = "objc2-io-kit" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71c1c64d6120e51cd86033f67176b1cb66780c2efe34dec55176f77befd93c0a" +dependencies = [ + "libc", + "objc2-core-foundation", +] + [[package]] name = "object" version = "0.32.2" @@ -2525,9 +2542,9 @@ checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" [[package]] name = "openssl-sys" -version = "0.9.107" +version = "0.9.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8288979acd84749c744a9014b4382d42b8f7b2592847b5afb2ed29e5d16ede07" +checksum = "e145e1651e858e820e4860f7b9c5e169bc1d8ce1c86043be79fa7b7634821847" dependencies = [ "cc", "libc", @@ -2577,6 +2594,12 @@ version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" +[[package]] +name = "owo-colors" +version = "4.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1036865bb9422d3300cf723f657c2851d0e9ab12567854b1f4eba3d77decf564" + [[package]] name = "pad" version = "0.1.6" @@ -2681,7 +2704,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -2798,7 +2821,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "abec3fb083c10660b3854367697da94c674e9e82aa7511014dc958beeb7215e9" dependencies = [ - "owo-colors", + "owo-colors 3.5.0", "pad", ] @@ -2810,33 +2833,22 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" [[package]] name = "proc-macro2" -version = "1.0.94" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" dependencies = [ "unicode-ident", ] [[package]] name = "psm" -version = "0.1.25" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f58e5423e24c18cc840e1c98370b3993c6649cd1678b4d24318bcf0a083cbe88" +checksum = "6e944464ec8536cd1beb0bbfd96987eb5e3b72f2ecdafdc5c769a37f1fa2ae1f" dependencies = [ "cc", ] -[[package]] -name = "pulldown-cmark" -version = "0.9.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57206b407293d2bcd3af849ce869d52068623f19e1b5ff8e8778e3309439682b" -dependencies = [ - "bitflags", - "memchr", - "unicase", -] - [[package]] name = "pulldown-cmark" version = "0.11.3" @@ -2895,13 +2907,12 @@ dependencies = [ [[package]] name = "rand" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" +checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" dependencies = [ "rand_chacha 0.9.0", "rand_core 0.9.3", - "zerocopy", ] [[package]] @@ -2930,7 +2941,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.16", ] [[package]] @@ -2973,9 +2984,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.11" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2f103c6d277498fbceb16e84d317e2a400f160f46904d5f5410848c829511a3" +checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af" dependencies = [ "bitflags", ] @@ -2986,7 +2997,7 @@ version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.16", "libredox", "thiserror 1.0.69", ] @@ -2997,7 +3008,7 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.16", "libredox", "thiserror 2.0.12", ] @@ -3179,7 +3190,7 @@ name = "rustc_abi" version = "0.0.0" dependencies = [ "bitflags", - "rand 0.9.0", + "rand 0.9.1", "rand_xoshiro", "rustc_data_structures", "rustc_hashes", @@ -3583,13 +3594,13 @@ dependencies = [ "rustc_query_system", "rustc_resolve", "rustc_session", - "rustc_smir", "rustc_span", "rustc_target", "rustc_trait_selection", "rustc_ty_utils", "serde_json", "shlex", + "stable_mir", "tracing", "windows 0.59.0", ] @@ -3693,7 +3704,7 @@ dependencies = [ "fluent-syntax", "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", "unic-langid", ] @@ -3805,7 +3816,7 @@ dependencies = [ name = "rustc_incremental" version = "0.0.0" dependencies = [ - "rand 0.9.0", + "rand 0.9.1", "rustc_ast", "rustc_data_structures", "rustc_errors", @@ -3839,7 +3850,7 @@ version = "0.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -3985,7 +3996,7 @@ version = "0.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", "synstructure", ] @@ -4015,6 +4026,7 @@ dependencies = [ "rustc_session", "rustc_span", "rustc_target", + "tempfile", "tracing", ] @@ -4314,7 +4326,7 @@ version = "0.0.0" dependencies = [ "bitflags", "itertools", - "pulldown-cmark 0.11.3", + "pulldown-cmark", "rustc_arena", "rustc_ast", "rustc_ast_pretty", @@ -4371,7 +4383,7 @@ dependencies = [ "bitflags", "getopts", "libc", - "rand 0.9.0", + "rand 0.9.1", "rustc_abi", "rustc_ast", "rustc_data_structures", @@ -4481,7 +4493,6 @@ dependencies = [ "itertools", "rustc_abi", "rustc_ast", - "rustc_attr_parsing", "rustc_data_structures", "rustc_errors", "rustc_fluent_macro", @@ -4575,7 +4586,7 @@ version = "0.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", "synstructure", ] @@ -4599,7 +4610,6 @@ dependencies = [ "indexmap", "itertools", "minifier", - "pulldown-cmark 0.9.6", "pulldown-cmark-escape", "regex", "rustdoc-json-types", @@ -4666,7 +4676,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -4700,9 +4710,9 @@ dependencies = [ [[package]] name = "rustix" -version = "1.0.5" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d97817398dd4bb2e6da002002db259209759911da105da92bec29ccb12cf58bf" +checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" dependencies = [ "bitflags", "errno", @@ -4803,7 +4813,7 @@ checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -4840,9 +4850,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.8" +version = "0.10.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", "cpufeatures", @@ -4961,9 +4971,9 @@ dependencies = [ [[package]] name = "stacker" -version = "0.1.20" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "601f9201feb9b09c00266478bf459952b9ef9a6b94edb2f21eba14ab681a60a9" +checksum = "cddb07e32ddb770749da91081d8d0ac3a16f1a569a18b20348cd371f5dead06b" dependencies = [ "cc", "cfg-if", @@ -5049,9 +5059,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.100" +version = "2.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" +checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" dependencies = [ "proc-macro2", "quote", @@ -5060,24 +5070,25 @@ dependencies = [ [[package]] name = "synstructure" -version = "0.13.1" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] name = "sysinfo" -version = "0.31.4" +version = "0.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "355dbe4f8799b304b05e1b0f05fc59b2a18d36645cf169607da45bde2f69a1be" +checksum = "b897c8ea620e181c7955369a31be5f48d9a9121cb59fd33ecef9ff2a34323422" dependencies = [ - "core-foundation-sys", "libc", - "windows 0.57.0", + "objc2-core-foundation", + "objc2-io-kit", + "windows 0.61.1", ] [[package]] @@ -5161,7 +5172,7 @@ version = "0.1.0" dependencies = [ "indicatif", "num", - "rand 0.9.0", + "rand 0.9.1", "rand_chacha 0.9.0", "rayon", ] @@ -5198,7 +5209,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -5209,7 +5220,7 @@ checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -5335,9 +5346,9 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.8" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +checksum = "3da5db5a963e24bc68be8b17b6fa82814bb22ee8660f192bb182771d498f09a3" dependencies = [ "serde", ] @@ -5375,7 +5386,7 @@ checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -5546,7 +5557,7 @@ checksum = "1ed7f4237ba393424195053097c1516bd4590dc82b84f2f97c5c69e12704555b" dependencies = [ "proc-macro-hack", "quote", - "syn 2.0.100", + "syn 2.0.101", "unic-langid-impl", ] @@ -5762,7 +5773,7 @@ dependencies = [ "log", "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", "wasm-bindgen-shared", ] @@ -5784,7 +5795,7 @@ checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -5952,16 +5963,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "windows" -version = "0.57.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12342cb4d8e3b046f3d80effd474a7a02447231330ef77d71daa6fbc40681143" -dependencies = [ - "windows-core 0.57.0", - "windows-targets 0.52.6", -] - [[package]] name = "windows" version = "0.59.0" @@ -5972,6 +5973,19 @@ dependencies = [ "windows-targets 0.53.0", ] +[[package]] +name = "windows" +version = "0.61.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5ee8f3d025738cb02bad7868bbb5f8a6327501e870bf51f1b455b0a2454a419" +dependencies = [ + "windows-collections", + "windows-core 0.61.0", + "windows-future", + "windows-link", + "windows-numerics", +] + [[package]] name = "windows-bindgen" version = "0.61.0" @@ -5984,15 +5998,12 @@ dependencies = [ ] [[package]] -name = "windows-core" -version = "0.57.0" +name = "windows-collections" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2ed2439a290666cd67ecce2b0ffaad89c2a56b976b736e6ece670297897832d" +checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" dependencies = [ - "windows-implement 0.57.0", - "windows-interface 0.57.0", - "windows-result 0.1.2", - "windows-targets 0.52.6", + "windows-core 0.61.0", ] [[package]] @@ -6002,8 +6013,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "810ce18ed2112484b0d4e15d022e5f598113e220c53e373fb31e67e21670c1ce" dependencies = [ "windows-implement 0.59.0", - "windows-interface 0.59.1", - "windows-result 0.3.2", + "windows-interface", + "windows-result", "windows-strings 0.3.1", "windows-targets 0.53.0", ] @@ -6015,21 +6026,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980" dependencies = [ "windows-implement 0.60.0", - "windows-interface 0.59.1", + "windows-interface", "windows-link", - "windows-result 0.3.2", + "windows-result", "windows-strings 0.4.0", ] [[package]] -name = "windows-implement" -version = "0.57.0" +name = "windows-future" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7" +checksum = "7a1d6bbefcb7b60acd19828e1bc965da6fcf18a7e39490c5f8be71e54a19ba32" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", + "windows-core 0.61.0", + "windows-link", ] [[package]] @@ -6040,7 +6050,7 @@ checksum = "83577b051e2f49a058c308f17f273b570a6a758386fc291b5f6a934dd84e48c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -6051,18 +6061,7 @@ checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", -] - -[[package]] -name = "windows-interface" -version = "0.57.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -6073,7 +6072,7 @@ checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -6083,12 +6082,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" [[package]] -name = "windows-result" -version = "0.1.2" +name = "windows-numerics" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8" +checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" dependencies = [ - "windows-targets 0.52.6", + "windows-core 0.61.0", + "windows-link", ] [[package]] @@ -6341,9 +6341,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.7.6" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63d3fcd9bba44b03821e7d699eeee959f3126dcc4aa8e4ae18ec617c2a5cea10" +checksum = "d9fb597c990f03753e08d3c29efbfcf2019a003b4bf4ba19225c158e1549f0f3" dependencies = [ "memchr", ] @@ -6464,28 +6464,28 @@ checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", "synstructure", ] [[package]] name = "zerocopy" -version = "0.8.24" +version = "0.8.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2586fea28e186957ef732a5f8b3be2da217d65c5969d4b1e17f973ebbe876879" +checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.24" +version = "0.8.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a996a8f63c5c4448cd959ac1bab0aaa3306ccfd060472f85943ee0750f0169be" +checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] [[package]] @@ -6505,7 +6505,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", "synstructure", ] @@ -6528,5 +6528,5 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.101", ] diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 9d216ef3dd84..114b9835b98c 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1633,6 +1633,9 @@ pub enum ExprKind { /// An `if` block, with an optional `else` block. /// /// `if expr { block } else { expr }` + /// + /// If present, the "else" expr is always `ExprKind::Block` (for `else`) or + /// `ExprKind::If` (for `else if`). If(P, P, Option>), /// A while loop, with an optional label. /// diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 8e1a3cd14354..9f3aed9216c2 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -492,9 +492,8 @@ impl<'hir> LoweringContext<'_, 'hir> { let mut generic_args = ThinVec::new(); for (idx, arg) in args.iter().cloned().enumerate() { if legacy_args_idx.contains(&idx) { - let parent_def_id = self.current_hir_id_owner.def_id; let node_id = self.next_node_id(); - self.create_def(parent_def_id, node_id, None, DefKind::AnonConst, f.span); + self.create_def(node_id, None, DefKind::AnonConst, f.span); let mut visitor = WillCreateDefIdsVisitor {}; let const_value = if let ControlFlow::Break(span) = visitor.visit_expr(&arg) { AstP(Expr { diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index c009abd729da..f48a571b86a7 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -1310,7 +1310,9 @@ impl<'hir> LoweringContext<'_, 'hir> { // create a fake body so that the entire rest of the compiler doesn't have to deal with // this as a special case. return self.lower_fn_body(decl, contract, |this| { - if attrs.iter().any(|a| a.has_name(sym::rustc_intrinsic)) { + if attrs.iter().any(|a| a.has_name(sym::rustc_intrinsic)) + || this.tcx.is_sdylib_interface_build() + { let span = this.lower_span(span); let empty_block = hir::Block { hir_id: this.next_id(), diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 8b1c63cd21d8..8597820073a5 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -55,8 +55,8 @@ use rustc_errors::{DiagArgFromDisplay, DiagCtxtHandle, StashKey}; use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res}; use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId}; use rustc_hir::{ - self as hir, ConstArg, GenericArg, HirId, ItemLocalMap, LangItem, LifetimeSource, - LifetimeSyntax, ParamName, TraitCandidate, + self as hir, AngleBrackets, ConstArg, GenericArg, HirId, ItemLocalMap, LangItem, + LifetimeSource, LifetimeSyntax, ParamName, TraitCandidate, }; use rustc_index::{Idx, IndexSlice, IndexVec}; use rustc_macros::extension; @@ -500,12 +500,12 @@ enum GenericArgsMode { impl<'a, 'hir> LoweringContext<'a, 'hir> { fn create_def( &mut self, - parent: LocalDefId, node_id: ast::NodeId, name: Option, def_kind: DefKind, span: Span, ) -> LocalDefId { + let parent = self.current_hir_id_owner.def_id; debug_assert_ne!(node_id, ast::DUMMY_NODE_ID); assert!( self.opt_local_def_id(node_id).is_none(), @@ -515,7 +515,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.tcx.hir_def_key(self.local_def_id(node_id)), ); - let def_id = self.tcx.at(span).create_def(parent, name, def_kind).def_id(); + let def_id = self + .tcx + .at(span) + .create_def(parent, name, def_kind, None, &mut self.resolver.disambiguator) + .def_id(); debug!("create_def: def_id_to_node_id[{:?}] <-> {:?}", def_id, node_id); self.resolver.node_id_to_def_id.insert(node_id, def_id); @@ -787,7 +791,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { LifetimeRes::Fresh { param, kind, .. } => { // Late resolution delegates to us the creation of the `LocalDefId`. let _def_id = self.create_def( - self.current_hir_id_owner.def_id, param, Some(kw::UnderscoreLifetime), DefKind::LifetimeParam, @@ -1087,7 +1090,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { match arg { ast::GenericArg::Lifetime(lt) => GenericArg::Lifetime(self.lower_lifetime( lt, - LifetimeSource::Path { with_angle_brackets: true }, + LifetimeSource::Path { angle_brackets: hir::AngleBrackets::Full }, lt.ident.into(), )), ast::GenericArg::Type(ty) => { @@ -1779,13 +1782,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { &mut self, id: NodeId, span: Span, - with_angle_brackets: bool, + angle_brackets: AngleBrackets, ) -> &'hir hir::Lifetime { self.new_named_lifetime( id, id, Ident::new(kw::UnderscoreLifetime, span), - LifetimeSource::Path { with_angle_brackets }, + LifetimeSource::Path { angle_brackets }, LifetimeSyntax::Hidden, ) } @@ -2113,8 +2116,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { hir::ConstArgKind::Path(qpath) } else { // Construct an AnonConst where the expr is the "ty"'s path. - - let parent_def_id = self.current_hir_id_owner.def_id; let node_id = self.next_node_id(); let span = self.lower_span(span); @@ -2122,7 +2123,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // We're lowering a const argument that was originally thought to be a type argument, // so the def collector didn't create the def ahead of time. That's why we have to do // it here. - let def_id = self.create_def(parent_def_id, node_id, None, DefKind::AnonConst, span); + let def_id = self.create_def(node_id, None, DefKind::AnonConst, span); let hir_id = self.lower_node_id(node_id); let path_expr = Expr { diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index 4a6929ef0117..58dea472f1d3 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -522,14 +522,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { span: Span, base_type: Span, ) -> &'hir hir::ConstArg<'hir> { - let parent_def_id = self.current_hir_id_owner.def_id; let node_id = self.next_node_id(); // Add a definition for the in-band const def. // We're generating a range end that didn't exist in the AST, // so the def collector didn't create the def ahead of time. That's why we have to do // it here. - let def_id = self.create_def(parent_def_id, node_id, None, DefKind::AnonConst, span); + let def_id = self.create_def(node_id, None, DefKind::AnonConst, span); let hir_id = self.lower_node_id(node_id); let unstable_span = self.mark_span_with_reason( diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs index fabe40a9d041..5cda64ce7b4b 100644 --- a/compiler/rustc_ast_lowering/src/path.rs +++ b/compiler/rustc_ast_lowering/src/path.rs @@ -432,27 +432,31 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // Note: these spans are used for diagnostics when they can't be inferred. // See rustc_resolve::late::lifetimes::LifetimeContext::add_missing_lifetime_specifiers_label - let (elided_lifetime_span, with_angle_brackets) = if generic_args.span.is_empty() { - // If there are no brackets, use the identifier span. + let (elided_lifetime_span, angle_brackets) = if generic_args.span.is_empty() { + // No brackets, e.g. `Path`: use an empty span just past the end of the identifier. // HACK: we use find_ancestor_inside to properly suggest elided spans in paths // originating from macros, since the segment's span might be from a macro arg. - (segment_ident_span.find_ancestor_inside(path_span).unwrap_or(path_span), false) - } else if generic_args.is_empty() { - // If there are brackets, but not generic arguments, then use the opening bracket - (generic_args.span.with_hi(generic_args.span.lo() + BytePos(1)), true) + ( + segment_ident_span.find_ancestor_inside(path_span).unwrap_or(path_span), + hir::AngleBrackets::Missing, + ) } else { - // Else use an empty span right after the opening bracket. - (generic_args.span.with_lo(generic_args.span.lo() + BytePos(1)).shrink_to_lo(), true) + // Brackets, e.g. `Path<>` or `Path`: use an empty span just after the `<`. + ( + generic_args.span.with_lo(generic_args.span.lo() + BytePos(1)).shrink_to_lo(), + if generic_args.is_empty() { + hir::AngleBrackets::Empty + } else { + hir::AngleBrackets::Full + }, + ) }; generic_args.args.insert_many( 0, (start..end).map(|id| { - let l = self.lower_lifetime_hidden_in_path( - id, - elided_lifetime_span, - with_angle_brackets, - ); + let l = + self.lower_lifetime_hidden_in_path(id, elided_lifetime_span, angle_brackets); GenericArg::Lifetime(l) }), ); diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 1feb3e9bf9b4..cbf4f2f5eb2b 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -82,6 +82,10 @@ struct AstValidator<'a> { /// Used to ban explicit safety on foreign items when the extern block is not marked as unsafe. extern_mod_safety: Option, + lint_node_id: NodeId, + + is_sdylib_interface: bool, + lint_buffer: &'a mut LintBuffer, } @@ -826,7 +830,7 @@ fn validate_generic_param_order(dcx: DiagCtxtHandle<'_>, generics: &[GenericPara impl<'a> Visitor<'a> for AstValidator<'a> { fn visit_attribute(&mut self, attr: &Attribute) { - validate_attr::check_attr(&self.sess.psess, attr); + validate_attr::check_attr(&self.sess.psess, attr, self.lint_node_id); } fn visit_ty(&mut self, ty: &'a Ty) { @@ -839,6 +843,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.has_proc_macro_decls = true; } + let previous_lint_node_id = mem::replace(&mut self.lint_node_id, item.id); + if let Some(ident) = item.kind.ident() && attr::contains_name(&item.attrs, sym::no_mangle) { @@ -948,7 +954,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.check_defaultness(item.span, *defaultness); let is_intrinsic = item.attrs.iter().any(|a| a.has_name(sym::rustc_intrinsic)); - if body.is_none() && !is_intrinsic { + if body.is_none() && !is_intrinsic && !self.is_sdylib_interface { self.dcx().emit_err(errors::FnWithoutBody { span: item.span, replace_span: self.ending_semi_or_hi(item.span), @@ -1128,6 +1134,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } _ => visit::walk_item(self, item), } + + self.lint_node_id = previous_lint_node_id; } fn visit_foreign_item(&mut self, fi: &'a ForeignItem) { @@ -1435,7 +1443,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { }); } AssocItemKind::Fn(box Fn { body, .. }) => { - if body.is_none() { + if body.is_none() && !self.is_sdylib_interface { self.dcx().emit_err(errors::AssocFnWithoutBody { span: item.span, replace_span: self.ending_semi_or_hi(item.span), @@ -1683,6 +1691,7 @@ pub fn check_crate( sess: &Session, features: &Features, krate: &Crate, + is_sdylib_interface: bool, lints: &mut LintBuffer, ) -> bool { let mut validator = AstValidator { @@ -1694,6 +1703,8 @@ pub fn check_crate( outer_impl_trait_span: None, disallow_tilde_const: Some(TildeConstReason::Item), extern_mod_safety: None, + lint_node_id: CRATE_NODE_ID, + is_sdylib_interface, lint_buffer: lints, }; visit::walk_crate(&mut validator, krate); diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index e312f15f05b0..915613a39137 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -514,6 +514,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) { gate_all!(contracts_internals, "contract internal machinery is for internal use only"); 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"); if !visitor.features.never_patterns() { if let Some(spans) = spans.get(&sym::never_patterns) { diff --git a/compiler/rustc_ast_pretty/src/pp.rs b/compiler/rustc_ast_pretty/src/pp.rs index 142c80b8e39e..8a0dbadf18cd 100644 --- a/compiler/rustc_ast_pretty/src/pp.rs +++ b/compiler/rustc_ast_pretty/src/pp.rs @@ -244,9 +244,6 @@ struct BufEntry { // forgotten will trigger a panic in `drop`. (Closing a box more than once // isn't possible because `BoxMarker` doesn't implement `Copy` or `Clone`.) // -// FIXME(nnethercote): the panic in `drop` is currently disabled because a few -// places fail to close their boxes. It can be enabled once they are fixed. -// // Note: it would be better to make open/close mismatching impossible and avoid // the need for this marker type altogether by having functions like // `with_ibox` that open a box, call a closure, and then close the box. That @@ -261,8 +258,7 @@ impl !Copy for BoxMarker {} impl Drop for BoxMarker { fn drop(&mut self) { - // FIXME(nnethercote): enable once the bad cases are fixed - //panic!("BoxMarker not ended with `Printer::end()`"); + panic!("BoxMarker not ended with `Printer::end()`"); } } diff --git a/compiler/rustc_ast_pretty/src/pprust/mod.rs b/compiler/rustc_ast_pretty/src/pprust/mod.rs index 551506f2aef8..a05e2bd6a5d7 100644 --- a/compiler/rustc_ast_pretty/src/pprust/mod.rs +++ b/compiler/rustc_ast_pretty/src/pprust/mod.rs @@ -7,7 +7,9 @@ use std::borrow::Cow; use rustc_ast as ast; use rustc_ast::token::{Token, TokenKind}; use rustc_ast::tokenstream::{TokenStream, TokenTree}; -pub use state::{AnnNode, Comments, PpAnn, PrintState, State, print_crate}; +pub use state::{ + AnnNode, Comments, PpAnn, PrintState, State, print_crate, print_crate_as_interface, +}; /// Print the token kind precisely, without converting `$crate` into its respective crate name. pub fn token_kind_to_string(tok: &TokenKind) -> Cow<'static, str> { diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index b5925fab7d95..0990c9b27eb0 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -221,6 +221,7 @@ pub struct State<'a> { pub s: pp::Printer, comments: Option>, ann: &'a (dyn PpAnn + 'a), + is_sdylib_interface: bool, } const INDENT_UNIT: isize = 4; @@ -236,9 +237,41 @@ pub fn print_crate<'a>( is_expanded: bool, edition: Edition, g: &AttrIdGenerator, +) -> String { + let mut s = State { + s: pp::Printer::new(), + comments: Some(Comments::new(sm, filename, input)), + ann, + is_sdylib_interface: false, + }; + + print_crate_inner(&mut s, krate, is_expanded, edition, g); + s.s.eof() +} + +pub fn print_crate_as_interface( + krate: &ast::Crate, + edition: Edition, + g: &AttrIdGenerator, ) -> String { let mut s = - State { s: pp::Printer::new(), comments: Some(Comments::new(sm, filename, input)), ann }; + State { s: pp::Printer::new(), comments: None, ann: &NoAnn, is_sdylib_interface: true }; + + print_crate_inner(&mut s, krate, false, edition, g); + s.s.eof() +} + +fn print_crate_inner<'a>( + s: &mut State<'a>, + krate: &ast::Crate, + is_expanded: bool, + edition: Edition, + g: &AttrIdGenerator, +) { + // We need to print shebang before anything else + // otherwise the resulting code will not compile + // and shebang will be useless. + s.maybe_print_shebang(); if is_expanded && !krate.attrs.iter().any(|attr| attr.has_name(sym::no_core)) { // We need to print `#![no_std]` (and its feature gate) so that @@ -277,8 +310,7 @@ pub fn print_crate<'a>( s.print_item(item); } s.print_remaining_comments(); - s.ann.post(&mut s, AnnNode::Crate(krate)); - s.s.eof() + s.ann.post(s, AnnNode::Crate(krate)); } /// Should two consecutive tokens be printed with a space between them? @@ -560,6 +592,20 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere self.word(st) } + fn maybe_print_shebang(&mut self) { + if let Some(cmnt) = self.peek_comment() { + // Comment is a shebang if it's: + // Isolated, starts with #! and doesn't continue with `[` + // See [rustc_lexer::strip_shebang] and [gather_comments] from pprust/state.rs for details + if cmnt.style == CommentStyle::Isolated + && cmnt.lines.first().map_or(false, |l| l.starts_with("#!")) + { + let cmnt = self.next_comment().unwrap(); + self.print_comment(cmnt); + } + } + } + fn print_inner_attributes(&mut self, attrs: &[ast::Attribute]) -> bool { self.print_either_attributes(attrs, ast::AttrStyle::Inner, false, true) } @@ -1092,7 +1138,7 @@ impl<'a> PrintState<'a> for State<'a> { impl<'a> State<'a> { pub fn new() -> State<'a> { - State { s: pp::Printer::new(), comments: None, ann: &NoAnn } + State { s: pp::Printer::new(), comments: None, ann: &NoAnn, is_sdylib_interface: false } } fn commasep_cmnt(&mut self, b: Breaks, elts: &[T], mut op: F, mut get_span: G) diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs index 38cadc77b777..c9a7e2aebd01 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs @@ -13,7 +13,7 @@ use rustc_ast::{ use crate::pp::Breaks::Inconsistent; use crate::pprust::state::fixup::FixupContext; -use crate::pprust::state::{AnnNode, BoxMarker, INDENT_UNIT, PrintState, State}; +use crate::pprust::state::{AnnNode, INDENT_UNIT, PrintState, State}; impl<'a> State<'a> { fn print_else(&mut self, els: Option<&ast::Expr>) { @@ -485,12 +485,12 @@ impl<'a> State<'a> { self.print_block_with_attrs(body, attrs, cb, ib); } ast::ExprKind::Loop(blk, opt_label, _) => { + let cb = self.cbox(0); + let ib = self.ibox(0); if let Some(label) = opt_label { self.print_ident(label.ident); self.word_space(":"); } - let cb = self.cbox(0); - let ib = self.ibox(0); self.word_nbsp("loop"); self.print_block_with_attrs(blk, attrs, cb, ib); } @@ -542,15 +542,6 @@ impl<'a> State<'a> { self.print_fn_params_and_ret(fn_decl, true); self.space(); self.print_expr(body, FixupContext::default()); - // FIXME(nnethercote): Bogus. Reduce visibility of `ended` once it's fixed. - let fake_ib = BoxMarker; - self.end(fake_ib); - - // A box will be closed by print_expr, but we didn't want an overall - // wrapper so we closed the corresponding opening. so create an - // empty box to satisfy the close. - // FIXME(nnethercote): Bogus. - let _ib = self.ibox(0); } ast::ExprKind::Block(blk, opt_label) => { if let Some(label) = opt_label { diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index 1e02ac8fd5d1..70cf2f2a4598 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -160,6 +160,10 @@ impl<'a> State<'a> { /// Pretty-prints an item. pub(crate) fn print_item(&mut self, item: &ast::Item) { + if self.is_sdylib_interface && item.span.is_dummy() { + // Do not print prelude for interface files. + return; + } self.hardbreak_if_not_bol(); self.maybe_print_comment(item.span.lo()); self.print_outer_attributes(&item.attrs); @@ -682,6 +686,13 @@ impl<'a> State<'a> { self.print_contract(contract); } if let Some((body, (cb, ib))) = body_cb_ib { + if self.is_sdylib_interface { + self.word(";"); + self.end(ib); // end inner head-block + self.end(cb); // end outer head-block + return; + } + self.nbsp(); self.print_block_with_attrs(body, attrs, cb, ib); } else { diff --git a/compiler/rustc_borrowck/src/constraints/mod.rs b/compiler/rustc_borrowck/src/constraints/mod.rs index a52269df6828..514bbfe359b1 100644 --- a/compiler/rustc_borrowck/src/constraints/mod.rs +++ b/compiler/rustc_borrowck/src/constraints/mod.rs @@ -7,7 +7,7 @@ use rustc_middle::ty::{RegionVid, TyCtxt, VarianceDiagInfo}; use rustc_span::Span; use tracing::{debug, instrument}; -use crate::region_infer::{ConstraintSccs, RegionDefinition, RegionTracker}; +use crate::region_infer::{AnnotatedSccs, ConstraintSccs, RegionDefinition, SccAnnotations}; use crate::type_check::Locations; use crate::universal_regions::UniversalRegions; @@ -61,12 +61,14 @@ impl<'tcx> OutlivesConstraintSet<'tcx> { &self, static_region: RegionVid, definitions: &IndexVec>, - ) -> ConstraintSccs { + ) -> AnnotatedSccs { let constraint_graph = self.graph(definitions.len()); let region_graph = &constraint_graph.region_graph(self, static_region); - ConstraintSccs::new_with_annotation(®ion_graph, |r| { - RegionTracker::new(r, &definitions[r]) - }) + let mut annotation_visitor = SccAnnotations::new(definitions); + ( + ConstraintSccs::new_with_annotation(®ion_graph, &mut annotation_visitor), + annotation_visitor.scc_to_annotation, + ) } /// This method handles Universe errors by rewriting the constraint @@ -79,12 +81,12 @@ impl<'tcx> OutlivesConstraintSet<'tcx> { /// eventually go away. /// /// For a more precise definition, see the documentation for - /// [`RegionTracker::has_incompatible_universes()`]. + /// [`crate::region_infer::RegionTracker`]. /// /// This edge case used to be handled during constraint propagation /// by iterating over the strongly connected components in the constraint /// graph while maintaining a set of bookkeeping mappings similar - /// to what is stored in `RegionTracker` and manually adding 'sttaic as + /// to what is stored in `RegionTracker` and manually adding 'static as /// needed. /// /// It was rewritten as part of the Polonius project with the goal of moving @@ -108,9 +110,9 @@ impl<'tcx> OutlivesConstraintSet<'tcx> { &mut self, universal_regions: &UniversalRegions<'tcx>, definitions: &IndexVec>, - ) -> ConstraintSccs { + ) -> AnnotatedSccs { let fr_static = universal_regions.fr_static; - let sccs = self.compute_sccs(fr_static, definitions); + let (sccs, annotations) = self.compute_sccs(fr_static, definitions); // Changed to `true` if we added any constraints to `self` and need to // recompute SCCs. @@ -124,7 +126,7 @@ impl<'tcx> OutlivesConstraintSet<'tcx> { continue; } - let annotation = sccs.annotation(scc); + let annotation = annotations[scc]; // If this SCC participates in a universe violation, // e.g. if it reaches a region with a universe smaller than @@ -154,7 +156,7 @@ impl<'tcx> OutlivesConstraintSet<'tcx> { self.compute_sccs(fr_static, definitions) } else { // If we didn't add any back-edges; no more work needs doing - sccs + (sccs, annotations) } } } diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 0f8acadb978c..3b7d31b1b13b 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -2954,12 +2954,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { } } - let name = if borrow_span.in_external_macro(self.infcx.tcx.sess.source_map()) { - // Don't name local variables in external macros. - "value".to_string() - } else { - format!("`{name}`") - }; + let name = format!("`{name}`"); let mut err = self.path_does_not_live_long_enough(borrow_span, &name); diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index f9f63ae92a84..5e3f3ffa2ea8 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -317,6 +317,14 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { opt: DescribePlaceOpt, ) -> Option { let local = place.local; + if self.body.local_decls[local] + .source_info + .span + .in_external_macro(self.infcx.tcx.sess.source_map()) + { + return None; + } + let mut autoderef_index = None; let mut buf = String::new(); let mut ok = self.append_local_to_string(local, &mut buf); diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 44af1b765399..3e075d420a3a 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -47,7 +47,7 @@ use rustc_mir_dataflow::impls::{ use rustc_mir_dataflow::move_paths::{ InitIndex, InitLocation, LookupResult, MoveData, MovePathIndex, }; -use rustc_mir_dataflow::{Analysis, EntryStates, Results, ResultsVisitor, visit_results}; +use rustc_mir_dataflow::{Analysis, Results, ResultsVisitor, visit_results}; use rustc_session::lint::builtin::{TAIL_EXPR_DROP_ORDER, UNUSED_MUT}; use rustc_span::{ErrorGuaranteed, Span, Symbol}; use smallvec::SmallVec; @@ -127,6 +127,14 @@ fn mir_borrowck( Ok(tcx.arena.alloc(opaque_types)) } else { let mut root_cx = BorrowCheckRootCtxt::new(tcx, def); + // We need to manually borrowck all nested bodies from the HIR as + // we do not generate MIR for dead code. Not doing so causes us to + // never check closures in dead code. + let nested_bodies = tcx.nested_bodies_within(def); + for def_id in nested_bodies { + root_cx.get_or_insert_nested(def_id); + } + let PropagatedBorrowCheckResults { closure_requirements, used_mut_upvars } = do_mir_borrowck(&mut root_cx, def, None).0; debug_assert!(closure_requirements.is_none()); @@ -461,11 +469,13 @@ fn do_mir_borrowck<'tcx>( // Compute and report region errors, if any. mbcx.report_region_errors(nll_errors); - let mut flow_results = get_flow_results(tcx, body, &move_data, &borrow_set, ®ioncx); + let (mut flow_analysis, flow_entry_states) = + get_flow_results(tcx, body, &move_data, &borrow_set, ®ioncx); visit_results( body, traversal::reverse_postorder(body).map(|(bb, _)| bb), - &mut flow_results, + &mut flow_analysis, + &flow_entry_states, &mut mbcx, ); @@ -525,7 +535,7 @@ fn get_flow_results<'a, 'tcx>( move_data: &'a MoveData<'tcx>, borrow_set: &'a BorrowSet<'tcx>, regioncx: &RegionInferenceContext<'tcx>, -) -> Results<'tcx, Borrowck<'a, 'tcx>> { +) -> (Borrowck<'a, 'tcx>, Results) { // We compute these three analyses individually, but them combine them into // a single results so that `mbcx` can visit them all together. let borrows = Borrows::new(tcx, body, regioncx, borrow_set).iterate_to_fixpoint( @@ -550,14 +560,14 @@ fn get_flow_results<'a, 'tcx>( ever_inits: ever_inits.analysis, }; - assert_eq!(borrows.entry_states.len(), uninits.entry_states.len()); - assert_eq!(borrows.entry_states.len(), ever_inits.entry_states.len()); - let entry_states: EntryStates<'_, Borrowck<'_, '_>> = - itertools::izip!(borrows.entry_states, uninits.entry_states, ever_inits.entry_states) + assert_eq!(borrows.results.len(), uninits.results.len()); + assert_eq!(borrows.results.len(), ever_inits.results.len()); + let results: Results<_> = + itertools::izip!(borrows.results, uninits.results, ever_inits.results) .map(|(borrows, uninits, ever_inits)| BorrowckDomain { borrows, uninits, ever_inits }) .collect(); - Results { analysis, entry_states } + (analysis, results) } pub(crate) struct BorrowckInferCtxt<'tcx> { @@ -705,7 +715,7 @@ struct MirBorrowckCtxt<'a, 'infcx, 'tcx> { impl<'a, 'tcx> ResultsVisitor<'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt<'a, '_, 'tcx> { fn visit_after_early_statement_effect( &mut self, - _results: &mut Results<'tcx, Borrowck<'a, 'tcx>>, + _analysis: &mut Borrowck<'a, 'tcx>, state: &BorrowckDomain, stmt: &Statement<'tcx>, location: Location, @@ -781,7 +791,7 @@ impl<'a, 'tcx> ResultsVisitor<'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt<'a, fn visit_after_early_terminator_effect( &mut self, - _results: &mut Results<'tcx, Borrowck<'a, 'tcx>>, + _analysis: &mut Borrowck<'a, 'tcx>, state: &BorrowckDomain, term: &Terminator<'tcx>, loc: Location, @@ -901,7 +911,7 @@ impl<'a, 'tcx> ResultsVisitor<'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt<'a, fn visit_after_primary_terminator_effect( &mut self, - _results: &mut Results<'tcx, Borrowck<'a, 'tcx>>, + _analysis: &mut Borrowck<'a, 'tcx>, state: &BorrowckDomain, term: &Terminator<'tcx>, loc: Location, diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index c256051c122f..b4ff3d66f3d5 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -47,12 +47,13 @@ mod reverse_sccs; pub(crate) mod values; -pub(crate) type ConstraintSccs = Sccs; +pub(crate) type ConstraintSccs = Sccs; +pub(crate) type AnnotatedSccs = (ConstraintSccs, IndexVec); /// An annotation for region graph SCCs that tracks -/// the values of its elements. +/// the values of its elements. This annotates a single SCC. #[derive(Copy, Debug, Clone)] -pub struct RegionTracker { +pub(crate) struct RegionTracker { /// The largest universe of a placeholder reached from this SCC. /// This includes placeholders within this SCC. max_placeholder_universe_reached: UniverseIndex, @@ -97,6 +98,32 @@ impl scc::Annotation for RegionTracker { } } +/// A Visitor for SCC annotation construction. +pub(crate) struct SccAnnotations<'d, 'tcx, A: scc::Annotation> { + pub(crate) scc_to_annotation: IndexVec, + definitions: &'d IndexVec>, +} + +impl<'d, 'tcx, A: scc::Annotation> SccAnnotations<'d, 'tcx, A> { + pub(crate) fn new(definitions: &'d IndexVec>) -> Self { + Self { scc_to_annotation: IndexVec::new(), definitions } + } +} + +impl scc::Annotations for SccAnnotations<'_, '_, RegionTracker> { + fn new(&self, element: RegionVid) -> RegionTracker { + RegionTracker::new(element, &self.definitions[element]) + } + + fn annotate_scc(&mut self, scc: ConstraintSccIndex, annotation: RegionTracker) { + let idx = self.scc_to_annotation.push(annotation); + assert!(idx == scc); + } + + type Ann = RegionTracker; + type SccIdx = ConstraintSccIndex; +} + impl RegionTracker { pub(crate) fn new(rvid: RegionVid, definition: &RegionDefinition<'_>) -> Self { let (representative_is_placeholder, representative_is_existential) = match definition.origin @@ -166,6 +193,8 @@ pub struct RegionInferenceContext<'tcx> { /// compute the values of each region. constraint_sccs: ConstraintSccs, + scc_annotations: IndexVec, + /// Reverse of the SCC constraint graph -- i.e., an edge `A -> B` exists if /// `B: A`. This is used to compute the universal regions that are required /// to outlive a given SCC. Computed lazily. @@ -446,7 +475,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { let definitions = create_definitions(infcx, &universal_regions); - let constraint_sccs = + let (constraint_sccs, scc_annotations) = outlives_constraints.add_outlives_static(&universal_regions, &definitions); let constraints = Frozen::freeze(outlives_constraints); let constraint_graph = Frozen::freeze(constraints.graph(definitions.len())); @@ -472,6 +501,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { constraints, constraint_graph, constraint_sccs, + scc_annotations, rev_scc_graph: None, member_constraints, member_constraints_applied: Vec::new(), @@ -798,7 +828,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { // If the member region lives in a higher universe, we currently choose // the most conservative option by leaving it unchanged. - if !self.constraint_sccs().annotation(scc).min_universe().is_root() { + if !self.scc_universe(scc).is_root() { return; } @@ -874,8 +904,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// in `scc_a`. Used during constraint propagation, and only once /// the value of `scc_b` has been computed. fn universe_compatible(&self, scc_b: ConstraintSccIndex, scc_a: ConstraintSccIndex) -> bool { - let a_annotation = self.constraint_sccs().annotation(scc_a); - let b_annotation = self.constraint_sccs().annotation(scc_b); + let a_annotation = self.scc_annotations[scc_a]; + let b_annotation = self.scc_annotations[scc_b]; let a_universe = a_annotation.min_universe(); // If scc_b's declared universe is a subset of @@ -991,7 +1021,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { "lower_bound = {:?} r_scc={:?} universe={:?}", lower_bound, r_scc, - self.constraint_sccs.annotation(r_scc).min_universe() + self.scc_universe(r_scc) ); // If the type test requires that `T: 'a` where `'a` is a // placeholder from another universe, that effectively requires @@ -1472,7 +1502,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// The minimum universe of any variable reachable from this /// SCC, inside or outside of it. fn scc_universe(&self, scc: ConstraintSccIndex) -> UniverseIndex { - self.constraint_sccs().annotation(scc).min_universe() + self.scc_annotations[scc].min_universe() } /// Checks the final value for the free region `fr` to see if it @@ -2216,7 +2246,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// they *must* be equal (though not having the same repr does not /// mean they are unequal). fn scc_representative(&self, scc: ConstraintSccIndex) -> RegionVid { - self.constraint_sccs.annotation(scc).representative + self.scc_annotations[scc].representative } pub(crate) fn liveness_constraints(&self) -> &LivenessValues { diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index 550c57338d30..25cbd579ea1c 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -267,13 +267,13 @@ impl<'tcx> InferCtxt<'tcx> { return Ty::new_error(self.tcx, e); } - if let Err(guar) = check_opaque_type_parameter_valid( + if let Err(err) = check_opaque_type_parameter_valid( self, opaque_type_key, instantiated_ty.span, DefiningScopeKind::MirBorrowck, ) { - return Ty::new_error(self.tcx, guar); + return Ty::new_error(self.tcx, err.report(self)); } let definition_ty = instantiated_ty diff --git a/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs b/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs index b2ed8a358279..8e04791461b2 100644 --- a/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs +++ b/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs @@ -7,6 +7,8 @@ use rustc_middle::ty::RegionVid; use crate::RegionInferenceContext; use crate::constraints::ConstraintSccIndex; +use crate::region_infer::ConstraintSccs; +use crate::universal_regions::UniversalRegions; pub(crate) struct ReverseSccGraph { graph: VecGraph, @@ -19,6 +21,29 @@ pub(crate) struct ReverseSccGraph { } impl ReverseSccGraph { + pub(super) fn compute( + constraint_sccs: &ConstraintSccs, + universal_regions: &UniversalRegions<'_>, + ) -> Self { + let graph = constraint_sccs.reverse(); + let mut paired_scc_regions = universal_regions + .universal_regions_iter() + .map(|region| (constraint_sccs.scc(region), region)) + .collect::>(); + paired_scc_regions.sort(); + let universal_regions = paired_scc_regions.iter().map(|&(_, region)| region).collect(); + + let mut scc_regions = FxIndexMap::default(); + let mut start = 0; + for chunk in paired_scc_regions.chunk_by(|&(scc1, _), &(scc2, _)| scc1 == scc2) { + let (scc, _) = chunk[0]; + + scc_regions.insert(scc, start..start + chunk.len()); + start += chunk.len(); + } + ReverseSccGraph { graph, scc_regions, universal_regions } + } + /// Find all universal regions that are required to outlive the given SCC. pub(super) fn upper_bounds(&self, scc0: ConstraintSccIndex) -> impl Iterator { let mut duplicates = FxIndexSet::default(); @@ -40,23 +65,7 @@ impl RegionInferenceContext<'_> { return; } - let graph = self.constraint_sccs.reverse(); - let mut paired_scc_regions = self - .universal_regions() - .universal_regions_iter() - .map(|region| (self.constraint_sccs.scc(region), region)) - .collect::>(); - paired_scc_regions.sort(); - let universal_regions = paired_scc_regions.iter().map(|&(_, region)| region).collect(); - - let mut scc_regions = FxIndexMap::default(); - let mut start = 0; - for chunk in paired_scc_regions.chunk_by(|&(scc1, _), &(scc2, _)| scc1 == scc2) { - let (scc, _) = chunk[0]; - scc_regions.insert(scc, start..start + chunk.len()); - start += chunk.len(); - } - - self.rev_scc_graph = Some(ReverseSccGraph { graph, scc_regions, universal_regions }); + self.rev_scc_graph = + Some(ReverseSccGraph::compute(&self.constraint_sccs, self.universal_regions())); } } diff --git a/compiler/rustc_borrowck/src/root_cx.rs b/compiler/rustc_borrowck/src/root_cx.rs index 13daa5c72214..66b526fa02a5 100644 --- a/compiler/rustc_borrowck/src/root_cx.rs +++ b/compiler/rustc_borrowck/src/root_cx.rs @@ -62,7 +62,10 @@ impl<'tcx> BorrowCheckRootCtxt<'tcx> { self.tainted_by_errors = Some(guar); } - fn get_or_insert_nested(&mut self, def_id: LocalDefId) -> &PropagatedBorrowCheckResults<'tcx> { + pub(super) fn get_or_insert_nested( + &mut self, + def_id: LocalDefId, + ) -> &PropagatedBorrowCheckResults<'tcx> { debug_assert_eq!( self.tcx.typeck_root_def_id(def_id.to_def_id()), self.root_def_id.to_def_id() diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs index 536a27763d29..92732aba29ba 100644 --- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs +++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs @@ -41,8 +41,8 @@ type NormalizedInputsAndOutput<'tcx> = Vec>; pub(crate) struct CreateResult<'tcx> { pub(crate) universal_region_relations: Frozen>, - pub(crate) region_bound_pairs: RegionBoundPairs<'tcx>, - pub(crate) known_type_outlives_obligations: Vec>, + pub(crate) region_bound_pairs: Frozen>, + pub(crate) known_type_outlives_obligations: Frozen>>, pub(crate) normalized_inputs_and_output: NormalizedInputsAndOutput<'tcx>, } @@ -333,8 +333,8 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { outlives: self.outlives.freeze(), inverse_outlives: self.inverse_outlives.freeze(), }), - known_type_outlives_obligations, - region_bound_pairs: self.region_bound_pairs, + known_type_outlives_obligations: Frozen::freeze(known_type_outlives_obligations), + region_bound_pairs: Frozen::freeze(self.region_bound_pairs), normalized_inputs_and_output, } } diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 99a544279b96..8c5122571209 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -151,8 +151,8 @@ pub(crate) fn type_check<'a, 'tcx>( body, promoted, user_type_annotations: &body.user_type_annotations, - region_bound_pairs, - known_type_outlives_obligations, + region_bound_pairs: ®ion_bound_pairs, + known_type_outlives_obligations: &known_type_outlives_obligations, reported_errors: Default::default(), universal_regions: &universal_region_relations.universal_regions, location_table, @@ -216,8 +216,8 @@ struct TypeChecker<'a, 'tcx> { /// User type annotations are shared between the main MIR and the MIR of /// all of the promoted items. user_type_annotations: &'a CanonicalUserTypeAnnotations<'tcx>, - region_bound_pairs: RegionBoundPairs<'tcx>, - known_type_outlives_obligations: Vec>, + region_bound_pairs: &'a RegionBoundPairs<'tcx>, + known_type_outlives_obligations: &'a [ty::PolyTypeOutlivesPredicate<'tcx>], reported_errors: FxIndexSet<(Ty<'tcx>, Span)>, universal_regions: &'a UniversalRegions<'tcx>, location_table: &'a PoloniusLocationTable, @@ -412,9 +412,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { constraint_conversion::ConstraintConversion::new( self.infcx, self.universal_regions, - &self.region_bound_pairs, + self.region_bound_pairs, self.infcx.param_env, - &self.known_type_outlives_obligations, + self.known_type_outlives_obligations, locations, locations.span(self.body), category, @@ -2506,9 +2506,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { constraint_conversion::ConstraintConversion::new( self.infcx, self.universal_regions, - &self.region_bound_pairs, + self.region_bound_pairs, self.infcx.param_env, - &self.known_type_outlives_obligations, + self.known_type_outlives_obligations, locations, self.body.span, // irrelevant; will be overridden. ConstraintCategory::Boring, // same as above. diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index 12654001a1e2..39f9d5f90051 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -1,3 +1,5 @@ +use std::ops::Range; + use parse::Position::ArgumentNamed; use rustc_ast::ptr::P; use rustc_ast::tokenstream::TokenStream; @@ -335,7 +337,7 @@ fn make_format_args( return ExpandResult::Ready(Err(guar)); } - let to_span = |inner_span: parse::InnerSpan| { + let to_span = |inner_span: Range| { is_source_literal.then(|| { fmt_span.from_inner(InnerSpan { start: inner_span.start, end: inner_span.end }) }) @@ -407,7 +409,7 @@ fn make_format_args( let mut placeholder_index = 0; for piece in &pieces { - match *piece { + match piece.clone() { parse::Piece::Lit(s) => { unfinished_literal.push_str(s); } @@ -417,7 +419,8 @@ fn make_format_args( unfinished_literal.clear(); } - let span = parser.arg_places.get(placeholder_index).and_then(|&s| to_span(s)); + let span = + parser.arg_places.get(placeholder_index).and_then(|s| to_span(s.clone())); placeholder_index += 1; let position_span = to_span(position_span); @@ -609,7 +612,7 @@ fn make_format_args( fn invalid_placeholder_type_error( ecx: &ExtCtxt<'_>, ty: &str, - ty_span: Option, + ty_span: Option>, fmt_span: Span, ) { let sp = ty_span.map(|sp| fmt_span.from_inner(InnerSpan::new(sp.start, sp.end))); diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs index d3f47ad72633..e866b8962551 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs @@ -1282,7 +1282,7 @@ fn codegen_regular_intrinsic_call<'tcx>( intrinsic.name, ); } - return Err(Instance::new(instance.def_id(), instance.args)); + return Err(Instance::new_raw(instance.def_id(), instance.args)); } } diff --git a/compiler/rustc_codegen_gcc/src/back/lto.rs b/compiler/rustc_codegen_gcc/src/back/lto.rs index e5221c7da319..faeb2643ecb8 100644 --- a/compiler/rustc_codegen_gcc/src/back/lto.rs +++ b/compiler/rustc_codegen_gcc/src/back/lto.rs @@ -44,7 +44,11 @@ use crate::{GccCodegenBackend, GccContext, SyncContext, to_gcc_opt_level}; pub fn crate_type_allows_lto(crate_type: CrateType) -> bool { match crate_type { - CrateType::Executable | CrateType::Dylib | CrateType::Staticlib | CrateType::Cdylib => true, + CrateType::Executable + | CrateType::Dylib + | CrateType::Staticlib + | CrateType::Cdylib + | CrateType::Sdylib => true, CrateType::Rlib | CrateType::ProcMacro => false, } } diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs index d22f4229e237..2ed5ec4381ed 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs @@ -399,7 +399,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc } // Fall back to default body - _ => return Err(Instance::new(instance.def_id(), instance.args)), + _ => return Err(Instance::new_raw(instance.def_id(), instance.args)), }; if !fn_abi.ret.is_ignore() { diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index 39b3a23e0b1b..cb329323f5d7 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -42,7 +42,8 @@ fn crate_type_allows_lto(crate_type: CrateType) -> bool { | CrateType::Dylib | CrateType::Staticlib | CrateType::Cdylib - | CrateType::ProcMacro => true, + | CrateType::ProcMacro + | CrateType::Sdylib => true, CrateType::Rlib => false, } } diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/unused.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/unused.rs index 68f60f169b5b..fe3a7a1580b5 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/unused.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen/unused.rs @@ -157,7 +157,7 @@ fn make_dummy_instance<'tcx>(tcx: TyCtxt<'tcx>, local_def_id: LocalDefId) -> ty: let def_id = local_def_id.to_def_id(); // Make a dummy instance that fills in all generics with placeholders. - ty::Instance::new( + ty::Instance::new_raw( def_id, ty::GenericArgs::for_item(tcx, def_id, |param, _| { if let ty::GenericParamDefKind::Lifetime = param.kind { diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs index 4ffe551df09b..8f0948b8183b 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs @@ -95,7 +95,11 @@ pub(crate) fn needs_gdb_debug_scripts_section(cx: &CodegenCx<'_, '_>) -> bool { // in the `.debug_gdb_scripts` section. For that reason, we make sure that the // section is only emitted for leaf crates. let embed_visualizers = cx.tcx.crate_types().iter().any(|&crate_type| match crate_type { - CrateType::Executable | CrateType::Dylib | CrateType::Cdylib | CrateType::Staticlib => { + CrateType::Executable + | CrateType::Dylib + | CrateType::Cdylib + | CrateType::Staticlib + | CrateType::Sdylib => { // These are crate types for which we will embed pretty printers since they // are treated as leaf crates. true diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index ffeab59b05c3..bfaad8f2f1ef 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -613,7 +613,7 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { _ => { debug!("unknown intrinsic '{}' -- falling back to default body", name); // Call the fallback body instead of generating the intrinsic code - return Err(ty::Instance::new(instance.def_id(), instance.args)); + return Err(ty::Instance::new_raw(instance.def_id(), instance.args)); } }; diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 6412a537a793..8f57f0983abb 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -19,6 +19,7 @@ use rustc_session::config::{PrintKind, PrintRequest}; use rustc_span::Symbol; use rustc_target::spec::{MergeFunctions, PanicStrategy, SmallDataThresholdSupport}; use rustc_target::target_features::{RUSTC_SPECIAL_FEATURES, RUSTC_SPECIFIC_FEATURES}; +use smallvec::{SmallVec, smallvec}; use crate::back::write::create_informational_target_machine; use crate::errors::{ @@ -180,27 +181,27 @@ impl<'a> TargetFeatureFoldStrength<'a> { pub(crate) struct LLVMFeature<'a> { llvm_feature_name: &'a str, - dependency: Option>, + dependencies: SmallVec<[TargetFeatureFoldStrength<'a>; 1]>, } impl<'a> LLVMFeature<'a> { fn new(llvm_feature_name: &'a str) -> Self { - Self { llvm_feature_name, dependency: None } + Self { llvm_feature_name, dependencies: SmallVec::new() } } - fn with_dependency( + fn with_dependencies( llvm_feature_name: &'a str, - dependency: TargetFeatureFoldStrength<'a>, + dependencies: SmallVec<[TargetFeatureFoldStrength<'a>; 1]>, ) -> Self { - Self { llvm_feature_name, dependency: Some(dependency) } + Self { llvm_feature_name, dependencies } } - fn contains(&self, feat: &str) -> bool { + fn contains(&'a self, feat: &str) -> bool { self.iter().any(|dep| dep == feat) } fn iter(&'a self) -> impl Iterator { - let dependencies = self.dependency.iter().map(|feat| feat.as_str()); + let dependencies = self.dependencies.iter().map(|feat| feat.as_str()); std::iter::once(self.llvm_feature_name).chain(dependencies) } } @@ -210,7 +211,7 @@ impl<'a> IntoIterator for LLVMFeature<'a> { type IntoIter = impl Iterator; fn into_iter(self) -> Self::IntoIter { - let dependencies = self.dependency.into_iter().map(|feat| feat.as_str()); + let dependencies = self.dependencies.into_iter().map(|feat| feat.as_str()); std::iter::once(self.llvm_feature_name).chain(dependencies) } } @@ -240,9 +241,9 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option Some(LLVMFeature::with_dependency( + ("x86", "sse4.2") => Some(LLVMFeature::with_dependencies( "sse4.2", - TargetFeatureFoldStrength::EnableOnly("crc32"), + smallvec![TargetFeatureFoldStrength::EnableOnly("crc32")], )), ("x86", "pclmulqdq") => Some(LLVMFeature::new("pclmul")), ("x86", "rdrand") => Some(LLVMFeature::new("rdrnd")), @@ -262,9 +263,10 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option Some(LLVMFeature::new("b16b16")), ("aarch64", "flagm2") => Some(LLVMFeature::new("altnzcv")), // Rust ties fp and neon together. - ("aarch64", "neon") => { - Some(LLVMFeature::with_dependency("neon", TargetFeatureFoldStrength::Both("fp-armv8"))) - } + ("aarch64", "neon") => Some(LLVMFeature::with_dependencies( + "neon", + smallvec![TargetFeatureFoldStrength::Both("fp-armv8")], + )), // In LLVM neon implicitly enables fp, but we manually enable // neon when a feature only implicitly enables fp ("aarch64", "fhm") => Some(LLVMFeature::new("fp16fml")), @@ -273,11 +275,18 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option None, // only existed in 18 ("arm", "fp16") => Some(LLVMFeature::new("fullfp16")), // Filter out features that are not supported by the current LLVM version + ("loongarch64", "div32" | "lam-bh" | "lamcas" | "ld-seq-sa" | "scq") + if get_version().0 < 20 => + { + None + } + // Filter out features that are not supported by the current LLVM version ("riscv32" | "riscv64", "zacas") if get_version().0 < 20 => None, // Enable the evex512 target feature if an avx512 target feature is enabled. - ("x86", s) if s.starts_with("avx512") => { - Some(LLVMFeature::with_dependency(s, TargetFeatureFoldStrength::EnableOnly("evex512"))) - } + ("x86", s) if s.starts_with("avx512") => Some(LLVMFeature::with_dependencies( + s, + smallvec![TargetFeatureFoldStrength::EnableOnly("evex512")], + )), // Support for `wide-arithmetic` will first land in LLVM 20 as part of // llvm/llvm-project#111598 ("wasm32" | "wasm64", "wide-arithmetic") if get_version() < (20, 0, 0) => None, @@ -295,6 +304,21 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option None, + ("x86", "avx10.1") => Some(LLVMFeature::new("avx10.1-512")), + ("x86", "avx10.2") if get_version().0 < 20 => None, + ("x86", "avx10.2") if get_version().0 >= 20 => Some(LLVMFeature::new("avx10.2-512")), + ("x86", "apxf") => Some(LLVMFeature::with_dependencies( + "egpr", + smallvec![ + TargetFeatureFoldStrength::Both("push2pop2"), + TargetFeatureFoldStrength::Both("ppx"), + TargetFeatureFoldStrength::Both("ndd"), + TargetFeatureFoldStrength::Both("ccmp"), + TargetFeatureFoldStrength::Both("cf"), + TargetFeatureFoldStrength::Both("nf"), + TargetFeatureFoldStrength::Both("zu"), + ], + )), (_, s) => Some(LLVMFeature::new(s)), } } @@ -844,7 +868,7 @@ pub(crate) fn global_llvm_features( "{}{}", enable_disable, llvm_feature.llvm_feature_name )) - .chain(llvm_feature.dependency.into_iter().filter_map( + .chain(llvm_feature.dependencies.into_iter().filter_map( move |feat| match (enable, feat) { (_, TargetFeatureFoldStrength::Both(f)) | (true, TargetFeatureFoldStrength::EnableOnly(f)) => { diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 323538969d73..159c17b0af75 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -1053,9 +1053,10 @@ fn link_natively( strip_with_external_utility(sess, stripcmd, out_filename, &["--strip-debug"]) } // Per the manpage, `-x` is the maximum safe strip level for dynamic libraries. (#93988) - (Strip::Symbols, CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro) => { - strip_with_external_utility(sess, stripcmd, out_filename, &["-x"]) - } + ( + Strip::Symbols, + CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro | CrateType::Sdylib, + ) => strip_with_external_utility(sess, stripcmd, out_filename, &["-x"]), (Strip::Symbols, _) => { strip_with_external_utility(sess, stripcmd, out_filename, &["--strip-all"]) } @@ -1243,8 +1244,10 @@ fn add_sanitizer_libraries( // which should be linked to both executables and dynamic libraries. // Everywhere else the runtimes are currently distributed as static // libraries which should be linked to executables only. - if matches!(crate_type, CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro) - && !(sess.target.is_like_darwin || sess.target.is_like_msvc) + if matches!( + crate_type, + CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro | CrateType::Sdylib + ) && !(sess.target.is_like_darwin || sess.target.is_like_msvc) { return; } @@ -1938,6 +1941,7 @@ fn add_late_link_args( codegen_results: &CodegenResults, ) { let any_dynamic_crate = crate_type == CrateType::Dylib + || crate_type == CrateType::Sdylib || codegen_results.crate_info.dependency_formats.iter().any(|(ty, list)| { *ty == crate_type && list.iter().any(|&linkage| linkage == Linkage::Dynamic) }); diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index a09eec5dd74b..8fc83908efbc 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -816,7 +816,9 @@ impl<'a> Linker for GccLinker<'a> { writeln!(f, "EXPORTS")?; for symbol in symbols { debug!(" _{symbol}"); - writeln!(f, " {symbol}")?; + // Quote the name in case it's reserved by linker in some way + // (this accounts for names with dots in particular). + writeln!(f, " \"{symbol}\"")?; } }; if let Err(error) = res { @@ -1815,7 +1817,7 @@ pub(crate) fn linked_symbols( crate_type: CrateType, ) -> Vec<(String, SymbolExportKind)> { match crate_type { - CrateType::Executable | CrateType::Cdylib | CrateType::Dylib => (), + CrateType::Executable | CrateType::Cdylib | CrateType::Dylib | CrateType::Sdylib => (), CrateType::Staticlib | CrateType::ProcMacro | CrateType::Rlib => { return Vec::new(); } diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs index ebcccf1b97d9..ec46c71b0e40 100644 --- a/compiler/rustc_codegen_ssa/src/back/metadata.rs +++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs @@ -270,45 +270,61 @@ pub(super) fn elf_os_abi(sess: &Session) -> u8 { pub(super) fn elf_e_flags(architecture: Architecture, sess: &Session) -> u32 { match architecture { - Architecture::Mips => { - let arch = match sess.target.options.cpu.as_ref() { - "mips1" => elf::EF_MIPS_ARCH_1, - "mips2" => elf::EF_MIPS_ARCH_2, + Architecture::Mips | Architecture::Mips64 | Architecture::Mips64_N32 => { + // "N32" indicates an "ILP32" data model on a 64-bit MIPS CPU + // like SPARC's "v8+", x86_64's "x32", or the watchOS "arm64_32". + let is_32bit = architecture == Architecture::Mips; + let mut e_flags = match sess.target.options.cpu.as_ref() { + "mips1" if is_32bit => elf::EF_MIPS_ARCH_1, + "mips2" if is_32bit => elf::EF_MIPS_ARCH_2, "mips3" => elf::EF_MIPS_ARCH_3, "mips4" => elf::EF_MIPS_ARCH_4, "mips5" => elf::EF_MIPS_ARCH_5, - s if s.contains("r6") => elf::EF_MIPS_ARCH_32R6, - _ => elf::EF_MIPS_ARCH_32R2, + "mips32r2" if is_32bit => elf::EF_MIPS_ARCH_32R2, + "mips32r6" if is_32bit => elf::EF_MIPS_ARCH_32R6, + "mips64r2" if !is_32bit => elf::EF_MIPS_ARCH_64R2, + "mips64r6" if !is_32bit => elf::EF_MIPS_ARCH_64R6, + s if s.starts_with("mips32") && !is_32bit => { + sess.dcx().fatal(format!("invalid CPU `{}` for 64-bit MIPS target", s)) + } + s if s.starts_with("mips64") && is_32bit => { + sess.dcx().fatal(format!("invalid CPU `{}` for 32-bit MIPS target", s)) + } + _ if is_32bit => elf::EF_MIPS_ARCH_32R2, + _ => elf::EF_MIPS_ARCH_64R2, }; - let mut e_flags = elf::EF_MIPS_CPIC | arch; - - // If the ABI is explicitly given, use it or default to O32. - match sess.target.options.llvm_abiname.to_lowercase().as_str() { - "n32" => e_flags |= elf::EF_MIPS_ABI2, - "o32" => e_flags |= elf::EF_MIPS_ABI_O32, - _ => e_flags |= elf::EF_MIPS_ABI_O32, + // If the ABI is explicitly given, use it, or default to O32 on 32-bit MIPS, + // which is the only "true" 32-bit option that LLVM supports. + match sess.target.options.llvm_abiname.as_ref() { + "o32" if is_32bit => e_flags |= elf::EF_MIPS_ABI_O32, + "n32" if !is_32bit => e_flags |= elf::EF_MIPS_ABI2, + "n64" if !is_32bit => {} + "" if is_32bit => e_flags |= elf::EF_MIPS_ABI_O32, + "" => sess.dcx().fatal("LLVM ABI must be specifed for 64-bit MIPS targets"), + s if is_32bit => { + sess.dcx().fatal(format!("invalid LLVM ABI `{}` for 32-bit MIPS target", s)) + } + s => sess.dcx().fatal(format!("invalid LLVM ABI `{}` for 64-bit MIPS target", s)), }; if sess.target.options.relocation_model != RelocModel::Static { - e_flags |= elf::EF_MIPS_PIC; + // PIC means position-independent code. CPIC means "calls PIC". + // CPIC was mutually exclusive with PIC according to + // the SVR4 MIPS ABI https://refspecs.linuxfoundation.org/elf/mipsabi.pdf + // and should have only appeared on static objects with dynamically calls. + // At some point someone (GCC?) decided to set CPIC even for PIC. + // Nowadays various things expect both set on the same object file + // and may even error if you mix CPIC and non-CPIC object files, + // despite that being the entire point of the CPIC ABI extension! + // As we are in Rome, we do as the Romans do. + e_flags |= elf::EF_MIPS_PIC | elf::EF_MIPS_CPIC; } if sess.target.options.cpu.contains("r6") { e_flags |= elf::EF_MIPS_NAN2008; } e_flags } - Architecture::Mips64 => { - // copied from `mips64el-linux-gnuabi64-gcc foo.c -c` - let e_flags = elf::EF_MIPS_CPIC - | elf::EF_MIPS_PIC - | if sess.target.options.cpu.contains("r6") { - elf::EF_MIPS_ARCH_64R6 | elf::EF_MIPS_NAN2008 - } else { - elf::EF_MIPS_ARCH_64R2 - }; - e_flags - } Architecture::Riscv32 | Architecture::Riscv64 => { // Source: https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/079772828bd10933d34121117a222b4cc0ee2200/riscv-elf.adoc let mut e_flags: u32 = 0x0; diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index 2bfab1f43bce..5f0a0cf922af 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -29,7 +29,7 @@ fn crate_export_threshold(crate_type: CrateType) -> SymbolExportLevel { CrateType::Executable | CrateType::Staticlib | CrateType::ProcMacro | CrateType::Cdylib => { SymbolExportLevel::C } - CrateType::Rlib | CrateType::Dylib => SymbolExportLevel::Rust, + CrateType::Rlib | CrateType::Dylib | CrateType::Sdylib => SymbolExportLevel::Rust, } } @@ -45,7 +45,7 @@ pub fn crates_export_threshold(crate_types: &[CrateType]) -> SymbolExportLevel { } fn reachable_non_generics_provider(tcx: TyCtxt<'_>, _: LocalCrate) -> DefIdMap { - if !tcx.sess.opts.output_types.should_codegen() { + if !tcx.sess.opts.output_types.should_codegen() && !tcx.is_sdylib_interface_build() { return Default::default(); } @@ -164,11 +164,11 @@ fn is_reachable_non_generic_provider_extern(tcx: TyCtxt<'_>, def_id: DefId) -> b tcx.reachable_non_generics(def_id.krate).contains_key(&def_id) } -fn exported_symbols_provider_local( - tcx: TyCtxt<'_>, +fn exported_symbols_provider_local<'tcx>( + tcx: TyCtxt<'tcx>, _: LocalCrate, -) -> &[(ExportedSymbol<'_>, SymbolExportInfo)] { - if !tcx.sess.opts.output_types.should_codegen() { +) -> &'tcx [(ExportedSymbol<'tcx>, SymbolExportInfo)] { + if !tcx.sess.opts.output_types.should_codegen() && !tcx.is_sdylib_interface_build() { return &[]; } @@ -321,6 +321,38 @@ fn exported_symbols_provider_local( let cgus = tcx.collect_and_partition_mono_items(()).codegen_units; + // Do not export symbols that cannot be instantiated by downstream crates. + let reachable_set = tcx.reachable_set(()); + let is_local_to_current_crate = |ty: Ty<'_>| { + let no_refs = ty.peel_refs(); + let root_def_id = match no_refs.kind() { + ty::Closure(closure, _) => *closure, + ty::FnDef(def_id, _) => *def_id, + ty::Coroutine(def_id, _) => *def_id, + ty::CoroutineClosure(def_id, _) => *def_id, + ty::CoroutineWitness(def_id, _) => *def_id, + _ => return false, + }; + let Some(root_def_id) = root_def_id.as_local() else { + return false; + }; + + let is_local = !reachable_set.contains(&root_def_id); + is_local + }; + + let is_instantiable_downstream = + |did: Option, generic_args: GenericArgsRef<'tcx>| { + generic_args + .types() + .chain(did.into_iter().map(move |did| tcx.type_of(did).skip_binder())) + .all(move |arg| { + arg.walk().all(|ty| { + ty.as_type().map_or(true, |ty| !is_local_to_current_crate(ty)) + }) + }) + }; + // The symbols created in this loop are sorted below it #[allow(rustc::potential_query_instability)] for (mono_item, data) in cgus.iter().flat_map(|cgu| cgu.items().iter()) { @@ -349,7 +381,12 @@ fn exported_symbols_provider_local( match *mono_item { MonoItem::Fn(Instance { def: InstanceKind::Item(def), args }) => { - if args.non_erasable_generics().next().is_some() { + let has_generics = args.non_erasable_generics().next().is_some(); + + let should_export = + has_generics && is_instantiable_downstream(Some(def), &args); + + if should_export { let symbol = ExportedSymbol::Generic(def, args); symbols.push(( symbol, @@ -364,14 +401,24 @@ fn exported_symbols_provider_local( MonoItem::Fn(Instance { def: InstanceKind::DropGlue(_, Some(ty)), args }) => { // A little sanity-check assert_eq!(args.non_erasable_generics().next(), Some(GenericArgKind::Type(ty))); - symbols.push(( - ExportedSymbol::DropGlue(ty), - SymbolExportInfo { - level: SymbolExportLevel::Rust, - kind: SymbolExportKind::Text, - used: false, - }, - )); + + // Drop glue did is always going to be non-local outside of libcore, thus we don't need to check it's locality (which includes invoking `type_of` query). + let should_export = match ty.kind() { + ty::Adt(_, args) => is_instantiable_downstream(None, args), + ty::Closure(_, args) => is_instantiable_downstream(None, args), + _ => true, + }; + + if should_export { + symbols.push(( + ExportedSymbol::DropGlue(ty), + SymbolExportInfo { + level: SymbolExportLevel::Rust, + kind: SymbolExportKind::Text, + used: false, + }, + )); + } } MonoItem::Fn(Instance { def: InstanceKind::AsyncDropGlueCtorShim(_, ty), @@ -565,7 +612,7 @@ pub(crate) fn symbol_name_for_instance_in_crate<'tcx>( ExportedSymbol::Generic(def_id, args) => { rustc_symbol_mangling::symbol_name_for_instance_in_crate( tcx, - Instance::new(def_id, args), + Instance::new_raw(def_id, args), instantiating_crate, ) } @@ -613,7 +660,7 @@ fn calling_convention_for_symbol<'tcx>( None } ExportedSymbol::NonGeneric(def_id) => Some(Instance::mono(tcx, def_id)), - ExportedSymbol::Generic(def_id, args) => Some(Instance::new(def_id, args)), + ExportedSymbol::Generic(def_id, args) => Some(Instance::new_raw(def_id, args)), // DropGlue always use the Rust calling convention and thus follow the target's default // symbol decoration scheme. ExportedSymbol::DropGlue(..) => None, diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index f5480da2808f..775ab9071e74 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -457,7 +457,13 @@ where rustc_hir::InlineAsmOperand::SymFn { expr } => { let ty = cx.tcx().typeck(item_id.owner_id).expr_ty(expr); let instance = match ty.kind() { - &ty::FnDef(def_id, args) => Instance::new(def_id, args), + &ty::FnDef(def_id, args) => Instance::expect_resolve( + cx.tcx(), + ty::TypingEnv::fully_monomorphized(), + def_id, + args, + expr.span, + ), _ => span_bug!(*op_sp, "asm sym is not a function"), }; @@ -1092,7 +1098,7 @@ impl CrateInfo { } let embed_visualizers = tcx.crate_types().iter().any(|&crate_type| match crate_type { - CrateType::Executable | CrateType::Dylib | CrateType::Cdylib => { + CrateType::Executable | CrateType::Dylib | CrateType::Cdylib | CrateType::Sdylib => { // These are crate types for which we invoke the linker and can embed // NatVis visualizers. true diff --git a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs index 0301ef437c0d..d2a687359e0b 100644 --- a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs +++ b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs @@ -95,7 +95,9 @@ fn inline_to_global_operand<'a, 'tcx, Cx: LayoutOf<'tcx, LayoutOfResult = TyAndL ); let instance = match mono_type.kind() { - &ty::FnDef(def_id, args) => Instance::new(def_id, args), + &ty::FnDef(def_id, args) => { + Instance::expect_resolve(cx.tcx(), cx.typing_env(), def_id, args, value.span) + } _ => bug!("asm sym is not a function"), }; diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index dd481e04abbd..f4defd2aa134 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -12,6 +12,27 @@ const_eval_already_reported = const_eval_assume_false = `assume` called with `false` +const_eval_bad_pointer_op = {$operation -> + [MemoryAccess] memory access failed + [InboundsPointerArithmetic] in-bounds pointer arithmetic failed + *[Dereferenceable] pointer not dereferenceable +} +const_eval_bad_pointer_op_attempting = {const_eval_bad_pointer_op}: {$operation -> + [MemoryAccess] attempting to access {$inbounds_size -> + [1] 1 byte + *[x] {$inbounds_size} bytes + } + [InboundsPointerArithmetic] attempting to offset pointer by {$inbounds_size -> + [1] 1 byte + *[x] {$inbounds_size} bytes + } + *[Dereferenceable] pointer must {$inbounds_size -> + [0] point to some allocation + [1] be dereferenceable for 1 byte + *[x] be dereferenceable for {$inbounds_size} bytes + } + } + const_eval_bounds_check_failed = indexing out of bounds: the len is {$len} but the index is {$index} const_eval_call_nonzero_intrinsic = @@ -39,9 +60,9 @@ const_eval_copy_nonoverlapping_overlapping = `copy_nonoverlapping` called on overlapping ranges const_eval_dangling_int_pointer = - {$bad_pointer_message}: {const_eval_expected_inbounds_pointer}, but got {$pointer} which is a dangling pointer (it has no provenance) + {const_eval_bad_pointer_op_attempting}, but got {$pointer} which is a dangling pointer (it has no provenance) const_eval_dangling_null_pointer = - {$bad_pointer_message}: {const_eval_expected_inbounds_pointer}, but got a null pointer + {const_eval_bad_pointer_op_attempting}, but got null pointer const_eval_dangling_ptr_in_final = encountered dangling pointer in final value of {const_eval_intern_kind} const_eval_dead_local = @@ -77,21 +98,6 @@ const_eval_error = {$error_kind -> const_eval_exact_div_has_remainder = exact_div: {$a} cannot be divided by {$b} without remainder -const_eval_expected_inbounds_pointer = - expected a pointer to {$inbounds_size_abs -> - [0] some allocation - *[x] {$inbounds_size_is_neg -> - [false] {$inbounds_size_abs -> - [1] 1 byte of memory - *[x] {$inbounds_size_abs} bytes of memory - } - *[true] the end of {$inbounds_size_abs -> - [1] 1 byte of memory - *[x] {$inbounds_size_abs} bytes of memory - } - } - } - const_eval_extern_static = cannot access extern static `{$did}` const_eval_extern_type_field = `extern type` field does not have a known offset @@ -111,7 +117,6 @@ const_eval_frame_note_inner = inside {$where_ -> const_eval_frame_note_last = the failure occurred here -const_eval_in_bounds_test = out-of-bounds pointer use const_eval_incompatible_calling_conventions = calling a function with calling convention {$callee_conv} using calling convention {$caller_conv} @@ -206,7 +211,6 @@ const_eval_long_running = const_eval_max_num_nodes_in_const = maximum number of nodes exceeded in constant {$global_const_id} -const_eval_memory_access_test = memory access failed const_eval_memory_exhausted = tried to allocate more memory than available to compiler @@ -287,8 +291,6 @@ const_eval_offset_from_out_of_bounds = `{$name}` called on two different pointers where the memory range between them is not in-bounds of an allocation const_eval_offset_from_overflow = `{$name}` called when first pointer is too far ahead of second -const_eval_offset_from_test = - out-of-bounds `offset_from` origin const_eval_offset_from_underflow = `{$name}` called when first pointer is too far before second const_eval_offset_from_unsigned_overflow = @@ -312,27 +314,25 @@ const_eval_partial_pointer_overwrite = unable to overwrite parts of a pointer in memory at {$ptr} const_eval_pointer_arithmetic_overflow = overflowing pointer arithmetic: the total offset in bytes does not fit in an `isize` -const_eval_pointer_arithmetic_test = out-of-bounds pointer arithmetic + const_eval_pointer_out_of_bounds = - {$bad_pointer_message}: {const_eval_expected_inbounds_pointer}, but got {$pointer} {$ptr_offset_is_neg -> - [true] which points to before the beginning of the allocation - *[false] {$inbounds_size_is_neg -> - [true] {$ptr_offset_abs -> - [0] which is at the beginning of the allocation - *[other] which does not have enough space to the beginning of the allocation - } - *[false] {$alloc_size_minus_ptr_offset -> - [0] which is at or beyond the end of the allocation of size {$alloc_size -> + {const_eval_bad_pointer_op_attempting}, but got {$pointer} which {$inbounds_size_is_neg -> + [false] {$alloc_size_minus_ptr_offset -> + [0] is at or beyond the end of the allocation of size {$alloc_size -> [1] 1 byte *[x] {$alloc_size} bytes } - [1] which is only 1 byte from the end of the allocation - *[x] which is only {$alloc_size_minus_ptr_offset} bytes from the end of the allocation + [1] is only 1 byte from the end of the allocation + *[x] is only {$alloc_size_minus_ptr_offset} bytes from the end of the allocation + } + *[true] {$ptr_offset_abs -> + [0] is at the beginning of the allocation + *[other] is only {$ptr_offset_abs} bytes from the beginning of the allocation } - } } + const_eval_pointer_use_after_free = - {$bad_pointer_message}: {$alloc_id} has been freed, so this pointer is dangling + {const_eval_bad_pointer_op}: {$alloc_id} has been freed, so this pointer is dangling const_eval_ptr_as_bytes_1 = this code performed an operation that depends on the underlying bytes representing a pointer const_eval_ptr_as_bytes_2 = diff --git a/compiler/rustc_const_eval/src/check_consts/ops.rs b/compiler/rustc_const_eval/src/check_consts/ops.rs index 7756e51c4c5f..1e5b98675c4f 100644 --- a/compiler/rustc_const_eval/src/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/check_consts/ops.rs @@ -352,7 +352,7 @@ fn build_error_for_const_call<'tcx>( ); err } - _ if tcx.opt_parent(callee) == tcx.get_diagnostic_item(sym::ArgumentMethods) => { + _ if tcx.opt_parent(callee) == tcx.get_diagnostic_item(sym::FmtArgumentsNew) => { ccx.dcx().create_err(errors::NonConstFmtMacroCall { span, kind: ccx.const_kind(), diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index 6472aaa57581..826ea0e58ecc 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -5,15 +5,14 @@ use either::Either; use rustc_abi::WrappingRange; use rustc_errors::codes::*; use rustc_errors::{ - Diag, DiagArgValue, DiagCtxtHandle, DiagMessage, Diagnostic, EmissionGuarantee, Level, - MultiSpan, Subdiagnostic, + Diag, DiagArgValue, DiagMessage, Diagnostic, EmissionGuarantee, Level, MultiSpan, Subdiagnostic, }; use rustc_hir::ConstContext; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_middle::mir::interpret::{ - CheckInAllocMsg, CtfeProvenance, ExpectedKind, InterpErrorKind, InvalidMetaKind, - InvalidProgramInfo, Misalignment, Pointer, PointerKind, ResourceExhaustionInfo, - UndefinedBehaviorInfo, UnsupportedOpInfo, ValidationErrorInfo, + CtfeProvenance, ExpectedKind, InterpErrorKind, InvalidMetaKind, InvalidProgramInfo, + Misalignment, Pointer, PointerKind, ResourceExhaustionInfo, UndefinedBehaviorInfo, + UnsupportedOpInfo, ValidationErrorInfo, }; use rustc_middle::ty::{self, Mutability, Ty}; use rustc_span::{Span, Symbol}; @@ -498,19 +497,6 @@ pub trait ReportErrorExt { } } -fn bad_pointer_message(msg: CheckInAllocMsg, dcx: DiagCtxtHandle<'_>) -> String { - use crate::fluent_generated::*; - - let msg = match msg { - CheckInAllocMsg::MemoryAccessTest => const_eval_memory_access_test, - CheckInAllocMsg::PointerArithmeticTest => const_eval_pointer_arithmetic_test, - CheckInAllocMsg::OffsetFromTest => const_eval_offset_from_test, - CheckInAllocMsg::InboundsTest => const_eval_in_bounds_test, - }; - - dcx.eagerly_translate_to_string(msg, [].into_iter()) -} - impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> { fn diagnostic_message(&self) -> DiagMessage { use UndefinedBehaviorInfo::*; @@ -564,7 +550,6 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> { fn add_args(self, diag: &mut Diag<'_, G>) { use UndefinedBehaviorInfo::*; - let dcx = diag.dcx; match self { Ub(_) => {} Custom(custom) => { @@ -612,12 +597,10 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> { diag.arg("vtable_dyn_type", vtable_dyn_type.to_string()); } PointerUseAfterFree(alloc_id, msg) => { - diag.arg("alloc_id", alloc_id) - .arg("bad_pointer_message", bad_pointer_message(msg, dcx)); + diag.arg("alloc_id", alloc_id).arg("operation", format!("{:?}", msg)); } PointerOutOfBounds { alloc_id, alloc_size, ptr_offset, inbounds_size, msg } => { diag.arg("alloc_size", alloc_size.bytes()); - diag.arg("bad_pointer_message", bad_pointer_message(msg, dcx)); diag.arg("pointer", { let mut out = format!("{:?}", alloc_id); if ptr_offset > 0 { @@ -627,14 +610,17 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> { } out }); + diag.arg("inbounds_size", inbounds_size); diag.arg("inbounds_size_is_neg", inbounds_size < 0); diag.arg("inbounds_size_abs", inbounds_size.unsigned_abs()); + diag.arg("ptr_offset", ptr_offset); diag.arg("ptr_offset_is_neg", ptr_offset < 0); diag.arg("ptr_offset_abs", ptr_offset.unsigned_abs()); diag.arg( "alloc_size_minus_ptr_offset", alloc_size.bytes().saturating_sub(ptr_offset as u64), ); + diag.arg("operation", format!("{:?}", msg)); } DanglingIntPointer { addr, inbounds_size, msg } => { if addr != 0 { @@ -644,9 +630,10 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> { ); } + diag.arg("inbounds_size", inbounds_size); diag.arg("inbounds_size_is_neg", inbounds_size < 0); diag.arg("inbounds_size_abs", inbounds_size.unsigned_abs()); - diag.arg("bad_pointer_message", bad_pointer_message(msg, dcx)); + diag.arg("operation", format!("{:?}", msg)); } AlignmentCheckFailed(Misalignment { required, has }, msg) => { diag.arg("required", required.bytes()); diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs index 8f0cb197c445..1dd96297d1fd 100644 --- a/compiler/rustc_const_eval/src/interpret/intern.rs +++ b/compiler/rustc_const_eval/src/interpret/intern.rs @@ -17,13 +17,13 @@ use hir::def::DefKind; use rustc_ast::Mutability; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_hir as hir; +use rustc_hir::definitions::{DefPathData, DisambiguatorState}; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; use rustc_middle::mir::interpret::{ConstAllocation, CtfeProvenance, InterpResult}; use rustc_middle::query::TyCtxtAt; use rustc_middle::span_bug; use rustc_middle::ty::layout::TyAndLayout; use rustc_span::def_id::LocalDefId; -use rustc_span::sym; use tracing::{instrument, trace}; use super::{ @@ -66,6 +66,7 @@ fn intern_shallow<'tcx, T, M: CompileTimeMachine<'tcx, T>>( ecx: &mut InterpCx<'tcx, M>, alloc_id: AllocId, mutability: Mutability, + disambiguator: Option<&mut DisambiguatorState>, ) -> Result + 'tcx, ()> { trace!("intern_shallow {:?}", alloc_id); // remove allocation @@ -88,7 +89,13 @@ fn intern_shallow<'tcx, T, M: CompileTimeMachine<'tcx, T>>( // link the alloc id to the actual allocation let alloc = ecx.tcx.mk_const_alloc(alloc); if let Some(static_id) = ecx.machine.static_def_id() { - intern_as_new_static(ecx.tcx, static_id, alloc_id, alloc); + intern_as_new_static( + ecx.tcx, + static_id, + alloc_id, + alloc, + disambiguator.expect("disambiguator needed"), + ); } else { ecx.tcx.set_alloc_id_memory(alloc_id, alloc); } @@ -102,11 +109,18 @@ fn intern_as_new_static<'tcx>( static_id: LocalDefId, alloc_id: AllocId, alloc: ConstAllocation<'tcx>, + disambiguator: &mut DisambiguatorState, ) { + // `intern_const_alloc_recursive` is called once per static and it contains the `DisambiguatorState`. + // The `::{{nested}}` path is thus unique to `intern_const_alloc_recursive` and the + // `DisambiguatorState` ensures the generated path is unique for this call as we generate + // `::{{nested#n}}` where `n` is the `n`th `intern_as_new_static` call. let feed = tcx.create_def( static_id, - Some(sym::nested), + None, DefKind::Static { safety: hir::Safety::Safe, mutability: alloc.0.mutability, nested: true }, + Some(DefPathData::NestedStatic), + disambiguator, ); tcx.set_nested_alloc_id_static(alloc_id, feed.def_id()); @@ -154,6 +168,8 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx, const_eval intern_kind: InternKind, ret: &MPlaceTy<'tcx>, ) -> Result<(), InternResult> { + let mut disambiguator = DisambiguatorState::new(); + // We are interning recursively, and for mutability we are distinguishing the "root" allocation // that we are starting in, and all other allocations that we are encountering recursively. let (base_mutability, inner_mutability, is_static) = match intern_kind { @@ -197,7 +213,9 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx, const_eval alloc.1.mutability = base_mutability; alloc.1.provenance().ptrs().iter().map(|&(_, prov)| prov).collect() } else { - intern_shallow(ecx, base_alloc_id, base_mutability).unwrap().collect() + intern_shallow(ecx, base_alloc_id, base_mutability, Some(&mut disambiguator)) + .unwrap() + .collect() }; // We need to distinguish "has just been interned" from "was already in `tcx`", // so we track this in a separate set. @@ -291,7 +309,7 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx, const_eval // okay with losing some potential for immutability here. This can anyway only affect // `static mut`. just_interned.insert(alloc_id); - match intern_shallow(ecx, alloc_id, inner_mutability) { + match intern_shallow(ecx, alloc_id, inner_mutability, Some(&mut disambiguator)) { Ok(nested) => todo.extend(nested), Err(()) => { ecx.tcx.dcx().delayed_bug("found dangling pointer during const interning"); @@ -313,8 +331,9 @@ pub fn intern_const_alloc_for_constprop<'tcx, T, M: CompileTimeMachine<'tcx, T>> return interp_ok(()); } // Move allocation to `tcx`. - if let Some(_) = - (intern_shallow(ecx, alloc_id, Mutability::Not).map_err(|()| err_ub!(DeadLocal))?).next() + if let Some(_) = intern_shallow(ecx, alloc_id, Mutability::Not, None) + .map_err(|()| err_ub!(DeadLocal))? + .next() { // We are not doing recursive interning, so we don't currently support provenance. // (If this assertion ever triggers, we should just implement a @@ -340,7 +359,7 @@ impl<'tcx> InterpCx<'tcx, DummyMachine> { let dest = self.allocate(layout, MemoryKind::Stack)?; f(self, &dest.clone().into())?; let alloc_id = dest.ptr().provenance.unwrap().alloc_id(); // this was just allocated, it must have provenance - for prov in intern_shallow(self, alloc_id, Mutability::Not).unwrap() { + for prov in intern_shallow(self, alloc_id, Mutability::Not, None).unwrap() { // We are not doing recursive interning, so we don't currently support provenance. // (If this assertion ever triggers, we should just implement a // proper recursive interning loop -- or just call `intern_const_alloc_recursive`. diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index d67b547ba1a4..04a8ed1e0f1e 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -348,7 +348,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // Check that the memory between them is dereferenceable at all, starting from the // origin pointer: `dist` is `a - b`, so it is based on `b`. - self.check_ptr_access_signed(b, dist, CheckInAllocMsg::OffsetFromTest) + self.check_ptr_access_signed(b, dist, CheckInAllocMsg::Dereferenceable) .map_err_kind(|_| { // This could mean they point to different allocations, or they point to the same allocation // but not the entire range between the pointers is in-bounds. @@ -372,7 +372,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { self.check_ptr_access_signed( a, dist.checked_neg().unwrap(), // i64::MIN is impossible as no allocation can be that large - CheckInAllocMsg::OffsetFromTest, + CheckInAllocMsg::Dereferenceable, ) .map_err_kind(|_| { // Make the error more specific. @@ -651,7 +651,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { offset_bytes: i64, ) -> InterpResult<'tcx, Pointer>> { // The offset must be in bounds starting from `ptr`. - self.check_ptr_access_signed(ptr, offset_bytes, CheckInAllocMsg::PointerArithmeticTest)?; + self.check_ptr_access_signed( + ptr, + offset_bytes, + CheckInAllocMsg::InboundsPointerArithmetic, + )?; // This also implies that there is no overflow, so we are done. interp_ok(ptr.wrapping_signed_offset(offset_bytes, self)) } diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index 9d8130661b04..43bf48a9b961 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -351,7 +351,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { kind = "static_mem" ) } - None => err_ub!(PointerUseAfterFree(alloc_id, CheckInAllocMsg::MemoryAccessTest)), + None => err_ub!(PointerUseAfterFree(alloc_id, CheckInAllocMsg::MemoryAccess)), }) .into(); }; @@ -414,10 +414,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { self, ptr, size, - CheckInAllocMsg::MemoryAccessTest, + CheckInAllocMsg::MemoryAccess, |this, alloc_id, offset, prov| { - let (size, align) = this - .get_live_alloc_size_and_align(alloc_id, CheckInAllocMsg::MemoryAccessTest)?; + let (size, align) = + this.get_live_alloc_size_and_align(alloc_id, CheckInAllocMsg::MemoryAccess)?; interp_ok((size, align, (alloc_id, offset, prov))) }, ) @@ -613,7 +613,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } Some(GlobalAlloc::Function { .. }) => throw_ub!(DerefFunctionPointer(id)), Some(GlobalAlloc::VTable(..)) => throw_ub!(DerefVTablePointer(id)), - None => throw_ub!(PointerUseAfterFree(id, CheckInAllocMsg::MemoryAccessTest)), + None => throw_ub!(PointerUseAfterFree(id, CheckInAllocMsg::MemoryAccess)), Some(GlobalAlloc::Static(def_id)) => { assert!(self.tcx.is_static(def_id)); // Thread-local statics do not have a constant address. They *must* be accessed via @@ -707,7 +707,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { self, ptr, size_i64, - CheckInAllocMsg::MemoryAccessTest, + CheckInAllocMsg::MemoryAccess, |this, alloc_id, offset, prov| { let alloc = this.get_alloc_raw(alloc_id)?; interp_ok((alloc.size(), alloc.align, (alloc_id, offset, prov, alloc))) @@ -809,7 +809,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { self, ptr, size_i64, - CheckInAllocMsg::MemoryAccessTest, + CheckInAllocMsg::MemoryAccess, |this, alloc_id, offset, prov| { let (alloc, machine) = this.get_alloc_raw_mut(alloc_id)?; interp_ok((alloc.size(), alloc.align, (alloc_id, offset, prov, alloc, machine))) @@ -1615,7 +1615,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { err_ub!(DanglingIntPointer { addr: offset, inbounds_size: size, - msg: CheckInAllocMsg::InboundsTest + msg: CheckInAllocMsg::Dereferenceable }) }) .into() diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index c86af5a9a4b1..8f39afa642ae 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -510,7 +510,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { self.ecx.check_ptr_access( place.ptr(), size, - CheckInAllocMsg::InboundsTest, // will anyway be replaced by validity message + CheckInAllocMsg::Dereferenceable, // will anyway be replaced by validity message ), self.path, Ub(DanglingIntPointer { addr: 0, .. }) => NullPtr { ptr_kind }, diff --git a/compiler/rustc_data_structures/src/graph/implementation/mod.rs b/compiler/rustc_data_structures/src/graph/linked_graph/mod.rs similarity index 88% rename from compiler/rustc_data_structures/src/graph/implementation/mod.rs rename to compiler/rustc_data_structures/src/graph/linked_graph/mod.rs index a80365938b96..ecb0095626b4 100644 --- a/compiler/rustc_data_structures/src/graph/implementation/mod.rs +++ b/compiler/rustc_data_structures/src/graph/linked_graph/mod.rs @@ -1,4 +1,4 @@ -//! A graph module for use in dataflow, region resolution, and elsewhere. +//! See [`LinkedGraph`]. //! //! # Interface details //! @@ -28,7 +28,23 @@ use tracing::debug; #[cfg(test)] mod tests; -pub struct Graph { +/// A concrete graph implementation that supports: +/// - Nodes and/or edges labelled with custom data types (`N` and `E` respectively). +/// - Incremental addition of new nodes/edges (but not removal). +/// - Flat storage of node/edge data in a pair of vectors. +/// - Iteration over any node's out-edges or in-edges, via linked lists +/// threaded through the node/edge data. +/// +/// # Caution +/// This is an older graph implementation that is still used by some pieces +/// of diagnostic/debugging code. New code that needs a graph data structure +/// should consider using `VecGraph` instead, or implementing its own +/// special-purpose graph with the specific features needed. +/// +/// This graph implementation predates the later [graph traits](crate::graph), +/// and does not implement those traits, so it has its own implementations of a +/// few basic graph algorithms. +pub struct LinkedGraph { nodes: Vec>, edges: Vec>, } @@ -71,13 +87,13 @@ impl NodeIndex { } } -impl Graph { - pub fn new() -> Graph { - Graph { nodes: Vec::new(), edges: Vec::new() } +impl LinkedGraph { + pub fn new() -> Self { + Self { nodes: Vec::new(), edges: Vec::new() } } - pub fn with_capacity(nodes: usize, edges: usize) -> Graph { - Graph { nodes: Vec::with_capacity(nodes), edges: Vec::with_capacity(edges) } + pub fn with_capacity(nodes: usize, edges: usize) -> Self { + Self { nodes: Vec::with_capacity(nodes), edges: Vec::with_capacity(edges) } } // # Simple accessors @@ -249,7 +265,7 @@ impl Graph { // # Iterators pub struct AdjacentEdges<'g, N, E> { - graph: &'g Graph, + graph: &'g LinkedGraph, direction: Direction, next: EdgeIndex, } @@ -285,7 +301,7 @@ impl<'g, N: Debug, E: Debug> Iterator for AdjacentEdges<'g, N, E> { } pub struct DepthFirstTraversal<'g, N, E> { - graph: &'g Graph, + graph: &'g LinkedGraph, stack: Vec, visited: DenseBitSet, direction: Direction, @@ -293,7 +309,7 @@ pub struct DepthFirstTraversal<'g, N, E> { impl<'g, N: Debug, E: Debug> DepthFirstTraversal<'g, N, E> { pub fn with_start_node( - graph: &'g Graph, + graph: &'g LinkedGraph, start_node: NodeIndex, direction: Direction, ) -> Self { diff --git a/compiler/rustc_data_structures/src/graph/implementation/tests.rs b/compiler/rustc_data_structures/src/graph/linked_graph/tests.rs similarity index 95% rename from compiler/rustc_data_structures/src/graph/implementation/tests.rs rename to compiler/rustc_data_structures/src/graph/linked_graph/tests.rs index 32a6d9ec881a..357aa81a57ca 100644 --- a/compiler/rustc_data_structures/src/graph/implementation/tests.rs +++ b/compiler/rustc_data_structures/src/graph/linked_graph/tests.rs @@ -1,11 +1,11 @@ use tracing::debug; -use crate::graph::implementation::*; +use super::{Debug, LinkedGraph, NodeIndex}; -type TestGraph = Graph<&'static str, &'static str>; +type TestGraph = LinkedGraph<&'static str, &'static str>; fn create_graph() -> TestGraph { - let mut graph = Graph::new(); + let mut graph = LinkedGraph::new(); // Create a simple graph // @@ -56,7 +56,7 @@ fn each_edge() { } fn test_adjacent_edges( - graph: &Graph, + graph: &LinkedGraph, start_index: NodeIndex, start_data: N, expected_incoming: &[(E, N)], diff --git a/compiler/rustc_data_structures/src/graph/mod.rs b/compiler/rustc_data_structures/src/graph/mod.rs index 4a1e5db6768d..20416b472b21 100644 --- a/compiler/rustc_data_structures/src/graph/mod.rs +++ b/compiler/rustc_data_structures/src/graph/mod.rs @@ -1,8 +1,8 @@ use rustc_index::Idx; pub mod dominators; -pub mod implementation; pub mod iterate; +pub mod linked_graph; mod reference; pub mod reversed; pub mod scc; diff --git a/compiler/rustc_data_structures/src/graph/scc/mod.rs b/compiler/rustc_data_structures/src/graph/scc/mod.rs index e7c4ea3daae4..518817ea0f53 100644 --- a/compiler/rustc_data_structures/src/graph/scc/mod.rs +++ b/compiler/rustc_data_structures/src/graph/scc/mod.rs @@ -10,10 +10,11 @@ use std::assert_matches::debug_assert_matches; use std::fmt::Debug; +use std::marker::PhantomData; use std::ops::Range; use rustc_index::{Idx, IndexSlice, IndexVec}; -use tracing::{debug, instrument}; +use tracing::{debug, instrument, trace}; use crate::fx::FxHashSet; use crate::graph::vec_graph::VecGraph; @@ -48,6 +49,25 @@ pub trait Annotation: Debug + Copy { } } +/// An accumulator for annotations. +pub trait Annotations { + type Ann: Annotation; + type SccIdx: Idx + Ord; + + fn new(&self, element: N) -> Self::Ann; + fn annotate_scc(&mut self, scc: Self::SccIdx, annotation: Self::Ann); +} + +/// The nil annotation accumulator, which does nothing. +struct NoAnnotations(PhantomData); + +impl Annotations for NoAnnotations { + type SccIdx = S; + type Ann = (); + fn new(&self, _element: N) {} + fn annotate_scc(&mut self, _scc: S, _annotation: ()) {} +} + /// The empty annotation, which does nothing. impl Annotation for () { fn merge_reached(self, _other: Self) -> Self { @@ -62,23 +82,20 @@ impl Annotation for () { /// the index type for the graph nodes and `S` is the index type for /// the SCCs. We can map from each node to the SCC that it /// participates in, and we also have the successors of each SCC. -pub struct Sccs { +pub struct Sccs { /// For each node, what is the SCC index of the SCC to which it /// belongs. scc_indices: IndexVec, /// Data about all the SCCs. - scc_data: SccData, + scc_data: SccData, } /// Information about an invidividual SCC node. -struct SccDetails { +struct SccDetails { /// For this SCC, the range of `all_successors` where its /// successors can be found. range: Range, - - /// User-specified metadata about the SCC. - annotation: A, } // The name of this struct should discourage you from making it public and leaking @@ -87,10 +104,10 @@ struct SccDetails { // is difficult when it's publicly inspectable. // // Obey the law of Demeter! -struct SccData { +struct SccData { /// Maps SCC indices to their metadata, including /// offsets into `all_successors`. - scc_details: IndexVec>, + scc_details: IndexVec, /// Contains the successors for all the Sccs, concatenated. The /// range of indices corresponding to a given SCC is found in its @@ -98,24 +115,18 @@ struct SccData { all_successors: Vec, } -impl Sccs { +impl Sccs { /// Compute SCCs without annotations. pub fn new(graph: &impl Successors) -> Self { - Self::new_with_annotation(graph, |_| ()) + Self::new_with_annotation(graph, &mut NoAnnotations(PhantomData::)) } -} -impl Sccs { /// Compute SCCs and annotate them with a user-supplied annotation - pub fn new_with_annotation A>( + pub fn new_with_annotation>( graph: &impl Successors, - to_annotation: F, + annotations: &mut A, ) -> Self { - SccsConstruction::construct(graph, to_annotation) - } - - pub fn annotation(&self, scc: S) -> A { - self.scc_data.annotation(scc) + SccsConstruction::construct(graph, annotations) } pub fn scc_indices(&self) -> &IndexSlice { @@ -160,7 +171,7 @@ impl Sccs { } } -impl DirectedGraph for Sccs { +impl DirectedGraph for Sccs { type Node = S; fn num_nodes(&self) -> usize { @@ -168,19 +179,19 @@ impl DirectedGraph for Sccs { } } -impl NumEdges for Sccs { +impl NumEdges for Sccs { fn num_edges(&self) -> usize { self.scc_data.all_successors.len() } } -impl Successors for Sccs { +impl Successors for Sccs { fn successors(&self, node: S) -> impl Iterator { self.successors(node).iter().cloned() } } -impl SccData { +impl SccData { /// Number of SCCs, fn len(&self) -> usize { self.scc_details.len() @@ -192,9 +203,8 @@ impl SccData { } /// Creates a new SCC with `successors` as its successors and - /// the maximum weight of its internal nodes `scc_max_weight` and /// returns the resulting index. - fn create_scc(&mut self, successors: impl IntoIterator, annotation: A) -> S { + fn create_scc(&mut self, successors: impl IntoIterator) -> S { // Store the successors on `scc_successors_vec`, remembering // the range of indices. let all_successors_start = self.all_successors.len(); @@ -202,35 +212,28 @@ impl SccData { let all_successors_end = self.all_successors.len(); debug!( - "create_scc({:?}) successors={:?}, annotation={:?}", + "create_scc({:?}) successors={:?}", self.len(), &self.all_successors[all_successors_start..all_successors_end], - annotation ); let range = all_successors_start..all_successors_end; - let metadata = SccDetails { range, annotation }; + let metadata = SccDetails { range }; self.scc_details.push(metadata) } - - fn annotation(&self, scc: S) -> A { - self.scc_details[scc].annotation - } } -struct SccsConstruction<'c, G, S, A, F> +struct SccsConstruction<'c, 'a, G, A> where G: DirectedGraph + Successors, - S: Idx, - A: Annotation, - F: Fn(G::Node) -> A, + A: Annotations, { graph: &'c G, /// The state of each node; used during walk to record the stack /// and after walk to record what cycle each node ended up being /// in. - node_states: IndexVec>, + node_states: IndexVec>, /// The stack of nodes that we are visiting as part of the DFS. node_stack: Vec, @@ -239,23 +242,21 @@ where /// position in this stack, and when we encounter a successor SCC, /// we push it on the stack. When we complete an SCC, we can pop /// everything off the stack that was found along the way. - successors_stack: Vec, + successors_stack: Vec, /// A set used to strip duplicates. As we accumulate successors /// into the successors_stack, we sometimes get duplicate entries. /// We use this set to remove those -- we also keep its storage /// around between successors to amortize memory allocation costs. - duplicate_set: FxHashSet, + duplicate_set: FxHashSet, - scc_data: SccData, + scc_data: SccData, - /// A function that constructs an initial SCC annotation - /// out of a single node. - to_annotation: F, + annotations: &'a mut A, } #[derive(Copy, Clone, Debug)] -enum NodeState { +enum NodeState { /// This node has not yet been visited as part of the DFS. /// /// After SCC construction is complete, this state ought to be @@ -286,7 +287,7 @@ enum NodeState { /// The state of walking a given node. #[derive(Copy, Clone, Debug)] -enum WalkReturn { +enum WalkReturn { /// The walk found a cycle, but the entire component is not known to have /// been fully walked yet. We only know the minimum depth of this /// component in a minimum spanning tree of the graph. This component @@ -299,12 +300,10 @@ enum WalkReturn { Complete { scc_index: S, annotation: A }, } -impl<'c, G, S, A, F> SccsConstruction<'c, G, S, A, F> +impl<'c, 'a, G, A> SccsConstruction<'c, 'a, G, A> where G: DirectedGraph + Successors, - S: Idx, - F: Fn(G::Node) -> A, - A: Annotation, + A: Annotations, { /// Identifies SCCs in the graph `G` and computes the resulting /// DAG. This uses a variant of [Tarjan's @@ -320,7 +319,7 @@ where /// Additionally, we keep track of a current annotation of the SCC. /// /// [wikipedia]: https://bit.ly/2EZIx84 - fn construct(graph: &'c G, to_annotation: F) -> Sccs { + fn construct(graph: &'c G, annotations: &'a mut A) -> Sccs { let num_nodes = graph.num_nodes(); let mut this = Self { @@ -330,7 +329,7 @@ where successors_stack: Vec::new(), scc_data: SccData { scc_details: IndexVec::new(), all_successors: Vec::new() }, duplicate_set: FxHashSet::default(), - to_annotation, + annotations, }; let scc_indices = graph @@ -346,7 +345,7 @@ where Sccs { scc_indices, scc_data: this.scc_data } } - fn start_walk_from(&mut self, node: G::Node) -> WalkReturn { + fn start_walk_from(&mut self, node: G::Node) -> WalkReturn { self.inspect_node(node).unwrap_or_else(|| self.walk_unvisited_node(node)) } @@ -362,7 +361,7 @@ where /// Otherwise, we are looking at a node that has already been /// completely visited. We therefore return `WalkReturn::Complete` /// with its associated SCC index. - fn inspect_node(&mut self, node: G::Node) -> Option> { + fn inspect_node(&mut self, node: G::Node) -> Option> { Some(match self.find_state(node) { NodeState::InCycle { scc_index, annotation } => { WalkReturn::Complete { scc_index, annotation } @@ -385,7 +384,7 @@ where /// of `r2` (and updates `r` to reflect current result). This is /// basically the "find" part of a standard union-find algorithm /// (with path compression). - fn find_state(&mut self, mut node: G::Node) -> NodeState { + fn find_state(&mut self, mut node: G::Node) -> NodeState { // To avoid recursion we temporarily reuse the `parent` of each // InCycleWith link to encode a downwards link while compressing // the path. After we have found the root or deepest node being @@ -408,7 +407,7 @@ where // a potentially derived version of the root state for non-root nodes in the chain. let (root_state, assigned_state) = { loop { - debug!("find_state(r = {node:?} in state {:?})", self.node_states[node]); + trace!("find_state(r = {node:?} in state {:?})", self.node_states[node]); match self.node_states[node] { // This must have been the first and only state since it is unexplored*; // no update needed! * Unless there is a bug :') @@ -482,7 +481,7 @@ where if previous_node == node { return root_state; } - debug!("Compressing {node:?} down to {previous_node:?} with state {assigned_state:?}"); + trace!("Compressing {node:?} down to {previous_node:?} with state {assigned_state:?}"); // Update to previous node in the link. match self.node_states[previous_node] { @@ -507,9 +506,9 @@ where /// Call this method when `inspect_node` has returned `None`. Having the /// caller decide avoids mutual recursion between the two methods and allows /// us to maintain an allocated stack for nodes on the path between calls. - #[instrument(skip(self, initial), level = "debug")] - fn walk_unvisited_node(&mut self, initial: G::Node) -> WalkReturn { - debug!("Walk unvisited node: {initial:?}"); + #[instrument(skip(self, initial), level = "trace")] + fn walk_unvisited_node(&mut self, initial: G::Node) -> WalkReturn { + trace!("Walk unvisited node: {initial:?}"); struct VisitingNodeFrame { node: G::Node, successors: Option, @@ -537,7 +536,7 @@ where successors_len: 0, min_cycle_root: initial, successor_node: initial, - current_component_annotation: (self.to_annotation)(initial), + current_component_annotation: self.annotations.new(initial), }]; let mut return_value = None; @@ -556,11 +555,7 @@ where let node = *node; let depth = *depth; - // node is definitely in the current component, add it to the annotation. - if node != initial { - current_component_annotation.update_scc((self.to_annotation)(node)); - } - debug!( + trace!( "Visiting {node:?} at depth {depth:?}, annotation: {current_component_annotation:?}" ); @@ -568,7 +563,7 @@ where Some(successors) => successors, None => { // This None marks that we still have the initialize this node's frame. - debug!(?depth, ?node); + trace!(?depth, ?node); debug_assert_matches!(self.node_states[node], NodeState::NotVisited); @@ -598,7 +593,7 @@ where return_value.take().into_iter().map(|walk| (*successor_node, Some(walk))); let successor_walk = successors.map(|successor_node| { - debug!(?node, ?successor_node); + trace!(?node, ?successor_node); (successor_node, self.inspect_node(successor_node)) }); for (successor_node, walk) in returned_walk.chain(successor_walk) { @@ -609,13 +604,13 @@ where min_depth: successor_min_depth, annotation: successor_annotation, }) => { - debug!( + trace!( "Cycle found from {node:?}, minimum depth: {successor_min_depth:?}, annotation: {successor_annotation:?}" ); // Track the minimum depth we can reach. assert!(successor_min_depth <= depth); if successor_min_depth < *min_depth { - debug!(?node, ?successor_min_depth); + trace!(?node, ?successor_min_depth); *min_depth = successor_min_depth; *min_cycle_root = successor_node; } @@ -627,20 +622,20 @@ where scc_index: successor_scc_index, annotation: successor_annotation, }) => { - debug!( + trace!( "Complete; {node:?} is root of complete-visited SCC idx {successor_scc_index:?} with annotation {successor_annotation:?}" ); // Push the completed SCC indices onto // the `successors_stack` for later. - debug!(?node, ?successor_scc_index); + trace!(?node, ?successor_scc_index); successors_stack.push(successor_scc_index); current_component_annotation.update_reachable(successor_annotation); } // `node` has no more (direct) successors; search recursively. None => { let depth = depth + 1; - debug!("Recursing down into {successor_node:?} at depth {depth:?}"); - debug!(?depth, ?successor_node); + trace!("Recursing down into {successor_node:?} at depth {depth:?}"); + trace!(?depth, ?successor_node); // Remember which node the return value will come from. frame.successor_node = successor_node; // Start a new stack frame, then step into it. @@ -652,14 +647,14 @@ where min_depth: depth, min_cycle_root: successor_node, successor_node, - current_component_annotation: (self.to_annotation)(successor_node), + current_component_annotation: self.annotations.new(successor_node), }); continue 'recurse; } } } - debug!("Finished walk from {node:?} with annotation: {current_component_annotation:?}"); + trace!("Finished walk from {node:?} with annotation: {current_component_annotation:?}"); // Completed walk, remove `node` from the stack. let r = self.node_stack.pop(); @@ -691,8 +686,9 @@ where debug!("Creating SCC rooted in {node:?} with successor {:?}", frame.successor_node); - let scc_index = - self.scc_data.create_scc(deduplicated_successors, current_component_annotation); + let scc_index = self.scc_data.create_scc(deduplicated_successors); + + self.annotations.annotate_scc(scc_index, current_component_annotation); self.node_states[node] = NodeState::InCycle { scc_index, annotation: current_component_annotation }; diff --git a/compiler/rustc_data_structures/src/graph/scc/tests.rs b/compiler/rustc_data_structures/src/graph/scc/tests.rs index 373f87bfdbcf..8f04baf51f35 100644 --- a/compiler/rustc_data_structures/src/graph/scc/tests.rs +++ b/compiler/rustc_data_structures/src/graph/scc/tests.rs @@ -5,8 +5,31 @@ use crate::graph::tests::TestGraph; #[derive(Copy, Clone, Debug)] struct MaxReached(usize); -type UsizeSccs = Sccs; -type MaxReachedSccs = Sccs; +struct Maxes(IndexVec, fn(usize) -> usize); +type UsizeSccs = Sccs; + +impl Annotations for Maxes { + fn new(&self, element: usize) -> MaxReached { + MaxReached(self.1(element)) + } + + fn annotate_scc(&mut self, scc: usize, annotation: MaxReached) { + let i = self.0.push(annotation); + assert!(i == scc); + } + + type Ann = MaxReached; + type SccIdx = usize; +} + +impl Maxes { + fn annotation(&self, scc: usize) -> MaxReached { + self.0[scc] + } + fn new(mapping: fn(usize) -> usize) -> Self { + Self(IndexVec::new(), mapping) + } +} impl Annotation for MaxReached { fn merge_scc(self, other: Self) -> Self { @@ -14,7 +37,7 @@ impl Annotation for MaxReached { } fn merge_reached(self, other: Self) -> Self { - self.merge_scc(other) + Self(std::cmp::max(other.0, self.0)) } } @@ -24,17 +47,32 @@ impl PartialEq for MaxReached { } } -impl MaxReached { - fn from_usize(nr: usize) -> Self { - Self(nr) - } -} - #[derive(Copy, Clone, Debug)] struct MinMaxIn { min: usize, max: usize, } +struct MinMaxes(IndexVec, fn(usize) -> MinMaxIn); + +impl MinMaxes { + fn annotation(&self, scc: usize) -> MinMaxIn { + self.0[scc] + } +} + +impl Annotations for MinMaxes { + fn new(&self, element: usize) -> MinMaxIn { + self.1(element) + } + + fn annotate_scc(&mut self, scc: usize, annotation: MinMaxIn) { + let i = self.0.push(annotation); + assert!(i == scc); + } + + type Ann = MinMaxIn; + type SccIdx = usize; +} impl Annotation for MinMaxIn { fn merge_scc(self, other: Self) -> Self { @@ -261,67 +299,68 @@ fn bench_sccc(b: &mut test::Bencher) { #[test] fn test_max_self_loop() { let graph = TestGraph::new(0, &[(0, 0)]); - let sccs: MaxReachedSccs = - Sccs::new_with_annotation(&graph, |n| if n == 0 { MaxReached(17) } else { MaxReached(0) }); - assert_eq!(sccs.annotation(0), 17); + let mut annotations = Maxes(IndexVec::new(), |n| if n == 0 { 17 } else { 0 }); + Sccs::new_with_annotation(&graph, &mut annotations); + assert_eq!(annotations.0[0], 17); } #[test] fn test_max_branch() { let graph = TestGraph::new(0, &[(0, 1), (0, 2), (1, 3), (2, 4)]); - let sccs: MaxReachedSccs = Sccs::new_with_annotation(&graph, MaxReached::from_usize); - assert_eq!(sccs.annotation(sccs.scc(0)), 4); - assert_eq!(sccs.annotation(sccs.scc(1)), 3); - assert_eq!(sccs.annotation(sccs.scc(2)), 4); -} -#[test] -fn test_single_cycle_max() { - let graph = TestGraph::new(0, &[(0, 2), (2, 3), (2, 4), (4, 1), (1, 2)]); - let sccs: MaxReachedSccs = Sccs::new_with_annotation(&graph, MaxReached::from_usize); - assert_eq!(sccs.annotation(sccs.scc(2)), 4); - assert_eq!(sccs.annotation(sccs.scc(0)), 4); + let mut annotations = Maxes(IndexVec::new(), |n| n); + let sccs = Sccs::new_with_annotation(&graph, &mut annotations); + assert_eq!(annotations.0[sccs.scc(0)], 4); + assert_eq!(annotations.0[sccs.scc(1)], 3); + assert_eq!(annotations.0[sccs.scc(2)], 4); } #[test] -fn test_simple_cycle_max() { - let graph = TestGraph::new(0, &[(0, 1), (1, 2), (2, 0)]); - let sccs: MaxReachedSccs = Sccs::new_with_annotation(&graph, MaxReached::from_usize); - assert_eq!(sccs.num_sccs(), 1); +fn test_single_cycle_max() { + let graph = TestGraph::new(0, &[(0, 2), (2, 3), (2, 4), (4, 1), (1, 2)]); + let mut annotations = Maxes(IndexVec::new(), |n| n); + let sccs = Sccs::new_with_annotation(&graph, &mut annotations); + assert_eq!(annotations.0[sccs.scc(2)], 4); + assert_eq!(annotations.0[sccs.scc(0)], 4); } #[test] fn test_double_cycle_max() { let graph = TestGraph::new(0, &[(0, 1), (1, 2), (1, 4), (2, 3), (2, 4), (3, 5), (4, 1), (5, 4)]); - let sccs: MaxReachedSccs = - Sccs::new_with_annotation(&graph, |n| if n == 5 { MaxReached(2) } else { MaxReached(1) }); + let mut annotations = Maxes(IndexVec::new(), |n| if n == 5 { 2 } else { 1 }); - assert_eq!(sccs.annotation(sccs.scc(0)).0, 2); + let sccs = Sccs::new_with_annotation(&graph, &mut annotations); + + assert_eq!(annotations.0[sccs.scc(0)].0, 2); } #[test] fn test_bug_minimised() { let graph = TestGraph::new(0, &[(0, 3), (0, 1), (3, 2), (2, 3), (1, 4), (4, 5), (5, 4)]); - let sccs: MaxReachedSccs = Sccs::new_with_annotation(&graph, |n| match n { - 3 => MaxReached(1), - _ => MaxReached(0), + let mut annotations = Maxes(IndexVec::new(), |n| match n { + 3 => 1, + _ => 0, }); - assert_eq!(sccs.annotation(sccs.scc(2)), 1); - assert_eq!(sccs.annotation(sccs.scc(1)), 0); - assert_eq!(sccs.annotation(sccs.scc(4)), 0); + + let sccs = Sccs::new_with_annotation(&graph, &mut annotations); + assert_eq!(annotations.annotation(sccs.scc(2)), 1); + assert_eq!(annotations.annotation(sccs.scc(1)), 0); + assert_eq!(annotations.annotation(sccs.scc(4)), 0); } #[test] fn test_bug_max_leak_minimised() { let graph = TestGraph::new(0, &[(0, 1), (0, 2), (1, 3), (3, 0), (3, 4), (4, 3)]); - let sccs: MaxReachedSccs = Sccs::new_with_annotation(&graph, |w| match w { - 4 => MaxReached(1), - _ => MaxReached(0), + let mut annotations = Maxes(IndexVec::new(), |w| match w { + 4 => 1, + _ => 0, }); - assert_eq!(sccs.annotation(sccs.scc(2)), 0); - assert_eq!(sccs.annotation(sccs.scc(3)), 1); - assert_eq!(sccs.annotation(sccs.scc(0)), 1); + let sccs = Sccs::new_with_annotation(&graph, &mut annotations); + + assert_eq!(annotations.annotation(sccs.scc(2)), 0); + assert_eq!(annotations.annotation(sccs.scc(3)), 1); + assert_eq!(annotations.annotation(sccs.scc(0)), 1); } #[test] @@ -369,48 +408,49 @@ fn test_bug_max_leak() { (23, 24), ], ); - let sccs: MaxReachedSccs = Sccs::new_with_annotation(&graph, |w| match w { - 22 => MaxReached(1), - 24 => MaxReached(2), - 27 => MaxReached(2), - _ => MaxReached(0), + let mut annotations = Maxes::new(|w| match w { + 22 => 1, + 24 => 2, + 27 => 2, + _ => 0, }); + let sccs = Sccs::new_with_annotation(&graph, &mut annotations); - assert_eq!(sccs.annotation(sccs.scc(2)), 0); - assert_eq!(sccs.annotation(sccs.scc(7)), 0); - assert_eq!(sccs.annotation(sccs.scc(8)), 2); - assert_eq!(sccs.annotation(sccs.scc(23)), 2); - assert_eq!(sccs.annotation(sccs.scc(3)), 2); - assert_eq!(sccs.annotation(sccs.scc(0)), 2); + assert_eq!(annotations.annotation(sccs.scc(2)), 0); + assert_eq!(annotations.annotation(sccs.scc(7)), 0); + assert_eq!(annotations.annotation(sccs.scc(8)), 2); + assert_eq!(annotations.annotation(sccs.scc(23)), 2); + assert_eq!(annotations.annotation(sccs.scc(3)), 2); + assert_eq!(annotations.annotation(sccs.scc(0)), 2); } #[test] fn test_bug_max_zero_stick_shape() { let graph = TestGraph::new(0, &[(0, 1), (1, 2), (2, 3), (3, 2), (3, 4)]); - - let sccs: MaxReachedSccs = Sccs::new_with_annotation(&graph, |w| match w { - 4 => MaxReached(1), - _ => MaxReached(0), + let mut annotations = Maxes::new(|w| match w { + 4 => 1, + _ => 0, }); + let sccs = Sccs::new_with_annotation(&graph, &mut annotations); - assert_eq!(sccs.annotation(sccs.scc(0)), 1); - assert_eq!(sccs.annotation(sccs.scc(1)), 1); - assert_eq!(sccs.annotation(sccs.scc(2)), 1); - assert_eq!(sccs.annotation(sccs.scc(3)), 1); - assert_eq!(sccs.annotation(sccs.scc(4)), 1); + assert_eq!(annotations.annotation(sccs.scc(0)), 1); + assert_eq!(annotations.annotation(sccs.scc(1)), 1); + assert_eq!(annotations.annotation(sccs.scc(2)), 1); + assert_eq!(annotations.annotation(sccs.scc(3)), 1); + assert_eq!(annotations.annotation(sccs.scc(4)), 1); } #[test] fn test_min_max_in() { let graph = TestGraph::new(0, &[(0, 1), (0, 2), (1, 3), (3, 0), (3, 4), (4, 3), (3, 5)]); - let sccs: Sccs = - Sccs::new_with_annotation(&graph, |w| MinMaxIn { min: w, max: w }); + let mut annotations = MinMaxes(IndexVec::new(), |w| MinMaxIn { min: w, max: w }); + let sccs = Sccs::new_with_annotation(&graph, &mut annotations); - assert_eq!(sccs.annotation(sccs.scc(2)).min, 2); - assert_eq!(sccs.annotation(sccs.scc(2)).max, 2); - assert_eq!(sccs.annotation(sccs.scc(0)).min, 0); - assert_eq!(sccs.annotation(sccs.scc(0)).max, 4); - assert_eq!(sccs.annotation(sccs.scc(3)).min, 0); - assert_eq!(sccs.annotation(sccs.scc(3)).max, 4); - assert_eq!(sccs.annotation(sccs.scc(5)).min, 5); + assert_eq!(annotations.annotation(sccs.scc(2)).min, 2); + assert_eq!(annotations.annotation(sccs.scc(2)).max, 2); + assert_eq!(annotations.annotation(sccs.scc(0)).min, 0); + assert_eq!(annotations.annotation(sccs.scc(0)).max, 4); + assert_eq!(annotations.annotation(sccs.scc(3)).min, 0); + assert_eq!(annotations.annotation(sccs.scc(3)).max, 4); + assert_eq!(annotations.annotation(sccs.scc(5)).min, 5); } diff --git a/compiler/rustc_data_structures/src/jobserver.rs b/compiler/rustc_data_structures/src/jobserver.rs index 1204f2d692d6..3ed1ea7543f4 100644 --- a/compiler/rustc_data_structures/src/jobserver.rs +++ b/compiler/rustc_data_structures/src/jobserver.rs @@ -1,7 +1,8 @@ -use std::sync::{LazyLock, OnceLock}; +use std::sync::{Arc, LazyLock, OnceLock}; pub use jobserver_crate::{Acquired, Client, HelperThread}; use jobserver_crate::{FromEnv, FromEnvErrorKind}; +use parking_lot::{Condvar, Mutex}; // We can only call `from_env_ext` once per process @@ -71,10 +72,93 @@ pub fn client() -> Client { GLOBAL_CLIENT_CHECKED.get().expect(ACCESS_ERROR).clone() } -pub fn acquire_thread() { - GLOBAL_CLIENT_CHECKED.get().expect(ACCESS_ERROR).acquire_raw().ok(); +struct ProxyData { + /// The number of tokens assigned to threads. + /// If this is 0, a single token is still assigned to this process, but is unused. + used: u16, + + /// The number of threads requesting a token + pending: u16, } -pub fn release_thread() { - GLOBAL_CLIENT_CHECKED.get().expect(ACCESS_ERROR).release_raw().ok(); +/// This is a jobserver proxy used to ensure that we hold on to at least one token. +pub struct Proxy { + client: Client, + data: Mutex, + + /// Threads which are waiting on a token will wait on this. + wake_pending: Condvar, + + helper: OnceLock, +} + +impl Proxy { + pub fn new() -> Arc { + let proxy = Arc::new(Proxy { + client: client(), + data: Mutex::new(ProxyData { used: 1, pending: 0 }), + wake_pending: Condvar::new(), + helper: OnceLock::new(), + }); + let proxy_ = Arc::clone(&proxy); + let helper = proxy + .client + .clone() + .into_helper_thread(move |token| { + if let Ok(token) = token { + let mut data = proxy_.data.lock(); + if data.pending > 0 { + // Give the token to a waiting thread + token.drop_without_releasing(); + assert!(data.used > 0); + data.used += 1; + data.pending -= 1; + proxy_.wake_pending.notify_one(); + } else { + // The token is no longer needed, drop it. + drop(data); + drop(token); + } + } + }) + .expect("failed to create helper thread"); + proxy.helper.set(helper).unwrap(); + proxy + } + + pub fn acquire_thread(&self) { + let mut data = self.data.lock(); + + if data.used == 0 { + // There was a free token around. This can + // happen when all threads release their token. + assert_eq!(data.pending, 0); + data.used += 1; + } else { + // Request a token from the helper thread. We can't directly use `acquire_raw` + // as we also need to be able to wait for the final token in the process which + // does not get a corresponding `release_raw` call. + self.helper.get().unwrap().request_token(); + data.pending += 1; + self.wake_pending.wait(&mut data); + } + } + + pub fn release_thread(&self) { + let mut data = self.data.lock(); + + if data.pending > 0 { + // Give the token to a waiting thread + data.pending -= 1; + self.wake_pending.notify_one(); + } else { + data.used -= 1; + + // Release the token unless it's the last one in the process + if data.used > 0 { + drop(data); + self.client.release_raw().ok(); + } + } + } } diff --git a/compiler/rustc_data_structures/src/marker.rs b/compiler/rustc_data_structures/src/marker.rs index dfd9bd320761..e0df1b232e13 100644 --- a/compiler/rustc_data_structures/src/marker.rs +++ b/compiler/rustc_data_structures/src/marker.rs @@ -59,8 +59,8 @@ macro_rules! already_send { // These structures are already `Send`. already_send!( [std::backtrace::Backtrace][std::io::Stdout][std::io::Stderr][std::io::Error][std::fs::File] - [rustc_arena::DroplessArena][crate::memmap::Mmap][crate::profiling::SelfProfiler] - [crate::owned_slice::OwnedSlice] + [rustc_arena::DroplessArena][jobserver_crate::Client][jobserver_crate::HelperThread] + [crate::memmap::Mmap][crate::profiling::SelfProfiler][crate::owned_slice::OwnedSlice] ); macro_rules! impl_dyn_send { @@ -134,8 +134,8 @@ macro_rules! already_sync { already_sync!( [std::sync::atomic::AtomicBool][std::sync::atomic::AtomicUsize][std::sync::atomic::AtomicU8] [std::sync::atomic::AtomicU32][std::backtrace::Backtrace][std::io::Error][std::fs::File] - [jobserver_crate::Client][crate::memmap::Mmap][crate::profiling::SelfProfiler] - [crate::owned_slice::OwnedSlice] + [jobserver_crate::Client][jobserver_crate::HelperThread][crate::memmap::Mmap] + [crate::profiling::SelfProfiler][crate::owned_slice::OwnedSlice] ); // Use portable AtomicU64 for targets without native 64-bit atomics diff --git a/compiler/rustc_data_structures/src/sync.rs b/compiler/rustc_data_structures/src/sync.rs index 80d49effbf8a..b28c333d860c 100644 --- a/compiler/rustc_data_structures/src/sync.rs +++ b/compiler/rustc_data_structures/src/sync.rs @@ -43,7 +43,7 @@ pub use self::freeze::{FreezeLock, FreezeReadGuard, FreezeWriteGuard}; pub use self::lock::{Lock, LockGuard, Mode}; pub use self::mode::{is_dyn_thread_safe, set_dyn_thread_safe_mode}; pub use self::parallel::{ - join, par_for_each_in, par_map, parallel_guard, scope, spawn, try_par_for_each_in, + broadcast, join, par_for_each_in, par_map, parallel_guard, scope, spawn, try_par_for_each_in, }; pub use self::vec::{AppendOnlyIndexVec, AppendOnlyVec}; pub use self::worker_local::{Registry, WorkerLocal}; diff --git a/compiler/rustc_data_structures/src/sync/parallel.rs b/compiler/rustc_data_structures/src/sync/parallel.rs index 64db39cc4c6e..ab65c7f3a6b5 100644 --- a/compiler/rustc_data_structures/src/sync/parallel.rs +++ b/compiler/rustc_data_structures/src/sync/parallel.rs @@ -237,3 +237,13 @@ pub fn par_map, R: DynSend, C: FromIterato } }) } + +pub fn broadcast(op: impl Fn(usize) -> R + DynSync) -> Vec { + if mode::is_dyn_thread_safe() { + let op = FromDyn::from(op); + let results = rayon_core::broadcast(|context| op.derive(op(context.index()))); + results.into_iter().map(|r| r.into_inner()).collect() + } else { + vec![op(0)] + } +} diff --git a/compiler/rustc_driver_impl/Cargo.toml b/compiler/rustc_driver_impl/Cargo.toml index c823d11126e2..9da4f2dbc273 100644 --- a/compiler/rustc_driver_impl/Cargo.toml +++ b/compiler/rustc_driver_impl/Cargo.toml @@ -44,13 +44,13 @@ rustc_privacy = { path = "../rustc_privacy" } rustc_query_system = { path = "../rustc_query_system" } rustc_resolve = { path = "../rustc_resolve" } rustc_session = { path = "../rustc_session" } -rustc_smir = { path = "../rustc_smir" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } rustc_trait_selection = { path = "../rustc_trait_selection" } rustc_ty_utils = { path = "../rustc_ty_utils" } serde_json = "1.0.59" shlex = "1.0" +stable_mir = { path = "../stable_mir", features = ["rustc_internal"] } tracing = { version = "0.1.35" } # tidy-alphabetical-end diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index d18fa8928140..95cfe221d3fe 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -54,8 +54,8 @@ use rustc_metadata::locator; use rustc_middle::ty::TyCtxt; use rustc_parse::{new_parser_from_file, new_parser_from_source_str, unwrap_or_emit_fatal}; use rustc_session::config::{ - CG_OPTIONS, ErrorOutputType, Input, OptionDesc, OutFileName, OutputType, UnstableOptions, - Z_OPTIONS, nightly_options, parse_target_triple, + CG_OPTIONS, CrateType, ErrorOutputType, Input, OptionDesc, OutFileName, OutputType, + UnstableOptions, Z_OPTIONS, nightly_options, parse_target_triple, }; use rustc_session::getopts::{self, Matches}; use rustc_session::lint::{Lint, LintId}; @@ -352,6 +352,8 @@ pub fn run_compiler(at_args: &[String], callbacks: &mut (dyn Callbacks + Send)) passes::write_dep_info(tcx); + passes::write_interface(tcx); + if sess.opts.output_types.contains_key(&OutputType::DepInfo) && sess.opts.output_types.len() == 1 { @@ -461,6 +463,7 @@ fn handle_explain(early_dcx: &EarlyDiagCtxt, registry: Registry, code: &str, col // Allow "E0123" or "0123" form. let upper_cased_code = code.to_ascii_uppercase(); if let Ok(code) = upper_cased_code.strip_prefix('E').unwrap_or(&upper_cased_code).parse::() + && code <= ErrCode::MAX_AS_U32 && let Ok(description) = registry.try_find_description(ErrCode::from_u32(code)) { let mut is_in_code_block = false; @@ -816,6 +819,7 @@ fn print_crate_info( let supported_crate_types = CRATE_TYPES .iter() .filter(|(_, crate_type)| !invalid_output_for_target(&sess, *crate_type)) + .filter(|(_, crate_type)| *crate_type != CrateType::Sdylib) .map(|(crate_type_sym, _)| *crate_type_sym) .collect::>(); for supported_crate_type in supported_crate_types { diff --git a/compiler/rustc_driver_impl/src/pretty.rs b/compiler/rustc_driver_impl/src/pretty.rs index 16d70af7e05d..ec77043cd128 100644 --- a/compiler/rustc_driver_impl/src/pretty.rs +++ b/compiler/rustc_driver_impl/src/pretty.rs @@ -10,8 +10,8 @@ use rustc_middle::ty::{self, TyCtxt}; use rustc_mir_build::thir::print::{thir_flat, thir_tree}; use rustc_session::Session; use rustc_session::config::{OutFileName, PpHirMode, PpMode, PpSourceMode}; -use rustc_smir::rustc_internal::pretty::write_smir_pretty; use rustc_span::{FileName, Ident}; +use stable_mir::rustc_internal::pretty::write_smir_pretty; use tracing::debug; use {rustc_ast as ast, rustc_hir_pretty as pprust_hir}; diff --git a/compiler/rustc_error_codes/src/error_codes/E0207.md b/compiler/rustc_error_codes/src/error_codes/E0207.md index 5b35748f4723..f80b0093ecc5 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0207.md +++ b/compiler/rustc_error_codes/src/error_codes/E0207.md @@ -195,7 +195,7 @@ impl<'a> Contains for Foo { Please note that unconstrained lifetime parameters are not supported if they are being used by an associated type. -In cases where the associated type's lifetime is meant to be tied to the the +In cases where the associated type's lifetime is meant to be tied to the self type, and none of the methods on the trait need ownership or different mutability, then an option is to implement the trait on a borrowed type: diff --git a/compiler/rustc_error_codes/src/error_codes/E0253.md b/compiler/rustc_error_codes/src/error_codes/E0253.md index 705d1bfc53e5..628f5e252fbb 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0253.md +++ b/compiler/rustc_error_codes/src/error_codes/E0253.md @@ -1,9 +1,13 @@ +#### Note: this error code is no longer emitted by the compiler. + Attempt was made to import an unimportable type. This can happen when trying to import a type from a trait. Erroneous code example: -```compile_fail,E0253 +``` +#![feature(import_trait_associated_functions)] + mod foo { pub trait MyTrait { type SomeType; diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index 2df3281568be..0994813ecb9c 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -274,7 +274,12 @@ impl<'a> StripUnconfigured<'a> { /// is in the original source file. Gives a compiler error if the syntax of /// the attribute is incorrect. pub(crate) fn expand_cfg_attr(&self, cfg_attr: &Attribute, recursive: bool) -> Vec { - validate_attr::check_attribute_safety(&self.sess.psess, AttributeSafety::Normal, &cfg_attr); + validate_attr::check_attribute_safety( + &self.sess.psess, + Some(AttributeSafety::Normal), + &cfg_attr, + ast::CRATE_NODE_ID, + ); // A trace attribute left in AST in place of the original `cfg_attr` attribute. // It can later be used by lints or other diagnostics. diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 1f430b0018f5..d4853d1357f3 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -1983,7 +1983,11 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { let mut span: Option = None; while let Some(attr) = attrs.next() { rustc_ast_passes::feature_gate::check_attribute(attr, self.cx.sess, features); - validate_attr::check_attr(&self.cx.sess.psess, attr); + validate_attr::check_attr( + &self.cx.sess.psess, + attr, + self.cx.current_expansion.lint_node_id, + ); let current_span = if let Some(sp) = span { sp.to(attr.span) } else { attr.span }; span = Some(current_span); diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index a5e6b1c00d69..c117e0fcf7cc 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -536,6 +536,12 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ // Unstable attributes: // ========================================================================== + // Linking: + gated!( + export_stable, Normal, template!(Word), WarnFollowing, + EncodeCrossCrate::No, experimental!(export_stable) + ), + // Testing: gated!( test_runner, CrateLevel, template!(List: "path"), ErrorFollowing, diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 75e09cacb1f1..a5f89b7a076a 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -316,6 +316,7 @@ declare_features! ( // Unstable `#[target_feature]` directives. (unstable, aarch64_unstable_target_feature, "1.82.0", Some(44839)), (unstable, aarch64_ver_target_feature, "1.27.0", Some(44839)), + (unstable, apx_target_feature, "CURRENT_RUSTC_VERSION", Some(139284)), (unstable, arm_target_feature, "1.27.0", Some(44839)), (unstable, avx512_target_feature, "1.27.0", Some(44839)), (unstable, bpf_target_feature, "1.54.0", Some(44839)), @@ -393,6 +394,8 @@ declare_features! ( (unstable, async_for_loop, "1.77.0", Some(118898)), /// Allows `async` trait bound modifier. (unstable, async_trait_bounds, "1.85.0", Some(62290)), + /// Allows using Intel AVX10 target features and intrinsics + (unstable, avx10_target_feature, "CURRENT_RUSTC_VERSION", Some(138843)), /// Allows using C-variadics. (unstable, c_variadic, "1.34.0", Some(44930)), /// Allows the use of `#[cfg(contract_checks)` to check if contract checks are enabled. @@ -483,6 +486,8 @@ declare_features! ( (unstable, explicit_extern_abis, "CURRENT_RUSTC_VERSION", Some(134986)), /// Allows explicit tail calls via `become` expression. (incomplete, explicit_tail_calls, "1.72.0", Some(112788)), + /// Allows using `#[export_stable]` which indicates that an item is exportable. + (incomplete, export_stable, "CURRENT_RUSTC_VERSION", Some(139939)), /// Allows using `aapcs`, `efiapi`, `sysv64` and `win64` as calling conventions /// for functions with varargs. (unstable, extended_varargs_abi_support, "1.65.0", Some(100189)), @@ -506,6 +511,8 @@ declare_features! ( (incomplete, fn_delegation, "1.76.0", Some(118212)), /// Allows impls for the Freeze trait. (internal, freeze_impls, "1.78.0", Some(121675)), + /// Frontmatter `---` blocks for use by external tools. + (unstable, frontmatter, "CURRENT_RUSTC_VERSION", Some(136889)), /// Allows defining gen blocks and `gen fn`. (unstable, gen_blocks, "1.75.0", Some(117078)), /// Infer generic args for both consts and types. diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs index 9372ab532bf3..507c94aca8b9 100644 --- a/compiler/rustc_hir/src/def.rs +++ b/compiler/rustc_hir/src/def.rs @@ -269,18 +269,10 @@ impl DefKind { | DefKind::TyParam | DefKind::ExternCrate => DefPathData::TypeNs(name.unwrap()), - // An associated type name will be missing for an RPITIT. - DefKind::AssocTy => { - if let Some(name) = name { - DefPathData::TypeNs(name) - } else { - DefPathData::AnonAssocTy - } - } + // An associated type name will be missing for an RPITIT (DefPathData::AnonAssocTy), + // but those provide their own DefPathData. + DefKind::AssocTy => DefPathData::TypeNs(name.unwrap()), - // It's not exactly an anon const, but wrt DefPathData, there - // is no difference. - DefKind::Static { nested: true, .. } => DefPathData::AnonConst, DefKind::Fn | DefKind::Const | DefKind::ConstParam diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs index bf7b1eefcf68..98b41187f114 100644 --- a/compiler/rustc_hir/src/definitions.rs +++ b/compiler/rustc_hir/src/definitions.rs @@ -68,7 +68,7 @@ impl DefPathTable { // // See the documentation for DefPathHash for more information. panic!( - "found DefPathHash collision between {def_path1:?} and {def_path2:?}. \ + "found DefPathHash collision between {def_path1:#?} and {def_path2:#?}. \ Compilation cannot continue." ); } @@ -97,13 +97,31 @@ impl DefPathTable { } } +#[derive(Debug)] +pub struct DisambiguatorState { + next: UnordMap<(LocalDefId, DefPathData), u32>, +} + +impl DisambiguatorState { + pub fn new() -> Self { + Self { next: Default::default() } + } + + /// Creates a `DisambiguatorState` where the next allocated `(LocalDefId, DefPathData)` pair + /// will have `index` as the disambiguator. + pub fn with(def_id: LocalDefId, data: DefPathData, index: u32) -> Self { + let mut this = Self::new(); + this.next.insert((def_id, data), index); + this + } +} + /// The definition table containing node definitions. /// It holds the `DefPathTable` for `LocalDefId`s/`DefPath`s. /// It also stores mappings to convert `LocalDefId`s to/from `HirId`s. #[derive(Debug)] pub struct Definitions { table: DefPathTable, - next_disambiguator: UnordMap<(LocalDefId, DefPathData), u32>, } /// A unique identifier that we can use to lookup a definition @@ -127,7 +145,7 @@ impl DefKey { let DisambiguatedDefPathData { ref data, disambiguator } = self.disambiguated_data; std::mem::discriminant(data).hash(&mut hasher); - if let Some(name) = data.get_opt_name() { + if let Some(name) = data.hashed_symbol() { // Get a stable hash by considering the symbol chars rather than // the symbol index. name.as_str().hash(&mut hasher); @@ -173,7 +191,11 @@ impl DisambiguatedDefPathData { } } DefPathDataName::Anon { namespace } => { - write!(writer, "{{{}#{}}}", namespace, self.disambiguator) + if let DefPathData::AnonAssocTy(method) = self.data { + write!(writer, "{}::{{{}#{}}}", method, namespace, self.disambiguator) + } else { + write!(writer, "{{{}#{}}}", namespace, self.disambiguator) + } } } } @@ -287,10 +309,13 @@ pub enum DefPathData { /// An existential `impl Trait` type node. /// Argument position `impl Trait` have a `TypeNs` with their pretty-printed name. OpaqueTy, - /// An anonymous associated type from an RPITIT. - AnonAssocTy, + /// An anonymous associated type from an RPITIT. The symbol refers to the name of the method + /// that defined the type. + AnonAssocTy(Symbol), /// A synthetic body for a coroutine's by-move body. SyntheticCoroutineBody, + /// Additional static data referred to by a static. + NestedStatic, } impl Definitions { @@ -342,11 +367,20 @@ impl Definitions { let root = LocalDefId { local_def_index: table.allocate(key, def_path_hash) }; assert_eq!(root.local_def_index, CRATE_DEF_INDEX); - Definitions { table, next_disambiguator: Default::default() } + Definitions { table } } - /// Adds a definition with a parent definition. - pub fn create_def(&mut self, parent: LocalDefId, data: DefPathData) -> LocalDefId { + /// Creates a definition with a parent definition. + /// If there are multiple definitions with the same DefPathData and the same parent, use + /// `disambiguator` to differentiate them. Distinct `DisambiguatorState` instances are not + /// guaranteed to generate unique disambiguators and should instead ensure that the `parent` + /// and `data` pair is distinct from other instances. + pub fn create_def( + &mut self, + parent: LocalDefId, + data: DefPathData, + disambiguator: &mut DisambiguatorState, + ) -> LocalDefId { // We can't use `Debug` implementation for `LocalDefId` here, since it tries to acquire a // reference to `Definitions` and we're already holding a mutable reference. debug!( @@ -354,12 +388,12 @@ impl Definitions { self.def_path(parent).to_string_no_crate_verbose(), ); - // The root node must be created with `create_root_def()`. + // The root node must be created in `new()`. assert!(data != DefPathData::CrateRoot); // Find the next free disambiguator for this key. let disambiguator = { - let next_disamb = self.next_disambiguator.entry((parent, data)).or_insert(0); + let next_disamb = disambiguator.next.entry((parent, data)).or_insert(0); let disambiguator = *next_disamb; *next_disamb = next_disamb.checked_add(1).expect("disambiguator overflow"); disambiguator @@ -422,8 +456,30 @@ impl DefPathData { | Ctor | AnonConst | OpaqueTy - | AnonAssocTy - | SyntheticCoroutineBody => None, + | AnonAssocTy(..) + | SyntheticCoroutineBody + | NestedStatic => None, + } + } + + fn hashed_symbol(&self) -> Option { + use self::DefPathData::*; + match *self { + TypeNs(name) | ValueNs(name) | MacroNs(name) | LifetimeNs(name) | AnonAssocTy(name) => { + Some(name) + } + + Impl + | ForeignMod + | CrateRoot + | Use + | GlobalAsm + | Closure + | Ctor + | AnonConst + | OpaqueTy + | SyntheticCoroutineBody + | NestedStatic => None, } } @@ -443,8 +499,9 @@ impl DefPathData { Ctor => DefPathDataName::Anon { namespace: sym::constructor }, AnonConst => DefPathDataName::Anon { namespace: sym::constant }, OpaqueTy => DefPathDataName::Anon { namespace: sym::opaque }, - AnonAssocTy => DefPathDataName::Anon { namespace: sym::anon_assoc }, + AnonAssocTy(..) => DefPathDataName::Anon { namespace: sym::anon_assoc }, SyntheticCoroutineBody => DefPathDataName::Anon { namespace: sym::synthetic }, + NestedStatic => DefPathDataName::Anon { namespace: sym::nested }, } } } diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index af587ee5bdcd..107aea4e5a40 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -35,18 +35,24 @@ use crate::def_id::{DefId, LocalDefIdMap}; pub(crate) use crate::hir_id::{HirId, ItemLocalId, ItemLocalMap, OwnerId}; use crate::intravisit::{FnKind, VisitorExt}; +#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable_Generic)] +pub enum AngleBrackets { + /// E.g. `Path`. + Missing, + /// E.g. `Path<>`. + Empty, + /// E.g. `Path`. + Full, +} + #[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable_Generic)] pub enum LifetimeSource { /// E.g. `&Type`, `&'_ Type`, `&'a Type`, `&mut Type`, `&'_ mut Type`, `&'a mut Type` Reference, - /// E.g. `ContainsLifetime`, `ContainsLifetime<'_>`, `ContainsLifetime<'a>` - Path { - /// - true for `ContainsLifetime<'_>`, `ContainsLifetime<'a>`, - /// `ContainsLifetime<'_, T>`, `ContainsLifetime<'a, T>` - /// - false for `ContainsLifetime` - with_angle_brackets: bool, - }, + /// E.g. `ContainsLifetime`, `ContainsLifetime<>`, `ContainsLifetime<'_>`, + /// `ContainsLifetime<'a>` + Path { angle_brackets: AngleBrackets }, /// E.g. `impl Trait + '_`, `impl Trait + 'a` OutlivesBound, @@ -304,12 +310,17 @@ impl Lifetime { (Named | Anonymous, _) => (self.ident.span, format!("{new_lifetime}")), // The user wrote `Path`, and omitted the `'_,`. - (Hidden, Path { with_angle_brackets: true }) => { + (Hidden, Path { angle_brackets: AngleBrackets::Full }) => { (self.ident.span, format!("{new_lifetime}, ")) } + // The user wrote `Path<>`, and omitted the `'_`.. + (Hidden, Path { angle_brackets: AngleBrackets::Empty }) => { + (self.ident.span, format!("{new_lifetime}")) + } + // The user wrote `Path` and omitted the `<'_>`. - (Hidden, Path { with_angle_brackets: false }) => { + (Hidden, Path { angle_brackets: AngleBrackets::Missing }) => { (self.ident.span.shrink_to_hi(), format!("<{new_lifetime}>")) } @@ -2730,6 +2741,9 @@ pub enum ExprKind<'hir> { /// An `if` block, with an optional else block. /// /// I.e., `if { } else { }`. + /// + /// The "then" expr is always `ExprKind::Block`. If present, the "else" expr is always + /// `ExprKind::Block` (for `else`) or `ExprKind::If` (for `else if`). If(&'hir Expr<'hir>, &'hir Expr<'hir>, Option<&'hir Expr<'hir>>), /// A conditionless loop (can be exited with `break`, `continue`, or `return`). /// diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index fa36fe797161..2ec14b2f018c 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -76,6 +76,36 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> { ) } + /// Convenience function to *deeply* normalize during wfcheck. In the old solver, + /// this just dispatches to [`WfCheckingCtxt::normalize`], but in the new solver + /// this calls `deeply_normalize` and reports errors if they are encountered. + /// + /// This function should be called in favor of `normalize` in cases where we will + /// then check the well-formedness of the type, since we only use the normalized + /// signature types for implied bounds when checking regions. + // FIXME(-Znext-solver): This should be removed when we compute implied outlives + // bounds using the unnormalized signature of the function we're checking. + fn deeply_normalize(&self, span: Span, loc: Option, value: T) -> T + where + T: TypeFoldable>, + { + if self.infcx.next_trait_solver() { + match self.ocx.deeply_normalize( + &ObligationCause::new(span, self.body_def_id, ObligationCauseCode::WellFormed(loc)), + self.param_env, + value.clone(), + ) { + Ok(value) => value, + Err(errors) => { + self.infcx.err_ctxt().report_fulfillment_errors(errors); + value + } + } + } else { + self.normalize(span, loc, value) + } + } + fn register_wf_obligation(&self, span: Span, loc: Option, term: ty::Term<'tcx>) { let cause = traits::ObligationCause::new( span, @@ -297,7 +327,8 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) -> Result<() { let res = enter_wf_checking_ctxt(tcx, item.span, def_id, |wfcx| { let ty = tcx.type_of(def_id).instantiate_identity(); - let item_ty = wfcx.normalize(hir_ty.span, Some(WellFormedLoc::Ty(def_id)), ty); + let item_ty = + wfcx.deeply_normalize(hir_ty.span, Some(WellFormedLoc::Ty(def_id)), ty); wfcx.register_wf_obligation( hir_ty.span, Some(WellFormedLoc::Ty(def_id)), @@ -1073,7 +1104,7 @@ fn check_associated_item( match item.kind { ty::AssocKind::Const { .. } => { let ty = tcx.type_of(item.def_id).instantiate_identity(); - let ty = wfcx.normalize(span, Some(WellFormedLoc::Ty(item_id)), ty); + let ty = wfcx.deeply_normalize(span, Some(WellFormedLoc::Ty(item_id)), ty); wfcx.register_wf_obligation(span, loc, ty.into()); check_sized_if_body( wfcx, @@ -1102,7 +1133,7 @@ fn check_associated_item( } if item.defaultness(tcx).has_value() { let ty = tcx.type_of(item.def_id).instantiate_identity(); - let ty = wfcx.normalize(span, Some(WellFormedLoc::Ty(item_id)), ty); + let ty = wfcx.deeply_normalize(span, Some(WellFormedLoc::Ty(item_id)), ty); wfcx.register_wf_obligation(span, loc, ty.into()); } Ok(()) @@ -1149,7 +1180,7 @@ fn check_type_defn<'tcx>( let field_id = field.did.expect_local(); let hir::FieldDef { ty: hir_ty, .. } = tcx.hir_node_by_def_id(field_id).expect_field(); - let ty = wfcx.normalize( + let ty = wfcx.deeply_normalize( hir_ty.span, None, tcx.type_of(field.did).instantiate_identity(), @@ -1310,7 +1341,7 @@ fn check_item_type( enter_wf_checking_ctxt(tcx, ty_span, item_id, |wfcx| { let ty = tcx.type_of(item_id).instantiate_identity(); - let item_ty = wfcx.normalize(ty_span, Some(WellFormedLoc::Ty(item_id)), ty); + let item_ty = wfcx.deeply_normalize(ty_span, Some(WellFormedLoc::Ty(item_id)), ty); let forbid_unsized = match unsized_handling { UnsizedHandling::Forbid => true, @@ -1375,7 +1406,7 @@ fn check_impl<'tcx>( // other `Foo` impls are incoherent. tcx.ensure_ok().coherent_trait(trait_ref.def_id)?; let trait_span = hir_trait_ref.path.span; - let trait_ref = wfcx.normalize( + let trait_ref = wfcx.deeply_normalize( trait_span, Some(WellFormedLoc::Ty(item.hir_id().expect_owner().def_id)), trait_ref, @@ -1435,7 +1466,7 @@ fn check_impl<'tcx>( } None => { let self_ty = tcx.type_of(item.owner_id).instantiate_identity(); - let self_ty = wfcx.normalize( + let self_ty = wfcx.deeply_normalize( item.span, Some(WellFormedLoc::Ty(item.hir_id().expect_owner().def_id)), self_ty, @@ -1640,7 +1671,7 @@ fn check_fn_or_method<'tcx>( sig.inputs_and_output = tcx.mk_type_list_from_iter(sig.inputs_and_output.iter().enumerate().map(|(idx, ty)| { - wfcx.normalize( + wfcx.deeply_normalize( arg_span(idx), Some(WellFormedLoc::Param { function: def_id, diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 59ab36d98fda..a89160785eb1 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -14,6 +14,7 @@ use rustc_ast::visit::walk_list; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_errors::ErrorGuaranteed; use rustc_hir::def::{DefKind, Res}; +use rustc_hir::definitions::DisambiguatorState; use rustc_hir::intravisit::{self, InferKind, Visitor, VisitorExt}; use rustc_hir::{ self as hir, AmbigArg, GenericArg, GenericParam, GenericParamKind, HirId, LifetimeKind, Node, @@ -63,6 +64,7 @@ impl ResolvedArg { struct BoundVarContext<'a, 'tcx> { tcx: TyCtxt<'tcx>, rbv: &'a mut ResolveBoundVars, + disambiguator: &'a mut DisambiguatorState, scope: ScopeRef<'a>, } @@ -245,8 +247,12 @@ pub(crate) fn provide(providers: &mut Providers) { #[instrument(level = "debug", skip(tcx))] fn resolve_bound_vars(tcx: TyCtxt<'_>, local_def_id: hir::OwnerId) -> ResolveBoundVars { let mut rbv = ResolveBoundVars::default(); - let mut visitor = - BoundVarContext { tcx, rbv: &mut rbv, scope: &Scope::Root { opt_parent_item: None } }; + let mut visitor = BoundVarContext { + tcx, + rbv: &mut rbv, + scope: &Scope::Root { opt_parent_item: None }, + disambiguator: &mut DisambiguatorState::new(), + }; match tcx.hir_owner_node(local_def_id) { hir::OwnerNode::Item(item) => visitor.visit_item(item), hir::OwnerNode::ForeignItem(item) => visitor.visit_foreign_item(item), @@ -515,9 +521,10 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { let capture_all_in_scope_lifetimes = opaque_captures_all_in_scope_lifetimes(opaque); if capture_all_in_scope_lifetimes { + let tcx = self.tcx; let lifetime_ident = |def_id: LocalDefId| { - let name = self.tcx.item_name(def_id.to_def_id()); - let span = self.tcx.def_span(def_id); + let name = tcx.item_name(def_id.to_def_id()); + let span = tcx.def_span(def_id); Ident::new(name, span) }; @@ -1091,8 +1098,8 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { where F: for<'b> FnOnce(&mut BoundVarContext<'b, 'tcx>), { - let BoundVarContext { tcx, rbv, .. } = self; - let mut this = BoundVarContext { tcx: *tcx, rbv, scope: &wrap_scope }; + let BoundVarContext { tcx, rbv, disambiguator, .. } = self; + let mut this = BoundVarContext { tcx: *tcx, rbv, disambiguator, scope: &wrap_scope }; let span = debug_span!("scope", scope = ?this.scope.debug_truncated()); { let _enter = span.enter(); @@ -1446,7 +1453,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { #[instrument(level = "trace", skip(self, opaque_capture_scopes), ret)] fn remap_opaque_captures( - &self, + &mut self, opaque_capture_scopes: &Vec<(LocalDefId, &RefCell>)>, mut lifetime: ResolvedArg, ident: Ident, @@ -1462,8 +1469,17 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { for &(opaque_def_id, captures) in opaque_capture_scopes.iter().rev() { let mut captures = captures.borrow_mut(); let remapped = *captures.entry(lifetime).or_insert_with(|| { - let feed = - self.tcx.create_def(opaque_def_id, Some(ident.name), DefKind::LifetimeParam); + // `opaque_def_id` is unique to the `BoundVarContext` pass which is executed once + // per `resolve_bound_vars` query. This is the only location that creates nested + // lifetime inside a opaque type. `::LifetimeNs(..)` is thus unique + // to this query and duplicates within the query are handled by `self.disambiguator`. + let feed = self.tcx.create_def( + opaque_def_id, + Some(ident.name), + DefKind::LifetimeParam, + None, + &mut self.disambiguator, + ); feed.def_span(ident.span); feed.def_ident_span(Some(ident.span)); feed.def_id() diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index fcb7382549f4..5e79e9320153 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -1770,7 +1770,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { span: Span, opt_self_ty: Option>, item_def_id: DefId, - trait_segment: &hir::PathSegment<'tcx>, + trait_segment: Option<&hir::PathSegment<'tcx>>, item_segment: &hir::PathSegment<'tcx>, ) -> Ty<'tcx> { match self.lower_qpath_shared( @@ -1795,7 +1795,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { span: Span, opt_self_ty: Option>, item_def_id: DefId, - trait_segment: &hir::PathSegment<'tcx>, + trait_segment: Option<&hir::PathSegment<'tcx>>, item_segment: &hir::PathSegment<'tcx>, ) -> Const<'tcx> { match self.lower_qpath_shared( @@ -1820,7 +1820,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { span: Span, opt_self_ty: Option>, item_def_id: DefId, - trait_segment: &hir::PathSegment<'tcx>, + trait_segment: Option<&hir::PathSegment<'tcx>>, item_segment: &hir::PathSegment<'tcx>, assoc_tag: ty::AssocTag, ) -> Result<(DefId, GenericArgsRef<'tcx>), ErrorGuaranteed> { @@ -1840,7 +1840,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { debug!(?self_ty); let trait_ref = - self.lower_mono_trait_ref(span, trait_def_id, self_ty, trait_segment, false); + self.lower_mono_trait_ref(span, trait_def_id, self_ty, trait_segment.unwrap(), false); debug!(?trait_ref); let item_args = @@ -2196,16 +2196,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } } Res::Def(DefKind::AssocTy, def_id) => { - debug_assert!(path.segments.len() >= 2); - let _ = self.prohibit_generic_args( - path.segments[..path.segments.len() - 2].iter(), - GenericsArgsErrExtend::None, - ); + let trait_segment = if let [modules @ .., trait_, _item] = path.segments { + let _ = self.prohibit_generic_args(modules.iter(), GenericsArgsErrExtend::None); + Some(trait_) + } else { + None + }; self.lower_qpath_ty( span, opt_self_ty, def_id, - &path.segments[path.segments.len() - 2], + trait_segment, path.segments.last().unwrap(), ) } @@ -2413,16 +2414,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ty::Const::new_unevaluated(tcx, ty::UnevaluatedConst::new(did, args)) } Res::Def(DefKind::AssocConst, did) => { - debug_assert!(path.segments.len() >= 2); - let _ = self.prohibit_generic_args( - path.segments[..path.segments.len() - 2].iter(), - GenericsArgsErrExtend::None, - ); + let trait_segment = if let [modules @ .., trait_, _item] = path.segments { + let _ = self.prohibit_generic_args(modules.iter(), GenericsArgsErrExtend::None); + Some(trait_) + } else { + None + }; self.lower_qpath_const( span, opt_self_ty, did, - &path.segments[path.segments.len() - 2], + trait_segment, path.segments.last().unwrap(), ) } diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 309b8f2c7613..91dde13be550 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -216,7 +216,7 @@ pub fn check_crate(tcx: TyCtxt<'_>) { check::maybe_check_static_with_link_section(tcx, item_def_id); } DefKind::Const if tcx.generics_of(item_def_id).is_empty() => { - let instance = ty::Instance::new(item_def_id.into(), ty::GenericArgs::empty()); + let instance = ty::Instance::new_raw(item_def_id.into(), ty::GenericArgs::empty()); let cid = GlobalId { instance, promoted: None }; let typing_env = ty::TypingEnv::fully_monomorphized(); tcx.ensure_ok().eval_to_const_value_raw(typing_env.as_query_input(cid)); diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 15e997aebcb8..09bf84ab64fb 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -110,6 +110,7 @@ impl<'a> State<'a> { } self.print_attr_item(&unparsed, unparsed.span); self.word("]"); + self.hardbreak() } hir::Attribute::Parsed(AttributeKind::DocComment { style, kind, comment, .. }) => { self.word(rustc_ast_pretty::pprust::state::doc_comment_to_string( @@ -183,7 +184,7 @@ impl<'a> State<'a> { Node::Ty(a) => self.print_type(a), Node::AssocItemConstraint(a) => self.print_assoc_item_constraint(a), Node::TraitRef(a) => self.print_trait_ref(a), - Node::OpaqueTy(o) => self.print_opaque_ty(o), + Node::OpaqueTy(_) => panic!("cannot print Node::OpaqueTy"), Node::Pat(a) => self.print_pat(a), Node::TyPat(a) => self.print_ty_pat(a), Node::PatField(a) => self.print_patfield(a), @@ -654,10 +655,11 @@ impl<'a> State<'a> { self.bclose(item.span, cb); } hir::ItemKind::GlobalAsm { asm, .. } => { - // FIXME(nnethercote): `ib` is unclosed - let (cb, _ib) = self.head("global_asm!"); + let (cb, ib) = self.head("global_asm!"); self.print_inline_asm(asm); - self.end(cb) + self.word(";"); + self.end(cb); + self.end(ib); } hir::ItemKind::TyAlias(ident, ty, generics) => { let (cb, ib) = self.head("type"); @@ -764,14 +766,6 @@ impl<'a> State<'a> { self.print_path(t.path, false); } - fn print_opaque_ty(&mut self, o: &hir::OpaqueTy<'_>) { - // FIXME(nnethercote): `cb` and `ib` are unclosed - let (_cb, _ib) = self.head("opaque"); - self.word("{"); - self.print_bounds("impl", o.bounds); - self.word("}"); - } - fn print_formal_generic_params(&mut self, generic_params: &[hir::GenericParam<'_>]) { if !generic_params.is_empty() { self.word("for"); @@ -1509,7 +1503,7 @@ impl<'a> State<'a> { } hir::ExprKind::DropTemps(init) => { // Print `{`: - let cb = self.cbox(INDENT_UNIT); + let cb = self.cbox(0); let ib = self.ibox(0); self.bopen(ib); @@ -1532,16 +1526,18 @@ impl<'a> State<'a> { self.print_if(test, blk, elseopt); } hir::ExprKind::Loop(blk, opt_label, _, _) => { + let cb = self.cbox(0); + let ib = self.ibox(0); if let Some(label) = opt_label { self.print_ident(label.ident); self.word_space(":"); } - let (cb, ib) = self.head("loop"); + self.word_nbsp("loop"); self.print_block(blk, cb, ib); } hir::ExprKind::Match(expr, arms, _) => { - let cb = self.cbox(INDENT_UNIT); - let ib = self.ibox(INDENT_UNIT); + let cb = self.cbox(0); + let ib = self.ibox(0); self.word_nbsp("match"); self.print_expr_as_cond(expr); self.space(); @@ -1572,15 +1568,6 @@ impl<'a> State<'a> { // This is a bare expression. self.ann.nested(self, Nested::Body(body)); - // FIXME(nnethercote): this is bogus - let fake_ib = BoxMarker; - self.end(fake_ib); - - // A box will be closed by `print_expr`, but we didn't want an overall - // wrapper so we closed the corresponding opening. so create an - // empty box to satisfy the close. - // FIXME(nnethercote): this is bogus, and `print_expr` is missing - let _ib = self.ibox(0); } hir::ExprKind::Block(blk, opt_label) => { if let Some(label) = opt_label { diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs index 38319862334a..61dd8c573073 100644 --- a/compiler/rustc_hir_typeck/src/_match.rs +++ b/compiler/rustc_hir_typeck/src/_match.rs @@ -11,7 +11,7 @@ use rustc_trait_selection::traits::{ use tracing::{debug, instrument}; use crate::coercion::{AsCoercionSite, CoerceMany}; -use crate::{Diverges, Expectation, FnCtxt, Needs}; +use crate::{Diverges, Expectation, FnCtxt, GatherLocalsVisitor, Needs}; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { #[instrument(skip(self), level = "debug", ret)] @@ -43,6 +43,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // #55810: Type check patterns first so we get types for all bindings. let scrut_span = scrut.span.find_ancestor_inside(expr.span).unwrap_or(scrut.span); for arm in arms { + GatherLocalsVisitor::gather_from_arm(self, arm); + self.check_pat_top(arm.pat, scrutinee_ty, Some(scrut_span), Some(scrut), None); } @@ -601,7 +603,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // FIXME(-Znext-solver): Remove this branch once `replace_opaque_types_with_infer` is gone. ty::Infer(ty::TyVar(_)) => self .inner - .borrow() + .borrow_mut() + .opaque_types() .iter_opaque_types() .find(|(_, v)| v.ty == expected_ty) .map(|(k, _)| (k.def_id, k.args))?, diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index caf36ba47bd7..5bfc3e810d9f 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -1051,20 +1051,19 @@ impl<'a, 'tcx> CastCheck<'tcx> { fn check_ref_cast( &self, fcx: &FnCtxt<'a, 'tcx>, - m_expr: ty::TypeAndMut<'tcx>, - m_cast: ty::TypeAndMut<'tcx>, + mut m_expr: ty::TypeAndMut<'tcx>, + mut m_cast: ty::TypeAndMut<'tcx>, ) -> Result> { // array-ptr-cast: allow mut-to-mut, mut-to-const, const-to-const + m_expr.ty = fcx.try_structurally_resolve_type(self.expr_span, m_expr.ty); + m_cast.ty = fcx.try_structurally_resolve_type(self.cast_span, m_cast.ty); + if m_expr.mutbl >= m_cast.mutbl && let ty::Array(ety, _) = m_expr.ty.kind() && fcx.can_eq(fcx.param_env, *ety, m_cast.ty) { - // Due to the limitations of LLVM global constants, - // region pointers end up pointing at copies of - // vector elements instead of the original values. - // To allow raw pointers to work correctly, we - // need to special-case obtaining a raw pointer - // from a region pointer to a vector. + // Due to historical reasons we allow directly casting references of + // arrays into raw pointers of their element type. // Coerce to a raw pointer so that we generate RawPtr in MIR. let array_ptr_type = Ty::new_ptr(fcx.tcx, m_expr.ty, m_expr.mutbl); diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs index 2189fdf0f343..99103f14d682 100644 --- a/compiler/rustc_hir_typeck/src/check.rs +++ b/compiler/rustc_hir_typeck/src/check.rs @@ -3,7 +3,6 @@ use std::cell::RefCell; use rustc_abi::ExternAbi; use rustc_hir as hir; use rustc_hir::def::DefKind; -use rustc_hir::intravisit::Visitor; use rustc_hir::lang_items::LangItem; use rustc_hir_analysis::check::check_function_signature; use rustc_infer::infer::RegionVariableOrigin; @@ -50,7 +49,9 @@ pub(super) fn check_fn<'a, 'tcx>( let span = body.value.span; - GatherLocalsVisitor::new(fcx).visit_body(body); + for param in body.params { + GatherLocalsVisitor::gather_from_param(fcx, param); + } // C-variadic fns also have a `VaList` input that's not listed in `fn_sig` // (as it's created inside the body itself, not passed in from outside). diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index db2650ed357e..2c28ffd1fe3d 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -16,7 +16,6 @@ use rustc_errors::{ }; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::DefId; -use rustc_hir::intravisit::Visitor; use rustc_hir::lang_items::LangItem; use rustc_hir::{ExprKind, HirId, QPath}; use rustc_hir_analysis::NoVariantNamed; @@ -50,8 +49,8 @@ use crate::errors::{ YieldExprOutsideOfCoroutine, }; use crate::{ - BreakableCtxt, CoroutineTypes, Diverges, FnCtxt, Needs, TupleArgumentsFlag, cast, - fatally_break_rust, report_unexpected_variant_res, type_error_struct, + BreakableCtxt, CoroutineTypes, Diverges, FnCtxt, GatherLocalsVisitor, Needs, + TupleArgumentsFlag, cast, fatally_break_rust, report_unexpected_variant_res, type_error_struct, }; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { @@ -1518,11 +1517,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let_expr: &'tcx hir::LetExpr<'tcx>, hir_id: HirId, ) -> Ty<'tcx> { + GatherLocalsVisitor::gather_from_let_expr(self, let_expr, hir_id); + // for let statements, this is done in check_stmt let init = let_expr.init; self.warn_if_unreachable(init.hir_id, init.span, "block in `let` expression"); + // otherwise check exactly as a let statement self.check_decl((let_expr, hir_id).into()); + // but return a bool, for this is a boolean expression if let ast::Recovered::Yes(error_guaranteed) = let_expr.recovered { self.set_tainted_by_errors(error_guaranteed); @@ -1827,7 +1830,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Create a new function context. let def_id = block.def_id; let fcx = FnCtxt::new(self, self.param_env, def_id); - crate::GatherLocalsVisitor::new(&fcx).visit_body(body); let ty = fcx.check_expr_with_expectation(body.value, expected); fcx.require_type_is_sized(ty, body.value.span, ObligationCauseCode::SizedConstOrStatic); diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs index 17e13ec0a376..3493d359028d 100644 --- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -158,7 +158,7 @@ pub trait TypeInformationCtxt<'tcx> { fn resolve_vars_if_possible>>(&self, t: T) -> T; - fn try_structurally_resolve_type(&self, span: Span, ty: Ty<'tcx>) -> Ty<'tcx>; + fn structurally_resolve_type(&self, span: Span, ty: Ty<'tcx>) -> Ty<'tcx>; fn report_bug(&self, span: Span, msg: impl ToString) -> Self::Error; @@ -191,8 +191,8 @@ impl<'tcx> TypeInformationCtxt<'tcx> for &FnCtxt<'_, 'tcx> { self.infcx.resolve_vars_if_possible(t) } - fn try_structurally_resolve_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> { - (**self).try_structurally_resolve_type(sp, ty) + fn structurally_resolve_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> { + (**self).structurally_resolve_type(sp, ty) } fn report_bug(&self, span: Span, msg: impl ToString) -> Self::Error { @@ -236,7 +236,7 @@ impl<'tcx> TypeInformationCtxt<'tcx> for (&LateContext<'tcx>, LocalDefId) { self.0.maybe_typeck_results().expect("expected typeck results") } - fn try_structurally_resolve_type(&self, _span: Span, ty: Ty<'tcx>) -> Ty<'tcx> { + fn structurally_resolve_type(&self, _span: Span, ty: Ty<'tcx>) -> Ty<'tcx> { // FIXME: Maybe need to normalize here. ty } @@ -776,7 +776,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx // Select just those fields of the `with` // expression that will actually be used - match self.cx.try_structurally_resolve_type(with_expr.span, with_place.place.ty()).kind() { + match self.cx.structurally_resolve_type(with_expr.span, with_place.place.ty()).kind() { ty::Adt(adt, args) if adt.is_struct() => { // Consume those fields of the with expression that are needed. for (f_index, with_field) in adt.non_enum_variant().fields.iter_enumerated() { @@ -1176,7 +1176,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx /// two operations: a dereference to reach the array data and then an index to /// jump forward to the relevant item. impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx, Cx, D> { - fn resolve_type_vars_or_bug( + fn expect_and_resolve_type( &self, id: HirId, ty: Option>, @@ -1185,12 +1185,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx Some(ty) => { let ty = self.cx.resolve_vars_if_possible(ty); self.cx.error_reported_in_ty(ty)?; - if ty.is_ty_var() { - debug!("resolve_type_vars_or_bug: infer var from {:?}", ty); - Err(self.cx.report_bug(self.cx.tcx().hir_span(id), "encountered type variable")) - } else { - Ok(ty) - } + Ok(ty) } None => { // FIXME: We shouldn't be relying on the infcx being tainted. @@ -1201,15 +1196,15 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx } fn node_ty(&self, hir_id: HirId) -> Result, Cx::Error> { - self.resolve_type_vars_or_bug(hir_id, self.cx.typeck_results().node_type_opt(hir_id)) + self.expect_and_resolve_type(hir_id, self.cx.typeck_results().node_type_opt(hir_id)) } fn expr_ty(&self, expr: &hir::Expr<'_>) -> Result, Cx::Error> { - self.resolve_type_vars_or_bug(expr.hir_id, self.cx.typeck_results().expr_ty_opt(expr)) + self.expect_and_resolve_type(expr.hir_id, self.cx.typeck_results().expr_ty_opt(expr)) } fn expr_ty_adjusted(&self, expr: &hir::Expr<'_>) -> Result, Cx::Error> { - self.resolve_type_vars_or_bug( + self.expect_and_resolve_type( expr.hir_id, self.cx.typeck_results().expr_ty_adjusted_opt(expr), ) @@ -1264,10 +1259,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx // a bind-by-ref means that the base_ty will be the type of the ident itself, // but what we want here is the type of the underlying value being borrowed. // So peel off one-level, turning the &T into T. - match self - .cx - .try_structurally_resolve_type(pat.span, base_ty) - .builtin_deref(false) + match self.cx.structurally_resolve_type(pat.span, base_ty).builtin_deref(false) { Some(ty) => Ok(ty), None => { @@ -1513,10 +1505,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx if node_ty != place_ty && self .cx - .try_structurally_resolve_type( - self.cx.tcx().hir_span(base_place.hir_id), - place_ty, - ) + .structurally_resolve_type(self.cx.tcx().hir_span(base_place.hir_id), place_ty) .is_impl_trait() { projections.push(Projection { kind: ProjectionKind::OpaqueCast, ty: node_ty }); @@ -1538,7 +1527,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx let base_ty = self.expr_ty_adjusted(base)?; let ty::Ref(region, _, mutbl) = - *self.cx.try_structurally_resolve_type(base.span, base_ty).kind() + *self.cx.structurally_resolve_type(base.span, base_ty).kind() else { span_bug!(expr.span, "cat_overloaded_place: base is not a reference"); }; @@ -1556,7 +1545,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx let base_curr_ty = base_place.place.ty(); let deref_ty = match self .cx - .try_structurally_resolve_type(self.cx.tcx().hir_span(base_place.hir_id), base_curr_ty) + .structurally_resolve_type(self.cx.tcx().hir_span(base_place.hir_id), base_curr_ty) .builtin_deref(true) { Some(ty) => ty, @@ -1584,7 +1573,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx ) -> Result { let res = self.cx.typeck_results().qpath_res(qpath, pat_hir_id); let ty = self.cx.typeck_results().node_type(pat_hir_id); - let ty::Adt(adt_def, _) = self.cx.try_structurally_resolve_type(span, ty).kind() else { + let ty::Adt(adt_def, _) = self.cx.structurally_resolve_type(span, ty).kind() else { return Err(self .cx .report_bug(span, "struct or tuple struct pattern not applied to an ADT")); @@ -1616,7 +1605,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx span: Span, ) -> Result { let ty = self.cx.typeck_results().node_type(pat_hir_id); - match self.cx.try_structurally_resolve_type(span, ty).kind() { + match self.cx.structurally_resolve_type(span, ty).kind() { ty::Adt(adt_def, _) => Ok(adt_def.variant(variant_index).fields.len()), _ => { self.cx @@ -1631,7 +1620,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx /// Here `pat_hir_id` is the HirId of the pattern itself. fn total_fields_in_tuple(&self, pat_hir_id: HirId, span: Span) -> Result { let ty = self.cx.typeck_results().node_type(pat_hir_id); - match self.cx.try_structurally_resolve_type(span, ty).kind() { + match self.cx.structurally_resolve_type(span, ty).kind() { ty::Tuple(args) => Ok(args.len()), _ => Err(self.cx.report_bug(span, "tuple pattern not applied to a tuple")), } @@ -1820,7 +1809,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx PatKind::Slice(before, ref slice, after) => { let Some(element_ty) = self .cx - .try_structurally_resolve_type(pat.span, place_with_id.place.ty()) + .structurally_resolve_type(pat.span, place_with_id.place.ty()) .builtin_index() else { debug!("explicit index of non-indexable type {:?}", place_with_id); @@ -1890,7 +1879,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx } fn is_multivariant_adt(&self, ty: Ty<'tcx>, span: Span) -> bool { - if let ty::Adt(def, _) = self.cx.try_structurally_resolve_type(span, ty).kind() { + if let ty::Adt(def, _) = self.cx.structurally_resolve_type(span, ty).kind() { // Note that if a non-exhaustive SingleVariant is defined in another crate, we need // to assume that more cases will be added to the variant in the future. This mean // that we should handle non-exhaustive SingleVariant the same way we would handle diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index c804dc5e7fba..6cc7e82bbf73 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -37,8 +37,8 @@ use crate::method::probe::IsSuggestion; use crate::method::probe::Mode::MethodCall; use crate::method::probe::ProbeScope::TraitsInScope; use crate::{ - BreakableCtxt, Diverges, Expectation, FnCtxt, LoweredTy, Needs, TupleArgumentsFlag, errors, - struct_span_code_err, + BreakableCtxt, Diverges, Expectation, FnCtxt, GatherLocalsVisitor, LoweredTy, Needs, + TupleArgumentsFlag, errors, struct_span_code_err, }; rustc_index::newtype_index! { @@ -1765,6 +1765,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Type check a `let` statement. fn check_decl_local(&self, local: &'tcx hir::LetStmt<'tcx>) { + GatherLocalsVisitor::gather_from_local(self, local); + let ty = self.check_decl(local.into()); self.write_ty(local.hir_id, ty); if local.pat.is_never_pattern() { diff --git a/compiler/rustc_hir_typeck/src/gather_locals.rs b/compiler/rustc_hir_typeck/src/gather_locals.rs index 5d87e800096f..a8bbc89dbded 100644 --- a/compiler/rustc_hir_typeck/src/gather_locals.rs +++ b/compiler/rustc_hir_typeck/src/gather_locals.rs @@ -55,6 +55,14 @@ impl<'a> From<(&'a hir::LetExpr<'a>, HirId)> for Declaration<'a> { } } +/// The `GatherLocalsVisitor` is responsible for initializing local variable types +/// in the [`ty::TypeckResults`] for all subpatterns in statements and expressions +/// like `let`, `match`, and params of function bodies. It also adds `Sized` bounds +/// for these types (with exceptions for unsized feature gates like `unsized_fn_params`). +/// +/// Failure to visit locals will cause an ICE in writeback when the local's type is +/// resolved. Visiting locals twice will ICE in the `GatherLocalsVisitor`, since it +/// will overwrite the type previously stored in the local. pub(super) struct GatherLocalsVisitor<'a, 'tcx> { fcx: &'a FnCtxt<'a, 'tcx>, // parameters are special cases of patterns, but we want to handle them as @@ -63,9 +71,37 @@ pub(super) struct GatherLocalsVisitor<'a, 'tcx> { outermost_fn_param_pat: Option<(Span, HirId)>, } +// N.B. additional `gather_*` functions should be careful to only walk the pattern +// for new expressions, since visiting sub-expressions or nested bodies may initialize +// locals which are not conceptually owned by the gathered statement or expression. impl<'a, 'tcx> GatherLocalsVisitor<'a, 'tcx> { - pub(super) fn new(fcx: &'a FnCtxt<'a, 'tcx>) -> Self { - Self { fcx, outermost_fn_param_pat: None } + pub(crate) fn gather_from_local(fcx: &'a FnCtxt<'a, 'tcx>, local: &'tcx hir::LetStmt<'tcx>) { + let mut visitor = GatherLocalsVisitor { fcx, outermost_fn_param_pat: None }; + visitor.declare(local.into()); + visitor.visit_pat(local.pat); + } + + pub(crate) fn gather_from_let_expr( + fcx: &'a FnCtxt<'a, 'tcx>, + let_expr: &'tcx hir::LetExpr<'tcx>, + expr_hir_id: hir::HirId, + ) { + let mut visitor = GatherLocalsVisitor { fcx, outermost_fn_param_pat: None }; + visitor.declare((let_expr, expr_hir_id).into()); + visitor.visit_pat(let_expr.pat); + } + + pub(crate) fn gather_from_param(fcx: &'a FnCtxt<'a, 'tcx>, param: &'tcx hir::Param<'tcx>) { + let mut visitor = GatherLocalsVisitor { + fcx, + outermost_fn_param_pat: Some((param.ty_span, param.hir_id)), + }; + visitor.visit_pat(param.pat); + } + + pub(crate) fn gather_from_arm(fcx: &'a FnCtxt<'a, 'tcx>, local: &'tcx hir::Arm<'tcx>) { + let mut visitor = GatherLocalsVisitor { fcx, outermost_fn_param_pat: None }; + visitor.visit_pat(local.pat); } fn assign(&mut self, span: Span, nid: HirId, ty_opt: Option>) -> Ty<'tcx> { @@ -73,12 +109,12 @@ impl<'a, 'tcx> GatherLocalsVisitor<'a, 'tcx> { None => { // Infer the variable's type. let var_ty = self.fcx.next_ty_var(span); - self.fcx.locals.borrow_mut().insert(nid, var_ty); + assert_eq!(self.fcx.locals.borrow_mut().insert(nid, var_ty), None); var_ty } Some(typ) => { // Take type that the user specified. - self.fcx.locals.borrow_mut().insert(nid, typ); + assert_eq!(self.fcx.locals.borrow_mut().insert(nid, typ), None); typ } } @@ -133,13 +169,6 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> { intravisit::walk_expr(self, expr) } - fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) { - let old_outermost_fn_param_pat = - self.outermost_fn_param_pat.replace((param.ty_span, param.hir_id)); - intravisit::walk_param(self, param); - self.outermost_fn_param_pat = old_outermost_fn_param_pat; - } - // Add pattern bindings. fn visit_pat(&mut self, p: &'tcx hir::Pat<'tcx>) { if let PatKind::Binding(_, _, ident, _) = p.kind { diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index d861a4f81b0e..78233a34c461 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -46,7 +46,6 @@ use rustc_errors::codes::*; use rustc_errors::{Applicability, ErrorGuaranteed, pluralize, struct_span_code_err}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::intravisit::Visitor; use rustc_hir::{HirId, HirIdMap, Node}; use rustc_hir_analysis::check::check_abi; use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer; @@ -191,9 +190,6 @@ fn typeck_with_inspect<'tcx>( let wf_code = ObligationCauseCode::WellFormed(Some(WellFormedLoc::Ty(def_id))); fcx.register_wf_obligation(expected_type.into(), body.value.span, wf_code); - // Gather locals in statics (because of block expressions). - GatherLocalsVisitor::new(&fcx).visit_body(body); - fcx.check_expr_coercible_to_type(body.value, expected_type, None); fcx.write_ty(id, expected_type); diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 7520782930a2..f9502153afdc 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -177,16 +177,20 @@ enum PeelKind { /// Only peel reference types. This is used for explicit `deref!(_)` patterns, which dereference /// any number of `&`/`&mut` references, plus a single smart pointer. ExplicitDerefPat, - /// Implicitly peel any number of references, and if `deref_patterns` is enabled, smart pointer - /// ADTs. In order to peel only as much as necessary for the pattern to match, the `until_adt` - /// field contains the ADT def that the pattern is a constructor for, if applicable, so that we - /// don't peel it. See [`ResolvedPat`] for more information. - Implicit { until_adt: Option }, + /// Implicitly peel references, and if `deref_patterns` is enabled, smart pointer ADTs. + Implicit { + /// The ADT the pattern is a constructor for, if applicable, so that we don't peel it. See + /// [`ResolvedPat`] for more information. + until_adt: Option, + /// The number of references at the head of the pattern's type, so we can leave that many + /// untouched. This is `1` for string literals, and `0` for most patterns. + pat_ref_layers: usize, + }, } impl AdjustMode { const fn peel_until_adt(opt_adt_def: Option) -> AdjustMode { - AdjustMode::Peel { kind: PeelKind::Implicit { until_adt: opt_adt_def } } + AdjustMode::Peel { kind: PeelKind::Implicit { until_adt: opt_adt_def, pat_ref_layers: 0 } } } const fn peel_all() -> AdjustMode { AdjustMode::peel_until_adt(None) @@ -488,9 +492,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match pat.kind { // Peel off a `&` or `&mut` from the scrutinee type. See the examples in // `tests/ui/rfcs/rfc-2005-default-binding-mode`. - _ if let AdjustMode::Peel { .. } = adjust_mode + _ if let AdjustMode::Peel { kind: peel_kind } = adjust_mode && pat.default_binding_modes - && let ty::Ref(_, inner_ty, inner_mutability) = *expected.kind() => + && let ty::Ref(_, inner_ty, inner_mutability) = *expected.kind() + && self.should_peel_ref(peel_kind, expected) => { debug!("inspecting {:?}", expected); @@ -531,24 +536,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // If `deref_patterns` is enabled, peel a smart pointer from the scrutinee type. See the // examples in `tests/ui/pattern/deref_patterns/`. _ if self.tcx.features().deref_patterns() - && let AdjustMode::Peel { kind: PeelKind::Implicit { until_adt } } = adjust_mode + && let AdjustMode::Peel { kind: peel_kind } = adjust_mode && pat.default_binding_modes - // For simplicity, only apply overloaded derefs if `expected` is a known ADT. - // FIXME(deref_patterns): we'll get better diagnostics for users trying to - // implicitly deref generics if we allow them here, but primitives, tuples, and - // inference vars definitely should be stopped. Figure out what makes most sense. - && let ty::Adt(scrutinee_adt, _) = *expected.kind() - // Don't peel if the pattern type already matches the scrutinee. E.g., stop here if - // matching on a `Cow<'a, T>` scrutinee with a `Cow::Owned(_)` pattern. - && until_adt != Some(scrutinee_adt.did()) - // At this point, the pattern isn't able to match `expected` without peeling. Check - // that it implements `Deref` before assuming it's a smart pointer, to get a normal - // type error instead of a missing impl error if not. This only checks for `Deref`, - // not `DerefPure`: we require that too, but we want a trait error if it's missing. - && let Some(deref_trait) = self.tcx.lang_items().deref_trait() - && self - .type_implements_trait(deref_trait, [expected], self.param_env) - .may_apply() => + && self.should_peel_smart_pointer(peel_kind, expected) => { debug!("scrutinee ty {expected:?} is a smart pointer, inserting overloaded deref"); // The scrutinee is a smart pointer; implicitly dereference it. This adds a @@ -680,21 +670,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // String and byte-string literals result in types `&str` and `&[u8]` respectively. // All other literals result in non-reference types. - // As a result, we allow `if let 0 = &&0 {}` but not `if let "foo" = &&"foo" {}`. - // - // Call `resolve_vars_if_possible` here for inline const blocks. - PatKind::Expr(lt) => match self.resolve_vars_if_possible(self.check_pat_expr_unadjusted(lt)).kind() { - ty::Ref(..) => AdjustMode::Pass, - _ => { - // Path patterns have already been handled, and inline const blocks currently - // aren't possible to write, so any handling for them would be untested. - if cfg!(debug_assertions) - && self.tcx.features().deref_patterns() - && !matches!(lt.kind, PatExprKind::Lit { .. }) - { - span_bug!(lt.span, "FIXME(deref_patterns): adjust mode unimplemented for {:?}", lt.kind); + // As a result, we allow `if let 0 = &&0 {}` but not `if let "foo" = &&"foo" {}` unless + // `deref_patterns` is enabled. + PatKind::Expr(lt) => { + // Path patterns have already been handled, and inline const blocks currently + // aren't possible to write, so any handling for them would be untested. + if cfg!(debug_assertions) + && self.tcx.features().deref_patterns() + && !matches!(lt.kind, PatExprKind::Lit { .. }) + { + span_bug!(lt.span, "FIXME(deref_patterns): adjust mode unimplemented for {:?}", lt.kind); + } + // Call `resolve_vars_if_possible` here for inline const blocks. + let lit_ty = self.resolve_vars_if_possible(self.check_pat_expr_unadjusted(lt)); + // If `deref_patterns` is enabled, allow `if let "foo" = &&"foo" {}`. + if self.tcx.features().deref_patterns() { + let mut peeled_ty = lit_ty; + let mut pat_ref_layers = 0; + while let ty::Ref(_, inner_ty, mutbl) = *peeled_ty.kind() { + // We rely on references at the head of constants being immutable. + debug_assert!(mutbl.is_not()); + pat_ref_layers += 1; + peeled_ty = inner_ty; } - AdjustMode::peel_all() + AdjustMode::Peel { kind: PeelKind::Implicit { until_adt: None, pat_ref_layers } } + } else { + if lit_ty.is_ref() { AdjustMode::Pass } else { AdjustMode::peel_all() } } }, @@ -720,6 +721,67 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + /// Assuming `expected` is a reference type, determine whether to peel it before matching. + fn should_peel_ref(&self, peel_kind: PeelKind, mut expected: Ty<'tcx>) -> bool { + debug_assert!(expected.is_ref()); + let pat_ref_layers = match peel_kind { + PeelKind::ExplicitDerefPat => 0, + PeelKind::Implicit { pat_ref_layers, .. } => pat_ref_layers, + }; + + // Most patterns don't have reference types, so we'll want to peel all references from the + // scrutinee before matching. To optimize for the common case, return early. + if pat_ref_layers == 0 { + return true; + } + debug_assert!( + self.tcx.features().deref_patterns(), + "Peeling for patterns with reference types is gated by `deref_patterns`." + ); + + // If the pattern has as many or more layers of reference as the expected type, we can match + // without peeling more, unless we find a smart pointer or `&mut` that we also need to peel. + // We don't treat `&` and `&mut` as interchangeable, but by peeling `&mut`s before matching, + // we can still, e.g., match on a `&mut str` with a string literal pattern. This is because + // string literal patterns may be used where `str` is expected. + let mut expected_ref_layers = 0; + while let ty::Ref(_, inner_ty, mutbl) = *expected.kind() { + if mutbl.is_mut() { + // Mutable references can't be in the final value of constants, thus they can't be + // at the head of their types, thus we should always peel `&mut`. + return true; + } + expected_ref_layers += 1; + expected = inner_ty; + } + pat_ref_layers < expected_ref_layers || self.should_peel_smart_pointer(peel_kind, expected) + } + + /// Determine whether `expected` is a smart pointer type that should be peeled before matching. + fn should_peel_smart_pointer(&self, peel_kind: PeelKind, expected: Ty<'tcx>) -> bool { + // Explicit `deref!(_)` patterns match against smart pointers; don't peel in that case. + if let PeelKind::Implicit { until_adt, .. } = peel_kind + // For simplicity, only apply overloaded derefs if `expected` is a known ADT. + // FIXME(deref_patterns): we'll get better diagnostics for users trying to + // implicitly deref generics if we allow them here, but primitives, tuples, and + // inference vars definitely should be stopped. Figure out what makes most sense. + && let ty::Adt(scrutinee_adt, _) = *expected.kind() + // Don't peel if the pattern type already matches the scrutinee. E.g., stop here if + // matching on a `Cow<'a, T>` scrutinee with a `Cow::Owned(_)` pattern. + && until_adt != Some(scrutinee_adt.did()) + // At this point, the pattern isn't able to match `expected` without peeling. Check + // that it implements `Deref` before assuming it's a smart pointer, to get a normal + // type error instead of a missing impl error if not. This only checks for `Deref`, + // not `DerefPure`: we require that too, but we want a trait error if it's missing. + && let Some(deref_trait) = self.tcx.lang_items().deref_trait() + && self.type_implements_trait(deref_trait, [expected], self.param_env).may_apply() + { + true + } else { + false + } + } + fn check_pat_expr_unadjusted(&self, lt: &'tcx hir::PatExpr<'tcx>) -> Ty<'tcx> { let ty = match <.kind { rustc_hir::PatExprKind::Lit { lit, negated } => { diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index 4a171a08ef72..8e7ce83044cd 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -555,15 +555,16 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { } } - if let Err(guar) = check_opaque_type_parameter_valid( + if let Err(err) = check_opaque_type_parameter_valid( &self.fcx, opaque_type_key, hidden_type.span, DefiningScopeKind::HirTypeck, ) { - self.typeck_results - .concrete_opaque_types - .insert(opaque_type_key.def_id, ty::OpaqueHiddenType::new_error(tcx, guar)); + self.typeck_results.concrete_opaque_types.insert( + opaque_type_key.def_id, + ty::OpaqueHiddenType::new_error(tcx, err.report(self.fcx)), + ); } let hidden_type = hidden_type.remap_generic_params_to_declaration_params( diff --git a/compiler/rustc_incremental/src/assert_dep_graph.rs b/compiler/rustc_incremental/src/assert_dep_graph.rs index 1b2056f541f3..0e04a2a784ec 100644 --- a/compiler/rustc_incremental/src/assert_dep_graph.rs +++ b/compiler/rustc_incremental/src/assert_dep_graph.rs @@ -38,7 +38,7 @@ use std::fs::{self, File}; use std::io::Write; use rustc_data_structures::fx::FxIndexSet; -use rustc_data_structures::graph::implementation::{Direction, INCOMING, NodeIndex, OUTGOING}; +use rustc_data_structures::graph::linked_graph::{Direction, INCOMING, NodeIndex, OUTGOING}; use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId}; use rustc_hir::intravisit::{self, Visitor}; use rustc_middle::dep_graph::{ diff --git a/compiler/rustc_incremental/src/persist/save.rs b/compiler/rustc_incremental/src/persist/save.rs index 94ce6d9fa81f..58fea3278a83 100644 --- a/compiler/rustc_incremental/src/persist/save.rs +++ b/compiler/rustc_incremental/src/persist/save.rs @@ -44,10 +44,6 @@ pub(crate) fn save_dep_graph(tcx: TyCtxt<'_>) { sess.time("assert_dep_graph", || assert_dep_graph(tcx)); sess.time("check_dirty_clean", || dirty_clean::check_dirty_clean_annotations(tcx)); - if sess.opts.unstable_opts.incremental_info { - tcx.dep_graph.print_incremental_info() - } - join( move || { sess.time("incr_comp_persist_dep_graph", || { @@ -172,12 +168,5 @@ pub(crate) fn build_dep_graph( // First encode the commandline arguments hash sess.opts.dep_tracking_hash(false).encode(&mut encoder); - Some(DepGraph::new( - sess, - prev_graph, - prev_work_products, - encoder, - sess.opts.unstable_opts.query_dep_graph, - sess.opts.unstable_opts.incremental_info, - )) + Some(DepGraph::new(sess, prev_graph, prev_work_products, encoder)) } diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index 5220071c5005..1ae864c454f2 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -132,7 +132,13 @@ impl<'tcx> InferCtxt<'tcx> { let certainty = if errors.is_empty() { Certainty::Proven } else { Certainty::Ambiguous }; - let opaque_types = self.take_opaque_types_for_query_response(); + let opaque_types = self + .inner + .borrow_mut() + .opaque_type_storage + .take_opaque_types() + .map(|(k, v)| (k, v.ty)) + .collect(); Ok(QueryResponse { var_values: inference_vars, @@ -143,24 +149,6 @@ impl<'tcx> InferCtxt<'tcx> { }) } - /// Used by the new solver as that one takes the opaque types at the end of a probe - /// to deal with multiple candidates without having to recompute them. - pub fn clone_opaque_types_for_query_response( - &self, - ) -> Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)> { - self.inner - .borrow() - .opaque_type_storage - .opaque_types - .iter() - .map(|(k, v)| (*k, v.ty)) - .collect() - } - - fn take_opaque_types_for_query_response(&self) -> Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)> { - self.take_opaque_types().into_iter().map(|(k, v)| (k, v.ty)).collect() - } - /// Given the (canonicalized) result to a canonical query, /// instantiates the result so it can be used, plugging in the /// values from the canonical query. (Note that the result may diff --git a/compiler/rustc_infer/src/infer/context.rs b/compiler/rustc_infer/src/infer/context.rs index 75affa139770..22d7ce79bb46 100644 --- a/compiler/rustc_infer/src/infer/context.rs +++ b/compiler/rustc_infer/src/infer/context.rs @@ -121,19 +121,19 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> { self.enter_forall(value, f) } - fn equate_ty_vids_raw(&self, a: rustc_type_ir::TyVid, b: rustc_type_ir::TyVid) { + fn equate_ty_vids_raw(&self, a: ty::TyVid, b: ty::TyVid) { self.inner.borrow_mut().type_variables().equate(a, b); } - fn equate_int_vids_raw(&self, a: rustc_type_ir::IntVid, b: rustc_type_ir::IntVid) { + fn equate_int_vids_raw(&self, a: ty::IntVid, b: ty::IntVid) { self.inner.borrow_mut().int_unification_table().union(a, b); } - fn equate_float_vids_raw(&self, a: rustc_type_ir::FloatVid, b: rustc_type_ir::FloatVid) { + fn equate_float_vids_raw(&self, a: ty::FloatVid, b: ty::FloatVid) { self.inner.borrow_mut().float_unification_table().union(a, b); } - fn equate_const_vids_raw(&self, a: rustc_type_ir::ConstVid, b: rustc_type_ir::ConstVid) { + fn equate_const_vids_raw(&self, a: ty::ConstVid, b: ty::ConstVid) { self.inner.borrow_mut().const_unification_table().union(a, b); } @@ -141,8 +141,8 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> { &self, relation: &mut R, target_is_expected: bool, - target_vid: rustc_type_ir::TyVid, - instantiation_variance: rustc_type_ir::Variance, + target_vid: ty::TyVid, + instantiation_variance: ty::Variance, source_ty: Ty<'tcx>, ) -> RelateResult<'tcx, ()> { self.instantiate_ty_var( @@ -154,19 +154,11 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> { ) } - fn instantiate_int_var_raw( - &self, - vid: rustc_type_ir::IntVid, - value: rustc_type_ir::IntVarValue, - ) { + fn instantiate_int_var_raw(&self, vid: ty::IntVid, value: ty::IntVarValue) { self.inner.borrow_mut().int_unification_table().union_value(vid, value); } - fn instantiate_float_var_raw( - &self, - vid: rustc_type_ir::FloatVid, - value: rustc_type_ir::FloatVarValue, - ) { + fn instantiate_float_var_raw(&self, vid: ty::FloatVid, value: ty::FloatVarValue) { self.inner.borrow_mut().float_unification_table().union_value(vid, value); } @@ -174,7 +166,7 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> { &self, relation: &mut R, target_is_expected: bool, - target_vid: rustc_type_ir::ConstVid, + target_vid: ty::ConstVid, source_ct: ty::Const<'tcx>, ) -> RelateResult<'tcx, ()> { self.instantiate_const_var(relation, target_is_expected, target_vid, source_ct) diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs index e3522137d838..2185886901e5 100644 --- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs +++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs @@ -3,8 +3,8 @@ use std::fmt; use rustc_data_structures::fx::FxHashSet; -use rustc_data_structures::graph::implementation::{ - Direction, Graph, INCOMING, NodeIndex, OUTGOING, +use rustc_data_structures::graph::linked_graph::{ + Direction, INCOMING, LinkedGraph, NodeIndex, OUTGOING, }; use rustc_data_structures::intern::Interned; use rustc_data_structures::unord::UnordSet; @@ -118,7 +118,7 @@ struct RegionAndOrigin<'tcx> { origin: SubregionOrigin<'tcx>, } -type RegionGraph<'tcx> = Graph<(), Constraint<'tcx>>; +type RegionGraph<'tcx> = LinkedGraph<(), Constraint<'tcx>>; struct LexicalResolver<'cx, 'tcx> { region_rels: &'cx RegionRelations<'cx, 'tcx>, @@ -668,7 +668,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { fn construct_graph(&self) -> RegionGraph<'tcx> { let num_vars = self.num_vars(); - let mut graph = Graph::new(); + let mut graph = LinkedGraph::new(); for _ in 0..num_vars { graph.add_node(()); diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index d25542dadd59..070d285b5a63 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -31,9 +31,9 @@ use rustc_middle::traits::solve::Goal; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::{ self, BoundVarReplacerDelegate, ConstVid, FloatVid, GenericArg, GenericArgKind, GenericArgs, - GenericArgsRef, GenericParamDefKind, InferConst, IntVid, PseudoCanonicalInput, Term, TermKind, - Ty, TyCtxt, TyVid, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable, - TypeVisitableExt, TypingEnv, TypingMode, fold_regions, + GenericArgsRef, GenericParamDefKind, InferConst, IntVid, OpaqueHiddenType, OpaqueTypeKey, + PseudoCanonicalInput, Term, TermKind, Ty, TyCtxt, TyVid, TypeFoldable, TypeFolder, + TypeSuperFoldable, TypeVisitable, TypeVisitableExt, TypingEnv, TypingMode, fold_regions, }; use rustc_span::{Span, Symbol}; use snapshot::undo_log::InferCtxtUndoLogs; @@ -198,7 +198,7 @@ impl<'tcx> InferCtxtInner<'tcx> { } #[inline] - fn opaque_types(&mut self) -> opaque_types::OpaqueTypeTable<'_, 'tcx> { + pub fn opaque_types(&mut self) -> opaque_types::OpaqueTypeTable<'_, 'tcx> { self.opaque_type_storage.with_log(&mut self.undo_log) } @@ -224,15 +224,6 @@ impl<'tcx> InferCtxtInner<'tcx> { .expect("region constraints already solved") .with_log(&mut self.undo_log) } - - // Iterates through the opaque type definitions without taking them; this holds the - // `InferCtxtInner` lock, so make sure to not do anything with `InferCtxt` side-effects - // while looping through this. - pub fn iter_opaque_types( - &self, - ) -> impl Iterator, ty::OpaqueHiddenType<'tcx>)> { - self.opaque_type_storage.opaque_types.iter().map(|(&k, &v)| (k, v)) - } } pub struct InferCtxt<'tcx> { @@ -954,13 +945,13 @@ impl<'tcx> InferCtxt<'tcx> { } #[instrument(level = "debug", skip(self), ret)] - pub fn take_opaque_types(&self) -> opaque_types::OpaqueTypeMap<'tcx> { - std::mem::take(&mut self.inner.borrow_mut().opaque_type_storage.opaque_types) + pub fn take_opaque_types(&self) -> Vec<(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)> { + self.inner.borrow_mut().opaque_type_storage.take_opaque_types().collect() } #[instrument(level = "debug", skip(self), ret)] - pub fn clone_opaque_types(&self) -> opaque_types::OpaqueTypeMap<'tcx> { - self.inner.borrow().opaque_type_storage.opaque_types.clone() + pub fn clone_opaque_types(&self) -> Vec<(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)> { + self.inner.borrow_mut().opaque_type_storage.iter_opaque_types().collect() } #[inline(always)] diff --git a/compiler/rustc_infer/src/infer/opaque_types/mod.rs b/compiler/rustc_infer/src/infer/opaque_types/mod.rs index ce5d2e6e17a9..df7144c31da5 100644 --- a/compiler/rustc_infer/src/infer/opaque_types/mod.rs +++ b/compiler/rustc_infer/src/infer/opaque_types/mod.rs @@ -1,5 +1,4 @@ use hir::def_id::{DefId, LocalDefId}; -use rustc_data_structures::fx::FxIndexMap; use rustc_hir as hir; use rustc_middle::bug; use rustc_middle::traits::ObligationCause; @@ -19,7 +18,6 @@ use crate::traits::{self, Obligation, PredicateObligations}; mod table; -pub(crate) type OpaqueTypeMap<'tcx> = FxIndexMap, OpaqueHiddenType<'tcx>>; pub(crate) use table::{OpaqueTypeStorage, OpaqueTypeTable}; impl<'tcx> InferCtxt<'tcx> { diff --git a/compiler/rustc_infer/src/infer/opaque_types/table.rs b/compiler/rustc_infer/src/infer/opaque_types/table.rs index ba6cc0d783dd..3c5bf9d722b9 100644 --- a/compiler/rustc_infer/src/infer/opaque_types/table.rs +++ b/compiler/rustc_infer/src/infer/opaque_types/table.rs @@ -1,18 +1,17 @@ +use std::ops::Deref; + +use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::undo_log::UndoLogs; use rustc_middle::bug; use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey, Ty}; use tracing::instrument; -use super::OpaqueTypeMap; use crate::infer::snapshot::undo_log::{InferCtxtUndoLogs, UndoLog}; #[derive(Default, Debug, Clone)] -pub(crate) struct OpaqueTypeStorage<'tcx> { - /// Opaque types found in explicit return types and their - /// associated fresh inference variable. Writeback resolves these - /// variables to get the concrete type, which can be used to - /// 'de-opaque' OpaqueHiddenType, after typeck is done with all functions. - pub opaque_types: OpaqueTypeMap<'tcx>, +pub struct OpaqueTypeStorage<'tcx> { + opaque_types: FxIndexMap, OpaqueHiddenType<'tcx>>, + duplicate_entries: Vec<(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)>, } impl<'tcx> OpaqueTypeStorage<'tcx> { @@ -33,6 +32,52 @@ impl<'tcx> OpaqueTypeStorage<'tcx> { } } + pub(crate) fn pop_duplicate_entry(&mut self) { + let entry = self.duplicate_entries.pop(); + assert!(entry.is_some()); + } + + pub(crate) fn is_empty(&self) -> bool { + let OpaqueTypeStorage { opaque_types, duplicate_entries } = self; + opaque_types.is_empty() && duplicate_entries.is_empty() + } + + pub(crate) fn take_opaque_types( + &mut self, + ) -> impl Iterator, OpaqueHiddenType<'tcx>)> { + let OpaqueTypeStorage { opaque_types, duplicate_entries } = self; + std::mem::take(opaque_types).into_iter().chain(std::mem::take(duplicate_entries)) + } + + /// Only returns the opaque types from the lookup table. These are used + /// when normalizing opaque types and have a unique key. + /// + /// Outside of canonicalization one should generally use `iter_opaque_types` + /// to also consider duplicate entries. + pub fn iter_lookup_table( + &self, + ) -> impl Iterator, OpaqueHiddenType<'tcx>)> { + self.opaque_types.iter().map(|(k, v)| (*k, *v)) + } + + /// Only returns the opaque types which are stored in `duplicate_entries`. + /// + /// These have to considered when checking all opaque type uses but are e.g. + /// irrelevant for canonical inputs as nested queries never meaningfully + /// accesses them. + pub fn iter_duplicate_entries( + &self, + ) -> impl Iterator, OpaqueHiddenType<'tcx>)> { + self.duplicate_entries.iter().copied() + } + + pub fn iter_opaque_types( + &self, + ) -> impl Iterator, OpaqueHiddenType<'tcx>)> { + let OpaqueTypeStorage { opaque_types, duplicate_entries } = self; + opaque_types.iter().map(|(k, v)| (*k, *v)).chain(duplicate_entries.iter().copied()) + } + #[inline] pub(crate) fn with_log<'a>( &'a mut self, @@ -44,21 +89,27 @@ impl<'tcx> OpaqueTypeStorage<'tcx> { impl<'tcx> Drop for OpaqueTypeStorage<'tcx> { fn drop(&mut self) { - if !self.opaque_types.is_empty() { + if !self.is_empty() { ty::tls::with(|tcx| tcx.dcx().delayed_bug(format!("{:?}", self.opaque_types))); } } } -pub(crate) struct OpaqueTypeTable<'a, 'tcx> { +pub struct OpaqueTypeTable<'a, 'tcx> { storage: &'a mut OpaqueTypeStorage<'tcx>, undo_log: &'a mut InferCtxtUndoLogs<'tcx>, } +impl<'tcx> Deref for OpaqueTypeTable<'_, 'tcx> { + type Target = OpaqueTypeStorage<'tcx>; + fn deref(&self) -> &Self::Target { + self.storage + } +} impl<'a, 'tcx> OpaqueTypeTable<'a, 'tcx> { #[instrument(skip(self), level = "debug")] - pub(crate) fn register( + pub fn register( &mut self, key: OpaqueTypeKey<'tcx>, hidden_type: OpaqueHiddenType<'tcx>, @@ -72,4 +123,9 @@ impl<'a, 'tcx> OpaqueTypeTable<'a, 'tcx> { self.undo_log.push(UndoLog::OpaqueTypes(key, None)); None } + + pub fn add_duplicate(&mut self, key: OpaqueTypeKey<'tcx>, hidden_type: OpaqueHiddenType<'tcx>) { + self.storage.duplicate_entries.push((key, hidden_type)); + self.undo_log.push(UndoLog::DuplicateOpaqueType); + } } diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index a89cef50c9b4..8dde99c45cfa 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -63,11 +63,11 @@ use rustc_data_structures::undo_log::UndoLogs; use rustc_middle::bug; use rustc_middle::mir::ConstraintCategory; use rustc_middle::traits::query::NoSolution; +use rustc_middle::ty::outlives::{Component, push_outlives_components}; use rustc_middle::ty::{ self, GenericArgKind, GenericArgsRef, PolyTypeOutlivesPredicate, Region, Ty, TyCtxt, TypeFoldable as _, TypeVisitableExt, }; -use rustc_type_ir::outlives::{Component, push_outlives_components}; use smallvec::smallvec; use tracing::{debug, instrument}; diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs index c14c288c6e4e..69feecfe30a4 100644 --- a/compiler/rustc_infer/src/infer/outlives/verify.rs +++ b/compiler/rustc_infer/src/infer/outlives/verify.rs @@ -1,7 +1,7 @@ use std::assert_matches::assert_matches; +use rustc_middle::ty::outlives::{Component, compute_alias_components_recursive}; use rustc_middle::ty::{self, OutlivesPredicate, Ty, TyCtxt}; -use rustc_type_ir::outlives::{Component, compute_alias_components_recursive}; use smallvec::smallvec; use tracing::{debug, instrument, trace}; diff --git a/compiler/rustc_infer/src/infer/projection.rs b/compiler/rustc_infer/src/infer/projection.rs index 1bee9632110b..2a4f9db8963c 100644 --- a/compiler/rustc_infer/src/infer/projection.rs +++ b/compiler/rustc_infer/src/infer/projection.rs @@ -1,7 +1,8 @@ use rustc_middle::traits::ObligationCause; -use rustc_middle::ty::{self, Ty}; +use rustc_middle::ty; use super::InferCtxt; +use crate::infer::Term; use crate::traits::{Obligation, PredicateObligations}; impl<'tcx> InferCtxt<'tcx> { @@ -11,24 +12,32 @@ impl<'tcx> InferCtxt<'tcx> { /// of the given projection. This allows us to proceed with projections /// while they cannot be resolved yet due to missing information or /// simply due to the lack of access to the trait resolution machinery. - pub fn projection_ty_to_infer( + pub fn projection_term_to_infer( &self, param_env: ty::ParamEnv<'tcx>, - projection_ty: ty::AliasTy<'tcx>, + alias_term: ty::AliasTerm<'tcx>, cause: ObligationCause<'tcx>, recursion_depth: usize, obligations: &mut PredicateObligations<'tcx>, - ) -> Ty<'tcx> { + ) -> Term<'tcx> { debug_assert!(!self.next_trait_solver()); - let ty_var = self.next_ty_var(self.tcx.def_span(projection_ty.def_id)); + + let span = self.tcx.def_span(alias_term.def_id); + let infer_var = if alias_term.kind(self.tcx).is_type() { + self.next_ty_var(span).into() + } else { + self.next_const_var(span).into() + }; + let projection = ty::PredicateKind::Clause(ty::ClauseKind::Projection(ty::ProjectionPredicate { - projection_term: projection_ty.into(), - term: ty_var.into(), + projection_term: alias_term, + term: infer_var, })); let obligation = Obligation::with_depth(self.tcx, cause, recursion_depth, param_env, projection); obligations.push(obligation); - ty_var + + infer_var } } diff --git a/compiler/rustc_infer/src/infer/relate/mod.rs b/compiler/rustc_infer/src/infer/relate/mod.rs index e6d1003cab61..6d25dfeb8593 100644 --- a/compiler/rustc_infer/src/infer/relate/mod.rs +++ b/compiler/rustc_infer/src/infer/relate/mod.rs @@ -2,9 +2,8 @@ //! (except for some relations used for diagnostics and heuristics in the compiler). //! As well as the implementation of `Relate` for interned things (`Ty`/`Const`/etc). -pub use rustc_middle::ty::relate::RelateResult; -pub use rustc_type_ir::relate::combine::PredicateEmittingRelation; -pub use rustc_type_ir::relate::*; +pub use rustc_middle::ty::relate::combine::PredicateEmittingRelation; +pub use rustc_middle::ty::relate::{RelateResult, *}; mod generalize; mod higher_ranked; diff --git a/compiler/rustc_infer/src/infer/relate/type_relating.rs b/compiler/rustc_infer/src/infer/relate/type_relating.rs index 009271a8378f..04ff776594e6 100644 --- a/compiler/rustc_infer/src/infer/relate/type_relating.rs +++ b/compiler/rustc_infer/src/infer/relate/type_relating.rs @@ -3,9 +3,8 @@ use rustc_middle::ty::relate::combine::{super_combine_consts, super_combine_tys} use rustc_middle::ty::relate::{ Relate, RelateResult, TypeRelation, relate_args_invariantly, relate_args_with_variances, }; -use rustc_middle::ty::{self, Ty, TyCtxt, TyVar}; +use rustc_middle::ty::{self, DelayedSet, Ty, TyCtxt, TyVar}; use rustc_span::Span; -use rustc_type_ir::data_structures::DelayedSet; use tracing::{debug, instrument}; use crate::infer::BoundRegionConversionTime::HigherRankedType; diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs index 245f1a4ac5ed..4b0ace8c554d 100644 --- a/compiler/rustc_infer/src/infer/resolve.rs +++ b/compiler/rustc_infer/src/infer/resolve.rs @@ -1,9 +1,8 @@ use rustc_middle::bug; use rustc_middle::ty::{ - self, Const, FallibleTypeFolder, InferConst, Ty, TyCtxt, TypeFoldable, TypeFolder, + self, Const, DelayedMap, FallibleTypeFolder, InferConst, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, }; -use rustc_type_ir::data_structures::DelayedMap; use super::{FixupError, FixupResult, InferCtxt}; diff --git a/compiler/rustc_infer/src/infer/snapshot/fudge.rs b/compiler/rustc_infer/src/infer/snapshot/fudge.rs index 39c8c40ea7d8..e210479581ba 100644 --- a/compiler/rustc_infer/src/infer/snapshot/fudge.rs +++ b/compiler/rustc_infer/src/infer/snapshot/fudge.rs @@ -3,9 +3,8 @@ use std::ops::Range; use rustc_data_structures::{snapshot_vec as sv, unify as ut}; use rustc_middle::ty::{ self, ConstVid, FloatVid, IntVid, RegionVid, Ty, TyCtxt, TyVid, TypeFoldable, TypeFolder, - TypeSuperFoldable, + TypeSuperFoldable, TypeVisitableExt, }; -use rustc_type_ir::TypeVisitableExt; use tracing::instrument; use ut::UnifyKey; diff --git a/compiler/rustc_infer/src/infer/snapshot/undo_log.rs b/compiler/rustc_infer/src/infer/snapshot/undo_log.rs index ba7d8f588e68..b7412d3d6a6d 100644 --- a/compiler/rustc_infer/src/infer/snapshot/undo_log.rs +++ b/compiler/rustc_infer/src/infer/snapshot/undo_log.rs @@ -17,6 +17,7 @@ pub struct Snapshot<'tcx> { /// Records the "undo" data for a single operation that affects some form of inference variable. #[derive(Clone)] pub(crate) enum UndoLog<'tcx> { + DuplicateOpaqueType, OpaqueTypes(OpaqueTypeKey<'tcx>, Option>), TypeVariables(sv::UndoLog>>), ConstUnificationTable(sv::UndoLog>>), @@ -58,6 +59,7 @@ impl_from! { impl<'tcx> Rollback> for InferCtxtInner<'tcx> { fn reverse(&mut self, undo: UndoLog<'tcx>) { match undo { + UndoLog::DuplicateOpaqueType => self.opaque_type_storage.pop_duplicate_entry(), UndoLog::OpaqueTypes(key, idx) => self.opaque_type_storage.remove(key, idx), UndoLog::TypeVariables(undo) => self.type_variable_storage.reverse(undo), UndoLog::ConstUnificationTable(undo) => self.const_unification_storage.reverse(undo), diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs index 66ed49fe3267..6461fbe0d33b 100644 --- a/compiler/rustc_infer/src/traits/util.rs +++ b/compiler/rustc_infer/src/traits/util.rs @@ -1,7 +1,7 @@ use rustc_data_structures::fx::FxHashSet; +pub use rustc_middle::ty::elaborate::*; use rustc_middle::ty::{self, TyCtxt}; use rustc_span::{Ident, Span}; -pub use rustc_type_ir::elaborate::*; use crate::traits::{self, Obligation, ObligationCauseCode, PredicateObligation}; diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index 708fe23b7915..cf494f8d686e 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -5,7 +5,7 @@ use std::sync::Arc; use rustc_ast::{LitKind, MetaItemKind, token}; use rustc_codegen_ssa::traits::CodegenBackend; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_data_structures::jobserver; +use rustc_data_structures::jobserver::{self, Proxy}; use rustc_data_structures::stable_hasher::StableHasher; use rustc_errors::registry::Registry; use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed}; @@ -40,7 +40,12 @@ pub struct Compiler { pub sess: Session, pub codegen_backend: Box, pub(crate) override_queries: Option, + + /// A reference to the current `GlobalCtxt` which we pass on to `GlobalCtxt`. pub(crate) current_gcx: CurrentGcx, + + /// A jobserver reference which we pass on to `GlobalCtxt`. + pub(crate) jobserver_proxy: Arc, } /// Converts strings provided as `--cfg [cfgspec]` into a `Cfg`. @@ -415,7 +420,7 @@ pub fn run_compiler(config: Config, f: impl FnOnce(&Compiler) -> R + Se config.opts.unstable_opts.threads, &config.extra_symbols, SourceMapInputs { file_loader, path_mapping, hash_kind, checksum_hash_kind }, - |current_gcx| { + |current_gcx, jobserver_proxy| { // The previous `early_dcx` can't be reused here because it doesn't // impl `Send`. Creating a new one is fine. let early_dcx = EarlyDiagCtxt::new(config.opts.error_format); @@ -511,6 +516,7 @@ pub fn run_compiler(config: Config, f: impl FnOnce(&Compiler) -> R + Se codegen_backend, override_queries: config.override_queries, current_gcx, + jobserver_proxy, }; // There are two paths out of `f`. diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index aad63f4edcf3..f4d11a7c0be2 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -7,6 +7,7 @@ use std::{env, fs, iter}; use rustc_ast as ast; use rustc_codegen_ssa::traits::CodegenBackend; +use rustc_data_structures::jobserver::Proxy; use rustc_data_structures::parallel; use rustc_data_structures::steal::Steal; use rustc_data_structures::sync::{AppendOnlyIndexVec, FreezeLock, WorkerLocal}; @@ -30,10 +31,11 @@ use rustc_resolve::Resolver; use rustc_session::config::{CrateType, Input, OutFileName, OutputFilenames, OutputType}; use rustc_session::cstore::Untracked; use rustc_session::output::{collect_crate_types, filename_for_input}; +use rustc_session::parse::feature_err; use rustc_session::search_paths::PathKind; use rustc_session::{Limit, Session}; use rustc_span::{ - ErrorGuaranteed, FileName, SourceFileHash, SourceFileHashAlgorithm, Span, Symbol, sym, + DUMMY_SP, ErrorGuaranteed, FileName, SourceFileHash, SourceFileHashAlgorithm, Span, Symbol, sym, }; use rustc_target::spec::PanicStrategy; use rustc_trait_selection::traits; @@ -236,6 +238,7 @@ fn configure_and_expand( sess, features, &krate, + tcx.is_sdylib_interface_build(), resolver.lint_buffer(), ) }); @@ -252,6 +255,9 @@ fn configure_and_expand( sess.dcx().emit_err(errors::MixedProcMacroCrate); } } + if crate_types.contains(&CrateType::Sdylib) && !tcx.features().export_stable() { + feature_err(sess, sym::export_stable, DUMMY_SP, "`sdylib` crate type is unstable").emit(); + } if is_proc_macro_crate && sess.panic_strategy() == PanicStrategy::Abort { sess.dcx().emit_warn(errors::ProcMacroCratePanicAbort); @@ -741,6 +747,25 @@ pub fn write_dep_info(tcx: TyCtxt<'_>) { } } +pub fn write_interface<'tcx>(tcx: TyCtxt<'tcx>) { + if !tcx.crate_types().contains(&rustc_session::config::CrateType::Sdylib) { + return; + } + let _timer = tcx.sess.timer("write_interface"); + let (_, krate) = &*tcx.resolver_for_lowering().borrow(); + + let krate = rustc_ast_pretty::pprust::print_crate_as_interface( + krate, + tcx.sess.psess.edition, + &tcx.sess.psess.attr_id_generator, + ); + let export_output = tcx.output_filenames(()).interface_path(); + let mut file = fs::File::create_buffered(export_output).unwrap(); + if let Err(err) = write!(file, "{}", krate) { + tcx.dcx().fatal(format!("error writing interface file: {}", err)); + } +} + pub static DEFAULT_QUERY_PROVIDERS: LazyLock = LazyLock::new(|| { let providers = &mut Providers::default(); providers.analysis = analysis; @@ -841,12 +866,13 @@ pub fn create_and_enter_global_ctxt FnOnce(TyCtxt<'tcx>) -> T>( dyn for<'tcx> FnOnce( &'tcx Session, CurrentGcx, + Arc, &'tcx OnceLock>, &'tcx WorkerLocal>, &'tcx WorkerLocal>, F, ) -> T, - > = Box::new(move |sess, current_gcx, gcx_cell, arena, hir_arena, f| { + > = Box::new(move |sess, current_gcx, jobserver_proxy, gcx_cell, arena, hir_arena, f| { TyCtxt::create_global_ctxt( gcx_cell, sess, @@ -865,6 +891,7 @@ pub fn create_and_enter_global_ctxt FnOnce(TyCtxt<'tcx>) -> T>( ), providers.hooks, current_gcx, + jobserver_proxy, |tcx| { let feed = tcx.create_crate_num(stable_crate_id).unwrap(); assert_eq!(feed.key(), LOCAL_CRATE); @@ -887,7 +914,15 @@ pub fn create_and_enter_global_ctxt FnOnce(TyCtxt<'tcx>) -> T>( ) }); - inner(&compiler.sess, compiler.current_gcx.clone(), &gcx_cell, &arena, &hir_arena, f) + inner( + &compiler.sess, + compiler.current_gcx.clone(), + Arc::clone(&compiler.jobserver_proxy), + &gcx_cell, + &arena, + &hir_arena, + f, + ) } /// Runs all analyses that we guarantee to run, even if errors were reported in earlier analyses. @@ -919,6 +954,8 @@ fn run_required_analyses(tcx: TyCtxt<'_>) { CStore::from_tcx(tcx).report_unused_deps(tcx); }, { + tcx.ensure_ok().exportable_items(LOCAL_CRATE); + tcx.ensure_ok().stable_order_of_exportable_impls(LOCAL_CRATE); tcx.par_hir_for_each_module(|module| { tcx.ensure_ok().check_mod_loops(module); tcx.ensure_ok().check_mod_attrs(module); diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index 4d346b50c808..087b11fdf9d9 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -1,11 +1,12 @@ use std::env::consts::{DLL_PREFIX, DLL_SUFFIX}; use std::path::{Path, PathBuf}; -use std::sync::OnceLock; use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::{Arc, OnceLock}; use std::{env, iter, thread}; use rustc_ast as ast; use rustc_codegen_ssa::traits::CodegenBackend; +use rustc_data_structures::jobserver::Proxy; use rustc_data_structures::sync; use rustc_metadata::{DylibError, load_symbol_from_dylib}; use rustc_middle::ty::CurrentGcx; @@ -124,7 +125,7 @@ fn init_stack_size(early_dcx: &EarlyDiagCtxt) -> usize { }) } -fn run_in_thread_with_globals R + Send, R: Send>( +fn run_in_thread_with_globals) -> R + Send, R: Send>( thread_stack_size: usize, edition: Edition, sm_inputs: SourceMapInputs, @@ -150,7 +151,7 @@ fn run_in_thread_with_globals R + Send, R: Send>( edition, extra_symbols, Some(sm_inputs), - || f(CurrentGcx::new()), + || f(CurrentGcx::new(), Proxy::new()), ) }) .unwrap() @@ -163,7 +164,10 @@ fn run_in_thread_with_globals R + Send, R: Send>( }) } -pub(crate) fn run_in_thread_pool_with_globals R + Send, R: Send>( +pub(crate) fn run_in_thread_pool_with_globals< + F: FnOnce(CurrentGcx, Arc) -> R + Send, + R: Send, +>( thread_builder_diag: &EarlyDiagCtxt, edition: Edition, threads: usize, @@ -173,8 +177,8 @@ pub(crate) fn run_in_thread_pool_with_globals R + Send, ) -> R { use std::process; + use rustc_data_structures::defer; use rustc_data_structures::sync::FromDyn; - use rustc_data_structures::{defer, jobserver}; use rustc_middle::ty::tls; use rustc_query_impl::QueryCtxt; use rustc_query_system::query::{QueryContext, break_query_cycles}; @@ -189,11 +193,11 @@ pub(crate) fn run_in_thread_pool_with_globals R + Send, edition, sm_inputs, extra_symbols, - |current_gcx| { + |current_gcx, jobserver_proxy| { // Register the thread for use with the `WorkerLocal` type. registry.register(); - f(current_gcx) + f(current_gcx, jobserver_proxy) }, ); } @@ -201,10 +205,14 @@ pub(crate) fn run_in_thread_pool_with_globals R + Send, let current_gcx = FromDyn::from(CurrentGcx::new()); let current_gcx2 = current_gcx.clone(); + let proxy = Proxy::new(); + + let proxy_ = Arc::clone(&proxy); + let proxy__ = Arc::clone(&proxy); let builder = rayon_core::ThreadPoolBuilder::new() .thread_name(|_| "rustc".to_string()) - .acquire_thread_handler(jobserver::acquire_thread) - .release_thread_handler(jobserver::release_thread) + .acquire_thread_handler(move || proxy_.acquire_thread()) + .release_thread_handler(move || proxy__.release_thread()) .num_threads(threads) .deadlock_handler(move || { // On deadlock, creates a new thread and forwards information in thread @@ -268,7 +276,7 @@ pub(crate) fn run_in_thread_pool_with_globals R + Send, }, // Run `f` on the first thread in the thread pool. move |pool: &rayon_core::ThreadPool| { - pool.install(|| f(current_gcx.into_inner())) + pool.install(|| f(current_gcx.into_inner(), proxy)) }, ) .unwrap() diff --git a/compiler/rustc_lexer/src/cursor.rs b/compiler/rustc_lexer/src/cursor.rs index e0e3bd0e30b1..526693d3de1f 100644 --- a/compiler/rustc_lexer/src/cursor.rs +++ b/compiler/rustc_lexer/src/cursor.rs @@ -1,5 +1,10 @@ use std::str::Chars; +pub enum FrontmatterAllowed { + Yes, + No, +} + /// Peekable iterator over a char sequence. /// /// Next characters can be peeked via `first` method, @@ -8,6 +13,7 @@ pub struct Cursor<'a> { len_remaining: usize, /// Iterator over chars. Slightly faster than a &str. chars: Chars<'a>, + pub(crate) frontmatter_allowed: FrontmatterAllowed, #[cfg(debug_assertions)] prev: char, } @@ -15,10 +21,11 @@ pub struct Cursor<'a> { pub(crate) const EOF_CHAR: char = '\0'; impl<'a> Cursor<'a> { - pub fn new(input: &'a str) -> Cursor<'a> { + pub fn new(input: &'a str, frontmatter_allowed: FrontmatterAllowed) -> Cursor<'a> { Cursor { len_remaining: input.len(), chars: input.chars(), + frontmatter_allowed, #[cfg(debug_assertions)] prev: EOF_CHAR, } @@ -95,6 +102,11 @@ impl<'a> Cursor<'a> { Some(c) } + /// Moves to a substring by a number of bytes. + pub(crate) fn bump_bytes(&mut self, n: usize) { + self.chars = self.as_str()[n..].chars(); + } + /// Eats symbols while predicate returns true or until the end of file is reached. pub(crate) fn eat_while(&mut self, mut predicate: impl FnMut(char) -> bool) { // It was tried making optimized version of this for eg. line comments, but diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs index f9c71b2fa651..2374f3882509 100644 --- a/compiler/rustc_lexer/src/lib.rs +++ b/compiler/rustc_lexer/src/lib.rs @@ -35,8 +35,8 @@ pub use unicode_xid::UNICODE_VERSION as UNICODE_XID_VERSION; use self::LiteralKind::*; use self::TokenKind::*; -pub use crate::cursor::Cursor; use crate::cursor::EOF_CHAR; +pub use crate::cursor::{Cursor, FrontmatterAllowed}; /// Parsed token. /// It doesn't contain information about data that has been parsed, @@ -57,17 +57,27 @@ impl Token { #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum TokenKind { /// A line comment, e.g. `// comment`. - LineComment { doc_style: Option }, + LineComment { + doc_style: Option, + }, /// A block comment, e.g. `/* block comment */`. /// /// Block comments can be recursive, so a sequence like `/* /* */` /// will not be considered terminated and will result in a parsing error. - BlockComment { doc_style: Option, terminated: bool }, + BlockComment { + doc_style: Option, + terminated: bool, + }, /// Any whitespace character sequence. Whitespace, + Frontmatter { + has_invalid_preceding_whitespace: bool, + invalid_infostring: bool, + }, + /// An identifier or keyword, e.g. `ident` or `continue`. Ident, @@ -109,10 +119,15 @@ pub enum TokenKind { /// this type will need to check for and reject that case. /// /// See [LiteralKind] for more details. - Literal { kind: LiteralKind, suffix_start: u32 }, + Literal { + kind: LiteralKind, + suffix_start: u32, + }, /// A lifetime, e.g. `'a`. - Lifetime { starts_with_number: bool }, + Lifetime { + starts_with_number: bool, + }, /// `;` Semi, @@ -280,7 +295,7 @@ pub fn strip_shebang(input: &str) -> Option { #[inline] pub fn validate_raw_str(input: &str, prefix_len: u32) -> Result<(), RawStrError> { debug_assert!(!input.is_empty()); - let mut cursor = Cursor::new(input); + let mut cursor = Cursor::new(input, FrontmatterAllowed::No); // Move past the leading `r` or `br`. for _ in 0..prefix_len { cursor.bump().unwrap(); @@ -290,7 +305,7 @@ pub fn validate_raw_str(input: &str, prefix_len: u32) -> Result<(), RawStrError> /// Creates an iterator that produces tokens from the input string. pub fn tokenize(input: &str) -> impl Iterator { - let mut cursor = Cursor::new(input); + let mut cursor = Cursor::new(input, FrontmatterAllowed::No); std::iter::from_fn(move || { let token = cursor.advance_token(); if token.kind != TokenKind::Eof { Some(token) } else { None } @@ -361,7 +376,34 @@ impl Cursor<'_> { Some(c) => c, None => return Token::new(TokenKind::Eof, 0), }; + let token_kind = match first_char { + c if matches!(self.frontmatter_allowed, FrontmatterAllowed::Yes) + && is_whitespace(c) => + { + let mut last = first_char; + while is_whitespace(self.first()) { + let Some(c) = self.bump() else { + break; + }; + last = c; + } + // invalid frontmatter opening as whitespace preceding it isn't newline. + // combine the whitespace and the frontmatter to a single token as we shall + // error later. + if last != '\n' && self.as_str().starts_with("---") { + self.bump(); + self.frontmatter(true) + } else { + Whitespace + } + } + '-' if matches!(self.frontmatter_allowed, FrontmatterAllowed::Yes) + && self.as_str().starts_with("--") => + { + // happy path + self.frontmatter(false) + } // Slash, comment or block comment. '/' => match self.first() { '/' => self.line_comment(), @@ -464,11 +506,110 @@ impl Cursor<'_> { c if !c.is_ascii() && c.is_emoji_char() => self.invalid_ident(), _ => Unknown, }; + if matches!(self.frontmatter_allowed, FrontmatterAllowed::Yes) + && !matches!(token_kind, Whitespace) + { + // stop allowing frontmatters after first non-whitespace token + self.frontmatter_allowed = FrontmatterAllowed::No; + } let res = Token::new(token_kind, self.pos_within_token()); self.reset_pos_within_token(); res } + /// Given that one `-` was eaten, eat the rest of the frontmatter. + fn frontmatter(&mut self, has_invalid_preceding_whitespace: bool) -> TokenKind { + debug_assert_eq!('-', self.prev()); + + let pos = self.pos_within_token(); + self.eat_while(|c| c == '-'); + + // one `-` is eaten by the caller. + let length_opening = self.pos_within_token() - pos + 1; + + // must be ensured by the caller + debug_assert!(length_opening >= 3); + + // 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 + // `---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(|ch| ch != '\n' && is_whitespace(ch)); + let invalid_infostring = self.first() != '\n'; + + let mut s = self.as_str(); + let mut found = false; + while let Some(closing) = s.find(&"-".repeat(length_opening as usize)) { + let preceding_chars_start = s[..closing].rfind("\n").map_or(0, |i| i + 1); + if s[preceding_chars_start..closing].chars().all(is_whitespace) { + // candidate found + self.bump_bytes(closing); + // in case like + // ---cargo + // --- blahblah + // or + // ---cargo + // ---- + // combine those stuff into this frontmatter token such that it gets detected later. + self.eat_until(b'\n'); + found = true; + break; + } else { + s = &s[closing + length_opening as usize..]; + } + } + + if !found { + // recovery strategy: a closing statement might have precending whitespace/newline + // but not have enough dashes to properly close. In this case, we eat until there, + // and report a mismatch in the parser. + let mut rest = self.as_str(); + // We can look for a shorter closing (starting with four dashes but closing with three) + // and other indications that Rust has started and the infostring has ended. + let mut potential_closing = rest + .find("\n---") + // n.b. only in the case where there are dashes, we move the index to the line where + // the dashes start as we eat to include that line. For other cases those are Rust code + // and not included in the frontmatter. + .map(|x| x + 1) + .or_else(|| rest.find("\nuse ")) + .or_else(|| rest.find("\n//!")) + .or_else(|| rest.find("\n#![")); + + if potential_closing.is_none() { + // a less fortunate recovery if all else fails which finds any dashes preceded by whitespace + // on a standalone line. Might be wrong. + while let Some(closing) = rest.find("---") { + let preceding_chars_start = rest[..closing].rfind("\n").map_or(0, |i| i + 1); + if rest[preceding_chars_start..closing].chars().all(is_whitespace) { + // candidate found + potential_closing = Some(closing); + break; + } else { + rest = &rest[closing + 3..]; + } + } + } + + if let Some(potential_closing) = potential_closing { + // bump to the potential closing, and eat everything on that line. + self.bump_bytes(potential_closing); + self.eat_until(b'\n'); + } else { + // eat everything. this will get reported as an unclosed frontmatter. + self.eat_while(|_| true); + } + } + + Frontmatter { has_invalid_preceding_whitespace, invalid_infostring } + } + fn line_comment(&mut self) -> TokenKind { debug_assert!(self.prev() == '/' && self.first() == '/'); self.bump(); diff --git a/compiler/rustc_lexer/src/tests.rs b/compiler/rustc_lexer/src/tests.rs index 8203ae70b070..fc8d9b9d57bc 100644 --- a/compiler/rustc_lexer/src/tests.rs +++ b/compiler/rustc_lexer/src/tests.rs @@ -4,7 +4,7 @@ use super::*; fn check_raw_str(s: &str, expected: Result) { let s = &format!("r{}", s); - let mut cursor = Cursor::new(s); + let mut cursor = Cursor::new(s, FrontmatterAllowed::No); cursor.bump(); let res = cursor.raw_double_quoted_string(0); assert_eq!(res, expected); diff --git a/compiler/rustc_lint/src/autorefs.rs b/compiler/rustc_lint/src/autorefs.rs index 5dd26854c957..91d58d92466a 100644 --- a/compiler/rustc_lint/src/autorefs.rs +++ b/compiler/rustc_lint/src/autorefs.rs @@ -15,9 +15,9 @@ declare_lint! { /// /// ```rust /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] { - /// &raw mut (*ptr)[..16] - /// // ^^^^^^ this calls `IndexMut::index_mut(&mut ..., ..16)`, - /// // implicitly creating a reference + /// unsafe { &raw mut (*ptr)[..16] } + /// // ^^^^^^ this calls `IndexMut::index_mut(&mut ..., ..16)`, + /// // implicitly creating a reference /// } /// ``` /// @@ -34,17 +34,17 @@ declare_lint! { /// /// ```rust /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] { - /// &raw mut (&mut *ptr)[..16] + /// unsafe { &raw mut (&mut *ptr)[..16] } /// } /// ``` /// /// Otherwise try to find an alternative way to achive your goals using only raw pointers: /// /// ```rust - /// use std::slice; + /// use std::ptr; /// - /// unsafe fn fun(ptr: *mut [u8]) -> *mut [u8] { - /// slice::from_raw_parts_mut(ptr.cast(), 16) + /// fn fun(ptr: *mut [u8]) -> *mut [u8] { + /// ptr::slice_from_raw_parts_mut(ptr.cast(), 16) /// } /// ``` pub DANGEROUS_IMPLICIT_AUTOREFS, @@ -75,10 +75,9 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitAutorefs { _ => return, }, ExprKind::Index(base, _, _) => base, - ExprKind::MethodCall(_, inner, _, _) - if let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) - && cx.tcx.has_attr(def_id, sym::rustc_no_implicit_autorefs) => - { + ExprKind::MethodCall(_, inner, _, _) => { + // PERF: Checking of `#[rustc_no_implicit_refs]` is deferred below + // because checking for attribute is a bit costly. inner } ExprKind::Field(inner, _) => inner, @@ -99,6 +98,14 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitAutorefs { peel_place_mappers(inner).kind // 1. Deref of a raw pointer. && typeck.expr_ty(dereferenced).is_raw_ptr() + // PERF: 5. b. A method call annotated with `#[rustc_no_implicit_refs]` + && match expr.kind { + ExprKind::MethodCall(..) => matches!( + cx.typeck_results().type_dependent_def_id(expr.hir_id), + Some(def_id) if cx.tcx.has_attr(def_id, sym::rustc_no_implicit_autorefs) + ), + _ => true, + } { cx.emit_span_lint( DANGEROUS_IMPLICIT_AUTOREFS, diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 41b43f647986..95e31e4af1e3 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -976,6 +976,9 @@ declare_lint! { /// ```rust /// #[unsafe(no_mangle)] /// fn foo(t: T) {} + /// + /// #[unsafe(export_name = "bar")] + /// fn bar(t: T) {} /// ``` /// /// {{produces}} @@ -983,10 +986,11 @@ declare_lint! { /// ### Explanation /// /// A function with generics must have its symbol mangled to accommodate - /// the generic parameter. The [`no_mangle` attribute] has no effect in - /// this situation, and should be removed. + /// the generic parameter. The [`no_mangle`] and [`export_name`] attributes + /// have no effect in this situation, and should be removed. /// - /// [`no_mangle` attribute]: https://doc.rust-lang.org/reference/abi.html#the-no_mangle-attribute + /// [`no_mangle`]: https://doc.rust-lang.org/reference/abi.html#the-no_mangle-attribute + /// [`export_name`]: https://doc.rust-lang.org/reference/abi.html#the-export_name-attribute NO_MANGLE_GENERIC_ITEMS, Warn, "generic items must be mangled" @@ -997,7 +1001,7 @@ declare_lint_pass!(InvalidNoMangleItems => [NO_MANGLE_CONST_ITEMS, NO_MANGLE_GEN impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems { fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) { let attrs = cx.tcx.hir_attrs(it.hir_id()); - let check_no_mangle_on_generic_fn = |no_mangle_attr: &hir::Attribute, + let check_no_mangle_on_generic_fn = |attr: &hir::Attribute, impl_generics: Option<&hir::Generics<'_>>, generics: &hir::Generics<'_>, span| { @@ -1010,7 +1014,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems { cx.emit_span_lint( NO_MANGLE_GENERIC_ITEMS, span, - BuiltinNoMangleGeneric { suggestion: no_mangle_attr.span() }, + BuiltinNoMangleGeneric { suggestion: attr.span() }, ); break; } @@ -1019,8 +1023,10 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems { }; match it.kind { hir::ItemKind::Fn { generics, .. } => { - if let Some(no_mangle_attr) = attr::find_by_name(attrs, sym::no_mangle) { - check_no_mangle_on_generic_fn(no_mangle_attr, None, generics, it.span); + if let Some(attr) = attr::find_by_name(attrs, sym::export_name) + .or_else(|| attr::find_by_name(attrs, sym::no_mangle)) + { + check_no_mangle_on_generic_fn(attr, None, generics, it.span); } } hir::ItemKind::Const(..) => { @@ -1048,11 +1054,12 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems { hir::ItemKind::Impl(hir::Impl { generics, items, .. }) => { for it in *items { if let hir::AssocItemKind::Fn { .. } = it.kind { - if let Some(no_mangle_attr) = - attr::find_by_name(cx.tcx.hir_attrs(it.id.hir_id()), sym::no_mangle) + let attrs = cx.tcx.hir_attrs(it.id.hir_id()); + if let Some(attr) = attr::find_by_name(attrs, sym::export_name) + .or_else(|| attr::find_by_name(attrs, sym::no_mangle)) { check_no_mangle_on_generic_fn( - no_mangle_attr, + attr, Some(generics), cx.tcx.hir_get_generics(it.id.owner_id.def_id).unwrap(), it.span, diff --git a/compiler/rustc_lint/src/foreign_modules.rs b/compiler/rustc_lint/src/foreign_modules.rs index 0494c78a7a97..d0668794198a 100644 --- a/compiler/rustc_lint/src/foreign_modules.rs +++ b/compiler/rustc_lint/src/foreign_modules.rs @@ -104,7 +104,7 @@ impl ClashingExternDeclarations { /// for the item, return its HirId without updating the set. fn insert(&mut self, tcx: TyCtxt<'_>, fi: hir::ForeignItemId) -> Option { let did = fi.owner_id.to_def_id(); - let instance = Instance::new(did, ty::List::identity_for_item(tcx, did)); + let instance = Instance::new_raw(did, ty::List::identity_for_item(tcx, did)); let name = Symbol::intern(tcx.symbol_name(instance).name); if let Some(&existing_id) = self.seen_decls.get(&name) { // Avoid updating the map with the new entry when we do find a collision. We want to diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 806bca78f787..50a27d7e84f5 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -942,6 +942,22 @@ trait UnusedDelimLint { match s.kind { StmtKind::Let(ref local) if Self::LINT_EXPR_IN_PATTERN_MATCHING_CTX => { if let Some((init, els)) = local.kind.init_else_opt() { + if els.is_some() + && let ExprKind::Paren(paren) = &init.kind + && !init.span.eq_ctxt(paren.span) + { + // This branch prevents cases where parentheses wrap an expression + // resulting from macro expansion, such as: + // ``` + // macro_rules! x { + // () => { None:: }; + // } + // let Some(_) = (x!{}) else { return }; + // // -> let Some(_) = (None::) else { return }; + // // ~ ~ No Lint + // ``` + return; + } let ctx = match els { None => UnusedDelimsCtx::AssignedValue, Some(_) => UnusedDelimsCtx::AssignedValueLetElse, diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 03b8112938cf..3cea24634fee 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -2352,37 +2352,11 @@ declare_lint! { } declare_lint! { - /// The `soft_unstable` lint detects unstable features that were - /// unintentionally allowed on stable. - /// - /// ### Example - /// - /// ```rust,compile_fail - /// #[cfg(test)] - /// extern crate test; - /// - /// #[bench] - /// fn name(b: &mut test::Bencher) { - /// b.iter(|| 123) - /// } - /// ``` - /// - /// {{produces}} - /// - /// ### Explanation - /// - /// The [`bench` attribute] was accidentally allowed to be specified on - /// the [stable release channel]. Turning this to a hard error would have - /// broken some projects. This lint allows those projects to continue to - /// build correctly when [`--cap-lints`] is used, but otherwise signal an - /// error that `#[bench]` should not be used on the stable channel. This - /// is a [future-incompatible] lint to transition this to a hard error in - /// the future. See [issue #64266] for more details. + /// The `soft_unstable` lint detects unstable features that were unintentionally allowed on + /// stable. This is a [future-incompatible] lint to transition this to a hard error in the + /// future. See [issue #64266] for more details. /// /// [issue #64266]: https://github.com/rust-lang/rust/issues/64266 - /// [`bench` attribute]: https://doc.rust-lang.org/nightly/unstable-book/library-features/test.html - /// [stable release channel]: https://doc.rust-lang.org/book/appendix-07-nightly-rust.html - /// [`--cap-lints`]: https://doc.rust-lang.org/rustc/lints/levels.html#capping-lints /// [future-incompatible]: ../index.md#future-incompatible-lints pub SOFT_UNSTABLE, Deny, diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index ebe8eb57f2cd..d4a05fbbbc5d 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -512,8 +512,13 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine( #endif } +#if LLVM_VERSION_GE(21, 0) + TargetMachine *TM = TheTarget->createTargetMachine(Trip, CPU, Feature, + Options, RM, CM, OptLevel); +#else TargetMachine *TM = TheTarget->createTargetMachine( Trip.getTriple(), CPU, Feature, Options, RM, CM, OptLevel); +#endif return wrap(TM); } diff --git a/compiler/rustc_log/src/lib.rs b/compiler/rustc_log/src/lib.rs index 49dd388f14cc..1bb502ca3d06 100644 --- a/compiler/rustc_log/src/lib.rs +++ b/compiler/rustc_log/src/lib.rs @@ -37,6 +37,7 @@ use std::env::{self, VarError}; use std::fmt::{self, Display}; use std::io::{self, IsTerminal}; +use tracing::dispatcher::SetGlobalDefaultError; use tracing_core::{Event, Subscriber}; use tracing_subscriber::filter::{Directive, EnvFilter, LevelFilter}; use tracing_subscriber::fmt::FmtContext; @@ -131,10 +132,10 @@ pub fn init_logger(cfg: LoggerConfig) -> Result<(), Error> { .without_time() .event_format(BacktraceFormatter { backtrace_target }); let subscriber = subscriber.with(fmt_layer); - tracing::subscriber::set_global_default(subscriber).unwrap(); + tracing::subscriber::set_global_default(subscriber)?; } Err(_) => { - tracing::subscriber::set_global_default(subscriber).unwrap(); + tracing::subscriber::set_global_default(subscriber)?; } }; @@ -180,6 +181,7 @@ pub enum Error { InvalidColorValue(String), NonUnicodeColorValue, InvalidWraptree(String), + AlreadyInit(SetGlobalDefaultError), } impl std::error::Error for Error {} @@ -199,6 +201,13 @@ impl Display for Error { formatter, "invalid log WRAPTREE value '{value}': expected a non-negative integer", ), + Error::AlreadyInit(tracing_error) => Display::fmt(tracing_error, formatter), } } } + +impl From for Error { + fn from(tracing_error: SetGlobalDefaultError) -> Self { + Error::AlreadyInit(tracing_error) + } +} diff --git a/compiler/rustc_metadata/Cargo.toml b/compiler/rustc_metadata/Cargo.toml index b11f9260be7c..26878c488b74 100644 --- a/compiler/rustc_metadata/Cargo.toml +++ b/compiler/rustc_metadata/Cargo.toml @@ -26,6 +26,7 @@ rustc_serialize = { path = "../rustc_serialize" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } +tempfile = "3.7.1" tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index 1c3222bbfeb6..07fb2de8a3e0 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -148,7 +148,7 @@ impl<'a> std::fmt::Debug for CrateDump<'a> { writeln!(fmt, " hash: {}", data.hash())?; writeln!(fmt, " reqd: {:?}", data.dep_kind())?; writeln!(fmt, " priv: {:?}", data.is_private_dep())?; - let CrateSource { dylib, rlib, rmeta } = data.source(); + let CrateSource { dylib, rlib, rmeta, sdylib_interface } = data.source(); if let Some(dylib) = dylib { writeln!(fmt, " dylib: {}", dylib.0.display())?; } @@ -158,6 +158,9 @@ impl<'a> std::fmt::Debug for CrateDump<'a> { if let Some(rmeta) = rmeta { writeln!(fmt, " rmeta: {}", rmeta.0.display())?; } + if let Some(sdylib_interface) = sdylib_interface { + writeln!(fmt, " sdylib interface: {}", sdylib_interface.0.display())?; + } } Ok(()) } diff --git a/compiler/rustc_metadata/src/dependency_format.rs b/compiler/rustc_metadata/src/dependency_format.rs index be31aa629c86..fcae33c73c9c 100644 --- a/compiler/rustc_metadata/src/dependency_format.rs +++ b/compiler/rustc_metadata/src/dependency_format.rs @@ -88,45 +88,42 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList { return IndexVec::new(); } - let preferred_linkage = match ty { - // Generating a dylib without `-C prefer-dynamic` means that we're going - // to try to eagerly statically link all dependencies. This is normally - // done for end-product dylibs, not intermediate products. - // - // Treat cdylibs and staticlibs similarly. If `-C prefer-dynamic` is set, - // the caller may be code-size conscious, but without it, it makes sense - // to statically link a cdylib or staticlib. For staticlibs we use - // `-Z staticlib-prefer-dynamic` for now. This may be merged into - // `-C prefer-dynamic` in the future. - CrateType::Dylib | CrateType::Cdylib => { - if sess.opts.cg.prefer_dynamic { - Linkage::Dynamic - } else { + let preferred_linkage = + match ty { + // Generating a dylib without `-C prefer-dynamic` means that we're going + // to try to eagerly statically link all dependencies. This is normally + // done for end-product dylibs, not intermediate products. + // + // Treat cdylibs and staticlibs similarly. If `-C prefer-dynamic` is set, + // the caller may be code-size conscious, but without it, it makes sense + // to statically link a cdylib or staticlib. For staticlibs we use + // `-Z staticlib-prefer-dynamic` for now. This may be merged into + // `-C prefer-dynamic` in the future. + CrateType::Dylib | CrateType::Cdylib | CrateType::Sdylib => { + if sess.opts.cg.prefer_dynamic { Linkage::Dynamic } else { Linkage::Static } + } + CrateType::Staticlib => { + if sess.opts.unstable_opts.staticlib_prefer_dynamic { + Linkage::Dynamic + } else { + Linkage::Static + } + } + + // If the global prefer_dynamic switch is turned off, or the final + // executable will be statically linked, prefer static crate linkage. + CrateType::Executable if !sess.opts.cg.prefer_dynamic || sess.crt_static(Some(ty)) => { Linkage::Static } - } - CrateType::Staticlib => { - if sess.opts.unstable_opts.staticlib_prefer_dynamic { - Linkage::Dynamic - } else { - Linkage::Static - } - } + CrateType::Executable => Linkage::Dynamic, - // If the global prefer_dynamic switch is turned off, or the final - // executable will be statically linked, prefer static crate linkage. - CrateType::Executable if !sess.opts.cg.prefer_dynamic || sess.crt_static(Some(ty)) => { - Linkage::Static - } - CrateType::Executable => Linkage::Dynamic, + // proc-macro crates are mostly cdylibs, but we also need metadata. + CrateType::ProcMacro => Linkage::Static, - // proc-macro crates are mostly cdylibs, but we also need metadata. - CrateType::ProcMacro => Linkage::Static, - - // No linkage happens with rlibs, we just needed the metadata (which we - // got long ago), so don't bother with anything. - CrateType::Rlib => Linkage::NotLinked, - }; + // No linkage happens with rlibs, we just needed the metadata (which we + // got long ago), so don't bother with anything. + CrateType::Rlib => Linkage::NotLinked, + }; let mut unavailable_as_static = Vec::new(); @@ -165,7 +162,9 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList { let all_dylibs = || { tcx.crates(()).iter().filter(|&&cnum| { - !tcx.dep_kind(cnum).macros_only() && tcx.used_crate_source(cnum).dylib.is_some() + !tcx.dep_kind(cnum).macros_only() + && (tcx.used_crate_source(cnum).dylib.is_some() + || tcx.used_crate_source(cnum).sdylib_interface.is_some()) }) }; @@ -273,7 +272,7 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList { match *kind { Linkage::NotLinked | Linkage::IncludedFromDylib => {} Linkage::Static if src.rlib.is_some() => continue, - Linkage::Dynamic if src.dylib.is_some() => continue, + Linkage::Dynamic if src.dylib.is_some() || src.sdylib_interface.is_some() => continue, kind => { let kind = match kind { Linkage::Static => "rlib", diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs index f0a898d678ca..10123cb9a9dd 100644 --- a/compiler/rustc_metadata/src/locator.rs +++ b/compiler/rustc_metadata/src/locator.rs @@ -220,7 +220,7 @@ use std::{cmp, fmt}; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_data_structures::memmap::Mmap; -use rustc_data_structures::owned_slice::slice_owned; +use rustc_data_structures::owned_slice::{OwnedSlice, slice_owned}; use rustc_data_structures::svh::Svh; use rustc_errors::{DiagArgValue, IntoDiagArg}; use rustc_fs_util::try_canonicalize; @@ -231,6 +231,7 @@ use rustc_session::search_paths::PathKind; use rustc_session::utils::CanonicalizedPath; use rustc_span::{Span, Symbol}; use rustc_target::spec::{Target, TargetTuple}; +use tempfile::Builder as TempFileBuilder; use tracing::{debug, info}; use crate::creader::{Library, MetadataLoader}; @@ -277,6 +278,7 @@ pub(crate) enum CrateFlavor { Rlib, Rmeta, Dylib, + SDylib, } impl fmt::Display for CrateFlavor { @@ -285,6 +287,7 @@ impl fmt::Display for CrateFlavor { CrateFlavor::Rlib => "rlib", CrateFlavor::Rmeta => "rmeta", CrateFlavor::Dylib => "dylib", + CrateFlavor::SDylib => "sdylib", }) } } @@ -295,6 +298,7 @@ impl IntoDiagArg for CrateFlavor { CrateFlavor::Rlib => DiagArgValue::Str(Cow::Borrowed("rlib")), CrateFlavor::Rmeta => DiagArgValue::Str(Cow::Borrowed("rmeta")), CrateFlavor::Dylib => DiagArgValue::Str(Cow::Borrowed("dylib")), + CrateFlavor::SDylib => DiagArgValue::Str(Cow::Borrowed("sdylib")), } } } @@ -379,14 +383,18 @@ impl<'a> CrateLocator<'a> { &format!("{}{}{}", self.target.dll_prefix, self.crate_name, extra_prefix); let staticlib_prefix = &format!("{}{}{}", self.target.staticlib_prefix, self.crate_name, extra_prefix); + let interface_prefix = rmeta_prefix; let rmeta_suffix = ".rmeta"; let rlib_suffix = ".rlib"; let dylib_suffix = &self.target.dll_suffix; let staticlib_suffix = &self.target.staticlib_suffix; + let interface_suffix = ".rs"; - let mut candidates: FxIndexMap<_, (FxIndexMap<_, _>, FxIndexMap<_, _>, FxIndexMap<_, _>)> = - Default::default(); + let mut candidates: FxIndexMap< + _, + (FxIndexMap<_, _>, FxIndexMap<_, _>, FxIndexMap<_, _>, FxIndexMap<_, _>), + > = Default::default(); // First, find all possible candidate rlibs and dylibs purely based on // the name of the files themselves. We're trying to match against an @@ -417,6 +425,7 @@ impl<'a> CrateLocator<'a> { (rlib_prefix.as_str(), rlib_suffix, CrateFlavor::Rlib), (rmeta_prefix.as_str(), rmeta_suffix, CrateFlavor::Rmeta), (dylib_prefix, dylib_suffix, CrateFlavor::Dylib), + (interface_prefix, interface_suffix, CrateFlavor::SDylib), ] { if prefix == staticlib_prefix && suffix == staticlib_suffix { should_check_staticlibs = false; @@ -425,7 +434,7 @@ impl<'a> CrateLocator<'a> { for (hash, spf) in matches { info!("lib candidate: {}", spf.path.display()); - let (rlibs, rmetas, dylibs) = + let (rlibs, rmetas, dylibs, interfaces) = candidates.entry(hash.to_string()).or_default(); { // As a perforamnce optimisation we canonicalize the path and skip @@ -446,6 +455,7 @@ impl<'a> CrateLocator<'a> { CrateFlavor::Rlib => rlibs.insert(path, search_path.kind), CrateFlavor::Rmeta => rmetas.insert(path, search_path.kind), CrateFlavor::Dylib => dylibs.insert(path, search_path.kind), + CrateFlavor::SDylib => interfaces.insert(path, search_path.kind), }; } } @@ -472,8 +482,8 @@ impl<'a> CrateLocator<'a> { // libraries corresponds to the crate id and hash criteria that this // search is being performed for. let mut libraries = FxIndexMap::default(); - for (_hash, (rlibs, rmetas, dylibs)) in candidates { - if let Some((svh, lib)) = self.extract_lib(rlibs, rmetas, dylibs)? { + for (_hash, (rlibs, rmetas, dylibs, interfaces)) in candidates { + if let Some((svh, lib)) = self.extract_lib(rlibs, rmetas, dylibs, interfaces)? { libraries.insert(svh, lib); } } @@ -508,6 +518,7 @@ impl<'a> CrateLocator<'a> { rlibs: FxIndexMap, rmetas: FxIndexMap, dylibs: FxIndexMap, + interfaces: FxIndexMap, ) -> Result, CrateError> { let mut slot = None; // Order here matters, rmeta should come first. @@ -515,12 +526,17 @@ impl<'a> CrateLocator<'a> { // Make sure there's at most one rlib and at most one dylib. // // See comment in `extract_one` below. - let source = CrateSource { - rmeta: self.extract_one(rmetas, CrateFlavor::Rmeta, &mut slot)?, - rlib: self.extract_one(rlibs, CrateFlavor::Rlib, &mut slot)?, - dylib: self.extract_one(dylibs, CrateFlavor::Dylib, &mut slot)?, - }; - Ok(slot.map(|(svh, metadata, _)| (svh, Library { source, metadata }))) + let rmeta = self.extract_one(rmetas, CrateFlavor::Rmeta, &mut slot)?; + let rlib = self.extract_one(rlibs, CrateFlavor::Rlib, &mut slot)?; + let sdylib_interface = self.extract_one(interfaces, CrateFlavor::SDylib, &mut slot)?; + let dylib = self.extract_one(dylibs, CrateFlavor::Dylib, &mut slot)?; + + if sdylib_interface.is_some() && dylib.is_none() { + return Err(CrateError::FullMetadataNotFound(self.crate_name, CrateFlavor::SDylib)); + } + + let source = CrateSource { rmeta, rlib, dylib, sdylib_interface }; + Ok(slot.map(|(svh, metadata, _, _)| (svh, Library { source, metadata }))) } fn needs_crate_flavor(&self, flavor: CrateFlavor) -> bool { @@ -550,7 +566,7 @@ impl<'a> CrateLocator<'a> { &mut self, m: FxIndexMap, flavor: CrateFlavor, - slot: &mut Option<(Svh, MetadataBlob, PathBuf)>, + slot: &mut Option<(Svh, MetadataBlob, PathBuf, CrateFlavor)>, ) -> Result, CrateError> { // If we are producing an rlib, and we've already loaded metadata, then // we should not attempt to discover further crate sources (unless we're @@ -586,6 +602,7 @@ impl<'a> CrateLocator<'a> { &lib, self.metadata_loader, self.cfg_version, + Some(self.crate_name), ) { Ok(blob) => { if let Some(h) = self.crate_matches(&blob, &lib) { @@ -610,6 +627,11 @@ impl<'a> CrateLocator<'a> { } Err(MetadataError::LoadFailure(err)) => { info!("no metadata found: {}", err); + // Metadata was loaded from interface file earlier. + if let Some((.., CrateFlavor::SDylib)) = slot { + ret = Some((lib, kind)); + continue; + } // The file was present and created by the same compiler version, but we // couldn't load it for some reason. Give a hard error instead of silently // ignoring it, but only if we would have given an error anyway. @@ -679,7 +701,7 @@ impl<'a> CrateLocator<'a> { return Err(CrateError::FullMetadataNotFound(self.crate_name, flavor)); } } else { - *slot = Some((hash, metadata, lib.clone())); + *slot = Some((hash, metadata, lib.clone(), flavor)); } ret = Some((lib, kind)); } @@ -736,6 +758,7 @@ impl<'a> CrateLocator<'a> { let mut rlibs = FxIndexMap::default(); let mut rmetas = FxIndexMap::default(); let mut dylibs = FxIndexMap::default(); + let mut sdylib_interfaces = FxIndexMap::default(); for loc in &self.exact_paths { let loc_canon = loc.canonicalized(); let loc_orig = loc.original(); @@ -763,6 +786,9 @@ impl<'a> CrateLocator<'a> { rmetas.insert(loc_canon.clone(), PathKind::ExternFlag); continue; } + if file.ends_with(".rs") { + sdylib_interfaces.insert(loc_canon.clone(), PathKind::ExternFlag); + } } let dll_prefix = self.target.dll_prefix.as_ref(); let dll_suffix = self.target.dll_suffix.as_ref(); @@ -776,7 +802,8 @@ impl<'a> CrateLocator<'a> { } // Extract the dylib/rlib/rmeta triple. - self.extract_lib(rlibs, rmetas, dylibs).map(|opt| opt.map(|(_, lib)| lib)) + self.extract_lib(rlibs, rmetas, dylibs, sdylib_interfaces) + .map(|opt| opt.map(|(_, lib)| lib)) } pub(crate) fn into_error(self, dep_root: Option) -> CrateError { @@ -797,6 +824,7 @@ fn get_metadata_section<'p>( filename: &'p Path, loader: &dyn MetadataLoader, cfg_version: &'static str, + crate_name: Option, ) -> Result> { if !filename.exists() { return Err(MetadataError::NotPresent(filename)); @@ -805,6 +833,55 @@ fn get_metadata_section<'p>( CrateFlavor::Rlib => { loader.get_rlib_metadata(target, filename).map_err(MetadataError::LoadFailure)? } + CrateFlavor::SDylib => { + let compiler = std::env::current_exe().map_err(|_err| { + MetadataError::LoadFailure( + "couldn't obtain current compiler binary when loading sdylib interface" + .to_string(), + ) + })?; + + let tmp_path = match TempFileBuilder::new().prefix("rustc").tempdir() { + Ok(tmp_path) => tmp_path, + Err(error) => { + return Err(MetadataError::LoadFailure(format!( + "couldn't create a temp dir: {}", + error + ))); + } + }; + + let crate_name = crate_name.unwrap(); + debug!("compiling {}", filename.display()); + // FIXME: This will need to be done either within the current compiler session or + // as a separate compiler session in the same process. + let res = std::process::Command::new(compiler) + .arg(&filename) + .arg("--emit=metadata") + .arg(format!("--crate-name={}", crate_name)) + .arg(format!("--out-dir={}", tmp_path.path().display())) + .arg("-Zbuild-sdylib-interface") + .output() + .map_err(|err| { + MetadataError::LoadFailure(format!("couldn't compile interface: {}", err)) + })?; + + if !res.status.success() { + return Err(MetadataError::LoadFailure(format!( + "couldn't compile interface: {}", + std::str::from_utf8(&res.stderr).unwrap_or_default() + ))); + } + + // Load interface metadata instead of crate metadata. + let interface_metadata_name = format!("lib{}.rmeta", crate_name); + let rmeta_file = tmp_path.path().join(interface_metadata_name); + debug!("loading interface metadata from {}", rmeta_file.display()); + let rmeta = get_rmeta_metadata_section(&rmeta_file)?; + let _ = std::fs::remove_file(rmeta_file); + + rmeta + } CrateFlavor::Dylib => { let buf = loader.get_dylib_metadata(target, filename).map_err(MetadataError::LoadFailure)?; @@ -834,24 +911,7 @@ fn get_metadata_section<'p>( // Header is okay -> inflate the actual metadata buf.slice(|buf| &buf[data_start..(data_start + metadata_len)]) } - CrateFlavor::Rmeta => { - // mmap the file, because only a small fraction of it is read. - let file = std::fs::File::open(filename).map_err(|_| { - MetadataError::LoadFailure(format!( - "failed to open rmeta metadata: '{}'", - filename.display() - )) - })?; - let mmap = unsafe { Mmap::map(file) }; - let mmap = mmap.map_err(|_| { - MetadataError::LoadFailure(format!( - "failed to mmap rmeta metadata: '{}'", - filename.display() - )) - })?; - - slice_owned(mmap, Deref::deref) - } + CrateFlavor::Rmeta => get_rmeta_metadata_section(filename)?, }; let Ok(blob) = MetadataBlob::new(raw_bytes) else { return Err(MetadataError::LoadFailure(format!( @@ -877,6 +937,25 @@ fn get_metadata_section<'p>( } } +fn get_rmeta_metadata_section<'a, 'p>(filename: &'p Path) -> Result> { + // mmap the file, because only a small fraction of it is read. + let file = std::fs::File::open(filename).map_err(|_| { + MetadataError::LoadFailure(format!( + "failed to open rmeta metadata: '{}'", + filename.display() + )) + })?; + let mmap = unsafe { Mmap::map(file) }; + let mmap = mmap.map_err(|_| { + MetadataError::LoadFailure(format!( + "failed to mmap rmeta metadata: '{}'", + filename.display() + )) + })?; + + Ok(slice_owned(mmap, Deref::deref)) +} + /// A diagnostic function for dumping crate metadata to an output stream. pub fn list_file_metadata( target: &Target, @@ -887,7 +966,7 @@ pub fn list_file_metadata( cfg_version: &'static str, ) -> IoResult<()> { let flavor = get_flavor_from_path(path); - match get_metadata_section(target, flavor, path, metadata_loader, cfg_version) { + match get_metadata_section(target, flavor, path, metadata_loader, cfg_version, None) { Ok(metadata) => metadata.list_crate_metadata(out, ls_kinds), Err(msg) => write!(out, "{msg}\n"), } diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 3c2245347f97..bd813cadedcd 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -1489,6 +1489,17 @@ impl<'a> CrateMetadataRef<'a> { tcx.arena.alloc_from_iter(self.root.lang_items_missing.decode(self)) } + fn get_exportable_items(self) -> impl Iterator { + self.root.exportable_items.decode(self).map(move |index| self.local_def_id(index)) + } + + fn get_stable_order_of_exportable_impls(self) -> impl Iterator { + self.root + .stable_order_of_exportable_impls + .decode(self) + .map(move |v| (self.local_def_id(v.0), v.1)) + } + fn exported_symbols<'tcx>( self, tcx: TyCtxt<'tcx>, diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index ecc2dcc5318d..76bae39ef8c0 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -406,6 +406,8 @@ provide! { tcx, def_id, other, cdata, used_crate_source => { Arc::clone(&cdata.source) } debugger_visualizers => { cdata.get_debugger_visualizers() } + exportable_items => { tcx.arena.alloc_from_iter(cdata.get_exportable_items()) } + stable_order_of_exportable_impls => { tcx.arena.alloc(cdata.get_stable_order_of_exportable_impls().collect()) } exported_symbols => { let syms = cdata.exported_symbols(tcx); diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 3ea61d1b40a6..7ac72ef814a9 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -551,8 +551,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { match source_file.name { FileName::Real(ref original_file_name) => { - // FIXME: This should probably to conditionally remapped under - // a RemapPathScopeComponents but which one? let adapted_file_name = source_map .path_mapping() .to_embeddable_absolute_path(original_file_name.clone(), working_directory); @@ -673,6 +671,11 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let debugger_visualizers = stat!("debugger-visualizers", || self.encode_debugger_visualizers()); + let exportable_items = stat!("exportable-items", || self.encode_exportable_items()); + + let stable_order_of_exportable_impls = + stat!("exportable-items", || self.encode_stable_order_of_exportable_impls()); + // Encode exported symbols info. This is prefetched in `encode_metadata`. let exported_symbols = stat!("exported-symbols", || { self.encode_exported_symbols(tcx.exported_symbols(LOCAL_CRATE)) @@ -740,6 +743,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { traits, impls, incoherent_impls, + exportable_items, + stable_order_of_exportable_impls, exported_symbols, interpret_alloc_index, tables, @@ -2149,6 +2154,20 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.lazy_array(&all_impls) } + fn encode_exportable_items(&mut self) -> LazyArray { + empty_proc_macro!(self); + self.lazy_array(self.tcx.exportable_items(LOCAL_CRATE).iter().map(|def_id| def_id.index)) + } + + fn encode_stable_order_of_exportable_impls(&mut self) -> LazyArray<(DefIndex, usize)> { + empty_proc_macro!(self); + let stable_order_of_exportable_impls = + self.tcx.stable_order_of_exportable_impls(LOCAL_CRATE); + self.lazy_array( + stable_order_of_exportable_impls.iter().map(|(def_id, idx)| (def_id.index, *idx)), + ) + } + // Encodes all symbols exported from this crate into the metadata. // // This pass is seeded off the reachability list calculated in the diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 5aa81f41b7b4..c86cf567283f 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -280,6 +280,8 @@ pub(crate) struct CrateRoot { tables: LazyTables, debugger_visualizers: LazyArray, + exportable_items: LazyArray, + stable_order_of_exportable_impls: LazyArray<(DefIndex, usize)>, exported_symbols: LazyArray<(ExportedSymbol<'static>, SymbolExportInfo)>, syntax_contexts: SyntaxContextTable, diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index 2dcb0de92b78..a0f459740893 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -91,6 +91,8 @@ macro_rules! arena_types { [] autodiff_item: rustc_ast::expand::autodiff_attrs::AutoDiffItem, [] ordered_name_set: rustc_data_structures::fx::FxIndexSet, [] valtree: rustc_middle::ty::ValTreeKind<'tcx>, + [] stable_order_of_exportable_impls: + rustc_data_structures::fx::FxIndexMap, // Note that this deliberately duplicates items in the `rustc_hir::arena`, // since we need to allocate this type on both the `rustc_hir` arena diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index 711036865bbd..979608df79c0 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -27,7 +27,6 @@ // tidy-alphabetical-start #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] -#![allow(rustc::potential_query_instability)] #![allow(rustc::untranslatable_diagnostic)] #![cfg_attr(bootstrap, feature(let_chains))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] diff --git a/compiler/rustc_middle/src/middle/exported_symbols.rs b/compiler/rustc_middle/src/middle/exported_symbols.rs index 3c62017072e4..1d67d0fe3bbf 100644 --- a/compiler/rustc_middle/src/middle/exported_symbols.rs +++ b/compiler/rustc_middle/src/middle/exported_symbols.rs @@ -56,7 +56,7 @@ impl<'tcx> ExportedSymbol<'tcx> { match *self { ExportedSymbol::NonGeneric(def_id) => tcx.symbol_name(ty::Instance::mono(tcx, def_id)), ExportedSymbol::Generic(def_id, args) => { - tcx.symbol_name(ty::Instance::new(def_id, args)) + tcx.symbol_name(ty::Instance::new_raw(def_id, args)) } ExportedSymbol::DropGlue(ty) => { tcx.symbol_name(ty::Instance::resolve_drop_in_place(tcx, ty)) diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index 890756a17cae..6ff3cac049b3 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -221,13 +221,11 @@ pub enum InvalidProgramInfo<'tcx> { #[derive(Debug, Copy, Clone)] pub enum CheckInAllocMsg { /// We are access memory. - MemoryAccessTest, + MemoryAccess, /// We are doing pointer arithmetic. - PointerArithmeticTest, - /// We are doing pointer offset_from. - OffsetFromTest, + InboundsPointerArithmetic, /// None of the above -- generic/unspecific inbounds test. - InboundsTest, + Dereferenceable, } /// Details of which pointer is not aligned. diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs index e5d1dda3aa0f..4a5c42c721c1 100644 --- a/compiler/rustc_middle/src/mir/interpret/queries.rs +++ b/compiler/rustc_middle/src/mir/interpret/queries.rs @@ -23,7 +23,7 @@ impl<'tcx> TyCtxt<'tcx> { // into `const_eval` which will return `ErrorHandled::TooGeneric` if any of them are // encountered. let args = GenericArgs::identity_for_item(self, def_id); - let instance = ty::Instance::new(def_id, args); + let instance = ty::Instance::new_raw(def_id, args); let cid = GlobalId { instance, promoted: None }; let typing_env = ty::TypingEnv::post_analysis(self, def_id); self.const_eval_global_id(typing_env, cid, DUMMY_SP) @@ -39,7 +39,7 @@ impl<'tcx> TyCtxt<'tcx> { // into `const_eval` which will return `ErrorHandled::TooGeneric` if any of them are // encountered. let args = GenericArgs::identity_for_item(self, def_id); - let instance = ty::Instance::new(def_id, args); + let instance = ty::Instance::new_raw(def_id, args); let cid = GlobalId { instance, promoted: None }; let typing_env = ty::TypingEnv::post_analysis(self, def_id); let inputs = self.erase_regions(typing_env.as_query_input(cid)); @@ -209,7 +209,7 @@ impl<'tcx> TyCtxtEnsureOk<'tcx> { // into `const_eval` which will return `ErrorHandled::TooGeneric` if any of them are // encountered. let args = GenericArgs::identity_for_item(self.tcx, def_id); - let instance = ty::Instance::new(def_id, self.tcx.erase_regions(args)); + let instance = ty::Instance::new_raw(def_id, self.tcx.erase_regions(args)); let cid = GlobalId { instance, promoted: None }; let typing_env = ty::TypingEnv::post_analysis(self.tcx, def_id); // Const-eval shouldn't depend on lifetimes at all, so we can erase them, which should diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index 6b413a7383a5..7243f87ee638 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -318,7 +318,7 @@ impl<'tcx> fmt::Display for MonoItem<'tcx> { match *self { MonoItem::Fn(instance) => write!(f, "fn {instance}"), MonoItem::Static(def_id) => { - write!(f, "static {}", Instance::new(def_id, GenericArgs::empty())) + write!(f, "static {}", Instance::new_raw(def_id, GenericArgs::empty())) } MonoItem::GlobalAsm(..) => write!(f, "global_asm"), } diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs index 8a1ead7d19d0..0834fa8844c0 100644 --- a/compiler/rustc_middle/src/mir/terminator.rs +++ b/compiler/rustc_middle/src/mir/terminator.rs @@ -437,8 +437,8 @@ impl<'tcx> Terminator<'tcx> { } #[inline] - pub fn successors_mut(&mut self) -> SuccessorsMut<'_> { - self.kind.successors_mut() + pub fn successors_mut<'a>(&'a mut self, f: impl FnMut(&'a mut BasicBlock)) { + self.kind.successors_mut(f) } #[inline] @@ -486,7 +486,6 @@ pub use helper::*; mod helper { use super::*; pub type Successors<'a> = impl DoubleEndedIterator + 'a; - pub type SuccessorsMut<'a> = impl DoubleEndedIterator + 'a; impl SwitchTargets { /// Like [`SwitchTargets::target_for_value`], but returning the same type as @@ -560,69 +559,63 @@ mod helper { } #[inline] - #[define_opaque(SuccessorsMut)] - pub fn successors_mut(&mut self) -> SuccessorsMut<'_> { + pub fn successors_mut<'a>(&'a mut self, mut f: impl FnMut(&'a mut BasicBlock)) { use self::TerminatorKind::*; - match *self { - // 3-successors for async drop: target, unwind, dropline (parent coroutine drop) - Drop { - target: ref mut t, - unwind: UnwindAction::Cleanup(ref mut u), - drop: Some(ref mut d), - .. - } => slice::from_mut(t).into_iter().chain(Some(u).into_iter().chain(Some(d))), - // 2-successors - Call { - target: Some(ref mut t), unwind: UnwindAction::Cleanup(ref mut u), .. + match self { + Drop { target, unwind, drop, .. } => { + f(target); + if let UnwindAction::Cleanup(u) = unwind { + f(u) + } + if let Some(d) = drop { + f(d) + } } - | Yield { resume: ref mut t, drop: Some(ref mut u), .. } - | Drop { - target: ref mut t, - unwind: UnwindAction::Cleanup(ref mut u), - drop: None, - .. + Call { target, unwind, .. } => { + if let Some(target) = target { + f(target); + } + if let UnwindAction::Cleanup(u) = unwind { + f(u) + } } - | Drop { target: ref mut t, unwind: _, drop: Some(ref mut u), .. } - | Assert { target: ref mut t, unwind: UnwindAction::Cleanup(ref mut u), .. } - | FalseUnwind { - real_target: ref mut t, - unwind: UnwindAction::Cleanup(ref mut u), - } => slice::from_mut(t).into_iter().chain(Some(u).into_iter().chain(None)), - // single successor - Goto { target: ref mut t } - | Call { target: None, unwind: UnwindAction::Cleanup(ref mut t), .. } - | Call { target: Some(ref mut t), unwind: _, .. } - | Yield { resume: ref mut t, drop: None, .. } - | Drop { target: ref mut t, unwind: _, .. } - | Assert { target: ref mut t, unwind: _, .. } - | FalseUnwind { real_target: ref mut t, unwind: _ } => { - slice::from_mut(t).into_iter().chain(None.into_iter().chain(None)) + Yield { resume, drop, .. } => { + f(resume); + if let Some(d) = drop { + f(d) + } + } + Assert { target, unwind, .. } | FalseUnwind { real_target: target, unwind } => { + f(target); + if let UnwindAction::Cleanup(u) = unwind { + f(u) + } + } + Goto { target } => { + f(target); } - // No successors UnwindResume | UnwindTerminate(_) | CoroutineDrop | Return | Unreachable - | TailCall { .. } - | Call { target: None, unwind: _, .. } => { - (&mut []).into_iter().chain(None.into_iter().chain(None)) + | TailCall { .. } => {} + InlineAsm { targets, unwind, .. } => { + for target in targets { + f(target); + } + if let UnwindAction::Cleanup(u) = unwind { + f(u) + } } - // Multiple successors - InlineAsm { ref mut targets, unwind: UnwindAction::Cleanup(ref mut u), .. } => { - targets.iter_mut().chain(Some(u).into_iter().chain(None)) + SwitchInt { targets, .. } => { + for target in &mut targets.targets { + f(target); + } } - InlineAsm { ref mut targets, unwind: _, .. } => { - targets.iter_mut().chain(None.into_iter().chain(None)) - } - SwitchInt { ref mut targets, .. } => { - targets.targets.iter_mut().chain(None.into_iter().chain(None)) - } - // FalseEdge - FalseEdge { ref mut real_target, ref mut imaginary_target } => { - slice::from_mut(real_target) - .into_iter() - .chain(Some(imaginary_target).into_iter().chain(None)) + FalseEdge { real_target, imaginary_target } => { + f(real_target); + f(imaginary_target); } } } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 88f4c4ae4d36..b2133fea08cc 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -387,7 +387,7 @@ rustc_queries! { } } - query stalled_generators_within( + query nested_bodies_within( key: LocalDefId ) -> &'tcx ty::List { desc { @@ -2205,7 +2205,7 @@ rustc_queries! { query maybe_unused_trait_imports(_: ()) -> &'tcx FxIndexSet { desc { "fetching potentially unused trait imports" } } - query names_imported_by_glob_use(def_id: LocalDefId) -> &'tcx UnordSet { + query names_imported_by_glob_use(def_id: LocalDefId) -> &'tcx FxIndexSet { desc { |tcx| "finding names imported by glob use for `{}`", tcx.def_path_str(def_id) } } @@ -2239,6 +2239,16 @@ rustc_queries! { separate_provide_extern } + query stable_order_of_exportable_impls(_: CrateNum) -> &'tcx FxIndexMap { + desc { "fetching the stable impl's order" } + separate_provide_extern + } + + query exportable_items(_: CrateNum) -> &'tcx [DefId] { + desc { "fetching all exportable items in a crate" } + separate_provide_extern + } + /// The list of symbols exported from the given crate. /// /// - All names contained in `exported_symbols(cnum)` are guaranteed to @@ -2471,7 +2481,7 @@ rustc_queries! { query resolve_instance_raw( key: ty::PseudoCanonicalInput<'tcx, (DefId, GenericArgsRef<'tcx>)> ) -> Result>, ErrorGuaranteed> { - desc { "resolving instance `{}`", ty::Instance::new(key.value.0, key.value.1) } + desc { "resolving instance `{}`", ty::Instance::new_raw(key.value.0, key.value.1) } } query reveal_opaque_types_in_bounds(key: ty::Clauses<'tcx>) -> ty::Clauses<'tcx> { diff --git a/compiler/rustc_middle/src/query/on_disk_cache.rs b/compiler/rustc_middle/src/query/on_disk_cache.rs index 5431097cb1d7..e1876f8f0f9b 100644 --- a/compiler/rustc_middle/src/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/query/on_disk_cache.rs @@ -2,7 +2,7 @@ use std::collections::hash_map::Entry; use std::mem; use std::sync::Arc; -use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; +use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet}; use rustc_data_structures::memmap::Mmap; use rustc_data_structures::sync::{HashMapExt, Lock, RwLock}; use rustc_data_structures::unhash::UnhashMap; @@ -57,7 +57,7 @@ pub struct OnDiskCache { // Collects all `QuerySideEffect` created during the current compilation // session. - current_side_effects: Lock>, + current_side_effects: Lock>, file_index_to_stable_id: FxHashMap, diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 086ec529f33a..b9a014d14c0d 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -292,7 +292,10 @@ pub enum ExprKind<'tcx> { If { if_then_scope: region::Scope, cond: ExprId, + /// `then` is always `ExprKind::Block`. then: ExprId, + /// If present, the `else_opt` expr is always `ExprKind::Block` (for + /// `else`) or `ExprKind::If` (for `else if`). else_opt: Option, }, /// A function call. Method calls and overloaded operators are converted to plain function calls. diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 0865e378bf3b..0759fa3da428 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -21,6 +21,7 @@ use rustc_data_structures::defer; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::intern::Interned; +use rustc_data_structures::jobserver::Proxy; use rustc_data_structures::profiling::SelfProfilerRef; use rustc_data_structures::sharded::{IntoPointer, ShardedHashMap}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; @@ -28,13 +29,12 @@ use rustc_data_structures::steal::Steal; use rustc_data_structures::sync::{ self, DynSend, DynSync, FreezeReadGuard, Lock, RwLock, WorkerLocal, }; -use rustc_data_structures::unord::UnordSet; use rustc_errors::{ Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, LintDiagnostic, MultiSpan, }; use rustc_hir::def::{CtorKind, DefKind}; use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId}; -use rustc_hir::definitions::Definitions; +use rustc_hir::definitions::{DefPathData, Definitions, DisambiguatorState}; use rustc_hir::intravisit::VisitorExt; use rustc_hir::lang_items::LangItem; use rustc_hir::{self as hir, Attribute, HirId, Node, TraitCandidate}; @@ -242,10 +242,18 @@ impl<'tcx> Interner for TyCtxt<'tcx> { ty::AliasTermKind::ProjectionTy } } + DefKind::AssocConst => { + if let DefKind::Impl { of_trait: false } = self.def_kind(self.parent(alias.def_id)) + { + ty::AliasTermKind::InherentConst + } else { + ty::AliasTermKind::ProjectionConst + } + } DefKind::OpaqueTy => ty::AliasTermKind::OpaqueTy, DefKind::TyAlias => ty::AliasTermKind::FreeTy, - DefKind::AssocConst => ty::AliasTermKind::ProjectionConst, - DefKind::AnonConst | DefKind::Const | DefKind::Ctor(_, CtorKind::Const) => { + DefKind::Const => ty::AliasTermKind::FreeConst, + DefKind::AnonConst | DefKind::Ctor(_, CtorKind::Const) => { ty::AliasTermKind::UnevaluatedConst } kind => bug!("unexpected DefKind in AliasTy: {kind:?}"), @@ -683,15 +691,17 @@ impl<'tcx> Interner for TyCtxt<'tcx> { self.opaque_types_defined_by(defining_anchor) } - fn opaque_types_and_generators_defined_by( + fn opaque_types_and_coroutines_defined_by( self, defining_anchor: Self::LocalDefId, ) -> Self::LocalDefIds { if self.next_trait_solver_globally() { + let coroutines_defined_by = self + .nested_bodies_within(defining_anchor) + .iter() + .filter(|def_id| self.is_coroutine(def_id.to_def_id())); self.mk_local_def_ids_from_iter( - self.opaque_types_defined_by(defining_anchor) - .iter() - .chain(self.stalled_generators_within(defining_anchor)), + self.opaque_types_defined_by(defining_anchor).iter().chain(coroutines_defined_by), ) } else { self.opaque_types_defined_by(defining_anchor) @@ -1441,6 +1451,9 @@ pub struct GlobalCtxt<'tcx> { pub(crate) alloc_map: interpret::AllocMap<'tcx>, current_gcx: CurrentGcx, + + /// A jobserver reference used to release then acquire a token while waiting on a query. + pub jobserver_proxy: Arc, } impl<'tcx> GlobalCtxt<'tcx> { @@ -1645,6 +1658,7 @@ impl<'tcx> TyCtxt<'tcx> { query_system: QuerySystem<'tcx>, hooks: crate::hooks::Providers, current_gcx: CurrentGcx, + jobserver_proxy: Arc, f: impl FnOnce(TyCtxt<'tcx>) -> T, ) -> T { let data_layout = s.target.parse_data_layout().unwrap_or_else(|err| { @@ -1679,6 +1693,7 @@ impl<'tcx> TyCtxt<'tcx> { data_layout, alloc_map: interpret::AllocMap::new(), current_gcx, + jobserver_proxy, }); // This is a separate function to work around a crash with parallel rustc (#135870) @@ -1814,9 +1829,10 @@ impl<'tcx> TyCtxt<'tcx> { self.crate_types() .iter() .map(|ty| match *ty { - CrateType::Executable | CrateType::Staticlib | CrateType::Cdylib => { - MetadataKind::None - } + CrateType::Executable + | CrateType::Staticlib + | CrateType::Cdylib + | CrateType::Sdylib => MetadataKind::None, CrateType::Rlib => MetadataKind::Uncompressed, CrateType::Dylib | CrateType::ProcMacro => MetadataKind::Compressed, }) @@ -1963,8 +1979,11 @@ impl<'tcx> TyCtxtAt<'tcx> { parent: LocalDefId, name: Option, def_kind: DefKind, + override_def_path_data: Option, + disambiguator: &mut DisambiguatorState, ) -> TyCtxtFeed<'tcx, LocalDefId> { - let feed = self.tcx.create_def(parent, name, def_kind); + let feed = + self.tcx.create_def(parent, name, def_kind, override_def_path_data, disambiguator); feed.def_span(self.span); feed @@ -1978,8 +1997,10 @@ impl<'tcx> TyCtxt<'tcx> { parent: LocalDefId, name: Option, def_kind: DefKind, + override_def_path_data: Option, + disambiguator: &mut DisambiguatorState, ) -> TyCtxtFeed<'tcx, LocalDefId> { - let data = def_kind.def_path_data(name); + let data = override_def_path_data.unwrap_or_else(|| def_kind.def_path_data(name)); // The following call has the side effect of modifying the tables inside `definitions`. // These very tables are relied on by the incr. comp. engine to decode DepNodes and to // decode the on-disk cache. @@ -1989,12 +2010,7 @@ impl<'tcx> TyCtxt<'tcx> { // - has been created by this call to `create_def`. // As a consequence, this LocalDefId is always re-created before it is needed by the incr. // comp. engine itself. - // - // This call also writes to the value of the `source_span` query. - // This is fine because: - // - that query is `eval_always` so we won't miss its result changing; - // - this write will have happened before that query is called. - let def_id = self.untracked.definitions.write().create_def(parent, data); + let def_id = self.untracked.definitions.write().create_def(parent, data, disambiguator); // This function modifies `self.definitions` using a side-effect. // We need to ensure that these side effects are re-run by the incr. comp. engine. @@ -2119,7 +2135,8 @@ impl<'tcx> TyCtxt<'tcx> { CrateType::Executable | CrateType::Staticlib | CrateType::ProcMacro - | CrateType::Cdylib => false, + | CrateType::Cdylib + | CrateType::Sdylib => false, // FIXME rust-lang/rust#64319, rust-lang/rust#64872: // We want to block export of generics from dylibs, @@ -2407,6 +2424,8 @@ macro_rules! sty_debug_print { $(let mut $variant = total;)* for shard in tcx.interners.type_.lock_shards() { + // It seems that ordering doesn't affect anything here. + #[allow(rustc::potential_query_instability)] let types = shard.iter(); for &(InternedInSet(t), ()) in types { let variant = match t.internee { @@ -3301,6 +3320,10 @@ impl<'tcx> TyCtxt<'tcx> { && self.impl_trait_header(def_id).unwrap().constness == hir::Constness::Const } + pub fn is_sdylib_interface_build(self) -> bool { + self.sess.opts.unstable_opts.build_sdylib_interface + } + pub fn intrinsic(self, def_id: impl IntoQueryParam + Copy) -> Option { match self.def_kind(def_id) { DefKind::Fn | DefKind::AssocFn => {} @@ -3393,9 +3416,7 @@ pub fn provide(providers: &mut Providers) { providers.maybe_unused_trait_imports = |tcx, ()| &tcx.resolutions(()).maybe_unused_trait_imports; providers.names_imported_by_glob_use = |tcx, id| { - tcx.arena.alloc(UnordSet::from( - tcx.resolutions(()).glob_map.get(&id).cloned().unwrap_or_default(), - )) + tcx.arena.alloc(tcx.resolutions(()).glob_map.get(&id).cloned().unwrap_or_default()) }; providers.extern_mod_stmt_cnum = diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index fbb57b8df6bb..b122ada0925d 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -3,7 +3,7 @@ use std::fmt::Write; use std::ops::ControlFlow; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::FxIndexMap; use rustc_errors::{ Applicability, Diag, DiagArgValue, IntoDiagArg, into_diag_arg_using_display, listify, pluralize, }; @@ -287,7 +287,7 @@ pub fn suggest_constraining_type_params<'a>( param_names_and_constraints: impl Iterator)>, span_to_replace: Option, ) -> bool { - let mut grouped = FxHashMap::default(); + let mut grouped = FxIndexMap::default(); let mut unstable_suggestion = false; param_names_and_constraints.for_each(|(param_name, constraint, def_id)| { let stable = match def_id { diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index d660e7d0d602..0d99a1b51499 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -491,7 +491,15 @@ fn resolve_async_drop_poll<'tcx>(mut cor_ty: Ty<'tcx>) -> Instance<'tcx> { } impl<'tcx> Instance<'tcx> { - pub fn new(def_id: DefId, args: GenericArgsRef<'tcx>) -> Instance<'tcx> { + /// Creates a new [`InstanceKind::Item`] from the `def_id` and `args`. + /// + /// Note that this item corresponds to the body of `def_id` directly, which + /// likely does not make sense for trait items which need to be resolved to an + /// implementation, and which may not even have a body themselves. Usages of + /// this function should probably use [`Instance::expect_resolve`], or if run + /// in a polymorphic environment or within a lint (that may encounter ambiguity) + /// [`Instance::try_resolve`] instead. + pub fn new_raw(def_id: DefId, args: GenericArgsRef<'tcx>) -> Instance<'tcx> { assert!( !args.has_escaping_bound_vars(), "args of instance {def_id:?} has escaping bound vars: {args:?}" @@ -510,7 +518,7 @@ impl<'tcx> Instance<'tcx> { } }); - Instance::new(def_id, args) + Instance::new_raw(def_id, args) } #[inline] @@ -603,7 +611,7 @@ impl<'tcx> Instance<'tcx> { let type_length = type_length(args); if !tcx.type_length_limit().value_within_limit(type_length) { let (shrunk, written_to_path) = - shrunk_instance_name(tcx, Instance::new(def_id, args)); + shrunk_instance_name(tcx, Instance::new_raw(def_id, args)); let mut path = PathBuf::new(); let was_written = if let Some(path2) = written_to_path { path = path2; @@ -773,7 +781,7 @@ impl<'tcx> Instance<'tcx> { match needs_fn_once_adapter_shim(actual_kind, requested_kind) { Ok(true) => Instance::fn_once_adapter_instance(tcx, def_id, args), - _ => Instance::new(def_id, args), + _ => Instance::new_raw(def_id, args), } } @@ -899,7 +907,7 @@ impl<'tcx> Instance<'tcx> { // This is important for `Iterator`'s combinators, but also useful for // adding future default methods to `Future`, for instance. debug_assert!(tcx.defaultness(trait_item_id).has_value()); - Some(Instance::new(trait_item_id, rcvr_args)) + Some(Instance::new_raw(trait_item_id, rcvr_args)) } } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 2f4c03f0953d..2d69a1c2b553 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -38,6 +38,7 @@ use rustc_errors::{Diag, ErrorGuaranteed}; use rustc_hir::LangItem; use rustc_hir::def::{CtorKind, CtorOf, DefKind, DocLinkResMap, LifetimeRes, Res}; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LocalDefIdMap}; +use rustc_hir::definitions::DisambiguatorState; use rustc_index::IndexVec; use rustc_index::bit_set::BitMatrix; use rustc_macros::{ @@ -50,9 +51,17 @@ 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, kw, sym}; -pub use rustc_type_ir::data_structures::DelayedSet; +pub use rustc_type_ir::data_structures::{DelayedMap, DelayedSet}; +#[allow( + hidden_glob_reexports, + rustc::usage_of_type_ir_inherent, + rustc::non_glob_import_of_type_ir_inherent +)] +use rustc_type_ir::inherent; pub use rustc_type_ir::relate::VarianceDiagInfo; pub use rustc_type_ir::*; +#[allow(hidden_glob_reexports, unused_imports)] +use rustc_type_ir::{InferCtxtLike, Interner}; use tracing::{debug, instrument}; pub use vtable::*; use {rustc_ast as ast, rustc_attr_data_structures as attr, rustc_hir as hir}; @@ -173,7 +182,7 @@ pub struct ResolverGlobalCtxt { pub extern_crate_map: UnordMap, pub maybe_unused_trait_imports: FxIndexSet, pub module_children: LocalDefIdMap>, - pub glob_map: FxHashMap>, + pub glob_map: FxIndexMap>, pub main_def: Option, pub trait_impls: FxIndexMap>, /// A list of proc macro LocalDefIds, written out in the order in which @@ -209,6 +218,8 @@ pub struct ResolverAstLowering { pub node_id_to_def_id: NodeMap, + pub disambiguator: DisambiguatorState, + pub trait_map: NodeMap>, /// List functions and methods for which lifetime elision was successful. pub lifetime_elision_allowed: FxHashSet, @@ -298,7 +309,10 @@ impl Visibility { } else if restricted_id == tcx.parent_module_from_def_id(def_id).to_local_def_id() { "pub(self)".to_string() } else { - format!("pub({})", tcx.item_name(restricted_id.to_def_id())) + format!( + "pub(in crate{})", + tcx.def_path(restricted_id.to_def_id()).to_string_no_crate_verbose() + ) } } ty::Visibility::Public => "pub".to_string(), @@ -1929,13 +1943,17 @@ impl<'tcx> TyCtxt<'tcx> { if arg_cor_ty.is_coroutine() { let span = self.def_span(def_id); let source_info = SourceInfo::outermost(span); + // Even minimal, empty coroutine has 3 states (RESERVED_VARIANTS), + // so variant_fields and variant_source_info should have 3 elements. let variant_fields: IndexVec> = iter::repeat(IndexVec::new()).take(CoroutineArgs::RESERVED_VARIANTS).collect(); + let variant_source_info: IndexVec = + iter::repeat(source_info).take(CoroutineArgs::RESERVED_VARIANTS).collect(); let proxy_layout = CoroutineLayout { field_tys: [].into(), field_names: [].into(), variant_fields, - variant_source_info: [source_info].into(), + variant_source_info, storage_conflicts: BitMatrix::new(0, 0), }; return Some(self.arena.alloc(proxy_layout)); @@ -1978,6 +1996,10 @@ impl<'tcx> TyCtxt<'tcx> { None } + pub fn is_exportable(self, def_id: DefId) -> bool { + self.exportable_items(def_id.krate).contains(&def_id) + } + /// Check if the given `DefId` is `#\[automatically_derived\]`, *and* /// whether it was produced by expanding a builtin derive macro. pub fn is_builtin_derived(self, def_id: DefId) -> bool { diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index ad8677f7c7da..bc1423a9e3c2 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -6,7 +6,7 @@ use std::ops::{Deref, DerefMut}; use rustc_abi::{ExternAbi, Size}; use rustc_apfloat::Float; use rustc_apfloat::ieee::{Double, Half, Quad, Single}; -use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; +use rustc_data_structures::fx::{FxIndexMap, IndexEntry}; use rustc_data_structures::unord::UnordMap; use rustc_hir as hir; use rustc_hir::LangItem; @@ -3195,7 +3195,7 @@ define_print! { ty::AliasTerm<'tcx> { match self.kind(cx.tcx()) { - ty::AliasTermKind::InherentTy => p!(pretty_print_inherent_projection(*self)), + ty::AliasTermKind::InherentTy | ty::AliasTermKind::InherentConst => p!(pretty_print_inherent_projection(*self)), ty::AliasTermKind::ProjectionTy => { if !(cx.should_print_verbose() || with_reduced_queries()) && cx.tcx().is_impl_trait_in_trait(self.def_id) @@ -3205,7 +3205,8 @@ define_print! { p!(print_def_path(self.def_id, self.args)); } } - | ty::AliasTermKind::FreeTy + ty::AliasTermKind::FreeTy + | ty::AliasTermKind::FreeConst | ty::AliasTermKind::OpaqueTy | ty::AliasTermKind::UnevaluatedConst | ty::AliasTermKind::ProjectionConst => { @@ -3496,8 +3497,8 @@ pub fn trimmed_def_paths(tcx: TyCtxt<'_>, (): ()) -> DefIdMap { // Once constructed, unique namespace+symbol pairs will have a `Some(_)` entry, while // non-unique pairs will have a `None` entry. - let unique_symbols_rev: &mut FxHashMap<(Namespace, Symbol), Option> = - &mut FxHashMap::default(); + let unique_symbols_rev: &mut FxIndexMap<(Namespace, Symbol), Option> = + &mut FxIndexMap::default(); for symbol_set in tcx.resolutions(()).glob_map.values() { for symbol in symbol_set { @@ -3507,27 +3508,23 @@ pub fn trimmed_def_paths(tcx: TyCtxt<'_>, (): ()) -> DefIdMap { } } - for_each_def(tcx, |ident, ns, def_id| { - use std::collections::hash_map::Entry::{Occupied, Vacant}; - - match unique_symbols_rev.entry((ns, ident.name)) { - Occupied(mut v) => match v.get() { - None => {} - Some(existing) => { - if *existing != def_id { - v.insert(None); - } + for_each_def(tcx, |ident, ns, def_id| match unique_symbols_rev.entry((ns, ident.name)) { + IndexEntry::Occupied(mut v) => match v.get() { + None => {} + Some(existing) => { + if *existing != def_id { + v.insert(None); } - }, - Vacant(v) => { - v.insert(Some(def_id)); } + }, + IndexEntry::Vacant(v) => { + v.insert(Some(def_id)); } }); // Put the symbol from all the unique namespace+symbol pairs into `map`. let mut map: DefIdMap = Default::default(); - for ((_, symbol), opt_def_id) in unique_symbols_rev.drain() { + for ((_, symbol), opt_def_id) in unique_symbols_rev.drain(..) { use std::collections::hash_map::Entry::{Occupied, Vacant}; if let Some(def_id) = opt_def_id { diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index f5158edffcff..6fe5927c29fc 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -966,7 +966,9 @@ impl<'tcx> TyCtxt<'tcx> { } ty::AliasTermKind::OpaqueTy => Some(self.variances_of(def_id)), ty::AliasTermKind::InherentTy + | ty::AliasTermKind::InherentConst | ty::AliasTermKind::FreeTy + | ty::AliasTermKind::FreeConst | ty::AliasTermKind::UnevaluatedConst | ty::AliasTermKind::ProjectionConst => None, } diff --git a/compiler/rustc_mir_build/src/builder/mod.rs b/compiler/rustc_mir_build/src/builder/mod.rs index 59a52ae67cb1..9cf051a8760b 100644 --- a/compiler/rustc_mir_build/src/builder/mod.rs +++ b/compiler/rustc_mir_build/src/builder/mod.rs @@ -998,7 +998,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.source_scope = source_scope; } - if self.tcx.intrinsic(self.def_id).is_some_and(|i| i.must_be_overridden) { + if self.tcx.intrinsic(self.def_id).is_some_and(|i| i.must_be_overridden) + || self.tcx.is_sdylib_interface_build() + { let source_info = self.source_info(rustc_span::DUMMY_SP); self.cfg.terminate(block, source_info, TerminatorKind::Unreachable); self.cfg.start_new_block().unit() diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 8e69ff568b92..fcd106d78e25 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -553,8 +553,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { let res = self.typeck_results.qpath_res(qpath, id); let (def_id, user_ty) = match res { - Res::Def(DefKind::Const, def_id) => (def_id, None), - Res::Def(DefKind::AssocConst, def_id) => { + Res::Def(DefKind::Const, def_id) | Res::Def(DefKind::AssocConst, def_id) => { (def_id, self.typeck_results.user_provided_types().get(id)) } @@ -568,6 +567,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { // Lower the named constant to a THIR pattern. let args = self.typeck_results.node_args(id); + // FIXME(mgca): we will need to special case IACs here to have type system compatible + // generic args, instead of how we represent them in body expressions. let c = ty::Const::new_unevaluated(self.tcx, ty::UnevaluatedConst { def: def_id, args }); let mut pattern = self.const_to_pat(c, ty, id, span); diff --git a/compiler/rustc_mir_dataflow/src/framework/cursor.rs b/compiler/rustc_mir_dataflow/src/framework/cursor.rs index d5005768b80b..3f6e7a066192 100644 --- a/compiler/rustc_mir_dataflow/src/framework/cursor.rs +++ b/compiler/rustc_mir_dataflow/src/framework/cursor.rs @@ -1,5 +1,6 @@ //! Random access inspection of the results of a dataflow analysis. +use std::borrow::Cow; use std::cmp::Ordering; use std::ops::{Deref, DerefMut}; @@ -9,38 +10,30 @@ use rustc_middle::mir::{self, BasicBlock, Location}; use super::{Analysis, Direction, Effect, EffectIndex, Results}; -/// Some `ResultsCursor`s want to own a `Results`, and some want to borrow a `Results`, either -/// mutable or immutably. This type allows all of the above. It's similar to `Cow`. -pub enum ResultsHandle<'a, 'tcx, A> -where - A: Analysis<'tcx>, -{ - BorrowedMut(&'a mut Results<'tcx, A>), - Owned(Results<'tcx, A>), +/// Some `ResultsCursor`s want to own an `Analysis`, and some want to borrow an `Analysis`, either +/// mutable or immutably. This type allows all of the above. It's similar to `Cow`, but `Cow` +/// doesn't allow mutable borrowing. +enum CowMut<'a, T> { + BorrowedMut(&'a mut T), + Owned(T), } -impl<'tcx, A> Deref for ResultsHandle<'_, 'tcx, A> -where - A: Analysis<'tcx>, -{ - type Target = Results<'tcx, A>; +impl Deref for CowMut<'_, T> { + type Target = T; - fn deref(&self) -> &Results<'tcx, A> { + fn deref(&self) -> &T { match self { - ResultsHandle::BorrowedMut(borrowed) => borrowed, - ResultsHandle::Owned(owned) => owned, + CowMut::BorrowedMut(borrowed) => borrowed, + CowMut::Owned(owned) => owned, } } } -impl<'tcx, A> DerefMut for ResultsHandle<'_, 'tcx, A> -where - A: Analysis<'tcx>, -{ - fn deref_mut(&mut self) -> &mut Results<'tcx, A> { +impl DerefMut for CowMut<'_, T> { + fn deref_mut(&mut self) -> &mut T { match self { - ResultsHandle::BorrowedMut(borrowed) => borrowed, - ResultsHandle::Owned(owned) => owned, + CowMut::BorrowedMut(borrowed) => borrowed, + CowMut::Owned(owned) => owned, } } } @@ -60,7 +53,8 @@ where A: Analysis<'tcx>, { body: &'mir mir::Body<'tcx>, - results: ResultsHandle<'mir, 'tcx, A>, + analysis: CowMut<'mir, A>, + results: Cow<'mir, Results>, state: A::Domain, pos: CursorPosition, @@ -88,11 +82,15 @@ where self.body } - /// Returns a new cursor that can inspect `results`. - pub fn new(body: &'mir mir::Body<'tcx>, results: ResultsHandle<'mir, 'tcx, A>) -> Self { - let bottom_value = results.analysis.bottom_value(body); + fn new( + body: &'mir mir::Body<'tcx>, + analysis: CowMut<'mir, A>, + results: Cow<'mir, Results>, + ) -> Self { + let bottom_value = analysis.bottom_value(body); ResultsCursor { body, + analysis, results, // Initialize to the `bottom_value` and set `state_needs_reset` to tell the cursor that @@ -107,6 +105,24 @@ where } } + /// Returns a new cursor that takes ownership of and inspects analysis results. + pub fn new_owning( + body: &'mir mir::Body<'tcx>, + analysis: A, + results: Results, + ) -> Self { + Self::new(body, CowMut::Owned(analysis), Cow::Owned(results)) + } + + /// Returns a new cursor that borrows and inspects analysis results. + pub fn new_borrowing( + body: &'mir mir::Body<'tcx>, + analysis: &'mir mut A, + results: &'mir Results, + ) -> Self { + Self::new(body, CowMut::BorrowedMut(analysis), Cow::Borrowed(results)) + } + /// Allows inspection of unreachable basic blocks even with `debug_assertions` enabled. #[cfg(test)] pub(crate) fn allow_unreachable(&mut self) { @@ -116,7 +132,7 @@ where /// Returns the `Analysis` used to generate the underlying `Results`. pub fn analysis(&self) -> &A { - &self.results.analysis + &self.analysis } /// Resets the cursor to hold the entry set for the given basic block. @@ -128,7 +144,7 @@ where #[cfg(debug_assertions)] assert!(self.reachable_blocks.contains(block)); - self.state.clone_from(self.results.entry_set_for_block(block)); + self.state.clone_from(&self.results[block]); self.pos = CursorPosition::block_entry(block); self.state_needs_reset = false; } @@ -220,7 +236,7 @@ where let target_effect_index = effect.at_index(target.statement_index); A::Direction::apply_effects_in_range( - &mut self.results.analysis, + &mut *self.analysis, &mut self.state, target.block, block_data, @@ -236,7 +252,7 @@ where /// This can be used, e.g., to apply the call return effect directly to the cursor without /// creating an extra copy of the dataflow state. pub fn apply_custom_effect(&mut self, f: impl FnOnce(&mut A, &mut A::Domain)) { - f(&mut self.results.analysis, &mut self.state); + f(&mut self.analysis, &mut self.state); self.state_needs_reset = true; } } diff --git a/compiler/rustc_mir_dataflow/src/framework/direction.rs b/compiler/rustc_mir_dataflow/src/framework/direction.rs index b8c26dad59f4..e955e38ad10f 100644 --- a/compiler/rustc_mir_dataflow/src/framework/direction.rs +++ b/compiler/rustc_mir_dataflow/src/framework/direction.rs @@ -5,7 +5,7 @@ use rustc_middle::mir::{ }; use super::visitor::ResultsVisitor; -use super::{Analysis, Effect, EffectIndex, Results}; +use super::{Analysis, Effect, EffectIndex}; pub trait Direction { const IS_FORWARD: bool; @@ -36,13 +36,13 @@ pub trait Direction { A: Analysis<'tcx>; /// Called by `ResultsVisitor` to recompute the analysis domain values for - /// all locations in a basic block (starting from the entry value stored - /// in `Results`) and to visit them with `vis`. + /// all locations in a basic block (starting from `entry_state` and to + /// visit them with `vis`. fn visit_results_in_block<'mir, 'tcx, A>( state: &mut A::Domain, block: BasicBlock, block_data: &'mir mir::BasicBlockData<'tcx>, - results: &mut Results<'tcx, A>, + analysis: &mut A, vis: &mut impl ResultsVisitor<'tcx, A>, ) where A: Analysis<'tcx>; @@ -211,28 +211,26 @@ impl Direction for Backward { state: &mut A::Domain, block: BasicBlock, block_data: &'mir mir::BasicBlockData<'tcx>, - results: &mut Results<'tcx, A>, + analysis: &mut A, vis: &mut impl ResultsVisitor<'tcx, A>, ) where A: Analysis<'tcx>, { - state.clone_from(results.entry_set_for_block(block)); - vis.visit_block_end(state); let loc = Location { block, statement_index: block_data.statements.len() }; let term = block_data.terminator(); - results.analysis.apply_early_terminator_effect(state, term, loc); - vis.visit_after_early_terminator_effect(results, state, term, loc); - results.analysis.apply_primary_terminator_effect(state, term, loc); - vis.visit_after_primary_terminator_effect(results, state, term, loc); + analysis.apply_early_terminator_effect(state, term, loc); + vis.visit_after_early_terminator_effect(analysis, state, term, loc); + analysis.apply_primary_terminator_effect(state, term, loc); + vis.visit_after_primary_terminator_effect(analysis, state, term, loc); for (statement_index, stmt) in block_data.statements.iter().enumerate().rev() { let loc = Location { block, statement_index }; - results.analysis.apply_early_statement_effect(state, stmt, loc); - vis.visit_after_early_statement_effect(results, state, stmt, loc); - results.analysis.apply_primary_statement_effect(state, stmt, loc); - vis.visit_after_primary_statement_effect(results, state, stmt, loc); + analysis.apply_early_statement_effect(state, stmt, loc); + vis.visit_after_early_statement_effect(analysis, state, stmt, loc); + analysis.apply_primary_statement_effect(state, stmt, loc); + vis.visit_after_primary_statement_effect(analysis, state, stmt, loc); } vis.visit_block_start(state); @@ -393,29 +391,27 @@ impl Direction for Forward { state: &mut A::Domain, block: BasicBlock, block_data: &'mir mir::BasicBlockData<'tcx>, - results: &mut Results<'tcx, A>, + analysis: &mut A, vis: &mut impl ResultsVisitor<'tcx, A>, ) where A: Analysis<'tcx>, { - state.clone_from(results.entry_set_for_block(block)); - vis.visit_block_start(state); for (statement_index, stmt) in block_data.statements.iter().enumerate() { let loc = Location { block, statement_index }; - results.analysis.apply_early_statement_effect(state, stmt, loc); - vis.visit_after_early_statement_effect(results, state, stmt, loc); - results.analysis.apply_primary_statement_effect(state, stmt, loc); - vis.visit_after_primary_statement_effect(results, state, stmt, loc); + analysis.apply_early_statement_effect(state, stmt, loc); + vis.visit_after_early_statement_effect(analysis, state, stmt, loc); + analysis.apply_primary_statement_effect(state, stmt, loc); + vis.visit_after_primary_statement_effect(analysis, state, stmt, loc); } let loc = Location { block, statement_index: block_data.statements.len() }; let term = block_data.terminator(); - results.analysis.apply_early_terminator_effect(state, term, loc); - vis.visit_after_early_terminator_effect(results, state, term, loc); - results.analysis.apply_primary_terminator_effect(state, term, loc); - vis.visit_after_primary_terminator_effect(results, state, term, loc); + analysis.apply_early_terminator_effect(state, term, loc); + vis.visit_after_early_terminator_effect(analysis, state, term, loc); + analysis.apply_primary_terminator_effect(state, term, loc); + vis.visit_after_primary_terminator_effect(analysis, state, term, loc); vis.visit_block_end(state); } diff --git a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs index b5e9a0b89324..a7d5422a3d72 100644 --- a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs +++ b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs @@ -21,7 +21,9 @@ use tracing::debug; use {rustc_ast as ast, rustc_graphviz as dot}; use super::fmt::{DebugDiffWithAdapter, DebugWithAdapter, DebugWithContext}; -use super::{Analysis, CallReturnPlaces, Direction, Results, ResultsCursor, ResultsVisitor}; +use super::{ + Analysis, CallReturnPlaces, Direction, Results, ResultsCursor, ResultsVisitor, visit_results, +}; use crate::errors::{ DuplicateValuesFor, PathMustEndInFilename, RequiresAnArgument, UnknownFormatter, }; @@ -32,7 +34,8 @@ use crate::errors::{ pub(super) fn write_graphviz_results<'tcx, A>( tcx: TyCtxt<'tcx>, body: &Body<'tcx>, - results: &mut Results<'tcx, A>, + analysis: &mut A, + results: &Results, pass_name: Option<&'static str>, ) -> std::io::Result<()> where @@ -77,7 +80,7 @@ where let mut buf = Vec::new(); - let graphviz = Formatter::new(body, results, style); + let graphviz = Formatter::new(body, analysis, results, style); let mut render_opts = vec![dot::RenderOption::Fontname(tcx.sess.opts.unstable_opts.graphviz_font.clone())]; if tcx.sess.opts.unstable_opts.graphviz_dark_mode { @@ -203,10 +206,11 @@ where { body: &'mir Body<'tcx>, // The `RefCell` is used because `::node_label` - // takes `&self`, but it needs to modify the results. This is also the + // takes `&self`, but it needs to modify the analysis. This is also the // reason for the `Formatter`/`BlockFormatter` split; `BlockFormatter` has // the operations that involve the mutation, i.e. within the `borrow_mut`. - results: RefCell<&'mir mut Results<'tcx, A>>, + analysis: RefCell<&'mir mut A>, + results: &'mir Results, style: OutputStyle, reachable: DenseBitSet, } @@ -217,11 +221,12 @@ where { fn new( body: &'mir Body<'tcx>, - results: &'mir mut Results<'tcx, A>, + analysis: &'mir mut A, + results: &'mir Results, style: OutputStyle, ) -> Self { let reachable = traversal::reachable_as_bitset(body); - Formatter { body, results: results.into(), style, reachable } + Formatter { body, analysis: analysis.into(), results, style, reachable } } } @@ -259,12 +264,12 @@ where } fn node_label(&self, block: &Self::Node) -> dot::LabelText<'_> { - let mut results = self.results.borrow_mut(); + let analysis = &mut **self.analysis.borrow_mut(); - let diffs = StateDiffCollector::run(self.body, *block, *results, self.style); + let diffs = StateDiffCollector::run(self.body, *block, analysis, self.results, self.style); let mut fmt = BlockFormatter { - cursor: results.as_results_cursor(self.body), + cursor: ResultsCursor::new_borrowing(self.body, analysis, self.results), style: self.style, bg: Background::Light, }; @@ -692,7 +697,8 @@ impl StateDiffCollector { fn run<'tcx, A>( body: &Body<'tcx>, block: BasicBlock, - results: &mut Results<'tcx, A>, + analysis: &mut A, + results: &Results, style: OutputStyle, ) -> Self where @@ -700,12 +706,12 @@ impl StateDiffCollector { D: DebugWithContext, { let mut collector = StateDiffCollector { - prev_state: results.analysis.bottom_value(body), + prev_state: analysis.bottom_value(body), after: vec![], before: (style == OutputStyle::BeforeAndAfter).then_some(vec![]), }; - results.visit_with(body, std::iter::once(block), &mut collector); + visit_results(body, std::iter::once(block), analysis, results, &mut collector); collector } } @@ -729,49 +735,49 @@ where fn visit_after_early_statement_effect( &mut self, - results: &mut Results<'tcx, A>, + analysis: &mut A, state: &A::Domain, _statement: &mir::Statement<'tcx>, _location: Location, ) { if let Some(before) = self.before.as_mut() { - before.push(diff_pretty(state, &self.prev_state, &results.analysis)); + before.push(diff_pretty(state, &self.prev_state, analysis)); self.prev_state.clone_from(state) } } fn visit_after_primary_statement_effect( &mut self, - results: &mut Results<'tcx, A>, + analysis: &mut A, state: &A::Domain, _statement: &mir::Statement<'tcx>, _location: Location, ) { - self.after.push(diff_pretty(state, &self.prev_state, &results.analysis)); + self.after.push(diff_pretty(state, &self.prev_state, analysis)); self.prev_state.clone_from(state) } fn visit_after_early_terminator_effect( &mut self, - results: &mut Results<'tcx, A>, + analysis: &mut A, state: &A::Domain, _terminator: &mir::Terminator<'tcx>, _location: Location, ) { if let Some(before) = self.before.as_mut() { - before.push(diff_pretty(state, &self.prev_state, &results.analysis)); + before.push(diff_pretty(state, &self.prev_state, analysis)); self.prev_state.clone_from(state) } } fn visit_after_primary_terminator_effect( &mut self, - results: &mut Results<'tcx, A>, + analysis: &mut A, state: &A::Domain, _terminator: &mir::Terminator<'tcx>, _location: Location, ) { - self.after.push(diff_pretty(state, &self.prev_state, &results.analysis)); + self.after.push(diff_pretty(state, &self.prev_state, analysis)); self.prev_state.clone_from(state) } } diff --git a/compiler/rustc_mir_dataflow/src/framework/mod.rs b/compiler/rustc_mir_dataflow/src/framework/mod.rs index 09f6cdb5c4a7..9cadec100b53 100644 --- a/compiler/rustc_mir_dataflow/src/framework/mod.rs +++ b/compiler/rustc_mir_dataflow/src/framework/mod.rs @@ -58,8 +58,9 @@ mod visitor; pub use self::cursor::ResultsCursor; pub use self::direction::{Backward, Direction, Forward}; pub use self::lattice::{JoinSemiLattice, MaybeReachable}; -pub use self::results::{EntryStates, Results}; -pub use self::visitor::{ResultsVisitor, visit_results}; +pub(crate) use self::results::AnalysisAndResults; +pub use self::results::Results; +pub use self::visitor::{ResultsVisitor, visit_reachable_results, visit_results}; /// Analysis domains are all bitsets of various kinds. This trait holds /// operations needed by all of them. @@ -247,17 +248,15 @@ pub trait Analysis<'tcx> { tcx: TyCtxt<'tcx>, body: &'mir mir::Body<'tcx>, pass_name: Option<&'static str>, - ) -> Results<'tcx, Self> + ) -> AnalysisAndResults<'tcx, Self> where Self: Sized, Self::Domain: DebugWithContext, { - let mut entry_states = - IndexVec::from_fn_n(|_| self.bottom_value(body), body.basic_blocks.len()); - self.initialize_start_block(body, &mut entry_states[mir::START_BLOCK]); + let mut results = IndexVec::from_fn_n(|_| self.bottom_value(body), body.basic_blocks.len()); + self.initialize_start_block(body, &mut results[mir::START_BLOCK]); - if Self::Direction::IS_BACKWARD && entry_states[mir::START_BLOCK] != self.bottom_value(body) - { + if Self::Direction::IS_BACKWARD && results[mir::START_BLOCK] != self.bottom_value(body) { bug!("`initialize_start_block` is not yet supported for backward dataflow analyses"); } @@ -280,10 +279,9 @@ pub trait Analysis<'tcx> { // every iteration. let mut state = self.bottom_value(body); while let Some(bb) = dirty_queue.pop() { - // Set the state to the entry state of the block. - // This is equivalent to `state = entry_states[bb].clone()`, - // but it saves an allocation, thus improving compile times. - state.clone_from(&entry_states[bb]); + // Set the state to the entry state of the block. This is equivalent to `state = + // results[bb].clone()`, but it saves an allocation, thus improving compile times. + state.clone_from(&results[bb]); Self::Direction::apply_effects_in_block( &mut self, @@ -292,7 +290,7 @@ pub trait Analysis<'tcx> { bb, &body[bb], |target: BasicBlock, state: &Self::Domain| { - let set_changed = entry_states[target].join(state); + let set_changed = results[target].join(state); if set_changed { dirty_queue.insert(target); } @@ -300,16 +298,14 @@ pub trait Analysis<'tcx> { ); } - let mut results = Results { analysis: self, entry_states }; - if tcx.sess.opts.unstable_opts.dump_mir_dataflow { - let res = write_graphviz_results(tcx, body, &mut results, pass_name); + let res = write_graphviz_results(tcx, body, &mut self, &results, pass_name); if let Err(e) = res { error!("Failed to write graphviz dataflow results: {}", e); } } - results + AnalysisAndResults { analysis: self, results } } } diff --git a/compiler/rustc_mir_dataflow/src/framework/results.rs b/compiler/rustc_mir_dataflow/src/framework/results.rs index 93dfc06a878a..7b7e981d3a55 100644 --- a/compiler/rustc_mir_dataflow/src/framework/results.rs +++ b/compiler/rustc_mir_dataflow/src/framework/results.rs @@ -1,63 +1,30 @@ //! Dataflow analysis results. use rustc_index::IndexVec; -use rustc_middle::mir::{BasicBlock, Body, traversal}; +use rustc_middle::mir::{BasicBlock, Body}; -use super::{Analysis, ResultsCursor, ResultsVisitor, visit_results}; -use crate::framework::cursor::ResultsHandle; +use super::{Analysis, ResultsCursor}; -pub type EntryStates<'tcx, A> = IndexVec>::Domain>; +/// The results of a dataflow analysis that has converged to fixpoint. It only holds the domain +/// values at the entry of each basic block. Domain values in other parts of the block are +/// recomputed on the fly by visitors (i.e. `ResultsCursor`, or `ResultsVisitor` impls). +pub type Results = IndexVec; -/// A dataflow analysis that has converged to fixpoint. It only holds the domain values at the -/// entry of each basic block. Domain values in other parts of the block are recomputed on the fly -/// by visitors (i.e. `ResultsCursor`, or `ResultsVisitor` impls). -#[derive(Clone)] -pub struct Results<'tcx, A> +/// Utility type used in a few places where it's convenient to bundle an analysis with its results. +pub struct AnalysisAndResults<'tcx, A> where A: Analysis<'tcx>, { pub analysis: A, - pub entry_states: EntryStates<'tcx, A>, + pub results: Results, } -impl<'tcx, A> Results<'tcx, A> +impl<'tcx, A> AnalysisAndResults<'tcx, A> where A: Analysis<'tcx>, { - /// Creates a `ResultsCursor` that mutably borrows the `Results`, which is appropriate when the - /// `Results` is also used outside the cursor. - pub fn as_results_cursor<'mir>( - &'mir mut self, - body: &'mir Body<'tcx>, - ) -> ResultsCursor<'mir, 'tcx, A> { - ResultsCursor::new(body, ResultsHandle::BorrowedMut(self)) - } - - /// Creates a `ResultsCursor` that takes ownership of the `Results`. + /// Creates a `ResultsCursor` that takes ownership of `self`. pub fn into_results_cursor<'mir>(self, body: &'mir Body<'tcx>) -> ResultsCursor<'mir, 'tcx, A> { - ResultsCursor::new(body, ResultsHandle::Owned(self)) - } - - /// Gets the dataflow state for the given block. - pub fn entry_set_for_block(&self, block: BasicBlock) -> &A::Domain { - &self.entry_states[block] - } - - pub fn visit_with<'mir>( - &mut self, - body: &'mir Body<'tcx>, - blocks: impl IntoIterator, - vis: &mut impl ResultsVisitor<'tcx, A>, - ) { - visit_results(body, blocks, self, vis) - } - - pub fn visit_reachable_with<'mir>( - &mut self, - body: &'mir Body<'tcx>, - vis: &mut impl ResultsVisitor<'tcx, A>, - ) { - let blocks = traversal::reachable(body); - visit_results(body, blocks.map(|(bb, _)| bb), self, vis) + ResultsCursor::new_owning(body, self.analysis, self.results) } } diff --git a/compiler/rustc_mir_dataflow/src/framework/tests.rs b/compiler/rustc_mir_dataflow/src/framework/tests.rs index ae0f1179e6fa..8602bb557652 100644 --- a/compiler/rustc_mir_dataflow/src/framework/tests.rs +++ b/compiler/rustc_mir_dataflow/src/framework/tests.rs @@ -79,7 +79,7 @@ fn mock_body<'tcx>() -> mir::Body<'tcx> { /// /// The `102` in the block's entry set is derived from the basic block index and ensures that the /// expected state is unique across all basic blocks. Remember, it is generated by -/// `mock_entry_states`, not from actually running `MockAnalysis` to fixpoint. +/// `mock_results`, not from actually running `MockAnalysis` to fixpoint. struct MockAnalysis<'tcx, D> { body: &'tcx mir::Body<'tcx>, dir: PhantomData, @@ -96,7 +96,7 @@ impl MockAnalysis<'_, D> { ret } - fn mock_entry_states(&self) -> IndexVec> { + fn mock_results(&self) -> IndexVec> { let empty = self.bottom_value(self.body); let mut ret = IndexVec::from_elem(empty, &self.body.basic_blocks); @@ -255,7 +255,7 @@ fn test_cursor(analysis: MockAnalysis<'_, D>) { let body = analysis.body; let mut cursor = - Results { entry_states: analysis.mock_entry_states(), analysis }.into_results_cursor(body); + AnalysisAndResults { results: analysis.mock_results(), analysis }.into_results_cursor(body); cursor.allow_unreachable(); diff --git a/compiler/rustc_mir_dataflow/src/framework/visitor.rs b/compiler/rustc_mir_dataflow/src/framework/visitor.rs index c9fdf46c4f5b..fbb9e4108726 100644 --- a/compiler/rustc_mir_dataflow/src/framework/visitor.rs +++ b/compiler/rustc_mir_dataflow/src/framework/visitor.rs @@ -1,4 +1,4 @@ -use rustc_middle::mir::{self, BasicBlock, Location}; +use rustc_middle::mir::{self, BasicBlock, Location, traversal}; use super::{Analysis, Direction, Results}; @@ -7,12 +7,13 @@ use super::{Analysis, Direction, Results}; pub fn visit_results<'mir, 'tcx, A>( body: &'mir mir::Body<'tcx>, blocks: impl IntoIterator, - results: &mut Results<'tcx, A>, + analysis: &mut A, + results: &Results, vis: &mut impl ResultsVisitor<'tcx, A>, ) where A: Analysis<'tcx>, { - let mut state = results.analysis.bottom_value(body); + let mut state = analysis.bottom_value(body); #[cfg(debug_assertions)] let reachable_blocks = mir::traversal::reachable_as_bitset(body); @@ -22,10 +23,24 @@ pub fn visit_results<'mir, 'tcx, A>( assert!(reachable_blocks.contains(block)); let block_data = &body[block]; - A::Direction::visit_results_in_block(&mut state, block, block_data, results, vis); + state.clone_from(&results[block]); + A::Direction::visit_results_in_block(&mut state, block, block_data, analysis, vis); } } +/// Like `visit_results`, but only for reachable blocks. +pub fn visit_reachable_results<'mir, 'tcx, A>( + body: &'mir mir::Body<'tcx>, + analysis: &mut A, + results: &Results, + vis: &mut impl ResultsVisitor<'tcx, A>, +) where + A: Analysis<'tcx>, +{ + let blocks = traversal::reachable(body).map(|(bb, _)| bb); + visit_results(body, blocks, analysis, results, vis) +} + /// A visitor over the results of an `Analysis`. Use this when you want to inspect domain values in /// many or all locations; use `ResultsCursor` if you want to inspect domain values only in certain /// locations. @@ -38,7 +53,7 @@ where /// Called after the "early" effect of the given statement is applied to `state`. fn visit_after_early_statement_effect( &mut self, - _results: &mut Results<'tcx, A>, + _analysis: &mut A, _state: &A::Domain, _statement: &mir::Statement<'tcx>, _location: Location, @@ -48,7 +63,7 @@ where /// Called after the "primary" effect of the given statement is applied to `state`. fn visit_after_primary_statement_effect( &mut self, - _results: &mut Results<'tcx, A>, + _analysis: &mut A, _state: &A::Domain, _statement: &mir::Statement<'tcx>, _location: Location, @@ -58,7 +73,7 @@ where /// Called after the "early" effect of the given terminator is applied to `state`. fn visit_after_early_terminator_effect( &mut self, - _results: &mut Results<'tcx, A>, + _analysis: &mut A, _state: &A::Domain, _terminator: &mir::Terminator<'tcx>, _location: Location, @@ -70,7 +85,7 @@ where /// The `call_return_effect` (if one exists) will *not* be applied to `state`. fn visit_after_primary_terminator_effect( &mut self, - _results: &mut Results<'tcx, A>, + _analysis: &mut A, _state: &A::Domain, _terminator: &mir::Terminator<'tcx>, _location: Location, diff --git a/compiler/rustc_mir_dataflow/src/lib.rs b/compiler/rustc_mir_dataflow/src/lib.rs index 38f82b127465..658fbf505e44 100644 --- a/compiler/rustc_mir_dataflow/src/lib.rs +++ b/compiler/rustc_mir_dataflow/src/lib.rs @@ -18,8 +18,8 @@ pub use self::drop_flag_effects::{ move_path_children_matching, on_all_children_bits, on_lookup_result_bits, }; pub use self::framework::{ - Analysis, Backward, Direction, EntryStates, Forward, GenKill, JoinSemiLattice, MaybeReachable, - Results, ResultsCursor, ResultsVisitor, fmt, graphviz, lattice, visit_results, + Analysis, Backward, Direction, Forward, GenKill, JoinSemiLattice, MaybeReachable, Results, + ResultsCursor, ResultsVisitor, fmt, graphviz, lattice, visit_reachable_results, visit_results, }; use self::move_paths::MoveData; diff --git a/compiler/rustc_mir_dataflow/src/points.rs b/compiler/rustc_mir_dataflow/src/points.rs index 21590ff1bbad..70d1a34b5fb1 100644 --- a/compiler/rustc_mir_dataflow/src/points.rs +++ b/compiler/rustc_mir_dataflow/src/points.rs @@ -98,7 +98,8 @@ rustc_index::newtype_index! { pub fn save_as_intervals<'tcx, N, A>( elements: &DenseLocationMap, body: &mir::Body<'tcx>, - mut results: Results<'tcx, A>, + mut analysis: A, + results: Results, ) -> SparseIntervalMatrix where N: Idx, @@ -109,7 +110,8 @@ where visit_results( body, body.basic_blocks.reverse_postorder().iter().copied(), - &mut results, + &mut analysis, + &results, &mut visitor, ); visitor.values @@ -127,7 +129,7 @@ where { fn visit_after_primary_statement_effect<'mir>( &mut self, - _results: &mut Results<'tcx, A>, + _analysis: &mut A, state: &A::Domain, _statement: &'mir mir::Statement<'tcx>, location: Location, @@ -141,7 +143,7 @@ where fn visit_after_primary_terminator_effect<'mir>( &mut self, - _results: &mut Results<'tcx, A>, + _analysis: &mut A, state: &A::Domain, _terminator: &'mir mir::Terminator<'tcx>, location: Location, diff --git a/compiler/rustc_mir_dataflow/src/rustc_peek.rs b/compiler/rustc_mir_dataflow/src/rustc_peek.rs index 399141aa9212..303fc767b9a3 100644 --- a/compiler/rustc_mir_dataflow/src/rustc_peek.rs +++ b/compiler/rustc_mir_dataflow/src/rustc_peek.rs @@ -39,23 +39,23 @@ pub fn sanity_check<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { let move_data = MoveData::gather_moves(body, tcx, |_| true); if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_maybe_init).is_some() { - let flow_inits = - MaybeInitializedPlaces::new(tcx, body, &move_data).iterate_to_fixpoint(tcx, body, None); - - sanity_check_via_rustc_peek(tcx, flow_inits.into_results_cursor(body)); + let flow_inits = MaybeInitializedPlaces::new(tcx, body, &move_data) + .iterate_to_fixpoint(tcx, body, None) + .into_results_cursor(body); + sanity_check_via_rustc_peek(tcx, flow_inits); } if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_maybe_uninit).is_some() { let flow_uninits = MaybeUninitializedPlaces::new(tcx, body, &move_data) - .iterate_to_fixpoint(tcx, body, None); - - sanity_check_via_rustc_peek(tcx, flow_uninits.into_results_cursor(body)); + .iterate_to_fixpoint(tcx, body, None) + .into_results_cursor(body); + sanity_check_via_rustc_peek(tcx, flow_uninits); } if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_liveness).is_some() { - let flow_liveness = MaybeLiveLocals.iterate_to_fixpoint(tcx, body, None); - - sanity_check_via_rustc_peek(tcx, flow_liveness.into_results_cursor(body)); + let flow_liveness = + MaybeLiveLocals.iterate_to_fixpoint(tcx, body, None).into_results_cursor(body); + sanity_check_via_rustc_peek(tcx, flow_liveness); } if has_rustc_mir_with(tcx, def_id, sym::stop_after_dataflow).is_some() { diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index 263f0c40f5a5..cddb2f847785 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -79,7 +79,9 @@ use rustc_mir_dataflow::impls::{ MaybeBorrowedLocals, MaybeLiveLocals, MaybeRequiresStorage, MaybeStorageLive, always_storage_live_locals, }; -use rustc_mir_dataflow::{Analysis, Results, ResultsVisitor}; +use rustc_mir_dataflow::{ + Analysis, Results, ResultsCursor, ResultsVisitor, visit_reachable_results, +}; use rustc_span::def_id::{DefId, LocalDefId}; use rustc_span::source_map::dummy_spanned; use rustc_span::symbol::sym; @@ -680,18 +682,29 @@ fn locals_live_across_suspend_points<'tcx>( .iterate_to_fixpoint(tcx, body, None) .into_results_cursor(body); - // Calculate the MIR locals which have been previously - // borrowed (even if they are still active). - let borrowed_locals_results = - MaybeBorrowedLocals.iterate_to_fixpoint(tcx, body, Some("coroutine")); - - let mut borrowed_locals_cursor = borrowed_locals_results.clone().into_results_cursor(body); + // Calculate the MIR locals that have been previously borrowed (even if they are still active). + let borrowed_locals = MaybeBorrowedLocals.iterate_to_fixpoint(tcx, body, Some("coroutine")); + let mut borrowed_locals_analysis1 = borrowed_locals.analysis; + let mut borrowed_locals_analysis2 = borrowed_locals_analysis1.clone(); // trivial + let borrowed_locals_cursor1 = ResultsCursor::new_borrowing( + body, + &mut borrowed_locals_analysis1, + &borrowed_locals.results, + ); + let mut borrowed_locals_cursor2 = ResultsCursor::new_borrowing( + body, + &mut borrowed_locals_analysis2, + &borrowed_locals.results, + ); // Calculate the MIR locals that we need to keep storage around for. - let mut requires_storage_results = - MaybeRequiresStorage::new(borrowed_locals_results.into_results_cursor(body)) - .iterate_to_fixpoint(tcx, body, None); - let mut requires_storage_cursor = requires_storage_results.as_results_cursor(body); + let mut requires_storage = + MaybeRequiresStorage::new(borrowed_locals_cursor1).iterate_to_fixpoint(tcx, body, None); + let mut requires_storage_cursor = ResultsCursor::new_borrowing( + body, + &mut requires_storage.analysis, + &requires_storage.results, + ); // Calculate the liveness of MIR locals ignoring borrows. let mut liveness = @@ -720,8 +733,8 @@ fn locals_live_across_suspend_points<'tcx>( // If a borrow is converted to a raw reference, we must also assume that it lives // forever. Note that the final liveness is still bounded by the storage liveness // of the local, which happens using the `intersect` operation below. - borrowed_locals_cursor.seek_before_primary_effect(loc); - live_locals.union(borrowed_locals_cursor.get()); + borrowed_locals_cursor2.seek_before_primary_effect(loc); + live_locals.union(borrowed_locals_cursor2.get()); } // Store the storage liveness for later use so we can restore the state @@ -763,7 +776,8 @@ fn locals_live_across_suspend_points<'tcx>( body, &saved_locals, always_live_locals.clone(), - requires_storage_results, + &mut requires_storage.analysis, + &requires_storage.results, ); LivenessInfo { @@ -828,7 +842,8 @@ fn compute_storage_conflicts<'mir, 'tcx>( body: &'mir Body<'tcx>, saved_locals: &'mir CoroutineSavedLocals, always_live_locals: DenseBitSet, - mut requires_storage: Results<'tcx, MaybeRequiresStorage<'mir, 'tcx>>, + analysis: &mut MaybeRequiresStorage<'mir, 'tcx>, + results: &Results>, ) -> BitMatrix { assert_eq!(body.local_decls.len(), saved_locals.domain_size()); @@ -848,7 +863,7 @@ fn compute_storage_conflicts<'mir, 'tcx>( eligible_storage_live: DenseBitSet::new_empty(body.local_decls.len()), }; - requires_storage.visit_reachable_with(body, &mut visitor); + visit_reachable_results(body, analysis, results, &mut visitor); let local_conflicts = visitor.local_conflicts; @@ -891,7 +906,7 @@ impl<'a, 'tcx> ResultsVisitor<'tcx, MaybeRequiresStorage<'a, 'tcx>> { fn visit_after_early_statement_effect( &mut self, - _results: &mut Results<'tcx, MaybeRequiresStorage<'a, 'tcx>>, + _analysis: &mut MaybeRequiresStorage<'a, 'tcx>, state: &DenseBitSet, _statement: &Statement<'tcx>, loc: Location, @@ -901,7 +916,7 @@ impl<'a, 'tcx> ResultsVisitor<'tcx, MaybeRequiresStorage<'a, 'tcx>> fn visit_after_early_terminator_effect( &mut self, - _results: &mut Results<'tcx, MaybeRequiresStorage<'a, 'tcx>>, + _analysis: &mut MaybeRequiresStorage<'a, 'tcx>, state: &DenseBitSet, _terminator: &Terminator<'tcx>, loc: Location, @@ -1064,10 +1079,8 @@ fn insert_switch<'tcx>( }, ); - let blocks = body.basic_blocks_mut().iter_mut(); - - for target in blocks.flat_map(|b| b.terminator_mut().successors_mut()) { - *target += 1; + for b in body.basic_blocks_mut().iter_mut() { + b.terminator_mut().successors_mut(|target| *target += 1); } } diff --git a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs index dd0e07f2218e..0a839d91404e 100644 --- a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs +++ b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs @@ -73,6 +73,7 @@ use rustc_data_structures::unord::UnordMap; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::definitions::DisambiguatorState; use rustc_middle::bug; use rustc_middle::hir::place::{Projection, ProjectionKind}; use rustc_middle::mir::visit::MutVisitor; @@ -213,8 +214,15 @@ pub(crate) fn coroutine_by_move_body_def_id<'tcx>( let mut by_move_body = body.clone(); MakeByMoveBody { tcx, field_remapping, by_move_coroutine_ty }.visit_body(&mut by_move_body); - // This will always be `{closure#1}`, since the original coroutine is `{closure#0}`. - let body_def = tcx.create_def(parent_def_id, None, DefKind::SyntheticCoroutineBody); + // This path is unique since we're in a query so we'll only be called once with `parent_def_id` + // and this is the only location creating `SyntheticCoroutineBody`. + let body_def = tcx.create_def( + parent_def_id, + None, + DefKind::SyntheticCoroutineBody, + None, + &mut DisambiguatorState::new(), + ); by_move_body.source = mir::MirSource::from_instance(InstanceKind::Item(body_def.def_id().to_def_id())); dump_mir(tcx, false, "built", &"after", &by_move_body, |_, _| Ok(())); diff --git a/compiler/rustc_mir_transform/src/coverage/mappings.rs b/compiler/rustc_mir_transform/src/coverage/mappings.rs index 73bd2d0705e1..b4b4d0416fb9 100644 --- a/compiler/rustc_mir_transform/src/coverage/mappings.rs +++ b/compiler/rustc_mir_transform/src/coverage/mappings.rs @@ -91,7 +91,7 @@ pub(super) fn extract_all_mapping_info_from_mir<'tcx>( // When debugging flag `-Zcoverage-options=no-mir-spans` is set, we need // to give the same treatment to _all_ functions, because `llvm-cov` // seems to ignore functions that don't have any ordinary code spans. - if let Some(span) = hir_info.fn_sig_span_extended { + if let Some(span) = hir_info.fn_sig_span { code_mappings.push(CodeMapping { span, bcb: START_BCB }); } } else { diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index f2e8f9e1bcd6..702c62eddc7f 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -268,9 +268,9 @@ fn inject_statement(mir_body: &mut mir::Body<'_>, counter_kind: CoverageKind, bb struct ExtractedHirInfo { function_source_hash: u64, is_async_fn: bool, - /// The span of the function's signature, extended to the start of `body_span`. + /// The span of the function's signature, if available. /// Must have the same context and filename as the body span. - fn_sig_span_extended: Option, + fn_sig_span: Option, body_span: Span, /// "Holes" are regions within the function body (or its expansions) that /// should not be included in coverage spans for this function @@ -308,30 +308,20 @@ fn extract_hir_info<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> ExtractedHir // The actual signature span is only used if it has the same context and // filename as the body, and precedes the body. - let fn_sig_span_extended = maybe_fn_sig - .map(|fn_sig| fn_sig.span) - .filter(|&fn_sig_span| { - let source_map = tcx.sess.source_map(); - let file_idx = |span: Span| source_map.lookup_source_file_idx(span.lo()); + let fn_sig_span = maybe_fn_sig.map(|fn_sig| fn_sig.span).filter(|&fn_sig_span| { + let source_map = tcx.sess.source_map(); + let file_idx = |span: Span| source_map.lookup_source_file_idx(span.lo()); - fn_sig_span.eq_ctxt(body_span) - && fn_sig_span.hi() <= body_span.lo() - && file_idx(fn_sig_span) == file_idx(body_span) - }) - // If so, extend it to the start of the body span. - .map(|fn_sig_span| fn_sig_span.with_hi(body_span.lo())); + fn_sig_span.eq_ctxt(body_span) + && fn_sig_span.hi() <= body_span.lo() + && file_idx(fn_sig_span) == file_idx(body_span) + }); let function_source_hash = hash_mir_source(tcx, hir_body); let hole_spans = extract_hole_spans_from_hir(tcx, hir_body); - ExtractedHirInfo { - function_source_hash, - is_async_fn, - fn_sig_span_extended, - body_span, - hole_spans, - } + ExtractedHirInfo { function_source_hash, is_async_fn, fn_sig_span, body_span, hole_spans } } fn hash_mir_source<'tcx>(tcx: TyCtxt<'tcx>, hir_body: &'tcx hir::Body<'tcx>) -> u64 { diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs index f57a158e3e4a..ec76076020eb 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans.rs @@ -1,11 +1,8 @@ -use std::collections::VecDeque; -use std::iter; - use rustc_data_structures::fx::FxHashSet; use rustc_middle::mir; use rustc_middle::ty::TyCtxt; use rustc_span::{DesugaringKind, ExpnKind, MacroKind, Span}; -use tracing::{debug, debug_span, instrument}; +use tracing::instrument; use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph}; use crate::coverage::spans::from_mir::{Hole, RawSpanFromMir, SpanFromMir}; @@ -42,12 +39,12 @@ pub(super) fn extract_refined_covspans<'tcx>( return; } - // Also add the adjusted function signature span, if available. + // Also add the function signature span, if available. // Otherwise, add a fake span at the start of the body, to avoid an ugly // gap between the start of the body and the first real span. // FIXME: Find a more principled way to solve this problem. covspans.push(SpanFromMir::for_fn_sig( - hir_info.fn_sig_span_extended.unwrap_or_else(|| body_span.shrink_to_lo()), + hir_info.fn_sig_span.unwrap_or_else(|| body_span.shrink_to_lo()), )); // First, perform the passes that need macro information. @@ -83,24 +80,17 @@ pub(super) fn extract_refined_covspans<'tcx>( holes.sort_by(|a, b| compare_spans(a.span, b.span)); holes.dedup_by(|b, a| a.merge_if_overlapping_or_adjacent(b)); - // Split the covspans into separate buckets that don't overlap any holes. - let buckets = divide_spans_into_buckets(covspans, &holes); + // Discard any span that overlaps with a hole. + discard_spans_overlapping_holes(&mut covspans, &holes); - for covspans in buckets { - let _span = debug_span!("processing bucket", ?covspans).entered(); + // Perform more refinement steps after holes have been dealt with. + let mut covspans = remove_unwanted_overlapping_spans(covspans); + covspans.dedup_by(|b, a| a.merge_if_eligible(b)); - let mut covspans = remove_unwanted_overlapping_spans(covspans); - debug!(?covspans, "after removing overlaps"); - - // Do one last merge pass, to simplify the output. - covspans.dedup_by(|b, a| a.merge_if_eligible(b)); - debug!(?covspans, "after merge"); - - code_mappings.extend(covspans.into_iter().map(|Covspan { span, bcb }| { - // Each span produced by the refiner represents an ordinary code region. - mappings::CodeMapping { span, bcb } - })); - } + code_mappings.extend(covspans.into_iter().map(|Covspan { span, bcb }| { + // Each span produced by the refiner represents an ordinary code region. + mappings::CodeMapping { span, bcb } + })); } /// Macros that expand into branches (e.g. `assert!`, `trace!`) tend to generate @@ -142,52 +132,36 @@ fn shrink_visible_macro_spans(tcx: TyCtxt<'_>, covspans: &mut Vec) } } -/// Uses the holes to divide the given covspans into buckets, such that: -/// - No span in any hole overlaps a bucket (discarding spans if necessary). -/// - The spans in each bucket are strictly after all spans in previous buckets, -/// and strictly before all spans in subsequent buckets. +/// Discard all covspans that overlap a hole. /// -/// The lists of covspans and holes must be sorted. -/// The resulting buckets are sorted relative to each other, and each bucket's -/// contents are sorted. -#[instrument(level = "debug")] -fn divide_spans_into_buckets(input_covspans: Vec, holes: &[Hole]) -> Vec> { - debug_assert!(input_covspans.is_sorted_by(|a, b| compare_spans(a.span, b.span).is_le())); +/// The lists of covspans and holes must be sorted, and any holes that overlap +/// with each other must have already been merged. +fn discard_spans_overlapping_holes(covspans: &mut Vec, holes: &[Hole]) { + debug_assert!(covspans.is_sorted_by(|a, b| compare_spans(a.span, b.span).is_le())); debug_assert!(holes.is_sorted_by(|a, b| compare_spans(a.span, b.span).is_le())); + debug_assert!(holes.array_windows().all(|[a, b]| !a.span.overlaps_or_adjacent(b.span))); - // Now we're ready to start grouping spans into buckets separated by holes. + let mut curr_hole = 0usize; + let mut overlaps_hole = |covspan: &Covspan| -> bool { + while let Some(hole) = holes.get(curr_hole) { + // Both lists are sorted, so we can permanently skip any holes that + // end before the start of the current span. + if hole.span.hi() <= covspan.span.lo() { + curr_hole += 1; + continue; + } - let mut input_covspans = VecDeque::from(input_covspans); + return hole.span.overlaps(covspan.span); + } - // For each hole: - // - Identify the spans that are entirely or partly before the hole. - // - Discard any that overlap with the hole. - // - Add the remaining identified spans to the corresponding bucket. - let mut buckets = (0..holes.len()).map(|_| vec![]).collect::>(); - for (hole, bucket) in holes.iter().zip(&mut buckets) { - bucket.extend( - drain_front_while(&mut input_covspans, |c| c.span.lo() < hole.span.hi()) - .filter(|c| !c.span.overlaps(hole.span)), - ); - } + // No holes left, so this covspan doesn't overlap with any holes. + false + }; - // Any remaining spans form their own final bucket, after the final hole. - // (If there were no holes, this will just be all of the initial spans.) - buckets.push(Vec::from(input_covspans)); - - buckets + covspans.retain(|covspan| !overlaps_hole(covspan)); } -/// Similar to `.drain(..)`, but stops just before it would remove an item not -/// satisfying the predicate. -fn drain_front_while<'a, T>( - queue: &'a mut VecDeque, - mut pred_fn: impl FnMut(&T) -> bool, -) -> impl Iterator { - iter::from_fn(move || queue.pop_front_if(|x| pred_fn(x))) -} - -/// Takes one of the buckets of (sorted) spans extracted from MIR, and "refines" +/// Takes a list of sorted spans extracted from MIR, and "refines" /// those spans by removing spans that overlap in unwanted ways. #[instrument(level = "debug")] fn remove_unwanted_overlapping_spans(sorted_spans: Vec) -> Vec { @@ -227,19 +201,21 @@ struct Covspan { } impl Covspan { - /// If `self` and `other` can be merged (i.e. they have the same BCB), - /// mutates `self.span` to also include `other.span` and returns true. + /// If `self` and `other` can be merged, mutates `self.span` to also + /// include `other.span` and returns true. /// - /// Note that compatible covspans can be merged even if their underlying - /// spans are not overlapping/adjacent; any space between them will also be - /// part of the merged covspan. + /// Two covspans can be merged if they have the same BCB, and they are + /// overlapping or adjacent. fn merge_if_eligible(&mut self, other: &Self) -> bool { - if self.bcb != other.bcb { - return false; - } + let eligible_for_merge = + |a: &Self, b: &Self| (a.bcb == b.bcb) && a.span.overlaps_or_adjacent(b.span); - self.span = self.span.to(other.span); - true + if eligible_for_merge(self, other) { + self.span = self.span.to(other.span); + true + } else { + false + } } } diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index a2103a004d2d..99b95e7312bd 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -23,7 +23,7 @@ use rustc_mir_dataflow::lattice::{FlatSet, HasBottom}; use rustc_mir_dataflow::value_analysis::{ Map, PlaceIndex, State, TrackElem, ValueOrPlace, debug_with_context, }; -use rustc_mir_dataflow::{Analysis, Results, ResultsVisitor}; +use rustc_mir_dataflow::{Analysis, ResultsVisitor, visit_reachable_results}; use rustc_span::DUMMY_SP; use tracing::{debug, debug_span, instrument}; @@ -61,13 +61,14 @@ impl<'tcx> crate::MirPass<'tcx> for DataflowConstProp { let map = Map::new(tcx, body, place_limit); // Perform the actual dataflow analysis. - let analysis = ConstAnalysis::new(tcx, body, map); - let mut results = - debug_span!("analyze").in_scope(|| analysis.iterate_to_fixpoint(tcx, body, None)); + let mut const_ = debug_span!("analyze") + .in_scope(|| ConstAnalysis::new(tcx, body, map).iterate_to_fixpoint(tcx, body, None)); // Collect results and patch the body afterwards. let mut visitor = Collector::new(tcx, &body.local_decls); - debug_span!("collect").in_scope(|| results.visit_reachable_with(body, &mut visitor)); + debug_span!("collect").in_scope(|| { + visit_reachable_results(body, &mut const_.analysis, &const_.results, &mut visitor) + }); let mut patch = visitor.patch; debug_span!("patch").in_scope(|| patch.visit_body_preserves_cfg(body)); } @@ -959,10 +960,10 @@ fn try_write_constant<'tcx>( } impl<'tcx> ResultsVisitor<'tcx, ConstAnalysis<'_, 'tcx>> for Collector<'_, 'tcx> { - #[instrument(level = "trace", skip(self, results, statement))] + #[instrument(level = "trace", skip(self, analysis, statement))] fn visit_after_early_statement_effect( &mut self, - results: &mut Results<'tcx, ConstAnalysis<'_, 'tcx>>, + analysis: &mut ConstAnalysis<'_, 'tcx>, state: &State>, statement: &Statement<'tcx>, location: Location, @@ -972,8 +973,8 @@ impl<'tcx> ResultsVisitor<'tcx, ConstAnalysis<'_, 'tcx>> for Collector<'_, 'tcx> OperandCollector { state, visitor: self, - ecx: &mut results.analysis.ecx, - map: &results.analysis.map, + ecx: &mut analysis.ecx, + map: &analysis.map, } .visit_rvalue(rvalue, location); } @@ -981,10 +982,10 @@ impl<'tcx> ResultsVisitor<'tcx, ConstAnalysis<'_, 'tcx>> for Collector<'_, 'tcx> } } - #[instrument(level = "trace", skip(self, results, statement))] + #[instrument(level = "trace", skip(self, analysis, statement))] fn visit_after_primary_statement_effect( &mut self, - results: &mut Results<'tcx, ConstAnalysis<'_, 'tcx>>, + analysis: &mut ConstAnalysis<'_, 'tcx>, state: &State>, statement: &Statement<'tcx>, location: Location, @@ -994,12 +995,9 @@ impl<'tcx> ResultsVisitor<'tcx, ConstAnalysis<'_, 'tcx>> for Collector<'_, 'tcx> // Don't overwrite the assignment if it already uses a constant (to keep the span). } StatementKind::Assign(box (place, _)) => { - if let Some(value) = self.try_make_constant( - &mut results.analysis.ecx, - place, - state, - &results.analysis.map, - ) { + if let Some(value) = + self.try_make_constant(&mut analysis.ecx, place, state, &analysis.map) + { self.patch.assignments.insert(location, value); } } @@ -1009,18 +1007,13 @@ impl<'tcx> ResultsVisitor<'tcx, ConstAnalysis<'_, 'tcx>> for Collector<'_, 'tcx> fn visit_after_early_terminator_effect( &mut self, - results: &mut Results<'tcx, ConstAnalysis<'_, 'tcx>>, + analysis: &mut ConstAnalysis<'_, 'tcx>, state: &State>, terminator: &Terminator<'tcx>, location: Location, ) { - OperandCollector { - state, - visitor: self, - ecx: &mut results.analysis.ecx, - map: &results.analysis.map, - } - .visit_terminator(terminator, location); + OperandCollector { state, visitor: self, ecx: &mut analysis.ecx, map: &analysis.map } + .visit_terminator(terminator, location); } } diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs index 7395ad496dbd..4c94a6c524e0 100644 --- a/compiler/rustc_mir_transform/src/dest_prop.rs +++ b/compiler/rustc_mir_transform/src/dest_prop.rs @@ -171,7 +171,7 @@ impl<'tcx> crate::MirPass<'tcx> for DestinationPropagation { let live = MaybeLiveLocals.iterate_to_fixpoint(tcx, body, Some("MaybeLiveLocals-DestProp")); let points = DenseLocationMap::new(body); - let mut live = save_as_intervals(&points, body, live); + let mut live = save_as_intervals(&points, body, live.analysis, live.results); // In order to avoid having to collect data for every single pair of locals in the body, we // do not allow doing more than one merge for places that are derived from the same local at diff --git a/compiler/rustc_mir_transform/src/jump_threading.rs b/compiler/rustc_mir_transform/src/jump_threading.rs index ada2c0b76cf7..31b361ec1a92 100644 --- a/compiler/rustc_mir_transform/src/jump_threading.rs +++ b/compiler/rustc_mir_transform/src/jump_threading.rs @@ -757,12 +757,12 @@ impl OpportunitySet { // Replace `succ` by `new_succ` where it appears. let mut num_edges = 0; - for s in basic_blocks[current].terminator_mut().successors_mut() { + basic_blocks[current].terminator_mut().successors_mut(|s| { if *s == succ { *s = new_succ; num_edges += 1; } - } + }); // Update predecessors with the new block. let _new_succ = self.predecessors.push(num_edges); diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 24f4c11a66d6..dc0eacd36130 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -701,8 +701,6 @@ pub(crate) fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<' // Now, we need to shrink the generated MIR. &ref_prop::ReferencePropagation, &sroa::ScalarReplacementOfAggregates, - &match_branches::MatchBranchSimplification, - // inst combine is after MatchBranchSimplification to clean up Ne(_1, false) &multiple_return_terminators::MultipleReturnTerminators, // After simplifycfg, it allows us to discover new opportunities for peephole // optimizations. @@ -711,6 +709,7 @@ pub(crate) fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<' &dead_store_elimination::DeadStoreElimination::Initial, &gvn::GVN, &simplify::SimplifyLocals::AfterGVN, + &match_branches::MatchBranchSimplification, &dataflow_const_prop::DataflowConstProp, &single_use_consts::SingleUseConsts, &o1(simplify_branches::SimplifyConstCondition::AfterConstProp), diff --git a/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs b/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs index b8cb101f93c7..75f351f05c30 100644 --- a/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs +++ b/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs @@ -235,8 +235,9 @@ pub(crate) fn run_lint<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &Body< // When we encounter a DROP of some place P we only care // about the drop if `P` may be initialized. let move_data = MoveData::gather_moves(body, tcx, |_| true); - let maybe_init = MaybeInitializedPlaces::new(tcx, body, &move_data); - let mut maybe_init = maybe_init.iterate_to_fixpoint(tcx, body, None).into_results_cursor(body); + let mut maybe_init = MaybeInitializedPlaces::new(tcx, body, &move_data) + .iterate_to_fixpoint(tcx, body, None) + .into_results_cursor(body); let mut block_drop_value_info = IndexVec::from_elem_n(MovePathIndexAtBlock::Unknown, body.basic_blocks.len()); for (&block, candidates) in &bid_per_block { diff --git a/compiler/rustc_mir_transform/src/match_branches.rs b/compiler/rustc_mir_transform/src/match_branches.rs index b37241185c93..8c0c30968990 100644 --- a/compiler/rustc_mir_transform/src/match_branches.rs +++ b/compiler/rustc_mir_transform/src/match_branches.rs @@ -19,30 +19,32 @@ impl<'tcx> crate::MirPass<'tcx> for MatchBranchSimplification { fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { let typing_env = body.typing_env(tcx); - let mut should_cleanup = false; - for bb_idx in body.basic_blocks.indices() { - match &body.basic_blocks[bb_idx].terminator().kind { + let mut apply_patch = false; + let mut patch = MirPatch::new(body); + for (bb, bb_data) in body.basic_blocks.iter_enumerated() { + match &bb_data.terminator().kind { TerminatorKind::SwitchInt { discr: Operand::Copy(_) | Operand::Move(_), targets, .. // We require that the possible target blocks don't contain this block. - } if !targets.all_targets().contains(&bb_idx) => {} + } if !targets.all_targets().contains(&bb) => {} // Only optimize switch int statements _ => continue, }; - if SimplifyToIf.simplify(tcx, body, bb_idx, typing_env).is_some() { - should_cleanup = true; + if SimplifyToIf.simplify(tcx, body, &mut patch, bb, typing_env).is_some() { + apply_patch = true; continue; } - if SimplifyToExp::default().simplify(tcx, body, bb_idx, typing_env).is_some() { - should_cleanup = true; + if SimplifyToExp::default().simplify(tcx, body, &mut patch, bb, typing_env).is_some() { + apply_patch = true; continue; } } - if should_cleanup { + if apply_patch { + patch.apply(body); simplify_cfg(tcx, body); } } @@ -59,7 +61,8 @@ trait SimplifyMatch<'tcx> { fn simplify( &mut self, tcx: TyCtxt<'tcx>, - body: &mut Body<'tcx>, + body: &Body<'tcx>, + patch: &mut MirPatch<'tcx>, switch_bb_idx: BasicBlock, typing_env: ty::TypingEnv<'tcx>, ) -> Option<()> { @@ -73,8 +76,6 @@ trait SimplifyMatch<'tcx> { let discr_ty = discr.ty(body.local_decls(), tcx); self.can_simplify(tcx, targets, typing_env, bbs, discr_ty)?; - let mut patch = MirPatch::new(body); - // Take ownership of items now that we know we can optimize. let discr = discr.clone(); @@ -87,19 +88,9 @@ trait SimplifyMatch<'tcx> { let parent_end = Location { block: switch_bb_idx, statement_index }; patch.add_statement(parent_end, StatementKind::StorageLive(discr_local)); patch.add_assign(parent_end, Place::from(discr_local), Rvalue::Use(discr)); - self.new_stmts( - tcx, - targets, - typing_env, - &mut patch, - parent_end, - bbs, - discr_local, - discr_ty, - ); + self.new_stmts(tcx, targets, typing_env, patch, parent_end, bbs, discr_local, discr_ty); patch.add_statement(parent_end, StatementKind::StorageDead(discr_local)); patch.patch_terminator(switch_bb_idx, bbs[first].terminator().kind.clone()); - patch.apply(body); Some(()) } diff --git a/compiler/rustc_mir_transform/src/prettify.rs b/compiler/rustc_mir_transform/src/prettify.rs index 8ccfbe2f194b..8217feff24ec 100644 --- a/compiler/rustc_mir_transform/src/prettify.rs +++ b/compiler/rustc_mir_transform/src/prettify.rs @@ -115,9 +115,7 @@ impl<'tcx> MutVisitor<'tcx> for BasicBlockUpdater<'tcx> { } fn visit_terminator(&mut self, terminator: &mut Terminator<'tcx>, _location: Location) { - for succ in terminator.successors_mut() { - *succ = self.map[*succ]; - } + terminator.successors_mut(|succ| *succ = self.map[*succ]); } } diff --git a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs index 1dd34005d664..797056ad52d4 100644 --- a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs +++ b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs @@ -58,13 +58,13 @@ impl<'tcx> crate::MirPass<'tcx> for RemoveNoopLandingPads { } } - for target in body[bb].terminator_mut().successors_mut() { + body[bb].terminator_mut().successors_mut(|target| { if *target != resume_block && nop_landing_pads.contains(*target) { debug!(" folding noop jump to {:?} to resume block", target); *target = resume_block; jumps_folded += 1; } - } + }); let is_nop_landing_pad = self.is_nop_landing_pad(bb, body, &nop_landing_pads); if is_nop_landing_pad { diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index 0d9a04b760a2..9688ac8ed2e2 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -298,10 +298,9 @@ fn local_decls_for_sig<'tcx>( fn dropee_emit_retag<'tcx>( tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, - dropee_ptr: Place<'tcx>, + mut dropee_ptr: Place<'tcx>, span: Span, ) -> Place<'tcx> { - let mut dropee_ptr = dropee_ptr; if tcx.sess.opts.unstable_opts.mir_emit_retag { let source_info = SourceInfo::outermost(span); // We want to treat the function argument as if it was passed by `&mut`. As such, we @@ -365,8 +364,8 @@ fn build_drop_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option>) new_body(source, blocks, local_decls_for_sig(&sig, span), sig.inputs().len(), span); // The first argument (index 0), but add 1 for the return value. - let mut dropee_ptr = Place::from(Local::new(1 + 0)); - dropee_ptr = dropee_emit_retag(tcx, &mut body, dropee_ptr, span); + let dropee_ptr = Place::from(Local::new(1 + 0)); + let dropee_ptr = dropee_emit_retag(tcx, &mut body, dropee_ptr, span); if ty.is_some() { let patch = { diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs index 4f2cce8ac104..8f88228d9bbd 100644 --- a/compiler/rustc_mir_transform/src/simplify.rs +++ b/compiler/rustc_mir_transform/src/simplify.rs @@ -147,9 +147,8 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> { let mut terminator = self.basic_blocks[bb].terminator.take().expect("invalid terminator state"); - for successor in terminator.successors_mut() { - self.collapse_goto_chain(successor, &mut changed); - } + terminator + .successors_mut(|successor| self.collapse_goto_chain(successor, &mut changed)); let mut inner_changed = true; merged_blocks.clear(); @@ -375,9 +374,7 @@ pub(super) fn remove_dead_blocks(body: &mut Body<'_>) { } for block in basic_blocks { - for target in block.terminator_mut().successors_mut() { - *target = replacements[target.index()]; - } + block.terminator_mut().successors_mut(|target| *target = replacements[target.index()]); } } diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 76dad6b35714..c6a81e60b2b5 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -205,6 +205,7 @@ //! this is not implemented however: a mono item will be produced //! regardless of whether it is actually needed or not. +use std::cell::OnceCell; use std::path::PathBuf; use rustc_attr_parsing::InlineAttr; @@ -348,6 +349,27 @@ impl<'tcx> Extend>> for MonoItems<'tcx> { } } +fn collect_items_root<'tcx>( + tcx: TyCtxt<'tcx>, + starting_item: Spanned>, + state: &SharedState<'tcx>, + recursion_limit: Limit, +) { + if !state.visited.lock_mut().insert(starting_item.node) { + // We've been here already, no need to search again. + return; + } + let mut recursion_depths = DefIdMap::default(); + collect_items_rec( + tcx, + starting_item, + state, + &mut recursion_depths, + recursion_limit, + CollectionMode::UsedItems, + ); +} + /// Collect all monomorphized items reachable from `starting_point`, and emit a note diagnostic if a /// post-monomorphization error is encountered during a collection step. /// @@ -362,24 +384,6 @@ fn collect_items_rec<'tcx>( recursion_limit: Limit, mode: CollectionMode, ) { - if mode == CollectionMode::UsedItems { - if !state.visited.lock_mut().insert(starting_item.node) { - // We've been here already, no need to search again. - return; - } - } else { - if state.visited.lock().contains(&starting_item.node) { - // We've already done a *full* visit on this one, no need to do the "mention" visit. - return; - } - if !state.mentioned.lock_mut().insert(starting_item.node) { - // We've been here already, no need to search again. - return; - } - // There's some risk that we first do a 'mention' visit and then a full visit. But there's no - // harm in that, the mention visit will trigger all the queries and the results are cached. - } - let mut used_items = MonoItems::new(); let mut mentioned_items = MonoItems::new(); let recursion_depth_reset; @@ -536,6 +540,20 @@ fn collect_items_rec<'tcx>( state.usage_map.lock_mut().record_used(starting_item.node, &used_items); } + { + let mut visited = OnceCell::default(); + if mode == CollectionMode::UsedItems { + used_items + .items + .retain(|k, _| visited.get_mut_or_init(|| state.visited.lock_mut()).insert(*k)); + } + + let mut mentioned = OnceCell::default(); + mentioned_items.items.retain(|k, _| { + !visited.get_or_init(|| state.visited.lock()).contains(k) + && mentioned.get_mut_or_init(|| state.mentioned.lock_mut()).insert(*k) + }); + } if mode == CollectionMode::MentionedItems { assert!(used_items.is_empty(), "'mentioned' collection should never encounter used items"); } else { @@ -913,7 +931,7 @@ fn visit_instance_use<'tcx>( // We explicitly skip this otherwise to ensure we get a linker error // if anyone tries to call this intrinsic and the codegen backend did not // override the implementation. - let instance = ty::Instance::new(instance.def_id(), instance.args); + let instance = ty::Instance::new_raw(instance.def_id(), instance.args); if tcx.should_codegen_locally(instance) { output.push(create_fn_mono_item(tcx, instance, source)); } @@ -1502,7 +1520,7 @@ impl<'v> RootCollector<'_, 'v> { ty::Closure(def_id, args) | ty::Coroutine(def_id, args) | ty::CoroutineClosure(def_id, args) => { - Instance::new(def_id, self.tcx.erase_regions(args)) + Instance::new_raw(def_id, self.tcx.erase_regions(args)) } _ => unreachable!(), }; @@ -1689,15 +1707,7 @@ pub(crate) fn collect_crate_mono_items<'tcx>( tcx.sess.time("monomorphization_collector_graph_walk", || { par_for_each_in(roots, |root| { - let mut recursion_depths = DefIdMap::default(); - collect_items_rec( - tcx, - dummy_spanned(*root), - &state, - &mut recursion_depths, - recursion_limit, - CollectionMode::UsedItems, - ); + collect_items_root(tcx, dummy_spanned(*root), &state, recursion_limit); }); }); diff --git a/compiler/rustc_monomorphize/src/lib.rs b/compiler/rustc_monomorphize/src/lib.rs index 8469e0f17a69..1b484da698aa 100644 --- a/compiler/rustc_monomorphize/src/lib.rs +++ b/compiler/rustc_monomorphize/src/lib.rs @@ -4,6 +4,7 @@ #![feature(file_buffered)] #![feature(if_let_guard)] #![feature(impl_trait_in_assoc_type)] +#![feature(once_cell_get_mut)] // tidy-alphabetical-end use rustc_hir::lang_items::LangItem; diff --git a/compiler/rustc_next_trait_solver/src/delegate.rs b/compiler/rustc_next_trait_solver/src/delegate.rs index 25493970a0ce..9e8fbd66b708 100644 --- a/compiler/rustc_next_trait_solver/src/delegate.rs +++ b/compiler/rustc_next_trait_solver/src/delegate.rs @@ -39,7 +39,10 @@ pub trait SolverDelegate: Deref + Sized { term: ::Term, ) -> Option::Predicate>>>; - fn clone_opaque_types_for_query_response( + fn clone_opaque_types_lookup_table( + &self, + ) -> Vec<(ty::OpaqueTypeKey, ::Ty)>; + fn clone_duplicate_opaque_types( &self, ) -> Vec<(ty::OpaqueTypeKey, ::Ty)>; @@ -68,6 +71,12 @@ pub trait SolverDelegate: Deref + Sized { hidden_ty: ::Ty, span: ::Span, ) -> Option<::Ty>; + fn add_duplicate_opaque_type( + &self, + opaque_type_key: ty::OpaqueTypeKey, + hidden_ty: ::Ty, + span: ::Span, + ); fn add_item_bounds_for_hidden_type( &self, diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs index dded84f67686..65b10e4f23f0 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs @@ -56,7 +56,10 @@ where &self, goal: Goal, ) -> (Vec, CanonicalInput) { - let opaque_types = self.delegate.clone_opaque_types_for_query_response(); + // We only care about one entry per `OpaqueTypeKey` here, + // so we only canonicalize the lookup table and ignore + // duplicate entries. + let opaque_types = self.delegate.clone_opaque_types_lookup_table(); let (goal, opaque_types) = (goal, opaque_types).fold_with(&mut EagerResolver::new(self.delegate)); @@ -241,19 +244,21 @@ where Default::default() }; - ExternalConstraintsData { - region_constraints, - opaque_types: self - .delegate - .clone_opaque_types_for_query_response() - .into_iter() - // Only return *newly defined* opaque types. - .filter(|(a, _)| { - self.predefined_opaques_in_body.opaque_types.iter().all(|(pa, _)| pa != a) - }) - .collect(), - normalization_nested_goals, - } + // We only return *newly defined* opaque types from canonical queries. + // + // Constraints for any existing opaque types are already tracked by changes + // to the `var_values`. + let opaque_types = self + .delegate + .clone_opaque_types_lookup_table() + .into_iter() + .filter(|(a, _)| { + self.predefined_opaques_in_body.opaque_types.iter().all(|(pa, _)| pa != a) + }) + .chain(self.delegate.clone_duplicate_opaque_types()) + .collect(); + + ExternalConstraintsData { region_constraints, opaque_types, normalization_nested_goals } } /// After calling a canonical query, we apply the constraints returned @@ -432,7 +437,16 @@ where fn register_new_opaque_types(&mut self, opaque_types: &[(ty::OpaqueTypeKey, I::Ty)]) { for &(key, ty) in opaque_types { let prev = self.delegate.register_hidden_type_in_storage(key, ty, self.origin_span); - assert_eq!(prev, None); + // We eagerly resolve inference variables when computing the query response. + // This can cause previously distinct opaque type keys to now be structurally equal. + // + // To handle this, we store any duplicate entries in a separate list to check them + // at the end of typeck/borrowck. We could alternatively eagerly equate the hidden + // types here. However, doing so is difficult as it may result in nested goals and + // any errors may make it harder to track the control flow for diagnostics. + if let Some(prev) = prev { + self.delegate.add_duplicate_opaque_type(key, prev, self.origin_span); + } } } } diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index 6dd554299a69..c13e73080550 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -14,7 +14,7 @@ use rustc_type_ir::{ TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, }; -use tracing::{instrument, trace}; +use tracing::{debug, instrument, trace}; use super::has_only_region_constraints; use crate::coherence; @@ -361,7 +361,20 @@ where for &(key, ty) in &input.predefined_opaques_in_body.opaque_types { let prev = ecx.delegate.register_hidden_type_in_storage(key, ty, ecx.origin_span); - assert_eq!(prev, None); + // It may be possible that two entries in the opaque type storage end up + // with the same key after resolving contained inference variables. + // + // We could put them in the duplicate list but don't have to. The opaques we + // encounter here are already tracked in the caller, so there's no need to + // also store them here. We'd take them out when computing the query response + // and then discard them, as they're already present in the input. + // + // Ideally we'd drop duplicate opaque type definitions when computing + // the canonical input. This is more annoying to implement and may cause a + // perf regression, so we do it inside of the query for now. + if let Some(prev) = prev { + debug!(?key, ?ty, ?prev, "ignore duplicate in `opaque_type_storage`"); + } } if !ecx.nested_goals.is_empty() { @@ -1065,14 +1078,17 @@ where &mut self, key: ty::OpaqueTypeKey, ) -> Option<(ty::OpaqueTypeKey, I::Ty)> { - let mut matching = - self.delegate.clone_opaque_types_for_query_response().into_iter().filter( - |(candidate_key, _)| { - candidate_key.def_id == key.def_id - && DeepRejectCtxt::relate_rigid_rigid(self.cx()) - .args_may_unify(candidate_key.args, key.args) - }, - ); + // We shouldn't have any duplicate entries when using + // this function during `TypingMode::Analysis`. + let duplicate_entries = self.delegate.clone_duplicate_opaque_types(); + assert!(duplicate_entries.is_empty(), "unexpected duplicates: {duplicate_entries:?}"); + let mut matching = self.delegate.clone_opaque_types_lookup_table().into_iter().filter( + |(candidate_key, _)| { + candidate_key.def_id == key.def_id + && DeepRejectCtxt::relate_rigid_rigid(self.cx()) + .args_may_unify(candidate_key.args, key.args) + }, + ); let first = matching.next(); let second = matching.next(); assert_eq!(second, None); diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/free_alias.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/free_alias.rs index d077f8a9be8a..8aa6e4a3d711 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/free_alias.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/free_alias.rs @@ -19,19 +19,25 @@ where goal: Goal>, ) -> QueryResult { let cx = self.cx(); - let free_ty = goal.predicate.alias; + let free_alias = goal.predicate.alias; // Check where clauses self.add_goals( GoalSource::Misc, - cx.predicates_of(free_ty.def_id) - .iter_instantiated(cx, free_ty.args) + cx.predicates_of(free_alias.def_id) + .iter_instantiated(cx, free_alias.args) .map(|pred| goal.with(cx, pred)), ); - let actual = cx.type_of(free_ty.def_id).instantiate(cx, free_ty.args); - self.instantiate_normalizes_to_term(goal, actual.into()); + let actual = if free_alias.kind(cx).is_type() { + cx.type_of(free_alias.def_id).instantiate(cx, free_alias.args) + } else { + // FIXME(mgca): once const items are actual aliases defined as equal to type system consts + // this should instead return that. + panic!("normalizing free const aliases in the type system is unsupported"); + }; + self.instantiate_normalizes_to_term(goal, actual.into()); self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } } diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs index 1d1ff09ee410..2640238f5a90 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs @@ -15,12 +15,12 @@ where D: SolverDelegate, I: Interner, { - pub(super) fn normalize_inherent_associated_type( + pub(super) fn normalize_inherent_associated_term( &mut self, goal: Goal>, ) -> QueryResult { let cx = self.cx(); - let inherent = goal.predicate.alias.expect_ty(cx); + let inherent = goal.predicate.alias; let impl_def_id = cx.parent(inherent.def_id); let impl_args = self.fresh_args_for_item(impl_def_id); @@ -48,8 +48,13 @@ where .map(|pred| goal.with(cx, pred)), ); - let normalized = cx.type_of(inherent.def_id).instantiate(cx, inherent_args); - self.instantiate_normalizes_to_term(goal, normalized.into()); + let normalized = if inherent.kind(cx).is_type() { + cx.type_of(inherent.def_id).instantiate(cx, inherent_args).into() + } else { + // FIXME(mgca): Properly handle IACs in the type system + panic!("normalizing inherent associated consts in the type system is unsupported"); + }; + self.instantiate_normalizes_to_term(goal, normalized); self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } } diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs index b030af483817..400b4ce1200c 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs @@ -48,9 +48,13 @@ where }) }) } - ty::AliasTermKind::InherentTy => self.normalize_inherent_associated_type(goal), + ty::AliasTermKind::InherentTy | ty::AliasTermKind::InherentConst => { + self.normalize_inherent_associated_term(goal) + } ty::AliasTermKind::OpaqueTy => self.normalize_opaque_type(goal), - ty::AliasTermKind::FreeTy => self.normalize_free_alias(goal), + ty::AliasTermKind::FreeTy | ty::AliasTermKind::FreeConst => { + self.normalize_free_alias(goal) + } ty::AliasTermKind::UnevaluatedConst => self.normalize_anon_const(goal), } } @@ -333,6 +337,8 @@ where cx.type_of(target_item_def_id).map_bound(|ty| ty.into()) } ty::AliasTermKind::ProjectionConst => { + // FIXME(mgca): once const items are actual aliases defined as equal to type system consts + // this should instead return that. if cx.features().associated_const_equality() { panic!("associated const projection is not supported yet") } else { diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index ac4f7ed64e22..3d7e0fcc3086 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -297,6 +297,19 @@ parse_forgot_paren = perhaps you forgot parentheses? parse_found_expr_would_be_stmt = expected expression, found `{$token}` .label = expected expression +parse_frontmatter_extra_characters_after_close = extra characters after frontmatter close are not allowed +parse_frontmatter_invalid_close_preceding_whitespace = invalid preceding whitespace for frontmatter close + .note = frontmatter close should not be preceded by whitespace +parse_frontmatter_invalid_infostring = invalid infostring for frontmatter + .note = frontmatter infostrings must be a single identifier immediately following the opening +parse_frontmatter_invalid_opening_preceding_whitespace = invalid preceding whitespace for frontmatter opening + .note = frontmatter opening should not be preceded by whitespace +parse_frontmatter_length_mismatch = frontmatter close does not match the opening + .label_opening = the opening here has {$len_opening} dashes... + .label_close = ...while the close has {$len_close} dashes +parse_frontmatter_unclosed = unclosed frontmatter + .note = frontmatter opening here was not closed + parse_function_body_equals_expr = function body cannot be `= expression;` .suggestion = surround the expression with `{"{"}` and `{"}"}` instead of `=` and `;` @@ -702,6 +715,16 @@ parse_parenthesized_lifetime_suggestion = remove the parentheses parse_path_double_colon = path separator must be a double colon .suggestion = use a double colon instead + +parse_path_found_attribute_in_params = `Trait(...)` syntax does not support attributes in parameters + .suggestion = remove the attributes + +parse_path_found_c_variadic_params = `Trait(...)` syntax does not support c_variadic parameters + .suggestion = remove the `...` + +parse_path_found_named_params = `Trait(...)` syntax does not support named parameters + .suggestion = remove the parameter name + parse_pattern_method_param_without_body = patterns aren't allowed in methods without bodies .suggestion = give this argument a name or use an underscore to ignore it diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 6a6fb0eb9b5b..766baf6f80c7 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -735,6 +735,61 @@ pub(crate) struct FoundExprWouldBeStmt { pub suggestion: ExprParenthesesNeeded, } +#[derive(Diagnostic)] +#[diag(parse_frontmatter_extra_characters_after_close)] +pub(crate) struct FrontmatterExtraCharactersAfterClose { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(parse_frontmatter_invalid_infostring)] +#[note] +pub(crate) struct FrontmatterInvalidInfostring { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(parse_frontmatter_invalid_opening_preceding_whitespace)] +pub(crate) struct FrontmatterInvalidOpeningPrecedingWhitespace { + #[primary_span] + pub span: Span, + #[note] + pub note_span: Span, +} + +#[derive(Diagnostic)] +#[diag(parse_frontmatter_unclosed)] +pub(crate) struct FrontmatterUnclosed { + #[primary_span] + pub span: Span, + #[note] + pub note_span: Span, +} + +#[derive(Diagnostic)] +#[diag(parse_frontmatter_invalid_close_preceding_whitespace)] +pub(crate) struct FrontmatterInvalidClosingPrecedingWhitespace { + #[primary_span] + pub span: Span, + #[note] + pub note_span: Span, +} + +#[derive(Diagnostic)] +#[diag(parse_frontmatter_length_mismatch)] +pub(crate) struct FrontmatterLengthMismatch { + #[primary_span] + pub span: Span, + #[label(parse_label_opening)] + pub opening: Span, + #[label(parse_label_close)] + pub close: Span, + pub len_opening: usize, + pub len_close: usize, +} + #[derive(Diagnostic)] #[diag(parse_leading_plus_not_supported)] pub(crate) struct LeadingPlusNotSupported { @@ -1591,6 +1646,30 @@ pub(crate) struct ExpectedFnPathFoundFnKeyword { pub fn_token_span: Span, } +#[derive(Diagnostic)] +#[diag(parse_path_found_named_params)] +pub(crate) struct FnPathFoundNamedParams { + #[primary_span] + #[suggestion(applicability = "machine-applicable", code = "")] + pub named_param_span: Span, +} + +#[derive(Diagnostic)] +#[diag(parse_path_found_c_variadic_params)] +pub(crate) struct PathFoundCVariadicParams { + #[primary_span] + #[suggestion(applicability = "machine-applicable", code = "")] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(parse_path_found_attribute_in_params)] +pub(crate) struct PathFoundAttributeInParams { + #[primary_span] + #[suggestion(applicability = "machine-applicable", code = "")] + pub span: Span, +} + #[derive(Diagnostic)] #[diag(parse_path_double_colon)] pub(crate) struct PathSingleColon { diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index e8a5cae54cf8..78c5742414b8 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -7,7 +7,9 @@ use rustc_ast::tokenstream::TokenStream; use rustc_ast::util::unicode::contains_text_flow_control_chars; use rustc_errors::codes::*; use rustc_errors::{Applicability, Diag, DiagCtxtHandle, StashKey}; -use rustc_lexer::{Base, Cursor, DocStyle, LiteralKind, RawStrError}; +use rustc_lexer::{ + Base, Cursor, DocStyle, FrontmatterAllowed, LiteralKind, RawStrError, is_whitespace, +}; use rustc_literal_escaper::{EscapeError, Mode, unescape_mixed, unescape_unicode}; use rustc_session::lint::BuiltinLintDiag; use rustc_session::lint::builtin::{ @@ -15,7 +17,7 @@ use rustc_session::lint::builtin::{ TEXT_DIRECTION_CODEPOINT_IN_COMMENT, }; use rustc_session::parse::ParseSess; -use rustc_span::{BytePos, Pos, Span, Symbol}; +use rustc_span::{BytePos, Pos, Span, Symbol, sym}; use tracing::debug; use crate::errors; @@ -56,7 +58,7 @@ pub(crate) fn lex_token_trees<'psess, 'src>( start_pos = start_pos + BytePos::from_usize(shebang_len); } - let cursor = Cursor::new(src); + let cursor = Cursor::new(src, FrontmatterAllowed::Yes); let mut lexer = Lexer { psess, start_pos, @@ -193,6 +195,11 @@ impl<'psess, 'src> Lexer<'psess, 'src> { let content = self.str_from_to(content_start, content_end); self.cook_doc_comment(content_start, content, CommentKind::Block, doc_style) } + rustc_lexer::TokenKind::Frontmatter { has_invalid_preceding_whitespace, invalid_infostring } => { + self.validate_frontmatter(start, has_invalid_preceding_whitespace, invalid_infostring); + preceded_by_whitespace = true; + continue; + } rustc_lexer::TokenKind::Whitespace => { preceded_by_whitespace = true; continue; @@ -256,7 +263,7 @@ impl<'psess, 'src> Lexer<'psess, 'src> { // was consumed. let lit_start = start + BytePos(prefix_len); self.pos = lit_start; - self.cursor = Cursor::new(&str_before[prefix_len as usize..]); + self.cursor = Cursor::new(&str_before[prefix_len as usize..], FrontmatterAllowed::No); self.report_unknown_prefix(start); let prefix_span = self.mk_sp(start, lit_start); return (Token::new(self.ident(start), prefix_span), preceded_by_whitespace); @@ -361,7 +368,7 @@ impl<'psess, 'src> Lexer<'psess, 'src> { // Reset the state so we just lex the `'r`. let lt_start = start + BytePos(2); self.pos = lt_start; - self.cursor = Cursor::new(&str_before[2 as usize..]); + self.cursor = Cursor::new(&str_before[2 as usize..], FrontmatterAllowed::No); let lifetime_name = self.str_from(start); let ident = Symbol::intern(lifetime_name); @@ -474,6 +481,91 @@ impl<'psess, 'src> Lexer<'psess, 'src> { } } + fn validate_frontmatter( + &self, + start: BytePos, + has_invalid_preceding_whitespace: bool, + invalid_infostring: bool, + ) { + let s = self.str_from(start); + let real_start = s.find("---").unwrap(); + let frontmatter_opening_pos = BytePos(real_start as u32) + start; + let s_new = &s[real_start..]; + let within = s_new.trim_start_matches('-'); + let len_opening = s_new.len() - within.len(); + + let frontmatter_opening_end_pos = frontmatter_opening_pos + BytePos(len_opening as u32); + if has_invalid_preceding_whitespace { + let line_start = + BytePos(s[..real_start].rfind("\n").map_or(0, |i| i as u32 + 1)) + start; + let span = self.mk_sp(line_start, frontmatter_opening_end_pos); + let label_span = self.mk_sp(line_start, frontmatter_opening_pos); + self.dcx().emit_err(errors::FrontmatterInvalidOpeningPrecedingWhitespace { + span, + note_span: label_span, + }); + } + + if invalid_infostring { + let line_end = s[real_start..].find('\n').unwrap_or(s[real_start..].len()); + let span = self.mk_sp( + frontmatter_opening_end_pos, + frontmatter_opening_pos + BytePos(line_end as u32), + ); + self.dcx().emit_err(errors::FrontmatterInvalidInfostring { span }); + } + + let last_line_start = within.rfind('\n').map_or(0, |i| i + 1); + let last_line = &within[last_line_start..]; + let last_line_trimmed = last_line.trim_start_matches(is_whitespace); + let last_line_start_pos = frontmatter_opening_end_pos + BytePos(last_line_start as u32); + + let frontmatter_span = self.mk_sp(frontmatter_opening_pos, self.pos); + self.psess.gated_spans.gate(sym::frontmatter, frontmatter_span); + + if !last_line_trimmed.starts_with("---") { + let label_span = self.mk_sp(frontmatter_opening_pos, frontmatter_opening_end_pos); + self.dcx().emit_err(errors::FrontmatterUnclosed { + span: frontmatter_span, + note_span: label_span, + }); + return; + } + + if last_line_trimmed.len() != last_line.len() { + let line_end = last_line_start_pos + BytePos(last_line.len() as u32); + let span = self.mk_sp(last_line_start_pos, line_end); + let whitespace_end = + last_line_start_pos + BytePos((last_line.len() - last_line_trimmed.len()) as u32); + let label_span = self.mk_sp(last_line_start_pos, whitespace_end); + self.dcx().emit_err(errors::FrontmatterInvalidClosingPrecedingWhitespace { + span, + note_span: label_span, + }); + } + + let rest = last_line_trimmed.trim_start_matches('-'); + let len_close = last_line_trimmed.len() - rest.len(); + if len_close != len_opening { + let span = self.mk_sp(frontmatter_opening_pos, self.pos); + let opening = self.mk_sp(frontmatter_opening_pos, frontmatter_opening_end_pos); + let last_line_close_pos = last_line_start_pos + BytePos(len_close as u32); + let close = self.mk_sp(last_line_start_pos, last_line_close_pos); + self.dcx().emit_err(errors::FrontmatterLengthMismatch { + span, + opening, + close, + len_opening, + len_close, + }); + } + + if !rest.trim_matches(is_whitespace).is_empty() { + let span = self.mk_sp(last_line_start_pos, self.pos); + self.dcx().emit_err(errors::FrontmatterExtraCharactersAfterClose { span }); + } + } + fn cook_doc_comment( &self, content_start: BytePos, @@ -839,7 +931,7 @@ impl<'psess, 'src> Lexer<'psess, 'src> { let space_pos = start + BytePos(1); let space_span = self.mk_sp(space_pos, space_pos); - let mut cursor = Cursor::new(str_before); + let mut cursor = Cursor::new(str_before, FrontmatterAllowed::No); let (is_string, span, unterminated) = match cursor.guarded_double_quoted_string() { Some(rustc_lexer::GuardedStr { n_hashes, terminated, token_len }) => { @@ -905,7 +997,7 @@ impl<'psess, 'src> Lexer<'psess, 'src> { // For backwards compatibility, roll back to after just the first `#` // and return the `Pound` token. self.pos = start + BytePos(1); - self.cursor = Cursor::new(&str_before[1..]); + self.cursor = Cursor::new(&str_before[1..], FrontmatterAllowed::No); token::Pound } } diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 4be8a90368d2..babc55ccc0f9 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -2894,7 +2894,7 @@ impl<'a> Parser<'a> { let (mut params, _) = self.parse_paren_comma_seq(|p| { p.recover_vcs_conflict_marker(); let snapshot = p.create_snapshot_for_diagnostic(); - let param = p.parse_param_general(req_name, first_param).or_else(|e| { + let param = p.parse_param_general(req_name, first_param, true).or_else(|e| { let guar = e.emit(); // When parsing a param failed, we should check to make the span of the param // not contain '(' before it. @@ -2922,7 +2922,13 @@ impl<'a> Parser<'a> { /// Parses a single function parameter. /// /// - `self` is syntactically allowed when `first_param` holds. - fn parse_param_general(&mut self, req_name: ReqName, first_param: bool) -> PResult<'a, Param> { + /// - `recover_arg_parse` is used to recover from a failed argument parse. + pub(super) fn parse_param_general( + &mut self, + req_name: ReqName, + first_param: bool, + recover_arg_parse: bool, + ) -> PResult<'a, Param> { let lo = self.token.span; let attrs = self.parse_outer_attributes()?; self.collect_tokens(None, attrs, ForceCollect::No, |this, attrs| { @@ -2990,12 +2996,13 @@ impl<'a> Parser<'a> { // If this is a C-variadic argument and we hit an error, return the error. Err(err) if this.token == token::DotDotDot => return Err(err), Err(err) if this.unmatched_angle_bracket_count > 0 => return Err(err), - // Recover from attempting to parse the argument as a type without pattern. - Err(err) => { + Err(err) if recover_arg_parse => { + // Recover from attempting to parse the argument as a type without pattern. err.cancel(); this.restore_snapshot(parser_snapshot_before_ty); this.recover_arg_parse()? } + Err(err) => return Err(err), } }; diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 1093e4f4af0a..9bce2fa74caa 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -15,7 +15,11 @@ use tracing::debug; use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign}; use super::{Parser, Restrictions, TokenType}; -use crate::errors::{self, PathSingleColon, PathTripleColon}; +use crate::ast::{PatKind, TyKind}; +use crate::errors::{ + self, FnPathFoundNamedParams, PathFoundAttributeInParams, PathFoundCVariadicParams, + PathSingleColon, PathTripleColon, +}; use crate::exp; use crate::parser::{CommaRecoveryMode, RecoverColon, RecoverComma}; @@ -396,7 +400,28 @@ impl<'a> Parser<'a> { snapshot = Some(self.create_snapshot_for_diagnostic()); } - let (inputs, _) = match self.parse_paren_comma_seq(|p| p.parse_ty()) { + let dcx = self.dcx(); + let parse_params_result = self.parse_paren_comma_seq(|p| { + let param = p.parse_param_general(|_| false, false, false); + param.map(move |param| { + if !matches!(param.pat.kind, PatKind::Missing) { + dcx.emit_err(FnPathFoundNamedParams { + named_param_span: param.pat.span, + }); + } + if matches!(param.ty.kind, TyKind::CVarArgs) { + dcx.emit_err(PathFoundCVariadicParams { span: param.pat.span }); + } + if !param.attrs.is_empty() { + dcx.emit_err(PathFoundAttributeInParams { + span: param.attrs[0].span, + }); + } + param.ty + }) + }); + + let (inputs, _) = match parse_params_result { Ok(output) => output, Err(mut error) if prev_token_before_parsing == token::PathSep => { error.span_label( diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index 6a1c2af48ed5..378cbb846379 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -3,7 +3,8 @@ use rustc_ast::token::Delimiter; use rustc_ast::tokenstream::DelimSpan; use rustc_ast::{ - self as ast, AttrArgs, Attribute, DelimArgs, MetaItem, MetaItemInner, MetaItemKind, Safety, + self as ast, AttrArgs, Attribute, DelimArgs, MetaItem, MetaItemInner, MetaItemKind, NodeId, + Safety, }; use rustc_errors::{Applicability, FatalError, PResult}; use rustc_feature::{AttributeSafety, AttributeTemplate, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute}; @@ -15,21 +16,19 @@ use rustc_span::{Span, Symbol, sym}; use crate::{errors, parse_in}; -pub fn check_attr(psess: &ParseSess, attr: &Attribute) { +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) { return; } - let attr_info = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)); - let attr_item = attr.get_normal_item(); + let builtin_attr_info = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)); - // All non-builtin attributes are considered safe - let safety = attr_info.map(|x| x.safety).unwrap_or(AttributeSafety::Normal); - check_attribute_safety(psess, safety, attr); + let builtin_attr_safety = builtin_attr_info.map(|x| x.safety); + check_attribute_safety(psess, builtin_attr_safety, attr, id); // Check input tokens for built-in and key-value attributes. - match attr_info { + 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 => { match parse_meta(psess, attr) { @@ -43,6 +42,7 @@ pub fn check_attr(psess: &ParseSess, attr: &Attribute) { } } _ => { + let attr_item = attr.get_normal_item(); if let AttrArgs::Eq { .. } = attr_item.args { // All key-value attributes are restricted to meta-item syntax. match parse_meta(psess, attr) { @@ -154,11 +154,23 @@ fn is_attr_template_compatible(template: &AttributeTemplate, meta: &ast::MetaIte } } -pub fn check_attribute_safety(psess: &ParseSess, safety: AttributeSafety, attr: &Attribute) { +pub fn check_attribute_safety( + psess: &ParseSess, + builtin_attr_safety: Option, + attr: &Attribute, + id: NodeId, +) { let attr_item = attr.get_normal_item(); + match (builtin_attr_safety, attr_item.unsafety) { + // - Unsafe builtin attribute + // - User wrote `#[unsafe(..)]`, which is permitted on any edition + (Some(AttributeSafety::Unsafe { .. }), Safety::Unsafe(..)) => { + // OK + } - if let AttributeSafety::Unsafe { unsafe_since } = safety { - if let ast::Safety::Default = attr_item.unsafety { + // - Unsafe builtin attribute + // - User did not write `#[unsafe(..)]` + (Some(AttributeSafety::Unsafe { unsafe_since }), Safety::Default) => { let path_span = attr_item.path.span; // If the `attr_item`'s span is not from a macro, then just suggest @@ -185,7 +197,7 @@ pub fn check_attribute_safety(psess: &ParseSess, safety: AttributeSafety, attr: psess.buffer_lint( UNSAFE_ATTR_OUTSIDE_UNSAFE, path_span, - ast::CRATE_NODE_ID, + id, BuiltinLintDiag::UnsafeAttrOutsideUnsafe { attribute_name_span: path_span, sugg_spans: (diag_span.shrink_to_lo(), diag_span.shrink_to_hi()), @@ -193,11 +205,38 @@ pub fn check_attribute_safety(psess: &ParseSess, safety: AttributeSafety, attr: ); } } - } else if let Safety::Unsafe(unsafe_span) = attr_item.unsafety { - psess.dcx().emit_err(errors::InvalidAttrUnsafe { - span: unsafe_span, - name: attr_item.path.clone(), - }); + + // - Normal builtin attribute, or any non-builtin attribute + // - All non-builtin attributes are currently considered safe; writing `#[unsafe(..)]` is + // not permitted on non-builtin attributes or normal builtin attributes + (Some(AttributeSafety::Normal) | None, Safety::Unsafe(unsafe_span)) => { + psess.dcx().emit_err(errors::InvalidAttrUnsafe { + span: unsafe_span, + name: attr_item.path.clone(), + }); + } + + // - Normal builtin attribute + // - No explicit `#[unsafe(..)]` written. + (Some(AttributeSafety::Normal), Safety::Default) => { + // OK + } + + // - Non-builtin attribute + // - No explicit `#[unsafe(..)]` written. + (None, Safety::Default) => { + // OK + } + + ( + Some(AttributeSafety::Unsafe { .. } | AttributeSafety::Normal) | None, + Safety::Safe(..), + ) => { + psess.dcx().span_delayed_bug( + attr_item.span(), + "`check_attribute_safety` does not expect `Safety::Safe` on attributes", + ); + } } } diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs index c59e6cb5c33f..9dd064aca662 100644 --- a/compiler/rustc_parse_format/src/lib.rs +++ b/compiler/rustc_parse_format/src/lib.rs @@ -15,50 +15,13 @@ )] // tidy-alphabetical-end +use std::ops::Range; + pub use Alignment::*; pub use Count::*; pub use Position::*; use rustc_literal_escaper::{Mode, unescape_unicode}; -// Note: copied from rustc_span -/// Range inside of a `Span` used for diagnostics when we only have access to relative positions. -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub struct InnerSpan { - pub start: usize, - pub end: usize, -} - -impl InnerSpan { - pub fn new(start: usize, end: usize) -> InnerSpan { - InnerSpan { start, end } - } -} - -/// The location and before/after width of a character whose width has changed from its source code -/// representation -#[derive(Copy, Clone, PartialEq, Eq)] -pub struct InnerWidthMapping { - /// Index of the character in the source - pub position: usize, - /// The inner width in characters - pub before: usize, - /// The transformed width in characters - pub after: usize, -} - -impl InnerWidthMapping { - pub fn new(position: usize, before: usize, after: usize) -> InnerWidthMapping { - InnerWidthMapping { position, before, after } - } -} - -/// Whether the input string is a literal. If yes, it contains the inner width mappings. -#[derive(Clone, PartialEq, Eq)] -enum InputStringKind { - NotALiteral, - Literal { width_mappings: Vec }, -} - /// The type of format string that we are parsing. #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum ParseMode { @@ -68,15 +31,6 @@ pub enum ParseMode { InlineAsm, } -#[derive(Copy, Clone)] -struct InnerOffset(usize); - -impl InnerOffset { - fn to(self, end: InnerOffset) -> InnerSpan { - InnerSpan::new(self.0, end.0) - } -} - /// A piece is a portion of the format string which represents the next part /// to emit. These are emitted as a stream by the `Parser` class. #[derive(Clone, Debug, PartialEq)] @@ -89,24 +43,48 @@ pub enum Piece<'a> { } /// Representation of an argument specification. -#[derive(Copy, Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq)] pub struct Argument<'a> { /// Where to find this argument pub position: Position<'a>, /// The span of the position indicator. Includes any whitespace in implicit /// positions (`{ }`). - pub position_span: InnerSpan, + pub position_span: Range, /// How to format the argument pub format: FormatSpec<'a>, } +impl<'a> Argument<'a> { + pub fn is_identifier(&self) -> bool { + matches!(self.position, Position::ArgumentNamed(_)) + && matches!( + self.format, + FormatSpec { + fill: None, + fill_span: None, + align: AlignUnknown, + sign: None, + alternate: false, + zero_pad: false, + debug_hex: None, + precision: CountImplied, + precision_span: None, + width: CountImplied, + width_span: None, + ty: "", + ty_span: None, + }, + ) + } +} + /// Specification for the formatting of an argument in the format string. -#[derive(Copy, Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq)] pub struct FormatSpec<'a> { /// Optionally specified character to fill alignment with. pub fill: Option, /// Span of the optionally specified fill character. - pub fill_span: Option, + pub fill_span: Option>, /// Optionally specified alignment. pub align: Alignment, /// The `+` or `-` flag. @@ -120,21 +98,21 @@ pub struct FormatSpec<'a> { /// The integer precision to use. pub precision: Count<'a>, /// The span of the precision formatting flag (for diagnostics). - pub precision_span: Option, + pub precision_span: Option>, /// The string width requested for the resulting format. pub width: Count<'a>, /// The span of the width formatting flag (for diagnostics). - pub width_span: Option, + pub width_span: Option>, /// The descriptor string representing the name of the format desired for /// this argument, this can be empty or any number of characters, although /// it is required to be one word. pub ty: &'a str, /// The span of the descriptor string (for diagnostics). - pub ty_span: Option, + pub ty_span: Option>, } /// Enum describing where an argument for a format can be located. -#[derive(Copy, Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq)] pub enum Position<'a> { /// The argument is implied to be located at an index ArgumentImplicitlyIs(usize), @@ -186,12 +164,12 @@ pub enum DebugHex { /// A count is used for the precision and width parameters of an integer, and /// can reference either an argument or a literal integer. -#[derive(Copy, Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq)] pub enum Count<'a> { /// The count is specified explicitly. CountIs(u16), /// The count is specified by the argument with the given name. - CountIsName(&'a str, InnerSpan), + CountIsName(&'a str, Range), /// The count is specified by the argument at the given index. CountIsParam(usize), /// The count is specified by a star (like in `{:.*}`) that refers to the argument at the given index. @@ -204,8 +182,8 @@ pub struct ParseError { pub description: String, pub note: Option, pub label: String, - pub span: InnerSpan, - pub secondary_label: Option<(String, InnerSpan)>, + pub span: Range, + pub secondary_label: Option<(String, Range)>, pub suggestion: Suggestion, } @@ -216,12 +194,12 @@ pub enum Suggestion { UsePositional, /// Remove `r#` from identifier: /// `format!("{r#foo}")` -> `format!("{foo}")` - RemoveRawIdent(InnerSpan), + RemoveRawIdent(Range), /// Reorder format parameter: /// `format!("{foo:?#}")` -> `format!("{foo:#?}")` /// `format!("{foo:?x}")` -> `format!("{foo:x?}")` /// `format!("{foo:?X}")` -> `format!("{foo:X?}")` - ReorderFormatParameter(InnerSpan, String), + ReorderFormatParameter(Range, String), } /// The parser structure for interpreting the input format string. This is @@ -232,92 +210,94 @@ pub enum Suggestion { /// necessary there's probably lots of room for improvement performance-wise. pub struct Parser<'a> { mode: ParseMode, + /// Input to be parsed input: &'a str, - cur: std::iter::Peekable>, + /// Tuples of the span in the code snippet (input as written before being unescaped), the pos in input, and the char in input + input_vec: Vec<(Range, usize, char)>, + /// Index into input_vec + input_vec_index: usize, /// Error messages accumulated during parsing pub errors: Vec, /// Current position of implicit positional argument pointer pub curarg: usize, - /// `Some(raw count)` when the string is "raw", used to position spans correctly - style: Option, /// Start and end byte offset of every successfully parsed argument - pub arg_places: Vec, - /// Characters whose length has been changed from their in-code representation - width_map: Vec, + pub arg_places: Vec>, /// Span of the last opening brace seen, used for error reporting - last_opening_brace: Option, - /// Whether the source string is comes from `println!` as opposed to `format!` or `print!` - append_newline: bool, + last_open_brace: Option>, /// Whether this formatting string was written directly in the source. This controls whether we /// can use spans to refer into it and give better error messages. /// N.B: This does _not_ control whether implicit argument captures can be used. pub is_source_literal: bool, + /// Index to the end of the literal snippet + end_of_snippet: usize, /// Start position of the current line. cur_line_start: usize, /// Start and end byte offset of every line of the format string. Excludes /// newline characters and leading whitespace. - pub line_spans: Vec, + pub line_spans: Vec>, } impl<'a> Iterator for Parser<'a> { type Item = Piece<'a>; fn next(&mut self) -> Option> { - if let Some(&(pos, c)) = self.cur.peek() { - match c { + if let Some(&(Range { start, end }, idx, ch)) = self.input_vec.get(self.input_vec_index) { + match ch { '{' => { - let curr_last_brace = self.last_opening_brace; - let byte_pos = self.to_span_index(pos); - let lbrace_end = InnerOffset(byte_pos.0 + self.to_span_width(pos)); - self.last_opening_brace = Some(byte_pos.to(lbrace_end)); - self.cur.next(); - if self.consume('{') { - self.last_opening_brace = curr_last_brace; - - Some(Piece::Lit(self.string(pos + 1))) + self.input_vec_index += 1; + if let Some(&(_, i, '{')) = self.input_vec.get(self.input_vec_index) { + self.input_vec_index += 1; + // double open brace escape: "{{" + // next state after this is either end-of-input or seen-a-brace + Some(Piece::Lit(self.string(i))) } else { - let arg = self.argument(lbrace_end); - if let Some(rbrace_pos) = self.consume_closing_brace(&arg) { + // single open brace + self.last_open_brace = Some(start..end); + let arg = self.argument(); + if let Some(close_brace_range) = self.consume_closing_brace(&arg) { if self.is_source_literal { - let lbrace_byte_pos = self.to_span_index(pos); - let rbrace_byte_pos = self.to_span_index(rbrace_pos); - - let width = self.to_span_width(rbrace_pos); - - self.arg_places.push( - lbrace_byte_pos.to(InnerOffset(rbrace_byte_pos.0 + width)), - ); + self.arg_places.push(start..close_brace_range.end); } - } else if let Some(&(_, maybe)) = self.cur.peek() { - match maybe { + } else if let Some(&(_, _, c)) = self.input_vec.get(self.input_vec_index) { + match c { '?' => self.suggest_format_debug(), - '<' | '^' | '>' => self.suggest_format_align(maybe), - _ => self.suggest_positional_arg_instead_of_captured_arg(arg), + '<' | '^' | '>' => self.suggest_format_align(c), + _ => { + self.suggest_positional_arg_instead_of_captured_arg(arg.clone()) + } } } Some(Piece::NextArgument(Box::new(arg))) } } '}' => { - self.cur.next(); - if self.consume('}') { - Some(Piece::Lit(self.string(pos + 1))) + self.input_vec_index += 1; + if let Some(&(_, i, '}')) = self.input_vec.get(self.input_vec_index) { + self.input_vec_index += 1; + // double close brace escape: "}}" + // next state after this is either end-of-input or start + Some(Piece::Lit(self.string(i))) } else { - let err_pos = self.to_span_index(pos); - self.err_with_note( - "unmatched `}` found", - "unmatched `}`", - "if you intended to print `}`, you can escape it using `}}`", - err_pos.to(err_pos), - ); + // error: single close brace without corresponding open brace + self.errors.push(ParseError { + description: "unmatched `}` found".into(), + note: Some( + "if you intended to print `}`, you can escape it using `}}`".into(), + ), + label: "unmatched `}`".into(), + span: start..end, + secondary_label: None, + suggestion: Suggestion::None, + }); None } } - _ => Some(Piece::Lit(self.string(pos))), + _ => Some(Piece::Lit(self.string(idx))), } } else { + // end of input if self.is_source_literal { - let span = self.span(self.cur_line_start, self.input.len()); + let span = self.cur_line_start..self.end_of_snippet; if self.line_spans.last() != Some(&span) { self.line_spans.push(span); } @@ -328,71 +308,104 @@ impl<'a> Iterator for Parser<'a> { } impl<'a> Parser<'a> { - /// Creates a new parser for the given format string + /// Creates a new parser for the given unescaped input string and + /// optional code snippet (the input as written before being unescaped), + /// where `style` is `Some(nr_hashes)` when the snippet is a raw string with that many hashes. + /// If the input comes via `println` or `panic`, then it has a newline already appended, + /// which is reflected in the `appended_newline` parameter. pub fn new( - s: &'a str, + input: &'a str, style: Option, snippet: Option, - append_newline: bool, + appended_newline: bool, mode: ParseMode, - ) -> Parser<'a> { - let input_string_kind = find_width_map_from_snippet(s, snippet, style); - let (width_map, is_source_literal) = match input_string_kind { - InputStringKind::Literal { width_mappings } => (width_mappings, true), - InputStringKind::NotALiteral => (Vec::new(), false), + ) -> Self { + let quote_offset = style.map_or(1, |nr_hashes| nr_hashes + 2); + + let (is_source_literal, end_of_snippet, pre_input_vec) = if let Some(snippet) = snippet { + if let Some(nr_hashes) = style { + // snippet is a raw string, which starts with 'r', a number of hashes, and a quote + // and ends with a quote and the same number of hashes + (true, snippet.len() - nr_hashes - 1, vec![]) + } else { + // snippet is not a raw string + if snippet.starts_with('"') { + // snippet looks like an ordinary string literal + // check whether it is the escaped version of input + let without_quotes = &snippet[1..snippet.len() - 1]; + let (mut ok, mut vec) = (true, vec![]); + let mut chars = input.chars(); + unescape_unicode(without_quotes, Mode::Str, &mut |range, res| match res { + Ok(ch) if ok && chars.next().is_some_and(|c| ch == c) => { + vec.push((range, ch)); + } + _ => { + ok = false; + vec = vec![]; + } + }); + let end = vec.last().map(|(r, _)| r.end).unwrap_or(0); + if ok { + if appended_newline { + if chars.as_str() == "\n" { + vec.push((end..end + 1, '\n')); + (true, 1 + end, vec) + } else { + (false, snippet.len(), vec![]) + } + } else if chars.as_str() == "" { + (true, 1 + end, vec) + } else { + (false, snippet.len(), vec![]) + } + } else { + (false, snippet.len(), vec![]) + } + } else { + // snippet is not a raw string and does not start with '"' + (false, snippet.len(), vec![]) + } + } + } else { + // snippet is None + (false, input.len() - if appended_newline { 1 } else { 0 }, vec![]) + }; + + let input_vec: Vec<(Range, usize, char)> = if pre_input_vec.is_empty() { + // Snippet is *not* input before unescaping, so spans pointing at it will be incorrect. + // This can happen with proc macros that respan generated literals. + input + .char_indices() + .map(|(idx, c)| { + let i = idx + quote_offset; + (i..i + c.len_utf8(), idx, c) + }) + .collect() + } else { + // Snippet is input before unescaping + input + .char_indices() + .zip(pre_input_vec) + .map(|((i, c), (r, _))| (r.start + quote_offset..r.end + quote_offset, i, c)) + .collect() }; Parser { mode, - input: s, - cur: s.char_indices().peekable(), + input, + input_vec, + input_vec_index: 0, errors: vec![], curarg: 0, - style, arg_places: vec![], - width_map, - last_opening_brace: None, - append_newline, + last_open_brace: None, is_source_literal, - cur_line_start: 0, + end_of_snippet, + cur_line_start: quote_offset, line_spans: vec![], } } - /// Notifies of an error. The message doesn't actually need to be of type - /// String, but I think it does when this eventually uses conditions so it - /// might as well start using it now. - fn err(&mut self, description: impl Into, label: impl Into, span: InnerSpan) { - self.errors.push(ParseError { - description: description.into(), - note: None, - label: label.into(), - span, - secondary_label: None, - suggestion: Suggestion::None, - }); - } - - /// Notifies of an error. The message doesn't actually need to be of type - /// String, but I think it does when this eventually uses conditions so it - /// might as well start using it now. - fn err_with_note( - &mut self, - description: impl Into, - label: impl Into, - note: impl Into, - span: InnerSpan, - ) { - self.errors.push(ParseError { - description: description.into(), - note: Some(note.into()), - label: label.into(), - span, - secondary_label: None, - suggestion: Suggestion::None, - }); - } - /// Optionally consumes the specified character. If the character is not at /// the current position, then the current iterator isn't moved and `false` is /// returned, otherwise the character is consumed and `true` is returned. @@ -404,94 +417,56 @@ impl<'a> Parser<'a> { /// the current position, then the current iterator isn't moved and `None` is /// returned, otherwise the character is consumed and the current position is /// returned. - fn consume_pos(&mut self, c: char) -> Option { - if let Some(&(pos, maybe)) = self.cur.peek() { - if c == maybe { - self.cur.next(); - return Some(pos); + fn consume_pos(&mut self, ch: char) -> Option<(Range, usize)> { + if let Some((r, i, c)) = self.input_vec.get(self.input_vec_index) { + if ch == *c { + self.input_vec_index += 1; + return Some((r.clone(), *i)); } } None } - fn remap_pos(&self, mut pos: usize) -> InnerOffset { - for width in &self.width_map { - if pos > width.position { - pos += width.before - width.after; - } else if pos == width.position && width.after == 0 { - pos += width.before; - } else { - break; - } - } - - InnerOffset(pos) - } - - fn to_span_index(&self, pos: usize) -> InnerOffset { - // This handles the raw string case, the raw argument is the number of # - // in r###"..."### (we need to add one because of the `r`). - let raw = self.style.map_or(0, |raw| raw + 1); - let pos = self.remap_pos(pos); - InnerOffset(raw + pos.0 + 1) - } - - fn to_span_width(&self, pos: usize) -> usize { - let pos = self.remap_pos(pos); - match self.width_map.iter().find(|w| w.position == pos.0) { - Some(w) => w.before, - None => 1, - } - } - - fn span(&self, start_pos: usize, end_pos: usize) -> InnerSpan { - let start = self.to_span_index(start_pos); - let end = self.to_span_index(end_pos); - start.to(end) - } - /// Forces consumption of the specified character. If the character is not /// found, an error is emitted. - fn consume_closing_brace(&mut self, arg: &Argument<'_>) -> Option { + fn consume_closing_brace(&mut self, arg: &Argument<'_>) -> Option> { self.ws(); - let pos; - let description; - - if let Some(&(peek_pos, maybe)) = self.cur.peek() { - if maybe == '}' { - self.cur.next(); - return Some(peek_pos); + let (range, description) = if let Some((r, _, c)) = self.input_vec.get(self.input_vec_index) + { + if *c == '}' { + self.input_vec_index += 1; + return Some(r.clone()); } - - pos = peek_pos; - description = format!("expected `}}`, found `{}`", maybe.escape_debug()); + // or r.clone()? + (r.start..r.start, format!("expected `}}`, found `{}`", c.escape_debug())) } else { - description = "expected `}` but string was terminated".to_owned(); - // point at closing `"` - pos = self.input.len() - if self.append_newline { 1 } else { 0 }; - } + ( + // point at closing `"` + self.end_of_snippet..self.end_of_snippet, + "expected `}` but string was terminated".to_owned(), + ) + }; - let pos = self.to_span_index(pos); - - let label = "expected `}`".to_owned(); let (note, secondary_label) = if arg.format.fill == Some('}') { ( Some("the character `}` is interpreted as a fill character because of the `:` that precedes it".to_owned()), - arg.format.fill_span.map(|sp| ("this is not interpreted as a formatting closing brace".to_owned(), sp)), + arg.format.fill_span.clone().map(|sp| ("this is not interpreted as a formatting closing brace".to_owned(), sp)), ) } else { ( Some("if you intended to print `{`, you can escape it using `{{`".to_owned()), - self.last_opening_brace.map(|sp| ("because of this opening brace".to_owned(), sp)), + self.last_open_brace + .clone() + .map(|sp| ("because of this opening brace".to_owned(), sp)), ) }; self.errors.push(ParseError { description, note, - label, - span: pos.to(pos), + label: "expected `}`".to_owned(), + span: range.start..range.start, secondary_label, suggestion: Suggestion::None, }); @@ -501,28 +476,30 @@ impl<'a> Parser<'a> { /// Consumes all whitespace characters until the first non-whitespace character fn ws(&mut self) { - while let Some(_) = self.cur.next_if(|&(_, c)| c.is_whitespace()) {} + let rest = &self.input_vec[self.input_vec_index..]; + let step = rest.iter().position(|&(_, _, c)| !c.is_whitespace()).unwrap_or(rest.len()); + self.input_vec_index += step; } /// Parses all of a string which is to be considered a "raw literal" in a /// format string. This is everything outside of the braces. fn string(&mut self, start: usize) -> &'a str { - // we may not consume the character, peek the iterator - while let Some(&(pos, c)) = self.cur.peek() { + while let Some((r, i, c)) = self.input_vec.get(self.input_vec_index) { match c { '{' | '}' => { - return &self.input[start..pos]; + return &self.input[start..*i]; } '\n' if self.is_source_literal => { - self.line_spans.push(self.span(self.cur_line_start, pos)); - self.cur_line_start = pos + 1; - self.cur.next(); + self.input_vec_index += 1; + self.line_spans.push(self.cur_line_start..r.start); + self.cur_line_start = r.end; } _ => { - if self.is_source_literal && pos == self.cur_line_start && c.is_whitespace() { - self.cur_line_start = pos + c.len_utf8(); + self.input_vec_index += 1; + if self.is_source_literal && r.start == self.cur_line_start && c.is_whitespace() + { + self.cur_line_start = r.end; } - self.cur.next(); } } } @@ -530,15 +507,13 @@ impl<'a> Parser<'a> { } /// Parses an `Argument` structure, or what's contained within braces inside the format string. - fn argument(&mut self, start: InnerOffset) -> Argument<'a> { - let pos = self.position(); + fn argument(&mut self) -> Argument<'a> { + let start_idx = self.input_vec_index; - let end = self - .cur - .clone() - .find(|(_, ch)| !ch.is_whitespace()) - .map_or(start, |(end, _)| self.to_span_index(end)); - let position_span = start.to(end); + let position = self.position(); + self.ws(); + + let end_idx = self.input_vec_index; let format = match self.mode { ParseMode::Format => self.format(), @@ -546,16 +521,15 @@ impl<'a> Parser<'a> { }; // Resolve position after parsing format spec. - let pos = match pos { - Some(position) => position, - None => { - let i = self.curarg; - self.curarg += 1; - ArgumentImplicitlyIs(i) - } - }; + let position = position.unwrap_or_else(|| { + let i = self.curarg; + self.curarg += 1; + ArgumentImplicitlyIs(i) + }); - Argument { position: pos, position_span, format } + let position_span = + self.input_vec_index2range(start_idx).start..self.input_vec_index2range(end_idx).start; + Argument { position, position_span, format } } /// Parses a positional argument for a format. This could either be an @@ -566,23 +540,26 @@ impl<'a> Parser<'a> { if let Some(i) = self.integer() { Some(ArgumentIs(i.into())) } else { - match self.cur.peek() { - Some(&(lo, c)) if rustc_lexer::is_id_start(c) => { + match self.input_vec.get(self.input_vec_index) { + Some((range, _, c)) if rustc_lexer::is_id_start(*c) => { + let start = range.start; let word = self.word(); // Recover from `r#ident` in format strings. // FIXME: use a let chain if word == "r" { - if let Some((pos, '#')) = self.cur.peek() { - if self.input[pos + 1..] - .chars() - .next() - .is_some_and(rustc_lexer::is_id_start) + if let Some((r, _, '#')) = self.input_vec.get(self.input_vec_index) { + if self + .input_vec + .get(self.input_vec_index + 1) + .is_some_and(|(_, _, c)| rustc_lexer::is_id_start(*c)) { - self.cur.next(); + self.input_vec_index += 1; + let prefix_end = r.end; let word = self.word(); - let prefix_span = self.span(lo, lo + 2); - let full_span = self.span(lo, lo + 2 + word.len()); + let prefix_span = start..prefix_end; + let full_span = + start..self.input_vec_index2range(self.input_vec_index).start; self.errors.insert(0, ParseError { description: "raw identifiers are not supported".to_owned(), note: Some("identifiers in format strings can be keywords and don't need to be prefixed with `r#`".to_string()), @@ -598,7 +575,6 @@ impl<'a> Parser<'a> { Some(ArgumentNamed(word)) } - // This is an `ArgumentNext`. // Record the fact and do the resolution after parsing the // format spec, to make things like `{:.*}` work. @@ -607,8 +583,16 @@ impl<'a> Parser<'a> { } } - fn current_pos(&mut self) -> usize { - if let Some(&(pos, _)) = self.cur.peek() { pos } else { self.input.len() } + fn input_vec_index2pos(&self, index: usize) -> usize { + if let Some(&(_, pos, _)) = self.input_vec.get(index) { pos } else { self.input.len() } + } + + fn input_vec_index2range(&self, index: usize) -> Range { + if let Some((r, _, _)) = self.input_vec.get(index) { + r.clone() + } else { + self.end_of_snippet..self.end_of_snippet + } } /// Parses a format specifier at the current position, returning all of the @@ -634,11 +618,11 @@ impl<'a> Parser<'a> { } // fill character - if let Some(&(idx, c)) = self.cur.peek() { - if let Some((_, '>' | '<' | '^')) = self.cur.clone().nth(1) { + if let Some(&(ref r, _, c)) = self.input_vec.get(self.input_vec_index) { + if let Some((_, _, '>' | '<' | '^')) = self.input_vec.get(self.input_vec_index + 1) { + self.input_vec_index += 1; spec.fill = Some(c); - spec.fill_span = Some(self.span(idx, idx + 1)); - self.cur.next(); + spec.fill_span = Some(r.clone()); } } // Alignment @@ -662,14 +646,14 @@ impl<'a> Parser<'a> { // Width and precision let mut havewidth = false; - if self.consume('0') { + if let Some((range, _)) = self.consume_pos('0') { // small ambiguity with '0$' as a format string. In theory this is a // '0' flag and then an ill-formatted format string with just a '$' // and no count, but this is better if we instead interpret this as // no '0' flag and '0$' as the width instead. - if let Some(end) = self.consume_pos('$') { + if let Some((r, _)) = self.consume_pos('$') { spec.width = CountIsParam(0); - spec.width_span = Some(self.span(end - 1, end + 1)); + spec.width_span = Some(range.start..r.end); havewidth = true; } else { spec.zero_pad = true; @@ -677,15 +661,15 @@ impl<'a> Parser<'a> { } if !havewidth { - let start = self.current_pos(); - spec.width = self.count(start); + let start_idx = self.input_vec_index; + spec.width = self.count(); if spec.width != CountImplied { - let end = self.current_pos(); - spec.width_span = Some(self.span(start, end)); + let end = self.input_vec_index2range(self.input_vec_index).start; + spec.width_span = Some(self.input_vec_index2range(start_idx).start..end); } } - if let Some(start) = self.consume_pos('.') { + if let Some((range, _)) = self.consume_pos('.') { if self.consume('*') { // Resolve `CountIsNextParam`. // We can do this immediately as `position` is resolved later. @@ -693,13 +677,13 @@ impl<'a> Parser<'a> { self.curarg += 1; spec.precision = CountIsStar(i); } else { - spec.precision = self.count(start + 1); + spec.precision = self.count(); } - let end = self.current_pos(); - spec.precision_span = Some(self.span(start, end)); + spec.precision_span = + Some(range.start..self.input_vec_index2range(self.input_vec_index).start); } - let ty_span_start = self.current_pos(); + let start_idx = self.input_vec_index; // Optional radix followed by the actual format specifier if self.consume('x') { if self.consume('?') { @@ -715,19 +699,33 @@ impl<'a> Parser<'a> { } else { spec.ty = "X"; } - } else if self.consume('?') { + } else if let Some((range, _)) = self.consume_pos('?') { spec.ty = "?"; - if let Some(&(_, maybe)) = self.cur.peek() { - match maybe { - '#' | 'x' | 'X' => self.suggest_format_parameter(maybe), + if let Some((r, _, c)) = self.input_vec.get(self.input_vec_index) { + match c { + '#' | 'x' | 'X' => self.errors.insert( + 0, + ParseError { + description: format!("expected `}}`, found `{c}`"), + note: None, + label: "expected `'}'`".into(), + span: r.clone(), + secondary_label: None, + suggestion: Suggestion::ReorderFormatParameter( + range.start..r.end, + format!("{c}?"), + ), + }, + ), _ => (), } } } else { spec.ty = self.word(); if !spec.ty.is_empty() { - let ty_span_end = self.current_pos(); - spec.ty_span = Some(self.span(ty_span_start, ty_span_end)); + let start = self.input_vec_index2range(start_idx).start; + let end = self.input_vec_index2range(self.input_vec_index).start; + spec.ty_span = Some(start..end); } } spec @@ -755,11 +753,12 @@ impl<'a> Parser<'a> { return spec; } - let ty_span_start = self.current_pos(); + let start_idx = self.input_vec_index; spec.ty = self.word(); if !spec.ty.is_empty() { - let ty_span_end = self.current_pos(); - spec.ty_span = Some(self.span(ty_span_start, ty_span_end)); + let start = self.input_vec_index2range(start_idx).start; + let end = self.input_vec_index2range(self.input_vec_index).start; + spec.ty_span = Some(start..end); } spec @@ -768,55 +767,58 @@ impl<'a> Parser<'a> { /// Parses a `Count` parameter at the current position. This does not check /// for 'CountIsNextParam' because that is only used in precision, not /// width. - fn count(&mut self, start: usize) -> Count<'a> { + fn count(&mut self) -> Count<'a> { if let Some(i) = self.integer() { if self.consume('$') { CountIsParam(i.into()) } else { CountIs(i) } } else { - let tmp = self.cur.clone(); + let start_idx = self.input_vec_index; let word = self.word(); if word.is_empty() { - self.cur = tmp; CountImplied - } else if let Some(end) = self.consume_pos('$') { - let name_span = self.span(start, end); - CountIsName(word, name_span) + } else if let Some((r, _)) = self.consume_pos('$') { + CountIsName(word, self.input_vec_index2range(start_idx).start..r.start) } else { - self.cur = tmp; + self.input_vec_index = start_idx; CountImplied } } } - /// Parses a word starting at the current position. A word is the same as + /// Parses a word starting at the current position. A word is the same as a /// Rust identifier, except that it can't start with `_` character. fn word(&mut self) -> &'a str { - let start = match self.cur.peek() { - Some(&(pos, c)) if rustc_lexer::is_id_start(c) => { - self.cur.next(); - pos + let index = self.input_vec_index; + match self.input_vec.get(self.input_vec_index) { + Some(&(ref r, i, c)) if rustc_lexer::is_id_start(c) => { + self.input_vec_index += 1; + (r.start, i) } _ => { return ""; } }; - let mut end = None; - while let Some(&(pos, c)) = self.cur.peek() { - if rustc_lexer::is_id_continue(c) { - self.cur.next(); + let (err_end, end): (usize, usize) = loop { + if let Some(&(ref r, i, c)) = self.input_vec.get(self.input_vec_index) { + if rustc_lexer::is_id_continue(c) { + self.input_vec_index += 1; + } else { + break (r.start, i); + } } else { - end = Some(pos); - break; + break (self.end_of_snippet, self.input.len()); } - } - let end = end.unwrap_or(self.input.len()); - let word = &self.input[start..end]; + }; + + let word = &self.input[self.input_vec_index2pos(index)..end]; if word == "_" { - self.err_with_note( - "invalid argument name `_`", - "invalid argument name", - "argument name cannot be a single underscore", - self.span(start, end), - ); + self.errors.push(ParseError { + description: "invalid argument name `_`".into(), + note: Some("argument name cannot be a single underscore".into()), + label: "invalid argument name".into(), + span: self.input_vec_index2range(index).start..err_end, + secondary_label: None, + suggestion: Suggestion::None, + }); } word } @@ -825,9 +827,10 @@ impl<'a> Parser<'a> { let mut cur: u16 = 0; let mut found = false; let mut overflow = false; - let start = self.current_pos(); - while let Some(&(_, c)) = self.cur.peek() { + let start_index = self.input_vec_index; + while let Some(&(_, _, c)) = self.input_vec.get(self.input_vec_index) { if let Some(i) = c.to_digit(10) { + self.input_vec_index += 1; let (tmp, mul_overflow) = cur.overflowing_mul(10); let (tmp, add_overflow) = tmp.overflowing_add(i as u16); if mul_overflow || add_overflow { @@ -835,40 +838,42 @@ impl<'a> Parser<'a> { } cur = tmp; found = true; - self.cur.next(); } else { break; } } if overflow { - let end = self.current_pos(); - let overflowed_int = &self.input[start..end]; - self.err( - format!( + let overflowed_int = &self.input[self.input_vec_index2pos(start_index) + ..self.input_vec_index2pos(self.input_vec_index)]; + self.errors.push(ParseError { + description: format!( "integer `{}` does not fit into the type `u16` whose range is `0..={}`", overflowed_int, u16::MAX ), - "integer out of range for `u16`", - self.span(start, end), - ); + note: None, + label: "integer out of range for `u16`".into(), + span: self.input_vec_index2range(start_index).start + ..self.input_vec_index2range(self.input_vec_index).end, + secondary_label: None, + suggestion: Suggestion::None, + }); } found.then_some(cur) } fn suggest_format_debug(&mut self) { - if let (Some(pos), Some(_)) = (self.consume_pos('?'), self.consume_pos(':')) { + if let (Some((range, _)), Some(_)) = (self.consume_pos('?'), self.consume_pos(':')) { let word = self.word(); - let pos = self.to_span_index(pos); self.errors.insert( 0, ParseError { description: "expected format parameter to occur after `:`".to_owned(), note: Some(format!("`?` comes after `:`, try `{}:{}` instead", word, "?")), label: "expected `?` to occur after `:`".to_owned(), - span: pos.to(pos), + span: range, secondary_label: None, suggestion: Suggestion::None, }, @@ -877,15 +882,14 @@ impl<'a> Parser<'a> { } fn suggest_format_align(&mut self, alignment: char) { - if let Some(pos) = self.consume_pos(alignment) { - let pos = self.to_span_index(pos); + if let Some((range, _)) = self.consume_pos(alignment) { self.errors.insert( 0, ParseError { description: "expected format parameter to occur after `:`".to_owned(), note: None, label: format!("expected `{}` to occur after `:`", alignment), - span: pos.to(pos), + span: range, secondary_label: None, suggestion: Suggestion::None, }, @@ -894,10 +898,13 @@ impl<'a> Parser<'a> { } fn suggest_positional_arg_instead_of_captured_arg(&mut self, arg: Argument<'a>) { - if let Some(end) = self.consume_pos('.') { - let byte_pos = self.to_span_index(end); - let start = InnerOffset(byte_pos.0 + 1); - let field = self.argument(start); + // If the argument is not an identifier, it is not a field access. + if !arg.is_identifier() { + return; + } + + if let Some((_range, _pos)) = self.consume_pos('.') { + let field = self.argument(); // We can only parse simple `foo.bar` field access or `foo.0` tuple index access, any // deeper nesting, or another type of expression, like method calls, are not supported if !self.consume('}') { @@ -912,10 +919,7 @@ impl<'a> Parser<'a> { description: "field access isn't supported".to_string(), note: None, label: "not supported".to_string(), - span: InnerSpan::new( - arg.position_span.start, - field.position_span.end, - ), + span: arg.position_span.start..field.position_span.end, secondary_label: None, suggestion: Suggestion::UsePositional, }, @@ -928,10 +932,7 @@ impl<'a> Parser<'a> { description: "tuple index access isn't supported".to_string(), note: None, label: "not supported".to_string(), - span: InnerSpan::new( - arg.position_span.start, - field.position_span.end, - ), + span: arg.position_span.start..field.position_span.end, secondary_label: None, suggestion: Suggestion::UsePositional, }, @@ -942,164 +943,6 @@ impl<'a> Parser<'a> { } } } - - fn suggest_format_parameter(&mut self, c: char) { - let replacement = match c { - '#' => "#?", - 'x' => "x?", - 'X' => "X?", - _ => return, - }; - let Some(pos) = self.consume_pos(c) else { - return; - }; - - let span = self.span(pos - 1, pos + 1); - let pos = self.to_span_index(pos); - - self.errors.insert( - 0, - ParseError { - description: format!("expected `}}`, found `{c}`"), - note: None, - label: "expected `'}'`".into(), - span: pos.to(pos), - secondary_label: None, - suggestion: Suggestion::ReorderFormatParameter(span, format!("{replacement}")), - }, - ) - } -} - -/// Finds the indices of all characters that have been processed and differ between the actual -/// written code (code snippet) and the `InternedString` that gets processed in the `Parser` -/// in order to properly synthesise the intra-string `Span`s for error diagnostics. -fn find_width_map_from_snippet( - input: &str, - snippet: Option, - str_style: Option, -) -> InputStringKind { - let snippet = match snippet { - Some(ref s) if s.starts_with('"') || s.starts_with("r\"") || s.starts_with("r#") => s, - _ => return InputStringKind::NotALiteral, - }; - - if str_style.is_some() { - return InputStringKind::Literal { width_mappings: Vec::new() }; - } - - // Strip quotes. - let snippet = &snippet[1..snippet.len() - 1]; - - // Macros like `println` add a newline at the end. That technically doesn't make them "literals" anymore, but it's fine - // since we will never need to point our spans there, so we lie about it here by ignoring it. - // Since there might actually be newlines in the source code, we need to normalize away all trailing newlines. - // If we only trimmed it off the input, `format!("\n")` would cause a mismatch as here we they actually match up. - // Alternatively, we could just count the trailing newlines and only trim one from the input if they don't match up. - let input_no_nl = input.trim_end_matches('\n'); - let Some(unescaped) = unescape_string(snippet) else { - return InputStringKind::NotALiteral; - }; - - let unescaped_no_nl = unescaped.trim_end_matches('\n'); - - if unescaped_no_nl != input_no_nl { - // The source string that we're pointing at isn't our input, so spans pointing at it will be incorrect. - // This can for example happen with proc macros that respan generated literals. - return InputStringKind::NotALiteral; - } - - let mut s = snippet.char_indices(); - let mut width_mappings = vec![]; - while let Some((pos, c)) = s.next() { - match (c, s.clone().next()) { - // skip whitespace and empty lines ending in '\\' - ('\\', Some((_, '\n'))) => { - let _ = s.next(); - let mut width = 2; - - while let Some((_, c)) = s.clone().next() { - if matches!(c, ' ' | '\n' | '\t') { - width += 1; - let _ = s.next(); - } else { - break; - } - } - - width_mappings.push(InnerWidthMapping::new(pos, width, 0)); - } - ('\\', Some((_, 'n' | 't' | 'r' | '0' | '\\' | '\'' | '\"'))) => { - width_mappings.push(InnerWidthMapping::new(pos, 2, 1)); - let _ = s.next(); - } - ('\\', Some((_, 'x'))) => { - // consume `\xAB` literal - s.nth(2); - width_mappings.push(InnerWidthMapping::new(pos, 4, 1)); - } - ('\\', Some((_, 'u'))) => { - let mut width = 2; - let _ = s.next(); - - if let Some((_, next_c)) = s.next() { - if next_c == '{' { - // consume up to 6 hexanumeric chars - let digits_len = - s.clone().take(6).take_while(|(_, c)| c.is_ascii_hexdigit()).count(); - - let len_utf8 = s - .as_str() - .get(..digits_len) - .and_then(|digits| u32::from_str_radix(digits, 16).ok()) - .and_then(char::from_u32) - .map_or(1, char::len_utf8); - - // Skip the digits, for chars that encode to more than 1 utf-8 byte - // exclude as many digits as it is greater than 1 byte - // - // So for a 3 byte character, exclude 2 digits - let required_skips = digits_len.saturating_sub(len_utf8.saturating_sub(1)); - - // skip '{' and '}' also - width += required_skips + 2; - - s.nth(digits_len); - } else if next_c.is_ascii_hexdigit() { - width += 1; - - // We suggest adding `{` and `}` when appropriate, accept it here as if - // it were correct - let mut i = 0; // consume up to 6 hexanumeric chars - while let (Some((_, c)), _) = (s.next(), i < 6) { - if c.is_ascii_hexdigit() { - width += 1; - } else { - break; - } - i += 1; - } - } - } - - width_mappings.push(InnerWidthMapping::new(pos, width, 1)); - } - _ => {} - } - } - - InputStringKind::Literal { width_mappings } -} - -fn unescape_string(string: &str) -> Option { - let mut buf = String::new(); - let mut ok = true; - unescape_unicode(string, Mode::Str, &mut |_, unescaped_char| match unescaped_char { - Ok(c) => buf.push(c), - Err(_) => ok = false, - }); - - ok.then_some(buf) } // Assert a reasonable size for `Piece` diff --git a/compiler/rustc_parse_format/src/tests.rs b/compiler/rustc_parse_format/src/tests.rs index cc8a0069c4ec..e6a7f24034ad 100644 --- a/compiler/rustc_parse_format/src/tests.rs +++ b/compiler/rustc_parse_format/src/tests.rs @@ -41,7 +41,6 @@ fn simple() { same("}}", &[Lit("}")]); same("\\}}", &[Lit("\\"), Lit("}")]); } - #[test] fn invalid01() { musterr("{") @@ -79,23 +78,48 @@ fn invalid_precision() { } #[test] -fn format_nothing() { +fn format_empty() { same( "{}", &[NextArgument(Box::new(Argument { position: ArgumentImplicitlyIs(0), - position_span: InnerSpan { start: 2, end: 2 }, + position_span: 2..2, format: fmtdflt(), }))], ); } #[test] +fn format_tab_empty() { + let fmt_pre = r###""\t{}""###; + let fmt = "\t{}"; + let parser = Parser::new(fmt, None, Some(fmt_pre.into()), false, ParseMode::Format); + assert_eq!( + parser.collect::>>(), + &[ + Lit("\t"), + NextArgument(Box::new(Argument { + position: ArgumentImplicitlyIs(0), + position_span: 4..4, + format: fmtdflt(), + })) + ], + ); +} +#[test] +fn format_open_brace_tab() { + let fmt_pre = r###""{\t""###; + let fmt = "{\t"; + let mut parser = Parser::new(fmt, None, Some(fmt_pre.into()), false, ParseMode::Format); + let _ = parser.by_ref().collect::>>(); + assert_eq!(parser.errors[0].span, 4..4); +} +#[test] fn format_position() { same( "{3}", &[NextArgument(Box::new(Argument { position: ArgumentIs(3), - position_span: InnerSpan { start: 2, end: 3 }, + position_span: 2..3, format: fmtdflt(), }))], ); @@ -106,7 +130,7 @@ fn format_position_nothing_else() { "{3:}", &[NextArgument(Box::new(Argument { position: ArgumentIs(3), - position_span: InnerSpan { start: 2, end: 3 }, + position_span: 2..3, format: fmtdflt(), }))], ); @@ -117,18 +141,54 @@ fn format_named() { "{name}", &[NextArgument(Box::new(Argument { position: ArgumentNamed("name"), - position_span: InnerSpan { start: 2, end: 6 }, + position_span: 2..6, format: fmtdflt(), }))], ) } #[test] +fn format_named_space_nothing() { + same( + "{name} {}", + &[ + NextArgument(Box::new(Argument { + position: ArgumentNamed("name"), + position_span: 2..6, + format: fmtdflt(), + })), + Lit(" "), + NextArgument(Box::new(Argument { + position: ArgumentImplicitlyIs(0), + position_span: 9..9, + format: fmtdflt(), + })), + ], + ) +} +#[test] +fn format_raw() { + let snippet = r###"r#"assertion `left {op} right` failed"#"###.into(); + let source = r#"assertion `left {op} right` failed"#; + + let parser = Parser::new(source, Some(1), Some(snippet), true, ParseMode::Format); + let expected = &[ + Lit("assertion `left "), + NextArgument(Box::new(Argument { + position: ArgumentNamed("op"), + position_span: 20..22, + format: fmtdflt(), + })), + Lit(" right` failed"), + ]; + assert_eq!(parser.collect::>>(), expected); +} +#[test] fn format_type() { same( "{3:x}", &[NextArgument(Box::new(Argument { position: ArgumentIs(3), - position_span: InnerSpan { start: 2, end: 3 }, + position_span: 2..3, format: FormatSpec { fill: None, fill_span: None, @@ -153,7 +213,7 @@ fn format_align_fill() { "{3:>}", &[NextArgument(Box::new(Argument { position: ArgumentIs(3), - position_span: InnerSpan { start: 2, end: 3 }, + position_span: 2..3, format: FormatSpec { fill: None, fill_span: None, @@ -175,10 +235,10 @@ fn format_align_fill() { "{3:0<}", &[NextArgument(Box::new(Argument { position: ArgumentIs(3), - position_span: InnerSpan { start: 2, end: 3 }, + position_span: 2..3, format: FormatSpec { fill: Some('0'), - fill_span: Some(InnerSpan::new(4, 5)), + fill_span: Some(4..5), align: AlignLeft, sign: None, alternate: false, @@ -197,10 +257,10 @@ fn format_align_fill() { "{3:*>>(), + &[Lit("\n .intel_syntax noprefix\n nop")] + ); + assert_eq!(parser.line_spans, &[2..2, 11..33, 42..45]); +} +#[test] +fn asm_concat() { + let asm_pre = r###"concat!("invalid", "_", "instruction")"###; + let asm = "invalid_instruction"; + let mut parser = Parser::new(asm, None, Some(asm_pre.into()), false, ParseMode::InlineAsm); + assert!(!parser.is_source_literal); + assert_eq!(parser.by_ref().collect::>>(), &[Lit(asm)]); + assert_eq!(parser.line_spans, &[]); +} diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 413726ddd82d..6d815e510ea2 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -356,6 +356,8 @@ passes_ignored_derived_impls = passes_implied_feature_not_exist = feature `{$implied_by}` implying `{$feature}` does not exist +passes_incorrect_crate_type = lang items are not allowed in stable dylibs + passes_incorrect_do_not_recommend_args = `#[diagnostic::do_not_recommend]` does not expect any arguments @@ -742,6 +744,23 @@ passes_trait_impl_const_stable = passes_transparent_incompatible = transparent {$target} cannot have other repr hints +passes_unexportable_adt_with_private_fields = ADT types with private fields are not exportable + .note = `{$field_name}` is private + +passes_unexportable_fn_abi = only functions with "C" ABI are exportable + +passes_unexportable_generic_fn = generic functions are not exportable + +passes_unexportable_item = {$descr}'s are not exportable + +passes_unexportable_priv_item = private items are not exportable + .note = is only usable at visibility `{$vis_descr}` + +passes_unexportable_type_in_interface = {$desc} with `#[export_stable]` attribute uses type `{$ty}`, which is not exportable + .label = not exportable + +passes_unexportable_type_repr = types with unstable layout are not exportable + passes_unknown_external_lang_item = unknown external lang item: `{$lang_item}` diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index a61d446a3a93..c68f8df49fc7 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -277,6 +277,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | sym::cfg_attr | sym::cfg_trace | sym::cfg_attr_trace + | sym::export_stable // handled in `check_export` // need to be fixed | sym::cfi_encoding // FIXME(cfi_encoding) | sym::pointee // FIXME(derive_coerce_pointee) @@ -625,6 +626,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { sym::naked, sym::instruction_set, sym::repr, + sym::rustc_std_internal_symbol, // code generation sym::cold, // documentation @@ -682,7 +684,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } } - if !other_attr.has_any_name(ALLOW_LIST) { + if !other_attr.has_any_name(ALLOW_LIST) + && !matches!(other_attr.path().as_slice(), [sym::rustfmt, ..]) + { let path = other_attr.path(); let path: Vec<_> = path.iter().map(|s| s.as_str()).collect(); let other_attr_name = path.join("::"); diff --git a/compiler/rustc_passes/src/check_export.rs b/compiler/rustc_passes/src/check_export.rs new file mode 100644 index 000000000000..2bb698689bee --- /dev/null +++ b/compiler/rustc_passes/src/check_export.rs @@ -0,0 +1,398 @@ +use std::iter; +use std::ops::ControlFlow; + +use rustc_abi::ExternAbi; +use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; +use rustc_hir as hir; +use rustc_hir::def::DefKind; +use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::intravisit::{self, Visitor}; +use rustc_middle::hir::nested_filter; +use rustc_middle::middle::privacy::{EffectiveVisibility, Level}; +use rustc_middle::query::{LocalCrate, Providers}; +use rustc_middle::ty::{ + self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, Visibility, +}; +use rustc_session::config::CrateType; +use rustc_span::{Span, sym}; + +use crate::errors::UnexportableItem; + +struct ExportableItemCollector<'tcx> { + tcx: TyCtxt<'tcx>, + exportable_items: FxIndexSet, + in_exportable_mod: bool, + seen_exportable_in_mod: bool, +} + +impl<'tcx> ExportableItemCollector<'tcx> { + fn new(tcx: TyCtxt<'tcx>) -> ExportableItemCollector<'tcx> { + ExportableItemCollector { + tcx, + exportable_items: Default::default(), + in_exportable_mod: false, + seen_exportable_in_mod: false, + } + } + + fn report_wrong_site(&self, def_id: LocalDefId) { + let def_descr = self.tcx.def_descr(def_id.to_def_id()); + self.tcx.dcx().emit_err(UnexportableItem::Item { + descr: &format!("{}", def_descr), + span: self.tcx.def_span(def_id), + }); + } + + fn item_is_exportable(&self, def_id: LocalDefId) -> bool { + let has_attr = self.tcx.has_attr(def_id, sym::export_stable); + if !self.in_exportable_mod && !has_attr { + return false; + } + + let visibilities = self.tcx.effective_visibilities(()); + let is_pub = visibilities.is_directly_public(def_id); + + if has_attr && !is_pub { + let vis = visibilities.effective_vis(def_id).cloned().unwrap_or( + EffectiveVisibility::from_vis(Visibility::Restricted( + self.tcx.parent_module_from_def_id(def_id).to_local_def_id(), + )), + ); + let vis = vis.at_level(Level::Direct); + let span = self.tcx.def_span(def_id); + + self.tcx.dcx().emit_err(UnexportableItem::PrivItem { + vis_note: span, + vis_descr: &vis.to_string(def_id, self.tcx), + span, + }); + return false; + } + + is_pub && (has_attr || self.in_exportable_mod) + } + + fn add_exportable(&mut self, def_id: LocalDefId) { + self.seen_exportable_in_mod = true; + self.exportable_items.insert(def_id.to_def_id()); + } + + fn walk_item_with_mod(&mut self, item: &'tcx hir::Item<'tcx>) { + let def_id = item.hir_id().owner.def_id; + let old_exportable_mod = self.in_exportable_mod; + if self.tcx.get_attr(def_id, sym::export_stable).is_some() { + self.in_exportable_mod = true; + } + let old_seen_exportable_in_mod = std::mem::replace(&mut self.seen_exportable_in_mod, false); + + intravisit::walk_item(self, item); + + if self.seen_exportable_in_mod || self.in_exportable_mod { + self.exportable_items.insert(def_id.to_def_id()); + } + + self.seen_exportable_in_mod = old_seen_exportable_in_mod; + self.in_exportable_mod = old_exportable_mod; + } +} + +impl<'tcx> Visitor<'tcx> for ExportableItemCollector<'tcx> { + type NestedFilter = nested_filter::All; + + fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt { + self.tcx + } + + fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { + let def_id = item.hir_id().owner.def_id; + // Applying #[extern] attribute to modules is simply equivalent to + // applying the attribute to every public item within it. + match item.kind { + hir::ItemKind::Mod(..) => { + self.walk_item_with_mod(item); + return; + } + hir::ItemKind::Impl(impl_) if impl_.of_trait.is_none() => { + self.walk_item_with_mod(item); + return; + } + _ => {} + } + + if !self.item_is_exportable(def_id) { + return; + } + + match item.kind { + hir::ItemKind::Fn { .. } + | hir::ItemKind::Struct(..) + | hir::ItemKind::Enum(..) + | hir::ItemKind::Union(..) + | hir::ItemKind::TyAlias(..) => { + self.add_exportable(def_id); + } + hir::ItemKind::Use(path, _) => { + for res in &path.res { + // Only local items are exportable. + if let Some(res_id) = res.opt_def_id() + && let Some(res_id) = res_id.as_local() + { + self.add_exportable(res_id); + } + } + } + // handled above + hir::ItemKind::Mod(..) => unreachable!(), + hir::ItemKind::Impl(impl_) if impl_.of_trait.is_none() => { + unreachable!(); + } + _ => self.report_wrong_site(def_id), + } + } + + fn visit_impl_item(&mut self, item: &'tcx hir::ImplItem<'tcx>) { + let def_id = item.hir_id().owner.def_id; + if !self.item_is_exportable(def_id) { + return; + } + match item.kind { + hir::ImplItemKind::Fn(..) | hir::ImplItemKind::Type(..) => { + self.add_exportable(def_id); + } + _ => self.report_wrong_site(def_id), + } + } + + fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) { + let def_id = item.hir_id().owner.def_id; + if !self.item_is_exportable(def_id) { + self.report_wrong_site(def_id); + } + } + + fn visit_trait_item(&mut self, item: &'tcx hir::TraitItem<'tcx>) { + let def_id = item.hir_id().owner.def_id; + if !self.item_is_exportable(def_id) { + self.report_wrong_site(def_id); + } + } +} + +struct ExportableItemsChecker<'tcx, 'a> { + tcx: TyCtxt<'tcx>, + exportable_items: &'a FxIndexSet, + item_id: DefId, +} + +impl<'tcx, 'a> ExportableItemsChecker<'tcx, 'a> { + fn check(&mut self) { + match self.tcx.def_kind(self.item_id) { + DefKind::Fn | DefKind::AssocFn => self.check_fn(), + DefKind::Enum | DefKind::Struct | DefKind::Union => self.check_ty(), + _ => {} + } + } + + fn check_fn(&mut self) { + let def_id = self.item_id.expect_local(); + let span = self.tcx.def_span(def_id); + + if self.tcx.generics_of(def_id).requires_monomorphization(self.tcx) { + self.tcx.dcx().emit_err(UnexportableItem::GenericFn(span)); + return; + } + + let sig = self.tcx.fn_sig(def_id).instantiate_identity().skip_binder(); + if !matches!(sig.abi, ExternAbi::C { .. }) { + self.tcx.dcx().emit_err(UnexportableItem::FnAbi(span)); + return; + } + + let sig = self + .tcx + .try_normalize_erasing_regions(ty::TypingEnv::non_body_analysis(self.tcx, def_id), sig) + .unwrap_or(sig); + + let hir_id = self.tcx.local_def_id_to_hir_id(def_id); + let decl = self.tcx.hir_fn_decl_by_hir_id(hir_id).unwrap(); + + for (input_ty, input_hir) in iter::zip(sig.inputs(), decl.inputs) { + self.check_nested_types_are_exportable(*input_ty, input_hir.span); + } + + if let hir::FnRetTy::Return(ret_hir) = decl.output { + self.check_nested_types_are_exportable(sig.output(), ret_hir.span); + } + } + + fn check_ty(&mut self) { + let ty = self.tcx.type_of(self.item_id).skip_binder(); + if let ty::Adt(adt_def, _) = ty.kind() { + if !adt_def.repr().inhibit_struct_field_reordering() { + self.tcx + .dcx() + .emit_err(UnexportableItem::TypeRepr(self.tcx.def_span(self.item_id))); + } + + // FIXME: support `#[export(unsafe_stable_abi = "hash")]` syntax + for variant in adt_def.variants() { + for field in &variant.fields { + if !field.vis.is_public() { + self.tcx.dcx().emit_err(UnexportableItem::AdtWithPrivFields { + span: self.tcx.def_span(self.item_id), + vis_note: self.tcx.def_span(field.did), + field_name: field.name.as_str(), + }); + } + } + } + } + } + + fn check_nested_types_are_exportable(&mut self, ty: Ty<'tcx>, ty_span: Span) { + let res = ty.visit_with(self); + if let Some(err_cause) = res.break_value() { + self.tcx.dcx().emit_err(UnexportableItem::TypeInInterface { + span: self.tcx.def_span(self.item_id), + desc: self.tcx.def_descr(self.item_id), + ty: &format!("{}", err_cause), + ty_span, + }); + } + } +} + +impl<'tcx, 'a> TypeVisitor> for ExportableItemsChecker<'tcx, 'a> { + type Result = ControlFlow>; + + fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result { + match ty.kind() { + ty::Adt(adt_def, _) => { + let did = adt_def.did(); + let exportable = if did.is_local() { + self.exportable_items.contains(&did) + } else { + self.tcx.is_exportable(did) + }; + if !exportable { + return ControlFlow::Break(ty); + } + for variant in adt_def.variants() { + for field in &variant.fields { + let field_ty = self.tcx.type_of(field.did).instantiate_identity(); + field_ty.visit_with(self)?; + } + } + + return ty.super_visit_with(self); + } + + ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Bool | ty::Char | ty::Error(_) => {} + + ty::Array(_, _) + | ty::Ref(_, _, _) + | ty::Param(_) + | ty::Closure(_, _) + | ty::Dynamic(_, _, _) + | ty::Coroutine(_, _) + | ty::Foreign(_) + | ty::Str + | ty::Tuple(_) + | ty::Pat(..) + | ty::Slice(_) + | ty::RawPtr(_, _) + | ty::FnDef(_, _) + | ty::FnPtr(_, _) + | ty::CoroutineClosure(_, _) + | ty::CoroutineWitness(_, _) + | ty::Never + | ty::UnsafeBinder(_) + | ty::Alias(ty::AliasTyKind::Opaque, _) => { + return ControlFlow::Break(ty); + } + + ty::Alias(..) | ty::Infer(_) | ty::Placeholder(_) | ty::Bound(..) => unreachable!(), + } + ControlFlow::Continue(()) + } +} + +/// Exportable items: +/// +/// 1. Structs/enums/unions with a stable representation (e.g. repr(i32) or repr(C)). +/// 2. Primitive types. +/// 3. Non-generic functions with a stable ABI (e.g. extern "C") for which every user +/// defined type used in the signature is also marked as `#[export]`. +fn exportable_items_provider_local<'tcx>(tcx: TyCtxt<'tcx>, _: LocalCrate) -> &'tcx [DefId] { + if !tcx.crate_types().contains(&CrateType::Sdylib) && !tcx.is_sdylib_interface_build() { + return &[]; + } + + let mut visitor = ExportableItemCollector::new(tcx); + tcx.hir_walk_toplevel_module(&mut visitor); + let exportable_items = visitor.exportable_items; + for item_id in exportable_items.iter() { + let mut validator = + ExportableItemsChecker { tcx, exportable_items: &exportable_items, item_id: *item_id }; + validator.check(); + } + + tcx.arena.alloc_from_iter(exportable_items.into_iter()) +} + +struct ImplsOrderVisitor<'tcx> { + tcx: TyCtxt<'tcx>, + order: FxIndexMap, +} + +impl<'tcx> ImplsOrderVisitor<'tcx> { + fn new(tcx: TyCtxt<'tcx>) -> ImplsOrderVisitor<'tcx> { + ImplsOrderVisitor { tcx, order: Default::default() } + } +} + +impl<'tcx> Visitor<'tcx> for ImplsOrderVisitor<'tcx> { + type NestedFilter = nested_filter::All; + + fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt { + self.tcx + } + + fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { + if let hir::ItemKind::Impl(impl_) = item.kind + && impl_.of_trait.is_none() + && self.tcx.is_exportable(item.owner_id.def_id.to_def_id()) + { + self.order.insert(item.owner_id.def_id.to_def_id(), self.order.len()); + } + intravisit::walk_item(self, item); + } +} + +/// During symbol mangling rustc uses a special index to distinguish between two impls of +/// the same type in the same module(See `DisambiguatedDefPathData`). For exportable items +/// we cannot use the current approach because it is dependent on the compiler's +/// implementation. +/// +/// In order to make disambiguation independent of the compiler version we can assign an +/// id to each impl according to the relative order of elements in the source code. +fn stable_order_of_exportable_impls<'tcx>( + tcx: TyCtxt<'tcx>, + _: LocalCrate, +) -> &'tcx FxIndexMap { + if !tcx.crate_types().contains(&CrateType::Sdylib) && !tcx.is_sdylib_interface_build() { + return tcx.arena.alloc(FxIndexMap::::default()); + } + + let mut vis = ImplsOrderVisitor::new(tcx); + tcx.hir_walk_toplevel_module(&mut vis); + tcx.arena.alloc(vis.order) +} + +pub(crate) fn provide(providers: &mut Providers) { + *providers = Providers { + exportable_items: exportable_items_provider_local, + stable_order_of_exportable_impls, + ..*providers + }; +} diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index b1b4b9ee9276..00682a9c7a79 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -1422,6 +1422,13 @@ pub(crate) struct IncorrectTarget<'a> { pub at_least: bool, } +#[derive(Diagnostic)] +#[diag(passes_incorrect_crate_type)] +pub(crate) struct IncorrectCrateType { + #[primary_span] + pub span: Span, +} + #[derive(LintDiagnostic)] #[diag(passes_useless_assignment)] pub(crate) struct UselessAssignment<'a> { @@ -1919,3 +1926,50 @@ pub(crate) struct UnsupportedAttributesInWhere { #[primary_span] pub span: MultiSpan, } + +#[derive(Diagnostic)] +pub(crate) enum UnexportableItem<'a> { + #[diag(passes_unexportable_item)] + Item { + #[primary_span] + span: Span, + descr: &'a str, + }, + + #[diag(passes_unexportable_generic_fn)] + GenericFn(#[primary_span] Span), + + #[diag(passes_unexportable_fn_abi)] + FnAbi(#[primary_span] Span), + + #[diag(passes_unexportable_type_repr)] + TypeRepr(#[primary_span] Span), + + #[diag(passes_unexportable_type_in_interface)] + TypeInInterface { + #[primary_span] + span: Span, + desc: &'a str, + ty: &'a str, + #[label] + ty_span: Span, + }, + + #[diag(passes_unexportable_priv_item)] + PrivItem { + #[primary_span] + span: Span, + #[note] + vis_note: Span, + vis_descr: &'a str, + }, + + #[diag(passes_unexportable_adt_with_private_fields)] + AdtWithPrivFields { + #[primary_span] + span: Span, + #[note] + vis_note: Span, + field_name: &'a str, + }, +} diff --git a/compiler/rustc_passes/src/lang_items.rs b/compiler/rustc_passes/src/lang_items.rs index 664bd4ad0a25..275714c2d0e4 100644 --- a/compiler/rustc_passes/src/lang_items.rs +++ b/compiler/rustc_passes/src/lang_items.rs @@ -19,7 +19,8 @@ use rustc_session::cstore::ExternCrate; use rustc_span::Span; use crate::errors::{ - DuplicateLangItem, IncorrectTarget, LangItemOnIncorrectTarget, UnknownLangItem, + DuplicateLangItem, IncorrectCrateType, IncorrectTarget, LangItemOnIncorrectTarget, + UnknownLangItem, }; use crate::weak_lang_items; @@ -236,6 +237,10 @@ impl<'ast, 'tcx> LanguageItemCollector<'ast, 'tcx> { } } + if self.tcx.crate_types().contains(&rustc_session::config::CrateType::Sdylib) { + self.tcx.dcx().emit_err(IncorrectCrateType { span: attr_span }); + } + self.collect_item(lang_item, item_def_id.to_def_id(), Some(item_span)); } } diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs index 424bce9d4d47..001725e28827 100644 --- a/compiler/rustc_passes/src/lib.rs +++ b/compiler/rustc_passes/src/lib.rs @@ -19,6 +19,7 @@ use rustc_middle::query::Providers; pub mod abi_test; mod check_attr; +mod check_export; pub mod dead; mod debugger_visualizer; mod diagnostic_items; @@ -54,4 +55,5 @@ pub fn provide(providers: &mut Providers) { reachable::provide(providers); stability::provide(providers); upvars::provide(providers); + check_export::provide(providers); } diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs index 321e5729b727..f0e8fa986fea 100644 --- a/compiler/rustc_passes/src/reachable.rs +++ b/compiler/rustc_passes/src/reachable.rs @@ -435,10 +435,12 @@ fn has_custom_linkage(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { fn reachable_set(tcx: TyCtxt<'_>, (): ()) -> LocalDefIdSet { let effective_visibilities = &tcx.effective_visibilities(()); - let any_library = tcx - .crate_types() - .iter() - .any(|ty| *ty == CrateType::Rlib || *ty == CrateType::Dylib || *ty == CrateType::ProcMacro); + let any_library = tcx.crate_types().iter().any(|ty| { + *ty == CrateType::Rlib + || *ty == CrateType::Dylib + || *ty == CrateType::ProcMacro + || *ty == CrateType::Sdylib + }); let mut reachable_context = ReachableContext { tcx, maybe_typeck_results: None, diff --git a/compiler/rustc_passes/src/weak_lang_items.rs b/compiler/rustc_passes/src/weak_lang_items.rs index 701f500e4f60..93d164e7d01f 100644 --- a/compiler/rustc_passes/src/weak_lang_items.rs +++ b/compiler/rustc_passes/src/weak_lang_items.rs @@ -67,7 +67,8 @@ fn verify(tcx: TyCtxt<'_>, items: &lang_items::LanguageItems) { | CrateType::ProcMacro | CrateType::Cdylib | CrateType::Executable - | CrateType::Staticlib => true, + | CrateType::Staticlib + | CrateType::Sdylib => true, CrateType::Rlib => false, }); if !needs_check { diff --git a/compiler/rustc_pattern_analysis/messages.ftl b/compiler/rustc_pattern_analysis/messages.ftl index 41a1d958f109..d3a3107f8e89 100644 --- a/compiler/rustc_pattern_analysis/messages.ftl +++ b/compiler/rustc_pattern_analysis/messages.ftl @@ -6,6 +6,10 @@ pattern_analysis_excluside_range_missing_max = exclusive range missing `{$max}` .label = this range doesn't match `{$max}` because `..` is an exclusive range .suggestion = use an inclusive range instead +pattern_analysis_mixed_deref_pattern_constructors = mix of deref patterns and normal constructors + .deref_pattern_label = matches on the result of dereferencing `{$smart_pointer_ty}` + .normal_constructor_label = matches directly on `{$smart_pointer_ty}` + pattern_analysis_non_exhaustive_omitted_pattern = some variants are not matched explicitly .help = ensure that all variants are matched explicitly by adding the suggested match arms .note = the matched value is of type `{$scrut_ty}` and the `non_exhaustive_omitted_patterns` attribute was found diff --git a/compiler/rustc_pattern_analysis/src/constructor.rs b/compiler/rustc_pattern_analysis/src/constructor.rs index 4ce868f014f4..f7a4931c1114 100644 --- a/compiler/rustc_pattern_analysis/src/constructor.rs +++ b/compiler/rustc_pattern_analysis/src/constructor.rs @@ -696,6 +696,10 @@ pub enum Constructor { F128Range(IeeeFloat, IeeeFloat, RangeEnd), /// String literals. Strings are not quite the same as `&[u8]` so we treat them separately. Str(Cx::StrLit), + /// Deref patterns (enabled by the `deref_patterns` feature) provide a way of matching on a + /// smart pointer ADT through its pointee. They don't directly correspond to ADT constructors, + /// and currently are not supported alongside them. Carries the type of the pointee. + DerefPattern(Cx::Ty), /// Constants that must not be matched structurally. They are treated as black boxes for the /// purposes of exhaustiveness: we must not inspect them, and they don't count towards making a /// match exhaustive. @@ -740,6 +744,7 @@ impl Clone for Constructor { Constructor::F64Range(lo, hi, end) => Constructor::F64Range(*lo, *hi, *end), Constructor::F128Range(lo, hi, end) => Constructor::F128Range(*lo, *hi, *end), Constructor::Str(value) => Constructor::Str(value.clone()), + Constructor::DerefPattern(ty) => Constructor::DerefPattern(ty.clone()), Constructor::Opaque(inner) => Constructor::Opaque(inner.clone()), Constructor::Or => Constructor::Or, Constructor::Never => Constructor::Never, @@ -856,6 +861,10 @@ impl Constructor { } (Slice(self_slice), Slice(other_slice)) => self_slice.is_covered_by(*other_slice), + // Deref patterns only interact with other deref patterns. Prior to usefulness analysis, + // we ensure they don't appear alongside any other non-wild non-opaque constructors. + (DerefPattern(_), DerefPattern(_)) => true, + // Opaque constructors don't interact with anything unless they come from the // syntactically identical pattern. (Opaque(self_id), Opaque(other_id)) => self_id == other_id, @@ -932,6 +941,7 @@ impl Constructor { F64Range(lo, hi, end) => write!(f, "{lo}{end}{hi}")?, F128Range(lo, hi, end) => write!(f, "{lo}{end}{hi}")?, Str(value) => write!(f, "{value:?}")?, + DerefPattern(_) => write!(f, "deref!({:?})", fields.next().unwrap())?, Opaque(..) => write!(f, "")?, Or => { for pat in fields { @@ -1039,8 +1049,17 @@ impl ConstructorSet { let mut missing = Vec::new(); // Constructors in `ctors`, except wildcards and opaques. let mut seen = Vec::new(); + // If we see a deref pattern, it must be the only non-wildcard non-opaque constructor; we + // ensure this prior to analysis. + let mut deref_pat_present = false; for ctor in ctors.cloned() { match ctor { + DerefPattern(..) => { + if !deref_pat_present { + deref_pat_present = true; + present.push(ctor); + } + } Opaque(..) => present.push(ctor), Wildcard => {} // discard wildcards _ => seen.push(ctor), @@ -1048,6 +1067,9 @@ impl ConstructorSet { } match self { + _ if deref_pat_present => { + // Deref patterns are the only constructor; nothing is missing. + } ConstructorSet::Struct { empty } => { if !seen.is_empty() { present.push(Struct); diff --git a/compiler/rustc_pattern_analysis/src/errors.rs b/compiler/rustc_pattern_analysis/src/errors.rs index e60930d6cd21..156ba9737673 100644 --- a/compiler/rustc_pattern_analysis/src/errors.rs +++ b/compiler/rustc_pattern_analysis/src/errors.rs @@ -1,5 +1,5 @@ use rustc_errors::{Diag, EmissionGuarantee, Subdiagnostic}; -use rustc_macros::{LintDiagnostic, Subdiagnostic}; +use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_middle::ty::Ty; use rustc_span::Span; @@ -133,3 +133,15 @@ pub(crate) struct NonExhaustiveOmittedPatternLintOnArm { pub lint_level: &'static str, pub lint_name: &'static str, } + +#[derive(Diagnostic)] +#[diag(pattern_analysis_mixed_deref_pattern_constructors)] +pub(crate) struct MixedDerefPatternConstructors<'tcx> { + #[primary_span] + pub spans: Vec, + pub smart_pointer_ty: Ty<'tcx>, + #[label(pattern_analysis_deref_pattern_label)] + pub deref_pattern_label: Span, + #[label(pattern_analysis_normal_constructor_label)] + pub normal_constructor_label: Span, +} diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index 7c12f69f14c1..a89d01dcbbe4 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -269,6 +269,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { } _ => bug!("bad slice pattern {:?} {:?}", ctor, ty), }, + DerefPattern(pointee_ty) => reveal_and_alloc(cx, once(pointee_ty.inner())), Bool(..) | IntRange(..) | F16Range(..) | F32Range(..) | F64Range(..) | F128Range(..) | Str(..) | Opaque(..) | Never | NonExhaustive | Hidden | Missing | PrivateUninhabited | Wildcard => &[], @@ -296,7 +297,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { } _ => bug!("Unexpected type for constructor `{ctor:?}`: {ty:?}"), }, - Ref => 1, + Ref | DerefPattern(_) => 1, Slice(slice) => slice.arity(), Bool(..) | IntRange(..) | F16Range(..) | F32Range(..) | F64Range(..) | F128Range(..) | Str(..) | Opaque(..) | Never | NonExhaustive | Hidden | Missing @@ -493,11 +494,15 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { ), }; } - PatKind::DerefPattern { .. } => { - // FIXME(deref_patterns): At least detect that `box _` is irrefutable. - fields = vec![]; - arity = 0; - ctor = Opaque(OpaqueId::new()); + PatKind::DerefPattern { subpattern, .. } => { + // NB(deref_patterns): This assumes the deref pattern is matching on a trusted + // `DerefPure` type. If the `Deref` impl isn't trusted, exhaustiveness must take + // into account that multiple calls to deref may return different results. Hence + // multiple deref! patterns cannot be exhaustive together unless each is exhaustive + // by itself. + fields = vec![self.lower_pat(subpattern).at_index(0)]; + arity = 1; + ctor = DerefPattern(cx.reveal_opaque_ty(subpattern.ty)); } PatKind::Leaf { subpatterns } | PatKind::Variant { subpatterns, .. } => { match ty.kind() { @@ -874,6 +879,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { print::write_ref_like(&mut s, pat.ty().inner(), &print(&pat.fields[0])).unwrap(); s } + DerefPattern(_) => format!("deref!({})", print(&pat.fields[0])), Slice(slice) => { let (prefix_len, has_dot_dot) = match slice.kind { SliceKind::FixedLen(len) => (len, false), @@ -1100,6 +1106,14 @@ pub fn analyze_match<'p, 'tcx>( scrut_ty: Ty<'tcx>, ) -> Result, ErrorGuaranteed> { let scrut_ty = tycx.reveal_opaque_ty(scrut_ty); + + // The analysis doesn't support deref patterns mixed with normal constructors; error if present. + // FIXME(deref_patterns): This only needs to run when a deref pattern was found during lowering. + if tycx.tcx.features().deref_patterns() { + let pat_column = PatternColumn::new(arms); + detect_mixed_deref_pat_ctors(tycx, &pat_column)?; + } + let scrut_validity = PlaceValidity::from_bool(tycx.known_valid_scrutinee); let report = compute_match_usefulness( tycx, @@ -1119,6 +1133,51 @@ pub fn analyze_match<'p, 'tcx>( Ok(report) } +// FIXME(deref_patterns): Currently it's the responsibility of the frontend (rustc or rust-analyzer) +// to ensure that deref patterns don't appear in the same column as normal constructors. Deref +// patterns aren't currently implemented in rust-analyzer, but should they be, the columnwise check +// here could be made generic and shared between frontends. +fn detect_mixed_deref_pat_ctors<'p, 'tcx>( + cx: &RustcPatCtxt<'p, 'tcx>, + column: &PatternColumn<'p, RustcPatCtxt<'p, 'tcx>>, +) -> Result<(), ErrorGuaranteed> { + let Some(&ty) = column.head_ty() else { + return Ok(()); + }; + + // Check for a mix of deref patterns and normal constructors. + let mut normal_ctor_span = None; + let mut deref_pat_span = None; + for pat in column.iter() { + match pat.ctor() { + // The analysis can handle mixing deref patterns with wildcards and opaque patterns. + Wildcard | Opaque(_) => {} + DerefPattern(_) => deref_pat_span = Some(pat.data().span), + // Nothing else can be compared to deref patterns in `Constructor::is_covered_by`. + _ => normal_ctor_span = Some(pat.data().span), + } + } + if let Some(normal_constructor_label) = normal_ctor_span + && let Some(deref_pattern_label) = deref_pat_span + { + return Err(cx.tcx.dcx().emit_err(errors::MixedDerefPatternConstructors { + spans: vec![deref_pattern_label, normal_constructor_label], + smart_pointer_ty: ty.inner(), + deref_pattern_label, + normal_constructor_label, + })); + } + + // Specialize and recurse into the patterns' fields. + let set = column.analyze_ctors(cx, &ty)?; + for ctor in set.present { + for specialized_column in column.specialize(cx, &ty, &ctor).iter() { + detect_mixed_deref_pat_ctors(cx, specialized_column)?; + } + } + Ok(()) +} + struct RecursiveOpaque { def_id: DefId, } diff --git a/compiler/rustc_pattern_analysis/src/usefulness.rs b/compiler/rustc_pattern_analysis/src/usefulness.rs index 11ebbea07fa4..53638f2a57dd 100644 --- a/compiler/rustc_pattern_analysis/src/usefulness.rs +++ b/compiler/rustc_pattern_analysis/src/usefulness.rs @@ -702,6 +702,7 @@ //! - `ui/consts/const_in_pattern` //! - `ui/rfc-2008-non-exhaustive` //! - `ui/half-open-range-patterns` +//! - `ui/pattern/deref-patterns` //! - probably many others //! //! I (Nadrieril) prefer to put new tests in `ui/pattern/usefulness` unless there's a specific @@ -866,7 +867,8 @@ impl PlaceValidity { /// inside `&` and union fields where validity is reset to `MaybeInvalid`. fn specialize(self, ctor: &Constructor) -> Self { // We preserve validity except when we go inside a reference or a union field. - if matches!(ctor, Constructor::Ref | Constructor::UnionField) { + if matches!(ctor, Constructor::Ref | Constructor::DerefPattern(_) | Constructor::UnionField) + { // Validity of `x: &T` does not imply validity of `*x: T`. MaybeInvalid } else { diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index d11fa8bad9be..9fbbcdc75569 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -4,6 +4,7 @@ use std::num::NonZero; +use rustc_data_structures::jobserver::Proxy; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::{DynSend, DynSync}; use rustc_data_structures::unord::UnordMap; @@ -69,6 +70,11 @@ impl<'tcx> HasDepContext for QueryCtxt<'tcx> { impl<'tcx> QueryContext for QueryCtxt<'tcx> { type QueryInfo = QueryStackDeferred<'tcx>; + #[inline] + fn jobserver_proxy(&self) -> &Proxy { + &*self.jobserver_proxy + } + #[inline] fn next_job_id(self) -> QueryJobId { QueryJobId( diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index 0d56db160996..3ae56cef2c42 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -11,7 +11,7 @@ use rustc_data_structures::outline; use rustc_data_structures::profiling::QueryInvocationId; use rustc_data_structures::sharded::{self, ShardedHashMap}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_data_structures::sync::{AtomicU64, Lock}; +use rustc_data_structures::sync::{AtomicU64, Lock, is_dyn_thread_safe}; use rustc_data_structures::unord::UnordMap; use rustc_errors::DiagInner; use rustc_index::IndexVec; @@ -124,19 +124,11 @@ impl DepGraph { prev_graph: Arc, prev_work_products: WorkProductMap, encoder: FileEncoder, - record_graph: bool, - record_stats: bool, ) -> DepGraph { let prev_graph_node_count = prev_graph.node_count(); - let current = CurrentDepGraph::new( - session, - prev_graph_node_count, - encoder, - record_graph, - record_stats, - Arc::clone(&prev_graph), - ); + let current = + CurrentDepGraph::new(session, prev_graph_node_count, encoder, Arc::clone(&prev_graph)); let colors = DepNodeColorMap::new(prev_graph_node_count); @@ -1052,17 +1044,8 @@ impl DepGraph { } } - pub fn print_incremental_info(&self) { - if let Some(data) = &self.data { - data.current.encoder.print_incremental_info( - data.current.total_read_count.load(Ordering::Relaxed), - data.current.total_duplicate_read_count.load(Ordering::Relaxed), - ) - } - } - pub fn finish_encoding(&self) -> FileEncodeResult { - if let Some(data) = &self.data { data.current.encoder.finish() } else { Ok(0) } + if let Some(data) = &self.data { data.current.encoder.finish(&data.current) } else { Ok(0) } } pub(crate) fn next_virtual_depnode_index(&self) -> DepNodeIndex { @@ -1179,8 +1162,8 @@ pub(super) struct CurrentDepGraph { /// These are simple counters that are for profiling and /// debugging and only active with `debug_assertions`. - total_read_count: AtomicU64, - total_duplicate_read_count: AtomicU64, + pub(super) total_read_count: AtomicU64, + pub(super) total_duplicate_read_count: AtomicU64, } impl CurrentDepGraph { @@ -1188,8 +1171,6 @@ impl CurrentDepGraph { session: &Session, prev_graph_node_count: usize, encoder: FileEncoder, - record_graph: bool, - record_stats: bool, previous: Arc, ) -> Self { let mut stable_hasher = StableHasher::new(); @@ -1211,14 +1192,7 @@ impl CurrentDepGraph { session.opts.unstable_opts.incremental_verify_ich || cfg!(debug_assertions); CurrentDepGraph { - encoder: GraphEncoder::new( - encoder, - prev_graph_node_count, - record_graph, - record_stats, - &session.prof, - previous, - ), + encoder: GraphEncoder::new(session, encoder, prev_graph_node_count, previous), anon_node_to_index: ShardedHashMap::with_capacity( // FIXME: The count estimate is off as anon nodes are only a portion of the nodes. new_node_count_estimate / sharded::shards(), @@ -1345,6 +1319,7 @@ impl Default for TaskDeps { // array, using one u32 per entry. pub(super) struct DepNodeColorMap { values: IndexVec, + sync: bool, } const COMPRESSED_NONE: u32 = u32::MAX; @@ -1353,7 +1328,10 @@ const COMPRESSED_RED: u32 = u32::MAX - 1; impl DepNodeColorMap { fn new(size: usize) -> DepNodeColorMap { debug_assert!(COMPRESSED_RED > DepNodeIndex::MAX_AS_U32); - DepNodeColorMap { values: (0..size).map(|_| AtomicU32::new(COMPRESSED_NONE)).collect() } + DepNodeColorMap { + values: (0..size).map(|_| AtomicU32::new(COMPRESSED_NONE)).collect(), + sync: is_dyn_thread_safe(), + } } #[inline] @@ -1362,6 +1340,37 @@ impl DepNodeColorMap { if value <= DepNodeIndex::MAX_AS_U32 { Some(DepNodeIndex::from_u32(value)) } else { None } } + /// This tries to atomically mark a node green and assign `index` as the new + /// index. This returns `Ok` if `index` gets assigned, otherwise it returns + /// the alreadly allocated index in `Err`. + #[inline] + pub(super) fn try_mark_green( + &self, + prev_index: SerializedDepNodeIndex, + index: DepNodeIndex, + ) -> Result<(), DepNodeIndex> { + let value = &self.values[prev_index]; + if self.sync { + match value.compare_exchange( + COMPRESSED_NONE, + index.as_u32(), + Ordering::Relaxed, + Ordering::Relaxed, + ) { + Ok(_) => Ok(()), + Err(v) => Err(DepNodeIndex::from_u32(v)), + } + } else { + let v = value.load(Ordering::Relaxed); + if v == COMPRESSED_NONE { + value.store(index.as_u32(), Ordering::Relaxed); + Ok(()) + } else { + Err(DepNodeIndex::from_u32(v)) + } + } + } + #[inline] pub(super) fn get(&self, index: SerializedDepNodeIndex) -> Option { match self.values[index].load(Ordering::Acquire) { diff --git a/compiler/rustc_query_system/src/dep_graph/mod.rs b/compiler/rustc_query_system/src/dep_graph/mod.rs index 3a80835afad5..89d1db878095 100644 --- a/compiler/rustc_query_system/src/dep_graph/mod.rs +++ b/compiler/rustc_query_system/src/dep_graph/mod.rs @@ -12,6 +12,7 @@ pub(crate) use graph::DepGraphData; pub use graph::{DepGraph, DepNodeIndex, TaskDepsRef, WorkProduct, WorkProductMap, hash_result}; pub use query::DepGraphQuery; use rustc_data_structures::profiling::SelfProfilerRef; +use rustc_data_structures::sync::DynSync; use rustc_session::Session; pub use serialized::{SerializedDepGraph, SerializedDepNodeIndex}; use tracing::instrument; @@ -89,7 +90,7 @@ pub trait DepContext: Copy { } } -pub trait Deps { +pub trait Deps: DynSync { /// Execute the operation with provided dependencies. fn with_deps(deps: TaskDepsRef<'_>, op: OP) -> R where diff --git a/compiler/rustc_query_system/src/dep_graph/query.rs b/compiler/rustc_query_system/src/dep_graph/query.rs index 624f4e4578ed..724a01327aba 100644 --- a/compiler/rustc_query_system/src/dep_graph/query.rs +++ b/compiler/rustc_query_system/src/dep_graph/query.rs @@ -1,11 +1,11 @@ use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::graph::implementation::{Direction, Graph, INCOMING, NodeIndex}; +use rustc_data_structures::graph::linked_graph::{Direction, INCOMING, LinkedGraph, NodeIndex}; use rustc_index::IndexVec; use super::{DepNode, DepNodeIndex}; pub struct DepGraphQuery { - pub graph: Graph, + pub graph: LinkedGraph, pub indices: FxHashMap, pub dep_index_to_index: IndexVec>, } @@ -15,7 +15,7 @@ impl DepGraphQuery { let node_count = prev_node_count + prev_node_count / 4; let edge_count = 6 * node_count; - let graph = Graph::with_capacity(node_count, edge_count); + let graph = LinkedGraph::with_capacity(node_count, edge_count); let indices = FxHashMap::default(); let dep_index_to_index = IndexVec::new(); diff --git a/compiler/rustc_query_system/src/dep_graph/serialized.rs b/compiler/rustc_query_system/src/dep_graph/serialized.rs index d2bcde143835..f1b609a3ca90 100644 --- a/compiler/rustc_query_system/src/dep_graph/serialized.rs +++ b/compiler/rustc_query_system/src/dep_graph/serialized.rs @@ -12,7 +12,7 @@ //! node and edge count are stored at the end of the file, all the arrays can be //! pre-allocated with the right length. //! -//! The encoding of the de-pgraph is generally designed around the fact that fixed-size +//! The encoding of the dep-graph is generally designed around the fact that fixed-size //! reads of encoded data are generally faster than variable-sized reads. Ergo we adopt //! essentially the same varint encoding scheme used in the rmeta format; the edge lists //! for each node on the graph store a 2-bit integer which is the number of bytes per edge @@ -34,24 +34,32 @@ //! [`DepKind`], number of edges, and bytes per edge are all bit-packed together, if they fit. //! If the number of edges in this node does not fit in the bits available in the header, we //! store it directly after the header with leb128. +//! +//! Dep-graph indices are bulk allocated to threads inside `LocalEncoderState`. Having threads +//! own these indices helps avoid races when they are conditionally used when marking nodes green. +//! It also reduces congestion on the shared index count. -use std::iter; +use std::cell::RefCell; +use std::cmp::max; use std::marker::PhantomData; use std::sync::Arc; +use std::sync::atomic::Ordering; +use std::{iter, mem, u64}; use rustc_data_structures::fingerprint::{Fingerprint, PackedFingerprint}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::outline; use rustc_data_structures::profiling::SelfProfilerRef; -use rustc_data_structures::sync::Lock; +use rustc_data_structures::sync::{AtomicU64, Lock, WorkerLocal, broadcast}; use rustc_data_structures::unhash::UnhashMap; -use rustc_index::{Idx, IndexVec}; +use rustc_index::IndexVec; use rustc_serialize::opaque::mem_encoder::MemEncoder; use rustc_serialize::opaque::{FileEncodeResult, FileEncoder, IntEncodedWithFixedSize, MemDecoder}; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; +use rustc_session::Session; use tracing::{debug, instrument}; -use super::graph::{DepNodeColor, DepNodeColorMap}; +use super::graph::{CurrentDepGraph, DepNodeColor, DepNodeColorMap}; use super::query::DepGraphQuery; use super::{DepKind, DepNode, DepNodeIndex, Deps}; use crate::dep_graph::edges::EdgesVec; @@ -76,6 +84,9 @@ const DEP_NODE_PAD: usize = DEP_NODE_SIZE - 1; const DEP_NODE_WIDTH_BITS: usize = DEP_NODE_SIZE / 2; /// Data for use when recompiling the **current crate**. +/// +/// There may be unused indices with DEP_KIND_NULL in this graph due to batch allocation of +/// indices to threads. #[derive(Debug, Default)] pub struct SerializedDepGraph { /// The set of all DepNodes in the graph @@ -184,26 +195,30 @@ impl SerializedDepGraph { pub fn decode(d: &mut MemDecoder<'_>, deps: &D) -> Arc { // The last 16 bytes are the node count and edge count. debug!("position: {:?}", d.position()); - let (node_count, edge_count) = - d.with_position(d.len() - 2 * IntEncodedWithFixedSize::ENCODED_SIZE, |d| { + + // `node_max` is the number of indices including empty nodes while `node_count` + // is the number of actually encoded nodes. + let (node_max, node_count, edge_count) = + d.with_position(d.len() - 3 * IntEncodedWithFixedSize::ENCODED_SIZE, |d| { debug!("position: {:?}", d.position()); + let node_max = IntEncodedWithFixedSize::decode(d).0 as usize; let node_count = IntEncodedWithFixedSize::decode(d).0 as usize; let edge_count = IntEncodedWithFixedSize::decode(d).0 as usize; - (node_count, edge_count) + (node_max, node_count, edge_count) }); debug!("position: {:?}", d.position()); debug!(?node_count, ?edge_count); - let graph_bytes = d.len() - (2 * IntEncodedWithFixedSize::ENCODED_SIZE) - d.position(); + let graph_bytes = d.len() - (3 * IntEncodedWithFixedSize::ENCODED_SIZE) - d.position(); let mut nodes = IndexVec::from_elem_n( DepNode { kind: D::DEP_KIND_NULL, hash: PackedFingerprint::from(Fingerprint::ZERO) }, - node_count, + node_max, ); - let mut fingerprints = IndexVec::from_elem_n(Fingerprint::ZERO, node_count); + let mut fingerprints = IndexVec::from_elem_n(Fingerprint::ZERO, node_max); let mut edge_list_indices = - IndexVec::from_elem_n(EdgeHeader { repr: 0, num_edges: 0 }, node_count); + IndexVec::from_elem_n(EdgeHeader { repr: 0, num_edges: 0 }, node_max); // This estimation assumes that all of the encoded bytes are for the edge lists or for the // fixed-size node headers. But that's not necessarily true; if any edge list has a length @@ -217,7 +232,7 @@ impl SerializedDepGraph { let mut edge_list_data = Vec::with_capacity(graph_bytes - node_count * size_of::>()); - for _index in 0..node_count { + for _ in 0..node_count { // Decode the header for this edge; the header packs together as many of the fixed-size // fields as possible to limit the number of times we update decoder state. let node_header = @@ -263,8 +278,8 @@ impl SerializedDepGraph { for (idx, node) in nodes.iter_enumerated() { if index[node.kind.as_usize()].insert(node.hash, idx).is_some() { - // Side effect nodes can have duplicates - if node.kind != D::DEP_KIND_SIDE_EFFECT { + // Empty nodes and side effect nodes can have duplicates + if node.kind != D::DEP_KIND_NULL && node.kind != D::DEP_KIND_SIDE_EFFECT { let name = deps.name(node.kind); panic!( "Error: A dep graph node ({name}) does not have an unique index. \ @@ -508,17 +523,32 @@ struct Stat { edge_counter: u64, } -struct EncoderState { - previous: Arc, - encoder: FileEncoder, - total_node_count: usize, - total_edge_count: usize, - stats: Option>, - - mem_encoder: MemEncoder, +struct LocalEncoderState { + next_node_index: u32, + remaining_node_index: u32, + encoder: MemEncoder, + node_count: usize, + edge_count: usize, /// Stores the number of times we've encoded each dep kind. kind_stats: Vec, +} + +struct LocalEncoderResult { + node_max: u32, + node_count: usize, + edge_count: usize, + + /// Stores the number of times we've encoded each dep kind. + kind_stats: Vec, +} + +struct EncoderState { + next_node_index: AtomicU64, + previous: Arc, + file: Lock>, + local: WorkerLocal>, + stats: Option>>, marker: PhantomData, } @@ -526,34 +556,63 @@ impl EncoderState { fn new(encoder: FileEncoder, record_stats: bool, previous: Arc) -> Self { Self { previous, - encoder, - total_edge_count: 0, - total_node_count: 0, - stats: record_stats.then(FxHashMap::default), - mem_encoder: MemEncoder::new(), - kind_stats: iter::repeat(0).take(D::DEP_KIND_MAX as usize + 1).collect(), + next_node_index: AtomicU64::new(0), + stats: record_stats.then(|| Lock::new(FxHashMap::default())), + file: Lock::new(Some(encoder)), + local: WorkerLocal::new(|_| { + RefCell::new(LocalEncoderState { + next_node_index: 0, + remaining_node_index: 0, + edge_count: 0, + node_count: 0, + encoder: MemEncoder::new(), + kind_stats: iter::repeat(0).take(D::DEP_KIND_MAX as usize + 1).collect(), + }) + }), marker: PhantomData, } } #[inline] - fn alloc_index(&mut self) -> DepNodeIndex { - let index = DepNodeIndex::new(self.total_node_count); - self.total_node_count += 1; - index + fn next_index(&self, local: &mut LocalEncoderState) -> DepNodeIndex { + if local.remaining_node_index == 0 { + const COUNT: u32 = 256; + + // We assume that there won't be enough active threads to overflow `u64` from `u32::MAX` here. + // This can exceed u32::MAX by at most `N` * `COUNT` where `N` is the thread pool count since + // `try_into().unwrap()` will make threads panic when `self.next_node_index` exceeds u32::MAX. + local.next_node_index = + self.next_node_index.fetch_add(COUNT as u64, Ordering::Relaxed).try_into().unwrap(); + + // Check that we'll stay within `u32` + local.next_node_index.checked_add(COUNT).unwrap(); + + local.remaining_node_index = COUNT; + } + + DepNodeIndex::from_u32(local.next_node_index) + } + + /// Marks the index previously returned by `next_index` as used. + #[inline] + fn bump_index(&self, local: &mut LocalEncoderState) { + local.remaining_node_index -= 1; + local.next_node_index += 1; + local.node_count += 1; } #[inline] fn record( - &mut self, + &self, node: DepNode, index: DepNodeIndex, edge_count: usize, - edges: impl FnOnce(&mut Self) -> Vec, + edges: impl FnOnce(&Self) -> Vec, record_graph: &Option>, - ) -> DepNodeIndex { - self.kind_stats[node.kind.as_usize()] += 1; - self.total_edge_count += edge_count; + local: &mut LocalEncoderState, + ) { + local.kind_stats[node.kind.as_usize()] += 1; + local.edge_count += edge_count; if let Some(record_graph) = &record_graph { // Call `edges` before the outlined code to allow the closure to be optimized out. @@ -568,40 +627,47 @@ impl EncoderState { }); } - if let Some(stats) = &mut self.stats { + if let Some(stats) = &self.stats { let kind = node.kind; // Outline the stats code as it's typically disabled and cold. outline(move || { + let mut stats = stats.lock(); let stat = stats.entry(kind).or_insert(Stat { kind, node_counter: 0, edge_counter: 0 }); stat.node_counter += 1; stat.edge_counter += edge_count as u64; }); } - - index } #[inline] - fn flush_mem_encoder(&mut self) { - let data = &mut self.mem_encoder.data; + fn flush_mem_encoder(&self, local: &mut LocalEncoderState) { + let data = &mut local.encoder.data; if data.len() > 64 * 1024 { - self.encoder.emit_raw_bytes(&data[..]); + self.file.lock().as_mut().unwrap().emit_raw_bytes(&data[..]); data.clear(); } } /// Encodes a node to the current graph. fn encode_node( - &mut self, + &self, + index: DepNodeIndex, node: &NodeInfo, record_graph: &Option>, - ) -> DepNodeIndex { - let index = self.alloc_index(); - node.encode::(&mut self.mem_encoder, index); - self.flush_mem_encoder(); - self.record(node.node, index, node.edges.len(), |_| node.edges[..].to_vec(), record_graph) + local: &mut LocalEncoderState, + ) { + node.encode::(&mut local.encoder, index); + self.flush_mem_encoder(&mut *local); + self.record( + node.node, + index, + node.edges.len(), + |_| node.edges[..].to_vec(), + record_graph, + &mut *local, + ); } /// Encodes a node that was promoted from the previous graph. It reads the information directly from @@ -612,16 +678,17 @@ impl EncoderState { /// It expects all edges to already have a new dep node index assigned. #[inline] fn encode_promoted_node( - &mut self, + &self, + index: DepNodeIndex, prev_index: SerializedDepNodeIndex, record_graph: &Option>, colors: &DepNodeColorMap, - ) -> DepNodeIndex { - let index = self.alloc_index(); + local: &mut LocalEncoderState, + ) { let node = self.previous.index_to_node(prev_index); let fingerprint = self.previous.fingerprint_by_index(prev_index); let edge_count = NodeInfo::encode_promoted::( - &mut self.mem_encoder, + &mut local.encoder, node, index, fingerprint, @@ -629,7 +696,7 @@ impl EncoderState { colors, &self.previous, ); - self.flush_mem_encoder(); + self.flush_mem_encoder(&mut *local); self.record( node, index, @@ -641,38 +708,60 @@ impl EncoderState { .collect() }, record_graph, + &mut *local, ); - index } - fn finish(self, profiler: &SelfProfilerRef) -> FileEncodeResult { - let Self { - mut encoder, - mem_encoder, - total_node_count, - total_edge_count, - stats: _, - kind_stats, - marker: _, - previous, - } = self; + fn finish(&self, profiler: &SelfProfilerRef, current: &CurrentDepGraph) -> FileEncodeResult { + // Prevent more indices from being allocated. + self.next_node_index.store(u32::MAX as u64 + 1, Ordering::SeqCst); - encoder.emit_raw_bytes(&mem_encoder.data); + let results = broadcast(|_| { + let mut local = self.local.borrow_mut(); - let node_count = total_node_count.try_into().unwrap(); - let edge_count = total_edge_count.try_into().unwrap(); + // Prevent more indices from being allocated on this thread. + local.remaining_node_index = 0; + + let data = mem::replace(&mut local.encoder.data, Vec::new()); + self.file.lock().as_mut().unwrap().emit_raw_bytes(&data); + + LocalEncoderResult { + kind_stats: local.kind_stats.clone(), + node_max: local.next_node_index, + node_count: local.node_count, + edge_count: local.edge_count, + } + }); + + let mut encoder = self.file.lock().take().unwrap(); + + let mut kind_stats: Vec = iter::repeat(0).take(D::DEP_KIND_MAX as usize + 1).collect(); + + let mut node_max = 0; + let mut node_count = 0; + let mut edge_count = 0; + + for result in results { + node_max = max(node_max, result.node_max); + node_count += result.node_count; + edge_count += result.edge_count; + for (i, stat) in result.kind_stats.iter().enumerate() { + kind_stats[i] += stat; + } + } // Encode the number of each dep kind encountered for count in kind_stats.iter() { count.encode(&mut encoder); } - previous.session_count.checked_add(1).unwrap().encode(&mut encoder); + self.previous.session_count.checked_add(1).unwrap().encode(&mut encoder); - debug!(?node_count, ?edge_count); + debug!(?node_max, ?node_count, ?edge_count); debug!("position: {:?}", encoder.position()); - IntEncodedWithFixedSize(node_count).encode(&mut encoder); - IntEncodedWithFixedSize(edge_count).encode(&mut encoder); + IntEncodedWithFixedSize(node_max.try_into().unwrap()).encode(&mut encoder); + IntEncodedWithFixedSize(node_count.try_into().unwrap()).encode(&mut encoder); + IntEncodedWithFixedSize(edge_count.try_into().unwrap()).encode(&mut encoder); debug!("position: {:?}", encoder.position()); // Drop the encoder so that nothing is written after the counts. let result = encoder.finish(); @@ -681,44 +770,20 @@ impl EncoderState { // don't need a dependency on rustc_incremental just for that. profiler.artifact_size("dep_graph", "dep-graph.bin", position as u64); } + + self.print_incremental_info(current, node_count, edge_count); + result } -} -pub(crate) struct GraphEncoder { - profiler: SelfProfilerRef, - status: Lock>>, - record_graph: Option>, -} - -impl GraphEncoder { - pub(crate) fn new( - encoder: FileEncoder, - prev_node_count: usize, - record_graph: bool, - record_stats: bool, - profiler: &SelfProfilerRef, - previous: Arc, - ) -> Self { - let record_graph = record_graph.then(|| Lock::new(DepGraphQuery::new(prev_node_count))); - let status = Lock::new(Some(EncoderState::new(encoder, record_stats, previous))); - GraphEncoder { status, record_graph, profiler: profiler.clone() } - } - - pub(crate) fn with_query(&self, f: impl Fn(&DepGraphQuery)) { - if let Some(record_graph) = &self.record_graph { - f(&record_graph.lock()) - } - } - - pub(crate) fn print_incremental_info( + fn print_incremental_info( &self, - total_read_count: u64, - total_duplicate_read_count: u64, + current: &CurrentDepGraph, + total_node_count: usize, + total_edge_count: usize, ) { - let mut status = self.status.lock(); - let status = status.as_mut().unwrap(); - if let Some(record_stats) = &status.stats { + if let Some(record_stats) = &self.stats { + let record_stats = record_stats.lock(); let mut stats: Vec<_> = record_stats.values().collect(); stats.sort_by_key(|s| -(s.node_counter as i64)); @@ -730,10 +795,13 @@ impl GraphEncoder { eprintln!("[incremental] DepGraph Statistics"); eprintln!("{SEPARATOR}"); eprintln!("[incremental]"); - eprintln!("[incremental] Total Node Count: {}", status.total_node_count); - eprintln!("[incremental] Total Edge Count: {}", status.total_edge_count); + eprintln!("[incremental] Total Node Count: {}", total_node_count); + eprintln!("[incremental] Total Edge Count: {}", total_edge_count); if cfg!(debug_assertions) { + let total_read_count = current.total_read_count.load(Ordering::Relaxed); + let total_duplicate_read_count = + current.total_duplicate_read_count.load(Ordering::Relaxed); eprintln!("[incremental] Total Edge Reads: {total_read_count}"); eprintln!("[incremental] Total Duplicate Edge Reads: {total_duplicate_read_count}"); } @@ -747,7 +815,7 @@ impl GraphEncoder { for stat in stats { let node_kind_ratio = - (100.0 * (stat.node_counter as f64)) / (status.total_node_count as f64); + (100.0 * (stat.node_counter as f64)) / (total_node_count as f64); let node_kind_avg_edges = (stat.edge_counter as f64) / (stat.node_counter as f64); eprintln!( @@ -763,6 +831,35 @@ impl GraphEncoder { eprintln!("[incremental]"); } } +} + +pub(crate) struct GraphEncoder { + profiler: SelfProfilerRef, + status: EncoderState, + record_graph: Option>, +} + +impl GraphEncoder { + pub(crate) fn new( + sess: &Session, + encoder: FileEncoder, + prev_node_count: usize, + previous: Arc, + ) -> Self { + let record_graph = sess + .opts + .unstable_opts + .query_dep_graph + .then(|| Lock::new(DepGraphQuery::new(prev_node_count))); + let status = EncoderState::new(encoder, sess.opts.unstable_opts.incremental_info, previous); + GraphEncoder { status, record_graph, profiler: sess.prof.clone() } + } + + pub(crate) fn with_query(&self, f: impl Fn(&DepGraphQuery)) { + if let Some(record_graph) = &self.record_graph { + f(&record_graph.lock()) + } + } /// Encodes a node that does not exists in the previous graph. pub(crate) fn send_new( @@ -773,7 +870,11 @@ impl GraphEncoder { ) -> DepNodeIndex { let _prof_timer = self.profiler.generic_activity("incr_comp_encode_dep_graph"); let node = NodeInfo { node, fingerprint, edges }; - self.status.lock().as_mut().unwrap().encode_node(&node, &self.record_graph) + let mut local = self.status.local.borrow_mut(); + let index = self.status.next_index(&mut *local); + self.status.bump_index(&mut *local); + self.status.encode_node(index, &node, &self.record_graph, &mut *local); + index } /// Encodes a node that exists in the previous graph, but was re-executed. @@ -791,23 +892,24 @@ impl GraphEncoder { let _prof_timer = self.profiler.generic_activity("incr_comp_encode_dep_graph"); let node = NodeInfo { node, fingerprint, edges }; - let mut status = self.status.lock(); - let status = status.as_mut().unwrap(); + let mut local = self.status.local.borrow_mut(); - // Check colors inside the lock to avoid racing when `send_promoted` is called concurrently - // on the same index. - match colors.get(prev_index) { - None => { - let dep_node_index = status.encode_node(&node, &self.record_graph); - colors.insert( - prev_index, - if is_green { DepNodeColor::Green(dep_node_index) } else { DepNodeColor::Red }, - ); - dep_node_index + let index = self.status.next_index(&mut *local); + + if is_green { + // Use `try_mark_green` to avoid racing when `send_promoted` is called concurrently + // on the same index. + match colors.try_mark_green(prev_index, index) { + Ok(()) => (), + Err(dep_node_index) => return dep_node_index, } - Some(DepNodeColor::Green(dep_node_index)) => dep_node_index, - Some(DepNodeColor::Red) => panic!(), + } else { + colors.insert(prev_index, DepNodeColor::Red); } + + self.status.bump_index(&mut *local); + self.status.encode_node(index, &node, &self.record_graph, &mut *local); + index } /// Encodes a node that was promoted from the previous graph. It reads the information directly from @@ -822,26 +924,30 @@ impl GraphEncoder { ) -> DepNodeIndex { let _prof_timer = self.profiler.generic_activity("incr_comp_encode_dep_graph"); - let mut status = self.status.lock(); - let status = status.as_mut().unwrap(); + let mut local = self.status.local.borrow_mut(); + let index = self.status.next_index(&mut *local); - // Check colors inside the lock to avoid racing when `send_promoted` or `send_and_color` + // Use `try_mark_green` to avoid racing when `send_promoted` or `send_and_color` // is called concurrently on the same index. - match colors.get(prev_index) { - None => { - let dep_node_index = - status.encode_promoted_node(prev_index, &self.record_graph, colors); - colors.insert(prev_index, DepNodeColor::Green(dep_node_index)); - dep_node_index + match colors.try_mark_green(prev_index, index) { + Ok(()) => { + self.status.bump_index(&mut *local); + self.status.encode_promoted_node( + index, + prev_index, + &self.record_graph, + colors, + &mut *local, + ); + index } - Some(DepNodeColor::Green(dep_node_index)) => dep_node_index, - Some(DepNodeColor::Red) => panic!(), + Err(dep_node_index) => dep_node_index, } } - pub(crate) fn finish(&self) -> FileEncodeResult { + pub(crate) fn finish(&self, current: &CurrentDepGraph) -> FileEncodeResult { let _prof_timer = self.profiler.generic_activity("incr_comp_encode_dep_graph_finish"); - self.status.lock().take().unwrap().finish(&self.profiler) + self.status.finish(&self.profiler, current) } } diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs index de35cd79ea27..6321abc5087f 100644 --- a/compiler/rustc_query_system/src/query/job.rs +++ b/compiler/rustc_query_system/src/query/job.rs @@ -7,7 +7,6 @@ use std::sync::Arc; use parking_lot::{Condvar, Mutex}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_data_structures::jobserver; use rustc_errors::{Diag, DiagCtxtHandle}; use rustc_hir::def::DefKind; use rustc_session::Session; @@ -207,12 +206,13 @@ impl QueryLatch { /// Awaits for the query job to complete. pub(super) fn wait_on( &self, + qcx: impl QueryContext, query: Option, span: Span, ) -> Result<(), CycleError> { let waiter = Arc::new(QueryWaiter { query, span, cycle: Mutex::new(None), condvar: Condvar::new() }); - self.wait_on_inner(&waiter); + self.wait_on_inner(qcx, &waiter); // FIXME: Get rid of this lock. We have ownership of the QueryWaiter // although another thread may still have a Arc reference so we cannot // use Arc::get_mut @@ -224,7 +224,7 @@ impl QueryLatch { } /// Awaits the caller on this latch by blocking the current thread. - fn wait_on_inner(&self, waiter: &Arc>) { + fn wait_on_inner(&self, qcx: impl QueryContext, waiter: &Arc>) { let mut info = self.info.lock(); if !info.complete { // We push the waiter on to the `waiters` list. It can be accessed inside @@ -237,11 +237,12 @@ impl QueryLatch { // we have to be in the `wait` call. This is ensured by the deadlock handler // getting the self.info lock. rayon_core::mark_blocked(); - jobserver::release_thread(); + let proxy = qcx.jobserver_proxy(); + proxy.release_thread(); waiter.condvar.wait(&mut info); // Release the lock before we potentially block in `acquire_thread` drop(info); - jobserver::acquire_thread(); + proxy.acquire_thread(); } } diff --git a/compiler/rustc_query_system/src/query/mod.rs b/compiler/rustc_query_system/src/query/mod.rs index ef21af7dafba..855769dacc3e 100644 --- a/compiler/rustc_query_system/src/query/mod.rs +++ b/compiler/rustc_query_system/src/query/mod.rs @@ -16,6 +16,7 @@ mod caches; pub use self::caches::{DefIdCache, DefaultCache, QueryCache, SingleCache, VecCache}; mod config; +use rustc_data_structures::jobserver::Proxy; use rustc_data_structures::sync::{DynSend, DynSync}; use rustc_errors::DiagInner; use rustc_hashes::Hash64; @@ -151,6 +152,10 @@ pub enum QuerySideEffect { pub trait QueryContext: HasDepContext { type QueryInfo: Clone; + /// Gets a jobserver reference which is used to release then acquire + /// a token while waiting on a query. + fn jobserver_proxy(&self) -> &Proxy; + fn next_job_id(self) -> QueryJobId; /// Get the query information from the TLS context. diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs index 6ea8e3b92008..3c1fc7317848 100644 --- a/compiler/rustc_query_system/src/query/plumbing.rs +++ b/compiler/rustc_query_system/src/query/plumbing.rs @@ -297,7 +297,7 @@ where // With parallel queries we might just have to wait on some other // thread. - let result = latch.wait_on(current, span); + let result = latch.wait_on(qcx, current, span); match result { Ok(()) => { diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl index 558a01713dc7..38cdfa72a14d 100644 --- a/compiler/rustc_resolve/messages.ftl +++ b/compiler/rustc_resolve/messages.ftl @@ -218,10 +218,6 @@ resolve_invalid_asm_sym = .label = is a local variable .help = `sym` operands must refer to either a function or a static -resolve_is_not_directly_importable = - `{$target}` is not directly importable - .label = cannot be imported directly - resolve_is_private = {$ident_descr} `{$ident}` is private .label = private {$ident_descr} @@ -231,9 +227,6 @@ resolve_item_was_behind_feature = resolve_item_was_cfg_out = the item is gated here -resolve_items_in_traits_are_not_importable = - items in traits are not importable - resolve_label_with_similar_name_reachable = a label with a similar name is reachable diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 363a75911ad4..74daad083946 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1181,11 +1181,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } { let in_module_is_extern = !in_module.def_id().is_local(); in_module.for_each_child(self, |this, ident, ns, name_binding| { - // avoid non-importable candidates - if !name_binding.is_importable() - // FIXME(import_trait_associated_functions): remove this when `import_trait_associated_functions` is stable - || name_binding.is_assoc_const_or_fn() - && !this.tcx.features().import_trait_associated_functions() + // Avoid non-importable candidates. + if name_binding.is_assoc_item() + && !this.tcx.features().import_trait_associated_functions() { return; } diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index e26b300f13ef..7fe74378b674 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -781,22 +781,6 @@ pub(crate) struct CannotGlobImportAllCrates { pub(crate) span: Span, } -#[derive(Diagnostic)] -#[diag(resolve_items_in_traits_are_not_importable)] -pub(crate) struct ItemsInTraitsAreNotImportable { - #[primary_span] - pub(crate) span: Span, -} - -#[derive(Diagnostic)] -#[diag(resolve_is_not_directly_importable, code = E0253)] -pub(crate) struct IsNotDirectlyImportable { - #[primary_span] - #[label] - pub(crate) span: Span, - pub(crate) target: Ident, -} - #[derive(Subdiagnostic)] #[suggestion( resolve_unexpected_res_change_ty_to_const_param_sugg, diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 762e08b2be5f..816efd0d5fa2 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -30,8 +30,7 @@ use crate::diagnostics::{DiagMode, Suggestion, import_candidates}; use crate::errors::{ CannotBeReexportedCratePublic, CannotBeReexportedCratePublicNS, CannotBeReexportedPrivate, CannotBeReexportedPrivateNS, CannotDetermineImportResolution, CannotGlobImportAllCrates, - ConsiderAddingMacroExport, ConsiderMarkingAsPub, IsNotDirectlyImportable, - ItemsInTraitsAreNotImportable, + ConsiderAddingMacroExport, ConsiderMarkingAsPub, }; use crate::{ AmbiguityError, AmbiguityKind, BindingKey, Finalize, ImportSuggestion, Module, @@ -835,11 +834,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let parent = import.parent_scope.module; match source_bindings[ns].get() { - Err(Undetermined) => indeterminate_count += 1, - // Don't update the resolution, because it was never added. - Err(Determined) if target.name == kw::Underscore => {} - Ok(binding) if binding.is_importable() => { - if binding.is_assoc_const_or_fn() + Ok(binding) => { + if binding.is_assoc_item() && !this.tcx.features().import_trait_associated_functions() { feature_err( @@ -850,21 +846,21 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ) .emit(); } + let imported_binding = this.import(binding, import); target_bindings[ns].set(Some(imported_binding)); this.define(parent, target, ns, imported_binding); } - source_binding @ (Ok(..) | Err(Determined)) => { - if source_binding.is_ok() { - this.dcx() - .create_err(IsNotDirectlyImportable { span: import.span, target }) - .emit(); + Err(Determined) => { + // Don't update the resolution for underscores, because it was never added. + if target.name != kw::Underscore { + let key = BindingKey::new(target, ns); + this.update_resolution(parent, key, false, |_, resolution| { + resolution.single_imports.swap_remove(&import); + }); } - let key = BindingKey::new(target, ns); - this.update_resolution(parent, key, false, |_, resolution| { - resolution.single_imports.swap_remove(&import); - }); } + Err(Undetermined) => indeterminate_count += 1, } } }); @@ -1428,10 +1424,17 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { return; }; - if module.is_trait() { - self.dcx().emit_err(ItemsInTraitsAreNotImportable { span: import.span }); - return; - } else if module == import.parent_scope.module { + if module.is_trait() && !self.tcx.features().import_trait_associated_functions() { + feature_err( + self.tcx.sess, + sym::import_trait_associated_functions, + import.span, + "`use` associated items of traits is unstable", + ) + .emit(); + } + + if module == import.parent_scope.module { return; } else if is_prelude { self.prelude = Some(module); diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index d2da3ac7d86f..7e516d82df1d 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -56,6 +56,7 @@ use rustc_hir::def::{ self, CtorOf, DefKind, DocLinkResMap, LifetimeRes, NonMacroAttrKind, PartialRes, PerNS, }; use rustc_hir::def_id::{CRATE_DEF_ID, CrateNum, DefId, LOCAL_CRATE, LocalDefId, LocalDefIdMap}; +use rustc_hir::definitions::DisambiguatorState; use rustc_hir::{PrimTy, TraitCandidate}; use rustc_metadata::creader::{CStore, CrateLoader}; use rustc_middle::metadata::ModChild; @@ -949,14 +950,8 @@ impl<'ra> NameBindingData<'ra> { } } - fn is_importable(&self) -> bool { - !matches!(self.res(), Res::Def(DefKind::AssocTy, _)) - } - - // FIXME(import_trait_associated_functions): associate `const` or `fn` are not importable unless - // the feature `import_trait_associated_functions` is enable - fn is_assoc_const_or_fn(&self) -> bool { - matches!(self.res(), Res::Def(DefKind::AssocConst | DefKind::AssocFn, _)) + fn is_assoc_item(&self) -> bool { + matches!(self.res(), Res::Def(DefKind::AssocConst | DefKind::AssocFn | DefKind::AssocTy, _)) } fn macro_kind(&self) -> Option { @@ -1104,7 +1099,7 @@ pub struct Resolver<'ra, 'tcx> { underscore_disambiguator: u32, /// Maps glob imports to the names of items actually imported. - glob_map: FxHashMap>, + glob_map: FxIndexMap>, glob_error: Option, visibilities_for_hashing: Vec<(LocalDefId, ty::Visibility)>, used_imports: FxHashSet, @@ -1185,6 +1180,8 @@ pub struct Resolver<'ra, 'tcx> { node_id_to_def_id: NodeMap>, + disambiguator: DisambiguatorState, + /// Indices of unnamed struct or variant fields with unresolved attributes. placeholder_field_indices: FxHashMap, /// When collecting definitions from an AST fragment produced by a macro invocation `ExpnId` @@ -1348,7 +1345,7 @@ impl<'tcx> Resolver<'_, 'tcx> { ); // FIXME: remove `def_span` body, pass in the right spans here and call `tcx.at().create_def()` - let feed = self.tcx.create_def(parent, name, def_kind); + let feed = self.tcx.create_def(parent, name, def_kind, None, &mut self.disambiguator); let def_id = feed.def_id(); // Create the definition. @@ -1562,6 +1559,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { lint_buffer: LintBuffer::default(), next_node_id: CRATE_NODE_ID, node_id_to_def_id, + disambiguator: DisambiguatorState::new(), placeholder_field_indices: Default::default(), invocation_parents, legacy_const_generic_args: Default::default(), @@ -1691,6 +1689,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { .into_items() .map(|(k, f)| (k, f.key())) .collect(), + disambiguator: self.disambiguator, trait_map: self.trait_map, lifetime_elision_allowed: self.lifetime_elision_allowed, lint_buffer: Steal::new(self.lint_buffer), diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs index 4b1b3903e403..f7f354d12e8c 100644 --- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs +++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs @@ -717,12 +717,13 @@ fn encode_ty_name(tcx: TyCtxt<'_>, def_id: DefId) -> String { hir::definitions::DefPathData::AnonConst => "k", hir::definitions::DefPathData::OpaqueTy => "i", hir::definitions::DefPathData::SyntheticCoroutineBody => "s", + hir::definitions::DefPathData::NestedStatic => "n", hir::definitions::DefPathData::CrateRoot | hir::definitions::DefPathData::Use | hir::definitions::DefPathData::GlobalAsm | hir::definitions::DefPathData::MacroNs(..) | hir::definitions::DefPathData::LifetimeNs(..) - | hir::definitions::DefPathData::AnonAssocTy => { + | hir::definitions::DefPathData::AnonAssocTy(..) => { bug!("encode_ty_name: unexpected `{:?}`", disambiguated_data.data); } }); diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index e2d36f6a4e2f..60e1b465ba96 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -24,7 +24,8 @@ use rustc_macros::{Decodable, Encodable, HashStable_Generic}; use rustc_span::edition::{DEFAULT_EDITION, EDITION_NAME_LIST, Edition, LATEST_STABLE_EDITION}; use rustc_span::source_map::FilePathMapping; use rustc_span::{ - FileName, FileNameDisplayPreference, RealFileName, SourceFileHashAlgorithm, Symbol, sym, + FileName, FileNameDisplayPreference, FileNameEmbeddablePreference, RealFileName, + SourceFileHashAlgorithm, Symbol, sym, }; use rustc_target::spec::{ FramePointer, LinkSelfContainedComponents, LinkerFeatures, SplitDebuginfo, Target, TargetTuple, @@ -1169,6 +1170,10 @@ impl OutputFilenames { .unwrap_or_else(|| OutFileName::Real(self.output_path(flavor))) } + pub fn interface_path(&self) -> PathBuf { + self.out_directory.join(format!("lib{}.rs", self.crate_stem)) + } + /// Gets the output path where a compilation artifact of the given type /// should be placed on disk. fn output_path(&self, flavor: OutputType) -> PathBuf { @@ -1316,6 +1321,11 @@ fn file_path_mapping( } else { FileNameDisplayPreference::Local }, + if unstable_opts.remap_path_scope.is_all() { + FileNameEmbeddablePreference::RemappedOnly + } else { + FileNameEmbeddablePreference::LocalAndRemapped + }, ) } @@ -1452,13 +1462,17 @@ pub enum CrateType { Staticlib, Cdylib, ProcMacro, + Sdylib, } impl CrateType { pub fn has_metadata(self) -> bool { match self { CrateType::Rlib | CrateType::Dylib | CrateType::ProcMacro => true, - CrateType::Executable | CrateType::Cdylib | CrateType::Staticlib => false, + CrateType::Executable + | CrateType::Cdylib + | CrateType::Staticlib + | CrateType::Sdylib => false, } } } @@ -2818,6 +2832,7 @@ pub fn parse_crate_types_from_list(list_list: Vec) -> Result CrateType::Cdylib, "bin" => CrateType::Executable, "proc-macro" => CrateType::ProcMacro, + "sdylib" => CrateType::Sdylib, _ => { return Err(format!( "unknown crate type: `{part}`, expected one of: \ @@ -2915,6 +2930,7 @@ impl fmt::Display for CrateType { CrateType::Staticlib => "staticlib".fmt(f), CrateType::Cdylib => "cdylib".fmt(f), CrateType::ProcMacro => "proc-macro".fmt(f), + CrateType::Sdylib => "sdylib".fmt(f), } } } diff --git a/compiler/rustc_session/src/cstore.rs b/compiler/rustc_session/src/cstore.rs index c8a5c22ad123..4cfc745dec28 100644 --- a/compiler/rustc_session/src/cstore.rs +++ b/compiler/rustc_session/src/cstore.rs @@ -27,6 +27,7 @@ pub struct CrateSource { pub dylib: Option<(PathBuf, PathKind)>, pub rlib: Option<(PathBuf, PathKind)>, pub rmeta: Option<(PathBuf, PathKind)>, + pub sdylib_interface: Option<(PathBuf, PathKind)>, } impl CrateSource { diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 5f4695fb1841..b95ebfbe89f2 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -2113,6 +2113,8 @@ options! { "emit noalias metadata for box (default: yes)"), branch_protection: Option = (None, parse_branch_protection, [TRACKED], "set options for branch target identification and pointer authentication on AArch64"), + build_sdylib_interface: bool = (false, parse_bool, [UNTRACKED], + "whether the stable interface is being built"), cf_protection: CFProtection = (CFProtection::None, parse_cfprotection, [TRACKED], "instrument control-flow architecture protection"), check_cfg_all_expected: bool = (false, parse_bool, [UNTRACKED], @@ -2208,7 +2210,7 @@ options! { fewer_names: Option = (None, parse_opt_bool, [TRACKED], "reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR) \ (default: no)"), - fixed_x18: bool = (false, parse_bool, [TRACKED], + fixed_x18: bool = (false, parse_bool, [TRACKED TARGET_MODIFIER], "make the x18 register reserved on AArch64 (default: no)"), flatten_format_args: bool = (true, parse_bool, [TRACKED], "flatten nested format_args!() and literals into a simplified format_args!() call \ diff --git a/compiler/rustc_session/src/output.rs b/compiler/rustc_session/src/output.rs index 46dae9144cd4..cba70b5bd5d1 100644 --- a/compiler/rustc_session/src/output.rs +++ b/compiler/rustc_session/src/output.rs @@ -98,7 +98,7 @@ pub fn filename_for_input( CrateType::Rlib => { OutFileName::Real(outputs.out_directory.join(&format!("lib{libname}.rlib"))) } - CrateType::Cdylib | CrateType::ProcMacro | CrateType::Dylib => { + CrateType::Cdylib | CrateType::ProcMacro | CrateType::Dylib | CrateType::Sdylib => { let (prefix, suffix) = (&sess.target.dll_prefix, &sess.target.dll_suffix); OutFileName::Real(outputs.out_directory.join(&format!("{prefix}{libname}{suffix}"))) } @@ -167,6 +167,7 @@ pub const CRATE_TYPES: &[(Symbol, CrateType)] = &[ (sym::staticlib, CrateType::Staticlib), (sym::proc_dash_macro, CrateType::ProcMacro), (sym::bin, CrateType::Executable), + (sym::sdylib, CrateType::Sdylib), ]; pub fn categorize_crate_type(s: Symbol) -> Option { @@ -187,6 +188,11 @@ pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec BodyBuilder<'tcx> { pub(crate) fn new(tcx: TyCtxt<'tcx>, instance: ty::Instance<'tcx>) -> Self { let instance = match instance.def { // To get the fallback body of an intrinsic, we need to convert it to an item. - ty::InstanceKind::Intrinsic(def_id) => ty::Instance::new(def_id, instance.args), + ty::InstanceKind::Intrinsic(def_id) => ty::Instance::new_raw(def_id, instance.args), _ => instance, }; BodyBuilder { tcx, instance } diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index ab0a802dc7f7..b621920d62ba 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -41,6 +41,7 @@ use tracing::{debug, trace}; use crate::def_id::{CRATE_DEF_ID, CrateNum, DefId, LOCAL_CRATE, StableCrateId}; use crate::edition::Edition; +use crate::source_map::SourceMap; use crate::symbol::{Symbol, kw, sym}; use crate::{DUMMY_SP, HashStableContext, Span, SpanDecoder, SpanEncoder, with_session_globals}; @@ -907,6 +908,30 @@ impl SyntaxContext { pub fn edition(self) -> Edition { HygieneData::with(|data| data.expn_data(data.outer_expn(self)).edition) } + + /// Returns whether this context originates in a foreign crate's external macro. + /// + /// This is used to test whether a lint should not even begin to figure out whether it should + /// be reported on the current node. + pub fn in_external_macro(self, sm: &SourceMap) -> bool { + let expn_data = self.outer_expn_data(); + match expn_data.kind { + ExpnKind::Root + | ExpnKind::Desugaring( + DesugaringKind::ForLoop + | DesugaringKind::WhileLoop + | DesugaringKind::OpaqueTy + | DesugaringKind::Async + | DesugaringKind::Await, + ) => false, + ExpnKind::AstPass(_) | ExpnKind::Desugaring(_) => true, // well, it's "external" + ExpnKind::Macro(MacroKind::Bang, _) => { + // Dummy span for the `def_site` means it's an external macro. + expn_data.def_site.is_dummy() || sm.is_imported(expn_data.def_site) + } + ExpnKind::Macro { .. } => true, // definitely a plugin + } + } } impl fmt::Debug for SyntaxContext { diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 9722031f209b..61c96e67c17f 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -224,7 +224,7 @@ pub fn with_metavar_spans(f: impl FnOnce(&MetavarSpansMap) -> R) -> R { // FIXME: We should use this enum or something like it to get rid of the // use of magic `/rust/1.x/...` paths across the board. -#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Decodable)] +#[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Decodable, Encodable)] pub enum RealFileName { LocalPath(PathBuf), /// For remapped paths (namely paths into libstd that have been mapped @@ -250,28 +250,6 @@ impl Hash for RealFileName { } } -// This is functionally identical to #[derive(Encodable)], with the exception of -// an added assert statement -impl Encodable for RealFileName { - fn encode(&self, encoder: &mut S) { - match *self { - RealFileName::LocalPath(ref local_path) => { - encoder.emit_u8(0); - local_path.encode(encoder); - } - - RealFileName::Remapped { ref local_path, ref virtual_name } => { - encoder.emit_u8(1); - // For privacy and build reproducibility, we must not embed host-dependant path - // in artifacts if they have been remapped by --remap-path-prefix - assert!(local_path.is_none()); - local_path.encode(encoder); - virtual_name.encode(encoder); - } - } - } -} - impl RealFileName { /// Returns the path suitable for reading from the file system on the local host, /// if this information exists. @@ -368,6 +346,16 @@ impl From for FileName { } } +#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)] +pub enum FileNameEmbeddablePreference { + /// If a remapped path is available, only embed the `virtual_path` and omit the `local_path`. + /// + /// Otherwise embed the local-path into the `virtual_path`. + RemappedOnly, + /// Embed the original path as well as its remapped `virtual_path` component if available. + LocalAndRemapped, +} + #[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)] pub enum FileNameDisplayPreference { /// Display the path after the application of rewrite rules provided via `--remap-path-prefix`. @@ -606,28 +594,13 @@ impl Span { !self.is_dummy() && sm.is_span_accessible(self) } - /// Returns whether `span` originates in a foreign crate's external macro. + /// Returns whether this span originates in a foreign crate's external macro. /// /// This is used to test whether a lint should not even begin to figure out whether it should /// be reported on the current node. + #[inline] pub fn in_external_macro(self, sm: &SourceMap) -> bool { - let expn_data = self.ctxt().outer_expn_data(); - match expn_data.kind { - ExpnKind::Root - | ExpnKind::Desugaring( - DesugaringKind::ForLoop - | DesugaringKind::WhileLoop - | DesugaringKind::OpaqueTy - | DesugaringKind::Async - | DesugaringKind::Await, - ) => false, - ExpnKind::AstPass(_) | ExpnKind::Desugaring(_) => true, // well, it's "external" - ExpnKind::Macro(MacroKind::Bang, _) => { - // Dummy span for the `def_site` means it's an external macro. - expn_data.def_site.is_dummy() || sm.is_imported(expn_data.def_site) - } - ExpnKind::Macro { .. } => true, // definitely a plugin - } + self.ctxt().in_external_macro(sm) } /// Returns `true` if `span` originates in a derive-macro's expansion. diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index 0273bb040f43..8a3644163caf 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -1108,18 +1108,28 @@ pub fn get_source_map() -> Option> { pub struct FilePathMapping { mapping: Vec<(PathBuf, PathBuf)>, filename_display_for_diagnostics: FileNameDisplayPreference, + filename_embeddable_preference: FileNameEmbeddablePreference, } impl FilePathMapping { pub fn empty() -> FilePathMapping { - FilePathMapping::new(Vec::new(), FileNameDisplayPreference::Local) + FilePathMapping::new( + Vec::new(), + FileNameDisplayPreference::Local, + FileNameEmbeddablePreference::RemappedOnly, + ) } pub fn new( mapping: Vec<(PathBuf, PathBuf)>, filename_display_for_diagnostics: FileNameDisplayPreference, + filename_embeddable_preference: FileNameEmbeddablePreference, ) -> FilePathMapping { - FilePathMapping { mapping, filename_display_for_diagnostics } + FilePathMapping { + mapping, + filename_display_for_diagnostics, + filename_embeddable_preference, + } } /// Applies any path prefix substitution as defined by the mapping. @@ -1217,11 +1227,13 @@ impl FilePathMapping { ) -> RealFileName { match file_path { // Anything that's already remapped we don't modify, except for erasing - // the `local_path` portion. - RealFileName::Remapped { local_path: _, virtual_name } => { + // the `local_path` portion (if desired). + RealFileName::Remapped { local_path, virtual_name } => { RealFileName::Remapped { - // We do not want any local path to be exported into metadata - local_path: None, + local_path: match self.filename_embeddable_preference { + FileNameEmbeddablePreference::RemappedOnly => None, + FileNameEmbeddablePreference::LocalAndRemapped => local_path, + }, // We use the remapped name verbatim, even if it looks like a relative // path. The assumption is that the user doesn't want us to further // process paths that have gone through remapping. @@ -1231,12 +1243,18 @@ impl FilePathMapping { RealFileName::LocalPath(unmapped_file_path) => { // If no remapping has been applied yet, try to do so - let (new_path, was_remapped) = self.map_prefix(unmapped_file_path); + let (new_path, was_remapped) = self.map_prefix(&unmapped_file_path); if was_remapped { // It was remapped, so don't modify further return RealFileName::Remapped { - local_path: None, virtual_name: new_path.into_owned(), + // But still provide the local path if desired + local_path: match self.filename_embeddable_preference { + FileNameEmbeddablePreference::RemappedOnly => None, + FileNameEmbeddablePreference::LocalAndRemapped => { + Some(unmapped_file_path) + } + }, }; } @@ -1252,17 +1270,23 @@ impl FilePathMapping { match working_directory { RealFileName::LocalPath(unmapped_working_dir_abs) => { - let file_path_abs = unmapped_working_dir_abs.join(unmapped_file_path_rel); + let unmapped_file_path_abs = + unmapped_working_dir_abs.join(unmapped_file_path_rel); // Although neither `working_directory` nor the file name were subject // to path remapping, the concatenation between the two may be. Hence // we need to do a remapping here. - let (file_path_abs, was_remapped) = self.map_prefix(file_path_abs); + let (file_path_abs, was_remapped) = + self.map_prefix(&unmapped_file_path_abs); if was_remapped { RealFileName::Remapped { - // Erase the actual path - local_path: None, virtual_name: file_path_abs.into_owned(), + local_path: match self.filename_embeddable_preference { + FileNameEmbeddablePreference::RemappedOnly => None, + FileNameEmbeddablePreference::LocalAndRemapped => { + Some(unmapped_file_path_abs) + } + }, } } else { // No kind of remapping applied to this path, so @@ -1271,15 +1295,20 @@ impl FilePathMapping { } } RealFileName::Remapped { - local_path: _, + local_path, virtual_name: remapped_working_dir_abs, } => { // If working_directory has been remapped, then we emit // Remapped variant as the expanded path won't be valid RealFileName::Remapped { - local_path: None, virtual_name: Path::new(remapped_working_dir_abs) - .join(unmapped_file_path_rel), + .join(&unmapped_file_path_rel), + local_path: match self.filename_embeddable_preference { + FileNameEmbeddablePreference::RemappedOnly => None, + FileNameEmbeddablePreference::LocalAndRemapped => local_path + .as_ref() + .map(|local_path| local_path.join(unmapped_file_path_rel)), + }, } } } @@ -1287,27 +1316,6 @@ impl FilePathMapping { } } - /// Expand a relative path to an absolute path **without** remapping taken into account. - /// - /// The resulting `RealFileName` will have its `virtual_path` portion erased if - /// possible (i.e. if there's also a remapped path). - pub fn to_local_embeddable_absolute_path( - &self, - file_path: RealFileName, - working_directory: &RealFileName, - ) -> RealFileName { - let file_path = file_path.local_path_if_available(); - if file_path.is_absolute() { - // No remapping has applied to this path and it is absolute, - // so the working directory cannot influence it either, so - // we are done. - return RealFileName::LocalPath(file_path.to_path_buf()); - } - debug_assert!(file_path.is_relative()); - let working_directory = working_directory.local_path_if_available(); - RealFileName::LocalPath(Path::new(working_directory).join(file_path)) - } - /// Attempts to (heuristically) reverse a prefix mapping. /// /// Returns [`Some`] if there is exactly one mapping where the "to" part is diff --git a/compiler/rustc_span/src/source_map/tests.rs b/compiler/rustc_span/src/source_map/tests.rs index 957f55e39138..589c2a363548 100644 --- a/compiler/rustc_span/src/source_map/tests.rs +++ b/compiler/rustc_span/src/source_map/tests.rs @@ -305,6 +305,7 @@ fn path_prefix_remapping() { let mapping = &FilePathMapping::new( vec![(path("abc/def"), path("foo"))], FileNameDisplayPreference::Remapped, + FileNameEmbeddablePreference::RemappedOnly, ); assert_eq!(map_path_prefix(mapping, "abc/def/src/main.rs"), path_str("foo/src/main.rs")); @@ -316,6 +317,7 @@ fn path_prefix_remapping() { let mapping = &FilePathMapping::new( vec![(path("abc/def"), path("/foo"))], FileNameDisplayPreference::Remapped, + FileNameEmbeddablePreference::RemappedOnly, ); assert_eq!(map_path_prefix(mapping, "abc/def/src/main.rs"), path_str("/foo/src/main.rs")); @@ -327,6 +329,7 @@ fn path_prefix_remapping() { let mapping = &FilePathMapping::new( vec![(path("/abc/def"), path("foo"))], FileNameDisplayPreference::Remapped, + FileNameEmbeddablePreference::RemappedOnly, ); assert_eq!(map_path_prefix(mapping, "/abc/def/src/main.rs"), path_str("foo/src/main.rs")); @@ -338,6 +341,7 @@ fn path_prefix_remapping() { let mapping = &FilePathMapping::new( vec![(path("/abc/def"), path("/foo"))], FileNameDisplayPreference::Remapped, + FileNameEmbeddablePreference::RemappedOnly, ); assert_eq!(map_path_prefix(mapping, "/abc/def/src/main.rs"), path_str("/foo/src/main.rs")); @@ -351,6 +355,7 @@ fn path_prefix_remapping_expand_to_absolute() { let mapping = &FilePathMapping::new( vec![(path("/foo"), path("FOO")), (path("/bar"), path("BAR"))], FileNameDisplayPreference::Remapped, + FileNameEmbeddablePreference::RemappedOnly, ); let working_directory = path("/foo"); let working_directory = RealFileName::Remapped { @@ -448,6 +453,71 @@ fn path_prefix_remapping_expand_to_absolute() { ); } +#[test] +fn path_prefix_remapping_expand_to_absolute_and_local() { + // "virtual" working directory is relative path + let mapping = &FilePathMapping::new( + vec![(path("/foo"), path("FOO")), (path("/bar"), path("BAR"))], + FileNameDisplayPreference::Remapped, + FileNameEmbeddablePreference::LocalAndRemapped, + ); + let working_directory = path("/foo"); + let working_directory = RealFileName::Remapped { + local_path: Some(working_directory.clone()), + virtual_name: mapping.map_prefix(working_directory).0.into_owned(), + }; + + assert_eq!(working_directory.remapped_path_if_available(), path("FOO")); + + // Unmapped absolute path + assert_eq!( + mapping.to_embeddable_absolute_path( + RealFileName::LocalPath(path("/foo/src/main.rs")), + &working_directory + ), + RealFileName::Remapped { + local_path: Some(path("/foo/src/main.rs")), + virtual_name: path("FOO/src/main.rs") + } + ); + + // Unmapped absolute path with unrelated working directory + assert_eq!( + mapping.to_embeddable_absolute_path( + RealFileName::LocalPath(path("/bar/src/main.rs")), + &working_directory + ), + RealFileName::Remapped { + local_path: Some(path("/bar/src/main.rs")), + virtual_name: path("BAR/src/main.rs") + } + ); + + // Already remapped absolute path, with unrelated working directory + assert_eq!( + mapping.to_embeddable_absolute_path( + RealFileName::Remapped { + local_path: Some(path("/bar/src/main.rs")), + virtual_name: path("BAR/src/main.rs"), + }, + &working_directory + ), + RealFileName::Remapped { + local_path: Some(path("/bar/src/main.rs")), + virtual_name: path("BAR/src/main.rs") + } + ); + + // Already remapped relative path + assert_eq!( + mapping.to_embeddable_absolute_path( + RealFileName::Remapped { local_path: None, virtual_name: path("XYZ/src/main.rs") }, + &working_directory + ), + RealFileName::Remapped { local_path: None, virtual_name: path("XYZ/src/main.rs") } + ); +} + #[test] fn path_prefix_remapping_reverse() { // Ignores options without alphanumeric chars. @@ -455,6 +525,7 @@ fn path_prefix_remapping_reverse() { let mapping = &FilePathMapping::new( vec![(path("abc"), path("/")), (path("def"), path("."))], FileNameDisplayPreference::Remapped, + FileNameEmbeddablePreference::RemappedOnly, ); assert_eq!(reverse_map_prefix(mapping, "/hello.rs"), None); @@ -466,6 +537,7 @@ fn path_prefix_remapping_reverse() { let mapping = &FilePathMapping::new( vec![(path("abc"), path("/redacted")), (path("def"), path("/redacted"))], FileNameDisplayPreference::Remapped, + FileNameEmbeddablePreference::RemappedOnly, ); assert_eq!(reverse_map_prefix(mapping, "/redacted/hello.rs"), None); @@ -476,6 +548,7 @@ fn path_prefix_remapping_reverse() { let mapping = &FilePathMapping::new( vec![(path("abc"), path("/redacted")), (path("def/ghi"), path("/fake/dir"))], FileNameDisplayPreference::Remapped, + FileNameEmbeddablePreference::RemappedOnly, ); assert_eq!( diff --git a/compiler/rustc_span/src/span_encoding.rs b/compiler/rustc_span/src/span_encoding.rs index 9d6c7d2a42a3..a4a47dc99b08 100644 --- a/compiler/rustc_span/src/span_encoding.rs +++ b/compiler/rustc_span/src/span_encoding.rs @@ -306,8 +306,21 @@ impl Span { /// Returns `true` if this span comes from any kind of macro, desugaring or inlining. #[inline] pub fn from_expansion(self) -> bool { - // If the span is fully inferred then ctxt > MAX_CTXT - self.inline_ctxt().map_or(true, |ctxt| !ctxt.is_root()) + let ctxt = match_span_kind! { + self, + // All branches here, except `InlineParent`, actually return `span.ctxt_or_parent_or_marker`. + // Since `Interned` is selected if the field contains `CTXT_INTERNED_MARKER` returning that value + // as the context allows the compiler to optimize out the branch that selects between either + // `Interned` and `PartiallyInterned`. + // + // Interned contexts can never be the root context and `CTXT_INTERNED_MARKER` has a different value + // than the root context so this works for checking is this is an expansion. + InlineCtxt(span) => SyntaxContext::from_u16(span.ctxt), + InlineParent(_span) => SyntaxContext::root(), + PartiallyInterned(span) => SyntaxContext::from_u16(span.ctxt), + Interned(_span) => SyntaxContext::from_u16(CTXT_INTERNED_MARKER), + }; + !ctxt.is_root() } /// Returns `true` if this is a dummy span with any hygienic context. diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index ba3e6d7ca826..40cec4083089 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -174,7 +174,6 @@ symbols! { Arc, ArcWeak, Argument, - ArgumentMethods, ArrayIntoIter, AsMut, AsRef, @@ -249,6 +248,7 @@ symbols! { Error, File, FileType, + FmtArgumentsNew, Fn, FnMut, FnOnce, @@ -459,6 +459,7 @@ symbols! { anonymous_lifetime_in_impl_trait, any, append_const_msg, + apx_target_feature, arbitrary_enum_discriminant, arbitrary_self_types, arbitrary_self_types_pointers, @@ -531,6 +532,7 @@ symbols! { autodiff, automatically_derived, avx, + avx10_target_feature, avx512_target_feature, avx512bw, avx512f, @@ -913,6 +915,7 @@ symbols! { explicit_generic_args_with_impl_trait, explicit_tail_calls, export_name, + export_stable, expr, expr_2021, expr_fragment_specifier_2024, @@ -1047,6 +1050,7 @@ symbols! { from_u16, from_usize, from_yeet, + frontmatter, fs_create_dir, fsub_algebraic, fsub_fast, @@ -1877,6 +1881,7 @@ symbols! { saturating_add, saturating_div, saturating_sub, + sdylib, search_unbox, select_unpredictable, self_in_typedefs, diff --git a/compiler/rustc_symbol_mangling/src/export.rs b/compiler/rustc_symbol_mangling/src/export.rs new file mode 100644 index 000000000000..770401fc8cfe --- /dev/null +++ b/compiler/rustc_symbol_mangling/src/export.rs @@ -0,0 +1,181 @@ +use std::assert_matches::debug_assert_matches; + +use rustc_abi::IntegerType; +use rustc_data_structures::stable_hasher::StableHasher; +use rustc_hashes::Hash128; +use rustc_hir::def::DefKind; +use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; +use rustc_span::symbol::{Symbol, sym}; + +trait AbiHashStable<'tcx> { + fn abi_hash(&self, tcx: TyCtxt<'tcx>, hasher: &mut StableHasher); +} +macro_rules! default_hash_impl { + ($($t:ty,)+) => { + $(impl<'tcx> AbiHashStable<'tcx> for $t { + #[inline] + fn abi_hash(&self, _tcx: TyCtxt<'tcx>, hasher: &mut StableHasher) { + ::std::hash::Hash::hash(self, hasher); + } + })* + }; +} + +default_hash_impl! { i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize, } + +impl<'tcx> AbiHashStable<'tcx> for bool { + #[inline] + fn abi_hash(&self, tcx: TyCtxt<'tcx>, hasher: &mut StableHasher) { + (if *self { 1u8 } else { 0u8 }).abi_hash(tcx, hasher); + } +} + +impl<'tcx> AbiHashStable<'tcx> for str { + #[inline] + fn abi_hash(&self, tcx: TyCtxt<'tcx>, hasher: &mut StableHasher) { + self.as_bytes().abi_hash(tcx, hasher); + } +} + +impl<'tcx> AbiHashStable<'tcx> for String { + #[inline] + fn abi_hash(&self, tcx: TyCtxt<'tcx>, hasher: &mut StableHasher) { + self[..].abi_hash(tcx, hasher); + } +} + +impl<'tcx> AbiHashStable<'tcx> for Symbol { + #[inline] + fn abi_hash(&self, tcx: TyCtxt<'tcx>, hasher: &mut StableHasher) { + self.as_str().abi_hash(tcx, hasher); + } +} + +impl<'tcx, T: AbiHashStable<'tcx>> AbiHashStable<'tcx> for [T] { + fn abi_hash(&self, tcx: TyCtxt<'tcx>, hasher: &mut StableHasher) { + self.len().abi_hash(tcx, hasher); + for item in self { + item.abi_hash(tcx, hasher); + } + } +} + +impl<'tcx> AbiHashStable<'tcx> for Ty<'tcx> { + fn abi_hash(&self, tcx: TyCtxt<'tcx>, hasher: &mut StableHasher) { + match self.kind() { + ty::Bool => sym::bool.abi_hash(tcx, hasher), + ty::Char => sym::char.abi_hash(tcx, hasher), + ty::Int(int_ty) => int_ty.name_str().abi_hash(tcx, hasher), + ty::Uint(uint_ty) => uint_ty.name_str().abi_hash(tcx, hasher), + ty::Float(float_ty) => float_ty.name_str().abi_hash(tcx, hasher), + + ty::Adt(adt_def, args) => { + adt_def.is_struct().abi_hash(tcx, hasher); + adt_def.is_enum().abi_hash(tcx, hasher); + adt_def.is_union().abi_hash(tcx, hasher); + + if let Some(align) = adt_def.repr().align { + align.bits().abi_hash(tcx, hasher); + } + + if let Some(integer) = adt_def.repr().int { + match integer { + IntegerType::Pointer(sign) => sign.abi_hash(tcx, hasher), + IntegerType::Fixed(integer, sign) => { + integer.int_ty_str().abi_hash(tcx, hasher); + sign.abi_hash(tcx, hasher); + } + } + } + + if let Some(pack) = adt_def.repr().pack { + pack.bits().abi_hash(tcx, hasher); + } + + adt_def.repr().c().abi_hash(tcx, hasher); + + for variant in adt_def.variants() { + variant.name.abi_hash(tcx, hasher); + for field in &variant.fields { + field.name.abi_hash(tcx, hasher); + let field_ty = tcx.type_of(field.did).instantiate_identity(); + field_ty.abi_hash(tcx, hasher); + } + } + args.abi_hash(tcx, hasher); + } + + ty::Tuple(args) if args.len() == 0 => {} + + // FIXME: Not yet supported. + ty::Foreign(_) + | ty::Ref(_, _, _) + | ty::Str + | ty::Array(_, _) + | ty::Pat(_, _) + | ty::Slice(_) + | ty::RawPtr(_, _) + | ty::FnDef(_, _) + | ty::FnPtr(_, _) + | ty::Dynamic(_, _, _) + | ty::Closure(_, _) + | ty::CoroutineClosure(_, _) + | ty::Coroutine(_, _) + | ty::CoroutineWitness(_, _) + | ty::Never + | ty::Tuple(_) + | ty::Alias(_, _) + | ty::Param(_) + | ty::Bound(_, _) + | ty::Placeholder(_) + | ty::Infer(_) + | ty::UnsafeBinder(_) => unreachable!(), + + ty::Error(_) => {} + } + } +} + +impl<'tcx> AbiHashStable<'tcx> for ty::FnSig<'tcx> { + fn abi_hash(&self, tcx: TyCtxt<'tcx>, hasher: &mut StableHasher) { + for ty in self.inputs_and_output { + ty.abi_hash(tcx, hasher); + } + self.safety.is_safe().abi_hash(tcx, hasher); + } +} + +impl<'tcx> AbiHashStable<'tcx> for ty::GenericArg<'tcx> { + fn abi_hash(&self, tcx: TyCtxt<'tcx>, hasher: &mut StableHasher) { + self.unpack().abi_hash(tcx, hasher); + } +} + +impl<'tcx> AbiHashStable<'tcx> for ty::GenericArgKind<'tcx> { + fn abi_hash(&self, tcx: TyCtxt<'tcx>, hasher: &mut StableHasher) { + match self { + ty::GenericArgKind::Type(t) => t.abi_hash(tcx, hasher), + ty::GenericArgKind::Lifetime(_) | ty::GenericArgKind::Const(_) => unimplemented!(), + } + } +} + +pub(crate) fn compute_hash_of_export_fn<'tcx>( + tcx: TyCtxt<'tcx>, + instance: Instance<'tcx>, +) -> String { + let def_id = instance.def_id(); + debug_assert_matches!(tcx.def_kind(def_id), DefKind::Fn | DefKind::AssocFn); + + let args = instance.args; + let sig_ty = tcx.fn_sig(def_id).instantiate(tcx, args); + let sig_ty = tcx.instantiate_bound_regions_with_erased(sig_ty); + + let hash = { + let mut hasher = StableHasher::new(); + sig_ty.abi_hash(tcx, &mut hasher); + hasher.finish::() + }; + + hash.as_u128().to_string() +} diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs index ca8918e06aaf..a51d7da878a2 100644 --- a/compiler/rustc_symbol_mangling/src/lib.rs +++ b/compiler/rustc_symbol_mangling/src/lib.rs @@ -92,6 +92,7 @@ #![cfg_attr(bootstrap, feature(let_chains))] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] +#![feature(assert_matches)] #![feature(rustdoc_internals)] // tidy-alphabetical-end @@ -104,6 +105,7 @@ use rustc_middle::ty::{self, Instance, TyCtxt}; use rustc_session::config::SymbolManglingVersion; use tracing::debug; +mod export; mod hashed; mod legacy; mod v0; @@ -296,12 +298,21 @@ fn compute_symbol_name<'tcx>( tcx.symbol_mangling_version(mangling_version_crate) }; - let symbol = match mangling_version { - SymbolManglingVersion::Legacy => legacy::mangle(tcx, instance, instantiating_crate), - SymbolManglingVersion::V0 => v0::mangle(tcx, instance, instantiating_crate), - SymbolManglingVersion::Hashed => hashed::mangle(tcx, instance, instantiating_crate, || { - v0::mangle(tcx, instance, instantiating_crate) - }), + let symbol = match tcx.is_exportable(def_id) { + true => format!( + "{}.{}", + v0::mangle(tcx, instance, instantiating_crate, true), + export::compute_hash_of_export_fn(tcx, instance) + ), + false => match mangling_version { + SymbolManglingVersion::Legacy => legacy::mangle(tcx, instance, instantiating_crate), + SymbolManglingVersion::V0 => v0::mangle(tcx, instance, instantiating_crate, false), + SymbolManglingVersion::Hashed => { + hashed::mangle(tcx, instance, instantiating_crate, || { + v0::mangle(tcx, instance, instantiating_crate, false) + }) + } + }, }; debug_assert!( diff --git a/compiler/rustc_symbol_mangling/src/test.rs b/compiler/rustc_symbol_mangling/src/test.rs index ddeeadff13d1..0c6d1495e39c 100644 --- a/compiler/rustc_symbol_mangling/src/test.rs +++ b/compiler/rustc_symbol_mangling/src/test.rs @@ -56,7 +56,7 @@ impl SymbolNamesTest<'_> { // some subset. for attr in tcx.get_attrs(def_id, SYMBOL_NAME) { let def_id = def_id.to_def_id(); - let instance = Instance::new( + let instance = Instance::new_raw( def_id, tcx.erase_regions(GenericArgs::identity_for_item(tcx, def_id)), ); diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index f8f2714ee42d..1f45440eecfc 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -26,6 +26,7 @@ pub(super) fn mangle<'tcx>( tcx: TyCtxt<'tcx>, instance: Instance<'tcx>, instantiating_crate: Option, + is_exportable: bool, ) -> String { let def_id = instance.def_id(); // FIXME(eddyb) this should ideally not be needed. @@ -35,6 +36,7 @@ pub(super) fn mangle<'tcx>( let mut cx: SymbolMangler<'_> = SymbolMangler { tcx, start_offset: prefix.len(), + is_exportable, paths: FxHashMap::default(), types: FxHashMap::default(), consts: FxHashMap::default(), @@ -93,6 +95,7 @@ pub fn mangle_internal_symbol<'tcx>(tcx: TyCtxt<'tcx>, item_name: &str) -> Strin let mut cx: SymbolMangler<'_> = SymbolMangler { tcx, start_offset: prefix.len(), + is_exportable: false, paths: FxHashMap::default(), types: FxHashMap::default(), consts: FxHashMap::default(), @@ -135,6 +138,7 @@ pub(super) fn mangle_typeid_for_trait_ref<'tcx>( let mut cx = SymbolMangler { tcx, start_offset: 0, + is_exportable: false, paths: FxHashMap::default(), types: FxHashMap::default(), consts: FxHashMap::default(), @@ -163,6 +167,7 @@ struct SymbolMangler<'tcx> { tcx: TyCtxt<'tcx>, binders: Vec, out: String, + is_exportable: bool, /// The length of the prefix in `out` (e.g. 2 for `_R`). start_offset: usize, @@ -376,7 +381,14 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { args, )?; } else { - self.push_disambiguator(key.disambiguated_data.disambiguator as u64); + let exported_impl_order = self.tcx.stable_order_of_exportable_impls(impl_def_id.krate); + let disambiguator = match self.is_exportable { + true => exported_impl_order[&impl_def_id] as u64, + false => { + exported_impl_order.len() as u64 + key.disambiguated_data.disambiguator as u64 + } + }; + self.push_disambiguator(disambiguator); self.print_def_path(parent_def_id, &[])?; } @@ -818,8 +830,10 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { fn path_crate(&mut self, cnum: CrateNum) -> Result<(), PrintError> { self.push("C"); - let stable_crate_id = self.tcx.def_path_hash(cnum.as_def_id()).stable_crate_id(); - self.push_disambiguator(stable_crate_id.as_u64()); + if !self.is_exportable { + let stable_crate_id = self.tcx.def_path_hash(cnum.as_def_id()).stable_crate_id(); + self.push_disambiguator(stable_crate_id.as_u64()); + } let name = self.tcx.crate_name(cnum); self.push_ident(name.as_str()); Ok(()) @@ -867,6 +881,7 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { DefPathData::AnonConst => 'k', DefPathData::OpaqueTy => 'i', DefPathData::SyntheticCoroutineBody => 's', + DefPathData::NestedStatic => 'n', // These should never show up as `path_append` arguments. DefPathData::CrateRoot @@ -875,7 +890,7 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { | DefPathData::Impl | DefPathData::MacroNs(_) | DefPathData::LifetimeNs(_) - | DefPathData::AnonAssocTy => { + | DefPathData::AnonAssocTy(..) => { bug!("symbol_names: unexpected DefPathData: {:?}", disambiguated_data.data) } }; diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 37ea0d6e7b58..303be54a6d78 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -3567,7 +3567,19 @@ impl Target { "x86" => (Architecture::I386, None), "s390x" => (Architecture::S390x, None), "mips" | "mips32r6" => (Architecture::Mips, None), - "mips64" | "mips64r6" => (Architecture::Mips64, None), + "mips64" | "mips64r6" => ( + // While there are currently no builtin targets + // using the N32 ABI, it is possible to specify + // it using a custom target specification. N32 + // is an ILP32 ABI like the Aarch64_Ilp32 + // and X86_64_X32 cases above and below this one. + if self.options.llvm_abiname.as_ref() == "n32" { + Architecture::Mips64_N32 + } else { + Architecture::Mips64 + }, + None, + ), "x86_64" => ( if self.pointer_width == 32 { Architecture::X86_64_X32 diff --git a/compiler/rustc_target/src/spec/targets/mips64_openwrt_linux_musl.rs b/compiler/rustc_target/src/spec/targets/mips64_openwrt_linux_musl.rs index 71b3fbe00b2f..508abc010184 100644 --- a/compiler/rustc_target/src/spec/targets/mips64_openwrt_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/mips64_openwrt_linux_musl.rs @@ -27,6 +27,7 @@ pub(crate) fn target() -> Target { abi: "abi64".into(), endian: Endian::Big, mcount: "_mcount".into(), + llvm_abiname: "n64".into(), ..base }, } diff --git a/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_gnuabi64.rs b/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_gnuabi64.rs index b130ca29c7f0..a26350ff2250 100644 --- a/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_gnuabi64.rs +++ b/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_gnuabi64.rs @@ -22,6 +22,7 @@ pub(crate) fn target() -> Target { features: "+mips64r2,+xgot".into(), max_atomic_width: Some(64), mcount: "_mcount".into(), + llvm_abiname: "n64".into(), ..base::linux_gnu::opts() }, diff --git a/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_muslabi64.rs b/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_muslabi64.rs index 4ea7c7bff44a..fd5095030530 100644 --- a/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_muslabi64.rs +++ b/compiler/rustc_target/src/spec/targets/mips64_unknown_linux_muslabi64.rs @@ -25,6 +25,7 @@ pub(crate) fn target() -> Target { mcount: "_mcount".into(), // FIXME(compiler-team#422): musl targets should be dynamically linked by default. crt_static_default: true, + llvm_abiname: "n64".into(), ..base }, } diff --git a/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_gnuabi64.rs b/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_gnuabi64.rs index a9afea27ef34..19bceadc6223 100644 --- a/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_gnuabi64.rs +++ b/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_gnuabi64.rs @@ -19,6 +19,7 @@ pub(crate) fn target() -> Target { features: "+mips64r2,+xgot".into(), max_atomic_width: Some(64), mcount: "_mcount".into(), + llvm_abiname: "n64".into(), ..base::linux_gnu::opts() }, diff --git a/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_muslabi64.rs b/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_muslabi64.rs index 7bdd9edda70c..aa087b1a35af 100644 --- a/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_muslabi64.rs +++ b/compiler/rustc_target/src/spec/targets/mips64el_unknown_linux_muslabi64.rs @@ -19,6 +19,11 @@ pub(crate) fn target() -> Target { pointer_width: 64, data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".into(), arch: "mips64".into(), - options: TargetOptions { abi: "abi64".into(), mcount: "_mcount".into(), ..base }, + options: TargetOptions { + abi: "abi64".into(), + mcount: "_mcount".into(), + llvm_abiname: "n64".into(), + ..base + }, } } diff --git a/compiler/rustc_target/src/spec/targets/mipsisa64r6_unknown_linux_gnuabi64.rs b/compiler/rustc_target/src/spec/targets/mipsisa64r6_unknown_linux_gnuabi64.rs index 3eefa27ea04b..cdd5f6b84365 100644 --- a/compiler/rustc_target/src/spec/targets/mipsisa64r6_unknown_linux_gnuabi64.rs +++ b/compiler/rustc_target/src/spec/targets/mipsisa64r6_unknown_linux_gnuabi64.rs @@ -22,6 +22,7 @@ pub(crate) fn target() -> Target { features: "+mips64r6".into(), max_atomic_width: Some(64), mcount: "_mcount".into(), + llvm_abiname: "n64".into(), ..base::linux_gnu::opts() }, diff --git a/compiler/rustc_target/src/spec/targets/mipsisa64r6el_unknown_linux_gnuabi64.rs b/compiler/rustc_target/src/spec/targets/mipsisa64r6el_unknown_linux_gnuabi64.rs index 0887180791c7..88879a25818b 100644 --- a/compiler/rustc_target/src/spec/targets/mipsisa64r6el_unknown_linux_gnuabi64.rs +++ b/compiler/rustc_target/src/spec/targets/mipsisa64r6el_unknown_linux_gnuabi64.rs @@ -19,6 +19,7 @@ pub(crate) fn target() -> Target { features: "+mips64r6".into(), max_atomic_width: Some(64), mcount: "_mcount".into(), + llvm_abiname: "n64".into(), ..base::linux_gnu::opts() }, diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index 69c8b9119ab2..5a21925ba04e 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -102,6 +102,9 @@ impl Stability { // check whether they're named already elsewhere in rust // e.g. in stdarch and whether the given name matches LLVM's // if it doesn't, to_llvm_feature in llvm_util in rustc_codegen_llvm needs to be adapted. +// Additionally, if the feature is not available in older version of LLVM supported by the current +// rust, the same function must be updated to filter out these features to avoid triggering +// warnings. // // Also note that all target features listed here must be purely additive: for target_feature 1.1 to // be sound, we can never allow features like `+soft-float` (on x86) to be controlled on a @@ -390,7 +393,28 @@ static X86_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("amx-tf32", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]), ("amx-tile", Unstable(sym::x86_amx_intrinsics), &[]), ("amx-transpose", Unstable(sym::x86_amx_intrinsics), &["amx-tile"]), + ("apxf", Unstable(sym::apx_target_feature), &[]), ("avx", Stable, &["sse4.2"]), + ( + "avx10.1", + Unstable(sym::avx10_target_feature), + &[ + "avx512bf16", + "avx512bitalg", + "avx512bw", + "avx512cd", + "avx512dq", + "avx512f", + "avx512fp16", + "avx512ifma", + "avx512vbmi", + "avx512vbmi2", + "avx512vl", + "avx512vnni", + "avx512vpopcntdq", + ], + ), + ("avx10.2", Unstable(sym::avx10_target_feature), &["avx10.1"]), ("avx2", Stable, &["avx"]), ("avx512bf16", Unstable(sym::avx512_target_feature), &["avx512bw"]), ("avx512bitalg", Unstable(sym::avx512_target_feature), &["avx512bw"]), @@ -398,7 +422,7 @@ static X86_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("avx512cd", Unstable(sym::avx512_target_feature), &["avx512f"]), ("avx512dq", Unstable(sym::avx512_target_feature), &["avx512f"]), ("avx512f", Unstable(sym::avx512_target_feature), &["avx2", "fma", "f16c"]), - ("avx512fp16", Unstable(sym::avx512_target_feature), &["avx512bw", "avx512vl", "avx512dq"]), + ("avx512fp16", Unstable(sym::avx512_target_feature), &["avx512bw"]), ("avx512ifma", Unstable(sym::avx512_target_feature), &["avx512f"]), ("avx512vbmi", Unstable(sym::avx512_target_feature), &["avx512bw"]), ("avx512vbmi2", Unstable(sym::avx512_target_feature), &["avx512bw"]), @@ -507,7 +531,7 @@ static RISCV_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("unaligned-vector-mem", Unstable(sym::riscv_target_feature), &[]), ("v", Unstable(sym::riscv_target_feature), &["zvl128b", "zve64d"]), ("za128rs", Unstable(sym::riscv_target_feature), &[]), - ("za64rs", Unstable(sym::riscv_target_feature), &[]), + ("za64rs", Unstable(sym::riscv_target_feature), &["za128rs"]), // Za64rs ⊃ Za128rs ("zaamo", Unstable(sym::riscv_target_feature), &[]), ("zabha", Unstable(sym::riscv_target_feature), &["zaamo"]), ("zacas", Unstable(sym::riscv_target_feature), &["zaamo"]), @@ -526,12 +550,20 @@ static RISCV_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("zcmop", Unstable(sym::riscv_target_feature), &["zca"]), ("zdinx", Unstable(sym::riscv_target_feature), &["zfinx"]), ("zfa", Unstable(sym::riscv_target_feature), &["f"]), + ("zfbfmin", Unstable(sym::riscv_target_feature), &["f"]), // and a subset of Zfhmin ("zfh", Unstable(sym::riscv_target_feature), &["zfhmin"]), ("zfhmin", Unstable(sym::riscv_target_feature), &["f"]), ("zfinx", Unstable(sym::riscv_target_feature), &["zicsr"]), ("zhinx", Unstable(sym::riscv_target_feature), &["zhinxmin"]), ("zhinxmin", Unstable(sym::riscv_target_feature), &["zfinx"]), + ("zic64b", Unstable(sym::riscv_target_feature), &[]), + ("zicbom", Unstable(sym::riscv_target_feature), &[]), + ("zicbop", Unstable(sym::riscv_target_feature), &[]), ("zicboz", Unstable(sym::riscv_target_feature), &[]), + ("ziccamoa", Unstable(sym::riscv_target_feature), &[]), + ("ziccif", Unstable(sym::riscv_target_feature), &[]), + ("zicclsm", Unstable(sym::riscv_target_feature), &[]), + ("ziccrse", Unstable(sym::riscv_target_feature), &[]), ("zicntr", Unstable(sym::riscv_target_feature), &["zicsr"]), ("zicond", Unstable(sym::riscv_target_feature), &[]), ("zicsr", Unstable(sym::riscv_target_feature), &[]), @@ -558,6 +590,8 @@ static RISCV_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("zve64d", Unstable(sym::riscv_target_feature), &["zve64f", "d"]), ("zve64f", Unstable(sym::riscv_target_feature), &["zve32f", "zve64x"]), ("zve64x", Unstable(sym::riscv_target_feature), &["zve32x", "zvl64b"]), + ("zvfbfmin", Unstable(sym::riscv_target_feature), &["zve32f"]), + ("zvfbfwma", Unstable(sym::riscv_target_feature), &["zfbfmin", "zvfbfmin"]), ("zvfh", Unstable(sym::riscv_target_feature), &["zvfhmin", "zve32f", "zfhmin"]), // Zvfh ⊃ Zvfhmin ("zvfhmin", Unstable(sym::riscv_target_feature), &["zve32f"]), ("zvkb", Unstable(sym::riscv_target_feature), &["zve32x"]), @@ -963,12 +997,12 @@ impl Target { // about what the intended ABI is. match &*self.llvm_abiname { "ilp32d" | "lp64d" => { - // Requires d (which implies f), incompatible with e. - FeatureConstraints { required: &["d"], incompatible: &["e"] } + // Requires d (which implies f), incompatible with e and zfinx. + FeatureConstraints { required: &["d"], incompatible: &["e", "zfinx"] } } "ilp32f" | "lp64f" => { - // Requires f, incompatible with e. - FeatureConstraints { required: &["f"], incompatible: &["e"] } + // Requires f, incompatible with e and zfinx. + FeatureConstraints { required: &["f"], incompatible: &["e", "zfinx"] } } "ilp32" | "lp64" => { // Requires nothing, incompatible with e. diff --git a/compiler/rustc_trait_selection/Cargo.toml b/compiler/rustc_trait_selection/Cargo.toml index a5cc8d9ea012..1071105522d1 100644 --- a/compiler/rustc_trait_selection/Cargo.toml +++ b/compiler/rustc_trait_selection/Cargo.toml @@ -8,7 +8,6 @@ edition = "2024" itertools = "0.12" rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } -rustc_attr_parsing = { path = "../rustc_attr_parsing" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_fluent_macro = { path = "../rustc_fluent_macro" } diff --git a/compiler/rustc_trait_selection/messages.ftl b/compiler/rustc_trait_selection/messages.ftl index 74e38f525c8e..cf6dd40718b3 100644 --- a/compiler/rustc_trait_selection/messages.ftl +++ b/compiler/rustc_trait_selection/messages.ftl @@ -148,9 +148,6 @@ trait_selection_dtcs_has_req_note = the used `impl` has a `'static` requirement trait_selection_dtcs_introduces_requirement = calling this method introduces the `impl`'s `'static` requirement trait_selection_dtcs_suggestion = consider relaxing the implicit `'static` requirement -trait_selection_empty_on_clause_in_rustc_on_unimplemented = empty `on`-clause in `#[rustc_on_unimplemented]` - .label = empty on-clause here - trait_selection_explicit_lifetime_required_sugg_with_ident = add explicit lifetime `{$named}` to the type of `{$simple_ident}` trait_selection_explicit_lifetime_required_sugg_with_param_type = add explicit lifetime `{$named}` to type @@ -187,9 +184,6 @@ trait_selection_inherent_projection_normalization_overflow = overflow evaluating trait_selection_invalid_format_specifier = invalid format specifier .help = no format specifier are supported in this position -trait_selection_invalid_on_clause_in_rustc_on_unimplemented = invalid `on`-clause in `#[rustc_on_unimplemented]` - .label = invalid on-clause here - trait_selection_label_bad = {$bad_kind -> *[other] cannot infer type [more_info] cannot infer {$prefix_kind -> @@ -237,10 +231,6 @@ trait_selection_negative_positive_conflict = found both positive and negative im .positive_implementation_here = positive implementation here .positive_implementation_in_crate = positive implementation in crate `{$positive_impl_cname}` -trait_selection_no_value_in_rustc_on_unimplemented = this attribute must have a valid value - .label = expected value here - .note = eg `#[rustc_on_unimplemented(message="foo")]` - trait_selection_nothing = {""} trait_selection_oc_cant_coerce_force_inline = @@ -339,6 +329,22 @@ trait_selection_ril_introduced_by = requirement introduced by this return type trait_selection_ril_introduced_here = `'static` requirement introduced here trait_selection_ril_static_introduced_by = "`'static` lifetime requirement introduced by the return type +trait_selection_rustc_on_unimplemented_empty_on_clause = empty `on`-clause in `#[rustc_on_unimplemented]` + .label = empty `on`-clause here +trait_selection_rustc_on_unimplemented_expected_identifier = expected an identifier inside this `on`-clause + .label = expected an identifier here, not `{$path}` +trait_selection_rustc_on_unimplemented_expected_one_predicate_in_not = expected a single predicate in `not(..)` + .label = unexpected quantity of predicates here +trait_selection_rustc_on_unimplemented_invalid_flag = invalid flag in `on`-clause + .label = expected one of the `crate_local`, `direct` or `from_desugaring` flags, not `{$invalid_flag}` +trait_selection_rustc_on_unimplemented_invalid_predicate = this predicate is invalid + .label = expected one of `any`, `all` or `not` here, not `{$invalid_pred}` +trait_selection_rustc_on_unimplemented_missing_value = this attribute must have a value + .label = expected value here + .note = e.g. `#[rustc_on_unimplemented(message="foo")]` +trait_selection_rustc_on_unimplemented_unsupported_literal_in_on = literals inside `on`-clauses are not supported + .label = unexpected literal here + trait_selection_source_kind_closure_return = try giving this closure an explicit return type 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 ab2aa0ae4697..970160ba212a 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 @@ -15,6 +15,7 @@ use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId}; use rustc_hir::intravisit::Visitor; use rustc_hir::{self as hir, LangItem, Node}; use rustc_infer::infer::{InferOk, TypeTrace}; +use rustc_infer::traits::ImplSource; use rustc_infer::traits::solve::Goal; use rustc_middle::traits::SignatureMismatchData; use rustc_middle::traits::select::OverflowError; @@ -48,8 +49,8 @@ use crate::infer::{self, InferCtxt, InferCtxtExt as _}; use crate::traits::query::evaluate_obligation::InferCtxtExt as _; use crate::traits::{ MismatchedProjectionTypes, NormalizeExt, Obligation, ObligationCause, ObligationCauseCode, - ObligationCtxt, Overflow, PredicateObligation, SelectionError, SignatureMismatch, - TraitDynIncompatible, elaborate, + ObligationCtxt, Overflow, PredicateObligation, SelectionContext, SelectionError, + SignatureMismatch, TraitDynIncompatible, elaborate, specialization_graph, }; impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { @@ -1495,32 +1496,33 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } - let secondary_span = (|| { + let secondary_span = self.probe(|_| { let ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj)) = predicate.kind().skip_binder() else { return None; }; - let mut associated_items = vec![]; - self.tcx.for_each_relevant_impl( - self.tcx.trait_of_item(proj.projection_term.def_id)?, - proj.projection_term.self_ty(), - |impl_def_id| { - associated_items.extend( - self.tcx.associated_items(impl_def_id).in_definition_order().find( - |assoc| { - assoc.trait_item_def_id == Some(proj.projection_term.def_id) - }, - ), - ); - }, - ); - - let [associated_item]: &[ty::AssocItem] = &associated_items[..] else { + let Ok(Some(ImplSource::UserDefined(impl_data))) = SelectionContext::new(self) + .poly_select(&obligation.with( + self.tcx, + predicate.kind().rebind(proj.projection_term.trait_ref(self.tcx)), + )) + else { return None; }; - match self.tcx.hir_get_if_local(associated_item.def_id) { + + let Ok(node) = + specialization_graph::assoc_def(self.tcx, impl_data.impl_def_id, proj.def_id()) + else { + return None; + }; + + if !node.is_final() { + return None; + } + + match self.tcx.hir_get_if_local(node.item.def_id) { Some( hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Type(_, Some(ty)), @@ -1543,7 +1545,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { )), _ => None, } - })(); + }); self.note_type_err( &mut diag, diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs index 4c4491269b75..d5ee6e2123a1 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs @@ -4,6 +4,7 @@ use std::path::PathBuf; use rustc_ast::{LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit}; use rustc_errors::codes::*; use rustc_errors::{ErrorGuaranteed, struct_span_code_err}; +use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::{AttrArgs, Attribute}; use rustc_macros::LintDiagnostic; @@ -13,17 +14,16 @@ use rustc_middle::ty::{self, GenericArgsRef, GenericParamDef, GenericParamDefKin use rustc_session::lint::builtin::UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES; use rustc_span::{Span, Symbol, sym}; use tracing::{debug, info}; -use {rustc_attr_parsing as attr, rustc_hir as hir}; use super::{ObligationCauseCode, PredicateObligation}; use crate::error_reporting::TypeErrCtxt; -use crate::error_reporting::traits::on_unimplemented_condition::{Condition, ConditionOptions}; +use crate::error_reporting::traits::on_unimplemented_condition::{ + ConditionOptions, OnUnimplementedCondition, +}; use crate::error_reporting::traits::on_unimplemented_format::{ Ctx, FormatArgs, FormatString, FormatWarning, }; -use crate::errors::{ - EmptyOnClauseInOnUnimplemented, InvalidOnClauseInOnUnimplemented, NoValueInOnUnimplemented, -}; +use crate::errors::{InvalidOnClause, NoValueInOnUnimplemented}; use crate::infer::InferCtxtExt; impl<'tcx> TypeErrCtxt<'_, 'tcx> { @@ -306,21 +306,21 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { #[derive(Clone, Debug)] pub struct OnUnimplementedFormatString { /// Symbol of the format string, i.e. `"content"` - pub symbol: Symbol, + symbol: Symbol, ///The span of the format string, i.e. `"content"` - pub span: Span, - pub is_diagnostic_namespace_variant: bool, + span: Span, + is_diagnostic_namespace_variant: bool, } #[derive(Debug)] pub struct OnUnimplementedDirective { - pub condition: Option, - pub subcommands: Vec, - pub message: Option<(Span, OnUnimplementedFormatString)>, - pub label: Option<(Span, OnUnimplementedFormatString)>, - pub notes: Vec, - pub parent_label: Option, - pub append_const_msg: Option, + condition: Option, + subcommands: Vec, + message: Option<(Span, OnUnimplementedFormatString)>, + label: Option<(Span, OnUnimplementedFormatString)>, + notes: Vec, + parent_label: Option, + append_const_msg: Option, } /// For the `#[rustc_on_unimplemented]` attribute @@ -427,18 +427,12 @@ impl<'tcx> OnUnimplementedDirective { } else { let cond = item_iter .next() - .ok_or_else(|| tcx.dcx().emit_err(EmptyOnClauseInOnUnimplemented { span }))? - .meta_item_or_bool() - .ok_or_else(|| tcx.dcx().emit_err(InvalidOnClauseInOnUnimplemented { span }))?; - attr::eval_condition(cond, &tcx.sess, Some(tcx.features()), &mut |cfg| { - if let Some(value) = cfg.value - && let Err(guar) = parse_value(value, cfg.span) - { - errored = Some(guar); - } - true - }); - Some(Condition { inner: cond.clone() }) + .ok_or_else(|| tcx.dcx().emit_err(InvalidOnClause::Empty { span }))?; + + match OnUnimplementedCondition::parse(cond) { + Ok(condition) => Some(condition), + Err(e) => return Err(tcx.dcx().emit_err(e)), + } }; let mut message = None; @@ -724,7 +718,7 @@ impl<'tcx> OnUnimplementedDirective { result } - pub fn evaluate( + pub(crate) fn evaluate( &self, tcx: TyCtxt<'tcx>, trait_ref: ty::TraitRef<'tcx>, @@ -744,7 +738,7 @@ impl<'tcx> OnUnimplementedDirective { for command in self.subcommands.iter().chain(Some(self)).rev() { debug!(?command); if let Some(ref condition) = command.condition - && !condition.matches_predicate(tcx, condition_options) + && !condition.matches_predicate(condition_options) { debug!("evaluate: skipping {:?} due to condition", command); continue; diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_condition.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_condition.rs index 116cfb01cb63..13753761f092 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_condition.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_condition.rs @@ -1,52 +1,251 @@ -use rustc_ast::MetaItemInner; -use rustc_attr_parsing as attr; -use rustc_middle::ty::{self, TyCtxt}; +use rustc_ast::{MetaItemInner, MetaItemKind, MetaItemLit}; use rustc_parse_format::{ParseMode, Parser, Piece, Position}; -use rustc_span::{DesugaringKind, Span, Symbol, kw, sym}; +use rustc_span::{DesugaringKind, Ident, Span, Symbol, kw, sym}; -/// A predicate in an attribute using on, all, any, -/// similar to a cfg predicate. +use crate::errors::InvalidOnClause; + +/// Represents the `on` filter in `#[rustc_on_unimplemented]`. #[derive(Debug)] -pub struct Condition { - pub inner: MetaItemInner, +pub(crate) struct OnUnimplementedCondition { + span: Span, + pred: Predicate, } -impl Condition { - pub fn span(&self) -> Span { - self.inner.span() +impl OnUnimplementedCondition { + pub(crate) fn span(&self) -> Span { + self.span } - pub fn matches_predicate<'tcx>(&self, tcx: TyCtxt<'tcx>, options: &ConditionOptions) -> bool { - attr::eval_condition(&self.inner, tcx.sess, Some(tcx.features()), &mut |cfg| { - let value = cfg.value.map(|v| { - // `with_no_visible_paths` is also used when generating the options, - // so we need to match it here. - ty::print::with_no_visible_paths!({ - Parser::new(v.as_str(), None, None, false, ParseMode::Format) - .map(|p| match p { - Piece::Lit(s) => s.to_owned(), - Piece::NextArgument(a) => match a.position { - Position::ArgumentNamed(arg) => { - let s = Symbol::intern(arg); - match options.generic_args.iter().find(|(k, _)| *k == s) { - Some((_, val)) => val.to_string(), - None => format!("{{{arg}}}"), - } - } - Position::ArgumentImplicitlyIs(_) => String::from("{}"), - Position::ArgumentIs(idx) => format!("{{{idx}}}"), - }, - }) - .collect() - }) - }); - - options.contains(cfg.name, &value) + pub(crate) fn matches_predicate(&self, options: &ConditionOptions) -> bool { + self.pred.eval(&mut |p| match p { + FlagOrNv::Flag(b) => options.has_flag(*b), + FlagOrNv::NameValue(NameValue { name, value }) => { + let value = value.format(&options.generic_args); + options.contains(*name, value) + } }) } + + pub(crate) fn parse(input: &MetaItemInner) -> Result { + let span = input.span(); + let pred = Predicate::parse(input)?; + Ok(OnUnimplementedCondition { span, pred }) + } } -/// Used with `Condition::matches_predicate` to test whether the condition applies +/// Predicate(s) in `#[rustc_on_unimplemented]`'s `on` filter. See [`OnUnimplementedCondition`]. +/// +/// It is similar to the predicate in the `cfg` attribute, +/// and may contain nested predicates. +#[derive(Debug)] +enum Predicate { + /// A condition like `on(crate_local)`. + Flag(Flag), + /// A match, like `on(Rhs = "Whatever")`. + Match(NameValue), + /// Negation, like `on(not($pred))`. + Not(Box), + /// True if all predicates are true, like `on(all($a, $b, $c))`. + All(Vec), + /// True if any predicate is true, like `on(any($a, $b, $c))`. + Any(Vec), +} + +impl Predicate { + fn parse(input: &MetaItemInner) -> Result { + let meta_item = match input { + MetaItemInner::MetaItem(meta_item) => meta_item, + MetaItemInner::Lit(lit) => { + return Err(InvalidOnClause::UnsupportedLiteral { span: lit.span }); + } + }; + + let Some(predicate) = meta_item.ident() else { + return Err(InvalidOnClause::ExpectedIdentifier { + span: meta_item.path.span, + path: meta_item.path.clone(), + }); + }; + + match meta_item.kind { + MetaItemKind::List(ref mis) => match predicate.name { + sym::any => Ok(Predicate::Any(Predicate::parse_sequence(mis)?)), + sym::all => Ok(Predicate::All(Predicate::parse_sequence(mis)?)), + sym::not => match &**mis { + [one] => Ok(Predicate::Not(Box::new(Predicate::parse(one)?))), + [first, .., last] => Err(InvalidOnClause::ExpectedOnePredInNot { + span: first.span().to(last.span()), + }), + [] => Err(InvalidOnClause::ExpectedOnePredInNot { span: meta_item.span }), + }, + invalid_pred => { + Err(InvalidOnClause::InvalidPredicate { span: predicate.span, invalid_pred }) + } + }, + MetaItemKind::NameValue(MetaItemLit { symbol, .. }) => { + let name = Name::parse(predicate); + let value = FilterFormatString::parse(symbol); + let kv = NameValue { name, value }; + Ok(Predicate::Match(kv)) + } + MetaItemKind::Word => { + let flag = Flag::parse(predicate)?; + Ok(Predicate::Flag(flag)) + } + } + } + + fn parse_sequence(sequence: &[MetaItemInner]) -> Result, InvalidOnClause> { + sequence.iter().map(Predicate::parse).collect() + } + + fn eval(&self, eval: &mut impl FnMut(FlagOrNv<'_>) -> bool) -> bool { + match self { + Predicate::Flag(flag) => eval(FlagOrNv::Flag(flag)), + Predicate::Match(nv) => eval(FlagOrNv::NameValue(nv)), + Predicate::Not(not) => !not.eval(eval), + Predicate::All(preds) => preds.into_iter().all(|pred| pred.eval(eval)), + Predicate::Any(preds) => preds.into_iter().any(|pred| pred.eval(eval)), + } + } +} + +/// Represents a `MetaWord` in an `on`-filter. +#[derive(Debug, Clone, Copy)] +enum Flag { + /// Whether the code causing the trait bound to not be fulfilled + /// is part of the user's crate. + CrateLocal, + /// Whether the obligation is user-specified rather than derived. + Direct, + /// Whether we are in some kind of desugaring like + /// `?` or `try { .. }`. + FromDesugaring, +} + +impl Flag { + fn parse(Ident { name, span }: Ident) -> Result { + match name { + sym::crate_local => Ok(Flag::CrateLocal), + sym::direct => Ok(Flag::Direct), + sym::from_desugaring => Ok(Flag::FromDesugaring), + invalid_flag => Err(InvalidOnClause::InvalidFlag { invalid_flag, span }), + } + } +} + +/// A `MetaNameValueStr` in an `on`-filter. +/// +/// For example, `#[rustc_on_unimplemented(on(name = "value", message = "hello"))]`. +#[derive(Debug, Clone)] +struct NameValue { + name: Name, + /// Something like `"&str"` or `"alloc::string::String"`, + /// in which case it just contains a single string piece. + /// But if it is something like `"&[{A}]"` then it must be formatted later. + value: FilterFormatString, +} + +/// The valid names of the `on` filter. +#[derive(Debug, Clone, Copy)] +enum Name { + Cause, + FromDesugaring, + SelfUpper, + GenericArg(Symbol), +} + +impl Name { + fn parse(Ident { name, .. }: Ident) -> Self { + match name { + sym::_Self | kw::SelfUpper => Name::SelfUpper, + sym::from_desugaring => Name::FromDesugaring, + sym::cause => Name::Cause, + // FIXME(mejrs) Perhaps we should start checking that + // this actually is a valid generic parameter? + generic => Name::GenericArg(generic), + } + } +} + +#[derive(Debug, Clone)] +enum FlagOrNv<'p> { + Flag(&'p Flag), + NameValue(&'p NameValue), +} + +/// Represents a value inside an `on` filter. +/// +/// For example, `#[rustc_on_unimplemented(on(name = "value", message = "hello"))]`. +/// If it is a simple literal like this then `pieces` will be `[LitOrArg::Lit("value")]`. +/// The `Arg` variant is used when it contains formatting like +/// `#[rustc_on_unimplemented(on(Self = "&[{A}]", message = "hello"))]`. +#[derive(Debug, Clone)] +struct FilterFormatString { + pieces: Vec, +} + +#[derive(Debug, Clone)] +enum LitOrArg { + Lit(String), + Arg(String), +} + +impl FilterFormatString { + fn parse(input: Symbol) -> Self { + let pieces = Parser::new(input.as_str(), None, None, false, ParseMode::Format) + .map(|p| match p { + Piece::Lit(s) => LitOrArg::Lit(s.to_owned()), + // We just ignore formatspecs here + Piece::NextArgument(a) => match a.position { + // In `TypeErrCtxt::on_unimplemented_note` we substitute `"{integral}"` even + // if the integer type has been resolved, to allow targeting all integers. + // `"{integer}"` and `"{float}"` come from numerics that haven't been inferred yet, + // from the `Display` impl of `InferTy` to be precise. + // + // Don't try to format these later! + Position::ArgumentNamed(arg @ "integer" | arg @ "integral" | arg @ "float") => { + LitOrArg::Lit(format!("{{{arg}}}")) + } + + // FIXME(mejrs) We should check if these correspond to a generic of the trait. + Position::ArgumentNamed(arg) => LitOrArg::Arg(arg.to_owned()), + + // FIXME(mejrs) These should really be warnings/errors + Position::ArgumentImplicitlyIs(_) => LitOrArg::Lit(String::from("{}")), + Position::ArgumentIs(idx) => LitOrArg::Lit(format!("{{{idx}}}")), + }, + }) + .collect(); + Self { pieces } + } + + fn format(&self, generic_args: &[(Symbol, String)]) -> String { + let mut ret = String::new(); + + for piece in &self.pieces { + match piece { + LitOrArg::Lit(s) => ret.push_str(s), + LitOrArg::Arg(arg) => { + let s = Symbol::intern(arg); + match generic_args.iter().find(|(k, _)| *k == s) { + Some((_, val)) => ret.push_str(val), + None => { + // FIXME(mejrs) If we start checking as mentioned in + // FilterFormatString::parse then this shouldn't happen + let _ = std::fmt::write(&mut ret, format_args!("{{{s}}}")); + } + } + } + } + } + + ret + } +} + +/// Used with `OnUnimplementedCondition::matches_predicate` to evaluate the +/// [`OnUnimplementedCondition`]. /// /// For example, given a /// ```rust,ignore (just an example) @@ -85,36 +284,34 @@ impl Condition { /// } /// ``` #[derive(Debug)] -pub struct ConditionOptions { +pub(crate) struct ConditionOptions { /// All the self types that may apply. - /// for example - pub self_types: Vec, + pub(crate) self_types: Vec, // The kind of compiler desugaring. - pub from_desugaring: Option, - /// Match on a variant of [rustc_infer::traits::ObligationCauseCode] - pub cause: Option, - pub crate_local: bool, + pub(crate) from_desugaring: Option, + /// Match on a variant of [rustc_infer::traits::ObligationCauseCode]. + pub(crate) cause: Option, + pub(crate) crate_local: bool, /// Is the obligation "directly" user-specified, rather than derived? - pub direct: bool, - // A list of the generic arguments and their reified types - pub generic_args: Vec<(Symbol, String)>, + pub(crate) direct: bool, + // A list of the generic arguments and their reified types. + pub(crate) generic_args: Vec<(Symbol, String)>, } impl ConditionOptions { - pub fn contains(&self, key: Symbol, value: &Option) -> bool { - match (key, value) { - (sym::_Self | kw::SelfUpper, Some(value)) => self.self_types.contains(&value), - // from_desugaring as a flag - (sym::from_desugaring, None) => self.from_desugaring.is_some(), - // from_desugaring as key == value - (sym::from_desugaring, Some(v)) if let Some(ds) = self.from_desugaring => ds.matches(v), - (sym::cause, Some(value)) => self.cause.as_deref() == Some(value), - (sym::crate_local, None) => self.crate_local, - (sym::direct, None) => self.direct, - (other, Some(value)) => { - self.generic_args.iter().any(|(k, v)| *k == other && v == value) - } - _ => false, + fn has_flag(&self, name: Flag) -> bool { + match name { + Flag::CrateLocal => self.crate_local, + Flag::Direct => self.direct, + Flag::FromDesugaring => self.from_desugaring.is_some(), + } + } + fn contains(&self, name: Name, value: String) -> bool { + match name { + Name::SelfUpper => self.self_types.contains(&value), + Name::FromDesugaring => self.from_desugaring.is_some_and(|ds| ds.matches(&value)), + Name::Cause => self.cause == Some(value), + Name::GenericArg(arg) => self.generic_args.contains(&(arg, value)), } } } diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_format.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_format.rs index f835406122b8..d8b90844b7d2 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_format.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_format.rs @@ -1,11 +1,12 @@ use std::fmt; +use std::ops::Range; use errors::*; use rustc_middle::ty::TyCtxt; use rustc_middle::ty::print::TraitRefPrintSugared; use rustc_parse_format::{ - Alignment, Argument, Count, FormatSpec, InnerSpan, ParseError, ParseMode, Parser, - Piece as RpfPiece, Position, + Alignment, Argument, Count, FormatSpec, ParseError, ParseMode, Parser, Piece as RpfPiece, + Position, }; use rustc_session::lint::builtin::UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES; use rustc_span::def_id::DefId; @@ -173,7 +174,7 @@ impl FormatString { pieces.push(Piece::Lit(lit.into())); } RpfPiece::NextArgument(arg) => { - warn_on_format_spec(arg.format, &mut warnings, span); + warn_on_format_spec(arg.format.clone(), &mut warnings, span); let arg = parse_arg(&arg, ctx, &mut warnings, span); pieces.push(Piece::Arg(arg)); } @@ -233,7 +234,7 @@ fn parse_arg<'tcx>( | Ctx::DiagnosticOnUnimplemented { tcx, trait_def_id }) = ctx; let trait_name = tcx.item_ident(*trait_def_id); let generics = tcx.generics_of(trait_def_id); - let span = slice_span(input_span, arg.position_span); + let span = slice_span(input_span, arg.position_span.clone()); match arg.position { // Something like "hello {name}" @@ -335,14 +336,12 @@ fn warn_on_format_spec(spec: FormatSpec<'_>, warnings: &mut Vec, } } -/// Helper function because `Span` and `rustc_parse_format::InnerSpan` don't know about each other -fn slice_span(input: Span, inner: InnerSpan) -> Span { - let InnerSpan { start, end } = inner; +fn slice_span(input: Span, range: Range) -> Span { let span = input.data(); Span::new( - span.lo + BytePos::from_usize(start), - span.lo + BytePos::from_usize(end), + span.lo + BytePos::from_usize(range.start), + span.lo + BytePos::from_usize(range.end), span.ctxt, span.parent, ) diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs index 1063115ed237..04cae1c9b641 100644 --- a/compiler/rustc_trait_selection/src/errors.rs +++ b/compiler/rustc_trait_selection/src/errors.rs @@ -1,5 +1,6 @@ use std::path::PathBuf; +use rustc_ast::Path; use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; use rustc_errors::codes::*; use rustc_errors::{ @@ -31,23 +32,50 @@ pub struct UnableToConstructConstantValue<'a> { } #[derive(Diagnostic)] -#[diag(trait_selection_empty_on_clause_in_rustc_on_unimplemented, code = E0232)] -pub struct EmptyOnClauseInOnUnimplemented { - #[primary_span] - #[label] - pub span: Span, +pub enum InvalidOnClause { + #[diag(trait_selection_rustc_on_unimplemented_empty_on_clause, code = E0232)] + Empty { + #[primary_span] + #[label] + span: Span, + }, + #[diag(trait_selection_rustc_on_unimplemented_expected_one_predicate_in_not, code = E0232)] + ExpectedOnePredInNot { + #[primary_span] + #[label] + span: Span, + }, + #[diag(trait_selection_rustc_on_unimplemented_unsupported_literal_in_on, code = E0232)] + UnsupportedLiteral { + #[primary_span] + #[label] + span: Span, + }, + #[diag(trait_selection_rustc_on_unimplemented_expected_identifier, code = E0232)] + ExpectedIdentifier { + #[primary_span] + #[label] + span: Span, + path: Path, + }, + #[diag(trait_selection_rustc_on_unimplemented_invalid_predicate, code = E0232)] + InvalidPredicate { + #[primary_span] + #[label] + span: Span, + invalid_pred: Symbol, + }, + #[diag(trait_selection_rustc_on_unimplemented_invalid_flag, code = E0232)] + InvalidFlag { + #[primary_span] + #[label] + span: Span, + invalid_flag: Symbol, + }, } #[derive(Diagnostic)] -#[diag(trait_selection_invalid_on_clause_in_rustc_on_unimplemented, code = E0232)] -pub struct InvalidOnClauseInOnUnimplemented { - #[primary_span] - #[label] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(trait_selection_no_value_in_rustc_on_unimplemented, code = E0232)] +#[diag(trait_selection_rustc_on_unimplemented_missing_value, code = E0232)] #[note] pub struct NoValueInOnUnimplemented { #[primary_span] diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs index cce67b066dde..332204a0c5f0 100644 --- a/compiler/rustc_trait_selection/src/opaque_types.rs +++ b/compiler/rustc_trait_selection/src/opaque_types.rs @@ -13,6 +13,49 @@ use crate::errors::NonGenericOpaqueTypeParam; use crate::regions::OutlivesEnvironmentBuildExt; use crate::traits::ObligationCtxt; +pub enum InvalidOpaqueTypeArgs<'tcx> { + AlreadyReported(ErrorGuaranteed), + NotAParam { opaque_type_key: OpaqueTypeKey<'tcx>, param_index: usize, span: Span }, + DuplicateParam { opaque_type_key: OpaqueTypeKey<'tcx>, param_indices: Vec, span: Span }, +} +impl From for InvalidOpaqueTypeArgs<'_> { + fn from(guar: ErrorGuaranteed) -> Self { + InvalidOpaqueTypeArgs::AlreadyReported(guar) + } +} +impl<'tcx> InvalidOpaqueTypeArgs<'tcx> { + pub fn report(self, infcx: &InferCtxt<'tcx>) -> ErrorGuaranteed { + let tcx = infcx.tcx; + match self { + InvalidOpaqueTypeArgs::AlreadyReported(guar) => guar, + InvalidOpaqueTypeArgs::NotAParam { opaque_type_key, param_index, span } => { + let opaque_generics = tcx.generics_of(opaque_type_key.def_id); + let opaque_param = opaque_generics.param_at(param_index, tcx); + let kind = opaque_param.kind.descr(); + infcx.dcx().emit_err(NonGenericOpaqueTypeParam { + arg: opaque_type_key.args[param_index], + kind, + span, + param_span: tcx.def_span(opaque_param.def_id), + }) + } + InvalidOpaqueTypeArgs::DuplicateParam { opaque_type_key, param_indices, span } => { + let opaque_generics = tcx.generics_of(opaque_type_key.def_id); + let descr = opaque_generics.param_at(param_indices[0], tcx).kind.descr(); + let spans: Vec<_> = param_indices + .into_iter() + .map(|i| tcx.def_span(opaque_generics.param_at(i, tcx).def_id)) + .collect(); + infcx + .dcx() + .struct_span_err(span, "non-defining opaque type use in defining scope") + .with_span_note(spans, format!("{descr} used multiple times")) + .emit() + } + } + } +} + /// Opaque type parameter validity check as documented in the [rustc-dev-guide chapter]. /// /// [rustc-dev-guide chapter]: @@ -22,23 +65,19 @@ pub fn check_opaque_type_parameter_valid<'tcx>( opaque_type_key: OpaqueTypeKey<'tcx>, span: Span, defining_scope_kind: DefiningScopeKind, -) -> Result<(), ErrorGuaranteed> { +) -> Result<(), InvalidOpaqueTypeArgs<'tcx>> { let tcx = infcx.tcx; - let opaque_generics = tcx.generics_of(opaque_type_key.def_id); let opaque_env = LazyOpaqueTyEnv::new(tcx, opaque_type_key.def_id); let mut seen_params: FxIndexMap<_, Vec<_>> = FxIndexMap::default(); // Avoid duplicate errors in case the opaque has already been malformed in // HIR typeck. if let DefiningScopeKind::MirBorrowck = defining_scope_kind { - if let Err(guar) = infcx + infcx .tcx .type_of_opaque_hir_typeck(opaque_type_key.def_id) .instantiate_identity() - .error_reported() - { - return Err(guar); - } + .error_reported()?; } for (i, arg) in opaque_type_key.iter_captured_args(tcx) { @@ -64,32 +103,18 @@ pub fn check_opaque_type_parameter_valid<'tcx>( } } else { // Prevent `fn foo() -> Foo` from being defining. - let opaque_param = opaque_generics.param_at(i, tcx); - let kind = opaque_param.kind.descr(); - opaque_env.param_is_error(i)?; - - return Err(infcx.dcx().emit_err(NonGenericOpaqueTypeParam { - arg, - kind, - span, - param_span: tcx.def_span(opaque_param.def_id), - })); + return Err(InvalidOpaqueTypeArgs::NotAParam { opaque_type_key, param_index: i, span }); } } - for (_, indices) in seen_params { - if indices.len() > 1 { - let descr = opaque_generics.param_at(indices[0], tcx).kind.descr(); - let spans: Vec<_> = indices - .into_iter() - .map(|i| tcx.def_span(opaque_generics.param_at(i, tcx).def_id)) - .collect(); - return Err(infcx - .dcx() - .struct_span_err(span, "non-defining opaque type use in defining scope") - .with_span_note(spans, format!("{descr} used multiple times")) - .emit()); + for (_, param_indices) in seen_params { + if param_indices.len() > 1 { + return Err(InvalidOpaqueTypeArgs::DuplicateParam { + opaque_type_key, + param_indices, + span, + }); } } diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs index ef64da131891..87b8db59a78e 100644 --- a/compiler/rustc_trait_selection/src/solve/delegate.rs +++ b/compiler/rustc_trait_selection/src/solve/delegate.rs @@ -104,8 +104,23 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< .map(|obligations| obligations.into_iter().map(|obligation| obligation.as_goal()).collect()) } - fn clone_opaque_types_for_query_response(&self) -> Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)> { - self.0.clone_opaque_types_for_query_response() + fn clone_opaque_types_lookup_table(&self) -> Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)> { + self.0 + .inner + .borrow_mut() + .opaque_types() + .iter_lookup_table() + .map(|(k, h)| (k, h.ty)) + .collect() + } + fn clone_duplicate_opaque_types(&self) -> Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)> { + self.0 + .inner + .borrow_mut() + .opaque_types() + .iter_duplicate_entries() + .map(|(k, h)| (k, h.ty)) + .collect() } fn make_deduplicated_outlives_constraints( @@ -156,14 +171,26 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< fn register_hidden_type_in_storage( &self, opaque_type_key: ty::OpaqueTypeKey<'tcx>, - hidden_ty: ::Ty, - span: ::Span, - ) -> Option<::Ty> { + hidden_ty: Ty<'tcx>, + span: Span, + ) -> Option> { self.0.register_hidden_type_in_storage( opaque_type_key, ty::OpaqueHiddenType { span, ty: hidden_ty }, ) } + fn add_duplicate_opaque_type( + &self, + opaque_type_key: ty::OpaqueTypeKey<'tcx>, + hidden_ty: Ty<'tcx>, + span: Span, + ) { + self.0 + .inner + .borrow_mut() + .opaque_types() + .add_duplicate(opaque_type_key, ty::OpaqueHiddenType { span, ty: hidden_ty }) + } fn add_item_bounds_for_hidden_type( &self, diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 0987c5b42d88..5b938456e03b 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -51,7 +51,7 @@ pub use self::dyn_compatibility::{ pub use self::engine::{ObligationCtxt, TraitEngineExt}; pub use self::fulfill::{FulfillmentContext, OldSolverError, PendingPredicateObligation}; pub use self::normalize::NormalizeExt; -pub use self::project::{normalize_inherent_projection, normalize_projection_ty}; +pub use self::project::{normalize_inherent_projection, normalize_projection_term}; pub use self::select::{ EvaluationCache, EvaluationResult, IntercrateAmbiguityCause, OverflowError, SelectionCache, SelectionContext, diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs index 5f0acd46f86a..88a0c402702e 100644 --- a/compiler/rustc_trait_selection/src/traits/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/normalize.rs @@ -1,6 +1,7 @@ //! Deeply normalize types using the old trait solver. use rustc_data_structures::stack::ensure_sufficient_stack; +use rustc_hir::def::DefKind; use rustc_infer::infer::at::At; use rustc_infer::infer::{InferCtxt, InferOk}; use rustc_infer::traits::{ @@ -10,15 +11,12 @@ use rustc_macros::extension; use rustc_middle::span_bug; use rustc_middle::traits::{ObligationCause, ObligationCauseCode}; use rustc_middle::ty::{ - self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable, TypeVisitableExt, - TypingMode, + self, AliasTerm, Term, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable, + TypeVisitableExt, TypingMode, }; use tracing::{debug, instrument}; -use super::{ - BoundVarReplacer, PlaceholderReplacer, SelectionContext, project, - with_replaced_escaping_bound_vars, -}; +use super::{BoundVarReplacer, PlaceholderReplacer, SelectionContext, project}; use crate::error_reporting::InferCtxtErrorExt; use crate::error_reporting::traits::OverflowCause; use crate::solve::NextSolverError; @@ -178,6 +176,163 @@ impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> { if !needs_normalization(self.selcx.infcx, &value) { value } else { value.fold_with(self) } } + + // FIXME(mgca): While this supports constants, it is only used for types by default right now + #[instrument(level = "debug", skip(self), ret)] + fn normalize_trait_projection(&mut self, proj: AliasTerm<'tcx>) -> Term<'tcx> { + if !proj.has_escaping_bound_vars() { + // When we don't have escaping bound vars we can normalize ambig aliases + // to inference variables (done in `normalize_projection_ty`). This would + // be wrong if there were escaping bound vars as even if we instantiated + // the bound vars with placeholders, we wouldn't be able to map them back + // after normalization succeeded. + // + // Also, as an optimization: when we don't have escaping bound vars, we don't + // need to replace them with placeholders (see branch below). + let proj = proj.fold_with(self); + project::normalize_projection_term( + self.selcx, + self.param_env, + proj, + self.cause.clone(), + self.depth, + self.obligations, + ) + } else { + // If there are escaping bound vars, we temporarily replace the + // bound vars with placeholders. Note though, that in the case + // that we still can't project for whatever reason (e.g. self + // type isn't known enough), we *can't* register an obligation + // and return an inference variable (since then that obligation + // would have bound vars and that's a can of worms). Instead, + // we just give up and fall back to pretending like we never tried! + // + // Note: this isn't necessarily the final approach here; we may + // want to figure out how to register obligations with escaping vars + // or handle this some other way. + let infcx = self.selcx.infcx; + let (proj, mapped_regions, mapped_types, mapped_consts) = + BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, proj); + let proj = proj.fold_with(self); + let normalized_term = project::opt_normalize_projection_term( + self.selcx, + self.param_env, + proj, + self.cause.clone(), + self.depth, + self.obligations, + ) + .ok() + .flatten() + .unwrap_or(proj.to_term(infcx.tcx)); + + PlaceholderReplacer::replace_placeholders( + infcx, + mapped_regions, + mapped_types, + mapped_consts, + &self.universes, + normalized_term, + ) + } + } + + // FIXME(mgca): While this supports constants, it is only used for types by default right now + #[instrument(level = "debug", skip(self), ret)] + fn normalize_inherent_projection(&mut self, inherent: AliasTerm<'tcx>) -> Term<'tcx> { + if !inherent.has_escaping_bound_vars() { + // When we don't have escaping bound vars we can normalize ambig aliases + // to inference variables (done in `normalize_projection_ty`). This would + // be wrong if there were escaping bound vars as even if we instantiated + // the bound vars with placeholders, we wouldn't be able to map them back + // after normalization succeeded. + // + // Also, as an optimization: when we don't have escaping bound vars, we don't + // need to replace them with placeholders (see branch below). + + let inherent = inherent.fold_with(self); + project::normalize_inherent_projection( + self.selcx, + self.param_env, + inherent, + self.cause.clone(), + self.depth, + self.obligations, + ) + } else { + let infcx = self.selcx.infcx; + let (inherent, mapped_regions, mapped_types, mapped_consts) = + BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, inherent); + let inherent = inherent.fold_with(self); + let inherent = project::normalize_inherent_projection( + self.selcx, + self.param_env, + inherent, + self.cause.clone(), + self.depth, + self.obligations, + ); + + PlaceholderReplacer::replace_placeholders( + infcx, + mapped_regions, + mapped_types, + mapped_consts, + &self.universes, + inherent, + ) + } + } + + // FIXME(mgca): While this supports constants, it is only used for types by default right now + #[instrument(level = "debug", skip(self), ret)] + fn normalize_free_alias(&mut self, free: AliasTerm<'tcx>) -> Term<'tcx> { + let recursion_limit = self.cx().recursion_limit(); + if !recursion_limit.value_within_limit(self.depth) { + self.selcx.infcx.err_ctxt().report_overflow_error( + OverflowCause::DeeplyNormalize(free.into()), + self.cause.span, + false, + |diag| { + diag.note(crate::fluent_generated::trait_selection_ty_alias_overflow); + }, + ); + } + + let infcx = self.selcx.infcx; + self.obligations.extend( + // FIXME(BoxyUwU): + // FIXME(lazy_type_alias): + // It seems suspicious to instantiate the predicates with arguments that might be bound vars, + // we might wind up instantiating one of these bound vars underneath a hrtb. + infcx.tcx.predicates_of(free.def_id).instantiate_own(infcx.tcx, free.args).map( + |(mut predicate, span)| { + if free.has_escaping_bound_vars() { + (predicate, ..) = BoundVarReplacer::replace_bound_vars( + infcx, + &mut self.universes, + predicate, + ); + } + let mut cause = self.cause.clone(); + cause.map_code(|code| ObligationCauseCode::TypeAlias(code, span, free.def_id)); + Obligation::new(infcx.tcx, cause, self.param_env, predicate) + }, + ), + ); + self.depth += 1; + let res = if free.kind(infcx.tcx).is_type() { + infcx.tcx.type_of(free.def_id).instantiate(infcx.tcx, free.args).fold_with(self).into() + } else { + // FIXME(mgca): once const items are actual aliases defined as equal to type system consts + // this should instead use that rather than evaluating. + super::evaluate_const(infcx, free.to_term(infcx.tcx).expect_const(), self.param_env) + .super_fold_with(self) + .into() + }; + self.depth -= 1; + res + } } impl<'a, 'b, 'tcx> TypeFolder> for AssocTypeNormalizer<'a, 'b, 'tcx> { @@ -259,186 +414,63 @@ impl<'a, 'b, 'tcx> TypeFolder> for AssocTypeNormalizer<'a, 'b, 'tcx } } - ty::Projection if !data.has_escaping_bound_vars() => { - // When we don't have escaping bound vars we can normalize ambig aliases - // to inference variables (done in `normalize_projection_ty`). This would - // be wrong if there were escaping bound vars as even if we instantiated - // the bound vars with placeholders, we wouldn't be able to map them back - // after normalization succeeded. - // - // Also, as an optimization: when we don't have escaping bound vars, we don't - // need to replace them with placeholders (see branch below). - let data = data.fold_with(self); - let normalized_ty = project::normalize_projection_ty( - self.selcx, - self.param_env, - data, - self.cause.clone(), - self.depth, - self.obligations, - ); - debug!( - ?self.depth, - ?ty, - ?normalized_ty, - obligations.len = ?self.obligations.len(), - "AssocTypeNormalizer: normalized type" - ); - normalized_ty.expect_type() - } - - ty::Projection => { - // If there are escaping bound vars, we temporarily replace the - // bound vars with placeholders. Note though, that in the case - // that we still can't project for whatever reason (e.g. self - // type isn't known enough), we *can't* register an obligation - // and return an inference variable (since then that obligation - // would have bound vars and that's a can of worms). Instead, - // we just give up and fall back to pretending like we never tried! - // - // Note: this isn't necessarily the final approach here; we may - // want to figure out how to register obligations with escaping vars - // or handle this some other way. - - let infcx = self.selcx.infcx; - let (data, mapped_regions, mapped_types, mapped_consts) = - BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, data); - let data = data.fold_with(self); - let normalized_ty = project::opt_normalize_projection_term( - self.selcx, - self.param_env, - data.into(), - self.cause.clone(), - self.depth, - self.obligations, - ) - .ok() - .flatten() - .map(|term| term.expect_type()) - .map(|normalized_ty| { - PlaceholderReplacer::replace_placeholders( - infcx, - mapped_regions, - mapped_types, - mapped_consts, - &self.universes, - normalized_ty, - ) - }) - .unwrap_or_else(|| ty.super_fold_with(self)); - - debug!( - ?self.depth, - ?ty, - ?normalized_ty, - obligations.len = ?self.obligations.len(), - "AssocTypeNormalizer: normalized type" - ); - normalized_ty - } - ty::Free => { - let recursion_limit = self.cx().recursion_limit(); - if !recursion_limit.value_within_limit(self.depth) { - self.selcx.infcx.err_ctxt().report_overflow_error( - OverflowCause::DeeplyNormalize(data.into()), - self.cause.span, - false, - |diag| { - diag.note(crate::fluent_generated::trait_selection_ty_alias_overflow); - }, - ); - } - - let infcx = self.selcx.infcx; - self.obligations.extend( - infcx.tcx.predicates_of(data.def_id).instantiate_own(infcx.tcx, data.args).map( - |(mut predicate, span)| { - if data.has_escaping_bound_vars() { - (predicate, ..) = BoundVarReplacer::replace_bound_vars( - infcx, - &mut self.universes, - predicate, - ); - } - let mut cause = self.cause.clone(); - cause.map_code(|code| { - ObligationCauseCode::TypeAlias(code, span, data.def_id) - }); - Obligation::new(infcx.tcx, cause, self.param_env, predicate) - }, - ), - ); - self.depth += 1; - let res = infcx - .tcx - .type_of(data.def_id) - .instantiate(infcx.tcx, data.args) - .fold_with(self); - self.depth -= 1; - res - } - - ty::Inherent if !data.has_escaping_bound_vars() => { - // This branch is *mostly* just an optimization: when we don't - // have escaping bound vars, we don't need to replace them with - // placeholders (see branch below). *Also*, we know that we can - // register an obligation to *later* project, since we know - // there won't be bound vars there. - - let data = data.fold_with(self); - - project::normalize_inherent_projection( - self.selcx, - self.param_env, - data, - self.cause.clone(), - self.depth, - self.obligations, - ) - } - - ty::Inherent => { - let infcx = self.selcx.infcx; - let (data, mapped_regions, mapped_types, mapped_consts) = - BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, data); - let data = data.fold_with(self); - let ty = project::normalize_inherent_projection( - self.selcx, - self.param_env, - data, - self.cause.clone(), - self.depth, - self.obligations, - ); - - PlaceholderReplacer::replace_placeholders( - infcx, - mapped_regions, - mapped_types, - mapped_consts, - &self.universes, - ty, - ) - } + ty::Projection => self.normalize_trait_projection(data.into()).expect_type(), + ty::Inherent => self.normalize_inherent_projection(data.into()).expect_type(), + ty::Free => self.normalize_free_alias(data.into()).expect_type(), } } #[instrument(skip(self), level = "debug")] - fn fold_const(&mut self, constant: ty::Const<'tcx>) -> ty::Const<'tcx> { + fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { let tcx = self.selcx.tcx(); - if tcx.features().generic_const_exprs() || !needs_normalization(self.selcx.infcx, &constant) - { - constant + if tcx.features().generic_const_exprs() || !needs_normalization(self.selcx.infcx, &ct) { + return ct; + } + + // Doing "proper" normalization of const aliases is inherently cyclic until const items + // are real aliases instead of having bodies. We gate proper const alias handling behind + // mgca to avoid breaking stable code, though this should become the "main" codepath long + // before mgca is stabilized. + // + // FIXME(BoxyUwU): Enabling this by default is blocked on a refactoring to how const items + // are represented. + if tcx.features().min_generic_const_args() { + let uv = match ct.kind() { + ty::ConstKind::Unevaluated(uv) => uv, + _ => return ct.super_fold_with(self), + }; + + let ct = match tcx.def_kind(uv.def) { + DefKind::AssocConst => match tcx.def_kind(tcx.parent(uv.def)) { + DefKind::Trait => self.normalize_trait_projection(uv.into()), + DefKind::Impl { of_trait: false } => { + self.normalize_inherent_projection(uv.into()) + } + kind => unreachable!( + "unexpected `DefKind` for const alias' resolution's parent def: {:?}", + kind + ), + }, + DefKind::Const | DefKind::AnonConst => self.normalize_free_alias(uv.into()), + kind => { + unreachable!("unexpected `DefKind` for const alias to resolve to: {:?}", kind) + } + }; + + // We re-fold the normalized const as the `ty` field on `ConstKind::Value` may be + // unnormalized after const evaluation returns. + ct.expect_const().super_fold_with(self) } else { - let constant = constant.super_fold_with(self); - debug!(?constant, ?self.param_env); - with_replaced_escaping_bound_vars( + let ct = ct.super_fold_with(self); + return super::with_replaced_escaping_bound_vars( self.selcx.infcx, &mut self.universes, - constant, - |constant| super::evaluate_const(self.selcx.infcx, constant, self.param_env), + ct, + |ct| super::evaluate_const(self.selcx.infcx, ct, self.param_env), ) - .super_fold_with(self) + .super_fold_with(self); + // We re-fold the normalized const as the `ty` field on `ConstKind::Value` may be + // unnormalized after const evaluation returns. } } diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index dd868c9d40ea..ca58da5ca6d5 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -5,7 +5,6 @@ use std::ops::ControlFlow; use rustc_data_structures::sso::SsoHashSet; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::ErrorGuaranteed; -use rustc_hir::def::DefKind; use rustc_hir::lang_items::LangItem; use rustc_infer::infer::DefineOpaqueTypes; use rustc_infer::infer::resolve::OpportunisticRegionResolver; @@ -172,6 +171,7 @@ pub(super) enum ProjectAndUnifyResult<'tcx> { /// ``` /// If successful, this may result in additional obligations. Also returns /// the projection cache key used to track these additional obligations. +// FIXME(mgca): While this supports constants, it is only used for types by default right now #[instrument(level = "debug", skip(selcx))] pub(super) fn poly_project_and_unify_term<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, @@ -201,6 +201,7 @@ pub(super) fn poly_project_and_unify_term<'cx, 'tcx>( /// If successful, this may result in additional obligations. /// /// See [poly_project_and_unify_term] for an explanation of the return value. +// FIXME(mgca): While this supports constants, it is only used for types by default right now #[instrument(level = "debug", skip(selcx))] fn project_and_unify_term<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, @@ -258,34 +259,28 @@ fn project_and_unify_term<'cx, 'tcx>( /// there are unresolved type variables in the projection, we will /// instantiate it with a fresh type variable `$X` and generate a new /// obligation `::Item == $X` for later. -pub fn normalize_projection_ty<'a, 'b, 'tcx>( +// FIXME(mgca): While this supports constants, it is only used for types by default right now +pub fn normalize_projection_term<'a, 'b, 'tcx>( selcx: &'a mut SelectionContext<'b, 'tcx>, param_env: ty::ParamEnv<'tcx>, - projection_ty: ty::AliasTy<'tcx>, + alias_term: ty::AliasTerm<'tcx>, cause: ObligationCause<'tcx>, depth: usize, obligations: &mut PredicateObligations<'tcx>, ) -> Term<'tcx> { - opt_normalize_projection_term( - selcx, - param_env, - projection_ty.into(), - cause.clone(), - depth, - obligations, - ) - .ok() - .flatten() - .unwrap_or_else(move || { - // if we bottom out in ambiguity, create a type variable - // and a deferred predicate to resolve this when more type - // information is available. + opt_normalize_projection_term(selcx, param_env, alias_term, cause.clone(), depth, obligations) + .ok() + .flatten() + .unwrap_or_else(move || { + // if we bottom out in ambiguity, create a type variable + // and a deferred predicate to resolve this when more type + // information is available. - selcx - .infcx - .projection_ty_to_infer(param_env, projection_ty, cause, depth + 1, obligations) - .into() - }) + selcx + .infcx + .projection_term_to_infer(param_env, alias_term, cause, depth + 1, obligations) + .into() + }) } /// The guts of `normalize`: normalize a specific projection like `( /// often immediately appended to another obligations vector. So now this /// function takes an obligations vector and appends to it directly, which is /// slightly uglier but avoids the need for an extra short-lived allocation. +// FIXME(mgca): While this supports constants, it is only used for types by default right now #[instrument(level = "debug", skip(selcx, param_env, cause, obligations))] pub(super) fn opt_normalize_projection_term<'a, 'b, 'tcx>( selcx: &'a mut SelectionContext<'b, 'tcx>, @@ -456,6 +452,7 @@ pub(super) fn opt_normalize_projection_term<'a, 'b, 'tcx>( /// an error for this obligation, but we legitimately should not, /// because it contains `[type error]`. Yuck! (See issue #29857 for /// one case where this arose.) +// FIXME(mgca): While this supports constants, it is only used for types by default right now fn normalize_to_error<'a, 'tcx>( selcx: &SelectionContext<'a, 'tcx>, param_env: ty::ParamEnv<'tcx>, @@ -469,9 +466,10 @@ fn normalize_to_error<'a, 'tcx>( | ty::AliasTermKind::InherentTy | ty::AliasTermKind::OpaqueTy | ty::AliasTermKind::FreeTy => selcx.infcx.next_ty_var(cause.span).into(), - ty::AliasTermKind::UnevaluatedConst | ty::AliasTermKind::ProjectionConst => { - selcx.infcx.next_const_var(cause.span).into() - } + ty::AliasTermKind::FreeConst + | ty::AliasTermKind::InherentConst + | ty::AliasTermKind::UnevaluatedConst + | ty::AliasTermKind::ProjectionConst => selcx.infcx.next_const_var(cause.span).into(), }; let mut obligations = PredicateObligations::new(); obligations.push(Obligation { @@ -484,36 +482,37 @@ fn normalize_to_error<'a, 'tcx>( } /// Confirm and normalize the given inherent projection. +// FIXME(mgca): While this supports constants, it is only used for types by default right now #[instrument(level = "debug", skip(selcx, param_env, cause, obligations))] pub fn normalize_inherent_projection<'a, 'b, 'tcx>( selcx: &'a mut SelectionContext<'b, 'tcx>, param_env: ty::ParamEnv<'tcx>, - alias_ty: ty::AliasTy<'tcx>, + alias_term: ty::AliasTerm<'tcx>, cause: ObligationCause<'tcx>, depth: usize, obligations: &mut PredicateObligations<'tcx>, -) -> Ty<'tcx> { +) -> ty::Term<'tcx> { let tcx = selcx.tcx(); if !tcx.recursion_limit().value_within_limit(depth) { // Halt compilation because it is important that overflows never be masked. tcx.dcx().emit_fatal(InherentProjectionNormalizationOverflow { span: cause.span, - ty: alias_ty.to_string(), + ty: alias_term.to_string(), }); } - let args = compute_inherent_assoc_ty_args( + let args = compute_inherent_assoc_term_args( selcx, param_env, - alias_ty, + alias_term, cause.clone(), depth, obligations, ); // Register the obligations arising from the impl and from the associated type itself. - let predicates = tcx.predicates_of(alias_ty.def_id).instantiate(tcx, args); + let predicates = tcx.predicates_of(alias_term.def_id).instantiate(tcx, args); for (predicate, span) in predicates { let predicate = normalize_with_depth_to( selcx, @@ -531,7 +530,7 @@ pub fn normalize_inherent_projection<'a, 'b, 'tcx>( // cause code, inherent projections will be printed with identity instantiation in // diagnostics which is not ideal. // Consider creating separate cause codes for this specific situation. - ObligationCauseCode::WhereClause(alias_ty.def_id, span), + ObligationCauseCode::WhereClause(alias_term.def_id, span), ); obligations.push(Obligation::with_depth( @@ -543,27 +542,33 @@ pub fn normalize_inherent_projection<'a, 'b, 'tcx>( )); } - let ty = tcx.type_of(alias_ty.def_id).instantiate(tcx, args); + let term: Term<'tcx> = if alias_term.kind(tcx).is_type() { + tcx.type_of(alias_term.def_id).instantiate(tcx, args).into() + } else { + get_associated_const_value(selcx, alias_term.to_term(tcx).expect_const(), param_env).into() + }; - let mut ty = selcx.infcx.resolve_vars_if_possible(ty); - if ty.has_aliases() { - ty = normalize_with_depth_to(selcx, param_env, cause.clone(), depth + 1, ty, obligations); + let mut term = selcx.infcx.resolve_vars_if_possible(term); + if term.has_aliases() { + term = + normalize_with_depth_to(selcx, param_env, cause.clone(), depth + 1, term, obligations); } - ty + term } -pub fn compute_inherent_assoc_ty_args<'a, 'b, 'tcx>( +// FIXME(mgca): While this supports constants, it is only used for types by default right now +pub fn compute_inherent_assoc_term_args<'a, 'b, 'tcx>( selcx: &'a mut SelectionContext<'b, 'tcx>, param_env: ty::ParamEnv<'tcx>, - alias_ty: ty::AliasTy<'tcx>, + alias_term: ty::AliasTerm<'tcx>, cause: ObligationCause<'tcx>, depth: usize, obligations: &mut PredicateObligations<'tcx>, ) -> ty::GenericArgsRef<'tcx> { let tcx = selcx.tcx(); - let impl_def_id = tcx.parent(alias_ty.def_id); + let impl_def_id = tcx.parent(alias_term.def_id); let impl_args = selcx.infcx.fresh_args_for_item(cause.span, impl_def_id); let mut impl_ty = tcx.type_of(impl_def_id).instantiate(tcx, impl_args); @@ -580,7 +585,7 @@ pub fn compute_inherent_assoc_ty_args<'a, 'b, 'tcx>( // Infer the generic parameters of the impl by unifying the // impl type with the self type of the projection. - let mut self_ty = alias_ty.self_ty(); + let mut self_ty = alias_term.self_ty(); if !selcx.infcx.next_trait_solver() { self_ty = normalize_with_depth_to( selcx, @@ -602,7 +607,7 @@ pub fn compute_inherent_assoc_ty_args<'a, 'b, 'tcx>( } } - alias_ty.rebase_inherent_args_onto_impl(impl_args, tcx) + alias_term.rebase_inherent_args_onto_impl(impl_args, tcx) } enum Projected<'tcx> { @@ -630,6 +635,7 @@ impl<'tcx> Progress<'tcx> { /// /// IMPORTANT: /// - `obligation` must be fully normalized +// FIXME(mgca): While this supports constants, it is only used for types by default right now #[instrument(level = "info", skip(selcx))] fn project<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, @@ -896,7 +902,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( ImplSource::UserDefined(impl_data) => { // We have to be careful when projecting out of an // impl because of specialization. If we are not in - // codegen (i.e., projection mode is not "any"), and the + // codegen (i.e., `TypingMode` is not `PostAnalysis`), and the // impl's type is declared as default, then we disable // projection (even if the trait ref is fully // monomorphic). In the case where trait ref is not @@ -1189,6 +1195,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( }); } +// FIXME(mgca): While this supports constants, it is only used for types by default right now fn confirm_candidate<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTermObligation<'tcx>, @@ -1222,6 +1229,7 @@ fn confirm_candidate<'cx, 'tcx>( result } +// FIXME(mgca): While this supports constants, it is only used for types by default right now fn confirm_select_candidate<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTermObligation<'tcx>, @@ -1873,6 +1881,7 @@ fn confirm_async_fn_kind_helper_candidate<'cx, 'tcx>( .with_addl_obligations(nested) } +// FIXME(mgca): While this supports constants, it is only used for types by default right now fn confirm_param_env_candidate<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTermObligation<'tcx>, @@ -1926,9 +1935,7 @@ fn confirm_param_env_candidate<'cx, 'tcx>( ) { Ok(InferOk { value: _, obligations }) => { nested_obligations.extend(obligations); - assoc_ty_own_obligations(selcx, obligation, &mut nested_obligations); - // FIXME(associated_const_equality): Handle consts here as well? Maybe this progress type should just take - // a term instead. + assoc_term_own_obligations(selcx, obligation, &mut nested_obligations); Progress { term: cache_entry.term, obligations: nested_obligations } } Err(e) => { @@ -1942,6 +1949,7 @@ fn confirm_param_env_candidate<'cx, 'tcx>( } } +// FIXME(mgca): While this supports constants, it is only used for types by default right now fn confirm_impl_candidate<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTermObligation<'tcx>, @@ -1955,8 +1963,8 @@ fn confirm_impl_candidate<'cx, 'tcx>( let trait_def_id = tcx.trait_id_of_impl(impl_def_id).unwrap(); let param_env = obligation.param_env; - let assoc_ty = match specialization_graph::assoc_def(tcx, impl_def_id, assoc_item_id) { - Ok(assoc_ty) => assoc_ty, + let assoc_term = match specialization_graph::assoc_def(tcx, impl_def_id, assoc_item_id) { + Ok(assoc_term) => assoc_term, Err(guar) => return Ok(Projected::Progress(Progress::error(tcx, guar))), }; @@ -1965,10 +1973,10 @@ fn confirm_impl_candidate<'cx, 'tcx>( // has impossible-to-satisfy predicates (since those were // allowed in ), // or because the impl is literally missing the definition. - if !assoc_ty.item.defaultness(tcx).has_value() { + if !assoc_term.item.defaultness(tcx).has_value() { debug!( "confirm_impl_candidate: no associated type {:?} for {:?}", - assoc_ty.item.name(), + assoc_term.item.name(), obligation.predicate ); if tcx.impl_self_is_guaranteed_unsized(impl_def_id) { @@ -1979,7 +1987,11 @@ fn confirm_impl_candidate<'cx, 'tcx>( return Ok(Projected::NoProgress(obligation.predicate.to_term(tcx))); } else { return Ok(Projected::Progress(Progress { - term: Ty::new_misc_error(tcx).into(), + term: if obligation.predicate.kind(tcx).is_type() { + Ty::new_misc_error(tcx).into() + } else { + ty::Const::new_misc_error(tcx).into() + }, obligations: nested, })); } @@ -1992,27 +2004,32 @@ fn confirm_impl_candidate<'cx, 'tcx>( // * `args` is `[u32]` // * `args` ends up as `[u32, S]` let args = obligation.predicate.args.rebase_onto(tcx, trait_def_id, args); - let args = translate_args(selcx.infcx, param_env, impl_def_id, args, assoc_ty.defining_node); - let is_const = matches!(tcx.def_kind(assoc_ty.item.def_id), DefKind::AssocConst); + let args = translate_args(selcx.infcx, param_env, impl_def_id, args, assoc_term.defining_node); - let term: ty::EarlyBinder<'tcx, ty::Term<'tcx>> = if is_const { - let did = assoc_ty.item.def_id; - let identity_args = crate::traits::GenericArgs::identity_for_item(tcx, did); - let uv = ty::UnevaluatedConst::new(did, identity_args); - ty::EarlyBinder::bind(ty::Const::new_unevaluated(tcx, uv).into()) + let term = if obligation.predicate.kind(tcx).is_type() { + tcx.type_of(assoc_term.item.def_id).map_bound(|ty| ty.into()) } else { - tcx.type_of(assoc_ty.item.def_id).map_bound(|ty| ty.into()) + ty::EarlyBinder::bind( + get_associated_const_value( + selcx, + obligation.predicate.to_term(tcx).expect_const(), + param_env, + ) + .into(), + ) }; - let progress = if !tcx.check_args_compatible(assoc_ty.item.def_id, args) { - let err = Ty::new_error_with_message( - tcx, - obligation.cause.span, - "impl item and trait item have different parameters", - ); - Progress { term: err.into(), obligations: nested } + let progress = if !tcx.check_args_compatible(assoc_term.item.def_id, args) { + let msg = "impl item and trait item have different parameters"; + let span = obligation.cause.span; + let err = if obligation.predicate.kind(tcx).is_type() { + Ty::new_error_with_message(tcx, span, msg).into() + } else { + ty::Const::new_error_with_message(tcx, span, msg).into() + }; + Progress { term: err, obligations: nested } } else { - assoc_ty_own_obligations(selcx, obligation, &mut nested); + assoc_term_own_obligations(selcx, obligation, &mut nested); Progress { term: term.instantiate(tcx, args), obligations: nested } }; Ok(Projected::Progress(progress)) @@ -2020,7 +2037,8 @@ fn confirm_impl_candidate<'cx, 'tcx>( // Get obligations corresponding to the predicates from the where-clause of the // associated type itself. -fn assoc_ty_own_obligations<'cx, 'tcx>( +// FIXME(mgca): While this supports constants, it is only used for types by default right now +fn assoc_term_own_obligations<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTermObligation<'tcx>, nested: &mut PredicateObligations<'tcx>, @@ -2090,3 +2108,15 @@ impl<'cx, 'tcx> ProjectionCacheKeyExt<'cx, 'tcx> for ProjectionCacheKey<'tcx> { }) } } + +fn get_associated_const_value<'tcx>( + selcx: &mut SelectionContext<'_, 'tcx>, + alias_ct: ty::Const<'tcx>, + param_env: ty::ParamEnv<'tcx>, +) -> ty::Const<'tcx> { + // FIXME(mgca): We shouldn't be invoking ctfe here, instead const items should be aliases to type + // system consts that we can retrieve with some `query const_arg_of_alias` query. Evaluating the + // constant is "close enough" to getting the actual rhs of the const item for now even if it might + // lead to some cycles + super::evaluate_const(selcx.infcx, alias_ct, param_env) +} diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 8008c7e4d342..94190cd3ae33 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -406,7 +406,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let predicate = self.infcx.enter_forall_and_leak_universe(obligation.predicate); let mut assume = predicate.trait_ref.args.const_at(2); - // FIXME(mgca): We should shallowly normalize this. if self.tcx().features().generic_const_exprs() { assume = crate::traits::evaluate_const(self.infcx, assume, obligation.param_env) } diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 2e32cda7602e..08d3b92e9b5e 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -6,6 +6,7 @@ use std::iter; use rustc_hir as hir; +use rustc_hir::def::DefKind; use rustc_hir::lang_items::LangItem; use rustc_infer::traits::{ObligationCauseCode, PredicateObligations}; use rustc_middle::bug; @@ -486,7 +487,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { /// Pushes the obligations required for an inherent alias to be WF /// into `self.out`. // FIXME(inherent_associated_types): Merge this function with `fn compute_alias`. - fn add_wf_preds_for_inherent_projection(&mut self, data: ty::AliasTy<'tcx>) { + fn add_wf_preds_for_inherent_projection(&mut self, data: ty::AliasTerm<'tcx>) { // An inherent projection is well-formed if // // (a) its predicates hold (*) @@ -498,7 +499,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { if !data.self_ty().has_escaping_bound_vars() { // FIXME(inherent_associated_types): Should this happen inside of a snapshot? // FIXME(inherent_associated_types): This is incompatible with the new solver and lazy norm! - let args = traits::project::compute_inherent_assoc_ty_args( + let args = traits::project::compute_inherent_assoc_term_args( &mut traits::SelectionContext::new(self.infcx), self.param_env, data, @@ -776,7 +777,7 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { self.out.extend(obligations); } ty::Alias(ty::Inherent, data) => { - self.add_wf_preds_for_inherent_projection(data); + self.add_wf_preds_for_inherent_projection(data.into()); return; // Subtree handled by compute_inherent_projection. } @@ -961,9 +962,6 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { match c.kind() { ty::ConstKind::Unevaluated(uv) => { if !c.has_escaping_bound_vars() { - let obligations = self.nominal_obligations(uv.def, uv.args); - self.out.extend(obligations); - let predicate = ty::Binder::dummy(ty::PredicateKind::Clause( ty::ClauseKind::ConstEvaluatable(c), )); @@ -975,6 +973,16 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { self.param_env, predicate, )); + + if tcx.def_kind(uv.def) == DefKind::AssocConst + && tcx.def_kind(tcx.parent(uv.def)) == (DefKind::Impl { of_trait: false }) + { + self.add_wf_preds_for_inherent_projection(uv.into()); + return; // Subtree is handled by above function + } else { + let obligations = self.nominal_obligations(uv.def, uv.args); + self.out.extend(obligations); + } } } ty::ConstKind::Infer(_) => { diff --git a/compiler/rustc_traits/src/normalize_projection_ty.rs b/compiler/rustc_traits/src/normalize_projection_ty.rs index 14a92ebb9f96..e52898cc6e24 100644 --- a/compiler/rustc_traits/src/normalize_projection_ty.rs +++ b/compiler/rustc_traits/src/normalize_projection_ty.rs @@ -32,8 +32,14 @@ fn normalize_canonicalized_projection_ty<'tcx>( let selcx = &mut SelectionContext::new(ocx.infcx); let cause = ObligationCause::dummy(); let mut obligations = PredicateObligations::new(); - let answer = - traits::normalize_projection_ty(selcx, param_env, goal, cause, 0, &mut obligations); + let answer = traits::normalize_projection_term( + selcx, + param_env, + goal.into(), + cause, + 0, + &mut obligations, + ); ocx.register_obligations(obligations); // #112047: With projections and opaques, we are able to create opaques that // are recursive (given some generic parameters of the opaque's type variables). @@ -104,14 +110,14 @@ fn normalize_canonicalized_inherent_projection_ty<'tcx>( let answer = traits::normalize_inherent_projection( selcx, param_env, - goal, + goal.into(), cause, 0, &mut obligations, ); ocx.register_obligations(obligations); - Ok(NormalizationResult { normalized_ty: answer }) + Ok(NormalizationResult { normalized_ty: answer.expect_type() }) }, ) } diff --git a/compiler/rustc_transmute/src/layout/dfa.rs b/compiler/rustc_transmute/src/layout/dfa.rs index 05afa28db31a..6d072c336af2 100644 --- a/compiler/rustc_transmute/src/layout/dfa.rs +++ b/compiler/rustc_transmute/src/layout/dfa.rs @@ -266,7 +266,7 @@ where } #[cfg(test)] - pub(crate) fn from_edges>( + pub(crate) fn from_edges>( start: u32, accept: u32, edges: &[(u32, B, u32)], @@ -275,8 +275,8 @@ where let accept = State(accept); let mut transitions: Map> = Map::default(); - for (src, edge, dst) in edges.iter().copied() { - transitions.entry(State(src)).or_default().push((edge.into(), State(dst))); + for &(src, ref edge, dst) in edges.iter() { + transitions.entry(State(src)).or_default().push((edge.clone().into(), State(dst))); } let transitions = transitions @@ -401,12 +401,24 @@ mod edge_set { mut join: impl FnMut(Option, Option) -> S, ) -> EdgeSet where - S: Copy, + S: Copy + Eq, { + let mut runs: SmallVec<[(Byte, S); 1]> = SmallVec::new(); let xs = self.runs.iter().copied(); let ys = other.runs.iter().copied(); - // FIXME(@joshlf): Merge contiguous runs with common destination. - EdgeSet { runs: union(xs, ys).map(|(range, (x, y))| (range, join(x, y))).collect() } + for (range, (x, y)) in union(xs, ys) { + let state = join(x, y); + match runs.last_mut() { + // Merge contiguous runs with a common destination. + Some(&mut (ref mut last_range, ref mut last_state)) + if last_range.end == range.start && *last_state == state => + { + last_range.end = range.end + } + _ => runs.push((range, state)), + } + } + EdgeSet { runs } } } } diff --git a/compiler/rustc_transmute/src/maybe_transmutable/tests.rs b/compiler/rustc_transmute/src/maybe_transmutable/tests.rs index fbb4639dbd63..0227ad71ae66 100644 --- a/compiler/rustc_transmute/src/maybe_transmutable/tests.rs +++ b/compiler/rustc_transmute/src/maybe_transmutable/tests.rs @@ -314,7 +314,7 @@ mod union { let u = s.clone().union(t.clone(), new_state); let expected_u = - Dfa::from_edges(b, a, &[(b, 0, c), (b, 1, d), (d, 1, a), (d, 0, a), (c, 0, a)]); + Dfa::from_edges(b, a, &[(b, 0..=0, c), (b, 1..=1, d), (d, 0..=1, a), (c, 0..=0, a)]); assert_eq!(u, expected_u); diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs index 6cb9fdc6f931..f14a45aa1e3b 100644 --- a/compiler/rustc_ty_utils/src/assoc.rs +++ b/compiler/rustc_ty_utils/src/assoc.rs @@ -1,6 +1,7 @@ use rustc_data_structures::fx::FxIndexSet; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId}; +use rustc_hir::definitions::{DefPathData, DisambiguatorState}; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{self as hir, AmbigArg}; use rustc_middle::query::Providers; @@ -159,6 +160,22 @@ fn associated_item_from_impl_item_ref(impl_item_ref: &hir::ImplItemRef) -> ty::A container: ty::AssocItemContainer::Impl, } } +struct RPITVisitor { + rpits: FxIndexSet, +} + +impl<'tcx> Visitor<'tcx> for RPITVisitor { + fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx, AmbigArg>) { + if let hir::TyKind::OpaqueDef(opaq) = ty.kind + && self.rpits.insert(opaq.def_id) + { + for bound in opaq.bounds { + intravisit::walk_param_bound(self, bound); + } + } + intravisit::walk_ty(self, ty) + } +} /// Given an `fn_def_id` of a trait or a trait implementation: /// @@ -177,23 +194,6 @@ fn associated_types_for_impl_traits_in_associated_fn( match tcx.def_kind(parent_def_id) { DefKind::Trait => { - struct RPITVisitor { - rpits: FxIndexSet, - } - - impl<'tcx> Visitor<'tcx> for RPITVisitor { - fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx, AmbigArg>) { - if let hir::TyKind::OpaqueDef(opaq) = ty.kind - && self.rpits.insert(opaq.def_id) - { - for bound in opaq.bounds { - intravisit::walk_param_bound(self, bound); - } - } - intravisit::walk_ty(self, ty) - } - } - let mut visitor = RPITVisitor { rpits: FxIndexSet::default() }; if let Some(output) = tcx.hir_get_fn_output(fn_def_id) { @@ -246,9 +246,23 @@ fn associated_type_for_impl_trait_in_trait( let trait_def_id = tcx.local_parent(fn_def_id); assert_eq!(tcx.def_kind(trait_def_id), DefKind::Trait); + // Collect all opaque types in return position for the method and use + // the index as the disambiguator to make an unique def path. + let mut visitor = RPITVisitor { rpits: FxIndexSet::default() }; + visitor.visit_fn_ret_ty(tcx.hir_get_fn_output(fn_def_id).unwrap()); + let disambiguator = visitor.rpits.get_index_of(&opaque_ty_def_id).unwrap().try_into().unwrap(); + let span = tcx.def_span(opaque_ty_def_id); - // No name because this is an anonymous associated type. - let trait_assoc_ty = tcx.at(span).create_def(trait_def_id, None, DefKind::AssocTy); + // Also use the method name to create an unique def path. + let data = DefPathData::AnonAssocTy(tcx.item_name(fn_def_id.to_def_id())); + let trait_assoc_ty = tcx.at(span).create_def( + trait_def_id, + // No name because this is an anonymous associated type. + None, + DefKind::AssocTy, + Some(data), + &mut DisambiguatorState::with(trait_def_id, data, disambiguator), + ); let local_def_id = trait_assoc_ty.def_id(); let def_id = local_def_id.to_def_id(); @@ -299,8 +313,22 @@ fn associated_type_for_impl_trait_in_impl( hir::FnRetTy::DefaultReturn(_) => tcx.def_span(impl_fn_def_id), hir::FnRetTy::Return(ty) => ty.span, }; - // No name because this is an anonymous associated type. - let impl_assoc_ty = tcx.at(span).create_def(impl_local_def_id, None, DefKind::AssocTy); + + // Use the same disambiguator and method name as the anon associated type in the trait. + let disambiguated_data = tcx.def_key(trait_assoc_def_id).disambiguated_data; + let DefPathData::AnonAssocTy(name) = disambiguated_data.data else { + bug!("expected anon associated type") + }; + let data = DefPathData::AnonAssocTy(name); + + let impl_assoc_ty = tcx.at(span).create_def( + impl_local_def_id, + // No name because this is an anonymous associated type. + None, + DefKind::AssocTy, + Some(data), + &mut DisambiguatorState::with(impl_local_def_id, data, disambiguated_data.disambiguator), + ); let local_def_id = impl_assoc_ty.def_id(); let def_id = local_def_id.to_def_id(); diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index da83566dad02..166e8f193429 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -235,7 +235,7 @@ fn resolve_associated_item<'tcx>( tcx.ensure_ok().compare_impl_item(leaf_def_item)?; } - Some(ty::Instance::new(leaf_def.item.def_id, args)) + Some(ty::Instance::new_raw(leaf_def.item.def_id, args)) } traits::ImplSource::Builtin(BuiltinImplSource::Object(_), _) => { let trait_ref = ty::TraitRef::from_method(tcx, trait_id, rcvr_args); @@ -280,7 +280,7 @@ fn resolve_associated_item<'tcx>( // Use the default `fn clone_from` from `trait Clone`. let args = tcx.erase_regions(rcvr_args); - Some(ty::Instance::new(trait_item_id, args)) + Some(ty::Instance::new_raw(trait_item_id, args)) } } else if tcx.is_lang_item(trait_ref.def_id, LangItem::FnPtrTrait) { if tcx.is_lang_item(trait_item_id, LangItem::FnPtrAddr) { @@ -329,7 +329,7 @@ fn resolve_associated_item<'tcx>( // sync with the built-in trait implementations (since all of the // implementations return `FnOnce::Output`). if ty::ClosureKind::FnOnce == args.as_coroutine_closure().kind() { - Some(Instance::new(coroutine_closure_def_id, args)) + Some(Instance::new_raw(coroutine_closure_def_id, args)) } else { Some(Instance { def: ty::InstanceKind::ConstructCoroutineInClosureShim { @@ -362,7 +362,7 @@ fn resolve_associated_item<'tcx>( args, }) } else { - Some(Instance::new(coroutine_closure_def_id, args)) + Some(Instance::new_raw(coroutine_closure_def_id, args)) } } ty::Closure(closure_def_id, args) => { @@ -381,7 +381,7 @@ fn resolve_associated_item<'tcx>( let name = tcx.item_name(trait_item_id); assert_eq!(name, sym::transmute); let args = tcx.erase_regions(rcvr_args); - Some(ty::Instance::new(trait_item_id, args)) + Some(ty::Instance::new_raw(trait_item_id, args)) } else { Instance::try_resolve_item_for_coroutine(tcx, trait_item_id, trait_id, rcvr_args) } diff --git a/compiler/rustc_ty_utils/src/lib.rs b/compiler/rustc_ty_utils/src/lib.rs index ea0f6b8dfba7..f79b6d44bfdf 100644 --- a/compiler/rustc_ty_utils/src/lib.rs +++ b/compiler/rustc_ty_utils/src/lib.rs @@ -29,10 +29,10 @@ mod implied_bounds; mod instance; mod layout; mod needs_drop; +mod nested_bodies; mod opaque_types; mod representability; pub mod sig_types; -mod stalled_generators; mod structural_match; mod ty; @@ -51,5 +51,5 @@ pub fn provide(providers: &mut Providers) { ty::provide(providers); instance::provide(providers); structural_match::provide(providers); - stalled_generators::provide(providers); + nested_bodies::provide(providers); } diff --git a/compiler/rustc_ty_utils/src/nested_bodies.rs b/compiler/rustc_ty_utils/src/nested_bodies.rs new file mode 100644 index 000000000000..7c74d8eb6351 --- /dev/null +++ b/compiler/rustc_ty_utils/src/nested_bodies.rs @@ -0,0 +1,34 @@ +use rustc_hir as hir; +use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::intravisit::Visitor; +use rustc_middle::query::Providers; +use rustc_middle::ty::{self, TyCtxt}; + +fn nested_bodies_within<'tcx>(tcx: TyCtxt<'tcx>, item: LocalDefId) -> &'tcx ty::List { + let body = tcx.hir_body_owned_by(item); + let mut collector = + NestedBodiesVisitor { tcx, root_def_id: item.to_def_id(), nested_bodies: vec![] }; + collector.visit_body(body); + tcx.mk_local_def_ids(&collector.nested_bodies) +} + +struct NestedBodiesVisitor<'tcx> { + tcx: TyCtxt<'tcx>, + root_def_id: DefId, + nested_bodies: Vec, +} + +impl<'tcx> Visitor<'tcx> for NestedBodiesVisitor<'tcx> { + fn visit_nested_body(&mut self, id: hir::BodyId) { + let body_def_id = self.tcx.hir_body_owner_def_id(id); + if self.tcx.typeck_root_def_id(body_def_id.to_def_id()) == self.root_def_id { + self.nested_bodies.push(body_def_id); + let body = self.tcx.hir_body(id); + self.visit_body(body); + } + } +} + +pub(super) fn provide(providers: &mut Providers) { + *providers = Providers { nested_bodies_within, ..*providers }; +} diff --git a/compiler/rustc_ty_utils/src/stalled_generators.rs b/compiler/rustc_ty_utils/src/stalled_generators.rs deleted file mode 100644 index 8b45e8b0f6f9..000000000000 --- a/compiler/rustc_ty_utils/src/stalled_generators.rs +++ /dev/null @@ -1,54 +0,0 @@ -use rustc_hir as hir; -use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_hir::intravisit; -use rustc_hir::intravisit::Visitor; -use rustc_middle::query::Providers; -use rustc_middle::ty::{self, TyCtxt}; - -fn stalled_generators_within<'tcx>( - tcx: TyCtxt<'tcx>, - item: LocalDefId, -) -> &'tcx ty::List { - if !tcx.next_trait_solver_globally() { - return ty::List::empty(); - } - - let body = tcx.hir_body_owned_by(item); - let mut collector = - StalledGeneratorVisitor { tcx, root_def_id: item.to_def_id(), stalled_coroutines: vec![] }; - collector.visit_body(body); - tcx.mk_local_def_ids(&collector.stalled_coroutines) -} - -struct StalledGeneratorVisitor<'tcx> { - tcx: TyCtxt<'tcx>, - root_def_id: DefId, - stalled_coroutines: Vec, -} - -impl<'tcx> Visitor<'tcx> for StalledGeneratorVisitor<'tcx> { - fn visit_nested_body(&mut self, id: hir::BodyId) { - if self.tcx.typeck_root_def_id(self.tcx.hir_body_owner_def_id(id).to_def_id()) - == self.root_def_id - { - let body = self.tcx.hir_body(id); - self.visit_body(body); - } - } - - fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) { - if let hir::ExprKind::Closure(&hir::Closure { - def_id, - kind: hir::ClosureKind::Coroutine(_), - .. - }) = ex.kind - { - self.stalled_coroutines.push(def_id); - } - intravisit::walk_expr(self, ex); - } -} - -pub(super) fn provide(providers: &mut Providers) { - *providers = Providers { stalled_generators_within, ..*providers }; -} diff --git a/compiler/rustc_type_ir/src/infer_ctxt.rs b/compiler/rustc_type_ir/src/infer_ctxt.rs index 8fa56c359996..7d2654de4409 100644 --- a/compiler/rustc_type_ir/src/infer_ctxt.rs +++ b/compiler/rustc_type_ir/src/infer_ctxt.rs @@ -100,7 +100,7 @@ impl TypingMode { pub fn typeck_for_body(cx: I, body_def_id: I::LocalDefId) -> TypingMode { TypingMode::Analysis { defining_opaque_types_and_generators: cx - .opaque_types_and_generators_defined_by(body_def_id), + .opaque_types_and_coroutines_defined_by(body_def_id), } } diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 6410da1f7409..0fd2d9f3ad38 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -341,7 +341,7 @@ pub trait Interner: fn opaque_types_defined_by(self, defining_anchor: Self::LocalDefId) -> Self::LocalDefIds; - fn opaque_types_and_generators_defined_by( + fn opaque_types_and_coroutines_defined_by( self, defining_anchor: Self::LocalDefId, ) -> Self::LocalDefIds; diff --git a/compiler/rustc_type_ir/src/predicate.rs b/compiler/rustc_type_ir/src/predicate.rs index 0411c5c2325e..b59495b93c83 100644 --- a/compiler/rustc_type_ir/src/predicate.rs +++ b/compiler/rustc_type_ir/src/predicate.rs @@ -474,10 +474,15 @@ pub enum AliasTermKind { /// Currently only used if the type alias references opaque types. /// Can always be normalized away. FreeTy, - /// An unevaluated const coming from a generic const expression. + + /// An unevaluated anonymous constants. UnevaluatedConst, /// An unevaluated const coming from an associated const. ProjectionConst, + /// A top level const item not part of a trait or impl. + FreeConst, + /// An associated const in an inherent `impl` + InherentConst, } impl AliasTermKind { @@ -486,11 +491,27 @@ impl AliasTermKind { AliasTermKind::ProjectionTy => "associated type", AliasTermKind::ProjectionConst => "associated const", AliasTermKind::InherentTy => "inherent associated type", + AliasTermKind::InherentConst => "inherent associated const", AliasTermKind::OpaqueTy => "opaque type", AliasTermKind::FreeTy => "type alias", + AliasTermKind::FreeConst => "unevaluated constant", AliasTermKind::UnevaluatedConst => "unevaluated constant", } } + + pub fn is_type(self) -> bool { + match self { + AliasTermKind::ProjectionTy + | AliasTermKind::InherentTy + | AliasTermKind::OpaqueTy + | AliasTermKind::FreeTy => true, + + AliasTermKind::UnevaluatedConst + | AliasTermKind::ProjectionConst + | AliasTermKind::InherentConst + | AliasTermKind::FreeConst => false, + } + } } impl From for AliasTermKind { @@ -566,7 +587,10 @@ impl AliasTerm { | AliasTermKind::InherentTy | AliasTermKind::OpaqueTy | AliasTermKind::FreeTy => {} - AliasTermKind::UnevaluatedConst | AliasTermKind::ProjectionConst => { + AliasTermKind::InherentConst + | AliasTermKind::FreeConst + | AliasTermKind::UnevaluatedConst + | AliasTermKind::ProjectionConst => { panic!("Cannot turn `UnevaluatedConst` into `AliasTy`") } } @@ -603,18 +627,19 @@ impl AliasTerm { ty::AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () }, ) .into(), - AliasTermKind::UnevaluatedConst | AliasTermKind::ProjectionConst => { - I::Const::new_unevaluated( - interner, - ty::UnevaluatedConst::new(self.def_id, self.args), - ) - .into() - } + AliasTermKind::FreeConst + | AliasTermKind::InherentConst + | AliasTermKind::UnevaluatedConst + | AliasTermKind::ProjectionConst => I::Const::new_unevaluated( + interner, + ty::UnevaluatedConst::new(self.def_id, self.args), + ) + .into(), } } } -/// The following methods work only with (trait) associated type projections. +/// The following methods work only with (trait) associated term projections. impl AliasTerm { pub fn self_ty(self) -> I::Ty { self.args.type_at(0) @@ -659,6 +684,31 @@ impl AliasTerm { } } +/// The following methods work only with inherent associated term projections. +impl AliasTerm { + /// Transform the generic parameters to have the given `impl` args as the base and the GAT args on top of that. + /// + /// Does the following transformation: + /// + /// ```text + /// [Self, P_0...P_m] -> [I_0...I_n, P_0...P_m] + /// + /// I_i impl args + /// P_j GAT args + /// ``` + pub fn rebase_inherent_args_onto_impl( + self, + impl_args: I::GenericArgs, + interner: I, + ) -> I::GenericArgs { + debug_assert!(matches!( + self.kind(interner), + AliasTermKind::InherentTy | AliasTermKind::InherentConst + )); + interner.mk_args_from_iter(impl_args.iter().chain(self.args.iter().skip(1))) + } +} + impl From> for AliasTerm { fn from(ty: ty::AliasTy) -> Self { AliasTerm { args: ty.args, def_id: ty.def_id, _use_alias_term_new_instead: () } diff --git a/compiler/rustc_type_ir/src/relate.rs b/compiler/rustc_type_ir/src/relate.rs index c80a567117c6..e3c4a793b37f 100644 --- a/compiler/rustc_type_ir/src/relate.rs +++ b/compiler/rustc_type_ir/src/relate.rs @@ -273,8 +273,10 @@ impl Relate for ty::AliasTerm { false, // do not fetch `type_of(a_def_id)`, as it will cause a cycle )?, ty::AliasTermKind::ProjectionTy + | ty::AliasTermKind::FreeConst | ty::AliasTermKind::FreeTy | ty::AliasTermKind::InherentTy + | ty::AliasTermKind::InherentConst | ty::AliasTermKind::UnevaluatedConst | ty::AliasTermKind::ProjectionConst => { relate_args_invariantly(relation, a.args, b.args)? diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs index 21adbffc0274..cf2e4284d10d 100644 --- a/compiler/rustc_type_ir/src/ty_kind.rs +++ b/compiler/rustc_type_ir/src/ty_kind.rs @@ -514,28 +514,6 @@ impl AliasTy { } } -/// The following methods work only with inherent associated type projections. -impl AliasTy { - /// Transform the generic parameters to have the given `impl` args as the base and the GAT args on top of that. - /// - /// Does the following transformation: - /// - /// ```text - /// [Self, P_0...P_m] -> [I_0...I_n, P_0...P_m] - /// - /// I_i impl args - /// P_j GAT args - /// ``` - pub fn rebase_inherent_args_onto_impl( - self, - impl_args: I::GenericArgs, - interner: I, - ) -> I::GenericArgs { - debug_assert_eq!(self.kind(interner), AliasTyKind::Inherent); - interner.mk_args_from_iter(impl_args.iter().chain(self.args.iter().skip(1))) - } -} - #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] #[cfg_attr( feature = "nightly", diff --git a/compiler/stable_mir/Cargo.toml b/compiler/stable_mir/Cargo.toml index 3a01ee5783ee..516c8e9c718b 100644 --- a/compiler/stable_mir/Cargo.toml +++ b/compiler/stable_mir/Cargo.toml @@ -5,3 +5,9 @@ edition = "2024" [dependencies] rustc_smir = { path = "../rustc_smir" } + +[features] +# Provides access to APIs that expose internals of the rust compiler. +# APIs enabled by this feature are unstable. They can be removed or modified +# at any point and they are not included in the crate's semantic versioning. +rustc_internal = [] diff --git a/compiler/stable_mir/src/lib.rs b/compiler/stable_mir/src/lib.rs index cc0fb52433d9..688f3936b26c 100644 --- a/compiler/stable_mir/src/lib.rs +++ b/compiler/stable_mir/src/lib.rs @@ -4,4 +4,8 @@ //! This is a transitional measure as described in [PR #139319](https://github.com/rust-lang/rust/pull/139319). //! Once the refactoring is complete, the `stable_mir` implementation will be moved back here. +/// Export the rustc_internal APIs. Note that this module has no stability +/// guarantees and it is not taken into account for semver. +#[cfg(feature = "rustc_internal")] +pub use rustc_smir::rustc_internal; pub use rustc_smir::stable_mir::*; diff --git a/library/Cargo.lock b/library/Cargo.lock index f5c04a3bf48c..5100b4d8176d 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -32,12 +32,6 @@ dependencies = [ "core", ] -[[package]] -name = "allocator-api2" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" - [[package]] name = "alloctests" version = "0.0.0" @@ -67,9 +61,9 @@ dependencies = [ [[package]] name = "compiler_builtins" -version = "0.1.156" +version = "0.1.158" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1ffbd2789fe5bb95b96a2e22cbe3128239dc46ff0374e0d38e9f102062d7055" +checksum = "164cdc689e4c6d69417f77a5f48be240c291e84fbef0b1281755dc754b19c809" dependencies = [ "cc", "rustc-std-workspace-core", @@ -134,11 +128,10 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.2" +version = "0.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3" dependencies = [ - "allocator-api2", "compiler_builtins", "rustc-std-workspace-alloc", "rustc-std-workspace-core", @@ -221,15 +214,6 @@ dependencies = [ "unwind", ] -[[package]] -name = "proc-macro2" -version = "1.0.94" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" -dependencies = [ - "unicode-ident", -] - [[package]] name = "proc_macro" version = "0.0.0" @@ -246,15 +230,6 @@ dependencies = [ "cc", ] -[[package]] -name = "quote" -version = "1.0.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" -dependencies = [ - "proc-macro2", -] - [[package]] name = "r-efi" version = "5.2.0" @@ -278,12 +253,11 @@ dependencies = [ [[package]] name = "rand" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" +checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" dependencies = [ "rand_core", - "zerocopy", ] [[package]] @@ -387,17 +361,6 @@ dependencies = [ "rustc-std-workspace-core", ] -[[package]] -name = "syn" -version = "2.0.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - [[package]] name = "sysroot" version = "0.0.0" @@ -418,12 +381,6 @@ dependencies = [ "std", ] -[[package]] -name = "unicode-ident" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" - [[package]] name = "unicode-width" version = "0.1.14" @@ -544,23 +501,3 @@ name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" - -[[package]] -name = "zerocopy" -version = "0.8.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2586fea28e186957ef732a5f8b3be2da217d65c5969d4b1e17f973ebbe876879" -dependencies = [ - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.8.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a996a8f63c5c4448cd959ac1bab0aaa3306ccfd060472f85943ee0750f0169be" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] diff --git a/library/alloc/Cargo.toml b/library/alloc/Cargo.toml index 994221de8663..51ddc9bf9fc9 100644 --- a/library/alloc/Cargo.toml +++ b/library/alloc/Cargo.toml @@ -16,7 +16,7 @@ bench = false [dependencies] core = { path = "../core", public = true } -compiler_builtins = { version = "=0.1.156", features = ['rustc-dep-of-std'] } +compiler_builtins = { version = "=0.1.158", features = ['rustc-dep-of-std'] } [features] compiler-builtins-mem = ['compiler_builtins/mem'] diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index 78b7da9d6b3e..5ca32ed741af 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -1917,14 +1917,13 @@ pub struct ExtractIf< V, F, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator + Clone = Global, -> where - F: 'a + FnMut(&K, &mut V) -> bool, -{ +> { pred: F, inner: ExtractIfInner<'a, K, V>, /// The BTreeMap will outlive this IntoIter so we don't care about drop order for `alloc`. alloc: A, } + /// Most of the implementation of ExtractIf are generic over the type /// of the predicate, thus also serving for BTreeSet::ExtractIf. pub(super) struct ExtractIfInner<'a, K, V> { @@ -1940,14 +1939,14 @@ pub(super) struct ExtractIfInner<'a, K, V> { } #[unstable(feature = "btree_extract_if", issue = "70530")] -impl fmt::Debug for ExtractIf<'_, K, V, F> +impl fmt::Debug for ExtractIf<'_, K, V, F, A> where K: fmt::Debug, V: fmt::Debug, - F: FnMut(&K, &mut V) -> bool, + A: Allocator + Clone, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("ExtractIf").field(&self.inner.peek()).finish() + f.debug_struct("ExtractIf").field("peek", &self.inner.peek()).finish_non_exhaustive() } } diff --git a/library/alloc/src/collections/btree/set.rs b/library/alloc/src/collections/btree/set.rs index 7ad9e59dfede..343934680b87 100644 --- a/library/alloc/src/collections/btree/set.rs +++ b/library/alloc/src/collections/btree/set.rs @@ -1556,10 +1556,7 @@ pub struct ExtractIf< T, F, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator + Clone = Global, -> where - T: 'a, - F: 'a + FnMut(&T) -> bool, -{ +> { pred: F, inner: super::map::ExtractIfInner<'a, T, SetValZST>, /// The BTreeMap will outlive this IntoIter so we don't care about drop order for `alloc`. @@ -1567,13 +1564,15 @@ pub struct ExtractIf< } #[unstable(feature = "btree_extract_if", issue = "70530")] -impl fmt::Debug for ExtractIf<'_, T, F, A> +impl fmt::Debug for ExtractIf<'_, T, F, A> where T: fmt::Debug, - F: FnMut(&T) -> bool, + A: Allocator + Clone, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("ExtractIf").field(&self.inner.peek().map(|(k, _)| k)).finish() + f.debug_struct("ExtractIf") + .field("peek", &self.inner.peek().map(|(k, _)| k)) + .finish_non_exhaustive() } } diff --git a/library/alloc/src/collections/linked_list.rs b/library/alloc/src/collections/linked_list.rs index cc42a120e4fa..00e2805d11f6 100644 --- a/library/alloc/src/collections/linked_list.rs +++ b/library/alloc/src/collections/linked_list.rs @@ -1976,9 +1976,14 @@ where } #[stable(feature = "extract_if", since = "1.87.0")] -impl fmt::Debug for ExtractIf<'_, T, F> { +impl fmt::Debug for ExtractIf<'_, T, F, A> +where + T: fmt::Debug, + A: Allocator, +{ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("ExtractIf").field(&self.list).finish() + let peek = self.it.map(|node| unsafe { &node.as_ref().element }); + f.debug_struct("ExtractIf").field("peek", &peek).finish_non_exhaustive() } } diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index f8844e2d3a5c..712f38a76c01 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -1188,6 +1188,73 @@ impl VecDeque { } } + /// Shortens the deque, keeping the last `len` elements and dropping + /// the rest. + /// + /// If `len` is greater or equal to the deque's current length, this has + /// no effect. + /// + /// # Examples + /// + /// ``` + /// # #![feature(vec_deque_truncate_front)] + /// use std::collections::VecDeque; + /// + /// let mut buf = VecDeque::new(); + /// buf.push_front(5); + /// buf.push_front(10); + /// buf.push_front(15); + /// assert_eq!(buf, [15, 10, 5]); + /// assert_eq!(buf.as_slices(), (&[15, 10, 5][..], &[][..])); + /// buf.truncate_front(1); + /// assert_eq!(buf.as_slices(), (&[5][..], &[][..])); + /// ``` + #[unstable(feature = "vec_deque_truncate_front", issue = "140667")] + pub fn truncate_front(&mut self, len: usize) { + /// Runs the destructor for all items in the slice when it gets dropped (normally or + /// during unwinding). + struct Dropper<'a, T>(&'a mut [T]); + + impl<'a, T> Drop for Dropper<'a, T> { + fn drop(&mut self) { + unsafe { + ptr::drop_in_place(self.0); + } + } + } + + unsafe { + if len >= self.len { + // No action is taken + return; + } + + let (front, back) = self.as_mut_slices(); + if len > back.len() { + // The 'back' slice remains unchanged. + // front.len() + back.len() == self.len, so 'end' is non-negative + // and end < front.len() + let end = front.len() - (len - back.len()); + let drop_front = front.get_unchecked_mut(..end) as *mut _; + self.head += end; + self.len = len; + ptr::drop_in_place(drop_front); + } else { + let drop_front = front as *mut _; + // 'end' is non-negative by the condition above + let end = back.len() - len; + let drop_back = back.get_unchecked_mut(..end) as *mut _; + self.head = self.to_physical_idx(self.len - len); + self.len = len; + + // Make sure the second half is dropped even when a destructor + // in the first one panics. + let _back_dropper = Dropper(&mut *drop_back); + ptr::drop_in_place(drop_front); + } + } + } + /// Returns a reference to the underlying allocator. #[unstable(feature = "allocator_api", issue = "32838")] #[inline] diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 619d9f258e34..4b8ea708e7e5 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -3536,11 +3536,11 @@ impl Default for Weak { } } -// NOTE: We checked_add here to deal with mem::forget safely. In particular -// if you mem::forget Rcs (or Weaks), the ref-count can overflow, and then -// you can free the allocation while outstanding Rcs (or Weaks) exist. -// We abort because this is such a degenerate scenario that we don't care about -// what happens -- no real program should ever experience this. +// NOTE: If you mem::forget Rcs (or Weaks), drop is skipped and the ref-count +// is not decremented, meaning the ref-count can overflow, and then you can +// free the allocation while outstanding Rcs (or Weaks) exist, which would be +// unsound. We abort because this is such a degenerate scenario that we don't +// care about what happens -- no real program should ever experience this. // // This should have negligible overhead since you don't actually need to // clone these much in Rust thanks to ownership and move-semantics. diff --git a/library/alloc/src/vec/extract_if.rs b/library/alloc/src/vec/extract_if.rs index 8a591a877964..a456d3d9e602 100644 --- a/library/alloc/src/vec/extract_if.rs +++ b/library/alloc/src/vec/extract_if.rs @@ -1,5 +1,5 @@ use core::ops::{Range, RangeBounds}; -use core::{ptr, slice}; +use core::{fmt, ptr, slice}; use super::Vec; use crate::alloc::{Allocator, Global}; @@ -16,7 +16,6 @@ use crate::alloc::{Allocator, Global}; /// let iter: std::vec::ExtractIf<'_, _, _> = v.extract_if(.., |x| *x % 2 == 0); /// ``` #[stable(feature = "extract_if", since = "1.87.0")] -#[derive(Debug)] #[must_use = "iterators are lazy and do nothing unless consumed"] pub struct ExtractIf< 'a, @@ -108,3 +107,15 @@ impl Drop for ExtractIf<'_, T, F, A> { } } } + +#[stable(feature = "extract_if", since = "1.87.0")] +impl fmt::Debug for ExtractIf<'_, T, F, A> +where + T: fmt::Debug, + A: Allocator, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let peek = if self.idx < self.end { self.vec.get(self.idx) } else { None }; + f.debug_struct("ExtractIf").field("peek", &peek).finish_non_exhaustive() + } +} diff --git a/library/alloc/src/vec/into_iter.rs b/library/alloc/src/vec/into_iter.rs index 1af110691ba6..37df928228d9 100644 --- a/library/alloc/src/vec/into_iter.rs +++ b/library/alloc/src/vec/into_iter.rs @@ -258,6 +258,11 @@ impl Iterator for IntoIter { self.len() } + #[inline] + fn last(mut self) -> Option { + self.next_back() + } + #[inline] fn next_chunk(&mut self) -> Result<[T; N], core::array::IntoIter> { let mut raw_ary = [const { MaybeUninit::uninit() }; N]; diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 65a83cb98ba6..a97912304c89 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -3659,28 +3659,34 @@ impl Vec { /// /// If the returned `ExtractIf` is not exhausted, e.g. because it is dropped without iterating /// or the iteration short-circuits, then the remaining elements will be retained. - /// Use [`retain`] with a negated predicate if you do not need the returned iterator. + /// Use [`retain_mut`] with a negated predicate if you do not need the returned iterator. /// - /// [`retain`]: Vec::retain + /// [`retain_mut`]: Vec::retain_mut /// /// Using this method is equivalent to the following code: /// /// ``` - /// # use std::cmp::min; - /// # let some_predicate = |x: &mut i32| { *x == 2 || *x == 3 || *x == 6 }; - /// # let mut vec = vec![1, 2, 3, 4, 5, 6]; - /// # let range = 1..4; + /// # let some_predicate = |x: &mut i32| { *x % 2 == 1 }; + /// # let mut vec = vec![0, 1, 2, 3, 4, 5, 6]; + /// # let mut vec2 = vec.clone(); + /// # let range = 1..5; /// let mut i = range.start; - /// while i < min(vec.len(), range.end) { + /// let end_items = vec.len() - range.end; + /// # let mut extracted = vec![]; + /// + /// while i < vec.len() - end_items { /// if some_predicate(&mut vec[i]) { /// let val = vec.remove(i); + /// # extracted.push(val); /// // your code here /// } else { /// i += 1; /// } /// } /// - /// # assert_eq!(vec, vec![1, 4, 5]); + /// # let extracted2: Vec<_> = vec2.extract_if(range, some_predicate).collect(); + /// # assert_eq!(vec, vec2); + /// # assert_eq!(extracted, extracted2); /// ``` /// /// But `extract_if` is easier to use. `extract_if` is also more efficient, diff --git a/library/alloctests/tests/lib.rs b/library/alloctests/tests/lib.rs index f1f4cc6f93bb..38309585fad6 100644 --- a/library/alloctests/tests/lib.rs +++ b/library/alloctests/tests/lib.rs @@ -37,6 +37,7 @@ #![feature(str_as_str)] #![feature(strict_provenance_lints)] #![feature(vec_deque_pop_if)] +#![feature(vec_deque_truncate_front)] #![feature(unique_rc_arc)] #![feature(macro_metavar_expr_concat)] #![allow(internal_features)] diff --git a/library/alloctests/tests/vec_deque.rs b/library/alloctests/tests/vec_deque.rs index 1b03c29e5bda..b77ea3a312be 100644 --- a/library/alloctests/tests/vec_deque.rs +++ b/library/alloctests/tests/vec_deque.rs @@ -1686,6 +1686,40 @@ fn truncate_leak() { assert_eq!(unsafe { DROPS }, 7); } +#[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] +fn truncate_front_leak() { + static mut DROPS: i32 = 0; + + struct D(bool); + + impl Drop for D { + fn drop(&mut self) { + unsafe { + DROPS += 1; + } + + if self.0 { + panic!("panic in `drop`"); + } + } + } + + let mut q = VecDeque::new(); + q.push_back(D(false)); + q.push_back(D(false)); + q.push_back(D(false)); + q.push_back(D(false)); + q.push_back(D(false)); + q.push_front(D(true)); + q.push_front(D(false)); + q.push_front(D(false)); + + catch_unwind(AssertUnwindSafe(|| q.truncate_front(1))).ok(); + + assert_eq!(unsafe { DROPS }, 7); +} + #[test] #[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_drain_leak() { @@ -1863,3 +1897,38 @@ fn test_collect_from_into_iter_keeps_allocation() { assert_eq!(v.capacity(), 13); } } + +#[test] +fn test_truncate_front() { + let mut v = VecDeque::with_capacity(13); + v.extend(0..7); + assert_eq!(v.as_slices(), ([0, 1, 2, 3, 4, 5, 6].as_slice(), [].as_slice())); + v.truncate_front(10); + assert_eq!(v.len(), 7); + assert_eq!(v.as_slices(), ([0, 1, 2, 3, 4, 5, 6].as_slice(), [].as_slice())); + v.truncate_front(7); + assert_eq!(v.len(), 7); + assert_eq!(v.as_slices(), ([0, 1, 2, 3, 4, 5, 6].as_slice(), [].as_slice())); + v.truncate_front(3); + assert_eq!(v.as_slices(), ([4, 5, 6].as_slice(), [].as_slice())); + assert_eq!(v.len(), 3); + v.truncate_front(0); + assert_eq!(v.as_slices(), ([].as_slice(), [].as_slice())); + assert_eq!(v.len(), 0); + + v.clear(); + v.extend(0..7); + assert_eq!(v.as_slices(), ([0, 1, 2, 3, 4, 5, 6].as_slice(), [].as_slice())); + v.push_front(9); + v.push_front(8); + v.push_front(7); + assert_eq!(v.as_slices(), ([7, 8, 9].as_slice(), [0, 1, 2, 3, 4, 5, 6].as_slice())); + v.truncate_front(12); + assert_eq!(v.as_slices(), ([7, 8, 9].as_slice(), [0, 1, 2, 3, 4, 5, 6].as_slice())); + v.truncate_front(10); + assert_eq!(v.as_slices(), ([7, 8, 9].as_slice(), [0, 1, 2, 3, 4, 5, 6].as_slice())); + v.truncate_front(8); + assert_eq!(v.as_slices(), ([9].as_slice(), [0, 1, 2, 3, 4, 5, 6].as_slice())); + v.truncate_front(5); + assert_eq!(v.as_slices(), ([2, 3, 4, 5, 6].as_slice(), [].as_slice())); +} diff --git a/library/backtrace b/library/backtrace index 9d2c34e7e63a..6c882eb11984 160000 --- a/library/backtrace +++ b/library/backtrace @@ -1 +1 @@ -Subproject commit 9d2c34e7e63afe1e71c333b247065e3b7ba4d883 +Subproject commit 6c882eb11984d737f62e85f36703effaf34c2453 diff --git a/library/core/Cargo.toml b/library/core/Cargo.toml index fe61f552a49d..99e52d0ada0a 100644 --- a/library/core/Cargo.toml +++ b/library/core/Cargo.toml @@ -31,7 +31,6 @@ level = "warn" check-cfg = [ 'cfg(bootstrap)', 'cfg(no_fp_fmt_parse)', - 'cfg(stdarch_intel_sde)', # core use #[path] imports to portable-simd `core_simd` crate # and to stdarch `core_arch` crate which messes-up with Cargo list # of declared features, we therefor expect any feature cfg diff --git a/library/core/src/alloc/mod.rs b/library/core/src/alloc/mod.rs index 9805cee1c331..9d608d5e83c4 100644 --- a/library/core/src/alloc/mod.rs +++ b/library/core/src/alloc/mod.rs @@ -90,7 +90,7 @@ impl fmt::Display for AllocError { /// # Safety /// /// Memory blocks that are [*currently allocated*] by an allocator, -/// must point to valid memory, and retain their validity while until either: +/// must point to valid memory, and retain their validity until either: /// - the memory block is deallocated, or /// - the allocator is dropped. /// @@ -112,7 +112,9 @@ pub unsafe trait Allocator { /// /// The returned block of memory remains valid as long as it is [*currently allocated*] and the shorter of: /// - the borrow-checker lifetime of the allocator type itself. - /// - as long as at the allocator and all its clones has not been dropped. + /// - as long as the allocator and all its clones have not been dropped. + /// + /// [*currently allocated*]: #currently-allocated-memory /// /// # Errors /// diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 580f95eddce7..4f7f8a5b84dd 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -622,44 +622,9 @@ pub struct Arguments<'a> { args: &'a [rt::Argument<'a>], } -/// Used by the format_args!() macro to create a fmt::Arguments object. #[doc(hidden)] #[unstable(feature = "fmt_internals", issue = "none")] impl<'a> Arguments<'a> { - #[inline] - pub const fn new_const(pieces: &'a [&'static str; N]) -> Self { - const { assert!(N <= 1) }; - Arguments { pieces, fmt: None, args: &[] } - } - - /// When using the format_args!() macro, this function is used to generate the - /// Arguments structure. - #[inline] - pub const fn new_v1( - pieces: &'a [&'static str; P], - args: &'a [rt::Argument<'a>; A], - ) -> Arguments<'a> { - const { assert!(P >= A && P <= A + 1, "invalid args") } - Arguments { pieces, fmt: None, args } - } - - /// Specifies nonstandard formatting parameters. - /// - /// An `rt::UnsafeArg` is required because the following invariants must be held - /// in order for this function to be safe: - /// 1. The `pieces` slice must be at least as long as `fmt`. - /// 2. Every `rt::Placeholder::position` value within `fmt` must be a valid index of `args`. - /// 3. Every `rt::Count::Param` within `fmt` must contain a valid index of `args`. - #[inline] - pub const fn new_v1_formatted( - pieces: &'a [&'static str], - args: &'a [rt::Argument<'a>], - fmt: &'a [rt::Placeholder], - _unsafe_arg: rt::UnsafeArg, - ) -> Arguments<'a> { - Arguments { pieces, fmt: Some(fmt), args } - } - /// Estimates the length of the formatted text. /// /// This is intended to be used for setting initial `String` capacity diff --git a/library/core/src/fmt/rt.rs b/library/core/src/fmt/rt.rs index e409771362e4..c2a8a39bcac8 100644 --- a/library/core/src/fmt/rt.rs +++ b/library/core/src/fmt/rt.rs @@ -1,7 +1,10 @@ #![allow(missing_debug_implementations)] #![unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")] -//! These are the lang items used by format_args!(). +//! All types and methods in this file are used by the compiler in +//! the expansion/lowering of format_args!(). +//! +//! Do not modify them without understanding the consequences for the format_args!() macro. use super::*; use crate::hint::unreachable_unchecked; @@ -110,46 +113,45 @@ macro_rules! argument_new { }; } -#[rustc_diagnostic_item = "ArgumentMethods"] impl Argument<'_> { #[inline] - pub fn new_display(x: &T) -> Argument<'_> { + pub const fn new_display(x: &T) -> Argument<'_> { argument_new!(T, x, ::fmt) } #[inline] - pub fn new_debug(x: &T) -> Argument<'_> { + pub const fn new_debug(x: &T) -> Argument<'_> { argument_new!(T, x, ::fmt) } #[inline] - pub fn new_debug_noop(x: &T) -> Argument<'_> { + pub const fn new_debug_noop(x: &T) -> Argument<'_> { argument_new!(T, x, |_: &T, _| Ok(())) } #[inline] - pub fn new_octal(x: &T) -> Argument<'_> { + pub const fn new_octal(x: &T) -> Argument<'_> { argument_new!(T, x, ::fmt) } #[inline] - pub fn new_lower_hex(x: &T) -> Argument<'_> { + pub const fn new_lower_hex(x: &T) -> Argument<'_> { argument_new!(T, x, ::fmt) } #[inline] - pub fn new_upper_hex(x: &T) -> Argument<'_> { + pub const fn new_upper_hex(x: &T) -> Argument<'_> { argument_new!(T, x, ::fmt) } #[inline] - pub fn new_pointer(x: &T) -> Argument<'_> { + pub const fn new_pointer(x: &T) -> Argument<'_> { argument_new!(T, x, ::fmt) } #[inline] - pub fn new_binary(x: &T) -> Argument<'_> { + pub const fn new_binary(x: &T) -> Argument<'_> { argument_new!(T, x, ::fmt) } #[inline] - pub fn new_lower_exp(x: &T) -> Argument<'_> { + pub const fn new_lower_exp(x: &T) -> Argument<'_> { argument_new!(T, x, ::fmt) } #[inline] - pub fn new_upper_exp(x: &T) -> Argument<'_> { + pub const fn new_upper_exp(x: &T) -> Argument<'_> { argument_new!(T, x, ::fmt) } #[inline] @@ -200,15 +202,8 @@ impl Argument<'_> { /// let f = format_args!("{}", "a"); /// println!("{f}"); /// ``` - /// - /// This function should _not_ be const, to make sure we don't accept - /// format_args!() and panic!() with arguments in const, even when not evaluated: - /// - /// ```compile_fail,E0015 - /// const _: () = if false { panic!("a {}", "a") }; - /// ``` #[inline] - pub fn none() -> [Self; 0] { + pub const fn none() -> [Self; 0] { [] } } @@ -229,3 +224,57 @@ impl UnsafeArg { Self { _private: () } } } + +/// Used by the format_args!() macro to create a fmt::Arguments object. +#[doc(hidden)] +#[unstable(feature = "fmt_internals", issue = "none")] +#[rustc_diagnostic_item = "FmtArgumentsNew"] +impl<'a> Arguments<'a> { + #[inline] + pub const fn new_const(pieces: &'a [&'static str; N]) -> Self { + const { assert!(N <= 1) }; + Arguments { pieces, fmt: None, args: &[] } + } + + /// When using the format_args!() macro, this function is used to generate the + /// Arguments structure. + /// + /// This function should _not_ be const, to make sure we don't accept + /// format_args!() and panic!() with arguments in const, even when not evaluated: + /// + /// ```compile_fail,E0015 + /// const _: () = if false { panic!("a {}", "a") }; + /// ``` + #[inline] + pub fn new_v1( + pieces: &'a [&'static str; P], + args: &'a [rt::Argument<'a>; A], + ) -> Arguments<'a> { + const { assert!(P >= A && P <= A + 1, "invalid args") } + Arguments { pieces, fmt: None, args } + } + + /// Specifies nonstandard formatting parameters. + /// + /// An `rt::UnsafeArg` is required because the following invariants must be held + /// in order for this function to be safe: + /// 1. The `pieces` slice must be at least as long as `fmt`. + /// 2. Every `rt::Placeholder::position` value within `fmt` must be a valid index of `args`. + /// 3. Every `rt::Count::Param` within `fmt` must contain a valid index of `args`. + /// + /// This function should _not_ be const, to make sure we don't accept + /// format_args!() and panic!() with arguments in const, even when not evaluated: + /// + /// ```compile_fail,E0015 + /// const _: () = if false { panic!("a {:1}", "a") }; + /// ``` + #[inline] + pub fn new_v1_formatted( + pieces: &'a [&'static str], + args: &'a [rt::Argument<'a>], + fmt: &'a [rt::Placeholder], + _unsafe_arg: rt::UnsafeArg, + ) -> Arguments<'a> { + Arguments { pieces, fmt: Some(fmt), args } + } +} diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs index 1ca23ab6eea6..394a3ea67783 100644 --- a/library/core/src/hint.rs +++ b/library/core/src/hint.rs @@ -763,8 +763,6 @@ pub const fn cold_path() { /// /// Distribute values evenly between two buckets: /// ``` -/// #![feature(select_unpredictable)] -/// /// use std::hash::BuildHasher; /// use std::hint; /// @@ -780,7 +778,7 @@ pub const fn cold_path() { /// # assert_eq!(bucket_one.len() + bucket_two.len(), 1); /// ``` #[inline(always)] -#[unstable(feature = "select_unpredictable", issue = "133962")] +#[stable(feature = "select_unpredictable", since = "CURRENT_RUSTC_VERSION")] pub fn select_unpredictable(condition: bool, true_val: T, false_val: T) -> T { // FIXME(https://github.com/rust-lang/unsafe-code-guidelines/issues/245): // Change this to use ManuallyDrop instead. diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index c5d5bc000f1c..5649736e4049 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -3320,7 +3320,6 @@ pub const fn is_val_statically_known(_arg: T) -> bool { #[inline] #[rustc_intrinsic] #[rustc_intrinsic_const_stable_indirect] -#[rustc_allow_const_fn_unstable(const_swap_nonoverlapping)] // this is anyway not called since CTFE implements the intrinsic pub const unsafe fn typed_swap_nonoverlapping(x: *mut T, y: *mut T) { // SAFETY: The caller provided single non-overlapping items behind // pointers, so swapping them with `count: 1` is fine. diff --git a/library/core/src/intrinsics/simd.rs b/library/core/src/intrinsics/simd.rs index 6afe924f99d0..86e3f8509ee2 100644 --- a/library/core/src/intrinsics/simd.rs +++ b/library/core/src/intrinsics/simd.rs @@ -577,11 +577,9 @@ pub unsafe fn simd_select(mask: M, if_true: T, if_false: T) -> T; /// For each element, if the bit in `mask` is `1`, select the element from /// `if_true`. If the corresponding bit in `mask` is `0`, select the element from /// `if_false`. +/// The remaining bits of the mask are ignored. /// /// The bitmask bit order matches `simd_bitmask`. -/// -/// # Safety -/// Padding bits must be all zero. #[rustc_intrinsic] #[rustc_nounwind] pub unsafe fn simd_select_bitmask(m: M, yes: T, no: T) -> T; diff --git a/library/core/src/iter/adapters/cloned.rs b/library/core/src/iter/adapters/cloned.rs index 72d746289711..aea6d64281ae 100644 --- a/library/core/src/iter/adapters/cloned.rs +++ b/library/core/src/iter/adapters/cloned.rs @@ -1,6 +1,5 @@ use core::num::NonZero; -use crate::cmp::Ordering; use crate::iter::adapters::zip::try_get_unchecked; use crate::iter::adapters::{SourceIter, TrustedRandomAccess, TrustedRandomAccessNoCoerce}; use crate::iter::{FusedIterator, InPlaceIterable, TrustedLen, UncheckedIterator}; @@ -42,31 +41,13 @@ where self.it.next().cloned() } - #[inline] fn size_hint(&self) -> (usize, Option) { self.it.size_hint() } - #[inline] - fn count(self) -> usize { - self.it.count() - } - - fn last(self) -> Option { - self.it.last().cloned() - } - - #[inline] - fn advance_by(&mut self, n: usize) -> Result<(), NonZero> { - self.it.advance_by(n) - } - - fn nth(&mut self, n: usize) -> Option { - self.it.nth(n).cloned() - } - fn try_fold(&mut self, init: B, f: F) -> R where + Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try, { @@ -80,58 +61,6 @@ where self.it.map(T::clone).fold(init, f) } - fn find

(&mut self, mut predicate: P) -> Option - where - P: FnMut(&Self::Item) -> bool, - { - self.it.find(move |x| predicate(&x)).cloned() - } - - fn max_by(self, mut compare: F) -> Option - where - F: FnMut(&Self::Item, &Self::Item) -> Ordering, - { - self.it.max_by(move |&x, &y| compare(x, y)).cloned() - } - - fn min_by(self, mut compare: F) -> Option - where - F: FnMut(&Self::Item, &Self::Item) -> Ordering, - { - self.it.min_by(move |&x, &y| compare(x, y)).cloned() - } - - fn cmp(self, other: O) -> Ordering - where - O: IntoIterator, - Self::Item: Ord, - { - self.it.cmp_by(other, |x, y| x.cmp(&y)) - } - - fn partial_cmp(self, other: O) -> Option - where - O: IntoIterator, - Self::Item: PartialOrd, - { - self.it.partial_cmp_by(other, |x, y| x.partial_cmp(&y)) - } - - fn eq(self, other: O) -> bool - where - O: IntoIterator, - Self::Item: PartialEq, - { - self.it.eq_by(other, |x, y| x == &y) - } - - fn is_sorted_by(self, mut compare: F) -> bool - where - F: FnMut(&Self::Item, &Self::Item) -> bool, - { - self.it.is_sorted_by(move |&x, &y| compare(x, y)) - } - unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> T where Self: TrustedRandomAccessNoCoerce, @@ -152,13 +81,9 @@ where self.it.next_back().cloned() } - #[inline] - fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero> { - self.it.advance_back_by(n) - } - fn try_rfold(&mut self, init: B, f: F) -> R where + Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try, { @@ -171,13 +96,6 @@ where { self.it.map(T::clone).rfold(init, f) } - - fn rfind

(&mut self, mut predicate: P) -> Option - where - P: FnMut(&Self::Item) -> bool, - { - self.it.rfind(move |x| predicate(&x)).cloned() - } } #[stable(feature = "iter_cloned", since = "1.1.0")] @@ -186,12 +104,10 @@ where I: ExactSizeIterator, T: Clone, { - #[inline] fn len(&self) -> usize { self.it.len() } - #[inline] fn is_empty(&self) -> bool { self.it.is_empty() } diff --git a/library/core/src/iter/adapters/copied.rs b/library/core/src/iter/adapters/copied.rs index 73913aa34a9e..23e4e25ab538 100644 --- a/library/core/src/iter/adapters/copied.rs +++ b/library/core/src/iter/adapters/copied.rs @@ -1,4 +1,3 @@ -use crate::cmp::Ordering; use crate::iter::adapters::zip::try_get_unchecked; use crate::iter::adapters::{SourceIter, TrustedRandomAccess, TrustedRandomAccessNoCoerce}; use crate::iter::{FusedIterator, InPlaceIterable, TrustedLen}; @@ -49,35 +48,20 @@ where fn next_chunk( &mut self, - ) -> Result<[Self::Item; N], array::IntoIter> { + ) -> Result<[Self::Item; N], array::IntoIter> + where + Self: Sized, + { >::spec_next_chunk(&mut self.it) } - #[inline] fn size_hint(&self) -> (usize, Option) { self.it.size_hint() } - #[inline] - fn count(self) -> usize { - self.it.count() - } - - fn last(self) -> Option { - self.it.last().copied() - } - - #[inline] - fn advance_by(&mut self, n: usize) -> Result<(), NonZero> { - self.it.advance_by(n) - } - - fn nth(&mut self, n: usize) -> Option { - self.it.nth(n).copied() - } - fn try_fold(&mut self, init: B, f: F) -> R where + Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try, { @@ -91,56 +75,21 @@ where self.it.fold(init, copy_fold(f)) } - fn find

(&mut self, mut predicate: P) -> Option - where - P: FnMut(&Self::Item) -> bool, - { - self.it.find(move |x| predicate(&x)).copied() + fn nth(&mut self, n: usize) -> Option { + self.it.nth(n).copied() } - fn max_by(self, mut compare: F) -> Option - where - F: FnMut(&Self::Item, &Self::Item) -> Ordering, - { - self.it.max_by(move |&x, &y| compare(x, y)).copied() + fn last(self) -> Option { + self.it.last().copied() } - fn min_by(self, mut compare: F) -> Option - where - F: FnMut(&Self::Item, &Self::Item) -> Ordering, - { - self.it.min_by(move |&x, &y| compare(x, y)).copied() + fn count(self) -> usize { + self.it.count() } - fn cmp(self, other: O) -> Ordering - where - O: IntoIterator, - Self::Item: Ord, - { - self.it.cmp_by(other, |x, y| x.cmp(&y)) - } - - fn partial_cmp(self, other: O) -> Option - where - O: IntoIterator, - Self::Item: PartialOrd, - { - self.it.partial_cmp_by(other, |x, y| x.partial_cmp(&y)) - } - - fn eq(self, other: O) -> bool - where - O: IntoIterator, - Self::Item: PartialEq, - { - self.it.eq_by(other, |x, y| x == &y) - } - - fn is_sorted_by(self, mut compare: F) -> bool - where - F: FnMut(&Self::Item, &Self::Item) -> bool, - { - self.it.is_sorted_by(move |&x, &y| compare(x, y)) + #[inline] + fn advance_by(&mut self, n: usize) -> Result<(), NonZero> { + self.it.advance_by(n) } unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> T @@ -163,13 +112,9 @@ where self.it.next_back().copied() } - #[inline] - fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero> { - self.it.advance_back_by(n) - } - fn try_rfold(&mut self, init: B, f: F) -> R where + Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try, { @@ -183,11 +128,9 @@ where self.it.rfold(init, copy_fold(f)) } - fn rfind

(P); +struct WrapOutput(O); + +impl Trait for Wrap

{ + type Output = WrapOutput; +} + +fn wrap(x: P) -> impl Trait { + Wrap(x) +} + +fn consume(_: P) -> P::Output { + unimplemented!() +} + +pub fn recurse() -> impl Sized { + consume(wrap(recurse)) +} +pub fn main() {} diff --git a/tests/crashes/139738.rs b/tests/crashes/139738.rs new file mode 100644 index 000000000000..c0e7307de6c3 --- /dev/null +++ b/tests/crashes/139738.rs @@ -0,0 +1,3 @@ +//@ known-bug: #139738 +#![feature(generic_const_exprs)] +fn b<'a>() -> impl IntoIterator<[(); (|_: &'a u8| 0, 0).1]> {} diff --git a/tests/crashes/139815.rs b/tests/crashes/139815.rs new file mode 100644 index 000000000000..9094acdc94b2 --- /dev/null +++ b/tests/crashes/139815.rs @@ -0,0 +1,14 @@ +//@ known-bug: #139815 + +#![feature(generic_const_exprs)] +fn is_123( + x: [u32; { + N + 1; + 5 + }], +) -> bool { + match x { + [1, 2] => true, + _ => false, + } +} diff --git a/tests/crashes/139817.rs b/tests/crashes/139817.rs new file mode 100644 index 000000000000..d439ed4cacbd --- /dev/null +++ b/tests/crashes/139817.rs @@ -0,0 +1,8 @@ +//@ known-bug: #139817 +fn enum_upvar() { + type T = impl Copy; + let foo: T = Some((42, std::marker::PhantomData::)); + let x = move || match foo { + None => (), + }; +} diff --git a/tests/crashes/139825.rs b/tests/crashes/139825.rs new file mode 100644 index 000000000000..8c5b6b80f0ba --- /dev/null +++ b/tests/crashes/139825.rs @@ -0,0 +1,5 @@ +//@ known-bug: #139825 +//@compile-flags: --check-cfg=cfg(docsrs,test) --crate-type lib +struct a +where + for<#[cfg(b)] c> u8:; diff --git a/tests/incremental/circular-dependencies.rs b/tests/incremental/circular-dependencies.rs index bd3b109b62c7..c7b5b931fbbe 100644 --- a/tests/incremental/circular-dependencies.rs +++ b/tests/incremental/circular-dependencies.rs @@ -15,7 +15,6 @@ pub struct Foo; pub fn consume_foo(_: Foo) {} //[cfail2]~^ NOTE function defined here -//[cfail2]~| NOTE pub fn produce_foo() -> Foo { Foo diff --git a/tests/incremental/ich_nested_items.rs b/tests/incremental/ich_nested_items.rs index 19628e0bce1b..c2a041ba268c 100644 --- a/tests/incremental/ich_nested_items.rs +++ b/tests/incremental/ich_nested_items.rs @@ -7,6 +7,7 @@ #![crate_type = "rlib"] #![feature(rustc_attrs)] +#![allow(dead_code)] #[rustc_clean(except = "opt_hir_owner_nodes", cfg = "cfail2")] pub fn foo() { diff --git a/tests/incremental/incremental_proc_macro.rs b/tests/incremental/incremental_proc_macro.rs index 3cf89cae6528..fc32aad5645c 100644 --- a/tests/incremental/incremental_proc_macro.rs +++ b/tests/incremental/incremental_proc_macro.rs @@ -12,5 +12,5 @@ extern crate incremental_proc_macro_aux; #[derive(IncrementalMacro)] pub struct Foo { - x: u32 + _x: u32 } diff --git a/tests/incremental/issue-49595/issue-49595.rs b/tests/incremental/issue-49595/issue-49595.rs index a291188f746e..7fe843135dfe 100644 --- a/tests/incremental/issue-49595/issue-49595.rs +++ b/tests/incremental/issue-49595/issue-49595.rs @@ -10,7 +10,7 @@ mod tests { #[cfg_attr(not(cfail1), test)] - fn test() { + fn _test() { } } diff --git a/tests/incremental/issue-84252-global-alloc.rs b/tests/incremental/issue-84252-global-alloc.rs index 8dc611df9d87..cd2cb2313bd3 100644 --- a/tests/incremental/issue-84252-global-alloc.rs +++ b/tests/incremental/issue-84252-global-alloc.rs @@ -1,5 +1,6 @@ //@ revisions: cfail1 cfail2 //@ build-pass +//@ needs-crate-type: cdylib #![crate_type="lib"] #![crate_type="cdylib"] diff --git a/tests/incremental/issue-85360-eval-obligation-ice.rs b/tests/incremental/issue-85360-eval-obligation-ice.rs index 70bb43f39ecf..2148e45bb387 100644 --- a/tests/incremental/issue-85360-eval-obligation-ice.rs +++ b/tests/incremental/issue-85360-eval-obligation-ice.rs @@ -4,6 +4,8 @@ //@ edition: 2021 //@ build-pass +#![allow(dead_code)] + use core::any::Any; use core::marker::PhantomData; diff --git a/tests/incremental/no_mangle.rs b/tests/incremental/no_mangle.rs index 1a01a40113a2..36b82a7b863c 100644 --- a/tests/incremental/no_mangle.rs +++ b/tests/incremental/no_mangle.rs @@ -1,6 +1,7 @@ //@ revisions:cfail1 cfail2 //@ check-pass //@ compile-flags: --crate-type cdylib +//@ needs-crate-type: cdylib #![deny(unused_attributes)] diff --git a/tests/incremental/thinlto/cgu_keeps_identical_fn.rs b/tests/incremental/thinlto/cgu_keeps_identical_fn.rs index 5751759223b9..d124a3498c4a 100644 --- a/tests/incremental/thinlto/cgu_keeps_identical_fn.rs +++ b/tests/incremental/thinlto/cgu_keeps_identical_fn.rs @@ -33,12 +33,12 @@ mod foo { // Trivial functions like this one are imported very reliably by ThinLTO. - #[cfg(any(cfail1, cfail4))] + #[cfg(cfail1)] pub fn inlined_fn() -> u32 { 1234 } - #[cfg(not(any(cfail1, cfail4)))] + #[cfg(not(cfail1))] pub fn inlined_fn() -> u32 { 1234 } diff --git a/tests/incremental/unrecoverable_query.rs b/tests/incremental/unrecoverable_query.rs index e17236bebd25..798a418f7990 100644 --- a/tests/incremental/unrecoverable_query.rs +++ b/tests/incremental/unrecoverable_query.rs @@ -8,6 +8,8 @@ //@ compile-flags: --crate-type=lib //@ build-pass +#![allow(dead_code)] + pub trait P { type A; } diff --git a/tests/mir-opt/coverage/branch_match_arms.main.InstrumentCoverage.diff b/tests/mir-opt/coverage/branch_match_arms.main.InstrumentCoverage.diff index 542b70bcee96..d465b8bded22 100644 --- a/tests/mir-opt/coverage/branch_match_arms.main.InstrumentCoverage.diff +++ b/tests/mir-opt/coverage/branch_match_arms.main.InstrumentCoverage.diff @@ -26,11 +26,20 @@ debug a => _9; } -+ coverage Code { bcb: bcb0 } => $DIR/branch_match_arms.rs:14:1: 15:21 (#0); -+ coverage Code { bcb: bcb1 } => $DIR/branch_match_arms.rs:16:17: 16:32 (#0); -+ coverage Code { bcb: bcb3 } => $DIR/branch_match_arms.rs:17:17: 17:32 (#0); -+ coverage Code { bcb: bcb4 } => $DIR/branch_match_arms.rs:18:17: 18:32 (#0); -+ coverage Code { bcb: bcb5 } => $DIR/branch_match_arms.rs:19:17: 19:32 (#0); ++ coverage Code { bcb: bcb0 } => $DIR/branch_match_arms.rs:14:1: 14:10 (#0); ++ coverage Code { bcb: bcb0 } => $DIR/branch_match_arms.rs:15:11: 15:21 (#0); ++ coverage Code { bcb: bcb1 } => $DIR/branch_match_arms.rs:16:17: 16:18 (#0); ++ coverage Code { bcb: bcb1 } => $DIR/branch_match_arms.rs:16:23: 16:30 (#0); ++ coverage Code { bcb: bcb1 } => $DIR/branch_match_arms.rs:16:31: 16:32 (#0); ++ coverage Code { bcb: bcb3 } => $DIR/branch_match_arms.rs:17:17: 17:18 (#0); ++ coverage Code { bcb: bcb3 } => $DIR/branch_match_arms.rs:17:23: 17:30 (#0); ++ coverage Code { bcb: bcb3 } => $DIR/branch_match_arms.rs:17:31: 17:32 (#0); ++ coverage Code { bcb: bcb4 } => $DIR/branch_match_arms.rs:18:17: 18:18 (#0); ++ coverage Code { bcb: bcb4 } => $DIR/branch_match_arms.rs:18:23: 18:30 (#0); ++ coverage Code { bcb: bcb4 } => $DIR/branch_match_arms.rs:18:31: 18:32 (#0); ++ coverage Code { bcb: bcb5 } => $DIR/branch_match_arms.rs:19:17: 19:18 (#0); ++ coverage Code { bcb: bcb5 } => $DIR/branch_match_arms.rs:19:23: 19:30 (#0); ++ coverage Code { bcb: bcb5 } => $DIR/branch_match_arms.rs:19:31: 19:32 (#0); + coverage Code { bcb: bcb2 } => $DIR/branch_match_arms.rs:21:2: 21:2 (#0); + bb0: { diff --git a/tests/mir-opt/coverage/instrument_coverage.bar.InstrumentCoverage.diff b/tests/mir-opt/coverage/instrument_coverage.bar.InstrumentCoverage.diff index 06e5f011c761..cf6d85abd80e 100644 --- a/tests/mir-opt/coverage/instrument_coverage.bar.InstrumentCoverage.diff +++ b/tests/mir-opt/coverage/instrument_coverage.bar.InstrumentCoverage.diff @@ -4,7 +4,9 @@ fn bar() -> bool { let mut _0: bool; -+ coverage Code { bcb: bcb0 } => $DIR/instrument_coverage.rs:27:1: 29:2 (#0); ++ coverage Code { bcb: bcb0 } => $DIR/instrument_coverage.rs:27:1: 27:17 (#0); ++ coverage Code { bcb: bcb0 } => $DIR/instrument_coverage.rs:28:5: 28:9 (#0); ++ coverage Code { bcb: bcb0 } => $DIR/instrument_coverage.rs:29:2: 29:2 (#0); + bb0: { + Coverage::VirtualCounter(bcb0); diff --git a/tests/mir-opt/coverage/instrument_coverage.main.InstrumentCoverage.diff b/tests/mir-opt/coverage/instrument_coverage.main.InstrumentCoverage.diff index 30de92f3b868..980c5e202ffd 100644 --- a/tests/mir-opt/coverage/instrument_coverage.main.InstrumentCoverage.diff +++ b/tests/mir-opt/coverage/instrument_coverage.main.InstrumentCoverage.diff @@ -7,7 +7,7 @@ let mut _2: bool; let mut _3: !; -+ coverage Code { bcb: bcb0 } => $DIR/instrument_coverage.rs:13:1: 13:11 (#0); ++ coverage Code { bcb: bcb0 } => $DIR/instrument_coverage.rs:13:1: 13:10 (#0); + coverage Code { bcb: bcb1 } => $DIR/instrument_coverage.rs:15:12: 15:15 (#0); + coverage Code { bcb: bcb2 } => $DIR/instrument_coverage.rs:16:13: 16:18 (#0); + coverage Code { bcb: bcb3 } => $DIR/instrument_coverage.rs:17:10: 17:10 (#0); diff --git a/tests/mir-opt/coverage/instrument_coverage_cleanup.main.CleanupPostBorrowck.diff b/tests/mir-opt/coverage/instrument_coverage_cleanup.main.CleanupPostBorrowck.diff index 1a22adeba6fc..b707cd41788a 100644 --- a/tests/mir-opt/coverage/instrument_coverage_cleanup.main.CleanupPostBorrowck.diff +++ b/tests/mir-opt/coverage/instrument_coverage_cleanup.main.CleanupPostBorrowck.diff @@ -7,7 +7,8 @@ coverage branch { true: BlockMarkerId(0), false: BlockMarkerId(1) } => $DIR/instrument_coverage_cleanup.rs:14:8: 14:36 (#0) - coverage Code { bcb: bcb0 } => $DIR/instrument_coverage_cleanup.rs:13:1: 14:36 (#0); + coverage Code { bcb: bcb0 } => $DIR/instrument_coverage_cleanup.rs:13:1: 13:10 (#0); + coverage Code { bcb: bcb0 } => $DIR/instrument_coverage_cleanup.rs:14:8: 14:36 (#0); coverage Code { bcb: bcb3 } => $DIR/instrument_coverage_cleanup.rs:14:37: 14:39 (#0); coverage Code { bcb: bcb1 } => $DIR/instrument_coverage_cleanup.rs:14:39: 14:39 (#0); coverage Code { bcb: bcb2 } => $DIR/instrument_coverage_cleanup.rs:15:2: 15:2 (#0); diff --git a/tests/mir-opt/coverage/instrument_coverage_cleanup.main.InstrumentCoverage.diff b/tests/mir-opt/coverage/instrument_coverage_cleanup.main.InstrumentCoverage.diff index b77969a3e169..239b845c2311 100644 --- a/tests/mir-opt/coverage/instrument_coverage_cleanup.main.InstrumentCoverage.diff +++ b/tests/mir-opt/coverage/instrument_coverage_cleanup.main.InstrumentCoverage.diff @@ -7,7 +7,8 @@ coverage branch { true: BlockMarkerId(0), false: BlockMarkerId(1) } => $DIR/instrument_coverage_cleanup.rs:14:8: 14:36 (#0) -+ coverage Code { bcb: bcb0 } => $DIR/instrument_coverage_cleanup.rs:13:1: 14:36 (#0); ++ coverage Code { bcb: bcb0 } => $DIR/instrument_coverage_cleanup.rs:13:1: 13:10 (#0); ++ coverage Code { bcb: bcb0 } => $DIR/instrument_coverage_cleanup.rs:14:8: 14:36 (#0); + coverage Code { bcb: bcb3 } => $DIR/instrument_coverage_cleanup.rs:14:37: 14:39 (#0); + coverage Code { bcb: bcb1 } => $DIR/instrument_coverage_cleanup.rs:14:39: 14:39 (#0); + coverage Code { bcb: bcb2 } => $DIR/instrument_coverage_cleanup.rs:15:2: 15:2 (#0); diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-abort.diff b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-abort.diff index f36157a762c2..39ba480d2033 100644 --- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-abort.diff +++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-abort.diff @@ -8,9 +8,9 @@ let mut _3: u16; let mut _4: u32; + scope 1 (inlined core::num::::unchecked_shl) { -+ let mut _5: bool; -+ let _6: (); ++ let _5: (); + scope 2 (inlined core::ub_checks::check_language_ub) { ++ let mut _6: bool; + scope 3 (inlined core::ub_checks::check_language_ub::runtime) { + } + } @@ -22,20 +22,20 @@ StorageLive(_4); _4 = copy _2; - _0 = core::num::::unchecked_shl(move _3, move _4) -> [return: bb1, unwind unreachable]; -+ StorageLive(_6); + StorageLive(_5); -+ _5 = UbChecks(); -+ switchInt(move _5) -> [0: bb2, otherwise: bb1]; ++ StorageLive(_6); ++ _6 = UbChecks(); ++ switchInt(copy _6) -> [0: bb2, otherwise: bb1]; } bb1: { -+ _6 = core::num::::unchecked_shl::precondition_check(copy _4) -> [return: bb2, unwind unreachable]; ++ _5 = core::num::::unchecked_shl::precondition_check(copy _4) -> [return: bb2, unwind unreachable]; + } + + bb2: { -+ StorageDead(_5); + _0 = ShlUnchecked(copy _3, copy _4); + StorageDead(_6); ++ StorageDead(_5); StorageDead(_4); StorageDead(_3); return; diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-unwind.diff b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-unwind.diff index be1b066c6c1b..5a758d357406 100644 --- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-unwind.diff +++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-unwind.diff @@ -8,9 +8,9 @@ let mut _3: u16; let mut _4: u32; + scope 1 (inlined core::num::::unchecked_shl) { -+ let mut _5: bool; -+ let _6: (); ++ let _5: (); + scope 2 (inlined core::ub_checks::check_language_ub) { ++ let mut _6: bool; + scope 3 (inlined core::ub_checks::check_language_ub::runtime) { + } + } @@ -22,20 +22,20 @@ StorageLive(_4); _4 = copy _2; - _0 = core::num::::unchecked_shl(move _3, move _4) -> [return: bb1, unwind continue]; -+ StorageLive(_6); + StorageLive(_5); -+ _5 = UbChecks(); -+ switchInt(move _5) -> [0: bb2, otherwise: bb1]; ++ StorageLive(_6); ++ _6 = UbChecks(); ++ switchInt(copy _6) -> [0: bb2, otherwise: bb1]; } bb1: { -+ _6 = core::num::::unchecked_shl::precondition_check(copy _4) -> [return: bb2, unwind unreachable]; ++ _5 = core::num::::unchecked_shl::precondition_check(copy _4) -> [return: bb2, unwind unreachable]; + } + + bb2: { -+ StorageDead(_5); + _0 = ShlUnchecked(copy _3, copy _4); + StorageDead(_6); ++ StorageDead(_5); StorageDead(_4); StorageDead(_3); return; diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-abort.diff b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-abort.diff index 360687f3c4e7..a0caf141f2d0 100644 --- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-abort.diff +++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-abort.diff @@ -8,9 +8,9 @@ let mut _3: i64; let mut _4: u32; + scope 1 (inlined core::num::::unchecked_shr) { -+ let mut _5: bool; -+ let _6: (); ++ let _5: (); + scope 2 (inlined core::ub_checks::check_language_ub) { ++ let mut _6: bool; + scope 3 (inlined core::ub_checks::check_language_ub::runtime) { + } + } @@ -22,20 +22,20 @@ StorageLive(_4); _4 = copy _2; - _0 = core::num::::unchecked_shr(move _3, move _4) -> [return: bb1, unwind unreachable]; -+ StorageLive(_6); + StorageLive(_5); -+ _5 = UbChecks(); -+ switchInt(move _5) -> [0: bb2, otherwise: bb1]; ++ StorageLive(_6); ++ _6 = UbChecks(); ++ switchInt(copy _6) -> [0: bb2, otherwise: bb1]; } bb1: { -+ _6 = core::num::::unchecked_shr::precondition_check(copy _4) -> [return: bb2, unwind unreachable]; ++ _5 = core::num::::unchecked_shr::precondition_check(copy _4) -> [return: bb2, unwind unreachable]; + } + + bb2: { -+ StorageDead(_5); + _0 = ShrUnchecked(copy _3, copy _4); + StorageDead(_6); ++ StorageDead(_5); StorageDead(_4); StorageDead(_3); return; diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-unwind.diff b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-unwind.diff index 986df55df037..633089e7b2a2 100644 --- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-unwind.diff +++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-unwind.diff @@ -8,9 +8,9 @@ let mut _3: i64; let mut _4: u32; + scope 1 (inlined core::num::::unchecked_shr) { -+ let mut _5: bool; -+ let _6: (); ++ let _5: (); + scope 2 (inlined core::ub_checks::check_language_ub) { ++ let mut _6: bool; + scope 3 (inlined core::ub_checks::check_language_ub::runtime) { + } + } @@ -22,20 +22,20 @@ StorageLive(_4); _4 = copy _2; - _0 = core::num::::unchecked_shr(move _3, move _4) -> [return: bb1, unwind continue]; -+ StorageLive(_6); + StorageLive(_5); -+ _5 = UbChecks(); -+ switchInt(move _5) -> [0: bb2, otherwise: bb1]; ++ StorageLive(_6); ++ _6 = UbChecks(); ++ switchInt(copy _6) -> [0: bb2, otherwise: bb1]; } bb1: { -+ _6 = core::num::::unchecked_shr::precondition_check(copy _4) -> [return: bb2, unwind unreachable]; ++ _5 = core::num::::unchecked_shr::precondition_check(copy _4) -> [return: bb2, unwind unreachable]; + } + + bb2: { -+ StorageDead(_5); + _0 = ShrUnchecked(copy _3, copy _4); + StorageDead(_6); ++ StorageDead(_5); StorageDead(_4); StorageDead(_3); return; diff --git a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-abort.diff b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-abort.diff index 28878736ed7c..a5986a4315a2 100644 --- a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-abort.diff +++ b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-abort.diff @@ -10,9 +10,9 @@ + scope 2 { + } + scope 3 (inlined unreachable_unchecked) { -+ let mut _4: bool; -+ let _5: (); ++ let _4: (); + scope 4 (inlined core::ub_checks::check_language_ub) { ++ let mut _5: bool; + scope 5 (inlined core::ub_checks::check_language_ub::runtime) { + } + } @@ -24,7 +24,7 @@ _2 = move _1; - _0 = Option::::unwrap_unchecked(move _2) -> [return: bb1, unwind unreachable]; + StorageLive(_3); -+ StorageLive(_5); ++ StorageLive(_4); + _3 = discriminant(_2); + switchInt(move _3) -> [0: bb2, 1: bb3, otherwise: bb1]; } @@ -34,15 +34,15 @@ + } + + bb2: { -+ StorageLive(_4); -+ _4 = UbChecks(); -+ assume(copy _4); -+ _5 = unreachable_unchecked::precondition_check() -> [return: bb1, unwind unreachable]; ++ StorageLive(_5); ++ _5 = UbChecks(); ++ assume(copy _5); ++ _4 = unreachable_unchecked::precondition_check() -> [return: bb1, unwind unreachable]; + } + + bb3: { + _0 = move ((_2 as Some).0: T); -+ StorageDead(_5); ++ StorageDead(_4); + StorageDead(_3); StorageDead(_2); return; diff --git a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-unwind.diff b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-unwind.diff index 27b6bb6a5bb2..12b03a6b6d92 100644 --- a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-unwind.diff +++ b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-unwind.diff @@ -10,9 +10,9 @@ + scope 2 { + } + scope 3 (inlined unreachable_unchecked) { -+ let mut _4: bool; -+ let _5: (); ++ let _4: (); + scope 4 (inlined core::ub_checks::check_language_ub) { ++ let mut _5: bool; + scope 5 (inlined core::ub_checks::check_language_ub::runtime) { + } + } @@ -24,7 +24,7 @@ _2 = move _1; - _0 = Option::::unwrap_unchecked(move _2) -> [return: bb1, unwind: bb2]; + StorageLive(_3); -+ StorageLive(_5); ++ StorageLive(_4); + _3 = discriminant(_2); + switchInt(move _3) -> [0: bb2, 1: bb3, otherwise: bb1]; } @@ -38,15 +38,15 @@ - bb2 (cleanup): { - resume; + bb2: { -+ StorageLive(_4); -+ _4 = UbChecks(); -+ assume(copy _4); -+ _5 = unreachable_unchecked::precondition_check() -> [return: bb1, unwind unreachable]; ++ StorageLive(_5); ++ _5 = UbChecks(); ++ assume(copy _5); ++ _4 = unreachable_unchecked::precondition_check() -> [return: bb1, unwind unreachable]; + } + + bb3: { + _0 = move ((_2 as Some).0: T); -+ StorageDead(_5); ++ StorageDead(_4); + StorageDead(_3); + StorageDead(_2); + return; diff --git a/tests/mir-opt/instsimplify/ub_check.unwrap_unchecked.InstSimplify-after-simplifycfg.diff b/tests/mir-opt/instsimplify/ub_check.unwrap_unchecked.InstSimplify-after-simplifycfg.diff index 5fee9a6733dd..82353a2d5404 100644 --- a/tests/mir-opt/instsimplify/ub_check.unwrap_unchecked.InstSimplify-after-simplifycfg.diff +++ b/tests/mir-opt/instsimplify/ub_check.unwrap_unchecked.InstSimplify-after-simplifycfg.diff @@ -10,9 +10,9 @@ scope 2 { } scope 3 (inlined unreachable_unchecked) { - let mut _4: bool; - let _5: (); + let _4: (); scope 4 (inlined core::ub_checks::check_language_ub) { + let mut _5: bool; scope 5 (inlined core::ub_checks::check_language_ub::runtime) { } } @@ -23,7 +23,7 @@ StorageLive(_2); _2 = copy _1; StorageLive(_3); - StorageLive(_5); + StorageLive(_4); _3 = discriminant(_2); switchInt(move _3) -> [0: bb2, 1: bb3, otherwise: bb1]; } @@ -33,16 +33,16 @@ } bb2: { - StorageLive(_4); -- _4 = UbChecks(); -+ _4 = const false; - assume(copy _4); - _5 = unreachable_unchecked::precondition_check() -> [return: bb1, unwind unreachable]; + StorageLive(_5); +- _5 = UbChecks(); ++ _5 = const false; + assume(copy _5); + _4 = unreachable_unchecked::precondition_check() -> [return: bb1, unwind unreachable]; } bb3: { _0 = move ((_2 as Some).0: i32); - StorageDead(_5); + StorageDead(_4); StorageDead(_3); StorageDead(_2); return; diff --git a/tests/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff b/tests/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff index 1ab9be966522..d8eace98d556 100644 --- a/tests/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff +++ b/tests/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff @@ -5,23 +5,18 @@ debug bytes => _1; let mut _0: std::option::Option<[u8; 4]>; let _2: [u32; 4]; - let mut _3: [u8; 16]; - let mut _5: [u8; 4]; - let mut _6: u32; + let mut _4: [u8; 4]; scope 1 { debug dwords => _2; scope 2 { - debug ip => _4; - let _4: u32; + debug ip => _3; + let _3: u32; } } bb0: { StorageLive(_2); - StorageLive(_3); - _3 = copy _1; - _2 = move _3 as [u32; 4] (Transmute); - StorageDead(_3); + _2 = copy _1 as [u32; 4] (Transmute); switchInt(copy _2[0 of 4]) -> [0: bb1, otherwise: bb4]; } @@ -34,15 +29,10 @@ } bb3: { + _3 = copy _2[3 of 4]; StorageLive(_4); - _4 = copy _2[3 of 4]; - StorageLive(_5); - StorageLive(_6); - _6 = copy _4; - _5 = move _6 as [u8; 4] (Transmute); - StorageDead(_6); - _0 = Option::<[u8; 4]>::Some(move _5); - StorageDead(_5); + _4 = copy _3 as [u8; 4] (Transmute); + _0 = Option::<[u8; 4]>::Some(move _4); StorageDead(_4); goto -> bb5; } diff --git a/tests/mir-opt/pre-codegen/matchbr.match1.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/matchbr.match1.PreCodegen.after.mir new file mode 100644 index 000000000000..3a202728ea91 --- /dev/null +++ b/tests/mir-opt/pre-codegen/matchbr.match1.PreCodegen.after.mir @@ -0,0 +1,13 @@ +// MIR for `match1` after PreCodegen + +fn match1(_1: bool, _2: i32, _3: i32) -> i32 { + debug c => _1; + debug v1 => _2; + debug v2 => _3; + let mut _0: i32; + + bb0: { + _0 = Sub(copy _2, copy _3); + return; + } +} diff --git a/tests/mir-opt/pre-codegen/matchbr.rs b/tests/mir-opt/pre-codegen/matchbr.rs new file mode 100644 index 000000000000..1822739da2c7 --- /dev/null +++ b/tests/mir-opt/pre-codegen/matchbr.rs @@ -0,0 +1,10 @@ +#![crate_type = "lib"] + +// EMIT_MIR matchbr.match1.PreCodegen.after.mir +pub fn match1(c: bool, v1: i32, v2: i32) -> i32 { + // CHECK-LABEL: fn match1( + // CHECK: bb0: + // CHECK-NEXT: _0 = Sub + // CHECK-NEXT: return; + if c { v1 - v2 } else { v1 - v2 } +} diff --git a/tests/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals-final.panic-abort.diff b/tests/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals-final.panic-abort.diff index c363dfcbf70b..ff1bc58524bc 100644 --- a/tests/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals-final.panic-abort.diff +++ b/tests/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals-final.panic-abort.diff @@ -8,6 +8,9 @@ let mut _3: std::option::Option; let mut _4: isize; let mut _5: isize; +- let mut _7: bool; +- let mut _8: u8; +- let mut _9: bool; scope 1 { debug a => _6; let _6: u8; @@ -32,9 +35,7 @@ } bb2: { - StorageLive(_6); _6 = copy (((_1.0: std::option::Option) as Some).0: u8); - StorageDead(_6); goto -> bb3; } diff --git a/tests/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals-final.panic-unwind.diff b/tests/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals-final.panic-unwind.diff index 895b0067d2e6..2c289c664754 100644 --- a/tests/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals-final.panic-unwind.diff +++ b/tests/mir-opt/simplify_locals_fixedpoint.foo.SimplifyLocals-final.panic-unwind.diff @@ -8,6 +8,9 @@ let mut _3: std::option::Option; let mut _4: isize; let mut _5: isize; +- let mut _7: bool; +- let mut _8: u8; +- let mut _9: bool; scope 1 { debug a => _6; let _6: u8; @@ -32,9 +35,7 @@ } bb2: { - StorageLive(_6); _6 = copy (((_1.0: std::option::Option) as Some).0: u8); - StorageDead(_6); goto -> bb3; } diff --git a/tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff b/tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff index a1df868cde05..33f1ad9bef4e 100644 --- a/tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff +++ b/tests/mir-opt/sroa/lifetimes.foo.ScalarReplacementOfAggregates.diff @@ -121,7 +121,7 @@ StorageDead(_18); _16 = &_17; _15 = &(*_16); - _11 = Arguments::<'_>::new_v1::<3, 2>(move _12, move _15) -> [return: bb5, unwind unreachable]; + _11 = core::fmt::rt::>::new_v1::<3, 2>(move _12, move _15) -> [return: bb5, unwind unreachable]; } bb5: { diff --git a/tests/pretty/hir-delegation.pp b/tests/pretty/hir-delegation.pp index 872a6a45aede..e452cee63659 100644 --- a/tests/pretty/hir-delegation.pp +++ b/tests/pretty/hir-delegation.pp @@ -2,7 +2,8 @@ //@ pretty-mode:hir //@ pp-exact:hir-delegation.pp -#![allow(incomplete_features)]#![feature(fn_delegation)] +#![allow(incomplete_features)] +#![feature(fn_delegation)] #[prelude_import] use ::std::prelude::rust_2015::*; #[macro_use] diff --git a/tests/pretty/issue-4264.pp b/tests/pretty/issue-4264.pp index 3cff6ca33dab..eb808f7122a9 100644 --- a/tests/pretty/issue-4264.pp +++ b/tests/pretty/issue-4264.pp @@ -34,7 +34,7 @@ fn bar() ({ ((::alloc::fmt::format as for<'a> fn(Arguments<'a>) -> String {format})(((format_arguments::new_const as - fn(&[&'static str; 1]) -> Arguments<'_> {Arguments::<'_>::new_const::<1>})((&([("test" + fn(&[&'static str; 1]) -> Arguments<'_> {core::fmt::rt::>::new_const::<1>})((&([("test" as &str)] as [&str; 1]) as &[&str; 1])) as Arguments<'_>)) as String) } as String)) as String); diff --git a/tests/pretty/shebang-at-top.pp b/tests/pretty/shebang-at-top.pp new file mode 100644 index 000000000000..a27972526364 --- /dev/null +++ b/tests/pretty/shebang-at-top.pp @@ -0,0 +1,12 @@ +#!/usr/bin/env rust +#![feature(prelude_import)] +#![no_std] +#[prelude_import] +use ::std::prelude::rust_2015::*; +#[macro_use] +extern crate std; +//@ pretty-mode:expanded +//@ pp-exact:shebang-at-top.pp +//@ pretty-compare-only + +fn main() {} diff --git a/tests/pretty/shebang-at-top.rs b/tests/pretty/shebang-at-top.rs new file mode 100644 index 000000000000..8bfa925fa1ab --- /dev/null +++ b/tests/pretty/shebang-at-top.rs @@ -0,0 +1,6 @@ +#!/usr/bin/env rust +//@ pretty-mode:expanded +//@ pp-exact:shebang-at-top.pp +//@ pretty-compare-only + +fn main() {} diff --git a/tests/run-make/export/compile-interface-error/app.rs b/tests/run-make/export/compile-interface-error/app.rs new file mode 100644 index 000000000000..f619745a7112 --- /dev/null +++ b/tests/run-make/export/compile-interface-error/app.rs @@ -0,0 +1,3 @@ +extern crate libr; + +fn main() {} diff --git a/tests/run-make/export/compile-interface-error/liblibr.rs b/tests/run-make/export/compile-interface-error/liblibr.rs new file mode 100644 index 000000000000..906d8d7be12c --- /dev/null +++ b/tests/run-make/export/compile-interface-error/liblibr.rs @@ -0,0 +1,5 @@ +#![feature(export_stable)] + +// interface file is broken(priv fn): +#[export_stable] +extern "C" fn foo(); diff --git a/tests/run-make/export/compile-interface-error/rmake.rs b/tests/run-make/export/compile-interface-error/rmake.rs new file mode 100644 index 000000000000..89474e9d4fbf --- /dev/null +++ b/tests/run-make/export/compile-interface-error/rmake.rs @@ -0,0 +1,9 @@ +use run_make_support::rustc; + +fn main() { + // Do not produce the interface, use the broken one. + rustc() + .input("app.rs") + .run_fail() + .assert_stderr_contains("couldn't compile interface"); +} diff --git a/tests/run-make/export/disambiguator/app.rs b/tests/run-make/export/disambiguator/app.rs new file mode 100644 index 000000000000..27e0e2280e54 --- /dev/null +++ b/tests/run-make/export/disambiguator/app.rs @@ -0,0 +1,7 @@ +extern crate libr; + +use libr::*; + +fn main() { + assert_eq!(S::::foo(), 2); +} diff --git a/tests/run-make/export/disambiguator/libr.rs b/tests/run-make/export/disambiguator/libr.rs new file mode 100644 index 000000000000..b294d5c9e8ed --- /dev/null +++ b/tests/run-make/export/disambiguator/libr.rs @@ -0,0 +1,27 @@ +// `S::::foo` and `S::::foo` have same `DefPath` modulo disambiguator. +// `libr.rs` interface may not contain `S::::foo` as private items aren't +// exportable. We should make sure that original `S::::foo` and the one +// produced during interface generation have same mangled names. + +#![feature(export_stable)] +#![crate_type = "sdylib"] + +#[export_stable] +#[repr(C)] +pub struct S(pub T); + +struct S1; +pub struct S2; + +impl S { + extern "C" fn foo() -> i32 { + 1 + } +} + +#[export_stable] +impl S { + pub extern "C" fn foo() -> i32 { + 2 + } +} diff --git a/tests/run-make/export/disambiguator/rmake.rs b/tests/run-make/export/disambiguator/rmake.rs new file mode 100644 index 000000000000..743db1933fb4 --- /dev/null +++ b/tests/run-make/export/disambiguator/rmake.rs @@ -0,0 +1,12 @@ +use run_make_support::rustc; + +fn main() { + rustc() + .env("RUSTC_FORCE_RUSTC_VERSION", "1") + .input("libr.rs") + .run(); + rustc() + .env("RUSTC_FORCE_RUSTC_VERSION", "2") + .input("app.rs") + .run(); +} diff --git a/tests/run-make/export/extern-opt/app.rs b/tests/run-make/export/extern-opt/app.rs new file mode 100644 index 000000000000..765c9925d5f7 --- /dev/null +++ b/tests/run-make/export/extern-opt/app.rs @@ -0,0 +1,6 @@ +extern crate libr; +use libr::*; + +fn main() { + assert_eq!(foo(1), 1); +} diff --git a/tests/run-make/export/extern-opt/libinterface.rs b/tests/run-make/export/extern-opt/libinterface.rs new file mode 100644 index 000000000000..313cfbe7d59c --- /dev/null +++ b/tests/run-make/export/extern-opt/libinterface.rs @@ -0,0 +1,4 @@ +#![feature(export_stable)] + +#[export_stable] +pub extern "C" fn foo(x: i32) -> i32; diff --git a/tests/run-make/export/extern-opt/libr.rs b/tests/run-make/export/extern-opt/libr.rs new file mode 100644 index 000000000000..026ebb4233df --- /dev/null +++ b/tests/run-make/export/extern-opt/libr.rs @@ -0,0 +1,5 @@ +#![feature(export_stable)] +#![crate_type = "sdylib"] + +#[export_stable] +pub extern "C" fn foo(x: i32) -> i32 { x } diff --git a/tests/run-make/export/extern-opt/rmake.rs b/tests/run-make/export/extern-opt/rmake.rs new file mode 100644 index 000000000000..821e2eb21491 --- /dev/null +++ b/tests/run-make/export/extern-opt/rmake.rs @@ -0,0 +1,23 @@ +use run_make_support::{rustc, dynamic_lib_name}; + +fn main() { + rustc() + .env("RUSTC_FORCE_RUSTC_VERSION", "1") + .input("libr.rs") + .run(); + + rustc() + .env("RUSTC_FORCE_RUSTC_VERSION", "2") + .input("app.rs") + .extern_("libr", "libinterface.rs") + .extern_("libr", dynamic_lib_name("libr")) + .run(); + + rustc() + .env("RUSTC_FORCE_RUSTC_VERSION", "2") + .input("app.rs") + .extern_("libr", "interface.rs") // wrong interface format + .extern_("libr", dynamic_lib_name("libr")) + .run_fail() + .assert_stderr_contains("extern location for libr does not exist"); +} diff --git a/tests/run-make/export/simple/app.rs b/tests/run-make/export/simple/app.rs new file mode 100644 index 000000000000..ba34bdd7b566 --- /dev/null +++ b/tests/run-make/export/simple/app.rs @@ -0,0 +1,8 @@ +extern crate libr; +use libr::*; + +fn main() { + let s = m::S { x: 42 }; + assert_eq!(m::foo1(s), 42); + assert_eq!(m::S::foo2(1), 1); +} diff --git a/tests/run-make/export/simple/libr.rs b/tests/run-make/export/simple/libr.rs new file mode 100644 index 000000000000..e10b76a6e52e --- /dev/null +++ b/tests/run-make/export/simple/libr.rs @@ -0,0 +1,22 @@ +#![feature(export_stable)] +#![crate_type = "sdylib"] + +#[export_stable] +pub mod m { + #[repr(C)] + pub struct S { + pub x: i32, + } + + pub extern "C" fn foo1(x: S) -> i32 { + x.x + } + + pub type Integer = i32; + + impl S { + pub extern "C" fn foo2(x: Integer) -> Integer { + x + } + } +} diff --git a/tests/run-make/export/simple/rmake.rs b/tests/run-make/export/simple/rmake.rs new file mode 100644 index 000000000000..743db1933fb4 --- /dev/null +++ b/tests/run-make/export/simple/rmake.rs @@ -0,0 +1,12 @@ +use run_make_support::rustc; + +fn main() { + rustc() + .env("RUSTC_FORCE_RUSTC_VERSION", "1") + .input("libr.rs") + .run(); + rustc() + .env("RUSTC_FORCE_RUSTC_VERSION", "2") + .input("app.rs") + .run(); +} diff --git a/tests/run-make/remap-path-prefix-dwarf/rmake.rs b/tests/run-make/remap-path-prefix-dwarf/rmake.rs index ede1d6157425..3d6ca014fc2a 100644 --- a/tests/run-make/remap-path-prefix-dwarf/rmake.rs +++ b/tests/run-make/remap-path-prefix-dwarf/rmake.rs @@ -91,6 +91,59 @@ fn main() { )), dwarf_test: DwarfDump::ParentTest, }); + + check_dwarf_deps("macro", DwarfDump::AvoidSrcPath); + check_dwarf_deps("diagnostics", DwarfDump::AvoidSrcPath); + check_dwarf_deps("macro,diagnostics", DwarfDump::AvoidSrcPath); + check_dwarf_deps("object", DwarfDump::ContainsSrcPath); +} + +#[track_caller] +fn check_dwarf_deps(scope: &str, dwarf_test: DwarfDump) { + // build some_value.rs + let mut rustc_sm = rustc(); + rustc_sm.input(cwd().join("src/some_value.rs")); + rustc_sm.arg("-Cdebuginfo=2"); + rustc_sm.arg(format!("-Zremap-path-scope={}", scope)); + rustc_sm.arg("--remap-path-prefix"); + rustc_sm.arg(format!("{}=/REMAPPED", cwd().display())); + rustc_sm.arg("-Csplit-debuginfo=off"); + rustc_sm.run(); + + // build print_value.rs + let print_value_rlib = rust_lib_name(&format!("print_value.{scope}")); + let mut rustc_pv = rustc(); + rustc_pv.input(cwd().join("src/print_value.rs")); + rustc_pv.output(&print_value_rlib); + rustc_pv.arg("-Cdebuginfo=2"); + rustc_pv.arg(format!("-Zremap-path-scope={}", scope)); + rustc_pv.arg("--remap-path-prefix"); + rustc_pv.arg(format!("{}=/REMAPPED", cwd().display())); + rustc_pv.arg("-Csplit-debuginfo=off"); + rustc_pv.run(); + + match dwarf_test { + DwarfDump::AvoidSrcPath => { + llvm_dwarfdump() + .input(print_value_rlib) + .run() + .assert_stdout_not_contains("REMAPPED/src/some_value.rs") + .assert_stdout_not_contains("REMAPPED/src/print_value.rs") + .assert_stdout_not_contains("REMAPPED/REMAPPED") + .assert_stdout_contains(cwd().join("src/some_value.rs").display().to_string()) + .assert_stdout_contains(cwd().join("src/print_value.rs").display().to_string()); + } + DwarfDump::ContainsSrcPath => { + llvm_dwarfdump() + .input(print_value_rlib) + .run() + .assert_stdout_contains("REMAPPED/src/some_value.rs") + .assert_stdout_contains("REMAPPED/src/print_value.rs") + .assert_stdout_not_contains(cwd().join("src/some_value.rs").display().to_string()) + .assert_stdout_not_contains(cwd().join("src/print_value.rs").display().to_string()); + } + _ => unreachable!(), + } } #[track_caller] diff --git a/tests/run-make/remap-path-prefix-dwarf/src/print_value.rs b/tests/run-make/remap-path-prefix-dwarf/src/print_value.rs new file mode 100644 index 000000000000..f7653025ba5a --- /dev/null +++ b/tests/run-make/remap-path-prefix-dwarf/src/print_value.rs @@ -0,0 +1,7 @@ +#![crate_type = "rlib"] + +extern crate some_value; + +pub fn print_value() { + println!("{}", some_value::get_some_value()); +} diff --git a/tests/run-make/remap-path-prefix-dwarf/src/some_value.rs b/tests/run-make/remap-path-prefix-dwarf/src/some_value.rs new file mode 100644 index 000000000000..aa95a1bdf73b --- /dev/null +++ b/tests/run-make/remap-path-prefix-dwarf/src/some_value.rs @@ -0,0 +1,6 @@ +#![crate_type = "rlib"] + +#[inline] +pub fn get_some_value() -> i32 { + 42 +} diff --git a/tests/run-make/remap-path-prefix/rmake.rs b/tests/run-make/remap-path-prefix/rmake.rs index aeb30e72d5bf..b4f7f4769b5b 100644 --- a/tests/run-make/remap-path-prefix/rmake.rs +++ b/tests/run-make/remap-path-prefix/rmake.rs @@ -47,10 +47,10 @@ fn main() { out_object.run(); rmeta_contains("/the/aux/lib.rs"); - rmeta_not_contains("auxiliary"); + rmeta_contains("auxiliary"); out_macro.run(); rmeta_contains("/the/aux/lib.rs"); - rmeta_not_contains("auxiliary"); + rmeta_contains("auxiliary"); out_diagobj.run(); rmeta_contains("/the/aux/lib.rs"); rmeta_not_contains("auxiliary"); @@ -58,6 +58,7 @@ fn main() { //FIXME(Oneirical): These could be generalized into run_make_support // helper functions. +#[track_caller] fn rmeta_contains(expected: &str) { // Normalize to account for path differences in Windows. if !bstr::BString::from(rfs::read("liblib.rmeta")).replace(b"\\", b"/").contains_str(expected) { @@ -69,6 +70,7 @@ fn rmeta_contains(expected: &str) { } } +#[track_caller] fn rmeta_not_contains(expected: &str) { // Normalize to account for path differences in Windows. if bstr::BString::from(rfs::read("liblib.rmeta")).replace(b"\\", b"/").contains_str(expected) { diff --git a/tests/run-make/rustdoc-tempdir-removal/compile-error.rs b/tests/run-make/rustdoc-tempdir-removal/compile-error.rs new file mode 100644 index 000000000000..66a3b3f270b7 --- /dev/null +++ b/tests/run-make/rustdoc-tempdir-removal/compile-error.rs @@ -0,0 +1,5 @@ +#![doc(test(attr(deny(warnings))))] + +//! ``` +//! let a = 12; +//! ``` diff --git a/tests/run-make/rustdoc-tempdir-removal/rmake.rs b/tests/run-make/rustdoc-tempdir-removal/rmake.rs new file mode 100644 index 000000000000..bd87f05b7cf5 --- /dev/null +++ b/tests/run-make/rustdoc-tempdir-removal/rmake.rs @@ -0,0 +1,34 @@ +// This test ensures that no temporary folder is "left behind" when doctests fail for any reason. + +//@ only-linux + +use std::path::Path; + +use run_make_support::{path, rfs, rustdoc}; + +fn run_doctest_and_check_tmpdir(tmp_dir: &Path, doctest: &str, edition: &str) { + let output = + rustdoc().input(doctest).env("TMPDIR", tmp_dir).arg("--test").edition(edition).run_fail(); + + output.assert_exit_code(101).assert_stdout_contains( + "test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out", + ); + + rfs::read_dir_entries(tmp_dir, |entry| { + panic!("Found an item inside the temporary folder: {entry:?}"); + }); +} + +fn run_doctest_and_check_tmpdir_for_edition(tmp_dir: &Path, edition: &str) { + run_doctest_and_check_tmpdir(tmp_dir, "compile-error.rs", edition); + run_doctest_and_check_tmpdir(tmp_dir, "run-error.rs", edition); +} + +fn main() { + let tmp_dir = path("tmp"); + rfs::create_dir(&tmp_dir); + + run_doctest_and_check_tmpdir_for_edition(&tmp_dir, "2018"); + // We use the 2024 edition to check that it's also working for merged doctests. + run_doctest_and_check_tmpdir_for_edition(&tmp_dir, "2024"); +} diff --git a/tests/run-make/rustdoc-tempdir-removal/run-error.rs b/tests/run-make/rustdoc-tempdir-removal/run-error.rs new file mode 100644 index 000000000000..4ac95f6dd61a --- /dev/null +++ b/tests/run-make/rustdoc-tempdir-removal/run-error.rs @@ -0,0 +1,3 @@ +//! ``` +//! panic!(); +//! ``` diff --git a/tests/rustdoc-gui/sidebar.goml b/tests/rustdoc-gui/sidebar.goml index 38160cc49d08..9c66b84165f8 100644 --- a/tests/rustdoc-gui/sidebar.goml +++ b/tests/rustdoc-gui/sidebar.goml @@ -199,6 +199,42 @@ assert-position-false: (".sidebar-crate > h2 > a", {"x": -3}) drag-and-drop: ((205, 100), (108, 100)) assert-position: (".sidebar-crate > h2 > a", {"x": -3}) +// Check that the mobile sidebar and the source sidebar use the same icon. +store-css: (".mobile-topbar .sidebar-menu-toggle::before", {"content": image_url}) +// Then we go to a source page. +click: ".main-heading .src" +assert-css: ("#sidebar-button a::before", {"content": |image_url|}) +// Check that hover events work as expected. +store-css: ("#sidebar-button a", {"background-color": sidebar_background}) +move-cursor-to: "#sidebar-button a" +store-css: ("#sidebar-button a:hover", {"background-color": sidebar_background_hover}) +assert: |sidebar_background| != |sidebar_background_hover| +click: "#sidebar-button a" +wait-for: "html.src-sidebar-expanded" +assert-css: ("#sidebar-button a:hover", {"background-color": |sidebar_background_hover|}) +move-cursor-to: "#settings-menu" +assert-css: ("#sidebar-button a:not(:hover)", {"background-color": |sidebar_background|}) +// Closing sidebar. +click: "#sidebar-button a" +wait-for: "html:not(.src-sidebar-expanded)" +// Now we check the same when the sidebar button is moved alongside the search. +set-window-size: (500, 500) +store-css: ("#sidebar-button a:hover", {"background-color": not_sidebar_background_hover}) +move-cursor-to: "#settings-menu" +store-css: ("#sidebar-button a:not(:hover)", {"background-color": not_sidebar_background}) +// The sidebar background is supposed to be the same as the main background. +assert-css: ("body", {"background-color": |not_sidebar_background|}) +assert: |not_sidebar_background| != |not_sidebar_background_hover| && |not_sidebar_background| != |sidebar_background| +// The hover background is supposed to be the same as the sidebar background. +assert: |not_sidebar_background_hover| == |sidebar_background| +click: "#sidebar-button a" +wait-for: "html.src-sidebar-expanded" +// And now the background colors are supposed to be the same as the sidebar since the sidebar has +// been open. +assert-css: ("#sidebar-button a:hover", {"background-color": |sidebar_background_hover|}) +move-cursor-to: "h2" +assert-css: ("#sidebar-button a:not(:hover)", {"background-color": |sidebar_background|}) + // Configuration option to show TOC in sidebar. set-local-storage: {"rustdoc-hide-toc": "true"} go-to: "file://" + |DOC_PATH| + "/test_docs/enum.WhoLetTheDogOut.html" diff --git a/tests/rustdoc-js-std/path-maxeditdistance.js b/tests/rustdoc-js-std/path-maxeditdistance.js index fd12a0564966..6989e7d6488b 100644 --- a/tests/rustdoc-js-std/path-maxeditdistance.js +++ b/tests/rustdoc-js-std/path-maxeditdistance.js @@ -13,9 +13,9 @@ const EXPECTED = [ { 'path': 'std::vec', 'name': 'IntoIter' }, { 'path': 'std::vec::Vec', 'name': 'from_iter' }, { 'path': 'std::vec::Vec', 'name': 'into_iter' }, + { 'path': 'std::vec::ExtractIf', 'name': 'into_iter' }, { 'path': 'std::vec::Drain', 'name': 'into_iter' }, { 'path': 'std::vec::IntoIter', 'name': 'into_iter' }, - { 'path': 'std::vec::ExtractIf', 'name': 'into_iter' }, { 'path': 'std::vec::Splice', 'name': 'into_iter' }, { 'path': 'std::collections::VecDeque', 'name': 'iter' }, { 'path': 'std::collections::VecDeque', 'name': 'iter_mut' }, diff --git a/tests/rustdoc-json/attrs/automatically_derived.rs b/tests/rustdoc-json/attrs/automatically_derived.rs index 4e1ab3d145e5..6c90d6386499 100644 --- a/tests/rustdoc-json/attrs/automatically_derived.rs +++ b/tests/rustdoc-json/attrs/automatically_derived.rs @@ -9,5 +9,5 @@ impl Default for Manual { } } -//@ is '$.index[?(@.inner.impl.for.resolved_path.path == "Derive" && @.inner.impl.trait.path == "Default")].attrs' '["#[automatically_derived]"]' +//@ is '$.index[?(@.inner.impl.for.resolved_path.path == "Derive" && @.inner.impl.trait.path == "Default")].attrs' '["#[automatically_derived]\n"]' //@ is '$.index[?(@.inner.impl.for.resolved_path.path == "Manual" && @.inner.impl.trait.path == "Default")].attrs' '[]' diff --git a/tests/rustdoc-json/attrs/export_name_2021.rs b/tests/rustdoc-json/attrs/export_name_2021.rs index 254e9f6ef5bf..4e6526419bdb 100644 --- a/tests/rustdoc-json/attrs/export_name_2021.rs +++ b/tests/rustdoc-json/attrs/export_name_2021.rs @@ -1,6 +1,6 @@ //@ edition: 2021 #![no_std] -//@ is "$.index[?(@.name=='example')].attrs" '["#[export_name = \"altered\"]"]' +//@ is "$.index[?(@.name=='example')].attrs" '["#[export_name = \"altered\"]\n"]' #[export_name = "altered"] pub extern "C" fn example() {} diff --git a/tests/rustdoc-json/attrs/export_name_2024.rs b/tests/rustdoc-json/attrs/export_name_2024.rs index 8129c109306c..f6a2a92b5bcd 100644 --- a/tests/rustdoc-json/attrs/export_name_2024.rs +++ b/tests/rustdoc-json/attrs/export_name_2024.rs @@ -4,6 +4,6 @@ // The representation of `#[unsafe(export_name = ..)]` in rustdoc in edition 2024 // is still `#[export_name = ..]` without the `unsafe` attribute wrapper. -//@ is "$.index[?(@.name=='example')].attrs" '["#[export_name = \"altered\"]"]' +//@ is "$.index[?(@.name=='example')].attrs" '["#[export_name = \"altered\"]\n"]' #[unsafe(export_name = "altered")] pub extern "C" fn example() {} diff --git a/tests/rustdoc-json/attrs/must_use.rs b/tests/rustdoc-json/attrs/must_use.rs index 64df8e5f509f..20696dce7121 100644 --- a/tests/rustdoc-json/attrs/must_use.rs +++ b/tests/rustdoc-json/attrs/must_use.rs @@ -1,9 +1,9 @@ #![no_std] -//@ is "$.index[?(@.name=='example')].attrs" '["#[must_use]"]' +//@ is "$.index[?(@.name=='example')].attrs" '["#[must_use]\n"]' #[must_use] pub fn example() -> impl Iterator {} -//@ is "$.index[?(@.name=='explicit_message')].attrs" '["#[must_use = \"does nothing if you do not use it\"]"]' +//@ is "$.index[?(@.name=='explicit_message')].attrs" '["#[must_use = \"does nothing if you do not use it\"]\n"]' #[must_use = "does nothing if you do not use it"] pub fn explicit_message() -> impl Iterator {} diff --git a/tests/rustdoc-json/attrs/no_mangle_2021.rs b/tests/rustdoc-json/attrs/no_mangle_2021.rs index 588be7256db5..10a372572ae5 100644 --- a/tests/rustdoc-json/attrs/no_mangle_2021.rs +++ b/tests/rustdoc-json/attrs/no_mangle_2021.rs @@ -1,6 +1,6 @@ //@ edition: 2021 #![no_std] -//@ is "$.index[?(@.name=='example')].attrs" '["#[no_mangle]"]' +//@ is "$.index[?(@.name=='example')].attrs" '["#[no_mangle]\n"]' #[no_mangle] pub extern "C" fn example() {} diff --git a/tests/rustdoc-json/attrs/no_mangle_2024.rs b/tests/rustdoc-json/attrs/no_mangle_2024.rs index 0d500e20e6c5..8f3a14cbecbf 100644 --- a/tests/rustdoc-json/attrs/no_mangle_2024.rs +++ b/tests/rustdoc-json/attrs/no_mangle_2024.rs @@ -4,6 +4,6 @@ // The representation of `#[unsafe(no_mangle)]` in rustdoc in edition 2024 // is still `#[no_mangle]` without the `unsafe` attribute wrapper. -//@ is "$.index[?(@.name=='example')].attrs" '["#[no_mangle]"]' +//@ is "$.index[?(@.name=='example')].attrs" '["#[no_mangle]\n"]' #[unsafe(no_mangle)] pub extern "C" fn example() {} diff --git a/tests/rustdoc-json/attrs/non_exhaustive.rs b/tests/rustdoc-json/attrs/non_exhaustive.rs index b95f1a8171fd..3064b86422d1 100644 --- a/tests/rustdoc-json/attrs/non_exhaustive.rs +++ b/tests/rustdoc-json/attrs/non_exhaustive.rs @@ -1,18 +1,18 @@ #![no_std] -//@ is "$.index[?(@.name=='MyEnum')].attrs" '["#[non_exhaustive]"]' +//@ is "$.index[?(@.name=='MyEnum')].attrs" '["#[non_exhaustive]\n"]' #[non_exhaustive] pub enum MyEnum { First, } pub enum NonExhaustiveVariant { - //@ is "$.index[?(@.name=='Variant')].attrs" '["#[non_exhaustive]"]' + //@ is "$.index[?(@.name=='Variant')].attrs" '["#[non_exhaustive]\n"]' #[non_exhaustive] Variant(i64), } -//@ is "$.index[?(@.name=='MyStruct')].attrs" '["#[non_exhaustive]"]' +//@ is "$.index[?(@.name=='MyStruct')].attrs" '["#[non_exhaustive]\n"]' #[non_exhaustive] pub struct MyStruct { pub x: i64, diff --git a/tests/rustdoc-json/keyword_private.rs b/tests/rustdoc-json/keyword_private.rs index fea546c9fb60..5e9a2c101636 100644 --- a/tests/rustdoc-json/keyword_private.rs +++ b/tests/rustdoc-json/keyword_private.rs @@ -5,7 +5,7 @@ //@ !has "$.index[?(@.name=='match')]" //@ has "$.index[?(@.name=='foo')]" -//@ is "$.index[?(@.name=='foo')].attrs" '["#[doc(keyword = \"match\")]"]' +//@ is "$.index[?(@.name=='foo')].attrs" '["#[doc(keyword = \"match\")]\n"]' //@ is "$.index[?(@.name=='foo')].docs" '"this is a test!"' #[doc(keyword = "match")] /// this is a test! @@ -13,7 +13,7 @@ pub mod foo {} //@ !has "$.index[?(@.name=='break')]" //@ has "$.index[?(@.name=='bar')]" -//@ is "$.index[?(@.name=='bar')].attrs" '["#[doc(keyword = \"break\")]"]' +//@ is "$.index[?(@.name=='bar')].attrs" '["#[doc(keyword = \"break\")]\n"]' //@ is "$.index[?(@.name=='bar')].docs" '"hello"' #[doc(keyword = "break")] /// hello diff --git a/tests/rustdoc-ui/doctest/auxiliary/items.rs b/tests/rustdoc-ui/doctest/auxiliary/items.rs new file mode 100644 index 000000000000..40d4eb261e5a --- /dev/null +++ b/tests/rustdoc-ui/doctest/auxiliary/items.rs @@ -0,0 +1 @@ +fn item() {} diff --git a/tests/rustdoc-ui/doctest/auxiliary/macro-after-main.rs b/tests/rustdoc-ui/doctest/auxiliary/macro-after-main.rs deleted file mode 100644 index ed7584b74253..000000000000 --- a/tests/rustdoc-ui/doctest/auxiliary/macro-after-main.rs +++ /dev/null @@ -1 +0,0 @@ -use std::string::String; diff --git a/tests/rustdoc-ui/doctest/macro-after-main.rs b/tests/rustdoc-ui/doctest/macro-after-main.rs deleted file mode 100644 index 0a42343f1c27..000000000000 --- a/tests/rustdoc-ui/doctest/macro-after-main.rs +++ /dev/null @@ -1,16 +0,0 @@ -// This test checks a corner case where the macro calls used to be skipped, -// making them considered as statement, and therefore some cases where -// `include!` macro was then put into a function body, making the doctest -// compilation fail. - -//@ compile-flags:--test -//@ normalize-stdout: "tests/rustdoc-ui/doctest" -> "$$DIR" -//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME" -//@ check-pass - -//! ``` -//! include!("./auxiliary/macro-after-main.rs"); -//! -//! fn main() {} -//! eprintln!(); -//! ``` diff --git a/tests/rustdoc-ui/doctest/macro-after-main.stdout b/tests/rustdoc-ui/doctest/macro-after-main.stdout deleted file mode 100644 index 72ffe2b5a27c..000000000000 --- a/tests/rustdoc-ui/doctest/macro-after-main.stdout +++ /dev/null @@ -1,6 +0,0 @@ - -running 1 test -test $DIR/macro-after-main.rs - (line 11) ... ok - -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME - diff --git a/tests/rustdoc-ui/doctest/main-alongside-macro-calls.fail.stdout b/tests/rustdoc-ui/doctest/main-alongside-macro-calls.fail.stdout new file mode 100644 index 000000000000..65989a8ef47c --- /dev/null +++ b/tests/rustdoc-ui/doctest/main-alongside-macro-calls.fail.stdout @@ -0,0 +1,60 @@ + +running 4 tests +test $DIR/main-alongside-macro-calls.rs - (line 19) ... ok +test $DIR/main-alongside-macro-calls.rs - (line 24) ... ok +test $DIR/main-alongside-macro-calls.rs - (line 28) ... FAILED +test $DIR/main-alongside-macro-calls.rs - (line 33) ... FAILED + +failures: + +---- $DIR/main-alongside-macro-calls.rs - (line 28) stdout ---- +error: macros that expand to items must be delimited with braces or followed by a semicolon + --> $DIR/main-alongside-macro-calls.rs:30:1 + | +LL | println!(); + | ^^^^^^^^^^ + | + = note: this error originates in the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: macro expansion ignores `{` and any tokens following + --> $SRC_DIR/std/src/macros.rs:LL:COL + | + ::: $DIR/main-alongside-macro-calls.rs:30:1 + | +LL | println!(); + | ---------- caused by the macro expansion here + | + = note: the usage of `print!` is likely invalid in item context + +error: aborting due to 2 previous errors + +Couldn't compile the test. +---- $DIR/main-alongside-macro-calls.rs - (line 33) stdout ---- +error: macros that expand to items must be delimited with braces or followed by a semicolon + --> $DIR/main-alongside-macro-calls.rs:34:1 + | +LL | println!(); + | ^^^^^^^^^^ + | + = note: this error originates in the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: macro expansion ignores `{` and any tokens following + --> $SRC_DIR/std/src/macros.rs:LL:COL + | + ::: $DIR/main-alongside-macro-calls.rs:34:1 + | +LL | println!(); + | ---------- caused by the macro expansion here + | + = note: the usage of `print!` is likely invalid in item context + +error: aborting due to 2 previous errors + +Couldn't compile the test. + +failures: + $DIR/main-alongside-macro-calls.rs - (line 28) + $DIR/main-alongside-macro-calls.rs - (line 33) + +test result: FAILED. 2 passed; 2 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/tests/rustdoc-ui/doctest/main-alongside-macro-calls.pass.stdout b/tests/rustdoc-ui/doctest/main-alongside-macro-calls.pass.stdout new file mode 100644 index 000000000000..93a4bbd87368 --- /dev/null +++ b/tests/rustdoc-ui/doctest/main-alongside-macro-calls.pass.stdout @@ -0,0 +1,9 @@ + +running 4 tests +test $DIR/main-alongside-macro-calls.rs - (line 19) ... ok +test $DIR/main-alongside-macro-calls.rs - (line 24) ... ok +test $DIR/main-alongside-macro-calls.rs - (line 28) - compile fail ... ok +test $DIR/main-alongside-macro-calls.rs - (line 33) - compile fail ... ok + +test result: ok. 4 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/tests/rustdoc-ui/doctest/main-alongside-macro-calls.rs b/tests/rustdoc-ui/doctest/main-alongside-macro-calls.rs new file mode 100644 index 000000000000..b455d8b0cc35 --- /dev/null +++ b/tests/rustdoc-ui/doctest/main-alongside-macro-calls.rs @@ -0,0 +1,44 @@ +// This test ensures that if there is are any macro calls alongside a `main` function, +// it will indeed consider the `main` function as the program entry point and *won't* +// generate its own `main` function to wrap everything even though macro calls are +// valid in statement contexts, too, and could just as well expand to statements or +// expressions (we don't perform any macro expansion to find `main`, see also +// ). +// +// See <./main-alongside-stmts.rs> for comparison. +// +//@ compile-flags:--test --test-args --test-threads=1 +//@ normalize-stdout: "tests/rustdoc-ui/doctest" -> "$$DIR" +//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME" +//@ revisions: pass fail +//@[pass] check-pass +//@[fail] failure-status: 101 + +// Regression test for : + +//! ``` +//! fn main() {} +//! include!("./auxiliary/items.rs"); +//! ``` +//! +//! ``` +//! include!("./auxiliary/items.rs"); +//! fn main() {} +//! ``` + +// Regression test for : +// We test the "same" thing twice: Once via `compile_fail` to more closely mirror the reported +// regression and once without it to make sure that it leads to the expected rustc errors, +// namely `println!(…)` not being valid in item contexts. + +#![cfg_attr(pass, doc = " ```compile_fail")] +#![cfg_attr(fail, doc = " ```")] +//! fn main() {} +//! println!(); +//! ``` +//! +#![cfg_attr(pass, doc = " ```compile_fail")] +#![cfg_attr(fail, doc = " ```")] +//! println!(); +//! fn main() {} +//! ``` diff --git a/tests/rustdoc-ui/doctest/main-alongside-stmts.rs b/tests/rustdoc-ui/doctest/main-alongside-stmts.rs new file mode 100644 index 000000000000..5965f928cdd1 --- /dev/null +++ b/tests/rustdoc-ui/doctest/main-alongside-stmts.rs @@ -0,0 +1,33 @@ +// This test ensures that if there is are any statements alongside a `main` function, +// it will not consider the `main` function as the program entry point but instead +// will generate its own `main` function to wrap everything as it needs to reside in a +// module where only *items* are permitted syntactically. +// +// See <./main-alongside-macro-calls.rs> for comparison. +// +// This is a regression test for: +// * +// * +// +//@ compile-flags:--test --test-args --test-threads=1 +//@ normalize-stdout: "tests/rustdoc-ui/doctest" -> "$$DIR" +//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME" +//@ check-pass + +//! ``` +//! # if cfg!(miri) { return; } +//! use std::ops::Deref; +//! +//! fn main() { +//! assert!(false); +//! } +//! ``` +//! +//! ``` +//! let x = 2; +//! assert_eq!(x, 2); +//! +//! fn main() { +//! assert!(false); +//! } +//! ``` diff --git a/tests/rustdoc-ui/doctest/main-alongside-stmts.stdout b/tests/rustdoc-ui/doctest/main-alongside-stmts.stdout new file mode 100644 index 000000000000..9b9a3fe8a68f --- /dev/null +++ b/tests/rustdoc-ui/doctest/main-alongside-stmts.stdout @@ -0,0 +1,7 @@ + +running 2 tests +test $DIR/main-alongside-stmts.rs - (line 17) ... ok +test $DIR/main-alongside-stmts.rs - (line 26) ... ok + +test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/tests/rustdoc-ui/doctest/test-main-alongside-exprs.rs b/tests/rustdoc-ui/doctest/test-main-alongside-exprs.rs deleted file mode 100644 index ee2299c0fd87..000000000000 --- a/tests/rustdoc-ui/doctest/test-main-alongside-exprs.rs +++ /dev/null @@ -1,22 +0,0 @@ -// This test ensures that if there is an expression alongside a `main` -// function, it will not consider the entire code to be part of the `main` -// function and will generate its own function to wrap everything. -// -// This is a regression test for: -// * -// * -//@ compile-flags:--test -//@ normalize-stdout: "tests/rustdoc-ui/doctest" -> "$$DIR" -//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME" -//@ check-pass - -#![crate_name = "foo"] - -//! ``` -//! # if cfg!(miri) { return; } -//! use std::ops::Deref; -//! -//! fn main() { -//! println!("Hi!"); -//! } -//! ``` diff --git a/tests/rustdoc-ui/doctest/test-main-alongside-exprs.stdout b/tests/rustdoc-ui/doctest/test-main-alongside-exprs.stdout deleted file mode 100644 index 90d7c3546bf1..000000000000 --- a/tests/rustdoc-ui/doctest/test-main-alongside-exprs.stdout +++ /dev/null @@ -1,6 +0,0 @@ - -running 1 test -test $DIR/test-main-alongside-exprs.rs - (line 15) ... ok - -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME - diff --git a/tests/rustdoc-ui/ice-bug-report-url.rs b/tests/rustdoc-ui/ice-bug-report-url.rs index 9260644e44f1..2e384fa1be62 100644 --- a/tests/rustdoc-ui/ice-bug-report-url.rs +++ b/tests/rustdoc-ui/ice-bug-report-url.rs @@ -1,8 +1,6 @@ //@ compile-flags: -Ztreat-err-as-bug //@ rustc-env:RUSTC_ICE=0 //@ failure-status: 101 -//@ error-pattern: aborting due to -//@ error-pattern: we would appreciate a bug report: https://github.com/rust-lang/rust/issues/new?labels=C-bug%2C+I-ICE%2C+T-rustdoc&template=ice.md //@ normalize-stderr: "note: compiler flags.*\n\n" -> "" //@ normalize-stderr: "note: rustc.*running on.*" -> "note: rustc {version} running on {platform}" @@ -13,3 +11,6 @@ fn wrong() //~^ ERROR expected one of + +//~? RAW aborting due to +//~? RAW we would appreciate a bug report: https://github.com/rust-lang/rust/issues/new?labels=C-bug%2C+I-ICE%2C+T-rustdoc&template=ice.md diff --git a/tests/rustdoc-ui/ice-bug-report-url.stderr b/tests/rustdoc-ui/ice-bug-report-url.stderr index 14a961c2ce01..b6eb8a1792df 100644 --- a/tests/rustdoc-ui/ice-bug-report-url.stderr +++ b/tests/rustdoc-ui/ice-bug-report-url.stderr @@ -1,5 +1,5 @@ error: internal compiler error: expected one of `->`, `where`, or `{`, found `` - --> $DIR/ice-bug-report-url.rs:14:10 + --> $DIR/ice-bug-report-url.rs:12:10 | LL | fn wrong() | ^ expected one of `->`, `where`, or `{` diff --git a/tests/rustdoc-ui/issues/issue-81662-shortness.rs b/tests/rustdoc-ui/issues/issue-81662-shortness.rs index 8719442c34f9..5d1951dbe3ee 100644 --- a/tests/rustdoc-ui/issues/issue-81662-shortness.rs +++ b/tests/rustdoc-ui/issues/issue-81662-shortness.rs @@ -1,6 +1,5 @@ //@ compile-flags:--test --error-format=short //@ check-stdout -//@ error-pattern:cannot find function `foo` //@ normalize-stdout: "tests/rustdoc-ui/issues" -> "$$DIR" //@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME" //@ failure-status: 101 @@ -11,3 +10,5 @@ fn foo() { println!("Hello, world!"); } + +//~? RAW cannot find function `foo` diff --git a/tests/rustdoc-ui/issues/issue-81662-shortness.stdout b/tests/rustdoc-ui/issues/issue-81662-shortness.stdout index 8fcc7ed272f0..94a82cf0afc4 100644 --- a/tests/rustdoc-ui/issues/issue-81662-shortness.stdout +++ b/tests/rustdoc-ui/issues/issue-81662-shortness.stdout @@ -1,16 +1,16 @@ running 1 test -test $DIR/issue-81662-shortness.rs - foo (line 8) ... FAILED +test $DIR/issue-81662-shortness.rs - foo (line 7) ... FAILED failures: ----- $DIR/issue-81662-shortness.rs - foo (line 8) stdout ---- -$DIR/issue-81662-shortness.rs:9:1: error[E0425]: cannot find function `foo` in this scope: not found in this scope +---- $DIR/issue-81662-shortness.rs - foo (line 7) stdout ---- +$DIR/issue-81662-shortness.rs:8:1: error[E0425]: cannot find function `foo` in this scope: not found in this scope error: aborting due to 1 previous error Couldn't compile the test. failures: - $DIR/issue-81662-shortness.rs - foo (line 8) + $DIR/issue-81662-shortness.rs - foo (line 7) test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME diff --git a/tests/rustdoc-ui/issues/issue-83883-describe-lints.rs b/tests/rustdoc-ui/issues/issue-83883-describe-lints.rs index 35d2fda45850..62a0942df1b1 100644 --- a/tests/rustdoc-ui/issues/issue-83883-describe-lints.rs +++ b/tests/rustdoc-ui/issues/issue-83883-describe-lints.rs @@ -1,10 +1,11 @@ //@ compile-flags: -W help //@ check-pass //@ check-stdout -//@ error-pattern:Lint checks provided -//@ error-pattern:rustdoc::broken-intra-doc-links // // ignore-tidy-linelength // //@ normalize-stdout: "( +name default meaning\n +---- ------- -------\n)?( *[[:word:]:-]+ (allow |warn |deny |forbid ) [^\n]+\n)+" -> " $$NAMES $$LEVELS $$MEANINGS" //@ normalize-stdout: " +name sub-lints\n +---- ---------\n( *[[:word:]:-]+ [^\n]+\n)+" -> " $$NAMES $$SUB_LINTS" + +//~? RAW Lint checks provided +//~? RAW rustdoc::broken-intra-doc-links diff --git a/tests/rustdoc-ui/unportable-markdown.rs b/tests/rustdoc-ui/unportable-markdown.rs deleted file mode 100644 index 105fc1e59d53..000000000000 --- a/tests/rustdoc-ui/unportable-markdown.rs +++ /dev/null @@ -1,62 +0,0 @@ -// https://internals.rust-lang.org/t/proposal-migrate-the-syntax-of-rustdoc-markdown-footnotes-to-be-compatible-with-the-syntax-used-in-github/18929 -// -// A series of test cases for CommonMark corner cases that pulldown-cmark 0.11 fixes. -// -// This version of the lint is targeted at two especially-common cases where docs got broken. -// Other differences in parsing should not warn. -#![allow(rustdoc::broken_intra_doc_links)] -#![deny(rustdoc::unportable_markdown)] - -/// -/// -/// Test footnote [^foot]. -/// -/// [^foot]: This is nested within the footnote now, but didn't used to be. -/// -/// This is a multi-paragraph footnote. -pub struct GfmFootnotes; - -/// -/// -/// test [^foo][^bar] -/// -/// [^foo]: test -/// [^bar]: test2 -pub struct FootnoteSmashedName; - -/// -/// -/// - _t -/// # test -/// t_ -pub struct NestingCornerCase; - -/// -/// -/// *~~__emphasis strike strong__~~* ~~*__strike emphasis strong__*~~ -pub struct Emphasis1; - -/// -/// -/// | -/// | -pub struct NotEnoughTable; - -/// -/// -/// foo -/// >bar -//~^ ERROR unportable markdown -pub struct BlockQuoteNoSpace; - -/// Negative test. -/// -/// foo -/// > bar -pub struct BlockQuoteSpace; - -/// Negative test. -/// -/// >bar -/// baz -pub struct BlockQuoteNoSpaceStart; diff --git a/tests/rustdoc-ui/unportable-markdown.stderr b/tests/rustdoc-ui/unportable-markdown.stderr deleted file mode 100644 index 952ae4bb6eec..000000000000 --- a/tests/rustdoc-ui/unportable-markdown.stderr +++ /dev/null @@ -1,23 +0,0 @@ -error: unportable markdown - --> $DIR/unportable-markdown.rs:48:5 - | -LL | /// >bar - | ^ - | - = help: confusing block quote with no space after the `>` marker -note: the lint level is defined here - --> $DIR/unportable-markdown.rs:8:9 - | -LL | #![deny(rustdoc::unportable_markdown)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: if the quote is intended, add a space - | -LL | /// > bar - | + -help: if it should not be a quote, escape it - | -LL | /// \>bar - | + - -error: aborting due to 1 previous error - diff --git a/tests/rustdoc/anchor-id-duplicate-method-name-25001.rs b/tests/rustdoc/anchors/anchor-id-duplicate-method-name-25001.rs similarity index 100% rename from tests/rustdoc/anchor-id-duplicate-method-name-25001.rs rename to tests/rustdoc/anchors/anchor-id-duplicate-method-name-25001.rs diff --git a/tests/rustdoc/anchor-id-trait-method-15169.rs b/tests/rustdoc/anchors/anchor-id-trait-method-15169.rs similarity index 100% rename from tests/rustdoc/anchor-id-trait-method-15169.rs rename to tests/rustdoc/anchors/anchor-id-trait-method-15169.rs diff --git a/tests/rustdoc/anchor-id-trait-tymethod-28478.rs b/tests/rustdoc/anchors/anchor-id-trait-tymethod-28478.rs similarity index 100% rename from tests/rustdoc/anchor-id-trait-tymethod-28478.rs rename to tests/rustdoc/anchors/anchor-id-trait-tymethod-28478.rs diff --git a/tests/rustdoc/anchors.no_const_anchor.html b/tests/rustdoc/anchors/anchors.no_const_anchor.html similarity index 100% rename from tests/rustdoc/anchors.no_const_anchor.html rename to tests/rustdoc/anchors/anchors.no_const_anchor.html diff --git a/tests/rustdoc/anchors.no_const_anchor2.html b/tests/rustdoc/anchors/anchors.no_const_anchor2.html similarity index 100% rename from tests/rustdoc/anchors.no_const_anchor2.html rename to tests/rustdoc/anchors/anchors.no_const_anchor2.html diff --git a/tests/rustdoc/anchors.no_method_anchor.html b/tests/rustdoc/anchors/anchors.no_method_anchor.html similarity index 100% rename from tests/rustdoc/anchors.no_method_anchor.html rename to tests/rustdoc/anchors/anchors.no_method_anchor.html diff --git a/tests/rustdoc/anchors.no_trait_method_anchor.html b/tests/rustdoc/anchors/anchors.no_trait_method_anchor.html similarity index 100% rename from tests/rustdoc/anchors.no_trait_method_anchor.html rename to tests/rustdoc/anchors/anchors.no_trait_method_anchor.html diff --git a/tests/rustdoc/anchors.no_tymethod_anchor.html b/tests/rustdoc/anchors/anchors.no_tymethod_anchor.html similarity index 100% rename from tests/rustdoc/anchors.no_tymethod_anchor.html rename to tests/rustdoc/anchors/anchors.no_tymethod_anchor.html diff --git a/tests/rustdoc/anchors.no_type_anchor.html b/tests/rustdoc/anchors/anchors.no_type_anchor.html similarity index 100% rename from tests/rustdoc/anchors.no_type_anchor.html rename to tests/rustdoc/anchors/anchors.no_type_anchor.html diff --git a/tests/rustdoc/anchors.no_type_anchor2.html b/tests/rustdoc/anchors/anchors.no_type_anchor2.html similarity index 100% rename from tests/rustdoc/anchors.no_type_anchor2.html rename to tests/rustdoc/anchors/anchors.no_type_anchor2.html diff --git a/tests/rustdoc/anchors.rs b/tests/rustdoc/anchors/anchors.rs similarity index 100% rename from tests/rustdoc/anchors.rs rename to tests/rustdoc/anchors/anchors.rs diff --git a/tests/rustdoc/auxiliary/issue-86620-1.rs b/tests/rustdoc/anchors/auxiliary/issue-86620-1.rs similarity index 100% rename from tests/rustdoc/auxiliary/issue-86620-1.rs rename to tests/rustdoc/anchors/auxiliary/issue-86620-1.rs diff --git a/tests/rustdoc/disambiguate-anchors-32890.rs b/tests/rustdoc/anchors/disambiguate-anchors-32890.rs similarity index 100% rename from tests/rustdoc/disambiguate-anchors-32890.rs rename to tests/rustdoc/anchors/disambiguate-anchors-32890.rs diff --git a/tests/rustdoc/disambiguate-anchors-header-29449.rs b/tests/rustdoc/anchors/disambiguate-anchors-header-29449.rs similarity index 100% rename from tests/rustdoc/disambiguate-anchors-header-29449.rs rename to tests/rustdoc/anchors/disambiguate-anchors-header-29449.rs diff --git a/tests/rustdoc/method-anchor-in-blanket-impl-86620.rs b/tests/rustdoc/anchors/method-anchor-in-blanket-impl-86620.rs similarity index 100% rename from tests/rustdoc/method-anchor-in-blanket-impl-86620.rs rename to tests/rustdoc/anchors/method-anchor-in-blanket-impl-86620.rs diff --git a/tests/rustdoc/trait-impl-items-links-and-anchors.rs b/tests/rustdoc/anchors/trait-impl-items-links-and-anchors.rs similarity index 100% rename from tests/rustdoc/trait-impl-items-links-and-anchors.rs rename to tests/rustdoc/anchors/trait-impl-items-links-and-anchors.rs diff --git a/tests/rustdoc/assoc-fns.rs b/tests/rustdoc/assoc/assoc-fns.rs similarity index 100% rename from tests/rustdoc/assoc-fns.rs rename to tests/rustdoc/assoc/assoc-fns.rs diff --git a/tests/rustdoc/assoc-item-cast.rs b/tests/rustdoc/assoc/assoc-item-cast.rs similarity index 100% rename from tests/rustdoc/assoc-item-cast.rs rename to tests/rustdoc/assoc/assoc-item-cast.rs diff --git a/tests/rustdoc/assoc-type-bindings-20646.rs b/tests/rustdoc/assoc/assoc-type-bindings-20646.rs similarity index 100% rename from tests/rustdoc/assoc-type-bindings-20646.rs rename to tests/rustdoc/assoc/assoc-type-bindings-20646.rs diff --git a/tests/rustdoc/assoc-types.rs b/tests/rustdoc/assoc/assoc-types.rs similarity index 100% rename from tests/rustdoc/assoc-types.rs rename to tests/rustdoc/assoc/assoc-types.rs diff --git a/tests/rustdoc/auxiliary/cross-crate-hidden-assoc-trait-items.rs b/tests/rustdoc/assoc/auxiliary/cross-crate-hidden-assoc-trait-items.rs similarity index 100% rename from tests/rustdoc/auxiliary/cross-crate-hidden-assoc-trait-items.rs rename to tests/rustdoc/assoc/auxiliary/cross-crate-hidden-assoc-trait-items.rs diff --git a/tests/rustdoc/auxiliary/issue-20646.rs b/tests/rustdoc/assoc/auxiliary/issue-20646.rs similarity index 100% rename from tests/rustdoc/auxiliary/issue-20646.rs rename to tests/rustdoc/assoc/auxiliary/issue-20646.rs diff --git a/tests/rustdoc/auxiliary/issue-20727.rs b/tests/rustdoc/assoc/auxiliary/issue-20727.rs similarity index 100% rename from tests/rustdoc/auxiliary/issue-20727.rs rename to tests/rustdoc/assoc/auxiliary/issue-20727.rs diff --git a/tests/rustdoc/auxiliary/normalize-assoc-item.rs b/tests/rustdoc/assoc/auxiliary/normalize-assoc-item.rs similarity index 100% rename from tests/rustdoc/auxiliary/normalize-assoc-item.rs rename to tests/rustdoc/assoc/auxiliary/normalize-assoc-item.rs diff --git a/tests/rustdoc/cross-crate-hidden-assoc-trait-items.rs b/tests/rustdoc/assoc/cross-crate-hidden-assoc-trait-items.rs similarity index 100% rename from tests/rustdoc/cross-crate-hidden-assoc-trait-items.rs rename to tests/rustdoc/assoc/cross-crate-hidden-assoc-trait-items.rs diff --git a/tests/rustdoc/doc-assoc-item.rs b/tests/rustdoc/assoc/doc-assoc-item.rs similarity index 100% rename from tests/rustdoc/doc-assoc-item.rs rename to tests/rustdoc/assoc/doc-assoc-item.rs diff --git a/tests/rustdoc/inline-assoc-type-20727-bindings.rs b/tests/rustdoc/assoc/inline-assoc-type-20727-bindings.rs similarity index 100% rename from tests/rustdoc/inline-assoc-type-20727-bindings.rs rename to tests/rustdoc/assoc/inline-assoc-type-20727-bindings.rs diff --git a/tests/rustdoc/inline-assoc-type-20727-bounds-deref.rs b/tests/rustdoc/assoc/inline-assoc-type-20727-bounds-deref.rs similarity index 100% rename from tests/rustdoc/inline-assoc-type-20727-bounds-deref.rs rename to tests/rustdoc/assoc/inline-assoc-type-20727-bounds-deref.rs diff --git a/tests/rustdoc/inline-assoc-type-20727-bounds-index.rs b/tests/rustdoc/assoc/inline-assoc-type-20727-bounds-index.rs similarity index 100% rename from tests/rustdoc/inline-assoc-type-20727-bounds-index.rs rename to tests/rustdoc/assoc/inline-assoc-type-20727-bounds-index.rs diff --git a/tests/rustdoc/inline-assoc-type-20727-bounds.rs b/tests/rustdoc/assoc/inline-assoc-type-20727-bounds.rs similarity index 100% rename from tests/rustdoc/inline-assoc-type-20727-bounds.rs rename to tests/rustdoc/assoc/inline-assoc-type-20727-bounds.rs diff --git a/tests/rustdoc/normalize-assoc-item.rs b/tests/rustdoc/assoc/normalize-assoc-item.rs similarity index 100% rename from tests/rustdoc/normalize-assoc-item.rs rename to tests/rustdoc/assoc/normalize-assoc-item.rs diff --git a/tests/rustdoc/async-fn-opaque-item.rs b/tests/rustdoc/async/async-fn-opaque-item.rs similarity index 100% rename from tests/rustdoc/async-fn-opaque-item.rs rename to tests/rustdoc/async/async-fn-opaque-item.rs diff --git a/tests/rustdoc/async-fn.rs b/tests/rustdoc/async/async-fn.rs similarity index 100% rename from tests/rustdoc/async-fn.rs rename to tests/rustdoc/async/async-fn.rs diff --git a/tests/rustdoc/async-move-doctest.rs b/tests/rustdoc/async/async-move-doctest.rs similarity index 100% rename from tests/rustdoc/async-move-doctest.rs rename to tests/rustdoc/async/async-move-doctest.rs diff --git a/tests/rustdoc/async-trait-sig.rs b/tests/rustdoc/async/async-trait-sig.rs similarity index 100% rename from tests/rustdoc/async-trait-sig.rs rename to tests/rustdoc/async/async-trait-sig.rs diff --git a/tests/rustdoc/async-trait.rs b/tests/rustdoc/async/async-trait.rs similarity index 100% rename from tests/rustdoc/async-trait.rs rename to tests/rustdoc/async/async-trait.rs diff --git a/tests/rustdoc/auxiliary/async-trait-dep.rs b/tests/rustdoc/async/auxiliary/async-trait-dep.rs similarity index 100% rename from tests/rustdoc/auxiliary/async-trait-dep.rs rename to tests/rustdoc/async/auxiliary/async-trait-dep.rs diff --git a/tests/rustdoc/auto-impl-for-trait.rs b/tests/rustdoc/auto/auto-impl-for-trait.rs similarity index 100% rename from tests/rustdoc/auto-impl-for-trait.rs rename to tests/rustdoc/auto/auto-impl-for-trait.rs diff --git a/tests/rustdoc/auto-impl-primitive.rs b/tests/rustdoc/auto/auto-impl-primitive.rs similarity index 100% rename from tests/rustdoc/auto-impl-primitive.rs rename to tests/rustdoc/auto/auto-impl-primitive.rs diff --git a/tests/rustdoc/auto-trait-bounds-by-associated-type-50159.rs b/tests/rustdoc/auto/auto-trait-bounds-by-associated-type-50159.rs similarity index 100% rename from tests/rustdoc/auto-trait-bounds-by-associated-type-50159.rs rename to tests/rustdoc/auto/auto-trait-bounds-by-associated-type-50159.rs diff --git a/tests/rustdoc/auto-trait-bounds-inference-variables-54705.rs b/tests/rustdoc/auto/auto-trait-bounds-inference-variables-54705.rs similarity index 100% rename from tests/rustdoc/auto-trait-bounds-inference-variables-54705.rs rename to tests/rustdoc/auto/auto-trait-bounds-inference-variables-54705.rs diff --git a/tests/rustdoc/auto-trait-bounds-where-51236.rs b/tests/rustdoc/auto/auto-trait-bounds-where-51236.rs similarity index 100% rename from tests/rustdoc/auto-trait-bounds-where-51236.rs rename to tests/rustdoc/auto/auto-trait-bounds-where-51236.rs diff --git a/tests/rustdoc/auto-trait-negative-impl-55321.rs b/tests/rustdoc/auto/auto-trait-negative-impl-55321.rs similarity index 100% rename from tests/rustdoc/auto-trait-negative-impl-55321.rs rename to tests/rustdoc/auto/auto-trait-negative-impl-55321.rs diff --git a/tests/rustdoc/auto-trait-not-send.rs b/tests/rustdoc/auto/auto-trait-not-send.rs similarity index 100% rename from tests/rustdoc/auto-trait-not-send.rs rename to tests/rustdoc/auto/auto-trait-not-send.rs diff --git a/tests/rustdoc/auto-traits.rs b/tests/rustdoc/auto/auto-traits.rs similarity index 100% rename from tests/rustdoc/auto-traits.rs rename to tests/rustdoc/auto/auto-traits.rs diff --git a/tests/rustdoc/auto_aliases.rs b/tests/rustdoc/auto/auto_aliases.rs similarity index 100% rename from tests/rustdoc/auto_aliases.rs rename to tests/rustdoc/auto/auto_aliases.rs diff --git a/tests/rustdoc/auxiliary/auto-traits.rs b/tests/rustdoc/auto/auxiliary/auto-traits.rs similarity index 100% rename from tests/rustdoc/auxiliary/auto-traits.rs rename to tests/rustdoc/auto/auxiliary/auto-traits.rs diff --git a/tests/rustdoc/assoc-consts-underscore.rs b/tests/rustdoc/constant/assoc-consts-underscore.rs similarity index 100% rename from tests/rustdoc/assoc-consts-underscore.rs rename to tests/rustdoc/constant/assoc-consts-underscore.rs diff --git a/tests/rustdoc/assoc-consts-version.rs b/tests/rustdoc/constant/assoc-consts-version.rs similarity index 100% rename from tests/rustdoc/assoc-consts-version.rs rename to tests/rustdoc/constant/assoc-consts-version.rs diff --git a/tests/rustdoc/assoc-consts.rs b/tests/rustdoc/constant/assoc-consts.rs similarity index 100% rename from tests/rustdoc/assoc-consts.rs rename to tests/rustdoc/constant/assoc-consts.rs diff --git a/tests/rustdoc/associated-consts.rs b/tests/rustdoc/constant/associated-consts.rs similarity index 100% rename from tests/rustdoc/associated-consts.rs rename to tests/rustdoc/constant/associated-consts.rs diff --git a/tests/rustdoc/const-display.rs b/tests/rustdoc/constant/const-display.rs similarity index 100% rename from tests/rustdoc/const-display.rs rename to tests/rustdoc/constant/const-display.rs diff --git a/tests/rustdoc/const-doc.rs b/tests/rustdoc/constant/const-doc.rs similarity index 100% rename from tests/rustdoc/const-doc.rs rename to tests/rustdoc/constant/const-doc.rs diff --git a/tests/rustdoc/const-effect-param.rs b/tests/rustdoc/constant/const-effect-param.rs similarity index 100% rename from tests/rustdoc/const-effect-param.rs rename to tests/rustdoc/constant/const-effect-param.rs diff --git a/tests/rustdoc/const-underscore.rs b/tests/rustdoc/constant/const-underscore.rs similarity index 100% rename from tests/rustdoc/const-underscore.rs rename to tests/rustdoc/constant/const-underscore.rs diff --git a/tests/rustdoc/const-value-display.rs b/tests/rustdoc/constant/const-value-display.rs similarity index 100% rename from tests/rustdoc/const-value-display.rs rename to tests/rustdoc/constant/const-value-display.rs diff --git a/tests/rustdoc/const.rs b/tests/rustdoc/constant/const.rs similarity index 100% rename from tests/rustdoc/const.rs rename to tests/rustdoc/constant/const.rs diff --git a/tests/rustdoc/document-item-with-associated-const-in-where-clause.rs b/tests/rustdoc/constant/document-item-with-associated-const-in-where-clause.rs similarity index 100% rename from tests/rustdoc/document-item-with-associated-const-in-where-clause.rs rename to tests/rustdoc/constant/document-item-with-associated-const-in-where-clause.rs diff --git a/tests/rustdoc/generic-const-items.rs b/tests/rustdoc/constant/generic-const-items.rs similarity index 100% rename from tests/rustdoc/generic-const-items.rs rename to tests/rustdoc/constant/generic-const-items.rs diff --git a/tests/rustdoc/generic_const_exprs.rs b/tests/rustdoc/constant/generic_const_exprs.rs similarity index 100% rename from tests/rustdoc/generic_const_exprs.rs rename to tests/rustdoc/constant/generic_const_exprs.rs diff --git a/tests/rustdoc/glob-shadowing-const.rs b/tests/rustdoc/constant/glob-shadowing-const.rs similarity index 100% rename from tests/rustdoc/glob-shadowing-const.rs rename to tests/rustdoc/constant/glob-shadowing-const.rs diff --git a/tests/rustdoc/hide-complex-unevaluated-const-arguments.rs b/tests/rustdoc/constant/hide-complex-unevaluated-const-arguments.rs similarity index 100% rename from tests/rustdoc/hide-complex-unevaluated-const-arguments.rs rename to tests/rustdoc/constant/hide-complex-unevaluated-const-arguments.rs diff --git a/tests/rustdoc/hide-complex-unevaluated-consts.rs b/tests/rustdoc/constant/hide-complex-unevaluated-consts.rs similarity index 100% rename from tests/rustdoc/hide-complex-unevaluated-consts.rs rename to tests/rustdoc/constant/hide-complex-unevaluated-consts.rs diff --git a/tests/rustdoc/ice-associated-const-equality-105952.rs b/tests/rustdoc/constant/ice-associated-const-equality-105952.rs similarity index 100% rename from tests/rustdoc/ice-associated-const-equality-105952.rs rename to tests/rustdoc/constant/ice-associated-const-equality-105952.rs diff --git a/tests/rustdoc/legacy-const-generic.rs b/tests/rustdoc/constant/legacy-const-generic.rs similarity index 100% rename from tests/rustdoc/legacy-const-generic.rs rename to tests/rustdoc/constant/legacy-const-generic.rs diff --git a/tests/rustdoc/link-assoc-const.rs b/tests/rustdoc/constant/link-assoc-const.rs similarity index 100% rename from tests/rustdoc/link-assoc-const.rs rename to tests/rustdoc/constant/link-assoc-const.rs diff --git a/tests/rustdoc/redirect-const.rs b/tests/rustdoc/constant/redirect-const.rs similarity index 100% rename from tests/rustdoc/redirect-const.rs rename to tests/rustdoc/constant/redirect-const.rs diff --git a/tests/rustdoc/rfc-2632-const-trait-impl.rs b/tests/rustdoc/constant/rfc-2632-const-trait-impl.rs similarity index 100% rename from tests/rustdoc/rfc-2632-const-trait-impl.rs rename to tests/rustdoc/constant/rfc-2632-const-trait-impl.rs diff --git a/tests/rustdoc/show-const-contents.rs b/tests/rustdoc/constant/show-const-contents.rs similarity index 100% rename from tests/rustdoc/show-const-contents.rs rename to tests/rustdoc/constant/show-const-contents.rs diff --git a/tests/rustdoc/doc-cfg-hide.rs b/tests/rustdoc/doc-cfg/doc-cfg-hide.rs similarity index 100% rename from tests/rustdoc/doc-cfg-hide.rs rename to tests/rustdoc/doc-cfg/doc-cfg-hide.rs diff --git a/tests/rustdoc/doc-cfg-implicit-gate.rs b/tests/rustdoc/doc-cfg/doc-cfg-implicit-gate.rs similarity index 100% rename from tests/rustdoc/doc-cfg-implicit-gate.rs rename to tests/rustdoc/doc-cfg/doc-cfg-implicit-gate.rs diff --git a/tests/rustdoc/doc-cfg-implicit.rs b/tests/rustdoc/doc-cfg/doc-cfg-implicit.rs similarity index 100% rename from tests/rustdoc/doc-cfg-implicit.rs rename to tests/rustdoc/doc-cfg/doc-cfg-implicit.rs diff --git a/tests/rustdoc/doc-cfg-inherit-from-module-79201.rs b/tests/rustdoc/doc-cfg/doc-cfg-inherit-from-module-79201.rs similarity index 100% rename from tests/rustdoc/doc-cfg-inherit-from-module-79201.rs rename to tests/rustdoc/doc-cfg/doc-cfg-inherit-from-module-79201.rs diff --git a/tests/rustdoc/doc-cfg-simplification.rs b/tests/rustdoc/doc-cfg/doc-cfg-simplification.rs similarity index 100% rename from tests/rustdoc/doc-cfg-simplification.rs rename to tests/rustdoc/doc-cfg/doc-cfg-simplification.rs diff --git a/tests/rustdoc/doc-cfg-target-feature.rs b/tests/rustdoc/doc-cfg/doc-cfg-target-feature.rs similarity index 100% rename from tests/rustdoc/doc-cfg-target-feature.rs rename to tests/rustdoc/doc-cfg/doc-cfg-target-feature.rs diff --git a/tests/rustdoc/doc-cfg-traits.rs b/tests/rustdoc/doc-cfg/doc-cfg-traits.rs similarity index 100% rename from tests/rustdoc/doc-cfg-traits.rs rename to tests/rustdoc/doc-cfg/doc-cfg-traits.rs diff --git a/tests/rustdoc/doc-cfg.rs b/tests/rustdoc/doc-cfg/doc-cfg.rs similarity index 100% rename from tests/rustdoc/doc-cfg.rs rename to tests/rustdoc/doc-cfg/doc-cfg.rs diff --git a/tests/rustdoc/auxiliary/enum-variant.rs b/tests/rustdoc/enum/auxiliary/enum-variant.rs similarity index 100% rename from tests/rustdoc/auxiliary/enum-variant.rs rename to tests/rustdoc/enum/auxiliary/enum-variant.rs diff --git a/tests/rustdoc/auxiliary/variant-struct.rs b/tests/rustdoc/enum/auxiliary/variant-struct.rs similarity index 100% rename from tests/rustdoc/auxiliary/variant-struct.rs rename to tests/rustdoc/enum/auxiliary/variant-struct.rs diff --git a/tests/rustdoc/enum-headings.rs b/tests/rustdoc/enum/enum-headings.rs similarity index 100% rename from tests/rustdoc/enum-headings.rs rename to tests/rustdoc/enum/enum-headings.rs diff --git a/tests/rustdoc/enum-non-exhaustive-108925.rs b/tests/rustdoc/enum/enum-non-exhaustive-108925.rs similarity index 100% rename from tests/rustdoc/enum-non-exhaustive-108925.rs rename to tests/rustdoc/enum/enum-non-exhaustive-108925.rs diff --git a/tests/rustdoc/enum-variant-doc-hidden-field-88600.rs b/tests/rustdoc/enum/enum-variant-doc-hidden-field-88600.rs similarity index 100% rename from tests/rustdoc/enum-variant-doc-hidden-field-88600.rs rename to tests/rustdoc/enum/enum-variant-doc-hidden-field-88600.rs diff --git a/tests/rustdoc/enum-variant-fields-heading.rs b/tests/rustdoc/enum/enum-variant-fields-heading.rs similarity index 100% rename from tests/rustdoc/enum-variant-fields-heading.rs rename to tests/rustdoc/enum/enum-variant-fields-heading.rs diff --git a/tests/rustdoc/enum-variant-fields-heading.variants.html b/tests/rustdoc/enum/enum-variant-fields-heading.variants.html similarity index 100% rename from tests/rustdoc/enum-variant-fields-heading.variants.html rename to tests/rustdoc/enum/enum-variant-fields-heading.variants.html diff --git a/tests/rustdoc/enum-variant-value.rs b/tests/rustdoc/enum/enum-variant-value.rs similarity index 100% rename from tests/rustdoc/enum-variant-value.rs rename to tests/rustdoc/enum/enum-variant-value.rs diff --git a/tests/rustdoc/render-enum-variant-structlike-32395.rs b/tests/rustdoc/enum/render-enum-variant-structlike-32395.rs similarity index 100% rename from tests/rustdoc/render-enum-variant-structlike-32395.rs rename to tests/rustdoc/enum/render-enum-variant-structlike-32395.rs diff --git a/tests/rustdoc/strip-enum-variant.no-not-shown.html b/tests/rustdoc/enum/strip-enum-variant.no-not-shown.html similarity index 100% rename from tests/rustdoc/strip-enum-variant.no-not-shown.html rename to tests/rustdoc/enum/strip-enum-variant.no-not-shown.html diff --git a/tests/rustdoc/strip-enum-variant.rs b/tests/rustdoc/enum/strip-enum-variant.rs similarity index 100% rename from tests/rustdoc/strip-enum-variant.rs rename to tests/rustdoc/enum/strip-enum-variant.rs diff --git a/tests/rustdoc/extern/auxiliary/empty.rs b/tests/rustdoc/extern/auxiliary/empty.rs new file mode 100644 index 000000000000..d11c69f812a8 --- /dev/null +++ b/tests/rustdoc/extern/auxiliary/empty.rs @@ -0,0 +1 @@ +// intentionally empty diff --git a/tests/rustdoc/auxiliary/extern-links.rs b/tests/rustdoc/extern/auxiliary/extern-links.rs similarity index 100% rename from tests/rustdoc/auxiliary/extern-links.rs rename to tests/rustdoc/extern/auxiliary/extern-links.rs diff --git a/tests/rustdoc/auxiliary/external-cross-doc.md b/tests/rustdoc/extern/auxiliary/external-cross-doc.md similarity index 100% rename from tests/rustdoc/auxiliary/external-cross-doc.md rename to tests/rustdoc/extern/auxiliary/external-cross-doc.md diff --git a/tests/rustdoc/auxiliary/external-cross.rs b/tests/rustdoc/extern/auxiliary/external-cross.rs similarity index 100% rename from tests/rustdoc/auxiliary/external-cross.rs rename to tests/rustdoc/extern/auxiliary/external-cross.rs diff --git a/tests/rustdoc/auxiliary/external-doc.md b/tests/rustdoc/extern/auxiliary/external-doc.md similarity index 100% rename from tests/rustdoc/auxiliary/external-doc.md rename to tests/rustdoc/extern/auxiliary/external-doc.md diff --git a/tests/rustdoc/auxiliary/html_root.rs b/tests/rustdoc/extern/auxiliary/html_root.rs similarity index 100% rename from tests/rustdoc/auxiliary/html_root.rs rename to tests/rustdoc/extern/auxiliary/html_root.rs diff --git a/tests/rustdoc/auxiliary/issue-30109-1.rs b/tests/rustdoc/extern/auxiliary/issue-30109-1.rs similarity index 100% rename from tests/rustdoc/auxiliary/issue-30109-1.rs rename to tests/rustdoc/extern/auxiliary/issue-30109-1.rs diff --git a/tests/rustdoc/auxiliary/no_html_root.rs b/tests/rustdoc/extern/auxiliary/no_html_root.rs similarity index 100% rename from tests/rustdoc/auxiliary/no_html_root.rs rename to tests/rustdoc/extern/auxiliary/no_html_root.rs diff --git a/tests/rustdoc/auxiliary/panic-item.rs b/tests/rustdoc/extern/auxiliary/panic-item.rs similarity index 100% rename from tests/rustdoc/auxiliary/panic-item.rs rename to tests/rustdoc/extern/auxiliary/panic-item.rs diff --git a/tests/rustdoc/auxiliary/pub-extern-crate.rs b/tests/rustdoc/extern/auxiliary/pub-extern-crate.rs similarity index 100% rename from tests/rustdoc/auxiliary/pub-extern-crate.rs rename to tests/rustdoc/extern/auxiliary/pub-extern-crate.rs diff --git a/tests/rustdoc/auxiliary/rustdoc-extern-default-method.rs b/tests/rustdoc/extern/auxiliary/rustdoc-extern-default-method.rs similarity index 100% rename from tests/rustdoc/auxiliary/rustdoc-extern-default-method.rs rename to tests/rustdoc/extern/auxiliary/rustdoc-extern-default-method.rs diff --git a/tests/rustdoc/auxiliary/rustdoc-extern-method.rs b/tests/rustdoc/extern/auxiliary/rustdoc-extern-method.rs similarity index 100% rename from tests/rustdoc/auxiliary/rustdoc-extern-method.rs rename to tests/rustdoc/extern/auxiliary/rustdoc-extern-method.rs diff --git a/tests/rustdoc/extern/auxiliary/variant-struct.rs b/tests/rustdoc/extern/auxiliary/variant-struct.rs new file mode 100644 index 000000000000..0f3d2e5f1b7a --- /dev/null +++ b/tests/rustdoc/extern/auxiliary/variant-struct.rs @@ -0,0 +1,5 @@ +pub enum Foo { + Bar { + qux: (), + } +} diff --git a/tests/rustdoc/extern-default-method.no_href_on_anchor.html b/tests/rustdoc/extern/extern-default-method.no_href_on_anchor.html similarity index 100% rename from tests/rustdoc/extern-default-method.no_href_on_anchor.html rename to tests/rustdoc/extern/extern-default-method.no_href_on_anchor.html diff --git a/tests/rustdoc/extern-default-method.rs b/tests/rustdoc/extern/extern-default-method.rs similarity index 100% rename from tests/rustdoc/extern-default-method.rs rename to tests/rustdoc/extern/extern-default-method.rs diff --git a/tests/rustdoc/extern-fn-22038.rs b/tests/rustdoc/extern/extern-fn-22038.rs similarity index 100% rename from tests/rustdoc/extern-fn-22038.rs rename to tests/rustdoc/extern/extern-fn-22038.rs diff --git a/tests/rustdoc/extern-html-root-url-precedence.rs b/tests/rustdoc/extern/extern-html-root-url-precedence.rs similarity index 100% rename from tests/rustdoc/extern-html-root-url-precedence.rs rename to tests/rustdoc/extern/extern-html-root-url-precedence.rs diff --git a/tests/rustdoc/extern-html-root-url.rs b/tests/rustdoc/extern/extern-html-root-url.rs similarity index 100% rename from tests/rustdoc/extern-html-root-url.rs rename to tests/rustdoc/extern/extern-html-root-url.rs diff --git a/tests/rustdoc/extern-links.rs b/tests/rustdoc/extern/extern-links.rs similarity index 100% rename from tests/rustdoc/extern-links.rs rename to tests/rustdoc/extern/extern-links.rs diff --git a/tests/rustdoc/extern-method.rs b/tests/rustdoc/extern/extern-method.rs similarity index 100% rename from tests/rustdoc/extern-method.rs rename to tests/rustdoc/extern/extern-method.rs diff --git a/tests/rustdoc/external-cross.rs b/tests/rustdoc/extern/external-cross.rs similarity index 100% rename from tests/rustdoc/external-cross.rs rename to tests/rustdoc/extern/external-cross.rs diff --git a/tests/rustdoc/external-doc.rs b/tests/rustdoc/extern/external-doc.rs similarity index 100% rename from tests/rustdoc/external-doc.rs rename to tests/rustdoc/extern/external-doc.rs diff --git a/tests/rustdoc/hidden-extern-34025.rs b/tests/rustdoc/extern/hidden-extern-34025.rs similarity index 100% rename from tests/rustdoc/hidden-extern-34025.rs rename to tests/rustdoc/extern/hidden-extern-34025.rs diff --git a/tests/rustdoc/link-extern-crate-33178.rs b/tests/rustdoc/extern/link-extern-crate-33178.rs similarity index 100% rename from tests/rustdoc/link-extern-crate-33178.rs rename to tests/rustdoc/extern/link-extern-crate-33178.rs diff --git a/tests/rustdoc/link-extern-crate-item-30109.rs b/tests/rustdoc/extern/link-extern-crate-item-30109.rs similarity index 100% rename from tests/rustdoc/link-extern-crate-item-30109.rs rename to tests/rustdoc/extern/link-extern-crate-item-30109.rs diff --git a/tests/rustdoc/link-extern-crate-title-33178.rs b/tests/rustdoc/extern/link-extern-crate-title-33178.rs similarity index 100% rename from tests/rustdoc/link-extern-crate-title-33178.rs rename to tests/rustdoc/extern/link-extern-crate-title-33178.rs diff --git a/tests/rustdoc/pub-extern-crate.rs b/tests/rustdoc/extern/pub-extern-crate.rs similarity index 100% rename from tests/rustdoc/pub-extern-crate.rs rename to tests/rustdoc/extern/pub-extern-crate.rs diff --git a/tests/rustdoc/unsafe-extern-blocks.rs b/tests/rustdoc/extern/unsafe-extern-blocks.rs similarity index 100% rename from tests/rustdoc/unsafe-extern-blocks.rs rename to tests/rustdoc/extern/unsafe-extern-blocks.rs diff --git a/tests/rustdoc/unused-extern-crate.rs b/tests/rustdoc/extern/unused-extern-crate.rs similarity index 100% rename from tests/rustdoc/unused-extern-crate.rs rename to tests/rustdoc/extern/unused-extern-crate.rs diff --git a/tests/rustdoc/auxiliary/cross-crate-hidden-impl-parameter.rs b/tests/rustdoc/impl/auxiliary/cross-crate-hidden-impl-parameter.rs similarity index 100% rename from tests/rustdoc/auxiliary/cross-crate-hidden-impl-parameter.rs rename to tests/rustdoc/impl/auxiliary/cross-crate-hidden-impl-parameter.rs diff --git a/tests/rustdoc/auxiliary/extern-impl-trait.rs b/tests/rustdoc/impl/auxiliary/extern-impl-trait.rs similarity index 100% rename from tests/rustdoc/auxiliary/extern-impl-trait.rs rename to tests/rustdoc/impl/auxiliary/extern-impl-trait.rs diff --git a/tests/rustdoc/auxiliary/incoherent-impl-types.rs b/tests/rustdoc/impl/auxiliary/incoherent-impl-types.rs similarity index 100% rename from tests/rustdoc/auxiliary/incoherent-impl-types.rs rename to tests/rustdoc/impl/auxiliary/incoherent-impl-types.rs diff --git a/tests/rustdoc/auxiliary/issue-100204-aux.rs b/tests/rustdoc/impl/auxiliary/issue-100204-aux.rs similarity index 100% rename from tests/rustdoc/auxiliary/issue-100204-aux.rs rename to tests/rustdoc/impl/auxiliary/issue-100204-aux.rs diff --git a/tests/rustdoc/auxiliary/issue-17476.rs b/tests/rustdoc/impl/auxiliary/issue-17476.rs similarity index 100% rename from tests/rustdoc/auxiliary/issue-17476.rs rename to tests/rustdoc/impl/auxiliary/issue-17476.rs diff --git a/tests/rustdoc/auxiliary/issue-21092.rs b/tests/rustdoc/impl/auxiliary/issue-21092.rs similarity index 100% rename from tests/rustdoc/auxiliary/issue-21092.rs rename to tests/rustdoc/impl/auxiliary/issue-21092.rs diff --git a/tests/rustdoc/auxiliary/issue-22025.rs b/tests/rustdoc/impl/auxiliary/issue-22025.rs similarity index 100% rename from tests/rustdoc/auxiliary/issue-22025.rs rename to tests/rustdoc/impl/auxiliary/issue-22025.rs diff --git a/tests/rustdoc/auxiliary/issue-53689.rs b/tests/rustdoc/impl/auxiliary/issue-53689.rs similarity index 100% rename from tests/rustdoc/auxiliary/issue-53689.rs rename to tests/rustdoc/impl/auxiliary/issue-53689.rs diff --git a/tests/rustdoc/auxiliary/precise-capturing.rs b/tests/rustdoc/impl/auxiliary/precise-capturing.rs similarity index 100% rename from tests/rustdoc/auxiliary/precise-capturing.rs rename to tests/rustdoc/impl/auxiliary/precise-capturing.rs diff --git a/tests/rustdoc/auxiliary/real_gimli.rs b/tests/rustdoc/impl/auxiliary/real_gimli.rs similarity index 100% rename from tests/rustdoc/auxiliary/real_gimli.rs rename to tests/rustdoc/impl/auxiliary/real_gimli.rs diff --git a/tests/rustdoc/auxiliary/realcore.rs b/tests/rustdoc/impl/auxiliary/realcore.rs similarity index 100% rename from tests/rustdoc/auxiliary/realcore.rs rename to tests/rustdoc/impl/auxiliary/realcore.rs diff --git a/tests/rustdoc/auxiliary/rustdoc-default-impl.rs b/tests/rustdoc/impl/auxiliary/rustdoc-default-impl.rs similarity index 100% rename from tests/rustdoc/auxiliary/rustdoc-default-impl.rs rename to tests/rustdoc/impl/auxiliary/rustdoc-default-impl.rs diff --git a/tests/rustdoc/auxiliary/rustdoc-impl-parts-crosscrate.rs b/tests/rustdoc/impl/auxiliary/rustdoc-impl-parts-crosscrate.rs similarity index 100% rename from tests/rustdoc/auxiliary/rustdoc-impl-parts-crosscrate.rs rename to tests/rustdoc/impl/auxiliary/rustdoc-impl-parts-crosscrate.rs diff --git a/tests/rustdoc/blanket-impl-29503.rs b/tests/rustdoc/impl/blanket-impl-29503.rs similarity index 100% rename from tests/rustdoc/blanket-impl-29503.rs rename to tests/rustdoc/impl/blanket-impl-29503.rs diff --git a/tests/rustdoc/blanket-impl-78673.rs b/tests/rustdoc/impl/blanket-impl-78673.rs similarity index 100% rename from tests/rustdoc/blanket-impl-78673.rs rename to tests/rustdoc/impl/blanket-impl-78673.rs diff --git a/tests/rustdoc/cross-crate-hidden-impl-parameter.rs b/tests/rustdoc/impl/cross-crate-hidden-impl-parameter.rs similarity index 100% rename from tests/rustdoc/cross-crate-hidden-impl-parameter.rs rename to tests/rustdoc/impl/cross-crate-hidden-impl-parameter.rs diff --git a/tests/rustdoc/deduplicate-glob-import-impl-21474.rs b/tests/rustdoc/impl/deduplicate-glob-import-impl-21474.rs similarity index 100% rename from tests/rustdoc/deduplicate-glob-import-impl-21474.rs rename to tests/rustdoc/impl/deduplicate-glob-import-impl-21474.rs diff --git a/tests/rustdoc/deduplicate-trait-impl-22025.rs b/tests/rustdoc/impl/deduplicate-trait-impl-22025.rs similarity index 100% rename from tests/rustdoc/deduplicate-trait-impl-22025.rs rename to tests/rustdoc/impl/deduplicate-trait-impl-22025.rs diff --git a/tests/rustdoc/default-impl.rs b/tests/rustdoc/impl/default-impl.rs similarity index 100% rename from tests/rustdoc/default-impl.rs rename to tests/rustdoc/impl/default-impl.rs diff --git a/tests/rustdoc/deprecated-impls.rs b/tests/rustdoc/impl/deprecated-impls.rs similarity index 100% rename from tests/rustdoc/deprecated-impls.rs rename to tests/rustdoc/impl/deprecated-impls.rs diff --git a/tests/rustdoc/doc-hidden-trait-implementors-33069.rs b/tests/rustdoc/impl/doc-hidden-trait-implementors-33069.rs similarity index 100% rename from tests/rustdoc/doc-hidden-trait-implementors-33069.rs rename to tests/rustdoc/impl/doc-hidden-trait-implementors-33069.rs diff --git a/tests/rustdoc/doc_auto_cfg_nested_impl.rs b/tests/rustdoc/impl/doc_auto_cfg_nested_impl.rs similarity index 100% rename from tests/rustdoc/doc_auto_cfg_nested_impl.rs rename to tests/rustdoc/impl/doc_auto_cfg_nested_impl.rs diff --git a/tests/rustdoc/duplicated_impl.rs b/tests/rustdoc/impl/duplicated_impl.rs similarity index 100% rename from tests/rustdoc/duplicated_impl.rs rename to tests/rustdoc/impl/duplicated_impl.rs diff --git a/tests/rustdoc/empty-impl-block.rs b/tests/rustdoc/impl/empty-impl-block.rs similarity index 100% rename from tests/rustdoc/empty-impl-block.rs rename to tests/rustdoc/impl/empty-impl-block.rs diff --git a/tests/rustdoc/empty-impls.rs b/tests/rustdoc/impl/empty-impls.rs similarity index 100% rename from tests/rustdoc/empty-impls.rs rename to tests/rustdoc/impl/empty-impls.rs diff --git a/tests/rustdoc/extern-impl-trait.rs b/tests/rustdoc/impl/extern-impl-trait.rs similarity index 100% rename from tests/rustdoc/extern-impl-trait.rs rename to tests/rustdoc/impl/extern-impl-trait.rs diff --git a/tests/rustdoc/extern-impl.rs b/tests/rustdoc/impl/extern-impl.rs similarity index 100% rename from tests/rustdoc/extern-impl.rs rename to tests/rustdoc/impl/extern-impl.rs diff --git a/tests/rustdoc/foreign-implementors-js-43701.rs b/tests/rustdoc/impl/foreign-implementors-js-43701.rs similarity index 100% rename from tests/rustdoc/foreign-implementors-js-43701.rs rename to tests/rustdoc/impl/foreign-implementors-js-43701.rs diff --git a/tests/rustdoc/generic-impl.rs b/tests/rustdoc/impl/generic-impl.rs similarity index 100% rename from tests/rustdoc/generic-impl.rs rename to tests/rustdoc/impl/generic-impl.rs diff --git a/tests/rustdoc/hidden-implementors-90781.rs b/tests/rustdoc/impl/hidden-implementors-90781.rs similarity index 100% rename from tests/rustdoc/hidden-implementors-90781.rs rename to tests/rustdoc/impl/hidden-implementors-90781.rs diff --git a/tests/rustdoc/hidden-impls.rs b/tests/rustdoc/impl/hidden-impls.rs similarity index 100% rename from tests/rustdoc/hidden-impls.rs rename to tests/rustdoc/impl/hidden-impls.rs diff --git a/tests/rustdoc/hidden-trait-struct-impls.rs b/tests/rustdoc/impl/hidden-trait-struct-impls.rs similarity index 100% rename from tests/rustdoc/hidden-trait-struct-impls.rs rename to tests/rustdoc/impl/hidden-trait-struct-impls.rs diff --git a/tests/rustdoc/hide-mut-methods-if-no-derefmut-impl-74083.rs b/tests/rustdoc/impl/hide-mut-methods-if-no-derefmut-impl-74083.rs similarity index 100% rename from tests/rustdoc/hide-mut-methods-if-no-derefmut-impl-74083.rs rename to tests/rustdoc/impl/hide-mut-methods-if-no-derefmut-impl-74083.rs diff --git a/tests/rustdoc/impl-alias-substituted.rs b/tests/rustdoc/impl/impl-alias-substituted.rs similarity index 100% rename from tests/rustdoc/impl-alias-substituted.rs rename to tests/rustdoc/impl/impl-alias-substituted.rs diff --git a/tests/rustdoc/impl-assoc-type-21092.rs b/tests/rustdoc/impl/impl-assoc-type-21092.rs similarity index 100% rename from tests/rustdoc/impl-assoc-type-21092.rs rename to tests/rustdoc/impl/impl-assoc-type-21092.rs diff --git a/tests/rustdoc/impl-associated-items-order.rs b/tests/rustdoc/impl/impl-associated-items-order.rs similarity index 100% rename from tests/rustdoc/impl-associated-items-order.rs rename to tests/rustdoc/impl/impl-associated-items-order.rs diff --git a/tests/rustdoc/impl-associated-items-sidebar.rs b/tests/rustdoc/impl/impl-associated-items-sidebar.rs similarity index 100% rename from tests/rustdoc/impl-associated-items-sidebar.rs rename to tests/rustdoc/impl/impl-associated-items-sidebar.rs diff --git a/tests/rustdoc/impl-blanket-53689.rs b/tests/rustdoc/impl/impl-blanket-53689.rs similarity index 100% rename from tests/rustdoc/impl-blanket-53689.rs rename to tests/rustdoc/impl/impl-blanket-53689.rs diff --git a/tests/rustdoc/impl-box.rs b/tests/rustdoc/impl/impl-box.rs similarity index 100% rename from tests/rustdoc/impl-box.rs rename to tests/rustdoc/impl/impl-box.rs diff --git a/tests/rustdoc/impl-disambiguation.rs b/tests/rustdoc/impl/impl-disambiguation.rs similarity index 100% rename from tests/rustdoc/impl-disambiguation.rs rename to tests/rustdoc/impl/impl-disambiguation.rs diff --git a/tests/rustdoc/impl-everywhere.rs b/tests/rustdoc/impl/impl-everywhere.rs similarity index 100% rename from tests/rustdoc/impl-everywhere.rs rename to tests/rustdoc/impl/impl-everywhere.rs diff --git a/tests/rustdoc/impl-in-const-block.rs b/tests/rustdoc/impl/impl-in-const-block.rs similarity index 100% rename from tests/rustdoc/impl-in-const-block.rs rename to tests/rustdoc/impl/impl-in-const-block.rs diff --git a/tests/rustdoc/impl-on-ty-alias-issue-119015.rs b/tests/rustdoc/impl/impl-on-ty-alias-issue-119015.rs similarity index 100% rename from tests/rustdoc/impl-on-ty-alias-issue-119015.rs rename to tests/rustdoc/impl/impl-on-ty-alias-issue-119015.rs diff --git a/tests/rustdoc/impl-parts-crosscrate.rs b/tests/rustdoc/impl/impl-parts-crosscrate.rs similarity index 100% rename from tests/rustdoc/impl-parts-crosscrate.rs rename to tests/rustdoc/impl/impl-parts-crosscrate.rs diff --git a/tests/rustdoc/impl-parts.rs b/tests/rustdoc/impl/impl-parts.rs similarity index 100% rename from tests/rustdoc/impl-parts.rs rename to tests/rustdoc/impl/impl-parts.rs diff --git a/tests/rustdoc/impl-ref-20175.rs b/tests/rustdoc/impl/impl-ref-20175.rs similarity index 100% rename from tests/rustdoc/impl-ref-20175.rs rename to tests/rustdoc/impl/impl-ref-20175.rs diff --git a/tests/rustdoc/impl-trait-43869.rs b/tests/rustdoc/impl/impl-trait-43869.rs similarity index 100% rename from tests/rustdoc/impl-trait-43869.rs rename to tests/rustdoc/impl/impl-trait-43869.rs diff --git a/tests/rustdoc/impl-trait-alias.rs b/tests/rustdoc/impl/impl-trait-alias.rs similarity index 100% rename from tests/rustdoc/impl-trait-alias.rs rename to tests/rustdoc/impl/impl-trait-alias.rs diff --git a/tests/rustdoc/impl-trait-precise-capturing.rs b/tests/rustdoc/impl/impl-trait-precise-capturing.rs similarity index 100% rename from tests/rustdoc/impl-trait-precise-capturing.rs rename to tests/rustdoc/impl/impl-trait-precise-capturing.rs diff --git a/tests/rustdoc/impl-type-parameter-33592.rs b/tests/rustdoc/impl/impl-type-parameter-33592.rs similarity index 100% rename from tests/rustdoc/impl-type-parameter-33592.rs rename to tests/rustdoc/impl/impl-type-parameter-33592.rs diff --git a/tests/rustdoc/implementor-stable-version.rs b/tests/rustdoc/impl/implementor-stable-version.rs similarity index 100% rename from tests/rustdoc/implementor-stable-version.rs rename to tests/rustdoc/impl/implementor-stable-version.rs diff --git a/tests/rustdoc/implementors-unstable-75588.rs b/tests/rustdoc/impl/implementors-unstable-75588.rs similarity index 100% rename from tests/rustdoc/implementors-unstable-75588.rs rename to tests/rustdoc/impl/implementors-unstable-75588.rs diff --git a/tests/rustdoc/inline-impl-through-glob-import-100204.rs b/tests/rustdoc/impl/inline-impl-through-glob-import-100204.rs similarity index 100% rename from tests/rustdoc/inline-impl-through-glob-import-100204.rs rename to tests/rustdoc/impl/inline-impl-through-glob-import-100204.rs diff --git a/tests/rustdoc/manual_impl.rs b/tests/rustdoc/impl/manual_impl.rs similarity index 100% rename from tests/rustdoc/manual_impl.rs rename to tests/rustdoc/impl/manual_impl.rs diff --git a/tests/rustdoc/method-link-foreign-trait-impl-17476.rs b/tests/rustdoc/impl/method-link-foreign-trait-impl-17476.rs similarity index 100% rename from tests/rustdoc/method-link-foreign-trait-impl-17476.rs rename to tests/rustdoc/impl/method-link-foreign-trait-impl-17476.rs diff --git a/tests/rustdoc/module-impls.rs b/tests/rustdoc/impl/module-impls.rs similarity index 100% rename from tests/rustdoc/module-impls.rs rename to tests/rustdoc/impl/module-impls.rs diff --git a/tests/rustdoc/must_implement_one_of.rs b/tests/rustdoc/impl/must_implement_one_of.rs similarity index 100% rename from tests/rustdoc/must_implement_one_of.rs rename to tests/rustdoc/impl/must_implement_one_of.rs diff --git a/tests/rustdoc/negative-impl-no-items.rs b/tests/rustdoc/impl/negative-impl-no-items.rs similarity index 100% rename from tests/rustdoc/negative-impl-no-items.rs rename to tests/rustdoc/impl/negative-impl-no-items.rs diff --git a/tests/rustdoc/negative-impl-sidebar.rs b/tests/rustdoc/impl/negative-impl-sidebar.rs similarity index 100% rename from tests/rustdoc/negative-impl-sidebar.rs rename to tests/rustdoc/impl/negative-impl-sidebar.rs diff --git a/tests/rustdoc/negative-impl.rs b/tests/rustdoc/impl/negative-impl.rs similarity index 100% rename from tests/rustdoc/negative-impl.rs rename to tests/rustdoc/impl/negative-impl.rs diff --git a/tests/rustdoc/return-impl-trait.rs b/tests/rustdoc/impl/return-impl-trait.rs similarity index 100% rename from tests/rustdoc/return-impl-trait.rs rename to tests/rustdoc/impl/return-impl-trait.rs diff --git a/tests/rustdoc/rustc-incoherent-impls.rs b/tests/rustdoc/impl/rustc-incoherent-impls.rs similarity index 100% rename from tests/rustdoc/rustc-incoherent-impls.rs rename to tests/rustdoc/impl/rustc-incoherent-impls.rs diff --git a/tests/rustdoc/same-crate-hidden-impl-parameter.rs b/tests/rustdoc/impl/same-crate-hidden-impl-parameter.rs similarity index 100% rename from tests/rustdoc/same-crate-hidden-impl-parameter.rs rename to tests/rustdoc/impl/same-crate-hidden-impl-parameter.rs diff --git a/tests/rustdoc/sidebar-trait-impl-disambiguate-78701.rs b/tests/rustdoc/impl/sidebar-trait-impl-disambiguate-78701.rs similarity index 100% rename from tests/rustdoc/sidebar-trait-impl-disambiguate-78701.rs rename to tests/rustdoc/impl/sidebar-trait-impl-disambiguate-78701.rs diff --git a/tests/rustdoc/struct-implementations-title.rs b/tests/rustdoc/impl/struct-implementations-title.rs similarity index 100% rename from tests/rustdoc/struct-implementations-title.rs rename to tests/rustdoc/impl/struct-implementations-title.rs diff --git a/tests/rustdoc/trait-impl.rs b/tests/rustdoc/impl/trait-impl.rs similarity index 100% rename from tests/rustdoc/trait-impl.rs rename to tests/rustdoc/impl/trait-impl.rs diff --git a/tests/rustdoc/trait-implementations-duplicate-self-45584.rs b/tests/rustdoc/impl/trait-implementations-duplicate-self-45584.rs similarity index 100% rename from tests/rustdoc/trait-implementations-duplicate-self-45584.rs rename to tests/rustdoc/impl/trait-implementations-duplicate-self-45584.rs diff --git a/tests/rustdoc/underscore-type-in-trait-impl-96381.rs b/tests/rustdoc/impl/underscore-type-in-trait-impl-96381.rs similarity index 100% rename from tests/rustdoc/underscore-type-in-trait-impl-96381.rs rename to tests/rustdoc/impl/underscore-type-in-trait-impl-96381.rs diff --git a/tests/rustdoc/universal-impl-trait.rs b/tests/rustdoc/impl/universal-impl-trait.rs similarity index 100% rename from tests/rustdoc/universal-impl-trait.rs rename to tests/rustdoc/impl/universal-impl-trait.rs diff --git a/tests/rustdoc/unneeded-trait-implementations-title.rs b/tests/rustdoc/impl/unneeded-trait-implementations-title.rs similarity index 100% rename from tests/rustdoc/unneeded-trait-implementations-title.rs rename to tests/rustdoc/impl/unneeded-trait-implementations-title.rs diff --git a/tests/rustdoc/ice-intra-doc-links-107995.rs b/tests/rustdoc/intra-doc/ice-intra-doc-links-107995.rs similarity index 100% rename from tests/rustdoc/ice-intra-doc-links-107995.rs rename to tests/rustdoc/intra-doc/ice-intra-doc-links-107995.rs diff --git a/tests/rustdoc/intra-doc-link-method-trait-impl-72340.rs b/tests/rustdoc/intra-doc/intra-doc-link-method-trait-impl-72340.rs similarity index 100% rename from tests/rustdoc/intra-doc-link-method-trait-impl-72340.rs rename to tests/rustdoc/intra-doc/intra-doc-link-method-trait-impl-72340.rs diff --git a/tests/rustdoc/auxiliary/jump-to-def-macro.rs b/tests/rustdoc/jump-to-def/auxiliary/jump-to-def-macro.rs similarity index 100% rename from tests/rustdoc/auxiliary/jump-to-def-macro.rs rename to tests/rustdoc/jump-to-def/auxiliary/jump-to-def-macro.rs diff --git a/tests/rustdoc/jump-to-def-doc-links-calls.rs b/tests/rustdoc/jump-to-def/jump-to-def-doc-links-calls.rs similarity index 100% rename from tests/rustdoc/jump-to-def-doc-links-calls.rs rename to tests/rustdoc/jump-to-def/jump-to-def-doc-links-calls.rs diff --git a/tests/rustdoc/jump-to-def-doc-links.rs b/tests/rustdoc/jump-to-def/jump-to-def-doc-links.rs similarity index 100% rename from tests/rustdoc/jump-to-def-doc-links.rs rename to tests/rustdoc/jump-to-def/jump-to-def-doc-links.rs diff --git a/tests/rustdoc/jump-to-def-macro.rs b/tests/rustdoc/jump-to-def/jump-to-def-macro.rs similarity index 100% rename from tests/rustdoc/jump-to-def-macro.rs rename to tests/rustdoc/jump-to-def/jump-to-def-macro.rs diff --git a/tests/rustdoc/jump-to-def-pats.rs b/tests/rustdoc/jump-to-def/jump-to-def-pats.rs similarity index 100% rename from tests/rustdoc/jump-to-def-pats.rs rename to tests/rustdoc/jump-to-def/jump-to-def-pats.rs diff --git a/tests/rustdoc/jump-to-def-prelude-types.rs b/tests/rustdoc/jump-to-def/jump-to-def-prelude-types.rs similarity index 100% rename from tests/rustdoc/jump-to-def-prelude-types.rs rename to tests/rustdoc/jump-to-def/jump-to-def-prelude-types.rs diff --git a/tests/rustdoc/jump-to-non-local-method.rs b/tests/rustdoc/jump-to-def/jump-to-non-local-method.rs similarity index 100% rename from tests/rustdoc/jump-to-non-local-method.rs rename to tests/rustdoc/jump-to-def/jump-to-non-local-method.rs diff --git a/tests/rustdoc/auxiliary/external-macro-src.rs b/tests/rustdoc/macro/auxiliary/external-macro-src.rs similarity index 100% rename from tests/rustdoc/auxiliary/external-macro-src.rs rename to tests/rustdoc/macro/auxiliary/external-macro-src.rs diff --git a/tests/rustdoc/macro/auxiliary/issue-99221-aux.rs b/tests/rustdoc/macro/auxiliary/issue-99221-aux.rs new file mode 100644 index 000000000000..e061e42b29db --- /dev/null +++ b/tests/rustdoc/macro/auxiliary/issue-99221-aux.rs @@ -0,0 +1,20 @@ +pub struct Option; +impl Option { + pub fn unwrap(self) {} +} + +mod macros { + use crate::Option; + /// [`Option::unwrap`] + #[macro_export] + macro_rules! print { + () => () + } +} + +mod structs { + use crate::Option; + /// [`Option::unwrap`] + pub struct Print; +} +pub use structs::Print; diff --git a/tests/rustdoc/auxiliary/macro_pub_in_module.rs b/tests/rustdoc/macro/auxiliary/macro_pub_in_module.rs similarity index 100% rename from tests/rustdoc/auxiliary/macro_pub_in_module.rs rename to tests/rustdoc/macro/auxiliary/macro_pub_in_module.rs diff --git a/tests/rustdoc/auxiliary/pub-use-extern-macros.rs b/tests/rustdoc/macro/auxiliary/pub-use-extern-macros.rs similarity index 100% rename from tests/rustdoc/auxiliary/pub-use-extern-macros.rs rename to tests/rustdoc/macro/auxiliary/pub-use-extern-macros.rs diff --git a/tests/rustdoc/compiler-derive-proc-macro.rs b/tests/rustdoc/macro/compiler-derive-proc-macro.rs similarity index 100% rename from tests/rustdoc/compiler-derive-proc-macro.rs rename to tests/rustdoc/macro/compiler-derive-proc-macro.rs diff --git a/tests/rustdoc/const-rendering-macros-33302.rs b/tests/rustdoc/macro/const-rendering-macros-33302.rs similarity index 100% rename from tests/rustdoc/const-rendering-macros-33302.rs rename to tests/rustdoc/macro/const-rendering-macros-33302.rs diff --git a/tests/rustdoc/decl_macro.rs b/tests/rustdoc/macro/decl_macro.rs similarity index 100% rename from tests/rustdoc/decl_macro.rs rename to tests/rustdoc/macro/decl_macro.rs diff --git a/tests/rustdoc/decl_macro_priv.rs b/tests/rustdoc/macro/decl_macro_priv.rs similarity index 100% rename from tests/rustdoc/decl_macro_priv.rs rename to tests/rustdoc/macro/decl_macro_priv.rs diff --git a/tests/rustdoc/doc-proc-macro.rs b/tests/rustdoc/macro/doc-proc-macro.rs similarity index 100% rename from tests/rustdoc/doc-proc-macro.rs rename to tests/rustdoc/macro/doc-proc-macro.rs diff --git a/tests/rustdoc/external-macro-src.rs b/tests/rustdoc/macro/external-macro-src.rs similarity index 100% rename from tests/rustdoc/external-macro-src.rs rename to tests/rustdoc/macro/external-macro-src.rs diff --git a/tests/rustdoc/macro-const-display-115295.rs b/tests/rustdoc/macro/macro-const-display-115295.rs similarity index 100% rename from tests/rustdoc/macro-const-display-115295.rs rename to tests/rustdoc/macro/macro-const-display-115295.rs diff --git a/tests/rustdoc/macro-doc-comment-23812.rs b/tests/rustdoc/macro/macro-doc-comment-23812.rs similarity index 100% rename from tests/rustdoc/macro-doc-comment-23812.rs rename to tests/rustdoc/macro/macro-doc-comment-23812.rs diff --git a/tests/rustdoc/macro-export-crate-root-108231.rs b/tests/rustdoc/macro/macro-export-crate-root-108231.rs similarity index 100% rename from tests/rustdoc/macro-export-crate-root-108231.rs rename to tests/rustdoc/macro/macro-export-crate-root-108231.rs diff --git a/tests/rustdoc/macro-generated-macro.macro_linebreak_pre.html b/tests/rustdoc/macro/macro-generated-macro.macro_linebreak_pre.html similarity index 100% rename from tests/rustdoc/macro-generated-macro.macro_linebreak_pre.html rename to tests/rustdoc/macro/macro-generated-macro.macro_linebreak_pre.html diff --git a/tests/rustdoc/macro-generated-macro.macro_morestuff_pre.html b/tests/rustdoc/macro/macro-generated-macro.macro_morestuff_pre.html similarity index 100% rename from tests/rustdoc/macro-generated-macro.macro_morestuff_pre.html rename to tests/rustdoc/macro/macro-generated-macro.macro_morestuff_pre.html diff --git a/tests/rustdoc/macro-generated-macro.rs b/tests/rustdoc/macro/macro-generated-macro.rs similarity index 100% rename from tests/rustdoc/macro-generated-macro.rs rename to tests/rustdoc/macro/macro-generated-macro.rs diff --git a/tests/rustdoc/macro-higher-kinded-function.rs b/tests/rustdoc/macro/macro-higher-kinded-function.rs similarity index 100% rename from tests/rustdoc/macro-higher-kinded-function.rs rename to tests/rustdoc/macro/macro-higher-kinded-function.rs diff --git a/tests/rustdoc/macro-ice-16019.rs b/tests/rustdoc/macro/macro-ice-16019.rs similarity index 100% rename from tests/rustdoc/macro-ice-16019.rs rename to tests/rustdoc/macro/macro-ice-16019.rs diff --git a/tests/rustdoc/macro-in-async-block.rs b/tests/rustdoc/macro/macro-in-async-block.rs similarity index 100% rename from tests/rustdoc/macro-in-async-block.rs rename to tests/rustdoc/macro/macro-in-async-block.rs diff --git a/tests/rustdoc/macro-in-closure.rs b/tests/rustdoc/macro/macro-in-closure.rs similarity index 100% rename from tests/rustdoc/macro-in-closure.rs rename to tests/rustdoc/macro/macro-in-closure.rs diff --git a/tests/rustdoc/macro-indirect-use.rs b/tests/rustdoc/macro/macro-indirect-use.rs similarity index 100% rename from tests/rustdoc/macro-indirect-use.rs rename to tests/rustdoc/macro/macro-indirect-use.rs diff --git a/tests/rustdoc/macro_pub_in_module.rs b/tests/rustdoc/macro/macro_pub_in_module.rs similarity index 100% rename from tests/rustdoc/macro_pub_in_module.rs rename to tests/rustdoc/macro/macro_pub_in_module.rs diff --git a/tests/rustdoc/macro_rules-matchers.rs b/tests/rustdoc/macro/macro_rules-matchers.rs similarity index 100% rename from tests/rustdoc/macro_rules-matchers.rs rename to tests/rustdoc/macro/macro_rules-matchers.rs diff --git a/tests/rustdoc/macros.rs b/tests/rustdoc/macro/macros.rs similarity index 100% rename from tests/rustdoc/macros.rs rename to tests/rustdoc/macro/macros.rs diff --git a/tests/rustdoc/multiple-macro-rules-w-same-name-99221.rs b/tests/rustdoc/macro/multiple-macro-rules-w-same-name-99221.rs similarity index 100% rename from tests/rustdoc/multiple-macro-rules-w-same-name-99221.rs rename to tests/rustdoc/macro/multiple-macro-rules-w-same-name-99221.rs diff --git a/tests/rustdoc/multiple-macro-rules-w-same-name-submodule-99221.rs b/tests/rustdoc/macro/multiple-macro-rules-w-same-name-submodule-99221.rs similarity index 100% rename from tests/rustdoc/multiple-macro-rules-w-same-name-submodule-99221.rs rename to tests/rustdoc/macro/multiple-macro-rules-w-same-name-submodule-99221.rs diff --git a/tests/rustdoc/proc-macro.rs b/tests/rustdoc/macro/proc-macro.rs similarity index 100% rename from tests/rustdoc/proc-macro.rs rename to tests/rustdoc/macro/proc-macro.rs diff --git a/tests/rustdoc/pub-use-extern-macros.rs b/tests/rustdoc/macro/pub-use-extern-macros.rs similarity index 100% rename from tests/rustdoc/pub-use-extern-macros.rs rename to tests/rustdoc/macro/pub-use-extern-macros.rs diff --git a/tests/rustdoc/rustc-macro-crate.rs b/tests/rustdoc/macro/rustc-macro-crate.rs similarity index 100% rename from tests/rustdoc/rustc-macro-crate.rs rename to tests/rustdoc/macro/rustc-macro-crate.rs diff --git a/tests/rustdoc/auxiliary/issue-15318.rs b/tests/rustdoc/primitive/auxiliary/issue-15318.rs similarity index 100% rename from tests/rustdoc/auxiliary/issue-15318.rs rename to tests/rustdoc/primitive/auxiliary/issue-15318.rs diff --git a/tests/rustdoc/auxiliary/primitive-doc.rs b/tests/rustdoc/primitive/auxiliary/primitive-doc.rs similarity index 100% rename from tests/rustdoc/auxiliary/primitive-doc.rs rename to tests/rustdoc/primitive/auxiliary/primitive-doc.rs diff --git a/tests/rustdoc/cross-crate-primitive-doc.rs b/tests/rustdoc/primitive/cross-crate-primitive-doc.rs similarity index 100% rename from tests/rustdoc/cross-crate-primitive-doc.rs rename to tests/rustdoc/primitive/cross-crate-primitive-doc.rs diff --git a/tests/rustdoc/no_std-primitive.rs b/tests/rustdoc/primitive/no_std-primitive.rs similarity index 100% rename from tests/rustdoc/no_std-primitive.rs rename to tests/rustdoc/primitive/no_std-primitive.rs diff --git a/tests/rustdoc/primitive-link.rs b/tests/rustdoc/primitive/primitive-link.rs similarity index 100% rename from tests/rustdoc/primitive-link.rs rename to tests/rustdoc/primitive/primitive-link.rs diff --git a/tests/rustdoc/primitive-raw-pointer-dox-15318-3.rs b/tests/rustdoc/primitive/primitive-raw-pointer-dox-15318-3.rs similarity index 100% rename from tests/rustdoc/primitive-raw-pointer-dox-15318-3.rs rename to tests/rustdoc/primitive/primitive-raw-pointer-dox-15318-3.rs diff --git a/tests/rustdoc/primitive-raw-pointer-link-15318.rs b/tests/rustdoc/primitive/primitive-raw-pointer-link-15318.rs similarity index 100% rename from tests/rustdoc/primitive-raw-pointer-link-15318.rs rename to tests/rustdoc/primitive/primitive-raw-pointer-link-15318.rs diff --git a/tests/rustdoc/primitive-raw-pointer-link-no-inlined-15318-2.rs b/tests/rustdoc/primitive/primitive-raw-pointer-link-no-inlined-15318-2.rs similarity index 100% rename from tests/rustdoc/primitive-raw-pointer-link-no-inlined-15318-2.rs rename to tests/rustdoc/primitive/primitive-raw-pointer-link-no-inlined-15318-2.rs diff --git a/tests/rustdoc/primitive-reference.rs b/tests/rustdoc/primitive/primitive-reference.rs similarity index 100% rename from tests/rustdoc/primitive-reference.rs rename to tests/rustdoc/primitive/primitive-reference.rs diff --git a/tests/rustdoc/primitive-slice-auto-trait.rs b/tests/rustdoc/primitive/primitive-slice-auto-trait.rs similarity index 100% rename from tests/rustdoc/primitive-slice-auto-trait.rs rename to tests/rustdoc/primitive/primitive-slice-auto-trait.rs diff --git a/tests/rustdoc/primitive-tuple-auto-trait.rs b/tests/rustdoc/primitive/primitive-tuple-auto-trait.rs similarity index 100% rename from tests/rustdoc/primitive-tuple-auto-trait.rs rename to tests/rustdoc/primitive/primitive-tuple-auto-trait.rs diff --git a/tests/rustdoc/primitive-tuple-variadic.rs b/tests/rustdoc/primitive/primitive-tuple-variadic.rs similarity index 100% rename from tests/rustdoc/primitive-tuple-variadic.rs rename to tests/rustdoc/primitive/primitive-tuple-variadic.rs diff --git a/tests/rustdoc/primitive-unit-auto-trait.rs b/tests/rustdoc/primitive/primitive-unit-auto-trait.rs similarity index 100% rename from tests/rustdoc/primitive-unit-auto-trait.rs rename to tests/rustdoc/primitive/primitive-unit-auto-trait.rs diff --git a/tests/rustdoc/search-index-primitive-inherent-method-23511.rs b/tests/rustdoc/primitive/search-index-primitive-inherent-method-23511.rs similarity index 100% rename from tests/rustdoc/search-index-primitive-inherent-method-23511.rs rename to tests/rustdoc/primitive/search-index-primitive-inherent-method-23511.rs diff --git a/tests/rustdoc/doc-hidden-private-67851-both.rs b/tests/rustdoc/private/doc-hidden-private-67851-both.rs similarity index 100% rename from tests/rustdoc/doc-hidden-private-67851-both.rs rename to tests/rustdoc/private/doc-hidden-private-67851-both.rs diff --git a/tests/rustdoc/doc-hidden-private-67851-hidden.rs b/tests/rustdoc/private/doc-hidden-private-67851-hidden.rs similarity index 100% rename from tests/rustdoc/doc-hidden-private-67851-hidden.rs rename to tests/rustdoc/private/doc-hidden-private-67851-hidden.rs diff --git a/tests/rustdoc/doc-hidden-private-67851-neither.rs b/tests/rustdoc/private/doc-hidden-private-67851-neither.rs similarity index 100% rename from tests/rustdoc/doc-hidden-private-67851-neither.rs rename to tests/rustdoc/private/doc-hidden-private-67851-neither.rs diff --git a/tests/rustdoc/doc-hidden-private-67851-private.rs b/tests/rustdoc/private/doc-hidden-private-67851-private.rs similarity index 100% rename from tests/rustdoc/doc-hidden-private-67851-private.rs rename to tests/rustdoc/private/doc-hidden-private-67851-private.rs diff --git a/tests/rustdoc/empty-impl-block-private-with-doc.rs b/tests/rustdoc/private/empty-impl-block-private-with-doc.rs similarity index 100% rename from tests/rustdoc/empty-impl-block-private-with-doc.rs rename to tests/rustdoc/private/empty-impl-block-private-with-doc.rs diff --git a/tests/rustdoc/empty-impl-block-private.rs b/tests/rustdoc/private/empty-impl-block-private.rs similarity index 100% rename from tests/rustdoc/empty-impl-block-private.rs rename to tests/rustdoc/private/empty-impl-block-private.rs diff --git a/tests/rustdoc/empty-mod-private.rs b/tests/rustdoc/private/empty-mod-private.rs similarity index 100% rename from tests/rustdoc/empty-mod-private.rs rename to tests/rustdoc/private/empty-mod-private.rs diff --git a/tests/rustdoc/enum-variant-private-46767.rs b/tests/rustdoc/private/enum-variant-private-46767.rs similarity index 100% rename from tests/rustdoc/enum-variant-private-46767.rs rename to tests/rustdoc/private/enum-variant-private-46767.rs diff --git a/tests/rustdoc/files-creation-private.rs b/tests/rustdoc/private/files-creation-private.rs similarity index 100% rename from tests/rustdoc/files-creation-private.rs rename to tests/rustdoc/private/files-creation-private.rs diff --git a/tests/rustdoc/hidden-private.rs b/tests/rustdoc/private/hidden-private.rs similarity index 100% rename from tests/rustdoc/hidden-private.rs rename to tests/rustdoc/private/hidden-private.rs diff --git a/tests/rustdoc/inline-private-with-intermediate-doc-hidden.rs b/tests/rustdoc/private/inline-private-with-intermediate-doc-hidden.rs similarity index 100% rename from tests/rustdoc/inline-private-with-intermediate-doc-hidden.rs rename to tests/rustdoc/private/inline-private-with-intermediate-doc-hidden.rs diff --git a/tests/rustdoc/inner-private-110422.rs b/tests/rustdoc/private/inner-private-110422.rs similarity index 100% rename from tests/rustdoc/inner-private-110422.rs rename to tests/rustdoc/private/inner-private-110422.rs diff --git a/tests/rustdoc/macro-document-private-duplicate.rs b/tests/rustdoc/private/macro-document-private-duplicate.rs similarity index 100% rename from tests/rustdoc/macro-document-private-duplicate.rs rename to tests/rustdoc/private/macro-document-private-duplicate.rs diff --git a/tests/rustdoc/macro-document-private.rs b/tests/rustdoc/private/macro-document-private.rs similarity index 100% rename from tests/rustdoc/macro-document-private.rs rename to tests/rustdoc/private/macro-document-private.rs diff --git a/tests/rustdoc/macro-private-not-documented.rs b/tests/rustdoc/private/macro-private-not-documented.rs similarity index 100% rename from tests/rustdoc/macro-private-not-documented.rs rename to tests/rustdoc/private/macro-private-not-documented.rs diff --git a/tests/rustdoc/missing-private-inlining-109258.rs b/tests/rustdoc/private/missing-private-inlining-109258.rs similarity index 100% rename from tests/rustdoc/missing-private-inlining-109258.rs rename to tests/rustdoc/private/missing-private-inlining-109258.rs diff --git a/tests/rustdoc/private-fields-tuple-struct.rs b/tests/rustdoc/private/private-fields-tuple-struct.rs similarity index 100% rename from tests/rustdoc/private-fields-tuple-struct.rs rename to tests/rustdoc/private/private-fields-tuple-struct.rs diff --git a/tests/rustdoc/private-non-local-fields-2.rs b/tests/rustdoc/private/private-non-local-fields-2.rs similarity index 100% rename from tests/rustdoc/private-non-local-fields-2.rs rename to tests/rustdoc/private/private-non-local-fields-2.rs diff --git a/tests/rustdoc/private-non-local-fields.rs b/tests/rustdoc/private/private-non-local-fields.rs similarity index 100% rename from tests/rustdoc/private-non-local-fields.rs rename to tests/rustdoc/private/private-non-local-fields.rs diff --git a/tests/rustdoc/private-type-alias.rs b/tests/rustdoc/private/private-type-alias.rs similarity index 100% rename from tests/rustdoc/private-type-alias.rs rename to tests/rustdoc/private/private-type-alias.rs diff --git a/tests/rustdoc/private-type-cycle-110629.rs b/tests/rustdoc/private/private-type-cycle-110629.rs similarity index 100% rename from tests/rustdoc/private-type-cycle-110629.rs rename to tests/rustdoc/private/private-type-cycle-110629.rs diff --git a/tests/rustdoc/private-use-decl-macro-47038.rs b/tests/rustdoc/private/private-use-decl-macro-47038.rs similarity index 100% rename from tests/rustdoc/private-use-decl-macro-47038.rs rename to tests/rustdoc/private/private-use-decl-macro-47038.rs diff --git a/tests/rustdoc/private-use.rs b/tests/rustdoc/private/private-use.rs similarity index 100% rename from tests/rustdoc/private-use.rs rename to tests/rustdoc/private/private-use.rs diff --git a/tests/rustdoc/public-impl-mention-private-generic-46380-2.rs b/tests/rustdoc/private/public-impl-mention-private-generic-46380-2.rs similarity index 100% rename from tests/rustdoc/public-impl-mention-private-generic-46380-2.rs rename to tests/rustdoc/private/public-impl-mention-private-generic-46380-2.rs diff --git a/tests/rustdoc/traits-in-bodies-private.rs b/tests/rustdoc/private/traits-in-bodies-private.rs similarity index 100% rename from tests/rustdoc/traits-in-bodies-private.rs rename to tests/rustdoc/private/traits-in-bodies-private.rs diff --git a/tests/rustdoc/alias-reexport.rs b/tests/rustdoc/reexport/alias-reexport.rs similarity index 100% rename from tests/rustdoc/alias-reexport.rs rename to tests/rustdoc/reexport/alias-reexport.rs diff --git a/tests/rustdoc/alias-reexport2.rs b/tests/rustdoc/reexport/alias-reexport2.rs similarity index 100% rename from tests/rustdoc/alias-reexport2.rs rename to tests/rustdoc/reexport/alias-reexport2.rs diff --git a/tests/rustdoc/anonymous-reexport-108931.rs b/tests/rustdoc/reexport/anonymous-reexport-108931.rs similarity index 100% rename from tests/rustdoc/anonymous-reexport-108931.rs rename to tests/rustdoc/reexport/anonymous-reexport-108931.rs diff --git a/tests/rustdoc/anonymous-reexport.rs b/tests/rustdoc/reexport/anonymous-reexport.rs similarity index 100% rename from tests/rustdoc/anonymous-reexport.rs rename to tests/rustdoc/reexport/anonymous-reexport.rs diff --git a/tests/rustdoc/auxiliary/alias-reexport.rs b/tests/rustdoc/reexport/auxiliary/alias-reexport.rs similarity index 100% rename from tests/rustdoc/auxiliary/alias-reexport.rs rename to tests/rustdoc/reexport/auxiliary/alias-reexport.rs diff --git a/tests/rustdoc/auxiliary/alias-reexport2.rs b/tests/rustdoc/reexport/auxiliary/alias-reexport2.rs similarity index 100% rename from tests/rustdoc/auxiliary/alias-reexport2.rs rename to tests/rustdoc/reexport/auxiliary/alias-reexport2.rs diff --git a/tests/rustdoc/reexport/auxiliary/all-item-types.rs b/tests/rustdoc/reexport/auxiliary/all-item-types.rs new file mode 100644 index 000000000000..f94bd998717a --- /dev/null +++ b/tests/rustdoc/reexport/auxiliary/all-item-types.rs @@ -0,0 +1,22 @@ +#![feature(extern_types)] + +pub mod foo_mod {} +extern "C" { + pub fn foo_ffn(); + pub static FOO_FSTATIC: FooStruct; + pub type FooFType; +} +pub fn foo_fn() {} +pub trait FooTrait {} +pub struct FooStruct; +pub enum FooEnum {} +pub union FooUnion { + x: (), +} +pub type FooType = FooStruct; +pub static FOO_STATIC: FooStruct = FooStruct; +pub const FOO_CONSTANT: FooStruct = FooStruct; +#[macro_export] +macro_rules! foo_macro { + () => (); +} diff --git a/tests/rustdoc/auxiliary/issue-113982-doc_auto_cfg-reexport-foreign.rs b/tests/rustdoc/reexport/auxiliary/issue-113982-doc_auto_cfg-reexport-foreign.rs similarity index 100% rename from tests/rustdoc/auxiliary/issue-113982-doc_auto_cfg-reexport-foreign.rs rename to tests/rustdoc/reexport/auxiliary/issue-113982-doc_auto_cfg-reexport-foreign.rs diff --git a/tests/rustdoc/auxiliary/issue-28927-1.rs b/tests/rustdoc/reexport/auxiliary/issue-28927-1.rs similarity index 100% rename from tests/rustdoc/auxiliary/issue-28927-1.rs rename to tests/rustdoc/reexport/auxiliary/issue-28927-1.rs diff --git a/tests/rustdoc/auxiliary/issue-28927-2.rs b/tests/rustdoc/reexport/auxiliary/issue-28927-2.rs similarity index 100% rename from tests/rustdoc/auxiliary/issue-28927-2.rs rename to tests/rustdoc/reexport/auxiliary/issue-28927-2.rs diff --git a/tests/rustdoc/auxiliary/primitive-reexport.rs b/tests/rustdoc/reexport/auxiliary/primitive-reexport.rs similarity index 100% rename from tests/rustdoc/auxiliary/primitive-reexport.rs rename to tests/rustdoc/reexport/auxiliary/primitive-reexport.rs diff --git a/tests/rustdoc/auxiliary/reexport-check.rs b/tests/rustdoc/reexport/auxiliary/reexport-check.rs similarity index 100% rename from tests/rustdoc/auxiliary/reexport-check.rs rename to tests/rustdoc/reexport/auxiliary/reexport-check.rs diff --git a/tests/rustdoc/auxiliary/reexport-doc-aux.rs b/tests/rustdoc/reexport/auxiliary/reexport-doc-aux.rs similarity index 100% rename from tests/rustdoc/auxiliary/reexport-doc-aux.rs rename to tests/rustdoc/reexport/auxiliary/reexport-doc-aux.rs diff --git a/tests/rustdoc/auxiliary/reexports.rs b/tests/rustdoc/reexport/auxiliary/reexports.rs similarity index 100% rename from tests/rustdoc/auxiliary/reexports.rs rename to tests/rustdoc/reexport/auxiliary/reexports.rs diff --git a/tests/rustdoc/blanket-reexport-item.rs b/tests/rustdoc/reexport/blanket-reexport-item.rs similarity index 100% rename from tests/rustdoc/blanket-reexport-item.rs rename to tests/rustdoc/reexport/blanket-reexport-item.rs diff --git a/tests/rustdoc/cfg_doc_reexport.rs b/tests/rustdoc/reexport/cfg_doc_reexport.rs similarity index 100% rename from tests/rustdoc/cfg_doc_reexport.rs rename to tests/rustdoc/reexport/cfg_doc_reexport.rs diff --git a/tests/rustdoc/doc-hidden-reexports-109449.rs b/tests/rustdoc/reexport/doc-hidden-reexports-109449.rs similarity index 100% rename from tests/rustdoc/doc-hidden-reexports-109449.rs rename to tests/rustdoc/reexport/doc-hidden-reexports-109449.rs diff --git a/tests/rustdoc/doc_auto_cfg-reexport-foreign-113982.rs b/tests/rustdoc/reexport/doc_auto_cfg-reexport-foreign-113982.rs similarity index 100% rename from tests/rustdoc/doc_auto_cfg-reexport-foreign-113982.rs rename to tests/rustdoc/reexport/doc_auto_cfg-reexport-foreign-113982.rs diff --git a/tests/rustdoc/duplicated-glob-reexport-60522.rs b/tests/rustdoc/reexport/duplicated-glob-reexport-60522.rs similarity index 100% rename from tests/rustdoc/duplicated-glob-reexport-60522.rs rename to tests/rustdoc/reexport/duplicated-glob-reexport-60522.rs diff --git a/tests/rustdoc/enum-variant-reexport-35488.rs b/tests/rustdoc/reexport/enum-variant-reexport-35488.rs similarity index 100% rename from tests/rustdoc/enum-variant-reexport-35488.rs rename to tests/rustdoc/reexport/enum-variant-reexport-35488.rs diff --git a/tests/rustdoc/foreigntype-reexport.rs b/tests/rustdoc/reexport/foreigntype-reexport.rs similarity index 100% rename from tests/rustdoc/foreigntype-reexport.rs rename to tests/rustdoc/reexport/foreigntype-reexport.rs diff --git a/tests/rustdoc/glob-reexport-attribute-merge-120487.rs b/tests/rustdoc/reexport/glob-reexport-attribute-merge-120487.rs similarity index 100% rename from tests/rustdoc/glob-reexport-attribute-merge-120487.rs rename to tests/rustdoc/reexport/glob-reexport-attribute-merge-120487.rs diff --git a/tests/rustdoc/glob-reexport-attribute-merge-doc-auto-cfg.rs b/tests/rustdoc/reexport/glob-reexport-attribute-merge-doc-auto-cfg.rs similarity index 100% rename from tests/rustdoc/glob-reexport-attribute-merge-doc-auto-cfg.rs rename to tests/rustdoc/reexport/glob-reexport-attribute-merge-doc-auto-cfg.rs diff --git a/tests/rustdoc/ice-reexport-crate-root-28927.rs b/tests/rustdoc/reexport/ice-reexport-crate-root-28927.rs similarity index 100% rename from tests/rustdoc/ice-reexport-crate-root-28927.rs rename to tests/rustdoc/reexport/ice-reexport-crate-root-28927.rs diff --git a/tests/rustdoc/local-reexport-doc.rs b/tests/rustdoc/reexport/local-reexport-doc.rs similarity index 100% rename from tests/rustdoc/local-reexport-doc.rs rename to tests/rustdoc/reexport/local-reexport-doc.rs diff --git a/tests/rustdoc/no-compiler-reexport.rs b/tests/rustdoc/reexport/no-compiler-reexport.rs similarity index 100% rename from tests/rustdoc/no-compiler-reexport.rs rename to tests/rustdoc/reexport/no-compiler-reexport.rs diff --git a/tests/rustdoc/overlapping-reexport-105735-2.rs b/tests/rustdoc/reexport/overlapping-reexport-105735-2.rs similarity index 100% rename from tests/rustdoc/overlapping-reexport-105735-2.rs rename to tests/rustdoc/reexport/overlapping-reexport-105735-2.rs diff --git a/tests/rustdoc/overlapping-reexport-105735.rs b/tests/rustdoc/reexport/overlapping-reexport-105735.rs similarity index 100% rename from tests/rustdoc/overlapping-reexport-105735.rs rename to tests/rustdoc/reexport/overlapping-reexport-105735.rs diff --git a/tests/rustdoc/primitive-reexport.rs b/tests/rustdoc/reexport/primitive-reexport.rs similarity index 100% rename from tests/rustdoc/primitive-reexport.rs rename to tests/rustdoc/reexport/primitive-reexport.rs diff --git a/tests/rustdoc/pub-reexport-of-pub-reexport-46506.rs b/tests/rustdoc/reexport/pub-reexport-of-pub-reexport-46506.rs similarity index 100% rename from tests/rustdoc/pub-reexport-of-pub-reexport-46506.rs rename to tests/rustdoc/reexport/pub-reexport-of-pub-reexport-46506.rs diff --git a/tests/rustdoc/reexport-attr-merge.rs b/tests/rustdoc/reexport/reexport-attr-merge.rs similarity index 100% rename from tests/rustdoc/reexport-attr-merge.rs rename to tests/rustdoc/reexport/reexport-attr-merge.rs diff --git a/tests/rustdoc/reexport-cfg.rs b/tests/rustdoc/reexport/reexport-cfg.rs similarity index 100% rename from tests/rustdoc/reexport-cfg.rs rename to tests/rustdoc/reexport/reexport-cfg.rs diff --git a/tests/rustdoc/reexport-check.rs b/tests/rustdoc/reexport/reexport-check.rs similarity index 100% rename from tests/rustdoc/reexport-check.rs rename to tests/rustdoc/reexport/reexport-check.rs diff --git a/tests/rustdoc/reexport-dep-foreign-fn.rs b/tests/rustdoc/reexport/reexport-dep-foreign-fn.rs similarity index 100% rename from tests/rustdoc/reexport-dep-foreign-fn.rs rename to tests/rustdoc/reexport/reexport-dep-foreign-fn.rs diff --git a/tests/rustdoc/reexport-doc-hidden-inside-private.rs b/tests/rustdoc/reexport/reexport-doc-hidden-inside-private.rs similarity index 100% rename from tests/rustdoc/reexport-doc-hidden-inside-private.rs rename to tests/rustdoc/reexport/reexport-doc-hidden-inside-private.rs diff --git a/tests/rustdoc/reexport-doc-hidden.rs b/tests/rustdoc/reexport/reexport-doc-hidden.rs similarity index 100% rename from tests/rustdoc/reexport-doc-hidden.rs rename to tests/rustdoc/reexport/reexport-doc-hidden.rs diff --git a/tests/rustdoc/reexport-doc.rs b/tests/rustdoc/reexport/reexport-doc.rs similarity index 100% rename from tests/rustdoc/reexport-doc.rs rename to tests/rustdoc/reexport/reexport-doc.rs diff --git a/tests/rustdoc/reexport-hidden-macro.rs b/tests/rustdoc/reexport/reexport-hidden-macro.rs similarity index 100% rename from tests/rustdoc/reexport-hidden-macro.rs rename to tests/rustdoc/reexport/reexport-hidden-macro.rs diff --git a/tests/rustdoc/reexport-macro.rs b/tests/rustdoc/reexport/reexport-macro.rs similarity index 100% rename from tests/rustdoc/reexport-macro.rs rename to tests/rustdoc/reexport/reexport-macro.rs diff --git a/tests/rustdoc/reexport-of-doc-hidden.rs b/tests/rustdoc/reexport/reexport-of-doc-hidden.rs similarity index 100% rename from tests/rustdoc/reexport-of-doc-hidden.rs rename to tests/rustdoc/reexport/reexport-of-doc-hidden.rs diff --git a/tests/rustdoc/reexport-of-reexport-108679.rs b/tests/rustdoc/reexport/reexport-of-reexport-108679.rs similarity index 100% rename from tests/rustdoc/reexport-of-reexport-108679.rs rename to tests/rustdoc/reexport/reexport-of-reexport-108679.rs diff --git a/tests/rustdoc/reexport-stability-tags-deprecated-and-portability.rs b/tests/rustdoc/reexport/reexport-stability-tags-deprecated-and-portability.rs similarity index 100% rename from tests/rustdoc/reexport-stability-tags-deprecated-and-portability.rs rename to tests/rustdoc/reexport/reexport-stability-tags-deprecated-and-portability.rs diff --git a/tests/rustdoc/reexport-stability-tags-unstable-and-portability.rs b/tests/rustdoc/reexport/reexport-stability-tags-unstable-and-portability.rs similarity index 100% rename from tests/rustdoc/reexport-stability-tags-unstable-and-portability.rs rename to tests/rustdoc/reexport/reexport-stability-tags-unstable-and-portability.rs diff --git a/tests/rustdoc/reexport-trait-from-hidden-111064-2.rs b/tests/rustdoc/reexport/reexport-trait-from-hidden-111064-2.rs similarity index 100% rename from tests/rustdoc/reexport-trait-from-hidden-111064-2.rs rename to tests/rustdoc/reexport/reexport-trait-from-hidden-111064-2.rs diff --git a/tests/rustdoc/reexport-trait-from-hidden-111064.rs b/tests/rustdoc/reexport/reexport-trait-from-hidden-111064.rs similarity index 100% rename from tests/rustdoc/reexport-trait-from-hidden-111064.rs rename to tests/rustdoc/reexport/reexport-trait-from-hidden-111064.rs diff --git a/tests/rustdoc/reexports-of-same-name.rs b/tests/rustdoc/reexport/reexports-of-same-name.rs similarity index 100% rename from tests/rustdoc/reexports-of-same-name.rs rename to tests/rustdoc/reexport/reexports-of-same-name.rs diff --git a/tests/rustdoc/reexports-priv.rs b/tests/rustdoc/reexport/reexports-priv.rs similarity index 100% rename from tests/rustdoc/reexports-priv.rs rename to tests/rustdoc/reexport/reexports-priv.rs diff --git a/tests/rustdoc/reexports.rs b/tests/rustdoc/reexport/reexports.rs similarity index 100% rename from tests/rustdoc/reexports.rs rename to tests/rustdoc/reexport/reexports.rs diff --git a/tests/rustdoc/assoc-type-source-link.rs b/tests/rustdoc/source-code-pages/assoc-type-source-link.rs similarity index 100% rename from tests/rustdoc/assoc-type-source-link.rs rename to tests/rustdoc/source-code-pages/assoc-type-source-link.rs diff --git a/tests/rustdoc/auxiliary/issue-26606-macro.rs b/tests/rustdoc/source-code-pages/auxiliary/issue-26606-macro.rs similarity index 100% rename from tests/rustdoc/auxiliary/issue-26606-macro.rs rename to tests/rustdoc/source-code-pages/auxiliary/issue-26606-macro.rs diff --git a/tests/rustdoc/auxiliary/issue-34274.rs b/tests/rustdoc/source-code-pages/auxiliary/issue-34274.rs similarity index 100% rename from tests/rustdoc/auxiliary/issue-34274.rs rename to tests/rustdoc/source-code-pages/auxiliary/issue-34274.rs diff --git a/tests/rustdoc/auxiliary/source-code-bar.rs b/tests/rustdoc/source-code-pages/auxiliary/source-code-bar.rs similarity index 100% rename from tests/rustdoc/auxiliary/source-code-bar.rs rename to tests/rustdoc/source-code-pages/auxiliary/source-code-bar.rs diff --git a/tests/rustdoc/auxiliary/source_code.rs b/tests/rustdoc/source-code-pages/auxiliary/source_code.rs similarity index 100% rename from tests/rustdoc/auxiliary/source_code.rs rename to tests/rustdoc/source-code-pages/auxiliary/source_code.rs diff --git a/tests/rustdoc/auxiliary/src-links-external.rs b/tests/rustdoc/source-code-pages/auxiliary/src-links-external.rs similarity index 100% rename from tests/rustdoc/auxiliary/src-links-external.rs rename to tests/rustdoc/source-code-pages/auxiliary/src-links-external.rs diff --git a/tests/rustdoc/check-source-code-urls-to-def-std.rs b/tests/rustdoc/source-code-pages/check-source-code-urls-to-def-std.rs similarity index 100% rename from tests/rustdoc/check-source-code-urls-to-def-std.rs rename to tests/rustdoc/source-code-pages/check-source-code-urls-to-def-std.rs diff --git a/tests/rustdoc/check-source-code-urls-to-def.rs b/tests/rustdoc/source-code-pages/check-source-code-urls-to-def.rs similarity index 100% rename from tests/rustdoc/check-source-code-urls-to-def.rs rename to tests/rustdoc/source-code-pages/check-source-code-urls-to-def.rs diff --git a/tests/rustdoc/doc-hidden-source.rs b/tests/rustdoc/source-code-pages/doc-hidden-source.rs similarity index 100% rename from tests/rustdoc/doc-hidden-source.rs rename to tests/rustdoc/source-code-pages/doc-hidden-source.rs diff --git a/tests/rustdoc/html-no-source.rs b/tests/rustdoc/source-code-pages/html-no-source.rs similarity index 100% rename from tests/rustdoc/html-no-source.rs rename to tests/rustdoc/source-code-pages/html-no-source.rs diff --git a/tests/rustdoc/source-code-highlight.rs b/tests/rustdoc/source-code-pages/source-code-highlight.rs similarity index 100% rename from tests/rustdoc/source-code-highlight.rs rename to tests/rustdoc/source-code-pages/source-code-highlight.rs diff --git a/tests/rustdoc/source-file.rs b/tests/rustdoc/source-code-pages/source-file.rs similarity index 100% rename from tests/rustdoc/source-file.rs rename to tests/rustdoc/source-code-pages/source-file.rs diff --git a/tests/rustdoc/source-line-numbers.rs b/tests/rustdoc/source-code-pages/source-line-numbers.rs similarity index 100% rename from tests/rustdoc/source-line-numbers.rs rename to tests/rustdoc/source-code-pages/source-line-numbers.rs diff --git a/tests/rustdoc/source-version-separator.rs b/tests/rustdoc/source-code-pages/source-version-separator.rs similarity index 100% rename from tests/rustdoc/source-version-separator.rs rename to tests/rustdoc/source-code-pages/source-version-separator.rs diff --git a/tests/rustdoc/src-link-external-macro-26606.rs b/tests/rustdoc/source-code-pages/src-link-external-macro-26606.rs similarity index 100% rename from tests/rustdoc/src-link-external-macro-26606.rs rename to tests/rustdoc/source-code-pages/src-link-external-macro-26606.rs diff --git a/tests/rustdoc/src-links-auto-impls.rs b/tests/rustdoc/source-code-pages/src-links-auto-impls.rs similarity index 100% rename from tests/rustdoc/src-links-auto-impls.rs rename to tests/rustdoc/source-code-pages/src-links-auto-impls.rs diff --git a/tests/rustdoc/src-links-external.rs b/tests/rustdoc/source-code-pages/src-links-external.rs similarity index 100% rename from tests/rustdoc/src-links-external.rs rename to tests/rustdoc/source-code-pages/src-links-external.rs diff --git a/tests/rustdoc/src-links-implementor-43893.rs b/tests/rustdoc/source-code-pages/src-links-implementor-43893.rs similarity index 100% rename from tests/rustdoc/src-links-implementor-43893.rs rename to tests/rustdoc/source-code-pages/src-links-implementor-43893.rs diff --git a/tests/rustdoc/src-links-inlined-34274.rs b/tests/rustdoc/source-code-pages/src-links-inlined-34274.rs similarity index 100% rename from tests/rustdoc/src-links-inlined-34274.rs rename to tests/rustdoc/source-code-pages/src-links-inlined-34274.rs diff --git a/tests/rustdoc/src-links.rs b/tests/rustdoc/source-code-pages/src-links.rs similarity index 100% rename from tests/rustdoc/src-links.rs rename to tests/rustdoc/source-code-pages/src-links.rs diff --git a/tests/rustdoc/src-links/compiletest-ignore-dir b/tests/rustdoc/source-code-pages/src-links/compiletest-ignore-dir similarity index 100% rename from tests/rustdoc/src-links/compiletest-ignore-dir rename to tests/rustdoc/source-code-pages/src-links/compiletest-ignore-dir diff --git a/tests/rustdoc/src-links/fizz.rs b/tests/rustdoc/source-code-pages/src-links/fizz.rs similarity index 100% rename from tests/rustdoc/src-links/fizz.rs rename to tests/rustdoc/source-code-pages/src-links/fizz.rs diff --git a/tests/rustdoc/src-links/mod.rs b/tests/rustdoc/source-code-pages/src-links/mod.rs similarity index 100% rename from tests/rustdoc/src-links/mod.rs rename to tests/rustdoc/source-code-pages/src-links/mod.rs diff --git a/tests/rustdoc/src-mod-path-absolute-26995.rs b/tests/rustdoc/source-code-pages/src-mod-path-absolute-26995.rs similarity index 100% rename from tests/rustdoc/src-mod-path-absolute-26995.rs rename to tests/rustdoc/source-code-pages/src-mod-path-absolute-26995.rs diff --git a/tests/rustdoc/version-separator-without-source.rs b/tests/rustdoc/source-code-pages/version-separator-without-source.rs similarity index 100% rename from tests/rustdoc/version-separator-without-source.rs rename to tests/rustdoc/source-code-pages/version-separator-without-source.rs diff --git a/tests/ui-fulldeps/stable-mir/check_assoc_items.rs b/tests/ui-fulldeps/stable-mir/check_assoc_items.rs index 755bec8747bc..bb95bedf9733 100644 --- a/tests/ui-fulldeps/stable-mir/check_assoc_items.rs +++ b/tests/ui-fulldeps/stable-mir/check_assoc_items.rs @@ -17,13 +17,13 @@ extern crate rustc_driver; extern crate rustc_interface; extern crate stable_mir; -use std::io::Write; use std::collections::HashSet; -use stable_mir::CrateDef; -use stable_mir::*; -use stable_mir::ty::*; +use std::io::Write; use std::ops::ControlFlow; +use stable_mir::ty::*; +use stable_mir::{CrateDef, *}; + const CRATE_NAME: &str = "crate_assoc_items"; /// This function uses the Stable MIR APIs to get information about the test crate. @@ -45,30 +45,30 @@ fn test_assoc_items() -> ControlFlow<()> { let local_impls = local_crate.trait_impls(); let local_traits = local_crate.trait_decls(); - let trait_assoc_item_defs: Vec = local_traits[0].associated_items() - .iter().map(|assoc_item| assoc_item.def_id).collect(); + let trait_assoc_item_defs: Vec = + local_traits[0].associated_items().iter().map(|assoc_item| assoc_item.def_id).collect(); check_items( &trait_assoc_item_defs, &[ - "ATrait::{anon_assoc#0}", + "ATrait::rpitit::{anon_assoc#0}", "ATrait::rpitit", "ATrait::Assoc", "ATrait::assoc_fn_no_self", "ATrait::assoc_fn_has_self", - ] + ], ); - let impl_assoc_item_defs: Vec = local_impls[0].associated_items() - .iter().map(|assoc_item| assoc_item.def_id).collect(); + let impl_assoc_item_defs: Vec = + local_impls[0].associated_items().iter().map(|assoc_item| assoc_item.def_id).collect(); check_items( &impl_assoc_item_defs, &[ - "::{anon_assoc#0}", + "::rpitit::{anon_assoc#0}", "::rpitit", "::Assoc", "::assoc_fn_no_self", "::assoc_fn_has_self", - ] + ], ); ControlFlow::Continue(()) diff --git a/tests/ui-fulldeps/stable-mir/check_attribute.rs b/tests/ui-fulldeps/stable-mir/check_attribute.rs index 81d5399d88aa..e4cc7b104b60 100644 --- a/tests/ui-fulldeps/stable-mir/check_attribute.rs +++ b/tests/ui-fulldeps/stable-mir/check_attribute.rs @@ -35,12 +35,12 @@ fn test_stable_mir() -> ControlFlow<()> { fn test_tool(items: &CrateItems) { let rustfmt_fn = *get_item(&items, "do_not_format").unwrap(); let rustfmt_attrs = rustfmt_fn.tool_attrs(&["rustfmt".to_string(), "skip".to_string()]); - assert_eq!(rustfmt_attrs[0].as_str(), "#[rustfmt::skip]"); + assert_eq!(rustfmt_attrs[0].as_str(), "#[rustfmt::skip]\n"); let clippy_fn = *get_item(&items, "complex_fn").unwrap(); let clippy_attrs = clippy_fn.tool_attrs(&["clippy".to_string(), "cyclomatic_complexity".to_string()]); - assert_eq!(clippy_attrs[0].as_str(), "#[clippy::cyclomatic_complexity = \"100\"]"); + assert_eq!(clippy_attrs[0].as_str(), "#[clippy::cyclomatic_complexity = \"100\"]\n"); } fn get_item<'a>( diff --git a/tests/ui/abi/compatibility.rs b/tests/ui/abi/compatibility.rs index be649029c863..68706f1e821a 100644 --- a/tests/ui/abi/compatibility.rs +++ b/tests/ui/abi/compatibility.rs @@ -40,7 +40,6 @@ //@ revisions: loongarch64 //@[loongarch64] compile-flags: --target loongarch64-unknown-linux-gnu //@[loongarch64] needs-llvm-components: loongarch -//@[loongarch64] min-llvm-version: 20 //FIXME: wasm is disabled due to . //FIXME @ revisions: wasm //FIXME @[wasm] compile-flags: --target wasm32-unknown-unknown diff --git a/tests/ui/abi/lib-defaults.rs b/tests/ui/abi/lib-defaults.rs deleted file mode 100644 index 2c2cad4f82dc..000000000000 --- a/tests/ui/abi/lib-defaults.rs +++ /dev/null @@ -1,15 +0,0 @@ -//@ run-pass -//@ dont-check-compiler-stderr (rust-lang/rust#54222) - -//@ compile-flags: -lrust_test_helpers - -#[link(name = "rust_test_helpers", kind = "static")] -extern "C" { - pub fn rust_dbg_extern_identity_u32(x: u32) -> u32; -} - -fn main() { - unsafe { - rust_dbg_extern_identity_u32(42); - } -} diff --git a/tests/ui/annotate-snippet/missing-type.rs b/tests/ui/annotate-snippet/missing-type.rs index ea1c2521103e..bfe8ab2f5ffe 100644 --- a/tests/ui/annotate-snippet/missing-type.rs +++ b/tests/ui/annotate-snippet/missing-type.rs @@ -1,6 +1,7 @@ //@ compile-flags: --error-format human-annotate-rs -Z unstable-options -//@ error-pattern:cannot find type `Iter` in this scope pub fn main() { let x: Iter; } + +//~? RAW cannot find type `Iter` in this scope diff --git a/tests/ui/annotate-snippet/missing-type.stderr b/tests/ui/annotate-snippet/missing-type.stderr index 89ce19c182f5..c16f022a77fa 100644 --- a/tests/ui/annotate-snippet/missing-type.stderr +++ b/tests/ui/annotate-snippet/missing-type.stderr @@ -1,5 +1,5 @@ error[E0412]: cannot find type `Iter` in this scope - --> $DIR/missing-type.rs:5:12 + --> $DIR/missing-type.rs:4:12 | LL | let x: Iter; | ^^^^ not found in this scope diff --git a/tests/ui/annotate-snippet/multispan.rs b/tests/ui/annotate-snippet/multispan.rs index b7cf22eebcbf..c2054f62d24c 100644 --- a/tests/ui/annotate-snippet/multispan.rs +++ b/tests/ui/annotate-snippet/multispan.rs @@ -1,5 +1,4 @@ //@ proc-macro: multispan.rs -//@ error-pattern:hello to you, too! //@ compile-flags: --error-format human-annotate-rs -Z unstable-options #![feature(proc_macro_hygiene)] @@ -27,3 +26,5 @@ fn main() { hello!(whoah. hi di hi di ho); hello!(hi good hi and good bye); } + +//~? RAW hello to you, too! diff --git a/tests/ui/annotate-snippet/multispan.stderr b/tests/ui/annotate-snippet/multispan.stderr index 833b67730325..baed54c59a4e 100644 --- a/tests/ui/annotate-snippet/multispan.stderr +++ b/tests/ui/annotate-snippet/multispan.stderr @@ -1,41 +1,41 @@ error: hello to you, too! - --> $DIR/multispan.rs:16:5 + --> $DIR/multispan.rs:15:5 | LL | hello!(hi); | ^^^^^^^^^^ | error: hello to you, too! - --> $DIR/multispan.rs:19:5 + --> $DIR/multispan.rs:18:5 | LL | hello!(hi hi); | ^^^^^^^^^^^^^ | error: hello to you, too! - --> $DIR/multispan.rs:22:5 + --> $DIR/multispan.rs:21:5 | LL | hello!(hi hi hi); | ^^^^^^^^^^^^^^^^ | error: hello to you, too! - --> $DIR/multispan.rs:25:5 + --> $DIR/multispan.rs:24:5 | LL | hello!(hi hey hi yo hi beep beep hi hi); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | error: hello to you, too! - --> $DIR/multispan.rs:26:5 + --> $DIR/multispan.rs:25:5 | LL | hello!(hi there, hi how are you? hi... hi.); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | error: hello to you, too! - --> $DIR/multispan.rs:27:5 + --> $DIR/multispan.rs:26:5 | LL | hello!(whoah. hi di hi di ho); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | error: hello to you, too! - --> $DIR/multispan.rs:28:5 + --> $DIR/multispan.rs:27:5 | LL | hello!(hi good hi and good bye); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/asm/global-asm-mono-sym-fn.rs b/tests/ui/asm/global-asm-mono-sym-fn.rs new file mode 100644 index 000000000000..e584a98badb0 --- /dev/null +++ b/tests/ui/asm/global-asm-mono-sym-fn.rs @@ -0,0 +1,27 @@ +// Test that we're properly monomorphizing sym args in global asm blocks +// that point to associated items. + +//@ edition: 2021 +//@ needs-asm-support +//@ only-x86_64-unknown-linux-gnu +//@ build-pass + +#![no_main] + +use std::arch::global_asm; + +fn foo() { + loop {} +} + +trait Foo { + fn bar(); +} + +impl Foo for i32 { + fn bar() { + loop {} + } +} + +global_asm!(".global main", "main:", "call {}", sym ::bar); diff --git a/tests/ui/asm/loongarch/bad-reg.loongarch64_lp64d.stderr b/tests/ui/asm/loongarch/bad-reg.loongarch64_lp64d.stderr index c88f3af76426..0e5441196501 100644 --- a/tests/ui/asm/loongarch/bad-reg.loongarch64_lp64d.stderr +++ b/tests/ui/asm/loongarch/bad-reg.loongarch64_lp64d.stderr @@ -1,35 +1,35 @@ error: invalid register `$r0`: constant zero cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:23:18 + --> $DIR/bad-reg.rs:22:18 | LL | asm!("", out("$r0") _); | ^^^^^^^^^^^^ error: invalid register `$tp`: reserved for TLS - --> $DIR/bad-reg.rs:25:18 + --> $DIR/bad-reg.rs:24:18 | LL | asm!("", out("$tp") _); | ^^^^^^^^^^^^ error: invalid register `$sp`: the stack pointer cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:27:18 + --> $DIR/bad-reg.rs:26:18 | LL | asm!("", out("$sp") _); | ^^^^^^^^^^^^ error: invalid register `$r21`: reserved by the ABI - --> $DIR/bad-reg.rs:29:18 + --> $DIR/bad-reg.rs:28:18 | LL | asm!("", out("$r21") _); | ^^^^^^^^^^^^^ error: invalid register `$fp`: the frame pointer cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:31:18 + --> $DIR/bad-reg.rs:30:18 | LL | asm!("", out("$fp") _); | ^^^^^^^^^^^^ error: invalid register `$r31`: $r31 is used internally by LLVM and cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:33:18 + --> $DIR/bad-reg.rs:32:18 | LL | asm!("", out("$r31") _); | ^^^^^^^^^^^^^ diff --git a/tests/ui/asm/loongarch/bad-reg.loongarch64_lp64s.stderr b/tests/ui/asm/loongarch/bad-reg.loongarch64_lp64s.stderr index cb8e55a9722d..6d0410dc6a13 100644 --- a/tests/ui/asm/loongarch/bad-reg.loongarch64_lp64s.stderr +++ b/tests/ui/asm/loongarch/bad-reg.loongarch64_lp64s.stderr @@ -1,59 +1,59 @@ error: invalid register `$r0`: constant zero cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:23:18 + --> $DIR/bad-reg.rs:22:18 | LL | asm!("", out("$r0") _); | ^^^^^^^^^^^^ error: invalid register `$tp`: reserved for TLS - --> $DIR/bad-reg.rs:25:18 + --> $DIR/bad-reg.rs:24:18 | LL | asm!("", out("$tp") _); | ^^^^^^^^^^^^ error: invalid register `$sp`: the stack pointer cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:27:18 + --> $DIR/bad-reg.rs:26:18 | LL | asm!("", out("$sp") _); | ^^^^^^^^^^^^ error: invalid register `$r21`: reserved by the ABI - --> $DIR/bad-reg.rs:29:18 + --> $DIR/bad-reg.rs:28:18 | LL | asm!("", out("$r21") _); | ^^^^^^^^^^^^^ error: invalid register `$fp`: the frame pointer cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:31:18 + --> $DIR/bad-reg.rs:30:18 | LL | asm!("", out("$fp") _); | ^^^^^^^^^^^^ error: invalid register `$r31`: $r31 is used internally by LLVM and cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:33:18 + --> $DIR/bad-reg.rs:32:18 | LL | asm!("", out("$r31") _); | ^^^^^^^^^^^^^ error: register class `freg` requires at least one of the following target features: d, f - --> $DIR/bad-reg.rs:37:26 + --> $DIR/bad-reg.rs:36:26 | LL | asm!("/* {} */", in(freg) f); | ^^^^^^^^^^ error: register class `freg` requires at least one of the following target features: d, f - --> $DIR/bad-reg.rs:39:26 + --> $DIR/bad-reg.rs:38:26 | LL | asm!("/* {} */", out(freg) _); | ^^^^^^^^^^^ error: register class `freg` requires at least one of the following target features: d, f - --> $DIR/bad-reg.rs:41:26 + --> $DIR/bad-reg.rs:40:26 | LL | asm!("/* {} */", in(freg) d); | ^^^^^^^^^^ error: register class `freg` requires at least one of the following target features: d, f - --> $DIR/bad-reg.rs:43:26 + --> $DIR/bad-reg.rs:42:26 | LL | asm!("/* {} */", out(freg) d); | ^^^^^^^^^^^ diff --git a/tests/ui/asm/loongarch/bad-reg.rs b/tests/ui/asm/loongarch/bad-reg.rs index db1c778e5a25..685b460bc922 100644 --- a/tests/ui/asm/loongarch/bad-reg.rs +++ b/tests/ui/asm/loongarch/bad-reg.rs @@ -1,7 +1,6 @@ //@ add-core-stubs //@ needs-asm-support //@ revisions: loongarch64_lp64d loongarch64_lp64s -//@ min-llvm-version: 20 //@[loongarch64_lp64d] compile-flags: --target loongarch64-unknown-linux-gnu //@[loongarch64_lp64d] needs-llvm-components: loongarch //@[loongarch64_lp64s] compile-flags: --target loongarch64-unknown-none-softfloat diff --git a/tests/ui/asm/naked-asm-mono-sym-fn.rs b/tests/ui/asm/naked-asm-mono-sym-fn.rs new file mode 100644 index 000000000000..948c290c0b4f --- /dev/null +++ b/tests/ui/asm/naked-asm-mono-sym-fn.rs @@ -0,0 +1,35 @@ +// Regression test for . +// Test that we're properly monomorphizing sym args in naked asm blocks +// that point to associated items. + +//@ edition: 2021 +//@ needs-asm-support +//@ only-x86_64 +//@ build-pass + +trait Tr { + extern "C" fn t(); +} + +enum E {} + +impl Tr for E { + extern "C" fn t() { + println!("Const generic: {}", C); + } +} + +#[unsafe(naked)] +extern "C" fn foo() { + core::arch::naked_asm!( + "push rax", + "call {fn}", + "pop rax", + "ret", + fn = sym ::t, + ); +} + +fn main() { + foo::>(); +} diff --git a/tests/ui/asm/naked-functions.rs b/tests/ui/asm/naked-functions.rs index 1eeb716e98a1..a6f41698b411 100644 --- a/tests/ui/asm/naked-functions.rs +++ b/tests/ui/asm/naked-functions.rs @@ -2,7 +2,7 @@ //@ ignore-nvptx64 //@ ignore-spirv -#![feature(asm_unwind, linkage)] +#![feature(asm_unwind, linkage, rustc_attrs)] #![crate_type = "lib"] use std::arch::{asm, naked_asm}; @@ -225,3 +225,15 @@ pub extern "C" fn compatible_doc_attributes() { pub extern "C" fn compatible_linkage() { naked_asm!("", options(raw)); } + +#[rustc_std_internal_symbol] +#[unsafe(naked)] +pub extern "C" fn rustc_std_internal_symbol() { + naked_asm!("", options(raw)); +} + +#[rustfmt::skip] +#[unsafe(naked)] +pub extern "C" fn rustfmt_skip() { + naked_asm!("", options(raw)); +} diff --git a/tests/ui/associated-inherent-types/bugs/wf-check-skipped.next.stderr b/tests/ui/associated-inherent-types/bugs/wf-check-skipped.next.stderr deleted file mode 100644 index 81ace4ebb6da..000000000000 --- a/tests/ui/associated-inherent-types/bugs/wf-check-skipped.next.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0277]: the size for values of type `[u32]` cannot be known at compilation time - --> $DIR/wf-check-skipped.rs:17:25 - | -LL | fn main() -> Foo::Bar::> {} - | ^^^^^^^^^^ doesn't have a size known at compile-time - | - = help: the trait `Sized` is not implemented for `[u32]` -note: required by an implicit `Sized` bound in `Vec` - --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/associated-inherent-types/bugs/wf-check-skipped.rs b/tests/ui/associated-inherent-types/bugs/wf-check-skipped.rs index 52df4efd13e9..2949007d770a 100644 --- a/tests/ui/associated-inherent-types/bugs/wf-check-skipped.rs +++ b/tests/ui/associated-inherent-types/bugs/wf-check-skipped.rs @@ -1,8 +1,8 @@ //@ revisions: current next //@[next] compile-flags: -Znext-solver //@ ignore-compare-mode-next-solver (explicit revisions) -//@[current] known-bug: #100041 -//@[current] check-pass +//@ known-bug: #100041 +//@ check-pass // FIXME(inherent_associated_types): This should fail. #![feature(inherent_associated_types)] @@ -15,4 +15,3 @@ impl Foo { } fn main() -> Foo::Bar::> {} -//[next]~^ ERROR the size for values of type `[u32]` cannot be known at compilation time diff --git a/tests/ui/associated-types/mismatch-two-relevant-impls.rs b/tests/ui/associated-types/mismatch-two-relevant-impls.rs new file mode 100644 index 000000000000..58fd567c2780 --- /dev/null +++ b/tests/ui/associated-types/mismatch-two-relevant-impls.rs @@ -0,0 +1,20 @@ +trait Tr { + type Assoc; +} + +struct W(T); + +impl Tr for W { + type Assoc = u32; +} + +impl Tr for W { + type Assoc = i32; +} + +fn needs_unit>() {} + +fn main() { + needs_unit::>(); + //~^ ERROR type mismatch resolving ` as Tr>::Assoc == ()` +} diff --git a/tests/ui/associated-types/mismatch-two-relevant-impls.stderr b/tests/ui/associated-types/mismatch-two-relevant-impls.stderr new file mode 100644 index 000000000000..2a1f3ef23ca7 --- /dev/null +++ b/tests/ui/associated-types/mismatch-two-relevant-impls.stderr @@ -0,0 +1,20 @@ +error[E0271]: type mismatch resolving ` as Tr>::Assoc == ()` + --> $DIR/mismatch-two-relevant-impls.rs:18:18 + | +LL | needs_unit::>(); + | ^^^^^^ type mismatch resolving ` as Tr>::Assoc == ()` + | +note: expected this to be `()` + --> $DIR/mismatch-two-relevant-impls.rs:8:18 + | +LL | type Assoc = u32; + | ^^^ +note: required by a bound in `needs_unit` + --> $DIR/mismatch-two-relevant-impls.rs:15:21 + | +LL | fn needs_unit>() {} + | ^^^^^^^^^^ required by this bound in `needs_unit` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0271`. diff --git a/tests/ui/async-await/async-closures/def-path.stderr b/tests/ui/async-await/async-closures/def-path.stderr index 13ebaf67e54a..b50e353b6988 100644 --- a/tests/ui/async-await/async-closures/def-path.stderr +++ b/tests/ui/async-await/async-closures/def-path.stderr @@ -5,11 +5,11 @@ LL | let x = async || {}; | -- the expected `async` closure body LL | LL | let () = x(); - | ^^ --- this expression has type `{static main::{closure#0}::{closure#0} upvar_tys=?16t resume_ty=ResumeTy yield_ty=() return_ty=() witness=?6t}` + | ^^ --- this expression has type `{static main::{closure#0}::{closure#0} upvar_tys=?16t resume_ty=ResumeTy yield_ty=() return_ty=() witness=?5t}` | | | expected `async` closure body, found `()` | - = note: expected `async` closure body `{static main::{closure#0}::{closure#0} upvar_tys=?16t resume_ty=ResumeTy yield_ty=() return_ty=() witness=?6t}` + = note: expected `async` closure body `{static main::{closure#0}::{closure#0} upvar_tys=?16t resume_ty=ResumeTy yield_ty=() return_ty=() witness=?5t}` found unit type `()` error: aborting due to 1 previous error diff --git a/tests/ui/attributes/export/crate-type-2.rs b/tests/ui/attributes/export/crate-type-2.rs new file mode 100644 index 000000000000..f0379f6d797c --- /dev/null +++ b/tests/ui/attributes/export/crate-type-2.rs @@ -0,0 +1,2 @@ +//@ compile-flags: --crate-type=sdylib +//~^ ERROR `sdylib` crate type is unstable diff --git a/tests/ui/attributes/export/crate-type-2.stderr b/tests/ui/attributes/export/crate-type-2.stderr new file mode 100644 index 000000000000..7ce6a500113f --- /dev/null +++ b/tests/ui/attributes/export/crate-type-2.stderr @@ -0,0 +1,9 @@ +error[E0658]: `sdylib` crate type is unstable + | + = note: see issue #139939 for more information + = help: add `#![feature(export_stable)]` 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/attributes/export/crate-type.rs b/tests/ui/attributes/export/crate-type.rs new file mode 100644 index 000000000000..bd092bbb1a1a --- /dev/null +++ b/tests/ui/attributes/export/crate-type.rs @@ -0,0 +1,2 @@ +#![crate_type = "sdylib"] +//~^ ERROR `sdylib` crate type is unstable diff --git a/tests/ui/attributes/export/crate-type.stderr b/tests/ui/attributes/export/crate-type.stderr new file mode 100644 index 000000000000..7ce6a500113f --- /dev/null +++ b/tests/ui/attributes/export/crate-type.stderr @@ -0,0 +1,9 @@ +error[E0658]: `sdylib` crate type is unstable + | + = note: see issue #139939 for more information + = help: add `#![feature(export_stable)]` 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/attributes/export/exportable.rs b/tests/ui/attributes/export/exportable.rs new file mode 100644 index 000000000000..f592fce88cd4 --- /dev/null +++ b/tests/ui/attributes/export/exportable.rs @@ -0,0 +1,139 @@ +//@ compile-flags: -Zunstable-options -Csymbol-mangling-version=v0 + +#![crate_type = "sdylib"] +#![allow(incomplete_features, improper_ctypes_definitions)] +#![feature(export_stable)] +#![feature(inherent_associated_types)] + +mod m { + #[export_stable] + pub struct S; + //~^ ERROR private items are not exportable + + pub fn foo() -> i32 { 0 } + //~^ ERROR only functions with "C" ABI are exportable +} + +#[export_stable] +pub use m::foo; + +#[export_stable] +pub mod m1 { + #[repr(C)] + pub struct S1; // OK, public type with stable repr + + struct S2; + + pub struct S3; + //~^ ERROR types with unstable layout are not exportable +} + +pub mod fn_sig { + #[export_stable] + pub fn foo1() {} + //~^ ERROR only functions with "C" ABI are exportable + + #[export_stable] + #[repr(C)] + pub struct S; + + #[export_stable] + pub extern "C" fn foo2(x: S) -> i32 { 0 } + + #[export_stable] + pub extern "C" fn foo3(x: Box) -> i32 { 0 } + //~^ ERROR function with `#[export_stable]` attribute uses type `Box`, which is not exportable +} + +pub mod impl_item { + pub struct S; + + impl S { + #[export_stable] + pub extern "C" fn foo1(&self) -> i32 { 0 } + //~^ ERROR method with `#[export_stable]` attribute uses type `&impl_item::S`, which is not exportable + + #[export_stable] + pub extern "C" fn foo2(self) -> i32 { 0 } + //~^ ERROR method with `#[export_stable]` attribute uses type `impl_item::S`, which is not exportable + } + + pub struct S2(T); + + impl S2 { + #[export_stable] + pub extern "C" fn foo1(&self) {} + //~^ ERROR generic functions are not exportable + } +} + +pub mod tys { + pub trait Trait { + type Type; + } + pub struct S; + + impl Trait for S { + type Type = (u32,); + } + + #[export_stable] + pub extern "C" fn foo1(x: ::Type) -> u32 { x.0 } + //~^ ERROR function with `#[export_stable]` attribute uses type `(u32,)`, which is not exportable + + #[export_stable] + pub type Type = [i32; 4]; + + #[export_stable] + pub extern "C" fn foo2(_x: Type) {} + //~^ ERROR function with `#[export_stable]` attribute uses type `[i32; 4]`, which is not exportable + + impl S { + #[export_stable] + pub type Type = extern "C" fn(); + } + + #[export_stable] + pub extern "C" fn foo3(_x: S::Type) {} + //~^ ERROR function with `#[export_stable]` attribute uses type `extern "C" fn()`, which is not exportable + + #[export_stable] + pub extern "C" fn foo4() -> impl Copy { + //~^ ERROR function with `#[export_stable]` attribute uses type `impl Copy`, which is not exportable + 0 + } +} + +pub mod privacy { + #[export_stable] + #[repr(C)] + pub struct S1 { + pub x: i32 + } + + #[export_stable] + #[repr(C)] + pub struct S2 { + //~^ ERROR ADT types with private fields are not exportable + x: i32 + } + + #[export_stable] + #[repr(i32)] + enum E { + //~^ ERROR private items are not exportable + Variant1 { x: i32 } + } +} + +pub mod use_site { + #[export_stable] + pub trait Trait {} + //~^ ERROR trait's are not exportable + + #[export_stable] + pub const C: i32 = 0; + //~^ ERROR constant's are not exportable +} + +fn main() {} diff --git a/tests/ui/attributes/export/exportable.stderr b/tests/ui/attributes/export/exportable.stderr new file mode 100644 index 000000000000..0f6469d35c3b --- /dev/null +++ b/tests/ui/attributes/export/exportable.stderr @@ -0,0 +1,130 @@ +error: private items are not exportable + --> $DIR/exportable.rs:10:5 + | +LL | pub struct S; + | ^^^^^^^^^^^^ + | +note: is only usable at visibility `pub(crate)` + --> $DIR/exportable.rs:10:5 + | +LL | pub struct S; + | ^^^^^^^^^^^^ + +error: private items are not exportable + --> $DIR/exportable.rs:123:5 + | +LL | enum E { + | ^^^^^^ + | +note: is only usable at visibility `pub(self)` + --> $DIR/exportable.rs:123:5 + | +LL | enum E { + | ^^^^^^ + +error: trait's are not exportable + --> $DIR/exportable.rs:131:5 + | +LL | pub trait Trait {} + | ^^^^^^^^^^^^^^^ + +error: constant's are not exportable + --> $DIR/exportable.rs:135:5 + | +LL | pub const C: i32 = 0; + | ^^^^^^^^^^^^^^^^ + +error: only functions with "C" ABI are exportable + --> $DIR/exportable.rs:13:5 + | +LL | pub fn foo() -> i32 { 0 } + | ^^^^^^^^^^^^^^^^^^^ + +error: types with unstable layout are not exportable + --> $DIR/exportable.rs:27:5 + | +LL | pub struct S3; + | ^^^^^^^^^^^^^ + +error: only functions with "C" ABI are exportable + --> $DIR/exportable.rs:33:5 + | +LL | pub fn foo1() {} + | ^^^^^^^^^^^^^ + +error: function with `#[export_stable]` attribute uses type `Box`, which is not exportable + --> $DIR/exportable.rs:44:5 + | +LL | pub extern "C" fn foo3(x: Box) -> i32 { 0 } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^------^^^^^^^^ + | | + | not exportable + +error: method with `#[export_stable]` attribute uses type `&impl_item::S`, which is not exportable + --> $DIR/exportable.rs:53:9 + | +LL | pub extern "C" fn foo1(&self) -> i32 { 0 } + | ^^^^^^^^^^^^^^^^^^^^^^^-----^^^^^^^^ + | | + | not exportable + +error: method with `#[export_stable]` attribute uses type `impl_item::S`, which is not exportable + --> $DIR/exportable.rs:57:9 + | +LL | pub extern "C" fn foo2(self) -> i32 { 0 } + | ^^^^^^^^^^^^^^^^^^^^^^^----^^^^^^^^ + | | + | not exportable + +error: generic functions are not exportable + --> $DIR/exportable.rs:65:9 + | +LL | pub extern "C" fn foo1(&self) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: function with `#[export_stable]` attribute uses type `(u32,)`, which is not exportable + --> $DIR/exportable.rs:81:5 + | +LL | pub extern "C" fn foo1(x: ::Type) -> u32 { x.0 } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^------------------^^^^^^^^ + | | + | not exportable + +error: function with `#[export_stable]` attribute uses type `[i32; 4]`, which is not exportable + --> $DIR/exportable.rs:88:5 + | +LL | pub extern "C" fn foo2(_x: Type) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^----^ + | | + | not exportable + +error: function with `#[export_stable]` attribute uses type `extern "C" fn()`, which is not exportable + --> $DIR/exportable.rs:97:5 + | +LL | pub extern "C" fn foo3(_x: S::Type) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^-------^ + | | + | not exportable + +error: function with `#[export_stable]` attribute uses type `impl Copy`, which is not exportable + --> $DIR/exportable.rs:101:5 + | +LL | pub extern "C" fn foo4() -> impl Copy { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^--------- + | | + | not exportable + +error: ADT types with private fields are not exportable + --> $DIR/exportable.rs:116:5 + | +LL | pub struct S2 { + | ^^^^^^^^^^^^^ + | +note: `x` is private + --> $DIR/exportable.rs:118:9 + | +LL | x: i32 + | ^^^^^^ + +error: aborting due to 16 previous errors + diff --git a/tests/ui/attributes/export/lang-item.rs b/tests/ui/attributes/export/lang-item.rs new file mode 100644 index 000000000000..b923b41a9575 --- /dev/null +++ b/tests/ui/attributes/export/lang-item.rs @@ -0,0 +1,8 @@ +#![feature(no_core, lang_items, export_stable)] +#![allow(incomplete_features)] +#![crate_type = "sdylib"] +#![no_core] + +#[lang = "sized"] +//~^ ERROR lang items are not allowed in stable dylibs +trait Sized {} diff --git a/tests/ui/attributes/export/lang-item.stderr b/tests/ui/attributes/export/lang-item.stderr new file mode 100644 index 000000000000..8c0741bdb6f2 --- /dev/null +++ b/tests/ui/attributes/export/lang-item.stderr @@ -0,0 +1,8 @@ +error: lang items are not allowed in stable dylibs + --> $DIR/lang-item.rs:6:1 + | +LL | #[lang = "sized"] + | ^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/auxiliary/issue-13560-1.rs b/tests/ui/attributes/no_link/auxiliary/empty-crate-1.rs similarity index 52% rename from tests/ui/auxiliary/issue-13560-1.rs rename to tests/ui/attributes/no_link/auxiliary/empty-crate-1.rs index baca1567e1b0..8bd2b3353b8f 100644 --- a/tests/ui/auxiliary/issue-13560-1.rs +++ b/tests/ui/attributes/no_link/auxiliary/empty-crate-1.rs @@ -1,3 +1 @@ -//@ no-prefer-dynamic - #![crate_type = "dylib"] diff --git a/tests/ui/auxiliary/issue-13560-2.rs b/tests/ui/attributes/no_link/auxiliary/empty-crate-2.rs similarity index 100% rename from tests/ui/auxiliary/issue-13560-2.rs rename to tests/ui/attributes/no_link/auxiliary/empty-crate-2.rs diff --git a/tests/ui/attributes/no_link/auxiliary/no_link-crate.rs b/tests/ui/attributes/no_link/auxiliary/no_link-crate.rs new file mode 100644 index 000000000000..1c3af5431cc6 --- /dev/null +++ b/tests/ui/attributes/no_link/auxiliary/no_link-crate.rs @@ -0,0 +1,6 @@ +//@ no-prefer-dynamic + +#![crate_type = "rlib"] + +#[macro_use] #[no_link] extern crate empty_crate_1 as t1; +#[macro_use] extern crate empty_crate_2 as t2; diff --git a/tests/ui/attributes/no_link/multiple-crates-and-no_link.rs b/tests/ui/attributes/no_link/multiple-crates-and-no_link.rs new file mode 100644 index 000000000000..0e6f1deb2172 --- /dev/null +++ b/tests/ui/attributes/no_link/multiple-crates-and-no_link.rs @@ -0,0 +1,17 @@ +//! Regression test for #13560. Previously, it was possible to +//! trigger an assert in crate numbering if a series of crates +//! being loaded included a "syntax-only" extern crate. +//! But it appears we don't mess with crate numbering for +//! `#[no_link]` crates anymore, so this test doesn't seem +//! to test anything now. + +//@ run-pass +//@ needs-crate-type: dylib +//@ aux-build:empty-crate-1.rs +//@ aux-build:empty-crate-2.rs +//@ aux-build:no_link-crate.rs + +extern crate empty_crate_2 as t2; +extern crate no_link_crate as t3; + +fn main() {} diff --git a/tests/ui/attributes/no_link/no-link-unknown-crate.rs b/tests/ui/attributes/no_link/no-link-unknown-crate.rs new file mode 100644 index 000000000000..3a91fa27ee3b --- /dev/null +++ b/tests/ui/attributes/no_link/no-link-unknown-crate.rs @@ -0,0 +1,19 @@ +//! Unfortunately the development of `#[phase]` and `#[no_link]` +//! predates Zulip, and thus has been lost in the sands of time. +//! Understanding the true nature of this test has been left as +//! an exercise for the reader. +//! +//! But we guess from the git history that originally this +//! test was supposed to check that we error if we can't find +//! an extern crate annotated with `#[phase(syntax)]`, +//! see `macro-crate-unknown-crate.rs` in +//! . Later, we changed +//! `#[phase]` to `#![feature(plugin)]` and added a `#[no_link]`. +//! +//! I suppose that this now tests that we still error if we can't +//! find a `#[no_link]` extern crate? + +#[no_link] +extern crate doesnt_exist; //~ ERROR can't find crate + +fn main() {} diff --git a/tests/ui/no-link-unknown-crate.stderr b/tests/ui/attributes/no_link/no-link-unknown-crate.stderr similarity index 85% rename from tests/ui/no-link-unknown-crate.stderr rename to tests/ui/attributes/no_link/no-link-unknown-crate.stderr index edc248db09ea..999b013866cd 100644 --- a/tests/ui/no-link-unknown-crate.stderr +++ b/tests/ui/attributes/no_link/no-link-unknown-crate.stderr @@ -1,5 +1,5 @@ error[E0463]: can't find crate for `doesnt_exist` - --> $DIR/no-link-unknown-crate.rs:2:1 + --> $DIR/no-link-unknown-crate.rs:17:1 | LL | extern crate doesnt_exist; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ can't find crate diff --git a/tests/ui/auxiliary/inner_static.rs b/tests/ui/auxiliary/inner_static.rs deleted file mode 100644 index 42dcd379d41e..000000000000 --- a/tests/ui/auxiliary/inner_static.rs +++ /dev/null @@ -1,51 +0,0 @@ -pub struct A { pub v: T } -pub struct B { pub v: T } - -pub mod test { - pub struct A { pub v: T } - - impl A { - pub fn foo(&self) -> isize { - static a: isize = 5; - return a - } - - pub fn bar(&self) -> isize { - static a: isize = 6; - return a; - } - } -} - -impl A { - pub fn foo(&self) -> isize { - static a: isize = 1; - return a - } - - pub fn bar(&self) -> isize { - static a: isize = 2; - return a; - } -} - -impl B { - pub fn foo(&self) -> isize { - static a: isize = 3; - return a - } - - pub fn bar(&self) -> isize { - static a: isize = 4; - return a; - } -} - -pub fn foo() -> isize { - let a = A { v: () }; - let b = B { v: () }; - let c = test::A { v: () }; - return a.foo() + a.bar() + - b.foo() + b.bar() + - c.foo() + c.bar(); -} diff --git a/tests/ui/auxiliary/issue-13560-3.rs b/tests/ui/auxiliary/issue-13560-3.rs deleted file mode 100644 index 4aab2ddc73a0..000000000000 --- a/tests/ui/auxiliary/issue-13560-3.rs +++ /dev/null @@ -1,6 +0,0 @@ -//@ no-prefer-dynamic - -#![crate_type = "rlib"] - -#[macro_use] #[no_link] extern crate issue_13560_1 as t1; -#[macro_use] extern crate issue_13560_2 as t2; diff --git a/tests/ui/bootstrap/rustc_bootstrap.rs b/tests/ui/bootstrap/rustc_bootstrap.rs index daa28e0cdf29..fb72bba95a15 100644 --- a/tests/ui/bootstrap/rustc_bootstrap.rs +++ b/tests/ui/bootstrap/rustc_bootstrap.rs @@ -38,10 +38,11 @@ // also affected by `RUSTC_BOOTSTRAP`. //@[force_stable] rustc-env:RUSTC_BOOTSTRAP=-1 //@[force_stable] compile-flags: -Z unstable-options -//@[force_stable] regex-error-pattern: error: the option `Z` is only accepted on the nightly compiler #![crate_type = "lib"] // Note: `rustc_attrs` is a perma-unstable internal feature that is unlikely to change, which is // used as a proxy to check `RUSTC_BOOTSTRAP` versus stability checking logic. #![feature(rustc_attrs)] + +//[force_stable]~? RAW the option `Z` is only accepted on the nightly compiler diff --git a/tests/ui/cast/cast-alias-of-array-to-element.rs b/tests/ui/cast/cast-alias-of-array-to-element.rs new file mode 100644 index 000000000000..124d0e0346f0 --- /dev/null +++ b/tests/ui/cast/cast-alias-of-array-to-element.rs @@ -0,0 +1,22 @@ +//@ check-pass +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver + +// Regression test for . +// Test that we structually normalize in the hacky `&[T; N] -> *const T` in cast. + +trait Mirror { + type Assoc: ?Sized; +} +impl Mirror for T { + type Assoc = T; +} + +struct W<'a>(&'a <[f32; 0] as Mirror>::Assoc); + +fn foo(x: W<'_>) -> *const f32 { + x.0 as *const f32 +} + +fn main() {} diff --git a/tests/ui/cfg/cfg_false_no_std-2.rs b/tests/ui/cfg/cfg_false_no_std-2.rs index 18b2c699fd7a..666c90deaf0f 100644 --- a/tests/ui/cfg/cfg_false_no_std-2.rs +++ b/tests/ui/cfg/cfg_false_no_std-2.rs @@ -1,7 +1,11 @@ // Error, the linked empty library is `no_std` and doesn't provide a panic handler. -//@ dont-require-annotations: ERROR //@ dont-check-compiler-stderr + +// NOTE: fix a panic strategy to prevent differing errors subject to target's default panic strategy +// which changes between targets. The specific panic strategy doesn't matter for test intention. +//@ compile-flags: -Cpanic=abort + //@ aux-build: cfg_false_lib_no_std_before.rs #![no_std] @@ -11,6 +15,3 @@ extern crate cfg_false_lib_no_std_before as _; fn main() {} //~? ERROR `#[panic_handler]` function required, but not found -// FIXME: This error is target-dependent, could be served by some "optional error" annotation -// instead of `dont-require-annotations`. -//FIXME~? ERROR unwinding panics are not supported without std diff --git a/tests/ui/check-cfg/and-more-diagnostic.rs b/tests/ui/check-cfg/and-more-diagnostic.rs index 977f55e8a6d1..5422829c5b31 100644 --- a/tests/ui/check-cfg/and-more-diagnostic.rs +++ b/tests/ui/check-cfg/and-more-diagnostic.rs @@ -5,7 +5,7 @@ //@ no-auto-check-cfg //@ compile-flags: --check-cfg=cfg() //@ normalize-stderr: "and \d+ more" -> "and X more" -//@ normalize-stderr: "`[a-zA-Z0-9_-]+`" -> "`xxx`" +//@ normalize-stderr: "`[a-zA-Z0-9_\.-]+`" -> "`xxx`" fn main() { cfg!(target_feature = "zebra"); diff --git a/tests/ui/check-cfg/target_feature.stderr b/tests/ui/check-cfg/target_feature.stderr index 4f7b8345e86a..eb66633f9dd7 100644 --- a/tests/ui/check-cfg/target_feature.stderr +++ b/tests/ui/check-cfg/target_feature.stderr @@ -27,8 +27,11 @@ LL | cfg!(target_feature = "_UNEXPECTED_VALUE"); `amx-tf32` `amx-tile` `amx-transpose` +`apxf` `atomics` `avx` +`avx10.1` +`avx10.2` `avx2` `avx512bf16` `avx512bitalg` @@ -324,12 +327,20 @@ LL | cfg!(target_feature = "_UNEXPECTED_VALUE"); `zcmop` `zdinx` `zfa` +`zfbfmin` `zfh` `zfhmin` `zfinx` `zhinx` `zhinxmin` +`zic64b` +`zicbom` +`zicbop` `zicboz` +`ziccamoa` +`ziccif` +`zicclsm` +`ziccrse` `zicntr` `zicond` `zicsr` @@ -356,6 +367,8 @@ LL | cfg!(target_feature = "_UNEXPECTED_VALUE"); `zve64d` `zve64f` `zve64x` +`zvfbfmin` +`zvfbfwma` `zvfh` `zvfhmin` `zvkb` diff --git a/tests/ui/closures/opaque-upvar.rs b/tests/ui/closures/opaque-upvar.rs new file mode 100644 index 000000000000..90e7c9ccb465 --- /dev/null +++ b/tests/ui/closures/opaque-upvar.rs @@ -0,0 +1,19 @@ +//@ check-pass +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver + +// Regression test for . +// This is only an issue in the new solver, but I'm testing it in both solvers for now. +// This has to do with the fact that the recursive `walk_dir` is a revealing use, which has not +// yet been constrained from the defining use by the time that closure signature inference is +// performed. We don't really care, though, since anywhere we structurally match on a type in +// upvar analysis, we already call `structurally_resolve_type` right before `.kind()`. + +fn walk_dir(cb: &()) -> impl Sized { + || { + let fut = walk_dir(cb); + }; +} + +fn main() {} diff --git a/tests/ui/closures/print/closure-print-generic-trim-off-verbose-2.stderr b/tests/ui/closures/print/closure-print-generic-trim-off-verbose-2.stderr index b71cfc503339..bcf5759a194f 100644 --- a/tests/ui/closures/print/closure-print-generic-trim-off-verbose-2.stderr +++ b/tests/ui/closures/print/closure-print-generic-trim-off-verbose-2.stderr @@ -9,7 +9,7 @@ LL | let c1 : () = c; | expected due to this | = note: expected unit type `()` - found closure `{mod1::f::{closure#0} closure_kind_ty=?8t closure_sig_as_fn_ptr_ty=extern "rust-call" fn(()) upvar_tys=?7t}` + found closure `{mod1::f::{closure#0} closure_kind_ty=?7t closure_sig_as_fn_ptr_ty=extern "rust-call" fn(()) upvar_tys=?6t}` help: use parentheses to call this closure | LL | let c1 : () = c(); diff --git a/tests/ui/closures/print/closure-print-generic-verbose-2.stderr b/tests/ui/closures/print/closure-print-generic-verbose-2.stderr index 88f4dc9b92ab..a8d2b07a00dc 100644 --- a/tests/ui/closures/print/closure-print-generic-verbose-2.stderr +++ b/tests/ui/closures/print/closure-print-generic-verbose-2.stderr @@ -9,7 +9,7 @@ LL | let c1 : () = c; | expected due to this | = note: expected unit type `()` - found closure `{f::{closure#0} closure_kind_ty=?8t closure_sig_as_fn_ptr_ty=extern "rust-call" fn(()) upvar_tys=?7t}` + found closure `{f::{closure#0} closure_kind_ty=?7t closure_sig_as_fn_ptr_ty=extern "rust-call" fn(()) upvar_tys=?6t}` help: use parentheses to call this closure | LL | let c1 : () = c(); diff --git a/tests/ui/codegen/equal-pointers-unequal/as-cast/basic.rs b/tests/ui/codegen/equal-pointers-unequal/as-cast/basic.rs deleted file mode 100644 index e2a00ce173d1..000000000000 --- a/tests/ui/codegen/equal-pointers-unequal/as-cast/basic.rs +++ /dev/null @@ -1,21 +0,0 @@ -//@ known-bug: #107975 -//@ compile-flags: -Copt-level=2 -//@ run-pass - -fn main() { - let a: usize = { - let v = 0u8; - &v as *const _ as usize - }; - let b: usize = { - let v = 0u8; - &v as *const _ as usize - }; - - // `a` and `b` are not equal. - assert_ne!(a, b); - // But they are the same number. - assert_eq!(format!("{a}"), format!("{b}")); - // And they are equal. - assert_eq!(a, b); -} diff --git a/tests/ui/codegen/equal-pointers-unequal/as-cast/function.rs b/tests/ui/codegen/equal-pointers-unequal/as-cast/function.rs deleted file mode 100644 index 15434de50f76..000000000000 --- a/tests/ui/codegen/equal-pointers-unequal/as-cast/function.rs +++ /dev/null @@ -1,22 +0,0 @@ -//@ known-bug: #107975 -//@ compile-flags: -Copt-level=2 -//@ run-pass - -// Based on https://github.com/rust-lang/rust/issues/107975#issuecomment-1434203908 - -fn f() -> usize { - let v = 0; - &v as *const _ as usize -} - -fn main() { - let a = f(); - let b = f(); - - // `a` and `b` are not equal. - assert_ne!(a, b); - // But they are the same number. - assert_eq!(format!("{a}"), format!("{b}")); - // And they are equal. - assert_eq!(a, b); -} diff --git a/tests/ui/codegen/equal-pointers-unequal/as-cast/print.rs b/tests/ui/codegen/equal-pointers-unequal/as-cast/print.rs deleted file mode 100644 index f33a9e511b61..000000000000 --- a/tests/ui/codegen/equal-pointers-unequal/as-cast/print.rs +++ /dev/null @@ -1,20 +0,0 @@ -//@ known-bug: #107975 -//@ compile-flags: -Copt-level=2 -//@ run-pass - -// https://github.com/rust-lang/rust/issues/107975#issuecomment-1430704499 - -fn main() { - let a = { - let v = 0; - &v as *const _ as usize - }; - let b = { - let v = 0; - &v as *const _ as usize - }; - - assert_ne!(a, b); - println!("{a}"); // or b - assert_eq!(a, b); -} diff --git a/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/basic.rs b/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/basic.rs deleted file mode 100644 index b2b4934aa5f1..000000000000 --- a/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/basic.rs +++ /dev/null @@ -1,23 +0,0 @@ -//@ known-bug: #107975 -//@ compile-flags: -Copt-level=2 -//@ run-pass - -use std::ptr; - -fn main() { - let a: usize = { - let v = 0u8; - ptr::from_ref(&v).expose_provenance() - }; - let b: usize = { - let v = 0u8; - ptr::from_ref(&v).expose_provenance() - }; - - // `a` and `b` are not equal. - assert_ne!(a, b); - // But they are the same number. - assert_eq!(format!("{a}"), format!("{b}")); - // And they are equal. - assert_eq!(a, b); -} diff --git a/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/function.rs b/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/function.rs deleted file mode 100644 index bf130c9f7598..000000000000 --- a/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/function.rs +++ /dev/null @@ -1,24 +0,0 @@ -//@ known-bug: #107975 -//@ compile-flags: -Copt-level=2 -//@ run-pass - -// Based on https://github.com/rust-lang/rust/issues/107975#issuecomment-1434203908 - -use std::ptr; - -fn f() -> usize { - let v = 0; - ptr::from_ref(&v).expose_provenance() -} - -fn main() { - let a = f(); - let b = f(); - - // `a` and `b` are not equal. - assert_ne!(a, b); - // But they are the same number. - assert_eq!(format!("{a}"), format!("{b}")); - // And they are equal. - assert_eq!(a, b); -} diff --git a/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/print.rs b/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/print.rs deleted file mode 100644 index 0baf8886395e..000000000000 --- a/tests/ui/codegen/equal-pointers-unequal/exposed-provenance/print.rs +++ /dev/null @@ -1,22 +0,0 @@ -//@ known-bug: #107975 -//@ compile-flags: -Copt-level=2 -//@ run-pass - -// https://github.com/rust-lang/rust/issues/107975#issuecomment-1430704499 - -use std::ptr; - -fn main() { - let a: usize = { - let v = 0; - ptr::from_ref(&v).expose_provenance() - }; - let b: usize = { - let v = 0; - ptr::from_ref(&v).expose_provenance() - }; - - assert_ne!(a, b); - println!("{a}"); // or b - assert_eq!(a, b); -} diff --git a/tests/ui/codegen/equal-pointers-unequal/strict-provenance/basic.rs b/tests/ui/codegen/equal-pointers-unequal/strict-provenance/basic.rs deleted file mode 100644 index 4602ec654d10..000000000000 --- a/tests/ui/codegen/equal-pointers-unequal/strict-provenance/basic.rs +++ /dev/null @@ -1,23 +0,0 @@ -//@ known-bug: #107975 -//@ compile-flags: -Copt-level=2 -//@ run-pass - -use std::ptr; - -fn main() { - let a: usize = { - let v = 0u8; - ptr::from_ref(&v).addr() - }; - let b: usize = { - let v = 0u8; - ptr::from_ref(&v).addr() - }; - - // `a` and `b` are not equal. - assert_ne!(a, b); - // But they are the same number. - assert_eq!(format!("{a}"), format!("{b}")); - // And they are equal. - assert_eq!(a, b); -} diff --git a/tests/ui/codegen/equal-pointers-unequal/strict-provenance/function.rs b/tests/ui/codegen/equal-pointers-unequal/strict-provenance/function.rs deleted file mode 100644 index 789a78c15b4e..000000000000 --- a/tests/ui/codegen/equal-pointers-unequal/strict-provenance/function.rs +++ /dev/null @@ -1,24 +0,0 @@ -//@ known-bug: #107975 -//@ compile-flags: -Copt-level=2 -//@ run-pass - -// Based on https://github.com/rust-lang/rust/issues/107975#issuecomment-1434203908 - -use std::ptr; - -fn f() -> usize { - let v = 0; - ptr::from_ref(&v).addr() -} - -fn main() { - let a = f(); - let b = f(); - - // `a` and `b` are not equal. - assert_ne!(a, b); - // But they are the same number. - assert_eq!(format!("{a}"), format!("{b}")); - // And they are equal. - assert_eq!(a, b); -} diff --git a/tests/ui/codegen/equal-pointers-unequal/strict-provenance/print.rs b/tests/ui/codegen/equal-pointers-unequal/strict-provenance/print.rs deleted file mode 100644 index b7165ce1e5ce..000000000000 --- a/tests/ui/codegen/equal-pointers-unequal/strict-provenance/print.rs +++ /dev/null @@ -1,22 +0,0 @@ -//@ known-bug: #107975 -//@ compile-flags: -Copt-level=2 -//@ run-pass - -// https://github.com/rust-lang/rust/issues/107975#issuecomment-1430704499 - -use std::ptr; - -fn main() { - let a: usize = { - let v = 0; - ptr::from_ref(&v).addr() - }; - let b: usize = { - let v = 0; - ptr::from_ref(&v).addr() - }; - - assert_ne!(a, b); - println!("{a}"); // or b - assert_eq!(a, b); -} diff --git a/tests/ui/compiletest-self-test/compile-flags-last.rs b/tests/ui/compiletest-self-test/compile-flags-last.rs index b78a64394b87..e0743d2aea58 100644 --- a/tests/ui/compiletest-self-test/compile-flags-last.rs +++ b/tests/ui/compiletest-self-test/compile-flags-last.rs @@ -4,4 +4,5 @@ // next flag as the argument of this flag. // //@ compile-flags: --cap-lints -//@ error-pattern: Argument to option 'cap-lints' missing + +//~? RAW Argument to option 'cap-lints' missing diff --git a/tests/ui/conditional-compilation/cfg-arg-invalid-7.rs b/tests/ui/conditional-compilation/cfg-arg-invalid-7.rs index b4344f1bca5c..f05adc7bf7aa 100644 --- a/tests/ui/conditional-compilation/cfg-arg-invalid-7.rs +++ b/tests/ui/conditional-compilation/cfg-arg-invalid-7.rs @@ -1,5 +1,6 @@ // Regression test for issue #89358. //@ compile-flags: --cfg a" -//@ error-pattern: unterminated double quote string -//@ error-pattern: this error occurred on the command line + +//~? RAW unterminated double quote string +//~? RAW this error occurred on the command line diff --git a/tests/ui/const-generics/const-arg-in-const-arg.min.stderr b/tests/ui/const-generics/const-arg-in-const-arg.min.stderr index 06a6a5f59d6d..16512cb69e23 100644 --- a/tests/ui/const-generics/const-arg-in-const-arg.min.stderr +++ b/tests/ui/const-generics/const-arg-in-const-arg.min.stderr @@ -240,41 +240,6 @@ note: the late bound lifetime parameter is introduced here LL | const fn faz<'a>(_: &'a ()) -> usize { 13 } | ^^ -error[E0747]: unresolved item provided when a constant was expected - --> $DIR/const-arg-in-const-arg.rs:36:24 - | -LL | let _: Foo<{ bar::() }>; - | ^ - | -help: if this generic argument was intended as a const parameter, surround it with braces - | -LL | let _: Foo<{ bar::<{ N }>() }>; - | + + - -error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present - --> $DIR/const-arg-in-const-arg.rs:38:24 - | -LL | let _: Foo<{ faz::<'a>(&()) }>; - | ^^ - | -note: the late bound lifetime parameter is introduced here - --> $DIR/const-arg-in-const-arg.rs:10:14 - | -LL | const fn faz<'a>(_: &'a ()) -> usize { 13 } - | ^^ - -error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present - --> $DIR/const-arg-in-const-arg.rs:41:24 - | -LL | let _: Foo<{ faz::<'b>(&()) }>; - | ^^ - | -note: the late bound lifetime parameter is introduced here - --> $DIR/const-arg-in-const-arg.rs:10:14 - | -LL | const fn faz<'a>(_: &'a ()) -> usize { 13 } - | ^^ - error: constant expression depends on a generic parameter --> $DIR/const-arg-in-const-arg.rs:25:17 | @@ -326,6 +291,41 @@ note: the late bound lifetime parameter is introduced here LL | const fn faz<'a>(_: &'a ()) -> usize { 13 } | ^^ +error[E0747]: unresolved item provided when a constant was expected + --> $DIR/const-arg-in-const-arg.rs:36:24 + | +LL | let _: Foo<{ bar::() }>; + | ^ + | +help: if this generic argument was intended as a const parameter, surround it with braces + | +LL | let _: Foo<{ bar::<{ N }>() }>; + | + + + +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present + --> $DIR/const-arg-in-const-arg.rs:38:24 + | +LL | let _: Foo<{ faz::<'a>(&()) }>; + | ^^ + | +note: the late bound lifetime parameter is introduced here + --> $DIR/const-arg-in-const-arg.rs:10:14 + | +LL | const fn faz<'a>(_: &'a ()) -> usize { 13 } + | ^^ + +error[E0794]: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present + --> $DIR/const-arg-in-const-arg.rs:41:24 + | +LL | let _: Foo<{ faz::<'b>(&()) }>; + | ^^ + | +note: the late bound lifetime parameter is introduced here + --> $DIR/const-arg-in-const-arg.rs:10:14 + | +LL | const fn faz<'a>(_: &'a ()) -> usize { 13 } + | ^^ + error[E0747]: unresolved item provided when a constant was expected --> $DIR/const-arg-in-const-arg.rs:45:27 | diff --git a/tests/ui/const-generics/generic_const_exprs/cross_crate_predicate.stderr b/tests/ui/const-generics/generic_const_exprs/cross_crate_predicate.stderr index a05aaf2af649..1aac357d60e4 100644 --- a/tests/ui/const-generics/generic_const_exprs/cross_crate_predicate.stderr +++ b/tests/ui/const-generics/generic_const_exprs/cross_crate_predicate.stderr @@ -39,14 +39,6 @@ error: unconstrained generic constant LL | let _ = const_evaluatable_lib::test1::(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: required by a bound in `test1` - --> $DIR/auxiliary/const_evaluatable_lib.rs:5:10 - | -LL | pub fn test1() -> [u8; std::mem::size_of::() - 1] - | ----- required by a bound in this function -LL | where -LL | [u8; std::mem::size_of::() - 1]: Sized, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `test1` help: try adding a `where` bound | LL | fn user() where [(); std::mem::size_of::() - 1]: { @@ -59,10 +51,13 @@ LL | let _ = const_evaluatable_lib::test1::(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: required by a bound in `test1` - --> $DIR/auxiliary/const_evaluatable_lib.rs:3:27 + --> $DIR/auxiliary/const_evaluatable_lib.rs:5:10 | LL | pub fn test1() -> [u8; std::mem::size_of::() - 1] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `test1` + | ----- required by a bound in this function +LL | where +LL | [u8; std::mem::size_of::() - 1]: Sized, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `test1` help: try adding a `where` bound | LL | fn user() where [(); std::mem::size_of::() - 1]: { diff --git a/tests/ui/const-generics/generic_const_exprs/dependence_lint.gce.stderr b/tests/ui/const-generics/generic_const_exprs/dependence_lint.gce.stderr index 7e318f8786f3..f6119c17bf47 100644 --- a/tests/ui/const-generics/generic_const_exprs/dependence_lint.gce.stderr +++ b/tests/ui/const-generics/generic_const_exprs/dependence_lint.gce.stderr @@ -1,22 +1,3 @@ -error: overly complex generic constant - --> $DIR/dependence_lint.rs:21:17 - | -LL | let _: [u8; if true { size_of::() } else { 3 }]; // error on stable, error with gce - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ control flow is not supported in generic constants - | - = help: consider moving this anonymous constant into a `const` function - -error: unconstrained generic constant - --> $DIR/dependence_lint.rs:14:12 - | -LL | let _: [u8; size_of::<*mut T>()]; // error on stable, error with gce - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: try adding a `where` bound - | -LL | fn foo() where [(); size_of::<*mut T>()]: { - | ++++++++++++++++++++++++++++++++ - error: unconstrained generic constant --> $DIR/dependence_lint.rs:10:9 | @@ -36,5 +17,24 @@ LL | [0; if false { size_of::() } else { 3 }]; // lint on stable, error w | = help: consider moving this anonymous constant into a `const` function +error: unconstrained generic constant + --> $DIR/dependence_lint.rs:14:12 + | +LL | let _: [u8; size_of::<*mut T>()]; // error on stable, error with gce + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: try adding a `where` bound + | +LL | fn foo() where [(); size_of::<*mut T>()]: { + | ++++++++++++++++++++++++++++++++ + +error: overly complex generic constant + --> $DIR/dependence_lint.rs:21:17 + | +LL | let _: [u8; if true { size_of::() } else { 3 }]; // error on stable, error with gce + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ control flow is not supported in generic constants + | + = help: consider moving this anonymous constant into a `const` function + error: aborting due to 4 previous errors diff --git a/tests/ui/const-generics/invalid-enum.stderr b/tests/ui/const-generics/invalid-enum.stderr index 7e8a632b34f7..f588ff0bc8eb 100644 --- a/tests/ui/const-generics/invalid-enum.stderr +++ b/tests/ui/const-generics/invalid-enum.stderr @@ -25,28 +25,6 @@ LL | let _: Example = Example { x: 0 }; | not a type | help: try using the variant's enum: `CompileFlag` -error[E0747]: unresolved item provided when a constant was expected - --> $DIR/invalid-enum.rs:31:18 - | -LL | let _: Example = Example { x: 0 }; - | ^^^^^^^^^^^^^^ - | -help: if this generic argument was intended as a const parameter, surround it with braces - | -LL | let _: Example<{ CompileFlag::A }, _> = Example { x: 0 }; - | + + - -error[E0747]: type provided when a constant was expected - --> $DIR/invalid-enum.rs:35:18 - | -LL | let _: Example = Example { x: 0 }; - | ^^^^^^^^^^^^^^^^^^^ - | -help: if this generic argument was intended as a const parameter, surround it with braces - | -LL | let _: Example<{ Example::ASSOC_FLAG }, _> = Example { x: 0 }; - | + + - error[E0747]: unresolved item provided when a constant was expected --> $DIR/invalid-enum.rs:23:12 | @@ -69,6 +47,28 @@ help: if this generic argument was intended as a const parameter, surround it wi LL | test_2::<_, { CompileFlag::A }>(0); | + + +error[E0747]: unresolved item provided when a constant was expected + --> $DIR/invalid-enum.rs:31:18 + | +LL | let _: Example = Example { x: 0 }; + | ^^^^^^^^^^^^^^ + | +help: if this generic argument was intended as a const parameter, surround it with braces + | +LL | let _: Example<{ CompileFlag::A }, _> = Example { x: 0 }; + | + + + +error[E0747]: type provided when a constant was expected + --> $DIR/invalid-enum.rs:35:18 + | +LL | let _: Example = Example { x: 0 }; + | ^^^^^^^^^^^^^^^^^^^ + | +help: if this generic argument was intended as a const parameter, surround it with braces + | +LL | let _: Example<{ Example::ASSOC_FLAG }, _> = Example { x: 0 }; + | + + + error: aborting due to 7 previous errors Some errors have detailed explanations: E0573, E0747. diff --git a/tests/ui/const-ptr/forbidden_slices.stderr b/tests/ui/const-ptr/forbidden_slices.stderr index 6f2da272ad3f..c73d2ca938cb 100644 --- a/tests/ui/const-ptr/forbidden_slices.stderr +++ b/tests/ui/const-ptr/forbidden_slices.stderr @@ -114,7 +114,7 @@ error[E0080]: could not evaluate static initializer --> $DIR/forbidden_slices.rs:54:25 | LL | from_ptr_range(ptr..ptr.add(2)) // errors inside libcore - | ^^^^^^^^^^ out-of-bounds pointer arithmetic: expected a pointer to 8 bytes of memory, but got ALLOC10 which is only 4 bytes from the end of the allocation + | ^^^^^^^^^^ in-bounds pointer arithmetic failed: attempting to offset pointer by 8 bytes, but got ALLOC10 which is only 4 bytes from the end of the allocation | note: inside `std::ptr::const_ptr::::add` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL @@ -169,7 +169,7 @@ error[E0080]: could not evaluate static initializer --> $DIR/forbidden_slices.rs:79:25 | LL | from_ptr_range(ptr..ptr.add(1)) - | ^^^^^^^^^^ out-of-bounds pointer arithmetic: expected a pointer to 8 bytes of memory, but got ALLOC11+0x1 which is only 7 bytes from the end of the allocation + | ^^^^^^^^^^ in-bounds pointer arithmetic failed: attempting to offset pointer by 8 bytes, but got ALLOC11+0x1 which is only 7 bytes from the end of the allocation | note: inside `std::ptr::const_ptr::::add` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL diff --git a/tests/ui/const-ptr/out_of_bounds_read.stderr b/tests/ui/const-ptr/out_of_bounds_read.stderr index b396fc4d71bc..1d625a26b78c 100644 --- a/tests/ui/const-ptr/out_of_bounds_read.stderr +++ b/tests/ui/const-ptr/out_of_bounds_read.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/out_of_bounds_read.rs:8:33 | LL | const _READ: u32 = unsafe { ptr::read(PAST_END_PTR) }; - | ^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got ALLOC0+0x4 which is at or beyond the end of the allocation of size 4 bytes + | ^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: attempting to access 4 bytes, but got ALLOC0+0x4 which is at or beyond the end of the allocation of size 4 bytes | note: inside `std::ptr::read::` --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL @@ -11,7 +11,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/out_of_bounds_read.rs:10:39 | LL | const _CONST_READ: u32 = unsafe { PAST_END_PTR.read() }; - | ^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got ALLOC0+0x4 which is at or beyond the end of the allocation of size 4 bytes + | ^^^^^^^^^^^^^^^^^^^ memory access failed: attempting to access 4 bytes, but got ALLOC0+0x4 which is at or beyond the end of the allocation of size 4 bytes | note: inside `std::ptr::const_ptr::::read` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL @@ -22,7 +22,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/out_of_bounds_read.rs:12:37 | LL | const _MUT_READ: u32 = unsafe { (PAST_END_PTR as *mut u32).read() }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got ALLOC0+0x4 which is at or beyond the end of the allocation of size 4 bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: attempting to access 4 bytes, but got ALLOC0+0x4 which is at or beyond the end of the allocation of size 4 bytes | note: inside `std::ptr::mut_ptr::::read` --> $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL diff --git a/tests/ui/consts/const-compare-bytes-ub.stderr b/tests/ui/consts/const-compare-bytes-ub.stderr index 9ef5c8ad43a1..0e77310c6bab 100644 --- a/tests/ui/consts/const-compare-bytes-ub.stderr +++ b/tests/ui/consts/const-compare-bytes-ub.stderr @@ -2,31 +2,31 @@ error[E0080]: evaluation of constant value failed --> $DIR/const-compare-bytes-ub.rs:9:9 | LL | compare_bytes(0 as *const u8, 2 as *const u8, 1) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 1 byte of memory, but got a null pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: attempting to access 1 byte, but got null pointer error[E0080]: evaluation of constant value failed --> $DIR/const-compare-bytes-ub.rs:13:9 | LL | compare_bytes(1 as *const u8, 0 as *const u8, 1) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 1 byte of memory, but got 0x1[noalloc] which is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: attempting to access 1 byte, but got 0x1[noalloc] which is a dangling pointer (it has no provenance) error[E0080]: evaluation of constant value failed --> $DIR/const-compare-bytes-ub.rs:17:9 | LL | compare_bytes(1 as *const u8, 2 as *const u8, 1) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 1 byte of memory, but got 0x1[noalloc] which is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: attempting to access 1 byte, but got 0x1[noalloc] which is a dangling pointer (it has no provenance) error[E0080]: evaluation of constant value failed --> $DIR/const-compare-bytes-ub.rs:21:9 | LL | compare_bytes([1, 2, 3].as_ptr(), [1, 2, 3, 4].as_ptr(), 4) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got ALLOC0 which is only 3 bytes from the end of the allocation + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: attempting to access 4 bytes, but got ALLOC0 which is only 3 bytes from the end of the allocation error[E0080]: evaluation of constant value failed --> $DIR/const-compare-bytes-ub.rs:25:9 | LL | compare_bytes([1, 2, 3, 4].as_ptr(), [1, 2, 3].as_ptr(), 4) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got ALLOC1 which is only 3 bytes from the end of the allocation + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: attempting to access 4 bytes, but got ALLOC1 which is only 3 bytes from the end of the allocation error[E0080]: evaluation of constant value failed --> $DIR/const-compare-bytes-ub.rs:29:9 diff --git a/tests/ui/consts/const-deref-ptr.stderr b/tests/ui/consts/const-deref-ptr.stderr index 070685e0b9d9..37502864947a 100644 --- a/tests/ui/consts/const-deref-ptr.stderr +++ b/tests/ui/consts/const-deref-ptr.stderr @@ -2,7 +2,7 @@ error[E0080]: could not evaluate static initializer --> $DIR/const-deref-ptr.rs:4:29 | LL | static C: u64 = unsafe {*(0xdeadbeef as *const u64)}; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 8 bytes of memory, but got 0xdeadbeef[noalloc] which is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: attempting to access 8 bytes, but got 0xdeadbeef[noalloc] which is a dangling pointer (it has no provenance) error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-eval/const_raw_ptr_ops2.rs b/tests/ui/consts/const-eval/const_raw_ptr_ops2.rs index ca96cfd9d193..0e88aa80c797 100644 --- a/tests/ui/consts/const-eval/const_raw_ptr_ops2.rs +++ b/tests/ui/consts/const-eval/const_raw_ptr_ops2.rs @@ -5,6 +5,6 @@ const Z: i32 = unsafe { *(&1 as *const i32) }; // bad, will thus error in miri const Z2: i32 = unsafe { *(42 as *const i32) }; //~ ERROR evaluation of constant value failed -//~| NOTE is a dangling pointer +//~| NOTE dangling pointer const Z3: i32 = unsafe { *(44 as *const i32) }; //~ ERROR evaluation of constant value failed -//~| NOTE is a dangling pointer +//~| NOTE dangling pointer diff --git a/tests/ui/consts/const-eval/const_raw_ptr_ops2.stderr b/tests/ui/consts/const-eval/const_raw_ptr_ops2.stderr index b0c864652e55..a8a5560ccb9c 100644 --- a/tests/ui/consts/const-eval/const_raw_ptr_ops2.stderr +++ b/tests/ui/consts/const-eval/const_raw_ptr_ops2.stderr @@ -2,13 +2,13 @@ error[E0080]: evaluation of constant value failed --> $DIR/const_raw_ptr_ops2.rs:7:26 | LL | const Z2: i32 = unsafe { *(42 as *const i32) }; - | ^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got 0x2a[noalloc] which is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^ memory access failed: attempting to access 4 bytes, but got 0x2a[noalloc] which is a dangling pointer (it has no provenance) error[E0080]: evaluation of constant value failed --> $DIR/const_raw_ptr_ops2.rs:9:26 | LL | const Z3: i32 = unsafe { *(44 as *const i32) }; - | ^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got 0x2c[noalloc] which is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^ memory access failed: attempting to access 4 bytes, but got 0x2c[noalloc] which is a dangling pointer (it has no provenance) error: aborting due to 2 previous errors diff --git a/tests/ui/consts/const-eval/format.stderr b/tests/ui/consts/const-eval/format.stderr index 4c4cbb372a7f..2f202705b7f9 100644 --- a/tests/ui/consts/const-eval/format.stderr +++ b/tests/ui/consts/const-eval/format.stderr @@ -1,16 +1,16 @@ error[E0015]: cannot call non-const formatting macro in constant functions - --> $DIR/format.rs:2:13 + --> $DIR/format.rs:2:5 | LL | panic!("{:?}", 0); - | ^^^^ + | ^^^^^^^^^^^^^^^^^ | = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants error[E0015]: cannot call non-const formatting macro in constant functions - --> $DIR/format.rs:7:15 + --> $DIR/format.rs:7:5 | LL | println!("{:?}", 0); - | ^^^^ + | ^^^^^^^^^^^^^^^^^^^ | = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants = 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/consts/const-eval/nonnull_as_ref_ub.stderr b/tests/ui/consts/const-eval/nonnull_as_ref_ub.stderr index bd6dafb93665..1996cd2721ec 100644 --- a/tests/ui/consts/const-eval/nonnull_as_ref_ub.stderr +++ b/tests/ui/consts/const-eval/nonnull_as_ref_ub.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/nonnull_as_ref_ub.rs:4:29 | LL | const _: () = assert!(42 == *unsafe { NON_NULL.as_ref() }); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 1 byte of memory, but got 0x1[noalloc] which is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: attempting to access 1 byte, but got 0x1[noalloc] which is a dangling pointer (it has no provenance) error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-eval/raw-pointer-ub.rs b/tests/ui/consts/const-eval/raw-pointer-ub.rs index 478e93a910e0..13a95f9b78f9 100644 --- a/tests/ui/consts/const-eval/raw-pointer-ub.rs +++ b/tests/ui/consts/const-eval/raw-pointer-ub.rs @@ -39,7 +39,7 @@ const OOB: () = unsafe { let mem = [0u32; 1]; let ptr = mem.as_ptr().cast::(); let _val = *ptr; //~ERROR: evaluation of constant value failed - //~^NOTE: expected a pointer to 8 bytes of memory + //~^NOTE: is only 4 bytes from the end of the allocation }; fn main() {} diff --git a/tests/ui/consts/const-eval/raw-pointer-ub.stderr b/tests/ui/consts/const-eval/raw-pointer-ub.stderr index 4fff293b2eef..ed5793c84c57 100644 --- a/tests/ui/consts/const-eval/raw-pointer-ub.stderr +++ b/tests/ui/consts/const-eval/raw-pointer-ub.stderr @@ -31,7 +31,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/raw-pointer-ub.rs:41:16 | LL | let _val = *ptr; - | ^^^^ memory access failed: expected a pointer to 8 bytes of memory, but got ALLOC0 which is only 4 bytes from the end of the allocation + | ^^^^ memory access failed: attempting to access 8 bytes, but got ALLOC0 which is only 4 bytes from the end of the allocation error: aborting due to 5 previous errors diff --git a/tests/ui/consts/const-eval/ub-nonnull.stderr b/tests/ui/consts/const-eval/ub-nonnull.stderr index c2cafbf60bcd..75dd0443ca4e 100644 --- a/tests/ui/consts/const-eval/ub-nonnull.stderr +++ b/tests/ui/consts/const-eval/ub-nonnull.stderr @@ -13,7 +13,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/ub-nonnull.rs:22:29 | LL | let out_of_bounds_ptr = &ptr[255]; - | ^^^^^^^^^ out-of-bounds pointer arithmetic: expected a pointer to 255 bytes of memory, but got ALLOC1 which is only 1 byte from the end of the allocation + | ^^^^^^^^^ in-bounds pointer arithmetic failed: attempting to offset pointer by 255 bytes, but got ALLOC1 which is only 1 byte from the end of the allocation error[E0080]: it is undefined behavior to use this value --> $DIR/ub-nonnull.rs:26:1 diff --git a/tests/ui/consts/const_in_pattern/reject_non_structural.rs b/tests/ui/consts/const_in_pattern/reject_non_structural.rs index 6478bf9c6ee1..39e5f732a898 100644 --- a/tests/ui/consts/const_in_pattern/reject_non_structural.rs +++ b/tests/ui/consts/const_in_pattern/reject_non_structural.rs @@ -93,7 +93,6 @@ fn main() { //~| NOTE constant of non-structural type trait Trait: Sized { const ASSOC: Option; } //~ NOTE constant defined here - //~^ NOTE impl Trait for NoDerive { const ASSOC: Option = Some(NoDerive); } match Some(NoDerive) { NoDerive::ASSOC => dbg!(NoDerive::ASSOC), _ => panic!("whoops"), }; //~^ ERROR constant of non-structural type `NoDerive` in a pattern diff --git a/tests/ui/consts/const_in_pattern/reject_non_structural.stderr b/tests/ui/consts/const_in_pattern/reject_non_structural.stderr index bf54d3d76aed..fa16d0b06a7f 100644 --- a/tests/ui/consts/const_in_pattern/reject_non_structural.stderr +++ b/tests/ui/consts/const_in_pattern/reject_non_structural.stderr @@ -118,14 +118,14 @@ LL | impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: constant of non-structural type `NoDerive` in a pattern - --> $DIR/reject_non_structural.rs:98:28 + --> $DIR/reject_non_structural.rs:97:28 | LL | struct NoDerive; | --------------- `NoDerive` must be annotated with `#[derive(PartialEq)]` to be usable in patterns ... LL | trait Trait: Sized { const ASSOC: Option; } | ------------------ ------------------------- constant defined here -... +LL | impl Trait for NoDerive { const ASSOC: Option = Some(NoDerive); } LL | match Some(NoDerive) { NoDerive::ASSOC => dbg!(NoDerive::ASSOC), _ => panic!("whoops"), }; | ^^^^^^^^^^^^^^^ constant of non-structural type | @@ -136,7 +136,7 @@ LL | impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: constant of non-structural type `NoDerive` in a pattern - --> $DIR/reject_non_structural.rs:103:28 + --> $DIR/reject_non_structural.rs:102:28 | LL | struct NoDerive; | --------------- `NoDerive` must be annotated with `#[derive(PartialEq)]` to be usable in patterns @@ -153,7 +153,7 @@ LL | impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: constant of non-structural type `NoDerive` in a pattern - --> $DIR/reject_non_structural.rs:108:29 + --> $DIR/reject_non_structural.rs:107:29 | LL | struct NoDerive; | --------------- `NoDerive` must be annotated with `#[derive(PartialEq)]` to be usable in patterns diff --git a/tests/ui/consts/copy-intrinsic.rs b/tests/ui/consts/copy-intrinsic.rs index 5ae467878001..da483d671f97 100644 --- a/tests/ui/consts/copy-intrinsic.rs +++ b/tests/ui/consts/copy-intrinsic.rs @@ -32,7 +32,7 @@ const COPY_OOB_1: () = unsafe { copy_nonoverlapping(0x100 as *const i32, dangle, 0); // Non-zero-sized copy is not. copy_nonoverlapping(0x100 as *const i32, dangle, 1); //~ ERROR evaluation of constant value failed [E0080] - //~| NOTE got 0x100[noalloc] which is a dangling pointer + //~| NOTE which is a dangling pointer }; const COPY_OOB_2: () = unsafe { let x = 0i32; @@ -41,7 +41,7 @@ const COPY_OOB_2: () = unsafe { copy_nonoverlapping(dangle, 0x100 as *mut i32, 0); // Non-zero-sized copy is not. copy_nonoverlapping(dangle, 0x100 as *mut i32, 1); //~ ERROR evaluation of constant value failed [E0080] - //~| NOTE +0x28 which is at or beyond the end of the allocation + //~| NOTE is at or beyond the end of the allocation of size 4 bytes }; const COPY_SIZE_OVERFLOW: () = unsafe { diff --git a/tests/ui/consts/copy-intrinsic.stderr b/tests/ui/consts/copy-intrinsic.stderr index 41af3a2cd2dc..13321b5703a3 100644 --- a/tests/ui/consts/copy-intrinsic.stderr +++ b/tests/ui/consts/copy-intrinsic.stderr @@ -2,13 +2,13 @@ error[E0080]: evaluation of constant value failed --> $DIR/copy-intrinsic.rs:34:5 | LL | copy_nonoverlapping(0x100 as *const i32, dangle, 1); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got 0x100[noalloc] which is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: attempting to access 4 bytes, but got 0x100[noalloc] which is a dangling pointer (it has no provenance) error[E0080]: evaluation of constant value failed --> $DIR/copy-intrinsic.rs:43:5 | LL | copy_nonoverlapping(dangle, 0x100 as *mut i32, 1); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got ALLOC0+0x28 which is at or beyond the end of the allocation of size 4 bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: attempting to access 4 bytes, but got ALLOC0+0x28 which is at or beyond the end of the allocation of size 4 bytes error[E0080]: evaluation of constant value failed --> $DIR/copy-intrinsic.rs:50:5 diff --git a/tests/ui/consts/missing_span_in_backtrace.rs b/tests/ui/consts/missing_span_in_backtrace.rs index c8c7453daa12..490eb57c24d4 100644 --- a/tests/ui/consts/missing_span_in_backtrace.rs +++ b/tests/ui/consts/missing_span_in_backtrace.rs @@ -1,7 +1,5 @@ //@ compile-flags: -Z ui-testing=no - -#![feature(const_swap_nonoverlapping)] use std::{ mem::{self, MaybeUninit}, ptr, diff --git a/tests/ui/consts/missing_span_in_backtrace.stderr b/tests/ui/consts/missing_span_in_backtrace.stderr index aad3d76dd269..88b3e37bb84f 100644 --- a/tests/ui/consts/missing_span_in_backtrace.stderr +++ b/tests/ui/consts/missing_span_in_backtrace.stderr @@ -1,11 +1,11 @@ error[E0080]: evaluation of constant value failed - --> $DIR/missing_span_in_backtrace.rs:16:9 + --> $DIR/missing_span_in_backtrace.rs:14:9 | -16 | / ptr::swap_nonoverlapping( -17 | | &mut ptr1 as *mut _ as *mut MaybeUninit, -18 | | &mut ptr2 as *mut _ as *mut MaybeUninit, -19 | | mem::size_of::<&i32>(), -20 | | ); +14 | / ptr::swap_nonoverlapping( +15 | | &mut ptr1 as *mut _ as *mut MaybeUninit, +16 | | &mut ptr2 as *mut _ as *mut MaybeUninit, +17 | | mem::size_of::<&i32>(), +18 | | ); | |_________^ unable to copy parts of a pointer from memory at ALLOC0 | note: inside `swap_nonoverlapping::>` diff --git a/tests/ui/consts/offset_ub.stderr b/tests/ui/consts/offset_ub.stderr index a247ad254651..699b63dfd66d 100644 --- a/tests/ui/consts/offset_ub.stderr +++ b/tests/ui/consts/offset_ub.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/offset_ub.rs:8:46 | LL | pub const BEFORE_START: *const u8 = unsafe { (&0u8 as *const u8).offset(-1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: expected a pointer to the end of 1 byte of memory, but got ALLOC0 which is at the beginning of the allocation + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ in-bounds pointer arithmetic failed: attempting to offset pointer by -$BYTES bytes, but got ALLOC0 which is at the beginning of the allocation | note: inside `std::ptr::const_ptr::::offset` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL @@ -11,7 +11,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/offset_ub.rs:9:43 | LL | pub const AFTER_END: *const u8 = unsafe { (&0u8 as *const u8).offset(2) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: expected a pointer to $BYTES bytes of memory, but got ALLOC1 which is only 1 byte from the end of the allocation + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ in-bounds pointer arithmetic failed: attempting to offset pointer by $BYTES bytes, but got ALLOC1 which is only 1 byte from the end of the allocation | note: inside `std::ptr::const_ptr::::offset` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL @@ -20,7 +20,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/offset_ub.rs:10:45 | LL | pub const AFTER_ARRAY: *const u8 = unsafe { [0u8; 100].as_ptr().offset(101) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: expected a pointer to $BYTES bytes of memory, but got ALLOC2 which is only $BYTES bytes from the end of the allocation + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ in-bounds pointer arithmetic failed: attempting to offset pointer by $BYTES bytes, but got ALLOC2 which is only $BYTES bytes from the end of the allocation | note: inside `std::ptr::const_ptr::::offset` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL @@ -47,7 +47,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/offset_ub.rs:14:56 | LL | pub const OVERFLOW_ADDRESS_SPACE: *const u8 = unsafe { (usize::MAX as *const u8).offset(2) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: expected a pointer to $BYTES bytes of memory, but got 0xf..f[noalloc] which is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ in-bounds pointer arithmetic failed: attempting to offset pointer by $BYTES bytes, but got 0xf..f[noalloc] which is a dangling pointer (it has no provenance) | note: inside `std::ptr::const_ptr::::offset` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL @@ -56,7 +56,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/offset_ub.rs:15:57 | LL | pub const UNDERFLOW_ADDRESS_SPACE: *const u8 = unsafe { (1 as *const u8).offset(-2) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: expected a pointer to the end of $BYTES bytes of memory, but got 0x1[noalloc] which is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ in-bounds pointer arithmetic failed: attempting to offset pointer by -$BYTES bytes, but got 0x1[noalloc] which is a dangling pointer (it has no provenance) | note: inside `std::ptr::const_ptr::::offset` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL @@ -65,7 +65,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/offset_ub.rs:16:49 | LL | pub const NEGATIVE_OFFSET: *const u8 = unsafe { [0u8; 1].as_ptr().wrapping_offset(-2).offset(-2) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: expected a pointer to the end of $BYTES bytes of memory, but got ALLOC3-0x2 which points to before the beginning of the allocation + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ in-bounds pointer arithmetic failed: attempting to offset pointer by -$BYTES bytes, but got ALLOC3-0x2 which is only $BYTES bytes from the beginning of the allocation | note: inside `std::ptr::const_ptr::::offset` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL @@ -74,7 +74,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/offset_ub.rs:18:50 | LL | pub const ZERO_SIZED_ALLOC: *const u8 = unsafe { [0u8; 0].as_ptr().offset(1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: expected a pointer to 1 byte of memory, but got ALLOC4 which is at or beyond the end of the allocation of size $BYTES bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ in-bounds pointer arithmetic failed: attempting to offset pointer by 1 byte, but got ALLOC4 which is at or beyond the end of the allocation of size $BYTES bytes | note: inside `std::ptr::const_ptr::::offset` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL @@ -83,7 +83,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/offset_ub.rs:19:42 | LL | pub const DANGLING: *const u8 = unsafe { ptr::NonNull::::dangling().as_ptr().offset(4) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: expected a pointer to $BYTES bytes of memory, but got 0x1[noalloc] which is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ in-bounds pointer arithmetic failed: attempting to offset pointer by $BYTES bytes, but got 0x1[noalloc] which is a dangling pointer (it has no provenance) | note: inside `std::ptr::mut_ptr::::offset` --> $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL @@ -92,7 +92,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/offset_ub.rs:22:47 | LL | pub const UNDERFLOW_ABS: *const u8 = unsafe { (usize::MAX as *const u8).offset(isize::MIN) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: expected a pointer to the end of $BYTES bytes of memory, but got 0xf..f[noalloc] which is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ in-bounds pointer arithmetic failed: attempting to offset pointer by -$BYTES bytes, but got 0xf..f[noalloc] which is a dangling pointer (it has no provenance) | note: inside `std::ptr::const_ptr::::offset` --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL diff --git a/tests/ui/auxiliary/issue-18502.rs b/tests/ui/cross-crate/auxiliary/inline-cross-crate.rs similarity index 100% rename from tests/ui/auxiliary/issue-18502.rs rename to tests/ui/cross-crate/auxiliary/inline-cross-crate.rs diff --git a/tests/ui/auxiliary/issue-76387.rs b/tests/ui/cross-crate/auxiliary/llvm-miscompile-MarkValue-MaybeLive.rs similarity index 100% rename from tests/ui/auxiliary/issue-76387.rs rename to tests/ui/cross-crate/auxiliary/llvm-miscompile-MarkValue-MaybeLive.rs diff --git a/tests/ui/cross-crate/inline-cross-crate.rs b/tests/ui/cross-crate/inline-cross-crate.rs new file mode 100644 index 000000000000..273aa8f8f0d8 --- /dev/null +++ b/tests/ui/cross-crate/inline-cross-crate.rs @@ -0,0 +1,12 @@ +//! Dpn't ice on using an inlined function from another crate +//! See and +//! + +//@ run-pass +//@ aux-build:inline-cross-crate.rs + +extern crate inline_cross_crate as fmt; + +fn main() { + ::fmt::baz(); +} diff --git a/tests/ui/cross-crate/llvm-miscompile-MarkValue-MaybeLive.rs b/tests/ui/cross-crate/llvm-miscompile-MarkValue-MaybeLive.rs new file mode 100644 index 000000000000..95d022ddd96e --- /dev/null +++ b/tests/ui/cross-crate/llvm-miscompile-MarkValue-MaybeLive.rs @@ -0,0 +1,22 @@ +//! Regression test for +//! Tests that LLVM doesn't miscompile this +//! See upstream fix: . + +//@ compile-flags: -C opt-level=3 +//@ aux-build: llvm-miscompile-MarkValue-MaybeLive.rs +//@ run-pass + +extern crate llvm_miscompile_MarkValue_MaybeLive; + +use llvm_miscompile_MarkValue_MaybeLive::FatPtr; + +fn print(data: &[u8]) { + println!("{:#?}", data); +} + +fn main() { + let ptr = FatPtr::new(20); + let data = unsafe { std::slice::from_raw_parts(ptr.as_ptr(), ptr.len()) }; + + print(data); +} diff --git a/tests/ui/debuginfo/debuginfo-type-name-layout-ice-94961-2.rs b/tests/ui/debuginfo/debuginfo-type-name-layout-ice-94961-2.rs index b79b5ff6fdb1..35210e78dcd9 100644 --- a/tests/ui/debuginfo/debuginfo-type-name-layout-ice-94961-2.rs +++ b/tests/ui/debuginfo/debuginfo-type-name-layout-ice-94961-2.rs @@ -1,4 +1,3 @@ -//FIXME~ ERROR values of the type `[u8; usize::MAX]` are too big for the target architecture // Make sure the compiler does not ICE when trying to generate the debuginfo name of a type that // causes a layout error. // This version of the test already ICE'd before the commit that introduce the ICE described in @@ -6,7 +5,6 @@ //@ compile-flags:-C debuginfo=2 --error-format=human //@ build-fail -//@ error-pattern: values of the type `[u8; usize::MAX]` are too big for the target architecture #![crate_type = "rlib"] @@ -18,5 +16,5 @@ pub fn foo() -> usize { std::mem::size_of::>() } -// FIXME: the error is reported on different lines on different targets -//FIXME~? ERROR values of the type `[u8; usize::MAX]` are too big for the target architecture +// FIXME(#140620): the error is reported on different lines on different targets +//~? RAW values of the type `[u8; usize::MAX]` are too big for the target architecture diff --git a/tests/ui/delegation/unsupported.stderr b/tests/ui/delegation/unsupported.stderr index cb14d9f459a2..53d05c3db8c4 100644 --- a/tests/ui/delegation/unsupported.stderr +++ b/tests/ui/delegation/unsupported.stderr @@ -1,4 +1,4 @@ -error[E0391]: cycle detected when computing type of `opaque::::{anon_assoc#0}` +error[E0391]: cycle detected when computing type of `opaque::::opaque_ret::{anon_assoc#0}` --> $DIR/unsupported.rs:22:25 | LL | reuse to_reuse::opaque_ret; @@ -9,7 +9,7 @@ note: ...which requires comparing an impl and trait method signature, inferring | LL | reuse to_reuse::opaque_ret; | ^^^^^^^^^^ - = note: ...which again requires computing type of `opaque::::{anon_assoc#0}`, completing the cycle + = note: ...which again requires computing type of `opaque::::opaque_ret::{anon_assoc#0}`, completing the cycle note: cycle used when checking that `opaque::` is well-formed --> $DIR/unsupported.rs:21:5 | @@ -17,7 +17,7 @@ LL | impl ToReuse for u8 { | ^^^^^^^^^^^^^^^^^^^ = 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[E0391]: cycle detected when computing type of `opaque::::{anon_assoc#0}` +error[E0391]: cycle detected when computing type of `opaque::::opaque_ret::{anon_assoc#0}` --> $DIR/unsupported.rs:25:24 | LL | reuse ToReuse::opaque_ret; @@ -28,7 +28,7 @@ note: ...which requires comparing an impl and trait method signature, inferring | LL | reuse ToReuse::opaque_ret; | ^^^^^^^^^^ - = note: ...which again requires computing type of `opaque::::{anon_assoc#0}`, completing the cycle + = note: ...which again requires computing type of `opaque::::opaque_ret::{anon_assoc#0}`, completing the cycle note: cycle used when checking that `opaque::` is well-formed --> $DIR/unsupported.rs:24:5 | diff --git a/tests/ui/derives/deriving-with-repr-packed-move-errors.rs b/tests/ui/derives/deriving-with-repr-packed-move-errors.rs index ffeb02d78b84..17aa750332c4 100644 --- a/tests/ui/derives/deriving-with-repr-packed-move-errors.rs +++ b/tests/ui/derives/deriving-with-repr-packed-move-errors.rs @@ -11,15 +11,15 @@ use std::cmp::Ordering; #[repr(packed)] #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default)] struct StructA(String); -//~^ ERROR: cannot move out of `self` which is behind a shared reference -//~| ERROR: cannot move out of `self` which is behind a shared reference -//~| ERROR: cannot move out of `other` which is behind a shared reference -//~| ERROR: cannot move out of `self` which is behind a shared reference -//~| ERROR: cannot move out of `other` which is behind a shared reference -//~| ERROR: cannot move out of `self` which is behind a shared reference -//~| ERROR: cannot move out of `other` which is behind a shared reference -//~| ERROR: cannot move out of `self` which is behind a shared reference -//~| ERROR: cannot move out of `self` which is behind a shared reference +//~^ ERROR: cannot move out of a shared reference [E0507] +//~| ERROR: cannot move out of a shared reference [E0507] +//~| ERROR: cannot move out of a shared reference [E0507] +//~| ERROR: cannot move out of a shared reference [E0507] +//~| ERROR: cannot move out of a shared reference [E0507] +//~| ERROR: cannot move out of a shared reference [E0507] +//~| ERROR: cannot move out of a shared reference [E0507] +//~| ERROR: cannot move out of a shared reference [E0507] +//~| ERROR: cannot move out of a shared reference [E0507] // Unrelated impl: additinal diagnostic should NOT be emitted diff --git a/tests/ui/derives/deriving-with-repr-packed-move-errors.stderr b/tests/ui/derives/deriving-with-repr-packed-move-errors.stderr index 68c3c8ae9ead..4b085425033d 100644 --- a/tests/ui/derives/deriving-with-repr-packed-move-errors.stderr +++ b/tests/ui/derives/deriving-with-repr-packed-move-errors.stderr @@ -1,10 +1,10 @@ -error[E0507]: cannot move out of `self` which is behind a shared reference +error[E0507]: cannot move out of a shared reference --> $DIR/deriving-with-repr-packed-move-errors.rs:13:16 | LL | #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default)] | ----- in this derive macro expansion LL | struct StructA(String); - | ^^^^^^ move occurs because `self.0` has type `String`, which does not implement the `Copy` trait + | ^^^^^^ move occurs because value has type `String`, which does not implement the `Copy` trait | = note: `#[derive(Debug)]` triggers a move because taking references to the fields of a packed struct is undefined behaviour help: consider cloning the value if the performance cost is acceptable @@ -12,13 +12,13 @@ help: consider cloning the value if the performance cost is acceptable LL | struct StructA(String.clone()); | ++++++++ -error[E0507]: cannot move out of `self` which is behind a shared reference +error[E0507]: cannot move out of a shared reference --> $DIR/deriving-with-repr-packed-move-errors.rs:13:16 | LL | #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default)] | --------- in this derive macro expansion LL | struct StructA(String); - | ^^^^^^ move occurs because `self.0` has type `String`, which does not implement the `Copy` trait + | ^^^^^^ move occurs because value has type `String`, which does not implement the `Copy` trait | = note: `#[derive(PartialEq)]` triggers a move because taking references to the fields of a packed struct is undefined behaviour help: consider cloning the value if the performance cost is acceptable @@ -26,27 +26,28 @@ help: consider cloning the value if the performance cost is acceptable LL | struct StructA(String.clone()); | ++++++++ -error[E0507]: cannot move out of `other` which is behind a shared reference +error[E0507]: cannot move out of a shared reference --> $DIR/deriving-with-repr-packed-move-errors.rs:13:16 | LL | #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default)] | --------- in this derive macro expansion LL | struct StructA(String); - | ^^^^^^ move occurs because `other.0` has type `String`, which does not implement the `Copy` trait + | ^^^^^^ move occurs because value has type `String`, which does not implement the `Copy` trait | = note: `#[derive(PartialEq)]` triggers a move because taking references to the fields of a packed struct is undefined behaviour + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` help: consider cloning the value if the performance cost is acceptable | LL | struct StructA(String.clone()); | ++++++++ -error[E0507]: cannot move out of `self` which is behind a shared reference +error[E0507]: cannot move out of a shared reference --> $DIR/deriving-with-repr-packed-move-errors.rs:13:16 | LL | #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default)] | ---------- in this derive macro expansion LL | struct StructA(String); - | ^^^^^^ move occurs because `self.0` has type `String`, which does not implement the `Copy` trait + | ^^^^^^ move occurs because value has type `String`, which does not implement the `Copy` trait | = note: `#[derive(PartialOrd)]` triggers a move because taking references to the fields of a packed struct is undefined behaviour help: consider cloning the value if the performance cost is acceptable @@ -54,27 +55,28 @@ help: consider cloning the value if the performance cost is acceptable LL | struct StructA(String.clone()); | ++++++++ -error[E0507]: cannot move out of `other` which is behind a shared reference +error[E0507]: cannot move out of a shared reference --> $DIR/deriving-with-repr-packed-move-errors.rs:13:16 | LL | #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default)] | ---------- in this derive macro expansion LL | struct StructA(String); - | ^^^^^^ move occurs because `other.0` has type `String`, which does not implement the `Copy` trait + | ^^^^^^ move occurs because value has type `String`, which does not implement the `Copy` trait | = note: `#[derive(PartialOrd)]` triggers a move because taking references to the fields of a packed struct is undefined behaviour + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` help: consider cloning the value if the performance cost is acceptable | LL | struct StructA(String.clone()); | ++++++++ -error[E0507]: cannot move out of `self` which is behind a shared reference +error[E0507]: cannot move out of a shared reference --> $DIR/deriving-with-repr-packed-move-errors.rs:13:16 | LL | #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default)] | --- in this derive macro expansion LL | struct StructA(String); - | ^^^^^^ move occurs because `self.0` has type `String`, which does not implement the `Copy` trait + | ^^^^^^ move occurs because value has type `String`, which does not implement the `Copy` trait | = note: `#[derive(Ord)]` triggers a move because taking references to the fields of a packed struct is undefined behaviour help: consider cloning the value if the performance cost is acceptable @@ -82,27 +84,28 @@ help: consider cloning the value if the performance cost is acceptable LL | struct StructA(String.clone()); | ++++++++ -error[E0507]: cannot move out of `other` which is behind a shared reference +error[E0507]: cannot move out of a shared reference --> $DIR/deriving-with-repr-packed-move-errors.rs:13:16 | LL | #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default)] | --- in this derive macro expansion LL | struct StructA(String); - | ^^^^^^ move occurs because `other.0` has type `String`, which does not implement the `Copy` trait + | ^^^^^^ move occurs because value has type `String`, which does not implement the `Copy` trait | = note: `#[derive(Ord)]` triggers a move because taking references to the fields of a packed struct is undefined behaviour + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` help: consider cloning the value if the performance cost is acceptable | LL | struct StructA(String.clone()); | ++++++++ -error[E0507]: cannot move out of `self` which is behind a shared reference +error[E0507]: cannot move out of a shared reference --> $DIR/deriving-with-repr-packed-move-errors.rs:13:16 | LL | #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default)] | ---- in this derive macro expansion LL | struct StructA(String); - | ^^^^^^ move occurs because `self.0` has type `String`, which does not implement the `Copy` trait + | ^^^^^^ move occurs because value has type `String`, which does not implement the `Copy` trait | = note: `#[derive(Hash)]` triggers a move because taking references to the fields of a packed struct is undefined behaviour help: consider cloning the value if the performance cost is acceptable @@ -110,13 +113,13 @@ help: consider cloning the value if the performance cost is acceptable LL | struct StructA(String.clone()); | ++++++++ -error[E0507]: cannot move out of `self` which is behind a shared reference +error[E0507]: cannot move out of a shared reference --> $DIR/deriving-with-repr-packed-move-errors.rs:13:16 | LL | #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Default)] | ----- in this derive macro expansion LL | struct StructA(String); - | ^^^^^^ move occurs because `self.0` has type `String`, which does not implement the `Copy` trait + | ^^^^^^ move occurs because value has type `String`, which does not implement the `Copy` trait | = note: `#[derive(Clone)]` triggers a move because taking references to the fields of a packed struct is undefined behaviour help: consider cloning the value if the performance cost is acceptable diff --git a/tests/ui/derives/deriving-with-repr-packed.rs b/tests/ui/derives/deriving-with-repr-packed.rs index d17b52842cef..cba0413c992e 100644 --- a/tests/ui/derives/deriving-with-repr-packed.rs +++ b/tests/ui/derives/deriving-with-repr-packed.rs @@ -20,7 +20,7 @@ struct Y(usize); #[derive(Debug, Default)] #[repr(packed)] struct X(Y); -//~^ ERROR cannot move out of `self` which is behind a shared reference +//~^ ERROR cannot move out of a shared reference [E0507] #[derive(Debug)] #[repr(packed)] diff --git a/tests/ui/derives/deriving-with-repr-packed.stderr b/tests/ui/derives/deriving-with-repr-packed.stderr index 5117f8d1112c..9cfc4abdc0cb 100644 --- a/tests/ui/derives/deriving-with-repr-packed.stderr +++ b/tests/ui/derives/deriving-with-repr-packed.stderr @@ -1,11 +1,11 @@ -error[E0507]: cannot move out of `self` which is behind a shared reference +error[E0507]: cannot move out of a shared reference --> $DIR/deriving-with-repr-packed.rs:22:10 | LL | #[derive(Debug, Default)] | ----- in this derive macro expansion LL | #[repr(packed)] LL | struct X(Y); - | ^ move occurs because `self.0` has type `Y`, which does not implement the `Copy` trait + | ^ move occurs because value has type `Y`, which does not implement the `Copy` trait | note: if `Y` implemented `Clone`, you could clone the value --> $DIR/deriving-with-repr-packed.rs:16:1 @@ -23,14 +23,14 @@ error[E0161]: cannot move a value of type `[u8]` LL | data: [u8], | ^^^^^^^^^^ the size of `[u8]` cannot be statically determined -error[E0507]: cannot move out of `self.data` which is behind a shared reference +error[E0507]: cannot move out of a shared reference --> $DIR/deriving-with-repr-packed.rs:29:5 | LL | #[derive(Debug)] | ----- in this derive macro expansion ... LL | data: [u8], - | ^^^^^^^^^^ move occurs because `self.data` has type `[u8]`, which does not implement the `Copy` trait + | ^^^^^^^^^^ move occurs because value has type `[u8]`, which does not implement the `Copy` trait | = note: `#[derive(Debug)]` triggers a move because taking references to the fields of a packed struct is undefined behaviour @@ -40,14 +40,14 @@ error[E0161]: cannot move a value of type `str` LL | data: str, | ^^^^^^^^^ the size of `str` cannot be statically determined -error[E0507]: cannot move out of `self.data` which is behind a shared reference +error[E0507]: cannot move out of a shared reference --> $DIR/deriving-with-repr-packed.rs:38:5 | LL | #[derive(Debug)] | ----- in this derive macro expansion ... LL | data: str, - | ^^^^^^^^^ move occurs because `self.data` has type `str`, which does not implement the `Copy` trait + | ^^^^^^^^^ move occurs because value has type `str`, which does not implement the `Copy` trait | = note: `#[derive(Debug)]` triggers a move because taking references to the fields of a packed struct is undefined behaviour diff --git a/tests/ui/diagnostic-width/flag-json.rs b/tests/ui/diagnostic-width/flag-json.rs index 00778872727b..edc7d2e2a425 100644 --- a/tests/ui/diagnostic-width/flag-json.rs +++ b/tests/ui/diagnostic-width/flag-json.rs @@ -1,9 +1,10 @@ //@ compile-flags: --diagnostic-width=20 --error-format=json -//@ error-pattern:expected `()`, found integer // This test checks that `-Z output-width` effects the JSON error output by restricting it to an // arbitrarily low value so that the effect is visible. fn main() { - let _: () = 42; + let _: () = 42; //~ ERROR mismatched types + //~| NOTE expected `()`, found integer + //~| NOTE expected due to this } diff --git a/tests/ui/diagnostic-width/flag-json.stderr b/tests/ui/diagnostic-width/flag-json.stderr index 6a54f86dcee5..cfc0364be76d 100644 --- a/tests/ui/diagnostic-width/flag-json.stderr +++ b/tests/ui/diagnostic-width/flag-json.stderr @@ -24,10 +24,10 @@ This error occurs when an expression was used in a place where the compiler expected an expression of a different type. It can occur in several cases, the most common being when calling a function and passing an argument which has a different type than the matching type in the function declaration. -"},"level":"error","spans":[{"file_name":"$DIR/flag-json.rs","byte_start":291,"byte_end":293,"line_start":8,"line_end":8,"column_start":17,"column_end":19,"is_primary":true,"text":[{"text":" let _: () = 42;","highlight_start":17,"highlight_end":19}],"label":"expected `()`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/flag-json.rs","byte_start":286,"byte_end":288,"line_start":8,"line_end":8,"column_start":12,"column_end":14,"is_primary":false,"text":[{"text":" let _: () = 42;","highlight_start":12,"highlight_end":14}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":"error[E0308]: mismatched types - --> $DIR/flag-json.rs:8:17 +"},"level":"error","spans":[{"file_name":"$DIR/flag-json.rs","byte_start":244,"byte_end":246,"line_start":7,"line_end":7,"column_start":17,"column_end":19,"is_primary":true,"text":[{"text":" let _: () = 42; + --> $DIR/flag-json.rs:7:17 | -LL | ..._: () = 42; +LL | ..._: () = 42; /... | -- ^^ expected `()`, found integer | | | expected due to this diff --git a/tests/ui/dyn-compatibility/mention-correct-dyn-incompatible-trait.stderr b/tests/ui/dyn-compatibility/mention-correct-dyn-incompatible-trait.stderr index bb3f7899bf1c..c1e93ccb83ca 100644 --- a/tests/ui/dyn-compatibility/mention-correct-dyn-incompatible-trait.stderr +++ b/tests/ui/dyn-compatibility/mention-correct-dyn-incompatible-trait.stderr @@ -1,21 +1,3 @@ -error[E0038]: the trait `Bar` is not dyn compatible - --> $DIR/mention-correct-dyn-incompatible-trait.rs:19:15 - | -LL | let test: &mut dyn Bar = &mut thing; - | ^^^^^^^^^^^^ `Bar` is not dyn compatible - | -note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit - --> $DIR/mention-correct-dyn-incompatible-trait.rs:4:8 - | -LL | fn foo(&self, val: T); - | ^^^ ...because method `foo` has generic type parameters -... -LL | trait Bar: Foo { } - | --- this trait is not dyn compatible... - = help: consider moving `foo` to another trait - = help: only type `Thing` implements `Bar`; consider using it directly instead. - error[E0038]: the trait `Bar` is not dyn compatible --> $DIR/mention-correct-dyn-incompatible-trait.rs:19:30 | @@ -35,6 +17,24 @@ LL | trait Bar: Foo { } = help: only type `Thing` implements `Bar`; consider using it directly instead. = note: required for the cast from `&mut Thing` to `&mut dyn Bar` +error[E0038]: the trait `Bar` is not dyn compatible + --> $DIR/mention-correct-dyn-incompatible-trait.rs:19:15 + | +LL | let test: &mut dyn Bar = &mut thing; + | ^^^^^^^^^^^^ `Bar` is not dyn compatible + | +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit + --> $DIR/mention-correct-dyn-incompatible-trait.rs:4:8 + | +LL | fn foo(&self, val: T); + | ^^^ ...because method `foo` has generic type parameters +... +LL | trait Bar: Foo { } + | --- this trait is not dyn compatible... + = help: consider moving `foo` to another trait + = help: only type `Thing` implements `Bar`; consider using it directly instead. + error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/error-codes/E0253.rs b/tests/ui/error-codes/E0253.rs deleted file mode 100644 index 8284f791c648..000000000000 --- a/tests/ui/error-codes/E0253.rs +++ /dev/null @@ -1,10 +0,0 @@ -mod foo { - pub trait MyTrait { - type SomeType; - } -} - -use foo::MyTrait::SomeType; - //~^ ERROR E0253 - -fn main() {} diff --git a/tests/ui/error-codes/E0253.stderr b/tests/ui/error-codes/E0253.stderr deleted file mode 100644 index 954dbc816939..000000000000 --- a/tests/ui/error-codes/E0253.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0253]: `SomeType` is not directly importable - --> $DIR/E0253.rs:7:5 - | -LL | use foo::MyTrait::SomeType; - | ^^^^^^^^^^^^^^^^^^^^^^ cannot be imported directly - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0253`. diff --git a/tests/ui/error-emitter/highlighting.rs b/tests/ui/error-emitter/highlighting.rs index b3c1acbd342c..d7a0c9d22466 100644 --- a/tests/ui/error-emitter/highlighting.rs +++ b/tests/ui/error-emitter/highlighting.rs @@ -1,7 +1,6 @@ // Make sure "highlighted" code is colored purple //@ compile-flags: --error-format=human --color=always -//@ error-pattern:for<'a>  //@ edition:2018 use core::pin::Pin; @@ -21,3 +20,5 @@ fn wrapped_fn<'a>(_: Box<(dyn Any + Send)>) -> Pin  diff --git a/tests/ui/error-emitter/highlighting.svg b/tests/ui/error-emitter/highlighting.svg index 68fc118f1a6e..19818ab6146c 100644 --- a/tests/ui/error-emitter/highlighting.svg +++ b/tests/ui/error-emitter/highlighting.svg @@ -23,7 +23,7 @@ error[E0308]: mismatched types - --> $DIR/highlighting.rs:22:11 + --> $DIR/highlighting.rs:21:11 | @@ -43,7 +43,7 @@ note: function defined here - --> $DIR/highlighting.rs:11:4 + --> $DIR/highlighting.rs:10:4 | diff --git a/tests/ui/error-emitter/highlighting.windows.svg b/tests/ui/error-emitter/highlighting.windows.svg index c7dd001434ee..f891bc1d2a68 100644 --- a/tests/ui/error-emitter/highlighting.windows.svg +++ b/tests/ui/error-emitter/highlighting.windows.svg @@ -24,7 +24,7 @@ error[E0308]: mismatched types - --> $DIR/highlighting.rs:22:11 + --> $DIR/highlighting.rs:21:11 | @@ -44,7 +44,7 @@ note: function defined here - --> $DIR/highlighting.rs:11:4 + --> $DIR/highlighting.rs:10:4 | diff --git a/tests/ui/error-emitter/multiline-multipart-suggestion.rs b/tests/ui/error-emitter/multiline-multipart-suggestion.rs index a938b280ca2e..92dede1b5d83 100644 --- a/tests/ui/error-emitter/multiline-multipart-suggestion.rs +++ b/tests/ui/error-emitter/multiline-multipart-suggestion.rs @@ -1,5 +1,4 @@ //@ compile-flags: --error-format=human --color=always -//@ error-pattern: missing lifetime specifier fn short(foo_bar: &Vec<&i32>) -> &i32 { &12 @@ -17,3 +16,5 @@ fn long2( &12 } fn main() {} + +//~? RAW missing lifetime specifier diff --git a/tests/ui/error-emitter/multiline-multipart-suggestion.svg b/tests/ui/error-emitter/multiline-multipart-suggestion.svg index c0fb98555ad8..dd84234236d7 100644 --- a/tests/ui/error-emitter/multiline-multipart-suggestion.svg +++ b/tests/ui/error-emitter/multiline-multipart-suggestion.svg @@ -23,7 +23,7 @@ error[E0106]: missing lifetime specifier - --> $DIR/multiline-multipart-suggestion.rs:4:34 + --> $DIR/multiline-multipart-suggestion.rs:3:34 | @@ -47,7 +47,7 @@ error[E0106]: missing lifetime specifier - --> $DIR/multiline-multipart-suggestion.rs:11:6 + --> $DIR/multiline-multipart-suggestion.rs:10:6 | @@ -83,7 +83,7 @@ error[E0106]: missing lifetime specifier - --> $DIR/multiline-multipart-suggestion.rs:16:29 + --> $DIR/multiline-multipart-suggestion.rs:15:29 | diff --git a/tests/ui/error-emitter/multiline-multipart-suggestion.windows.svg b/tests/ui/error-emitter/multiline-multipart-suggestion.windows.svg index 61b544001f08..144e57165da7 100644 --- a/tests/ui/error-emitter/multiline-multipart-suggestion.windows.svg +++ b/tests/ui/error-emitter/multiline-multipart-suggestion.windows.svg @@ -23,7 +23,7 @@ error[E0106]: missing lifetime specifier - --> $DIR/multiline-multipart-suggestion.rs:4:34 + --> $DIR/multiline-multipart-suggestion.rs:3:34 | @@ -47,7 +47,7 @@ error[E0106]: missing lifetime specifier - --> $DIR/multiline-multipart-suggestion.rs:11:6 + --> $DIR/multiline-multipart-suggestion.rs:10:6 | @@ -83,7 +83,7 @@ error[E0106]: missing lifetime specifier - --> $DIR/multiline-multipart-suggestion.rs:16:29 + --> $DIR/multiline-multipart-suggestion.rs:15:29 | diff --git a/tests/ui/explain.rs b/tests/ui/explain/basic.rs similarity index 100% rename from tests/ui/explain.rs rename to tests/ui/explain/basic.rs diff --git a/tests/ui/explain.stdout b/tests/ui/explain/basic.stdout similarity index 100% rename from tests/ui/explain.stdout rename to tests/ui/explain/basic.stdout diff --git a/tests/ui/explain/error-with-no-explanation.rs b/tests/ui/explain/error-with-no-explanation.rs new file mode 100644 index 000000000000..383820eb4580 --- /dev/null +++ b/tests/ui/explain/error-with-no-explanation.rs @@ -0,0 +1,3 @@ +// It's a valid error with no added explanation +//@ compile-flags: --explain E9999 +//~? ERROR: E9999 is not a valid error code diff --git a/tests/ui/explain/error-with-no-explanation.stderr b/tests/ui/explain/error-with-no-explanation.stderr new file mode 100644 index 000000000000..afb738cfecb9 --- /dev/null +++ b/tests/ui/explain/error-with-no-explanation.stderr @@ -0,0 +1,2 @@ +error: E9999 is not a valid error code + diff --git a/tests/ui/explain/invalid-error-code.rs b/tests/ui/explain/invalid-error-code.rs new file mode 100644 index 000000000000..114118d5196b --- /dev/null +++ b/tests/ui/explain/invalid-error-code.rs @@ -0,0 +1,2 @@ +//@ compile-flags: --explain error_code +//~? ERROR: error_code is not a valid error code diff --git a/tests/ui/explain/invalid-error-code.stderr b/tests/ui/explain/invalid-error-code.stderr new file mode 100644 index 000000000000..c33122ea88cb --- /dev/null +++ b/tests/ui/explain/invalid-error-code.stderr @@ -0,0 +1,2 @@ +error: error_code is not a valid error code + diff --git a/tests/ui/explain/no-E-prefix.rs b/tests/ui/explain/no-E-prefix.rs new file mode 100644 index 000000000000..39c9122bfe1b --- /dev/null +++ b/tests/ui/explain/no-E-prefix.rs @@ -0,0 +1,2 @@ +//@ compile-flags: --explain 425 +//@ check-pass diff --git a/tests/ui/explain/no-E-prefix.stdout b/tests/ui/explain/no-E-prefix.stdout new file mode 100644 index 000000000000..756b970aa7e6 --- /dev/null +++ b/tests/ui/explain/no-E-prefix.stdout @@ -0,0 +1,57 @@ +An unresolved name was used. + +Erroneous code examples: + +``` +something_that_doesnt_exist::foo; +// error: unresolved name `something_that_doesnt_exist::foo` + +// or: + +trait Foo { + fn bar() { + Self; // error: unresolved name `Self` + } +} + +// or: + +let x = unknown_variable; // error: unresolved name `unknown_variable` +``` + +Please verify that the name wasn't misspelled and ensure that the +identifier being referred to is valid for the given situation. Example: + +``` +enum something_that_does_exist { + Foo, +} +``` + +Or: + +``` +mod something_that_does_exist { + pub static foo : i32 = 0i32; +} + +something_that_does_exist::foo; // ok! +``` + +Or: + +``` +let unknown_variable = 12u32; +let x = unknown_variable; // ok! +``` + +If the item is not defined in the current module, it must be imported using a +`use` statement, like so: + +``` +use foo::bar; +bar(); +``` + +If the item you are importing is not defined in some super-module of the +current module, then it must also be declared as public (e.g., `pub fn`). diff --git a/tests/ui/explain/overflow-error-code.rs b/tests/ui/explain/overflow-error-code.rs new file mode 100644 index 000000000000..284d5cddb35a --- /dev/null +++ b/tests/ui/explain/overflow-error-code.rs @@ -0,0 +1,4 @@ +// Check that we don't crash on error codes exceeding our internal limit. +// issue: +//@ compile-flags: --explain E10000 +//~? ERROR: E10000 is not a valid error code diff --git a/tests/ui/explain/overflow-error-code.stderr b/tests/ui/explain/overflow-error-code.stderr new file mode 100644 index 000000000000..67e584ea32e1 --- /dev/null +++ b/tests/ui/explain/overflow-error-code.stderr @@ -0,0 +1,2 @@ +error: E10000 is not a valid error code + diff --git a/tests/ui/feature-gates/bench.rs b/tests/ui/feature-gates/bench.rs index 12e646f7a323..94c8992a8fe6 100644 --- a/tests/ui/feature-gates/bench.rs +++ b/tests/ui/feature-gates/bench.rs @@ -1,9 +1,7 @@ //@ edition:2018 #[bench] //~ ERROR use of unstable library feature `test` - //~| WARN this was previously accepted fn bench() {} use bench as _; //~ ERROR use of unstable library feature `test` - //~| WARN this was previously accepted fn main() {} diff --git a/tests/ui/feature-gates/bench.stderr b/tests/ui/feature-gates/bench.stderr index de78e863012d..f5fc579b23be 100644 --- a/tests/ui/feature-gates/bench.stderr +++ b/tests/ui/feature-gates/bench.stderr @@ -1,43 +1,23 @@ -error: use of unstable library feature `test`: `bench` is a part of custom test frameworks which are unstable +error[E0658]: use of unstable library feature `test`: `bench` is a part of custom test frameworks which are unstable --> $DIR/bench.rs:3:3 | LL | #[bench] | ^^^^^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #64266 - = note: `#[deny(soft_unstable)]` on by default + = note: see issue #50297 for more information + = help: add `#![feature(test)]` 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: use of unstable library feature `test`: `bench` is a part of custom test frameworks which are unstable - --> $DIR/bench.rs:7:5 +error[E0658]: use of unstable library feature `test`: `bench` is a part of custom test frameworks which are unstable + --> $DIR/bench.rs:6:5 | LL | use bench as _; | ^^^^^ | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #64266 + = note: see issue #50297 for more information + = help: add `#![feature(test)]` 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 2 previous errors -Future incompatibility report: Future breakage diagnostic: -error: use of unstable library feature `test`: `bench` is a part of custom test frameworks which are unstable - --> $DIR/bench.rs:3:3 - | -LL | #[bench] - | ^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #64266 - = note: `#[deny(soft_unstable)]` on by default - -Future breakage diagnostic: -error: use of unstable library feature `test`: `bench` is a part of custom test frameworks which are unstable - --> $DIR/bench.rs:7:5 - | -LL | use bench as _; - | ^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #64266 - = note: `#[deny(soft_unstable)]` on by default - +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-apx-target-feature.rs b/tests/ui/feature-gates/feature-gate-apx-target-feature.rs new file mode 100644 index 000000000000..a2ac4ac86ac0 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-apx-target-feature.rs @@ -0,0 +1,6 @@ +//@ only-x86_64 +#[target_feature(enable = "apxf")] +//~^ ERROR: currently unstable +unsafe fn foo() {} + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-apx-target-feature.stderr b/tests/ui/feature-gates/feature-gate-apx-target-feature.stderr new file mode 100644 index 000000000000..1999ab535379 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-apx-target-feature.stderr @@ -0,0 +1,13 @@ +error[E0658]: the target feature `apxf` is currently unstable + --> $DIR/feature-gate-apx-target-feature.rs:2:18 + | +LL | #[target_feature(enable = "apxf")] + | ^^^^^^^^^^^^^^^ + | + = note: see issue #139284 for more information + = help: add `#![feature(apx_target_feature)]` 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-avx10_target_feature.rs b/tests/ui/feature-gates/feature-gate-avx10_target_feature.rs new file mode 100644 index 000000000000..8557e67d1f41 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-avx10_target_feature.rs @@ -0,0 +1,6 @@ +//@ only-x86_64 +#[target_feature(enable = "avx10.1")] +//~^ ERROR: currently unstable +unsafe fn foo() {} + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-avx10_target_feature.stderr b/tests/ui/feature-gates/feature-gate-avx10_target_feature.stderr new file mode 100644 index 000000000000..e45ea3524ca7 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-avx10_target_feature.stderr @@ -0,0 +1,13 @@ +error[E0658]: the target feature `avx10.1` is currently unstable + --> $DIR/feature-gate-avx10_target_feature.rs:2:18 + | +LL | #[target_feature(enable = "avx10.1")] + | ^^^^^^^^^^^^^^^^^^ + | + = note: see issue #138843 for more information + = help: add `#![feature(avx10_target_feature)]` 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-export_stable.rs b/tests/ui/feature-gates/feature-gate-export_stable.rs new file mode 100644 index 000000000000..5d05fee059b8 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-export_stable.rs @@ -0,0 +1,5 @@ +#![crate_type="lib"] + +#[export_stable] +//~^ ERROR the `#[export_stable]` attribute is an experimental feature +pub mod a {} diff --git a/tests/ui/feature-gates/feature-gate-export_stable.stderr b/tests/ui/feature-gates/feature-gate-export_stable.stderr new file mode 100644 index 000000000000..6beb52a77e5c --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-export_stable.stderr @@ -0,0 +1,13 @@ +error[E0658]: the `#[export_stable]` attribute is an experimental feature + --> $DIR/feature-gate-export_stable.rs:3:1 + | +LL | #[export_stable] + | ^^^^^^^^^^^^^^^^ + | + = note: see issue #139939 for more information + = help: add `#![feature(export_stable)]` 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-frontmatter.rs b/tests/ui/feature-gates/feature-gate-frontmatter.rs new file mode 100644 index 000000000000..58e1f57eec02 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-frontmatter.rs @@ -0,0 +1,5 @@ +---cargo +//~^ ERROR: frontmatters are experimental +--- + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-frontmatter.stderr b/tests/ui/feature-gates/feature-gate-frontmatter.stderr new file mode 100644 index 000000000000..57d38db8e76a --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-frontmatter.stderr @@ -0,0 +1,15 @@ +error[E0658]: frontmatters are experimental + --> $DIR/feature-gate-frontmatter.rs:1:1 + | +LL | / ---cargo +LL | | +LL | | --- + | |___^ + | + = note: see issue #136889 for more information + = help: add `#![feature(frontmatter)]` 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-import-trait-associated-functions.rs b/tests/ui/feature-gates/feature-gate-import-trait-associated-functions.rs index aec13fb02028..c2c010eaba63 100644 --- a/tests/ui/feature-gates/feature-gate-import-trait-associated-functions.rs +++ b/tests/ui/feature-gates/feature-gate-import-trait-associated-functions.rs @@ -60,4 +60,7 @@ fn f() { let t: Option = DEFAULT; } +trait Glob {} +use Glob::*; //~ ERROR `use` associated items of traits is unstable + fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-import-trait-associated-functions.stderr b/tests/ui/feature-gates/feature-gate-import-trait-associated-functions.stderr index d342f5bd5512..fca3cef3e203 100644 --- a/tests/ui/feature-gates/feature-gate-import-trait-associated-functions.stderr +++ b/tests/ui/feature-gates/feature-gate-import-trait-associated-functions.stderr @@ -48,6 +48,16 @@ LL | use super::A::{self, DEFAULT, new}; = help: add `#![feature(import_trait_associated_functions)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: aborting due to 5 previous errors +error[E0658]: `use` associated items of traits is unstable + --> $DIR/feature-gate-import-trait-associated-functions.rs:64:5 + | +LL | use Glob::*; + | ^^^^^^^ + | + = note: see issue #134691 for more information + = help: add `#![feature(import_trait_associated_functions)]` 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 6 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/fn/fn-trait-use-named-params-issue-140169.rs b/tests/ui/fn/fn-trait-use-named-params-issue-140169.rs new file mode 100644 index 000000000000..218450abd499 --- /dev/null +++ b/tests/ui/fn/fn-trait-use-named-params-issue-140169.rs @@ -0,0 +1,12 @@ +fn f1(_: fn(a: u8)) {} +fn f2(_: impl Fn(u8, vvvv: u8)) {} //~ ERROR `Trait(...)` syntax does not support named parameters +fn f3(_: impl Fn(aaaa: u8, u8)) {} //~ ERROR `Trait(...)` syntax does not support named parameters +fn f4(_: impl Fn(aaaa: u8, vvvv: u8)) {} +//~^ ERROR `Trait(...)` syntax does not support named parameters +//~| ERROR `Trait(...)` syntax does not support named parameters +fn f5(_: impl Fn(u8, ...)) {} +//~^ ERROR `Trait(...)` syntax does not support c_variadic parameters +fn f6(_: impl Fn(u8, #[allow(unused_attributes)] u8)) {} +//~^ ERROR `Trait(...)` syntax does not support attributes in parameters + +fn main(){} diff --git a/tests/ui/fn/fn-trait-use-named-params-issue-140169.stderr b/tests/ui/fn/fn-trait-use-named-params-issue-140169.stderr new file mode 100644 index 000000000000..b72d5b7b3bc4 --- /dev/null +++ b/tests/ui/fn/fn-trait-use-named-params-issue-140169.stderr @@ -0,0 +1,38 @@ +error: `Trait(...)` syntax does not support named parameters + --> $DIR/fn-trait-use-named-params-issue-140169.rs:2:22 + | +LL | fn f2(_: impl Fn(u8, vvvv: u8)) {} + | ^^^^ help: remove the parameter name + +error: `Trait(...)` syntax does not support named parameters + --> $DIR/fn-trait-use-named-params-issue-140169.rs:3:18 + | +LL | fn f3(_: impl Fn(aaaa: u8, u8)) {} + | ^^^^ help: remove the parameter name + +error: `Trait(...)` syntax does not support named parameters + --> $DIR/fn-trait-use-named-params-issue-140169.rs:4:18 + | +LL | fn f4(_: impl Fn(aaaa: u8, vvvv: u8)) {} + | ^^^^ help: remove the parameter name + +error: `Trait(...)` syntax does not support named parameters + --> $DIR/fn-trait-use-named-params-issue-140169.rs:4:28 + | +LL | fn f4(_: impl Fn(aaaa: u8, vvvv: u8)) {} + | ^^^^ help: remove the parameter name + +error: `Trait(...)` syntax does not support c_variadic parameters + --> $DIR/fn-trait-use-named-params-issue-140169.rs:7:22 + | +LL | fn f5(_: impl Fn(u8, ...)) {} + | ^^^ help: remove the `...` + +error: `Trait(...)` syntax does not support attributes in parameters + --> $DIR/fn-trait-use-named-params-issue-140169.rs:9:22 + | +LL | fn f6(_: impl Fn(u8, #[allow(unused_attributes)] u8)) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the attributes + +error: aborting due to 6 previous errors + diff --git a/tests/ui/fn/param-mismatch-foreign.rs b/tests/ui/fn/param-mismatch-foreign.rs index eebca29d6c93..2ab2bf95448a 100644 --- a/tests/ui/fn/param-mismatch-foreign.rs +++ b/tests/ui/fn/param-mismatch-foreign.rs @@ -1,7 +1,6 @@ extern "C" { fn foo(x: i32, y: u32, z: i32); //~^ NOTE function defined here - //~| NOTE } fn main() { diff --git a/tests/ui/fn/param-mismatch-foreign.stderr b/tests/ui/fn/param-mismatch-foreign.stderr index fff3283cbb6c..835e0a3343e9 100644 --- a/tests/ui/fn/param-mismatch-foreign.stderr +++ b/tests/ui/fn/param-mismatch-foreign.stderr @@ -1,5 +1,5 @@ error[E0061]: this function takes 3 arguments but 2 arguments were supplied - --> $DIR/param-mismatch-foreign.rs:8:5 + --> $DIR/param-mismatch-foreign.rs:7:5 | LL | foo(1i32, 2i32); | ^^^ ---- argument #2 of type `u32` is missing diff --git a/tests/ui/fn/signature-error-reporting-under-verbose.rs b/tests/ui/fn/signature-error-reporting-under-verbose.rs index 4a72da789789..0047d452b7a6 100644 --- a/tests/ui/fn/signature-error-reporting-under-verbose.rs +++ b/tests/ui/fn/signature-error-reporting-under-verbose.rs @@ -4,7 +4,6 @@ fn foo(_: i32, _: i32) {} fn needs_ptr(_: fn(i32, u32)) {} //~^ NOTE function defined here -//~| NOTE fn main() { needs_ptr(foo); diff --git a/tests/ui/fn/signature-error-reporting-under-verbose.stderr b/tests/ui/fn/signature-error-reporting-under-verbose.stderr index 6c6a313c4df7..d9ccec23fcb6 100644 --- a/tests/ui/fn/signature-error-reporting-under-verbose.stderr +++ b/tests/ui/fn/signature-error-reporting-under-verbose.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/signature-error-reporting-under-verbose.rs:10:15 + --> $DIR/signature-error-reporting-under-verbose.rs:9:15 | LL | needs_ptr(foo); | --------- ^^^ expected fn pointer, found fn item diff --git a/tests/ui/frontmatter/auxiliary/lib.rs b/tests/ui/frontmatter/auxiliary/lib.rs new file mode 100644 index 000000000000..ff7094f410f5 --- /dev/null +++ b/tests/ui/frontmatter/auxiliary/lib.rs @@ -0,0 +1,6 @@ +---something +--- + +pub fn foo(x: i32) -> i32 { + -x +} diff --git a/tests/ui/frontmatter/auxiliary/makro.rs b/tests/ui/frontmatter/auxiliary/makro.rs new file mode 100644 index 000000000000..78e7417afb5f --- /dev/null +++ b/tests/ui/frontmatter/auxiliary/makro.rs @@ -0,0 +1,8 @@ +extern crate proc_macro; +use proc_macro::TokenStream; + +#[proc_macro] +pub fn check(_: TokenStream) -> TokenStream { + assert!("---\n---".parse::().unwrap().is_empty()); + Default::default() +} diff --git a/tests/ui/frontmatter/dot-in-infostring-leading.rs b/tests/ui/frontmatter/dot-in-infostring-leading.rs new file mode 100644 index 000000000000..0d3d699644e9 --- /dev/null +++ b/tests/ui/frontmatter/dot-in-infostring-leading.rs @@ -0,0 +1,9 @@ +---.toml +//~^ ERROR: invalid infostring for frontmatter +--- + +// infostrings cannot have leading dots + +#![feature(frontmatter)] + +fn main() {} diff --git a/tests/ui/frontmatter/dot-in-infostring-leading.stderr b/tests/ui/frontmatter/dot-in-infostring-leading.stderr new file mode 100644 index 000000000000..bc86bd80eece --- /dev/null +++ b/tests/ui/frontmatter/dot-in-infostring-leading.stderr @@ -0,0 +1,10 @@ +error: invalid infostring for frontmatter + --> $DIR/dot-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/dot-in-infostring-non-leading.rs b/tests/ui/frontmatter/dot-in-infostring-non-leading.rs new file mode 100644 index 000000000000..a4d17bb6e813 --- /dev/null +++ b/tests/ui/frontmatter/dot-in-infostring-non-leading.rs @@ -0,0 +1,9 @@ +---Cargo.toml +--- + +// infostrings can contain dots as long as a dot isn't the first character. +//@ check-pass + +#![feature(frontmatter)] + +fn main() {} diff --git a/tests/ui/frontmatter/escape.rs b/tests/ui/frontmatter/escape.rs new file mode 100644 index 000000000000..0e6f064607e8 --- /dev/null +++ b/tests/ui/frontmatter/escape.rs @@ -0,0 +1,14 @@ +---- + +--- + +---- + +//@ check-pass + +// This test checks that longer dashes for opening and closing can be used to +// escape sequences such as three dashes inside the frontmatter block. + +#![feature(frontmatter)] + +fn main() {} diff --git a/tests/ui/frontmatter/extra-after-end.rs b/tests/ui/frontmatter/extra-after-end.rs new file mode 100644 index 000000000000..de2cf4cc85ef --- /dev/null +++ b/tests/ui/frontmatter/extra-after-end.rs @@ -0,0 +1,7 @@ +--- +---cargo +//~^ ERROR: extra characters after frontmatter close are not allowed + +#![feature(frontmatter)] + +fn main() {} diff --git a/tests/ui/frontmatter/extra-after-end.stderr b/tests/ui/frontmatter/extra-after-end.stderr new file mode 100644 index 000000000000..c2770fdfd41f --- /dev/null +++ b/tests/ui/frontmatter/extra-after-end.stderr @@ -0,0 +1,8 @@ +error: extra characters after frontmatter close are not allowed + --> $DIR/extra-after-end.rs:2:1 + | +LL | ---cargo + | ^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/frontmatter/frontmatter-after-tokens.rs b/tests/ui/frontmatter/frontmatter-after-tokens.rs new file mode 100644 index 000000000000..6683991dc4af --- /dev/null +++ b/tests/ui/frontmatter/frontmatter-after-tokens.rs @@ -0,0 +1,10 @@ +#![feature(frontmatter)] + +--- +//~^ ERROR: expected item, found `-` +// FIXME(frontmatter): make this diagnostic better +--- + +// frontmatters must be at the start of a file. This test ensures that. + +fn main() {} diff --git a/tests/ui/frontmatter/frontmatter-after-tokens.stderr b/tests/ui/frontmatter/frontmatter-after-tokens.stderr new file mode 100644 index 000000000000..919456924d02 --- /dev/null +++ b/tests/ui/frontmatter/frontmatter-after-tokens.stderr @@ -0,0 +1,10 @@ +error: expected item, found `-` + --> $DIR/frontmatter-after-tokens.rs:3:1 + | +LL | --- + | ^ expected item + | + = note: for a full list of items that can appear in modules, see + +error: aborting due to 1 previous error + diff --git a/tests/ui/frontmatter/frontmatter-non-lexible-tokens.rs b/tests/ui/frontmatter/frontmatter-non-lexible-tokens.rs new file mode 100644 index 000000000000..ea042edef06b --- /dev/null +++ b/tests/ui/frontmatter/frontmatter-non-lexible-tokens.rs @@ -0,0 +1,12 @@ +---uwu +🏳️‍⚧️ +--- + +//@ check-pass + +#![feature(frontmatter)] + +// check that frontmatter blocks can have tokens that are otherwise not accepted by +// the lexer as Rust code. + +fn main() {} diff --git a/tests/ui/frontmatter/frontmatter-whitespace-1.rs b/tests/ui/frontmatter/frontmatter-whitespace-1.rs new file mode 100644 index 000000000000..8b6e2d1af849 --- /dev/null +++ b/tests/ui/frontmatter/frontmatter-whitespace-1.rs @@ -0,0 +1,10 @@ + --- +//~^ ERROR: invalid preceding whitespace for frontmatter opening + --- +//~^ ERROR: invalid preceding whitespace for frontmatter close + +#![feature(frontmatter)] + +// check that whitespaces should not precede the frontmatter opening or close. + +fn main() {} diff --git a/tests/ui/frontmatter/frontmatter-whitespace-1.stderr b/tests/ui/frontmatter/frontmatter-whitespace-1.stderr new file mode 100644 index 000000000000..37ece27acb22 --- /dev/null +++ b/tests/ui/frontmatter/frontmatter-whitespace-1.stderr @@ -0,0 +1,26 @@ +error: invalid preceding whitespace for frontmatter opening + --> $DIR/frontmatter-whitespace-1.rs:1:1 + | +LL | --- + | ^^^^^ + | +note: frontmatter opening should not be preceded by whitespace + --> $DIR/frontmatter-whitespace-1.rs:1:1 + | +LL | --- + | ^^ + +error: invalid preceding whitespace for frontmatter close + --> $DIR/frontmatter-whitespace-1.rs:3:1 + | +LL | --- + | ^^^^^ + | +note: frontmatter close should not be preceded by whitespace + --> $DIR/frontmatter-whitespace-1.rs:3:1 + | +LL | --- + | ^^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/frontmatter/frontmatter-whitespace-2.rs b/tests/ui/frontmatter/frontmatter-whitespace-2.rs new file mode 100644 index 000000000000..e8c100849b40 --- /dev/null +++ b/tests/ui/frontmatter/frontmatter-whitespace-2.rs @@ -0,0 +1,15 @@ +---cargo + +//@ compile-flags: --crate-type lib + +#![feature(frontmatter)] + +fn foo(x: i32) -> i32 { + ---x + //~^ ERROR: invalid preceding whitespace for frontmatter close + //~| ERROR: extra characters after frontmatter close are not allowed +} +//~^ ERROR: unexpected closing delimiter: `}` + +// this test is for the weird case that valid Rust code can have three dashes +// within them and get treated as a frontmatter close. diff --git a/tests/ui/frontmatter/frontmatter-whitespace-2.stderr b/tests/ui/frontmatter/frontmatter-whitespace-2.stderr new file mode 100644 index 000000000000..ada6af0ec04c --- /dev/null +++ b/tests/ui/frontmatter/frontmatter-whitespace-2.stderr @@ -0,0 +1,26 @@ +error: invalid preceding whitespace for frontmatter close + --> $DIR/frontmatter-whitespace-2.rs:8:1 + | +LL | ---x + | ^^^^^^^^ + | +note: frontmatter close should not be preceded by whitespace + --> $DIR/frontmatter-whitespace-2.rs:8:1 + | +LL | ---x + | ^^^^ + +error: extra characters after frontmatter close are not allowed + --> $DIR/frontmatter-whitespace-2.rs:8:1 + | +LL | ---x + | ^^^^^^^^ + +error: unexpected closing delimiter: `}` + --> $DIR/frontmatter-whitespace-2.rs:11:1 + | +LL | } + | ^ unexpected closing delimiter + +error: aborting due to 3 previous errors + diff --git a/tests/ui/frontmatter/frontmatter-whitespace-3.rs b/tests/ui/frontmatter/frontmatter-whitespace-3.rs new file mode 100644 index 000000000000..95e0981e2ae8 --- /dev/null +++ b/tests/ui/frontmatter/frontmatter-whitespace-3.rs @@ -0,0 +1,16 @@ + + +---cargo +--- + +// please note the whitespace characters after the first four lines. +// This ensures that we accept whitespaces before the frontmatter, after +// the frontmatter opening and the frontmatter close. + +//@ check-pass +// ignore-tidy-end-whitespace +// ignore-tidy-leading-newlines + +#![feature(frontmatter)] + +fn main() {} diff --git a/tests/ui/frontmatter/frontmatter-whitespace-4.rs b/tests/ui/frontmatter/frontmatter-whitespace-4.rs new file mode 100644 index 000000000000..3bda3227838c --- /dev/null +++ b/tests/ui/frontmatter/frontmatter-whitespace-4.rs @@ -0,0 +1,9 @@ +--- cargo +--- + +//@ check-pass +// A frontmatter infostring can have leading whitespace. + +#![feature(frontmatter)] + +fn main() {} diff --git a/tests/ui/frontmatter/included-frontmatter.rs b/tests/ui/frontmatter/included-frontmatter.rs new file mode 100644 index 000000000000..57616cd1228c --- /dev/null +++ b/tests/ui/frontmatter/included-frontmatter.rs @@ -0,0 +1,12 @@ +#![feature(frontmatter)] + +//@ check-pass + +include!("auxiliary/lib.rs"); + +// auxiliary/lib.rs contains a frontmatter. Ensure that we can use them in an +// `include!` macro. + +fn main() { + foo(1); +} diff --git a/tests/ui/frontmatter/infostring-fail.rs b/tests/ui/frontmatter/infostring-fail.rs new file mode 100644 index 000000000000..91542f62f1a5 --- /dev/null +++ b/tests/ui/frontmatter/infostring-fail.rs @@ -0,0 +1,9 @@ +---cargo,clippy +//~^ ERROR: invalid infostring for frontmatter +--- + +// infostrings can only be a single identifier. + +#![feature(frontmatter)] + +fn main() {} diff --git a/tests/ui/frontmatter/infostring-fail.stderr b/tests/ui/frontmatter/infostring-fail.stderr new file mode 100644 index 000000000000..6b264abc90f1 --- /dev/null +++ b/tests/ui/frontmatter/infostring-fail.stderr @@ -0,0 +1,10 @@ +error: invalid infostring for frontmatter + --> $DIR/infostring-fail.rs:1:4 + | +LL | ---cargo,clippy + | ^^^^^^^^^^^^ + | + = 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/mismatch-1.rs b/tests/ui/frontmatter/mismatch-1.rs new file mode 100644 index 000000000000..37e2b0af6b18 --- /dev/null +++ b/tests/ui/frontmatter/mismatch-1.rs @@ -0,0 +1,10 @@ +---cargo +//~^ ERROR: frontmatter close does not match the opening +---- + +// there must be the same number of dashes for both the opening and the close +// of the frontmatter. + +#![feature(frontmatter)] + +fn main() {} diff --git a/tests/ui/frontmatter/mismatch-1.stderr b/tests/ui/frontmatter/mismatch-1.stderr new file mode 100644 index 000000000000..b6e29294d9e1 --- /dev/null +++ b/tests/ui/frontmatter/mismatch-1.stderr @@ -0,0 +1,16 @@ +error: frontmatter close does not match the opening + --> $DIR/mismatch-1.rs:1:1 + | +LL | ---cargo + | ^-- + | | + | _the opening here has 3 dashes... + | | +LL | | +LL | | ---- + | |_---^ + | | + | ...while the close has 4 dashes + +error: aborting due to 1 previous error + diff --git a/tests/ui/frontmatter/mismatch-2.rs b/tests/ui/frontmatter/mismatch-2.rs new file mode 100644 index 000000000000..422abe1d6bc9 --- /dev/null +++ b/tests/ui/frontmatter/mismatch-2.rs @@ -0,0 +1,8 @@ +----cargo +//~^ ERROR: frontmatter close does not match the opening +---cargo +//~^ ERROR: extra characters after frontmatter close are not allowed + +#![feature(frontmatter)] + +fn main() {} diff --git a/tests/ui/frontmatter/mismatch-2.stderr b/tests/ui/frontmatter/mismatch-2.stderr new file mode 100644 index 000000000000..90bb7b80bcea --- /dev/null +++ b/tests/ui/frontmatter/mismatch-2.stderr @@ -0,0 +1,22 @@ +error: frontmatter close does not match the opening + --> $DIR/mismatch-2.rs:1:1 + | +LL | ----cargo + | ^--- + | | + | _the opening here has 4 dashes... + | | +LL | | +LL | | ---cargo + | |_---____^ + | | + | ...while the close has 3 dashes + +error: extra characters after frontmatter close are not allowed + --> $DIR/mismatch-2.rs:3:1 + | +LL | ---cargo + | ^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/frontmatter/multifrontmatter-2.rs b/tests/ui/frontmatter/multifrontmatter-2.rs new file mode 100644 index 000000000000..33cc30cb4655 --- /dev/null +++ b/tests/ui/frontmatter/multifrontmatter-2.rs @@ -0,0 +1,12 @@ +--- + --- +//~^ ERROR: invalid preceding whitespace for frontmatter close + + --- +//~^ ERROR: expected item, found `-` +// FIXME(frontmatter): make this diagnostic better +--- + +#![feature(frontmatter)] + +fn main() {} diff --git a/tests/ui/frontmatter/multifrontmatter-2.stderr b/tests/ui/frontmatter/multifrontmatter-2.stderr new file mode 100644 index 000000000000..ed9ac4029e27 --- /dev/null +++ b/tests/ui/frontmatter/multifrontmatter-2.stderr @@ -0,0 +1,22 @@ +error: invalid preceding whitespace for frontmatter close + --> $DIR/multifrontmatter-2.rs:2:1 + | +LL | --- + | ^^^^ + | +note: frontmatter close should not be preceded by whitespace + --> $DIR/multifrontmatter-2.rs:2:1 + | +LL | --- + | ^ + +error: expected item, found `-` + --> $DIR/multifrontmatter-2.rs:5:2 + | +LL | --- + | ^ expected item + | + = note: for a full list of items that can appear in modules, see + +error: aborting due to 2 previous errors + diff --git a/tests/ui/frontmatter/multifrontmatter.rs b/tests/ui/frontmatter/multifrontmatter.rs new file mode 100644 index 000000000000..f3afa47bd383 --- /dev/null +++ b/tests/ui/frontmatter/multifrontmatter.rs @@ -0,0 +1,13 @@ +--- +--- + +--- +//~^ ERROR: expected item, found `-` +// FIXME(frontmatter): make this diagnostic better +--- + +// test that we do not parse another frontmatter block after the first one. + +#![feature(frontmatter)] + +fn main() {} diff --git a/tests/ui/frontmatter/multifrontmatter.stderr b/tests/ui/frontmatter/multifrontmatter.stderr new file mode 100644 index 000000000000..2e9d1cee9ddb --- /dev/null +++ b/tests/ui/frontmatter/multifrontmatter.stderr @@ -0,0 +1,10 @@ +error: expected item, found `-` + --> $DIR/multifrontmatter.rs:4:1 + | +LL | --- + | ^ expected item + | + = note: for a full list of items that can appear in modules, see + +error: aborting due to 1 previous error + diff --git a/tests/ui/frontmatter/proc-macro-observer.rs b/tests/ui/frontmatter/proc-macro-observer.rs new file mode 100644 index 000000000000..bafbe912032e --- /dev/null +++ b/tests/ui/frontmatter/proc-macro-observer.rs @@ -0,0 +1,12 @@ +//@ check-pass +//@ proc-macro: makro.rs +//@ edition: 2021 + +#![feature(frontmatter)] + +makro::check!(); + +// checks that a proc-macro cannot observe frontmatter tokens. +// see auxiliary/makro.rs for how it is tested. + +fn main() {} diff --git a/tests/ui/frontmatter/shebang.rs b/tests/ui/frontmatter/shebang.rs new file mode 100644 index 000000000000..abd983f219bd --- /dev/null +++ b/tests/ui/frontmatter/shebang.rs @@ -0,0 +1,13 @@ +#!/usr/bin/env -S cargo -Zscript +--- +[dependencies] +clap = "4" +--- + +//@ check-pass + +// Shebangs on a file can precede a frontmatter. + +#![feature(frontmatter)] + +fn main () {} diff --git a/tests/ui/frontmatter/unclosed-1.rs b/tests/ui/frontmatter/unclosed-1.rs new file mode 100644 index 000000000000..d8b52b3e69c7 --- /dev/null +++ b/tests/ui/frontmatter/unclosed-1.rs @@ -0,0 +1,10 @@ +----cargo +//~^ ERROR: unclosed frontmatter + +// This test checks that the #! characters can help us recover a frontmatter +// close. There should not be a "missing `main` function" error as the rest +// are properly parsed. + +#![feature(frontmatter)] + +fn main() {} diff --git a/tests/ui/frontmatter/unclosed-1.stderr b/tests/ui/frontmatter/unclosed-1.stderr new file mode 100644 index 000000000000..04031d128398 --- /dev/null +++ b/tests/ui/frontmatter/unclosed-1.stderr @@ -0,0 +1,16 @@ +error: unclosed frontmatter + --> $DIR/unclosed-1.rs:1:1 + | +LL | / ----cargo +... | +LL | | + | |_^ + | +note: frontmatter opening here was not closed + --> $DIR/unclosed-1.rs:1:1 + | +LL | ----cargo + | ^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/frontmatter/unclosed-2.rs b/tests/ui/frontmatter/unclosed-2.rs new file mode 100644 index 000000000000..add266dce5b0 --- /dev/null +++ b/tests/ui/frontmatter/unclosed-2.rs @@ -0,0 +1,15 @@ +----cargo +//~^ ERROR: unclosed frontmatter +//~| ERROR: frontmatters are experimental + +//@ compile-flags: --crate-type lib + +// Leading whitespace on the feature line prevents recovery. However +// the dashes quoted will not be used for recovery and the entire file +// should be treated as within the frontmatter block. + + #![feature(frontmatter)] + +fn foo() -> &str { + "----" +} diff --git a/tests/ui/frontmatter/unclosed-2.stderr b/tests/ui/frontmatter/unclosed-2.stderr new file mode 100644 index 000000000000..0a4022c1557b --- /dev/null +++ b/tests/ui/frontmatter/unclosed-2.stderr @@ -0,0 +1,31 @@ +error: unclosed frontmatter + --> $DIR/unclosed-2.rs:1:1 + | +LL | / ----cargo +... | +LL | | "----" +LL | | } + | |__^ + | +note: frontmatter opening here was not closed + --> $DIR/unclosed-2.rs:1:1 + | +LL | ----cargo + | ^^^^ + +error[E0658]: frontmatters are experimental + --> $DIR/unclosed-2.rs:1:1 + | +LL | / ----cargo +... | +LL | | "----" +LL | | } + | |__^ + | + = note: see issue #136889 for more information + = help: add `#![feature(frontmatter)]` 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 2 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/frontmatter/unclosed-3.rs b/tests/ui/frontmatter/unclosed-3.rs new file mode 100644 index 000000000000..75f3fbda675c --- /dev/null +++ b/tests/ui/frontmatter/unclosed-3.rs @@ -0,0 +1,16 @@ +----cargo +//~^ ERROR: frontmatter close does not match the opening + +//@ compile-flags: --crate-type lib + +// Unfortunate recovery situation. Not really preventable with improving the +// recovery strategy, but this type of code is rare enough already. + + #![feature(frontmatter)] + +fn foo(x: i32) -> i32 { + ---x + //~^ ERROR: invalid preceding whitespace for frontmatter close + //~| ERROR: extra characters after frontmatter close are not allowed +} +//~^ ERROR: unexpected closing delimiter: `}` diff --git a/tests/ui/frontmatter/unclosed-3.stderr b/tests/ui/frontmatter/unclosed-3.stderr new file mode 100644 index 000000000000..cd69cb000408 --- /dev/null +++ b/tests/ui/frontmatter/unclosed-3.stderr @@ -0,0 +1,41 @@ +error: invalid preceding whitespace for frontmatter close + --> $DIR/unclosed-3.rs:12:1 + | +LL | ---x + | ^^^^^^^^ + | +note: frontmatter close should not be preceded by whitespace + --> $DIR/unclosed-3.rs:12:1 + | +LL | ---x + | ^^^^ + +error: frontmatter close does not match the opening + --> $DIR/unclosed-3.rs:1:1 + | +LL | ----cargo + | ^--- + | | + | _the opening here has 4 dashes... + | | +... | +LL | | fn foo(x: i32) -> i32 { +LL | | ---x + | |_---____^ + | | + | ...while the close has 3 dashes + +error: extra characters after frontmatter close are not allowed + --> $DIR/unclosed-3.rs:12:1 + | +LL | ---x + | ^^^^^^^^ + +error: unexpected closing delimiter: `}` + --> $DIR/unclosed-3.rs:15:1 + | +LL | } + | ^ unexpected closing delimiter + +error: aborting due to 4 previous errors + diff --git a/tests/ui/frontmatter/unclosed-4.rs b/tests/ui/frontmatter/unclosed-4.rs new file mode 100644 index 000000000000..41f6461db634 --- /dev/null +++ b/tests/ui/frontmatter/unclosed-4.rs @@ -0,0 +1,9 @@ +----cargo +//~^ ERROR: unclosed frontmatter + +//! Similarly, a module-level content should allow for recovery as well (as +//! per unclosed-1.rs) + +#![feature(frontmatter)] + +fn main() {} diff --git a/tests/ui/frontmatter/unclosed-4.stderr b/tests/ui/frontmatter/unclosed-4.stderr new file mode 100644 index 000000000000..b3ba56937bba --- /dev/null +++ b/tests/ui/frontmatter/unclosed-4.stderr @@ -0,0 +1,16 @@ +error: unclosed frontmatter + --> $DIR/unclosed-4.rs:1:1 + | +LL | / ----cargo +LL | | +LL | | + | |_^ + | +note: frontmatter opening here was not closed + --> $DIR/unclosed-4.rs:1:1 + | +LL | ----cargo + | ^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/frontmatter/unclosed-5.rs b/tests/ui/frontmatter/unclosed-5.rs new file mode 100644 index 000000000000..9abbcfff94c7 --- /dev/null +++ b/tests/ui/frontmatter/unclosed-5.rs @@ -0,0 +1,10 @@ +----cargo +//~^ ERROR: unclosed frontmatter +//~| ERROR: frontmatters are experimental + +// Similarly, a use statement should allow for recovery as well (as +// per unclosed-1.rs) + +use std::env; + +fn main() {} diff --git a/tests/ui/frontmatter/unclosed-5.stderr b/tests/ui/frontmatter/unclosed-5.stderr new file mode 100644 index 000000000000..e904014a175a --- /dev/null +++ b/tests/ui/frontmatter/unclosed-5.stderr @@ -0,0 +1,29 @@ +error: unclosed frontmatter + --> $DIR/unclosed-5.rs:1:1 + | +LL | / ----cargo +... | +LL | | + | |_^ + | +note: frontmatter opening here was not closed + --> $DIR/unclosed-5.rs:1:1 + | +LL | ----cargo + | ^^^^ + +error[E0658]: frontmatters are experimental + --> $DIR/unclosed-5.rs:1:1 + | +LL | / ----cargo +... | +LL | | + | |_^ + | + = note: see issue #136889 for more information + = help: add `#![feature(frontmatter)]` 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 2 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/generic-const-items/user_type_annotations_pattern.rs b/tests/ui/generic-const-items/user_type_annotations_pattern.rs new file mode 100644 index 000000000000..aa3846df2bca --- /dev/null +++ b/tests/ui/generic-const-items/user_type_annotations_pattern.rs @@ -0,0 +1,14 @@ +#![feature(generic_const_items)] +#![expect(incomplete_features)] + +const FOO<'a: 'static>: usize = 10; + +fn bar<'a>() { + match 10_usize { + FOO::<'a> => todo!(), + //~^ ERROR: lifetime may not live long enough + _ => todo!(), + } +} + +fn main() {} diff --git a/tests/ui/generic-const-items/user_type_annotations_pattern.stderr b/tests/ui/generic-const-items/user_type_annotations_pattern.stderr new file mode 100644 index 000000000000..e15be275d297 --- /dev/null +++ b/tests/ui/generic-const-items/user_type_annotations_pattern.stderr @@ -0,0 +1,11 @@ +error: lifetime may not live long enough + --> $DIR/user_type_annotations_pattern.rs:8:9 + | +LL | fn bar<'a>() { + | -- lifetime `'a` defined here +LL | match 10_usize { +LL | FOO::<'a> => todo!(), + | ^^^^^^^^^ requires that `'a` must outlive `'static` + +error: aborting due to 1 previous error + diff --git a/tests/ui/generics/export-name-on-generics.fixed b/tests/ui/generics/export-name-on-generics.fixed new file mode 100644 index 000000000000..4430cd9a2998 --- /dev/null +++ b/tests/ui/generics/export-name-on-generics.fixed @@ -0,0 +1,157 @@ +//@ run-rustfix +#![allow(dead_code, elided_named_lifetimes)] +#![deny(no_mangle_generic_items)] + +pub fn foo() {} //~ ERROR functions generic over types or consts must be mangled + +pub extern "C" fn bar() {} //~ ERROR functions generic over types or consts must be mangled + +#[export_name = "baz"] +pub fn baz(x: &i32) -> &i32 { x } + +#[export_name = "qux"] +pub fn qux<'a>(x: &'a i32) -> &i32 { x } + +pub struct Foo; + +impl Foo { + + pub fn foo() {} //~ ERROR functions generic over types or consts must be mangled + + + pub extern "C" fn bar() {} //~ ERROR functions generic over types or consts must be mangled + + #[export_name = "baz"] + pub fn baz(x: &i32) -> &i32 { x } + + #[export_name = "qux"] + pub fn qux<'a>(x: &'a i32) -> &i32 { x } +} + +trait Trait1 { + fn foo(); + extern "C" fn bar(); + fn baz(x: &i32) -> &i32; + fn qux<'a>(x: &'a i32) -> &i32; +} + +impl Trait1 for Foo { + + fn foo() {} //~ ERROR functions generic over types or consts must be mangled + + + extern "C" fn bar() {} //~ ERROR functions generic over types or consts must be mangled + + #[export_name = "baz"] + fn baz(x: &i32) -> &i32 { x } + + #[export_name = "qux"] + fn qux<'a>(x: &'a i32) -> &i32 { x } +} + +trait Trait2 { + fn foo(); + fn foo2(); + extern "C" fn bar(); + fn baz(x: &i32) -> &i32; + fn qux<'a>(x: &'a i32) -> &i32; +} + +impl Trait2 for Foo { + + fn foo() {} //~ ERROR functions generic over types or consts must be mangled + + + fn foo2() {} //~ ERROR functions generic over types or consts must be mangled + + + extern "C" fn bar() {} //~ ERROR functions generic over types or consts must be mangled + + + fn baz(x: &i32) -> &i32 { x } //~ ERROR functions generic over types or consts must be mangled + + + fn qux<'a>(x: &'a i32) -> &i32 { x } //~ ERROR functions generic over types or consts must be mangled +} + +pub struct Bar(#[allow(dead_code)] T); + +impl Bar { + + pub fn foo() {} //~ ERROR functions generic over types or consts must be mangled + + + pub extern "C" fn bar() {} //~ ERROR functions generic over types or consts must be mangled + + + pub fn baz() {} //~ ERROR functions generic over types or consts must be mangled +} + +impl Bar { + #[export_name = "qux"] + pub fn qux() {} +} + +trait Trait3 { + fn foo(); + extern "C" fn bar(); + fn baz(); +} + +impl Trait3 for Bar { + + fn foo() {} //~ ERROR functions generic over types or consts must be mangled + + + extern "C" fn bar() {} //~ ERROR functions generic over types or consts must be mangled + + + fn baz() {} //~ ERROR functions generic over types or consts must be mangled +} + +pub struct Baz<'a>(#[allow(dead_code)] &'a i32); + +impl<'a> Baz<'a> { + #[export_name = "foo"] + pub fn foo() {} + + #[export_name = "bar"] + pub fn bar<'b>(x: &'b i32) -> &i32 { x } +} + +trait Trait4 { + fn foo(); + fn bar<'a>(x: &'a i32) -> &i32; +} + +impl Trait4 for Bar { + #[export_name = "foo"] + fn foo() {} + + #[export_name = "bar"] + fn bar<'b>(x: &'b i32) -> &i32 { x } +} + +impl<'a> Trait4 for Baz<'a> { + #[export_name = "foo"] + fn foo() {} + + #[export_name = "bar"] + fn bar<'b>(x: &'b i32) -> &i32 { x } +} + +trait Trait5 { + fn foo(); +} + +impl Trait5 for Foo { + #[export_name = "foo"] + fn foo() {} +} + +impl Trait5 for Bar { + #[export_name = "foo"] + fn foo() {} +} + +fn main() {} diff --git a/tests/ui/generics/export-name-on-generics.rs b/tests/ui/generics/export-name-on-generics.rs new file mode 100644 index 000000000000..cbf110219605 --- /dev/null +++ b/tests/ui/generics/export-name-on-generics.rs @@ -0,0 +1,159 @@ +//@ run-rustfix +#![allow(dead_code, elided_named_lifetimes)] +#![deny(no_mangle_generic_items)] + +#[export_name = "foo"] +pub fn foo() {} //~ ERROR functions generic over types or consts must be mangled + +#[export_name = "bar"] +pub extern "C" fn bar() {} //~ ERROR functions generic over types or consts must be mangled + +#[export_name = "baz"] +pub fn baz(x: &i32) -> &i32 { x } + +#[export_name = "qux"] +pub fn qux<'a>(x: &'a i32) -> &i32 { x } + +pub struct Foo; + +impl Foo { + #[export_name = "foo"] + pub fn foo() {} //~ ERROR functions generic over types or consts must be mangled + + #[export_name = "bar"] + pub extern "C" fn bar() {} //~ ERROR functions generic over types or consts must be mangled + + #[export_name = "baz"] + pub fn baz(x: &i32) -> &i32 { x } + + #[export_name = "qux"] + pub fn qux<'a>(x: &'a i32) -> &i32 { x } +} + +trait Trait1 { + fn foo(); + extern "C" fn bar(); + fn baz(x: &i32) -> &i32; + fn qux<'a>(x: &'a i32) -> &i32; +} + +impl Trait1 for Foo { + #[export_name = "foo"] + fn foo() {} //~ ERROR functions generic over types or consts must be mangled + + #[export_name = "bar"] + extern "C" fn bar() {} //~ ERROR functions generic over types or consts must be mangled + + #[export_name = "baz"] + fn baz(x: &i32) -> &i32 { x } + + #[export_name = "qux"] + fn qux<'a>(x: &'a i32) -> &i32 { x } +} + +trait Trait2 { + fn foo(); + fn foo2(); + extern "C" fn bar(); + fn baz(x: &i32) -> &i32; + fn qux<'a>(x: &'a i32) -> &i32; +} + +impl Trait2 for Foo { + #[export_name = "foo"] + fn foo() {} //~ ERROR functions generic over types or consts must be mangled + + #[export_name = "foo2"] + fn foo2() {} //~ ERROR functions generic over types or consts must be mangled + + #[export_name = "baz"] + extern "C" fn bar() {} //~ ERROR functions generic over types or consts must be mangled + + #[export_name = "baz"] + fn baz(x: &i32) -> &i32 { x } //~ ERROR functions generic over types or consts must be mangled + + #[export_name = "qux"] + fn qux<'a>(x: &'a i32) -> &i32 { x } //~ ERROR functions generic over types or consts must be mangled +} + +pub struct Bar(#[allow(dead_code)] T); + +impl Bar { + #[export_name = "foo"] + pub fn foo() {} //~ ERROR functions generic over types or consts must be mangled + + #[export_name = "bar"] + pub extern "C" fn bar() {} //~ ERROR functions generic over types or consts must be mangled + + #[export_name = "baz"] + pub fn baz() {} //~ ERROR functions generic over types or consts must be mangled +} + +impl Bar { + #[export_name = "qux"] + pub fn qux() {} +} + +trait Trait3 { + fn foo(); + extern "C" fn bar(); + fn baz(); +} + +impl Trait3 for Bar { + #[export_name = "foo"] + fn foo() {} //~ ERROR functions generic over types or consts must be mangled + + #[export_name = "bar"] + extern "C" fn bar() {} //~ ERROR functions generic over types or consts must be mangled + + #[export_name = "baz"] + fn baz() {} //~ ERROR functions generic over types or consts must be mangled +} + +pub struct Baz<'a>(#[allow(dead_code)] &'a i32); + +impl<'a> Baz<'a> { + #[export_name = "foo"] + pub fn foo() {} + + #[export_name = "bar"] + pub fn bar<'b>(x: &'b i32) -> &i32 { x } +} + +trait Trait4 { + fn foo(); + fn bar<'a>(x: &'a i32) -> &i32; +} + +impl Trait4 for Bar { + #[export_name = "foo"] + fn foo() {} + + #[export_name = "bar"] + fn bar<'b>(x: &'b i32) -> &i32 { x } +} + +impl<'a> Trait4 for Baz<'a> { + #[export_name = "foo"] + fn foo() {} + + #[export_name = "bar"] + fn bar<'b>(x: &'b i32) -> &i32 { x } +} + +trait Trait5 { + fn foo(); +} + +impl Trait5 for Foo { + #[export_name = "foo"] + fn foo() {} +} + +impl Trait5 for Bar { + #[export_name = "foo"] + fn foo() {} +} + +fn main() {} diff --git a/tests/ui/generics/export-name-on-generics.stderr b/tests/ui/generics/export-name-on-generics.stderr new file mode 100644 index 000000000000..7bc7b8ca5593 --- /dev/null +++ b/tests/ui/generics/export-name-on-generics.stderr @@ -0,0 +1,144 @@ +error: functions generic over types or consts must be mangled + --> $DIR/export-name-on-generics.rs:6:1 + | +LL | #[export_name = "foo"] + | ---------------------- help: remove this attribute +LL | pub fn foo() {} + | ^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/export-name-on-generics.rs:3:9 + | +LL | #![deny(no_mangle_generic_items)] + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: functions generic over types or consts must be mangled + --> $DIR/export-name-on-generics.rs:9:1 + | +LL | #[export_name = "bar"] + | ---------------------- help: remove this attribute +LL | pub extern "C" fn bar() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: functions generic over types or consts must be mangled + --> $DIR/export-name-on-generics.rs:21:5 + | +LL | #[export_name = "foo"] + | ---------------------- help: remove this attribute +LL | pub fn foo() {} + | ^^^^^^^^^^^^^^^^^^ + +error: functions generic over types or consts must be mangled + --> $DIR/export-name-on-generics.rs:24:5 + | +LL | #[export_name = "bar"] + | ---------------------- help: remove this attribute +LL | pub extern "C" fn bar() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: functions generic over types or consts must be mangled + --> $DIR/export-name-on-generics.rs:42:5 + | +LL | #[export_name = "foo"] + | ---------------------- help: remove this attribute +LL | fn foo() {} + | ^^^^^^^^^^^^^^ + +error: functions generic over types or consts must be mangled + --> $DIR/export-name-on-generics.rs:45:5 + | +LL | #[export_name = "bar"] + | ---------------------- help: remove this attribute +LL | extern "C" fn bar() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: functions generic over types or consts must be mangled + --> $DIR/export-name-on-generics.rs:64:5 + | +LL | #[export_name = "foo"] + | ---------------------- help: remove this attribute +LL | fn foo() {} + | ^^^^^^^^^^^ + +error: functions generic over types or consts must be mangled + --> $DIR/export-name-on-generics.rs:67:5 + | +LL | #[export_name = "foo2"] + | ----------------------- help: remove this attribute +LL | fn foo2() {} + | ^^^^^^^^^^^^^^^ + +error: functions generic over types or consts must be mangled + --> $DIR/export-name-on-generics.rs:70:5 + | +LL | #[export_name = "baz"] + | ---------------------- help: remove this attribute +LL | extern "C" fn bar() {} + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: functions generic over types or consts must be mangled + --> $DIR/export-name-on-generics.rs:73:5 + | +LL | #[export_name = "baz"] + | ---------------------- help: remove this attribute +LL | fn baz(x: &i32) -> &i32 { x } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: functions generic over types or consts must be mangled + --> $DIR/export-name-on-generics.rs:76:5 + | +LL | #[export_name = "qux"] + | ---------------------- help: remove this attribute +LL | fn qux<'a>(x: &'a i32) -> &i32 { x } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: functions generic over types or consts must be mangled + --> $DIR/export-name-on-generics.rs:83:5 + | +LL | #[export_name = "foo"] + | ---------------------- help: remove this attribute +LL | pub fn foo() {} + | ^^^^^^^^^^^^^^^ + +error: functions generic over types or consts must be mangled + --> $DIR/export-name-on-generics.rs:86:5 + | +LL | #[export_name = "bar"] + | ---------------------- help: remove this attribute +LL | pub extern "C" fn bar() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: functions generic over types or consts must be mangled + --> $DIR/export-name-on-generics.rs:89:5 + | +LL | #[export_name = "baz"] + | ---------------------- help: remove this attribute +LL | pub fn baz() {} + | ^^^^^^^^^^^^^^^^^^ + +error: functions generic over types or consts must be mangled + --> $DIR/export-name-on-generics.rs:105:5 + | +LL | #[export_name = "foo"] + | ---------------------- help: remove this attribute +LL | fn foo() {} + | ^^^^^^^^^^^ + +error: functions generic over types or consts must be mangled + --> $DIR/export-name-on-generics.rs:108:5 + | +LL | #[export_name = "bar"] + | ---------------------- help: remove this attribute +LL | extern "C" fn bar() {} + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: functions generic over types or consts must be mangled + --> $DIR/export-name-on-generics.rs:111:5 + | +LL | #[export_name = "baz"] + | ---------------------- help: remove this attribute +LL | fn baz() {} + | ^^^^^^^^^^^^^^ + +error: aborting due to 17 previous errors + diff --git a/tests/ui/impl-privacy-xc-1.rs b/tests/ui/impl-privacy-xc-1.rs deleted file mode 100644 index 6a10986739cd..000000000000 --- a/tests/ui/impl-privacy-xc-1.rs +++ /dev/null @@ -1,10 +0,0 @@ -//@ run-pass -//@ aux-build:impl_privacy_xc_1.rs - - -extern crate impl_privacy_xc_1; - -pub fn main() { - let fish = impl_privacy_xc_1::Fish { x: 1 }; - fish.swim(); -} diff --git a/tests/ui/impl-trait/diagnostics/highlight-difference-between-expected-trait-and-found-trait.rs b/tests/ui/impl-trait/diagnostics/highlight-difference-between-expected-trait-and-found-trait.rs index f1c196a154d5..ffb7a1008e0f 100644 --- a/tests/ui/impl-trait/diagnostics/highlight-difference-between-expected-trait-and-found-trait.rs +++ b/tests/ui/impl-trait/diagnostics/highlight-difference-between-expected-trait-and-found-trait.rs @@ -1,6 +1,5 @@ //@ only-linux //@ compile-flags: --error-format=human --color=always -//@ error-pattern: the trait bound trait Foo: Bar {} @@ -18,3 +17,5 @@ fn foo() -> impl Foo { } fn main() {} + +//~? RAW the trait bound 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 1a79a9d7efa2..9832e28e008b 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 @@ - + ::Type; - | -LL - let _: S::Type; -LL + let _: ::Type; - | - error[E0034]: multiple applicable items in scope --> $DIR/disambiguate-multiple-blanket-impl.rs:30:8 | @@ -63,6 +48,21 @@ LL - S::CONST; LL + ::CONST; | +error[E0223]: ambiguous associated type + --> $DIR/disambiguate-multiple-blanket-impl.rs:36:12 + | +LL | let _: S::Type; + | ^^^^^^^ + | +help: use fully-qualified syntax + | +LL - let _: S::Type; +LL + let _: ::Type; + | +LL - let _: S::Type; +LL + let _: ::Type; + | + error: aborting due to 3 previous errors Some errors have detailed explanations: E0034, E0223. diff --git a/tests/ui/methods/disambiguate-multiple-impl.stderr b/tests/ui/methods/disambiguate-multiple-impl.stderr index 2563c2327b7a..319d5886f8ed 100644 --- a/tests/ui/methods/disambiguate-multiple-impl.stderr +++ b/tests/ui/methods/disambiguate-multiple-impl.stderr @@ -1,18 +1,3 @@ -error[E0223]: ambiguous associated type - --> $DIR/disambiguate-multiple-impl.rs:32:12 - | -LL | let _: S::Type = (); - | ^^^^^^^ - | -help: use fully-qualified syntax - | -LL - let _: S::Type = (); -LL + let _: ::Type = (); - | -LL - let _: S::Type = (); -LL + let _: ::Type = (); - | - error[E0034]: multiple applicable items in scope --> $DIR/disambiguate-multiple-impl.rs:29:8 | @@ -38,6 +23,21 @@ LL - S::foo(&s); LL + B::foo(&s); | +error[E0223]: ambiguous associated type + --> $DIR/disambiguate-multiple-impl.rs:32:12 + | +LL | let _: S::Type = (); + | ^^^^^^^ + | +help: use fully-qualified syntax + | +LL - let _: S::Type = (); +LL + let _: ::Type = (); + | +LL - let _: S::Type = (); +LL + let _: ::Type = (); + | + error[E0034]: multiple applicable items in scope --> $DIR/disambiguate-multiple-impl.rs:34:16 | diff --git a/tests/ui/methods/disambiguate-multiple-trait-2.stderr b/tests/ui/methods/disambiguate-multiple-trait-2.stderr index 08e264c20c89..f9119e607501 100644 --- a/tests/ui/methods/disambiguate-multiple-trait-2.stderr +++ b/tests/ui/methods/disambiguate-multiple-trait-2.stderr @@ -1,26 +1,3 @@ -error[E0221]: ambiguous associated type `Type` in bounds of `T` - --> $DIR/disambiguate-multiple-trait-2.rs:23:12 - | -LL | type Type; - | --------- ambiguous `Type` from `A` -... -LL | type Type; - | --------- ambiguous `Type` from `B` -... -LL | let _: T::Type; - | ^^^^^^^ ambiguous associated type `Type` - | -help: use fully-qualified syntax to disambiguate - | -LL - let _: T::Type; -LL + let _: ::Type; - | -help: use fully-qualified syntax to disambiguate - | -LL - let _: T::Type; -LL + let _: ::Type; - | - error[E0034]: multiple applicable items in scope --> $DIR/disambiguate-multiple-trait-2.rs:16:7 | @@ -73,19 +50,27 @@ LL - let _ = T::CONST; LL + let _ = ::CONST; | -error[E0223]: ambiguous associated type - --> $DIR/disambiguate-multiple-trait-2.rs:52:12 +error[E0221]: ambiguous associated type `Type` in bounds of `T` + --> $DIR/disambiguate-multiple-trait-2.rs:23:12 | -LL | let _: S::Type; - | ^^^^^^^ +LL | type Type; + | --------- ambiguous `Type` from `A` +... +LL | type Type; + | --------- ambiguous `Type` from `B` +... +LL | let _: T::Type; + | ^^^^^^^ ambiguous associated type `Type` | -help: use fully-qualified syntax +help: use fully-qualified syntax to disambiguate | -LL - let _: S::Type; -LL + let _: ::Type; +LL - let _: T::Type; +LL + let _: ::Type; | -LL - let _: S::Type; -LL + let _: ::Type; +help: use fully-qualified syntax to disambiguate + | +LL - let _: T::Type; +LL + let _: ::Type; | error[E0034]: multiple applicable items in scope @@ -138,6 +123,21 @@ LL - let _ = S::CONST; LL + let _ = ::CONST; | +error[E0223]: ambiguous associated type + --> $DIR/disambiguate-multiple-trait-2.rs:52:12 + | +LL | let _: S::Type; + | ^^^^^^^ + | +help: use fully-qualified syntax + | +LL - let _: S::Type; +LL + let _: ::Type; + | +LL - let _: S::Type; +LL + let _: ::Type; + | + error: aborting due to 6 previous errors Some errors have detailed explanations: E0034, E0221, E0223. diff --git a/tests/ui/methods/disambiguate-multiple-trait.stderr b/tests/ui/methods/disambiguate-multiple-trait.stderr index a977fe2cd033..f35eec3b048c 100644 --- a/tests/ui/methods/disambiguate-multiple-trait.stderr +++ b/tests/ui/methods/disambiguate-multiple-trait.stderr @@ -1,18 +1,3 @@ -error[E0223]: ambiguous associated type - --> $DIR/disambiguate-multiple-trait.rs:30:12 - | -LL | let _: S::Type; - | ^^^^^^^ - | -help: use fully-qualified syntax - | -LL - let _: S::Type; -LL + let _: ::Type; - | -LL - let _: S::Type; -LL + let _: ::Type; - | - error[E0034]: multiple applicable items in scope --> $DIR/disambiguate-multiple-trait.rs:24:8 | @@ -63,6 +48,21 @@ LL - let _ = S::CONST; LL + let _ = ::CONST; | +error[E0223]: ambiguous associated type + --> $DIR/disambiguate-multiple-trait.rs:30:12 + | +LL | let _: S::Type; + | ^^^^^^^ + | +help: use fully-qualified syntax + | +LL - let _: S::Type; +LL + let _: ::Type; + | +LL - let _: S::Type; +LL + let _: ::Type; + | + error: aborting due to 3 previous errors Some errors have detailed explanations: E0034, E0223. diff --git a/tests/ui/mir/lint/assignment-overlap.rs b/tests/ui/mir/lint/assignment-overlap.rs index 950279b1555f..bbc140904671 100644 --- a/tests/ui/mir/lint/assignment-overlap.rs +++ b/tests/ui/mir/lint/assignment-overlap.rs @@ -2,7 +2,7 @@ //@ build-fail //@ failure-status: 101 //@ dont-check-compiler-stderr -//@ error-pattern: encountered `Assign` statement with overlapping memory + #![feature(custom_mir, core_intrinsics)] extern crate core; use core::intrinsics::mir::*; @@ -13,6 +13,7 @@ pub fn main() { let a: [u8; 1024]; { a = a; //~ ERROR broken MIR + //~^ ERROR encountered `Assign` statement with overlapping memory Return() } } diff --git a/tests/ui/mir/lint/call-overlap.rs b/tests/ui/mir/lint/call-overlap.rs index 3c42e04e3ec8..f43edfb87382 100644 --- a/tests/ui/mir/lint/call-overlap.rs +++ b/tests/ui/mir/lint/call-overlap.rs @@ -2,7 +2,7 @@ //@ build-fail //@ failure-status: 101 //@ dont-check-compiler-stderr -//@ error-pattern: encountered overlapping memory in `Move` arguments to `Call` + #![feature(custom_mir, core_intrinsics)] extern crate core; use core::intrinsics::mir::*; @@ -13,6 +13,7 @@ pub fn main() { let a: [u8; 1024]; { Call(a = f(Move(a)), ReturnTo(bb1), UnwindUnreachable()) //~ ERROR broken MIR + //~^ ERROR encountered overlapping memory in `Move` arguments to `Call` } bb1 = { Return() diff --git a/tests/ui/mir/lint/storage-live.rs b/tests/ui/mir/lint/storage-live.rs index 19d046b619c4..252e3b8456c2 100644 --- a/tests/ui/mir/lint/storage-live.rs +++ b/tests/ui/mir/lint/storage-live.rs @@ -1,7 +1,5 @@ //@ compile-flags: -Zlint-mir -Ztreat-err-as-bug //@ failure-status: 101 -//@ error-pattern: broken MIR in -//@ error-pattern: StorageLive(_1) which already has storage here //@ normalize-stderr: "note: .*\n\n" -> "" //@ normalize-stderr: "thread 'rustc' panicked.*\n" -> "" //@ normalize-stderr: "storage_live\[....\]" -> "storage_live[HASH]" @@ -21,6 +19,7 @@ fn multiple_storage() { { StorageLive(a); StorageLive(a); //~ ERROR broken MIR + //~| ERROR StorageLive(_1) which already has storage here Return() } } diff --git a/tests/ui/mir/lint/storage-live.stderr b/tests/ui/mir/lint/storage-live.stderr index 651b8e2327ee..50df9ae061fc 100644 --- a/tests/ui/mir/lint/storage-live.stderr +++ b/tests/ui/mir/lint/storage-live.stderr @@ -1,12 +1,12 @@ error: internal compiler error: broken MIR in Item(DefId(0:8 ~ storage_live[HASH]::multiple_storage)) (after pass CheckForceInline) at bb0[1]: StorageLive(_1) which already has storage here - --> $DIR/storage-live.rs:23:13 + --> $DIR/storage-live.rs:21:13 | LL | StorageLive(a); | ^^^^^^^^^^^^^^ | note: delayed at compiler/rustc_mir_transform/src/lint.rs:LL:CC - disabled backtrace - --> $DIR/storage-live.rs:23:13 + --> $DIR/storage-live.rs:21:13 | LL | StorageLive(a); | ^^^^^^^^^^^^^^ diff --git a/tests/ui/mir/lint/storage-return.rs b/tests/ui/mir/lint/storage-return.rs index 3bbd0045d9db..c3e1f00bd720 100644 --- a/tests/ui/mir/lint/storage-return.rs +++ b/tests/ui/mir/lint/storage-return.rs @@ -1,7 +1,7 @@ //@ compile-flags: -Zlint-mir -Ztreat-err-as-bug -Zeagerly-emit-delayed-bugs //@ failure-status: 101 //@ dont-check-compiler-stderr -//@ error-pattern: has storage when returning + #![feature(custom_mir, core_intrinsics)] extern crate core; use core::intrinsics::mir::*; @@ -14,6 +14,7 @@ fn main() { StorageLive(a); RET = a; Return() //~ ERROR broken MIR + //~^ ERROR has storage when returning } } } diff --git a/tests/ui/mir/validate/critical-edge.rs b/tests/ui/mir/validate/critical-edge.rs index 9048d08a22a7..2a3bf6a6181b 100644 --- a/tests/ui/mir/validate/critical-edge.rs +++ b/tests/ui/mir/validate/critical-edge.rs @@ -5,7 +5,7 @@ //@ compile-flags: --crate-type=lib //@ failure-status: 101 //@ dont-check-compiler-stderr -//@ error-pattern: encountered critical edge in `Call` terminator + #![feature(custom_mir, core_intrinsics)] use core::intrinsics::mir::*; @@ -29,3 +29,5 @@ pub fn f(a: u32) -> u32 { } } } + +//~? RAW encountered critical edge in `Call` terminator diff --git a/tests/ui/mismatched_types/dont-point-return-on-E0308.rs b/tests/ui/mismatched_types/dont-point-return-on-E0308.rs index dca917e3ba1e..750329d29c00 100644 --- a/tests/ui/mismatched_types/dont-point-return-on-E0308.rs +++ b/tests/ui/mismatched_types/dont-point-return-on-E0308.rs @@ -2,7 +2,6 @@ async fn f(_: &()) {} //~^ NOTE function defined here -//~| NOTE // Second note is the span of the underlined argument, I think... fn main() { diff --git a/tests/ui/mismatched_types/dont-point-return-on-E0308.stderr b/tests/ui/mismatched_types/dont-point-return-on-E0308.stderr index 9d4852cff8c6..105dc5c2e798 100644 --- a/tests/ui/mismatched_types/dont-point-return-on-E0308.stderr +++ b/tests/ui/mismatched_types/dont-point-return-on-E0308.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/dont-point-return-on-E0308.rs:11:11 + --> $DIR/dont-point-return-on-E0308.rs:10:11 | LL | f(()); | - ^^ expected `&()`, found `()` diff --git a/tests/ui/mismatched_types/similar_paths_primitive.rs b/tests/ui/mismatched_types/similar_paths_primitive.rs index b20ca80ac071..a58fe68b8638 100644 --- a/tests/ui/mismatched_types/similar_paths_primitive.rs +++ b/tests/ui/mismatched_types/similar_paths_primitive.rs @@ -4,9 +4,8 @@ struct bool; //~ NOTE the other `bool` is defined in the current crate struct str; //~ NOTE the other `str` is defined in the current crate fn foo(_: bool) {} //~ NOTE function defined here - //~^ NOTE fn bar(_: &str) {} //~ NOTE function defined here - //~^ NOTE + fn main() { foo(true); //~^ ERROR mismatched types [E0308] diff --git a/tests/ui/mismatched_types/similar_paths_primitive.stderr b/tests/ui/mismatched_types/similar_paths_primitive.stderr index 9c1aa0d7105b..cf26234dba85 100644 --- a/tests/ui/mismatched_types/similar_paths_primitive.stderr +++ b/tests/ui/mismatched_types/similar_paths_primitive.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/similar_paths_primitive.rs:11:9 + --> $DIR/similar_paths_primitive.rs:10:9 | LL | foo(true); | --- ^^^^ expected `bool`, found a different `bool` @@ -20,7 +20,7 @@ LL | fn foo(_: bool) {} | ^^^ ------- error[E0308]: mismatched types - --> $DIR/similar_paths_primitive.rs:17:9 + --> $DIR/similar_paths_primitive.rs:16:9 | LL | bar("hello"); | --- ^^^^^^^ expected `str`, found a different `str` @@ -35,7 +35,7 @@ note: the other `str` is defined in the current crate LL | struct str; | ^^^^^^^^^^ note: function defined here - --> $DIR/similar_paths_primitive.rs:8:4 + --> $DIR/similar_paths_primitive.rs:7:4 | LL | fn bar(_: &str) {} | ^^^ ------- diff --git a/tests/ui/nll/nested-bodies-in-dead-code.rs b/tests/ui/nll/nested-bodies-in-dead-code.rs new file mode 100644 index 000000000000..6ac68f5adbce --- /dev/null +++ b/tests/ui/nll/nested-bodies-in-dead-code.rs @@ -0,0 +1,28 @@ +//@ edition: 2024 + +// Regression test for #140583. We want to borrowck nested +// bodies even if they are in dead code. While not necessary for +// soundness, it is desirable to error in such cases. + +fn main() { + return; + |x: &str| -> &'static str { x }; + //~^ ERROR lifetime may not live long enough + || { + || { + let temp = 1; + let p: &'static u32 = &temp; + //~^ ERROR `temp` does not live long enough + }; + }; + const { + let temp = 1; + let p: &'static u32 = &temp; + //~^ ERROR `temp` does not live long enough + }; + async { + let temp = 1; + let p: &'static u32 = &temp; + //~^ ERROR `temp` does not live long enough + }; +} diff --git a/tests/ui/nll/nested-bodies-in-dead-code.stderr b/tests/ui/nll/nested-bodies-in-dead-code.stderr new file mode 100644 index 000000000000..da6ccff5777c --- /dev/null +++ b/tests/ui/nll/nested-bodies-in-dead-code.stderr @@ -0,0 +1,50 @@ +error: lifetime may not live long enough + --> $DIR/nested-bodies-in-dead-code.rs:9:33 + | +LL | |x: &str| -> &'static str { x }; + | - ^ returning this value requires that `'1` must outlive `'static` + | | + | let's call the lifetime of this reference `'1` + +error[E0597]: `temp` does not live long enough + --> $DIR/nested-bodies-in-dead-code.rs:14:35 + | +LL | let temp = 1; + | ---- binding `temp` declared here +LL | let p: &'static u32 = &temp; + | ------------ ^^^^^ borrowed value does not live long enough + | | + | type annotation requires that `temp` is borrowed for `'static` +LL | +LL | }; + | - `temp` dropped here while still borrowed + +error[E0597]: `temp` does not live long enough + --> $DIR/nested-bodies-in-dead-code.rs:20:31 + | +LL | let temp = 1; + | ---- binding `temp` declared here +LL | let p: &'static u32 = &temp; + | ------------ ^^^^^ borrowed value does not live long enough + | | + | type annotation requires that `temp` is borrowed for `'static` +LL | +LL | }; + | - `temp` dropped here while still borrowed + +error[E0597]: `temp` does not live long enough + --> $DIR/nested-bodies-in-dead-code.rs:25:31 + | +LL | let temp = 1; + | ---- binding `temp` declared here +LL | let p: &'static u32 = &temp; + | ------------ ^^^^^ borrowed value does not live long enough + | | + | type annotation requires that `temp` is borrowed for `'static` +LL | +LL | }; + | - `temp` dropped here while still borrowed + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0597`. diff --git a/tests/ui/no-link-unknown-crate.rs b/tests/ui/no-link-unknown-crate.rs deleted file mode 100644 index c7da2e41832f..000000000000 --- a/tests/ui/no-link-unknown-crate.rs +++ /dev/null @@ -1,4 +0,0 @@ -#[no_link] -extern crate doesnt_exist; //~ ERROR can't find crate - -fn main() {} diff --git a/tests/ui/numeric/numeric-suffix/numeric-suffix-i32.fixed b/tests/ui/numeric/numeric-suffix/numeric-suffix-i32.fixed index e3b613cc3f64..9f891afc313a 100644 --- a/tests/ui/numeric/numeric-suffix/numeric-suffix-i32.fixed +++ b/tests/ui/numeric/numeric-suffix/numeric-suffix-i32.fixed @@ -12,17 +12,6 @@ fn foo(_x: N) {} //~| NOTE function defined here //~| NOTE function defined here //~| NOTE function defined here -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE fn main() { foo::(42_i32); diff --git a/tests/ui/numeric/numeric-suffix/numeric-suffix-i32.rs b/tests/ui/numeric/numeric-suffix/numeric-suffix-i32.rs index 3b384e763107..a735fade86ed 100644 --- a/tests/ui/numeric/numeric-suffix/numeric-suffix-i32.rs +++ b/tests/ui/numeric/numeric-suffix/numeric-suffix-i32.rs @@ -12,17 +12,6 @@ fn foo(_x: N) {} //~| NOTE function defined here //~| NOTE function defined here //~| NOTE function defined here -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE fn main() { foo::(42_usize); diff --git a/tests/ui/numeric/numeric-suffix/numeric-suffix-i32.stderr b/tests/ui/numeric/numeric-suffix/numeric-suffix-i32.stderr index 6c6b8b51c226..b3450b41d38c 100644 --- a/tests/ui/numeric/numeric-suffix/numeric-suffix-i32.stderr +++ b/tests/ui/numeric/numeric-suffix/numeric-suffix-i32.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/numeric-suffix-i32.rs:28:16 + --> $DIR/numeric-suffix-i32.rs:17:16 | LL | foo::(42_usize); | ---------- ^^^^^^^^ expected `i32`, found `usize` @@ -18,7 +18,7 @@ LL + foo::(42_i32); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-i32.rs:32:16 + --> $DIR/numeric-suffix-i32.rs:21:16 | LL | foo::(42_u64); | ---------- ^^^^^^ expected `i32`, found `u64` @@ -37,7 +37,7 @@ LL + foo::(42_i32); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-i32.rs:36:16 + --> $DIR/numeric-suffix-i32.rs:25:16 | LL | foo::(42_u32); | ---------- ^^^^^^ expected `i32`, found `u32` @@ -56,7 +56,7 @@ LL + foo::(42_i32); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-i32.rs:40:16 + --> $DIR/numeric-suffix-i32.rs:29:16 | LL | foo::(42_u16); | ---------- ^^^^^^ expected `i32`, found `u16` @@ -75,7 +75,7 @@ LL + foo::(42_i32); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-i32.rs:44:16 + --> $DIR/numeric-suffix-i32.rs:33:16 | LL | foo::(42_u8); | ---------- ^^^^^ expected `i32`, found `u8` @@ -94,7 +94,7 @@ LL + foo::(42_i32); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-i32.rs:48:16 + --> $DIR/numeric-suffix-i32.rs:37:16 | LL | foo::(42_isize); | ---------- ^^^^^^^^ expected `i32`, found `isize` @@ -113,7 +113,7 @@ LL + foo::(42_i32); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-i32.rs:52:16 + --> $DIR/numeric-suffix-i32.rs:41:16 | LL | foo::(42_i64); | ---------- ^^^^^^ expected `i32`, found `i64` @@ -132,7 +132,7 @@ LL + foo::(42_i32); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-i32.rs:57:16 + --> $DIR/numeric-suffix-i32.rs:46:16 | LL | foo::(42_i16); | ---------- ^^^^^^ expected `i32`, found `i16` @@ -151,7 +151,7 @@ LL + foo::(42_i32); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-i32.rs:61:16 + --> $DIR/numeric-suffix-i32.rs:50:16 | LL | foo::(42_i8); | ---------- ^^^^^ expected `i32`, found `i8` @@ -170,7 +170,7 @@ LL + foo::(42_i32); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-i32.rs:65:16 + --> $DIR/numeric-suffix-i32.rs:54:16 | LL | foo::(42.0_f64); | ---------- ^^^^^^^^ expected `i32`, found `f64` @@ -189,7 +189,7 @@ LL + foo::(42i32); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-i32.rs:69:16 + --> $DIR/numeric-suffix-i32.rs:58:16 | LL | foo::(42.0_f32); | ---------- ^^^^^^^^ expected `i32`, found `f32` diff --git a/tests/ui/numeric/numeric-suffix/numeric-suffix-i64.fixed b/tests/ui/numeric/numeric-suffix/numeric-suffix-i64.fixed index 0fcda6c1f806..6d1c585a5639 100644 --- a/tests/ui/numeric/numeric-suffix/numeric-suffix-i64.fixed +++ b/tests/ui/numeric/numeric-suffix/numeric-suffix-i64.fixed @@ -12,17 +12,6 @@ fn foo(_x: N) {} //~| NOTE function defined here //~| NOTE function defined here //~| NOTE function defined here -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE fn main() { foo::(42_i64); diff --git a/tests/ui/numeric/numeric-suffix/numeric-suffix-i64.rs b/tests/ui/numeric/numeric-suffix/numeric-suffix-i64.rs index 9c912bc38dad..fd4862be3873 100644 --- a/tests/ui/numeric/numeric-suffix/numeric-suffix-i64.rs +++ b/tests/ui/numeric/numeric-suffix/numeric-suffix-i64.rs @@ -12,17 +12,6 @@ fn foo(_x: N) {} //~| NOTE function defined here //~| NOTE function defined here //~| NOTE function defined here -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE fn main() { foo::(42_usize); diff --git a/tests/ui/numeric/numeric-suffix/numeric-suffix-i64.stderr b/tests/ui/numeric/numeric-suffix/numeric-suffix-i64.stderr index 7c26dd7be1c6..63326f49a8f0 100644 --- a/tests/ui/numeric/numeric-suffix/numeric-suffix-i64.stderr +++ b/tests/ui/numeric/numeric-suffix/numeric-suffix-i64.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/numeric-suffix-i64.rs:28:16 + --> $DIR/numeric-suffix-i64.rs:17:16 | LL | foo::(42_usize); | ---------- ^^^^^^^^ expected `i64`, found `usize` @@ -18,7 +18,7 @@ LL + foo::(42_i64); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-i64.rs:32:16 + --> $DIR/numeric-suffix-i64.rs:21:16 | LL | foo::(42_u64); | ---------- ^^^^^^ expected `i64`, found `u64` @@ -37,7 +37,7 @@ LL + foo::(42_i64); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-i64.rs:36:16 + --> $DIR/numeric-suffix-i64.rs:25:16 | LL | foo::(42_u32); | ---------- ^^^^^^ expected `i64`, found `u32` @@ -56,7 +56,7 @@ LL + foo::(42_i64); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-i64.rs:40:16 + --> $DIR/numeric-suffix-i64.rs:29:16 | LL | foo::(42_u16); | ---------- ^^^^^^ expected `i64`, found `u16` @@ -75,7 +75,7 @@ LL + foo::(42_i64); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-i64.rs:44:16 + --> $DIR/numeric-suffix-i64.rs:33:16 | LL | foo::(42_u8); | ---------- ^^^^^ expected `i64`, found `u8` @@ -94,7 +94,7 @@ LL + foo::(42_i64); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-i64.rs:48:16 + --> $DIR/numeric-suffix-i64.rs:37:16 | LL | foo::(42_isize); | ---------- ^^^^^^^^ expected `i64`, found `isize` @@ -113,7 +113,7 @@ LL + foo::(42_i64); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-i64.rs:53:16 + --> $DIR/numeric-suffix-i64.rs:42:16 | LL | foo::(42_i32); | ---------- ^^^^^^ expected `i64`, found `i32` @@ -132,7 +132,7 @@ LL + foo::(42_i64); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-i64.rs:57:16 + --> $DIR/numeric-suffix-i64.rs:46:16 | LL | foo::(42_i16); | ---------- ^^^^^^ expected `i64`, found `i16` @@ -151,7 +151,7 @@ LL + foo::(42_i64); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-i64.rs:61:16 + --> $DIR/numeric-suffix-i64.rs:50:16 | LL | foo::(42_i8); | ---------- ^^^^^ expected `i64`, found `i8` @@ -170,7 +170,7 @@ LL + foo::(42_i64); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-i64.rs:65:16 + --> $DIR/numeric-suffix-i64.rs:54:16 | LL | foo::(42.0_f64); | ---------- ^^^^^^^^ expected `i64`, found `f64` @@ -189,7 +189,7 @@ LL + foo::(42i64); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-i64.rs:69:16 + --> $DIR/numeric-suffix-i64.rs:58:16 | LL | foo::(42.0_f32); | ---------- ^^^^^^^^ expected `i64`, found `f32` diff --git a/tests/ui/numeric/numeric-suffix/numeric-suffix-isize.fixed b/tests/ui/numeric/numeric-suffix/numeric-suffix-isize.fixed index 23e7cf780e9a..f24fce3f1d67 100644 --- a/tests/ui/numeric/numeric-suffix/numeric-suffix-isize.fixed +++ b/tests/ui/numeric/numeric-suffix/numeric-suffix-isize.fixed @@ -12,17 +12,6 @@ fn foo(_x: N) {} //~| NOTE function defined here //~| NOTE function defined here //~| NOTE function defined here -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE fn main() { foo::(42_isize); diff --git a/tests/ui/numeric/numeric-suffix/numeric-suffix-isize.rs b/tests/ui/numeric/numeric-suffix/numeric-suffix-isize.rs index 5d6fd4d932ac..fdf86895ff23 100644 --- a/tests/ui/numeric/numeric-suffix/numeric-suffix-isize.rs +++ b/tests/ui/numeric/numeric-suffix/numeric-suffix-isize.rs @@ -12,17 +12,6 @@ fn foo(_x: N) {} //~| NOTE function defined here //~| NOTE function defined here //~| NOTE function defined here -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE fn main() { foo::(42_usize); diff --git a/tests/ui/numeric/numeric-suffix/numeric-suffix-isize.stderr b/tests/ui/numeric/numeric-suffix/numeric-suffix-isize.stderr index 8365350f2bfe..99561b19021a 100644 --- a/tests/ui/numeric/numeric-suffix/numeric-suffix-isize.stderr +++ b/tests/ui/numeric/numeric-suffix/numeric-suffix-isize.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/numeric-suffix-isize.rs:28:18 + --> $DIR/numeric-suffix-isize.rs:17:18 | LL | foo::(42_usize); | ------------ ^^^^^^^^ expected `isize`, found `usize` @@ -18,7 +18,7 @@ LL + foo::(42_isize); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-isize.rs:32:18 + --> $DIR/numeric-suffix-isize.rs:21:18 | LL | foo::(42_u64); | ------------ ^^^^^^ expected `isize`, found `u64` @@ -37,7 +37,7 @@ LL + foo::(42_isize); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-isize.rs:36:18 + --> $DIR/numeric-suffix-isize.rs:25:18 | LL | foo::(42_u32); | ------------ ^^^^^^ expected `isize`, found `u32` @@ -56,7 +56,7 @@ LL + foo::(42_isize); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-isize.rs:40:18 + --> $DIR/numeric-suffix-isize.rs:29:18 | LL | foo::(42_u16); | ------------ ^^^^^^ expected `isize`, found `u16` @@ -75,7 +75,7 @@ LL + foo::(42_isize); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-isize.rs:44:18 + --> $DIR/numeric-suffix-isize.rs:33:18 | LL | foo::(42_u8); | ------------ ^^^^^ expected `isize`, found `u8` @@ -94,7 +94,7 @@ LL + foo::(42_isize); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-isize.rs:49:18 + --> $DIR/numeric-suffix-isize.rs:38:18 | LL | foo::(42_i64); | ------------ ^^^^^^ expected `isize`, found `i64` @@ -113,7 +113,7 @@ LL + foo::(42_isize); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-isize.rs:53:18 + --> $DIR/numeric-suffix-isize.rs:42:18 | LL | foo::(42_i32); | ------------ ^^^^^^ expected `isize`, found `i32` @@ -132,7 +132,7 @@ LL + foo::(42_isize); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-isize.rs:57:18 + --> $DIR/numeric-suffix-isize.rs:46:18 | LL | foo::(42_i16); | ------------ ^^^^^^ expected `isize`, found `i16` @@ -151,7 +151,7 @@ LL + foo::(42_isize); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-isize.rs:61:18 + --> $DIR/numeric-suffix-isize.rs:50:18 | LL | foo::(42_i8); | ------------ ^^^^^ expected `isize`, found `i8` @@ -170,7 +170,7 @@ LL + foo::(42_isize); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-isize.rs:65:18 + --> $DIR/numeric-suffix-isize.rs:54:18 | LL | foo::(42.0_f64); | ------------ ^^^^^^^^ expected `isize`, found `f64` @@ -189,7 +189,7 @@ LL + foo::(42isize); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-isize.rs:69:18 + --> $DIR/numeric-suffix-isize.rs:58:18 | LL | foo::(42.0_f32); | ------------ ^^^^^^^^ expected `isize`, found `f32` diff --git a/tests/ui/numeric/numeric-suffix/numeric-suffix-u32.fixed b/tests/ui/numeric/numeric-suffix/numeric-suffix-u32.fixed index 2dd7d9aabdb5..eba5d7c1c266 100644 --- a/tests/ui/numeric/numeric-suffix/numeric-suffix-u32.fixed +++ b/tests/ui/numeric/numeric-suffix/numeric-suffix-u32.fixed @@ -12,17 +12,6 @@ fn foo(_x: N) {} //~| NOTE function defined here //~| NOTE function defined here //~| NOTE function defined here -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE fn main() { foo::(42_u32); diff --git a/tests/ui/numeric/numeric-suffix/numeric-suffix-u32.rs b/tests/ui/numeric/numeric-suffix/numeric-suffix-u32.rs index 46bbb0331854..d127353e9754 100644 --- a/tests/ui/numeric/numeric-suffix/numeric-suffix-u32.rs +++ b/tests/ui/numeric/numeric-suffix/numeric-suffix-u32.rs @@ -12,17 +12,6 @@ fn foo(_x: N) {} //~| NOTE function defined here //~| NOTE function defined here //~| NOTE function defined here -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE fn main() { foo::(42_usize); diff --git a/tests/ui/numeric/numeric-suffix/numeric-suffix-u32.stderr b/tests/ui/numeric/numeric-suffix/numeric-suffix-u32.stderr index 610e6ece2769..95e913595e5e 100644 --- a/tests/ui/numeric/numeric-suffix/numeric-suffix-u32.stderr +++ b/tests/ui/numeric/numeric-suffix/numeric-suffix-u32.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/numeric-suffix-u32.rs:28:16 + --> $DIR/numeric-suffix-u32.rs:17:16 | LL | foo::(42_usize); | ---------- ^^^^^^^^ expected `u32`, found `usize` @@ -18,7 +18,7 @@ LL + foo::(42_u32); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-u32.rs:32:16 + --> $DIR/numeric-suffix-u32.rs:21:16 | LL | foo::(42_u64); | ---------- ^^^^^^ expected `u32`, found `u64` @@ -37,7 +37,7 @@ LL + foo::(42_u32); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-u32.rs:37:16 + --> $DIR/numeric-suffix-u32.rs:26:16 | LL | foo::(42_u16); | ---------- ^^^^^^ expected `u32`, found `u16` @@ -56,7 +56,7 @@ LL + foo::(42_u32); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-u32.rs:41:16 + --> $DIR/numeric-suffix-u32.rs:30:16 | LL | foo::(42_u8); | ---------- ^^^^^ expected `u32`, found `u8` @@ -75,7 +75,7 @@ LL + foo::(42_u32); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-u32.rs:45:16 + --> $DIR/numeric-suffix-u32.rs:34:16 | LL | foo::(42_isize); | ---------- ^^^^^^^^ expected `u32`, found `isize` @@ -94,7 +94,7 @@ LL + foo::(42_u32); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-u32.rs:49:16 + --> $DIR/numeric-suffix-u32.rs:38:16 | LL | foo::(42_i64); | ---------- ^^^^^^ expected `u32`, found `i64` @@ -113,7 +113,7 @@ LL + foo::(42_u32); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-u32.rs:53:16 + --> $DIR/numeric-suffix-u32.rs:42:16 | LL | foo::(42_i32); | ---------- ^^^^^^ expected `u32`, found `i32` @@ -132,7 +132,7 @@ LL + foo::(42_u32); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-u32.rs:57:16 + --> $DIR/numeric-suffix-u32.rs:46:16 | LL | foo::(42_i16); | ---------- ^^^^^^ expected `u32`, found `i16` @@ -151,7 +151,7 @@ LL + foo::(42_u32); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-u32.rs:61:16 + --> $DIR/numeric-suffix-u32.rs:50:16 | LL | foo::(42_i8); | ---------- ^^^^^ expected `u32`, found `i8` @@ -170,7 +170,7 @@ LL + foo::(42_u32); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-u32.rs:65:16 + --> $DIR/numeric-suffix-u32.rs:54:16 | LL | foo::(42.0_f64); | ---------- ^^^^^^^^ expected `u32`, found `f64` @@ -189,7 +189,7 @@ LL + foo::(42u32); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-u32.rs:69:16 + --> $DIR/numeric-suffix-u32.rs:58:16 | LL | foo::(42.0_f32); | ---------- ^^^^^^^^ expected `u32`, found `f32` diff --git a/tests/ui/numeric/numeric-suffix/numeric-suffix-u64.fixed b/tests/ui/numeric/numeric-suffix/numeric-suffix-u64.fixed index 2dea195f0981..c8344211d3d0 100644 --- a/tests/ui/numeric/numeric-suffix/numeric-suffix-u64.fixed +++ b/tests/ui/numeric/numeric-suffix/numeric-suffix-u64.fixed @@ -12,17 +12,6 @@ fn foo(_x: N) {} //~| NOTE function defined here //~| NOTE function defined here //~| NOTE function defined here -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE fn main() { foo::(42_u64); diff --git a/tests/ui/numeric/numeric-suffix/numeric-suffix-u64.rs b/tests/ui/numeric/numeric-suffix/numeric-suffix-u64.rs index 6fca089b07d4..f9b35efbc4be 100644 --- a/tests/ui/numeric/numeric-suffix/numeric-suffix-u64.rs +++ b/tests/ui/numeric/numeric-suffix/numeric-suffix-u64.rs @@ -12,17 +12,6 @@ fn foo(_x: N) {} //~| NOTE function defined here //~| NOTE function defined here //~| NOTE function defined here -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE fn main() { foo::(42_usize); diff --git a/tests/ui/numeric/numeric-suffix/numeric-suffix-u64.stderr b/tests/ui/numeric/numeric-suffix/numeric-suffix-u64.stderr index 112dddccd6f4..0c92b4137614 100644 --- a/tests/ui/numeric/numeric-suffix/numeric-suffix-u64.stderr +++ b/tests/ui/numeric/numeric-suffix/numeric-suffix-u64.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/numeric-suffix-u64.rs:28:16 + --> $DIR/numeric-suffix-u64.rs:17:16 | LL | foo::(42_usize); | ---------- ^^^^^^^^ expected `u64`, found `usize` @@ -18,7 +18,7 @@ LL + foo::(42_u64); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-u64.rs:33:16 + --> $DIR/numeric-suffix-u64.rs:22:16 | LL | foo::(42_u32); | ---------- ^^^^^^ expected `u64`, found `u32` @@ -37,7 +37,7 @@ LL + foo::(42_u64); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-u64.rs:37:16 + --> $DIR/numeric-suffix-u64.rs:26:16 | LL | foo::(42_u16); | ---------- ^^^^^^ expected `u64`, found `u16` @@ -56,7 +56,7 @@ LL + foo::(42_u64); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-u64.rs:41:16 + --> $DIR/numeric-suffix-u64.rs:30:16 | LL | foo::(42_u8); | ---------- ^^^^^ expected `u64`, found `u8` @@ -75,7 +75,7 @@ LL + foo::(42_u64); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-u64.rs:45:16 + --> $DIR/numeric-suffix-u64.rs:34:16 | LL | foo::(42_isize); | ---------- ^^^^^^^^ expected `u64`, found `isize` @@ -94,7 +94,7 @@ LL + foo::(42_u64); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-u64.rs:49:16 + --> $DIR/numeric-suffix-u64.rs:38:16 | LL | foo::(42_i64); | ---------- ^^^^^^ expected `u64`, found `i64` @@ -113,7 +113,7 @@ LL + foo::(42_u64); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-u64.rs:53:16 + --> $DIR/numeric-suffix-u64.rs:42:16 | LL | foo::(42_i32); | ---------- ^^^^^^ expected `u64`, found `i32` @@ -132,7 +132,7 @@ LL + foo::(42_u64); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-u64.rs:57:16 + --> $DIR/numeric-suffix-u64.rs:46:16 | LL | foo::(42_i16); | ---------- ^^^^^^ expected `u64`, found `i16` @@ -151,7 +151,7 @@ LL + foo::(42_u64); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-u64.rs:61:16 + --> $DIR/numeric-suffix-u64.rs:50:16 | LL | foo::(42_i8); | ---------- ^^^^^ expected `u64`, found `i8` @@ -170,7 +170,7 @@ LL + foo::(42_u64); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-u64.rs:65:16 + --> $DIR/numeric-suffix-u64.rs:54:16 | LL | foo::(42.0_f64); | ---------- ^^^^^^^^ expected `u64`, found `f64` @@ -189,7 +189,7 @@ LL + foo::(42u64); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-u64.rs:69:16 + --> $DIR/numeric-suffix-u64.rs:58:16 | LL | foo::(42.0_f32); | ---------- ^^^^^^^^ expected `u64`, found `f32` diff --git a/tests/ui/numeric/numeric-suffix/numeric-suffix-usize.fixed b/tests/ui/numeric/numeric-suffix/numeric-suffix-usize.fixed index 63422c305d35..4d5176fe7245 100644 --- a/tests/ui/numeric/numeric-suffix/numeric-suffix-usize.fixed +++ b/tests/ui/numeric/numeric-suffix/numeric-suffix-usize.fixed @@ -12,17 +12,6 @@ fn foo(_x: N) {} //~| NOTE function defined here //~| NOTE function defined here //~| NOTE function defined here -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE fn main() { foo::(42_usize); diff --git a/tests/ui/numeric/numeric-suffix/numeric-suffix-usize.rs b/tests/ui/numeric/numeric-suffix/numeric-suffix-usize.rs index 4d20e4fc8431..118d8ca219ec 100644 --- a/tests/ui/numeric/numeric-suffix/numeric-suffix-usize.rs +++ b/tests/ui/numeric/numeric-suffix/numeric-suffix-usize.rs @@ -12,17 +12,6 @@ fn foo(_x: N) {} //~| NOTE function defined here //~| NOTE function defined here //~| NOTE function defined here -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE fn main() { foo::(42_usize); diff --git a/tests/ui/numeric/numeric-suffix/numeric-suffix-usize.stderr b/tests/ui/numeric/numeric-suffix/numeric-suffix-usize.stderr index e7d6a04f18ef..86181d6714f5 100644 --- a/tests/ui/numeric/numeric-suffix/numeric-suffix-usize.stderr +++ b/tests/ui/numeric/numeric-suffix/numeric-suffix-usize.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/numeric-suffix-usize.rs:29:18 + --> $DIR/numeric-suffix-usize.rs:18:18 | LL | foo::(42_u64); | ------------ ^^^^^^ expected `usize`, found `u64` @@ -18,7 +18,7 @@ LL + foo::(42_usize); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-usize.rs:33:18 + --> $DIR/numeric-suffix-usize.rs:22:18 | LL | foo::(42_u32); | ------------ ^^^^^^ expected `usize`, found `u32` @@ -37,7 +37,7 @@ LL + foo::(42_usize); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-usize.rs:37:18 + --> $DIR/numeric-suffix-usize.rs:26:18 | LL | foo::(42_u16); | ------------ ^^^^^^ expected `usize`, found `u16` @@ -56,7 +56,7 @@ LL + foo::(42_usize); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-usize.rs:41:18 + --> $DIR/numeric-suffix-usize.rs:30:18 | LL | foo::(42_u8); | ------------ ^^^^^ expected `usize`, found `u8` @@ -75,7 +75,7 @@ LL + foo::(42_usize); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-usize.rs:45:18 + --> $DIR/numeric-suffix-usize.rs:34:18 | LL | foo::(42_isize); | ------------ ^^^^^^^^ expected `usize`, found `isize` @@ -94,7 +94,7 @@ LL + foo::(42_usize); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-usize.rs:49:18 + --> $DIR/numeric-suffix-usize.rs:38:18 | LL | foo::(42_i64); | ------------ ^^^^^^ expected `usize`, found `i64` @@ -113,7 +113,7 @@ LL + foo::(42_usize); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-usize.rs:53:18 + --> $DIR/numeric-suffix-usize.rs:42:18 | LL | foo::(42_i32); | ------------ ^^^^^^ expected `usize`, found `i32` @@ -132,7 +132,7 @@ LL + foo::(42_usize); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-usize.rs:57:18 + --> $DIR/numeric-suffix-usize.rs:46:18 | LL | foo::(42_i16); | ------------ ^^^^^^ expected `usize`, found `i16` @@ -151,7 +151,7 @@ LL + foo::(42_usize); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-usize.rs:61:18 + --> $DIR/numeric-suffix-usize.rs:50:18 | LL | foo::(42_i8); | ------------ ^^^^^ expected `usize`, found `i8` @@ -170,7 +170,7 @@ LL + foo::(42_usize); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-usize.rs:65:18 + --> $DIR/numeric-suffix-usize.rs:54:18 | LL | foo::(42.0_f64); | ------------ ^^^^^^^^ expected `usize`, found `f64` @@ -189,7 +189,7 @@ LL + foo::(42usize); | error[E0308]: mismatched types - --> $DIR/numeric-suffix-usize.rs:69:18 + --> $DIR/numeric-suffix-usize.rs:58:18 | LL | foo::(42.0_f32); | ------------ ^^^^^^^^ expected `usize`, found `f32` diff --git a/tests/ui/numeric/numeric-suffix/numeric-suffix.fixed b/tests/ui/numeric/numeric-suffix/numeric-suffix.fixed index 270afb639575..b20b594dc2c3 100644 --- a/tests/ui/numeric/numeric-suffix/numeric-suffix.fixed +++ b/tests/ui/numeric/numeric-suffix/numeric-suffix.fixed @@ -69,75 +69,6 @@ fn foo(_x: N) {} //~| NOTE function defined here //~| NOTE function defined here //~| NOTE function defined here -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE - fn main() { foo::(42_u16); diff --git a/tests/ui/numeric/numeric-suffix/numeric-suffix.rs b/tests/ui/numeric/numeric-suffix/numeric-suffix.rs index 05be58e335bc..9272902f5190 100644 --- a/tests/ui/numeric/numeric-suffix/numeric-suffix.rs +++ b/tests/ui/numeric/numeric-suffix/numeric-suffix.rs @@ -69,75 +69,6 @@ fn foo(_x: N) {} //~| NOTE function defined here //~| NOTE function defined here //~| NOTE function defined here -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE -//~| NOTE - fn main() { foo::(42_usize); diff --git a/tests/ui/numeric/numeric-suffix/numeric-suffix.stderr b/tests/ui/numeric/numeric-suffix/numeric-suffix.stderr index d26639a76f0f..cae1268beec0 100644 --- a/tests/ui/numeric/numeric-suffix/numeric-suffix.stderr +++ b/tests/ui/numeric/numeric-suffix/numeric-suffix.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:143:16 + --> $DIR/numeric-suffix.rs:74:16 | LL | foo::(42_usize); | ---------- ^^^^^^^^ expected `u16`, found `usize` @@ -18,7 +18,7 @@ LL + foo::(42_u16); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:147:16 + --> $DIR/numeric-suffix.rs:78:16 | LL | foo::(42_u64); | ---------- ^^^^^^ expected `u16`, found `u64` @@ -37,7 +37,7 @@ LL + foo::(42_u16); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:151:16 + --> $DIR/numeric-suffix.rs:82:16 | LL | foo::(42_u32); | ---------- ^^^^^^ expected `u16`, found `u32` @@ -56,7 +56,7 @@ LL + foo::(42_u16); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:156:16 + --> $DIR/numeric-suffix.rs:87:16 | LL | foo::(42_u8); | ---------- ^^^^^ expected `u16`, found `u8` @@ -75,7 +75,7 @@ LL + foo::(42_u16); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:160:16 + --> $DIR/numeric-suffix.rs:91:16 | LL | foo::(42_isize); | ---------- ^^^^^^^^ expected `u16`, found `isize` @@ -94,7 +94,7 @@ LL + foo::(42_u16); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:164:16 + --> $DIR/numeric-suffix.rs:95:16 | LL | foo::(42_i64); | ---------- ^^^^^^ expected `u16`, found `i64` @@ -113,7 +113,7 @@ LL + foo::(42_u16); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:168:16 + --> $DIR/numeric-suffix.rs:99:16 | LL | foo::(42_i32); | ---------- ^^^^^^ expected `u16`, found `i32` @@ -132,7 +132,7 @@ LL + foo::(42_u16); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:172:16 + --> $DIR/numeric-suffix.rs:103:16 | LL | foo::(42_i16); | ---------- ^^^^^^ expected `u16`, found `i16` @@ -151,7 +151,7 @@ LL + foo::(42_u16); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:176:16 + --> $DIR/numeric-suffix.rs:107:16 | LL | foo::(42_i8); | ---------- ^^^^^ expected `u16`, found `i8` @@ -170,7 +170,7 @@ LL + foo::(42_u16); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:180:16 + --> $DIR/numeric-suffix.rs:111:16 | LL | foo::(42.0_f64); | ---------- ^^^^^^^^ expected `u16`, found `f64` @@ -189,7 +189,7 @@ LL + foo::(42u16); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:184:16 + --> $DIR/numeric-suffix.rs:115:16 | LL | foo::(42.0_f32); | ---------- ^^^^^^^^ expected `u16`, found `f32` @@ -208,7 +208,7 @@ LL + foo::(42u16); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:189:16 + --> $DIR/numeric-suffix.rs:120:16 | LL | foo::(42_usize); | ---------- ^^^^^^^^ expected `i16`, found `usize` @@ -227,7 +227,7 @@ LL + foo::(42_i16); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:193:16 + --> $DIR/numeric-suffix.rs:124:16 | LL | foo::(42_u64); | ---------- ^^^^^^ expected `i16`, found `u64` @@ -246,7 +246,7 @@ LL + foo::(42_i16); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:197:16 + --> $DIR/numeric-suffix.rs:128:16 | LL | foo::(42_u32); | ---------- ^^^^^^ expected `i16`, found `u32` @@ -265,7 +265,7 @@ LL + foo::(42_i16); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:201:16 + --> $DIR/numeric-suffix.rs:132:16 | LL | foo::(42_u16); | ---------- ^^^^^^ expected `i16`, found `u16` @@ -284,7 +284,7 @@ LL + foo::(42_i16); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:205:16 + --> $DIR/numeric-suffix.rs:136:16 | LL | foo::(42_u8); | ---------- ^^^^^ expected `i16`, found `u8` @@ -303,7 +303,7 @@ LL + foo::(42_i16); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:209:16 + --> $DIR/numeric-suffix.rs:140:16 | LL | foo::(42_isize); | ---------- ^^^^^^^^ expected `i16`, found `isize` @@ -322,7 +322,7 @@ LL + foo::(42_i16); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:213:16 + --> $DIR/numeric-suffix.rs:144:16 | LL | foo::(42_i64); | ---------- ^^^^^^ expected `i16`, found `i64` @@ -341,7 +341,7 @@ LL + foo::(42_i16); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:217:16 + --> $DIR/numeric-suffix.rs:148:16 | LL | foo::(42_i32); | ---------- ^^^^^^ expected `i16`, found `i32` @@ -360,7 +360,7 @@ LL + foo::(42_i16); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:222:16 + --> $DIR/numeric-suffix.rs:153:16 | LL | foo::(42_i8); | ---------- ^^^^^ expected `i16`, found `i8` @@ -379,7 +379,7 @@ LL + foo::(42_i16); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:226:16 + --> $DIR/numeric-suffix.rs:157:16 | LL | foo::(42.0_f64); | ---------- ^^^^^^^^ expected `i16`, found `f64` @@ -398,7 +398,7 @@ LL + foo::(42i16); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:230:16 + --> $DIR/numeric-suffix.rs:161:16 | LL | foo::(42.0_f32); | ---------- ^^^^^^^^ expected `i16`, found `f32` @@ -417,7 +417,7 @@ LL + foo::(42i16); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:235:15 + --> $DIR/numeric-suffix.rs:166:15 | LL | foo::(42_usize); | --------- ^^^^^^^^ expected `u8`, found `usize` @@ -436,7 +436,7 @@ LL + foo::(42_u8); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:239:15 + --> $DIR/numeric-suffix.rs:170:15 | LL | foo::(42_u64); | --------- ^^^^^^ expected `u8`, found `u64` @@ -455,7 +455,7 @@ LL + foo::(42_u8); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:243:15 + --> $DIR/numeric-suffix.rs:174:15 | LL | foo::(42_u32); | --------- ^^^^^^ expected `u8`, found `u32` @@ -474,7 +474,7 @@ LL + foo::(42_u8); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:247:15 + --> $DIR/numeric-suffix.rs:178:15 | LL | foo::(42_u16); | --------- ^^^^^^ expected `u8`, found `u16` @@ -493,7 +493,7 @@ LL + foo::(42_u8); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:252:15 + --> $DIR/numeric-suffix.rs:183:15 | LL | foo::(42_isize); | --------- ^^^^^^^^ expected `u8`, found `isize` @@ -512,7 +512,7 @@ LL + foo::(42_u8); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:256:15 + --> $DIR/numeric-suffix.rs:187:15 | LL | foo::(42_i64); | --------- ^^^^^^ expected `u8`, found `i64` @@ -531,7 +531,7 @@ LL + foo::(42_u8); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:260:15 + --> $DIR/numeric-suffix.rs:191:15 | LL | foo::(42_i32); | --------- ^^^^^^ expected `u8`, found `i32` @@ -550,7 +550,7 @@ LL + foo::(42_u8); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:264:15 + --> $DIR/numeric-suffix.rs:195:15 | LL | foo::(42_i16); | --------- ^^^^^^ expected `u8`, found `i16` @@ -569,7 +569,7 @@ LL + foo::(42_u8); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:268:15 + --> $DIR/numeric-suffix.rs:199:15 | LL | foo::(42_i8); | --------- ^^^^^ expected `u8`, found `i8` @@ -588,7 +588,7 @@ LL + foo::(42_u8); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:272:15 + --> $DIR/numeric-suffix.rs:203:15 | LL | foo::(42.0_f64); | --------- ^^^^^^^^ expected `u8`, found `f64` @@ -607,7 +607,7 @@ LL + foo::(42u8); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:276:15 + --> $DIR/numeric-suffix.rs:207:15 | LL | foo::(42.0_f32); | --------- ^^^^^^^^ expected `u8`, found `f32` @@ -626,7 +626,7 @@ LL + foo::(42u8); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:281:15 + --> $DIR/numeric-suffix.rs:212:15 | LL | foo::(42_usize); | --------- ^^^^^^^^ expected `i8`, found `usize` @@ -645,7 +645,7 @@ LL + foo::(42_i8); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:285:15 + --> $DIR/numeric-suffix.rs:216:15 | LL | foo::(42_u64); | --------- ^^^^^^ expected `i8`, found `u64` @@ -664,7 +664,7 @@ LL + foo::(42_i8); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:289:15 + --> $DIR/numeric-suffix.rs:220:15 | LL | foo::(42_u32); | --------- ^^^^^^ expected `i8`, found `u32` @@ -683,7 +683,7 @@ LL + foo::(42_i8); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:293:15 + --> $DIR/numeric-suffix.rs:224:15 | LL | foo::(42_u16); | --------- ^^^^^^ expected `i8`, found `u16` @@ -702,7 +702,7 @@ LL + foo::(42_i8); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:297:15 + --> $DIR/numeric-suffix.rs:228:15 | LL | foo::(42_u8); | --------- ^^^^^ expected `i8`, found `u8` @@ -721,7 +721,7 @@ LL + foo::(42_i8); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:301:15 + --> $DIR/numeric-suffix.rs:232:15 | LL | foo::(42_isize); | --------- ^^^^^^^^ expected `i8`, found `isize` @@ -740,7 +740,7 @@ LL + foo::(42_i8); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:305:15 + --> $DIR/numeric-suffix.rs:236:15 | LL | foo::(42_i64); | --------- ^^^^^^ expected `i8`, found `i64` @@ -759,7 +759,7 @@ LL + foo::(42_i8); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:309:15 + --> $DIR/numeric-suffix.rs:240:15 | LL | foo::(42_i32); | --------- ^^^^^^ expected `i8`, found `i32` @@ -778,7 +778,7 @@ LL + foo::(42_i8); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:313:15 + --> $DIR/numeric-suffix.rs:244:15 | LL | foo::(42_i16); | --------- ^^^^^^ expected `i8`, found `i16` @@ -797,7 +797,7 @@ LL + foo::(42_i8); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:318:15 + --> $DIR/numeric-suffix.rs:249:15 | LL | foo::(42.0_f64); | --------- ^^^^^^^^ expected `i8`, found `f64` @@ -816,7 +816,7 @@ LL + foo::(42i8); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:322:15 + --> $DIR/numeric-suffix.rs:253:15 | LL | foo::(42.0_f32); | --------- ^^^^^^^^ expected `i8`, found `f32` @@ -835,7 +835,7 @@ LL + foo::(42i8); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:327:16 + --> $DIR/numeric-suffix.rs:258:16 | LL | foo::(42_usize); | ---------- ^^^^^^^^ expected `f64`, found `usize` @@ -854,7 +854,7 @@ LL + foo::(42_f64); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:331:16 + --> $DIR/numeric-suffix.rs:262:16 | LL | foo::(42_u64); | ---------- ^^^^^^ expected `f64`, found `u64` @@ -873,7 +873,7 @@ LL + foo::(42_f64); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:335:16 + --> $DIR/numeric-suffix.rs:266:16 | LL | foo::(42_u32); | ---------- ^^^^^^ expected `f64`, found `u32` @@ -891,7 +891,7 @@ LL | foo::(42_u32.into()); | +++++++ error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:339:16 + --> $DIR/numeric-suffix.rs:270:16 | LL | foo::(42_u16); | ---------- ^^^^^^ expected `f64`, found `u16` @@ -909,7 +909,7 @@ LL | foo::(42_u16.into()); | +++++++ error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:343:16 + --> $DIR/numeric-suffix.rs:274:16 | LL | foo::(42_u8); | ---------- ^^^^^ expected `f64`, found `u8` @@ -927,7 +927,7 @@ LL | foo::(42_u8.into()); | +++++++ error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:347:16 + --> $DIR/numeric-suffix.rs:278:16 | LL | foo::(42_isize); | ---------- ^^^^^^^^ expected `f64`, found `isize` @@ -946,7 +946,7 @@ LL + foo::(42_f64); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:351:16 + --> $DIR/numeric-suffix.rs:282:16 | LL | foo::(42_i64); | ---------- ^^^^^^ expected `f64`, found `i64` @@ -965,7 +965,7 @@ LL + foo::(42_f64); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:355:16 + --> $DIR/numeric-suffix.rs:286:16 | LL | foo::(42_i32); | ---------- ^^^^^^ expected `f64`, found `i32` @@ -983,7 +983,7 @@ LL | foo::(42_i32.into()); | +++++++ error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:359:16 + --> $DIR/numeric-suffix.rs:290:16 | LL | foo::(42_i16); | ---------- ^^^^^^ expected `f64`, found `i16` @@ -1001,7 +1001,7 @@ LL | foo::(42_i16.into()); | +++++++ error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:363:16 + --> $DIR/numeric-suffix.rs:294:16 | LL | foo::(42_i8); | ---------- ^^^^^ expected `f64`, found `i8` @@ -1019,7 +1019,7 @@ LL | foo::(42_i8.into()); | +++++++ error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:368:16 + --> $DIR/numeric-suffix.rs:299:16 | LL | foo::(42.0_f32); | ---------- ^^^^^^^^ expected `f64`, found `f32` @@ -1038,7 +1038,7 @@ LL + foo::(42.0_f64); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:373:16 + --> $DIR/numeric-suffix.rs:304:16 | LL | foo::(42_usize); | ---------- ^^^^^^^^ expected `f32`, found `usize` @@ -1057,7 +1057,7 @@ LL + foo::(42_f32); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:377:16 + --> $DIR/numeric-suffix.rs:308:16 | LL | foo::(42_u64); | ---------- ^^^^^^ expected `f32`, found `u64` @@ -1076,7 +1076,7 @@ LL + foo::(42_f32); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:381:16 + --> $DIR/numeric-suffix.rs:312:16 | LL | foo::(42_u32); | ---------- ^^^^^^ expected `f32`, found `u32` @@ -1095,7 +1095,7 @@ LL + foo::(42_f32); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:385:16 + --> $DIR/numeric-suffix.rs:316:16 | LL | foo::(42_u16); | ---------- ^^^^^^ expected `f32`, found `u16` @@ -1113,7 +1113,7 @@ LL | foo::(42_u16.into()); | +++++++ error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:389:16 + --> $DIR/numeric-suffix.rs:320:16 | LL | foo::(42_u8); | ---------- ^^^^^ expected `f32`, found `u8` @@ -1131,7 +1131,7 @@ LL | foo::(42_u8.into()); | +++++++ error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:393:16 + --> $DIR/numeric-suffix.rs:324:16 | LL | foo::(42_isize); | ---------- ^^^^^^^^ expected `f32`, found `isize` @@ -1150,7 +1150,7 @@ LL + foo::(42_f32); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:397:16 + --> $DIR/numeric-suffix.rs:328:16 | LL | foo::(42_i64); | ---------- ^^^^^^ expected `f32`, found `i64` @@ -1169,7 +1169,7 @@ LL + foo::(42_f32); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:401:16 + --> $DIR/numeric-suffix.rs:332:16 | LL | foo::(42_i32); | ---------- ^^^^^^ expected `f32`, found `i32` @@ -1188,7 +1188,7 @@ LL + foo::(42_f32); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:405:16 + --> $DIR/numeric-suffix.rs:336:16 | LL | foo::(42_i16); | ---------- ^^^^^^ expected `f32`, found `i16` @@ -1206,7 +1206,7 @@ LL | foo::(42_i16.into()); | +++++++ error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:409:16 + --> $DIR/numeric-suffix.rs:340:16 | LL | foo::(42_i8); | ---------- ^^^^^ expected `f32`, found `i8` @@ -1224,7 +1224,7 @@ LL | foo::(42_i8.into()); | +++++++ error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:413:16 + --> $DIR/numeric-suffix.rs:344:16 | LL | foo::(42.0_f64); | ---------- ^^^^^^^^ expected `f32`, found `f64` @@ -1243,7 +1243,7 @@ LL + foo::(42.0_f32); | error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:419:16 + --> $DIR/numeric-suffix.rs:350:16 | LL | foo::(42_u8 as u16); | ---------- ^^^^^^^^^^^^ expected `u32`, found `u16` @@ -1261,7 +1261,7 @@ LL | foo::((42_u8 as u16).into()); | + ++++++++ error[E0308]: mismatched types - --> $DIR/numeric-suffix.rs:423:16 + --> $DIR/numeric-suffix.rs:354:16 | LL | foo::(-42_i8); | ---------- ^^^^^^ expected `i32`, found `i8` diff --git a/tests/ui/on-unimplemented/bad-annotation.rs b/tests/ui/on-unimplemented/bad-annotation.rs index f2b978657597..25de59781102 100644 --- a/tests/ui/on-unimplemented/bad-annotation.rs +++ b/tests/ui/on-unimplemented/bad-annotation.rs @@ -1,64 +1,109 @@ -// ignore-tidy-linelength - +#![crate_type = "lib"] #![feature(rustc_attrs)] - #![allow(unused)] #[rustc_on_unimplemented = "test error `{Self}` with `{Bar}` `{Baz}` `{Quux}`"] -trait Foo -{} +trait Foo {} -#[rustc_on_unimplemented="a collection of type `{Self}` cannot be built from an iterator over elements of type `{A}`"] +#[rustc_on_unimplemented = "a collection of type `{Self}` cannot \ + be built from an iterator over elements of type `{A}`"] trait MyFromIterator { /// Builds a container with elements from an external iterator. - fn my_from_iter>(iterator: T) -> Self; + fn my_from_iter>(iterator: T) -> Self; } #[rustc_on_unimplemented] //~^ ERROR malformed `rustc_on_unimplemented` attribute -trait BadAnnotation1 -{} +trait NoContent {} #[rustc_on_unimplemented = "Unimplemented trait error on `{Self}` with params `<{A},{B},{C}>`"] //~^ ERROR cannot find parameter C on this trait -trait BadAnnotation2 -{} +trait ParameterNotPresent {} #[rustc_on_unimplemented = "Unimplemented trait error on `{Self}` with params `<{A},{B},{}>`"] //~^ ERROR positional format arguments are not allowed here -trait BadAnnotation3 -{} +trait NoPositionalArgs {} -#[rustc_on_unimplemented(lorem="")] -//~^ ERROR this attribute must have a valid -trait BadAnnotation4 {} +#[rustc_on_unimplemented(lorem = "")] +//~^ ERROR this attribute must have a value +//~^^ NOTE e.g. `#[rustc_on_unimplemented(message="foo")]` +//~^^^ NOTE expected value here +trait EmptyMessage {} #[rustc_on_unimplemented(lorem(ipsum(dolor)))] -//~^ ERROR this attribute must have a valid -trait BadAnnotation5 {} +//~^ ERROR this attribute must have a value +//~^^ NOTE e.g. `#[rustc_on_unimplemented(message="foo")]` +//~^^^ NOTE expected value here +trait Invalid {} -#[rustc_on_unimplemented(message="x", message="y")] -//~^ ERROR this attribute must have a valid -trait BadAnnotation6 {} +#[rustc_on_unimplemented(message = "x", message = "y")] +//~^ ERROR this attribute must have a value +//~^^ NOTE e.g. `#[rustc_on_unimplemented(message="foo")]` +//~^^^ NOTE expected value here +trait DuplicateMessage {} -#[rustc_on_unimplemented(message="x", on(desugared, message="y"))] -//~^ ERROR this attribute must have a valid -trait BadAnnotation7 {} +#[rustc_on_unimplemented(message = "x", on(desugared, message = "y"))] +//~^ ERROR this attribute must have a value +//~^^ NOTE e.g. `#[rustc_on_unimplemented(message="foo")]` +//~^^^ NOTE expected value here +trait OnInWrongPosition {} -#[rustc_on_unimplemented(on(), message="y")] +#[rustc_on_unimplemented(on(), message = "y")] //~^ ERROR empty `on`-clause -trait BadAnnotation8 {} +//~^^ NOTE empty `on`-clause here +trait EmptyOn {} -#[rustc_on_unimplemented(on="x", message="y")] -//~^ ERROR this attribute must have a valid -trait BadAnnotation9 {} +#[rustc_on_unimplemented(on = "x", message = "y")] +//~^ ERROR this attribute must have a value +//~^^ NOTE e.g. `#[rustc_on_unimplemented(message="foo")]` +//~^^^ NOTE expected value here +trait ExpectedPredicateInOn {} -#[rustc_on_unimplemented(on(x="y"), message="y")] -trait BadAnnotation10 {} +#[rustc_on_unimplemented(on(x = "y"), message = "y")] +trait OnWithoutDirectives {} -#[rustc_on_unimplemented(on(desugared, on(desugared, message="x")), message="y")] -//~^ ERROR this attribute must have a valid -trait BadAnnotation11 {} +#[rustc_on_unimplemented(on(from_desugaring, on(from_desugaring, message = "x")), message = "y")] +//~^ ERROR this attribute must have a value +//~^^ NOTE e.g. `#[rustc_on_unimplemented(message="foo")]` +//~^^^ NOTE expected value here +trait NestedOn {} -pub fn main() { -} +#[rustc_on_unimplemented(on("y", message = "y"))] +//~^ ERROR literals inside `on`-clauses are not supported +//~^^ NOTE unexpected literal here +trait UnsupportedLiteral {} + +#[rustc_on_unimplemented(on(42, message = "y"))] +//~^ ERROR literals inside `on`-clauses are not supported +//~^^ NOTE unexpected literal here +trait UnsupportedLiteral2 {} + +#[rustc_on_unimplemented(on(not(a, b), message = "y"))] +//~^ ERROR expected a single predicate in `not(..)` [E0232] +//~^^ NOTE unexpected quantity of predicates here +trait ExpectedOnePattern {} + +#[rustc_on_unimplemented(on(not(), message = "y"))] +//~^ ERROR expected a single predicate in `not(..)` [E0232] +//~^^ NOTE unexpected quantity of predicates here +trait ExpectedOnePattern2 {} + +#[rustc_on_unimplemented(on(thing::What, message = "y"))] +//~^ ERROR expected an identifier inside this `on`-clause +//~^^ NOTE expected an identifier here, not `thing::What` +trait KeyMustBeIdentifier {} + +#[rustc_on_unimplemented(on(thing::What = "value", message = "y"))] +//~^ ERROR expected an identifier inside this `on`-clause +//~^^ NOTE expected an identifier here, not `thing::What` +trait KeyMustBeIdentifier2 {} + +#[rustc_on_unimplemented(on(aaaaaaaaaaaaaa(a, b), message = "y"))] +//~^ ERROR this predicate is invalid +//~^^ NOTE expected one of `any`, `all` or `not` here, not `aaaaaaaaaaaaaa` +trait InvalidPredicate {} + +#[rustc_on_unimplemented(on(something, message = "y"))] +//~^ ERROR invalid flag in `on`-clause +//~^^ NOTE expected one of the `crate_local`, `direct` or `from_desugaring` flags, not `something` +trait InvalidFlag {} diff --git a/tests/ui/on-unimplemented/bad-annotation.stderr b/tests/ui/on-unimplemented/bad-annotation.stderr index afd737dc85e6..35b919c7b785 100644 --- a/tests/ui/on-unimplemented/bad-annotation.stderr +++ b/tests/ui/on-unimplemented/bad-annotation.stderr @@ -1,5 +1,5 @@ error: malformed `rustc_on_unimplemented` attribute input - --> $DIR/bad-annotation.rs:17:1 + --> $DIR/bad-annotation.rs:15:1 | LL | #[rustc_on_unimplemented] | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -12,72 +12,120 @@ LL | #[rustc_on_unimplemented(/*opt*/ message = "...", /*opt*/ label = "...", /* | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ error[E0230]: cannot find parameter C on this trait - --> $DIR/bad-annotation.rs:22:90 + --> $DIR/bad-annotation.rs:19:90 | LL | #[rustc_on_unimplemented = "Unimplemented trait error on `{Self}` with params `<{A},{B},{C}>`"] | ^ error[E0231]: positional format arguments are not allowed here - --> $DIR/bad-annotation.rs:27:90 + --> $DIR/bad-annotation.rs:23:90 | LL | #[rustc_on_unimplemented = "Unimplemented trait error on `{Self}` with params `<{A},{B},{}>`"] | ^ -error[E0232]: this attribute must have a valid value - --> $DIR/bad-annotation.rs:32:26 +error[E0232]: this attribute must have a value + --> $DIR/bad-annotation.rs:27:26 | -LL | #[rustc_on_unimplemented(lorem="")] - | ^^^^^^^^ expected value here +LL | #[rustc_on_unimplemented(lorem = "")] + | ^^^^^^^^^^ expected value here | - = note: eg `#[rustc_on_unimplemented(message="foo")]` + = note: e.g. `#[rustc_on_unimplemented(message="foo")]` -error[E0232]: this attribute must have a valid value - --> $DIR/bad-annotation.rs:36:26 +error[E0232]: this attribute must have a value + --> $DIR/bad-annotation.rs:33:26 | LL | #[rustc_on_unimplemented(lorem(ipsum(dolor)))] | ^^^^^^^^^^^^^^^^^^^ expected value here | - = note: eg `#[rustc_on_unimplemented(message="foo")]` + = note: e.g. `#[rustc_on_unimplemented(message="foo")]` -error[E0232]: this attribute must have a valid value - --> $DIR/bad-annotation.rs:40:39 +error[E0232]: this attribute must have a value + --> $DIR/bad-annotation.rs:39:41 | -LL | #[rustc_on_unimplemented(message="x", message="y")] - | ^^^^^^^^^^^ expected value here +LL | #[rustc_on_unimplemented(message = "x", message = "y")] + | ^^^^^^^^^^^^^ expected value here | - = note: eg `#[rustc_on_unimplemented(message="foo")]` + = note: e.g. `#[rustc_on_unimplemented(message="foo")]` -error[E0232]: this attribute must have a valid value - --> $DIR/bad-annotation.rs:44:39 +error[E0232]: this attribute must have a value + --> $DIR/bad-annotation.rs:45:41 | -LL | #[rustc_on_unimplemented(message="x", on(desugared, message="y"))] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected value here +LL | #[rustc_on_unimplemented(message = "x", on(desugared, message = "y"))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected value here | - = note: eg `#[rustc_on_unimplemented(message="foo")]` + = note: e.g. `#[rustc_on_unimplemented(message="foo")]` error[E0232]: empty `on`-clause in `#[rustc_on_unimplemented]` - --> $DIR/bad-annotation.rs:48:26 + --> $DIR/bad-annotation.rs:51:26 | -LL | #[rustc_on_unimplemented(on(), message="y")] - | ^^^^ empty on-clause here +LL | #[rustc_on_unimplemented(on(), message = "y")] + | ^^^^ empty `on`-clause here -error[E0232]: this attribute must have a valid value - --> $DIR/bad-annotation.rs:52:26 +error[E0232]: this attribute must have a value + --> $DIR/bad-annotation.rs:56:26 | -LL | #[rustc_on_unimplemented(on="x", message="y")] - | ^^^^^^ expected value here +LL | #[rustc_on_unimplemented(on = "x", message = "y")] + | ^^^^^^^^ expected value here | - = note: eg `#[rustc_on_unimplemented(message="foo")]` + = note: e.g. `#[rustc_on_unimplemented(message="foo")]` -error[E0232]: this attribute must have a valid value - --> $DIR/bad-annotation.rs:59:40 +error[E0232]: this attribute must have a value + --> $DIR/bad-annotation.rs:65:46 | -LL | #[rustc_on_unimplemented(on(desugared, on(desugared, message="x")), message="y")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected value here +LL | #[rustc_on_unimplemented(on(from_desugaring, on(from_desugaring, message = "x")), message = "y")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected value here | - = note: eg `#[rustc_on_unimplemented(message="foo")]` + = note: e.g. `#[rustc_on_unimplemented(message="foo")]` -error: aborting due to 10 previous errors +error[E0232]: literals inside `on`-clauses are not supported + --> $DIR/bad-annotation.rs:71:29 + | +LL | #[rustc_on_unimplemented(on("y", message = "y"))] + | ^^^ unexpected literal here + +error[E0232]: literals inside `on`-clauses are not supported + --> $DIR/bad-annotation.rs:76:29 + | +LL | #[rustc_on_unimplemented(on(42, message = "y"))] + | ^^ unexpected literal here + +error[E0232]: expected a single predicate in `not(..)` + --> $DIR/bad-annotation.rs:81:33 + | +LL | #[rustc_on_unimplemented(on(not(a, b), message = "y"))] + | ^^^^ unexpected quantity of predicates here + +error[E0232]: expected a single predicate in `not(..)` + --> $DIR/bad-annotation.rs:86:29 + | +LL | #[rustc_on_unimplemented(on(not(), message = "y"))] + | ^^^^^ unexpected quantity of predicates here + +error[E0232]: expected an identifier inside this `on`-clause + --> $DIR/bad-annotation.rs:91:29 + | +LL | #[rustc_on_unimplemented(on(thing::What, message = "y"))] + | ^^^^^^^^^^^ expected an identifier here, not `thing::What` + +error[E0232]: expected an identifier inside this `on`-clause + --> $DIR/bad-annotation.rs:96:29 + | +LL | #[rustc_on_unimplemented(on(thing::What = "value", message = "y"))] + | ^^^^^^^^^^^ expected an identifier here, not `thing::What` + +error[E0232]: this predicate is invalid + --> $DIR/bad-annotation.rs:101:29 + | +LL | #[rustc_on_unimplemented(on(aaaaaaaaaaaaaa(a, b), message = "y"))] + | ^^^^^^^^^^^^^^ expected one of `any`, `all` or `not` here, not `aaaaaaaaaaaaaa` + +error[E0232]: invalid flag in `on`-clause + --> $DIR/bad-annotation.rs:106:29 + | +LL | #[rustc_on_unimplemented(on(something, message = "y"))] + | ^^^^^^^^^ expected one of the `crate_local`, `direct` or `from_desugaring` flags, not `something` + +error: aborting due to 18 previous errors Some errors have detailed explanations: E0230, E0231, E0232. For more information about an error, try `rustc --explain E0230`. diff --git a/tests/ui/panic-runtime/two-panic-runtimes.rs b/tests/ui/panic-runtime/two-panic-runtimes.rs index 80591edd1077..de76578a267f 100644 --- a/tests/ui/panic-runtime/two-panic-runtimes.rs +++ b/tests/ui/panic-runtime/two-panic-runtimes.rs @@ -1,11 +1,19 @@ // ignore-tidy-linelength //@ build-fail -//@ dont-require-annotations: ERROR //@ dont-check-compiler-stderr //@ aux-build:panic-runtime-unwind.rs //@ aux-build:panic-runtime-unwind2.rs //@ aux-build:panic-runtime-lang-items.rs +// NOTE: there can be additional errors regarding trying to mix this crate if the precompiled target +// (such as `wasm32-unknown-unknown` currently unconditionally defaulting to panic=abort) panic +// strategy differs to abort, then involving a potentially-unwinding `panic_runtime_unwind` that +// uses a different panic strategy. These errors are important but not to the test intention, which +// is to check that trying to bring two panic runtimes (`panic_runtime_unwind`) and +// (`panic_runtime_unwind2`) is prohibited. As such, the additional errors are not checked in this +// test. +//@ dont-require-annotations: ERROR + #![no_std] #![no_main] @@ -16,7 +24,3 @@ extern crate panic_runtime_lang_items; fn main() {} //~? ERROR cannot link together two panic runtimes: panic_runtime_unwind and panic_runtime_unwind2 -// FIXME: These errors are target-dependent, could be served by some "optional error" annotation -// instead of `dont-require-annotations`. -//FIXME~? ERROR the linked panic runtime `panic_runtime_unwind2` is not compiled with this crate's panic strategy `abort` -//FIXME~? ERROR the crate `panic_runtime_unwind` requires panic strategy `unwind` which is incompatible with this crate's strategy of `abort` diff --git a/tests/ui/panic-runtime/want-abort-got-unwind.rs b/tests/ui/panic-runtime/want-abort-got-unwind.rs index 42cdf8bc6626..7a6bd011d9e4 100644 --- a/tests/ui/panic-runtime/want-abort-got-unwind.rs +++ b/tests/ui/panic-runtime/want-abort-got-unwind.rs @@ -1,16 +1,18 @@ // ignore-tidy-linelength //@ build-fail -//@ dont-require-annotations: ERROR //@ dont-check-compiler-stderr //@ aux-build:panic-runtime-unwind.rs //@ compile-flags:-C panic=abort +// NOTE: depending on the target's default panic strategy, there can be additional errors that +// complain about linking two panic runtimes (e.g. precompiled `panic_unwind` if target default +// panic strategy is unwind, in addition to `panic_runtime_unwind`). These additional errors will +// not be observed on targets whose default panic strategy is abort, where `panic_abort` is linked +// in instead. +//@ dont-require-annotations: ERROR + extern crate panic_runtime_unwind; fn main() {} //~? ERROR the linked panic runtime `panic_runtime_unwind` is not compiled with this crate's panic strategy `abort` -// FIXME: These errors are target-dependent, could be served by some "optional error" annotation -// instead of `dont-require-annotations`. -//FIXME~? ERROR cannot link together two panic runtimes: panic_unwind and panic_runtime_unwind -//FIXME~? ERROR the crate `panic_unwind` requires panic strategy `unwind` which is incompatible with this crate's strategy of `abort` diff --git a/tests/ui/panic-runtime/want-abort-got-unwind2.rs b/tests/ui/panic-runtime/want-abort-got-unwind2.rs index ddf12cd2a9a5..da239a675e5b 100644 --- a/tests/ui/panic-runtime/want-abort-got-unwind2.rs +++ b/tests/ui/panic-runtime/want-abort-got-unwind2.rs @@ -1,17 +1,23 @@ // ignore-tidy-linelength //@ build-fail -//@ dont-require-annotations: ERROR //@ dont-check-compiler-stderr //@ aux-build:panic-runtime-unwind.rs //@ aux-build:wants-panic-runtime-unwind.rs //@ compile-flags:-C panic=abort +// Like `want-abort-got-unwind.rs`, this version checks that if the root binary wants abort panic +// runtime, that the compiler rejects a setup where a dependency crate in the dependency DAG +// transitively provides an unwind panic runtime (which also is built with `-Cpanic=unwind`, making +// that potentially-unwinding). + +// NOTE: similar to `want-abort-got-unwind.rs`, there can be additional errors if the target default +// panic strategy is unwind, because then the precompiled `panic_unwind` would also be linked in, +// duplicating `panic_runtime_unwind` (transitively). But those additional errors are not important +// to test intention. +//@ dont-require-annotations: ERROR + extern crate wants_panic_runtime_unwind; fn main() {} //~? ERROR the linked panic runtime `panic_runtime_unwind` is not compiled with this crate's panic strategy `abort` -// FIXME: These errors are target-dependent, could be served by some "optional error" annotation -// instead of `dont-require-annotations`. -//FIXME~? ERROR cannot link together two panic runtimes: panic_unwind and panic_runtime_unwind -//FIXME~? ERROR the crate `panic_unwind` requires panic strategy `unwind` which is incompatible with this crate's strategy of `abort` diff --git a/tests/ui/panics/default-backtrace-ice.rs b/tests/ui/panics/default-backtrace-ice.rs index cf8b0cea8496..e919e1a4ea62 100644 --- a/tests/ui/panics/default-backtrace-ice.rs +++ b/tests/ui/panics/default-backtrace-ice.rs @@ -1,8 +1,5 @@ //@ unset-rustc-env:RUST_BACKTRACE //@ compile-flags:-Z treat-err-as-bug=1 -//@ error-pattern:stack backtrace: -// Verify this is a full backtrace, not a short backtrace. -//@ error-pattern:__rust_begin_short_backtrace //@ failure-status:101 //@ ignore-msvc //@ normalize-stderr: "note: .*" -> "" @@ -21,3 +18,7 @@ // aren't reliable. fn main() { missing_ident; } //~ ERROR cannot find value `missing_ident` in this scope + +//~? RAW stack backtrace: +// Verify this is a full backtrace, not a short backtrace. +//~? RAW __rust_begin_short_backtrace diff --git a/tests/ui/panics/default-backtrace-ice.stderr b/tests/ui/panics/default-backtrace-ice.stderr index 2147b0971b5f..a7d99e325d9b 100644 --- a/tests/ui/panics/default-backtrace-ice.stderr +++ b/tests/ui/panics/default-backtrace-ice.stderr @@ -1,5 +1,5 @@ error: internal compiler error[E0425]: cannot find value `missing_ident` in this scope - --> $DIR/default-backtrace-ice.rs:23:13 + --> $DIR/default-backtrace-ice.rs:20:13 | LL | fn main() { missing_ident; } | ^^^^^^^^^^^^^ not found in this scope diff --git a/tests/ui/parser/diagnostics-parenthesized-type-arguments-ice-issue-122345.rs b/tests/ui/parser/diagnostics-parenthesized-type-arguments-ice-issue-122345.rs index 6bfe16ae37d2..db25ce440893 100644 --- a/tests/ui/parser/diagnostics-parenthesized-type-arguments-ice-issue-122345.rs +++ b/tests/ui/parser/diagnostics-parenthesized-type-arguments-ice-issue-122345.rs @@ -2,8 +2,10 @@ fn main() { unsafe { - dealloc(ptr2, Layout::(x: !)(1, 1)); //~ ERROR: expected one of `!`, `(`, `)`, `+`, `,`, `::`, or `<`, found `:` - //~^ ERROR: expected one of `.`, `;`, `?`, `}`, or an operator, found `)` - //~| NOTE while parsing this parenthesized list of type arguments starting here + dealloc(ptr2, Layout::(x: !)(1, 1)); //~ ERROR `Trait(...)` syntax does not support named parameters + //~^ ERROR cannot find function `dealloc` in this scope [E0425] + //~| ERROR cannot find value `ptr2` in this scope [E0425] + //~| ERROR the `!` type is experimental [E0658] + //~| ERROR cannot find function, tuple struct or tuple variant `Layout` in this scope [E0425] } } diff --git a/tests/ui/parser/diagnostics-parenthesized-type-arguments-ice-issue-122345.stderr b/tests/ui/parser/diagnostics-parenthesized-type-arguments-ice-issue-122345.stderr index c12bf7f9e3f0..a083883af219 100644 --- a/tests/ui/parser/diagnostics-parenthesized-type-arguments-ice-issue-122345.stderr +++ b/tests/ui/parser/diagnostics-parenthesized-type-arguments-ice-issue-122345.stderr @@ -1,16 +1,43 @@ -error: expected one of `!`, `(`, `)`, `+`, `,`, `::`, or `<`, found `:` - --> $DIR/diagnostics-parenthesized-type-arguments-ice-issue-122345.rs:5:33 +error: `Trait(...)` syntax does not support named parameters + --> $DIR/diagnostics-parenthesized-type-arguments-ice-issue-122345.rs:5:32 | LL | dealloc(ptr2, Layout::(x: !)(1, 1)); - | --- ^ expected one of 7 possible tokens - | | - | while parsing this parenthesized list of type arguments starting here + | ^ help: remove the parameter name -error: expected one of `.`, `;`, `?`, `}`, or an operator, found `)` - --> $DIR/diagnostics-parenthesized-type-arguments-ice-issue-122345.rs:5:43 +error[E0425]: cannot find function `dealloc` in this scope + --> $DIR/diagnostics-parenthesized-type-arguments-ice-issue-122345.rs:5:9 | LL | dealloc(ptr2, Layout::(x: !)(1, 1)); - | ^ expected one of `.`, `;`, `?`, `}`, or an operator + | ^^^^^^^ not found in this scope + | +help: consider importing this function + | +LL + use std::alloc::dealloc; + | -error: aborting due to 2 previous errors +error[E0425]: cannot find value `ptr2` in this scope + --> $DIR/diagnostics-parenthesized-type-arguments-ice-issue-122345.rs:5:17 + | +LL | dealloc(ptr2, Layout::(x: !)(1, 1)); + | ^^^^ not found in this scope +error[E0658]: the `!` type is experimental + --> $DIR/diagnostics-parenthesized-type-arguments-ice-issue-122345.rs:5:35 + | +LL | dealloc(ptr2, Layout::(x: !)(1, 1)); + | ^ + | + = note: see issue #35121 for more information + = help: add `#![feature(never_type)]` 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[E0425]: cannot find function, tuple struct or tuple variant `Layout` in this scope + --> $DIR/diagnostics-parenthesized-type-arguments-ice-issue-122345.rs:5:23 + | +LL | dealloc(ptr2, Layout::(x: !)(1, 1)); + | ^^^^^^ not found in this scope + +error: aborting due to 5 previous errors + +Some errors have detailed explanations: E0425, E0658. +For more information about an error, try `rustc --explain E0425`. diff --git a/tests/ui/parser/fn-arg-doc-comment.rs b/tests/ui/parser/fn-arg-doc-comment.rs index 21d753ad0372..57a4d15fa256 100644 --- a/tests/ui/parser/fn-arg-doc-comment.rs +++ b/tests/ui/parser/fn-arg-doc-comment.rs @@ -2,12 +2,10 @@ pub fn f( //~ NOTE function defined here /// Comment //~^ ERROR documentation comments cannot be applied to function parameters //~| NOTE doc comments are not allowed here - //~| NOTE id: u8, /// Other //~^ ERROR documentation comments cannot be applied to function parameters //~| NOTE doc comments are not allowed here - //~| NOTE a: u8, ) {} @@ -15,7 +13,6 @@ fn bar(id: #[allow(dead_code)] i32) {} //~^ ERROR attributes cannot be applied to a function parameter's type //~| NOTE attributes are not allowed here //~| NOTE function defined here -//~| NOTE fn main() { // verify that the parser recovered and properly typechecked the args diff --git a/tests/ui/parser/fn-arg-doc-comment.stderr b/tests/ui/parser/fn-arg-doc-comment.stderr index 1891c7089034..84c8bb3c2d09 100644 --- a/tests/ui/parser/fn-arg-doc-comment.stderr +++ b/tests/ui/parser/fn-arg-doc-comment.stderr @@ -1,5 +1,5 @@ error: attributes cannot be applied to a function parameter's type - --> $DIR/fn-arg-doc-comment.rs:14:12 + --> $DIR/fn-arg-doc-comment.rs:12:12 | LL | fn bar(id: #[allow(dead_code)] i32) {} | ^^^^^^^^^^^^^^^^^^^ attributes are not allowed here @@ -11,13 +11,13 @@ LL | /// Comment | ^^^^^^^^^^^ doc comments are not allowed here error: documentation comments cannot be applied to function parameters - --> $DIR/fn-arg-doc-comment.rs:7:5 + --> $DIR/fn-arg-doc-comment.rs:6:5 | LL | /// Other | ^^^^^^^^^ doc comments are not allowed here error[E0308]: arguments to this function are incorrect - --> $DIR/fn-arg-doc-comment.rs:22:5 + --> $DIR/fn-arg-doc-comment.rs:19:5 | LL | f("", ""); | ^ -- -- expected `u8`, found `&str` @@ -39,7 +39,7 @@ LL | | a: u8, | |_________- error[E0308]: mismatched types - --> $DIR/fn-arg-doc-comment.rs:26:9 + --> $DIR/fn-arg-doc-comment.rs:23:9 | LL | bar(""); | --- ^^ expected `i32`, found `&str` @@ -47,7 +47,7 @@ LL | bar(""); | arguments to this function are incorrect | note: function defined here - --> $DIR/fn-arg-doc-comment.rs:14:4 + --> $DIR/fn-arg-doc-comment.rs:12:4 | LL | fn bar(id: #[allow(dead_code)] i32) {} | ^^^ --------------------------- diff --git a/tests/ui/parser/issues/invalid-parse-format-issue-139104.rs b/tests/ui/parser/issues/invalid-parse-format-issue-139104.rs new file mode 100644 index 000000000000..7644df8be49a --- /dev/null +++ b/tests/ui/parser/issues/invalid-parse-format-issue-139104.rs @@ -0,0 +1,13 @@ +fn main() { + println!("{foo:_1.4}", foo = 3.14); //~ ERROR invalid format string: expected `}`, found `.` + println!("{0:_1.4}", 1.11); //~ ERROR invalid format string: expected `}`, found `.` + println!("{:_1.4}", 3.14); //~ ERROR invalid format string: expected `}`, found `.` + + println!("{foo:_1.4", foo = 3.14); //~ ERROR invalid format string: expected `}`, found `.` + println!("{0:_1.4", 1.11); //~ ERROR invalid format string: expected `}`, found `.` + println!("{:_1.4", 3.14); //~ ERROR invalid format string: expected `}`, found `.` + + println!("{ 0", 1.11); //~ ERROR invalid format string: expected `}`, found `0` + println!("{foo:1.4_1.4}", foo = 3.14); //~ ERROR invalid format string: expected `}`, found `.` + println!("{0:1.4_1.4}", 3.14); //~ ERROR invalid format string: expected `}`, found `.` +} diff --git a/tests/ui/parser/issues/invalid-parse-format-issue-139104.stderr b/tests/ui/parser/issues/invalid-parse-format-issue-139104.stderr new file mode 100644 index 000000000000..202aa450cab7 --- /dev/null +++ b/tests/ui/parser/issues/invalid-parse-format-issue-139104.stderr @@ -0,0 +1,92 @@ +error: invalid format string: expected `}`, found `.` + --> $DIR/invalid-parse-format-issue-139104.rs:2:22 + | +LL | println!("{foo:_1.4}", foo = 3.14); + | - ^ expected `}` in format string + | | + | because of this opening brace + | + = note: if you intended to print `{`, you can escape it using `{{` + +error: invalid format string: expected `}`, found `.` + --> $DIR/invalid-parse-format-issue-139104.rs:3:20 + | +LL | println!("{0:_1.4}", 1.11); + | - ^ expected `}` in format string + | | + | because of this opening brace + | + = note: if you intended to print `{`, you can escape it using `{{` + +error: invalid format string: expected `}`, found `.` + --> $DIR/invalid-parse-format-issue-139104.rs:4:19 + | +LL | println!("{:_1.4}", 3.14); + | - ^ expected `}` in format string + | | + | because of this opening brace + | + = note: if you intended to print `{`, you can escape it using `{{` + +error: invalid format string: expected `}`, found `.` + --> $DIR/invalid-parse-format-issue-139104.rs:6:22 + | +LL | println!("{foo:_1.4", foo = 3.14); + | - ^ expected `}` in format string + | | + | because of this opening brace + | + = note: if you intended to print `{`, you can escape it using `{{` + +error: invalid format string: expected `}`, found `.` + --> $DIR/invalid-parse-format-issue-139104.rs:7:20 + | +LL | println!("{0:_1.4", 1.11); + | - ^ expected `}` in format string + | | + | because of this opening brace + | + = note: if you intended to print `{`, you can escape it using `{{` + +error: invalid format string: expected `}`, found `.` + --> $DIR/invalid-parse-format-issue-139104.rs:8:19 + | +LL | println!("{:_1.4", 3.14); + | - ^ expected `}` in format string + | | + | because of this opening brace + | + = note: if you intended to print `{`, you can escape it using `{{` + +error: invalid format string: expected `}`, found `0` + --> $DIR/invalid-parse-format-issue-139104.rs:10:18 + | +LL | println!("{ 0", 1.11); + | - ^ expected `}` in format string + | | + | because of this opening brace + | + = note: if you intended to print `{`, you can escape it using `{{` + +error: invalid format string: expected `}`, found `.` + --> $DIR/invalid-parse-format-issue-139104.rs:11:25 + | +LL | println!("{foo:1.4_1.4}", foo = 3.14); + | - ^ expected `}` in format string + | | + | because of this opening brace + | + = note: if you intended to print `{`, you can escape it using `{{` + +error: invalid format string: expected `}`, found `.` + --> $DIR/invalid-parse-format-issue-139104.rs:12:23 + | +LL | println!("{0:1.4_1.4}", 3.14); + | - ^ expected `}` in format string + | | + | because of this opening brace + | + = note: if you intended to print `{`, you can escape it using `{{` + +error: aborting due to 9 previous errors + diff --git a/tests/ui/parser/issues/issue-103748-ICE-wrong-braces.rs b/tests/ui/parser/issues/issue-103748-ICE-wrong-braces.rs index 1c28c0632fa8..60dd88e65400 100644 --- a/tests/ui/parser/issues/issue-103748-ICE-wrong-braces.rs +++ b/tests/ui/parser/issues/issue-103748-ICE-wrong-braces.rs @@ -2,7 +2,4 @@ struct Apple((Apple, Option(Banana ? Citron))); //~^ ERROR invalid `?` in type -//~| ERROR expected one of `)` or `,`, found `Citron` -//~| ERROR cannot find type `Citron` in this scope [E0412] -//~| ERROR parenthesized type parameters may only be used with a `Fn` trait [E0214] -//~| ERROR `Apple` has infinite size +//~| ERROR unexpected token: `Citron` diff --git a/tests/ui/parser/issues/issue-103748-ICE-wrong-braces.stderr b/tests/ui/parser/issues/issue-103748-ICE-wrong-braces.stderr index 97a73b4fd5ed..c92535c3906b 100644 --- a/tests/ui/parser/issues/issue-103748-ICE-wrong-braces.stderr +++ b/tests/ui/parser/issues/issue-103748-ICE-wrong-braces.stderr @@ -10,44 +10,11 @@ LL - struct Apple((Apple, Option(Banana ? Citron))); LL + struct Apple((Apple, Option(Option Citron))); | -error: expected one of `)` or `,`, found `Citron` +error: unexpected token: `Citron` --> $DIR/issue-103748-ICE-wrong-braces.rs:3:38 | LL | struct Apple((Apple, Option(Banana ? Citron))); - | -^^^^^^ expected one of `)` or `,` - | | - | help: missing `,` + | ^^^^^^ unexpected token after this -error[E0412]: cannot find type `Citron` in this scope - --> $DIR/issue-103748-ICE-wrong-braces.rs:3:38 - | -LL | struct Apple((Apple, Option(Banana ? Citron))); - | ^^^^^^ not found in this scope +error: aborting due to 2 previous errors -error[E0214]: parenthesized type parameters may only be used with a `Fn` trait - --> $DIR/issue-103748-ICE-wrong-braces.rs:3:22 - | -LL | struct Apple((Apple, Option(Banana ? Citron))); - | ^^^^^^^^^^^^^^^^^^^^^^^ only `Fn` traits may use parentheses - | -help: use angle brackets instead - | -LL - struct Apple((Apple, Option(Banana ? Citron))); -LL + struct Apple((Apple, Option)); - | - -error[E0072]: recursive type `Apple` has infinite size - --> $DIR/issue-103748-ICE-wrong-braces.rs:3:1 - | -LL | struct Apple((Apple, Option(Banana ? Citron))); - | ^^^^^^^^^^^^ ----- recursive without indirection - | -help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle - | -LL | struct Apple((Box, Option(Banana ? Citron))); - | ++++ + - -error: aborting due to 5 previous errors - -Some errors have detailed explanations: E0072, E0214, E0412. -For more information about an error, try `rustc --explain E0072`. diff --git a/tests/ui/parser/issues/issue-87217-keyword-order/const-async-const.rs b/tests/ui/parser/issues/issue-87217-keyword-order/const-async-const.rs index c137e1363359..e6235b1e8923 100644 --- a/tests/ui/parser/issues/issue-87217-keyword-order/const-async-const.rs +++ b/tests/ui/parser/issues/issue-87217-keyword-order/const-async-const.rs @@ -10,6 +10,5 @@ const async const fn test() {} //~| ERROR functions cannot be both `const` and `async` //~| NOTE `const` because of this //~| NOTE `async` because of this -//~| NOTE fn main() {} diff --git a/tests/ui/parser/issues/issue-87217-keyword-order/several-kw-jump.rs b/tests/ui/parser/issues/issue-87217-keyword-order/several-kw-jump.rs index 49a49d337c47..40f993eafbb1 100644 --- a/tests/ui/parser/issues/issue-87217-keyword-order/several-kw-jump.rs +++ b/tests/ui/parser/issues/issue-87217-keyword-order/several-kw-jump.rs @@ -15,6 +15,5 @@ async unsafe const fn test() {} //~| ERROR functions cannot be both `const` and `async` //~| NOTE `const` because of this //~| NOTE `async` because of this -//~| NOTE fn main() {} diff --git a/tests/ui/auxiliary/issue-24106.rs b/tests/ui/pattern/auxiliary/cross-crate-enum-pattern.rs similarity index 100% rename from tests/ui/auxiliary/issue-24106.rs rename to tests/ui/pattern/auxiliary/cross-crate-enum-pattern.rs diff --git a/tests/ui/pattern/cross-crate-enum-pattern.rs b/tests/ui/pattern/cross-crate-enum-pattern.rs new file mode 100644 index 000000000000..254caf99277c --- /dev/null +++ b/tests/ui/pattern/cross-crate-enum-pattern.rs @@ -0,0 +1,13 @@ +//! Test that we can match on enum constants across crates. +//! +//! Regression test for . + + +//@ run-pass +//@ aux-build:cross-crate-enum-pattern.rs + +extern crate cross_crate_enum_pattern; + +fn main() { + cross_crate_enum_pattern::go::<()>(); +} diff --git a/tests/ui/pattern/deref-patterns/bindings.rs b/tests/ui/pattern/deref-patterns/bindings.rs index ac48e3ffefcc..92c01d737bac 100644 --- a/tests/ui/pattern/deref-patterns/bindings.rs +++ b/tests/ui/pattern/deref-patterns/bindings.rs @@ -13,7 +13,6 @@ fn simple_vec(vec: Vec) -> u32 { deref!([x]) => x, deref!([1, x]) => x + 200, deref!(ref slice) => slice.iter().sum(), - _ => 2000, } } @@ -25,7 +24,6 @@ fn simple_vec(vec: Vec) -> u32 { [x] => x, [1, x] => x + 200, deref!(ref slice) => slice.iter().sum(), - _ => 2000, } } diff --git a/tests/ui/pattern/deref-patterns/byte-string-type-errors.rs b/tests/ui/pattern/deref-patterns/byte-string-type-errors.rs index 64acc4748afd..fdcc6cb46111 100644 --- a/tests/ui/pattern/deref-patterns/byte-string-type-errors.rs +++ b/tests/ui/pattern/deref-patterns/byte-string-type-errors.rs @@ -33,4 +33,23 @@ fn main() { if let b"test" = *b"this array is too long" {} //~^ ERROR mismatched types //~| NOTE expected an array with a size of 22, found one with a size of 4 + + // Test matching on `&mut T`: we peel the `&mut` before applying the usual special cases. + // No special cases apply to `()`, so the "found" type is the type of the literal. + if let b"test" = &mut () {} + //~^ ERROR mismatched types + //~| NOTE expected `()`, found `&[u8; 4]` + + // If the pointee is an array or slice, the usual special cases will apply to the "found" type: + if let b"test" = &mut [] as &mut [i8] {} + //~^ ERROR mismatched type + //~| NOTE expected `[i8]`, found `[u8]` + + if let b"test" = &mut [()] {} + //~^ ERROR mismatched types + //~| NOTE expected `[(); 1]`, found `[u8; 4]` + + if let b"test" = &mut *b"this array is too long" {} + //~^ ERROR mismatched type + //~| NOTE expected an array with a size of 22, found one with a size of 4 } diff --git a/tests/ui/pattern/deref-patterns/byte-string-type-errors.stderr b/tests/ui/pattern/deref-patterns/byte-string-type-errors.stderr index 0317b7209e16..046682004be7 100644 --- a/tests/ui/pattern/deref-patterns/byte-string-type-errors.stderr +++ b/tests/ui/pattern/deref-patterns/byte-string-type-errors.stderr @@ -47,6 +47,44 @@ LL | if let b"test" = *b"this array is too long" {} | | | expected an array with a size of 22, found one with a size of 4 -error: aborting due to 5 previous errors +error[E0308]: mismatched types + --> $DIR/byte-string-type-errors.rs:39:12 + | +LL | if let b"test" = &mut () {} + | ^^^^^^^ ------- this expression has type `&mut ()` + | | + | expected `()`, found `&[u8; 4]` + +error[E0308]: mismatched types + --> $DIR/byte-string-type-errors.rs:44:12 + | +LL | if let b"test" = &mut [] as &mut [i8] {} + | ^^^^^^^ -------------------- this expression has type `&mut [i8]` + | | + | expected `[i8]`, found `[u8]` + | + = note: expected slice `[i8]` + found slice `[u8]` + +error[E0308]: mismatched types + --> $DIR/byte-string-type-errors.rs:48:12 + | +LL | if let b"test" = &mut [()] {} + | ^^^^^^^ --------- this expression has type `&mut [(); 1]` + | | + | expected `[(); 1]`, found `[u8; 4]` + | + = note: expected array `[(); 1]` + found array `[u8; 4]` + +error[E0308]: mismatched types + --> $DIR/byte-string-type-errors.rs:52:12 + | +LL | if let b"test" = &mut *b"this array is too long" {} + | ^^^^^^^ ------------------------------- this expression has type `&mut [u8; 22]` + | | + | expected an array with a size of 22, found one with a size of 4 + +error: aborting due to 9 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/pattern/deref-patterns/closure_capture.rs b/tests/ui/pattern/deref-patterns/closure_capture.rs index cf78eeda1d5a..497ec622b0cf 100644 --- a/tests/ui/pattern/deref-patterns/closure_capture.rs +++ b/tests/ui/pattern/deref-patterns/closure_capture.rs @@ -9,7 +9,7 @@ struct NoCopy; fn main() { let b = Rc::new("aaa".to_string()); let f = || { - let deref!(ref s) = b else { unreachable!() }; + let deref!(ref s) = b; assert_eq!(s.len(), 3); }; assert_eq!(b.len(), 3); @@ -26,7 +26,7 @@ fn main() { let mut b = "aaa".to_string(); let mut f = || { - let deref!(ref mut s) = b else { unreachable!() }; + let deref!(ref mut s) = b; s.make_ascii_uppercase(); }; f(); @@ -53,7 +53,7 @@ fn main() { let b = Box::new(NoCopy); let f = || { // this should move out of the box rather than borrow. - let deref!(x) = b else { unreachable!() }; + let deref!(x) = b; drop::(x); }; f(); @@ -61,7 +61,7 @@ fn main() { let b = Box::new((NoCopy,)); let f = || { // this should move out of the box rather than borrow. - let (x,) = b else { unreachable!() }; + let (x,) = b; drop::(x); }; f(); diff --git a/tests/ui/pattern/deref-patterns/const-pats-do-not-mislead-inference.rs b/tests/ui/pattern/deref-patterns/const-pats-do-not-mislead-inference.rs new file mode 100644 index 000000000000..3a2531f4b95e --- /dev/null +++ b/tests/ui/pattern/deref-patterns/const-pats-do-not-mislead-inference.rs @@ -0,0 +1,54 @@ +//@ revisions: stable deref_patterns +//@[deref_patterns] check-pass +//! `deref_patterns` allows string and byte string literal patterns to implicitly peel references +//! and smart pointers from the scrutinee before matching. Since strings and byte strings themselves +//! have reference types, we need to make sure we don't peel too much. By leaving the type of the +//! match scrutinee partially uninferred, these tests make sure we only peel as much as needed in +//! order to match. In particular, when peeling isn't needed, the results should be the same was +//! we'd get without `deref_patterns` enabled. + +#![cfg_attr(deref_patterns, feature(deref_patterns))] +#![cfg_attr(deref_patterns, expect(incomplete_features))] + +fn uninferred() -> T { unimplemented!() } + +// Assert type equality without allowing coercions. +trait Is {} +impl Is for T {} +fn has_type(_: impl Is) {} + +fn main() { + // We don't need to peel anything to unify the type of `x` with `&str`, so `x: &str`. + let x = uninferred(); + if let "..." = x {} + has_type::<&str>(x); + + // We don't need to peel anything to unify the type of `&x` with `&[u8; 3]`, so `x: [u8; 3]`. + let x = uninferred(); + if let b"..." = &x {} + has_type::<[u8; 3]>(x); + + // Peeling a single `&` lets us unify the type of `&x` with `&[u8; 3]`, giving `x: [u8; 3]`. + let x = uninferred(); + if let b"..." = &&x {} + //[stable]~^ ERROR: mismatched types + has_type::<[u8; 3]>(x); + + // We have to peel both the `&` and the box before unifying the type of `x` with `&str`. + let x = uninferred(); + if let "..." = &Box::new(x) {} + //[stable]~^ ERROR mismatched types + has_type::<&str>(x); + + // After peeling the box, we can unify the type of `&x` with `&[u8; 3]`, giving `x: [u8; 3]`. + let x = uninferred(); + if let b"..." = Box::new(&x) {} + //[stable]~^ ERROR mismatched types + has_type::<[u8; 3]>(x); + + // `&` and `&mut` aren't interchangeable: `&mut`s need to be peeled before unifying, like boxes: + let mut x = uninferred(); + if let "..." = &mut x {} + //[stable]~^ ERROR mismatched types + has_type::<&str>(x); +} diff --git a/tests/ui/pattern/deref-patterns/const-pats-do-not-mislead-inference.stable.stderr b/tests/ui/pattern/deref-patterns/const-pats-do-not-mislead-inference.stable.stderr new file mode 100644 index 000000000000..61079718c5d5 --- /dev/null +++ b/tests/ui/pattern/deref-patterns/const-pats-do-not-mislead-inference.stable.stderr @@ -0,0 +1,55 @@ +error[E0308]: mismatched types + --> $DIR/const-pats-do-not-mislead-inference.rs:33:12 + | +LL | if let b"..." = &&x {} + | ^^^^^^ --- this expression has type `&&_` + | | + | expected `&&_`, found `&[u8; 3]` + | + = note: expected reference `&&_` + found reference `&'static [u8; 3]` + +error[E0308]: mismatched types + --> $DIR/const-pats-do-not-mislead-inference.rs:39:12 + | +LL | if let "..." = &Box::new(x) {} + | ^^^^^ ------------ this expression has type `&Box<_>` + | | + | expected `&Box<_>`, found `&str` + | + = note: expected reference `&Box<_>` + found reference `&'static str` +help: consider dereferencing to access the inner value using the Deref trait + | +LL | if let "..." = &*Box::new(x) {} + | + + +error[E0308]: mismatched types + --> $DIR/const-pats-do-not-mislead-inference.rs:45:12 + | +LL | if let b"..." = Box::new(&x) {} + | ^^^^^^ ------------ this expression has type `Box<&_>` + | | + | expected `Box<&_>`, found `&[u8; 3]` + | + = note: expected struct `Box<&_>` + found reference `&'static [u8; 3]` +help: consider dereferencing to access the inner value using the Deref trait + | +LL | if let b"..." = *Box::new(&x) {} + | + + +error[E0308]: mismatched types + --> $DIR/const-pats-do-not-mislead-inference.rs:51:12 + | +LL | if let "..." = &mut x {} + | ^^^^^ ------ this expression has type `&mut _` + | | + | types differ in mutability + | + = note: expected mutable reference `&mut _` + found reference `&'static str` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/pattern/deref-patterns/deref-box.rs b/tests/ui/pattern/deref-patterns/deref-box.rs index 2d0a8d01972e..39b23dcab51e 100644 --- a/tests/ui/pattern/deref-patterns/deref-box.rs +++ b/tests/ui/pattern/deref-patterns/deref-box.rs @@ -6,18 +6,18 @@ #![expect(incomplete_features)] fn unbox_1(b: Box) -> T { - let deref!(x) = b else { unreachable!() }; + let deref!(x) = b; x } fn unbox_2(b: Box<(T,)>) -> T { - let (x,) = b else { unreachable!() }; + let (x,) = b; x } fn unbox_separately(b: Box<(T, T)>) -> (T, T) { - let (x, _) = b else { unreachable!() }; - let (_, y) = b else { unreachable!() }; + let (x, _) = b; + let (_, y) = b; (x, y) } @@ -31,7 +31,7 @@ fn main() { // test that borrowing from a box also works let mut b = "hi".to_owned().into_boxed_str(); - let deref!(ref mut s) = b else { unreachable!() }; + let deref!(ref mut s) = b; s.make_ascii_uppercase(); assert_eq!(&*b, "HI"); } diff --git a/tests/ui/pattern/deref-patterns/implicit-cow-deref.rs b/tests/ui/pattern/deref-patterns/implicit-cow-deref.rs index 04c83d4c33fd..24770261edc5 100644 --- a/tests/ui/pattern/deref-patterns/implicit-cow-deref.rs +++ b/tests/ui/pattern/deref-patterns/implicit-cow-deref.rs @@ -11,7 +11,6 @@ fn main() { match cow { [..] => {} - _ => unreachable!(), } match cow { @@ -22,14 +21,12 @@ fn main() { match Rc::new(&cow) { Cow::Borrowed { 0: _ } => {} Cow::Owned { 0: _ } => unreachable!(), - _ => unreachable!(), } let cow_of_cow: Cow<'_, Cow<'static, [u8]>> = Cow::Owned(cow); match cow_of_cow { [..] => {} - _ => unreachable!(), } // This matches on the outer `Cow` (the owned one). @@ -41,6 +38,5 @@ fn main() { match Rc::new(&cow_of_cow) { Cow::Borrowed { 0: _ } => unreachable!(), Cow::Owned { 0: _ } => {} - _ => unreachable!(), } } diff --git a/tests/ui/pattern/deref-patterns/needs-gate.rs b/tests/ui/pattern/deref-patterns/needs-gate.rs index 7944744ee839..953051f7b04b 100644 --- a/tests/ui/pattern/deref-patterns/needs-gate.rs +++ b/tests/ui/pattern/deref-patterns/needs-gate.rs @@ -29,4 +29,30 @@ fn main() { //~^ ERROR: mismatched types _ => {} } + + // `deref_patterns` allows string and byte string patterns to implicitly peel references. + match &"str" { + "str" => {} + //~^ ERROR: mismatched types + _ => {} + } + match &b"str" { + b"str" => {} + //~^ ERROR: mismatched types + _ => {} + } + match "str".to_owned() { + "str" => {} + //~^ ERROR: mismatched types + _ => {} + } + + // `deref_patterns` allows string and byte string patterns to match on mutable references. + // See also `tests/ui/pattern/byte-string-mutability-mismatch.rs`. + if let "str" = &mut *"str".to_string() {} + //~^ ERROR mismatched types + if let b"str" = &mut b"str".clone() {} + //~^ ERROR mismatched types + if let b"str" = &mut b"str".clone()[..] {} + //~^ ERROR mismatched types } diff --git a/tests/ui/pattern/deref-patterns/needs-gate.stderr b/tests/ui/pattern/deref-patterns/needs-gate.stderr index e886ca980558..3d938a7e23fc 100644 --- a/tests/ui/pattern/deref-patterns/needs-gate.stderr +++ b/tests/ui/pattern/deref-patterns/needs-gate.stderr @@ -47,7 +47,70 @@ LL | match *(b"test" as &[u8]) { LL | b"test" => {} | ^^^^^^^ expected `[u8]`, found `&[u8; 4]` -error: aborting due to 5 previous errors +error[E0308]: mismatched types + --> $DIR/needs-gate.rs:35:9 + | +LL | match &"str" { + | ------ this expression has type `&&str` +LL | "str" => {} + | ^^^^^ expected `&&str`, found `&str` + | + = note: expected reference `&&_` + found reference `&'static _` + +error[E0308]: mismatched types + --> $DIR/needs-gate.rs:40:9 + | +LL | match &b"str" { + | ------- this expression has type `&&[u8; 3]` +LL | b"str" => {} + | ^^^^^^ expected `&&[u8; 3]`, found `&[u8; 3]` + | + = note: expected reference `&&_` + found reference `&'static _` + +error[E0308]: mismatched types + --> $DIR/needs-gate.rs:45:9 + | +LL | match "str".to_owned() { + | ---------------- this expression has type `String` +LL | "str" => {} + | ^^^^^ expected `String`, found `&str` + +error[E0308]: mismatched types + --> $DIR/needs-gate.rs:52:12 + | +LL | if let "str" = &mut *"str".to_string() {} + | ^^^^^ ----------------------- this expression has type `&mut str` + | | + | types differ in mutability + | + = note: expected mutable reference `&mut _` + found reference `&'static _` + +error[E0308]: mismatched types + --> $DIR/needs-gate.rs:54:12 + | +LL | if let b"str" = &mut b"str".clone() {} + | ^^^^^^ ------------------- this expression has type `&mut [u8; 3]` + | | + | types differ in mutability + | + = note: expected mutable reference `&mut _` + found reference `&'static _` + +error[E0308]: mismatched types + --> $DIR/needs-gate.rs:56:12 + | +LL | if let b"str" = &mut b"str".clone()[..] {} + | ^^^^^^ ----------------------- this expression has type `&mut [u8]` + | | + | types differ in mutability + | + = note: expected mutable reference `&mut _` + found reference `&'static _` + +error: aborting due to 11 previous errors Some errors have detailed explanations: E0308, E0658. For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/pattern/deref-patterns/strings.rs b/tests/ui/pattern/deref-patterns/strings.rs index 536e943b3f67..fac15a9aee3d 100644 --- a/tests/ui/pattern/deref-patterns/strings.rs +++ b/tests/ui/pattern/deref-patterns/strings.rs @@ -14,10 +14,26 @@ fn main() { }; assert_eq!(test_actual, test_expect); - // Test string literals in explicit `deref!(_)` patterns. + // Test matching on `&mut str`. + let test_actual = match &mut *test_in.to_string() { + "zero" => 0, + "one" => 1, + _ => 2, + }; + assert_eq!(test_actual, test_expect); + + // Test string literals in deref patterns. let test_actual = match test_in.to_string() { deref!("zero") => 0, - deref!("one") => 1, + "one" => 1, + _ => 2, + }; + assert_eq!(test_actual, test_expect); + + // Test peeling references in addition to smart pointers. + let test_actual = match &test_in.to_string() { + deref!("zero") => 0, + "one" => 1, _ => 2, }; assert_eq!(test_actual, test_expect); @@ -47,18 +63,34 @@ fn main() { }; assert_eq!(test_actual, test_expect); - // Test byte string literals used as arrays in explicit `deref!(_)` patterns. - let test_actual = match Box::new(*test_in) { - deref!(b"0") => 0, - deref!(b"1") => 1, + // Test matching on `&mut [u8; N]`. + let test_actual = match &mut test_in.clone() { + b"0" => 0, + b"1" => 1, _ => 2, }; assert_eq!(test_actual, test_expect); - // Test byte string literals used as slices in explicit `deref!(_)` patterns. + // Test matching on `&mut [u8]`. + let test_actual = match &mut test_in.clone()[..] { + b"0" => 0, + b"1" => 1, + _ => 2, + }; + assert_eq!(test_actual, test_expect); + + // Test byte string literals used as arrays in deref patterns. + let test_actual = match Box::new(*test_in) { + deref!(b"0") => 0, + b"1" => 1, + _ => 2, + }; + assert_eq!(test_actual, test_expect); + + // Test byte string literals used as slices in deref patterns. let test_actual = match test_in.to_vec() { deref!(b"0") => 0, - deref!(b"1") => 1, + b"1" => 1, _ => 2, }; assert_eq!(test_actual, test_expect); diff --git a/tests/ui/pattern/deref-patterns/typeck_fail.rs b/tests/ui/pattern/deref-patterns/typeck_fail.rs index 52d84f7a34de..6ae87bb7bc36 100644 --- a/tests/ui/pattern/deref-patterns/typeck_fail.rs +++ b/tests/ui/pattern/deref-patterns/typeck_fail.rs @@ -2,19 +2,6 @@ #![allow(incomplete_features)] fn main() { - // FIXME(deref_patterns): fails to typecheck because string literal patterns don't peel - // references from the scrutinee. - match "foo".to_string() { - "foo" => {} - //~^ ERROR: mismatched types - _ => {} - } - match &"foo".to_string() { - "foo" => {} - //~^ ERROR: mismatched types - _ => {} - } - // Make sure we don't try implicitly dereferncing any ADT. match Some(0) { Ok(0) => {} diff --git a/tests/ui/pattern/deref-patterns/typeck_fail.stderr b/tests/ui/pattern/deref-patterns/typeck_fail.stderr index e87528c1c51a..fc29caac5630 100644 --- a/tests/ui/pattern/deref-patterns/typeck_fail.stderr +++ b/tests/ui/pattern/deref-patterns/typeck_fail.stderr @@ -1,24 +1,5 @@ error[E0308]: mismatched types - --> $DIR/typeck_fail.rs:8:9 - | -LL | match "foo".to_string() { - | ----------------- this expression has type `String` -LL | "foo" => {} - | ^^^^^ expected `String`, found `&str` - -error[E0308]: mismatched types - --> $DIR/typeck_fail.rs:13:9 - | -LL | match &"foo".to_string() { - | ------------------ this expression has type `&String` -LL | "foo" => {} - | ^^^^^ expected `&String`, found `&str` - | - = note: expected reference `&String` - found reference `&'static str` - -error[E0308]: mismatched types - --> $DIR/typeck_fail.rs:20:9 + --> $DIR/typeck_fail.rs:7:9 | LL | match Some(0) { | ------- this expression has type `Option<{integer}>` @@ -28,6 +9,6 @@ LL | Ok(0) => {} = note: expected enum `Option<{integer}>` found enum `Result<_, _>` -error: aborting due to 3 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/pattern/deref-patterns/usefulness/empty-types.rs b/tests/ui/pattern/deref-patterns/usefulness/empty-types.rs new file mode 100644 index 000000000000..03419030e72f --- /dev/null +++ b/tests/ui/pattern/deref-patterns/usefulness/empty-types.rs @@ -0,0 +1,47 @@ +//! Test that the place behind a deref pattern is treated as maybe-invalid, and thus empty arms +//! cannot be omitted. This is handled the same as for refs and union fields, so this leaves the +//! bulk of the testing to `tests/ui/pattern/usefulness/empty-types.rs`. +// FIXME(deref_patterns): On stabilization, cases for deref patterns could be worked into that file +// to keep the tests for empty types in one place and test more thoroughly. +#![feature(deref_patterns)] +#![expect(incomplete_features)] +#![deny(unreachable_patterns)] + +enum Void {} + +fn main() { + // Sanity check: matching on an empty type without pointer indirection lets us omit arms. + let opt_void: Option = None; + match opt_void { + None => {} + } + + // But if we hide it behind a smart pointer, we need an arm. + let box_opt_void: Box> = Box::new(None); + match box_opt_void { + //~^ ERROR non-exhaustive patterns: `deref!(Some(_))` not covered + None => {} + } + match box_opt_void { + None => {} + Some(_) => {} + } + match box_opt_void { + None => {} + _ => {} + } + + // For consistency, this behaves the same as if we manually dereferenced the scrutinee. + match *box_opt_void { + //~^ ERROR non-exhaustive patterns: `Some(_)` not covered + None => {} + } + match *box_opt_void { + None => {} + Some(_) => {} + } + match *box_opt_void { + None => {} + _ => {} + } +} diff --git a/tests/ui/pattern/deref-patterns/usefulness/empty-types.stderr b/tests/ui/pattern/deref-patterns/usefulness/empty-types.stderr new file mode 100644 index 000000000000..e32477085661 --- /dev/null +++ b/tests/ui/pattern/deref-patterns/usefulness/empty-types.stderr @@ -0,0 +1,38 @@ +error[E0004]: non-exhaustive patterns: `deref!(Some(_))` not covered + --> $DIR/empty-types.rs:21:11 + | +LL | match box_opt_void { + | ^^^^^^^^^^^^ pattern `deref!(Some(_))` not covered + | +note: `Box>` defined here + --> $SRC_DIR/alloc/src/boxed.rs:LL:COL + = note: the matched value is of type `Box>` + = note: `Void` is uninhabited but is not being matched by value, so a wildcard `_` is required +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 => {}, +LL + deref!(Some(_)) => todo!() + | + +error[E0004]: non-exhaustive patterns: `Some(_)` not covered + --> $DIR/empty-types.rs:35:11 + | +LL | match *box_opt_void { + | ^^^^^^^^^^^^^ pattern `Some(_)` not covered + | +note: `Option` defined here + --> $SRC_DIR/core/src/option.rs:LL:COL + ::: $SRC_DIR/core/src/option.rs:LL:COL + | + = note: not covered + = note: the matched value is of type `Option` + = note: `Void` is uninhabited but is not being matched by value, so a wildcard `_` is required +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 => {}, +LL + Some(_) => todo!() + | + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0004`. diff --git a/tests/ui/pattern/deref-patterns/usefulness/mixed-constructors.rs b/tests/ui/pattern/deref-patterns/usefulness/mixed-constructors.rs new file mode 100644 index 000000000000..f567dc07bb59 --- /dev/null +++ b/tests/ui/pattern/deref-patterns/usefulness/mixed-constructors.rs @@ -0,0 +1,48 @@ +//! Test matches with a mix of ADT constructors and deref patterns. Currently, usefulness analysis +//! doesn't support this, so make sure we catch it beforehand. As a consequence, it takes priority +//! over non-exhaustive match and unreachable pattern errors. +#![feature(deref_patterns)] +#![expect(incomplete_features)] +#![deny(unreachable_patterns)] + +use std::borrow::Cow; + +fn main() { + let cow: Cow<'static, bool> = Cow::Borrowed(&false); + + match cow { + true => {} + //~v ERROR mix of deref patterns and normal constructors + false => {} + Cow::Borrowed(_) => {} + } + + match cow { + Cow::Owned(_) => {} + Cow::Borrowed(_) => {} + true => {} + //~^ ERROR mix of deref patterns and normal constructors + } + + match cow { + _ => {} + Cow::Owned(_) => {} + false => {} + //~^ ERROR mix of deref patterns and normal constructors + } + + match (cow, 0) { + (Cow::Owned(_), 0) => {} + (Cow::Borrowed(_), 0) => {} + (true, 0) => {} + //~^ ERROR mix of deref patterns and normal constructors + } + + match (0, cow) { + (0, Cow::Owned(_)) => {} + (0, Cow::Borrowed(_)) => {} + _ => {} + (1, true) => {} + //~^ ERROR mix of deref patterns and normal constructors + } +} diff --git a/tests/ui/pattern/deref-patterns/usefulness/mixed-constructors.stderr b/tests/ui/pattern/deref-patterns/usefulness/mixed-constructors.stderr new file mode 100644 index 000000000000..5ad24164b985 --- /dev/null +++ b/tests/ui/pattern/deref-patterns/usefulness/mixed-constructors.stderr @@ -0,0 +1,43 @@ +error: mix of deref patterns and normal constructors + --> $DIR/mixed-constructors.rs:16:9 + | +LL | false => {} + | ^^^^^ matches on the result of dereferencing `Cow<'_, bool>` +LL | Cow::Borrowed(_) => {} + | ^^^^^^^^^^^^^^^^ matches directly on `Cow<'_, bool>` + +error: mix of deref patterns and normal constructors + --> $DIR/mixed-constructors.rs:22:9 + | +LL | Cow::Borrowed(_) => {} + | ^^^^^^^^^^^^^^^^ matches directly on `Cow<'_, bool>` +LL | true => {} + | ^^^^ matches on the result of dereferencing `Cow<'_, bool>` + +error: mix of deref patterns and normal constructors + --> $DIR/mixed-constructors.rs:29:9 + | +LL | Cow::Owned(_) => {} + | ^^^^^^^^^^^^^ matches directly on `Cow<'_, bool>` +LL | false => {} + | ^^^^^ matches on the result of dereferencing `Cow<'_, bool>` + +error: mix of deref patterns and normal constructors + --> $DIR/mixed-constructors.rs:36:10 + | +LL | (Cow::Borrowed(_), 0) => {} + | ^^^^^^^^^^^^^^^^ matches directly on `Cow<'_, bool>` +LL | (true, 0) => {} + | ^^^^ matches on the result of dereferencing `Cow<'_, bool>` + +error: mix of deref patterns and normal constructors + --> $DIR/mixed-constructors.rs:43:13 + | +LL | (0, Cow::Borrowed(_)) => {} + | ^^^^^^^^^^^^^^^^ matches directly on `Cow<'_, bool>` +LL | _ => {} +LL | (1, true) => {} + | ^^^^ matches on the result of dereferencing `Cow<'_, bool>` + +error: aborting due to 5 previous errors + diff --git a/tests/ui/pattern/deref-patterns/usefulness/non-exhaustive.rs b/tests/ui/pattern/deref-patterns/usefulness/non-exhaustive.rs new file mode 100644 index 000000000000..704cae8bdbc4 --- /dev/null +++ b/tests/ui/pattern/deref-patterns/usefulness/non-exhaustive.rs @@ -0,0 +1,28 @@ +//! Test non-exhaustive matches involving deref patterns. +#![feature(deref_patterns)] +#![expect(incomplete_features)] +#![deny(unreachable_patterns)] + +fn main() { + match Box::new(false) { + //~^ ERROR non-exhaustive patterns: `deref!(true)` not covered + false => {} + } + + match Box::new(Box::new(false)) { + //~^ ERROR non-exhaustive patterns: `deref!(deref!(false))` not covered + true => {} + } + + match Box::new((true, Box::new(false))) { + //~^ ERROR non-exhaustive patterns: `deref!((false, deref!(false)))` and `deref!((true, deref!(true)))` not covered + (true, false) => {} + (false, true) => {} + } + + enum T { A, B, C } + match Box::new((Box::new(T::A), Box::new(T::A))) { + //~^ ERROR non-exhaustive patterns: `deref!((deref!(T::C), _))` not covered + (T::A | T::B, T::C) => {} + } +} diff --git a/tests/ui/pattern/deref-patterns/usefulness/non-exhaustive.stderr b/tests/ui/pattern/deref-patterns/usefulness/non-exhaustive.stderr new file mode 100644 index 000000000000..55fa84bafde2 --- /dev/null +++ b/tests/ui/pattern/deref-patterns/usefulness/non-exhaustive.stderr @@ -0,0 +1,63 @@ +error[E0004]: non-exhaustive patterns: `deref!(true)` not covered + --> $DIR/non-exhaustive.rs:7:11 + | +LL | match Box::new(false) { + | ^^^^^^^^^^^^^^^ pattern `deref!(true)` not covered + | +note: `Box` defined here + --> $SRC_DIR/alloc/src/boxed.rs:LL:COL + = note: the matched value is of type `Box` +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 ~ false => {}, +LL + deref!(true) => todo!() + | + +error[E0004]: non-exhaustive patterns: `deref!(deref!(false))` not covered + --> $DIR/non-exhaustive.rs:12:11 + | +LL | match Box::new(Box::new(false)) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `deref!(deref!(false))` not covered + | +note: `Box>` defined here + --> $SRC_DIR/alloc/src/boxed.rs:LL:COL + = note: the matched value is of type `Box>` +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 ~ true => {}, +LL + deref!(deref!(false)) => todo!() + | + +error[E0004]: non-exhaustive patterns: `deref!((false, deref!(false)))` and `deref!((true, deref!(true)))` not covered + --> $DIR/non-exhaustive.rs:17:11 + | +LL | match Box::new((true, Box::new(false))) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ patterns `deref!((false, deref!(false)))` and `deref!((true, deref!(true)))` not covered + | +note: `Box<(bool, Box)>` defined here + --> $SRC_DIR/alloc/src/boxed.rs:LL:COL + = note: the matched value is of type `Box<(bool, Box)>` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms + | +LL ~ (false, true) => {}, +LL + deref!((false, deref!(false))) | deref!((true, deref!(true))) => todo!() + | + +error[E0004]: non-exhaustive patterns: `deref!((deref!(T::C), _))` not covered + --> $DIR/non-exhaustive.rs:24:11 + | +LL | match Box::new((Box::new(T::A), Box::new(T::A))) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `deref!((deref!(T::C), _))` not covered + | +note: `Box<(Box, Box)>` defined here + --> $SRC_DIR/alloc/src/boxed.rs:LL:COL + = note: the matched value is of type `Box<(Box, Box)>` +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 ~ (T::A | T::B, T::C) => {}, +LL + deref!((deref!(T::C), _)) => todo!() + | + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0004`. diff --git a/tests/ui/pattern/deref-patterns/usefulness/unreachable-patterns.rs b/tests/ui/pattern/deref-patterns/usefulness/unreachable-patterns.rs new file mode 100644 index 000000000000..2677fc54dedc --- /dev/null +++ b/tests/ui/pattern/deref-patterns/usefulness/unreachable-patterns.rs @@ -0,0 +1,33 @@ +//! Test unreachable patterns involving deref patterns. +#![feature(deref_patterns)] +#![expect(incomplete_features)] +#![deny(unreachable_patterns)] + +fn main() { + match Box::new(false) { + true => {} + false => {} + false => {} //~ ERROR unreachable pattern + } + + match Box::new(Box::new(false)) { + true => {} + false => {} + true => {} //~ ERROR unreachable pattern + } + + match Box::new((true, Box::new(false))) { + (true, _) => {} + (_, true) => {} + (false, false) => {} + _ => {} //~ ERROR unreachable pattern + } + + enum T { A, B, C } + match Box::new((Box::new(T::A), Box::new(T::A))) { + (T::A | T::B, T::A | T::C) => {} + (T::A, T::C) => {} //~ ERROR unreachable pattern + (T::B, T::A) => {} //~ ERROR unreachable pattern + _ => {} + } +} diff --git a/tests/ui/pattern/deref-patterns/usefulness/unreachable-patterns.stderr b/tests/ui/pattern/deref-patterns/usefulness/unreachable-patterns.stderr new file mode 100644 index 000000000000..045e11be3196 --- /dev/null +++ b/tests/ui/pattern/deref-patterns/usefulness/unreachable-patterns.stderr @@ -0,0 +1,60 @@ +error: unreachable pattern + --> $DIR/unreachable-patterns.rs:10:9 + | +LL | false => {} + | ----- matches all the relevant values +LL | false => {} + | ^^^^^ no value can reach this + | +note: the lint level is defined here + --> $DIR/unreachable-patterns.rs:4:9 + | +LL | #![deny(unreachable_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/unreachable-patterns.rs:16:9 + | +LL | true => {} + | ---- matches all the relevant values +LL | false => {} +LL | true => {} + | ^^^^ no value can reach this + +error: unreachable pattern + --> $DIR/unreachable-patterns.rs:23:9 + | +LL | _ => {} + | ^ no value can reach this + | +note: multiple earlier patterns match some of the same values + --> $DIR/unreachable-patterns.rs:23:9 + | +LL | (true, _) => {} + | --------- matches some of the same values +LL | (_, true) => {} + | --------- matches some of the same values +LL | (false, false) => {} + | -------------- matches some of the same values +LL | _ => {} + | ^ collectively making this unreachable + +error: unreachable pattern + --> $DIR/unreachable-patterns.rs:29:9 + | +LL | (T::A | T::B, T::A | T::C) => {} + | -------------------------- matches all the relevant values +LL | (T::A, T::C) => {} + | ^^^^^^^^^^^^ no value can reach this + +error: unreachable pattern + --> $DIR/unreachable-patterns.rs:30:9 + | +LL | (T::A | T::B, T::A | T::C) => {} + | -------------------------- matches all the relevant values +LL | (T::A, T::C) => {} +LL | (T::B, T::A) => {} + | ^^^^^^^^^^^^ no value can reach this + +error: aborting due to 5 previous errors + diff --git a/tests/ui/pattern/usefulness/issue-78123-non-exhaustive-reference.rs b/tests/ui/pattern/usefulness/issue-78123-non-exhaustive-reference.rs index cbfcf0eafd49..6c5a331b4b56 100644 --- a/tests/ui/pattern/usefulness/issue-78123-non-exhaustive-reference.rs +++ b/tests/ui/pattern/usefulness/issue-78123-non-exhaustive-reference.rs @@ -1,6 +1,5 @@ enum A {} //~^ NOTE `A` defined here - //~| NOTE fn f(a: &A) { match a {} diff --git a/tests/ui/pattern/usefulness/issue-78123-non-exhaustive-reference.stderr b/tests/ui/pattern/usefulness/issue-78123-non-exhaustive-reference.stderr index c37a9a515790..67ee38eed60c 100644 --- a/tests/ui/pattern/usefulness/issue-78123-non-exhaustive-reference.stderr +++ b/tests/ui/pattern/usefulness/issue-78123-non-exhaustive-reference.stderr @@ -1,5 +1,5 @@ error[E0004]: non-exhaustive patterns: type `&A` is non-empty - --> $DIR/issue-78123-non-exhaustive-reference.rs:6:11 + --> $DIR/issue-78123-non-exhaustive-reference.rs:5:11 | LL | match a {} | ^ diff --git a/tests/ui/pin-macro/lifetime_errors_on_promotion_misusage.rs b/tests/ui/pin-macro/lifetime_errors_on_promotion_misusage.rs index e505fe435207..2771b4717fbf 100644 --- a/tests/ui/pin-macro/lifetime_errors_on_promotion_misusage.rs +++ b/tests/ui/pin-macro/lifetime_errors_on_promotion_misusage.rs @@ -9,14 +9,14 @@ use core::{ fn function_call_stops_borrow_extension() { let phantom_pinned = identity(pin!(PhantomPinned)); - //~^ ERROR does not live long enough + //~^ ERROR temporary value dropped while borrowed [E0716] stuff(phantom_pinned) } fn promotion_only_works_for_the_innermost_block() { let phantom_pinned = { let phantom_pinned = pin!(PhantomPinned); - //~^ ERROR does not live long enough + //~^ ERROR temporary value dropped while borrowed [E0716] phantom_pinned }; stuff(phantom_pinned) diff --git a/tests/ui/pin-macro/lifetime_errors_on_promotion_misusage.stderr b/tests/ui/pin-macro/lifetime_errors_on_promotion_misusage.stderr index 43fb82be7c2f..4ecc6370d3ca 100644 --- a/tests/ui/pin-macro/lifetime_errors_on_promotion_misusage.stderr +++ b/tests/ui/pin-macro/lifetime_errors_on_promotion_misusage.stderr @@ -1,29 +1,31 @@ -error[E0597]: value does not live long enough +error[E0716]: temporary value dropped while borrowed --> $DIR/lifetime_errors_on_promotion_misusage.rs:11:35 | LL | let phantom_pinned = identity(pin!(PhantomPinned)); - | ^^^^^^^^^^^^^^^^^^^ - value dropped here while still borrowed + | ^^^^^^^^^^^^^^^^^^^ - temporary value is freed at the end of this statement | | - | borrowed value does not live long enough + | creates a temporary value which is freed while still in use LL | LL | stuff(phantom_pinned) | -------------- borrow later used here | + = note: consider using a `let` binding to create a longer lived value = note: this error originates in the macro `pin` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0597]: value does not live long enough +error[E0716]: temporary value dropped while borrowed --> $DIR/lifetime_errors_on_promotion_misusage.rs:18:30 | LL | let phantom_pinned = { | -------------- borrow later stored here LL | let phantom_pinned = pin!(PhantomPinned); - | ^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough + | ^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use ... LL | }; - | - value dropped here while still borrowed + | - temporary value is freed at the end of this statement | + = note: consider using a `let` binding to create a longer lived value = note: this error originates in the macro `pin` (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 E0597`. +For more information about this error, try `rustc --explain E0716`. diff --git a/tests/ui/auxiliary/impl_privacy_xc_1.rs b/tests/ui/privacy/auxiliary/impl-privacy-cross-crate-1.rs similarity index 100% rename from tests/ui/auxiliary/impl_privacy_xc_1.rs rename to tests/ui/privacy/auxiliary/impl-privacy-cross-crate-1.rs diff --git a/tests/ui/privacy/auxiliary/impl_privacy_xc_2.rs b/tests/ui/privacy/auxiliary/impl-privacy-cross-crate-2.rs similarity index 100% rename from tests/ui/privacy/auxiliary/impl_privacy_xc_2.rs rename to tests/ui/privacy/auxiliary/impl-privacy-cross-crate-2.rs diff --git a/tests/ui/privacy/impl-privacy-cross-crate-1.rs b/tests/ui/privacy/impl-privacy-cross-crate-1.rs new file mode 100644 index 000000000000..6b2ef3ccc781 --- /dev/null +++ b/tests/ui/privacy/impl-privacy-cross-crate-1.rs @@ -0,0 +1,10 @@ +//@ run-pass +//@ aux-build:impl-privacy-cross-crate-1.rs + + +extern crate impl_privacy_cross_crate_1; + +pub fn main() { + let fish = impl_privacy_cross_crate_1::Fish { x: 1 }; + fish.swim(); +} diff --git a/tests/ui/privacy/impl-privacy-cross-crate-2.rs b/tests/ui/privacy/impl-privacy-cross-crate-2.rs new file mode 100644 index 000000000000..fa07e6e8ccea --- /dev/null +++ b/tests/ui/privacy/impl-privacy-cross-crate-2.rs @@ -0,0 +1,10 @@ +//@ run-pass +//@ aux-build:impl-privacy-cross-crate-2.rs + +extern crate impl_privacy_cross_crate_2; + +pub fn main() { + let fish1 = impl_privacy_cross_crate_2::Fish { x: 1 }; + let fish2 = impl_privacy_cross_crate_2::Fish { x: 2 }; + if fish1.eq(&fish2) { println!("yes") } else { println!("no") }; +} diff --git a/tests/ui/privacy/impl-privacy-xc-2.rs b/tests/ui/privacy/impl-privacy-xc-2.rs deleted file mode 100644 index da345ba20720..000000000000 --- a/tests/ui/privacy/impl-privacy-xc-2.rs +++ /dev/null @@ -1,10 +0,0 @@ -//@ run-pass -//@ aux-build:impl_privacy_xc_2.rs - -extern crate impl_privacy_xc_2; - -pub fn main() { - let fish1 = impl_privacy_xc_2::Fish { x: 1 }; - let fish2 = impl_privacy_xc_2::Fish { x: 2 }; - if fish1.eq(&fish2) { println!("yes") } else { println!("no") }; -} diff --git a/tests/ui/pub/pub-restricted-warning.rs b/tests/ui/pub/pub-restricted-warning.rs new file mode 100644 index 000000000000..80384afbb008 --- /dev/null +++ b/tests/ui/pub/pub-restricted-warning.rs @@ -0,0 +1,25 @@ +//@ check-pass + +#![allow(dead_code)] + +mod outer { + pub mod inner { + pub(in crate::outer) struct Foo; + pub fn bar() -> Foo { + //~^ WARNING type `Foo` is more private than the item `outer::inner::bar` [private_interfaces] + Foo + } + } + + pub mod nested { + pub mod inner { + pub(in crate::outer::nested) struct NestedFoo; + pub fn bar() -> NestedFoo { + //~^ WARNING type `NestedFoo` is more private than the item `nested::inner::bar` [private_interfaces] + NestedFoo + } + } + } +} + +fn main() {} diff --git a/tests/ui/pub/pub-restricted-warning.stderr b/tests/ui/pub/pub-restricted-warning.stderr new file mode 100644 index 000000000000..74f32d3de3c2 --- /dev/null +++ b/tests/ui/pub/pub-restricted-warning.stderr @@ -0,0 +1,27 @@ +warning: type `Foo` is more private than the item `outer::inner::bar` + --> $DIR/pub-restricted-warning.rs:8:9 + | +LL | pub fn bar() -> Foo { + | ^^^^^^^^^^^^^^^^^^^ function `outer::inner::bar` is reachable at visibility `pub(crate)` + | +note: but type `Foo` is only usable at visibility `pub(in crate::outer)` + --> $DIR/pub-restricted-warning.rs:7:9 + | +LL | pub(in crate::outer) struct Foo; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: `#[warn(private_interfaces)]` on by default + +warning: type `NestedFoo` is more private than the item `nested::inner::bar` + --> $DIR/pub-restricted-warning.rs:17:13 + | +LL | pub fn bar() -> NestedFoo { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ function `nested::inner::bar` is reachable at visibility `pub(crate)` + | +note: but type `NestedFoo` is only usable at visibility `pub(in crate::outer::nested)` + --> $DIR/pub-restricted-warning.rs:16:13 + | +LL | pub(in crate::outer::nested) struct NestedFoo; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: 2 warnings emitted + 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 400969c279e6..99fd83e7b6ff 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 @@ -4,11 +4,11 @@ error[E0277]: the trait bound `Something: Termination` is not satisfied LL | fn main() -> Something { | ^^^^^^^^^ the trait `Termination` is not implemented for `Something` | -note: required by a bound in `Main::{anon_assoc#0}` +note: required by a bound in `Main::main::{anon_assoc#0}` --> $DIR/issue-103052-2.rs:3:27 | LL | fn main() -> impl std::process::Termination; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Main::{anon_assoc#0}` + | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Main::main::{anon_assoc#0}` error: aborting due to 1 previous error diff --git a/tests/ui/rust-2024/unsafe-attributes/auxiliary/safe_attr.rs b/tests/ui/rust-2024/unsafe-attributes/auxiliary/safe_attr.rs new file mode 100644 index 000000000000..161b71b9737b --- /dev/null +++ b/tests/ui/rust-2024/unsafe-attributes/auxiliary/safe_attr.rs @@ -0,0 +1,7 @@ +extern crate proc_macro; +use proc_macro::TokenStream; + +#[proc_macro_attribute] +pub fn safe(_attr: TokenStream, item: TokenStream) -> TokenStream { + item +} diff --git a/tests/ui/rust-2024/unsafe-attributes/safe-proc-macro-attribute.rs b/tests/ui/rust-2024/unsafe-attributes/safe-proc-macro-attribute.rs new file mode 100644 index 000000000000..56b7001bdbf0 --- /dev/null +++ b/tests/ui/rust-2024/unsafe-attributes/safe-proc-macro-attribute.rs @@ -0,0 +1,22 @@ +//! Anti-regression test for `#[safe]` proc-macro attribute. + +//@ revisions: unknown_attr proc_macro_attr +//@[proc_macro_attr] proc-macro: safe_attr.rs +//@[proc_macro_attr] check-pass + +#![warn(unsafe_attr_outside_unsafe)] + +#[cfg(proc_macro_attr)] +extern crate safe_attr; +#[cfg(proc_macro_attr)] +use safe_attr::safe; + +#[safe] +//[unknown_attr]~^ ERROR cannot find attribute `safe` in this scope +fn foo() {} + +#[safe(no_mangle)] +//[unknown_attr]~^ ERROR cannot find attribute `safe` in this scope +fn bar() {} + +fn main() {} diff --git a/tests/ui/rust-2024/unsafe-attributes/safe-proc-macro-attribute.unknown_attr.stderr b/tests/ui/rust-2024/unsafe-attributes/safe-proc-macro-attribute.unknown_attr.stderr new file mode 100644 index 000000000000..93c6d75e52ff --- /dev/null +++ b/tests/ui/rust-2024/unsafe-attributes/safe-proc-macro-attribute.unknown_attr.stderr @@ -0,0 +1,14 @@ +error: cannot find attribute `safe` in this scope + --> $DIR/safe-proc-macro-attribute.rs:18:3 + | +LL | #[safe(no_mangle)] + | ^^^^ + +error: cannot find attribute `safe` in this scope + --> $DIR/safe-proc-macro-attribute.rs:14:3 + | +LL | #[safe] + | ^^^^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-allow.rs b/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-allow.rs new file mode 100644 index 000000000000..76fdce7e5cff --- /dev/null +++ b/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-allow.rs @@ -0,0 +1,16 @@ +//@ check-pass +//@ edition: 2021 +// +// Anti-regression test for https://github.com/rust-lang/rust/issues/140602 +// where the generated warning couldn't be allowed due too being attached to +// the wrong AST node. + +#![deny(unsafe_attr_outside_unsafe)] + +#[allow(unsafe_attr_outside_unsafe)] +mod generated { + #[no_mangle] + fn _generated_foo() {} +} + +fn main() {} diff --git a/tests/ui/stability-attribute/generics-default-stability.stderr b/tests/ui/stability-attribute/generics-default-stability.stderr index f4f51a14248e..53ef3e170cc1 100644 --- a/tests/ui/stability-attribute/generics-default-stability.stderr +++ b/tests/ui/stability-attribute/generics-default-stability.stderr @@ -270,6 +270,18 @@ LL | let _: Struct3 = Struct3 { field1: 0, field2: 0 }; = help: add `#![feature(unstable_default)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +warning: use of deprecated field `unstable_generic_param::Struct4::field`: test + --> $DIR/generics-default-stability.rs:71:39 + | +LL | let _: Struct4 = Struct4 { field: 1 }; + | ^^^^^^^^ + +warning: use of deprecated field `unstable_generic_param::Struct4::field`: test + --> $DIR/generics-default-stability.rs:78:39 + | +LL | let _: Struct4 = Struct4 { field: 0 }; + | ^^^^^^^^ + error[E0658]: use of unstable library feature `unstable_default` --> $DIR/generics-default-stability.rs:84:20 | @@ -279,6 +291,12 @@ LL | let _: Struct5 = Struct5 { field: 1 }; = help: add `#![feature(unstable_default)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +warning: use of deprecated field `unstable_generic_param::Struct5::field`: test + --> $DIR/generics-default-stability.rs:84:39 + | +LL | let _: Struct5 = Struct5 { field: 1 }; + | ^^^^^^^^ + error[E0658]: use of unstable library feature `unstable_default` --> $DIR/generics-default-stability.rs:90:20 | @@ -297,6 +315,12 @@ LL | let _: Struct5 = Struct5 { field: 0 }; = help: add `#![feature(unstable_default)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +warning: use of deprecated field `unstable_generic_param::Struct5::field`: test + --> $DIR/generics-default-stability.rs:92:39 + | +LL | let _: Struct5 = Struct5 { field: 0 }; + | ^^^^^^^^ + error[E0658]: use of unstable library feature `unstable_default` --> $DIR/generics-default-stability.rs:100:19 | @@ -468,30 +492,6 @@ LL | let _: Box1 = Box1::new(1); = help: add `#![feature(box_alloc_param)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -warning: use of deprecated field `unstable_generic_param::Struct4::field`: test - --> $DIR/generics-default-stability.rs:71:39 - | -LL | let _: Struct4 = Struct4 { field: 1 }; - | ^^^^^^^^ - -warning: use of deprecated field `unstable_generic_param::Struct4::field`: test - --> $DIR/generics-default-stability.rs:78:39 - | -LL | let _: Struct4 = Struct4 { field: 0 }; - | ^^^^^^^^ - -warning: use of deprecated field `unstable_generic_param::Struct5::field`: test - --> $DIR/generics-default-stability.rs:84:39 - | -LL | let _: Struct5 = Struct5 { field: 1 }; - | ^^^^^^^^ - -warning: use of deprecated field `unstable_generic_param::Struct5::field`: test - --> $DIR/generics-default-stability.rs:92:39 - | -LL | let _: Struct5 = Struct5 { field: 0 }; - | ^^^^^^^^ - error: aborting due to 28 previous errors; 40 warnings emitted For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/stability-attribute/suggest-vec-allocator-api.stderr b/tests/ui/stability-attribute/suggest-vec-allocator-api.stderr index 6662ceda90b9..78b7d07b60cc 100644 --- a/tests/ui/stability-attribute/suggest-vec-allocator-api.stderr +++ b/tests/ui/stability-attribute/suggest-vec-allocator-api.stderr @@ -26,16 +26,6 @@ LL + String, LL ~ _)> = vec![]; | -error[E0658]: use of unstable library feature `allocator_api` - --> $DIR/suggest-vec-allocator-api.rs:8:26 - | -LL | let _boxed: Box = Box::new(10); - | ^ - | - = note: see issue #32838 for more information - = help: add `#![feature(allocator_api)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - error[E0658]: use of unstable library feature `allocator_api` --> $DIR/suggest-vec-allocator-api.rs:7:24 | @@ -48,6 +38,16 @@ LL | let _ = Vec::::new(); = help: add `#![feature(allocator_api)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +error[E0658]: use of unstable library feature `allocator_api` + --> $DIR/suggest-vec-allocator-api.rs:8:26 + | +LL | let _boxed: Box = Box::new(10); + | ^ + | + = note: see issue #32838 for more information + = help: add `#![feature(allocator_api)]` 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 4 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/statics/auxiliary/inner_static.rs b/tests/ui/statics/auxiliary/inner_static.rs new file mode 100644 index 000000000000..1c62046438fc --- /dev/null +++ b/tests/ui/statics/auxiliary/inner_static.rs @@ -0,0 +1,67 @@ +//! Test for inner statics with the same name. +//! +//! Before, the path name for all items defined in methods of traits and impls never +//! took into account the name of the method. This meant that if you had two statics +//! of the same name in two different methods the statics would end up having the +//! same symbol named (even after mangling) because the path components leading to +//! the symbol were exactly the same (just __extensions__ and the static name). +//! +//! It turns out that if you add the symbol "A" twice to LLVM, it automatically +//! makes the second one "A1" instead of "A". What this meant is that in local crate +//! compilations we never found this bug. Even across crates, this was never a +//! problem. The problem arises when you have generic methods that don't get +//! generated at compile-time of a library. If the statics were re-added to LLVM by +//! a client crate of a library in a different order, you would reference different +//! constants (the integer suffixes wouldn't be guaranteed to be the same). + +pub struct A { pub v: T } +pub struct B { pub v: T } + +pub mod test { + pub struct A { pub v: T } + + impl A { + pub fn foo(&self) -> isize { + static a: isize = 5; + return a + } + + pub fn bar(&self) -> isize { + static a: isize = 6; + return a; + } + } +} + +impl A { + pub fn foo(&self) -> isize { + static a: isize = 1; + return a + } + + pub fn bar(&self) -> isize { + static a: isize = 2; + return a; + } +} + +impl B { + pub fn foo(&self) -> isize { + static a: isize = 3; + return a + } + + pub fn bar(&self) -> isize { + static a: isize = 4; + return a; + } +} + +pub fn foo() -> isize { + let a = A { v: () }; + let b = B { v: () }; + let c = test::A { v: () }; + return a.foo() + a.bar() + + b.foo() + b.bar() + + c.foo() + c.bar(); +} diff --git a/tests/ui/statics/inner-static.rs b/tests/ui/statics/inner-static.rs new file mode 100644 index 000000000000..1916435c46a1 --- /dev/null +++ b/tests/ui/statics/inner-static.rs @@ -0,0 +1,30 @@ +//! Test for inner statics with the same name. +//! +//! Before, the path name for all items defined in methods of traits and impls never +//! took into account the name of the method. This meant that if you had two statics +//! of the same name in two different methods the statics would end up having the +//! same symbol named (even after mangling) because the path components leading to +//! the symbol were exactly the same (just __extensions__ and the static name). +//! +//! It turns out that if you add the symbol "A" twice to LLVM, it automatically +//! makes the second one "A1" instead of "A". What this meant is that in local crate +//! compilations we never found this bug. Even across crates, this was never a +//! problem. The problem arises when you have generic methods that don't get +//! generated at compile-time of a library. If the statics were re-added to LLVM by +//! a client crate of a library in a different order, you would reference different +//! constants (the integer suffixes wouldn't be guaranteed to be the same). + +//@ run-pass +//@ aux-build:inner_static.rs + + +extern crate inner_static; + +pub fn main() { + let a = inner_static::A::<()> { v: () }; + let b = inner_static::B::<()> { v: () }; + let c = inner_static::test::A::<()> { v: () }; + assert_eq!(a.bar(), 2); + assert_eq!(b.bar(), 4); + assert_eq!(c.bar(), 6); +} diff --git a/tests/ui/suggestions/impl-trait-missing-lifetime-gated.rs b/tests/ui/suggestions/impl-trait-missing-lifetime-gated.rs index 443a7e3835e3..f5c3da847c72 100644 --- a/tests/ui/suggestions/impl-trait-missing-lifetime-gated.rs +++ b/tests/ui/suggestions/impl-trait-missing-lifetime-gated.rs @@ -49,6 +49,17 @@ mod alone_in_path { //~| ERROR missing lifetime specifier } +mod alone_in_path2 { + trait Foo<'a> { fn next(&mut self) -> Option<&'a ()>; } + + fn f(_: impl Foo<>) {} + //~^ ERROR anonymous lifetimes in `impl Trait` are unstable + + fn g(mut x: impl Foo<>) -> Option<&()> { x.next() } + //~^ ERROR anonymous lifetimes in `impl Trait` are unstable + //~| ERROR missing lifetime specifier +} + mod in_path { trait Foo<'a, T> { fn next(&mut self) -> Option<&'a T>; } diff --git a/tests/ui/suggestions/impl-trait-missing-lifetime-gated.stderr b/tests/ui/suggestions/impl-trait-missing-lifetime-gated.stderr index 24013c85c875..92996ca84678 100644 --- a/tests/ui/suggestions/impl-trait-missing-lifetime-gated.stderr +++ b/tests/ui/suggestions/impl-trait-missing-lifetime-gated.stderr @@ -108,7 +108,28 @@ LL + fn g(mut x: impl Foo) -> Option<()> { x.next() } | error[E0106]: missing lifetime specifier - --> $DIR/impl-trait-missing-lifetime-gated.rs:58:41 + --> $DIR/impl-trait-missing-lifetime-gated.rs:58:39 + | +LL | fn g(mut x: impl Foo<>) -> Option<&()> { x.next() } + | ^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from +help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static` + | +LL | fn g(mut x: impl Foo<>) -> Option<&'static ()> { x.next() } + | +++++++ +help: consider introducing a named lifetime parameter + | +LL | fn g<'a>(mut x: impl Foo<>) -> Option<&'a ()> { x.next() } + | ++++ ++ +help: alternatively, you might want to return an owned value + | +LL - fn g(mut x: impl Foo<>) -> Option<&()> { x.next() } +LL + fn g(mut x: impl Foo<>) -> Option<()> { x.next() } + | + +error[E0106]: missing lifetime specifier + --> $DIR/impl-trait-missing-lifetime-gated.rs:69:41 | LL | fn g(mut x: impl Foo<()>) -> Option<&()> { x.next() } | ^ expected named lifetime parameter @@ -129,7 +150,7 @@ LL + fn g(mut x: impl Foo<()>) -> Option<()> { x.next() } | warning: elided lifetime has a name - --> $DIR/impl-trait-missing-lifetime-gated.rs:64:57 + --> $DIR/impl-trait-missing-lifetime-gated.rs:75:57 | LL | fn resolved_anonymous<'a, T: 'a>(f: impl Fn(&'a str) -> &T) { | -- lifetime `'a` declared here ^ this elided lifetime gets resolved as `'a` @@ -219,6 +240,32 @@ LL | fn g<'a>(mut x: impl Foo<'a>) -> Option<&()> { x.next() } error[E0658]: anonymous lifetimes in `impl Trait` are unstable --> $DIR/impl-trait-missing-lifetime-gated.rs:55:22 | +LL | fn f(_: impl Foo<>) {} + | ^ expected named lifetime parameter + | + = help: add `#![feature(anonymous_lifetime_in_impl_trait)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +help: consider introducing a named lifetime parameter + | +LL | fn f<'a>(_: impl Foo<'a>) {} + | ++++ ++ + +error[E0658]: anonymous lifetimes in `impl Trait` are unstable + --> $DIR/impl-trait-missing-lifetime-gated.rs:58:26 + | +LL | fn g(mut x: impl Foo<>) -> Option<&()> { x.next() } + | ^ expected named lifetime parameter + | + = help: add `#![feature(anonymous_lifetime_in_impl_trait)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +help: consider introducing a named lifetime parameter + | +LL | fn g<'a>(mut x: impl Foo<'a>) -> Option<&()> { x.next() } + | ++++ ++ + +error[E0658]: anonymous lifetimes in `impl Trait` are unstable + --> $DIR/impl-trait-missing-lifetime-gated.rs:66:22 + | LL | fn f(_: impl Foo<()>) {} | ^ expected named lifetime parameter | @@ -230,7 +277,7 @@ LL | fn f<'a>(_: impl Foo<'a, ()>) {} | ++++ +++ error[E0658]: anonymous lifetimes in `impl Trait` are unstable - --> $DIR/impl-trait-missing-lifetime-gated.rs:58:26 + --> $DIR/impl-trait-missing-lifetime-gated.rs:69:26 | LL | fn g(mut x: impl Foo<()>) -> Option<&()> { x.next() } | ^ expected named lifetime parameter @@ -242,7 +289,7 @@ help: consider introducing a named lifetime parameter LL | fn g<'a>(mut x: impl Foo<'a, ()>) -> Option<&()> { x.next() } | ++++ +++ -error: aborting due to 14 previous errors; 1 warning emitted +error: aborting due to 17 previous errors; 1 warning emitted Some errors have detailed explanations: E0106, E0658. For more information about an error, try `rustc --explain E0106`. diff --git a/tests/ui/target-feature/abi-incompatible-target-feature-attribute.riscv.stderr b/tests/ui/target-feature/abi-incompatible-target-feature-attribute.riscv.stderr new file mode 100644 index 000000000000..49c5479275f3 --- /dev/null +++ b/tests/ui/target-feature/abi-incompatible-target-feature-attribute.riscv.stderr @@ -0,0 +1,8 @@ +error: target feature `d` cannot be enabled with `#[target_feature]`: this feature is incompatible with the target ABI + --> $DIR/abi-incompatible-target-feature-attribute.rs:15:90 + | +LL | #[cfg_attr(x86, target_feature(enable = "soft-float"))] #[cfg_attr(riscv, target_feature(enable = "d"))] + | ^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/target-feature/abi-incompatible-target-feature-attribute.rs b/tests/ui/target-feature/abi-incompatible-target-feature-attribute.rs new file mode 100644 index 000000000000..a87334407592 --- /dev/null +++ b/tests/ui/target-feature/abi-incompatible-target-feature-attribute.rs @@ -0,0 +1,17 @@ +//! Ensure ABI-incompatible features cannot be enabled via `#[target_feature]`. +// ignore-tidy-linelength +//@ compile-flags: --crate-type=lib +//@ revisions: x86 riscv +//@[x86] compile-flags: --target=x86_64-unknown-linux-gnu +//@[x86] needs-llvm-components: x86 +//@[riscv] compile-flags: --target=riscv32e-unknown-none-elf +//@[riscv] needs-llvm-components: riscv +#![feature(no_core, lang_items, riscv_target_feature, x87_target_feature)] +#![no_core] + +#[lang = "sized"] +pub trait Sized {} + +#[cfg_attr(x86, target_feature(enable = "soft-float"))] #[cfg_attr(riscv, target_feature(enable = "d"))] +//~^ERROR: cannot be enabled with +pub unsafe fn my_fun() {} diff --git a/tests/ui/target-feature/abi-incompatible-target-feature-attribute.x86.stderr b/tests/ui/target-feature/abi-incompatible-target-feature-attribute.x86.stderr new file mode 100644 index 000000000000..81471fd7e303 --- /dev/null +++ b/tests/ui/target-feature/abi-incompatible-target-feature-attribute.x86.stderr @@ -0,0 +1,8 @@ +error: target feature `soft-float` cannot be enabled with `#[target_feature]`: this feature is incompatible with the target ABI + --> $DIR/abi-incompatible-target-feature-attribute.rs:15:32 + | +LL | #[cfg_attr(x86, target_feature(enable = "soft-float"))] #[cfg_attr(riscv, target_feature(enable = "d"))] + | ^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/target-feature/abi-incompatible-target-feature-flag-enable.riscv.stderr b/tests/ui/target-feature/abi-incompatible-target-feature-flag-enable.riscv.stderr new file mode 100644 index 000000000000..2dca0c220332 --- /dev/null +++ b/tests/ui/target-feature/abi-incompatible-target-feature-flag-enable.riscv.stderr @@ -0,0 +1,19 @@ +warning: target feature `d` must be disabled to ensure that the ABI of the current target can be implemented correctly + | + = note: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #116344 + +warning: unstable feature specified for `-Ctarget-feature`: `d` + | + = note: this feature is not stably supported; its behavior can change in the future + +warning: unstable feature specified for `-Ctarget-feature`: `f` + | + = note: this feature is not stably supported; its behavior can change in the future + +warning: unstable feature specified for `-Ctarget-feature`: `zicsr` + | + = note: this feature is not stably supported; its behavior can change in the future + +warning: 4 warnings emitted + diff --git a/tests/ui/target-feature/abi-incompatible-target-feature-flag-enable.rs b/tests/ui/target-feature/abi-incompatible-target-feature-flag-enable.rs new file mode 100644 index 000000000000..68e1d3b9ddc6 --- /dev/null +++ b/tests/ui/target-feature/abi-incompatible-target-feature-flag-enable.rs @@ -0,0 +1,22 @@ +//! Ensure ABI-incompatible features cannot be enabled via `-Ctarget-feature`. +// These are just warnings for now. +//@ check-pass +//@ compile-flags: --crate-type=lib +//@ revisions: x86 riscv +//@[x86] compile-flags: --target=x86_64-unknown-linux-gnu -Ctarget-feature=+soft-float +//@[x86] needs-llvm-components: x86 +//@[riscv] compile-flags: --target=riscv32e-unknown-none-elf -Ctarget-feature=+d +//@[riscv] needs-llvm-components: riscv + +#![feature(no_core, lang_items, riscv_target_feature)] +#![no_core] + +#[lang = "sized"] +pub trait Sized {} +#[lang = "freeze"] +pub trait Freeze {} + +//~? WARN must be disabled to ensure that the ABI of the current target can be implemented correctly +//~? WARN unstable feature specified for `-Ctarget-feature` +//[riscv]~? WARN unstable feature specified for `-Ctarget-feature` +//[riscv]~? WARN unstable feature specified for `-Ctarget-feature` diff --git a/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag.stderr b/tests/ui/target-feature/abi-incompatible-target-feature-flag-enable.x86.stderr similarity index 100% rename from tests/ui/target-feature/forbidden-hardfloat-target-feature-flag.stderr rename to tests/ui/target-feature/abi-incompatible-target-feature-flag-enable.x86.stderr diff --git a/tests/ui/target-feature/allowed-softfloat-target-feature-flag-disable.rs b/tests/ui/target-feature/abi-irrelevant-target-feature-flag-disable.rs similarity index 59% rename from tests/ui/target-feature/allowed-softfloat-target-feature-flag-disable.rs rename to tests/ui/target-feature/abi-irrelevant-target-feature-flag-disable.rs index 7368ef120fa6..0013d033b9c5 100644 --- a/tests/ui/target-feature/allowed-softfloat-target-feature-flag-disable.rs +++ b/tests/ui/target-feature/abi-irrelevant-target-feature-flag-disable.rs @@ -1,3 +1,6 @@ +//! `x87` is a required target feature on some x86 targets, but not on this one as this one +//! uses soft-floats. So ensure disabling the target feature here (which is a NOP) does +//! not trigger a warning. //@ compile-flags: --target=x86_64-unknown-none --crate-type=lib //@ needs-llvm-components: x86 //@ compile-flags: -Ctarget-feature=-x87 diff --git a/tests/ui/target-feature/allowed-softfloat-target-feature-flag-disable.stderr b/tests/ui/target-feature/abi-irrelevant-target-feature-flag-disable.stderr similarity index 100% rename from tests/ui/target-feature/allowed-softfloat-target-feature-flag-disable.stderr rename to tests/ui/target-feature/abi-irrelevant-target-feature-flag-disable.stderr diff --git a/tests/ui/target-feature/allowed-softfloat-target-feature-attribute.rs b/tests/ui/target-feature/abi-required-target-feature-attribute.rs similarity index 69% rename from tests/ui/target-feature/allowed-softfloat-target-feature-attribute.rs rename to tests/ui/target-feature/abi-required-target-feature-attribute.rs index 8b60820cc9b6..95723c57f94d 100644 --- a/tests/ui/target-feature/allowed-softfloat-target-feature-attribute.rs +++ b/tests/ui/target-feature/abi-required-target-feature-attribute.rs @@ -1,3 +1,5 @@ +//! Enabling a target feature that is anyway required changes nothing, so this is allowed +//! for `#[target_feature]`. //@ compile-flags: --target=x86_64-unknown-none --crate-type=lib //@ needs-llvm-components: x86 //@ build-pass diff --git a/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable-neon.stderr b/tests/ui/target-feature/abi-required-target-feature-flag-disable.aarch64.stderr similarity index 100% rename from tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable-neon.stderr rename to tests/ui/target-feature/abi-required-target-feature-flag-disable.aarch64.stderr diff --git a/tests/ui/target-feature/abi-required-target-feature-flag-disable.loongarch.stderr b/tests/ui/target-feature/abi-required-target-feature-flag-disable.loongarch.stderr new file mode 100644 index 000000000000..35102e0571f4 --- /dev/null +++ b/tests/ui/target-feature/abi-required-target-feature-flag-disable.loongarch.stderr @@ -0,0 +1,11 @@ +warning: target feature `d` must be enabled to ensure that the ABI of the current target can be implemented correctly + | + = note: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #116344 + +warning: unstable feature specified for `-Ctarget-feature`: `d` + | + = note: this feature is not stably supported; its behavior can change in the future + +warning: 2 warnings emitted + diff --git a/tests/ui/target-feature/abi-required-target-feature-flag-disable.riscv.stderr b/tests/ui/target-feature/abi-required-target-feature-flag-disable.riscv.stderr new file mode 100644 index 000000000000..35102e0571f4 --- /dev/null +++ b/tests/ui/target-feature/abi-required-target-feature-flag-disable.riscv.stderr @@ -0,0 +1,11 @@ +warning: target feature `d` must be enabled to ensure that the ABI of the current target can be implemented correctly + | + = note: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #116344 + +warning: unstable feature specified for `-Ctarget-feature`: `d` + | + = note: this feature is not stably supported; its behavior can change in the future + +warning: 2 warnings emitted + diff --git a/tests/ui/target-feature/abi-required-target-feature-flag-disable.rs b/tests/ui/target-feature/abi-required-target-feature-flag-disable.rs new file mode 100644 index 000000000000..c3ce05baa64b --- /dev/null +++ b/tests/ui/target-feature/abi-required-target-feature-flag-disable.rs @@ -0,0 +1,27 @@ +//! Ensure ABI-required features cannot be disabled via `-Ctarget-feature`. +//! Also covers the case of a feature indirectly disabling another via feature implications. +//@ compile-flags: --crate-type=lib +//@ revisions: x86 x86-implied aarch64 riscv loongarch +//@[x86] compile-flags: --target=x86_64-unknown-linux-gnu -Ctarget-feature=-x87 +//@[x86] needs-llvm-components: x86 +//@[x86-implied] compile-flags: --target=x86_64-unknown-linux-gnu -Ctarget-feature=-sse +//@[x86-implied] needs-llvm-components: x86 +//@[aarch64] compile-flags: --target=aarch64-unknown-linux-gnu -Ctarget-feature=-neon +//@[aarch64] needs-llvm-components: aarch64 +//@[riscv] compile-flags: --target=riscv64gc-unknown-none-elf -Ctarget-feature=-d +//@[riscv] needs-llvm-components: riscv +//@[loongarch] compile-flags: --target=loongarch64-unknown-none -Ctarget-feature=-d +//@[loongarch] needs-llvm-components: loongarch +// For now this is just a warning. +//@ build-pass +// Remove some LLVM warnings that only show up sometimes. +//@ normalize-stderr: "\n[^\n]*(target-abi|lp64f)[^\n]*" -> "" + +#![feature(no_core, lang_items)] +#![no_core] + +#[lang = "sized"] +pub trait Sized {} + +//~? WARN must be enabled to ensure that the ABI of the current target can be implemented correctly +//[x86,riscv,loongarch]~? WARN unstable feature specified for `-Ctarget-feature` diff --git a/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable-implied.stderr b/tests/ui/target-feature/abi-required-target-feature-flag-disable.x86-implied.stderr similarity index 100% rename from tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable-implied.stderr rename to tests/ui/target-feature/abi-required-target-feature-flag-disable.x86-implied.stderr diff --git a/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable.stderr b/tests/ui/target-feature/abi-required-target-feature-flag-disable.x86.stderr similarity index 100% rename from tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable.stderr rename to tests/ui/target-feature/abi-required-target-feature-flag-disable.x86.stderr diff --git a/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute.rs b/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute-e-d.rs similarity index 100% rename from tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute.rs rename to tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute-e-d.rs diff --git a/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute.stderr b/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute-e-d.stderr similarity index 77% rename from tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute.stderr rename to tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute-e-d.stderr index bfe767e5ffb0..84d27463b38c 100644 --- a/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute.stderr +++ b/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute-e-d.stderr @@ -1,5 +1,5 @@ error: target feature `d` cannot be enabled with `#[target_feature]`: this feature is incompatible with the target ABI - --> $DIR/forbidden-hardfloat-target-feature-attribute.rs:10:18 + --> $DIR/forbidden-hardfloat-target-feature-attribute-e-d.rs:10:18 | LL | #[target_feature(enable = "d")] | ^^^^^^^^^^^^ diff --git a/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute-f-zfinx.rs b/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute-f-zfinx.rs new file mode 100644 index 000000000000..d74f4a1d4b17 --- /dev/null +++ b/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute-f-zfinx.rs @@ -0,0 +1,12 @@ +//! Ensure ABI-incompatible features cannot be enabled via `#[target_feature]`. +//@ compile-flags: --target=riscv64gc-unknown-linux-gnu --crate-type=lib +//@ needs-llvm-components: riscv +#![feature(no_core, lang_items, riscv_target_feature)] +#![no_core] + +#[lang = "sized"] +pub trait Sized {} + +#[target_feature(enable = "zdinx")] +//~^ERROR: cannot be enabled with +pub unsafe fn my_fun() {} diff --git a/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute-f-zfinx.stderr b/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute-f-zfinx.stderr new file mode 100644 index 000000000000..af0e53f34f23 --- /dev/null +++ b/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute-f-zfinx.stderr @@ -0,0 +1,8 @@ +error: target feature `zfinx` cannot be enabled with `#[target_feature]`: this feature is incompatible with the target ABI + --> $DIR/forbidden-hardfloat-target-feature-attribute-f-zfinx.rs:10:18 + | +LL | #[target_feature(enable = "zdinx")] + | ^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable-implied.rs b/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable-implied.rs deleted file mode 100644 index 12e7e3bc45b3..000000000000 --- a/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable-implied.rs +++ /dev/null @@ -1,15 +0,0 @@ -//! Ensure that if disabling a target feature implies disabling an ABI-required target feature, -//! we complain. -//@ compile-flags: --target=x86_64-unknown-linux-gnu --crate-type=lib -//@ needs-llvm-components: x86 -//@ compile-flags: -Ctarget-feature=-sse -// For now this is just a warning. -//@ build-pass - -#![feature(no_core, lang_items)] -#![no_core] - -#[lang = "sized"] -pub trait Sized {} - -//~? WARN target feature `sse2` must be enabled to ensure that the ABI of the current target can be implemented correctly diff --git a/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable-neon.rs b/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable-neon.rs deleted file mode 100644 index 33e4f12694f3..000000000000 --- a/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable-neon.rs +++ /dev/null @@ -1,13 +0,0 @@ -//@ compile-flags: --target=aarch64-unknown-linux-gnu --crate-type=lib -//@ needs-llvm-components: aarch64 -//@ compile-flags: -Ctarget-feature=-neon -// For now this is just a warning. -//@ build-pass - -#![feature(no_core, lang_items)] -#![no_core] - -#[lang = "sized"] -pub trait Sized {} - -//~? WARN target feature `neon` must be enabled to ensure that the ABI of the current target can be implemented correctly diff --git a/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable.rs b/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable.rs deleted file mode 100644 index e1bd25ffad1e..000000000000 --- a/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable.rs +++ /dev/null @@ -1,15 +0,0 @@ -//! Ensure ABI-required features cannot be disabled via `-Ctarget-feature`. -//@ compile-flags: --target=x86_64-unknown-linux-gnu --crate-type=lib -//@ needs-llvm-components: x86 -//@ compile-flags: -Ctarget-feature=-x87 -// For now this is just a warning. -//@ build-pass - -#![feature(no_core, lang_items)] -#![no_core] - -#[lang = "sized"] -pub trait Sized {} - -//~? WARN target feature `x87` must be enabled to ensure that the ABI of the current target can be implemented correctly -//~? WARN unstable feature specified for `-Ctarget-feature`: `x87` diff --git a/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag.rs b/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag.rs deleted file mode 100644 index 4ccc6e0e941f..000000000000 --- a/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag.rs +++ /dev/null @@ -1,15 +0,0 @@ -//! Ensure ABI-incompatible features cannot be enabled via `-Ctarget-feature`. -//@ compile-flags: --target=x86_64-unknown-linux-gnu --crate-type=lib -//@ needs-llvm-components: x86 -//@ compile-flags: -Ctarget-feature=+soft-float -// For now this is just a warning. -//@ build-pass - -#![feature(no_core, lang_items, riscv_target_feature)] -#![no_core] - -#[lang = "sized"] -pub trait Sized {} - -//~? WARN target feature `soft-float` must be disabled to ensure that the ABI of the current target can be implemented correctl -//~? WARN unstable feature specified for `-Ctarget-feature`: `soft-float` diff --git a/tests/ui/target_modifiers/auxiliary/fixed_x18.rs b/tests/ui/target_modifiers/auxiliary/fixed_x18.rs new file mode 100644 index 000000000000..32eff76ec54c --- /dev/null +++ b/tests/ui/target_modifiers/auxiliary/fixed_x18.rs @@ -0,0 +1,7 @@ +//@ no-prefer-dynamic +//@ compile-flags: --target aarch64-unknown-none -Zfixed-x18 +//@ needs-llvm-components: aarch64 + +#![feature(no_core)] +#![crate_type = "rlib"] +#![no_core] diff --git a/tests/ui/target_modifiers/incompatible_fixedx18.error_generated.stderr b/tests/ui/target_modifiers/incompatible_fixedx18.error_generated.stderr new file mode 100644 index 000000000000..096d7cb5f258 --- /dev/null +++ b/tests/ui/target_modifiers/incompatible_fixedx18.error_generated.stderr @@ -0,0 +1,13 @@ +error: mixing `-Zfixed-x18` will cause an ABI mismatch in crate `incompatible_fixedx18` + --> $DIR/incompatible_fixedx18.rs:12:1 + | +LL | #![feature(no_core)] + | ^ + | + = help: the `-Zfixed-x18` flag modifies the ABI so Rust crates compiled with different values of this flag cannot be used together safely + = note: unset `-Zfixed-x18` in this crate is incompatible with `-Zfixed-x18=` in dependency `fixed_x18` + = help: set `-Zfixed-x18=` in this crate or unset `-Zfixed-x18` in `fixed_x18` + = help: if you are sure this will not cause problems, you may use `-Cunsafe-allow-abi-mismatch=fixed-x18` to silence this error + +error: aborting due to 1 previous error + diff --git a/tests/ui/target_modifiers/incompatible_fixedx18.rs b/tests/ui/target_modifiers/incompatible_fixedx18.rs new file mode 100644 index 000000000000..6c13984f608e --- /dev/null +++ b/tests/ui/target_modifiers/incompatible_fixedx18.rs @@ -0,0 +1,17 @@ +//@ aux-build:fixed_x18.rs +//@ compile-flags: --target aarch64-unknown-none +//@ needs-llvm-components: aarch64 + +//@ revisions:allow_match allow_mismatch error_generated +//@[allow_match] compile-flags: -Zfixed-x18 +//@[allow_mismatch] compile-flags: -Cunsafe-allow-abi-mismatch=fixed-x18 +//@[error_generated] compile-flags: +//@[allow_mismatch] check-pass +//@[allow_match] check-pass + +#![feature(no_core)] +//[error_generated]~^ ERROR mixing `-Zfixed-x18` will cause an ABI mismatch in crate `incompatible_fixedx18` +#![crate_type = "rlib"] +#![no_core] + +extern crate fixed_x18; diff --git a/tests/ui/traits/bound/on-structs-and-enums-locals.stderr b/tests/ui/traits/bound/on-structs-and-enums-locals.stderr index 01cf76c62d54..88077f4e4d7d 100644 --- a/tests/ui/traits/bound/on-structs-and-enums-locals.stderr +++ b/tests/ui/traits/bound/on-structs-and-enums-locals.stderr @@ -1,20 +1,3 @@ -error[E0277]: the trait bound `usize: Trait` is not satisfied - --> $DIR/on-structs-and-enums-locals.rs:15:14 - | -LL | let baz: Foo = loop { }; - | ^^^^^^^^^^ the trait `Trait` is not implemented for `usize` - | -help: this trait has no implementations, consider adding one - --> $DIR/on-structs-and-enums-locals.rs:1:1 - | -LL | trait Trait { - | ^^^^^^^^^^^ -note: required by a bound in `Foo` - --> $DIR/on-structs-and-enums-locals.rs:5:14 - | -LL | struct Foo { - | ^^^^^ required by this bound in `Foo` - error[E0277]: the trait bound `{integer}: Trait` is not satisfied --> $DIR/on-structs-and-enums-locals.rs:11:12 | @@ -32,6 +15,23 @@ note: required by a bound in `Foo` LL | struct Foo { | ^^^^^ required by this bound in `Foo` +error[E0277]: the trait bound `usize: Trait` is not satisfied + --> $DIR/on-structs-and-enums-locals.rs:15:14 + | +LL | let baz: Foo = loop { }; + | ^^^^^^^^^^ the trait `Trait` is not implemented for `usize` + | +help: this trait has no implementations, consider adding one + --> $DIR/on-structs-and-enums-locals.rs:1:1 + | +LL | trait Trait { + | ^^^^^^^^^^^ +note: required by a bound in `Foo` + --> $DIR/on-structs-and-enums-locals.rs:5:14 + | +LL | struct Foo { + | ^^^^^ required by this bound in `Foo` + error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/bound/on-structs-and-enums-xc1.stderr b/tests/ui/traits/bound/on-structs-and-enums-xc1.stderr index 3fb5decb723e..1f46415e2436 100644 --- a/tests/ui/traits/bound/on-structs-and-enums-xc1.stderr +++ b/tests/ui/traits/bound/on-structs-and-enums-xc1.stderr @@ -1,15 +1,3 @@ -error[E0277]: the trait bound `f64: Trait` is not satisfied - --> $DIR/on-structs-and-enums-xc1.rs:12:14 - | -LL | let bar: Bar = return; - | ^^^^^^^^ the trait `Trait` is not implemented for `f64` - | -note: required by a bound in `Bar` - --> $DIR/auxiliary/on_structs_and_enums_xc.rs:9:16 - | -LL | pub enum Bar { - | ^^^^^ required by this bound in `Bar` - error[E0277]: the trait bound `{integer}: Trait` is not satisfied --> $DIR/on-structs-and-enums-xc1.rs:9:12 | @@ -22,6 +10,18 @@ note: required by a bound in `Foo` LL | pub struct Foo { | ^^^^^ required by this bound in `Foo` +error[E0277]: the trait bound `f64: Trait` is not satisfied + --> $DIR/on-structs-and-enums-xc1.rs:12:14 + | +LL | let bar: Bar = return; + | ^^^^^^^^ the trait `Trait` is not implemented for `f64` + | +note: required by a bound in `Bar` + --> $DIR/auxiliary/on_structs_and_enums_xc.rs:9:16 + | +LL | pub enum Bar { + | ^^^^^ required by this bound in `Bar` + error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/next-solver/dont-ice-on-bad-transmute-in-typeck.stderr b/tests/ui/traits/next-solver/dont-ice-on-bad-transmute-in-typeck.stderr index 2d42fedae438..e1ae981b2492 100644 --- a/tests/ui/traits/next-solver/dont-ice-on-bad-transmute-in-typeck.stderr +++ b/tests/ui/traits/next-solver/dont-ice-on-bad-transmute-in-typeck.stderr @@ -1,8 +1,8 @@ error[E0277]: the trait bound `for<'a> (): Trait<'a>` is not satisfied - --> $DIR/dont-ice-on-bad-transmute-in-typeck.rs:7:11 + --> $DIR/dont-ice-on-bad-transmute-in-typeck.rs:7:22 | LL | fn foo(x: for<'a> fn(<() as Trait<'a>>::Assoc)) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> Trait<'a>` is not implemented for `()` + | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> Trait<'a>` is not implemented for `()` | help: this trait has no implementations, consider adding one --> $DIR/dont-ice-on-bad-transmute-in-typeck.rs:3:1 diff --git a/tests/ui/traits/next-solver/issue-118950-root-region.rs b/tests/ui/traits/next-solver/issue-118950-root-region.rs index 8fe53d6773b9..fe336766891d 100644 --- a/tests/ui/traits/next-solver/issue-118950-root-region.rs +++ b/tests/ui/traits/next-solver/issue-118950-root-region.rs @@ -19,5 +19,6 @@ impl Overlap for T {} impl Overlap fn(Assoc<'a, T>)> for T where Missing: Overlap {} //~^ ERROR cannot find type `Missing` in this scope //~| ERROR the trait bound `T: Overlap fn(Assoc<'a, T>)>` is not satisfied +//~| ERROR the trait bound `for<'a> *const T: ToUnit<'a>` is not satisfied fn main() {} diff --git a/tests/ui/traits/next-solver/issue-118950-root-region.stderr b/tests/ui/traits/next-solver/issue-118950-root-region.stderr index d2a58e95629a..45fa33dff52f 100644 --- a/tests/ui/traits/next-solver/issue-118950-root-region.stderr +++ b/tests/ui/traits/next-solver/issue-118950-root-region.stderr @@ -26,6 +26,18 @@ LL | trait ToUnit<'a> { | ^^^^^^^^^^^^^^^^ WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: ['^0.Named(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), "'a"), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc), .. } +error[E0277]: the trait bound `for<'a> *const T: ToUnit<'a>` is not satisfied + --> $DIR/issue-118950-root-region.rs:19:9 + | +LL | impl Overlap fn(Assoc<'a, T>)> for T where Missing: Overlap {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> ToUnit<'a>` is not implemented for `*const T` + | +help: this trait has no implementations, consider adding one + --> $DIR/issue-118950-root-region.rs:8:1 + | +LL | trait ToUnit<'a> { + | ^^^^^^^^^^^^^^^^ + error[E0277]: the trait bound `T: Overlap fn(Assoc<'a, T>)>` is not satisfied --> $DIR/issue-118950-root-region.rs:19:47 | @@ -37,7 +49,7 @@ help: consider further restricting type parameter `T` with trait `Overlap` LL | impl Overlap fn(Assoc<'a, T>)> for T where Missing: Overlap, T: Overlap fn(Assoc<'a, T>)> {} | ++++++++++++++++++++++++++++++++++++++ -error: aborting due to 3 previous errors; 1 warning emitted +error: aborting due to 4 previous errors; 1 warning emitted Some errors have detailed explanations: E0277, E0412. For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/next-solver/non-wf-in-coerce-pointers.stderr b/tests/ui/traits/next-solver/non-wf-in-coerce-pointers.stderr index 32a7766a638d..72be10367dac 100644 --- a/tests/ui/traits/next-solver/non-wf-in-coerce-pointers.stderr +++ b/tests/ui/traits/next-solver/non-wf-in-coerce-pointers.stderr @@ -1,8 +1,8 @@ error[E0277]: the trait bound `(): Wf` is not satisfied - --> $DIR/non-wf-in-coerce-pointers.rs:8:17 + --> $DIR/non-wf-in-coerce-pointers.rs:8:8 | LL | f: &'static <() as Wf>::Assoc, - | ^^^^^^^^^^^^^^^^^ the trait `Wf` is not implemented for `()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Wf` is not implemented for `()` | help: this trait has no implementations, consider adding one --> $DIR/non-wf-in-coerce-pointers.rs:3:1 diff --git a/tests/ui/traits/next-solver/opaques/duplicate-opaque-type-entries.rs b/tests/ui/traits/next-solver/opaques/duplicate-opaque-type-entries.rs new file mode 100644 index 000000000000..e0668ac3d39f --- /dev/null +++ b/tests/ui/traits/next-solver/opaques/duplicate-opaque-type-entries.rs @@ -0,0 +1,25 @@ +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver +//@ check-pass +#![crate_type = "lib"] +trait Eq {} +impl Eq for T {} +trait ConstrainAndEq {} +impl ConstrainAndEq for U +where + T: FnOnce() -> u32, + U: FnOnce() -> u32, + T: Eq, +{} + +fn constrain_and_eq, U>(_: T, _: U) {} +fn foo<'a>() -> impl Sized + use<'a> { + // This proves `foo<'a>: FnOnce() -> u32` and `foo<'1>: FnOnce() -> u32`, + // We constrain both `opaque<'a>` and `opaque<'1>` to `u32`, resulting in + // two distinct opaque type uses. Proving `foo<'a>: Eq>` then + // equates the two regions at which point the two opaque type keys are now + // equal. This previously caused an ICE. + constrain_and_eq(foo::<'a>, foo::<'_>); + 1u32 +} diff --git a/tests/ui/traits/trait-impl-self-mismatch.rs b/tests/ui/traits/trait-impl-self-mismatch.rs new file mode 100644 index 000000000000..54226cf2c9ad --- /dev/null +++ b/tests/ui/traits/trait-impl-self-mismatch.rs @@ -0,0 +1,19 @@ +//@compile-flags: -Zvalidate-mir -Zinline-mir -Zinline-mir-threshold=300 + +//! Ensure that a trait method implemented with the wrong signature +//! correctly triggers a compile error and not an ICE. +//! Regression test for . + +trait Bar { + fn bar(&self) {} +} + +impl Bar for T { + fn bar() { //~ ERROR method `bar` has a `&self` declaration in the trait, but not in the impl + let _ = "Hello".bytes().nth(3); + } +} + +fn main() { + ().bar(); +} diff --git a/tests/ui/traits/trait-impl-self-mismatch.stderr b/tests/ui/traits/trait-impl-self-mismatch.stderr new file mode 100644 index 000000000000..4ee06787c7d8 --- /dev/null +++ b/tests/ui/traits/trait-impl-self-mismatch.stderr @@ -0,0 +1,12 @@ +error[E0186]: method `bar` has a `&self` declaration in the trait, but not in the impl + --> $DIR/trait-impl-self-mismatch.rs:12:5 + | +LL | fn bar(&self) {} + | ------------- `&self` used in trait +... +LL | fn bar() { + | ^^^^^^^^ expected `&self` in impl + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0186`. diff --git a/tests/ui/treat-err-as-bug/err.rs b/tests/ui/treat-err-as-bug/err.rs index 9f0e293b4cb1..7868c06fee1c 100644 --- a/tests/ui/treat-err-as-bug/err.rs +++ b/tests/ui/treat-err-as-bug/err.rs @@ -1,7 +1,5 @@ //@ compile-flags: -Ztreat-err-as-bug //@ failure-status: 101 -//@ error-pattern: aborting due to `-Z treat-err-as-bug=1` -//@ error-pattern: [eval_static_initializer] evaluating initializer of static `C` //@ normalize-stderr: "note: .*\n\n" -> "" //@ normalize-stderr: "thread 'rustc' panicked.*:\n.*\n" -> "" //@ rustc-env:RUST_BACKTRACE=0 @@ -10,3 +8,6 @@ pub static C: u32 = 0 - 1; //~^ ERROR could not evaluate static initializer + +//~? RAW aborting due to `-Z treat-err-as-bug=1` +//~? RAW [eval_static_initializer] evaluating initializer of static `C` diff --git a/tests/ui/treat-err-as-bug/err.stderr b/tests/ui/treat-err-as-bug/err.stderr index df5fed3fb8e9..2049df22000a 100644 --- a/tests/ui/treat-err-as-bug/err.stderr +++ b/tests/ui/treat-err-as-bug/err.stderr @@ -1,5 +1,5 @@ error: internal compiler error[E0080]: could not evaluate static initializer - --> $DIR/err.rs:11:21 + --> $DIR/err.rs:9:21 | LL | pub static C: u32 = 0 - 1; | ^^^^^ attempt to compute `0_u32 - 1_u32`, which would overflow diff --git a/tests/ui/treat-err-as-bug/panic-causes-oom-112708.rs b/tests/ui/treat-err-as-bug/panic-causes-oom-112708.rs index cfb2d7c52180..3f963888c300 100644 --- a/tests/ui/treat-err-as-bug/panic-causes-oom-112708.rs +++ b/tests/ui/treat-err-as-bug/panic-causes-oom-112708.rs @@ -1,6 +1,5 @@ //@ compile-flags: -Ztreat-err-as-bug //@ dont-check-failure-status -//@ error-pattern: aborting due to `-Z treat-err-as-bug=1` //@ dont-check-compiler-stderr //@ rustc-env:RUST_BACKTRACE=0 @@ -8,3 +7,5 @@ fn main() { #[deny(while_true)] while true {} //~ ERROR denote infinite loops with `loop { ... }` } + +//~? RAW aborting due to `-Z treat-err-as-bug=1` diff --git a/tests/ui/treat-err-as-bug/span_delayed_bug.rs b/tests/ui/treat-err-as-bug/span_delayed_bug.rs index a242d11129f7..4681a8fc1ee0 100644 --- a/tests/ui/treat-err-as-bug/span_delayed_bug.rs +++ b/tests/ui/treat-err-as-bug/span_delayed_bug.rs @@ -1,7 +1,5 @@ //@ compile-flags: -Ztreat-err-as-bug -Zeagerly-emit-delayed-bugs //@ failure-status: 101 -//@ error-pattern: aborting due to `-Z treat-err-as-bug=1` -//@ error-pattern: [trigger_delayed_bug] triggering a delayed bug for testing incremental //@ normalize-stderr: "note: .*\n\n" -> "" //@ normalize-stderr: "thread 'rustc' panicked.*:\n.*\n" -> "" //@ rustc-env:RUST_BACKTRACE=0 @@ -10,3 +8,6 @@ #[rustc_delayed_bug_from_inside_query] fn main() {} //~ ERROR delayed bug triggered by #[rustc_delayed_bug_from_inside_query] + +//~? RAW aborting due to `-Z treat-err-as-bug=1` +//~? RAW [trigger_delayed_bug] triggering a delayed bug for testing incremental diff --git a/tests/ui/treat-err-as-bug/span_delayed_bug.stderr b/tests/ui/treat-err-as-bug/span_delayed_bug.stderr index 1c8d279c14c4..88983e95cee7 100644 --- a/tests/ui/treat-err-as-bug/span_delayed_bug.stderr +++ b/tests/ui/treat-err-as-bug/span_delayed_bug.stderr @@ -1,5 +1,5 @@ error: internal compiler error: delayed bug triggered by #[rustc_delayed_bug_from_inside_query] - --> $DIR/span_delayed_bug.rs:12:1 + --> $DIR/span_delayed_bug.rs:10:1 | LL | fn main() {} | ^^^^^^^^^ diff --git a/tests/ui/type-inference/regression-issue-81317.rs b/tests/ui/type-inference/regression-issue-81317.rs new file mode 100644 index 000000000000..0b1266e6a0fd --- /dev/null +++ b/tests/ui/type-inference/regression-issue-81317.rs @@ -0,0 +1,71 @@ +// Regression test for #81317: type can no longer be infered as of 1.49 +// +// The problem is that the xor operator and the index.into() call +// each have two candidate impls that could apply +// { S as BitXor, S as BitXor<&'a S> } for xor and +// { T::I as Into, T::I as Into } for index.into() +// previously inference was able to infer that the only valid combination was +// S as BitXor and T::I as Into +// +// after rust-lang/rust#73905 this is no longer infered +// +// the error message could be better e.g. +// when iv is unused or has an an explicitly specified type S +// there is currently the following help message +// +// error[E0284]: type annotations needed +// --> src/main.rs:13:24 +// | +// 44 | let iv = S ^ index.into(); +// | - ^^^^ +// | | +// | type must be known at this point +// | +// = note: cannot satisfy `>::Output == _` +// help: try using a fully qualified path to specify the expected types +// | +// 44 - let iv = S ^ index.into(); +// 44 + let iv = S ^ <::I as Into>::into(index); +// +// this is better as it's actually sufficent to fix the problem, +// while just specifying the type of iv as currently suggested is insufficent +// +//@ check-fail + +use std::ops::BitXor; + +pub struct S; + +pub trait P { + type I: Into + Into; +} + +pub fn decrypt_portion(index: T::I) { + let iv = S ^ index.into(); + //~^ ERROR type annotations needed + &iv.to_bytes_be(); +} + +impl S { + fn to_bytes_be(&self) -> &[u8] { + &[] + } +} + +impl BitXor for S { + type Output = S; + + fn bitxor(self, _rhs: Self) -> Self::Output { + S + } +} + +impl<'a> BitXor<&'a S> for S { + type Output = S; + + fn bitxor(self, _rhs: &'a S) -> Self::Output { + S + } +} + +fn main() {} diff --git a/tests/ui/type-inference/regression-issue-81317.stderr b/tests/ui/type-inference/regression-issue-81317.stderr new file mode 100644 index 000000000000..fcd3fca06e18 --- /dev/null +++ b/tests/ui/type-inference/regression-issue-81317.stderr @@ -0,0 +1,17 @@ +error[E0282]: type annotations needed + --> $DIR/regression-issue-81317.rs:44:9 + | +LL | let iv = S ^ index.into(); + | ^^ +LL | +LL | &iv.to_bytes_be(); + | -- type must be known at this point + | +help: consider giving `iv` an explicit type + | +LL | let iv: /* Type */ = S ^ index.into(); + | ++++++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/type/type-check/point-at-inference-4.rs b/tests/ui/type/type-check/point-at-inference-4.rs index 258374f299e2..504e6aa6db08 100644 --- a/tests/ui/type/type-check/point-at-inference-4.rs +++ b/tests/ui/type/type-check/point-at-inference-4.rs @@ -3,7 +3,6 @@ struct S(Option<(A, B)>); impl S { fn infer(&self, a: A, b: B) {} //~^ NOTE method defined here - //~| NOTE } fn main() { diff --git a/tests/ui/type/type-check/point-at-inference-4.stderr b/tests/ui/type/type-check/point-at-inference-4.stderr index adfb0cebf26e..8630f75d1190 100644 --- a/tests/ui/type/type-check/point-at-inference-4.stderr +++ b/tests/ui/type/type-check/point-at-inference-4.stderr @@ -1,5 +1,5 @@ error[E0061]: this method takes 2 arguments but 1 argument was supplied - --> $DIR/point-at-inference-4.rs:11:7 + --> $DIR/point-at-inference-4.rs:10:7 | LL | s.infer(0i32); | ^^^^^------ argument #2 is missing @@ -15,7 +15,7 @@ LL | s.infer(0i32, /* b */); | +++++++++ error[E0308]: mismatched types - --> $DIR/point-at-inference-4.rs:18:24 + --> $DIR/point-at-inference-4.rs:17:24 | LL | s.infer(0i32); | - ---- this argument has type `i32`... diff --git a/tests/ui/unboxed-closures/arg-constrained-after-closure-inference.rs b/tests/ui/unboxed-closures/arg-constrained-after-closure-inference.rs new file mode 100644 index 000000000000..343a27616d1d --- /dev/null +++ b/tests/ui/unboxed-closures/arg-constrained-after-closure-inference.rs @@ -0,0 +1,16 @@ +#![feature(unboxed_closures)] + +//@ check-pass + +// Regression test for #131758. We only know the type of `x` after closure upvar +// inference is done, even if we don't need to structurally resolve the type of `x`. + +trait Foo {} + +impl> Foo for T {} + +fn baz(_: T) {} + +fn main() { + baz(|x| ()); +} diff --git a/tests/ui/unpretty/exhaustive-asm.expanded.stdout b/tests/ui/unpretty/exhaustive-asm.expanded.stdout new file mode 100644 index 000000000000..92829b0ab15b --- /dev/null +++ b/tests/ui/unpretty/exhaustive-asm.expanded.stdout @@ -0,0 +1,33 @@ +#![feature(prelude_import)] +#[prelude_import] +use std::prelude::rust_2024::*; +#[macro_use] +extern crate std; +//@ revisions: expanded hir +//@[expanded]compile-flags: -Zunpretty=expanded +//@[expanded]check-pass +//@[hir]compile-flags: -Zunpretty=hir +//@[hir]check-pass +//@ edition:2024 +//@ only-x86_64 +// +// asm parts of exhaustive.rs. Separate because we only run this on x86_64. + +mod expressions { + /// ExprKind::InlineAsm + fn expr_inline_asm() { + let x; + asm!("mov {1}, {0}\nshl {1}, 1\nshl {0}, 2\nadd {0}, {1}", + inout(reg) + x, + out(reg) + _); + } +} + +mod items { + /// ItemKind::GlobalAsm + mod item_global_asm { + global_asm! (".globl my_asm_func"); + } +} diff --git a/tests/ui/unpretty/exhaustive-asm.hir.stdout b/tests/ui/unpretty/exhaustive-asm.hir.stdout new file mode 100644 index 000000000000..810db69bff16 --- /dev/null +++ b/tests/ui/unpretty/exhaustive-asm.hir.stdout @@ -0,0 +1,32 @@ +#[prelude_import] +use std::prelude::rust_2024::*; +#[macro_use] +extern crate std; +//@ revisions: expanded hir +//@[expanded]compile-flags: -Zunpretty=expanded +//@[expanded]check-pass +//@[hir]compile-flags: -Zunpretty=hir +//@[hir]check-pass +//@ edition:2024 +//@ only-x86_64 +// +// asm parts of exhaustive.rs. Separate because we only run this on x86_64. + +mod expressions { + /// ExprKind::InlineAsm + fn expr_inline_asm() { + let x; + asm!("mov {1}, {0}\nshl {1}, 1\nshl {0}, 2\nadd {0}, {1}", + inout(reg) + x, + out(reg) + _); + } +} + +mod items { + /// ItemKind::GlobalAsm + mod item_global_asm {/// ItemKind::GlobalAsm + global_asm! (".globl my_asm_func"); + } +} diff --git a/tests/ui/unpretty/exhaustive-asm.rs b/tests/ui/unpretty/exhaustive-asm.rs new file mode 100644 index 000000000000..74a45447a20f --- /dev/null +++ b/tests/ui/unpretty/exhaustive-asm.rs @@ -0,0 +1,31 @@ +//@ revisions: expanded hir +//@[expanded]compile-flags: -Zunpretty=expanded +//@[expanded]check-pass +//@[hir]compile-flags: -Zunpretty=hir +//@[hir]check-pass +//@ edition:2024 +//@ only-x86_64 +// +// asm parts of exhaustive.rs. Separate because we only run this on x86_64. + +mod expressions { + /// ExprKind::InlineAsm + fn expr_inline_asm() { + let x; + core::arch::asm!( + "mov {tmp}, {x}", + "shl {tmp}, 1", + "shl {x}, 2", + "add {x}, {tmp}", + x = inout(reg) x, + tmp = out(reg) _, + ); + } +} + +mod items { + /// ItemKind::GlobalAsm + mod item_global_asm { + core::arch::global_asm!(".globl my_asm_func"); + } +} diff --git a/tests/ui/unpretty/expanded-exhaustive.stdout b/tests/ui/unpretty/exhaustive.expanded.stdout similarity index 96% rename from tests/ui/unpretty/expanded-exhaustive.stdout rename to tests/ui/unpretty/exhaustive.expanded.stdout index c6ffbb0d316b..9712ba58e627 100644 --- a/tests/ui/unpretty/expanded-exhaustive.stdout +++ b/tests/ui/unpretty/exhaustive.expanded.stdout @@ -1,7 +1,13 @@ #![feature(prelude_import)] -//@ compile-flags: -Zunpretty=expanded +//@ revisions: expanded hir +//@[expanded]compile-flags: -Zunpretty=expanded +//@[expanded]check-pass +//@[hir]compile-flags: -Zunpretty=hir +//@[hir]check-fail //@ edition:2024 -//@ check-pass + +// Note: the HIR revision includes a `.stderr` file because there are some +// errors that only occur once we get past the AST. #![feature(auto_traits)] #![feature(box_patterns)] @@ -211,7 +217,10 @@ mod expressions { } /// ExprKind::Await - fn expr_await() { let fut; fut.await; } + fn expr_await() { + let fut; + fut.await; + } /// ExprKind::TryBlock fn expr_try_block() { try {} try { return; } } @@ -242,7 +251,9 @@ mod expressions { } /// ExprKind::Underscore - fn expr_underscore() { _; } + fn expr_underscore() { + _; + } /// ExprKind::Path fn expr_path() { @@ -275,16 +286,8 @@ mod expressions { /// ExprKind::Ret fn expr_ret() { return; return true; } - /// ExprKind::InlineAsm - fn expr_inline_asm() { - let x; - asm!("mov {1}, {0}\nshl {1}, 1\nshl {0}, 2\nadd {0}, {1}", - inout(reg) - x, - out(reg) - _); - } + /// ExprKind::InlineAsm: see exhaustive-asm.rs /// ExprKind::OffsetOf fn expr_offset_of() { @@ -300,65 +303,12 @@ mod expressions { - - - - - - // ... - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // concat_idents is deprecated @@ -450,10 +400,7 @@ mod items { unsafe extern "C++" {} unsafe extern "C" {} } - /// ItemKind::GlobalAsm - mod item_global_asm { - global_asm! (".globl my_asm_func"); - } + /// ItemKind::GlobalAsm: see exhaustive-asm.rs /// ItemKind::TyAlias mod item_ty_alias { pub type Type<'a> where T: 'a = T; diff --git a/tests/ui/unpretty/exhaustive.hir.stderr b/tests/ui/unpretty/exhaustive.hir.stderr new file mode 100644 index 000000000000..58f7ff0f5981 --- /dev/null +++ b/tests/ui/unpretty/exhaustive.hir.stderr @@ -0,0 +1,172 @@ +error[E0697]: closures cannot be static + --> $DIR/exhaustive.rs:211:9 + | +LL | static || value; + | ^^^^^^^^^ + +error[E0697]: closures cannot be static + --> $DIR/exhaustive.rs:212:9 + | +LL | static move || value; + | ^^^^^^^^^^^^^^ + +error[E0728]: `await` is only allowed inside `async` functions and blocks + --> $DIR/exhaustive.rs:241:13 + | +LL | fn expr_await() { + | --------------- this is not `async` +LL | let fut; +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:290:9 + | +LL | _; + | ^ `_` not allowed here + +error[E0214]: parenthesized type parameters may only be used with a `Fn` trait + --> $DIR/exhaustive.rs:300: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:301:9 + | +LL | x::(T, T) -> T; + | ^^^^^^^^^^^^^^ only `Fn` traits may use parentheses + | +help: use angle brackets instead + | +LL - x::(T, T) -> T; +LL + x:: -> T; + | + +error[E0214]: parenthesized type parameters may only be used with a `Fn` trait + --> $DIR/exhaustive.rs:302: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:302: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:305: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:305: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:392:9 + | +LL | yield; + | ^^^^^ + | +help: use `#[coroutine]` to make this closure a coroutine + | +LL | #[coroutine] fn expr_yield() { + | ++++++++++++ + +error[E0703]: invalid ABI: found `C++` + --> $DIR/exhaustive.rs:472:23 + | +LL | unsafe extern "C++" {} + | ^^^^^ invalid ABI + | + = note: invoke `rustc --print=calling-conventions` for a full list of supported calling conventions + +error: `..` patterns are not allowed here + --> $DIR/exhaustive.rs:679: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:794: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:809:16 + | +LL | let _: impl Send; + | ^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods + = note: see issue #63065 for more information + = help: add `#![feature(impl_trait_in_bindings)]` 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[E0562]: `impl Trait` is not allowed in the type of variable bindings + --> $DIR/exhaustive.rs:810:16 + | +LL | let _: impl Send + 'static; + | ^^^^^^^^^^^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods + = note: see issue #63065 for more information + = help: add `#![feature(impl_trait_in_bindings)]` 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[E0562]: `impl Trait` is not allowed in the type of variable bindings + --> $DIR/exhaustive.rs:811:16 + | +LL | let _: impl 'static + Send; + | ^^^^^^^^^^^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods + = note: see issue #63065 for more information + = help: add `#![feature(impl_trait_in_bindings)]` 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[E0562]: `impl Trait` is not allowed in the type of variable bindings + --> $DIR/exhaustive.rs:812:16 + | +LL | let _: impl ?Sized; + | ^^^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods + = note: see issue #63065 for more information + = help: add `#![feature(impl_trait_in_bindings)]` 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[E0562]: `impl Trait` is not allowed in the type of variable bindings + --> $DIR/exhaustive.rs:813:16 + | +LL | let _: impl ~const Clone; + | ^^^^^^^^^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods + = note: see issue #63065 for more information + = help: add `#![feature(impl_trait_in_bindings)]` 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[E0562]: `impl Trait` is not allowed in the type of variable bindings + --> $DIR/exhaustive.rs:814:16 + | +LL | let _: impl for<'a> Send; + | ^^^^^^^^^^^^^^^^^ + | + = note: `impl Trait` is only allowed in arguments and return types of functions and methods + = note: see issue #63065 for more information + = help: add `#![feature(impl_trait_in_bindings)]` 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 20 previous errors + +Some errors have detailed explanations: E0214, E0562, E0697, E0703, E0728. +For more information about an error, try `rustc --explain E0214`. diff --git a/tests/ui/unpretty/exhaustive.hir.stdout b/tests/ui/unpretty/exhaustive.hir.stdout new file mode 100644 index 000000000000..c20f123b16e8 --- /dev/null +++ b/tests/ui/unpretty/exhaustive.hir.stdout @@ -0,0 +1,724 @@ +//@ revisions: expanded hir +//@[expanded]compile-flags: -Zunpretty=expanded +//@[expanded]check-pass +//@[hir]compile-flags: -Zunpretty=hir +//@[hir]check-fail +//@ edition:2024 + +// Note: the HIR revision includes a `.stderr` file because there are some +// errors that only occur once we get past the AST. + +#![feature(auto_traits)] +#![feature(box_patterns)] +#![feature(builtin_syntax)] +#![feature(concat_idents)] +#![feature(const_trait_impl)] +#![feature(decl_macro)] +#![feature(deref_patterns)] +#![feature(dyn_star)] +#![feature(explicit_tail_calls)] +#![feature(gen_blocks)] +#![feature(more_qualified_paths)] +#![feature(never_patterns)] +#![feature(never_type)] +#![feature(pattern_types)] +#![feature(pattern_type_macro)] +#![feature(prelude_import)] +#![feature(specialization)] +#![feature(trace_macros)] +#![feature(trait_alias)] +#![feature(try_blocks)] +#![feature(yeet_expr)] +#![allow(incomplete_features)] +#[prelude_import] +use std::prelude::rust_2024::*; +#[macro_use] +extern crate std; + +#[prelude_import] +use self::prelude::*; + +mod prelude { + use std::prelude::rust_2024::*; + + type T = _; + + trait Trait { + const + CONST: + (); + } +} + +//! inner single-line doc comment +/*! + * inner multi-line doc comment + */ +#[doc = "inner doc attribute"] +#[allow(dead_code, unused_variables)] +#[no_std] +mod attributes {//! inner single-line doc comment + /*! + * inner multi-line doc comment + */ + #![doc = "inner doc attribute"] + #![allow(dead_code, unused_variables)] + #![no_std] + + /// outer single-line doc comment + /** + * outer multi-line doc comment + */ + #[doc = "outer doc attribute"] + #[doc = "macro"] + #[allow()] + #[attr = Repr([ReprC])] + struct Struct; +} + +mod expressions { + /// ExprKind::Array + fn expr_array() { + []; + [true]; + [true]; + [true, true]; + ["long........................................................................"]; + ["long............................................................", + true]; + } + + /// ExprKind::ConstBlock + fn expr_const_block() { + const { }; + const { 1 }; + const + { + struct S; + }; + } + + /// ExprKind::Call + fn expr_call() { + let f; + f(); + f::(); + f::<1>(); + f::<'static, u8, 1>(); + f(true); + f(true); + ()(); + } + + /// ExprKind::MethodCall + fn expr_method_call() { + let x; + x.f(); + x.f::(); + x.collect::>(); + } + + /// ExprKind::Tup + fn expr_tup() { (); (true,); (true, false); (true, false); } + + /// ExprKind::Binary + fn expr_binary() { + let (a, b, c, d, x, y); + true || false; + true || false && false; + a < 1 && 2 < b && c > 3 && 4 > d; + a & b & !c; + a + b * c - d + -1 * -2 - -3; + x = !y; + } + + /// ExprKind::Unary + fn expr_unary() { let expr; *expr; !expr; -expr; } + + /// ExprKind::Lit + fn expr_lit() { 'x'; 1000i8; 1.00000000000000000000001; } + + /// ExprKind::Cast + fn expr_cast() { let expr; expr as T; expr as T; } + + /// ExprKind::Type + fn expr_type() { let expr; type_ascribe!(expr, T); } + + /// ExprKind::Let + fn expr_let() { + let b; + if let Some(a) = b { } + if let _ = true && false { } + if let _ = (true && false) { } + } + + /// ExprKind::If + fn expr_if() { + if true { } + if !true { } + if let true = true { } else { } + if true { } else if false { } + if true { } else if false { } else { } + if true { return; } else if false { 0 } else { 0 } + } + + /// ExprKind::While + fn expr_while() { + loop { if false { } else { break; } } + 'a: loop { if false { } else { break; } } + loop { if let true = true { } else { break; } } + } + + /// ExprKind::ForLoop + fn expr_for_loop() { + let x; + { + let _t = + match #[lang = "into_iter"](x) { + mut iter => + loop { + match #[lang = "next"](&mut iter) { + #[lang = "None"] {} => break, + #[lang = "Some"] { 0: _ } => { } + } + }, + }; + _t + }; + { + let _t = + match #[lang = "into_iter"](x) { + mut iter => + 'a: loop { + match #[lang = "next"](&mut iter) { + #[lang = "None"] {} => break, + #[lang = "Some"] { 0: _ } => { } + } + }, + }; + _t + } + } + + /// ExprKind::Loop + fn expr_loop() { loop { } 'a: loop { } } + + /// ExprKind::Match + fn expr_match() { + let value; + match value { } + match value { ok => 1, } + match value { ok => 1, err => 0, } + } + + /// ExprKind::Closure + fn expr_closure() { + let value; + || { }; + |x| { }; + |x: u8| { }; + || (); + move || value; + || |mut _task_context: ResumeTy| { { let _t = value; _t } }; + move || |mut _task_context: ResumeTy| { { let _t = value; _t } }; + || value; + move || value; + || |mut _task_context: ResumeTy| { { let _t = value; _t } }; + move || |mut _task_context: ResumeTy| { { let _t = value; _t } }; + || -> u8 { value }; + 1 + (|| { }); + } + + /// ExprKind::Block + fn expr_block() { + { } + unsafe { } + 'a: { } + #[allow()] + { } + #[allow()] + { } + } + + /// ExprKind::Gen + fn expr_gen() { + |mut _task_context: ResumeTy| { }; + move |mut _task_context: ResumeTy| { }; + || { }; + move || { }; + |mut _task_context: ResumeTy| { }; + move |mut _task_context: ResumeTy| { }; + } + + /// ExprKind::Await + fn expr_await() { + let fut; + { + fut; + (/*ERROR*/) + }; + } + + /// ExprKind::TryBlock + fn expr_try_block() { + { #[lang = "from_output"](()) } + { return; #[lang = "from_output"](()) } + } + + /// ExprKind::Assign + fn expr_assign() { let expr; expr = true; } + + /// ExprKind::AssignOp + fn expr_assign_op() { let expr; expr += true; } + + /// ExprKind::Field + fn expr_field() { let expr; expr.field; expr.0; } + + /// ExprKind::Index + fn expr_index() { let expr; expr[true]; } + + /// ExprKind::Range + fn expr_range() { + let (lo, hi); + #[lang = "RangeFull"] { }; + #[lang = "RangeTo"] { end: hi }; + #[lang = "RangeFrom"] { start: lo }; + #[lang = "Range"] { start: lo, end: hi }; + #[lang = "Range"] { start: lo, end: hi }; + #[lang = "RangeToInclusive"] { end: hi }; + #[lang = "range_inclusive_new"](lo, hi); + #[lang = "range_inclusive_new"](-2, -1); + } + + /// ExprKind::Underscore + fn expr_underscore() { + (/*ERROR*/); + } + + /// ExprKind::Path + fn expr_path() { + let x; + crate::expressions::expr_path; + crate::expressions::expr_path::<'static>; + ::default; + ::default; + x; + x::; + crate::expressions::expr_path; + core::marker::PhantomData; + } + + /// ExprKind::AddrOf + fn expr_addr_of() { + let expr; + &expr; + &mut expr; + &raw const expr; + &raw mut expr; + } + + /// ExprKind::Break + fn expr_break() { 'a: { break; break 'a; break true; break 'a true; } } + + /// ExprKind::Continue + fn expr_continue() { 'a: { continue; continue 'a; } } + + /// ExprKind::Ret + fn expr_ret() { return; return true; } + + + /// ExprKind::InlineAsm: see exhaustive-asm.rs + /// ExprKind::OffsetOf + fn expr_offset_of() { + + + + + + + + + + + + + + // ... + + + + + + // concat_idents is deprecated + + + + + { offset_of!(T, field) }; + } + /// ExprKind::MacCall + fn expr_mac_call() { "..."; "..."; "..."; } + /// ExprKind::Struct + fn expr_struct() { + struct Struct { + } + let (x, base); + Struct { }; + ::Owned { }; + Struct { .. }; + Struct { ..base }; + Struct { x }; + Struct { x, ..base }; + Struct { x: true }; + Struct { x: true, .. }; + Struct { x: true, ..base }; + Struct { 0: true, ..base }; + } + /// ExprKind::Repeat + fn expr_repeat() { [(); 0]; } + /// ExprKind::Paren + fn expr_paren() { let expr; expr; } + /// ExprKind::Try + fn expr_try() { + let expr; + match #[lang = "branch"](expr) { + #[lang = "Break"] { 0: residual } => #[allow(unreachable_code)] + return #[lang = "from_residual"](residual), + #[lang = "Continue"] { 0: val } => #[allow(unreachable_code)] + val, + }; + } + /// ExprKind::Yield + fn expr_yield() { yield (); yield true; } + /// ExprKind::Yeet + fn expr_yeet() { + return #[lang = "from_yeet"](()); + return #[lang = "from_yeet"](0); + } + /// ExprKind::Become + fn expr_become() { become true; } + /// ExprKind::IncludedBytes + fn expr_include_bytes() { + b"data for include_bytes in ../expanded-exhaustive.rs\n"; + } + /// ExprKind::FormatArgs + fn expr_format_args() { + let expr; + format_arguments::new_const(&[]); + format_arguments::new_v1(&[""], + &[format_argument::new_display(&expr)]); + } +} +mod items { + /// ItemKind::ExternCrate + mod item_extern_crate {/// ItemKind::ExternCrate + extern crate core; + extern crate self as unpretty; + extern crate core as _; + } + /// ItemKind::Use + mod item_use {/// ItemKind::Use + use ::{}; + use crate::expressions; + use crate::items::item_use; + use core::*; + } + /// ItemKind::Static + mod item_static {/// ItemKind::Static + static A: () = { }; + static mut B: () = { }; + } + /// ItemKind::Const + mod item_const {/// ItemKind::Const + const A: () = { }; + trait TraitItems { + const + B: + (); + const + C: + () + = + { }; + } + } + /// ItemKind::Fn + mod item_fn {/// ItemKind::Fn + const unsafe extern "C" fn f() { } + async unsafe extern "C" fn g() + -> + /*impl Trait*/ |mut _task_context: ResumeTy| + { { let _t = { }; _t } } + fn h<'a, T>() where T: 'a { } + trait TraitItems { + unsafe extern "C" fn f(); + } + impl TraitItems for _ { + unsafe extern "C" fn f() { } + } + } + /// ItemKind::Mod + mod item_mod {/// ItemKind::Mod + } + /// ItemKind::ForeignMod + mod item_foreign_mod {/// ItemKind::ForeignMod + extern "Rust" { } + extern "C" { } + } + /// ItemKind::GlobalAsm: see exhaustive-asm.rs + /// ItemKind::TyAlias + mod item_ty_alias {/// ItemKind::GlobalAsm: see exhaustive-asm.rs + /// ItemKind::TyAlias + type Type<'a> where T: 'a = T; + } + /// ItemKind::Enum + mod item_enum {/// ItemKind::Enum + enum Void { } + enum Empty { + Unit, + Tuple(), + Struct { + }, + } + enum Generic<'a, T> where T: 'a { + Tuple(T), + Struct { + t: T, + }, + } + } + /// ItemKind::Struct + mod item_struct {/// ItemKind::Struct + struct Unit; + struct Tuple(); + struct Newtype(Unit); + struct Struct { + } + struct Generic<'a, T> where T: 'a { + t: T, + } + } + /// ItemKind::Union + mod item_union {/// ItemKind::Union + union Generic<'a, T> where T: 'a { + t: T, + } + } + /// ItemKind::Trait + mod item_trait {/// ItemKind::Trait + auto unsafe trait Send { } + trait Trait<'a>: Sized where Self: 'a { } + } + /// ItemKind::TraitAlias + mod item_trait_alias {/// ItemKind::TraitAlias + trait Trait = Sized where for<'a> T: 'a; + } + /// ItemKind::Impl + mod item_impl {/// ItemKind::Impl + impl () { } + impl () { } + impl Default for () { } + impl const Default for () { } + } + /// ItemKind::MacCall + mod item_mac_call {/// ItemKind::MacCall + } + /// ItemKind::MacroDef + mod item_macro_def {/// ItemKind::MacroDef + macro_rules! mac { () => {...}; } + macro stringify { () => {} } + } + /// ItemKind::Delegation + /*! FIXME: todo */ + mod item_delegation {/// ItemKind::Delegation + /*! FIXME: todo */ + } + /// ItemKind::DelegationMac + /*! FIXME: todo */ + mod item_delegation_mac {/// ItemKind::DelegationMac + /*! FIXME: todo */ + } +} +mod patterns { + /// PatKind::Missing + fn pat_missing() { let _: for fn(u32, T, &'_ str); } + /// PatKind::Wild + fn pat_wild() { let _; } + /// PatKind::Ident + fn pat_ident() { + let x; + let ref x; + let mut x; + let ref mut x; + let ref mut x@_; + } + /// PatKind::Struct + fn pat_struct() { + let T {}; + let T:: {}; + let T::<'static> {}; + let T { x }; + let T { x: _x }; + let T { .. }; + let T { x, .. }; + let T { x: _x, .. }; + let T { 0: _x, .. }; + let ::Owned {}; + } + /// PatKind::TupleStruct + fn pat_tuple_struct() { + struct Tuple(); + let Tuple(); + let Tuple::(); + let Tuple::<'static>(); + let Tuple(x); + let Tuple(..); + let Tuple(x, ..); + } + /// PatKind::Or + fn pat_or() { let true | false; let true; let true | false; } + /// PatKind::Path + fn pat_path() { + let core::marker::PhantomData; + let core::marker::PhantomData::; + let core::marker::PhantomData::<'static>; + let ::CONST; + } + /// PatKind::Tuple + fn pat_tuple() { let (); let (true,); let (true, false); } + /// PatKind::Box + fn pat_box() { let box pat; } + /// PatKind::Deref + fn pat_deref() { let deref!(pat); } + /// PatKind::Ref + fn pat_ref() { let &pat; let &mut pat; } + /// PatKind::Expr + fn pat_expr() { let 1000i8; let -""; } + /// PatKind::Range + fn pat_range() { let ..1; let 0...; let 0..1; let 0...1; let -2...-1; } + /// PatKind::Slice + fn pat_slice() { let []; let [true]; let [true]; let [true, false]; } + /// PatKind::Rest + fn pat_rest() { let _; } + /// PatKind::Never + fn pat_never() { let !; let Some(!); } + /// PatKind::Paren + fn pat_paren() { let pat; } + /// PatKind::MacCall + fn pat_mac_call() { let ""; let ""; let ""; } +} +mod statements { + /// StmtKind::Let + fn stmt_let() { + let _; + let _ = true; + let _: T = true; + let _ = true else { return; }; + } + /// StmtKind::Item + fn stmt_item() { + struct Struct { + } + struct Unit; + } + /// StmtKind::Expr + fn stmt_expr() { () } + /// StmtKind::Semi + fn stmt_semi() { 1 + 1; } + /// StmtKind::Empty + fn stmt_empty() { } + /// StmtKind::MacCall + fn stmt_mac_call() { "..."; "..."; "..."; } +} +mod types { + /// TyKind::Slice + fn ty_slice() { let _: [T]; } + /// TyKind::Array + fn ty_array() { let _: [T; 0]; } + /// TyKind::Ptr + fn ty_ptr() { let _: *const T; let _: *mut T; } + /// TyKind::Ref + fn ty_ref() { + let _: &T; + let _: &mut T; + let _: &'static T; + let _: &'static mut [T]; + let _: &T>>>; + let _: &T>>>; + } + /// TyKind::BareFn + fn ty_bare_fn() { + let _: fn(); + let _: fn() -> (); + let _: fn(T); + let _: fn(t: T); + let _: fn(); + let _: for<'a> fn(); + } + /// TyKind::Never + fn ty_never() { let _: !; } + /// TyKind::Tup + fn ty_tup() { let _: (); let _: (T,); let _: (T, T); } + /// TyKind::Path + fn ty_path() { + let _: T; + let _: T<'static>; + let _: T; + let _: T; + let _: T; + let _: ::Owned; + } + /// TyKind::TraitObject + fn ty_trait_object() { + let _: dyn Send; + let _: dyn Send + 'static; + let _: dyn Send + 'static; + let _: dyn for<'a> Send; + let _: dyn* Send; + } + /// TyKind::ImplTrait + const fn ty_impl_trait() { + let _: (/*ERROR*/); + let _: (/*ERROR*/); + let _: (/*ERROR*/); + let _: (/*ERROR*/); + let _: (/*ERROR*/); + let _: (/*ERROR*/); + } + /// TyKind::Paren + fn ty_paren() { let _: T; } + /// TyKind::Typeof + /*! unused for now */ + fn ty_typeof() { } + /// TyKind::Infer + fn ty_infer() { let _: _; } + /// TyKind::ImplicitSelf + /*! there is no syntax for this */ + fn ty_implicit_self() { } + /// TyKind::MacCall + #[expect(deprecated)] + fn ty_mac_call() { let _: T; let _: T; let _: T; } + /// TyKind::CVarArgs + /*! FIXME: todo */ + fn ty_c_var_args() { } + /// TyKind::Pat + fn ty_pat() { let _: u32 is 1..=RangeMax; } +} +mod visibilities { + /// VisibilityKind::Public + mod visibility_public {/// VisibilityKind::Public + struct Pub; + } + /// VisibilityKind::Restricted + mod visibility_restricted {/// VisibilityKind::Restricted + struct PubCrate; + struct PubSelf; + struct PubSuper; + struct PubInCrate; + struct PubInSelf; + struct PubInSuper; + struct PubInCrateVisibilities; + struct PubInSelfSuper; + struct PubInSuperMod; + } +} diff --git a/tests/ui/unpretty/expanded-exhaustive.rs b/tests/ui/unpretty/exhaustive.rs similarity index 90% rename from tests/ui/unpretty/expanded-exhaustive.rs rename to tests/ui/unpretty/exhaustive.rs index 5697f615b979..60ad3564689d 100644 --- a/tests/ui/unpretty/expanded-exhaustive.rs +++ b/tests/ui/unpretty/exhaustive.rs @@ -1,6 +1,12 @@ -//@ compile-flags: -Zunpretty=expanded +//@ revisions: expanded hir +//@[expanded]compile-flags: -Zunpretty=expanded +//@[expanded]check-pass +//@[hir]compile-flags: -Zunpretty=hir +//@[hir]check-fail //@ edition:2024 -//@ check-pass + +// Note: the HIR revision includes a `.stderr` file because there are some +// errors that only occur once we get past the AST. #![feature(auto_traits)] #![feature(box_patterns)] @@ -202,8 +208,8 @@ mod expressions { move || value; async || value; async move || value; - static || value; - static move || value; + static || value; //[hir]~ ERROR closures cannot be static + static move || value; //[hir]~ ERROR closures cannot be static (static async || value); (static async move || value); || -> u8 { value }; @@ -232,7 +238,7 @@ mod expressions { /// ExprKind::Await fn expr_await() { let fut; - fut.await; + fut.await; //[hir]~ ERROR `await` is only allowed } /// ExprKind::TryBlock @@ -281,7 +287,7 @@ mod expressions { /// ExprKind::Underscore fn expr_underscore() { - _; + _; //[hir]~ ERROR in expressions, `_` can only } /// ExprKind::Path @@ -291,10 +297,14 @@ mod expressions { crate::expressions::expr_path::<'static>; ::default; ::default::<>; - x::(); - x::(T, T) -> T; + x::(); //[hir]~ ERROR parenthesized type parameters + x::(T, T) -> T; //[hir]~ ERROR parenthesized type parameters crate::() -> ()::expressions::() -> ()::expr_path; + //[hir]~^ ERROR parenthesized type parameters + //[hir]~| ERROR parenthesized type parameters core::()::marker::()::PhantomData; + //[hir]~^ ERROR parenthesized type parameters + //[hir]~| ERROR parenthesized type parameters } /// ExprKind::AddrOf @@ -330,18 +340,7 @@ mod expressions { return true; } - /// ExprKind::InlineAsm - fn expr_inline_asm() { - let x; - core::arch::asm!( - "mov {tmp}, {x}", - "shl {tmp}, 1", - "shl {x}, 2", - "add {x}, {tmp}", - x = inout(reg) x, - tmp = out(reg) _, - ); - } + /// ExprKind::InlineAsm: see exhaustive-asm.rs /// ExprKind::OffsetOf fn expr_offset_of() { @@ -390,7 +389,7 @@ mod expressions { /// ExprKind::Yield fn expr_yield() { - yield; + yield; //[hir]~ ERROR `yield` can only be used yield true; } @@ -470,14 +469,11 @@ mod items { /// ItemKind::ForeignMod mod item_foreign_mod { - unsafe extern "C++" {} + unsafe extern "C++" {} //[hir]~ ERROR invalid ABI unsafe extern "C" {} } - /// ItemKind::GlobalAsm - mod item_global_asm { - core::arch::global_asm!(".globl my_asm_func"); - } + /// ItemKind::GlobalAsm: see exhaustive-asm.rs /// ItemKind::TyAlias mod item_ty_alias { @@ -680,7 +676,7 @@ mod patterns { /// PatKind::Rest fn pat_rest() { - let ..; + let ..; //[hir]~ ERROR `..` patterns are not allowed here } /// PatKind::Never @@ -795,7 +791,7 @@ mod types { let _: T<'static>; let _: T; let _: T::; - let _: T() -> !; + let _: T() -> !; //[hir]~ ERROR parenthesized type parameters let _: ::Owned; } @@ -810,12 +806,12 @@ mod types { /// TyKind::ImplTrait const fn ty_impl_trait() { - let _: impl Send; - let _: impl Send + 'static; - let _: impl 'static + Send; - let _: impl ?Sized; - let _: impl ~const Clone; - let _: impl for<'a> Send; + let _: impl Send; //[hir]~ ERROR `impl Trait` is not allowed + let _: impl Send + 'static; //[hir]~ ERROR `impl Trait` is not allowed + let _: impl 'static + Send; //[hir]~ ERROR `impl Trait` is not allowed + let _: impl ?Sized; //[hir]~ ERROR `impl Trait` is not allowed + let _: impl ~const Clone; //[hir]~ ERROR `impl Trait` is not allowed + let _: impl for<'a> Send; //[hir]~ ERROR `impl Trait` is not allowed } /// TyKind::Paren diff --git a/tests/ui/unpretty/hir-tree.rs b/tests/ui/unpretty/hir-tree.rs index 3388c60c4253..41ac51641c5e 100644 --- a/tests/ui/unpretty/hir-tree.rs +++ b/tests/ui/unpretty/hir-tree.rs @@ -3,8 +3,9 @@ //@ check-stdout //@ dont-check-compiler-stdout //@ dont-check-compiler-stderr -//@ regex-error-pattern: Hello, Rustaceans! fn main() { println!("Hello, Rustaceans!"); } + +//~? RAW Hello, Rustaceans! diff --git a/tests/ui/unpretty/expanded-interpolation.rs b/tests/ui/unpretty/interpolation-expanded.rs similarity index 100% rename from tests/ui/unpretty/expanded-interpolation.rs rename to tests/ui/unpretty/interpolation-expanded.rs diff --git a/tests/ui/unpretty/expanded-interpolation.stdout b/tests/ui/unpretty/interpolation-expanded.stdout similarity index 100% rename from tests/ui/unpretty/expanded-interpolation.stdout rename to tests/ui/unpretty/interpolation-expanded.stdout diff --git a/tests/ui/use/import_trait_associated_item_bad.rs b/tests/ui/use/import_trait_associated_item_bad.rs new file mode 100644 index 000000000000..d3d2a8e83cdd --- /dev/null +++ b/tests/ui/use/import_trait_associated_item_bad.rs @@ -0,0 +1,18 @@ +#![feature(import_trait_associated_functions)] +#![feature(min_generic_const_args)] +#![allow(incomplete_features)] + +trait Trait { + type AssocTy; + const CONST: usize; +} + +use Trait::AssocTy; +type Alias1 = AssocTy; //~ ERROR ambiguous associated type +type Alias2 = self::AssocTy; //~ ERROR ambiguous associated type + +use Trait::CONST; +type Alias3 = [u8; CONST]; //~ ERROR ambiguous associated constant +type Alias4 = [u8; self::CONST]; //~ ERROR ambiguous associated constant + +fn main() {} diff --git a/tests/ui/use/import_trait_associated_item_bad.stderr b/tests/ui/use/import_trait_associated_item_bad.stderr new file mode 100644 index 000000000000..d5cd5d37bd71 --- /dev/null +++ b/tests/ui/use/import_trait_associated_item_bad.stderr @@ -0,0 +1,49 @@ +error[E0223]: ambiguous associated type + --> $DIR/import_trait_associated_item_bad.rs:11:15 + | +LL | type Alias1 = AssocTy; + | ^^^^^^^ + | +help: if there were a type named `Example` that implemented `Trait`, you could use the fully-qualified path + | +LL | type Alias1 = ::AssocTy; + | ++++++++++++++++++++ + +error[E0223]: ambiguous associated type + --> $DIR/import_trait_associated_item_bad.rs:12:15 + | +LL | type Alias2 = self::AssocTy; + | ^^^^^^^^^^^^^ + | +help: if there were a type named `Example` that implemented `Trait`, you could use the fully-qualified path + | +LL - type Alias2 = self::AssocTy; +LL + type Alias2 = ::AssocTy; + | + +error[E0223]: ambiguous associated constant + --> $DIR/import_trait_associated_item_bad.rs:15:20 + | +LL | type Alias3 = [u8; CONST]; + | ^^^^^ + | +help: if there were a type named `Example` that implemented `Trait`, you could use the fully-qualified path + | +LL | type Alias3 = [u8; ::CONST]; + | ++++++++++++++++++++ + +error[E0223]: ambiguous associated constant + --> $DIR/import_trait_associated_item_bad.rs:16:20 + | +LL | type Alias4 = [u8; self::CONST]; + | ^^^^^^^^^^^ + | +help: if there were a type named `Example` that implemented `Trait`, you could use the fully-qualified path + | +LL - type Alias4 = [u8; self::CONST]; +LL + type Alias4 = [u8; ::CONST]; + | + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0223`. diff --git a/tests/ui/use/import_trait_associated_item_glob.rs b/tests/ui/use/import_trait_associated_item_glob.rs new file mode 100644 index 000000000000..8a712514ed59 --- /dev/null +++ b/tests/ui/use/import_trait_associated_item_glob.rs @@ -0,0 +1,17 @@ +//@ check-pass + +#![feature(import_trait_associated_functions)] + +trait Trait: Default { + fn f() -> Self { Default::default() } + fn g() -> Self { Default::default() } +} + +impl Trait for u8 {} + +use Trait::*; + +fn main() { + let _: u8 = f(); + let _: u8 = g(); +} diff --git a/tests/ui/use/use-from-trait-xc.rs b/tests/ui/use/use-from-trait-xc.rs index b030892aa269..220bf8cad46f 100644 --- a/tests/ui/use/use-from-trait-xc.rs +++ b/tests/ui/use/use-from-trait-xc.rs @@ -6,7 +6,7 @@ use use_from_trait_xc::Trait::foo; //~^ ERROR `use` associated items of traits is unstable [E0658] use use_from_trait_xc::Trait::Assoc; -//~^ ERROR `Assoc` is not directly importable +//~^ ERROR `use` associated items of traits is unstable [E0658] use use_from_trait_xc::Trait::CONST; //~^ ERROR `use` associated items of traits is unstable [E0658] diff --git a/tests/ui/use/use-from-trait-xc.stderr b/tests/ui/use/use-from-trait-xc.stderr index 0f8440aa5307..c8ee29b18d0c 100644 --- a/tests/ui/use/use-from-trait-xc.stderr +++ b/tests/ui/use/use-from-trait-xc.stderr @@ -8,11 +8,15 @@ LL | use use_from_trait_xc::Trait::foo; = help: add `#![feature(import_trait_associated_functions)]` 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[E0253]: `Assoc` is not directly importable +error[E0658]: `use` associated items of traits is unstable --> $DIR/use-from-trait-xc.rs:8:5 | LL | use use_from_trait_xc::Trait::Assoc; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot be imported directly + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #134691 for more information + = help: add `#![feature(import_trait_associated_functions)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: `use` associated items of traits is unstable --> $DIR/use-from-trait-xc.rs:11:5 @@ -74,5 +78,5 @@ LL | struct Foo; error: aborting due to 9 previous errors -Some errors have detailed explanations: E0253, E0432, E0603, E0658. -For more information about an error, try `rustc --explain E0253`. +Some errors have detailed explanations: E0432, E0603, E0658. +For more information about an error, try `rustc --explain E0432`. diff --git a/tests/ui/use/use-from-trait.rs b/tests/ui/use/use-from-trait.rs index 89b7aaa4ba38..cab661a29e8e 100644 --- a/tests/ui/use/use-from-trait.rs +++ b/tests/ui/use/use-from-trait.rs @@ -1,5 +1,5 @@ use Trait::foo; //~ ERROR `use` associated items of traits is unstable [E0658] -use Trait::Assoc; //~ ERROR `Assoc` is not directly importable +use Trait::Assoc; //~ ERROR `use` associated items of traits is unstable [E0658] use Trait::C; //~ ERROR `use` associated items of traits is unstable [E0658] use Foo::new; //~ ERROR unresolved import `Foo` [E0432] diff --git a/tests/ui/use/use-from-trait.stderr b/tests/ui/use/use-from-trait.stderr index 2dd78a354529..63cfcc207504 100644 --- a/tests/ui/use/use-from-trait.stderr +++ b/tests/ui/use/use-from-trait.stderr @@ -8,11 +8,15 @@ LL | use Trait::foo; = help: add `#![feature(import_trait_associated_functions)]` 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[E0253]: `Assoc` is not directly importable +error[E0658]: `use` associated items of traits is unstable --> $DIR/use-from-trait.rs:2:5 | LL | use Trait::Assoc; - | ^^^^^^^^^^^^ cannot be imported directly + | ^^^^^^^^^^^^ + | + = note: see issue #134691 for more information + = help: add `#![feature(import_trait_associated_functions)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: `use` associated items of traits is unstable --> $DIR/use-from-trait.rs:3:5 @@ -38,5 +42,5 @@ LL | use Foo::C2; error: aborting due to 5 previous errors -Some errors have detailed explanations: E0253, E0432, E0658. -For more information about an error, try `rustc --explain E0253`. +Some errors have detailed explanations: E0432, E0658. +For more information about an error, try `rustc --explain E0432`. diff --git a/tests/ui/wf/check-wf-of-normalized-signature.rs b/tests/ui/wf/check-wf-of-normalized-signature.rs new file mode 100644 index 000000000000..5fda69601d99 --- /dev/null +++ b/tests/ui/wf/check-wf-of-normalized-signature.rs @@ -0,0 +1,24 @@ +//@ revisions: current next +//@[next] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) +//@ check-pass + +// Regression test for . +// Ensure that we check the well-formedness of `::Output` after normalizing +// the type to `()`, since we only imply outlives bounds from the normalized signature, so we +// don't know (e.g.) that `&mut T` is WF. + + +trait Mode { + type Output; + fn from_mut(_r: &mut Self::Output) -> Self::Output<&mut T>; +} + +struct Check; + +impl Mode for Check { + type Output = (); + fn from_mut(_r: &mut Self::Output) -> Self::Output<&mut T> {} +} + +fn main() {} diff --git a/tests/ui/wf/wf-normalization-sized.next.stderr b/tests/ui/wf/wf-normalization-sized.next.stderr index 66c4f214415d..804dd0a252d1 100644 --- a/tests/ui/wf/wf-normalization-sized.next.stderr +++ b/tests/ui/wf/wf-normalization-sized.next.stderr @@ -8,7 +8,7 @@ LL | const _: <[[[[[[u8]]]]]] as WellUnformed>::RequestNormalize = (); = note: slice and array elements must have `Sized` type error[E0277]: the size for values of type `str` cannot be known at compilation time - --> $DIR/wf-normalization-sized.rs:22:11 + --> $DIR/wf-normalization-sized.rs:21:11 | LL | const _: as WellUnformed>::RequestNormalize = (); | ^^^^^^^^ doesn't have a size known at compile-time @@ -17,27 +17,6 @@ LL | const _: as WellUnformed>::RequestNormalize = (); note: required by an implicit `Sized` bound in `Vec` --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL -error[E0277]: the size for values of type `[[[[[u8]]]]]` cannot be known at compilation time - --> $DIR/wf-normalization-sized.rs:19:11 - | -LL | const _: <[[[[[[u8]]]]]] as WellUnformed>::RequestNormalize = (); - | ^^^^^^^^^^^^^^ doesn't have a size known at compile-time - | - = help: the trait `Sized` is not implemented for `[[[[[u8]]]]]` - = note: slice and array elements must have `Sized` type - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error[E0277]: the size for values of type `str` cannot be known at compilation time - --> $DIR/wf-normalization-sized.rs:22:11 - | -LL | const _: as WellUnformed>::RequestNormalize = (); - | ^^^^^^^^ doesn't have a size known at compile-time - | - = help: the trait `Sized` is not implemented for `str` -note: required by an implicit `Sized` bound in `Vec` - --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/wf/wf-normalization-sized.rs b/tests/ui/wf/wf-normalization-sized.rs index 5396cc8b32a8..e695fd93fb0e 100644 --- a/tests/ui/wf/wf-normalization-sized.rs +++ b/tests/ui/wf/wf-normalization-sized.rs @@ -18,9 +18,7 @@ impl WellUnformed for T { const _: <[[[[[[u8]]]]]] as WellUnformed>::RequestNormalize = (); //[next]~^ ERROR the size for values of type `[[[[[u8]]]]]` cannot be known at compilation time -//[next]~| ERROR the size for values of type `[[[[[u8]]]]]` cannot be known at compilation time const _: as WellUnformed>::RequestNormalize = (); //[next]~^ ERROR the size for values of type `str` cannot be known at compilation time -//[next]~| ERROR the size for values of type `str` cannot be known at compilation time fn main() {}

(&mut self, mut predicate: P) -> Option - where - P: FnMut(&Self::Item) -> bool, - { - self.it.rfind(move |x| predicate(&x)).copied() + #[inline] + fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero> { + self.it.advance_back_by(n) } } @@ -197,12 +140,10 @@ where I: ExactSizeIterator, T: Copy, { - #[inline] fn len(&self) -> usize { self.it.len() } - #[inline] fn is_empty(&self) -> bool { self.it.is_empty() } diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index d9534a445980..d1e71f0e60f2 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -56,12 +56,12 @@ pub trait Iterator { /// ``` /// let a = [1, 2, 3]; /// - /// let mut iter = a.iter(); + /// let mut iter = a.into_iter(); /// /// // A call to next() returns the next value... - /// assert_eq!(Some(&1), iter.next()); - /// assert_eq!(Some(&2), iter.next()); - /// assert_eq!(Some(&3), iter.next()); + /// assert_eq!(Some(1), iter.next()); + /// assert_eq!(Some(2), iter.next()); + /// assert_eq!(Some(3), iter.next()); /// /// // ... and then None once it's over. /// assert_eq!(None, iter.next()); @@ -239,10 +239,10 @@ pub trait Iterator { /// /// ``` /// let a = [1, 2, 3]; - /// assert_eq!(a.iter().last(), Some(&3)); + /// assert_eq!(a.into_iter().last(), Some(3)); /// /// let a = [1, 2, 3, 4, 5]; - /// assert_eq!(a.iter().last(), Some(&5)); + /// assert_eq!(a.into_iter().last(), Some(5)); /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -284,12 +284,12 @@ pub trait Iterator { /// use std::num::NonZero; /// /// let a = [1, 2, 3, 4]; - /// let mut iter = a.iter(); + /// let mut iter = a.into_iter(); /// /// assert_eq!(iter.advance_by(2), Ok(())); - /// assert_eq!(iter.next(), Some(&3)); + /// assert_eq!(iter.next(), Some(3)); /// assert_eq!(iter.advance_by(0), Ok(())); - /// assert_eq!(iter.advance_by(100), Err(NonZero::new(99).unwrap())); // only `&4` was skipped + /// assert_eq!(iter.advance_by(100), Err(NonZero::new(99).unwrap())); // only `4` was skipped /// ``` #[inline] #[unstable(feature = "iter_advance_by", reason = "recently added", issue = "77404")] @@ -322,7 +322,7 @@ pub trait Iterator { /// /// ``` /// let a = [1, 2, 3]; - /// assert_eq!(a.iter().nth(1), Some(&2)); + /// assert_eq!(a.into_iter().nth(1), Some(2)); /// ``` /// /// Calling `nth()` multiple times doesn't rewind the iterator: @@ -330,9 +330,9 @@ pub trait Iterator { /// ``` /// let a = [1, 2, 3]; /// - /// let mut iter = a.iter(); + /// let mut iter = a.into_iter(); /// - /// assert_eq!(iter.nth(1), Some(&2)); + /// assert_eq!(iter.nth(1), Some(2)); /// assert_eq!(iter.nth(1), None); /// ``` /// @@ -340,7 +340,7 @@ pub trait Iterator { /// /// ``` /// let a = [1, 2, 3]; - /// assert_eq!(a.iter().nth(10), None); + /// assert_eq!(a.into_iter().nth(10), None); /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -385,11 +385,11 @@ pub trait Iterator { /// /// ``` /// let a = [0, 1, 2, 3, 4, 5]; - /// let mut iter = a.iter().step_by(2); + /// let mut iter = a.into_iter().step_by(2); /// - /// assert_eq!(iter.next(), Some(&0)); - /// assert_eq!(iter.next(), Some(&2)); - /// assert_eq!(iter.next(), Some(&4)); + /// assert_eq!(iter.next(), Some(0)); + /// assert_eq!(iter.next(), Some(2)); + /// assert_eq!(iter.next(), Some(4)); /// assert_eq!(iter.next(), None); /// ``` #[inline] @@ -417,37 +417,37 @@ pub trait Iterator { /// Basic usage: /// /// ``` - /// let a1 = [1, 2, 3]; - /// let a2 = [4, 5, 6]; + /// let s1 = "abc".chars(); + /// let s2 = "def".chars(); /// - /// let mut iter = a1.iter().chain(a2.iter()); + /// let mut iter = s1.chain(s2); /// - /// assert_eq!(iter.next(), Some(&1)); - /// assert_eq!(iter.next(), Some(&2)); - /// assert_eq!(iter.next(), Some(&3)); - /// assert_eq!(iter.next(), Some(&4)); - /// assert_eq!(iter.next(), Some(&5)); - /// assert_eq!(iter.next(), Some(&6)); + /// assert_eq!(iter.next(), Some('a')); + /// assert_eq!(iter.next(), Some('b')); + /// assert_eq!(iter.next(), Some('c')); + /// assert_eq!(iter.next(), Some('d')); + /// assert_eq!(iter.next(), Some('e')); + /// assert_eq!(iter.next(), Some('f')); /// assert_eq!(iter.next(), None); /// ``` /// /// Since the argument to `chain()` uses [`IntoIterator`], we can pass /// anything that can be converted into an [`Iterator`], not just an - /// [`Iterator`] itself. For example, slices (`&[T]`) implement + /// [`Iterator`] itself. For example, arrays (`[T]`) implement /// [`IntoIterator`], and so can be passed to `chain()` directly: /// /// ``` - /// let s1 = &[1, 2, 3]; - /// let s2 = &[4, 5, 6]; + /// let a1 = [1, 2, 3]; + /// let a2 = [4, 5, 6]; /// - /// let mut iter = s1.iter().chain(s2); + /// let mut iter = a1.into_iter().chain(a2); /// - /// assert_eq!(iter.next(), Some(&1)); - /// assert_eq!(iter.next(), Some(&2)); - /// assert_eq!(iter.next(), Some(&3)); - /// assert_eq!(iter.next(), Some(&4)); - /// assert_eq!(iter.next(), Some(&5)); - /// assert_eq!(iter.next(), Some(&6)); + /// assert_eq!(iter.next(), Some(1)); + /// assert_eq!(iter.next(), Some(2)); + /// assert_eq!(iter.next(), Some(3)); + /// assert_eq!(iter.next(), Some(4)); + /// assert_eq!(iter.next(), Some(5)); + /// assert_eq!(iter.next(), Some(6)); /// assert_eq!(iter.next(), None); /// ``` /// @@ -496,31 +496,31 @@ pub trait Iterator { /// Basic usage: /// /// ``` - /// let a1 = [1, 2, 3]; - /// let a2 = [4, 5, 6]; + /// let s1 = "abc".chars(); + /// let s2 = "def".chars(); /// - /// let mut iter = a1.iter().zip(a2.iter()); + /// let mut iter = s1.zip(s2); /// - /// assert_eq!(iter.next(), Some((&1, &4))); - /// assert_eq!(iter.next(), Some((&2, &5))); - /// assert_eq!(iter.next(), Some((&3, &6))); + /// assert_eq!(iter.next(), Some(('a', 'd'))); + /// assert_eq!(iter.next(), Some(('b', 'e'))); + /// assert_eq!(iter.next(), Some(('c', 'f'))); /// assert_eq!(iter.next(), None); /// ``` /// /// Since the argument to `zip()` uses [`IntoIterator`], we can pass /// anything that can be converted into an [`Iterator`], not just an - /// [`Iterator`] itself. For example, slices (`&[T]`) implement + /// [`Iterator`] itself. For example, arrays (`[T]`) implement /// [`IntoIterator`], and so can be passed to `zip()` directly: /// /// ``` - /// let s1 = &[1, 2, 3]; - /// let s2 = &[4, 5, 6]; + /// let a1 = [1, 2, 3]; + /// let a2 = [4, 5, 6]; /// - /// let mut iter = s1.iter().zip(s2); + /// let mut iter = a1.into_iter().zip(a2); /// - /// assert_eq!(iter.next(), Some((&1, &4))); - /// assert_eq!(iter.next(), Some((&2, &5))); - /// assert_eq!(iter.next(), Some((&3, &6))); + /// assert_eq!(iter.next(), Some((1, 4))); + /// assert_eq!(iter.next(), Some((2, 5))); + /// assert_eq!(iter.next(), Some((3, 6))); /// assert_eq!(iter.next(), None); /// ``` /// @@ -604,12 +604,12 @@ pub trait Iterator { /// ``` /// #![feature(iter_intersperse)] /// - /// let mut a = [0, 1, 2].iter().intersperse(&100); - /// assert_eq!(a.next(), Some(&0)); // The first element from `a`. - /// assert_eq!(a.next(), Some(&100)); // The separator. - /// assert_eq!(a.next(), Some(&1)); // The next element from `a`. - /// assert_eq!(a.next(), Some(&100)); // The separator. - /// assert_eq!(a.next(), Some(&2)); // The last element from `a`. + /// let mut a = [0, 1, 2].into_iter().intersperse(100); + /// assert_eq!(a.next(), Some(0)); // The first element from `a`. + /// assert_eq!(a.next(), Some(100)); // The separator. + /// assert_eq!(a.next(), Some(1)); // The next element from `a`. + /// assert_eq!(a.next(), Some(100)); // The separator. + /// assert_eq!(a.next(), Some(2)); // The last element from `a`. /// assert_eq!(a.next(), None); // The iterator is finished. /// ``` /// @@ -617,7 +617,8 @@ pub trait Iterator { /// ``` /// #![feature(iter_intersperse)] /// - /// let hello = ["Hello", "World", "!"].iter().copied().intersperse(" ").collect::(); + /// let words = ["Hello", "World", "!"]; + /// let hello: String = words.into_iter().intersperse(" ").collect(); /// assert_eq!(hello, "Hello World !"); /// ``` /// @@ -673,7 +674,7 @@ pub trait Iterator { /// let src = ["Hello", "to", "all", "people", "!!"].iter().copied(); /// /// // The closure mutably borrows its context to generate an item. - /// let mut happy_emojis = [" ❤️ ", " 😀 "].iter().copied(); + /// let mut happy_emojis = [" ❤️ ", " 😀 "].into_iter(); /// let separator = || happy_emojis.next().unwrap_or(" 🦀 "); /// /// let result = src.intersperse_with(separator).collect::(); @@ -734,7 +735,7 @@ pub trait Iterator { /// /// // it won't even execute, as it is lazy. Rust will warn you about this. /// - /// // Instead, use for: + /// // Instead, use a for-loop: /// for x in 0..5 { /// println!("{x}"); /// } @@ -814,10 +815,10 @@ pub trait Iterator { /// ``` /// let a = [0i32, 1, 2]; /// - /// let mut iter = a.iter().filter(|x| x.is_positive()); + /// let mut iter = a.into_iter().filter(|x| x.is_positive()); /// - /// assert_eq!(iter.next(), Some(&1)); - /// assert_eq!(iter.next(), Some(&2)); + /// assert_eq!(iter.next(), Some(1)); + /// assert_eq!(iter.next(), Some(2)); /// assert_eq!(iter.next(), None); /// ``` /// @@ -826,21 +827,20 @@ pub trait Iterator { /// situation, where the type of the closure is a double reference: /// /// ``` - /// let a = [0, 1, 2]; + /// let s = &[0, 1, 2]; /// - /// let mut iter = a.iter().filter(|x| **x > 1); // need two *s! + /// let mut iter = s.iter().filter(|x| **x > 1); // needs two *s! /// /// assert_eq!(iter.next(), Some(&2)); /// assert_eq!(iter.next(), None); /// ``` /// - /// It's common to instead use destructuring on the argument to strip away - /// one: + /// It's common to instead use destructuring on the argument to strip away one: /// /// ``` - /// let a = [0, 1, 2]; + /// let s = &[0, 1, 2]; /// - /// let mut iter = a.iter().filter(|&x| *x > 1); // both & and * + /// let mut iter = s.iter().filter(|&x| *x > 1); // both & and * /// /// assert_eq!(iter.next(), Some(&2)); /// assert_eq!(iter.next(), None); @@ -849,9 +849,9 @@ pub trait Iterator { /// or both: /// /// ``` - /// let a = [0, 1, 2]; + /// let s = &[0, 1, 2]; /// - /// let mut iter = a.iter().filter(|&&x| x > 1); // two &s + /// let mut iter = s.iter().filter(|&&x| x > 1); // two &s /// /// assert_eq!(iter.next(), Some(&2)); /// assert_eq!(iter.next(), None); @@ -945,11 +945,11 @@ pub trait Iterator { /// ``` /// let a = ['a', 'b', 'c']; /// - /// let mut iter = a.iter().enumerate(); + /// let mut iter = a.into_iter().enumerate(); /// - /// assert_eq!(iter.next(), Some((0, &'a'))); - /// assert_eq!(iter.next(), Some((1, &'b'))); - /// assert_eq!(iter.next(), Some((2, &'c'))); + /// assert_eq!(iter.next(), Some((0, 'a'))); + /// assert_eq!(iter.next(), Some((1, 'b'))); + /// assert_eq!(iter.next(), Some((2, 'c'))); /// assert_eq!(iter.next(), None); /// ``` #[inline] @@ -980,19 +980,19 @@ pub trait Iterator { /// ``` /// let xs = [1, 2, 3]; /// - /// let mut iter = xs.iter().peekable(); + /// let mut iter = xs.into_iter().peekable(); /// /// // peek() lets us see into the future - /// assert_eq!(iter.peek(), Some(&&1)); - /// assert_eq!(iter.next(), Some(&1)); + /// assert_eq!(iter.peek(), Some(&1)); + /// assert_eq!(iter.next(), Some(1)); /// - /// assert_eq!(iter.next(), Some(&2)); + /// assert_eq!(iter.next(), Some(2)); /// /// // we can peek() multiple times, the iterator won't advance - /// assert_eq!(iter.peek(), Some(&&3)); - /// assert_eq!(iter.peek(), Some(&&3)); + /// assert_eq!(iter.peek(), Some(&3)); + /// assert_eq!(iter.peek(), Some(&3)); /// - /// assert_eq!(iter.next(), Some(&3)); + /// assert_eq!(iter.next(), Some(3)); /// /// // after the iterator is finished, so is peek() /// assert_eq!(iter.peek(), None); @@ -1005,21 +1005,21 @@ pub trait Iterator { /// ``` /// let xs = [1, 2, 3]; /// - /// let mut iter = xs.iter().peekable(); + /// let mut iter = xs.into_iter().peekable(); /// /// // `peek_mut()` lets us see into the future - /// assert_eq!(iter.peek_mut(), Some(&mut &1)); - /// assert_eq!(iter.peek_mut(), Some(&mut &1)); - /// assert_eq!(iter.next(), Some(&1)); + /// assert_eq!(iter.peek_mut(), Some(&mut 1)); + /// assert_eq!(iter.peek_mut(), Some(&mut 1)); + /// assert_eq!(iter.next(), Some(1)); /// - /// if let Some(mut p) = iter.peek_mut() { - /// assert_eq!(*p, &2); + /// if let Some(p) = iter.peek_mut() { + /// assert_eq!(*p, 2); /// // put a value into the iterator - /// *p = &1000; + /// *p = 1000; /// } /// /// // The value reappears as the iterator continues - /// assert_eq!(iter.collect::>(), vec![&1000, &3]); + /// assert_eq!(iter.collect::>(), vec![1000, 3]); /// ``` /// [`peek`]: Peekable::peek /// [`peek_mut`]: Peekable::peek_mut @@ -1051,10 +1051,10 @@ pub trait Iterator { /// ``` /// let a = [-1i32, 0, 1]; /// - /// let mut iter = a.iter().skip_while(|x| x.is_negative()); + /// let mut iter = a.into_iter().skip_while(|x| x.is_negative()); /// - /// assert_eq!(iter.next(), Some(&0)); - /// assert_eq!(iter.next(), Some(&1)); + /// assert_eq!(iter.next(), Some(0)); + /// assert_eq!(iter.next(), Some(1)); /// assert_eq!(iter.next(), None); /// ``` /// @@ -1063,9 +1063,9 @@ pub trait Iterator { /// situation, where the type of the closure argument is a double reference: /// /// ``` - /// let a = [-1, 0, 1]; + /// let s = &[-1, 0, 1]; /// - /// let mut iter = a.iter().skip_while(|x| **x < 0); // need two *s! + /// let mut iter = s.iter().skip_while(|x| **x < 0); // need two *s! /// /// assert_eq!(iter.next(), Some(&0)); /// assert_eq!(iter.next(), Some(&1)); @@ -1077,14 +1077,14 @@ pub trait Iterator { /// ``` /// let a = [-1, 0, 1, -2]; /// - /// let mut iter = a.iter().skip_while(|x| **x < 0); + /// let mut iter = a.into_iter().skip_while(|&x| x < 0); /// - /// assert_eq!(iter.next(), Some(&0)); - /// assert_eq!(iter.next(), Some(&1)); + /// assert_eq!(iter.next(), Some(0)); + /// assert_eq!(iter.next(), Some(1)); /// /// // while this would have been false, since we already got a false, /// // skip_while() isn't used any more - /// assert_eq!(iter.next(), Some(&-2)); + /// assert_eq!(iter.next(), Some(-2)); /// /// assert_eq!(iter.next(), None); /// ``` @@ -1115,9 +1115,9 @@ pub trait Iterator { /// ``` /// let a = [-1i32, 0, 1]; /// - /// let mut iter = a.iter().take_while(|x| x.is_negative()); + /// let mut iter = a.into_iter().take_while(|x| x.is_negative()); /// - /// assert_eq!(iter.next(), Some(&-1)); + /// assert_eq!(iter.next(), Some(-1)); /// assert_eq!(iter.next(), None); /// ``` /// @@ -1126,9 +1126,9 @@ pub trait Iterator { /// situation, where the type of the closure is a double reference: /// /// ``` - /// let a = [-1, 0, 1]; + /// let s = &[-1, 0, 1]; /// - /// let mut iter = a.iter().take_while(|x| **x < 0); // need two *s! + /// let mut iter = s.iter().take_while(|x| **x < 0); // need two *s! /// /// assert_eq!(iter.next(), Some(&-1)); /// assert_eq!(iter.next(), None); @@ -1139,12 +1139,12 @@ pub trait Iterator { /// ``` /// let a = [-1, 0, 1, -2]; /// - /// let mut iter = a.iter().take_while(|x| **x < 0); + /// let mut iter = a.into_iter().take_while(|&x| x < 0); /// - /// assert_eq!(iter.next(), Some(&-1)); + /// assert_eq!(iter.next(), Some(-1)); /// /// // We have more elements that are less than zero, but since we already - /// // got a false, take_while() isn't used any more + /// // got a false, take_while() ignores the remaining elements. /// assert_eq!(iter.next(), None); /// ``` /// @@ -1154,18 +1154,15 @@ pub trait Iterator { /// /// ``` /// let a = [1, 2, 3, 4]; - /// let mut iter = a.iter(); + /// let mut iter = a.into_iter(); /// - /// let result: Vec = iter.by_ref() - /// .take_while(|n| **n != 3) - /// .cloned() - /// .collect(); + /// let result: Vec = iter.by_ref().take_while(|&n| n != 3).collect(); /// - /// assert_eq!(result, &[1, 2]); + /// assert_eq!(result, [1, 2]); /// - /// let result: Vec = iter.cloned().collect(); + /// let result: Vec = iter.collect(); /// - /// assert_eq!(result, &[4]); + /// assert_eq!(result, [4]); /// ``` /// /// The `3` is no longer there, because it was consumed in order to see if @@ -1193,7 +1190,7 @@ pub trait Iterator { /// ``` /// let a = [-1i32, 4, 0, 1]; /// - /// let mut iter = a.iter().map_while(|x| 16i32.checked_div(*x)); + /// let mut iter = a.into_iter().map_while(|x| 16i32.checked_div(x)); /// /// assert_eq!(iter.next(), Some(-16)); /// assert_eq!(iter.next(), Some(4)); @@ -1208,8 +1205,8 @@ pub trait Iterator { /// ``` /// let a = [-1i32, 4, 0, 1]; /// - /// let mut iter = a.iter() - /// .map(|x| 16i32.checked_div(*x)) + /// let mut iter = a.into_iter() + /// .map(|x| 16i32.checked_div(x)) /// .take_while(|x| x.is_some()) /// .map(|x| x.unwrap()); /// @@ -1223,12 +1220,12 @@ pub trait Iterator { /// ``` /// let a = [0, 1, 2, -3, 4, 5, -6]; /// - /// let iter = a.iter().map_while(|x| u32::try_from(*x).ok()); - /// let vec = iter.collect::>(); + /// let iter = a.into_iter().map_while(|x| u32::try_from(x).ok()); + /// let vec: Vec<_> = iter.collect(); /// - /// // We have more elements which could fit in u32 (4, 5), but `map_while` returned `None` for `-3` + /// // We have more elements that could fit in u32 (such as 4, 5), but `map_while` returned `None` for `-3` /// // (as the `predicate` returned `None`) and `collect` stops at the first `None` encountered. - /// assert_eq!(vec, vec![0, 1, 2]); + /// assert_eq!(vec, [0, 1, 2]); /// ``` /// /// Because `map_while()` needs to look at the value in order to see if it @@ -1237,17 +1234,17 @@ pub trait Iterator { /// /// ``` /// let a = [1, 2, -3, 4]; - /// let mut iter = a.iter(); + /// let mut iter = a.into_iter(); /// /// let result: Vec = iter.by_ref() - /// .map_while(|n| u32::try_from(*n).ok()) + /// .map_while(|n| u32::try_from(n).ok()) /// .collect(); /// - /// assert_eq!(result, &[1, 2]); + /// assert_eq!(result, [1, 2]); /// - /// let result: Vec = iter.cloned().collect(); + /// let result: Vec = iter.collect(); /// - /// assert_eq!(result, &[4]); + /// assert_eq!(result, [4]); /// ``` /// /// The `-3` is no longer there, because it was consumed in order to see if @@ -1255,7 +1252,7 @@ pub trait Iterator { /// /// Note that unlike [`take_while`] this iterator is **not** fused. /// It is also not specified what this iterator returns after the first [`None`] is returned. - /// If you need fused iterator, use [`fuse`]. + /// If you need a fused iterator, use [`fuse`]. /// /// [`fuse`]: Iterator::fuse #[inline] @@ -1282,9 +1279,9 @@ pub trait Iterator { /// ``` /// let a = [1, 2, 3]; /// - /// let mut iter = a.iter().skip(2); + /// let mut iter = a.into_iter().skip(2); /// - /// assert_eq!(iter.next(), Some(&3)); + /// assert_eq!(iter.next(), Some(3)); /// assert_eq!(iter.next(), None); /// ``` #[inline] @@ -1312,10 +1309,10 @@ pub trait Iterator { /// ``` /// let a = [1, 2, 3]; /// - /// let mut iter = a.iter().take(2); + /// let mut iter = a.into_iter().take(2); /// - /// assert_eq!(iter.next(), Some(&1)); - /// assert_eq!(iter.next(), Some(&2)); + /// assert_eq!(iter.next(), Some(1)); + /// assert_eq!(iter.next(), Some(2)); /// assert_eq!(iter.next(), None); /// ``` /// @@ -1340,6 +1337,25 @@ pub trait Iterator { /// assert_eq!(iter.next(), Some(2)); /// assert_eq!(iter.next(), None); /// ``` + /// + /// Use [`by_ref`] to take from the iterator without consuming it, and then + /// continue using the original iterator: + /// + /// ``` + /// let mut words = ["hello", "world", "of", "Rust"].into_iter(); + /// + /// // Take the first two words. + /// let hello_world: Vec<_> = words.by_ref().take(2).collect(); + /// assert_eq!(hello_world, vec!["hello", "world"]); + /// + /// // Collect the rest of the words. + /// // We can only do this because we used `by_ref` earlier. + /// let of_rust: Vec<_> = words.collect(); + /// assert_eq!(of_rust, vec!["of", "Rust"]); + /// ``` + /// + /// [`by_ref`]: Iterator::by_ref + #[doc(alias = "limit")] #[inline] #[stable(feature = "rust1", since = "1.0.0")] fn take(self, n: usize) -> Take @@ -1370,7 +1386,7 @@ pub trait Iterator { /// ``` /// let a = [1, 2, 3, 4]; /// - /// let mut iter = a.iter().scan(1, |state, &x| { + /// let mut iter = a.into_iter().scan(1, |state, x| { /// // each iteration, we'll multiply the state by the element ... /// *state = *state * x; /// @@ -1448,8 +1464,8 @@ pub trait Iterator { /// /// ``` /// let data = vec![vec![1, 2, 3, 4], vec![5, 6]]; - /// let flattened = data.into_iter().flatten().collect::>(); - /// assert_eq!(flattened, &[1, 2, 3, 4, 5, 6]); + /// let flattened: Vec<_> = data.into_iter().flatten().collect(); + /// assert_eq!(flattened, [1, 2, 3, 4, 5, 6]); /// ``` /// /// Mapping and then flattening: @@ -1483,11 +1499,11 @@ pub trait Iterator { /// ``` /// let options = vec![Some(123), Some(321), None, Some(231)]; /// let flattened_options: Vec<_> = options.into_iter().flatten().collect(); - /// assert_eq!(flattened_options, vec![123, 321, 231]); + /// assert_eq!(flattened_options, [123, 321, 231]); /// /// let results = vec![Ok(123), Ok(321), Err(456), Ok(231)]; /// let flattened_results: Vec<_> = results.into_iter().flatten().collect(); - /// assert_eq!(flattened_results, vec![123, 321, 231]); + /// assert_eq!(flattened_results, [123, 321, 231]); /// ``` /// /// Flattening only removes one level of nesting at a time: @@ -1495,11 +1511,11 @@ pub trait Iterator { /// ``` /// let d3 = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]; /// - /// let d2 = d3.iter().flatten().collect::>(); - /// assert_eq!(d2, [&[1, 2], &[3, 4], &[5, 6], &[7, 8]]); + /// let d2: Vec<_> = d3.into_iter().flatten().collect(); + /// assert_eq!(d2, [[1, 2], [3, 4], [5, 6], [7, 8]]); /// - /// let d1 = d3.iter().flatten().flatten().collect::>(); - /// assert_eq!(d1, [&1, &2, &3, &4, &5, &6, &7, &8]); + /// let d1: Vec<_> = d3.into_iter().flatten().flatten().collect(); + /// assert_eq!(d1, [1, 2, 3, 4, 5, 6, 7, 8]); /// ``` /// /// Here we see that `flatten()` does not perform a "deep" flatten. @@ -1886,7 +1902,7 @@ pub trait Iterator { /// let a = [1, 2, 3]; /// /// let doubled: Vec = a.iter() - /// .map(|&x| x * 2) + /// .map(|x| x * 2) /// .collect(); /// /// assert_eq!(vec![2, 4, 6], doubled); @@ -1902,7 +1918,7 @@ pub trait Iterator { /// /// let a = [1, 2, 3]; /// - /// let doubled: VecDeque = a.iter().map(|&x| x * 2).collect(); + /// let doubled: VecDeque = a.iter().map(|x| x * 2).collect(); /// /// assert_eq!(2, doubled[0]); /// assert_eq!(4, doubled[1]); @@ -1935,8 +1951,8 @@ pub trait Iterator { /// ``` /// let chars = ['g', 'd', 'k', 'k', 'n']; /// - /// let hello: String = chars.iter() - /// .map(|&x| x as u8) + /// let hello: String = chars.into_iter() + /// .map(|x| x as u8) /// .map(|x| (x + 1) as char) /// .collect(); /// @@ -1949,14 +1965,14 @@ pub trait Iterator { /// ``` /// let results = [Ok(1), Err("nope"), Ok(3), Err("bad")]; /// - /// let result: Result, &str> = results.iter().cloned().collect(); + /// let result: Result, &str> = results.into_iter().collect(); /// /// // gives us the first error /// assert_eq!(Err("nope"), result); /// /// let results = [Ok(1), Ok(3)]; /// - /// let result: Result, &str> = results.iter().cloned().collect(); + /// let result: Result, &str> = results.into_iter().collect(); /// /// // gives us the list of answers /// assert_eq!(Ok(vec![1, 3]), result); @@ -2087,8 +2103,8 @@ pub trait Iterator { /// let a = [1, 2, 3]; /// let mut vec: Vec:: = vec![0, 1]; /// - /// a.iter().map(|&x| x * 2).collect_into(&mut vec); - /// a.iter().map(|&x| x * 10).collect_into(&mut vec); + /// a.iter().map(|x| x * 2).collect_into(&mut vec); + /// a.iter().map(|x| x * 10).collect_into(&mut vec); /// /// assert_eq!(vec, vec![0, 1, 2, 4, 6, 10, 20, 30]); /// ``` @@ -2101,8 +2117,8 @@ pub trait Iterator { /// let a = [1, 2, 3]; /// let mut vec: Vec:: = Vec::with_capacity(6); /// - /// a.iter().map(|&x| x * 2).collect_into(&mut vec); - /// a.iter().map(|&x| x * 10).collect_into(&mut vec); + /// a.iter().map(|x| x * 2).collect_into(&mut vec); + /// a.iter().map(|x| x * 10).collect_into(&mut vec); /// /// assert_eq!(6, vec.capacity()); /// assert_eq!(vec, vec![2, 4, 6, 10, 20, 30]); @@ -2156,8 +2172,8 @@ pub trait Iterator { /// .into_iter() /// .partition(|n| n % 2 == 0); /// - /// assert_eq!(even, vec![2]); - /// assert_eq!(odd, vec![1, 3]); + /// assert_eq!(even, [2]); + /// assert_eq!(odd, [1, 3]); /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn partition(self, f: F) -> (B, B) @@ -2215,11 +2231,11 @@ pub trait Iterator { /// let mut a = [1, 2, 3, 4, 5, 6, 7]; /// /// // Partition in-place between evens and odds - /// let i = a.iter_mut().partition_in_place(|&n| n % 2 == 0); + /// let i = a.iter_mut().partition_in_place(|n| n % 2 == 0); /// /// assert_eq!(i, 3); - /// assert!(a[..i].iter().all(|&n| n % 2 == 0)); // evens - /// assert!(a[i..].iter().all(|&n| n % 2 == 1)); // odds + /// assert!(a[..i].iter().all(|n| n % 2 == 0)); // evens + /// assert!(a[i..].iter().all(|n| n % 2 == 1)); // odds /// ``` #[unstable(feature = "iter_partition_in_place", reason = "new API", issue = "62543")] fn partition_in_place<'a, T: 'a, P>(mut self, ref mut predicate: P) -> usize @@ -2326,7 +2342,7 @@ pub trait Iterator { /// let a = [1, 2, 3]; /// /// // the checked sum of all of the elements of the array - /// let sum = a.iter().try_fold(0i8, |acc, &x| acc.checked_add(x)); + /// let sum = a.into_iter().try_fold(0i8, |acc, x| acc.checked_add(x)); /// /// assert_eq!(sum, Some(6)); /// ``` @@ -2335,16 +2351,16 @@ pub trait Iterator { /// /// ``` /// let a = [10, 20, 30, 100, 40, 50]; - /// let mut it = a.iter(); + /// let mut iter = a.into_iter(); /// /// // This sum overflows when adding the 100 element - /// let sum = it.try_fold(0i8, |acc, &x| acc.checked_add(x)); + /// let sum = iter.try_fold(0i8, |acc, x| acc.checked_add(x)); /// assert_eq!(sum, None); /// /// // Because it short-circuited, the remaining elements are still /// // available through the iterator. - /// assert_eq!(it.len(), 2); - /// assert_eq!(it.next(), Some(&40)); + /// assert_eq!(iter.len(), 2); + /// assert_eq!(iter.next(), Some(40)); /// ``` /// /// While you cannot `break` from a closure, the [`ControlFlow`] type allows @@ -2697,9 +2713,9 @@ pub trait Iterator { /// ``` /// let a = [1, 2, 3]; /// - /// assert!(a.iter().all(|&x| x > 0)); + /// assert!(a.into_iter().all(|x| x > 0)); /// - /// assert!(!a.iter().all(|&x| x > 2)); + /// assert!(!a.into_iter().all(|x| x > 2)); /// ``` /// /// Stopping at the first `false`: @@ -2707,12 +2723,12 @@ pub trait Iterator { /// ``` /// let a = [1, 2, 3]; /// - /// let mut iter = a.iter(); + /// let mut iter = a.into_iter(); /// - /// assert!(!iter.all(|&x| x != 2)); + /// assert!(!iter.all(|x| x != 2)); /// /// // we can still use `iter`, as there are more elements. - /// assert_eq!(iter.next(), Some(&3)); + /// assert_eq!(iter.next(), Some(3)); /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -2750,9 +2766,9 @@ pub trait Iterator { /// ``` /// let a = [1, 2, 3]; /// - /// assert!(a.iter().any(|&x| x > 0)); + /// assert!(a.into_iter().any(|x| x > 0)); /// - /// assert!(!a.iter().any(|&x| x > 5)); + /// assert!(!a.into_iter().any(|x| x > 5)); /// ``` /// /// Stopping at the first `true`: @@ -2760,12 +2776,12 @@ pub trait Iterator { /// ``` /// let a = [1, 2, 3]; /// - /// let mut iter = a.iter(); + /// let mut iter = a.into_iter(); /// - /// assert!(iter.any(|&x| x != 2)); + /// assert!(iter.any(|x| x != 2)); /// /// // we can still use `iter`, as there are more elements. - /// assert_eq!(iter.next(), Some(&2)); + /// assert_eq!(iter.next(), Some(2)); /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -2811,9 +2827,8 @@ pub trait Iterator { /// ``` /// let a = [1, 2, 3]; /// - /// assert_eq!(a.iter().find(|&&x| x == 2), Some(&2)); - /// - /// assert_eq!(a.iter().find(|&&x| x == 5), None); + /// assert_eq!(a.into_iter().find(|&x| x == 2), Some(2)); + /// assert_eq!(a.into_iter().find(|&x| x == 5), None); /// ``` /// /// Stopping at the first `true`: @@ -2821,12 +2836,12 @@ pub trait Iterator { /// ``` /// let a = [1, 2, 3]; /// - /// let mut iter = a.iter(); + /// let mut iter = a.into_iter(); /// - /// assert_eq!(iter.find(|&&x| x == 2), Some(&2)); + /// assert_eq!(iter.find(|&x| x == 2), Some(2)); /// /// // we can still use `iter`, as there are more elements. - /// assert_eq!(iter.next(), Some(&3)); + /// assert_eq!(iter.next(), Some(3)); /// ``` /// /// Note that `iter.find(f)` is equivalent to `iter.filter(f).next()`. @@ -2894,13 +2909,13 @@ pub trait Iterator { /// let a = ["1", "2", "lol", "NaN", "5"]; /// /// let is_my_num = |s: &str, search: i32| -> Result { - /// Ok(s.parse::()? == search) + /// Ok(s.parse::()? == search) /// }; /// - /// let result = a.iter().try_find(|&&s| is_my_num(s, 2)); - /// assert_eq!(result, Ok(Some(&"2"))); + /// let result = a.into_iter().try_find(|&s| is_my_num(s, 2)); + /// assert_eq!(result, Ok(Some("2"))); /// - /// let result = a.iter().try_find(|&&s| is_my_num(s, 5)); + /// let result = a.into_iter().try_find(|&s| is_my_num(s, 5)); /// assert!(result.is_err()); /// ``` /// @@ -2912,11 +2927,11 @@ pub trait Iterator { /// use std::num::NonZero; /// /// let a = [3, 5, 7, 4, 9, 0, 11u32]; - /// let result = a.iter().try_find(|&&x| NonZero::new(x).map(|y| y.is_power_of_two())); - /// assert_eq!(result, Some(Some(&4))); - /// let result = a.iter().take(3).try_find(|&&x| NonZero::new(x).map(|y| y.is_power_of_two())); + /// let result = a.into_iter().try_find(|&x| NonZero::new(x).map(|y| y.is_power_of_two())); + /// assert_eq!(result, Some(Some(4))); + /// let result = a.into_iter().take(3).try_find(|&x| NonZero::new(x).map(|y| y.is_power_of_two())); /// assert_eq!(result, Some(None)); - /// let result = a.iter().rev().try_find(|&&x| NonZero::new(x).map(|y| y.is_power_of_two())); + /// let result = a.into_iter().rev().try_find(|&x| NonZero::new(x).map(|y| y.is_power_of_two())); /// assert_eq!(result, None); /// ``` #[inline] @@ -2981,9 +2996,9 @@ pub trait Iterator { /// ``` /// let a = [1, 2, 3]; /// - /// assert_eq!(a.iter().position(|&x| x == 2), Some(1)); + /// assert_eq!(a.into_iter().position(|x| x == 2), Some(1)); /// - /// assert_eq!(a.iter().position(|&x| x == 5), None); + /// assert_eq!(a.into_iter().position(|x| x == 5), None); /// ``` /// /// Stopping at the first `true`: @@ -2991,15 +3006,15 @@ pub trait Iterator { /// ``` /// let a = [1, 2, 3, 4]; /// - /// let mut iter = a.iter(); + /// let mut iter = a.into_iter(); /// - /// assert_eq!(iter.position(|&x| x >= 2), Some(1)); + /// assert_eq!(iter.position(|x| x >= 2), Some(1)); /// /// // we can still use `iter`, as there are more elements. - /// assert_eq!(iter.next(), Some(&3)); + /// assert_eq!(iter.next(), Some(3)); /// /// // The returned index depends on iterator state - /// assert_eq!(iter.position(|&x| x == 4), Some(0)); + /// assert_eq!(iter.position(|x| x == 4), Some(0)); /// /// ``` #[inline] @@ -3049,9 +3064,9 @@ pub trait Iterator { /// ``` /// let a = [1, 2, 3]; /// - /// assert_eq!(a.iter().rposition(|&x| x == 3), Some(2)); + /// assert_eq!(a.into_iter().rposition(|x| x == 3), Some(2)); /// - /// assert_eq!(a.iter().rposition(|&x| x == 5), None); + /// assert_eq!(a.into_iter().rposition(|x| x == 5), None); /// ``` /// /// Stopping at the first `true`: @@ -3059,13 +3074,13 @@ pub trait Iterator { /// ``` /// let a = [-1, 2, 3, 4]; /// - /// let mut iter = a.iter(); + /// let mut iter = a.into_iter(); /// - /// assert_eq!(iter.rposition(|&x| x >= 2), Some(3)); + /// assert_eq!(iter.rposition(|x| x >= 2), Some(3)); /// /// // we can still use `iter`, as there are more elements. - /// assert_eq!(iter.next(), Some(&-1)); - /// assert_eq!(iter.next_back(), Some(&3)); + /// assert_eq!(iter.next(), Some(-1)); + /// assert_eq!(iter.next_back(), Some(3)); /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -3111,10 +3126,10 @@ pub trait Iterator { /// /// ``` /// let a = [1, 2, 3]; - /// let b: Vec = Vec::new(); + /// let b: [u32; 0] = []; /// - /// assert_eq!(a.iter().max(), Some(&3)); - /// assert_eq!(b.iter().max(), None); + /// assert_eq!(a.into_iter().max(), Some(3)); + /// assert_eq!(b.into_iter().max(), None); /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -3147,10 +3162,10 @@ pub trait Iterator { /// /// ``` /// let a = [1, 2, 3]; - /// let b: Vec = Vec::new(); + /// let b: [u32; 0] = []; /// - /// assert_eq!(a.iter().min(), Some(&1)); - /// assert_eq!(b.iter().min(), None); + /// assert_eq!(a.into_iter().min(), Some(1)); + /// assert_eq!(b.into_iter().min(), None); /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -3172,7 +3187,7 @@ pub trait Iterator { /// /// ``` /// let a = [-3_i32, 0, 1, 5, -10]; - /// assert_eq!(*a.iter().max_by_key(|x| x.abs()).unwrap(), -10); + /// assert_eq!(a.into_iter().max_by_key(|x| x.abs()).unwrap(), -10); /// ``` #[inline] #[stable(feature = "iter_cmp_by_key", since = "1.6.0")] @@ -3205,7 +3220,7 @@ pub trait Iterator { /// /// ``` /// let a = [-3_i32, 0, 1, 5, -10]; - /// assert_eq!(*a.iter().max_by(|x, y| x.cmp(y)).unwrap(), 5); + /// assert_eq!(a.into_iter().max_by(|x, y| x.cmp(y)).unwrap(), 5); /// ``` #[inline] #[stable(feature = "iter_max_by", since = "1.15.0")] @@ -3232,7 +3247,7 @@ pub trait Iterator { /// /// ``` /// let a = [-3_i32, 0, 1, 5, -10]; - /// assert_eq!(*a.iter().min_by_key(|x| x.abs()).unwrap(), 0); + /// assert_eq!(a.into_iter().min_by_key(|x| x.abs()).unwrap(), 0); /// ``` #[inline] #[stable(feature = "iter_cmp_by_key", since = "1.6.0")] @@ -3265,7 +3280,7 @@ pub trait Iterator { /// /// ``` /// let a = [-3_i32, 0, 1, 5, -10]; - /// assert_eq!(*a.iter().min_by(|x, y| x.cmp(y)).unwrap(), -10); + /// assert_eq!(a.into_iter().min_by(|x, y| x.cmp(y)).unwrap(), -10); /// ``` #[inline] #[stable(feature = "iter_min_by", since = "1.15.0")] @@ -3295,11 +3310,11 @@ pub trait Iterator { /// ``` /// let a = [1, 2, 3]; /// - /// let mut iter = a.iter().rev(); + /// let mut iter = a.into_iter().rev(); /// - /// assert_eq!(iter.next(), Some(&3)); - /// assert_eq!(iter.next(), Some(&2)); - /// assert_eq!(iter.next(), Some(&1)); + /// assert_eq!(iter.next(), Some(3)); + /// assert_eq!(iter.next(), Some(2)); + /// assert_eq!(iter.next(), Some(1)); /// /// assert_eq!(iter.next(), None); /// ``` @@ -3328,7 +3343,7 @@ pub trait Iterator { /// ``` /// let a = [(1, 2), (3, 4), (5, 6)]; /// - /// let (left, right): (Vec<_>, Vec<_>) = a.iter().cloned().unzip(); + /// let (left, right): (Vec<_>, Vec<_>) = a.into_iter().unzip(); /// /// assert_eq!(left, [1, 3, 5]); /// assert_eq!(right, [2, 4, 6]); @@ -3336,7 +3351,7 @@ pub trait Iterator { /// // you can also unzip multiple nested tuples at once /// let a = [(1, (2, 3)), (4, (5, 6))]; /// - /// let (x, (y, z)): (Vec<_>, (Vec<_>, Vec<_>)) = a.iter().cloned().unzip(); + /// let (x, (y, z)): (Vec<_>, (Vec<_>, Vec<_>)) = a.into_iter().unzip(); /// assert_eq!(x, [1, 4]); /// assert_eq!(y, [2, 5]); /// assert_eq!(z, [3, 6]); @@ -3368,8 +3383,8 @@ pub trait Iterator { /// // copied is the same as .map(|&x| x) /// let v_map: Vec<_> = a.iter().map(|&x| x).collect(); /// - /// assert_eq!(v_copied, vec![1, 2, 3]); - /// assert_eq!(v_map, vec![1, 2, 3]); + /// assert_eq!(v_copied, [1, 2, 3]); + /// assert_eq!(v_map, [1, 2, 3]); /// ``` #[stable(feature = "iter_copied", since = "1.36.0")] #[rustc_diagnostic_item = "iter_copied"] @@ -3404,8 +3419,8 @@ pub trait Iterator { /// // cloned is the same as .map(|&x| x), for integers /// let v_map: Vec<_> = a.iter().map(|&x| x).collect(); /// - /// assert_eq!(v_cloned, vec![1, 2, 3]); - /// assert_eq!(v_map, vec![1, 2, 3]); + /// assert_eq!(v_cloned, [1, 2, 3]); + /// assert_eq!(v_map, [1, 2, 3]); /// ``` /// /// To get the best performance, try to clone late: @@ -3441,15 +3456,14 @@ pub trait Iterator { /// ``` /// let a = [1, 2, 3]; /// - /// let mut it = a.iter().cycle(); + /// let mut iter = a.into_iter().cycle(); /// - /// assert_eq!(it.next(), Some(&1)); - /// assert_eq!(it.next(), Some(&2)); - /// assert_eq!(it.next(), Some(&3)); - /// assert_eq!(it.next(), Some(&1)); - /// assert_eq!(it.next(), Some(&2)); - /// assert_eq!(it.next(), Some(&3)); - /// assert_eq!(it.next(), Some(&1)); + /// loop { + /// assert_eq!(iter.next(), Some(1)); + /// assert_eq!(iter.next(), Some(2)); + /// assert_eq!(iter.next(), Some(3)); + /// # break; + /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -3607,9 +3621,9 @@ pub trait Iterator { /// let xs = [1, 2, 3, 4]; /// let ys = [1, 4, 9, 16]; /// - /// assert_eq!(xs.iter().cmp_by(&ys, |&x, &y| x.cmp(&y)), Ordering::Less); - /// assert_eq!(xs.iter().cmp_by(&ys, |&x, &y| (x * x).cmp(&y)), Ordering::Equal); - /// assert_eq!(xs.iter().cmp_by(&ys, |&x, &y| (2 * x).cmp(&y)), Ordering::Greater); + /// assert_eq!(xs.into_iter().cmp_by(ys, |x, y| x.cmp(&y)), Ordering::Less); + /// assert_eq!(xs.into_iter().cmp_by(ys, |x, y| (x * x).cmp(&y)), Ordering::Equal); + /// assert_eq!(xs.into_iter().cmp_by(ys, |x, y| (2 * x).cmp(&y)), Ordering::Greater); /// ``` #[unstable(feature = "iter_order_by", issue = "64295")] fn cmp_by(self, other: I, cmp: F) -> Ordering @@ -3691,15 +3705,15 @@ pub trait Iterator { /// let ys = [1.0, 4.0, 9.0, 16.0]; /// /// assert_eq!( - /// xs.iter().partial_cmp_by(&ys, |&x, &y| x.partial_cmp(&y)), + /// xs.iter().partial_cmp_by(ys, |x, y| x.partial_cmp(&y)), /// Some(Ordering::Less) /// ); /// assert_eq!( - /// xs.iter().partial_cmp_by(&ys, |&x, &y| (x * x).partial_cmp(&y)), + /// xs.iter().partial_cmp_by(ys, |x, y| (x * x).partial_cmp(&y)), /// Some(Ordering::Equal) /// ); /// assert_eq!( - /// xs.iter().partial_cmp_by(&ys, |&x, &y| (2.0 * x).partial_cmp(&y)), + /// xs.iter().partial_cmp_by(ys, |x, y| (2.0 * x).partial_cmp(&y)), /// Some(Ordering::Greater) /// ); /// ``` @@ -3757,7 +3771,7 @@ pub trait Iterator { /// let xs = [1, 2, 3, 4]; /// let ys = [1, 4, 9, 16]; /// - /// assert!(xs.iter().eq_by(&ys, |&x, &y| x * x == y)); + /// assert!(xs.iter().eq_by(ys, |x, y| x * x == y)); /// ``` #[unstable(feature = "iter_order_by", issue = "64295")] fn eq_by(self, other: I, eq: F) -> bool diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index 16c0c1180404..7dc8c060cd5b 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -1661,7 +1661,6 @@ pub(crate) mod builtin { #[unstable( feature = "test", issue = "50297", - soft, reason = "`bench` is a part of custom test frameworks which are unstable" )] #[allow_internal_unstable(test, rustc_attrs, coverage_attribute)] @@ -1748,8 +1747,8 @@ pub(crate) mod builtin { /* compiler built-in */ } - /// Provide a list of type aliases and other opaque-type-containing type definitions. - /// This list will be used in the body of the item it is applied to define opaque + /// Provide a list of type aliases and other opaque-type-containing type definitions + /// to an item with a body. This list will be used in that body to define opaque /// types' hidden types. /// Can only be applied to things that have bodies. #[unstable( diff --git a/library/core/src/num/diy_float.rs b/library/core/src/num/diy_float.rs index ce7f6475d059..e054e7f3f10a 100644 --- a/library/core/src/num/diy_float.rs +++ b/library/core/src/num/diy_float.rs @@ -21,61 +21,29 @@ pub struct Fp { impl Fp { /// Returns a correctly rounded product of itself and `other`. - pub fn mul(&self, other: &Fp) -> Fp { - const MASK: u64 = 0xffffffff; - let a = self.f >> 32; - let b = self.f & MASK; - let c = other.f >> 32; - let d = other.f & MASK; - let ac = a * c; - let bc = b * c; - let ad = a * d; - let bd = b * d; - let tmp = (bd >> 32) + (ad & MASK) + (bc & MASK) + (1 << 31) /* round */; - let f = ac + (ad >> 32) + (bc >> 32) + (tmp >> 32); + pub fn mul(self, other: Self) -> Self { + let (lo, hi) = self.f.widening_mul(other.f); + let f = hi + (lo >> 63) /* round */; let e = self.e + other.e + 64; - Fp { f, e } + Self { f, e } } /// Normalizes itself so that the resulting mantissa is at least `2^63`. - pub fn normalize(&self) -> Fp { - let mut f = self.f; - let mut e = self.e; - if f >> (64 - 32) == 0 { - f <<= 32; - e -= 32; - } - if f >> (64 - 16) == 0 { - f <<= 16; - e -= 16; - } - if f >> (64 - 8) == 0 { - f <<= 8; - e -= 8; - } - if f >> (64 - 4) == 0 { - f <<= 4; - e -= 4; - } - if f >> (64 - 2) == 0 { - f <<= 2; - e -= 2; - } - if f >> (64 - 1) == 0 { - f <<= 1; - e -= 1; - } + pub fn normalize(self) -> Self { + let lz = self.f.leading_zeros(); + let f = self.f << lz; + let e = self.e - lz as i16; debug_assert!(f >= (1 << 63)); - Fp { f, e } + Self { f, e } } /// Normalizes itself to have the shared exponent. /// It can only decrease the exponent (and thus increase the mantissa). - pub fn normalize_to(&self, e: i16) -> Fp { + pub fn normalize_to(self, e: i16) -> Self { let edelta = self.e - e; assert!(edelta >= 0); let edelta = edelta as usize; assert_eq!(self.f << edelta >> edelta, self.f); - Fp { f: self.f << edelta, e } + Self { f: self.f << edelta, e } } } diff --git a/library/core/src/num/flt2dec/strategy/grisu.rs b/library/core/src/num/flt2dec/strategy/grisu.rs index 2816de4c6333..d3bbb0934e0f 100644 --- a/library/core/src/num/flt2dec/strategy/grisu.rs +++ b/library/core/src/num/flt2dec/strategy/grisu.rs @@ -196,9 +196,9 @@ pub fn format_shortest_opt<'a>( let (minusk, cached) = cached_power(ALPHA - plus.e - 64, GAMMA - plus.e - 64); // scale fps. this gives the maximal error of 1 ulp (proved from Theorem 5.1). - let plus = plus.mul(&cached); - let minus = minus.mul(&cached); - let v = v.mul(&cached); + let plus = plus.mul(cached); + let minus = minus.mul(cached); + let v = v.mul(cached); debug_assert_eq!(plus.e, minus.e); debug_assert_eq!(plus.e, v.e); @@ -480,7 +480,7 @@ pub fn format_exact_opt<'a>( // normalize and scale `v`. let v = Fp { f: d.mant, e: d.exp }.normalize(); let (minusk, cached) = cached_power(ALPHA - v.e - 64, GAMMA - v.e - 64); - let v = v.mul(&cached); + let v = v.mul(cached); // divide `v` into integral and fractional parts. let e = -v.e as usize; diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index 445c789a7de2..aa103af93ffc 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -1065,10 +1065,45 @@ pub const unsafe fn swap(x: *mut T, y: *mut T) { /// assert_eq!(x, [7, 8, 3, 4]); /// assert_eq!(y, [1, 2, 9]); /// ``` +/// +/// # Const evaluation limitations +/// +/// If this function is invoked during const-evaluation, the current implementation has a small (and +/// rarely relevant) limitation: if `count` is at least 2 and the data pointed to by `x` or `y` +/// contains a pointer that crosses the boundary of two `T`-sized chunks of memory, the function may +/// fail to evaluate (similar to a panic during const-evaluation). This behavior may change in the +/// future. +/// +/// The limitation is illustrated by the following example: +/// +/// ``` +/// use std::mem::size_of; +/// use std::ptr; +/// +/// const { unsafe { +/// const PTR_SIZE: usize = size_of::<*const i32>(); +/// let mut data1 = [0u8; PTR_SIZE]; +/// let mut data2 = [0u8; PTR_SIZE]; +/// // Store a pointer in `data1`. +/// data1.as_mut_ptr().cast::<*const i32>().write_unaligned(&42); +/// // Swap the contents of `data1` and `data2` by swapping `PTR_SIZE` many `u8`-sized chunks. +/// // This call will fail, because the pointer in `data1` crosses the boundary +/// // between several of the 1-byte chunks that are being swapped here. +/// //ptr::swap_nonoverlapping(data1.as_mut_ptr(), data2.as_mut_ptr(), PTR_SIZE); +/// // Swap the contents of `data1` and `data2` by swapping a single chunk of size +/// // `[u8; PTR_SIZE]`. That works, as there is no pointer crossing the boundary between +/// // two chunks. +/// ptr::swap_nonoverlapping(&mut data1, &mut data2, 1); +/// // Read the pointer from `data2` and dereference it. +/// let ptr = data2.as_ptr().cast::<*const i32>().read_unaligned(); +/// assert!(*ptr == 42); +/// } } +/// ``` #[inline] #[stable(feature = "swap_nonoverlapping", since = "1.27.0")] -#[rustc_const_unstable(feature = "const_swap_nonoverlapping", issue = "133668")] +#[rustc_const_stable(feature = "const_swap_nonoverlapping", since = "CURRENT_RUSTC_VERSION")] #[rustc_diagnostic_item = "ptr_swap_nonoverlapping"] +#[rustc_allow_const_fn_unstable(const_eval_select)] // both implementations behave the same pub const unsafe fn swap_nonoverlapping(x: *mut T, y: *mut T, count: usize) { ub_checks::assert_unsafe_precondition!( check_library_ub, diff --git a/library/core/src/str/lossy.rs b/library/core/src/str/lossy.rs index ed2cefc59a51..8d4210c80827 100644 --- a/library/core/src/str/lossy.rs +++ b/library/core/src/str/lossy.rs @@ -147,12 +147,14 @@ impl fmt::Debug for Debug<'_> { /// An iterator used to decode a slice of mostly UTF-8 bytes to string slices /// ([`&str`]) and byte slices ([`&[u8]`][byteslice]). /// +/// This struct is created by the [`utf8_chunks`] method on bytes slices. /// If you want a simple conversion from UTF-8 byte slices to string slices, /// [`from_utf8`] is easier to use. /// /// See the [`Utf8Chunk`] type for documentation of the items yielded by this iterator. /// /// [byteslice]: slice +/// [`utf8_chunks`]: slice::utf8_chunks /// [`from_utf8`]: super::from_utf8 /// /// # Examples diff --git a/library/coretests/benches/ascii.rs b/library/coretests/benches/ascii.rs index 3fe45aa360bf..64bdc7fed118 100644 --- a/library/coretests/benches/ascii.rs +++ b/library/coretests/benches/ascii.rs @@ -354,7 +354,7 @@ static ASCII_CHARACTER_CLASS: [AsciiCharacterClass; 256] = [ ]; const ASCII_PATH: &[u8] = b"home/kyubey/rust/build/x86_64-unknown-linux-gnu/stage0/lib:/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0-tools/release/deps"; -const RUST_INCANTATION: &[u8] = br#"AR_x86_64_unknown_linux_gnu="ar" CARGO_INCREMENTAL="0" CARGO_PROFILE_RELEASE_DEBUG="1" CARGO_PROFILE_RELEASE_DEBUG_ASSERTIONS="false" CARGO_PROFILE_RELEASE_OVERFLOW_CHECKS="false" CARGO_TARGET_DIR="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0-std" CC_x86_64_unknown_linux_gnu="cc" CFG_COMPILER_HOST_TRIPLE="x86_64-unknown-linux-gnu" CFG_RELEASE_CHANNEL="dev" CFLAGS_x86_64_unknown_linux_gnu="-ffunction-sections -fdata-sections -fPIC -m64" CXXFLAGS_x86_64_unknown_linux_gnu="-ffunction-sections -fdata-sections -fPIC -m64" CXX_x86_64_unknown_linux_gnu="c++" LD_LIBRARY_PATH="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0-sysroot/lib/rustlib/x86_64-unknown-linux-gnu/lib" LIBC_CHECK_CFG="1" RANLIB_x86_64_unknown_linux_gnu="ar s" REAL_LIBRARY_PATH_VAR="LD_LIBRARY_PATH" RUSTBUILD_NATIVE_DIR="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/native" RUSTC="/home/kyubey/workspace/rust/build/bootstrap/debug/rustc" RUSTC_BOOTSTRAP="1" RUSTC_BREAK_ON_ICE="1" RUSTC_ERROR_METADATA_DST="/home/kyubey/workspace/rust/build/tmp/extended-error-metadata" RUSTC_FORCE_UNSTABLE="1" RUSTC_HOST_FUSE_LD_LLD="1" RUSTC_INSTALL_BINDIR="bin" RUSTC_LIBDIR="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0/lib" RUSTC_LINT_FLAGS="-Wrust_2018_idioms -Wunused_lifetimes -Wsemicolon_in_expressions_from_macros" RUSTC_REAL="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0/bin/rustc" RUSTC_SNAPSHOT="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0/bin/rustc" RUSTC_SNAPSHOT_LIBDIR="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0/lib" RUSTC_STAGE="0" RUSTC_SYSROOT="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0-sysroot" RUSTC_VERBOSE="0" RUSTDOC="/home/kyubey/workspace/rust/build/bootstrap/debug/rustdoc" RUSTDOCFLAGS="-C target-cpu=native --cfg=bootstrap -Csymbol-mangling-version=legacy -Zunstable-options -Zunstable-options --check-cfg=values(bootstrap) --check-cfg=values(stdarch_intel_sde) --check-cfg=values(no_fp_fmt_parse) --check-cfg=values(no_global_oom_handling) --check-cfg=values(no_rc) --check-cfg=values(no_sync) --check-cfg=values(freebsd12) --check-cfg=values(freebsd13) --check-cfg=values(backtrace_in_libstd) --check-cfg=values(target_env,\"libnx\") --check-cfg=values(target_arch,\"asmjs\",\"spirv\",\"nvptx\",\"xtensa\") -Clink-arg=-fuse-ld=lld -Clink-arg=-Wl,--threads=1 -Wrustdoc::invalid_codeblock_attributes --crate-version 1.72.0-dev -Zcrate-attr=doc(html_root_url=\"https://doc.rust-lang.org/nightly/\") -Zcrate-attr=warn(rust_2018_idioms)" RUSTDOC_FUSE_LD_LLD="1" RUSTDOC_LIBDIR="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0/lib" RUSTDOC_REAL="/path/to/nowhere/rustdoc/not/required" RUSTFLAGS="-C target-cpu=native --cfg=bootstrap -Csymbol-mangling-version=legacy -Zunstable-options -Zunstable-options --check-cfg=values(bootstrap) --check-cfg=values(stdarch_intel_sde) --check-cfg=values(no_fp_fmt_parse) --check-cfg=values(no_global_oom_handling) --check-cfg=values(no_rc) --check-cfg=values(no_sync) --check-cfg=values(freebsd12) --check-cfg=values(freebsd13) --check-cfg=values(backtrace_in_libstd) --check-cfg=values(target_env,\"libnx\") --check-cfg=values(target_arch,\"asmjs\",\"spirv\",\"nvptx\",\"xtensa\") -Zmacro-backtrace -Clink-args=-Wl,-z,origin -Clink-args=-Wl,-rpath,$ORIGIN/../lib -Clink-args=-fuse-ld=lld -Csplit-debuginfo=off -Cprefer-dynamic -Zinline-mir -Clto=off -Zcrate-attr=doc(html_root_url=\"https://doc.rust-lang.org/nightly/\")" RUST_COMPILER_RT_ROOT="/home/kyubey/workspace/rust/src/llvm-project/compiler-rt" RUST_TEST_THREADS="48" WINAPI_NO_BUNDLED_LIBRARIES="1" __CARGO_DEFAULT_LIB_METADATA="bootstrapstd" "/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0/bin/cargo" "bench" "--target" "x86_64-unknown-linux-gnu" "-Zcheck-cfg=names,values,output" "-Zbinary-dep-depinfo" "-j" "48" "--features" " panic-unwind backtrace compiler-builtins-c" "--manifest-path" "/home/kyubey/workspace/rust/library/sysroot/Cargo.toml" "-p" "core" "--" "bench_ascii_escape_display" "--quiet" "-Z" "unstable-options" "--format" "json""#; +const RUST_INCANTATION: &[u8] = br#"AR_x86_64_unknown_linux_gnu="ar" CARGO_INCREMENTAL="0" CARGO_PROFILE_RELEASE_DEBUG="1" CARGO_PROFILE_RELEASE_DEBUG_ASSERTIONS="false" CARGO_PROFILE_RELEASE_OVERFLOW_CHECKS="false" CARGO_TARGET_DIR="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0-std" CC_x86_64_unknown_linux_gnu="cc" CFG_COMPILER_HOST_TRIPLE="x86_64-unknown-linux-gnu" CFG_RELEASE_CHANNEL="dev" CFLAGS_x86_64_unknown_linux_gnu="-ffunction-sections -fdata-sections -fPIC -m64" CXXFLAGS_x86_64_unknown_linux_gnu="-ffunction-sections -fdata-sections -fPIC -m64" CXX_x86_64_unknown_linux_gnu="c++" LD_LIBRARY_PATH="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0-sysroot/lib/rustlib/x86_64-unknown-linux-gnu/lib" LIBC_CHECK_CFG="1" RANLIB_x86_64_unknown_linux_gnu="ar s" REAL_LIBRARY_PATH_VAR="LD_LIBRARY_PATH" RUSTBUILD_NATIVE_DIR="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/native" RUSTC="/home/kyubey/workspace/rust/build/bootstrap/debug/rustc" RUSTC_BOOTSTRAP="1" RUSTC_BREAK_ON_ICE="1" RUSTC_ERROR_METADATA_DST="/home/kyubey/workspace/rust/build/tmp/extended-error-metadata" RUSTC_FORCE_UNSTABLE="1" RUSTC_HOST_FUSE_LD_LLD="1" RUSTC_INSTALL_BINDIR="bin" RUSTC_LIBDIR="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0/lib" RUSTC_LINT_FLAGS="-Wrust_2018_idioms -Wunused_lifetimes -Wsemicolon_in_expressions_from_macros" RUSTC_REAL="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0/bin/rustc" RUSTC_SNAPSHOT="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0/bin/rustc" RUSTC_SNAPSHOT_LIBDIR="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0/lib" RUSTC_STAGE="0" RUSTC_SYSROOT="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0-sysroot" RUSTC_VERBOSE="0" RUSTDOC="/home/kyubey/workspace/rust/build/bootstrap/debug/rustdoc" RUSTDOCFLAGS="-C target-cpu=native --cfg=bootstrap -Csymbol-mangling-version=legacy -Zunstable-options -Zunstable-options --check-cfg=values(bootstrap) --check-cfg=values(no_fp_fmt_parse) --check-cfg=values(no_global_oom_handling) --check-cfg=values(no_rc) --check-cfg=values(no_sync) --check-cfg=values(freebsd12) --check-cfg=values(freebsd13) --check-cfg=values(backtrace_in_libstd) --check-cfg=values(target_env,\"libnx\") --check-cfg=values(target_arch,\"asmjs\",\"spirv\",\"nvptx\",\"xtensa\") -Clink-arg=-fuse-ld=lld -Clink-arg=-Wl,--threads=1 -Wrustdoc::invalid_codeblock_attributes --crate-version 1.72.0-dev -Zcrate-attr=doc(html_root_url=\"https://doc.rust-lang.org/nightly/\") -Zcrate-attr=warn(rust_2018_idioms)" RUSTDOC_FUSE_LD_LLD="1" RUSTDOC_LIBDIR="/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0/lib" RUSTDOC_REAL="/path/to/nowhere/rustdoc/not/required" RUSTFLAGS="-C target-cpu=native --cfg=bootstrap -Csymbol-mangling-version=legacy -Zunstable-options -Zunstable-options --check-cfg=values(bootstrap) --check-cfg=values(no_fp_fmt_parse) --check-cfg=values(no_global_oom_handling) --check-cfg=values(no_rc) --check-cfg=values(no_sync) --check-cfg=values(freebsd12) --check-cfg=values(freebsd13) --check-cfg=values(backtrace_in_libstd) --check-cfg=values(target_env,\"libnx\") --check-cfg=values(target_arch,\"asmjs\",\"spirv\",\"nvptx\",\"xtensa\") -Zmacro-backtrace -Clink-args=-Wl,-z,origin -Clink-args=-Wl,-rpath,$ORIGIN/../lib -Clink-args=-fuse-ld=lld -Csplit-debuginfo=off -Cprefer-dynamic -Zinline-mir -Clto=off -Zcrate-attr=doc(html_root_url=\"https://doc.rust-lang.org/nightly/\")" RUST_COMPILER_RT_ROOT="/home/kyubey/workspace/rust/src/llvm-project/compiler-rt" RUST_TEST_THREADS="48" WINAPI_NO_BUNDLED_LIBRARIES="1" __CARGO_DEFAULT_LIB_METADATA="bootstrapstd" "/home/kyubey/workspace/rust/build/x86_64-unknown-linux-gnu/stage0/bin/cargo" "bench" "--target" "x86_64-unknown-linux-gnu" "-Zcheck-cfg=names,values,output" "-Zbinary-dep-depinfo" "-j" "48" "--features" " panic-unwind backtrace compiler-builtins-c" "--manifest-path" "/home/kyubey/workspace/rust/library/sysroot/Cargo.toml" "-p" "core" "--" "bench_ascii_escape_display" "--quiet" "-Z" "unstable-options" "--format" "json""#; #[bench] fn bench_ascii_escape_display_no_escape(b: &mut Bencher) { diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index ef548971aafa..a71c4139308a 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -15,7 +15,6 @@ #![feature(char_max_len)] #![feature(clone_to_uninit)] #![feature(const_eval_select)] -#![feature(const_swap_nonoverlapping)] #![feature(const_trait_impl)] #![feature(core_intrinsics)] #![feature(core_intrinsics_fallbacks)] @@ -68,7 +67,6 @@ #![feature(pointer_is_aligned_to)] #![feature(portable_simd)] #![feature(ptr_metadata)] -#![feature(select_unpredictable)] #![feature(slice_from_ptr_range)] #![feature(slice_internals)] #![feature(slice_partition_dedup)] diff --git a/library/coretests/tests/ptr.rs b/library/coretests/tests/ptr.rs index 7d6e4eac1e21..bb60fb07468f 100644 --- a/library/coretests/tests/ptr.rs +++ b/library/coretests/tests/ptr.rs @@ -949,6 +949,10 @@ fn test_const_swap_ptr() { // Make sure they still work. assert!(*s1.0.ptr == 1); assert!(*s2.0.ptr == 666); + + // This is where we'd swap again using a `u8` type and a `count` of `size_of::()` if it + // were not for the limitation of `swap_nonoverlapping` around pointers crossing multiple + // elements. }; } diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index 36a1c57b0201..79e9b8430b8d 100644 --- a/library/proc_macro/src/lib.rs +++ b/library/proc_macro/src/lib.rs @@ -543,18 +543,18 @@ impl Span { /// The path to the source file in which this span occurs, for display purposes. /// /// This might not correspond to a valid file system path. - /// It might be remapped, or might be an artificial path such as `""`. - #[unstable(feature = "proc_macro_span", issue = "54725")] + /// It might be remapped (e.g. `"/src/lib.rs"`) or an artificial path (e.g. `""`). + #[stable(feature = "proc_macro_span_file", since = "CURRENT_RUSTC_VERSION")] pub fn file(&self) -> String { self.0.file() } - /// The path to the source file in which this span occurs on disk. + /// The path to the source file in which this span occurs on the local file system. /// /// This is the actual path on disk. It is unaffected by path remapping. /// /// This path should not be embedded in the output of the macro; prefer `file()` instead. - #[unstable(feature = "proc_macro_span", issue = "54725")] + #[stable(feature = "proc_macro_span_file", since = "CURRENT_RUSTC_VERSION")] pub fn local_file(&self) -> Option { self.0.local_file().map(|s| PathBuf::from(s)) } diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 940b671c5146..7915196e8e89 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -18,7 +18,7 @@ cfg-if = { version = "1.0", features = ['rustc-dep-of-std'] } panic_unwind = { path = "../panic_unwind", optional = true } panic_abort = { path = "../panic_abort" } core = { path = "../core", public = true } -compiler_builtins = { version = "=0.1.156" } +compiler_builtins = { version = "=0.1.158" } unwind = { path = "../unwind" } hashbrown = { version = "0.15", default-features = false, features = [ 'rustc-dep-of-std', @@ -57,7 +57,7 @@ object = { version = "0.36.0", default-features = false, optional = true, featur 'archive', ] } -[target.'cfg(windows)'.dependencies.windows-targets] +[target.'cfg(any(windows, target_os = "cygwin"))'.dependencies.windows-targets] path = "../windows_targets" [dev-dependencies] @@ -121,7 +121,6 @@ debug_typeid = ["core/debug_typeid"] # https://github.com/rust-lang/stdarch/blob/master/crates/std_detect/Cargo.toml std_detect_file_io = ["std_detect/std_detect_file_io"] std_detect_dlsym_getauxval = ["std_detect/std_detect_dlsym_getauxval"] -std_detect_env_override = ["std_detect/std_detect_env_override"] # Enable using raw-dylib for Windows imports. # This will eventually be the default. diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index 9ad26e5d28ec..961d6ee0665c 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -683,7 +683,7 @@ impl HashMap { /// ``` #[inline] #[rustc_lint_query_instability] - #[stable(feature = "hash_extract_if", since = "1.87.0")] + #[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")] pub fn extract_if(&mut self, pred: F) -> ExtractIf<'_, K, V, F> where F: FnMut(&K, &mut V) -> bool, @@ -1680,12 +1680,9 @@ impl<'a, K, V> Drain<'a, K, V> { /// ]); /// let iter = map.extract_if(|_k, v| *v % 2 == 0); /// ``` -#[stable(feature = "hash_extract_if", since = "1.87.0")] +#[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")] #[must_use = "iterators are lazy and do nothing unless consumed"] -pub struct ExtractIf<'a, K, V, F> -where - F: FnMut(&K, &mut V) -> bool, -{ +pub struct ExtractIf<'a, K, V, F> { base: base::ExtractIf<'a, K, V, F>, } @@ -2297,7 +2294,7 @@ where } } -#[stable(feature = "hash_extract_if", since = "1.87.0")] +#[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")] impl Iterator for ExtractIf<'_, K, V, F> where F: FnMut(&K, &mut V) -> bool, @@ -2314,13 +2311,14 @@ where } } -#[stable(feature = "hash_extract_if", since = "1.87.0")] +#[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")] impl FusedIterator for ExtractIf<'_, K, V, F> where F: FnMut(&K, &mut V) -> bool {} -#[stable(feature = "hash_extract_if", since = "1.87.0")] -impl<'a, K, V, F> fmt::Debug for ExtractIf<'a, K, V, F> +#[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")] +impl fmt::Debug for ExtractIf<'_, K, V, F> where - F: FnMut(&K, &mut V) -> bool, + K: fmt::Debug, + V: fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("ExtractIf").finish_non_exhaustive() diff --git a/library/std/src/collections/hash/set.rs b/library/std/src/collections/hash/set.rs index 7be000594bc5..fa2f4f0a58fe 100644 --- a/library/std/src/collections/hash/set.rs +++ b/library/std/src/collections/hash/set.rs @@ -308,7 +308,7 @@ impl HashSet { /// ``` #[inline] #[rustc_lint_query_instability] - #[stable(feature = "hash_extract_if", since = "1.87.0")] + #[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")] pub fn extract_if(&mut self, pred: F) -> ExtractIf<'_, T, F> where F: FnMut(&T) -> bool, @@ -1390,11 +1390,8 @@ pub struct Drain<'a, K: 'a> { /// /// let mut extract_ifed = a.extract_if(|v| v % 2 == 0); /// ``` -#[stable(feature = "hash_extract_if", since = "1.87.0")] -pub struct ExtractIf<'a, K, F> -where - F: FnMut(&K) -> bool, -{ +#[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")] +pub struct ExtractIf<'a, K, F> { base: base::ExtractIf<'a, K, F>, } @@ -1673,7 +1670,7 @@ impl fmt::Debug for Drain<'_, K> { } } -#[stable(feature = "hash_extract_if", since = "1.87.0")] +#[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")] impl Iterator for ExtractIf<'_, K, F> where F: FnMut(&K) -> bool, @@ -1690,13 +1687,13 @@ where } } -#[stable(feature = "hash_extract_if", since = "1.87.0")] +#[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")] impl FusedIterator for ExtractIf<'_, K, F> where F: FnMut(&K) -> bool {} -#[stable(feature = "hash_extract_if", since = "1.87.0")] -impl<'a, K, F> fmt::Debug for ExtractIf<'a, K, F> +#[stable(feature = "hash_extract_if", since = "CURRENT_RUSTC_VERSION")] +impl fmt::Debug for ExtractIf<'_, K, F> where - F: FnMut(&K) -> bool, + K: fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("ExtractIf").finish_non_exhaustive() diff --git a/library/std/src/env.rs b/library/std/src/env.rs index 1593969e114a..ce2dc7952207 100644 --- a/library/std/src/env.rs +++ b/library/std/src/env.rs @@ -12,9 +12,11 @@ use crate::error::Error; use crate::ffi::{OsStr, OsString}; +use crate::num::NonZero; +use crate::ops::Try; use crate::path::{Path, PathBuf}; use crate::sys::{env as env_imp, os as os_imp}; -use crate::{fmt, io, sys}; +use crate::{array, fmt, io, sys}; /// Returns the current working directory as a [`PathBuf`]. /// @@ -872,19 +874,36 @@ impl !Sync for Args {} #[stable(feature = "env", since = "1.0.0")] impl Iterator for Args { type Item = String; + fn next(&mut self) -> Option { self.inner.next().map(|s| s.into_string().unwrap()) } + + #[inline] fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } + + // Methods which skip args cannot simply delegate to the inner iterator, + // because `env::args` states that we will "panic during iteration if any + // argument to the process is not valid Unicode". + // + // This offers two possible interpretations: + // - a skipped argument is never encountered "during iteration" + // - even a skipped argument is encountered "during iteration" + // + // As a panic can be observed, we err towards validating even skipped + // arguments for now, though this is not explicitly promised by the API. } #[stable(feature = "env", since = "1.0.0")] impl ExactSizeIterator for Args { + #[inline] fn len(&self) -> usize { self.inner.len() } + + #[inline] fn is_empty(&self) -> bool { self.inner.is_empty() } @@ -914,19 +933,65 @@ impl !Sync for ArgsOs {} #[stable(feature = "env", since = "1.0.0")] impl Iterator for ArgsOs { type Item = OsString; + + #[inline] fn next(&mut self) -> Option { self.inner.next() } + + #[inline] + fn next_chunk( + &mut self, + ) -> Result<[OsString; N], array::IntoIter> { + self.inner.next_chunk() + } + + #[inline] fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } + + #[inline] + fn count(self) -> usize { + self.inner.len() + } + + #[inline] + fn last(self) -> Option { + self.inner.last() + } + + #[inline] + fn advance_by(&mut self, n: usize) -> Result<(), NonZero> { + self.inner.advance_by(n) + } + + #[inline] + fn try_fold(&mut self, init: B, f: F) -> R + where + F: FnMut(B, Self::Item) -> R, + R: Try, + { + self.inner.try_fold(init, f) + } + + #[inline] + fn fold(self, init: B, f: F) -> B + where + F: FnMut(B, Self::Item) -> B, + { + self.inner.fold(init, f) + } } #[stable(feature = "env", since = "1.0.0")] impl ExactSizeIterator for ArgsOs { + #[inline] fn len(&self) -> usize { self.inner.len() } + + #[inline] fn is_empty(&self) -> bool { self.inner.is_empty() } @@ -934,9 +999,15 @@ impl ExactSizeIterator for ArgsOs { #[stable(feature = "env_iterators", since = "1.12.0")] impl DoubleEndedIterator for ArgsOs { + #[inline] fn next_back(&mut self) -> Option { self.inner.next_back() } + + #[inline] + fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero> { + self.inner.advance_back_by(n) + } } #[stable(feature = "std_debug", since = "1.16.0")] diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index ce01175309a7..72bdf03ee61a 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -582,15 +582,25 @@ impl OsString { #[unstable(feature = "os_string_truncate", issue = "133262")] pub fn truncate(&mut self, len: usize) { self.as_os_str().inner.check_public_boundary(len); - self.inner.truncate(len); + // SAFETY: The length was just checked to be at a valid boundary. + unsafe { self.inner.truncate_unchecked(len) }; } - /// Provides plumbing to core `Vec::extend_from_slice`. - /// More well behaving alternative to allowing outer types - /// full mutable access to the core `Vec`. + /// Provides plumbing to `Vec::extend_from_slice` without giving full + /// mutable access to the `Vec`. + /// + /// # Safety + /// + /// The slice must be valid for the platform encoding (as described in + /// [`OsStr::from_encoded_bytes_unchecked`]). + /// + /// This bypasses the encoding-dependent surrogate joining, so `self` must + /// not end with a leading surrogate half and `other` must not start with + /// with a trailing surrogate half. #[inline] - pub(crate) fn extend_from_slice(&mut self, other: &[u8]) { - self.inner.extend_from_slice(other); + pub(crate) unsafe fn extend_from_slice_unchecked(&mut self, other: &[u8]) { + // SAFETY: Guaranteed by caller. + unsafe { self.inner.extend_from_slice_unchecked(other) }; } } diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index 3340a5dc23da..11f439b9996d 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -21,7 +21,6 @@ mod tests; use crate::ffi::OsString; -use crate::fmt; use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write}; use crate::path::{Path, PathBuf}; use crate::sealed::Sealed; @@ -29,6 +28,7 @@ use crate::sync::Arc; use crate::sys::fs as fs_imp; use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; use crate::time::SystemTime; +use crate::{error, fmt}; /// An object providing access to an open file on the filesystem. /// @@ -116,6 +116,22 @@ pub struct File { inner: fs_imp::File, } +/// An enumeration of possible errors which can occur while trying to acquire a lock +/// from the [`try_lock`] method and [`try_lock_shared`] method on a [`File`]. +/// +/// [`try_lock`]: File::try_lock +/// [`try_lock_shared`]: File::try_lock_shared +#[unstable(feature = "file_lock", issue = "130994")] +pub enum TryLockError { + /// The lock could not be acquired due to an I/O error on the file. The standard library will + /// not return an [`ErrorKind::WouldBlock`] error inside [`TryLockError::Error`] + /// + /// [`ErrorKind::WouldBlock`]: io::ErrorKind::WouldBlock + Error(io::Error), + /// The lock could not be acquired at this time because it is held by another handle/process. + WouldBlock, +} + /// Metadata information about a file. /// /// This structure is returned from the [`metadata`] or @@ -352,6 +368,30 @@ pub fn write, C: AsRef<[u8]>>(path: P, contents: C) -> io::Result inner(path.as_ref(), contents.as_ref()) } +#[unstable(feature = "file_lock", issue = "130994")] +impl error::Error for TryLockError {} + +#[unstable(feature = "file_lock", issue = "130994")] +impl fmt::Debug for TryLockError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + TryLockError::Error(err) => err.fmt(f), + TryLockError::WouldBlock => "WouldBlock".fmt(f), + } + } +} + +#[unstable(feature = "file_lock", issue = "130994")] +impl fmt::Display for TryLockError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + TryLockError::Error(_) => "lock acquisition failed due to I/O error", + TryLockError::WouldBlock => "lock acquisition failed because the operation would block", + } + .fmt(f) + } +} + impl File { /// Attempts to open a file in read-only mode. /// @@ -734,8 +774,8 @@ impl File { /// Try to acquire an exclusive lock on the file. /// - /// Returns `Ok(false)` if a different lock is already held on this file (via another - /// handle/descriptor). + /// Returns `Err(TryLockError::WouldBlock)` if a different lock is already held on this file + /// (via another handle/descriptor). /// /// This acquires an exclusive lock; no other file handle to this file may acquire another lock. /// @@ -777,23 +817,27 @@ impl File { /// /// ```no_run /// #![feature(file_lock)] - /// use std::fs::File; + /// use std::fs::{File, TryLockError}; /// /// fn main() -> std::io::Result<()> { /// let f = File::create("foo.txt")?; - /// f.try_lock()?; + /// match f.try_lock() { + /// Ok(_) => (), + /// Err(TryLockError::WouldBlock) => (), // Lock not acquired + /// Err(TryLockError::Error(err)) => return Err(err), + /// } /// Ok(()) /// } /// ``` #[unstable(feature = "file_lock", issue = "130994")] - pub fn try_lock(&self) -> io::Result { + pub fn try_lock(&self) -> Result<(), TryLockError> { self.inner.try_lock() } /// Try to acquire a shared (non-exclusive) lock on the file. /// - /// Returns `Ok(false)` if an exclusive lock is already held on this file (via another - /// handle/descriptor). + /// Returns `Err(TryLockError::WouldBlock)` if a different lock is already held on this file + /// (via another handle/descriptor). /// /// This acquires a shared lock; more than one file handle may hold a shared lock, but none may /// hold an exclusive lock at the same time. @@ -834,16 +878,21 @@ impl File { /// /// ```no_run /// #![feature(file_lock)] - /// use std::fs::File; + /// use std::fs::{File, TryLockError}; /// /// fn main() -> std::io::Result<()> { /// let f = File::open("foo.txt")?; - /// f.try_lock_shared()?; + /// match f.try_lock_shared() { + /// Ok(_) => (), + /// Err(TryLockError::WouldBlock) => (), // Lock not acquired + /// Err(TryLockError::Error(err)) => return Err(err), + /// } + /// /// Ok(()) /// } /// ``` #[unstable(feature = "file_lock", issue = "130994")] - pub fn try_lock_shared(&self) -> io::Result { + pub fn try_lock_shared(&self) -> Result<(), TryLockError> { self.inner.try_lock_shared() } @@ -2874,6 +2923,8 @@ pub fn remove_dir>(path: P) -> io::Result<()> { /// /// Consider ignoring the error if validating the removal is not required for your use case. /// +/// This function may return [`io::ErrorKind::DirectoryNotEmpty`] if the directory is concurrently +/// written into, which typically indicates some contents were removed but not all. /// [`io::ErrorKind::NotFound`] is only returned if no removal occurs. /// /// [`fs::remove_file`]: remove_file @@ -2992,7 +3043,7 @@ pub fn read_dir>(path: P) -> io::Result { /// When possible, permissions should be set at creation time instead. /// /// # Rationale -/// POSIX does not specify an `lchown` function, +/// POSIX does not specify an `lchmod` function, /// and symlinks can be followed regardless of what permission bits are set. /// /// # Errors diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs index 4712e58980cc..46b0d832fec4 100644 --- a/library/std/src/fs/tests.rs +++ b/library/std/src/fs/tests.rs @@ -1,6 +1,22 @@ use rand::RngCore; +#[cfg(any( + windows, + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_vendor = "apple", +))] +use crate::assert_matches::assert_matches; use crate::char::MAX_LEN_UTF8; +#[cfg(any( + windows, + target_os = "freebsd", + target_os = "linux", + target_os = "netbsd", + target_vendor = "apple", +))] +use crate::fs::TryLockError; use crate::fs::{self, File, FileTimes, OpenOptions}; use crate::io::prelude::*; use crate::io::{BorrowedBuf, ErrorKind, SeekFrom}; @@ -223,8 +239,8 @@ fn file_lock_multiple_shared() { check!(f2.lock_shared()); check!(f1.unlock()); check!(f2.unlock()); - assert!(check!(f1.try_lock_shared())); - assert!(check!(f2.try_lock_shared())); + check!(f1.try_lock_shared()); + check!(f2.try_lock_shared()); } #[test] @@ -243,12 +259,12 @@ fn file_lock_blocking() { // Check that shared locks block exclusive locks check!(f1.lock_shared()); - assert!(!check!(f2.try_lock())); + assert_matches!(f2.try_lock(), Err(TryLockError::WouldBlock)); check!(f1.unlock()); // Check that exclusive locks block shared locks check!(f1.lock()); - assert!(!check!(f2.try_lock_shared())); + assert_matches!(f2.try_lock_shared(), Err(TryLockError::WouldBlock)); } #[test] @@ -267,9 +283,9 @@ fn file_lock_drop() { // Check that locks are released when the File is dropped check!(f1.lock_shared()); - assert!(!check!(f2.try_lock())); + assert_matches!(f2.try_lock(), Err(TryLockError::WouldBlock)); drop(f1); - assert!(check!(f2.try_lock())); + check!(f2.try_lock()); } #[test] @@ -288,10 +304,10 @@ fn file_lock_dup() { // Check that locks are not dropped if the File has been cloned check!(f1.lock_shared()); - assert!(!check!(f2.try_lock())); + assert_matches!(f2.try_lock(), Err(TryLockError::WouldBlock)); let cloned = check!(f1.try_clone()); drop(f1); - assert!(!check!(f2.try_lock())); + assert_matches!(f2.try_lock(), Err(TryLockError::WouldBlock)); drop(cloned) } @@ -307,9 +323,9 @@ fn file_lock_double_unlock() { // Check that both are released by unlock() check!(f1.lock()); check!(f1.lock_shared()); - assert!(!check!(f2.try_lock())); + assert_matches!(f2.try_lock(), Err(TryLockError::WouldBlock)); check!(f1.unlock()); - assert!(check!(f2.try_lock())); + check!(f2.try_lock()); } #[test] diff --git a/library/std/src/io/pipe.rs b/library/std/src/io/pipe.rs index c6b7b49a351e..47243806cd2d 100644 --- a/library/std/src/io/pipe.rs +++ b/library/std/src/io/pipe.rs @@ -2,7 +2,7 @@ use crate::io; use crate::sys::anonymous_pipe::{AnonPipe, pipe as pipe_inner}; use crate::sys_common::{FromInner, IntoInner}; -/// Create an anonymous pipe. +/// Creates an anonymous pipe. /// /// # Behavior /// @@ -108,7 +108,7 @@ impl IntoInner for PipeWriter { } impl PipeReader { - /// Create a new [`PipeReader`] instance that shares the same underlying file description. + /// Creates a new [`PipeReader`] instance that shares the same underlying file description. /// /// # Examples /// @@ -167,7 +167,7 @@ impl PipeReader { } impl PipeWriter { - /// Create a new [`PipeWriter`] instance that shares the same underlying file description. + /// Creates a new [`PipeWriter`] instance that shares the same underlying file description. /// /// # Examples /// diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs index c9595b051e20..79b25040ef60 100644 --- a/library/std/src/keyword_docs.rs +++ b/library/std/src/keyword_docs.rs @@ -91,7 +91,7 @@ mod as_keyword {} /// /// When associated with `loop`, a break expression may be used to return a value from that loop. /// This is only valid with `loop` and not with any other type of loop. -/// If no value is specified, `break;` returns `()`. +/// If no value is specified for `break;` it returns `()`. /// Every `break` within a loop must return the same type. /// /// ```rust @@ -109,6 +109,33 @@ mod as_keyword {} /// println!("{result}"); /// ``` /// +/// It is also possible to exit from any *labelled* block returning the value early. +/// If no value is specified for `break;` it returns `()`. +/// +/// ```rust +/// let inputs = vec!["Cow", "Cat", "Dog", "Snake", "Cod"]; +/// +/// let mut results = vec![]; +/// for input in inputs { +/// let result = 'filter: { +/// if input.len() > 3 { +/// break 'filter Err("Too long"); +/// }; +/// +/// if !input.contains("C") { +/// break 'filter Err("No Cs"); +/// }; +/// +/// Ok(input.to_uppercase()) +/// }; +/// +/// results.push(result); +/// } +/// +/// // [Ok("COW"), Ok("CAT"), Err("No Cs"), Err("Too long"), Ok("COD")] +/// println!("{:?}", results) +/// ``` +/// /// For more details consult the [Reference on "break expression"] and the [Reference on "break and /// loop values"]. /// @@ -1206,6 +1233,28 @@ mod ref_keyword {} /// Ok(()) /// } /// ``` +/// +/// Within [closures] and [`async`] blocks, `return` returns a value from within the closure or +/// `async` block, not from the parent function: +/// +/// ```rust +/// fn foo() -> i32 { +/// let closure = || { +/// return 5; +/// }; +/// +/// let future = async { +/// return 10; +/// }; +/// +/// return 15; +/// } +/// +/// assert_eq!(foo(), 15); +/// ``` +/// +/// [closures]: ../book/ch13-01-closures.html +/// [`async`]: ../std/keyword.async.html mod return_keyword {} #[doc(keyword = "self")] @@ -2399,6 +2448,39 @@ mod while_keyword {} /// /// We have written an [async book] detailing `async`/`await` and trade-offs compared to using threads. /// +/// ## Control Flow +/// [`return`] statements and [`?`][try operator] operators within `async` blocks do not cause +/// a return from the parent function; rather, they cause the `Future` returned by the block to +/// return with that value. +/// +/// For example, the following Rust function will return `5`, causing `x` to take the [`!` type][never type]: +/// ```rust +/// #[expect(unused_variables)] +/// fn example() -> i32 { +/// let x = { +/// return 5; +/// }; +/// } +/// ``` +/// In contrast, the following asynchronous function assigns a `Future` to `x`, and +/// only returns `5` when `x` is `.await`ed: +/// ```rust +/// async fn example() -> i32 { +/// let x = async { +/// return 5; +/// }; +/// +/// x.await +/// } +/// ``` +/// Code using `?` behaves similarly - it causes the `async` block to return a [`Result`] without +/// affecting the parent function. +/// +/// Note that you cannot use `break` or `continue` from within an `async` block to affect the +/// control flow of a loop in the parent function. +/// +/// Control flow in `async` blocks is documented further in the [async book][async book blocks]. +/// /// ## Editions /// /// `async` is a keyword from the 2018 edition onwards. @@ -2408,6 +2490,11 @@ mod while_keyword {} /// [`Future`]: future::Future /// [`.await`]: ../std/keyword.await.html /// [async book]: https://rust-lang.github.io/async-book/ +/// [`return`]: ../std/keyword.return.html +/// [try operator]: ../reference/expressions/operator-expr.html#r-expr.try +/// [never type]: ../reference/types/never.html +/// [`Result`]: result::Result +/// [async book blocks]: https://rust-lang.github.io/async-book/part-guide/more-async-await.html#async-blocks mod async_keyword {} #[doc(keyword = "await")] diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index ba57ad9bae32..c011f9661ae7 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -301,6 +301,8 @@ #![feature(formatting_options)] #![feature(if_let_guard)] #![feature(intra_doc_pointers)] +#![feature(iter_advance_by)] +#![feature(iter_next_chunk)] #![feature(lang_items)] #![feature(let_chains)] #![feature(link_cfg)] @@ -321,6 +323,7 @@ #![feature(strict_provenance_lints)] #![feature(thread_local)] #![feature(try_blocks)] +#![feature(try_trait_v2)] #![feature(type_alias_impl_trait)] // tidy-alphabetical-end // diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 7cd20c48d893..1a4a7aa7448c 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -1529,11 +1529,13 @@ impl PathBuf { self.inner.truncate(end_file_stem.wrapping_sub(start)); // add the new extension, if any - let new = extension; + let new = extension.as_encoded_bytes(); if !new.is_empty() { self.inner.reserve_exact(new.len() + 1); - self.inner.push(OsStr::new(".")); - self.inner.push(new); + self.inner.push("."); + // SAFETY: Since a UTF-8 string was just pushed, it is not possible + // for the buffer to end with a surrogate half. + unsafe { self.inner.extend_from_slice_unchecked(new) }; } true @@ -1597,7 +1599,7 @@ impl PathBuf { Some(f) => f.as_encoded_bytes(), }; - let new = extension; + let new = extension.as_encoded_bytes(); if !new.is_empty() { // truncate until right after the file name // this is necessary for trimming the trailing slash @@ -1607,8 +1609,10 @@ impl PathBuf { // append the new extension self.inner.reserve_exact(new.len() + 1); - self.inner.push(OsStr::new(".")); - self.inner.push(new); + self.inner.push("."); + // SAFETY: Since a UTF-8 string was just pushed, it is not possible + // for the buffer to end with a surrogate half. + unsafe { self.inner.extend_from_slice_unchecked(new) }; } true @@ -2769,7 +2773,8 @@ impl Path { }; let mut new_path = PathBuf::with_capacity(new_capacity); - new_path.inner.extend_from_slice(slice_to_copy); + // SAFETY: The path is empty, so cannot have surrogate halves. + unsafe { new_path.inner.extend_from_slice_unchecked(slice_to_copy) }; new_path.set_extension(extension); new_path } diff --git a/library/std/src/process.rs b/library/std/src/process.rs index 76ce7bce81b1..df6b9a6e563c 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -168,8 +168,6 @@ use crate::num::NonZero; use crate::path::Path; use crate::sys::pipe::{AnonPipe, read2}; use crate::sys::process as imp; -#[stable(feature = "command_access", since = "1.57.0")] -pub use crate::sys_common::process::CommandEnvs; use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; use crate::{fmt, fs, str}; @@ -1073,7 +1071,7 @@ impl Command { /// ``` #[stable(feature = "process", since = "1.0.0")] pub fn output(&mut self) -> io::Result { - let (status, stdout, stderr) = self.inner.output()?; + let (status, stdout, stderr) = imp::output(&mut self.inner)?; Ok(Output { status: ExitStatus(status), stdout, stderr }) } @@ -1174,7 +1172,7 @@ impl Command { /// ``` #[stable(feature = "command_access", since = "1.57.0")] pub fn get_envs(&self) -> CommandEnvs<'_> { - self.inner.get_envs() + CommandEnvs { iter: self.inner.get_envs() } } /// Returns the working directory for the child process. @@ -1264,6 +1262,48 @@ impl<'a> ExactSizeIterator for CommandArgs<'a> { } } +/// An iterator over the command environment variables. +/// +/// This struct is created by +/// [`Command::get_envs`][crate::process::Command::get_envs]. See its +/// documentation for more. +#[must_use = "iterators are lazy and do nothing unless consumed"] +#[stable(feature = "command_access", since = "1.57.0")] +pub struct CommandEnvs<'a> { + iter: imp::CommandEnvs<'a>, +} + +#[stable(feature = "command_access", since = "1.57.0")] +impl<'a> Iterator for CommandEnvs<'a> { + type Item = (&'a OsStr, Option<&'a OsStr>); + + fn next(&mut self) -> Option { + self.iter.next() + } + + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + +#[stable(feature = "command_access", since = "1.57.0")] +impl<'a> ExactSizeIterator for CommandEnvs<'a> { + fn len(&self) -> usize { + self.iter.len() + } + + fn is_empty(&self) -> bool { + self.iter.is_empty() + } +} + +#[stable(feature = "command_access", since = "1.57.0")] +impl<'a> fmt::Debug for CommandEnvs<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.iter.fmt(f) + } +} + /// The output of a finished process. /// /// This is returned in a Result by either the [`output`] method of a diff --git a/library/std/src/sync/poison/mutex.rs b/library/std/src/sync/poison/mutex.rs index adb74bb6f3de..1c29c619edc3 100644 --- a/library/std/src/sync/poison/mutex.rs +++ b/library/std/src/sync/poison/mutex.rs @@ -253,11 +253,11 @@ unsafe impl Sync for MutexGuard<'_, T> {} /// The data protected by the mutex can be accessed through this guard via its /// [`Deref`] and [`DerefMut`] implementations. /// -/// This structure is created by the [`map`] and [`try_map`] methods on +/// This structure is created by the [`map`] and [`filter_map`] methods on /// [`MutexGuard`]. /// /// [`map`]: MutexGuard::map -/// [`try_map`]: MutexGuard::try_map +/// [`filter_map`]: MutexGuard::filter_map /// [`Condvar`]: crate::sync::Condvar #[must_use = "if unused the Mutex will immediately unlock"] #[must_not_suspend = "holding a MappedMutexGuard across suspend \ @@ -718,7 +718,7 @@ impl<'a, T: ?Sized> MutexGuard<'a, T> { U: ?Sized, { // SAFETY: the conditions of `MutexGuard::new` were satisfied when the original guard - // was created, and have been upheld throughout `map` and/or `try_map`. + // 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() })); @@ -739,17 +739,16 @@ impl<'a, T: ?Sized> MutexGuard<'a, T> { /// The `Mutex` is already locked, so this cannot fail. /// /// This is an associated function that needs to be used as - /// `MutexGuard::try_map(...)`. A method would interfere with methods of the + /// `MutexGuard::filter_map(...)`. A method would interfere with methods of the /// same name on the contents of the `MutexGuard` used through `Deref`. - #[doc(alias = "filter_map")] #[unstable(feature = "mapped_lock_guards", issue = "117108")] - pub fn try_map(orig: Self, f: F) -> Result, Self> + pub fn filter_map(orig: Self, f: F) -> Result, Self> where F: FnOnce(&mut T) -> Option<&mut U>, U: ?Sized, { // SAFETY: the conditions of `MutexGuard::new` were satisfied when the original guard - // was created, and have been upheld throughout `map` and/or `try_map`. + // 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() }) { @@ -826,7 +825,7 @@ impl<'a, T: ?Sized> MappedMutexGuard<'a, T> { U: ?Sized, { // SAFETY: the conditions of `MutexGuard::new` were satisfied when the original guard - // was created, and have been upheld throughout `map` and/or `try_map`. + // 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() })); @@ -847,17 +846,16 @@ impl<'a, T: ?Sized> MappedMutexGuard<'a, T> { /// The `Mutex` is already locked, so this cannot fail. /// /// This is an associated function that needs to be used as - /// `MappedMutexGuard::try_map(...)`. A method would interfere with methods of the + /// `MappedMutexGuard::filter_map(...)`. A method would interfere with methods of the /// same name on the contents of the `MutexGuard` used through `Deref`. - #[doc(alias = "filter_map")] #[unstable(feature = "mapped_lock_guards", issue = "117108")] - pub fn try_map(mut orig: Self, f: F) -> Result, Self> + pub fn filter_map(mut orig: Self, f: F) -> Result, Self> where F: FnOnce(&mut T) -> Option<&mut U>, U: ?Sized, { // SAFETY: the conditions of `MutexGuard::new` were satisfied when the original guard - // was created, and have been upheld throughout `map` and/or `try_map`. + // 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() }) { diff --git a/library/std/src/sync/poison/rwlock.rs b/library/std/src/sync/poison/rwlock.rs index a2abd4f692ec..6976c0a64e23 100644 --- a/library/std/src/sync/poison/rwlock.rs +++ b/library/std/src/sync/poison/rwlock.rs @@ -147,11 +147,11 @@ unsafe impl 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 [`try_map`] methods +/// This structure is created by the [`map`] and [`filter_map`] methods /// on [`RwLockReadGuard`]. /// /// [`map`]: RwLockReadGuard::map -/// [`try_map`]: RwLockReadGuard::try_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, \ @@ -176,11 +176,11 @@ unsafe impl 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 [`try_map`] methods +/// This structure is created by the [`map`] and [`filter_map`] methods /// on [`RwLockWriteGuard`]. /// /// [`map`]: RwLockWriteGuard::map -/// [`try_map`]: RwLockWriteGuard::try_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, \ @@ -788,7 +788,7 @@ impl Deref for MappedRwLockReadGuard<'_, 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 `try_map`. + // was created, and have been upheld throughout `map` and/or `filter_map`. unsafe { self.data.as_ref() } } } @@ -799,7 +799,7 @@ impl Deref for MappedRwLockWriteGuard<'_, 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 `try_map`. + // was created, and have been upheld throughout `map` and/or `filter_map`. unsafe { self.data.as_ref() } } } @@ -808,7 +808,7 @@ impl Deref for MappedRwLockWriteGuard<'_, T> { impl 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 `try_map`. + // was created, and have been upheld throughout `map` and/or `filter_map`. unsafe { self.data.as_mut() } } } @@ -838,7 +838,7 @@ impl Drop for RwLockWriteGuard<'_, T> { impl 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 `try_map`. + // was created, and have been upheld throughout `map` and/or `filter_map`. unsafe { self.inner_lock.read_unlock(); } @@ -850,7 +850,7 @@ impl 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 `try_map`. + // was created, and have been upheld throughout `map` and/or `filter_map`. unsafe { self.inner_lock.write_unlock(); } @@ -878,7 +878,7 @@ impl<'a, T: ?Sized> RwLockReadGuard<'a, T> { U: ?Sized, { // SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when the original guard - // was created, and have been upheld throughout `map` and/or `try_map`. + // 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() })); @@ -893,22 +893,21 @@ impl<'a, T: ?Sized> RwLockReadGuard<'a, T> { /// The `RwLock` is already locked for reading, so this cannot fail. /// /// This is an associated function that needs to be used as - /// `RwLockReadGuard::try_map(...)`. A method would interfere with methods + /// `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) and the RwLock will not be poisoned. - #[doc(alias = "filter_map")] #[unstable(feature = "mapped_lock_guards", issue = "117108")] - pub fn try_map(orig: Self, f: F) -> Result, Self> + pub fn filter_map(orig: Self, f: F) -> Result, 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 `try_map`. + // 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() }) { @@ -943,7 +942,7 @@ impl<'a, T: ?Sized> MappedRwLockReadGuard<'a, T> { U: ?Sized, { // SAFETY: the conditions of `RwLockReadGuard::new` were satisfied when the original guard - // was created, and have been upheld throughout `map` and/or `try_map`. + // 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() })); @@ -958,22 +957,21 @@ impl<'a, T: ?Sized> MappedRwLockReadGuard<'a, T> { /// The `RwLock` is already locked for reading, so this cannot fail. /// /// This is an associated function that needs to be used as - /// `MappedRwLockReadGuard::try_map(...)`. A method would interfere with + /// `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) and the RwLock will not be poisoned. - #[doc(alias = "filter_map")] #[unstable(feature = "mapped_lock_guards", issue = "117108")] - pub fn try_map(orig: Self, f: F) -> Result, Self> + pub fn filter_map(orig: Self, f: F) -> Result, 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 `try_map`. + // 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() }) { @@ -1008,7 +1006,7 @@ impl<'a, T: ?Sized> RwLockWriteGuard<'a, T> { U: ?Sized, { // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when the original guard - // was created, and have been upheld throughout `map` and/or `try_map`. + // 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() })); @@ -1029,22 +1027,21 @@ impl<'a, T: ?Sized> RwLockWriteGuard<'a, T> { /// The `RwLock` is already locked for writing, so this cannot fail. /// /// This is an associated function that needs to be used as - /// `RwLockWriteGuard::try_map(...)`. A method would interfere with methods + /// `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) and the RwLock will be poisoned. - #[doc(alias = "filter_map")] #[unstable(feature = "mapped_lock_guards", issue = "117108")] - pub fn try_map(orig: Self, f: F) -> Result, Self> + pub fn filter_map(orig: Self, f: F) -> Result, 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 `try_map`. + // 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() }) { @@ -1147,7 +1144,7 @@ impl<'a, T: ?Sized> MappedRwLockWriteGuard<'a, T> { U: ?Sized, { // SAFETY: the conditions of `RwLockWriteGuard::new` were satisfied when the original guard - // was created, and have been upheld throughout `map` and/or `try_map`. + // 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() })); @@ -1168,22 +1165,21 @@ impl<'a, T: ?Sized> MappedRwLockWriteGuard<'a, T> { /// The `RwLock` is already locked for writing, so this cannot fail. /// /// This is an associated function that needs to be used as - /// `MappedRwLockWriteGuard::try_map(...)`. A method would interfere with + /// `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) and the RwLock will be poisoned. - #[doc(alias = "filter_map")] #[unstable(feature = "mapped_lock_guards", issue = "117108")] - pub fn try_map(mut orig: Self, f: F) -> Result, Self> + pub fn filter_map(mut orig: Self, f: F) -> Result, 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 `try_map`. + // 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() }) { diff --git a/library/std/src/sys/args/common.rs b/library/std/src/sys/args/common.rs index 43ac5e959234..e787105a05a7 100644 --- a/library/std/src/sys/args/common.rs +++ b/library/std/src/sys/args/common.rs @@ -1,5 +1,7 @@ use crate::ffi::OsString; -use crate::{fmt, vec}; +use crate::num::NonZero; +use crate::ops::Try; +use crate::{array, fmt, vec}; pub struct Args { iter: vec::IntoIter, @@ -9,6 +11,7 @@ impl !Send for Args {} impl !Sync for Args {} impl Args { + #[inline] pub(super) fn new(args: Vec) -> Self { Args { iter: args.into_iter() } } @@ -22,22 +25,77 @@ impl fmt::Debug for Args { impl Iterator for Args { type Item = OsString; + + #[inline] fn next(&mut self) -> Option { self.iter.next() } + + #[inline] + fn next_chunk( + &mut self, + ) -> Result<[OsString; N], array::IntoIter> { + self.iter.next_chunk() + } + + #[inline] fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } -} -impl ExactSizeIterator for Args { - fn len(&self) -> usize { + #[inline] + fn count(self) -> usize { self.iter.len() } + + #[inline] + fn last(self) -> Option { + self.iter.last() + } + + #[inline] + fn advance_by(&mut self, n: usize) -> Result<(), NonZero> { + self.iter.advance_by(n) + } + + #[inline] + fn try_fold(&mut self, init: B, f: F) -> R + where + F: FnMut(B, Self::Item) -> R, + R: Try, + { + self.iter.try_fold(init, f) + } + + #[inline] + fn fold(self, init: B, f: F) -> B + where + F: FnMut(B, Self::Item) -> B, + { + self.iter.fold(init, f) + } } impl DoubleEndedIterator for Args { + #[inline] fn next_back(&mut self) -> Option { self.iter.next_back() } + + #[inline] + fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero> { + self.iter.advance_back_by(n) + } +} + +impl ExactSizeIterator for Args { + #[inline] + fn len(&self) -> usize { + self.iter.len() + } + + #[inline] + fn is_empty(&self) -> bool { + self.iter.is_empty() + } } diff --git a/library/std/src/sys/args/sgx.rs b/library/std/src/sys/args/sgx.rs index 2a4bc76aefb9..f800500c22a8 100644 --- a/library/std/src/sys/args/sgx.rs +++ b/library/std/src/sys/args/sgx.rs @@ -1,6 +1,8 @@ #![allow(fuzzy_provenance_casts)] // FIXME: this module systematically confuses pointers and integers use crate::ffi::OsString; +use crate::num::NonZero; +use crate::ops::Try; use crate::sync::atomic::{Atomic, AtomicUsize, Ordering}; use crate::sys::os_str::Buf; use crate::sys::pal::abi::usercalls::alloc; @@ -28,35 +30,81 @@ pub unsafe fn init(argc: isize, argv: *const *const u8) { pub fn args() -> Args { let args = unsafe { (ARGS.load(Ordering::Relaxed) as *const ArgsStore).as_ref() }; - if let Some(args) = args { Args(args.iter()) } else { Args([].iter()) } + let slice = args.map(|args| args.as_slice()).unwrap_or(&[]); + Args { iter: slice.iter() } } -pub struct Args(slice::Iter<'static, OsString>); +pub struct Args { + iter: slice::Iter<'static, OsString>, +} impl fmt::Debug for Args { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.as_slice().fmt(f) + self.iter.as_slice().fmt(f) } } impl Iterator for Args { type Item = OsString; - fn next(&mut self) -> Option { - self.0.next().cloned() - } - fn size_hint(&self) -> (usize, Option) { - self.0.size_hint() - } -} -impl ExactSizeIterator for Args { - fn len(&self) -> usize { - self.0.len() + fn next(&mut self) -> Option { + self.iter.next().cloned() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } + + #[inline] + fn count(self) -> usize { + self.iter.len() + } + + fn last(self) -> Option { + self.iter.last().cloned() + } + + #[inline] + fn advance_by(&mut self, n: usize) -> Result<(), NonZero> { + self.iter.advance_by(n) + } + + fn try_fold(&mut self, init: B, f: F) -> R + where + F: FnMut(B, Self::Item) -> R, + R: Try, + { + self.iter.by_ref().cloned().try_fold(init, f) + } + + fn fold(self, init: B, f: F) -> B + where + F: FnMut(B, Self::Item) -> B, + { + self.iter.cloned().fold(init, f) } } impl DoubleEndedIterator for Args { fn next_back(&mut self) -> Option { - self.0.next_back().cloned() + self.iter.next_back().cloned() + } + + #[inline] + fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero> { + self.iter.advance_back_by(n) + } +} + +impl ExactSizeIterator for Args { + #[inline] + fn len(&self) -> usize { + self.iter.len() + } + + #[inline] + fn is_empty(&self) -> bool { + self.iter.is_empty() } } diff --git a/library/std/src/sys/args/unsupported.rs b/library/std/src/sys/args/unsupported.rs index a2d75a619763..ecffc6d26414 100644 --- a/library/std/src/sys/args/unsupported.rs +++ b/library/std/src/sys/args/unsupported.rs @@ -15,22 +15,28 @@ impl fmt::Debug for Args { impl Iterator for Args { type Item = OsString; + + #[inline] fn next(&mut self) -> Option { None } + + #[inline] fn size_hint(&self) -> (usize, Option) { (0, Some(0)) } } -impl ExactSizeIterator for Args { - fn len(&self) -> usize { - 0 - } -} - impl DoubleEndedIterator for Args { + #[inline] fn next_back(&mut self) -> Option { None } } + +impl ExactSizeIterator for Args { + #[inline] + fn len(&self) -> usize { + 0 + } +} diff --git a/library/std/src/sys/exit_guard.rs b/library/std/src/sys/exit_guard.rs index 5a090f506661..bd70d1782440 100644 --- a/library/std/src/sys/exit_guard.rs +++ b/library/std/src/sys/exit_guard.rs @@ -1,14 +1,5 @@ cfg_if::cfg_if! { if #[cfg(target_os = "linux")] { - /// pthread_t is a pointer on some platforms, - /// so we wrap it in this to impl Send + Sync. - #[derive(Clone, Copy)] - #[repr(transparent)] - struct PThread(libc::pthread_t); - // Safety: pthread_t is safe to send between threads - unsafe impl Send for PThread {} - // Safety: pthread_t is safe to share between threads - unsafe impl Sync for PThread {} /// Mitigation for /// /// On glibc, `libc::exit` has been observed to not always be thread-safe. @@ -30,28 +21,34 @@ cfg_if::cfg_if! { /// (waiting for the process to exit). #[cfg_attr(any(test, doctest), allow(dead_code))] pub(crate) fn unique_thread_exit() { - let this_thread_id = unsafe { libc::pthread_self() }; - use crate::sync::{Mutex, PoisonError}; - static EXITING_THREAD_ID: Mutex> = Mutex::new(None); - let mut exiting_thread_id = - EXITING_THREAD_ID.lock().unwrap_or_else(PoisonError::into_inner); - match *exiting_thread_id { - None => { + use crate::ffi::c_int; + use crate::ptr; + use crate::sync::atomic::AtomicPtr; + use crate::sync::atomic::Ordering::{Acquire, Relaxed}; + + static EXITING_THREAD_ID: AtomicPtr = AtomicPtr::new(ptr::null_mut()); + + // We use the address of `errno` as a cheap and safe way to identify + // threads. As the C standard mandates that `errno` must have thread + // storage duration, we can rely on its address not changing over the + // lifetime of the thread. Additionally, accesses to `errno` are + // async-signal-safe, so this function is available in all imaginable + // circumstances. + let this_thread_id = crate::sys::os::errno_location(); + match EXITING_THREAD_ID.compare_exchange(ptr::null_mut(), this_thread_id, Acquire, Relaxed) { + Ok(_) => { // This is the first thread to call `unique_thread_exit`, - // and this is the first time it is called. - // Set EXITING_THREAD_ID to this thread's ID and return. - *exiting_thread_id = Some(PThread(this_thread_id)); - }, - Some(exiting_thread_id) if exiting_thread_id.0 == this_thread_id => { + // and this is the first time it is called. Continue exiting. + } + Err(exiting_thread_id) if exiting_thread_id == this_thread_id => { // This is the first thread to call `unique_thread_exit`, // but this is the second time it is called. // Abort the process. core::panicking::panic_nounwind("std::process::exit called re-entrantly") } - Some(_) => { + Err(_) => { // This is not the first thread to call `unique_thread_exit`. // Pause until the process exits. - drop(exiting_thread_id); loop { // Safety: libc::pause is safe to call. unsafe { libc::pause(); } diff --git a/library/std/src/sys/fs/hermit.rs b/library/std/src/sys/fs/hermit.rs index 99690abe8ed2..a9774bef9e33 100644 --- a/library/std/src/sys/fs/hermit.rs +++ b/library/std/src/sys/fs/hermit.rs @@ -1,4 +1,5 @@ use crate::ffi::{CStr, OsStr, OsString, c_char}; +use crate::fs::TryLockError; use crate::io::{self, BorrowedCursor, Error, ErrorKind, IoSlice, IoSliceMut, SeekFrom}; use crate::os::hermit::ffi::OsStringExt; use crate::os::hermit::hermit_abi::{ @@ -12,7 +13,7 @@ use crate::sys::common::small_c_string::run_path_with_cstr; use crate::sys::fd::FileDesc; pub use crate::sys::fs::common::{copy, exists}; use crate::sys::time::SystemTime; -use crate::sys::{cvt, unsupported}; +use crate::sys::{cvt, unsupported, unsupported_err}; use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; use crate::{fmt, mem}; @@ -366,12 +367,12 @@ impl File { unsupported() } - pub fn try_lock(&self) -> io::Result { - unsupported() + pub fn try_lock(&self) -> Result<(), TryLockError> { + Err(TryLockError::Error(unsupported_err())) } - pub fn try_lock_shared(&self) -> io::Result { - unsupported() + pub fn try_lock_shared(&self) -> Result<(), TryLockError> { + Err(TryLockError::Error(unsupported_err())) } pub fn unlock(&self) -> io::Result<()> { diff --git a/library/std/src/sys/fs/solid.rs b/library/std/src/sys/fs/solid.rs index 39de933b7248..3bfb39bac95b 100644 --- a/library/std/src/sys/fs/solid.rs +++ b/library/std/src/sys/fs/solid.rs @@ -2,6 +2,7 @@ use crate::ffi::{CStr, CString, OsStr, OsString}; use crate::fmt; +use crate::fs::TryLockError; use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, SeekFrom}; use crate::mem::MaybeUninit; use crate::os::raw::{c_int, c_short}; @@ -11,7 +12,7 @@ use crate::sync::Arc; pub use crate::sys::fs::common::exists; use crate::sys::pal::{abi, error}; use crate::sys::time::SystemTime; -use crate::sys::unsupported; +use crate::sys::{unsupported, unsupported_err}; use crate::sys_common::ignore_notfound; type CIntNotMinusOne = core::num::niche_types::NotAllOnes; @@ -352,12 +353,12 @@ impl File { unsupported() } - pub fn try_lock(&self) -> io::Result { - unsupported() + pub fn try_lock(&self) -> Result<(), TryLockError> { + Err(TryLockError::Error(unsupported_err())) } - pub fn try_lock_shared(&self) -> io::Result { - unsupported() + pub fn try_lock_shared(&self) -> Result<(), TryLockError> { + Err(TryLockError::Error(unsupported_err())) } pub fn unlock(&self) -> io::Result<()> { diff --git a/library/std/src/sys/fs/uefi.rs b/library/std/src/sys/fs/uefi.rs index d6ae86bd3d26..416c90b98b6d 100644 --- a/library/std/src/sys/fs/uefi.rs +++ b/library/std/src/sys/fs/uefi.rs @@ -2,6 +2,7 @@ use r_efi::protocols::file; use crate::ffi::OsString; use crate::fmt; +use crate::fs::TryLockError; use crate::hash::Hash; use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, SeekFrom}; use crate::path::{Path, PathBuf}; @@ -227,11 +228,11 @@ impl File { self.0 } - pub fn try_lock(&self) -> io::Result { + pub fn try_lock(&self) -> Result<(), TryLockError> { self.0 } - pub fn try_lock_shared(&self) -> io::Result { + pub fn try_lock_shared(&self) -> Result<(), TryLockError> { self.0 } diff --git a/library/std/src/sys/fs/unix.rs b/library/std/src/sys/fs/unix.rs index 5af59a2a914c..863358596c19 100644 --- a/library/std/src/sys/fs/unix.rs +++ b/library/std/src/sys/fs/unix.rs @@ -75,6 +75,7 @@ use libc::{dirent64, fstat64, ftruncate64, lseek64, lstat64, off64_t, open64, st use crate::ffi::{CStr, OsStr, OsString}; use crate::fmt::{self, Write as _}; +use crate::fs::TryLockError; use crate::io::{self, BorrowedCursor, Error, IoSlice, IoSliceMut, SeekFrom}; use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd}; use crate::os::unix::prelude::*; @@ -1310,15 +1311,17 @@ impl File { target_os = "netbsd", target_vendor = "apple", ))] - pub fn try_lock(&self) -> io::Result { + pub fn try_lock(&self) -> Result<(), TryLockError> { let result = cvt(unsafe { libc::flock(self.as_raw_fd(), libc::LOCK_EX | libc::LOCK_NB) }); - if let Err(ref err) = result { + if let Err(err) = result { if err.kind() == io::ErrorKind::WouldBlock { - return Ok(false); + Err(TryLockError::WouldBlock) + } else { + Err(TryLockError::Error(err)) } + } else { + Ok(()) } - result?; - return Ok(true); } #[cfg(not(any( @@ -1328,8 +1331,11 @@ impl File { target_os = "netbsd", target_vendor = "apple", )))] - pub fn try_lock(&self) -> io::Result { - Err(io::const_error!(io::ErrorKind::Unsupported, "try_lock() not supported")) + pub fn try_lock(&self) -> Result<(), TryLockError> { + Err(TryLockError::Error(io::const_error!( + io::ErrorKind::Unsupported, + "try_lock() not supported" + ))) } #[cfg(any( @@ -1339,15 +1345,17 @@ impl File { target_os = "netbsd", target_vendor = "apple", ))] - pub fn try_lock_shared(&self) -> io::Result { + pub fn try_lock_shared(&self) -> Result<(), TryLockError> { let result = cvt(unsafe { libc::flock(self.as_raw_fd(), libc::LOCK_SH | libc::LOCK_NB) }); - if let Err(ref err) = result { + if let Err(err) = result { if err.kind() == io::ErrorKind::WouldBlock { - return Ok(false); + Err(TryLockError::WouldBlock) + } else { + Err(TryLockError::Error(err)) } + } else { + Ok(()) } - result?; - return Ok(true); } #[cfg(not(any( @@ -1357,8 +1365,11 @@ impl File { target_os = "netbsd", target_vendor = "apple", )))] - pub fn try_lock_shared(&self) -> io::Result { - Err(io::const_error!(io::ErrorKind::Unsupported, "try_lock_shared() not supported")) + pub fn try_lock_shared(&self) -> Result<(), TryLockError> { + Err(TryLockError::Error(io::const_error!( + io::ErrorKind::Unsupported, + "try_lock_shared() not supported" + ))) } #[cfg(any( diff --git a/library/std/src/sys/fs/unsupported.rs b/library/std/src/sys/fs/unsupported.rs index 45e93deffa3a..0ff9533c0473 100644 --- a/library/std/src/sys/fs/unsupported.rs +++ b/library/std/src/sys/fs/unsupported.rs @@ -1,5 +1,6 @@ use crate::ffi::OsString; use crate::fmt; +use crate::fs::TryLockError; use crate::hash::{Hash, Hasher}; use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, SeekFrom}; use crate::path::{Path, PathBuf}; @@ -206,11 +207,11 @@ impl File { self.0 } - pub fn try_lock(&self) -> io::Result { + pub fn try_lock(&self) -> Result<(), TryLockError> { self.0 } - pub fn try_lock_shared(&self) -> io::Result { + pub fn try_lock_shared(&self) -> Result<(), TryLockError> { self.0 } diff --git a/library/std/src/sys/fs/wasi.rs b/library/std/src/sys/fs/wasi.rs index 773040571bc9..ebfc7377a2ea 100644 --- a/library/std/src/sys/fs/wasi.rs +++ b/library/std/src/sys/fs/wasi.rs @@ -1,4 +1,5 @@ use crate::ffi::{CStr, OsStr, OsString}; +use crate::fs::TryLockError; use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, SeekFrom}; use crate::mem::{self, ManuallyDrop}; use crate::os::raw::c_int; @@ -10,7 +11,7 @@ use crate::sys::common::small_c_string::run_path_with_cstr; use crate::sys::fd::WasiFd; pub use crate::sys::fs::common::exists; use crate::sys::time::SystemTime; -use crate::sys::unsupported; +use crate::sys::{unsupported, unsupported_err}; use crate::sys_common::{AsInner, FromInner, IntoInner, ignore_notfound}; use crate::{fmt, iter, ptr}; @@ -461,12 +462,12 @@ impl File { unsupported() } - pub fn try_lock(&self) -> io::Result { - unsupported() + pub fn try_lock(&self) -> Result<(), TryLockError> { + Err(TryLockError::Error(unsupported_err())) } - pub fn try_lock_shared(&self) -> io::Result { - unsupported() + pub fn try_lock_shared(&self) -> Result<(), TryLockError> { + Err(TryLockError::Error(unsupported_err())) } pub fn unlock(&self) -> io::Result<()> { diff --git a/library/std/src/sys/fs/windows.rs b/library/std/src/sys/fs/windows.rs index 9215f9375671..9039fd00f5d6 100644 --- a/library/std/src/sys/fs/windows.rs +++ b/library/std/src/sys/fs/windows.rs @@ -3,6 +3,7 @@ use crate::alloc::{Layout, alloc, dealloc}; use crate::borrow::Cow; use crate::ffi::{OsStr, OsString, c_void}; +use crate::fs::TryLockError; use crate::io::{self, BorrowedCursor, Error, IoSlice, IoSliceMut, SeekFrom}; use crate::mem::{self, MaybeUninit, offset_of}; use crate::os::windows::io::{AsHandle, BorrowedHandle}; @@ -399,7 +400,7 @@ impl File { self.acquire_lock(0) } - pub fn try_lock(&self) -> io::Result { + pub fn try_lock(&self) -> Result<(), TryLockError> { let result = cvt(unsafe { let mut overlapped = mem::zeroed(); c::LockFileEx( @@ -413,18 +414,18 @@ impl File { }); match result { - Ok(_) => Ok(true), + Ok(_) => Ok(()), Err(err) if err.raw_os_error() == Some(c::ERROR_IO_PENDING as i32) || err.raw_os_error() == Some(c::ERROR_LOCK_VIOLATION as i32) => { - Ok(false) + Err(TryLockError::WouldBlock) } - Err(err) => Err(err), + Err(err) => Err(TryLockError::Error(err)), } } - pub fn try_lock_shared(&self) -> io::Result { + pub fn try_lock_shared(&self) -> Result<(), TryLockError> { let result = cvt(unsafe { let mut overlapped = mem::zeroed(); c::LockFileEx( @@ -438,14 +439,14 @@ impl File { }); match result { - Ok(_) => Ok(true), + Ok(_) => Ok(()), Err(err) if err.raw_os_error() == Some(c::ERROR_IO_PENDING as i32) || err.raw_os_error() == Some(c::ERROR_LOCK_VIOLATION as i32) => { - Ok(false) + Err(TryLockError::WouldBlock) } - Err(err) => Err(err), + Err(err) => Err(TryLockError::Error(err)), } } diff --git a/library/std/src/sys/os_str/bytes.rs b/library/std/src/sys/os_str/bytes.rs index dfff2d3e5d31..4a8808c92304 100644 --- a/library/std/src/sys/os_str/bytes.rs +++ b/library/std/src/sys/os_str/bytes.rs @@ -216,19 +216,26 @@ impl Buf { self.as_slice().into_rc() } - /// Provides plumbing to core `Vec::truncate`. - /// More well behaving alternative to allowing outer types - /// full mutable access to the core `Vec`. + /// Provides plumbing to `Vec::truncate` without giving full mutable access + /// to the `Vec`. + /// + /// # Safety + /// + /// The length must be at an `OsStr` boundary, according to + /// `Slice::check_public_boundary`. #[inline] - pub(crate) fn truncate(&mut self, len: usize) { + pub unsafe fn truncate_unchecked(&mut self, len: usize) { self.inner.truncate(len); } - /// Provides plumbing to core `Vec::extend_from_slice`. - /// More well behaving alternative to allowing outer types - /// full mutable access to the core `Vec`. + /// Provides plumbing to `Vec::extend_from_slice` without giving full + /// mutable access to the `Vec`. + /// + /// # Safety + /// + /// This encoding has no safety requirements. #[inline] - pub(crate) fn extend_from_slice(&mut self, other: &[u8]) { + pub unsafe fn extend_from_slice_unchecked(&mut self, other: &[u8]) { self.inner.extend_from_slice(other); } } diff --git a/library/std/src/sys/os_str/wtf8.rs b/library/std/src/sys/os_str/wtf8.rs index a32f5d40f6a9..5174ea65d0cd 100644 --- a/library/std/src/sys/os_str/wtf8.rs +++ b/library/std/src/sys/os_str/wtf8.rs @@ -195,19 +195,31 @@ impl Buf { self.as_slice().into_rc() } - /// Provides plumbing to core `Vec::truncate`. - /// More well behaving alternative to allowing outer types - /// full mutable access to the core `Vec`. + /// Provides plumbing to `Vec::truncate` without giving full mutable access + /// to the `Vec`. + /// + /// # Safety + /// + /// The length must be at an `OsStr` boundary, according to + /// `Slice::check_public_boundary`. #[inline] - pub(crate) fn truncate(&mut self, len: usize) { + pub unsafe fn truncate_unchecked(&mut self, len: usize) { self.inner.truncate(len); } - /// Provides plumbing to core `Vec::extend_from_slice`. - /// More well behaving alternative to allowing outer types - /// full mutable access to the core `Vec`. + /// Provides plumbing to `Vec::extend_from_slice` without giving full + /// mutable access to the `Vec`. + /// + /// # Safety + /// + /// The slice must be valid for the platform encoding (as described in + /// [`Slice::from_encoded_bytes_unchecked`]). + /// + /// This bypasses the WTF-8 surrogate joining, so `self` must not end with a + /// leading surrogate half and `other` must not start with with a trailing + /// surrogate half. #[inline] - pub(crate) fn extend_from_slice(&mut self, other: &[u8]) { + pub unsafe fn extend_from_slice_unchecked(&mut self, other: &[u8]) { self.inner.extend_from_slice(other); } } diff --git a/library/std/src/sys/pal/unix/fuchsia.rs b/library/std/src/sys/pal/unix/fuchsia.rs index 7932bd26d76c..c118dee62476 100644 --- a/library/std/src/sys/pal/unix/fuchsia.rs +++ b/library/std/src/sys/pal/unix/fuchsia.rs @@ -1,48 +1,35 @@ -#![allow(non_camel_case_types, unused)] +#![expect(non_camel_case_types)] -use libc::{c_int, c_void, size_t}; +use libc::size_t; +use crate::ffi::{c_char, c_int, c_void}; use crate::io; -use crate::mem::MaybeUninit; -use crate::os::raw::c_char; + +////////// +// Time // +////////// + +pub type zx_time_t = i64; + +pub const ZX_TIME_INFINITE: zx_time_t = i64::MAX; + +unsafe extern "C" { + pub safe fn zx_clock_get_monotonic() -> zx_time_t; +} + +///////////// +// Handles // +///////////// pub type zx_handle_t = u32; -pub type zx_vaddr_t = usize; -pub type zx_rights_t = u32; -pub type zx_status_t = i32; pub const ZX_HANDLE_INVALID: zx_handle_t = 0; -pub type zx_time_t = i64; -pub const ZX_TIME_INFINITE: zx_time_t = i64::MAX; - -pub type zx_signals_t = u32; - -pub const ZX_OBJECT_SIGNAL_3: zx_signals_t = 1 << 3; - -pub const ZX_TASK_TERMINATED: zx_signals_t = ZX_OBJECT_SIGNAL_3; - -pub const ZX_RIGHT_SAME_RIGHTS: zx_rights_t = 1 << 31; - -// The upper four bits gives the minor version. -pub type zx_object_info_topic_t = u32; - -pub const ZX_INFO_PROCESS: zx_object_info_topic_t = 3 | (1 << 28); - -pub type zx_info_process_flags_t = u32; - -pub fn zx_cvt(t: T) -> io::Result -where - T: TryInto + Copy, -{ - if let Ok(status) = TryInto::try_into(t) { - if status < 0 { Err(io::Error::from_raw_os_error(status)) } else { Ok(t) } - } else { - Err(io::Error::last_os_error()) - } +unsafe extern "C" { + pub fn zx_handle_close(handle: zx_handle_t) -> zx_status_t; } -// Safe wrapper around zx_handle_t +/// A safe wrapper around `zx_handle_t`. pub struct Handle { raw: zx_handle_t, } @@ -65,6 +52,66 @@ impl Drop for Handle { } } +/////////// +// Futex // +/////////// + +pub type zx_futex_t = crate::sync::atomic::Atomic; + +unsafe extern "C" { + pub fn zx_object_wait_one( + handle: zx_handle_t, + signals: zx_signals_t, + timeout: zx_time_t, + pending: *mut zx_signals_t, + ) -> zx_status_t; + + pub fn zx_futex_wait( + value_ptr: *const zx_futex_t, + current_value: zx_futex_t, + new_futex_owner: zx_handle_t, + deadline: zx_time_t, + ) -> zx_status_t; + pub fn zx_futex_wake(value_ptr: *const zx_futex_t, wake_count: u32) -> zx_status_t; + pub fn zx_futex_wake_single_owner(value_ptr: *const zx_futex_t) -> zx_status_t; + pub safe fn zx_thread_self() -> zx_handle_t; +} + +//////////////// +// Properties // +//////////////// + +pub const ZX_PROP_NAME: u32 = 3; + +unsafe extern "C" { + pub fn zx_object_set_property( + handle: zx_handle_t, + property: u32, + value: *const libc::c_void, + value_size: libc::size_t, + ) -> zx_status_t; +} + +///////////// +// Signals // +///////////// + +pub type zx_signals_t = u32; + +pub const ZX_OBJECT_SIGNAL_3: zx_signals_t = 1 << 3; +pub const ZX_TASK_TERMINATED: zx_signals_t = ZX_OBJECT_SIGNAL_3; + +///////////////// +// Object info // +///////////////// + +// The upper four bits gives the minor version. +pub type zx_object_info_topic_t = u32; + +pub const ZX_INFO_PROCESS: zx_object_info_topic_t = 3 | (1 << 28); + +pub type zx_info_process_flags_t = u32; + // Returned for topic ZX_INFO_PROCESS #[derive(Default)] #[repr(C)] @@ -76,25 +123,6 @@ pub struct zx_info_process_t { } unsafe extern "C" { - pub fn zx_job_default() -> zx_handle_t; - - pub fn zx_task_kill(handle: zx_handle_t) -> zx_status_t; - - pub fn zx_handle_close(handle: zx_handle_t) -> zx_status_t; - - pub fn zx_handle_duplicate( - handle: zx_handle_t, - rights: zx_rights_t, - out: *const zx_handle_t, - ) -> zx_handle_t; - - pub fn zx_object_wait_one( - handle: zx_handle_t, - signals: zx_signals_t, - timeout: zx_time_t, - pending: *mut zx_signals_t, - ) -> zx_status_t; - pub fn zx_object_get_info( handle: zx_handle_t, topic: u32, @@ -105,6 +133,10 @@ unsafe extern "C" { ) -> zx_status_t; } +/////////////// +// Processes // +/////////////// + #[derive(Default)] #[repr(C)] pub struct fdio_spawn_action_t { @@ -130,6 +162,8 @@ unsafe extern "C" { pub fn fdio_fd_clone(fd: c_int, out_handle: *mut zx_handle_t) -> zx_status_t; pub fn fdio_fd_create(handle: zx_handle_t, fd: *mut c_int) -> zx_status_t; + + pub fn zx_task_kill(handle: zx_handle_t) -> zx_status_t; } // fdio_spawn_etc flags @@ -137,173 +171,34 @@ unsafe extern "C" { pub const FDIO_SPAWN_CLONE_JOB: u32 = 0x0001; pub const FDIO_SPAWN_CLONE_LDSVC: u32 = 0x0002; pub const FDIO_SPAWN_CLONE_NAMESPACE: u32 = 0x0004; -pub const FDIO_SPAWN_CLONE_STDIO: u32 = 0x0008; pub const FDIO_SPAWN_CLONE_ENVIRON: u32 = 0x0010; pub const FDIO_SPAWN_CLONE_UTC_CLOCK: u32 = 0x0020; -pub const FDIO_SPAWN_CLONE_ALL: u32 = 0xFFFF; // fdio_spawn_etc actions -pub const FDIO_SPAWN_ACTION_CLONE_FD: u32 = 0x0001; pub const FDIO_SPAWN_ACTION_TRANSFER_FD: u32 = 0x0002; -// Errors +//////////// +// Errors // +//////////// -#[allow(unused)] -pub const ERR_INTERNAL: zx_status_t = -1; +pub type zx_status_t = i32; -// ERR_NOT_SUPPORTED: The operation is not implemented, supported, -// or enabled. -#[allow(unused)] -pub const ERR_NOT_SUPPORTED: zx_status_t = -2; +pub const ZX_OK: zx_status_t = 0; +pub const ZX_ERR_NOT_SUPPORTED: zx_status_t = -2; +pub const ZX_ERR_INVALID_ARGS: zx_status_t = -10; +pub const ZX_ERR_BAD_HANDLE: zx_status_t = -11; +pub const ZX_ERR_WRONG_TYPE: zx_status_t = -12; +pub const ZX_ERR_BAD_STATE: zx_status_t = -20; +pub const ZX_ERR_TIMED_OUT: zx_status_t = -21; -// ERR_NO_RESOURCES: The system was not able to allocate some resource -// needed for the operation. -#[allow(unused)] -pub const ERR_NO_RESOURCES: zx_status_t = -3; - -// ERR_NO_MEMORY: The system was not able to allocate memory needed -// for the operation. -#[allow(unused)] -pub const ERR_NO_MEMORY: zx_status_t = -4; - -// ERR_CALL_FAILED: The second phase of zx_channel_call(; did not complete -// successfully. -#[allow(unused)] -pub const ERR_CALL_FAILED: zx_status_t = -5; - -// ERR_INTERRUPTED_RETRY: The system call was interrupted, but should be -// retried. This should not be seen outside of the VDSO. -#[allow(unused)] -pub const ERR_INTERRUPTED_RETRY: zx_status_t = -6; - -// ======= Parameter errors ======= -// ERR_INVALID_ARGS: an argument is invalid, ex. null pointer -#[allow(unused)] -pub const ERR_INVALID_ARGS: zx_status_t = -10; - -// ERR_BAD_HANDLE: A specified handle value does not refer to a handle. -#[allow(unused)] -pub const ERR_BAD_HANDLE: zx_status_t = -11; - -// ERR_WRONG_TYPE: The subject of the operation is the wrong type to -// perform the operation. -// Example: Attempting a message_read on a thread handle. -#[allow(unused)] -pub const ERR_WRONG_TYPE: zx_status_t = -12; - -// ERR_BAD_SYSCALL: The specified syscall number is invalid. -#[allow(unused)] -pub const ERR_BAD_SYSCALL: zx_status_t = -13; - -// ERR_OUT_OF_RANGE: An argument is outside the valid range for this -// operation. -#[allow(unused)] -pub const ERR_OUT_OF_RANGE: zx_status_t = -14; - -// ERR_BUFFER_TOO_SMALL: A caller provided buffer is too small for -// this operation. -#[allow(unused)] -pub const ERR_BUFFER_TOO_SMALL: zx_status_t = -15; - -// ======= Precondition or state errors ======= -// ERR_BAD_STATE: operation failed because the current state of the -// object does not allow it, or a precondition of the operation is -// not satisfied -#[allow(unused)] -pub const ERR_BAD_STATE: zx_status_t = -20; - -// ERR_TIMED_OUT: The time limit for the operation elapsed before -// the operation completed. -#[allow(unused)] -pub const ERR_TIMED_OUT: zx_status_t = -21; - -// ERR_SHOULD_WAIT: The operation cannot be performed currently but -// potentially could succeed if the caller waits for a prerequisite -// to be satisfied, for example waiting for a handle to be readable -// or writable. -// Example: Attempting to read from a message pipe that has no -// messages waiting but has an open remote will return ERR_SHOULD_WAIT. -// Attempting to read from a message pipe that has no messages waiting -// and has a closed remote end will return ERR_REMOTE_CLOSED. -#[allow(unused)] -pub const ERR_SHOULD_WAIT: zx_status_t = -22; - -// ERR_CANCELED: The in-progress operation (e.g., a wait) has been -// // canceled. -#[allow(unused)] -pub const ERR_CANCELED: zx_status_t = -23; - -// ERR_PEER_CLOSED: The operation failed because the remote end -// of the subject of the operation was closed. -#[allow(unused)] -pub const ERR_PEER_CLOSED: zx_status_t = -24; - -// ERR_NOT_FOUND: The requested entity is not found. -#[allow(unused)] -pub const ERR_NOT_FOUND: zx_status_t = -25; - -// ERR_ALREADY_EXISTS: An object with the specified identifier -// already exists. -// Example: Attempting to create a file when a file already exists -// with that name. -#[allow(unused)] -pub const ERR_ALREADY_EXISTS: zx_status_t = -26; - -// ERR_ALREADY_BOUND: The operation failed because the named entity -// is already owned or controlled by another entity. The operation -// could succeed later if the current owner releases the entity. -#[allow(unused)] -pub const ERR_ALREADY_BOUND: zx_status_t = -27; - -// ERR_UNAVAILABLE: The subject of the operation is currently unable -// to perform the operation. -// Note: This is used when there's no direct way for the caller to -// observe when the subject will be able to perform the operation -// and should thus retry. -#[allow(unused)] -pub const ERR_UNAVAILABLE: zx_status_t = -28; - -// ======= Permission check errors ======= -// ERR_ACCESS_DENIED: The caller did not have permission to perform -// the specified operation. -#[allow(unused)] -pub const ERR_ACCESS_DENIED: zx_status_t = -30; - -// ======= Input-output errors ======= -// ERR_IO: Otherwise unspecified error occurred during I/O. -#[allow(unused)] -pub const ERR_IO: zx_status_t = -40; - -// ERR_REFUSED: The entity the I/O operation is being performed on -// rejected the operation. -// Example: an I2C device NAK'ing a transaction or a disk controller -// rejecting an invalid command. -#[allow(unused)] -pub const ERR_IO_REFUSED: zx_status_t = -41; - -// ERR_IO_DATA_INTEGRITY: The data in the operation failed an integrity -// check and is possibly corrupted. -// Example: CRC or Parity error. -#[allow(unused)] -pub const ERR_IO_DATA_INTEGRITY: zx_status_t = -42; - -// ERR_IO_DATA_LOSS: The data in the operation is currently unavailable -// and may be permanently lost. -// Example: A disk block is irrecoverably damaged. -#[allow(unused)] -pub const ERR_IO_DATA_LOSS: zx_status_t = -43; - -// Filesystem specific errors -#[allow(unused)] -pub const ERR_BAD_PATH: zx_status_t = -50; -#[allow(unused)] -pub const ERR_NOT_DIR: zx_status_t = -51; -#[allow(unused)] -pub const ERR_NOT_FILE: zx_status_t = -52; -// ERR_FILE_BIG: A file exceeds a filesystem-specific size limit. -#[allow(unused)] -pub const ERR_FILE_BIG: zx_status_t = -53; -// ERR_NO_SPACE: Filesystem or device space is exhausted. -#[allow(unused)] -pub const ERR_NO_SPACE: zx_status_t = -54; +pub fn zx_cvt(t: T) -> io::Result +where + T: TryInto + Copy, +{ + if let Ok(status) = TryInto::try_into(t) { + if status < 0 { Err(io::Error::from_raw_os_error(status)) } else { Ok(t) } + } else { + Err(io::Error::last_os_error()) + } +} diff --git a/library/std/src/sys/pal/unix/futex.rs b/library/std/src/sys/pal/unix/futex.rs index 8d89163c42ce..c23278bdf5e5 100644 --- a/library/std/src/sys/pal/unix/futex.rs +++ b/library/std/src/sys/pal/unix/futex.rs @@ -254,67 +254,29 @@ pub fn futex_wake_all(futex: &Atomic) { unsafe { emscripten_futex_wake(futex, i32::MAX) }; } -#[cfg(target_os = "fuchsia")] -pub mod zircon { - pub type zx_futex_t = crate::sync::atomic::Atomic; - pub type zx_handle_t = u32; - pub type zx_status_t = i32; - pub type zx_time_t = i64; - - pub const ZX_HANDLE_INVALID: zx_handle_t = 0; - - pub const ZX_TIME_INFINITE: zx_time_t = zx_time_t::MAX; - - pub const ZX_OK: zx_status_t = 0; - pub const ZX_ERR_INVALID_ARGS: zx_status_t = -10; - pub const ZX_ERR_BAD_HANDLE: zx_status_t = -11; - pub const ZX_ERR_WRONG_TYPE: zx_status_t = -12; - pub const ZX_ERR_BAD_STATE: zx_status_t = -20; - pub const ZX_ERR_TIMED_OUT: zx_status_t = -21; - - unsafe extern "C" { - pub fn zx_clock_get_monotonic() -> zx_time_t; - pub fn zx_futex_wait( - value_ptr: *const zx_futex_t, - current_value: zx_futex_t, - new_futex_owner: zx_handle_t, - deadline: zx_time_t, - ) -> zx_status_t; - pub fn zx_futex_wake(value_ptr: *const zx_futex_t, wake_count: u32) -> zx_status_t; - pub fn zx_futex_wake_single_owner(value_ptr: *const zx_futex_t) -> zx_status_t; - pub fn zx_thread_self() -> zx_handle_t; - } -} - #[cfg(target_os = "fuchsia")] pub fn futex_wait(futex: &Atomic, expected: u32, timeout: Option) -> bool { + use super::fuchsia::*; + // Sleep forever if the timeout is longer than fits in a i64. let deadline = timeout - .and_then(|d| { - i64::try_from(d.as_nanos()) - .ok()? - .checked_add(unsafe { zircon::zx_clock_get_monotonic() }) - }) - .unwrap_or(zircon::ZX_TIME_INFINITE); + .and_then(|d| i64::try_from(d.as_nanos()).ok()?.checked_add(zx_clock_get_monotonic())) + .unwrap_or(ZX_TIME_INFINITE); unsafe { - zircon::zx_futex_wait( - futex, - core::sync::atomic::AtomicU32::new(expected), - zircon::ZX_HANDLE_INVALID, - deadline, - ) != zircon::ZX_ERR_TIMED_OUT + zx_futex_wait(futex, zx_futex_t::new(expected), ZX_HANDLE_INVALID, deadline) + != ZX_ERR_TIMED_OUT } } // Fuchsia doesn't tell us how many threads are woken up, so this always returns false. #[cfg(target_os = "fuchsia")] pub fn futex_wake(futex: &Atomic) -> bool { - unsafe { zircon::zx_futex_wake(futex, 1) }; + unsafe { super::fuchsia::zx_futex_wake(futex, 1) }; false } #[cfg(target_os = "fuchsia")] pub fn futex_wake_all(futex: &Atomic) { - unsafe { zircon::zx_futex_wake(futex, u32::MAX) }; + unsafe { super::fuchsia::zx_futex_wake(futex, u32::MAX) }; } diff --git a/library/std/src/sys/pal/unix/os.rs b/library/std/src/sys/pal/unix/os.rs index 4883303b88e2..48609030aed1 100644 --- a/library/std/src/sys/pal/unix/os.rs +++ b/library/std/src/sys/pal/unix/os.rs @@ -56,7 +56,7 @@ unsafe extern "C" { #[cfg_attr(target_os = "aix", link_name = "_Errno")] // SAFETY: this will always return the same pointer on a given thread. #[unsafe(ffi_const)] - fn errno_location() -> *mut c_int; + pub safe fn errno_location() -> *mut c_int; } /// Returns the platform-specific value of errno diff --git a/library/std/src/sys/pal/unix/thread.rs b/library/std/src/sys/pal/unix/thread.rs index 4cdc2eaf0e53..afda7c65e108 100644 --- a/library/std/src/sys/pal/unix/thread.rs +++ b/library/std/src/sys/pal/unix/thread.rs @@ -22,23 +22,6 @@ pub const DEFAULT_MIN_STACK_SIZE: usize = 256 * 1024; #[cfg(any(target_os = "espidf", target_os = "nuttx"))] pub const DEFAULT_MIN_STACK_SIZE: usize = 0; // 0 indicates that the stack size configured in the ESP-IDF/NuttX menuconfig system should be used -#[cfg(target_os = "fuchsia")] -mod zircon { - type zx_handle_t = u32; - type zx_status_t = i32; - pub const ZX_PROP_NAME: u32 = 3; - - unsafe extern "C" { - pub fn zx_object_set_property( - handle: zx_handle_t, - property: u32, - value: *const libc::c_void, - value_size: libc::size_t, - ) -> zx_status_t; - pub fn zx_thread_self() -> zx_handle_t; - } -} - pub struct Thread { id: libc::pthread_t, } @@ -216,7 +199,7 @@ impl Thread { #[cfg(target_os = "fuchsia")] pub fn set_name(name: &CStr) { - use self::zircon::*; + use super::fuchsia::*; unsafe { zx_object_set_property( zx_thread_self(), diff --git a/library/std/src/sys_common/process.rs b/library/std/src/sys/process/env.rs similarity index 67% rename from library/std/src/sys_common/process.rs rename to library/std/src/sys/process/env.rs index 9f61d69d8587..e08b476540ef 100644 --- a/library/std/src/sys_common/process.rs +++ b/library/std/src/sys/process/env.rs @@ -1,13 +1,9 @@ -#![allow(dead_code)] -#![unstable(feature = "process_internals", issue = "none")] - use crate::collections::BTreeMap; use crate::ffi::{OsStr, OsString}; -use crate::sys::pipe::read2; -use crate::sys::process::{EnvKey, ExitStatus, Process, StdioPipes}; -use crate::{env, fmt, io}; +use crate::sys::process::EnvKey; +use crate::{env, fmt}; -// Stores a set of changes to an environment +/// Stores a set of changes to an environment #[derive(Clone, Default)] pub struct CommandEnv { clear: bool, @@ -92,30 +88,23 @@ impl CommandEnv { } } -/// An iterator over the command environment variables. -/// -/// This struct is created by -/// [`Command::get_envs`][crate::process::Command::get_envs]. See its -/// documentation for more. -#[must_use = "iterators are lazy and do nothing unless consumed"] -#[stable(feature = "command_access", since = "1.57.0")] #[derive(Debug)] pub struct CommandEnvs<'a> { iter: crate::collections::btree_map::Iter<'a, EnvKey, Option>, } -#[stable(feature = "command_access", since = "1.57.0")] impl<'a> Iterator for CommandEnvs<'a> { type Item = (&'a OsStr, Option<&'a OsStr>); + fn next(&mut self) -> Option { self.iter.next().map(|(key, value)| (key.as_ref(), value.as_deref())) } + fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } } -#[stable(feature = "command_access", since = "1.57.0")] impl<'a> ExactSizeIterator for CommandEnvs<'a> { fn len(&self) -> usize { self.iter.len() @@ -124,30 +113,3 @@ impl<'a> ExactSizeIterator for CommandEnvs<'a> { self.iter.is_empty() } } - -pub fn wait_with_output( - mut process: Process, - mut pipes: StdioPipes, -) -> io::Result<(ExitStatus, Vec, Vec)> { - drop(pipes.stdin.take()); - - let (mut stdout, mut stderr) = (Vec::new(), Vec::new()); - match (pipes.stdout.take(), pipes.stderr.take()) { - (None, None) => {} - (Some(out), None) => { - let res = out.read_to_end(&mut stdout); - res.unwrap(); - } - (None, Some(err)) => { - let res = err.read_to_end(&mut stderr); - res.unwrap(); - } - (Some(out), Some(err)) => { - let res = read2(out, &mut stdout, err, &mut stderr); - res.unwrap(); - } - } - - let status = process.wait()?; - Ok((status, stdout, stderr)) -} diff --git a/library/std/src/sys/process/mod.rs b/library/std/src/sys/process/mod.rs index 92cfac7f47cf..91c7005a3285 100644 --- a/library/std/src/sys/process/mod.rs +++ b/library/std/src/sys/process/mod.rs @@ -14,6 +14,65 @@ cfg_if::cfg_if! { } } +// This module is shared by all platforms, but nearly all platforms except for +// the "normal" UNIX ones leave some of this code unused. +#[cfg_attr(not(target_os = "linux"), allow(dead_code))] +mod env; + +pub use env::CommandEnvs; pub use imp::{ Command, CommandArgs, EnvKey, ExitCode, ExitStatus, ExitStatusError, Process, Stdio, StdioPipes, }; + +#[cfg(any( + all( + target_family = "unix", + not(any( + target_os = "espidf", + target_os = "horizon", + target_os = "vita", + target_os = "nuttx" + )) + ), + target_os = "windows", +))] +pub fn output(cmd: &mut Command) -> crate::io::Result<(ExitStatus, Vec, Vec)> { + use crate::sys::pipe::read2; + + let (mut process, mut pipes) = cmd.spawn(Stdio::MakePipe, false)?; + + drop(pipes.stdin.take()); + let (mut stdout, mut stderr) = (Vec::new(), Vec::new()); + match (pipes.stdout.take(), pipes.stderr.take()) { + (None, None) => {} + (Some(out), None) => { + let res = out.read_to_end(&mut stdout); + res.unwrap(); + } + (None, Some(err)) => { + let res = err.read_to_end(&mut stderr); + res.unwrap(); + } + (Some(out), Some(err)) => { + let res = read2(out, &mut stdout, err, &mut stderr); + res.unwrap(); + } + } + + let status = process.wait()?; + Ok((status, stdout, stderr)) +} + +#[cfg(not(any( + all( + target_family = "unix", + not(any( + target_os = "espidf", + target_os = "horizon", + target_os = "vita", + target_os = "nuttx" + )) + ), + target_os = "windows", +)))] +pub use imp::output; diff --git a/library/std/src/sys/process/uefi.rs b/library/std/src/sys/process/uefi.rs index 5f922292d054..4864c5869881 100644 --- a/library/std/src/sys/process/uefi.rs +++ b/library/std/src/sys/process/uefi.rs @@ -1,5 +1,6 @@ use r_efi::protocols::{simple_text_input, simple_text_output}; +use super::env::{CommandEnv, CommandEnvs}; use crate::collections::BTreeMap; pub use crate::ffi::OsString as EnvKey; use crate::ffi::{OsStr, OsString}; @@ -10,7 +11,6 @@ use crate::sys::pal::helpers; use crate::sys::pal::os::error_string; use crate::sys::pipe::AnonPipe; use crate::sys::unsupported; -use crate::sys_common::process::{CommandEnv, CommandEnvs}; use crate::{fmt, io}; //////////////////////////////////////////////////////////////////////////////// @@ -139,72 +139,72 @@ impl Command { Stdio::MakePipe => unsupported(), } } +} - pub fn output(&mut self) -> io::Result<(ExitStatus, Vec, Vec)> { - let mut cmd = uefi_command_internal::Image::load_image(&self.prog)?; +pub fn output(command: &mut Command) -> io::Result<(ExitStatus, Vec, Vec)> { + let mut cmd = uefi_command_internal::Image::load_image(&command.prog)?; - // UEFI adds the bin name by default - if !self.args.is_empty() { - let args = uefi_command_internal::create_args(&self.prog, &self.args); - cmd.set_args(args); - } - - // Setup Stdout - let stdout = self.stdout.unwrap_or(Stdio::MakePipe); - let stdout = Self::create_pipe(stdout)?; - if let Some(con) = stdout { - cmd.stdout_init(con) - } else { - cmd.stdout_inherit() - }; - - // Setup Stderr - let stderr = self.stderr.unwrap_or(Stdio::MakePipe); - let stderr = Self::create_pipe(stderr)?; - if let Some(con) = stderr { - cmd.stderr_init(con) - } else { - cmd.stderr_inherit() - }; - - // Setup Stdin - let stdin = self.stdin.unwrap_or(Stdio::Null); - let stdin = Self::create_stdin(stdin)?; - if let Some(con) = stdin { - cmd.stdin_init(con) - } else { - cmd.stdin_inherit() - }; - - let env = env_changes(&self.env); - - // Set any new vars - if let Some(e) = &env { - for (k, (_, v)) in e { - match v { - Some(v) => unsafe { crate::env::set_var(k, v) }, - None => unsafe { crate::env::remove_var(k) }, - } - } - } - - let stat = cmd.start_image()?; - - // Rollback any env changes - if let Some(e) = env { - for (k, (v, _)) in e { - match v { - Some(v) => unsafe { crate::env::set_var(k, v) }, - None => unsafe { crate::env::remove_var(k) }, - } - } - } - - let stdout = cmd.stdout()?; - let stderr = cmd.stderr()?; - - Ok((ExitStatus(stat), stdout, stderr)) + // UEFI adds the bin name by default + if !command.args.is_empty() { + let args = uefi_command_internal::create_args(&command.prog, &command.args); + cmd.set_args(args); } + + // Setup Stdout + let stdout = command.stdout.unwrap_or(Stdio::MakePipe); + let stdout = Command::create_pipe(stdout)?; + if let Some(con) = stdout { + cmd.stdout_init(con) + } else { + cmd.stdout_inherit() + }; + + // Setup Stderr + let stderr = command.stderr.unwrap_or(Stdio::MakePipe); + let stderr = Command::create_pipe(stderr)?; + if let Some(con) = stderr { + cmd.stderr_init(con) + } else { + cmd.stderr_inherit() + }; + + // Setup Stdin + let stdin = command.stdin.unwrap_or(Stdio::Null); + let stdin = Command::create_stdin(stdin)?; + if let Some(con) = stdin { + cmd.stdin_init(con) + } else { + cmd.stdin_inherit() + }; + + let env = env_changes(&command.env); + + // Set any new vars + if let Some(e) = &env { + for (k, (_, v)) in e { + match v { + Some(v) => unsafe { crate::env::set_var(k, v) }, + None => unsafe { crate::env::remove_var(k) }, + } + } + } + + let stat = cmd.start_image()?; + + // Rollback any env changes + if let Some(e) = env { + for (k, (v, _)) in e { + match v { + Some(v) => unsafe { crate::env::set_var(k, v) }, + None => unsafe { crate::env::remove_var(k) }, + } + } + } + + let stdout = cmd.stdout()?; + let stderr = cmd.stderr()?; + + Ok((ExitStatus(stat), stdout, stderr)) } impl From for Stdio { diff --git a/library/std/src/sys/process/unix/common.rs b/library/std/src/sys/process/unix/common.rs index 8bc17f314911..a9c2510e6d45 100644 --- a/library/std/src/sys/process/unix/common.rs +++ b/library/std/src/sys/process/unix/common.rs @@ -12,7 +12,7 @@ use crate::sys::fs::File; #[cfg(not(target_os = "fuchsia"))] use crate::sys::fs::OpenOptions; use crate::sys::pipe::{self, AnonPipe}; -use crate::sys_common::process::{CommandEnv, CommandEnvs}; +use crate::sys::process::env::{CommandEnv, CommandEnvs}; use crate::sys_common::{FromInner, IntoInner}; use crate::{fmt, io, ptr}; diff --git a/library/std/src/sys/process/unix/fuchsia.rs b/library/std/src/sys/process/unix/fuchsia.rs index 0de32ecffd4b..017ab91797ce 100644 --- a/library/std/src/sys/process/unix/fuchsia.rs +++ b/library/std/src/sys/process/unix/fuchsia.rs @@ -31,11 +31,6 @@ impl Command { Ok((Process { handle: Handle::new(process_handle) }, ours)) } - pub fn output(&mut self) -> io::Result<(ExitStatus, Vec, Vec)> { - let (proc, pipes) = self.spawn(Stdio::MakePipe, false)?; - crate::sys_common::process::wait_with_output(proc, pipes) - } - pub fn exec(&mut self, default: Stdio) -> io::Error { if self.saw_nul() { return io::const_error!( @@ -81,7 +76,7 @@ impl Command { let mut handle = ZX_HANDLE_INVALID; let status = fdio_fd_clone(target_fd, &mut handle); - if status == ERR_INVALID_ARGS || status == ERR_NOT_SUPPORTED { + if status == ZX_ERR_INVALID_ARGS || status == ZX_ERR_NOT_SUPPORTED { // This descriptor is closed; skip it rather than generating an // error. return Ok(Default::default()); @@ -197,7 +192,7 @@ impl Process { zx_object_wait_one(self.handle.raw(), ZX_TASK_TERMINATED, 0, ptr::null_mut()); match status { 0 => {} // Success - x if x == ERR_TIMED_OUT => { + x if x == ZX_ERR_TIMED_OUT => { return Ok(None); } _ => { diff --git a/library/std/src/sys/process/unix/mod.rs b/library/std/src/sys/process/unix/mod.rs index 2e8b38f7de1b..ee8fd8b2ca3c 100644 --- a/library/std/src/sys/process/unix/mod.rs +++ b/library/std/src/sys/process/unix/mod.rs @@ -11,6 +11,7 @@ cfg_if::cfg_if! { } else if #[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "vita", target_os = "nuttx"))] { mod unsupported; use unsupported as imp; + pub use unsupported::output; } else { mod unix; use unix as imp; diff --git a/library/std/src/sys/process/unix/unix.rs b/library/std/src/sys/process/unix/unix.rs index ae1c9558281e..1b3bd2de265d 100644 --- a/library/std/src/sys/process/unix/unix.rs +++ b/library/std/src/sys/process/unix/unix.rs @@ -162,11 +162,6 @@ impl Command { } } - pub fn output(&mut self) -> io::Result<(ExitStatus, Vec, Vec)> { - let (proc, pipes) = self.spawn(Stdio::MakePipe, false)?; - crate::sys_common::process::wait_with_output(proc, pipes) - } - // WatchOS and TVOS headers mark the `fork`/`exec*` functions with // `__WATCHOS_PROHIBITED __TVOS_PROHIBITED`, and indicate that the // `posix_spawn*` functions should be used instead. It isn't entirely clear diff --git a/library/std/src/sys/process/unix/unsupported.rs b/library/std/src/sys/process/unix/unsupported.rs index 78d270923cfa..e86561a5c5c4 100644 --- a/library/std/src/sys/process/unix/unsupported.rs +++ b/library/std/src/sys/process/unix/unsupported.rs @@ -18,15 +18,15 @@ impl Command { unsupported() } - pub fn output(&mut self) -> io::Result<(ExitStatus, Vec, Vec)> { - unsupported() - } - pub fn exec(&mut self, _default: Stdio) -> io::Error { unsupported_err() } } +pub fn output(_: &mut Command) -> io::Result<(ExitStatus, Vec, Vec)> { + unsupported() +} + //////////////////////////////////////////////////////////////////////////////// // Processes //////////////////////////////////////////////////////////////////////////////// diff --git a/library/std/src/sys/process/unix/vxworks.rs b/library/std/src/sys/process/unix/vxworks.rs index b92446f0cf67..fab3b36ebf3f 100644 --- a/library/std/src/sys/process/unix/vxworks.rs +++ b/library/std/src/sys/process/unix/vxworks.rs @@ -112,11 +112,6 @@ impl Command { } } - pub fn output(&mut self) -> io::Result<(ExitStatus, Vec, Vec)> { - let (proc, pipes) = self.spawn(Stdio::MakePipe, false)?; - crate::sys_common::process::wait_with_output(proc, pipes) - } - pub fn exec(&mut self, default: Stdio) -> io::Error { let ret = Command::spawn(self, default, false); match ret { diff --git a/library/std/src/sys/process/unsupported.rs b/library/std/src/sys/process/unsupported.rs index fee81744f09e..469922c78aca 100644 --- a/library/std/src/sys/process/unsupported.rs +++ b/library/std/src/sys/process/unsupported.rs @@ -1,3 +1,4 @@ +use super::env::{CommandEnv, CommandEnvs}; pub use crate::ffi::OsString as EnvKey; use crate::ffi::{OsStr, OsString}; use crate::num::NonZero; @@ -5,7 +6,6 @@ use crate::path::Path; use crate::sys::fs::File; use crate::sys::pipe::AnonPipe; use crate::sys::unsupported; -use crate::sys_common::process::{CommandEnv, CommandEnvs}; use crate::{fmt, io}; //////////////////////////////////////////////////////////////////////////////// @@ -104,10 +104,10 @@ impl Command { ) -> io::Result<(Process, StdioPipes)> { unsupported() } +} - pub fn output(&mut self) -> io::Result<(ExitStatus, Vec, Vec)> { - unsupported() - } +pub fn output(_cmd: &mut Command) -> io::Result<(ExitStatus, Vec, Vec)> { + unsupported() } impl From for Stdio { diff --git a/library/std/src/sys/process/windows.rs b/library/std/src/sys/process/windows.rs index 4cfdf908c58d..4acd753eec91 100644 --- a/library/std/src/sys/process/windows.rs +++ b/library/std/src/sys/process/windows.rs @@ -5,6 +5,7 @@ mod tests; use core::ffi::c_void; +use super::env::{CommandEnv, CommandEnvs}; use crate::collections::BTreeMap; use crate::env::consts::{EXE_EXTENSION, EXE_SUFFIX}; use crate::ffi::{OsStr, OsString}; @@ -24,7 +25,6 @@ use crate::sys::pal::{ensure_no_nuls, fill_utf16_buf}; use crate::sys::pipe::{self, AnonPipe}; use crate::sys::{cvt, path, stdio}; use crate::sys_common::IntoInner; -use crate::sys_common::process::{CommandEnv, CommandEnvs}; use crate::{cmp, env, fmt, ptr}; //////////////////////////////////////////////////////////////////////////////// @@ -389,11 +389,6 @@ impl Command { )) } } - - pub fn output(&mut self) -> io::Result<(ExitStatus, Vec, Vec)> { - let (proc, pipes) = self.spawn(Stdio::MakePipe, false)?; - crate::sys_common::process::wait_with_output(proc, pipes) - } } impl fmt::Debug for Command { diff --git a/library/std/src/sys/sync/mutex/fuchsia.rs b/library/std/src/sys/sync/mutex/fuchsia.rs index 3d388a4564a3..cbb1926530f5 100644 --- a/library/std/src/sys/sync/mutex/fuchsia.rs +++ b/library/std/src/sys/sync/mutex/fuchsia.rs @@ -39,7 +39,7 @@ use crate::sync::atomic::Ordering::{Acquire, Relaxed, Release}; use crate::sync::atomic::{Atomic, AtomicU32}; -use crate::sys::futex::zircon::{ +use crate::sys::fuchsia::{ ZX_ERR_BAD_HANDLE, ZX_ERR_BAD_STATE, ZX_ERR_INVALID_ARGS, ZX_ERR_TIMED_OUT, ZX_ERR_WRONG_TYPE, ZX_OK, ZX_TIME_INFINITE, zx_futex_wait, zx_futex_wake_single_owner, zx_handle_t, zx_thread_self, @@ -83,13 +83,13 @@ impl Mutex { #[inline] pub fn try_lock(&self) -> bool { - let thread_self = unsafe { zx_thread_self() }; + let thread_self = zx_thread_self(); self.futex.compare_exchange(UNLOCKED, to_state(thread_self), Acquire, Relaxed).is_ok() } #[inline] pub fn lock(&self) { - let thread_self = unsafe { zx_thread_self() }; + let thread_self = zx_thread_self(); if let Err(state) = self.futex.compare_exchange(UNLOCKED, to_state(thread_self), Acquire, Relaxed) { diff --git a/library/std/src/sys_common/mod.rs b/library/std/src/sys_common/mod.rs index 2a5de7f66661..b7f4656fa370 100644 --- a/library/std/src/sys_common/mod.rs +++ b/library/std/src/sys_common/mod.rs @@ -20,7 +20,6 @@ #[cfg(test)] mod tests; -pub mod process; pub mod wstr; pub mod wtf8; diff --git a/library/std/tests/sync/mutex.rs b/library/std/tests/sync/mutex.rs index 88fb448d1ebf..ac82914d6de4 100644 --- a/library/std/tests/sync/mutex.rs +++ b/library/std/tests/sync/mutex.rs @@ -409,13 +409,13 @@ fn panic_while_mapping_unlocked_poison() { let _ = panic::catch_unwind(|| { let guard = lock.lock().unwrap(); - let _guard = MutexGuard::try_map::<(), _>(guard, |_| panic!()); + let _guard = MutexGuard::filter_map::<(), _>(guard, |_| panic!()); }); match lock.try_lock() { - Ok(_) => panic!("panicking in a MutexGuard::try_map closure should poison the Mutex"), + Ok(_) => panic!("panicking in a MutexGuard::filter_map closure should poison the Mutex"), Err(TryLockError::WouldBlock) => { - panic!("panicking in a MutexGuard::try_map closure should unlock the mutex") + panic!("panicking in a MutexGuard::filter_map closure should unlock the mutex") } Err(TryLockError::Poisoned(_)) => {} } @@ -437,13 +437,15 @@ fn panic_while_mapping_unlocked_poison() { let _ = panic::catch_unwind(|| { let guard = lock.lock().unwrap(); let guard = MutexGuard::map::<(), _>(guard, |val| val); - let _guard = MappedMutexGuard::try_map::<(), _>(guard, |_| panic!()); + let _guard = MappedMutexGuard::filter_map::<(), _>(guard, |_| panic!()); }); match lock.try_lock() { - Ok(_) => panic!("panicking in a MappedMutexGuard::try_map closure should poison the Mutex"), + Ok(_) => { + panic!("panicking in a MappedMutexGuard::filter_map closure should poison the Mutex") + } Err(TryLockError::WouldBlock) => { - panic!("panicking in a MappedMutexGuard::try_map closure should unlock the mutex") + panic!("panicking in a MappedMutexGuard::filter_map closure should unlock the mutex") } Err(TryLockError::Poisoned(_)) => {} } diff --git a/library/std/tests/sync/rwlock.rs b/library/std/tests/sync/rwlock.rs index d2c784aefcf6..1d55a1769483 100644 --- a/library/std/tests/sync/rwlock.rs +++ b/library/std/tests/sync/rwlock.rs @@ -517,16 +517,20 @@ fn panic_while_mapping_read_unlocked_no_poison() { let _ = panic::catch_unwind(|| { let guard = lock.read().unwrap(); - let _guard = RwLockReadGuard::try_map::<(), _>(guard, |_| panic!()); + let _guard = RwLockReadGuard::filter_map::<(), _>(guard, |_| panic!()); }); match lock.try_write() { Ok(_) => {} Err(TryLockError::WouldBlock) => { - panic!("panicking in a RwLockReadGuard::try_map closure should release the read lock") + panic!( + "panicking in a RwLockReadGuard::filter_map closure should release the read lock" + ) } Err(TryLockError::Poisoned(_)) => { - panic!("panicking in a RwLockReadGuard::try_map closure should not poison the RwLock") + panic!( + "panicking in a RwLockReadGuard::filter_map closure should not poison the RwLock" + ) } } @@ -549,16 +553,16 @@ fn panic_while_mapping_read_unlocked_no_poison() { let _ = panic::catch_unwind(|| { let guard = lock.read().unwrap(); let guard = RwLockReadGuard::map::<(), _>(guard, |val| val); - let _guard = MappedRwLockReadGuard::try_map::<(), _>(guard, |_| panic!()); + let _guard = MappedRwLockReadGuard::filter_map::<(), _>(guard, |_| panic!()); }); match lock.try_write() { Ok(_) => {} Err(TryLockError::WouldBlock) => panic!( - "panicking in a MappedRwLockReadGuard::try_map closure should release the read lock" + "panicking in a MappedRwLockReadGuard::filter_map closure should release the read lock" ), Err(TryLockError::Poisoned(_)) => panic!( - "panicking in a MappedRwLockReadGuard::try_map closure should not poison the RwLock" + "panicking in a MappedRwLockReadGuard::filter_map closure should not poison the RwLock" ), } @@ -585,15 +589,17 @@ fn panic_while_mapping_write_unlocked_poison() { let _ = panic::catch_unwind(|| { let guard = lock.write().unwrap(); - let _guard = RwLockWriteGuard::try_map::<(), _>(guard, |_| panic!()); + let _guard = RwLockWriteGuard::filter_map::<(), _>(guard, |_| panic!()); }); match lock.try_write() { Ok(_) => { - panic!("panicking in a RwLockWriteGuard::try_map closure should poison the RwLock") + panic!("panicking in a RwLockWriteGuard::filter_map closure should poison the RwLock") } Err(TryLockError::WouldBlock) => { - panic!("panicking in a RwLockWriteGuard::try_map closure should release the write lock") + panic!( + "panicking in a RwLockWriteGuard::filter_map closure should release the write lock" + ) } Err(TryLockError::Poisoned(_)) => {} } @@ -617,15 +623,15 @@ fn panic_while_mapping_write_unlocked_poison() { let _ = panic::catch_unwind(|| { let guard = lock.write().unwrap(); let guard = RwLockWriteGuard::map::<(), _>(guard, |val| val); - let _guard = MappedRwLockWriteGuard::try_map::<(), _>(guard, |_| panic!()); + let _guard = MappedRwLockWriteGuard::filter_map::<(), _>(guard, |_| panic!()); }); match lock.try_write() { Ok(_) => panic!( - "panicking in a MappedRwLockWriteGuard::try_map closure should poison the RwLock" + "panicking in a MappedRwLockWriteGuard::filter_map closure should poison the RwLock" ), Err(TryLockError::WouldBlock) => panic!( - "panicking in a MappedRwLockWriteGuard::try_map closure should release the write lock" + "panicking in a MappedRwLockWriteGuard::filter_map closure should release the write lock" ), Err(TryLockError::Poisoned(_)) => {} } diff --git a/library/stdarch b/library/stdarch index 1245618ccf5b..f1c1839c0deb 160000 --- a/library/stdarch +++ b/library/stdarch @@ -1 +1 @@ -Subproject commit 1245618ccf5b2df7ab1ebb0279b9f3f726670161 +Subproject commit f1c1839c0deb985a9f98cbd6b38a6d43f2df6157 diff --git a/library/sysroot/Cargo.toml b/library/sysroot/Cargo.toml index ec6ae31507e0..c149d513c32b 100644 --- a/library/sysroot/Cargo.toml +++ b/library/sysroot/Cargo.toml @@ -31,5 +31,4 @@ panic_immediate_abort = ["std/panic_immediate_abort"] profiler = ["dep:profiler_builtins"] std_detect_file_io = ["std/std_detect_file_io"] std_detect_dlsym_getauxval = ["std/std_detect_dlsym_getauxval"] -std_detect_env_override = ["std/std_detect_env_override"] windows_raw_dylib = ["std/windows_raw_dylib"] diff --git a/library/test/src/lib.rs b/library/test/src/lib.rs index acaf026c679b..7f56d1e36269 100644 --- a/library/test/src/lib.rs +++ b/library/test/src/lib.rs @@ -98,6 +98,15 @@ const SECONDARY_TEST_BENCH_BENCHMARKS_VAR: &str = "__RUST_TEST_BENCH_BENCHMARKS" // The default console test runner. It accepts the command line // arguments and a vector of test_descs. pub fn test_main(args: &[String], tests: Vec, options: Option) { + test_main_with_exit_callback(args, tests, options, || {}) +} + +pub fn test_main_with_exit_callback( + args: &[String], + tests: Vec, + options: Option, + exit_callback: F, +) { let mut opts = match cli::parse_opts(args) { Some(Ok(o)) => o, Some(Err(msg)) => { @@ -151,6 +160,7 @@ pub fn test_main(args: &[String], tests: Vec, options: Option {} Ok(false) => process::exit(ERROR_EXIT_CODE), diff --git a/library/windows_targets/src/lib.rs b/library/windows_targets/src/lib.rs index c7d158584ebd..bce54c5ffcef 100644 --- a/library/windows_targets/src/lib.rs +++ b/library/windows_targets/src/lib.rs @@ -34,6 +34,7 @@ pub macro link { } #[cfg(not(feature = "windows_raw_dylib"))] +#[cfg(not(target_os = "cygwin"))] // Cygwin doesn't need these libs #[cfg_attr(target_vendor = "win7", link(name = "advapi32"))] #[link(name = "ntdll")] #[link(name = "userenv")] diff --git a/rustfmt.toml b/rustfmt.toml index 7c384b876bf7..d9857a7e3e78 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -19,6 +19,7 @@ ignore = [ "/tests/debuginfo/", # These tests are somewhat sensitive to source code layout. "/tests/incremental/", # These tests are somewhat sensitive to source code layout. "/tests/pretty/", # These tests are very sensitive to source code layout. + "/tests/run-make/export", # These tests contain syntax errors. "/tests/run-make/translation/test.rs", # This test contains syntax errors. "/tests/rustdoc/", # Some have syntax errors, some are whitespace-sensitive. "/tests/rustdoc-gui/", # Some tests are sensitive to source code layout. diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock index d415668f54a7..cdad3bd46fab 100644 --- a/src/bootstrap/Cargo.lock +++ b/src/bootstrap/Cargo.lock @@ -64,7 +64,7 @@ dependencies = [ "tracing-subscriber", "tracing-tree", "walkdir", - "windows", + "windows 0.57.0", "xz2", ] @@ -158,12 +158,6 @@ dependencies = [ "cc", ] -[[package]] -name = "core-foundation-sys" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" - [[package]] name = "cpufeatures" version = "0.2.15" @@ -440,6 +434,25 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "objc2-core-foundation" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c10c2894a6fed806ade6027bcd50662746363a9589d3ec9d9bef30a4e4bc166" +dependencies = [ + "bitflags", +] + +[[package]] +name = "objc2-io-kit" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71c1c64d6120e51cd86033f67176b1cb66780c2efe34dec55176f77befd93c0a" +dependencies = [ + "libc", + "objc2-core-foundation", +] + [[package]] name = "object" version = "0.36.5" @@ -700,15 +713,16 @@ dependencies = [ [[package]] name = "sysinfo" -version = "0.33.0" +version = "0.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "948512566b1895f93b1592c7574baeb2de842f224f2aab158799ecadb8ebbb46" +checksum = "b897c8ea620e181c7955369a31be5f48d9a9121cb59fd33ecef9ff2a34323422" dependencies = [ - "core-foundation-sys", "libc", "memchr", "ntapi", - "windows", + "objc2-core-foundation", + "objc2-io-kit", + "windows 0.61.1", ] [[package]] @@ -927,22 +941,67 @@ version = "0.57.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "12342cb4d8e3b046f3d80effd474a7a02447231330ef77d71daa6fbc40681143" dependencies = [ - "windows-core", + "windows-core 0.57.0", "windows-targets", ] +[[package]] +name = "windows" +version = "0.61.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5ee8f3d025738cb02bad7868bbb5f8a6327501e870bf51f1b455b0a2454a419" +dependencies = [ + "windows-collections", + "windows-core 0.61.0", + "windows-future", + "windows-link", + "windows-numerics", +] + +[[package]] +name = "windows-collections" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" +dependencies = [ + "windows-core 0.61.0", +] + [[package]] name = "windows-core" version = "0.57.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2ed2439a290666cd67ecce2b0ffaad89c2a56b976b736e6ece670297897832d" dependencies = [ - "windows-implement", - "windows-interface", - "windows-result", + "windows-implement 0.57.0", + "windows-interface 0.57.0", + "windows-result 0.1.2", "windows-targets", ] +[[package]] +name = "windows-core" +version = "0.61.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980" +dependencies = [ + "windows-implement 0.60.0", + "windows-interface 0.59.1", + "windows-link", + "windows-result 0.3.2", + "windows-strings", +] + +[[package]] +name = "windows-future" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a1d6bbefcb7b60acd19828e1bc965da6fcf18a7e39490c5f8be71e54a19ba32" +dependencies = [ + "windows-core 0.61.0", + "windows-link", +] + [[package]] name = "windows-implement" version = "0.57.0" @@ -954,6 +1013,17 @@ dependencies = [ "syn", ] +[[package]] +name = "windows-implement" +version = "0.60.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "windows-interface" version = "0.57.0" @@ -965,6 +1035,33 @@ dependencies = [ "syn", ] +[[package]] +name = "windows-interface" +version = "0.59.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-link" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" + +[[package]] +name = "windows-numerics" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" +dependencies = [ + "windows-core 0.61.0", + "windows-link", +] + [[package]] name = "windows-result" version = "0.1.2" @@ -974,6 +1071,24 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "windows-result" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97" +dependencies = [ + "windows-link", +] + [[package]] name = "windows-sys" version = "0.52.0" diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index 712a9b04c1a1..e34de924cc18 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -58,7 +58,7 @@ walkdir = "2.4" xz2 = "0.1" # Dependencies needed by the build-metrics feature -sysinfo = { version = "0.33.0", default-features = false, optional = true, features = ["system"] } +sysinfo = { version = "0.35.0", default-features = false, optional = true, features = ["system"] } # Dependencies needed by the `tracing` feature tracing = { version = "0.1", optional = true, features = ["attributes"] } diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs index ae9511b78674..fa848c492b4d 100644 --- a/src/bootstrap/src/core/build_steps/check.rs +++ b/src/bootstrap/src/core/build_steps/check.rs @@ -527,3 +527,70 @@ tool_check_step!(Bootstrap { path: "src/bootstrap", default: false }); // `run-make-support` will be built as part of suitable run-make compiletest test steps, but support // check to make it easier to work on. tool_check_step!(RunMakeSupport { path: "src/tools/run-make-support", default: false }); + +/// Check step for the `coverage-dump` bootstrap tool. The coverage-dump tool +/// is used internally by coverage tests. +/// +/// FIXME(Zalathar): This is temporarily separate from the other tool check +/// steps so that it can use the stage 0 compiler instead of `top_stage`, +/// without introducing conflicts with the stage 0 redesign (#119899). +/// +/// After the stage 0 redesign lands, we can look into using the stage 0 +/// compiler to check all bootstrap tools (#139170). +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub(crate) struct CoverageDump; + +impl CoverageDump { + const PATH: &str = "src/tools/coverage-dump"; +} + +impl Step for CoverageDump { + type Output = (); + + /// Most contributors won't care about coverage-dump, so don't make their + /// check builds slower unless they opt in and check it explicitly. + const DEFAULT: bool = false; + const ONLY_HOSTS: bool = true; + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.path(Self::PATH) + } + + fn make_run(run: RunConfig<'_>) { + run.builder.ensure(Self {}); + } + + fn run(self, builder: &Builder<'_>) -> Self::Output { + // Make sure we haven't forgotten any fields, if there are any. + let Self {} = self; + let display_name = "coverage-dump"; + let host = builder.config.build; + let target = host; + let mode = Mode::ToolBootstrap; + + let compiler = builder.compiler(0, host); + let cargo = prepare_tool_cargo( + builder, + compiler, + mode, + target, + builder.kind, + Self::PATH, + SourceType::InTree, + &[], + ); + + let stamp = BuildStamp::new(&builder.cargo_out(compiler, mode, target)) + .with_prefix(&format!("{display_name}-check")); + + let _guard = builder.msg_tool( + builder.kind, + mode, + display_name, + compiler.stage, + &compiler.host, + &target, + ); + run_cargo(builder, cargo, builder.config.free_args.clone(), &stamp, vec![], true, false); + } +} diff --git a/src/bootstrap/src/core/build_steps/run.rs b/src/bootstrap/src/core/build_steps/run.rs index 5cacd5b99147..7ff385052940 100644 --- a/src/bootstrap/src/core/build_steps/run.rs +++ b/src/bootstrap/src/core/build_steps/run.rs @@ -392,3 +392,31 @@ impl Step for CyclicStep { builder.ensure(CyclicStep { n: self.n.saturating_sub(1) }) } } + +/// Step to manually run the coverage-dump tool (`./x run coverage-dump`). +/// +/// The coverage-dump tool is an internal detail of coverage tests, so this run +/// step is only needed when testing coverage-dump manually. +#[derive(Debug, PartialOrd, Ord, Clone, Hash, PartialEq, Eq)] +pub struct CoverageDump; + +impl Step for CoverageDump { + type Output = (); + + const DEFAULT: bool = false; + const ONLY_HOSTS: bool = true; + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.path("src/tools/coverage-dump") + } + + fn make_run(run: RunConfig<'_>) { + run.builder.ensure(Self {}); + } + + fn run(self, builder: &Builder<'_>) { + let mut cmd = builder.tool_cmd(Tool::CoverageDump); + cmd.args(&builder.config.free_args); + cmd.run(builder); + } +} diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index d4fccc535a6b..29fb576f5740 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -54,6 +54,7 @@ impl Step for CrateBootstrap { run.path("src/tools/jsondoclint") .path("src/tools/suggest-tests") .path("src/tools/replace-version-placeholder") + .path("src/tools/coverage-dump") // We want `./x test tidy` to _run_ the tidy tool, not its tests. // So we need a separate alias to test the tidy tool itself. .alias("tidyselftest") @@ -2556,9 +2557,9 @@ fn prepare_cargo_test( // We skip everything on Miri as then this overwrites the libdir set up // by `Cargo::new` and that actually makes things go wrong. if builder.kind != Kind::Miri { - let mut dylib_path = dylib_path(); - dylib_path.insert(0, PathBuf::from(&*builder.sysroot_target_libdir(compiler, target))); - cargo.env(dylib_path_var(), env::join_paths(&dylib_path).unwrap()); + let mut dylib_paths = builder.rustc_lib_paths(compiler); + dylib_paths.push(PathBuf::from(&builder.sysroot_target_libdir(compiler, target))); + helpers::add_dylib_path(dylib_paths, &mut cargo); } if builder.remote_tested(target) { diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs index 36b3c95d638c..d625c2ef5847 100644 --- a/src/bootstrap/src/core/builder/cargo.rs +++ b/src/bootstrap/src/core/builder/cargo.rs @@ -112,9 +112,8 @@ impl Cargo { let mut cargo = builder.cargo(compiler, mode, source_type, target, cmd_kind); match cmd_kind { - // No need to configure the target linker for these command types, - // as they don't invoke rustc at all. - Kind::Clean | Kind::Suggest | Kind::Format | Kind::Setup => {} + // No need to configure the target linker for these command types. + Kind::Clean | Kind::Check | Kind::Suggest | Kind::Format | Kind::Setup => {} _ => { cargo.configure_linker(builder); } @@ -205,6 +204,8 @@ impl Cargo { self } + // FIXME(onur-ozkan): Add coverage to make sure modifications to this function + // doesn't cause cache invalidations (e.g., #130108). fn configure_linker(&mut self, builder: &Builder<'_>) -> &mut Cargo { let target = self.target; let compiler = self.compiler; diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index c32d9c2870cf..15dc3380a39a 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -961,6 +961,7 @@ impl<'a> Builder<'a> { check::RunMakeSupport, check::Compiletest, check::FeaturesStatusDump, + check::CoverageDump, ), Kind::Test => describe!( crate::core::build_steps::toolstate::ToolStateCheck, @@ -1114,6 +1115,7 @@ impl<'a> Builder<'a> { run::UnicodeTableGenerator, run::FeaturesStatusDump, run::CyclicStep, + run::CoverageDump, ), Kind::Setup => { describe!(setup::Profile, setup::Hook, setup::Link, setup::Editor) @@ -1534,7 +1536,7 @@ impl<'a> Builder<'a> { let out = step.clone().run(self); let dur = start.elapsed(); let deps = self.time_spent_on_dependencies.replace(parent + dur); - (out, dur - deps) + (out, dur.saturating_sub(deps)) }; if self.config.print_step_timings && !self.config.dry_run() { diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index 88d181532a7f..1e6acad5c0fc 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -53,6 +53,7 @@ use tracing::{instrument, span}; pub use utils::change_tracker::{ CONFIG_CHANGE_HISTORY, find_recent_config_change_ids, human_readable_changes, }; +pub use utils::helpers::PanicTracker; use crate::core::build_steps::vendor::VENDOR_DIR; diff --git a/src/bootstrap/src/utils/cc_detect.rs b/src/bootstrap/src/utils/cc_detect.rs index 147b009d3f47..ceac24d4315c 100644 --- a/src/bootstrap/src/utils/cc_detect.rs +++ b/src/bootstrap/src/utils/cc_detect.rs @@ -96,6 +96,7 @@ pub fn find(build: &Build) { let targets: HashSet<_> = match build.config.cmd { // We don't need to check cross targets for these commands. crate::Subcommand::Clean { .. } + | crate::Subcommand::Check { .. } | crate::Subcommand::Suggest { .. } | crate::Subcommand::Format { .. } | crate::Subcommand::Setup { .. } => { diff --git a/src/bootstrap/src/utils/cc_detect/tests.rs b/src/bootstrap/src/utils/cc_detect/tests.rs index b4a1b52dd230..43d61ce02c5a 100644 --- a/src/bootstrap/src/utils/cc_detect/tests.rs +++ b/src/bootstrap/src/utils/cc_detect/tests.rs @@ -181,7 +181,7 @@ fn test_language_clang() { #[test] fn test_new_cc_build() { - let build = Build::new(Config { ..Config::parse(Flags::parse(&["check".to_owned()])) }); + let build = Build::new(Config { ..Config::parse(Flags::parse(&["build".to_owned()])) }); let target = TargetSelection::from_user("x86_64-unknown-linux-gnu"); let cfg = new_cc_build(&build, target.clone()); let compiler = cfg.get_compiler(); @@ -190,7 +190,7 @@ fn test_new_cc_build() { #[test] fn test_default_compiler_wasi() { - let build = Build::new(Config { ..Config::parse(Flags::parse(&["check".to_owned()])) }); + let build = Build::new(Config { ..Config::parse(Flags::parse(&["build".to_owned()])) }); let target = TargetSelection::from_user("wasm32-wasi"); let wasi_sdk = PathBuf::from("/wasi-sdk"); // SAFETY: bootstrap tests run on a single thread @@ -215,7 +215,7 @@ fn test_default_compiler_wasi() { #[test] fn test_default_compiler_fallback() { - let build = Build::new(Config { ..Config::parse(Flags::parse(&["check".to_owned()])) }); + let build = Build::new(Config { ..Config::parse(Flags::parse(&["build".to_owned()])) }); let target = TargetSelection::from_user("x86_64-unknown-linux-gnu"); let mut cfg = cc::Build::new(); let result = default_compiler(&mut cfg, Language::C, target, &build); @@ -224,7 +224,7 @@ fn test_default_compiler_fallback() { #[test] fn test_find_target_with_config() { - let mut build = Build::new(Config { ..Config::parse(Flags::parse(&["check".to_owned()])) }); + let mut build = Build::new(Config { ..Config::parse(Flags::parse(&["build".to_owned()])) }); let target = TargetSelection::from_user("x86_64-unknown-linux-gnu"); let mut target_config = Target::default(); target_config.cc = Some(PathBuf::from("dummy-cc")); @@ -249,7 +249,7 @@ fn test_find_target_with_config() { #[test] fn test_find_target_without_config() { - let mut build = Build::new(Config { ..Config::parse(Flags::parse(&["check".to_owned()])) }); + let mut build = Build::new(Config { ..Config::parse(Flags::parse(&["build".to_owned()])) }); let target = TargetSelection::from_user("x86_64-unknown-linux-gnu"); build.config.target_config.clear(); find_target(&build, target.clone()); @@ -262,7 +262,7 @@ fn test_find_target_without_config() { #[test] fn test_find() { - let mut build = Build::new(Config { ..Config::parse(Flags::parse(&["check".to_owned()])) }); + let mut build = Build::new(Config { ..Config::parse(Flags::parse(&["build".to_owned()])) }); let target1 = TargetSelection::from_user("x86_64-unknown-linux-gnu"); let target2 = TargetSelection::from_user("x86_64-unknown-openbsd"); build.targets.push(target1.clone()); diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs index 1299fbb7d629..b31b2757767c 100644 --- a/src/bootstrap/src/utils/helpers.rs +++ b/src/bootstrap/src/utils/helpers.rs @@ -7,8 +7,9 @@ use std::ffi::OsStr; use std::path::{Path, PathBuf}; use std::process::{Command, Stdio}; use std::sync::OnceLock; +use std::thread::panicking; use std::time::{Instant, SystemTime, UNIX_EPOCH}; -use std::{env, fs, io, str}; +use std::{env, fs, io, panic, str}; use build_helper::util::fail; use object::read::archive::ArchiveFile; @@ -22,6 +23,23 @@ pub use crate::utils::shared_helpers::{dylib_path, dylib_path_var}; #[cfg(test)] mod tests; +/// A wrapper around `std::panic::Location` used to track the location of panics +/// triggered by `t` macro usage. +pub struct PanicTracker<'a>(pub &'a panic::Location<'a>); + +impl Drop for PanicTracker<'_> { + fn drop(&mut self) { + if panicking() { + eprintln!( + "Panic was initiated from {}:{}:{}", + self.0.file(), + self.0.line(), + self.0.column() + ); + } + } +} + /// A helper macro to `unwrap` a result except also print out details like: /// /// * The file/line of the panic @@ -32,19 +50,21 @@ mod tests; /// using a `Result` with `try!`, but this may change one day... #[macro_export] macro_rules! t { - ($e:expr) => { + ($e:expr) => {{ + let _panic_guard = $crate::PanicTracker(std::panic::Location::caller()); match $e { Ok(e) => e, Err(e) => panic!("{} failed with {}", stringify!($e), e), } - }; + }}; // it can show extra info in the second parameter - ($e:expr, $extra:expr) => { + ($e:expr, $extra:expr) => {{ + let _panic_guard = $crate::PanicTracker(std::panic::Location::caller()); match $e { Ok(e) => e, Err(e) => panic!("{} failed with {} ({:?})", stringify!($e), e, $extra), } - }; + }}; } pub use t; diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version index 3428dd4826a7..e15121e0f316 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version +++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version @@ -1 +1 @@ -0.20.3 \ No newline at end of file +0.20.6 \ No newline at end of file diff --git a/src/doc/reference b/src/doc/reference index 3bf3402aea98..387392674d74 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit 3bf3402aea982b876eb56c87da17b0685c6461d5 +Subproject commit 387392674d74656f7cb437c05a96f0c52ea8e601 diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example index 0d7964d5b22c..8a8918c69853 160000 --- a/src/doc/rust-by-example +++ b/src/doc/rust-by-example @@ -1 +1 @@ -Subproject commit 0d7964d5b22cf920237ef1282d869564b4883b88 +Subproject commit 8a8918c698534547fa8a1a693cb3e7277f0bfb2f diff --git a/src/doc/rustc-dev-guide/src/mir/dataflow.md b/src/doc/rustc-dev-guide/src/mir/dataflow.md index f31da5ca22ee..85e57dd839b8 100644 --- a/src/doc/rustc-dev-guide/src/mir/dataflow.md +++ b/src/doc/rustc-dev-guide/src/mir/dataflow.md @@ -148,8 +148,7 @@ whereas this code uses [`ResultsCursor`]: ```rust,ignore let mut results = MyAnalysis::new() - .into_engine(tcx, body, def_id) - .iterate_to_fixpoint() + .iterate_to_fixpoint(tcx, body, None); .into_results_cursor(body); // Inspect the fixpoint state immediately before each `Drop` terminator. diff --git a/src/doc/rustc-dev-guide/src/tests/ui.md b/src/doc/rustc-dev-guide/src/tests/ui.md index b31c861c947a..721d20b65c5a 100644 --- a/src/doc/rustc-dev-guide/src/tests/ui.md +++ b/src/doc/rustc-dev-guide/src/tests/ui.md @@ -344,8 +344,7 @@ For checking runtime output, `//@ check-run-results` may be preferable. Only use `error-pattern` if none of the above works. -Line annotations `//~` are still checked in tests using `error-pattern`. -In exceptional cases, use `//@ compile-flags: --error-format=human` to opt out of these checks. +Line annotations `//~` and `error-pattern` are compatible and can be used in the same test. ### Diagnostic kinds (error levels) @@ -356,9 +355,12 @@ The diagnostic kinds that you can have are: - `NOTE` - `HELP` - `SUGGESTION` +- `RAW` The `SUGGESTION` kind is used for specifying what the expected replacement text should be for a diagnostic suggestion. +The `RAW` kind can be used for matching on lines from non-structured output sometimes emitted +by the compiler instead of or in addition to structured json. `ERROR` and `WARN` kinds are required to be exhaustively covered by line annotations `//~` by default. diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index cf41f5b86a85..a3939e5a5c45 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -58,6 +58,7 @@ - [thumbv7m-none-eabi](./platform-support/thumbv7m-none-eabi.md) - [thumbv8m.base-none-eabi](./platform-support/thumbv8m.base-none-eabi.md) - [thumbv8m.main-none-eabi\*](./platform-support/thumbv8m.main-none-eabi.md) + - [armv5te-unknown-linux-gnueabi](platform-support/armv5te-unknown-linux-gnueabi.md) - [armv6k-nintendo-3ds](platform-support/armv6k-nintendo-3ds.md) - [armv7-rtems-eabihf](platform-support/armv7-rtems-eabihf.md) - [armv7-sony-vita-newlibeabihf](platform-support/armv7-sony-vita-newlibeabihf.md) diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 50c7ae3ef8db..60002a5f9e5d 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -156,7 +156,7 @@ target | std | notes [`arm64ec-pc-windows-msvc`](platform-support/arm64ec-pc-windows-msvc.md) | ✓ | Arm64EC Windows MSVC [`armebv7r-none-eabi`](platform-support/armv7r-none-eabi.md) | * | Bare Armv7-R, Big Endian [`armebv7r-none-eabihf`](platform-support/armv7r-none-eabi.md) | * | Bare Armv7-R, Big Endian, hardfloat -`armv5te-unknown-linux-gnueabi` | ✓ | Armv5TE Linux (kernel 4.4, glibc 2.23) +[`armv5te-unknown-linux-gnueabi`](platform-support/armv5te-unknown-linux-gnueabi.md) | ✓ | Armv5TE Linux (kernel 4.4, glibc 2.23) `armv5te-unknown-linux-musleabi` | ✓ | Armv5TE Linux with musl 1.2.3 [`armv7-linux-androideabi`](platform-support/android.md) | ✓ | Armv7-A Android `armv7-unknown-linux-gnueabi` | ✓ | Armv7-A Linux (kernel 4.15, glibc 2.27) diff --git a/src/doc/rustc/src/platform-support/armv5te-unknown-linux-gnueabi.md b/src/doc/rustc/src/platform-support/armv5te-unknown-linux-gnueabi.md new file mode 100644 index 000000000000..1baf1049994b --- /dev/null +++ b/src/doc/rustc/src/platform-support/armv5te-unknown-linux-gnueabi.md @@ -0,0 +1,29 @@ +# `armv5te-unknown-linux-gnueabi` + +**Tier: 2** + +This target supports Linux programs with glibc on ARMv5TE CPUs without +floating-point units. + +## Target maintainers + +[@koalatux](https://github.com/koalatux) + +## Requirements + +The target is for cross-compilation only. Host tools are not supported. +std is fully supported. + +## Building the target + +Because this target is tier 2, artifacts are available from rustup. + +## Building Rust programs + +For building rust programs, you might want to specify GCC as linker in +`.cargo/config.toml` as follows: + +```toml +[target.armv5te-unknown-linux-gnueabi] +linker = "arm-linux-gnueabi-gcc" +``` diff --git a/src/doc/rustc/src/platform-support/riscv32im-risc0-zkvm-elf.md b/src/doc/rustc/src/platform-support/riscv32im-risc0-zkvm-elf.md index 09b42da26e74..1d02a7cfbc0b 100644 --- a/src/doc/rustc/src/platform-support/riscv32im-risc0-zkvm-elf.md +++ b/src/doc/rustc/src/platform-support/riscv32im-risc0-zkvm-elf.md @@ -8,7 +8,6 @@ RISC Zero's Zero Knowledge Virtual Machine (zkVM) implementing the RV32IM instru [@flaub](https://github.com/flaub) [@jbruestle](https://github.com/jbruestle) -[@SchmErik](https://github.com/SchmErik) ## Background diff --git a/src/doc/style-guide/src/nightly.md b/src/doc/style-guide/src/nightly.md index d870edf18882..66e7fa3c9f89 100644 --- a/src/doc/style-guide/src/nightly.md +++ b/src/doc/style-guide/src/nightly.md @@ -5,15 +5,3 @@ This chapter documents style and formatting for nightly-only syntax. The rest of Style and formatting for nightly-only syntax should be removed from this chapter and integrated into the appropriate sections of the style guide at the time of stabilization. There is no guarantee of the stability of this chapter in contrast to the rest of the style guide. Refer to the style team policy for nightly formatting procedure regarding breaking changes to this chapter. - -### `feature(precise_capturing)` - -A `use<'a, T>` precise capturing bound is formatted as if it were a single path segment with non-turbofished angle-bracketed args, like a trait bound whose identifier is `use`. - -``` -fn foo() -> impl Sized + use<'a> {} - -// is formatted analogously to: - -fn foo() -> impl Sized + Use<'a> {} -``` diff --git a/src/doc/style-guide/src/types.md b/src/doc/style-guide/src/types.md index b7921c8914e4..247f05b57695 100644 --- a/src/doc/style-guide/src/types.md +++ b/src/doc/style-guide/src/types.md @@ -59,3 +59,15 @@ Box< + Debug > ``` + +## Precise capturing bounds + +A `use<'a, T>` precise capturing bound is formatted as if it were a single path segment with non-turbofished angle-bracketed args, like a trait bound whose identifier is `use`. + +```rust +fn foo() -> impl Sized + use<'a> {} + +// is formatted analogously to: + +fn foo() -> impl Sized + Use<'a> {} +``` diff --git a/src/doc/unstable-book/src/language-features/arbitrary-self-types.md b/src/doc/unstable-book/src/language-features/arbitrary-self-types.md index 2f8b52d40439..d660dd13fe47 100644 --- a/src/doc/unstable-book/src/language-features/arbitrary-self-types.md +++ b/src/doc/unstable-book/src/language-features/arbitrary-self-types.md @@ -2,7 +2,7 @@ The tracking issue for this feature is: [#44874] -[#38788]: https://github.com/rust-lang/rust/issues/44874 +[#44874]: https://github.com/rust-lang/rust/issues/44874 ------------------------ diff --git a/src/doc/unstable-book/src/language-features/deref-patterns.md b/src/doc/unstable-book/src/language-features/deref-patterns.md index 0cc7106da48f..4c3d456b9af8 100644 --- a/src/doc/unstable-book/src/language-features/deref-patterns.md +++ b/src/doc/unstable-book/src/language-features/deref-patterns.md @@ -60,20 +60,30 @@ Like [`box_patterns`], deref patterns may move out of boxes: # #![feature(deref_patterns)] # #![allow(incomplete_features)] struct NoCopy; -// Match exhaustiveness analysis is not yet implemented. -let deref!(x) = Box::new(NoCopy) else { unreachable!() }; +let deref!(x) = Box::new(NoCopy); drop::(x); ``` -Additionally, when `deref_patterns` is enabled, string literal patterns may be written where `str` -is expected. Likewise, byte string literal patterns may be written where `[u8]` or `[u8; _]` is -expected. This lets them be used in `deref!(_)` patterns: +Additionally, `deref_patterns` implements changes to string and byte string literal patterns, +allowing then to be used in deref patterns: ```rust # #![feature(deref_patterns)] # #![allow(incomplete_features)] -match ("test".to_string(), b"test".to_vec()) { - (deref!("test"), deref!(b"test")) => {} +match ("test".to_string(), Box::from("test"), b"test".to_vec()) { + ("test", "test", b"test") => {} + _ => panic!(), +} + +// This works through multiple layers of reference and smart pointer: +match (&Box::new(&"test".to_string()), &&&"test") { + ("test", "test") => {} + _ => panic!(), +} + +// `deref!("...")` syntax may also be used: +match "test".to_string() { + deref!("test") => {} _ => panic!(), } @@ -82,10 +92,16 @@ match *"test" { "test" => {} _ => panic!(), } +match *b"test" { + b"test" => {} + _ => panic!(), +} +match *(b"test" as &[u8]) { + b"test" => {} + _ => panic!(), +} ``` -Implicit deref pattern syntax is not yet supported for string or byte string literals. - [`box_patterns`]: ./box-patterns.md [`string_deref_patterns`]: ./string-deref-patterns.md [smart pointers in the standard library]: https://doc.rust-lang.org/std/ops/trait.DerefPure.html#implementors diff --git a/src/doc/unstable-book/src/language-features/f128.md b/src/doc/unstable-book/src/language-features/f128.md index 0cc5f6772302..b523ffe10f25 100644 --- a/src/doc/unstable-book/src/language-features/f128.md +++ b/src/doc/unstable-book/src/language-features/f128.md @@ -6,4 +6,4 @@ The tracking issue for this feature is: [#116909] --- -Enable the `f128` type for IEEE 128-bit floating numbers (quad precision). +Enable the `f128` type for IEEE 128-bit floating numbers (quad precision). diff --git a/src/doc/unstable-book/src/language-features/f16.md b/src/doc/unstable-book/src/language-features/f16.md index efb07a5146d4..5f31dcbb06c0 100644 --- a/src/doc/unstable-book/src/language-features/f16.md +++ b/src/doc/unstable-book/src/language-features/f16.md @@ -6,4 +6,4 @@ The tracking issue for this feature is: [#116909] --- -Enable the `f16` type for IEEE 16-bit floating numbers (half precision). +Enable the `f16` type for IEEE 16-bit floating numbers (half precision). diff --git a/src/doc/unstable-book/src/language-features/frontmatter.md b/src/doc/unstable-book/src/language-features/frontmatter.md new file mode 100644 index 000000000000..1d5b4feb6ac1 --- /dev/null +++ b/src/doc/unstable-book/src/language-features/frontmatter.md @@ -0,0 +1,25 @@ +# `frontmatter` + +The tracking issue for this feature is: [#136889] + +------ + +The `frontmatter` feature allows an extra metadata block at the top of files for consumption by +external tools. For example, it can be used by [`cargo-script`] files to specify dependencies. + +```rust +#!/usr/bin/env -S cargo -Zscript +--- +[dependencies] +libc = "0.2.172" +--- +#![feature(frontmatter)] +# mod libc { pub type c_int = i32; } + +fn main() { + let x: libc::c_int = 1i32; +} +``` + +[#136889]: https://github.com/rust-lang/rust/issues/136889 +[`cargo-script`]: https://rust-lang.github.io/rfcs/3502-cargo-script.html diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index 27ae0553c60d..dbfdd8ebd167 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -14,7 +14,6 @@ base64 = "0.21.7" itertools = "0.12" indexmap = "2" minifier = { version = "0.3.5", default-features = false } -pulldown-cmark-old = { version = "0.9.6", package = "pulldown-cmark", default-features = false } pulldown-cmark-escape = { version = "0.11.0", features = ["simd"] } regex = "1" rustdoc-json-types = { path = "../rustdoc-json-types" } diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 829a9ca6e7dd..0cdf2f92a891 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -262,11 +262,21 @@ pub(crate) fn run(dcx: DiagCtxtHandle<'_>, input: Input, options: RustdocOptions Ok(None) => return, Err(error) => { eprintln!("{error}"); + // Since some files in the temporary folder are still owned and alive, we need + // to manually remove the folder. + let _ = std::fs::remove_dir_all(temp_dir.path()); std::process::exit(1); } }; - run_tests(opts, &rustdoc_options, &unused_extern_reports, standalone_tests, mergeable_tests); + run_tests( + opts, + &rustdoc_options, + &unused_extern_reports, + standalone_tests, + mergeable_tests, + Some(temp_dir), + ); let compiling_test_count = compiling_test_count.load(Ordering::SeqCst); @@ -316,6 +326,8 @@ pub(crate) fn run_tests( unused_extern_reports: &Arc>>, mut standalone_tests: Vec, mergeable_tests: FxIndexMap>, + // We pass this argument so we can drop it manually before using `exit`. + mut temp_dir: Option, ) { let mut test_args = Vec::with_capacity(rustdoc_options.test_args.len() + 1); test_args.insert(0, "rustdoctest".to_string()); @@ -382,9 +394,14 @@ pub(crate) fn run_tests( // `running 0 tests...`. if ran_edition_tests == 0 || !standalone_tests.is_empty() { standalone_tests.sort_by(|a, b| a.desc.name.as_slice().cmp(b.desc.name.as_slice())); - test::test_main(&test_args, standalone_tests, None); + test::test_main_with_exit_callback(&test_args, standalone_tests, None, || { + // We ensure temp dir destructor is called. + std::mem::drop(temp_dir.take()); + }); } if nb_errors != 0 { + // We ensure temp dir destructor is called. + std::mem::drop(temp_dir); // libtest::ERROR_EXIT_CODE is not public but it's the same value. std::process::exit(101); } @@ -450,7 +467,7 @@ enum TestFailure { } enum DirState { - Temp(tempfile::TempDir), + Temp(TempDir), Perm(PathBuf), } diff --git a/src/librustdoc/doctest/make.rs b/src/librustdoc/doctest/make.rs index 4194abc8d574..d4fbfb12582e 100644 --- a/src/librustdoc/doctest/make.rs +++ b/src/librustdoc/doctest/make.rs @@ -301,8 +301,6 @@ fn parse_source(source: &str, crate_name: &Option<&str>) -> Result) -> Result) -> Result) -> bool { let mut is_extern_crate = false; if !info.has_global_allocator @@ -351,8 +347,6 @@ fn parse_source(source: &str, crate_name: &Option<&str>) -> Result { - // We only push if it's the top item because otherwise, we would duplicate - // its content since the top-level item was already added. if fn_item.ident.name == sym::main { info.has_main_fn = true; } @@ -412,7 +406,32 @@ fn parse_source(source: &str, crate_name: &Option<&str>) -> Result { - is_extern_crate = check_item(&item, &mut info, crate_name); + is_extern_crate = check_item(item, &mut info, crate_name); + } + // We assume that the macro calls will expand to item(s) even though they could + // expand to statements and expressions. + StmtKind::MacCall(ref mac_call) => { + if !info.has_main_fn { + // For backward compatibility, we look for the token sequence `fn main(…)` + // in the macro input (!) to crudely detect main functions "masked by a + // wrapper macro". For the record, this is a horrible heuristic! + // See . + let mut iter = mac_call.mac.args.tokens.iter(); + while let Some(token) = iter.next() { + if let TokenTree::Token(token, _) = token + && let TokenKind::Ident(kw::Fn, _) = token.kind + && let Some(TokenTree::Token(ident, _)) = iter.peek() + && let TokenKind::Ident(sym::main, _) = ident.kind + && let Some(TokenTree::Delimited(.., Delimiter::Parenthesis, _)) = { + iter.next(); + iter.peek() + } + { + info.has_main_fn = true; + break; + } + } + } } StmtKind::Expr(ref expr) => { if matches!(expr.kind, ast::ExprKind::Err(_)) { @@ -421,35 +440,7 @@ fn parse_source(source: &str, crate_name: &Option<&str>) -> Result { - if info.has_main_fn { - continue; - } - let mut iter = mac_call.mac.args.tokens.iter(); - - while let Some(token) = iter.next() { - if let TokenTree::Token(token, _) = token - && let TokenKind::Ident(name, _) = token.kind - && name == kw::Fn - && let Some(TokenTree::Token(fn_token, _)) = iter.peek() - && let TokenKind::Ident(fn_name, _) = fn_token.kind - && fn_name == sym::main - && let Some(TokenTree::Delimited(_, _, Delimiter::Parenthesis, _)) = { - iter.next(); - iter.peek() - } - { - info.has_main_fn = true; - break; - } - } - } - _ => { - has_non_items = true; - } + StmtKind::Let(_) | StmtKind::Semi(_) | StmtKind::Empty => has_non_items = true, } // Weirdly enough, the `Stmt` span doesn't include its attributes, so we need to diff --git a/src/librustdoc/doctest/markdown.rs b/src/librustdoc/doctest/markdown.rs index 497a8d7c4a75..b3a3ce08a05a 100644 --- a/src/librustdoc/doctest/markdown.rs +++ b/src/librustdoc/doctest/markdown.rs @@ -116,6 +116,7 @@ pub(crate) fn test(input: &Input, options: Options) -> Result<(), String> { &Arc::new(Mutex::new(Vec::new())), standalone_tests, mergeable_tests, + None, ); Ok(()) } diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index c943d3ad4d05..2db1ea8450ce 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -9,7 +9,7 @@ use std::collections::VecDeque; use std::fmt::{Display, Write}; use rustc_data_structures::fx::FxIndexMap; -use rustc_lexer::{Cursor, LiteralKind, TokenKind}; +use rustc_lexer::{Cursor, FrontmatterAllowed, LiteralKind, TokenKind}; use rustc_span::edition::Edition; use rustc_span::symbol::Symbol; use rustc_span::{BytePos, DUMMY_SP, Span}; @@ -638,7 +638,8 @@ impl<'src> Classifier<'src> { /// Takes as argument the source code to HTML-ify, the rust edition to use and the source code /// file span which will be used later on by the `span_correspondence_map`. fn new(src: &'src str, file_span: Span, decoration_info: Option<&DecorationInfo>) -> Self { - let tokens = PeekIter::new(TokenIter { src, cursor: Cursor::new(src) }); + let tokens = + PeekIter::new(TokenIter { src, cursor: Cursor::new(src, FrontmatterAllowed::Yes) }); let decorations = decoration_info.map(Decorations::new); Classifier { tokens, @@ -884,6 +885,7 @@ impl<'src> Classifier<'src> { | TokenKind::At | TokenKind::Tilde | TokenKind::Colon + | TokenKind::Frontmatter { .. } | TokenKind::Unknown => return no_highlight(sink), TokenKind::Question => Class::QuestionMark, diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 19ac24a5d6e3..f838f3f1106f 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -55,6 +55,9 @@ xmlns="http://www.w3.org/2000/svg" fill="black" height="18px">\ --collapse-arrow-image: url('data:image/svg+xml,'); + --hamburger-image: url('data:image/svg+xml,\ + '); } :root.sans-serif { @@ -2001,9 +2004,11 @@ a.tooltip:hover::after { display: flex; margin-right: 4px; position: fixed; - left: 6px; height: 34px; width: 34px; +} +.hide-sidebar #sidebar-button { + left: 6px; background-color: var(--main-background-color); z-index: 1; } @@ -2019,6 +2024,8 @@ a.tooltip:hover::after { align-items: center; justify-content: center; flex-direction: column; +} +#settings-menu > a, #help-button > a, button#toggle-all-docs { border: 1px solid transparent; border-radius: var(--button-border-radius); color: var(--main-color); @@ -2031,14 +2038,15 @@ a.tooltip:hover::after { min-width: 0; } #sidebar-button > a { - background-color: var(--button-background-color); - border-color: var(--border-color); + background-color: var(--sidebar-background-color); width: 33px; } +#sidebar-button > a:hover, #sidebar-button > a:focus-visible { + background-color: var(--main-background-color); +} #settings-menu > a:hover, #settings-menu > a:focus-visible, #help-button > a:hover, #help-button > a:focus-visible, -#sidebar-button > a:hover, #sidebar-button > a:focus-visible, button#toggle-all-docs:hover, button#toggle-all-docs:focus-visible { border-color: var(--settings-button-border-focus); text-decoration: none; @@ -2405,10 +2413,9 @@ However, it's not needed with smaller screen width because the doc/code block is use hamburger button */ .src #sidebar-button > a::before, .sidebar-menu-toggle::before { /* hamburger button image */ - content: url('data:image/svg+xml,\ - '); + content: var(--hamburger-image); opacity: 0.75; + filter: var(--mobile-sidebar-menu-filter); } .sidebar-menu-toggle:hover::before, .sidebar-menu-toggle:active::before, @@ -2416,17 +2423,6 @@ However, it's not needed with smaller screen width because the doc/code block is opacity: 1; } -/* src sidebar button opens a folder view */ -.src #sidebar-button > a::before { - /* folder image */ - content: url('data:image/svg+xml,\ - \ - \ - '); - opacity: 0.75; -} - /* Media Queries */ /* Make sure all the buttons line wrap at the same time */ @@ -2611,9 +2607,6 @@ in src-script.js and main.js width: 22px; height: 22px; } - .sidebar-menu-toggle::before { - filter: var(--mobile-sidebar-menu-filter); - } .sidebar-menu-toggle:hover { background: var(--main-background-color); } @@ -2671,6 +2664,14 @@ in src-script.js and main.js margin: 0 0 -25px 0; padding: var(--nav-sub-mobile-padding); } + + html:not(.src-sidebar-expanded) .src #sidebar-button > a { + background-color: var(--main-background-color); + } + html:not(.src-sidebar-expanded) .src #sidebar-button > a:hover, + html:not(.src-sidebar-expanded) .src #sidebar-button > a:focus-visible { + background-color: var(--sidebar-background-color); + } } diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 44bd96a7e450..bca40b8117bd 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -170,12 +170,28 @@ pub fn main() { // NOTE: this compiles both versions of tracing unconditionally, because // - The compile time hit is not that bad, especially compared to rustdoc's incremental times, and // - Otherwise, there's no warning that logging is being ignored when `download-rustc` is enabled - // NOTE: The reason this doesn't show double logging when `download-rustc = false` and - // `debug_logging = true` is because all rustc logging goes to its version of tracing (the one - // in the sysroot), and all of rustdoc's logging goes to its version (the one in Cargo.toml). - init_logging(&early_dcx); - rustc_driver::init_logger(&early_dcx, rustc_log::LoggerConfig::from_env("RUSTDOC_LOG")); + crate::init_logging(&early_dcx); + match rustc_log::init_logger(rustc_log::LoggerConfig::from_env("RUSTDOC_LOG")) { + Ok(()) => {} + // With `download-rustc = true` there are definitely 2 distinct tracing crates in the + // dependency graph: one in the downloaded sysroot and one built just now as a dependency of + // rustdoc. So the sysroot's tracing is definitely not yet initialized here. + // + // But otherwise, depending on link style, there may or may not be 2 tracing crates in play. + // The one we just initialized in `crate::init_logging` above is rustdoc's direct dependency + // on tracing. When rustdoc is built by x.py using Cargo, rustc_driver's and rustc_log's + // tracing dependency is distinct from this one and also needs to be initialized (using the + // same RUSTDOC_LOG environment variable for both). Other build systems may use just a + // single tracing crate throughout the rustc and rustdoc build. + // + // The reason initializing 2 tracings does not show double logging when `download-rustc = + // false` and `debug_logging = true` is because all rustc logging goes only to its version + // of tracing (the one in the sysroot) and all of rustdoc's logging only goes to its version + // (the one in Cargo.toml). + Err(rustc_log::Error::AlreadyInit(_)) => {} + Err(error) => early_dcx.early_fatal(error.to_string()), + } let exit_code = rustc_driver::catch_with_exit_code(|| { let at_args = rustc_driver::args::raw_args(&early_dcx); diff --git a/src/librustdoc/lint.rs b/src/librustdoc/lint.rs index dcc27cd62e38..b09ea0568859 100644 --- a/src/librustdoc/lint.rs +++ b/src/librustdoc/lint.rs @@ -196,14 +196,6 @@ declare_rustdoc_lint! { "detects redundant explicit links in doc comments" } -declare_rustdoc_lint! { - /// This compatibility lint checks for Markdown syntax that works in the old engine but not - /// the new one. - UNPORTABLE_MARKDOWN, - Warn, - "detects markdown that is interpreted differently in different parser" -} - pub(crate) static RUSTDOC_LINTS: Lazy> = Lazy::new(|| { vec![ BROKEN_INTRA_DOC_LINKS, @@ -217,7 +209,6 @@ pub(crate) static RUSTDOC_LINTS: Lazy> = Lazy::new(|| { MISSING_CRATE_LEVEL_DOCS, UNESCAPED_BACKTICKS, REDUNDANT_EXPLICIT_LINKS, - UNPORTABLE_MARKDOWN, ] }); @@ -241,4 +232,5 @@ pub(crate) fn register_lints(_sess: &Session, lint_store: &mut LintStore) { .register_renamed("intra_doc_link_resolution_failure", "rustdoc::broken_intra_doc_links"); lint_store.register_renamed("non_autolinks", "rustdoc::bare_urls"); lint_store.register_renamed("rustdoc::non_autolinks", "rustdoc::bare_urls"); + lint_store.register_removed("rustdoc::unportable_markdown", "old parser removed"); } diff --git a/src/librustdoc/passes/lint.rs b/src/librustdoc/passes/lint.rs index 1ecb53e61ac3..7740d14148bf 100644 --- a/src/librustdoc/passes/lint.rs +++ b/src/librustdoc/passes/lint.rs @@ -6,7 +6,6 @@ mod check_code_block_syntax; mod html_tags; mod redundant_explicit_links; mod unescaped_backticks; -mod unportable_markdown; use super::Pass; use crate::clean::*; @@ -49,9 +48,6 @@ impl DocVisitor<'_> for Linter<'_, '_> { } if may_have_block_comment_or_html { html_tags::visit_item(self.cx, item, hir_id, &dox); - unportable_markdown::visit_item(self.cx, item, hir_id, &dox); - } else if may_have_link { - unportable_markdown::visit_item(self.cx, item, hir_id, &dox); } } diff --git a/src/librustdoc/passes/lint/unportable_markdown.rs b/src/librustdoc/passes/lint/unportable_markdown.rs deleted file mode 100644 index 95646413a2d2..000000000000 --- a/src/librustdoc/passes/lint/unportable_markdown.rs +++ /dev/null @@ -1,145 +0,0 @@ -//! Detects specific markdown syntax that's different between pulldown-cmark -//! 0.9 and 0.11. -//! -//! This is a mitigation for old parser bugs that affected some -//! real crates' docs. The old parser claimed to comply with CommonMark, -//! but it did not. These warnings will eventually be removed, -//! though some of them may become Clippy lints. -//! -//! -//! -//! - -use std::collections::{BTreeMap, BTreeSet}; - -use rustc_hir::HirId; -use rustc_lint_defs::Applicability; -use rustc_resolve::rustdoc::source_span_for_markdown_range; -use {pulldown_cmark as cmarkn, pulldown_cmark_old as cmarko}; - -use crate::clean::Item; -use crate::core::DocContext; - -pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item, hir_id: HirId, dox: &str) { - let tcx = cx.tcx; - - // P1: unintended strikethrough was fixed by requiring single-tildes to flank - // the same way underscores do, so nothing is done here - - // P2: block quotes without following space parsed wrong - // - // This is the set of starting points for block quotes with no space after - // the `>`. It is populated by the new parser, and if the old parser fails to - // clear it out, it'll produce a warning. - let mut spaceless_block_quotes = BTreeSet::new(); - - // P3: missing footnote references - // - // This is populated by listening for FootnoteReference from - // the new parser and old parser. - let mut missing_footnote_references = BTreeMap::new(); - let mut found_footnote_references = BTreeSet::new(); - - // populate problem cases from new parser - { - pub fn main_body_opts_new() -> cmarkn::Options { - cmarkn::Options::ENABLE_TABLES - | cmarkn::Options::ENABLE_FOOTNOTES - | cmarkn::Options::ENABLE_STRIKETHROUGH - | cmarkn::Options::ENABLE_TASKLISTS - | cmarkn::Options::ENABLE_SMART_PUNCTUATION - } - let parser_new = cmarkn::Parser::new_ext(dox, main_body_opts_new()).into_offset_iter(); - for (event, span) in parser_new { - if let cmarkn::Event::Start(cmarkn::Tag::BlockQuote(_)) = event { - if !dox[span.clone()].starts_with("> ") { - spaceless_block_quotes.insert(span.start); - } - } - if let cmarkn::Event::FootnoteReference(_) = event { - found_footnote_references.insert(span.start + 1); - } - } - } - - // remove cases where they don't actually differ - { - pub fn main_body_opts_old() -> cmarko::Options { - cmarko::Options::ENABLE_TABLES - | cmarko::Options::ENABLE_FOOTNOTES - | cmarko::Options::ENABLE_STRIKETHROUGH - | cmarko::Options::ENABLE_TASKLISTS - | cmarko::Options::ENABLE_SMART_PUNCTUATION - } - let parser_old = cmarko::Parser::new_ext(dox, main_body_opts_old()).into_offset_iter(); - for (event, span) in parser_old { - if let cmarko::Event::Start(cmarko::Tag::BlockQuote) = event - && !dox[span.clone()].starts_with("> ") - { - spaceless_block_quotes.remove(&span.start); - } - if let cmarko::Event::FootnoteReference(_) = event - && !found_footnote_references.contains(&(span.start + 1)) - { - missing_footnote_references.insert(span.start + 1, span); - } - } - } - - for start in spaceless_block_quotes { - let (span, precise) = - source_span_for_markdown_range(tcx, dox, &(start..start + 1), &item.attrs.doc_strings) - .map(|span| (span, true)) - .unwrap_or_else(|| (item.attr_span(tcx), false)); - - tcx.node_span_lint(crate::lint::UNPORTABLE_MARKDOWN, hir_id, span, |lint| { - lint.primary_message("unportable markdown"); - lint.help("confusing block quote with no space after the `>` marker".to_string()); - if precise { - lint.span_suggestion( - span.shrink_to_hi(), - "if the quote is intended, add a space", - " ", - Applicability::MaybeIncorrect, - ); - lint.span_suggestion( - span.shrink_to_lo(), - "if it should not be a quote, escape it", - "\\", - Applicability::MaybeIncorrect, - ); - } - }); - } - for (_caret, span) in missing_footnote_references { - let (ref_span, precise) = - source_span_for_markdown_range(tcx, dox, &span, &item.attrs.doc_strings) - .map(|span| (span, true)) - .unwrap_or_else(|| (item.attr_span(tcx), false)); - - tcx.node_span_lint(crate::lint::UNPORTABLE_MARKDOWN, hir_id, ref_span, |lint| { - lint.primary_message("unportable markdown"); - if precise { - lint.span_suggestion( - ref_span.shrink_to_lo(), - "if it should not be a footnote, escape it", - "\\", - Applicability::MaybeIncorrect, - ); - } - if dox.as_bytes().get(span.end) == Some(&b'[') { - lint.help("confusing footnote reference and link"); - if precise { - lint.span_suggestion( - ref_span.shrink_to_hi(), - "if the footnote is intended, add a space", - " ", - Applicability::MaybeIncorrect, - ); - } else { - lint.help("there should be a space between the link and the footnote"); - } - } - }); - } -} diff --git a/src/llvm-project b/src/llvm-project index a9865ceca081..8448283b4bd3 160000 --- a/src/llvm-project +++ b/src/llvm-project @@ -1 +1 @@ -Subproject commit a9865ceca08101071e25f3bba97bba8bf0ea9719 +Subproject commit 8448283b4bd34ea00d76fd4f18ec730b549d6e1d diff --git a/src/tools/clippy/clippy_lints/src/assigning_clones.rs b/src/tools/clippy/clippy_lints/src/assigning_clones.rs index 9acff676d4f6..8b8b42bbf722 100644 --- a/src/tools/clippy/clippy_lints/src/assigning_clones.rs +++ b/src/tools/clippy/clippy_lints/src/assigning_clones.rs @@ -3,14 +3,13 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::mir::{PossibleBorrowerMap, enclosing_mir}; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::sugg::Sugg; -use clippy_utils::{is_diag_trait_item, is_in_test, last_path_segment, local_is_initialized, path_to_local}; +use clippy_utils::{is_diag_trait_item, is_in_test, last_path_segment, local_is_initialized, path_to_local, sym}; use rustc_errors::Applicability; use rustc_hir::{self as hir, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::mir; use rustc_middle::ty::{self, Instance, Mutability}; use rustc_session::impl_lint_pass; -use rustc_span::symbol::sym; use rustc_span::{Span, SyntaxContext}; declare_clippy_lint! { @@ -86,9 +85,9 @@ impl<'tcx> LateLintPass<'tcx> for AssigningClones { && ctxt.is_root() && let which_trait = match fn_name { sym::clone if is_diag_trait_item(cx, fn_id, sym::Clone) => CloneTrait::Clone, - _ if fn_name.as_str() == "to_owned" - && is_diag_trait_item(cx, fn_id, sym::ToOwned) - && self.msrv.meets(cx, msrvs::CLONE_INTO) => + sym::to_owned + if is_diag_trait_item(cx, fn_id, sym::ToOwned) + && self.msrv.meets(cx, msrvs::CLONE_INTO) => { CloneTrait::ToOwned }, @@ -112,7 +111,7 @@ impl<'tcx> LateLintPass<'tcx> for AssigningClones { && resolved_assoc_items.in_definition_order().any(|assoc| match which_trait { CloneTrait::Clone => assoc.name() == sym::clone_from, - CloneTrait::ToOwned => assoc.name().as_str() == "clone_into", + CloneTrait::ToOwned => assoc.name() == sym::clone_into, } ) && !clone_source_borrows_from_dest(cx, lhs, rhs.span) diff --git a/src/tools/clippy/clippy_lints/src/attrs/blanket_clippy_restriction_lints.rs b/src/tools/clippy/clippy_lints/src/attrs/blanket_clippy_restriction_lints.rs index 457692ed5dc5..4d64eec25d27 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/blanket_clippy_restriction_lints.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/blanket_clippy_restriction_lints.rs @@ -1,17 +1,15 @@ use super::BLANKET_CLIPPY_RESTRICTION_LINTS; use super::utils::extract_clippy_lint; use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then}; +use clippy_utils::sym; use rustc_ast::MetaItemInner; use rustc_lint::{EarlyContext, Level, LintContext}; +use rustc_span::DUMMY_SP; use rustc_span::symbol::Symbol; -use rustc_span::{DUMMY_SP, sym}; pub(super) fn check(cx: &EarlyContext<'_>, name: Symbol, items: &[MetaItemInner]) { for lint in items { - if let Some(lint_name) = extract_clippy_lint(lint) - && lint_name.as_str() == "restriction" - && name != sym::allow - { + if name != sym::allow && extract_clippy_lint(lint) == Some(sym::restriction) { span_lint_and_help( cx, BLANKET_CLIPPY_RESTRICTION_LINTS, diff --git a/src/tools/clippy/clippy_lints/src/attrs/deprecated_cfg_attr.rs b/src/tools/clippy/clippy_lints/src/attrs/deprecated_cfg_attr.rs index 7fab97d3ea14..0edb50be8c77 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/deprecated_cfg_attr.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/deprecated_cfg_attr.rs @@ -73,7 +73,7 @@ fn check_deprecated_cfg_recursively(cx: &EarlyContext<'_>, attr: &rustc_ast::Met } fn check_cargo_clippy_attr(cx: &EarlyContext<'_>, item: &rustc_ast::MetaItem) { - if item.has_name(sym::feature) && item.value_str().is_some_and(|v| v.as_str() == "cargo-clippy") { + if item.has_name(sym::feature) && item.value_str() == Some(sym::cargo_clippy) { span_lint_and_sugg( cx, DEPRECATED_CLIPPY_CFG_ATTR, diff --git a/src/tools/clippy/clippy_lints/src/attrs/deprecated_semver.rs b/src/tools/clippy/clippy_lints/src/attrs/deprecated_semver.rs index 50943b36809d..bd6459d6f9db 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/deprecated_semver.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/deprecated_semver.rs @@ -1,5 +1,6 @@ use super::DEPRECATED_SEMVER; use clippy_utils::diagnostics::span_lint; +use clippy_utils::sym; use rustc_ast::{LitKind, MetaItemLit}; use rustc_lint::EarlyContext; use rustc_span::Span; @@ -7,7 +8,7 @@ use semver::Version; pub(super) fn check(cx: &EarlyContext<'_>, span: Span, lit: &MetaItemLit) { if let LitKind::Str(is, _) = lit.kind - && (is.as_str() == "TBD" || Version::parse(is.as_str()).is_ok()) + && (is == sym::TBD || Version::parse(is.as_str()).is_ok()) { return; } diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs b/src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs index 164d3540253a..ba31a51f738a 100644 --- a/src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs +++ b/src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs @@ -1,6 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::sugg::Sugg; +use clippy_utils::sym; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; @@ -19,7 +20,7 @@ pub(super) fn check( if let ty::Int(from) = cast_from.kind() && let ty::Uint(to) = cast_to.kind() && let ExprKind::MethodCall(method_path, receiver, [], _) = cast_expr.kind - && method_path.ident.name.as_str() == "abs" + && method_path.ident.name == sym::abs && msrv.meets(cx, msrvs::UNSIGNED_ABS) { let span = if from.bit_width() == to.bit_width() { diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs b/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs index 8742f5f1a0e0..e92879b853d7 100644 --- a/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs +++ b/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs @@ -1,9 +1,9 @@ use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; -use clippy_utils::expr_or_init; use clippy_utils::source::snippet; use clippy_utils::sugg::Sugg; use clippy_utils::ty::{get_discriminant_value, is_isize_or_usize}; +use clippy_utils::{expr_or_init, sym}; use rustc_abi::IntegerType; use rustc_errors::{Applicability, Diag}; use rustc_hir::def::{DefKind, Res}; @@ -73,7 +73,7 @@ fn apply_reductions(cx: &LateContext<'_>, nbits: u64, expr: &Expr<'_>, signed: b nbits }, ExprKind::MethodCall(method, _value, [], _) => { - if method.ident.name.as_str() == "signum" { + if method.ident.name == sym::signum { 0 // do not lint if cast comes from a `signum` function } else { nbits diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs b/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs index 3fca0f897077..01020f3eee21 100644 --- a/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs +++ b/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs @@ -1,11 +1,10 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::is_c_void; -use clippy_utils::{get_parent_expr, is_hir_ty_cfg_dependant}; +use clippy_utils::{get_parent_expr, is_hir_ty_cfg_dependant, sym}; use rustc_hir::{Expr, ExprKind, GenericArg}; use rustc_lint::LateContext; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, Ty}; -use rustc_span::sym; use super::CAST_PTR_ALIGNMENT; @@ -20,7 +19,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { ); lint_cast_ptr_alignment(cx, expr, cast_from, cast_to); } else if let ExprKind::MethodCall(method_path, self_arg, [], _) = &expr.kind - && method_path.ident.name.as_str() == "cast" + && method_path.ident.name == sym::cast && let Some(generic_args) = method_path.args && let [GenericArg::Type(cast_to)] = generic_args.args // There probably is no obvious reason to do this, just to be consistent with `as` cases. diff --git a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs index ae994e94a32b..8e8c55cf3832 100644 --- a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs +++ b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs @@ -8,7 +8,9 @@ use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Expr, ExprKind, Lit, Node, Path, QPath, TyKind, UnOp}; use rustc_lint::{LateContext, LintContext}; +use rustc_middle::ty::adjustment::Adjust; use rustc_middle::ty::{self, FloatTy, InferTy, Ty}; +use rustc_span::{Symbol, sym}; use std::ops::ControlFlow; use super::UNNECESSARY_CAST; @@ -142,6 +144,33 @@ pub(super) fn check<'tcx>( } if cast_from.kind() == cast_to.kind() && !expr.span.in_external_macro(cx.sess().source_map()) { + enum MaybeParenOrBlock { + Paren, + Block, + Nothing, + } + + fn is_borrow_expr(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { + matches!(expr.kind, ExprKind::AddrOf(..)) + || cx + .typeck_results() + .expr_adjustments(expr) + .first() + .is_some_and(|adj| matches!(adj.kind, Adjust::Borrow(_))) + } + + fn is_in_allowed_macro(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { + const ALLOWED_MACROS: &[Symbol] = &[ + sym::format_args_macro, + sym::assert_eq_macro, + sym::debug_assert_eq_macro, + sym::assert_ne_macro, + sym::debug_assert_ne_macro, + ]; + matches!(expr.span.ctxt().outer_expn_data().macro_def_id, Some(def_id) if + cx.tcx.get_diagnostic_name(def_id).is_some_and(|sym| ALLOWED_MACROS.contains(&sym))) + } + if let Some(id) = path_to_local(cast_expr) && !cx.tcx.hir_span(id).eq_ctxt(cast_expr.span) { @@ -150,15 +179,15 @@ pub(super) fn check<'tcx>( return false; } - // If the whole cast expression is a unary expression (`(*x as T)`) or an addressof - // expression (`(&x as T)`), then not surrounding the suggestion into a block risks us - // changing the precedence of operators if the cast expression is followed by an operation - // with higher precedence than the unary operator (`(*x as T).foo()` would become - // `*x.foo()`, which changes what the `*` applies on). - // The same is true if the expression encompassing the cast expression is a unary - // expression or an addressof expression. - let needs_block = matches!(cast_expr.kind, ExprKind::Unary(..) | ExprKind::AddrOf(..)) - || get_parent_expr(cx, expr).is_some_and(|e| matches!(e.kind, ExprKind::Unary(..) | ExprKind::AddrOf(..))); + // Changing `&(x as i32)` to `&x` would change the meaning of the code because the previous creates + // a reference to the temporary while the latter creates a reference to the original value. + let surrounding = match cx.tcx.parent_hir_node(expr.hir_id) { + Node::Expr(parent) if is_borrow_expr(cx, parent) && !is_in_allowed_macro(cx, parent) => { + MaybeParenOrBlock::Block + }, + Node::Expr(parent) if cast_expr.precedence() < parent.precedence() => MaybeParenOrBlock::Paren, + _ => MaybeParenOrBlock::Nothing, + }; span_lint_and_sugg( cx, @@ -166,10 +195,10 @@ pub(super) fn check<'tcx>( expr.span, format!("casting to the same type is unnecessary (`{cast_from}` -> `{cast_to}`)"), "try", - if needs_block { - format!("{{ {cast_str} }}") - } else { - cast_str + match surrounding { + MaybeParenOrBlock::Paren => format!("({cast_str})"), + MaybeParenOrBlock::Block => format!("{{ {cast_str} }}"), + MaybeParenOrBlock::Nothing => cast_str, }, Applicability::MachineApplicable, ); diff --git a/src/tools/clippy/clippy_lints/src/crate_in_macro_def.rs b/src/tools/clippy/clippy_lints/src/crate_in_macro_def.rs index c2aac7ca090b..19f62e8bf79c 100644 --- a/src/tools/clippy/clippy_lints/src/crate_in_macro_def.rs +++ b/src/tools/clippy/clippy_lints/src/crate_in_macro_def.rs @@ -5,8 +5,8 @@ use rustc_ast::tokenstream::{TokenStream, TokenTree}; use rustc_errors::Applicability; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::Span; use rustc_span::symbol::sym; +use rustc_span::{Span, kw}; declare_clippy_lint! { /// ### What it does @@ -105,12 +105,11 @@ fn contains_unhygienic_crate_reference(tts: &TokenStream) -> Option { fn is_crate_keyword(tt: &TokenTree) -> Option { if let TokenTree::Token( Token { - kind: TokenKind::Ident(symbol, _), + kind: TokenKind::Ident(kw::Crate, _), span, }, _, ) = tt - && symbol.as_str() == "crate" { Some(*span) } else { diff --git a/src/tools/clippy/clippy_lints/src/equatable_if_let.rs b/src/tools/clippy/clippy_lints/src/equatable_if_let.rs index 3afb687040f4..72f5eaf8a4bc 100644 --- a/src/tools/clippy/clippy_lints/src/equatable_if_let.rs +++ b/src/tools/clippy/clippy_lints/src/equatable_if_let.rs @@ -68,6 +68,38 @@ fn is_structural_partial_eq<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, other: T } } +/// Check if the pattern has any type mismatch that would prevent it from being used in an equality +/// check. This can happen if the expr has a reference type and the corresponding pattern is a +/// literal. +fn contains_type_mismatch(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool { + let mut result = false; + pat.walk(|p| { + if result { + return false; + } + + if p.span.in_external_macro(cx.sess().source_map()) { + return true; + } + + let adjust_pat = match p.kind { + PatKind::Or([p, ..]) => p, + _ => p, + }; + + if let Some(adjustments) = cx.typeck_results().pat_adjustments().get(adjust_pat.hir_id) + && adjustments.first().is_some_and(|first| first.source.is_ref()) + { + result = true; + return false; + } + + true + }); + + result +} + impl<'tcx> LateLintPass<'tcx> for PatternEquality { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { if let ExprKind::Let(let_expr) = expr.kind @@ -78,7 +110,7 @@ impl<'tcx> LateLintPass<'tcx> for PatternEquality { let pat_ty = cx.typeck_results().pat_ty(let_expr.pat); let mut applicability = Applicability::MachineApplicable; - if is_structural_partial_eq(cx, exp_ty, pat_ty) { + if is_structural_partial_eq(cx, exp_ty, pat_ty) && !contains_type_mismatch(cx, let_expr.pat) { let pat_str = match let_expr.pat.kind { PatKind::Struct(..) => format!( "({})", diff --git a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs index d5f0659f8427..553a00ed868d 100644 --- a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs +++ b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs @@ -3,7 +3,7 @@ use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::{ eq_expr_value, get_parent_expr, higher, is_in_const_context, is_inherent_method_call, is_no_std_crate, - numeric_literal, peel_blocks, sugg, + numeric_literal, peel_blocks, sugg, sym, }; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, PathSegment, UnOp}; @@ -435,7 +435,7 @@ fn check_expm1(cx: &LateContext<'_>, expr: &Expr<'_>) { rhs, ) = expr.kind && let ExprKind::MethodCall(path, self_arg, [], _) = &lhs.kind - && path.ident.name.as_str() == "exp" + && path.ident.name == sym::exp && cx.typeck_results().expr_ty(lhs).is_floating_point() && let Some(value) = ConstEvalCtxt::new(cx).eval(rhs) && (F32(1.0) == value || F64(1.0) == value) diff --git a/src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs b/src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs index c8828c936157..5e2e2c9dbf72 100644 --- a/src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs +++ b/src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs @@ -1,12 +1,11 @@ use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::path_def_id; use clippy_utils::ty::is_c_void; +use clippy_utils::{path_def_id, sym}; use rustc_hir::def_id::DefId; use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::declare_lint_pass; -use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -41,7 +40,7 @@ impl LateLintPass<'_> for FromRawWithVoidPtr { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { if let ExprKind::Call(box_from_raw, [arg]) = expr.kind && let ExprKind::Path(QPath::TypeRelative(ty, seg)) = box_from_raw.kind - && seg.ident.name.as_str() == "from_raw" + && seg.ident.name == sym::from_raw && let Some(type_str) = path_def_id(cx, ty).and_then(|id| def_id_matches_type(cx, id)) && let arg_kind = cx.typeck_results().expr_ty(arg).kind() && let ty::RawPtr(ty, _) = arg_kind 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 25b087e8484f..b816963cc825 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,13 +1,12 @@ 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::{is_in_const_context, is_integer_literal}; +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}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::Ty; use rustc_session::declare_lint_pass; -use rustc_span::symbol::sym; declare_clippy_lint! { /// ### What it does @@ -53,7 +52,7 @@ impl<'tcx> LateLintPass<'tcx> for FromStrRadix10 { // check if the second part of the path indeed calls the associated // function `from_str_radix` - && pathseg.ident.name.as_str() == "from_str_radix" + && pathseg.ident.name == sym::from_str_radix // check if the first part of the path is some integer primitive && let TyKind::Path(ty_qpath) = &ty.kind diff --git a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs index d2545e57652a..4c17834c3adf 100644 --- a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs +++ b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs @@ -10,10 +10,10 @@ use rustc_middle::hir::nested_filter; use rustc_middle::ty::{Ty, TypeckResults}; use rustc_session::declare_lint_pass; use rustc_span::Span; -use rustc_span::symbol::sym; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::source::{IntoSpan, SpanRangeExt, snippet}; +use clippy_utils::sym; use clippy_utils::ty::is_type_diagnostic_item; declare_clippy_lint! { @@ -326,6 +326,7 @@ impl<'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'_, '_, 'tcx> { fn visit_expr(&mut self, e: &'tcx Expr<'_>) { if let ExprKind::Call(fun, args) = e.kind && let ExprKind::Path(QPath::TypeRelative(ty, method)) = fun.kind + && matches!(method.ident.name, sym::new | sym::with_capacity) && let TyKind::Path(QPath::Resolved(None, ty_path)) = ty.kind && let Some(ty_did) = ty_path.res.opt_def_id() { @@ -333,10 +334,11 @@ impl<'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'_, '_, 'tcx> { return; } - if self.cx.tcx.is_diagnostic_item(sym::HashMap, ty_did) { - if method.ident.name == sym::new { + match (self.cx.tcx.get_diagnostic_name(ty_did), method.ident.name) { + (Some(sym::HashMap), sym::new) => { self.suggestions.insert(e.span, "HashMap::default()".to_string()); - } else if method.ident.name.as_str() == "with_capacity" { + }, + (Some(sym::HashMap), sym::with_capacity) => { self.suggestions.insert( e.span, format!( @@ -344,11 +346,11 @@ impl<'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'_, '_, 'tcx> { snippet(self.cx, args[0].span, "capacity"), ), ); - } - } else if self.cx.tcx.is_diagnostic_item(sym::HashSet, ty_did) { - if method.ident.name == sym::new { + }, + (Some(sym::HashSet), sym::new) => { self.suggestions.insert(e.span, "HashSet::default()".to_string()); - } else if method.ident.name.as_str() == "with_capacity" { + }, + (Some(sym::HashSet), sym::with_capacity) => { self.suggestions.insert( e.span, format!( @@ -356,7 +358,8 @@ impl<'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'_, '_, 'tcx> { snippet(self.cx, args[0].span, "capacity"), ), ); - } + }, + _ => {}, } } diff --git a/src/tools/clippy/clippy_lints/src/infinite_iter.rs b/src/tools/clippy/clippy_lints/src/infinite_iter.rs index 427a1f825555..c4e10837bf19 100644 --- a/src/tools/clippy/clippy_lints/src/infinite_iter.rs +++ b/src/tools/clippy/clippy_lints/src/infinite_iter.rs @@ -1,10 +1,9 @@ use clippy_utils::diagnostics::span_lint; -use clippy_utils::higher; use clippy_utils::ty::{get_type_diagnostic_name, implements_trait}; +use clippy_utils::{higher, sym}; use rustc_hir::{BorrowKind, Closure, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::symbol::sym; declare_clippy_lint! { /// ### What it does @@ -156,7 +155,7 @@ fn is_infinite(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness { .and(cap); } } - if method.ident.name.as_str() == "flat_map" + if method.ident.name == sym::flat_map && args.len() == 1 && let ExprKind::Closure(&Closure { body, .. }) = args[0].kind { @@ -224,7 +223,7 @@ fn complete_infinite_iter(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness { return MaybeInfinite.and(is_infinite(cx, receiver)); } } - if method.ident.name.as_str() == "last" && args.is_empty() { + if method.ident.name == sym::last && args.is_empty() { let not_double_ended = cx .tcx .get_diagnostic_item(sym::DoubleEndedIterator) @@ -232,7 +231,7 @@ fn complete_infinite_iter(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness { if not_double_ended { return is_infinite(cx, receiver); } - } else if method.ident.name.as_str() == "collect" { + } else if method.ident.name == sym::collect { let ty = cx.typeck_results().expr_ty(expr); if matches!( get_type_diagnostic_name(cx, ty), diff --git a/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs b/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs index 173232c511a5..900b20aa9cfb 100644 --- a/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs +++ b/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs @@ -1,14 +1,13 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::get_parent_as_impl; use clippy_utils::source::snippet; use clippy_utils::ty::{deref_chain, get_adt_inherent_method, implements_trait, make_normalized_projection}; +use clippy_utils::{get_parent_as_impl, sym}; use rustc_ast::Mutability; use rustc_errors::Applicability; use rustc_hir::{FnRetTy, ImplItemKind, ImplicitSelfKind, ItemKind, TyKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::ty::{self, Ty}; use rustc_session::declare_lint_pass; -use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -141,7 +140,7 @@ impl LateLintPass<'_> for IterWithoutIntoIter { ty.peel_refs().is_slice() || get_adt_inherent_method(cx, ty, expected_method_name).is_some() }) && let Some(iter_assoc_span) = imp.items.iter().find_map(|item| { - if item.ident.name.as_str() == "IntoIter" { + if item.ident.name == sym::IntoIter { Some(cx.tcx.hir_impl_item(item.id).expect_type().span) } else { None diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs index 8c71d34c95f6..aded31971cec 100644 --- a/src/tools/clippy/clippy_lints/src/len_zero.rs +++ b/src/tools/clippy/clippy_lints/src/len_zero.rs @@ -2,7 +2,9 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_the use clippy_utils::source::{SpanRangeExt, snippet_with_context}; use clippy_utils::sugg::{Sugg, has_enclosing_paren}; use clippy_utils::ty::implements_trait; -use clippy_utils::{fulfill_or_allowed, get_item_name, get_parent_as_impl, is_trait_method, peel_ref_operators, sym}; +use clippy_utils::{ + fulfill_or_allowed, get_parent_as_impl, is_trait_method, parent_item_name, peel_ref_operators, sym, +}; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::def::Res; @@ -533,9 +535,7 @@ fn check_cmp(cx: &LateContext<'_>, span: Span, method: &Expr<'_>, lit: &Expr<'_> if let (&ExprKind::MethodCall(method_path, receiver, [], _), ExprKind::Lit(lit)) = (&method.kind, &lit.kind) { // check if we are in an is_empty() method - if let Some(name) = get_item_name(cx, method) - && name.as_str() == "is_empty" - { + if parent_item_name(cx, method) == Some(sym::is_empty) { return; } diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index 5fa8f6f4bf3d..bc7fc60827a0 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs @@ -729,6 +729,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_early_pass(|| Box::new(misc_early::MiscEarlyLints)); store.register_late_pass(|_| Box::new(redundant_closure_call::RedundantClosureCall)); store.register_early_pass(|| Box::new(unused_unit::UnusedUnit)); + store.register_late_pass(|_| Box::new(unused_unit::UnusedUnit)); store.register_late_pass(|_| Box::new(returns::Return)); store.register_late_pass(move |tcx| Box::new(collapsible_if::CollapsibleIf::new(tcx, conf))); store.register_late_pass(|_| Box::new(items_after_statements::ItemsAfterStatements)); diff --git a/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs b/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs index 661b4b590d8f..388034c39f52 100644 --- a/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs +++ b/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::msrvs::Msrv; use clippy_utils::source::snippet_with_context; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; -use clippy_utils::{msrvs, path_to_local, std_or_core}; +use clippy_utils::{msrvs, path_to_local, std_or_core, sym}; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; @@ -11,7 +11,6 @@ use rustc_hir::intravisit::{Visitor, walk_expr}; use rustc_hir::{BindingMode, Block, Expr, ExprKind, HirId, Mutability, Node, Pat, PatKind, Stmt, StmtKind}; use rustc_lint::LateContext; use rustc_span::SyntaxContext; -use rustc_span::symbol::sym; /// Detects for loop pushing the same item into a Vec pub(super) fn check<'tcx>( @@ -187,8 +186,8 @@ fn get_vec_push<'tcx>( // Extract method being called and figure out the parameters for the method call && let ExprKind::MethodCall(path, self_expr, [pushed_item], _) = &semi_stmt.kind // Check that the method being called is push() on a Vec + && path.ident.name == sym::push && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_expr), sym::Vec) - && path.ident.name.as_str() == "push" { return Some((self_expr, pushed_item, semi_stmt.span.ctxt())); } diff --git a/src/tools/clippy/clippy_lints/src/manual_div_ceil.rs b/src/tools/clippy/clippy_lints/src/manual_div_ceil.rs index 444ecd5d2bb9..ed0cce754b95 100644 --- a/src/tools/clippy/clippy_lints/src/manual_div_ceil.rs +++ b/src/tools/clippy/clippy_lints/src/manual_div_ceil.rs @@ -1,7 +1,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::msrvs::{self, Msrv}; -use clippy_utils::source::snippet_with_applicability; +use clippy_utils::source::snippet_with_context; use clippy_utils::sugg::{Sugg, has_enclosing_paren}; use clippy_utils::{SpanlessEq, sym}; use rustc_ast::{BinOpKind, LitIntType, LitKind, UnOp}; @@ -199,9 +199,9 @@ fn build_suggestion( } else { format!("{dividend_sugg_str}{type_suffix}") }; - let divisor_snippet = snippet_with_applicability(cx, rhs.span.source_callsite(), "..", applicability); + let divisor_snippet = snippet_with_context(cx, rhs.span, expr.span.ctxt(), "..", applicability); - let sugg = format!("{suggestion_before_div_ceil}.div_ceil({divisor_snippet})"); + let sugg = format!("{suggestion_before_div_ceil}.div_ceil({})", divisor_snippet.0); span_lint_and_sugg( cx, diff --git a/src/tools/clippy/clippy_lints/src/manual_hash_one.rs b/src/tools/clippy/clippy_lints/src/manual_hash_one.rs index f71264a93ca8..b3ee45cc0209 100644 --- a/src/tools/clippy/clippy_lints/src/manual_hash_one.rs +++ b/src/tools/clippy/clippy_lints/src/manual_hash_one.rs @@ -3,12 +3,11 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::SpanRangeExt; use clippy_utils::visitors::{is_local_used, local_used_once}; -use clippy_utils::{is_trait_method, path_to_local_id}; +use clippy_utils::{is_trait_method, path_to_local_id, sym}; use rustc_errors::Applicability; use rustc_hir::{BindingMode, ExprKind, LetStmt, Node, PatKind, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; -use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -66,7 +65,7 @@ impl LateLintPass<'_> for ManualHashOne { && let Some(init) = local.init && !init.span.from_expansion() && let ExprKind::MethodCall(seg, build_hasher, [], _) = init.kind - && seg.ident.name.as_str() == "build_hasher" + && seg.ident.name == sym::build_hasher && let Node::Stmt(local_stmt) = cx.tcx.parent_hir_node(local.hir_id) && let Node::Block(block) = cx.tcx.parent_hir_node(local_stmt.hir_id) @@ -94,7 +93,7 @@ impl LateLintPass<'_> for ManualHashOne { && let Node::Expr(finish_expr) = cx.tcx.parent_hir_node(path_expr.hir_id) && !finish_expr.span.from_expansion() && let ExprKind::MethodCall(seg, _, [], _) = finish_expr.kind - && seg.ident.name.as_str() == "finish" + && seg.ident.name == sym::finish && self.msrv.meets(cx, msrvs::BUILD_HASHER_HASH_ONE) { diff --git a/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs b/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs index 8ab49bd2ea8e..ac8c88f02057 100644 --- a/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs +++ b/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::macros::matching_root_macro_call; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::sugg::Sugg; -use clippy_utils::{higher, is_in_const_context, path_to_local, peel_ref_operators}; +use clippy_utils::{higher, is_in_const_context, path_to_local, peel_ref_operators, sym}; use rustc_ast::LitKind::{Byte, Char}; use rustc_ast::ast::RangeLimits; use rustc_errors::Applicability; @@ -11,7 +11,7 @@ use rustc_hir::{Expr, ExprKind, Lit, Node, Param, PatExpr, PatExprKind, PatKind, use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, Ty}; use rustc_session::impl_lint_pass; -use rustc_span::{Span, sym}; +use rustc_span::Span; declare_clippy_lint! { /// ### What it does @@ -103,7 +103,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualIsAsciiCheck { check_is_ascii(cx, macro_call.span, recv, &range, None); } } else if let ExprKind::MethodCall(path, receiver, [arg], ..) = expr.kind - && path.ident.name.as_str() == "contains" + && path.ident.name == sym::contains && let Some(higher::Range { start: Some(start), end: Some(end), diff --git a/src/tools/clippy/clippy_lints/src/manual_option_as_slice.rs b/src/tools/clippy/clippy_lints/src/manual_option_as_slice.rs index e4ad3953b671..b365dbf088f5 100644 --- a/src/tools/clippy/clippy_lints/src/manual_option_as_slice.rs +++ b/src/tools/clippy/clippy_lints/src/manual_option_as_slice.rs @@ -1,14 +1,14 @@ use clippy_config::Conf; use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; use clippy_utils::msrvs::Msrv; -use clippy_utils::{is_none_arm, msrvs, peel_hir_expr_refs}; +use clippy_utils::{is_none_arm, msrvs, peel_hir_expr_refs, sym}; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Arm, Expr, ExprKind, LangItem, Pat, PatKind, QPath, is_range_literal}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::impl_lint_pass; -use rustc_span::{Span, Symbol, sym}; +use rustc_span::{Span, Symbol}; declare_clippy_lint! { /// ### What it does @@ -76,7 +76,7 @@ impl LateLintPass<'_> for ManualOptionAsSlice { } }, ExprKind::MethodCall(seg, callee, [], _) => { - if seg.ident.name.as_str() == "unwrap_or_default" { + if seg.ident.name == sym::unwrap_or_default { check_map(cx, callee, span, self.msrv); } }, 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 e666f31217cc..6d841853fbe5 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,11 +1,11 @@ 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}; +use clippy_utils::{is_mutable, is_trait_method, path_to_local, sym}; use rustc_errors::Applicability; use rustc_hir::{Expr, Node, PatKind}; use rustc_lint::LateContext; use rustc_middle::ty::Instance; -use rustc_span::{Span, sym}; +use rustc_span::Span; use super::DOUBLE_ENDED_ITERATOR_LAST; @@ -24,7 +24,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &'_ Expr<'_>, self_expr: &'_ Exp && let Ok(Some(fn_def)) = Instance::try_resolve(cx.tcx, cx.typing_env(), id, args) // find the provided definition of Iterator::last && let Some(item) = cx.tcx.get_diagnostic_item(sym::Iterator) - && let Some(last_def) = cx.tcx.provided_trait_methods(item).find(|m| m.name().as_str() == "last") + && let Some(last_def) = cx.tcx.provided_trait_methods(item).find(|m| m.name() == sym::last) // if the resolved method is the same as the provided definition && fn_def.def_id() == last_def.def_id && let self_ty = cx.typeck_results().expr_ty(self_expr) 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 da123f13d46f..4dd54cf19745 100644 --- a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs +++ b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs @@ -233,12 +233,12 @@ impl<'tcx> OffendingFilterExpr<'tcx> { // the latter only calls `effect` once let side_effect_expr_span = receiver.can_have_side_effects().then_some(receiver.span); - if cx.tcx.is_diagnostic_item(sym::Option, recv_ty.did()) && path.ident.name.as_str() == "is_some" { + if cx.tcx.is_diagnostic_item(sym::Option, recv_ty.did()) && path.ident.name == sym::is_some { Some(Self::IsSome { receiver, side_effect_expr_span, }) - } else if cx.tcx.is_diagnostic_item(sym::Result, recv_ty.did()) && path.ident.name.as_str() == "is_ok" { + } else if cx.tcx.is_diagnostic_item(sym::Result, recv_ty.did()) && path.ident.name == sym::is_ok { Some(Self::IsOk { receiver, side_effect_expr_span, diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs index ad374dee516c..10f4637d08f6 100644 --- a/src/tools/clippy/clippy_lints/src/methods/mod.rs +++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs @@ -4370,11 +4370,10 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// - /// Detect functions that end with `Option::and_then` or `Result::and_then`, and suggest using a question mark (`?`) instead. + /// Detect functions that end with `Option::and_then` or `Result::and_then`, and suggest using + /// the `?` operator instead. /// /// ### Why is this bad? - /// /// The `and_then` method is used to chain a computation that returns an `Option` or a `Result`. /// This can be replaced with the `?` operator, which is more concise and idiomatic. /// diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_character_iteration.rs b/src/tools/clippy/clippy_lints/src/methods/needless_character_iteration.rs index 743aacf05885..f528f7f065c6 100644 --- a/src/tools/clippy/clippy_lints/src/methods/needless_character_iteration.rs +++ b/src/tools/clippy/clippy_lints/src/methods/needless_character_iteration.rs @@ -9,7 +9,7 @@ use super::utils::get_last_chain_binding_hir_id; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::paths::CHAR_IS_ASCII; use clippy_utils::source::SpanRangeExt; -use clippy_utils::{match_def_path, path_to_local_id, peel_blocks}; +use clippy_utils::{match_def_path, path_to_local_id, peel_blocks, sym}; fn peels_expr_ref<'a, 'tcx>(mut expr: &'a Expr<'tcx>) -> &'a Expr<'tcx> { while let ExprKind::AddrOf(_, _, e) = expr.kind { @@ -32,7 +32,7 @@ fn handle_expr( // If we have `!is_ascii`, then only `.any()` should warn. And if the condition is // `is_ascii`, then only `.all()` should warn. if revert != is_all - && method.ident.name.as_str() == "is_ascii" + && method.ident.name == sym::is_ascii && path_to_local_id(receiver, first_param) && let char_arg_ty = cx.typeck_results().expr_ty_adjusted(receiver).peel_refs() && *char_arg_ty.kind() == ty::Char @@ -102,7 +102,7 @@ pub(super) fn check(cx: &LateContext<'_>, call_expr: &Expr<'_>, recv: &Expr<'_>, && let body = cx.tcx.hir_body(body) && let Some(first_param) = body.params.first() && let ExprKind::MethodCall(method, mut recv, [], _) = recv.kind - && method.ident.name.as_str() == "chars" + && method.ident.name == sym::chars && let str_ty = cx.typeck_results().expr_ty_adjusted(recv).peel_refs() && *str_ty.kind() == ty::Str { diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs index 6efaba525e3e..cd22583b8a25 100644 --- a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs +++ b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs @@ -9,7 +9,7 @@ use clippy_utils::ty::{ }; use clippy_utils::{ CaptureKind, can_move_expr_to_closure, fn_def_id, get_enclosing_block, higher, is_trait_method, path_to_local, - path_to_local_id, + path_to_local_id, sym, }; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{Applicability, MultiSpan}; @@ -20,8 +20,8 @@ use rustc_hir::{ use rustc_lint::LateContext; use rustc_middle::hir::nested_filter; use rustc_middle::ty::{self, AssocTag, ClauseKind, EarlyBinder, GenericArg, GenericArgKind, Ty}; +use rustc_span::Span; use rustc_span::symbol::Ident; -use rustc_span::{Span, sym}; const NEEDLESS_COLLECT_MSG: &str = "avoid using `collect()` when not needed"; @@ -339,7 +339,7 @@ impl<'tcx> Visitor<'tcx> for IterFunctionVisitor<'_, 'tcx> { // Check function calls on our collection if let ExprKind::MethodCall(method_name, recv, args, _) = &expr.kind { if args.is_empty() - && method_name.ident.name.as_str() == "collect" + && method_name.ident.name == sym::collect && is_trait_method(self.cx, expr, sym::Iterator) { self.current_mutably_captured_ids = get_captured_ids(self.cx, self.cx.typeck_results().expr_ty(recv)); diff --git a/src/tools/clippy/clippy_lints/src/methods/read_line_without_trim.rs b/src/tools/clippy/clippy_lints/src/methods/read_line_without_trim.rs index fe999a3b5f8f..407f2e80aff2 100644 --- a/src/tools/clippy/clippy_lints/src/methods/read_line_without_trim.rs +++ b/src/tools/clippy/clippy_lints/src/methods/read_line_without_trim.rs @@ -1,17 +1,16 @@ use std::ops::ControlFlow; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::get_parent_expr; use clippy_utils::source::snippet; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::visitors::for_each_local_use_after_expr; +use clippy_utils::{get_parent_expr, sym}; use rustc_ast::LitKind; use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::{BinOpKind, Expr, ExprKind, QPath}; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty}; -use rustc_span::sym; use super::READ_LINE_WITHOUT_TRIM; @@ -44,7 +43,7 @@ pub fn check(cx: &LateContext<'_>, call: &Expr<'_>, recv: &Expr<'_>, arg: &Expr< if let Some(parent) = get_parent_expr(cx, expr) { let data = if let ExprKind::MethodCall(segment, recv, args, span) = parent.kind { if args.is_empty() - && segment.ident.name.as_str() == "parse" + && segment.ident.name == sym::parse && let parse_result_ty = cx.typeck_results().expr_ty(parent) && is_type_diagnostic_item(cx, parse_result_ty, sym::Result) && let ty::Adt(_, substs) = parse_result_ty.kind() @@ -58,7 +57,7 @@ pub fn check(cx: &LateContext<'_>, call: &Expr<'_>, recv: &Expr<'_>, arg: &Expr< "calling `.parse()` on a string without trimming the trailing newline character", "checking", )) - } else if segment.ident.name.as_str() == "ends_with" + } else if segment.ident.name == sym::ends_with && recv.span == expr.span && let [arg] = args && expr_is_string_literal_without_trailing_newline(arg) diff --git a/src/tools/clippy/clippy_lints/src/methods/return_and_then.rs b/src/tools/clippy/clippy_lints/src/methods/return_and_then.rs index e8861935d421..91643b0dfefd 100644 --- a/src/tools/clippy/clippy_lints/src/methods/return_and_then.rs +++ b/src/tools/clippy/clippy_lints/src/methods/return_and_then.rs @@ -55,7 +55,6 @@ pub(super) fn check<'tcx>( None => &body_snip, }; - let msg = "use the question mark operator instead of an `and_then` call"; let sugg = format!( "let {} = {}?;\n{}", arg_snip, @@ -63,5 +62,13 @@ pub(super) fn check<'tcx>( reindent_multiline(inner, false, indent_of(cx, expr.span)) ); - span_lint_and_sugg(cx, RETURN_AND_THEN, expr.span, msg, "try", sugg, applicability); + span_lint_and_sugg( + cx, + RETURN_AND_THEN, + expr.span, + "use the `?` operator instead of an `and_then` call", + "try", + sugg, + applicability, + ); } diff --git a/src/tools/clippy/clippy_lints/src/methods/str_split.rs b/src/tools/clippy/clippy_lints/src/methods/str_split.rs index 3586e11f56ab..fb4ac7b3613d 100644 --- a/src/tools/clippy/clippy_lints/src/methods/str_split.rs +++ b/src/tools/clippy/clippy_lints/src/methods/str_split.rs @@ -1,5 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_context; +use clippy_utils::sym; use clippy_utils::visitors::is_const_evaluatable; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; @@ -19,7 +20,7 @@ pub(super) fn check<'a>(cx: &LateContext<'a>, expr: &'_ Expr<'_>, split_recv: &' && !is_const_evaluatable(cx, trim_recv) && let ExprKind::Lit(split_lit) = split_arg.kind && (matches!(split_lit.node, LitKind::Char('\n')) - || matches!(split_lit.node, LitKind::Str(sym, _) if (sym.as_str() == "\n" || sym.as_str() == "\r\n"))) + || matches!(split_lit.node, LitKind::Str(sym::LF | sym::CRLF, _))) { let mut app = Applicability::MaybeIncorrect; span_lint_and_sugg( diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs index f920f306bc1e..79ed352193fd 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs @@ -3,13 +3,12 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::is_copy; use clippy_utils::usage::mutated_variables; use clippy_utils::visitors::{Descend, for_each_expr_without_closures}; -use clippy_utils::{is_res_lang_ctor, is_trait_method, path_res, path_to_local_id}; +use clippy_utils::{is_res_lang_ctor, is_trait_method, path_res, path_to_local_id, sym}; use core::ops::ControlFlow; use rustc_hir as hir; use rustc_hir::LangItem::{OptionNone, OptionSome}; use rustc_lint::LateContext; use rustc_middle::ty; -use rustc_span::sym; use super::{UNNECESSARY_FILTER_MAP, UNNECESSARY_FIND_MAP}; @@ -95,7 +94,7 @@ fn check_expression<'tcx>(cx: &LateContext<'tcx>, arg_id: hir::HirId, expr: &'tc (true, true) }, hir::ExprKind::MethodCall(segment, recv, [arg], _) => { - if segment.ident.name.as_str() == "then_some" + if segment.ident.name == sym::then_some && cx.typeck_results().expr_ty(recv).is_bool() && path_to_local_id(arg, arg_id) { diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs index 206b0a8ae3cd..87bb8d46a1d6 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -7,7 +7,7 @@ use clippy_utils::ty::{get_iterator_item_ty, implements_trait, is_copy, is_type_ use clippy_utils::visitors::find_all_ret_expressions; use clippy_utils::{ fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item, is_expr_temporary_value, peel_middle_ty_refs, - return_ty, + return_ty, sym, }; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; @@ -20,7 +20,7 @@ use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref}; use rustc_middle::ty::{ self, ClauseKind, GenericArg, GenericArgKind, GenericArgsRef, ParamTy, ProjectionPredicate, TraitPredicate, Ty, }; -use rustc_span::{Symbol, sym}; +use rustc_span::Symbol; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; use rustc_trait_selection::traits::{Obligation, ObligationCause}; @@ -312,8 +312,7 @@ fn check_string_from_utf8<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, /// call of a `to_owned`-like function is unnecessary. fn check_split_call_arg(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol, receiver: &Expr<'_>) -> bool { if let Some(parent) = get_parent_expr(cx, expr) - && let Some((fn_name, argument_expr)) = get_fn_name_and_arg(cx, parent) - && fn_name.as_str() == "split" + && let Some((sym::split, argument_expr)) = get_fn_name_and_arg(cx, parent) && let Some(receiver_snippet) = receiver.span.get_source_text(cx) && let Some(arg_snippet) = argument_expr.span.get_source_text(cx) { @@ -614,8 +613,7 @@ fn has_lifetime(ty: Ty<'_>) -> bool { /// Returns true if the named method is `Iterator::cloned` or `Iterator::copied`. fn is_cloned_or_copied(cx: &LateContext<'_>, method_name: Symbol, method_def_id: DefId) -> bool { - (method_name.as_str() == "cloned" || method_name.as_str() == "copied") - && is_diag_trait_item(cx, method_def_id, sym::Iterator) + matches!(method_name, sym::cloned | sym::copied) && is_diag_trait_item(cx, method_def_id, sym::Iterator) } /// Returns true if the named method can be used to convert the receiver to its "owned" @@ -628,7 +626,7 @@ fn is_to_owned_like<'a>(cx: &LateContext<'a>, call_expr: &Expr<'a>, method_name: /// Returns true if the named method is `Cow::into_owned`. fn is_cow_into_owned(cx: &LateContext<'_>, method_name: Symbol, method_def_id: DefId) -> bool { - method_name.as_str() == "into_owned" && is_diag_item_method(cx, method_def_id, sym::Cow) + method_name == sym::into_owned && is_diag_item_method(cx, method_def_id, sym::Cow) } /// Returns true if the named method is `ToString::to_string` and it's called on a type that diff --git a/src/tools/clippy/clippy_lints/src/minmax.rs b/src/tools/clippy/clippy_lints/src/minmax.rs index ed89b3b34386..64eafc0ebccd 100644 --- a/src/tools/clippy/clippy_lints/src/minmax.rs +++ b/src/tools/clippy/clippy_lints/src/minmax.rs @@ -1,10 +1,9 @@ use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::span_lint; -use clippy_utils::is_trait_method; +use clippy_utils::{is_trait_method, sym}; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::sym; use std::cmp::Ordering::{Equal, Greater, Less}; declare_clippy_lint! { @@ -79,12 +78,10 @@ fn min_max<'a, 'tcx>(cx: &LateContext<'tcx>, expr: &'a Expr<'a>) -> Option<(MinM }, ExprKind::MethodCall(path, receiver, args @ [_], _) => { if cx.typeck_results().expr_ty(receiver).is_floating_point() || is_trait_method(cx, expr, sym::Ord) { - if path.ident.name.as_str() == "max" { - fetch_const(cx, Some(receiver), args, MinMax::Max) - } else if path.ident.name.as_str() == "min" { - fetch_const(cx, Some(receiver), args, MinMax::Min) - } else { - None + match path.ident.name { + sym::max => fetch_const(cx, Some(receiver), args, MinMax::Max), + sym::min => fetch_const(cx, Some(receiver), args, MinMax::Min), + _ => None, } } else { None diff --git a/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs b/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs index 1932d2d5f978..be7dd74fd62b 100644 --- a/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs +++ b/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs @@ -1,9 +1,9 @@ use std::ops::ControlFlow; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::is_path_lang_item; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::visitors::{Visitable, for_each_expr}; +use clippy_utils::{is_path_lang_item, sym}; use rustc_ast::LitKind; use rustc_data_structures::fx::FxHashSet; use rustc_hir::def::{DefKind, Res}; @@ -13,7 +13,7 @@ use rustc_hir::{ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{Ty, TypeckResults}; use rustc_session::declare_lint_pass; -use rustc_span::{Span, Symbol, sym}; +use rustc_span::{Span, Symbol}; declare_clippy_lint! { /// ### What it does @@ -116,7 +116,7 @@ fn should_lint<'tcx>( if path.ident.name == sym::debug_struct && is_type_diagnostic_item(cx, recv_ty, sym::Formatter) { has_debug_struct = true; - } else if path.ident.name.as_str() == "finish_non_exhaustive" + } else if path.ident.name == sym::finish_non_exhaustive && is_type_diagnostic_item(cx, recv_ty, sym::DebugStruct) { has_finish_non_exhaustive = true; 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 0e0855859628..d9f4fb271fb4 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 @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; use clippy_utils::macros::root_macro_call_first_node; -use clippy_utils::{get_parent_expr, path_to_local, path_to_local_id}; +use clippy_utils::{get_parent_expr, path_to_local, path_to_local_id, sym}; use rustc_hir::intravisit::{Visitor, walk_expr}; use rustc_hir::{BinOpKind, Block, Expr, ExprKind, HirId, LetStmt, Node, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -136,7 +136,7 @@ impl<'tcx> DivergenceVisitor<'_, 'tcx> { fn report_diverging_sub_expr(&mut self, e: &Expr<'_>) { if let Some(macro_call) = root_macro_call_first_node(self.cx, e) - && self.cx.tcx.item_name(macro_call.def_id).as_str() == "todo" + && self.cx.tcx.is_diagnostic_item(sym::todo_macro, macro_call.def_id) { return; } diff --git a/src/tools/clippy/clippy_lints/src/needless_for_each.rs b/src/tools/clippy/clippy_lints/src/needless_for_each.rs index 90b27f5dbac8..7dd96f1f037f 100644 --- a/src/tools/clippy/clippy_lints/src/needless_for_each.rs +++ b/src/tools/clippy/clippy_lints/src/needless_for_each.rs @@ -3,12 +3,12 @@ use rustc_hir::intravisit::{Visitor, walk_expr}; use rustc_hir::{Block, BlockCheckMode, Closure, Expr, ExprKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::{Span, sym}; +use rustc_span::Span; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::is_trait_method; use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::has_iter_method; +use clippy_utils::{is_trait_method, sym}; declare_clippy_lint! { /// ### What it does @@ -64,7 +64,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessForEach { iter_recv.kind, ExprKind::Array(..) | ExprKind::Call(..) | ExprKind::Path(..) ) - && method_name.ident.name.as_str() == "for_each" + && method_name.ident.name == sym::for_each && is_trait_method(cx, expr, sym::Iterator) // Checks the type of the `iter` method receiver is NOT a user defined type. && has_iter_method(cx, cx.typeck_results().expr_ty(iter_recv)).is_some() diff --git a/src/tools/clippy/clippy_lints/src/needless_question_mark.rs b/src/tools/clippy/clippy_lints/src/needless_question_mark.rs index 72b0a80260e9..2a2160c3be2d 100644 --- a/src/tools/clippy/clippy_lints/src/needless_question_mark.rs +++ b/src/tools/clippy/clippy_lints/src/needless_question_mark.rs @@ -1,6 +1,5 @@ -use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::path_res; -use clippy_utils::source::snippet; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Block, Body, Expr, ExprKind, LangItem, MatchSource, QPath}; @@ -9,52 +8,38 @@ use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does - /// Suggests alternatives for useless applications of `?` in terminating expressions + /// Suggests replacing `Ok(x?)` or `Some(x?)` with `x` in return positions where the `?` operator + /// is not needed to convert the type of `x`. /// /// ### Why is this bad? /// There's no reason to use `?` to short-circuit when execution of the body will end there anyway. /// /// ### Example /// ```no_run - /// struct TO { - /// magic: Option, + /// # use std::num::ParseIntError; + /// fn f(s: &str) -> Option { + /// Some(s.find('x')?) /// } /// - /// fn f(to: TO) -> Option { - /// Some(to.magic?) + /// fn g(s: &str) -> Result { + /// Ok(s.parse()?) /// } - /// - /// struct TR { - /// magic: Result, - /// } - /// - /// fn g(tr: Result) -> Result { - /// tr.and_then(|t| Ok(t.magic?)) - /// } - /// /// ``` /// Use instead: /// ```no_run - /// struct TO { - /// magic: Option, + /// # use std::num::ParseIntError; + /// fn f(s: &str) -> Option { + /// s.find('x') /// } /// - /// fn f(to: TO) -> Option { - /// to.magic - /// } - /// - /// struct TR { - /// magic: Result, - /// } - /// - /// fn g(tr: Result) -> Result { - /// tr.and_then(|t| t.magic) + /// fn g(s: &str) -> Result { + /// s.parse() /// } /// ``` #[clippy::version = "1.51.0"] pub NEEDLESS_QUESTION_MARK, complexity, - "Suggest `value.inner_option` instead of `Some(value.inner_option?)`. The same goes for `Result`." + "using `Ok(x?)` or `Some(x?)` where `x` would be equivalent" } declare_lint_pass!(NeedlessQuestionMark => [NEEDLESS_QUESTION_MARK]); @@ -111,10 +96,10 @@ fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { if let ExprKind::Call(path, [arg]) = expr.kind && let Res::Def(DefKind::Ctor(..), ctor_id) = path_res(cx, path) && let Some(variant_id) = cx.tcx.opt_parent(ctor_id) - && let sugg_remove = if cx.tcx.lang_items().option_some_variant() == Some(variant_id) { - "Some()" + && let variant = if cx.tcx.lang_items().option_some_variant() == Some(variant_id) { + "Some" } else if cx.tcx.lang_items().result_ok_variant() == Some(variant_id) { - "Ok()" + "Ok" } else { return; } @@ -126,14 +111,25 @@ fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { && let inner_ty = cx.typeck_results().expr_ty(inner_expr) && expr_ty == inner_ty { - span_lint_and_sugg( + span_lint_hir_and_then( cx, NEEDLESS_QUESTION_MARK, + expr.hir_id, expr.span, - "question mark operator is useless here", - format!("try removing question mark and `{sugg_remove}`"), - format!("{}", snippet(cx, inner_expr.span, r#""...""#)), - Applicability::MachineApplicable, + format!("enclosing `{variant}` and `?` operator are unneeded"), + |diag| { + diag.multipart_suggestion( + format!("remove the enclosing `{variant}` and `?` operator"), + vec![ + (expr.span.until(inner_expr.span), String::new()), + ( + inner_expr.span.shrink_to_hi().to(expr.span.shrink_to_hi()), + String::new(), + ), + ], + Applicability::MachineApplicable, + ); + }, ); } } 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 63859c0396e4..6d3e77b6b6e9 100644 --- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs +++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs @@ -263,7 +263,7 @@ impl<'tcx> NonCopyConst<'tcx> { fn is_value_unfrozen_poly(cx: &LateContext<'tcx>, body_id: BodyId, ty: Ty<'tcx>) -> bool { let def_id = body_id.hir_id.owner.to_def_id(); let args = ty::GenericArgs::identity_for_item(cx.tcx, def_id); - let instance = ty::Instance::new(def_id, args); + let instance = ty::Instance::new_raw(def_id, args); let cid = GlobalId { instance, promoted: None, diff --git a/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs b/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs index 852c3885f568..23a1622f30ff 100644 --- a/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs +++ b/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs @@ -1,10 +1,10 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::{SpanRangeExt, snippet_with_applicability}; +use clippy_utils::sym; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -43,12 +43,12 @@ impl<'tcx> LateLintPass<'tcx> for NonOctalUnixPermissions { match &expr.kind { ExprKind::MethodCall(path, func, [param], _) => { if let Some(adt) = cx.typeck_results().expr_ty(func).peel_refs().ty_adt_def() - && ((path.ident.name.as_str() == "mode" + && ((path.ident.name == sym::mode && matches!( cx.tcx.get_diagnostic_name(adt.did()), Some(sym::FsOpenOptions | sym::DirBuilder) )) - || (path.ident.name.as_str() == "set_mode" + || (path.ident.name == sym::set_mode && cx.tcx.is_diagnostic_item(sym::FsPermissions, adt.did()))) && let ExprKind::Lit(_) = param.kind && param.span.eq_ctxt(expr.span) diff --git a/src/tools/clippy/clippy_lints/src/non_zero_suggestions.rs b/src/tools/clippy/clippy_lints/src/non_zero_suggestions.rs index 635f5678e2a6..1b8ab1bdedf8 100644 --- a/src/tools/clippy/clippy_lints/src/non_zero_suggestions.rs +++ b/src/tools/clippy/clippy_lints/src/non_zero_suggestions.rs @@ -1,12 +1,12 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; +use clippy_utils::sym; use rustc_ast::ast::BinOpKind; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, Ty}; use rustc_session::declare_lint_pass; -use rustc_span::symbol::sym; declare_clippy_lint! { /// ### What it does @@ -72,7 +72,7 @@ fn check_non_zero_conversion(cx: &LateContext<'_>, expr: &Expr<'_>, applicabilit && let ExprKind::Path(qpath) = &func.kind && let Some(def_id) = cx.qpath_res(qpath, func.hir_id).opt_def_id() && let ExprKind::MethodCall(rcv_path, receiver, [], _) = &arg.kind - && rcv_path.ident.name.as_str() == "get" + && rcv_path.ident.name == sym::get { let fn_name = cx.tcx.item_name(def_id); let target_ty = cx.typeck_results().expr_ty(expr); diff --git a/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs b/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs index 01dc6a27c33e..ded161c8576a 100644 --- a/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs +++ b/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs @@ -1,7 +1,7 @@ use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::get_item_name; use clippy_utils::sugg::Sugg; +use clippy_utils::{parent_item_name, sym}; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp}; use rustc_lint::LateContext; @@ -34,7 +34,7 @@ pub(crate) fn check<'tcx>( return; } - if let Some(name) = get_item_name(cx, expr) { + if let Some(name) = parent_item_name(cx, expr) { let name = name.as_str(); if name == "eq" || name == "ne" || name == "is_nan" || name.starts_with("eq_") || name.ends_with("_eq") { return; @@ -106,7 +106,7 @@ fn is_signum(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { } if let ExprKind::MethodCall(method_name, self_arg, [], _) = expr.kind - && method_name.ident.name.as_str() == "signum" + && method_name.ident.name == sym::signum // Check that the receiver of the signum() is a float (expressions[0] is the receiver of // the method call) { diff --git a/src/tools/clippy/clippy_lints/src/permissions_set_readonly_false.rs b/src/tools/clippy/clippy_lints/src/permissions_set_readonly_false.rs index dc142b6e1577..da56a785007c 100644 --- a/src/tools/clippy/clippy_lints/src/permissions_set_readonly_false.rs +++ b/src/tools/clippy/clippy_lints/src/permissions_set_readonly_false.rs @@ -1,10 +1,10 @@ use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::sym; use clippy_utils::ty::is_type_diagnostic_item; use rustc_ast::ast::LitKind; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -33,7 +33,7 @@ impl<'tcx> LateLintPass<'tcx> for PermissionsSetReadonlyFalse { if let ExprKind::MethodCall(path, receiver, [arg], _) = &expr.kind && let ExprKind::Lit(lit) = &arg.kind && LitKind::Bool(false) == lit.node - && path.ident.name.as_str() == "set_readonly" + && path.ident.name == sym::set_readonly && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(receiver), sym::FsPermissions) { span_lint_and_then( diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs index 491961408adb..9149406642d6 100644 --- a/src/tools/clippy/clippy_lints/src/ptr.rs +++ b/src/tools/clippy/clippy_lints/src/ptr.rs @@ -743,9 +743,9 @@ fn check_ptr_eq<'tcx>( } // Remove one level of usize conversion if any - let (left, right) = match (expr_as_cast_to_usize(cx, left), expr_as_cast_to_usize(cx, right)) { - (Some(lhs), Some(rhs)) => (lhs, rhs), - _ => (left, right), + let (left, right, usize_peeled) = match (expr_as_cast_to_usize(cx, left), expr_as_cast_to_usize(cx, right)) { + (Some(lhs), Some(rhs)) => (lhs, rhs, true), + _ => (left, right, false), }; // This lint concerns raw pointers @@ -754,7 +754,12 @@ fn check_ptr_eq<'tcx>( return; } - let (left_var, right_var) = (peel_raw_casts(cx, left, left_ty), peel_raw_casts(cx, right, right_ty)); + let ((left_var, left_casts_peeled), (right_var, right_casts_peeled)) = + (peel_raw_casts(cx, left, left_ty), peel_raw_casts(cx, right, right_ty)); + + if !(usize_peeled || left_casts_peeled || right_casts_peeled) { + return; + } let mut app = Applicability::MachineApplicable; let left_snip = Sugg::hir_with_context(cx, left_var, expr.span.ctxt(), "_", &mut app); @@ -787,8 +792,9 @@ fn expr_as_cast_to_usize<'tcx>(cx: &LateContext<'tcx>, cast_expr: &'tcx Expr<'_> } } -// Peel raw casts if the remaining expression can be coerced to it -fn peel_raw_casts<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, expr_ty: Ty<'tcx>) -> &'tcx Expr<'tcx> { +// Peel raw casts if the remaining expression can be coerced to it, and whether casts have been +// peeled or not. +fn peel_raw_casts<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, expr_ty: Ty<'tcx>) -> (&'tcx Expr<'tcx>, bool) { if !expr.span.from_expansion() && let ExprKind::Cast(inner, _) = expr.kind && let ty::RawPtr(target_ty, _) = expr_ty.kind() @@ -796,8 +802,8 @@ fn peel_raw_casts<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, expr_ty: && let ty::RawPtr(inner_target_ty, _) | ty::Ref(_, inner_target_ty, _) = inner_ty.kind() && target_ty == inner_target_ty { - peel_raw_casts(cx, inner, inner_ty) + (peel_raw_casts(cx, inner, inner_ty).0, true) } else { - expr + (expr, false) } } diff --git a/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs b/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs index 7f74a2fff9f2..d8d813f9846d 100644 --- a/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs +++ b/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs @@ -1,10 +1,10 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; use clippy_utils::source::SpanRangeExt; +use clippy_utils::sym; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::sym; use std::fmt; declare_clippy_lint! { @@ -97,7 +97,7 @@ fn expr_as_ptr_offset_call<'tcx>( if path_segment.ident.name == sym::offset { return Some((arg_0, arg_1, Method::Offset)); } - if path_segment.ident.name.as_str() == "wrapping_offset" { + if path_segment.ident.name == sym::wrapping_offset { return Some((arg_0, arg_1, Method::WrappingOffset)); } } diff --git a/src/tools/clippy/clippy_lints/src/question_mark.rs b/src/tools/clippy/clippy_lints/src/question_mark.rs index d318897443da..c02e5e0621c9 100644 --- a/src/tools/clippy/clippy_lints/src/question_mark.rs +++ b/src/tools/clippy/clippy_lints/src/question_mark.rs @@ -10,7 +10,7 @@ use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; use clippy_utils::{ eq_expr_value, higher, is_else_clause, is_in_const_context, is_lint_allowed, is_path_lang_item, is_res_lang_ctor, pat_and_expr_can_be_question_mark, path_res, path_to_local, path_to_local_id, peel_blocks, peel_blocks_with_stmt, - span_contains_cfg, span_contains_comment, + span_contains_cfg, span_contains_comment, sym, }; use rustc_errors::Applicability; use rustc_hir::LangItem::{self, OptionNone, OptionSome, ResultErr, ResultOk}; @@ -22,15 +22,14 @@ use rustc_hir::{ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::{self, Ty}; use rustc_session::impl_lint_pass; -use rustc_span::sym; use rustc_span::symbol::Symbol; declare_clippy_lint! { /// ### What it does - /// Checks for expressions that could be replaced by the question mark operator. + /// Checks for expressions that could be replaced by the `?` operator. /// /// ### Why is this bad? - /// Question mark usage is more idiomatic. + /// Using the `?` operator is shorter and more idiomatic. /// /// ### Example /// ```ignore @@ -47,7 +46,7 @@ declare_clippy_lint! { #[clippy::version = "pre 1.29.0"] pub QUESTION_MARK, style, - "checks for expressions that could be replaced by the question mark operator" + "checks for expressions that could be replaced by the `?` operator" } pub struct QuestionMark { @@ -207,8 +206,8 @@ fn is_early_return(smbl: Symbol, cx: &LateContext<'_>, if_block: &IfBlockType<'_ is_type_diagnostic_item(cx, caller_ty, smbl) && expr_return_none_or_err(smbl, cx, if_then, caller, None) && match smbl { - sym::Option => call_sym.as_str() == "is_none", - sym::Result => call_sym.as_str() == "is_err", + sym::Option => call_sym == sym::is_none, + sym::Result => call_sym == sym::is_err, _ => false, } }, @@ -280,7 +279,7 @@ fn expr_return_none_or_err( /// } /// ``` /// -/// If it matches, it will suggest to use the question mark operator instead +/// If it matches, it will suggest to use the `?` operator instead fn check_is_none_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) { if let Some(higher::If { cond, then, r#else }) = higher::If::hir(expr) && !is_else_clause(cx.tcx, expr) diff --git a/src/tools/clippy/clippy_lints/src/question_mark_used.rs b/src/tools/clippy/clippy_lints/src/question_mark_used.rs index 0a974bf9d2f7..96ea485d7693 100644 --- a/src/tools/clippy/clippy_lints/src/question_mark_used.rs +++ b/src/tools/clippy/clippy_lints/src/question_mark_used.rs @@ -7,10 +7,10 @@ use rustc_session::declare_lint_pass; declare_clippy_lint! { /// ### What it does - /// Checks for expressions that use the question mark operator and rejects them. + /// Checks for expressions that use the `?` operator and rejects them. /// /// ### Why restrict this? - /// Sometimes code wants to avoid the question mark operator because for instance a local + /// Sometimes code wants to avoid the `?` operator because for instance a local /// block requires a macro to re-throw errors to attach additional information to the /// error. /// @@ -27,7 +27,7 @@ declare_clippy_lint! { #[clippy::version = "1.69.0"] pub QUESTION_MARK_USED, restriction, - "complains if the question mark operator is used" + "checks if the `?` operator is used" } declare_lint_pass!(QuestionMarkUsed => [QUESTION_MARK_USED]); @@ -40,15 +40,9 @@ impl<'tcx> LateLintPass<'tcx> for QuestionMarkUsed { } #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")] - span_lint_and_then( - cx, - QUESTION_MARK_USED, - expr.span, - "question mark operator was used", - |diag| { - diag.help("consider using a custom macro or match expression"); - }, - ); + span_lint_and_then(cx, QUESTION_MARK_USED, expr.span, "the `?` operator was used", |diag| { + diag.help("consider using a custom macro or match expression"); + }); } } } diff --git a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs index d26288adb391..30a5fe4db27e 100644 --- a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs +++ b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs @@ -3,14 +3,13 @@ use clippy_utils::macros::matching_root_macro_call; use clippy_utils::sugg::Sugg; use clippy_utils::{ SpanlessEq, get_enclosing_block, is_integer_literal, is_path_diagnostic_item, path_to_local, path_to_local_id, - span_contains_comment, + span_contains_comment, sym, }; use rustc_errors::Applicability; use rustc_hir::intravisit::{Visitor, walk_block, walk_expr, walk_stmt}; use rustc_hir::{BindingMode, Block, Expr, ExprKind, HirId, PatKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::symbol::sym; declare_clippy_lint! { /// ### What it does @@ -248,7 +247,7 @@ impl<'tcx> VectorInitializationVisitor<'_, 'tcx> { if self.initialization_found && let ExprKind::MethodCall(path, self_arg, [extend_arg], _) = expr.kind && path_to_local_id(self_arg, self.vec_alloc.local_id) - && path.ident.name.as_str() == "extend" + && path.ident.name == sym::extend && self.is_repeat_take(extend_arg) { self.slow_expression = Some(InitializationType::Extend(expr)); @@ -260,7 +259,7 @@ impl<'tcx> VectorInitializationVisitor<'_, 'tcx> { if self.initialization_found && let ExprKind::MethodCall(path, self_arg, [len_arg, fill_arg], _) = expr.kind && path_to_local_id(self_arg, self.vec_alloc.local_id) - && path.ident.name.as_str() == "resize" + && path.ident.name == sym::resize // Check that is filled with 0 && is_integer_literal(fill_arg, 0) { @@ -282,7 +281,7 @@ impl<'tcx> VectorInitializationVisitor<'_, 'tcx> { /// Returns `true` if give expression is `repeat(0).take(...)` fn is_repeat_take(&mut self, expr: &'tcx Expr<'tcx>) -> bool { if let ExprKind::MethodCall(take_path, recv, [len_arg], _) = expr.kind - && take_path.ident.name.as_str() == "take" + && take_path.ident.name == sym::take // Check that take is applied to `repeat(0)` && self.is_repeat_zero(recv) { diff --git a/src/tools/clippy/clippy_lints/src/strings.rs b/src/tools/clippy/clippy_lints/src/strings.rs index 43a3e6961051..af4d0d541f17 100644 --- a/src/tools/clippy/clippy_lints/src/strings.rs +++ b/src/tools/clippy/clippy_lints/src/strings.rs @@ -286,7 +286,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes { if !e.span.in_external_macro(cx.sess().source_map()) && let ExprKind::MethodCall(path, receiver, ..) = &e.kind - && path.ident.name.as_str() == "as_bytes" + && path.ident.name == sym::as_bytes && let ExprKind::Lit(lit) = &receiver.kind && let LitKind::Str(lit_content, _) = &lit.node { @@ -332,7 +332,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes { } if let ExprKind::MethodCall(path, recv, [], _) = &e.kind - && path.ident.name.as_str() == "into_bytes" + && path.ident.name == sym::into_bytes && let ExprKind::MethodCall(path, recv, [], _) = &recv.kind && matches!(path.ident.name.as_str(), "to_owned" | "to_string") && let ExprKind::Lit(lit) = &recv.kind @@ -556,7 +556,7 @@ impl<'tcx> LateLintPass<'tcx> for TrimSplitWhitespace { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) { let tyckres = cx.typeck_results(); if let ExprKind::MethodCall(path, split_recv, [], split_ws_span) = expr.kind - && path.ident.name.as_str() == "split_whitespace" + && path.ident.name == sym::split_whitespace && let Some(split_ws_def_id) = tyckres.type_dependent_def_id(expr.hir_id) && cx.tcx.is_diagnostic_item(sym::str_split_whitespace, split_ws_def_id) && let ExprKind::MethodCall(path, _trim_recv, [], trim_span) = split_recv.kind diff --git a/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs b/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs index 9993e6ae18b9..bb969bc802fe 100644 --- a/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs +++ b/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::match_def_path; use clippy_utils::source::snippet_with_applicability; +use clippy_utils::{match_def_path, sym}; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; @@ -38,11 +38,11 @@ declare_lint_pass!(ToDigitIsSome => [TO_DIGIT_IS_SOME]); impl<'tcx> LateLintPass<'tcx> for ToDigitIsSome { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) { if let hir::ExprKind::MethodCall(is_some_path, to_digit_expr, [], _) = &expr.kind - && is_some_path.ident.name.as_str() == "is_some" + && is_some_path.ident.name == sym::is_some { let match_result = match &to_digit_expr.kind { hir::ExprKind::MethodCall(to_digits_path, char_arg, [radix_arg], _) => { - if to_digits_path.ident.name.as_str() == "to_digit" + if to_digits_path.ident.name == sym::to_digit && let char_arg_ty = cx.typeck_results().expr_ty_adjusted(char_arg) && *char_arg_ty.kind() == ty::Char { 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 81c0a57083e8..1ccab62708b1 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/eager_transmute.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/eager_transmute.rs @@ -1,6 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::ty::is_normalizable; -use clippy_utils::{eq_expr_value, path_to_local}; +use clippy_utils::{eq_expr_value, path_to_local, sym}; use rustc_abi::WrappingRange; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, Node}; @@ -43,7 +43,7 @@ fn binops_with_local(cx: &LateContext<'_>, local_expr: &Expr<'_>, expr: &Expr<'_ binops_with_local(cx, local_expr, lhs) || binops_with_local(cx, local_expr, rhs) }, ExprKind::MethodCall(path, receiver, [arg], _) - if path.ident.name.as_str() == "contains" + if path.ident.name == sym::contains // ... `contains` called on some kind of range && let Some(receiver_adt) = cx.typeck_results().expr_ty(receiver).peel_refs().ty_adt_def() && let lang_items = cx.tcx.lang_items() @@ -81,7 +81,7 @@ pub(super) fn check<'tcx>( if let Some(then_some_call) = peel_parent_unsafe_blocks(cx, expr) && let ExprKind::MethodCall(path, receiver, [arg], _) = then_some_call.kind && cx.typeck_results().expr_ty(receiver).is_bool() - && path.ident.name.as_str() == "then_some" + && path.ident.name == sym::then_some && is_local_with_projections(transmutable) && binops_with_local(cx, transmutable, receiver) && is_normalizable(cx, cx.param_env, from_ty) diff --git a/src/tools/clippy/clippy_lints/src/types/vec_box.rs b/src/tools/clippy/clippy_lints/src/types/vec_box.rs index 769244c675e1..f13042a6fa6b 100644 --- a/src/tools/clippy/clippy_lints/src/types/vec_box.rs +++ b/src/tools/clippy/clippy_lints/src/types/vec_box.rs @@ -19,61 +19,58 @@ pub(super) fn check<'tcx>( def_id: DefId, box_size_threshold: u64, ) -> bool { - if cx.tcx.is_diagnostic_item(sym::Vec, def_id) { - if let Some(last) = last_path_segment(qpath).args - // Get the _ part of Vec<_> - && let Some(GenericArg::Type(ty)) = last.args.first() - // extract allocator from the Vec for later - && let vec_alloc_ty = last.args.get(1) - // ty is now _ at this point - && let TyKind::Path(ref ty_qpath) = ty.kind - && let res = cx.qpath_res(ty_qpath, ty.hir_id) - && let Some(def_id) = res.opt_def_id() - && Some(def_id) == cx.tcx.lang_items().owned_box() - // At this point, we know ty is Box, now get T - && let Some(last) = last_path_segment(ty_qpath).args - && let Some(GenericArg::Type(boxed_ty)) = last.args.first() - // extract allocator from the Box for later - && let boxed_alloc_ty = last.args.get(1) - // we don't expect to encounter `_` here so ignore `GenericArg::Infer` is okay - && let ty_ty = lower_ty(cx.tcx, boxed_ty.as_unambig_ty()) - && !ty_ty.has_escaping_bound_vars() - && ty_ty.is_sized(cx.tcx, cx.typing_env()) - && let Ok(ty_ty_size) = cx.layout_of(ty_ty).map(|l| l.size.bytes()) - && ty_ty_size < box_size_threshold - // https://github.com/rust-lang/rust-clippy/issues/7114 - && match (vec_alloc_ty, boxed_alloc_ty) { - (None, None) => true, - // this is in the event that we have something like - // Vec<_, Global>, in which case is equivalent to - // Vec<_> - (None, Some(GenericArg::Type(inner))) | (Some(GenericArg::Type(inner)), None) => { - if let TyKind::Path(path) = inner.kind - && let Some(did) = cx.qpath_res(&path, inner.hir_id).opt_def_id() { - cx.tcx.lang_items().get(LangItem::GlobalAlloc) == Some(did) - } else { - false - } - }, - (Some(GenericArg::Type(l)), Some(GenericArg::Type(r))) => - // we don't expect to encounter `_` here so ignore `GenericArg::Infer` is okay - lower_ty(cx.tcx, l.as_unambig_ty()) == lower_ty(cx.tcx, r.as_unambig_ty()), - _ => false - } - { - span_lint_and_sugg( - cx, - VEC_BOX, - hir_ty.span, - "`Vec` is already on the heap, the boxing is unnecessary", - "try", - format!("Vec<{}>", snippet(cx, boxed_ty.span, "..")), - Applicability::Unspecified, - ); - true - } else { - false + if cx.tcx.is_diagnostic_item(sym::Vec, def_id) + && let Some(last) = last_path_segment(qpath).args + // Get the _ part of Vec<_> + && let Some(GenericArg::Type(ty)) = last.args.first() + // extract allocator from the Vec for later + && let vec_alloc_ty = last.args.get(1) + // ty is now _ at this point + && let TyKind::Path(ref ty_qpath) = ty.kind + && let res = cx.qpath_res(ty_qpath, ty.hir_id) + && let Some(def_id) = res.opt_def_id() + && Some(def_id) == cx.tcx.lang_items().owned_box() + // At this point, we know ty is Box, now get T + && let Some(last) = last_path_segment(ty_qpath).args + && let Some(GenericArg::Type(boxed_ty)) = last.args.first() + // extract allocator from the Box for later + && let boxed_alloc_ty = last.args.get(1) + // we don't expect to encounter `_` here so ignore `GenericArg::Infer` is okay + && let ty_ty = lower_ty(cx.tcx, boxed_ty.as_unambig_ty()) + && !ty_ty.has_escaping_bound_vars() + && ty_ty.is_sized(cx.tcx, cx.typing_env()) + && let Ok(ty_ty_size) = cx.layout_of(ty_ty).map(|l| l.size.bytes()) + && ty_ty_size < box_size_threshold + // https://github.com/rust-lang/rust-clippy/issues/7114 + && match (vec_alloc_ty, boxed_alloc_ty) { + (None, None) => true, + // this is in the event that we have something like + // Vec<_, Global>, in which case is equivalent to + // Vec<_> + (None, Some(GenericArg::Type(inner))) | (Some(GenericArg::Type(inner)), None) => { + if let TyKind::Path(path) = inner.kind + && let Some(did) = cx.qpath_res(&path, inner.hir_id).opt_def_id() { + cx.tcx.lang_items().get(LangItem::GlobalAlloc) == Some(did) + } else { + false + } + }, + (Some(GenericArg::Type(l)), Some(GenericArg::Type(r))) => + // we don't expect to encounter `_` here so ignore `GenericArg::Infer` is okay + lower_ty(cx.tcx, l.as_unambig_ty()) == lower_ty(cx.tcx, r.as_unambig_ty()), + _ => false } + { + span_lint_and_sugg( + cx, + VEC_BOX, + hir_ty.span, + "`Vec` is already on the heap, the boxing is unnecessary", + "try", + format!("Vec<{}>", snippet(cx, boxed_ty.span, "..")), + Applicability::Unspecified, + ); + true } else { false } diff --git a/src/tools/clippy/clippy_lints/src/uninit_vec.rs b/src/tools/clippy/clippy_lints/src/uninit_vec.rs index 7803d5115c97..cee4a53f03cb 100644 --- a/src/tools/clippy/clippy_lints/src/uninit_vec.rs +++ b/src/tools/clippy/clippy_lints/src/uninit_vec.rs @@ -1,12 +1,12 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; use clippy_utils::higher::{VecInitKind, get_vec_init_kind}; use clippy_utils::ty::{is_type_diagnostic_item, is_uninit_value_valid_for_ty}; -use clippy_utils::{SpanlessEq, is_integer_literal, is_lint_allowed, path_to_local_id, peel_hir_expr_while}; +use clippy_utils::{SpanlessEq, is_integer_literal, is_lint_allowed, path_to_local_id, peel_hir_expr_while, sym}; use rustc_hir::{Block, Expr, ExprKind, HirId, PatKind, PathSegment, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::declare_lint_pass; -use rustc_span::{Span, sym}; +use rustc_span::Span; // TODO: add `ReadBuf` (RFC 2930) in "How to fix" once it is available in std declare_clippy_lint! { @@ -187,7 +187,7 @@ fn extract_init_or_reserve_target<'tcx>(cx: &LateContext<'tcx>, stmt: &'tcx Stmt fn is_reserve(cx: &LateContext<'_>, path: &PathSegment<'_>, self_expr: &Expr<'_>) -> bool { is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_expr).peel_refs(), sym::Vec) - && path.ident.name.as_str() == "reserve" + && path.ident.name == sym::reserve } /// Returns self if the expression is `Vec::set_len()` @@ -209,7 +209,7 @@ fn extract_set_len_self<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Opt ExprKind::MethodCall(path, self_expr, [arg], _) => { let self_type = cx.typeck_results().expr_ty(self_expr).peel_refs(); if is_type_diagnostic_item(cx, self_type, sym::Vec) - && path.ident.name.as_str() == "set_len" + && path.ident.name == sym::set_len && !is_integer_literal(arg, 0) { Some((self_expr, expr.span)) diff --git a/src/tools/clippy/clippy_lints/src/unused_self.rs b/src/tools/clippy/clippy_lints/src/unused_self.rs index d0067b1a65e7..12da891a71b1 100644 --- a/src/tools/clippy/clippy_lints/src/unused_self.rs +++ b/src/tools/clippy/clippy_lints/src/unused_self.rs @@ -1,6 +1,7 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::macros::root_macro_call_first_node; +use clippy_utils::sym; use clippy_utils::visitors::is_local_used; use rustc_hir::{Body, Impl, ImplItem, ImplItemKind, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -61,12 +62,10 @@ impl<'tcx> LateLintPass<'tcx> for UnusedSelf { let assoc_item = cx.tcx.associated_item(impl_item.owner_id); let contains_todo = |cx, body: &'_ Body<'_>| -> bool { clippy_utils::visitors::for_each_expr_without_closures(body.value, |e| { - if let Some(macro_call) = root_macro_call_first_node(cx, e) { - if cx.tcx.item_name(macro_call.def_id).as_str() == "todo" { - ControlFlow::Break(()) - } else { - ControlFlow::Continue(()) - } + if let Some(macro_call) = root_macro_call_first_node(cx, e) + && cx.tcx.is_diagnostic_item(sym::todo_macro, macro_call.def_id) + { + ControlFlow::Break(()) } else { ControlFlow::Continue(()) } diff --git a/src/tools/clippy/clippy_lints/src/unused_unit.rs b/src/tools/clippy/clippy_lints/src/unused_unit.rs index d5309aade7aa..9859ddfdf7bd 100644 --- a/src/tools/clippy/clippy_lints/src/unused_unit.rs +++ b/src/tools/clippy/clippy_lints/src/unused_unit.rs @@ -1,11 +1,18 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::{SpanRangeExt, position_before_rarrow}; -use rustc_ast::visit::FnKind; -use rustc_ast::{ClosureBinder, ast}; +use clippy_utils::{is_never_expr, is_unit_expr}; +use rustc_ast::{Block, StmtKind}; use rustc_errors::Applicability; -use rustc_lint::{EarlyContext, EarlyLintPass}; +use rustc_hir::def_id::LocalDefId; +use rustc_hir::intravisit::FnKind; +use rustc_hir::{ + AssocItemConstraintKind, Body, Expr, ExprKind, FnDecl, FnRetTy, GenericArgsParentheses, Node, PolyTraitRef, Term, + Ty, TyKind, +}; +use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::{BytePos, Span}; +use rustc_span::edition::Edition; +use rustc_span::{BytePos, Span, sym}; declare_clippy_lint! { /// ### What it does @@ -34,27 +41,89 @@ declare_clippy_lint! { declare_lint_pass!(UnusedUnit => [UNUSED_UNIT]); -impl EarlyLintPass for UnusedUnit { - fn check_fn(&mut self, cx: &EarlyContext<'_>, kind: FnKind<'_>, span: Span, _: ast::NodeId) { - if let ast::FnRetTy::Ty(ref ty) = kind.decl().output - && let ast::TyKind::Tup(ref vals) = ty.kind - && vals.is_empty() - && !ty.span.from_expansion() - && get_def(span) == get_def(ty.span) +impl<'tcx> LateLintPass<'tcx> for UnusedUnit { + fn check_fn( + &mut self, + cx: &LateContext<'tcx>, + kind: FnKind<'tcx>, + decl: &'tcx FnDecl<'tcx>, + body: &'tcx Body<'tcx>, + span: Span, + def_id: LocalDefId, + ) { + if let FnRetTy::Return(hir_ty) = decl.output + && is_unit_ty(hir_ty) + && !hir_ty.span.from_expansion() + && get_def(span) == get_def(hir_ty.span) { // implicit types in closure signatures are forbidden when `for<...>` is present - if let FnKind::Closure(&ClosureBinder::For { .. }, ..) = kind { + if let FnKind::Closure = kind + && let Node::Expr(expr) = cx.tcx.hir_node_by_def_id(def_id) + && let ExprKind::Closure(closure) = expr.kind + && !closure.bound_generic_params.is_empty() + { return; } - lint_unneeded_unit_return(cx, ty, span); + // unit never type fallback is no longer supported since Rust 2024. For more information, + // see + if cx.tcx.sess.edition() >= Edition::Edition2024 + && let ExprKind::Block(block, _) = body.value.kind + && let Some(expr) = block.expr + && is_never_expr(cx, expr).is_some() + { + return; + } + + lint_unneeded_unit_return(cx, hir_ty.span, span); } } - fn check_block(&mut self, cx: &EarlyContext<'_>, block: &ast::Block) { - if let Some(stmt) = block.stmts.last() - && let ast::StmtKind::Expr(ref expr) = stmt.kind + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { + if let ExprKind::Ret(Some(expr)) | ExprKind::Break(_, Some(expr)) = expr.kind && is_unit_expr(expr) + && !expr.span.from_expansion() + { + span_lint_and_sugg( + cx, + UNUSED_UNIT, + expr.span, + "unneeded `()`", + "remove the `()`", + String::new(), + Applicability::MachineApplicable, + ); + } + } + + fn check_poly_trait_ref(&mut self, cx: &LateContext<'tcx>, poly: &'tcx PolyTraitRef<'tcx>) { + let segments = &poly.trait_ref.path.segments; + + if segments.len() == 1 + && ["Fn", "FnMut", "FnOnce"].contains(&segments[0].ident.name.as_str()) + && let Some(args) = segments[0].args + && args.parenthesized == GenericArgsParentheses::ParenSugar + && let constraints = &args.constraints + && constraints.len() == 1 + && constraints[0].ident.name == sym::Output + && let AssocItemConstraintKind::Equality { term: Term::Ty(hir_ty) } = constraints[0].kind + && args.span_ext.hi() != poly.span.hi() + && !hir_ty.span.from_expansion() + && is_unit_ty(hir_ty) + { + lint_unneeded_unit_return(cx, hir_ty.span, poly.span); + } + } +} + +impl EarlyLintPass for UnusedUnit { + /// Check for unit expressions in blocks. This is left in the early pass because some macros + /// expand its inputs as-is, making it invisible to the late pass. See #4076. + fn check_block(&mut self, cx: &EarlyContext<'_>, block: &Block) { + if let Some(stmt) = block.stmts.last() + && let StmtKind::Expr(expr) = &stmt.kind + && let rustc_ast::ExprKind::Tup(inner) = &expr.kind + && inner.is_empty() && let ctxt = block.span.ctxt() && stmt.span.ctxt() == ctxt && expr.span.ctxt() == ctxt @@ -72,39 +141,10 @@ impl EarlyLintPass for UnusedUnit { ); } } +} - fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) { - match e.kind { - ast::ExprKind::Ret(Some(ref expr)) | ast::ExprKind::Break(_, Some(ref expr)) => { - if is_unit_expr(expr) && !expr.span.from_expansion() { - span_lint_and_sugg( - cx, - UNUSED_UNIT, - expr.span, - "unneeded `()`", - "remove the `()`", - String::new(), - Applicability::MachineApplicable, - ); - } - }, - _ => (), - } - } - - fn check_poly_trait_ref(&mut self, cx: &EarlyContext<'_>, poly: &ast::PolyTraitRef) { - let segments = &poly.trait_ref.path.segments; - - if segments.len() == 1 - && ["Fn", "FnMut", "FnOnce"].contains(&segments[0].ident.name.as_str()) - && let Some(args) = &segments[0].args - && let ast::GenericArgs::Parenthesized(generic_args) = &**args - && let ast::FnRetTy::Ty(ty) = &generic_args.output - && ty.kind.is_unit() - { - lint_unneeded_unit_return(cx, ty, generic_args.span); - } - } +fn is_unit_ty(ty: &Ty<'_>) -> bool { + matches!(ty.kind, TyKind::Tup([])) } // get the def site @@ -117,24 +157,15 @@ fn get_def(span: Span) -> Option { } } -// is this expr a `()` unit? -fn is_unit_expr(expr: &ast::Expr) -> bool { - if let ast::ExprKind::Tup(ref vals) = expr.kind { - vals.is_empty() - } else { - false - } -} - -fn lint_unneeded_unit_return(cx: &EarlyContext<'_>, ty: &ast::Ty, span: Span) { +fn lint_unneeded_unit_return(cx: &LateContext<'_>, ty_span: Span, span: Span) { let (ret_span, appl) = - span.with_hi(ty.span.hi()) + span.with_hi(ty_span.hi()) .get_source_text(cx) - .map_or((ty.span, Applicability::MaybeIncorrect), |src| { - position_before_rarrow(&src).map_or((ty.span, Applicability::MaybeIncorrect), |rpos| { + .map_or((ty_span, Applicability::MaybeIncorrect), |src| { + position_before_rarrow(&src).map_or((ty_span, Applicability::MaybeIncorrect), |rpos| { ( #[expect(clippy::cast_possible_truncation)] - ty.span.with_lo(BytePos(span.lo().0 + rpos as u32)), + ty_span.with_lo(BytePos(span.lo().0 + rpos as u32)), Applicability::MachineApplicable, ) }) diff --git a/src/tools/clippy/clippy_lints/src/unwrap.rs b/src/tools/clippy/clippy_lints/src/unwrap.rs index ce82b56eb946..ba140788bb54 100644 --- a/src/tools/clippy/clippy_lints/src/unwrap.rs +++ b/src/tools/clippy/clippy_lints/src/unwrap.rs @@ -208,7 +208,7 @@ fn is_option_as_mut_use(tcx: TyCtxt<'_>, expr_id: HirId) -> bool { if let Node::Expr(mutating_expr) = tcx.parent_hir_node(expr_id) && let ExprKind::MethodCall(path, _, [], _) = mutating_expr.kind { - path.ident.name.as_str() == "as_mut" + path.ident.name == sym::as_mut } else { false } @@ -278,7 +278,7 @@ fn consume_option_as_ref<'tcx>(expr: &'tcx Expr<'tcx>) -> (&'tcx Expr<'tcx>, Opt if let ExprKind::MethodCall(path, recv, [], _) = expr.kind { if path.ident.name == sym::as_ref { (recv, Some(AsRefKind::AsRef)) - } else if path.ident.name.as_str() == "as_mut" { + } else if path.ident.name == sym::as_mut { (recv, Some(AsRefKind::AsMut)) } else { (expr, None) diff --git a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs index 5b3f60ad6ab0..45a5dbabeb4e 100644 --- a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs +++ b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs @@ -154,7 +154,7 @@ impl LateLintPass<'_> for WildcardImports { (span, false) }; - let mut imports = used_imports.items().map(ToString::to_string).into_sorted_stable_ord(); + let mut imports: Vec<_> = used_imports.iter().map(ToString::to_string).collect(); let imports_string = if imports.len() == 1 { imports.pop().unwrap() } else if braced_glob { diff --git a/src/tools/clippy/clippy_lints/src/write.rs b/src/tools/clippy/clippy_lints/src/write.rs index 11c14c147776..f24c127c4521 100644 --- a/src/tools/clippy/clippy_lints/src/write.rs +++ b/src/tools/clippy/clippy_lints/src/write.rs @@ -1,8 +1,8 @@ use clippy_config::Conf; use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; -use clippy_utils::is_in_test; use clippy_utils::macros::{FormatArgsStorage, MacroCall, format_arg_removal_span, root_macro_call_first_node}; use clippy_utils::source::{SpanRangeExt, expand_past_previous_comma}; +use clippy_utils::{is_in_test, sym}; use rustc_ast::token::LitKind; use rustc_ast::{ FormatArgPosition, FormatArgPositionKind, FormatArgs, FormatArgsPiece, FormatOptions, FormatPlaceholder, @@ -12,7 +12,7 @@ use rustc_errors::Applicability; use rustc_hir::{Expr, Impl, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::impl_lint_pass; -use rustc_span::{BytePos, Span, sym}; +use rustc_span::{BytePos, Span}; declare_clippy_lint! { /// ### What it does @@ -359,7 +359,7 @@ fn is_debug_impl(cx: &LateContext<'_>, item: &Item<'_>) -> bool { } fn check_newline(cx: &LateContext<'_>, format_args: &FormatArgs, macro_call: &MacroCall, name: &str) { - let Some(FormatArgsPiece::Literal(last)) = format_args.template.last() else { + let Some(&FormatArgsPiece::Literal(last)) = format_args.template.last() else { return; }; @@ -401,7 +401,7 @@ fn check_newline(cx: &LateContext<'_>, format_args: &FormatArgs, macro_call: &Ma return; }; - if format_args.template.len() == 1 && last.as_str() == "\n" { + if format_args.template.len() == 1 && last == sym::LF { // print!("\n"), write!(f, "\n") diag.multipart_suggestion( @@ -427,9 +427,7 @@ fn check_newline(cx: &LateContext<'_>, format_args: &FormatArgs, macro_call: &Ma } fn check_empty_string(cx: &LateContext<'_>, format_args: &FormatArgs, macro_call: &MacroCall, name: &str) { - if let [FormatArgsPiece::Literal(literal)] = &format_args.template[..] - && literal.as_str() == "\n" - { + if let [FormatArgsPiece::Literal(sym::LF)] = &format_args.template[..] { let mut span = format_args.span; let lint = if name == "writeln" { diff --git a/src/tools/clippy/clippy_lints/src/zombie_processes.rs b/src/tools/clippy/clippy_lints/src/zombie_processes.rs index 39c1aab8967a..09f1084fe700 100644 --- a/src/tools/clippy/clippy_lints/src/zombie_processes.rs +++ b/src/tools/clippy/clippy_lints/src/zombie_processes.rs @@ -4,6 +4,7 @@ use clippy_utils::{fn_def_id, get_enclosing_block, path_to_local_id}; use rustc_ast::Mutability; use rustc_ast::visit::visit_opt; use rustc_errors::Applicability; +use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{Visitor, walk_block, walk_expr, walk_local}; use rustc_hir::{Expr, ExprKind, HirId, LetStmt, Node, PatKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -68,6 +69,7 @@ impl<'tcx> LateLintPass<'tcx> for ZombieProcesses { let mut vis = WaitFinder { cx, local_id, + body_id: cx.tcx.hir_enclosing_body_owner(expr.hir_id), state: VisitorState::WalkUpToLocal, early_return: None, missing_wait_branch: None, @@ -129,6 +131,7 @@ struct MaybeWait(Span); struct WaitFinder<'a, 'tcx> { cx: &'a LateContext<'tcx>, local_id: HirId, + body_id: LocalDefId, state: VisitorState, early_return: Option, // When joining two if branches where one of them doesn't call `wait()`, stores its span for more targeted help @@ -186,7 +189,7 @@ impl<'tcx> Visitor<'tcx> for WaitFinder<'_, 'tcx> { } } else { match ex.kind { - ExprKind::Ret(e) => { + ExprKind::Ret(e) if self.cx.tcx.hir_enclosing_body_owner(ex.hir_id) == self.body_id => { visit_opt!(self, visit_expr, e); if self.early_return.is_none() { self.early_return = Some(ex.span); diff --git a/src/tools/clippy/clippy_lints_internal/src/lib.rs b/src/tools/clippy/clippy_lints_internal/src/lib.rs index 1c42f4112f9a..b02d378619ca 100644 --- a/src/tools/clippy/clippy_lints_internal/src/lib.rs +++ b/src/tools/clippy/clippy_lints_internal/src/lib.rs @@ -2,6 +2,7 @@ #![allow( clippy::missing_docs_in_private_items, clippy::must_use_candidate, + clippy::symbol_as_str, rustc::diagnostic_outside_of_impl, rustc::untranslatable_diagnostic )] @@ -31,12 +32,12 @@ extern crate rustc_span; mod almost_standard_lint_formulation; mod collapsible_calls; -mod interning_literals; mod invalid_paths; mod lint_without_lint_pass; mod msrv_attr_impl; mod outer_expn_data_pass; mod produce_ice; +mod symbols; mod unnecessary_def_path; mod unsorted_clippy_utils_paths; @@ -45,7 +46,6 @@ use rustc_lint::{Lint, LintStore}; static LINTS: &[&Lint] = &[ almost_standard_lint_formulation::ALMOST_STANDARD_LINT_FORMULATION, collapsible_calls::COLLAPSIBLE_SPAN_LINT_CALLS, - interning_literals::INTERNING_LITERALS, invalid_paths::INVALID_PATHS, lint_without_lint_pass::DEFAULT_LINT, lint_without_lint_pass::INVALID_CLIPPY_VERSION_ATTRIBUTE, @@ -54,6 +54,8 @@ static LINTS: &[&Lint] = &[ msrv_attr_impl::MISSING_MSRV_ATTR_IMPL, outer_expn_data_pass::OUTER_EXPN_EXPN_DATA, produce_ice::PRODUCE_ICE, + symbols::INTERNING_LITERALS, + symbols::SYMBOL_AS_STR, unnecessary_def_path::UNNECESSARY_DEF_PATH, unsorted_clippy_utils_paths::UNSORTED_CLIPPY_UTILS_PATHS, ]; @@ -65,7 +67,7 @@ pub fn register_lints(store: &mut LintStore) { store.register_early_pass(|| Box::new(produce_ice::ProduceIce)); store.register_late_pass(|_| Box::new(collapsible_calls::CollapsibleCalls)); store.register_late_pass(|_| Box::new(invalid_paths::InvalidPaths)); - store.register_late_pass(|_| Box::::default()); + store.register_late_pass(|_| Box::::default()); store.register_late_pass(|_| Box::::default()); store.register_late_pass(|_| Box::::default()); store.register_late_pass(|_| Box::new(outer_expn_data_pass::OuterExpnDataPass)); diff --git a/src/tools/clippy/clippy_lints_internal/src/interning_literals.rs b/src/tools/clippy/clippy_lints_internal/src/symbols.rs similarity index 52% rename from src/tools/clippy/clippy_lints_internal/src/interning_literals.rs rename to src/tools/clippy/clippy_lints_internal/src/symbols.rs index 6cee37442349..c64e5821916b 100644 --- a/src/tools/clippy/clippy_lints_internal/src/interning_literals.rs +++ b/src/tools/clippy/clippy_lints_internal/src/symbols.rs @@ -1,7 +1,7 @@ -use clippy_utils::consts::{ConstEvalCtxt, Constant}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::ty::match_type; -use clippy_utils::{def_path_def_ids, paths}; +use clippy_utils::{def_path_def_ids, match_def_path, paths}; +use rustc_ast::LitKind; use rustc_data_structures::fx::FxHashMap; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; @@ -11,8 +11,8 @@ use rustc_lint_defs::declare_tool_lint; use rustc_middle::mir::ConstValue; use rustc_middle::ty; use rustc_session::impl_lint_pass; -use rustc_span::sym; use rustc_span::symbol::Symbol; +use rustc_span::{Span, sym}; declare_tool_lint! { /// ### What it does @@ -36,15 +36,37 @@ declare_tool_lint! { report_in_external_macro: true } +declare_tool_lint! { + /// ### What it does + /// Checks for calls to `Symbol::as_str` + /// + /// ### Why is this bad? + /// It's faster and easier to use the symbol constant. If one doesn't exist it can be added to `clippy_utils/src/sym.rs` + /// + /// ### Example + /// ```rust,ignore + /// symbol.as_str() == "foo" + /// ``` + /// + /// Use instead: + /// ```rust,ignore + /// symbol == sym::foo + /// ``` + pub clippy::SYMBOL_AS_STR, + Warn, + "calls to `Symbol::as_str`", + report_in_external_macro: true +} + #[derive(Default)] -pub struct InterningDefinedSymbol { +pub struct Symbols { // Maps the symbol to the import path symbol_map: FxHashMap, } -impl_lint_pass!(InterningDefinedSymbol => [INTERNING_LITERALS]); +impl_lint_pass!(Symbols => [INTERNING_LITERALS, SYMBOL_AS_STR]); -impl<'tcx> LateLintPass<'tcx> for InterningDefinedSymbol { +impl<'tcx> LateLintPass<'tcx> for Symbols { fn check_crate(&mut self, cx: &LateContext<'_>) { let modules = [ ("kw", &paths::KW_MODULE[..]), @@ -77,7 +99,8 @@ impl<'tcx> LateLintPass<'tcx> for InterningDefinedSymbol { if let ExprKind::Call(func, [arg]) = &expr.kind && let ty::FnDef(def_id, _) = cx.typeck_results().expr_ty(func).kind() && cx.tcx.is_diagnostic_item(sym::SymbolIntern, *def_id) - && let Some(Constant::Str(arg)) = ConstEvalCtxt::new(cx).eval_simple(arg) + && let ExprKind::Lit(lit) = arg.kind + && let LitKind::Str(name, _) = lit.node { span_lint_and_then( cx, @@ -85,18 +108,62 @@ impl<'tcx> LateLintPass<'tcx> for InterningDefinedSymbol { expr.span, "interning a string literal", |diag| { - let value = Symbol::intern(&arg).as_u32(); - let (message, path) = if let Some((prefix, name)) = self.symbol_map.get(&value) { - ("use the preinterned symbol", format!("{prefix}::{name}")) - } else { - ( - "add the symbol to `clippy_utils/src/sym.rs` and use it", - format!("sym::{}", arg.replace(|ch: char| !ch.is_alphanumeric(), "_")), - ) - }; + let (message, path) = suggestion(&mut self.symbol_map, name); diag.span_suggestion_verbose(expr.span, message, path, Applicability::MaybeIncorrect); }, ); } + + if let ExprKind::Binary(_, lhs, rhs) = expr.kind { + check_binary(cx, lhs, rhs, &mut self.symbol_map); + check_binary(cx, rhs, lhs, &mut self.symbol_map); + } + } +} + +fn check_binary( + cx: &LateContext<'_>, + lhs: &Expr<'_>, + rhs: &Expr<'_>, + symbols: &mut FxHashMap, +) { + if let Some(removal_span) = as_str_span(cx, lhs) + && let ExprKind::Lit(lit) = rhs.kind + && let LitKind::Str(name, _) = lit.node + { + span_lint_and_then(cx, SYMBOL_AS_STR, lhs.span, "converting a Symbol to a string", |diag| { + let (message, path) = suggestion(symbols, name); + diag.multipart_suggestion_verbose( + message, + vec![(removal_span, String::new()), (rhs.span, path)], + Applicability::MachineApplicable, + ); + }); + } +} + +fn suggestion(symbols: &mut FxHashMap, name: Symbol) -> (&'static str, String) { + if let Some((prefix, name)) = symbols.get(&name.as_u32()) { + ("use the preinterned symbol", format!("{prefix}::{name}")) + } else { + ( + "add the symbol to `clippy_utils/src/sym.rs` and use it", + format!("sym::{}", name.as_str().replace(|ch: char| !ch.is_alphanumeric(), "_")), + ) + } +} + +/// ```ignore +/// symbol.as_str() +/// // ^^^^^^^^ +/// ``` +fn as_str_span(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { + if let ExprKind::MethodCall(_, recv, [], _) = expr.kind + && let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) + && match_def_path(cx, method_def_id, &paths::SYMBOL_AS_STR) + { + Some(recv.span.shrink_to_hi().to(expr.span.shrink_to_hi())) + } else { + None } } diff --git a/src/tools/clippy/clippy_utils/README.md b/src/tools/clippy/clippy_utils/README.md index aceff14a1599..66192f866fa0 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: ``` -nightly-2025-04-22 +nightly-2025-05-01 ``` diff --git a/src/tools/clippy/clippy_utils/src/higher.rs b/src/tools/clippy/clippy_utils/src/higher.rs index d4e66ebd8e1f..dbb993482902 100644 --- a/src/tools/clippy/clippy_utils/src/higher.rs +++ b/src/tools/clippy/clippy_utils/src/higher.rs @@ -3,14 +3,14 @@ #![deny(clippy::missing_docs_in_private_items)] use crate::consts::{ConstEvalCtxt, Constant}; -use crate::is_expn_of; use crate::ty::is_type_diagnostic_item; +use crate::{is_expn_of, sym}; use rustc_ast::ast; use rustc_hir as hir; use rustc_hir::{Arm, Block, Expr, ExprKind, HirId, LoopSource, MatchSource, Node, Pat, QPath, StructTailExpr}; use rustc_lint::LateContext; -use rustc_span::{Span, sym, symbol}; +use rustc_span::{Span, symbol}; /// The essential nodes of a desugared for loop as well as the entire span: /// `for pat in arg { body }` becomes `(pat, arg, body)`. Returns `(pat, arg, body, span)`. @@ -474,7 +474,7 @@ pub fn get_vec_init_kind<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) - return Some(VecInitKind::New); } else if name.ident.name == symbol::kw::Default { return Some(VecInitKind::Default); - } else if name.ident.name.as_str() == "with_capacity" { + } else if name.ident.name == sym::with_capacity { let arg = args.first()?; return match ConstEvalCtxt::new(cx).eval_simple(arg) { Some(Constant::Int(num)) => Some(VecInitKind::WithConstCapacity(num)), diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index 17368a7530d7..c37231d09312 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -1118,8 +1118,8 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { self.hash_const_arg(e); }, TyPatKind::Or(variants) => { - for variant in variants.iter() { - self.hash_ty_pat(variant) + for variant in variants { + self.hash_ty_pat(variant); } }, TyPatKind::Err(_) => {}, diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 264b9b0406d0..187dfa4dda84 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -1412,7 +1412,7 @@ pub fn is_in_panic_handler(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { } /// Gets the name of the item the expression is in, if available. -pub fn get_item_name(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { +pub fn parent_item_name(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { let parent_id = cx.tcx.hir_get_parent_item(expr.hir_id).def_id; match cx.tcx.hir_node_by_def_id(parent_id) { Node::Item(item) => item.kind.ident().map(|ident| ident.name), @@ -2088,7 +2088,7 @@ pub fn match_libc_symbol(cx: &LateContext<'_>, did: DefId, name: &str) -> bool { let path = cx.get_def_path(did); // libc is meant to be used as a flat list of names, but they're all actually defined in different // modules based on the target platform. Ignore everything but crate name and the item name. - path.first().is_some_and(|s| s.as_str() == "libc") && path.last().is_some_and(|s| s.as_str() == name) + path.first().is_some_and(|s| *s == sym::libc) && path.last().is_some_and(|s| s.as_str() == name) } /// Returns the list of condition expressions and the list of blocks in a @@ -3101,7 +3101,7 @@ pub fn span_find_starting_semi(sm: &SourceMap, span: Span) -> Span { sm.span_take_while(span, |&ch| ch == ' ' || ch == ';') } -/// Returns whether the given let pattern and else body can be turned into a question mark +/// Returns whether the given let pattern and else body can be turned into the `?` operator /// /// For this example: /// ```ignore @@ -3124,8 +3124,7 @@ pub fn span_find_starting_semi(sm: &SourceMap, span: Span) -> Span { /// ``` /// /// We output `Some(a)` in the first instance, and `Some(FooBar { a, b })` in the second, because -/// the question mark operator is applicable here. Callers have to check whether we are in a -/// constant or not. +/// the `?` operator is applicable here. Callers have to check whether we are in a constant or not. pub fn pat_and_expr_can_be_question_mark<'a, 'hir>( cx: &LateContext<'_>, pat: &'a Pat<'hir>, diff --git a/src/tools/clippy/clippy_utils/src/sym.rs b/src/tools/clippy/clippy_utils/src/sym.rs index 1a30b473d106..38f077134c03 100644 --- a/src/tools/clippy/clippy_utils/src/sym.rs +++ b/src/tools/clippy/clippy_utils/src/sym.rs @@ -30,33 +30,75 @@ macro_rules! generate { } generate! { + abs, as_bytes, as_deref_mut, as_deref, as_mut, Binary, + build_hasher, + cargo_clippy: "cargo-clippy", Cargo_toml: "Cargo.toml", + cast, + chars, CLIPPY_ARGS, CLIPPY_CONF_DIR, + clone_into, cloned, + collect, contains, copied, + CRLF: "\r\n", Current, + ends_with, + exp, + extend, + finish_non_exhaustive, + finish, + flat_map, + for_each, + from_raw, + from_str_radix, get, insert, int_roundings, + into_bytes, + into_owned, IntoIter, + is_ascii, is_empty, + is_err, + is_none, is_ok, is_some, + last, + LF: "\n", LowerExp, LowerHex, + max, + min, + mode, msrv, Octal, or_default, + parse, + push, regex, + reserve, + resize, + restriction, rustfmt_skip, + set_len, + set_mode, + set_readonly, + signum, + split_whitespace, + split, Start, + take, + TBD, + then_some, + to_digit, to_owned, unused_extern_crates, unwrap_err, @@ -66,4 +108,6 @@ generate! { V4, V6, Weak, + with_capacity, + wrapping_offset, } diff --git a/src/tools/clippy/rust-toolchain.toml b/src/tools/clippy/rust-toolchain.toml index d2f79da1a541..39c7f0e4ad5a 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-04-22" +channel = "nightly-2025-05-01" # 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-internal/symbol_as_str.fixed b/src/tools/clippy/tests/ui-internal/symbol_as_str.fixed new file mode 100644 index 000000000000..3e26732836ca --- /dev/null +++ b/src/tools/clippy/tests/ui-internal/symbol_as_str.fixed @@ -0,0 +1,21 @@ +#![feature(rustc_private)] + +extern crate rustc_span; + +use clippy_utils::sym; +use rustc_span::{Symbol, kw}; + +fn f(s: Symbol) { + s == sym::f32; + //~^ symbol_as_str + s == sym::proc_dash_macro; + //~^ symbol_as_str + s == kw::SelfLower; + //~^ symbol_as_str + s == sym::msrv; + //~^ symbol_as_str + s == sym::Cargo_toml; + //~^ symbol_as_str + sym::get == s; + //~^ symbol_as_str +} diff --git a/src/tools/clippy/tests/ui-internal/symbol_as_str.rs b/src/tools/clippy/tests/ui-internal/symbol_as_str.rs new file mode 100644 index 000000000000..334c32d18983 --- /dev/null +++ b/src/tools/clippy/tests/ui-internal/symbol_as_str.rs @@ -0,0 +1,21 @@ +#![feature(rustc_private)] + +extern crate rustc_span; + +use clippy_utils::sym; +use rustc_span::{Symbol, kw}; + +fn f(s: Symbol) { + s.as_str() == "f32"; + //~^ symbol_as_str + s.as_str() == "proc-macro"; + //~^ symbol_as_str + s.as_str() == "self"; + //~^ symbol_as_str + s.as_str() == "msrv"; + //~^ symbol_as_str + s.as_str() == "Cargo.toml"; + //~^ symbol_as_str + "get" == s.as_str(); + //~^ symbol_as_str +} diff --git a/src/tools/clippy/tests/ui-internal/symbol_as_str.stderr b/src/tools/clippy/tests/ui-internal/symbol_as_str.stderr new file mode 100644 index 000000000000..39f81f3833c4 --- /dev/null +++ b/src/tools/clippy/tests/ui-internal/symbol_as_str.stderr @@ -0,0 +1,76 @@ +error: converting a Symbol to a string + --> tests/ui-internal/symbol_as_str.rs:9:5 + | +LL | s.as_str() == "f32"; + | ^^^^^^^^^^ + | + = note: `-D clippy::symbol-as-str` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::symbol_as_str)]` +help: use the preinterned symbol + | +LL - s.as_str() == "f32"; +LL + s == sym::f32; + | + +error: converting a Symbol to a string + --> tests/ui-internal/symbol_as_str.rs:11:5 + | +LL | s.as_str() == "proc-macro"; + | ^^^^^^^^^^ + | +help: use the preinterned symbol + | +LL - s.as_str() == "proc-macro"; +LL + s == sym::proc_dash_macro; + | + +error: converting a Symbol to a string + --> tests/ui-internal/symbol_as_str.rs:13:5 + | +LL | s.as_str() == "self"; + | ^^^^^^^^^^ + | +help: use the preinterned symbol + | +LL - s.as_str() == "self"; +LL + s == kw::SelfLower; + | + +error: converting a Symbol to a string + --> tests/ui-internal/symbol_as_str.rs:15:5 + | +LL | s.as_str() == "msrv"; + | ^^^^^^^^^^ + | +help: use the preinterned symbol + | +LL - s.as_str() == "msrv"; +LL + s == sym::msrv; + | + +error: converting a Symbol to a string + --> tests/ui-internal/symbol_as_str.rs:17:5 + | +LL | s.as_str() == "Cargo.toml"; + | ^^^^^^^^^^ + | +help: use the preinterned symbol + | +LL - s.as_str() == "Cargo.toml"; +LL + s == sym::Cargo_toml; + | + +error: converting a Symbol to a string + --> tests/ui-internal/symbol_as_str.rs:19:14 + | +LL | "get" == s.as_str(); + | ^^^^^^^^^^ + | +help: use the preinterned symbol + | +LL - "get" == s.as_str(); +LL + sym::get == s; + | + +error: aborting due to 6 previous errors + diff --git a/src/tools/clippy/tests/ui-internal/symbol_as_str_unfixable.rs b/src/tools/clippy/tests/ui-internal/symbol_as_str_unfixable.rs new file mode 100644 index 000000000000..635f28007e9a --- /dev/null +++ b/src/tools/clippy/tests/ui-internal/symbol_as_str_unfixable.rs @@ -0,0 +1,15 @@ +//@no-rustfix: paths that don't exist yet +#![feature(rustc_private)] + +extern crate rustc_span; + +use rustc_span::Symbol; + +fn f(s: Symbol) { + s.as_str() == "xyz123"; + //~^ symbol_as_str + s.as_str() == "with-dash"; + //~^ symbol_as_str + s.as_str() == "with.dot"; + //~^ symbol_as_str +} diff --git a/src/tools/clippy/tests/ui-internal/symbol_as_str_unfixable.stderr b/src/tools/clippy/tests/ui-internal/symbol_as_str_unfixable.stderr new file mode 100644 index 000000000000..5349983ca519 --- /dev/null +++ b/src/tools/clippy/tests/ui-internal/symbol_as_str_unfixable.stderr @@ -0,0 +1,40 @@ +error: converting a Symbol to a string + --> tests/ui-internal/symbol_as_str_unfixable.rs:9:5 + | +LL | s.as_str() == "xyz123"; + | ^^^^^^^^^^ + | + = note: `-D clippy::symbol-as-str` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::symbol_as_str)]` +help: add the symbol to `clippy_utils/src/sym.rs` and use it + | +LL - s.as_str() == "xyz123"; +LL + s == sym::xyz123; + | + +error: converting a Symbol to a string + --> tests/ui-internal/symbol_as_str_unfixable.rs:11:5 + | +LL | s.as_str() == "with-dash"; + | ^^^^^^^^^^ + | +help: add the symbol to `clippy_utils/src/sym.rs` and use it + | +LL - s.as_str() == "with-dash"; +LL + s == sym::with_dash; + | + +error: converting a Symbol to a string + --> tests/ui-internal/symbol_as_str_unfixable.rs:13:5 + | +LL | s.as_str() == "with.dot"; + | ^^^^^^^^^^ + | +help: add the symbol to `clippy_utils/src/sym.rs` and use it + | +LL - s.as_str() == "with.dot"; +LL + s == sym::with_dot; + | + +error: aborting due to 3 previous errors + diff --git a/src/tools/clippy/tests/ui/blocks_in_conditions.fixed b/src/tools/clippy/tests/ui/blocks_in_conditions.fixed index e696896538e5..6ae5b0cb2f04 100644 --- a/src/tools/clippy/tests/ui/blocks_in_conditions.fixed +++ b/src/tools/clippy/tests/ui/blocks_in_conditions.fixed @@ -4,7 +4,6 @@ #![allow( unused, unnecessary_transmutes, - clippy::let_and_return, clippy::needless_if, clippy::missing_transmute_annotations )] diff --git a/src/tools/clippy/tests/ui/blocks_in_conditions.rs b/src/tools/clippy/tests/ui/blocks_in_conditions.rs index 8c8f3249b8a7..3fd060620728 100644 --- a/src/tools/clippy/tests/ui/blocks_in_conditions.rs +++ b/src/tools/clippy/tests/ui/blocks_in_conditions.rs @@ -4,7 +4,6 @@ #![allow( unused, unnecessary_transmutes, - clippy::let_and_return, clippy::needless_if, clippy::missing_transmute_annotations )] diff --git a/src/tools/clippy/tests/ui/blocks_in_conditions.stderr b/src/tools/clippy/tests/ui/blocks_in_conditions.stderr index 41ff59c683e8..282c42a98bfc 100644 --- a/src/tools/clippy/tests/ui/blocks_in_conditions.stderr +++ b/src/tools/clippy/tests/ui/blocks_in_conditions.stderr @@ -1,5 +1,5 @@ error: in an `if` condition, avoid complex blocks or closures with blocks; instead, move the block or closure higher and bind it with a `let` - --> tests/ui/blocks_in_conditions.rs:31:5 + --> tests/ui/blocks_in_conditions.rs:30:5 | LL | / if { LL | | @@ -20,13 +20,13 @@ LL ~ }; if res { | error: omit braces around single expression condition - --> tests/ui/blocks_in_conditions.rs:43:8 + --> tests/ui/blocks_in_conditions.rs:42:8 | LL | if { true } { 6 } else { 10 } | ^^^^^^^^ help: try: `true` error: this boolean expression can be simplified - --> tests/ui/blocks_in_conditions.rs:49:8 + --> tests/ui/blocks_in_conditions.rs:48:8 | LL | if true && x == 3 { 6 } else { 10 } | ^^^^^^^^^^^^^^ help: try: `x == 3` 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 2ce0c04c3017..be31ee5fb486 100644 --- a/src/tools/clippy/tests/ui/double_ended_iterator_last.fixed +++ b/src/tools/clippy/tests/ui/double_ended_iterator_last.fixed @@ -84,6 +84,19 @@ fn issue_14139() { } fn drop_order() { + struct DropDeIterator(std::vec::IntoIter); + impl Iterator for DropDeIterator { + type Item = S; + fn next(&mut self) -> Option { + self.0.next() + } + } + impl DoubleEndedIterator for DropDeIterator { + fn next_back(&mut self) -> Option { + self.0.next_back() + } + } + struct S(&'static str); impl std::ops::Drop for S { fn drop(&mut self) { @@ -92,7 +105,7 @@ fn drop_order() { } let v = vec![S("one"), S("two"), S("three")]; - let mut v = v.into_iter(); + let mut v = DropDeIterator(v.into_iter()); println!("Last element is {}", v.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 a4eb9b3337b9..30864e15bce7 100644 --- a/src/tools/clippy/tests/ui/double_ended_iterator_last.rs +++ b/src/tools/clippy/tests/ui/double_ended_iterator_last.rs @@ -84,6 +84,19 @@ fn issue_14139() { } fn drop_order() { + struct DropDeIterator(std::vec::IntoIter); + impl Iterator for DropDeIterator { + type Item = S; + fn next(&mut self) -> Option { + self.0.next() + } + } + impl DoubleEndedIterator for DropDeIterator { + fn next_back(&mut self) -> Option { + self.0.next_back() + } + } + struct S(&'static str); impl std::ops::Drop for S { fn drop(&mut self) { @@ -92,7 +105,7 @@ fn drop_order() { } let v = vec![S("one"), S("two"), S("three")]; - let v = v.into_iter(); + let v = DropDeIterator(v.into_iter()); println!("Last element is {}", v.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 fe8cf2dcb259..72a6ead47a93 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:96:36 + --> tests/ui/double_ended_iterator_last.rs:109:36 | LL | println!("Last element is {}", v.last().unwrap().0); | ^^^^^^^^ @@ -26,7 +26,7 @@ LL | println!("Last element is {}", v.last().unwrap().0); = note: this change will alter drop order which may be undesirable help: try | -LL ~ let mut v = v.into_iter(); +LL ~ let mut v = DropDeIterator(v.into_iter()); LL ~ println!("Last element is {}", v.next_back().unwrap().0); | 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 index 7c5de8832d69..e9218bbb4094 100644 --- a/src/tools/clippy/tests/ui/double_ended_iterator_last_unfixable.rs +++ b/src/tools/clippy/tests/ui/double_ended_iterator_last_unfixable.rs @@ -11,6 +11,19 @@ fn main() { } fn drop_order() { + struct DropDeIterator(std::vec::IntoIter); + impl Iterator for DropDeIterator { + type Item = S; + fn next(&mut self) -> Option { + self.0.next() + } + } + impl DoubleEndedIterator for DropDeIterator { + fn next_back(&mut self) -> Option { + self.0.next_back() + } + } + struct S(&'static str); impl std::ops::Drop for S { fn drop(&mut self) { @@ -19,7 +32,7 @@ fn drop_order() { } let v = vec![S("one"), S("two"), S("three")]; - let v = (v.into_iter(), 42); + 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 index 845afc11f042..e330a22a3548 100644 --- a/src/tools/clippy/tests/ui/double_ended_iterator_last_unfixable.stderr +++ b/src/tools/clippy/tests/ui/double_ended_iterator_last_unfixable.stderr @@ -1,5 +1,5 @@ error: called `Iterator::last` on a `DoubleEndedIterator`; this will needlessly iterate the entire iterator - --> tests/ui/double_ended_iterator_last_unfixable.rs:23:36 + --> tests/ui/double_ended_iterator_last_unfixable.rs:36:36 | LL | println!("Last element is {}", v.0.last().unwrap().0); | ^^^^------ @@ -8,7 +8,7 @@ LL | println!("Last element is {}", v.0.last().unwrap().0); | = 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:23:36 + --> tests/ui/double_ended_iterator_last_unfixable.rs:36:36 | LL | println!("Last element is {}", v.0.last().unwrap().0); | ^^^ diff --git a/src/tools/clippy/tests/ui/equatable_if_let.fixed b/src/tools/clippy/tests/ui/equatable_if_let.fixed index 166b1387ba26..ce8b67f9ca7b 100644 --- a/src/tools/clippy/tests/ui/equatable_if_let.fixed +++ b/src/tools/clippy/tests/ui/equatable_if_let.fixed @@ -103,3 +103,39 @@ fn main() { external!({ if let 2 = $a {} }); } + +mod issue8710 { + fn str_ref(cs: &[char]) { + if matches!(cs.iter().next(), Some('i')) { + //~^ equatable_if_let + } else { + todo!(); + } + } + + fn i32_ref(cs: &[i32]) { + if matches!(cs.iter().next(), Some(1)) { + //~^ equatable_if_let + } else { + todo!(); + } + } + + fn enum_ref() { + #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] + enum MyEnum { + A(i32), + B, + } + + fn get_enum() -> Option<&'static MyEnum> { + todo!() + } + + if matches!(get_enum(), Some(MyEnum::B)) { + //~^ equatable_if_let + } else { + todo!(); + } + } +} diff --git a/src/tools/clippy/tests/ui/equatable_if_let.rs b/src/tools/clippy/tests/ui/equatable_if_let.rs index 09c2483ae6d4..ff09533f2651 100644 --- a/src/tools/clippy/tests/ui/equatable_if_let.rs +++ b/src/tools/clippy/tests/ui/equatable_if_let.rs @@ -103,3 +103,39 @@ fn main() { external!({ if let 2 = $a {} }); } + +mod issue8710 { + fn str_ref(cs: &[char]) { + if let Some('i') = cs.iter().next() { + //~^ equatable_if_let + } else { + todo!(); + } + } + + fn i32_ref(cs: &[i32]) { + if let Some(1) = cs.iter().next() { + //~^ equatable_if_let + } else { + todo!(); + } + } + + fn enum_ref() { + #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] + enum MyEnum { + A(i32), + B, + } + + fn get_enum() -> Option<&'static MyEnum> { + todo!() + } + + if let Some(MyEnum::B) = get_enum() { + //~^ equatable_if_let + } else { + todo!(); + } + } +} diff --git a/src/tools/clippy/tests/ui/equatable_if_let.stderr b/src/tools/clippy/tests/ui/equatable_if_let.stderr index 81e0e15a5c74..dd1832ad68b2 100644 --- a/src/tools/clippy/tests/ui/equatable_if_let.stderr +++ b/src/tools/clippy/tests/ui/equatable_if_let.stderr @@ -85,5 +85,23 @@ error: this pattern matching can be expressed using equality LL | if let inline!("abc") = "abc" { | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"abc" == inline!("abc")` -error: aborting due to 14 previous errors +error: this pattern matching can be expressed using `matches!` + --> tests/ui/equatable_if_let.rs:109:12 + | +LL | if let Some('i') = cs.iter().next() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(cs.iter().next(), Some('i'))` + +error: this pattern matching can be expressed using `matches!` + --> tests/ui/equatable_if_let.rs:117:12 + | +LL | if let Some(1) = cs.iter().next() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(cs.iter().next(), Some(1))` + +error: this pattern matching can be expressed using `matches!` + --> tests/ui/equatable_if_let.rs:135:12 + | +LL | if let Some(MyEnum::B) = get_enum() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `matches!(get_enum(), Some(MyEnum::B))` + +error: aborting due to 17 previous errors diff --git a/src/tools/clippy/tests/ui/manual_div_ceil.fixed b/src/tools/clippy/tests/ui/manual_div_ceil.fixed index 57fe8917afe8..58ee6978fc12 100644 --- a/src/tools/clippy/tests/ui/manual_div_ceil.fixed +++ b/src/tools/clippy/tests/ui/manual_div_ceil.fixed @@ -1,5 +1,21 @@ #![warn(clippy::manual_div_ceil)] +macro_rules! y { + () => { + let x = 33u32; + let _ = x.div_ceil(8); + //~^ manual_div_ceil + let _ = x.div_ceil(8); + //~^ manual_div_ceil + }; +} + +macro_rules! eight { + () => { + 8 + }; +} + fn main() { let x = 7_u32; let y = 4_u32; @@ -32,6 +48,13 @@ fn main() { let _ = (z as i32 + (y_i - 1)) / y_i; let _ = (7_u32 as i32 + (y_i - 1)) / y_i; let _ = (7_u32 as i32 + (4 - 1)) / 4; + + // Test lint with macro + y!(); + + // Also test if RHS should be result of macro expansion + let _ = 33u32.div_ceil(eight!()); + //~^ manual_div_ceil } fn issue_13843() { diff --git a/src/tools/clippy/tests/ui/manual_div_ceil.rs b/src/tools/clippy/tests/ui/manual_div_ceil.rs index ec343513e5ce..aa0d81b22a0e 100644 --- a/src/tools/clippy/tests/ui/manual_div_ceil.rs +++ b/src/tools/clippy/tests/ui/manual_div_ceil.rs @@ -1,5 +1,21 @@ #![warn(clippy::manual_div_ceil)] +macro_rules! y { + () => { + let x = 33u32; + let _ = (x + 7) / 8; + //~^ manual_div_ceil + let _ = (7 + x) / 8; + //~^ manual_div_ceil + }; +} + +macro_rules! eight { + () => { + 8 + }; +} + fn main() { let x = 7_u32; let y = 4_u32; @@ -32,6 +48,13 @@ fn main() { let _ = (z as i32 + (y_i - 1)) / y_i; let _ = (7_u32 as i32 + (y_i - 1)) / y_i; let _ = (7_u32 as i32 + (4 - 1)) / 4; + + // Test lint with macro + y!(); + + // Also test if RHS should be result of macro expansion + let _ = (33u32 + 7) / eight!(); + //~^ manual_div_ceil } fn issue_13843() { diff --git a/src/tools/clippy/tests/ui/manual_div_ceil.stderr b/src/tools/clippy/tests/ui/manual_div_ceil.stderr index 8e14ab274269..9be5a19bf391 100644 --- a/src/tools/clippy/tests/ui/manual_div_ceil.stderr +++ b/src/tools/clippy/tests/ui/manual_div_ceil.stderr @@ -1,5 +1,5 @@ error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil.rs:9:13 + --> tests/ui/manual_div_ceil.rs:25:13 | LL | let _ = (x + (y - 1)) / y; | ^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(y)` @@ -8,94 +8,122 @@ LL | let _ = (x + (y - 1)) / y; = help: to override `-D warnings` add `#[allow(clippy::manual_div_ceil)]` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil.rs:11:13 + --> tests/ui/manual_div_ceil.rs:27:13 | LL | let _ = ((y - 1) + x) / y; | ^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(y)` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil.rs:13:13 + --> tests/ui/manual_div_ceil.rs:29:13 | LL | let _ = (x + y - 1) / y; | ^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(y)` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil.rs:16:13 + --> tests/ui/manual_div_ceil.rs:32:13 | LL | let _ = (7_u32 + (4 - 1)) / 4; | ^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `7_u32.div_ceil(4)` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil.rs:18:13 + --> tests/ui/manual_div_ceil.rs:34:13 | LL | let _ = (7_i32 as u32 + (4 - 1)) / 4; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `(7_i32 as u32).div_ceil(4)` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil.rs:39:13 + --> tests/ui/manual_div_ceil.rs:6:17 + | +LL | let _ = (x + 7) / 8; + | ^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(8)` +... +LL | y!(); + | ---- in this macro invocation + | + = note: this error originates in the macro `y` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil.rs:8:17 + | +LL | let _ = (7 + x) / 8; + | ^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(8)` +... +LL | y!(); + | ---- in this macro invocation + | + = note: this error originates in the macro `y` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil.rs:56:13 + | +LL | let _ = (33u32 + 7) / eight!(); + | ^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `33u32.div_ceil(eight!())` + +error: manually reimplementing `div_ceil` + --> tests/ui/manual_div_ceil.rs:62:13 | LL | let _ = (2048 + x - 1) / x; | ^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048_usize.div_ceil(x)` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil.rs:43:13 + --> tests/ui/manual_div_ceil.rs:66:13 | LL | let _ = (2048usize + x - 1) / x; | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048usize.div_ceil(x)` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil.rs:47:13 + --> tests/ui/manual_div_ceil.rs:70:13 | LL | let _ = (2048_usize + x - 1) / x; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048_usize.div_ceil(x)` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil.rs:51:13 + --> tests/ui/manual_div_ceil.rs:74:13 | LL | let _ = (x + 4 - 1) / 4; | ^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(4)` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil.rs:54:18 + --> tests/ui/manual_div_ceil.rs:77:18 | LL | let _: u32 = (2048 + 6 - 1) / 6; | ^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048_u32.div_ceil(6)` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil.rs:56:20 + --> tests/ui/manual_div_ceil.rs:79:20 | LL | let _: usize = (2048 + 6 - 1) / 6; | ^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048_usize.div_ceil(6)` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil.rs:58:18 + --> tests/ui/manual_div_ceil.rs:81:18 | LL | let _: u32 = (0x2048 + 0x6 - 1) / 0x6; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `0x2048_u32.div_ceil(0x6)` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil.rs:61:13 + --> tests/ui/manual_div_ceil.rs:84:13 | LL | let _ = (2048 + 6u32 - 1) / 6u32; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `2048_u32.div_ceil(6u32)` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil.rs:64:13 + --> tests/ui/manual_div_ceil.rs:87:13 | LL | let _ = (1_000_000 + 6u32 - 1) / 6u32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.div_ceil()`: `1_000_000_u32.div_ceil(6u32)` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil.rs:70:13 + --> tests/ui/manual_div_ceil.rs:93:13 | LL | let _ = (x + 7) / 8; | ^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(8)` error: manually reimplementing `div_ceil` - --> tests/ui/manual_div_ceil.rs:72:13 + --> tests/ui/manual_div_ceil.rs:95:13 | LL | let _ = (7 + x) / 8; | ^^^^^^^^^^^ help: consider using `.div_ceil()`: `x.div_ceil(8)` -error: aborting due to 16 previous errors +error: aborting due to 19 previous errors diff --git a/src/tools/clippy/tests/ui/needless_if.fixed b/src/tools/clippy/tests/ui/needless_if.fixed index 6208ca19b82b..347dbff7c595 100644 --- a/src/tools/clippy/tests/ui/needless_if.fixed +++ b/src/tools/clippy/tests/ui/needless_if.fixed @@ -46,9 +46,7 @@ fn main() { if let true = true && true {} - if true - && let true = true - {} + if true && let true = true {} // Can lint nested `if let`s ({ //~^ needless_if diff --git a/src/tools/clippy/tests/ui/needless_if.rs b/src/tools/clippy/tests/ui/needless_if.rs index b459ff877be6..5e0f2a14408b 100644 --- a/src/tools/clippy/tests/ui/needless_if.rs +++ b/src/tools/clippy/tests/ui/needless_if.rs @@ -46,9 +46,7 @@ fn main() { if let true = true && true {} - if true - && let true = true - {} + if true && let true = true {} // Can lint nested `if let`s if { //~^ needless_if diff --git a/src/tools/clippy/tests/ui/needless_if.stderr b/src/tools/clippy/tests/ui/needless_if.stderr index eeb8d044526d..62cdf2459448 100644 --- a/src/tools/clippy/tests/ui/needless_if.stderr +++ b/src/tools/clippy/tests/ui/needless_if.stderr @@ -31,7 +31,7 @@ LL + }); | error: this `if` branch is empty - --> tests/ui/needless_if.rs:53:5 + --> tests/ui/needless_if.rs:51:5 | LL | / if { LL | | @@ -57,19 +57,19 @@ LL + } && true); | error: this `if` branch is empty - --> tests/ui/needless_if.rs:98:5 + --> tests/ui/needless_if.rs:96:5 | LL | if { maybe_side_effect() } {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can remove it: `({ maybe_side_effect() });` error: this `if` branch is empty - --> tests/ui/needless_if.rs:101:5 + --> tests/ui/needless_if.rs:99:5 | LL | if { maybe_side_effect() } && true {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can remove it: `({ maybe_side_effect() } && true);` error: this `if` branch is empty - --> tests/ui/needless_if.rs:106:5 + --> tests/ui/needless_if.rs:104:5 | LL | if true {} | ^^^^^^^^^^ help: you can remove it: `true;` diff --git a/src/tools/clippy/tests/ui/needless_late_init.fixed b/src/tools/clippy/tests/ui/needless_late_init.fixed index 391d4bc3fcc7..f832752ccd79 100644 --- a/src/tools/clippy/tests/ui/needless_late_init.fixed +++ b/src/tools/clippy/tests/ui/needless_late_init.fixed @@ -246,9 +246,7 @@ fn does_not_lint() { } let x; - if true - && let Some(n) = Some("let chains too") - { + if true && let Some(n) = Some("let chains too") { x = 1; } else { x = 2; diff --git a/src/tools/clippy/tests/ui/needless_late_init.rs b/src/tools/clippy/tests/ui/needless_late_init.rs index 6096e8300e1a..a52fbf529234 100644 --- a/src/tools/clippy/tests/ui/needless_late_init.rs +++ b/src/tools/clippy/tests/ui/needless_late_init.rs @@ -246,9 +246,7 @@ fn does_not_lint() { } let x; - if true - && let Some(n) = Some("let chains too") - { + if true && let Some(n) = Some("let chains too") { x = 1; } else { x = 2; diff --git a/src/tools/clippy/tests/ui/needless_late_init.stderr b/src/tools/clippy/tests/ui/needless_late_init.stderr index e7c36136847b..b24c12758816 100644 --- a/src/tools/clippy/tests/ui/needless_late_init.stderr +++ b/src/tools/clippy/tests/ui/needless_late_init.stderr @@ -276,7 +276,7 @@ LL ~ }; | error: unneeded late initialization - --> tests/ui/needless_late_init.rs:302:5 + --> tests/ui/needless_late_init.rs:300:5 | LL | let r; | ^^^^^^ created here diff --git a/src/tools/clippy/tests/ui/needless_question_mark.stderr b/src/tools/clippy/tests/ui/needless_question_mark.stderr index 55da4f28976c..8516cee48e67 100644 --- a/src/tools/clippy/tests/ui/needless_question_mark.stderr +++ b/src/tools/clippy/tests/ui/needless_question_mark.stderr @@ -1,100 +1,188 @@ -error: question mark operator is useless here +error: enclosing `Some` and `?` operator are unneeded --> tests/ui/needless_question_mark.rs:20:12 | LL | return Some(to.magic?); - | ^^^^^^^^^^^^^^^ help: try removing question mark and `Some()`: `to.magic` + | ^^^^^^^^^^^^^^^ | = note: `-D clippy::needless-question-mark` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::needless_question_mark)]` +help: remove the enclosing `Some` and `?` operator + | +LL - return Some(to.magic?); +LL + return to.magic; + | -error: question mark operator is useless here +error: enclosing `Some` and `?` operator are unneeded --> tests/ui/needless_question_mark.rs:29:12 | LL | return Some(to.magic?) - | ^^^^^^^^^^^^^^^ help: try removing question mark and `Some()`: `to.magic` + | ^^^^^^^^^^^^^^^ + | +help: remove the enclosing `Some` and `?` operator + | +LL - return Some(to.magic?) +LL + return to.magic + | -error: question mark operator is useless here +error: enclosing `Some` and `?` operator are unneeded --> tests/ui/needless_question_mark.rs:35:5 | LL | Some(to.magic?) - | ^^^^^^^^^^^^^^^ help: try removing question mark and `Some()`: `to.magic` + | ^^^^^^^^^^^^^^^ + | +help: remove the enclosing `Some` and `?` operator + | +LL - Some(to.magic?) +LL + to.magic + | -error: question mark operator is useless here +error: enclosing `Some` and `?` operator are unneeded --> tests/ui/needless_question_mark.rs:41:21 | LL | to.and_then(|t| Some(t.magic?)) - | ^^^^^^^^^^^^^^ help: try removing question mark and `Some()`: `t.magic` + | ^^^^^^^^^^^^^^ + | +help: remove the enclosing `Some` and `?` operator + | +LL - to.and_then(|t| Some(t.magic?)) +LL + to.and_then(|t| t.magic) + | -error: question mark operator is useless here +error: enclosing `Some` and `?` operator are unneeded --> tests/ui/needless_question_mark.rs:51:9 | LL | Some(t.magic?) - | ^^^^^^^^^^^^^^ help: try removing question mark and `Some()`: `t.magic` + | ^^^^^^^^^^^^^^ + | +help: remove the enclosing `Some` and `?` operator + | +LL - Some(t.magic?) +LL + t.magic + | -error: question mark operator is useless here +error: enclosing `Ok` and `?` operator are unneeded --> tests/ui/needless_question_mark.rs:57:12 | LL | return Ok(tr.magic?); - | ^^^^^^^^^^^^^ help: try removing question mark and `Ok()`: `tr.magic` + | ^^^^^^^^^^^^^ + | +help: remove the enclosing `Ok` and `?` operator + | +LL - return Ok(tr.magic?); +LL + return tr.magic; + | -error: question mark operator is useless here +error: enclosing `Ok` and `?` operator are unneeded --> tests/ui/needless_question_mark.rs:65:12 | LL | return Ok(tr.magic?) - | ^^^^^^^^^^^^^ help: try removing question mark and `Ok()`: `tr.magic` + | ^^^^^^^^^^^^^ + | +help: remove the enclosing `Ok` and `?` operator + | +LL - return Ok(tr.magic?) +LL + return tr.magic + | -error: question mark operator is useless here +error: enclosing `Ok` and `?` operator are unneeded --> tests/ui/needless_question_mark.rs:70:5 | LL | Ok(tr.magic?) - | ^^^^^^^^^^^^^ help: try removing question mark and `Ok()`: `tr.magic` + | ^^^^^^^^^^^^^ + | +help: remove the enclosing `Ok` and `?` operator + | +LL - Ok(tr.magic?) +LL + tr.magic + | -error: question mark operator is useless here +error: enclosing `Ok` and `?` operator are unneeded --> tests/ui/needless_question_mark.rs:75:21 | LL | tr.and_then(|t| Ok(t.magic?)) - | ^^^^^^^^^^^^ help: try removing question mark and `Ok()`: `t.magic` + | ^^^^^^^^^^^^ + | +help: remove the enclosing `Ok` and `?` operator + | +LL - tr.and_then(|t| Ok(t.magic?)) +LL + tr.and_then(|t| t.magic) + | -error: question mark operator is useless here +error: enclosing `Ok` and `?` operator are unneeded --> tests/ui/needless_question_mark.rs:84:9 | LL | Ok(t.magic?) - | ^^^^^^^^^^^^ help: try removing question mark and `Ok()`: `t.magic` + | ^^^^^^^^^^^^ + | +help: remove the enclosing `Ok` and `?` operator + | +LL - Ok(t.magic?) +LL + t.magic + | -error: question mark operator is useless here +error: enclosing `Ok` and `?` operator are unneeded --> tests/ui/needless_question_mark.rs:92:16 | LL | return Ok(t.magic?); - | ^^^^^^^^^^^^ help: try removing question mark and `Ok()`: `t.magic` + | ^^^^^^^^^^^^ + | +help: remove the enclosing `Ok` and `?` operator + | +LL - return Ok(t.magic?); +LL + return t.magic; + | -error: question mark operator is useless here +error: enclosing `Some` and `?` operator are unneeded --> tests/ui/needless_question_mark.rs:128:27 | LL | || -> Option<_> { Some(Some($expr)?) }() - | ^^^^^^^^^^^^^^^^^^ help: try removing question mark and `Some()`: `Some($expr)` + | ^^^^^^^^^^^^^^^^^^ ... LL | let _x = some_and_qmark_in_macro!(x?); | ---------------------------- in this macro invocation | = note: this error originates in the macro `some_and_qmark_in_macro` (in Nightly builds, run with -Z macro-backtrace for more info) +help: remove the enclosing `Some` and `?` operator + | +LL - || -> Option<_> { Some(Some($expr)?) }() +LL + || -> Option<_> { Some($expr) }() + | -error: question mark operator is useless here +error: enclosing `Some` and `?` operator are unneeded --> tests/ui/needless_question_mark.rs:140:5 | LL | Some(to.magic?) - | ^^^^^^^^^^^^^^^ help: try removing question mark and `Some()`: `to.magic` + | ^^^^^^^^^^^^^^^ + | +help: remove the enclosing `Some` and `?` operator + | +LL - Some(to.magic?) +LL + to.magic + | -error: question mark operator is useless here +error: enclosing `Ok` and `?` operator are unneeded --> tests/ui/needless_question_mark.rs:149:5 | LL | Ok(s.magic?) - | ^^^^^^^^^^^^ help: try removing question mark and `Ok()`: `s.magic` + | ^^^^^^^^^^^^ + | +help: remove the enclosing `Ok` and `?` operator + | +LL - Ok(s.magic?) +LL + s.magic + | -error: question mark operator is useless here +error: enclosing `Some` and `?` operator are unneeded --> tests/ui/needless_question_mark.rs:154:7 | LL | { Some(a?) } - | ^^^^^^^^ help: try removing question mark and `Some()`: `a` + | ^^^^^^^^ + | +help: remove the enclosing `Some` and `?` operator + | +LL - { Some(a?) } +LL + { a } + | error: aborting due to 15 previous errors diff --git a/src/tools/clippy/tests/ui/ptr_eq.fixed b/src/tools/clippy/tests/ui/ptr_eq.fixed index 484ff3073239..9629b3eea587 100644 --- a/src/tools/clippy/tests/ui/ptr_eq.fixed +++ b/src/tools/clippy/tests/ui/ptr_eq.fixed @@ -23,23 +23,25 @@ fn main() { //~^ ptr_eq let _ = std::ptr::eq(a, b); //~^ ptr_eq - let _ = std::ptr::eq(a.as_ptr(), b as *const _); - //~^ ptr_eq - let _ = std::ptr::eq(a.as_ptr(), b.as_ptr()); - //~^ ptr_eq + + // Do not lint: the rhs conversion is needed + let _ = a.as_ptr() == b as *const _; + + // Do not lint: we have two raw pointers already + let _ = a.as_ptr() == b.as_ptr(); // Do not lint - let _ = mac!(a, b); let _ = another_mac!(a, b); let a = &mut [1, 2, 3]; let b = &mut [1, 2, 3]; - let _ = std::ptr::eq(a.as_mut_ptr(), b as *mut [i32] as *mut _); - //~^ ptr_eq - let _ = std::ptr::eq(a.as_mut_ptr(), b.as_mut_ptr()); - //~^ ptr_eq + // Do not lint: the rhs conversion is needed + let _ = a.as_mut_ptr() == b as *mut [i32] as *mut _; + + // Do not lint: we have two raw pointers already + let _ = a.as_mut_ptr() == b.as_mut_ptr(); let _ = a == b; let _ = core::ptr::eq(a, b); @@ -51,8 +53,12 @@ fn main() { let _ = !std::ptr::eq(x, y); //~^ ptr_eq - #[allow(clippy::eq_op)] - let _issue14337 = std::ptr::eq(main as *const (), main as *const ()); + #[expect(clippy::eq_op)] + // Do not lint: casts are needed to not change type + let _issue14337 = main as *const () == main as *const (); + + // Do not peel the content of macros + let _ = std::ptr::eq(mac!(cast a), mac!(cast b)); //~^ ptr_eq // Do not peel the content of macros diff --git a/src/tools/clippy/tests/ui/ptr_eq.rs b/src/tools/clippy/tests/ui/ptr_eq.rs index f28707cc3e92..2b741d8df468 100644 --- a/src/tools/clippy/tests/ui/ptr_eq.rs +++ b/src/tools/clippy/tests/ui/ptr_eq.rs @@ -23,23 +23,25 @@ fn main() { //~^ ptr_eq let _ = a as *const _ == b as *const _; //~^ ptr_eq + + // Do not lint: the rhs conversion is needed let _ = a.as_ptr() == b as *const _; - //~^ ptr_eq + + // Do not lint: we have two raw pointers already let _ = a.as_ptr() == b.as_ptr(); - //~^ ptr_eq // Do not lint - let _ = mac!(a, b); let _ = another_mac!(a, b); let a = &mut [1, 2, 3]; let b = &mut [1, 2, 3]; + // Do not lint: the rhs conversion is needed let _ = a.as_mut_ptr() == b as *mut [i32] as *mut _; - //~^ ptr_eq + + // Do not lint: we have two raw pointers already let _ = a.as_mut_ptr() == b.as_mut_ptr(); - //~^ ptr_eq let _ = a == b; let _ = core::ptr::eq(a, b); @@ -51,8 +53,12 @@ fn main() { let _ = x as *const u32 != y as *mut u32 as *const u32; //~^ ptr_eq - #[allow(clippy::eq_op)] + #[expect(clippy::eq_op)] + // Do not lint: casts are needed to not change type let _issue14337 = main as *const () == main as *const (); + + // Do not peel the content of macros + let _ = mac!(cast a) as *const _ == mac!(cast b) as *const _; //~^ ptr_eq // Do not peel the content of macros diff --git a/src/tools/clippy/tests/ui/ptr_eq.stderr b/src/tools/clippy/tests/ui/ptr_eq.stderr index 906831b9e031..e7340624b595 100644 --- a/src/tools/clippy/tests/ui/ptr_eq.stderr +++ b/src/tools/clippy/tests/ui/ptr_eq.stderr @@ -14,52 +14,28 @@ LL | let _ = a as *const _ == b as *const _; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(a, b)` error: use `std::ptr::eq` when comparing raw pointers - --> tests/ui/ptr_eq.rs:26:13 - | -LL | let _ = a.as_ptr() == b as *const _; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(a.as_ptr(), b as *const _)` - -error: use `std::ptr::eq` when comparing raw pointers - --> tests/ui/ptr_eq.rs:28:13 - | -LL | let _ = a.as_ptr() == b.as_ptr(); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(a.as_ptr(), b.as_ptr())` - -error: use `std::ptr::eq` when comparing raw pointers - --> tests/ui/ptr_eq.rs:39:13 - | -LL | let _ = a.as_mut_ptr() == b as *mut [i32] as *mut _; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(a.as_mut_ptr(), b as *mut [i32] as *mut _)` - -error: use `std::ptr::eq` when comparing raw pointers - --> tests/ui/ptr_eq.rs:41:13 - | -LL | let _ = a.as_mut_ptr() == b.as_mut_ptr(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(a.as_mut_ptr(), b.as_mut_ptr())` - -error: use `std::ptr::eq` when comparing raw pointers - --> tests/ui/ptr_eq.rs:48:13 + --> tests/ui/ptr_eq.rs:50:13 | LL | let _ = x as *const u32 == y as *mut u32 as *const u32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(x, y)` error: use `std::ptr::eq` when comparing raw pointers - --> tests/ui/ptr_eq.rs:51:13 + --> tests/ui/ptr_eq.rs:53:13 | LL | let _ = x as *const u32 != y as *mut u32 as *const u32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `!std::ptr::eq(x, y)` error: use `std::ptr::eq` when comparing raw pointers - --> tests/ui/ptr_eq.rs:55:23 - | -LL | let _issue14337 = main as *const () == main as *const (); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(main as *const (), main as *const ())` - -error: use `std::ptr::eq` when comparing raw pointers - --> tests/ui/ptr_eq.rs:59:13 + --> tests/ui/ptr_eq.rs:61:13 | LL | let _ = mac!(cast a) as *const _ == mac!(cast b) as *const _; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(mac!(cast a), mac!(cast b))` -error: aborting due to 10 previous errors +error: use `std::ptr::eq` when comparing raw pointers + --> tests/ui/ptr_eq.rs:65:13 + | +LL | let _ = mac!(cast a) as *const _ == mac!(cast b) as *const _; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(mac!(cast a), mac!(cast b))` + +error: aborting due to 6 previous errors diff --git a/src/tools/clippy/tests/ui/ptr_eq_no_std.fixed b/src/tools/clippy/tests/ui/ptr_eq_no_std.fixed index d8ee4ea88f84..48cbad62e1a3 100644 --- a/src/tools/clippy/tests/ui/ptr_eq_no_std.fixed +++ b/src/tools/clippy/tests/ui/ptr_eq_no_std.fixed @@ -32,23 +32,25 @@ fn main() { //~^ ptr_eq let _ = core::ptr::eq(a, b); //~^ ptr_eq - let _ = core::ptr::eq(a.as_ptr(), b as *const _); - //~^ ptr_eq - let _ = core::ptr::eq(a.as_ptr(), b.as_ptr()); - //~^ ptr_eq + + // Do not lint: the rhs conversion is needed + let _ = a.as_ptr() == b as *const _; + + // Do not lint: we have two raw pointers already + let _ = a.as_ptr() == b.as_ptr(); // Do not lint - let _ = mac!(a, b); let _ = another_mac!(a, b); let a = &mut [1, 2, 3]; let b = &mut [1, 2, 3]; - let _ = core::ptr::eq(a.as_mut_ptr(), b as *mut [i32] as *mut _); - //~^ ptr_eq - let _ = core::ptr::eq(a.as_mut_ptr(), b.as_mut_ptr()); - //~^ ptr_eq + // Do not lint: the rhs conversion is needed + let _ = a.as_mut_ptr() == b as *mut [i32] as *mut _; + + // Do not lint: we have two raw pointers already + let _ = a.as_mut_ptr() == b.as_mut_ptr(); let _ = a == b; let _ = core::ptr::eq(a, b); diff --git a/src/tools/clippy/tests/ui/ptr_eq_no_std.rs b/src/tools/clippy/tests/ui/ptr_eq_no_std.rs index a236314c29b7..3827178640ee 100644 --- a/src/tools/clippy/tests/ui/ptr_eq_no_std.rs +++ b/src/tools/clippy/tests/ui/ptr_eq_no_std.rs @@ -32,23 +32,25 @@ fn main() { //~^ ptr_eq let _ = a as *const _ == b as *const _; //~^ ptr_eq + + // Do not lint: the rhs conversion is needed let _ = a.as_ptr() == b as *const _; - //~^ ptr_eq + + // Do not lint: we have two raw pointers already let _ = a.as_ptr() == b.as_ptr(); - //~^ ptr_eq // Do not lint - let _ = mac!(a, b); let _ = another_mac!(a, b); let a = &mut [1, 2, 3]; let b = &mut [1, 2, 3]; + // Do not lint: the rhs conversion is needed let _ = a.as_mut_ptr() == b as *mut [i32] as *mut _; - //~^ ptr_eq + + // Do not lint: we have two raw pointers already let _ = a.as_mut_ptr() == b.as_mut_ptr(); - //~^ ptr_eq let _ = a == b; let _ = core::ptr::eq(a, b); diff --git a/src/tools/clippy/tests/ui/ptr_eq_no_std.stderr b/src/tools/clippy/tests/ui/ptr_eq_no_std.stderr index 5b8135dc8e8b..8c7b1ff76661 100644 --- a/src/tools/clippy/tests/ui/ptr_eq_no_std.stderr +++ b/src/tools/clippy/tests/ui/ptr_eq_no_std.stderr @@ -13,29 +13,5 @@ error: use `core::ptr::eq` when comparing raw pointers LL | let _ = a as *const _ == b as *const _; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `core::ptr::eq(a, b)` -error: use `core::ptr::eq` when comparing raw pointers - --> tests/ui/ptr_eq_no_std.rs:35:13 - | -LL | let _ = a.as_ptr() == b as *const _; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `core::ptr::eq(a.as_ptr(), b as *const _)` - -error: use `core::ptr::eq` when comparing raw pointers - --> tests/ui/ptr_eq_no_std.rs:37:13 - | -LL | let _ = a.as_ptr() == b.as_ptr(); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `core::ptr::eq(a.as_ptr(), b.as_ptr())` - -error: use `core::ptr::eq` when comparing raw pointers - --> tests/ui/ptr_eq_no_std.rs:48:13 - | -LL | let _ = a.as_mut_ptr() == b as *mut [i32] as *mut _; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `core::ptr::eq(a.as_mut_ptr(), b as *mut [i32] as *mut _)` - -error: use `core::ptr::eq` when comparing raw pointers - --> tests/ui/ptr_eq_no_std.rs:50:13 - | -LL | let _ = a.as_mut_ptr() == b.as_mut_ptr(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `core::ptr::eq(a.as_mut_ptr(), b.as_mut_ptr())` - -error: aborting due to 6 previous errors +error: aborting due to 2 previous errors diff --git a/src/tools/clippy/tests/ui/question_mark.fixed b/src/tools/clippy/tests/ui/question_mark.fixed index 6bd071d07f52..507bc2b29d86 100644 --- a/src/tools/clippy/tests/ui/question_mark.fixed +++ b/src/tools/clippy/tests/ui/question_mark.fixed @@ -301,6 +301,11 @@ fn pattern() -> Result<(), PatternedError> { res } +fn expect_expr(a: Option) -> Option { + #[expect(clippy::needless_question_mark)] + Some(a?) +} + fn main() {} // `?` is not the same as `return None;` if inside of a try block diff --git a/src/tools/clippy/tests/ui/question_mark.rs b/src/tools/clippy/tests/ui/question_mark.rs index dd093c9bf480..64b51b849ede 100644 --- a/src/tools/clippy/tests/ui/question_mark.rs +++ b/src/tools/clippy/tests/ui/question_mark.rs @@ -371,6 +371,11 @@ fn pattern() -> Result<(), PatternedError> { res } +fn expect_expr(a: Option) -> Option { + #[expect(clippy::needless_question_mark)] + Some(a?) +} + fn main() {} // `?` is not the same as `return None;` if inside of a try block diff --git a/src/tools/clippy/tests/ui/question_mark.stderr b/src/tools/clippy/tests/ui/question_mark.stderr index 8fe04b895cea..d8ce4420aeeb 100644 --- a/src/tools/clippy/tests/ui/question_mark.stderr +++ b/src/tools/clippy/tests/ui/question_mark.stderr @@ -198,7 +198,7 @@ LL | | } | |_____^ help: replace it with: `func_returning_result()?;` error: this block may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:390:13 + --> tests/ui/question_mark.rs:395:13 | LL | / if a.is_none() { LL | | @@ -208,7 +208,7 @@ LL | | } | |_____________^ help: replace it with: `a?;` error: this `let...else` may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:451:5 + --> tests/ui/question_mark.rs:456:5 | LL | / let Some(v) = bar.foo.owned.clone() else { LL | | return None; @@ -216,7 +216,7 @@ LL | | }; | |______^ help: replace it with: `let v = bar.foo.owned.clone()?;` error: this `let...else` may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:466:5 + --> tests/ui/question_mark.rs:471:5 | LL | / let Some(ref x) = foo.opt_x else { LL | | return None; @@ -224,7 +224,7 @@ LL | | }; | |______^ help: replace it with: `let x = foo.opt_x.as_ref()?;` error: this `let...else` may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:476:5 + --> tests/ui/question_mark.rs:481:5 | LL | / let Some(ref mut x) = foo.opt_x else { LL | | return None; @@ -232,7 +232,7 @@ LL | | }; | |______^ help: replace it with: `let x = foo.opt_x.as_mut()?;` error: this `let...else` may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:487:5 + --> tests/ui/question_mark.rs:492:5 | LL | / let Some(ref x @ ref y) = foo.opt_x else { LL | | return None; @@ -240,7 +240,7 @@ LL | | }; | |______^ help: replace it with: `let x @ y = foo.opt_x.as_ref()?;` error: this `let...else` may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:491:5 + --> tests/ui/question_mark.rs:496:5 | LL | / let Some(ref x @ WrapperStructWithString(_)) = bar else { LL | | return None; @@ -248,7 +248,7 @@ LL | | }; | |______^ help: replace it with: `let x @ &WrapperStructWithString(_) = bar.as_ref()?;` error: this `let...else` may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:495:5 + --> tests/ui/question_mark.rs:500:5 | LL | / let Some(ref mut x @ WrapperStructWithString(_)) = bar else { LL | | return None; @@ -256,7 +256,7 @@ LL | | }; | |______^ help: replace it with: `let x @ &mut WrapperStructWithString(_) = bar.as_mut()?;` error: this block may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:517:5 + --> tests/ui/question_mark.rs:522:5 | LL | / if arg.is_none() { LL | | @@ -265,7 +265,7 @@ LL | | } | |_____^ help: replace it with: `arg?;` error: this `match` expression can be replaced with `?` - --> tests/ui/question_mark.rs:521:15 + --> tests/ui/question_mark.rs:526:15 | LL | let val = match arg { | _______________^ @@ -276,7 +276,7 @@ LL | | }; | |_____^ help: try instead: `arg?` error: this `let...else` may be rewritten with the `?` operator - --> tests/ui/question_mark.rs:531:5 + --> tests/ui/question_mark.rs:536:5 | LL | / let Some(a) = *a else { LL | | return None; diff --git a/src/tools/clippy/tests/ui/question_mark_used.stderr b/src/tools/clippy/tests/ui/question_mark_used.stderr index 53cb59c02166..82f0d3250407 100644 --- a/src/tools/clippy/tests/ui/question_mark_used.stderr +++ b/src/tools/clippy/tests/ui/question_mark_used.stderr @@ -1,4 +1,4 @@ -error: question mark operator was used +error: the `?` operator was used --> tests/ui/question_mark_used.rs:11:5 | LL | other_function()?; diff --git a/src/tools/clippy/tests/ui/return_and_then.stderr b/src/tools/clippy/tests/ui/return_and_then.stderr index cc611c3dba67..a7acbe7b3401 100644 --- a/src/tools/clippy/tests/ui/return_and_then.stderr +++ b/src/tools/clippy/tests/ui/return_and_then.stderr @@ -1,4 +1,4 @@ -error: use the question mark operator instead of an `and_then` call +error: use the `?` operator instead of an `and_then` call --> tests/ui/return_and_then.rs:5:9 | LL | / opt.and_then(|n| { @@ -20,7 +20,7 @@ LL + ret += n; LL + if n > 1 { Some(ret) } else { None } | -error: use the question mark operator instead of an `and_then` call +error: use the `?` operator instead of an `and_then` call --> tests/ui/return_and_then.rs:14:9 | LL | opt.and_then(|n| test_opt_block(Some(n))) @@ -32,7 +32,7 @@ LL ~ let n = opt?; LL + test_opt_block(Some(n)) | -error: use the question mark operator instead of an `and_then` call +error: use the `?` operator instead of an `and_then` call --> tests/ui/return_and_then.rs:19:9 | LL | gen_option(1).and_then(|n| test_opt_block(Some(n))) @@ -44,7 +44,7 @@ LL ~ let n = gen_option(1)?; LL + test_opt_block(Some(n)) | -error: use the question mark operator instead of an `and_then` call +error: use the `?` operator instead of an `and_then` call --> tests/ui/return_and_then.rs:24:9 | LL | opt.and_then(|n| if n > 1 { Ok(n + 1) } else { Err(n) }) @@ -56,7 +56,7 @@ LL ~ let n = opt?; LL + if n > 1 { Ok(n + 1) } else { Err(n) } | -error: use the question mark operator instead of an `and_then` call +error: use the `?` operator instead of an `and_then` call --> tests/ui/return_and_then.rs:29:9 | LL | opt.and_then(|n| test_res_block(Ok(n))) @@ -68,7 +68,7 @@ LL ~ let n = opt?; LL + test_res_block(Ok(n)) | -error: use the question mark operator instead of an `and_then` call +error: use the `?` operator instead of an `and_then` call --> tests/ui/return_and_then.rs:35:9 | LL | Some("").and_then(|x| if x.len() > 2 { Some(3) } else { None }) @@ -80,7 +80,7 @@ LL ~ let x = Some("")?; LL + if x.len() > 2 { Some(3) } else { None } | -error: use the question mark operator instead of an `and_then` call +error: use the `?` operator instead of an `and_then` call --> tests/ui/return_and_then.rs:41:9 | LL | / Some(match (vec![1, 2, 3], vec![1, 2, 4]) { diff --git a/src/tools/clippy/tests/ui/unnecessary_cast.fixed b/src/tools/clippy/tests/ui/unnecessary_cast.fixed index ba167e79a308..91ff4b9ee771 100644 --- a/src/tools/clippy/tests/ui/unnecessary_cast.fixed +++ b/src/tools/clippy/tests/ui/unnecessary_cast.fixed @@ -266,7 +266,21 @@ mod fixable { // Issue #11968: The suggestion for this lint removes the parentheses and leave the code as // `*x.pow(2)` which tries to dereference the return value rather than `x`. fn issue_11968(x: &usize) -> usize { - { *x }.pow(2) + (*x).pow(2) + //~^ unnecessary_cast + } + + #[allow(clippy::cast_lossless)] + fn issue_14640() { + let x = 5usize; + let vec: Vec = vec![1, 2, 3, 4, 5]; + assert_eq!(vec.len(), x); + //~^ unnecessary_cast + + let _ = (5i32 as i64).abs(); + //~^ unnecessary_cast + + let _ = 5i32 as i64; //~^ unnecessary_cast } } diff --git a/src/tools/clippy/tests/ui/unnecessary_cast.rs b/src/tools/clippy/tests/ui/unnecessary_cast.rs index 0f90a8b05965..5444a914db16 100644 --- a/src/tools/clippy/tests/ui/unnecessary_cast.rs +++ b/src/tools/clippy/tests/ui/unnecessary_cast.rs @@ -269,4 +269,18 @@ mod fixable { (*x as usize).pow(2) //~^ unnecessary_cast } + + #[allow(clippy::cast_lossless)] + fn issue_14640() { + let x = 5usize; + let vec: Vec = vec![1, 2, 3, 4, 5]; + assert_eq!(vec.len(), x as usize); + //~^ unnecessary_cast + + let _ = (5i32 as i64 as i64).abs(); + //~^ unnecessary_cast + + let _ = 5i32 as i64 as i64; + //~^ unnecessary_cast + } } diff --git a/src/tools/clippy/tests/ui/unnecessary_cast.stderr b/src/tools/clippy/tests/ui/unnecessary_cast.stderr index c83770c1a299..3e3c5eb81c10 100644 --- a/src/tools/clippy/tests/ui/unnecessary_cast.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_cast.stderr @@ -245,7 +245,25 @@ error: casting to the same type is unnecessary (`usize` -> `usize`) --> tests/ui/unnecessary_cast.rs:269:9 | LL | (*x as usize).pow(2) - | ^^^^^^^^^^^^^ help: try: `{ *x }` + | ^^^^^^^^^^^^^ help: try: `(*x)` -error: aborting due to 41 previous errors +error: casting to the same type is unnecessary (`usize` -> `usize`) + --> tests/ui/unnecessary_cast.rs:277:31 + | +LL | assert_eq!(vec.len(), x as usize); + | ^^^^^^^^^^ help: try: `x` + +error: casting to the same type is unnecessary (`i64` -> `i64`) + --> tests/ui/unnecessary_cast.rs:280:17 + | +LL | let _ = (5i32 as i64 as i64).abs(); + | ^^^^^^^^^^^^^^^^^^^^ help: try: `(5i32 as i64)` + +error: casting to the same type is unnecessary (`i64` -> `i64`) + --> tests/ui/unnecessary_cast.rs:283:17 + | +LL | let _ = 5i32 as i64 as i64; + | ^^^^^^^^^^^^^^^^^^ help: try: `5i32 as i64` + +error: aborting due to 44 previous errors diff --git a/src/tools/clippy/tests/ui/unused_unit.edition2021.fixed b/src/tools/clippy/tests/ui/unused_unit.edition2021.fixed new file mode 100644 index 000000000000..93dd58b8e9d7 --- /dev/null +++ b/src/tools/clippy/tests/ui/unused_unit.edition2021.fixed @@ -0,0 +1,146 @@ +//@revisions: edition2021 edition2024 +//@[edition2021] edition:2021 +//@[edition2024] edition:2024 + +// The output for humans should just highlight the whole span without showing +// the suggested replacement, but we also want to test that suggested +// replacement only removes one set of parentheses, rather than naïvely +// stripping away any starting or ending parenthesis characters—hence this +// test of the JSON error format. + +#![feature(custom_inner_attributes)] +#![feature(closure_lifetime_binder)] +#![rustfmt::skip] + +#![deny(clippy::unused_unit)] +#![allow(dead_code)] +#![allow(clippy::from_over_into)] + +struct Unitter; +impl Unitter { + #[allow(clippy::no_effect)] + pub fn get_unit(&self, f: F, _g: G) + //~^ unused_unit + //~| unused_unit + where G: Fn() { + //~^ unused_unit + let _y: &dyn Fn() = &f; + //~^ unused_unit + (); // this should not lint, as it's not in return type position + } +} + +impl Into<()> for Unitter { + #[rustfmt::skip] + fn into(self) { + //~^ unused_unit + + //~^ unused_unit + } +} + +trait Trait { + fn redundant(&self, _f: F, _g: G, _h: H) + //~^ unused_unit + where + G: FnMut(), + //~^ unused_unit + H: Fn(); + //~^ unused_unit +} + +impl Trait for Unitter { + fn redundant(&self, _f: F, _g: G, _h: H) + //~^ unused_unit + where + G: FnMut(), + //~^ unused_unit + H: Fn() {} + //~^ unused_unit +} + +fn return_unit() { } +//~^ unused_unit +//~| unused_unit + +#[allow(clippy::needless_return)] +#[allow(clippy::never_loop)] +#[allow(clippy::unit_cmp)] +fn main() { + let u = Unitter; + assert_eq!(u.get_unit(|| {}, return_unit), u.into()); + return_unit(); + loop { + break; + //~^ unused_unit + } + return; + //~^ unused_unit +} + +// https://github.com/rust-lang/rust-clippy/issues/4076 +fn foo() { + macro_rules! foo { + (recv($r:expr) -> $res:pat => $body:expr) => { + $body + } + } + + foo! { + recv(rx) -> _x => () + } +} + +#[rustfmt::skip] +fn test(){} +//~^ unused_unit + +#[rustfmt::skip] +fn test2(){} +//~^ unused_unit + +#[rustfmt::skip] +fn test3(){} +//~^ unused_unit + +fn macro_expr() { + macro_rules! e { + () => (()); + } + e!() +} + +mod issue9748 { + fn main() { + let _ = for<'a> |_: &'a u32| -> () {}; + } +} + +mod issue9949 { + fn main() { + #[doc = "documentation"] + () + } +} + +mod issue14577 { + trait Unit {} + impl Unit for () {} + + fn run(f: impl FnOnce() -> R) { + f(); + } + + #[allow(dependency_on_unit_never_type_fallback)] + fn bar() { + run(|| { todo!() }); + //~[edition2021]^ unused_unit + } + + struct UnitStruct; + impl UnitStruct { + fn apply Fn(&'c mut Self)>(&mut self, f: F) { + todo!() + } + } +} \ No newline at end of file diff --git a/src/tools/clippy/tests/ui/unused_unit.edition2021.stderr b/src/tools/clippy/tests/ui/unused_unit.edition2021.stderr new file mode 100644 index 000000000000..13cc20d4d7ad --- /dev/null +++ b/src/tools/clippy/tests/ui/unused_unit.edition2021.stderr @@ -0,0 +1,128 @@ +error: unneeded unit expression + --> tests/ui/unused_unit.rs:37:9 + | +LL | () + | ^^ help: remove the final `()` + | +note: the lint level is defined here + --> tests/ui/unused_unit.rs:15:9 + | +LL | #![deny(clippy::unused_unit)] + | ^^^^^^^^^^^^^^^^^^^ + +error: unneeded unit expression + --> tests/ui/unused_unit.rs:62:26 + | +LL | fn return_unit() -> () { () } + | ^^ help: remove the final `()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:22:28 + | +LL | pub fn get_unit (), G>(&self, f: F, _g: G) -> () + | ^^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:25:18 + | +LL | where G: Fn() -> () { + | ^^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:22:58 + | +LL | pub fn get_unit (), G>(&self, f: F, _g: G) -> () + | ^^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:27:26 + | +LL | let _y: &dyn Fn() -> () = &f; + | ^^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:35:18 + | +LL | fn into(self) -> () { + | ^^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:43:29 + | +LL | fn redundant (), G, H>(&self, _f: F, _g: G, _h: H) + | ^^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:46:19 + | +LL | G: FnMut() -> (), + | ^^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:48:16 + | +LL | H: Fn() -> (); + | ^^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:53:29 + | +LL | fn redundant (), G, H>(&self, _f: F, _g: G, _h: H) + | ^^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:56:19 + | +LL | G: FnMut() -> (), + | ^^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:58:16 + | +LL | H: Fn() -> () {} + | ^^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:62:17 + | +LL | fn return_unit() -> () { () } + | ^^^^^^ help: remove the `-> ()` + +error: unneeded `()` + --> tests/ui/unused_unit.rs:74:14 + | +LL | break(); + | ^^ help: remove the `()` + +error: unneeded `()` + --> tests/ui/unused_unit.rs:77:11 + | +LL | return(); + | ^^ help: remove the `()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:95:10 + | +LL | fn test()->(){} + | ^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:99:11 + | +LL | fn test2() ->(){} + | ^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:103:11 + | +LL | fn test3()-> (){} + | ^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:136:15 + | +LL | run(|| -> () { todo!() }); + | ^^^^^^ help: remove the `-> ()` + +error: aborting due to 20 previous errors + diff --git a/src/tools/clippy/tests/ui/unused_unit.edition2024.fixed b/src/tools/clippy/tests/ui/unused_unit.edition2024.fixed new file mode 100644 index 000000000000..987d901b97df --- /dev/null +++ b/src/tools/clippy/tests/ui/unused_unit.edition2024.fixed @@ -0,0 +1,146 @@ +//@revisions: edition2021 edition2024 +//@[edition2021] edition:2021 +//@[edition2024] edition:2024 + +// The output for humans should just highlight the whole span without showing +// the suggested replacement, but we also want to test that suggested +// replacement only removes one set of parentheses, rather than naïvely +// stripping away any starting or ending parenthesis characters—hence this +// test of the JSON error format. + +#![feature(custom_inner_attributes)] +#![feature(closure_lifetime_binder)] +#![rustfmt::skip] + +#![deny(clippy::unused_unit)] +#![allow(dead_code)] +#![allow(clippy::from_over_into)] + +struct Unitter; +impl Unitter { + #[allow(clippy::no_effect)] + pub fn get_unit(&self, f: F, _g: G) + //~^ unused_unit + //~| unused_unit + where G: Fn() { + //~^ unused_unit + let _y: &dyn Fn() = &f; + //~^ unused_unit + (); // this should not lint, as it's not in return type position + } +} + +impl Into<()> for Unitter { + #[rustfmt::skip] + fn into(self) { + //~^ unused_unit + + //~^ unused_unit + } +} + +trait Trait { + fn redundant(&self, _f: F, _g: G, _h: H) + //~^ unused_unit + where + G: FnMut(), + //~^ unused_unit + H: Fn(); + //~^ unused_unit +} + +impl Trait for Unitter { + fn redundant(&self, _f: F, _g: G, _h: H) + //~^ unused_unit + where + G: FnMut(), + //~^ unused_unit + H: Fn() {} + //~^ unused_unit +} + +fn return_unit() { } +//~^ unused_unit +//~| unused_unit + +#[allow(clippy::needless_return)] +#[allow(clippy::never_loop)] +#[allow(clippy::unit_cmp)] +fn main() { + let u = Unitter; + assert_eq!(u.get_unit(|| {}, return_unit), u.into()); + return_unit(); + loop { + break; + //~^ unused_unit + } + return; + //~^ unused_unit +} + +// https://github.com/rust-lang/rust-clippy/issues/4076 +fn foo() { + macro_rules! foo { + (recv($r:expr) -> $res:pat => $body:expr) => { + $body + } + } + + foo! { + recv(rx) -> _x => () + } +} + +#[rustfmt::skip] +fn test(){} +//~^ unused_unit + +#[rustfmt::skip] +fn test2(){} +//~^ unused_unit + +#[rustfmt::skip] +fn test3(){} +//~^ unused_unit + +fn macro_expr() { + macro_rules! e { + () => (()); + } + e!() +} + +mod issue9748 { + fn main() { + let _ = for<'a> |_: &'a u32| -> () {}; + } +} + +mod issue9949 { + fn main() { + #[doc = "documentation"] + () + } +} + +mod issue14577 { + trait Unit {} + impl Unit for () {} + + fn run(f: impl FnOnce() -> R) { + f(); + } + + #[allow(dependency_on_unit_never_type_fallback)] + fn bar() { + run(|| -> () { todo!() }); + //~[edition2021]^ unused_unit + } + + struct UnitStruct; + impl UnitStruct { + fn apply Fn(&'c mut Self)>(&mut self, f: F) { + todo!() + } + } +} \ No newline at end of file diff --git a/src/tools/clippy/tests/ui/unused_unit.edition2024.stderr b/src/tools/clippy/tests/ui/unused_unit.edition2024.stderr new file mode 100644 index 000000000000..a79e70e066bd --- /dev/null +++ b/src/tools/clippy/tests/ui/unused_unit.edition2024.stderr @@ -0,0 +1,122 @@ +error: unneeded unit expression + --> tests/ui/unused_unit.rs:37:9 + | +LL | () + | ^^ help: remove the final `()` + | +note: the lint level is defined here + --> tests/ui/unused_unit.rs:15:9 + | +LL | #![deny(clippy::unused_unit)] + | ^^^^^^^^^^^^^^^^^^^ + +error: unneeded unit expression + --> tests/ui/unused_unit.rs:62:26 + | +LL | fn return_unit() -> () { () } + | ^^ help: remove the final `()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:22:28 + | +LL | pub fn get_unit (), G>(&self, f: F, _g: G) -> () + | ^^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:25:18 + | +LL | where G: Fn() -> () { + | ^^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:22:58 + | +LL | pub fn get_unit (), G>(&self, f: F, _g: G) -> () + | ^^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:27:26 + | +LL | let _y: &dyn Fn() -> () = &f; + | ^^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:35:18 + | +LL | fn into(self) -> () { + | ^^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:43:29 + | +LL | fn redundant (), G, H>(&self, _f: F, _g: G, _h: H) + | ^^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:46:19 + | +LL | G: FnMut() -> (), + | ^^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:48:16 + | +LL | H: Fn() -> (); + | ^^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:53:29 + | +LL | fn redundant (), G, H>(&self, _f: F, _g: G, _h: H) + | ^^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:56:19 + | +LL | G: FnMut() -> (), + | ^^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:58:16 + | +LL | H: Fn() -> () {} + | ^^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:62:17 + | +LL | fn return_unit() -> () { () } + | ^^^^^^ help: remove the `-> ()` + +error: unneeded `()` + --> tests/ui/unused_unit.rs:74:14 + | +LL | break(); + | ^^ help: remove the `()` + +error: unneeded `()` + --> tests/ui/unused_unit.rs:77:11 + | +LL | return(); + | ^^ help: remove the `()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:95:10 + | +LL | fn test()->(){} + | ^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:99:11 + | +LL | fn test2() ->(){} + | ^^^^^ help: remove the `-> ()` + +error: unneeded unit return type + --> tests/ui/unused_unit.rs:103:11 + | +LL | fn test3()-> (){} + | ^^^^^ help: remove the `-> ()` + +error: aborting due to 19 previous errors + diff --git a/src/tools/clippy/tests/ui/unused_unit.fixed b/src/tools/clippy/tests/ui/unused_unit.fixed index e3c02681c9fd..6668bf90c092 100644 --- a/src/tools/clippy/tests/ui/unused_unit.fixed +++ b/src/tools/clippy/tests/ui/unused_unit.fixed @@ -120,3 +120,24 @@ mod issue9949 { () } } + +#[clippy::msrv = "1.85"] +mod issue14577 { + trait Unit {} + impl Unit for () {} + + fn run(f: impl FnOnce() -> R) { + f(); + } + + fn bar() { + run(|| -> () { todo!() }); + } + + struct UnitStruct; + impl UnitStruct { + fn apply Fn(&'c mut Self)>(&mut self, f: F) { + todo!() + } + } +} \ No newline at end of file diff --git a/src/tools/clippy/tests/ui/unused_unit.rs b/src/tools/clippy/tests/ui/unused_unit.rs index 4353026c594c..b7645f7b6a26 100644 --- a/src/tools/clippy/tests/ui/unused_unit.rs +++ b/src/tools/clippy/tests/ui/unused_unit.rs @@ -1,4 +1,6 @@ - +//@revisions: edition2021 edition2024 +//@[edition2021] edition:2021 +//@[edition2024] edition:2024 // The output for humans should just highlight the whole span without showing // the suggested replacement, but we also want to test that suggested @@ -120,3 +122,25 @@ mod issue9949 { () } } + +mod issue14577 { + trait Unit {} + impl Unit for () {} + + fn run(f: impl FnOnce() -> R) { + f(); + } + + #[allow(dependency_on_unit_never_type_fallback)] + fn bar() { + run(|| -> () { todo!() }); + //~[edition2021]^ unused_unit + } + + struct UnitStruct; + impl UnitStruct { + fn apply Fn(&'c mut Self)>(&mut self, f: F) { + todo!() + } + } +} \ No newline at end of file diff --git a/src/tools/clippy/tests/ui/unused_unit.stderr b/src/tools/clippy/tests/ui/unused_unit.stderr index 172fe0655028..366f2142095f 100644 --- a/src/tools/clippy/tests/ui/unused_unit.stderr +++ b/src/tools/clippy/tests/ui/unused_unit.stderr @@ -1,8 +1,8 @@ -error: unneeded unit return type - --> tests/ui/unused_unit.rs:20:58 +error: unneeded unit expression + --> tests/ui/unused_unit.rs:35:9 | -LL | pub fn get_unit (), G>(&self, f: F, _g: G) -> () - | ^^^^^^ help: remove the `-> ()` +LL | () + | ^^ help: remove the final `()` | note: the lint level is defined here --> tests/ui/unused_unit.rs:13:9 @@ -10,6 +10,12 @@ note: the lint level is defined here LL | #![deny(clippy::unused_unit)] | ^^^^^^^^^^^^^^^^^^^ +error: unneeded unit expression + --> tests/ui/unused_unit.rs:60:26 + | +LL | fn return_unit() -> () { () } + | ^^ help: remove the final `()` + error: unneeded unit return type --> tests/ui/unused_unit.rs:20:28 | @@ -22,6 +28,12 @@ error: unneeded unit return type LL | where G: Fn() -> () { | ^^^^^^ help: remove the `-> ()` +error: unneeded unit return type + --> tests/ui/unused_unit.rs:20:58 + | +LL | pub fn get_unit (), G>(&self, f: F, _g: G) -> () + | ^^^^^^ help: remove the `-> ()` + error: unneeded unit return type --> tests/ui/unused_unit.rs:25:26 | @@ -34,12 +46,6 @@ error: unneeded unit return type LL | fn into(self) -> () { | ^^^^^^ help: remove the `-> ()` -error: unneeded unit expression - --> tests/ui/unused_unit.rs:35:9 - | -LL | () - | ^^ help: remove the final `()` - error: unneeded unit return type --> tests/ui/unused_unit.rs:41:29 | @@ -82,12 +88,6 @@ error: unneeded unit return type LL | fn return_unit() -> () { () } | ^^^^^^ help: remove the `-> ()` -error: unneeded unit expression - --> tests/ui/unused_unit.rs:60:26 - | -LL | fn return_unit() -> () { () } - | ^^ help: remove the final `()` - error: unneeded `()` --> tests/ui/unused_unit.rs:72:14 | diff --git a/src/tools/clippy/tests/ui/wildcard_imports.fixed b/src/tools/clippy/tests/ui/wildcard_imports.fixed index a26b4a34190c..17510683f03e 100644 --- a/src/tools/clippy/tests/ui/wildcard_imports.fixed +++ b/src/tools/clippy/tests/ui/wildcard_imports.fixed @@ -16,7 +16,7 @@ use crate::fn_mod::foo; //~^ wildcard_imports use crate::mod_mod::inner_mod; //~^ wildcard_imports -use crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod}; +use crate::multi_fn_mod::{multi_foo, multi_bar, multi_inner_mod}; //~^ wildcard_imports #[macro_use] use crate::struct_mod::{A, inner_struct_mod}; @@ -26,7 +26,7 @@ use crate::struct_mod::{A, inner_struct_mod}; use wildcard_imports_helper::inner::inner_for_self_import; use wildcard_imports_helper::inner::inner_for_self_import::inner_extern_bar; //~^ wildcard_imports -use wildcard_imports_helper::{ExternA, extern_foo}; +use wildcard_imports_helper::{extern_foo, ExternA}; //~^ wildcard_imports use std::io::prelude::*; @@ -138,7 +138,7 @@ mod in_fn_test { fn test_extern() { use wildcard_imports_helper::inner::inner_for_self_import::{self, inner_extern_foo}; //~^ wildcard_imports - use wildcard_imports_helper::{ExternA, extern_foo}; + use wildcard_imports_helper::{extern_foo, ExternA}; //~^ wildcard_imports inner_for_self_import::inner_extern_foo(); @@ -160,7 +160,7 @@ mod in_fn_test { } fn test_extern_reexported() { - use wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}; + use wildcard_imports_helper::{extern_exported, ExternExportedStruct, ExternExportedEnum}; //~^ wildcard_imports extern_exported(); @@ -190,7 +190,7 @@ mod in_fn_test { } fn test_reexported() { - use crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}; + use crate::in_fn_test::{exported, ExportedStruct, ExportedEnum}; //~^ wildcard_imports exported(); diff --git a/src/tools/clippy/tests/ui/wildcard_imports.stderr b/src/tools/clippy/tests/ui/wildcard_imports.stderr index f774126102bc..26434656a509 100644 --- a/src/tools/clippy/tests/ui/wildcard_imports.stderr +++ b/src/tools/clippy/tests/ui/wildcard_imports.stderr @@ -17,7 +17,7 @@ error: usage of wildcard import --> tests/ui/wildcard_imports.rs:19:5 | LL | use crate::multi_fn_mod::*; - | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod}` + | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::multi_fn_mod::{multi_foo, multi_bar, multi_inner_mod}` error: usage of wildcard import --> tests/ui/wildcard_imports.rs:22:5 @@ -35,7 +35,7 @@ error: usage of wildcard import --> tests/ui/wildcard_imports.rs:29:5 | LL | use wildcard_imports_helper::*; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{extern_foo, ExternA}` error: usage of wildcard import --> tests/ui/wildcard_imports.rs:100:13 @@ -59,7 +59,7 @@ error: usage of wildcard import --> tests/ui/wildcard_imports.rs:141:13 | LL | use wildcard_imports_helper::*; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{extern_foo, ExternA}` error: usage of wildcard import --> tests/ui/wildcard_imports.rs:154:20 @@ -77,13 +77,13 @@ error: usage of wildcard import --> tests/ui/wildcard_imports.rs:163:13 | LL | use wildcard_imports_helper::*; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{extern_exported, ExternExportedStruct, ExternExportedEnum}` error: usage of wildcard import --> tests/ui/wildcard_imports.rs:193:9 | LL | use crate::in_fn_test::*; - | ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}` + | ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{exported, ExportedStruct, ExportedEnum}` error: usage of wildcard import --> tests/ui/wildcard_imports.rs:203:9 diff --git a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.fixed b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.fixed index a3d1aebba8af..f97b883ea231 100644 --- a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.fixed +++ b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.fixed @@ -14,7 +14,7 @@ use crate::fn_mod::foo; //~^ wildcard_imports use crate::mod_mod::inner_mod; //~^ wildcard_imports -use crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod}; +use crate::multi_fn_mod::{multi_foo, multi_bar, multi_inner_mod}; //~^ wildcard_imports use crate::struct_mod::{A, inner_struct_mod}; //~^ wildcard_imports @@ -23,7 +23,7 @@ use crate::struct_mod::{A, inner_struct_mod}; use wildcard_imports_helper::inner::inner_for_self_import::inner_extern_bar; //~^ wildcard_imports use wildcard_imports_helper::prelude::v1::*; -use wildcard_imports_helper::{ExternA, extern_foo}; +use wildcard_imports_helper::{extern_foo, ExternA}; //~^ wildcard_imports use std::io::prelude::*; @@ -132,7 +132,7 @@ mod in_fn_test { fn test_extern() { use wildcard_imports_helper::inner::inner_for_self_import::{self, inner_extern_foo}; //~^ wildcard_imports - use wildcard_imports_helper::{ExternA, extern_foo}; + use wildcard_imports_helper::{extern_foo, ExternA}; //~^ wildcard_imports inner_for_self_import::inner_extern_foo(); @@ -154,7 +154,7 @@ mod in_fn_test { } fn test_extern_reexported() { - use wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}; + use wildcard_imports_helper::{extern_exported, ExternExportedStruct, ExternExportedEnum}; //~^ wildcard_imports extern_exported(); @@ -184,7 +184,7 @@ mod in_fn_test { } fn test_reexported() { - use crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}; + use crate::in_fn_test::{exported, ExportedStruct, ExportedEnum}; //~^ wildcard_imports exported(); diff --git a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.stderr b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.stderr index a1b557f39f0d..873ce41b04f4 100644 --- a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.stderr +++ b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.stderr @@ -17,7 +17,7 @@ error: usage of wildcard import --> tests/ui/wildcard_imports_2021.rs:17:5 | LL | use crate::multi_fn_mod::*; - | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod}` + | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::multi_fn_mod::{multi_foo, multi_bar, multi_inner_mod}` error: usage of wildcard import --> tests/ui/wildcard_imports_2021.rs:19:5 @@ -35,7 +35,7 @@ error: usage of wildcard import --> tests/ui/wildcard_imports_2021.rs:26:5 | LL | use wildcard_imports_helper::*; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{extern_foo, ExternA}` error: usage of wildcard import --> tests/ui/wildcard_imports_2021.rs:95:13 @@ -59,7 +59,7 @@ error: usage of wildcard import --> tests/ui/wildcard_imports_2021.rs:135:13 | LL | use wildcard_imports_helper::*; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{extern_foo, ExternA}` error: usage of wildcard import --> tests/ui/wildcard_imports_2021.rs:148:20 @@ -77,13 +77,13 @@ error: usage of wildcard import --> tests/ui/wildcard_imports_2021.rs:157:13 | LL | use wildcard_imports_helper::*; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{extern_exported, ExternExportedStruct, ExternExportedEnum}` error: usage of wildcard import --> tests/ui/wildcard_imports_2021.rs:187:9 | LL | use crate::in_fn_test::*; - | ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}` + | ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{exported, ExportedStruct, ExportedEnum}` error: usage of wildcard import --> tests/ui/wildcard_imports_2021.rs:197:9 diff --git a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.fixed b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.fixed index a3d1aebba8af..f97b883ea231 100644 --- a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.fixed +++ b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.fixed @@ -14,7 +14,7 @@ use crate::fn_mod::foo; //~^ wildcard_imports use crate::mod_mod::inner_mod; //~^ wildcard_imports -use crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod}; +use crate::multi_fn_mod::{multi_foo, multi_bar, multi_inner_mod}; //~^ wildcard_imports use crate::struct_mod::{A, inner_struct_mod}; //~^ wildcard_imports @@ -23,7 +23,7 @@ use crate::struct_mod::{A, inner_struct_mod}; use wildcard_imports_helper::inner::inner_for_self_import::inner_extern_bar; //~^ wildcard_imports use wildcard_imports_helper::prelude::v1::*; -use wildcard_imports_helper::{ExternA, extern_foo}; +use wildcard_imports_helper::{extern_foo, ExternA}; //~^ wildcard_imports use std::io::prelude::*; @@ -132,7 +132,7 @@ mod in_fn_test { fn test_extern() { use wildcard_imports_helper::inner::inner_for_self_import::{self, inner_extern_foo}; //~^ wildcard_imports - use wildcard_imports_helper::{ExternA, extern_foo}; + use wildcard_imports_helper::{extern_foo, ExternA}; //~^ wildcard_imports inner_for_self_import::inner_extern_foo(); @@ -154,7 +154,7 @@ mod in_fn_test { } fn test_extern_reexported() { - use wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}; + use wildcard_imports_helper::{extern_exported, ExternExportedStruct, ExternExportedEnum}; //~^ wildcard_imports extern_exported(); @@ -184,7 +184,7 @@ mod in_fn_test { } fn test_reexported() { - use crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}; + use crate::in_fn_test::{exported, ExportedStruct, ExportedEnum}; //~^ wildcard_imports exported(); diff --git a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.stderr b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.stderr index a1b557f39f0d..873ce41b04f4 100644 --- a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.stderr +++ b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.stderr @@ -17,7 +17,7 @@ error: usage of wildcard import --> tests/ui/wildcard_imports_2021.rs:17:5 | LL | use crate::multi_fn_mod::*; - | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod}` + | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::multi_fn_mod::{multi_foo, multi_bar, multi_inner_mod}` error: usage of wildcard import --> tests/ui/wildcard_imports_2021.rs:19:5 @@ -35,7 +35,7 @@ error: usage of wildcard import --> tests/ui/wildcard_imports_2021.rs:26:5 | LL | use wildcard_imports_helper::*; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{extern_foo, ExternA}` error: usage of wildcard import --> tests/ui/wildcard_imports_2021.rs:95:13 @@ -59,7 +59,7 @@ error: usage of wildcard import --> tests/ui/wildcard_imports_2021.rs:135:13 | LL | use wildcard_imports_helper::*; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{extern_foo, ExternA}` error: usage of wildcard import --> tests/ui/wildcard_imports_2021.rs:148:20 @@ -77,13 +77,13 @@ error: usage of wildcard import --> tests/ui/wildcard_imports_2021.rs:157:13 | LL | use wildcard_imports_helper::*; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{extern_exported, ExternExportedStruct, ExternExportedEnum}` error: usage of wildcard import --> tests/ui/wildcard_imports_2021.rs:187:9 | LL | use crate::in_fn_test::*; - | ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}` + | ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{exported, ExportedStruct, ExportedEnum}` error: usage of wildcard import --> tests/ui/wildcard_imports_2021.rs:197:9 diff --git a/src/tools/clippy/tests/ui/zombie_processes.rs b/src/tools/clippy/tests/ui/zombie_processes.rs index 25bbc02ffb76..395f9dd2defb 100644 --- a/src/tools/clippy/tests/ui/zombie_processes.rs +++ b/src/tools/clippy/tests/ui/zombie_processes.rs @@ -176,3 +176,25 @@ fn return_wait() -> ExitStatus { let mut x = Command::new("").spawn().unwrap(); return x.wait().unwrap(); } + +mod issue14677 { + use std::io; + use std::process::Command; + + fn do_something Result<(), ()>>(f: F) { + todo!() + } + + fn foo() { + let mut child = Command::new("true").spawn().unwrap(); + let some_condition = true; + do_something(|| { + if some_condition { + return Err(()); + } + Ok(()) + }); + child.kill().unwrap(); + child.wait().unwrap(); + } +} diff --git a/src/tools/clippy/util/etc/pre-commit.sh b/src/tools/clippy/util/etc/pre-commit.sh index 5dd2ba3d5f53..528f8953b25d 100755 --- a/src/tools/clippy/util/etc/pre-commit.sh +++ b/src/tools/clippy/util/etc/pre-commit.sh @@ -6,7 +6,6 @@ set -e # Update lints cargo dev update_lints git add clippy_lints/src/lib.rs -git add clippy_lints/src/lib.*.rs # Formatting: # Git will not automatically add the formatted code to the staged changes once diff --git a/src/tools/compiletest/src/errors.rs b/src/tools/compiletest/src/errors.rs index a45f39b036cc..b5a2b7feac9d 100644 --- a/src/tools/compiletest/src/errors.rs +++ b/src/tools/compiletest/src/errors.rs @@ -15,6 +15,7 @@ pub enum ErrorKind { Note, Suggestion, Warning, + Raw, } impl ErrorKind { @@ -39,6 +40,7 @@ impl ErrorKind { "NOTE" | "note" | "MONO_ITEM" => ErrorKind::Note, "SUGGESTION" => ErrorKind::Suggestion, "WARN" | "WARNING" | "warn" | "warning" => ErrorKind::Warning, + "RAW" => ErrorKind::Raw, _ => panic!( "unexpected diagnostic kind `{s}`, expected \ `ERROR`, `WARN`, `NOTE`, `HELP` or `SUGGESTION`" @@ -55,6 +57,7 @@ impl fmt::Display for ErrorKind { ErrorKind::Note => write!(f, "NOTE"), ErrorKind::Suggestion => write!(f, "SUGGESTION"), ErrorKind::Warning => write!(f, "WARN"), + ErrorKind::Raw => write!(f, "RAW"), } } } diff --git a/src/tools/compiletest/src/json.rs b/src/tools/compiletest/src/json.rs index 960f5ba58882..6ed2b52c66d2 100644 --- a/src/tools/compiletest/src/json.rs +++ b/src/tools/compiletest/src/json.rs @@ -7,7 +7,6 @@ use regex::Regex; use serde::Deserialize; use crate::errors::{Error, ErrorKind}; -use crate::runtest::ProcRes; #[derive(Deserialize)] struct Diagnostic { @@ -140,28 +139,19 @@ pub fn extract_rendered(output: &str) -> String { .collect() } -pub fn parse_output(file_name: &str, output: &str, proc_res: &ProcRes) -> Vec { +pub fn parse_output(file_name: &str, output: &str) -> Vec { let mut errors = Vec::new(); for line in output.lines() { - // The compiler sometimes intermingles non-JSON stuff into the - // output. This hack just skips over such lines. Yuck. - if line.starts_with('{') { - match serde_json::from_str::(line) { - Ok(diagnostic) => push_actual_errors(&mut errors, &diagnostic, &[], file_name), - Err(error) => { - // Ignore the future compat report message - this is handled - // by `extract_rendered` - if serde_json::from_str::(line).is_err() { - proc_res.fatal( - Some(&format!( - "failed to decode compiler output as json: `{}`\nline: {}\noutput: {}", - error, line, output - )), - || (), - ); - } - } - } + // Compiler can emit non-json lines in non-`--error-format=json` modes, + // and in some situations even in json mode. + match serde_json::from_str::(line) { + Ok(diagnostic) => push_actual_errors(&mut errors, &diagnostic, &[], file_name), + Err(_) => errors.push(Error { + line_num: None, + kind: ErrorKind::Raw, + msg: line.to_string(), + require_annotation: false, + }), } } errors @@ -181,8 +171,6 @@ fn push_actual_errors( .filter(|(_, span)| Path::new(&span.file_name) == Path::new(&file_name)) .collect(); - let spans_in_this_file: Vec<_> = spans_info_in_this_file.iter().map(|(_, span)| span).collect(); - let primary_spans: Vec<_> = spans_info_in_this_file .iter() .filter(|(is_primary, _)| *is_primary) @@ -280,7 +268,9 @@ fn push_actual_errors( line_num: Some(span.line_start + index), kind: ErrorKind::Suggestion, msg: line.to_string(), - require_annotation: true, + // Empty suggestions (suggestions to remove something) are common + // and annotating them in source is not useful. + require_annotation: !line.is_empty(), }); } } @@ -294,13 +284,16 @@ fn push_actual_errors( } // Add notes for any labels that appear in the message. - for span in spans_in_this_file.iter().filter(|span| span.label.is_some()) { - errors.push(Error { - line_num: Some(span.line_start), - kind: ErrorKind::Note, - msg: span.label.clone().unwrap(), - require_annotation: true, - }); + for (_, span) in spans_info_in_this_file { + if let Some(label) = &span.label { + errors.push(Error { + line_num: Some(span.line_start), + kind: ErrorKind::Note, + msg: label.clone(), + // Empty labels (only underlining spans) are common and do not need annotations. + require_annotation: !label.is_empty(), + }); + } } // Flatten out the children. diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 97cb82c9e363..40c9f29375b2 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -23,7 +23,7 @@ use crate::common::{ output_base_dir, output_base_name, output_testname_unique, }; use crate::compute_diff::{DiffLine, make_diff, write_diff, write_filtered_diff}; -use crate::errors::{Error, ErrorKind}; +use crate::errors::{Error, ErrorKind, load_errors}; use crate::header::TestProps; use crate::read2::{Truncated, read2_abbreviated}; use crate::util::{Utf8PathBufExt, add_dylib_path, logv, static_regex}; @@ -577,23 +577,9 @@ impl<'test> TestCx<'test> { } } - fn check_all_error_patterns( - &self, - output_to_check: &str, - proc_res: &ProcRes, - pm: Option, - ) { - if self.props.error_patterns.is_empty() && self.props.regex_error_patterns.is_empty() { - if pm.is_some() { - // FIXME(#65865) - return; - } else { - self.fatal(&format!("no error pattern specified in {}", self.testpaths.file)); - } - } - + /// Check `error-pattern` and `regex-error-pattern` directives. + fn check_all_error_patterns(&self, output_to_check: &str, proc_res: &ProcRes) { let mut missing_patterns: Vec = Vec::new(); - self.check_error_patterns(output_to_check, &mut missing_patterns); self.check_regex_error_patterns(output_to_check, proc_res, &mut missing_patterns); @@ -670,7 +656,9 @@ impl<'test> TestCx<'test> { } } - fn check_expected_errors(&self, expected_errors: Vec, proc_res: &ProcRes) { + /// Check `//~ KIND message` annotations. + fn check_expected_errors(&self, proc_res: &ProcRes) { + let expected_errors = load_errors(&self.testpaths.file, self.revision); debug!( "check_expected_errors: expected_errors={:?} proc_res.status={:?}", expected_errors, proc_res.status @@ -711,11 +699,24 @@ impl<'test> TestCx<'test> { .collect(); // Parse the JSON output from the compiler and extract out the messages. - let actual_errors = json::parse_output(&diagnostic_file_name, &proc_res.stderr, proc_res); + let actual_errors = json::parse_output(&diagnostic_file_name, &self.get_output(proc_res)) + .into_iter() + .map(|e| Error { msg: self.normalize_output(&e.msg, &[]), ..e }); + let mut unexpected = Vec::new(); let mut found = vec![false; expected_errors.len()]; - for mut actual_error in actual_errors { - actual_error.msg = self.normalize_output(&actual_error.msg, &[]); + for actual_error in actual_errors { + for pattern in &self.props.error_patterns { + let pattern = pattern.trim(); + if actual_error.msg.contains(pattern) { + let q = if actual_error.line_num.is_none() { "?" } else { "" }; + self.fatal(&format!( + "error pattern '{pattern}' is found in structured \ + diagnostics, use `//~{q} {} {pattern}` instead", + actual_error.kind, + )); + } + } let opt_index = expected_errors.iter().enumerate().position(|(index, expected_error)| { diff --git a/src/tools/compiletest/src/runtest/incremental.rs b/src/tools/compiletest/src/runtest/incremental.rs index ea985866a052..90cff6bab4dc 100644 --- a/src/tools/compiletest/src/runtest/incremental.rs +++ b/src/tools/compiletest/src/runtest/incremental.rs @@ -100,16 +100,8 @@ impl TestCx<'_> { self.check_no_compiler_crash(&proc_res, self.props.should_ice); let output_to_check = self.get_output(&proc_res); - let expected_errors = errors::load_errors(&self.testpaths.file, self.revision); - if !expected_errors.is_empty() { - if !self.props.error_patterns.is_empty() || !self.props.regex_error_patterns.is_empty() - { - self.fatal("both error pattern and expected errors specified"); - } - self.check_expected_errors(expected_errors, &proc_res); - } else { - self.check_all_error_patterns(&output_to_check, &proc_res, pm); - } + self.check_expected_errors(&proc_res); + self.check_all_error_patterns(&output_to_check, &proc_res); if self.props.should_ice { match proc_res.status.code() { Some(101) => (), @@ -137,6 +129,6 @@ impl TestCx<'_> { let output_to_check = self.get_output(&proc_res); self.check_correct_failure_status(&proc_res); - self.check_all_error_patterns(&output_to_check, &proc_res, pm); + self.check_all_error_patterns(&output_to_check, &proc_res); } } diff --git a/src/tools/compiletest/src/runtest/ui.rs b/src/tools/compiletest/src/runtest/ui.rs index cf0ae14f81bf..cc50a918f757 100644 --- a/src/tools/compiletest/src/runtest/ui.rs +++ b/src/tools/compiletest/src/runtest/ui.rs @@ -9,7 +9,7 @@ use super::{ AllowUnused, Emit, FailMode, LinkToAux, PassMode, TargetLocation, TestCx, TestOutput, Truncated, UI_FIXED, WillExecute, }; -use crate::{errors, json}; +use crate::json; impl TestCx<'_> { pub(super) fn run_ui_test(&self) { @@ -127,9 +127,7 @@ impl TestCx<'_> { ); } - let expected_errors = errors::load_errors(&self.testpaths.file, self.revision); - - if let WillExecute::Yes = should_run { + let output_to_check = if let WillExecute::Yes = should_run { let proc_res = self.exec_compiled_test(); let run_output_errors = if self.props.check_run_results { self.load_compare_outputs(&proc_res, TestOutput::Run, explicit) @@ -150,44 +148,19 @@ impl TestCx<'_> { self.fatal_proc_rec("test run succeeded!", &proc_res); } - let output_to_check = self.get_output(&proc_res); - if !self.props.error_patterns.is_empty() || !self.props.regex_error_patterns.is_empty() - { - // "// error-pattern" comments - self.check_all_error_patterns(&output_to_check, &proc_res, pm); - } - self.check_forbid_output(&output_to_check, &proc_res) - } + self.get_output(&proc_res) + } else { + self.get_output(&proc_res) + }; debug!( - "run_ui_test: explicit={:?} config.compare_mode={:?} expected_errors={:?} \ + "run_ui_test: explicit={:?} config.compare_mode={:?} \ proc_res.status={:?} props.error_patterns={:?}", - explicit, - self.config.compare_mode, - expected_errors, - proc_res.status, - self.props.error_patterns + explicit, self.config.compare_mode, proc_res.status, self.props.error_patterns ); - if !explicit && self.config.compare_mode.is_none() { - // "//~ERROR comments" - self.check_expected_errors(expected_errors, &proc_res); - } else if explicit && !expected_errors.is_empty() { - let msg = format!( - "line {}: cannot combine `--error-format` with {} annotations; use `error-pattern` instead", - expected_errors[0].line_num_str(), - expected_errors[0].kind, - ); - self.fatal(&msg); - } - let output_to_check = self.get_output(&proc_res); - if should_run == WillExecute::No - && (!self.props.error_patterns.is_empty() - || !self.props.regex_error_patterns.is_empty()) - { - // "// error-pattern" comments - self.check_all_error_patterns(&output_to_check, &proc_res, pm); - } + self.check_expected_errors(&proc_res); + self.check_all_error_patterns(&output_to_check, &proc_res); self.check_forbid_output(&output_to_check, &proc_res); if self.props.run_rustfix && self.config.compare_mode.is_none() { diff --git a/src/tools/coverage-dump/Cargo.toml b/src/tools/coverage-dump/Cargo.toml index 7f14286b5d0c..6f92ac50d963 100644 --- a/src/tools/coverage-dump/Cargo.toml +++ b/src/tools/coverage-dump/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" [dependencies] anyhow = "1.0.71" +itertools = "0.12" leb128 = "0.2.5" md5 = { package = "md-5" , version = "0.10.5" } miniz_oxide = "0.7.1" diff --git a/src/tools/coverage-dump/src/covfun.rs b/src/tools/coverage-dump/src/covfun.rs index 82ebd33d0d1c..1cc9f4dc5d6a 100644 --- a/src/tools/coverage-dump/src/covfun.rs +++ b/src/tools/coverage-dump/src/covfun.rs @@ -1,23 +1,33 @@ use std::collections::HashMap; use std::fmt::{self, Debug, Write as _}; -use std::sync::OnceLock; +use std::sync::LazyLock; -use anyhow::{Context, anyhow}; +use anyhow::{Context, anyhow, bail, ensure}; +use itertools::Itertools; use regex::Regex; -use crate::parser::{Parser, unescape_llvm_string_contents}; +use crate::covmap::FilenameTables; +use crate::llvm_utils::unescape_llvm_string_contents; +use crate::parser::Parser; + +#[cfg(test)] +mod tests; pub(crate) fn dump_covfun_mappings( llvm_ir: &str, + filename_tables: &FilenameTables, function_names: &HashMap, ) -> anyhow::Result<()> { // Extract function coverage entries from the LLVM IR assembly, and associate // each entry with its (demangled) name. let mut covfun_entries = llvm_ir .lines() - .filter_map(covfun_line_data) - .map(|line_data| (function_names.get(&line_data.name_hash).map(String::as_str), line_data)) - .collect::>(); + .filter(|line| is_covfun_line(line)) + .map(parse_covfun_line) + .map_ok(|line_data| { + (function_names.get(&line_data.name_hash).map(String::as_str), line_data) + }) + .collect::, _>>()?; covfun_entries.sort_by(|a, b| { // Sort entries primarily by name, to help make the order consistent // across platforms and relatively insensitive to changes. @@ -41,8 +51,12 @@ pub(crate) fn dump_covfun_mappings( println!("Number of files: {num_files}"); for i in 0..num_files { - let global_file_id = parser.read_uleb128_u32()?; - println!("- file {i} => global file {global_file_id}"); + let global_file_id = parser.read_uleb128_usize()?; + let &CovfunLineData { filenames_hash, .. } = line_data; + let Some(filename) = filename_tables.lookup(filenames_hash, global_file_id) else { + bail!("couldn't resolve global file: {filenames_hash}, {global_file_id}"); + }; + println!("- file {i} => {filename}"); } let num_expressions = parser.read_uleb128_u32()?; @@ -107,36 +121,50 @@ pub(crate) fn dump_covfun_mappings( Ok(()) } +#[derive(Debug, PartialEq, Eq)] struct CovfunLineData { - name_hash: u64, is_used: bool, + name_hash: u64, + filenames_hash: u64, payload: Vec, } -/// Checks a line of LLVM IR assembly to see if it contains an `__llvm_covfun` -/// entry, and if so extracts relevant data in a `CovfunLineData`. -fn covfun_line_data(line: &str) -> Option { - let re = { - // We cheat a little bit and match variable names `@__covrec_[HASH]u` - // rather than the section name, because the section name is harder to - // extract and differs across Linux/Windows/macOS. We also extract the - // symbol name hash from the variable name rather than the data, since - // it's easier and both should match. - static RE: OnceLock = OnceLock::new(); - RE.get_or_init(|| { - Regex::new( - r#"^@__covrec_(?[0-9A-Z]+)(?u)? = .*\[[0-9]+ x i8\] c"(?[^"]*)".*$"#, - ) - .unwrap() - }) - }; +fn is_covfun_line(line: &str) -> bool { + line.starts_with("@__covrec_") +} - let captures = re.captures(line)?; - let name_hash = u64::from_str_radix(&captures["name_hash"], 16).unwrap(); +/// Given a line of LLVM IR assembly that should contain an `__llvm_covfun` +/// entry, parses it to extract relevant data in a `CovfunLineData`. +fn parse_covfun_line(line: &str) -> anyhow::Result { + ensure!(is_covfun_line(line)); + + // We cheat a little bit and match variable names `@__covrec_[HASH]u` + // rather than the section name, because the section name is harder to + // extract and differs across Linux/Windows/macOS. + const RE_STRING: &str = r#"(?x)^ + @__covrec_[0-9A-Z]+(?u)? + \ = \ # (trailing space) + .* + <\{ + \ i64 \ (? -? [0-9]+), + \ i32 \ -? [0-9]+, # (length of payload; currently unused) + \ i64 \ -? [0-9]+, # (source hash; currently unused) + \ i64 \ (? -? [0-9]+), + \ \[ [0-9]+ \ x \ i8 \] \ c"(?[^"]*)" + \ # (trailing space) + }> + .*$ + "#; + static RE: LazyLock = LazyLock::new(|| Regex::new(RE_STRING).unwrap()); + + let captures = + RE.captures(line).with_context(|| format!("couldn't parse covfun line: {line:?}"))?; let is_used = captures.name("is_used").is_some(); + let name_hash = i64::from_str_radix(&captures["name_hash"], 10).unwrap() as u64; + let filenames_hash = i64::from_str_radix(&captures["filenames_hash"], 10).unwrap() as u64; let payload = unescape_llvm_string_contents(&captures["payload"]); - Some(CovfunLineData { name_hash, is_used, payload }) + Ok(CovfunLineData { is_used, name_hash, filenames_hash, payload }) } // Extra parser methods only needed when parsing `covfun` payloads. diff --git a/src/tools/coverage-dump/src/covfun/tests.rs b/src/tools/coverage-dump/src/covfun/tests.rs new file mode 100644 index 000000000000..1ce833784bd4 --- /dev/null +++ b/src/tools/coverage-dump/src/covfun/tests.rs @@ -0,0 +1,53 @@ +use super::{CovfunLineData, parse_covfun_line}; + +/// Integers in LLVM IR are not inherently signed/unsigned, and the text format tends +/// to emit them in signed form, so this helper function converts `i64` to `u64`. +fn as_u64(x: i64) -> u64 { + x as u64 +} + +#[test] +fn parse_covfun_line_data() { + struct Case { + line: &'static str, + expected: CovfunLineData, + } + let cases = &[ + // Copied from `trivial.ll`: + Case { + line: r#"@__covrec_49A9BAAE5F896E81u = linkonce_odr hidden constant <{ i64, i32, i64, i64, [9 x i8] }> <{ i64 5307978893922758273, i32 9, i64 445092354169400020, i64 6343436898695299756, [9 x i8] c"\01\01\00\01\01\03\01\00\0D" }>, section "__LLVM_COV,__llvm_covfun", align 8"#, + expected: CovfunLineData { + is_used: true, + name_hash: as_u64(5307978893922758273), + filenames_hash: as_u64(6343436898695299756), + payload: b"\x01\x01\x00\x01\x01\x03\x01\x00\x0D".to_vec(), + }, + }, + // Copied from `on-off-sandwich.ll`: + Case { + line: r#"@__covrec_D0CE53C5E64F319Au = linkonce_odr hidden constant <{ i64, i32, i64, i64, [14 x i8] }> <{ i64 -3400688559180533350, i32 14, i64 7307957714577672185, i64 892196767019953100, [14 x i8] c"\01\01\00\02\01\10\05\02\10\01\07\05\00\06" }>, section "__LLVM_COV,__llvm_covfun", align 8"#, + expected: CovfunLineData { + is_used: true, + name_hash: as_u64(-3400688559180533350), + filenames_hash: as_u64(892196767019953100), + payload: b"\x01\x01\x00\x02\x01\x10\x05\x02\x10\x01\x07\x05\x00\x06".to_vec(), + }, + }, + // Copied from `no-core.ll`: + Case { + line: r#"@__covrec_F8016FC82D46106u = linkonce_odr hidden constant <{ i64, i32, i64, i64, [9 x i8] }> <{ i64 1116917981370409222, i32 9, i64 -8857254680411629915, i64 -3625186110715410276, [9 x i8] c"\01\01\00\01\01\0C\01\00\0D" }>, section "__LLVM_COV,__llvm_covfun", align 8"#, + expected: CovfunLineData { + is_used: true, + name_hash: as_u64(1116917981370409222), + filenames_hash: as_u64(-3625186110715410276), + payload: b"\x01\x01\x00\x01\x01\x0C\x01\x00\x0D".to_vec(), + }, + }, + ]; + + for &Case { line, ref expected } in cases { + println!("- {line}"); + let line_data = parse_covfun_line(line).map_err(|e| e.to_string()); + assert_eq!(line_data.as_ref(), Ok(expected)); + } +} diff --git a/src/tools/coverage-dump/src/covmap.rs b/src/tools/coverage-dump/src/covmap.rs new file mode 100644 index 000000000000..2246ca2d5757 --- /dev/null +++ b/src/tools/coverage-dump/src/covmap.rs @@ -0,0 +1,75 @@ +use std::collections::HashMap; +use std::sync::LazyLock; + +use anyhow::{Context, ensure}; +use regex::Regex; + +use crate::llvm_utils::{truncated_md5, unescape_llvm_string_contents}; +use crate::parser::Parser; + +#[derive(Debug, Default)] +pub(crate) struct FilenameTables { + map: HashMap>, +} + +impl FilenameTables { + pub(crate) fn lookup(&self, filenames_hash: u64, global_file_id: usize) -> Option<&str> { + let table = self.map.get(&filenames_hash)?; + let filename = table.get(global_file_id)?; + Some(filename) + } +} + +struct CovmapLineData { + payload: Vec, +} + +pub(crate) fn make_filename_tables(llvm_ir: &str) -> anyhow::Result { + let mut map = HashMap::default(); + + for line in llvm_ir.lines().filter(|line| is_covmap_line(line)) { + let CovmapLineData { payload } = parse_covmap_line(line)?; + + let mut parser = Parser::new(&payload); + let n_filenames = parser.read_uleb128_usize()?; + let uncompressed_bytes = parser.read_chunk_to_uncompressed_bytes()?; + parser.ensure_empty()?; + + let mut filenames_table = vec![]; + + let mut parser = Parser::new(&uncompressed_bytes); + for _ in 0..n_filenames { + let len = parser.read_uleb128_usize()?; + let bytes = parser.read_n_bytes(len)?; + let filename = str::from_utf8(bytes)?; + filenames_table.push(filename.to_owned()); + } + + let filenames_hash = truncated_md5(&payload); + map.insert(filenames_hash, filenames_table); + } + + Ok(FilenameTables { map }) +} + +fn is_covmap_line(line: &str) -> bool { + line.starts_with("@__llvm_coverage_mapping ") +} + +fn parse_covmap_line(line: &str) -> anyhow::Result { + ensure!(is_covmap_line(line)); + + const RE_STRING: &str = r#"(?x)^ + @__llvm_coverage_mapping \ = + .* + \[ [0-9]+ \ x \ i8 \] \ c"(?[^"]*)" + .*$ + "#; + static RE: LazyLock = LazyLock::new(|| Regex::new(RE_STRING).unwrap()); + + let captures = + RE.captures(line).with_context(|| format!("couldn't parse covmap line: {line:?}"))?; + let payload = unescape_llvm_string_contents(&captures["payload"]); + + Ok(CovmapLineData { payload }) +} diff --git a/src/tools/coverage-dump/src/llvm_utils.rs b/src/tools/coverage-dump/src/llvm_utils.rs new file mode 100644 index 000000000000..92322b256a82 --- /dev/null +++ b/src/tools/coverage-dump/src/llvm_utils.rs @@ -0,0 +1,85 @@ +use std::borrow::Cow; +use std::sync::OnceLock; + +use anyhow::{anyhow, ensure}; +use regex::bytes; + +use crate::parser::Parser; + +#[cfg(test)] +mod tests; + +/// Given the raw contents of a string literal in LLVM IR assembly, decodes any +/// backslash escapes and returns a vector containing the resulting byte string. +pub(crate) fn unescape_llvm_string_contents(contents: &str) -> Vec { + let escape_re = { + static RE: OnceLock = OnceLock::new(); + // LLVM IR supports two string escapes: `\\` and `\xx`. + RE.get_or_init(|| bytes::Regex::new(r"\\\\|\\([0-9A-Za-z]{2})").unwrap()) + }; + + fn u8_from_hex_digits(digits: &[u8]) -> u8 { + // We know that the input contains exactly 2 hex digits, so these calls + // should never fail. + assert_eq!(digits.len(), 2); + let digits = std::str::from_utf8(digits).unwrap(); + u8::from_str_radix(digits, 16).unwrap() + } + + escape_re + .replace_all(contents.as_bytes(), |captures: &bytes::Captures<'_>| { + let byte = match captures.get(1) { + None => b'\\', + Some(hex_digits) => u8_from_hex_digits(hex_digits.as_bytes()), + }; + [byte] + }) + .into_owned() +} + +/// LLVM's profiler/coverage metadata often uses an MD5 hash truncated to +/// 64 bits as a way to associate data stored in different tables/sections. +pub(crate) fn truncated_md5(bytes: &[u8]) -> u64 { + use md5::{Digest, Md5}; + let mut hasher = Md5::new(); + hasher.update(bytes); + let hash: [u8; 8] = hasher.finalize().as_slice()[..8].try_into().unwrap(); + // The truncated hash is explicitly little-endian, regardless of host + // or target platform. (See `MD5Result::low` in LLVM's `MD5.h`.) + u64::from_le_bytes(hash) +} + +impl<'a> Parser<'a> { + /// Reads a sequence of: + /// - Length of uncompressed data in bytes, as ULEB128 + /// - Length of compressed data in bytes (or 0), as ULEB128 + /// - The indicated number of compressed or uncompressed bytes + /// + /// If the number of compressed bytes is 0, the subsequent bytes are + /// uncompressed. Otherwise, the subsequent bytes are compressed, and will + /// be decompressed. + /// + /// Returns the uncompressed bytes that were read directly or decompressed. + pub(crate) fn read_chunk_to_uncompressed_bytes(&mut self) -> anyhow::Result> { + let uncompressed_len = self.read_uleb128_usize()?; + let compressed_len = self.read_uleb128_usize()?; + + if compressed_len == 0 { + // The bytes are uncompressed, so read them directly. + let uncompressed_bytes = self.read_n_bytes(uncompressed_len)?; + Ok(Cow::Borrowed(uncompressed_bytes)) + } else { + // The bytes are compressed, so read and decompress them. + let compressed_bytes = self.read_n_bytes(compressed_len)?; + + let uncompressed_bytes = miniz_oxide::inflate::decompress_to_vec_zlib_with_limit( + compressed_bytes, + uncompressed_len, + ) + .map_err(|e| anyhow!("{e:?}"))?; + ensure!(uncompressed_bytes.len() == uncompressed_len); + + Ok(Cow::Owned(uncompressed_bytes)) + } + } +} diff --git a/src/tools/coverage-dump/src/parser/tests.rs b/src/tools/coverage-dump/src/llvm_utils/tests.rs similarity index 80% rename from src/tools/coverage-dump/src/parser/tests.rs rename to src/tools/coverage-dump/src/llvm_utils/tests.rs index a673606b9c4c..506b0a6200bb 100644 --- a/src/tools/coverage-dump/src/parser/tests.rs +++ b/src/tools/coverage-dump/src/llvm_utils/tests.rs @@ -1,9 +1,5 @@ use super::unescape_llvm_string_contents; -// WARNING: These tests don't necessarily run in CI, and were mainly used to -// help track down problems when originally developing this tool. -// (The tool is still tested indirectly by snapshot tests that rely on it.) - // Tests for `unescape_llvm_string_contents`: #[test] diff --git a/src/tools/coverage-dump/src/main.rs b/src/tools/coverage-dump/src/main.rs index b21e3e292f2b..2c76d2f24602 100644 --- a/src/tools/coverage-dump/src/main.rs +++ b/src/tools/coverage-dump/src/main.rs @@ -1,4 +1,6 @@ mod covfun; +mod covmap; +mod llvm_utils; mod parser; mod prf_names; @@ -17,8 +19,9 @@ fn main() -> anyhow::Result<()> { let llvm_ir_path = args.get(1).context("LLVM IR file not specified")?; let llvm_ir = std::fs::read_to_string(llvm_ir_path).context("couldn't read LLVM IR file")?; + let filename_tables = covmap::make_filename_tables(&llvm_ir)?; let function_names = crate::prf_names::make_function_names_table(&llvm_ir)?; - crate::covfun::dump_covfun_mappings(&llvm_ir, &function_names)?; + crate::covfun::dump_covfun_mappings(&llvm_ir, &filename_tables, &function_names)?; Ok(()) } diff --git a/src/tools/coverage-dump/src/parser.rs b/src/tools/coverage-dump/src/parser.rs index 0bd4abdae3ef..f26a57b43b33 100644 --- a/src/tools/coverage-dump/src/parser.rs +++ b/src/tools/coverage-dump/src/parser.rs @@ -1,38 +1,4 @@ -#[cfg(test)] -mod tests; - -use std::sync::OnceLock; - use anyhow::ensure; -use regex::bytes; - -/// Given the raw contents of a string literal in LLVM IR assembly, decodes any -/// backslash escapes and returns a vector containing the resulting byte string. -pub(crate) fn unescape_llvm_string_contents(contents: &str) -> Vec { - let escape_re = { - static RE: OnceLock = OnceLock::new(); - // LLVM IR supports two string escapes: `\\` and `\xx`. - RE.get_or_init(|| bytes::Regex::new(r"\\\\|\\([0-9A-Za-z]{2})").unwrap()) - }; - - fn u8_from_hex_digits(digits: &[u8]) -> u8 { - // We know that the input contains exactly 2 hex digits, so these calls - // should never fail. - assert_eq!(digits.len(), 2); - let digits = std::str::from_utf8(digits).unwrap(); - u8::from_str_radix(digits, 16).unwrap() - } - - escape_re - .replace_all(contents.as_bytes(), |captures: &bytes::Captures<'_>| { - let byte = match captures.get(1) { - None => b'\\', - Some(hex_digits) => u8_from_hex_digits(hex_digits.as_bytes()), - }; - [byte] - }) - .into_owned() -} pub(crate) struct Parser<'a> { rest: &'a [u8], diff --git a/src/tools/coverage-dump/src/prf_names.rs b/src/tools/coverage-dump/src/prf_names.rs index 96d097c79a31..f9ab35deba50 100644 --- a/src/tools/coverage-dump/src/prf_names.rs +++ b/src/tools/coverage-dump/src/prf_names.rs @@ -1,10 +1,10 @@ use std::collections::HashMap; use std::sync::OnceLock; -use anyhow::{anyhow, ensure}; use regex::Regex; -use crate::parser::{Parser, unescape_llvm_string_contents}; +use crate::llvm_utils::{truncated_md5, unescape_llvm_string_contents}; +use crate::parser::Parser; /// Scans through the contents of an LLVM IR assembly file to find `__llvm_prf_names` /// entries, decodes them, and creates a table that maps name hash values to @@ -25,18 +25,6 @@ pub(crate) fn make_function_names_table(llvm_ir: &str) -> anyhow::Result u64 { - use md5::{Digest, Md5}; - let mut hasher = Md5::new(); - hasher.update(bytes); - let hash: [u8; 8] = hasher.finalize().as_slice()[..8].try_into().unwrap(); - // The truncated hash is explicitly little-endian, regardless of host - // or target platform. (See `MD5Result::low` in LLVM's `MD5.h`.) - u64::from_le_bytes(hash) - } - fn demangle_if_able(symbol_name_bytes: &[u8]) -> anyhow::Result { // In practice, raw symbol names should always be ASCII. let symbol_name_str = std::str::from_utf8(symbol_name_bytes)?; @@ -54,26 +42,8 @@ pub(crate) fn make_function_names_table(llvm_ir: &str) -> anyhow::Result anyhow::Result LintExtractor<'a> { if matches!( lint.name.as_str(), "unused_features" // broken lint + | "soft_unstable" // cannot have a stable example ) { return Ok(()); } diff --git a/src/tools/miri/.gitignore b/src/tools/miri/.gitignore index 03c5591b7875..ed2d0ba7ba07 100644 --- a/src/tools/miri/.gitignore +++ b/src/tools/miri/.gitignore @@ -9,6 +9,9 @@ tex/*/out *.mm_profdata perf.data perf.data.old -flamegraph.svg +flamegraph*.svg +rustc-ice*.txt tests/native-lib/libtestlib.so .auto-* + +/genmc/ diff --git a/src/tools/miri/CONTRIBUTING.md b/src/tools/miri/CONTRIBUTING.md index 0d77ca06e1b4..739f0702252a 100644 --- a/src/tools/miri/CONTRIBUTING.md +++ b/src/tools/miri/CONTRIBUTING.md @@ -19,12 +19,10 @@ When you get a review, please take care of the requested changes in new commits. existing commits. Generally avoid force-pushing. The only time you should force push is when there is a conflict with the master branch (in that case you should rebase across master, not merge), and all the way at the end of the review process when the reviewer tells you that the PR is done and you -should squash the commits. For the latter case, use `git rebase --keep-base ...` to squash without -changing the base commit your PR branches off of. Use your own judgment and the reviewer's guidance -to decide whether the PR should be squashed into a single commit or multiple logically separate -commits. (All this is to work around the fact that Github is quite bad at dealing with force pushes -and does not support `git range-diff`. Maybe one day Github will be good at git and then life can -become easier.) +should squash the commits. If you are unsure how to use `git rebase` to squash commits, use `./miri +squash` which automates the process but leaves little room for customization. (All this is to work +around the fact that Github is quite bad at dealing with force pushes and does not support `git +range-diff`. Maybe one day Github will be good at git and then life can become easier.) Most PRs bounce back and forth between the reviewer and the author several times, so it is good to keep track of who is expected to take the next step. We are using the `S-waiting-for-review` and diff --git a/src/tools/miri/Cargo.toml b/src/tools/miri/Cargo.toml index bb24e700e738..7b7be97aa518 100644 --- a/src/tools/miri/Cargo.toml +++ b/src/tools/miri/Cargo.toml @@ -65,6 +65,7 @@ harness = false [features] default = ["stack-cache"] +genmc = [] stack-cache = [] stack-cache-consistency-check = ["stack-cache"] diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md index 95e1770aa7ba..a78cc9d93198 100644 --- a/src/tools/miri/README.md +++ b/src/tools/miri/README.md @@ -277,22 +277,15 @@ Try running `cargo miri clean`. Miri adds its own set of `-Z` flags, which are usually set via the `MIRIFLAGS` environment variable. We first document the most relevant and most commonly used flags: -* `-Zmiri-address-reuse-rate=` changes the probability that a freed *non-stack* allocation - will be added to the pool for address reuse, and the probability that a new *non-stack* allocation - will be taken from the pool. Stack allocations never get added to or taken from the pool. The - default is `0.5`. -* `-Zmiri-address-reuse-cross-thread-rate=` changes the probability that an allocation which - attempts to reuse a previously freed block of memory will also consider blocks freed by *other - threads*. The default is `0.1`, which means by default, in 90% of the cases where an address reuse - attempt is made, only addresses from the same thread will be considered. Reusing an address from - another thread induces synchronization between those threads, which can mask data races and weak - memory bugs. -* `-Zmiri-compare-exchange-weak-failure-rate=` changes the failure rate of - `compare_exchange_weak` operations. The default is `0.8` (so 4 out of 5 weak ops will fail). - You can change it to any value between `0.0` and `1.0`, where `1.0` means it - will always fail and `0.0` means it will never fail. Note that setting it to - `1.0` will likely cause hangs, since it means programs using - `compare_exchange_weak` cannot make progress. +* `-Zmiri-deterministic-concurrency` makes Miri's concurrency-related behavior fully deterministic. + Strictly speaking, Miri is always fully deterministic when isolation is enabled (the default + mode), but this determinism is achieved by using an RNG with a fixed seed. Seemingly harmless + changes to the program, or just running it for a different target architecture, can thus lead to + completely different program behavior down the line. This flag disables the use of an RNG for + concurrency-related decisions. Therefore, Miri cannot find bugs that only occur under some + specific circumstances, but Miri's behavior will also be more stable across versions and targets. + This is equivalent to `-Zmiri-fixed-schedule -Zmiri-compare-exchange-weak-failure-rate=0.0 + -Zmiri-address-reuse-cross-thread-rate=0.0 -Zmiri-disable-weak-memory-emulation`. * `-Zmiri-disable-isolation` disables host isolation. As a consequence, the program has access to host resources such as environment variables, file systems, and randomness. @@ -334,9 +327,6 @@ environment variable. We first document the most relevant and most commonly used This will necessarily miss some bugs as those operations are not efficiently and accurately implementable in a sanitizer, but it will only miss bugs that concern memory/pointers which is subject to these operations. -* `-Zmiri-preemption-rate` configures the probability that at the end of a basic block, the active - thread will be preempted. The default is `0.01` (i.e., 1%). Setting this to `0` disables - preemption. * `-Zmiri-report-progress` makes Miri print the current stacktrace every now and then, so you can tell what it is doing when a program just keeps running. You can customize how frequently the report is printed via `-Zmiri-report-progress=`, which prints the report every N basic @@ -365,6 +355,22 @@ The remaining flags are for advanced use only, and more likely to change or be r Some of these are **unsound**, which means they can lead to Miri failing to detect cases of undefined behavior in a program. +* `-Zmiri-address-reuse-rate=` changes the probability that a freed *non-stack* allocation + will be added to the pool for address reuse, and the probability that a new *non-stack* allocation + will be taken from the pool. Stack allocations never get added to or taken from the pool. The + default is `0.5`. +* `-Zmiri-address-reuse-cross-thread-rate=` changes the probability that an allocation which + attempts to reuse a previously freed block of memory will also consider blocks freed by *other + threads*. The default is `0.1`, which means by default, in 90% of the cases where an address reuse + attempt is made, only addresses from the same thread will be considered. Reusing an address from + another thread induces synchronization between those threads, which can mask data races and weak + memory bugs. +* `-Zmiri-compare-exchange-weak-failure-rate=` changes the failure rate of + `compare_exchange_weak` operations. The default is `0.8` (so 4 out of 5 weak ops will fail). + You can change it to any value between `0.0` and `1.0`, where `1.0` means it + will always fail and `0.0` means it will never fail. Note that setting it to + `1.0` will likely cause hangs, since it means programs using + `compare_exchange_weak` cannot make progress. * `-Zmiri-disable-alignment-check` disables checking pointer alignment, so you can focus on other failures, but it means Miri can miss bugs in your program. Using this flag is **unsound**. @@ -383,6 +389,10 @@ to Miri failing to detect cases of undefined behavior in a program. this flag is **unsound**. * `-Zmiri-disable-weak-memory-emulation` disables the emulation of some C++11 weak memory effects. +* `-Zmiri-fixed-schedule` disables preemption (like `-Zmiri-preemption-rate=0.0`) and furthermore + disables the randomization of the next thread to be picked, instead fixing a round-robin schedule. + Note however that other aspects of Miri's concurrency behavior are still randomize; use + `-Zmiri-deterministic-concurrency` to disable them all. * `-Zmiri-native-lib=` is an experimental flag for providing support for calling native functions from inside the interpreter via FFI. The flag is supported only on Unix systems. Functions not provided by that file are still executed via the usual Miri shims. @@ -412,6 +422,10 @@ to Miri failing to detect cases of undefined behavior in a program. without an explicit value), `none` means it never recurses, `scalar` means it only recurses for types where we would also emit `noalias` annotations in the generated LLVM IR (types passed as individual scalars or pairs of scalars). Setting this to `none` is **unsound**. +* `-Zmiri-preemption-rate` configures the probability that at the end of a basic block, the active + thread will be preempted. The default is `0.01` (i.e., 1%). Setting this to `0` disables + preemption. Note that even without preemption, the schedule is still non-deterministic: + if a thread blocks or yields, the next thread is chosen randomly. * `-Zmiri-provenance-gc=` configures how often the pointer provenance garbage collector runs. The default is to search for and remove unreachable provenance once every `10000` basic blocks. Setting this to `0` disables the garbage collector, which causes some programs to have explosive memory @@ -443,9 +457,6 @@ to Miri failing to detect cases of undefined behavior in a program. casts are not supported in this mode, but that may change in the future. * `-Zmiri-force-page-size=` overrides the default page size for an architecture, in multiples of 1k. `4` is default for most targets. This value should always be a power of 2 and nonzero. -* `-Zmiri-unique-is-unique` performs additional aliasing checks for `core::ptr::Unique` to ensure - that it could theoretically be considered `noalias`. This flag is experimental and has - an effect only when used with `-Zmiri-tree-borrows`. [function ABI]: https://doc.rust-lang.org/reference/items/functions.html#extern-function-qualifier diff --git a/src/tools/miri/bench-cargo-miri/big-allocs/src/main.rs b/src/tools/miri/bench-cargo-miri/big-allocs/src/main.rs index 5b807ac3df1f..89797c498206 100644 --- a/src/tools/miri/bench-cargo-miri/big-allocs/src/main.rs +++ b/src/tools/miri/bench-cargo-miri/big-allocs/src/main.rs @@ -7,10 +7,7 @@ fn main() { // We can't use too big of an allocation or this code will encounter an allocation failure in // CI. Since the allocation can't be huge, we need to do a few iterations so that the effect // we're trying to measure is clearly visible above the interpreter's startup time. - // FIXME (https://github.com/rust-lang/miri/issues/4253): On 32bit targets, we can run out of - // usable addresses if we don't reuse, leading to random test failures. - let count = if cfg!(target_pointer_width = "32") { 8 } else { 12 }; - for _ in 0..count { + for _ in 0..20 { drop(Vec::::with_capacity(512 * 1024 * 1024)); } } diff --git a/src/tools/miri/miri-script/src/commands.rs b/src/tools/miri/miri-script/src/commands.rs index 17a7c06b5253..1c9750e2cbdc 100644 --- a/src/tools/miri/miri-script/src/commands.rs +++ b/src/tools/miri/miri-script/src/commands.rs @@ -1,7 +1,8 @@ use std::collections::HashMap; use std::ffi::{OsStr, OsString}; -use std::fs::File; -use std::io::{BufReader, BufWriter, Write}; +use std::fmt::Write as _; +use std::fs::{self, File}; +use std::io::{self, BufRead, BufReader, BufWriter, Write as _}; use std::ops::Not; use std::path::PathBuf; use std::time::Duration; @@ -169,7 +170,8 @@ impl Command { | Command::Toolchain { .. } | Command::Bench { .. } | Command::RustcPull { .. } - | Command::RustcPush { .. } => {} + | Command::RustcPush { .. } + | Command::Squash => {} } // Then run the actual command. match self { @@ -188,6 +190,7 @@ impl Command { Command::Toolchain { flags } => Self::toolchain(flags), Command::RustcPull { commit } => Self::rustc_pull(commit.clone()), Command::RustcPush { github_user, branch } => Self::rustc_push(github_user, branch), + Command::Squash => Self::squash(), } } @@ -383,6 +386,72 @@ impl Command { Ok(()) } + fn squash() -> Result<()> { + let sh = Shell::new()?; + sh.change_dir(miri_dir()?); + // Figure out base wrt latest upstream master. + // (We can't trust any of the local ones, they can all be outdated.) + let origin_master = { + cmd!(sh, "git fetch https://github.com/rust-lang/miri/") + .quiet() + .ignore_stdout() + .ignore_stderr() + .run()?; + cmd!(sh, "git rev-parse FETCH_HEAD").read()? + }; + let base = cmd!(sh, "git merge-base HEAD {origin_master}").read()?; + // Rebase onto that, setting ourselves as the sequence editor so that we can edit the sequence programmatically. + // We want to forward the host stdin so apparently we cannot use `cmd!`. + let mut cmd = process::Command::new("git"); + cmd.arg("rebase").arg(&base).arg("--interactive"); + cmd.env("GIT_SEQUENCE_EDITOR", env::current_exe()?); + cmd.env("MIRI_SCRIPT_IS_GIT_SEQUENCE_EDITOR", "1"); + cmd.current_dir(sh.current_dir()); + let result = cmd.status()?; + if !result.success() { + bail!("`git rebase` failed"); + } + Ok(()) + } + + pub fn squash_sequence_editor() -> Result<()> { + let sequence_file = env::args().nth(1).expect("git should pass us a filename"); + if sequence_file == "fmt" { + // This is probably us being called as a git hook as part of the rebase. Let's just + // ignore this. Sadly `git rebase` does not have a flag to skip running hooks. + return Ok(()); + } + // Read the provided sequence and adjust it. + let rebase_sequence = { + let mut rebase_sequence = String::new(); + let file = fs::File::open(&sequence_file).with_context(|| { + format!("failed to read rebase sequence from {sequence_file:?}") + })?; + let file = io::BufReader::new(file); + for line in file.lines() { + let line = line?; + // The first line is left unchanged. + if rebase_sequence.is_empty() { + writeln!(rebase_sequence, "{line}").unwrap(); + continue; + } + // If this is a "pick" like, make it "squash". + if let Some(rest) = line.strip_prefix("pick ") { + writeln!(rebase_sequence, "squash {rest}").unwrap(); + continue; + } + // We've reached the end of the relevant part of the sequence, and we can stop. + break; + } + rebase_sequence + }; + // Write out the adjusted sequence. + fs::write(&sequence_file, rebase_sequence).with_context(|| { + format!("failed to write adjusted rebase sequence to {sequence_file:?}") + })?; + Ok(()) + } + fn bench( target: Option, no_install: bool, diff --git a/src/tools/miri/miri-script/src/main.rs b/src/tools/miri/miri-script/src/main.rs index 279bdf8cc3f4..6aab2f79bd78 100644 --- a/src/tools/miri/miri-script/src/main.rs +++ b/src/tools/miri/miri-script/src/main.rs @@ -133,6 +133,8 @@ pub enum Command { #[arg(default_value = "miri-sync")] branch: String, }, + /// Squash the commits of the current feature branch into one. + Squash, } impl Command { @@ -154,7 +156,7 @@ impl Command { flags.extend(remainder); Ok(()) } - Self::Bench { .. } | Self::RustcPull { .. } | Self::RustcPush { .. } => + Self::Bench { .. } | Self::RustcPull { .. } | Self::RustcPush { .. } | Self::Squash => bail!("unexpected \"--\" found in arguments"), } } @@ -170,6 +172,11 @@ pub struct Cli { } fn main() -> Result<()> { + // If we are invoked as the git sequence editor, jump to that logic. + if !std::env::var_os("MIRI_SCRIPT_IS_GIT_SEQUENCE_EDITOR").unwrap_or_default().is_empty() { + return Command::squash_sequence_editor(); + } + // Split the arguments into the part before the `--` and the part after. // The `--` itself ends up in the second part. let miri_args: Vec<_> = std::env::args().take_while(|x| *x != "--").collect(); diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 59d53891217d..97bc826b57a4 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -1b8ab72680f36e783af84c1a3c4f8508572bd9f9 +2ad5f8607d0e192b60b130e5cc416b477b351c18 diff --git a/src/tools/miri/src/alloc_addresses/mod.rs b/src/tools/miri/src/alloc_addresses/mod.rs index 335e8d76999c..dd389d97cdce 100644 --- a/src/tools/miri/src/alloc_addresses/mod.rs +++ b/src/tools/miri/src/alloc_addresses/mod.rs @@ -114,8 +114,16 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { memory_kind: MemoryKind, ) -> InterpResult<'tcx, u64> { let this = self.eval_context_ref(); - let mut rng = this.machine.rng.borrow_mut(); let info = this.get_alloc_info(alloc_id); + + // Miri's address assignment leaks state across thread boundaries, which is incompatible + // with GenMC execution. So we instead let GenMC assign addresses to allocations. + if let Some(genmc_ctx) = this.machine.data_race.as_genmc_ref() { + let addr = genmc_ctx.handle_alloc(&this.machine, info.size, info.align, memory_kind)?; + return interp_ok(addr); + } + + let mut rng = this.machine.rng.borrow_mut(); // This is either called immediately after allocation (and then cached), or when // adjusting `tcx` pointers (which never get freed). So assert that we are looking // at a live allocation. This also ensures that we never re-assign an address to an @@ -197,6 +205,11 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { if global_state.next_base_addr > this.target_usize_max() { throw_exhaust!(AddressSpaceFull); } + // If we filled up more than half the address space, start aggressively reusing + // addresses to avoid running out. + if global_state.next_base_addr > u64::try_from(this.target_isize_max()).unwrap() { + global_state.reuse.address_space_shortage(); + } interp_ok(base_addr) } @@ -490,7 +503,7 @@ impl<'tcx> MiriMachine<'tcx> { // Also remember this address for future reuse. let thread = self.threads.active_thread(); global_state.reuse.add_addr(rng, addr, size, align, kind, thread, || { - if let Some(data_race) = &self.data_race { + if let Some(data_race) = self.data_race.as_vclocks_ref() { data_race.release_clock(&self.threads, |clock| clock.clone()) } else { VClock::default() diff --git a/src/tools/miri/src/alloc_addresses/reuse_pool.rs b/src/tools/miri/src/alloc_addresses/reuse_pool.rs index c0d24a9fbbcf..29d4f2bb7b0f 100644 --- a/src/tools/miri/src/alloc_addresses/reuse_pool.rs +++ b/src/tools/miri/src/alloc_addresses/reuse_pool.rs @@ -20,7 +20,7 @@ pub struct ReusePool { /// allocations as address-size pairs, the list must be sorted by the size and then the thread ID. /// /// Each of these maps has at most MAX_POOL_SIZE elements, and since alignment is limited to - /// less than 64 different possible value, that bounds the overall size of the pool. + /// less than 64 different possible values, that bounds the overall size of the pool. /// /// We also store the ID and the data-race clock of the thread that donated this pool element, /// to ensure synchronization with the thread that picks up this address. @@ -36,6 +36,15 @@ impl ReusePool { } } + /// Call this when we are using up a lot of the address space: if memory reuse is enabled at all, + /// this will bump the intra-thread reuse rate to 100% so that we can keep running this program as + /// long as possible. + pub fn address_space_shortage(&mut self) { + if self.address_reuse_rate > 0.0 { + self.address_reuse_rate = 1.0; + } + } + fn subpool(&mut self, align: Align) -> &mut Vec<(u64, Size, ThreadId, VClock)> { let pool_idx: usize = align.bytes().trailing_zeros().try_into().unwrap(); if self.pool.len() <= pool_idx { @@ -55,9 +64,7 @@ impl ReusePool { clock: impl FnOnce() -> VClock, ) { // Let's see if we even want to remember this address. - // We don't remember stack addresses: there's a lot of them (so the perf impact is big), - // and we only want to reuse stack slots within the same thread or else we'll add a lot of - // undesired synchronization. + // We don't remember stack addresses since there's so many of them (so the perf impact is big). if kind == MemoryKind::Stack || !rng.random_bool(self.address_reuse_rate) { return; } diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs index 8ff1c9d6ff02..69aa035fdc3d 100644 --- a/src/tools/miri/src/bin/miri.rs +++ b/src/tools/miri/src/bin/miri.rs @@ -28,13 +28,14 @@ use std::env::{self, VarError}; use std::num::NonZero; use std::ops::Range; use std::path::PathBuf; +use std::rc::Rc; use std::str::FromStr; use std::sync::atomic::{AtomicI32, AtomicU32, Ordering}; use std::sync::{Arc, Once}; use miri::{ - BacktraceStyle, BorrowTrackerMethod, MiriConfig, MiriEntryFnType, ProvenanceMode, RetagFields, - ValidationMode, + BacktraceStyle, BorrowTrackerMethod, GenmcConfig, GenmcCtx, MiriConfig, MiriEntryFnType, + ProvenanceMode, RetagFields, ValidationMode, }; use rustc_abi::ExternAbi; use rustc_data_structures::sync; @@ -60,6 +61,8 @@ use tracing::debug; struct MiriCompilerCalls { miri_config: Option, many_seeds: Option, + /// Settings for using GenMC with Miri. + genmc_config: Option, } struct ManySeedsConfig { @@ -68,8 +71,12 @@ struct ManySeedsConfig { } impl MiriCompilerCalls { - fn new(miri_config: MiriConfig, many_seeds: Option) -> Self { - Self { miri_config: Some(miri_config), many_seeds } + fn new( + miri_config: MiriConfig, + many_seeds: Option, + genmc_config: Option, + ) -> Self { + Self { miri_config: Some(miri_config), many_seeds, genmc_config } } } @@ -179,6 +186,12 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { optimizations is usually marginal at best."); } + if let Some(genmc_config) = &self.genmc_config { + let _genmc_ctx = Rc::new(GenmcCtx::new(&config, genmc_config)); + + todo!("GenMC mode not yet implemented"); + }; + if let Some(many_seeds) = self.many_seeds.take() { assert!(config.seed.is_none()); let exit_code = sync::IntoDynSyncSend(AtomicI32::new(rustc_driver::EXIT_SUCCESS)); @@ -187,8 +200,14 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { let mut config = config.clone(); config.seed = Some((*seed).into()); eprintln!("Trying seed: {seed}"); - let return_code = miri::eval_entry(tcx, entry_def_id, entry_type, config) - .unwrap_or(rustc_driver::EXIT_FAILURE); + let return_code = miri::eval_entry( + tcx, + entry_def_id, + entry_type, + &config, + /* genmc_ctx */ None, + ) + .unwrap_or(rustc_driver::EXIT_FAILURE); if return_code != rustc_driver::EXIT_SUCCESS { eprintln!("FAILING SEED: {seed}"); if !many_seeds.keep_going { @@ -206,11 +225,12 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { } std::process::exit(exit_code.0.into_inner()); } else { - let return_code = miri::eval_entry(tcx, entry_def_id, entry_type, config) + let return_code = miri::eval_entry(tcx, entry_def_id, entry_type, &config, None) .unwrap_or_else(|| { tcx.dcx().abort_if_errors(); rustc_driver::EXIT_FAILURE }); + std::process::exit(return_code); } @@ -506,6 +526,7 @@ fn main() { let mut many_seeds_keep_going = false; let mut miri_config = MiriConfig::default(); miri_config.env = env_snapshot; + let mut genmc_config = None; let mut rustc_args = vec![]; let mut after_dashdash = false; @@ -533,8 +554,6 @@ fn main() { } else if arg == "-Zmiri-tree-borrows" { miri_config.borrow_tracker = Some(BorrowTrackerMethod::TreeBorrows); miri_config.provenance_mode = ProvenanceMode::Strict; - } else if arg == "-Zmiri-unique-is-unique" { - miri_config.unique_is_unique = true; } else if arg == "-Zmiri-disable-data-race-detector" { miri_config.data_race_detector = false; miri_config.weak_memory_emulation = false; @@ -573,6 +592,13 @@ fn main() { miri_config.mute_stdout_stderr = true; } else if arg == "-Zmiri-retag-fields" { miri_config.retag_fields = RetagFields::Yes; + } else if arg == "-Zmiri-fixed-schedule" { + miri_config.fixed_scheduling = true; + } else if arg == "-Zmiri-deterministic-concurrency" { + miri_config.fixed_scheduling = true; + miri_config.address_reuse_cross_thread_rate = 0.0; + miri_config.cmpxchg_weak_failure_rate = 0.0; + miri_config.weak_memory_emulation = false; } else if let Some(retag_fields) = arg.strip_prefix("-Zmiri-retag-fields=") { miri_config.retag_fields = match retag_fields { "all" => RetagFields::Yes, @@ -596,6 +622,10 @@ fn main() { many_seeds = Some(0..64); } else if arg == "-Zmiri-many-seeds-keep-going" { many_seeds_keep_going = true; + } else if let Some(trimmed_arg) = arg.strip_prefix("-Zmiri-genmc") { + // FIXME(GenMC): Currently, GenMC mode is incompatible with aliasing model checking. + miri_config.borrow_tracker = None; + GenmcConfig::parse_arg(&mut genmc_config, trimmed_arg); } else if let Some(param) = arg.strip_prefix("-Zmiri-env-forward=") { miri_config.forwarded_env_vars.push(param.to_owned()); } else if let Some(param) = arg.strip_prefix("-Zmiri-env-set=") { @@ -690,14 +720,6 @@ fn main() { rustc_args.push(arg); } } - // `-Zmiri-unique-is-unique` should only be used with `-Zmiri-tree-borrows` - if miri_config.unique_is_unique - && !matches!(miri_config.borrow_tracker, Some(BorrowTrackerMethod::TreeBorrows)) - { - show_error!( - "-Zmiri-unique-is-unique only has an effect when -Zmiri-tree-borrows is also used" - ); - } // Tree Borrows implies strict provenance, and is not compatible with native calls. if matches!(miri_config.borrow_tracker, Some(BorrowTrackerMethod::TreeBorrows)) { if miri_config.provenance_mode != ProvenanceMode::Strict { @@ -727,7 +749,24 @@ fn main() { let many_seeds = many_seeds.map(|seeds| ManySeedsConfig { seeds, keep_going: many_seeds_keep_going }); + // Validate settings for data race detection and GenMC mode. + assert_eq!(genmc_config.is_some(), miri_config.genmc_mode); + if genmc_config.is_some() { + if !miri_config.data_race_detector { + show_error!("Cannot disable data race detection in GenMC mode (currently)"); + } else if !miri_config.weak_memory_emulation { + show_error!("Cannot disable weak memory emulation in GenMC mode"); + } + } else if miri_config.weak_memory_emulation && !miri_config.data_race_detector { + show_error!( + "Weak memory emulation cannot be enabled when the data race detector is disabled" + ); + }; + debug!("rustc arguments: {:?}", rustc_args); debug!("crate arguments: {:?}", miri_config.args); - run_compiler_and_exit(&rustc_args, &mut MiriCompilerCalls::new(miri_config, many_seeds)) + run_compiler_and_exit( + &rustc_args, + &mut MiriCompilerCalls::new(miri_config, many_seeds, genmc_config), + ) } diff --git a/src/tools/miri/src/borrow_tracker/mod.rs b/src/tools/miri/src/borrow_tracker/mod.rs index 9808102f4ba6..b66c561d2b8a 100644 --- a/src/tools/miri/src/borrow_tracker/mod.rs +++ b/src/tools/miri/src/borrow_tracker/mod.rs @@ -102,8 +102,6 @@ pub struct GlobalStateInner { tracked_pointer_tags: FxHashSet, /// Whether to recurse into datatypes when searching for pointers to retag. retag_fields: RetagFields, - /// Whether `core::ptr::Unique` gets special (`Box`-like) handling. - unique_is_unique: bool, } impl VisitProvenance for GlobalStateInner { @@ -164,7 +162,6 @@ impl GlobalStateInner { borrow_tracker_method: BorrowTrackerMethod, tracked_pointer_tags: FxHashSet, retag_fields: RetagFields, - unique_is_unique: bool, ) -> Self { GlobalStateInner { borrow_tracker_method, @@ -173,7 +170,6 @@ impl GlobalStateInner { protected_tags: FxHashMap::default(), tracked_pointer_tags, retag_fields, - unique_is_unique, } } @@ -239,7 +235,6 @@ impl BorrowTrackerMethod { self, config.tracked_pointer_tags.clone(), config.retag_fields, - config.unique_is_unique, )) } } diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs index 18a5a0612bb0..bc57ba697b38 100644 --- a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs @@ -594,7 +594,7 @@ trait EvalContextPrivExt<'tcx, 'ecx>: crate::MiriInterpCxExt<'tcx> { ) -> InterpResult<'tcx, Option> { let this = self.eval_context_mut(); // Ensure we bail out if the pointer goes out-of-bounds (see miri#1050). - this.check_ptr_access(place.ptr(), size, CheckInAllocMsg::InboundsTest)?; + this.check_ptr_access(place.ptr(), size, CheckInAllocMsg::Dereferenceable)?; // It is crucial that this gets called on all code paths, to ensure we track tag creation. let log_creation = |this: &MiriInterpCx<'tcx>, @@ -740,7 +740,7 @@ trait EvalContextPrivExt<'tcx, 'ecx>: crate::MiriInterpCxExt<'tcx> { if let Some(access) = access { assert_eq!(access, AccessKind::Write); // Make sure the data race model also knows about this. - if let Some(data_race) = alloc_extra.data_race.as_mut() { + if let Some(data_race) = alloc_extra.data_race.as_vclocks_mut() { data_race.write( alloc_id, range, @@ -789,7 +789,7 @@ trait EvalContextPrivExt<'tcx, 'ecx>: crate::MiriInterpCxExt<'tcx> { if let Some(access) = access { assert_eq!(access, AccessKind::Read); // Make sure the data race model also knows about this. - if let Some(data_race) = alloc_extra.data_race.as_ref() { + if let Some(data_race) = alloc_extra.data_race.as_vclocks_ref() { data_race.read( alloc_id, range, diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs index f39a606513d5..f3e32e75f2f2 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs @@ -2,7 +2,6 @@ use rustc_abi::{BackendRepr, Size}; use rustc_middle::mir::{Mutability, RetagKind}; use rustc_middle::ty::layout::HasTypingEnv; use rustc_middle::ty::{self, Ty}; -use rustc_span::def_id::DefId; use crate::borrow_tracker::{GlobalState, GlobalStateInner, ProtectorKind}; use crate::concurrency::data_race::NaReadType; @@ -115,14 +114,15 @@ impl<'tcx> Tree { /// Policy for a new borrow. #[derive(Debug, Clone, Copy)] struct NewPermission { - /// Optionally ignore the actual size to do a zero-size reborrow. - /// If this is set then `dereferenceable` is not enforced. - zero_size: bool, /// Which permission should the pointer start with. initial_state: Permission, /// Whether this pointer is part of the arguments of a function call. /// `protector` is `Some(_)` for all pointers marked `noalias`. protector: Option, + /// Whether a read should be performed on a retag. This should be `false` + /// for `Cell` because this could cause data races when using thread-safe + /// data types like `Mutex`. + initial_read: bool, } impl<'tcx> NewPermission { @@ -141,18 +141,19 @@ impl<'tcx> NewPermission { // To eliminate the case of Protected Reserved IM we override interior mutability // in the case of a protected reference: protected references are always considered // "freeze" in their reservation phase. - let initial_state = match mutability { - Mutability::Mut if ty_is_unpin => Permission::new_reserved(ty_is_freeze, is_protected), - Mutability::Not if ty_is_freeze => Permission::new_frozen(), + let (initial_state, initial_read) = match mutability { + Mutability::Mut if ty_is_unpin => + (Permission::new_reserved(ty_is_freeze, is_protected), true), + Mutability::Not if ty_is_freeze => (Permission::new_frozen(), true), + Mutability::Not if !ty_is_freeze => (Permission::new_cell(), false), // Raw pointers never enter this function so they are not handled. // However raw pointers are not the only pointers that take the parent - // tag, this also happens for `!Unpin` `&mut`s and interior mutable - // `&`s, which are excluded above. + // tag, this also happens for `!Unpin` `&mut`s, which are excluded above. _ => return None, }; let protector = is_protected.then_some(ProtectorKind::StrongProtector); - Some(Self { zero_size: false, initial_state, protector }) + Some(Self { initial_state, protector, initial_read }) } /// Compute permission for `Box`-like type (`Box` always, and also `Unique` if enabled). @@ -162,19 +163,18 @@ impl<'tcx> NewPermission { ty: Ty<'tcx>, kind: RetagKind, cx: &crate::MiriInterpCx<'tcx>, - zero_size: bool, ) -> Option { let pointee = ty.builtin_deref(true).unwrap(); pointee.is_unpin(*cx.tcx, cx.typing_env()).then_some(()).map(|()| { // Regular `Unpin` box, give it `noalias` but only a weak protector // because it is valid to deallocate it within the function. - let ty_is_freeze = ty.is_freeze(*cx.tcx, cx.typing_env()); + let ty_is_freeze = pointee.is_freeze(*cx.tcx, cx.typing_env()); let protected = kind == RetagKind::FnEntry; let initial_state = Permission::new_reserved(ty_is_freeze, protected); Self { - zero_size, initial_state, protector: protected.then_some(ProtectorKind::WeakProtector), + initial_read: true, } }) } @@ -197,7 +197,7 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Make sure the new permission makes sense as the initial permission of a fresh tag. assert!(new_perm.initial_state.is_initial()); // Ensure we bail out if the pointer goes out-of-bounds (see miri#1050). - this.check_ptr_access(place.ptr(), ptr_size, CheckInAllocMsg::InboundsTest)?; + this.check_ptr_access(place.ptr(), ptr_size, CheckInAllocMsg::Dereferenceable)?; // It is crucial that this gets called on all code paths, to ensure we track tag creation. let log_creation = |this: &MiriInterpCx<'tcx>, @@ -289,13 +289,15 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let mut tree_borrows = alloc_extra.borrow_tracker_tb().borrow_mut(); // All reborrows incur a (possibly zero-sized) read access to the parent - tree_borrows.perform_access( - orig_tag, - Some((range, AccessKind::Read, diagnostics::AccessCause::Reborrow)), - this.machine.borrow_tracker.as_ref().unwrap(), - alloc_id, - this.machine.current_span(), - )?; + if new_perm.initial_read { + tree_borrows.perform_access( + orig_tag, + Some((range, AccessKind::Read, diagnostics::AccessCause::Reborrow)), + this.machine.borrow_tracker.as_ref().unwrap(), + alloc_id, + this.machine.current_span(), + )?; + } // Record the parent-child pair in the tree. tree_borrows.new_child( orig_tag, @@ -308,8 +310,8 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> { drop(tree_borrows); // Also inform the data race model (but only if any bytes are actually affected). - if range.size.bytes() > 0 { - if let Some(data_race) = alloc_extra.data_race.as_ref() { + if range.size.bytes() > 0 && new_perm.initial_read { + if let Some(data_race) = alloc_extra.data_race.as_vclocks_ref() { data_race.read( alloc_id, range, @@ -333,15 +335,12 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Determine the size of the reborrow. // For most types this is the entire size of the place, however // - when `extern type` is involved we use the size of the known prefix, - // - if the pointer is not reborrowed (raw pointer) or if `zero_size` is set - // then we override the size to do a zero-length reborrow. - let reborrow_size = match new_perm { - NewPermission { zero_size: false, .. } => - this.size_and_align_of_mplace(place)? - .map(|(size, _)| size) - .unwrap_or(place.layout.size), - _ => Size::from_bytes(0), - }; + // - if the pointer is not reborrowed (raw pointer) then we override the size + // to do a zero-length reborrow. + let reborrow_size = this + .size_and_align_of_mplace(place)? + .map(|(size, _)| size) + .unwrap_or(place.layout.size); trace!("Creating new permission: {:?} with size {:?}", new_perm, reborrow_size); // This new tag is not guaranteed to actually be used. @@ -405,9 +404,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let this = self.eval_context_mut(); let options = this.machine.borrow_tracker.as_mut().unwrap().get_mut(); let retag_fields = options.retag_fields; - let unique_did = - options.unique_is_unique.then(|| this.tcx.lang_items().ptr_unique()).flatten(); - let mut visitor = RetagVisitor { ecx: this, kind, retag_fields, unique_did }; + let mut visitor = RetagVisitor { ecx: this, kind, retag_fields }; return visitor.visit_value(place); // The actual visitor. @@ -415,7 +412,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { ecx: &'ecx mut MiriInterpCx<'tcx>, kind: RetagKind, retag_fields: RetagFields, - unique_did: Option, } impl<'ecx, 'tcx> RetagVisitor<'ecx, 'tcx> { #[inline(always)] // yes this helps in our benchmarks @@ -446,12 +442,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn visit_box(&mut self, box_ty: Ty<'tcx>, place: &PlaceTy<'tcx>) -> InterpResult<'tcx> { // Only boxes for the global allocator get any special treatment. if box_ty.is_box_global(*self.ecx.tcx) { - let new_perm = NewPermission::from_unique_ty( - place.layout.ty, - self.kind, - self.ecx, - /* zero_size */ false, - ); + let new_perm = + NewPermission::from_unique_ty(place.layout.ty, self.kind, self.ecx); self.retag_ptr_inplace(place, new_perm)?; } interp_ok(()) @@ -485,16 +477,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // even if field retagging is not enabled. *shrug*) self.walk_value(place)?; } - ty::Adt(adt, _) if self.unique_did == Some(adt.did()) => { - let place = inner_ptr_of_unique(self.ecx, place)?; - let new_perm = NewPermission::from_unique_ty( - place.layout.ty, - self.kind, - self.ecx, - /* zero_size */ true, - ); - self.retag_ptr_inplace(&place, new_perm)?; - } _ => { // Not a reference/pointer/box. Only recurse if configured appropriately. let recurse = match self.retag_fields { @@ -533,8 +515,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Retag it. With protection! That is the entire point. let new_perm = NewPermission { initial_state: Permission::new_reserved(ty_is_freeze, /* protected */ true), - zero_size: false, protector: Some(ProtectorKind::StrongProtector), + initial_read: true, }; this.tb_retag_place(place, new_perm) } @@ -594,27 +576,3 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { tree_borrows.give_pointer_debug_name(tag, nth_parent, name) } } - -/// Takes a place for a `Unique` and turns it into a place with the inner raw pointer. -/// I.e. input is what you get from the visitor upon encountering an `adt` that is `Unique`, -/// and output can be used by `retag_ptr_inplace`. -fn inner_ptr_of_unique<'tcx>( - ecx: &MiriInterpCx<'tcx>, - place: &PlaceTy<'tcx>, -) -> InterpResult<'tcx, PlaceTy<'tcx>> { - // Follows the same layout as `interpret/visitor.rs:walk_value` for `Box` in - // `rustc_const_eval`, just with one fewer layer. - // Here we have a `Unique(NonNull(*mut), PhantomData)` - assert_eq!(place.layout.fields.count(), 2, "Unique must have exactly 2 fields"); - let (nonnull, phantom) = (ecx.project_field(place, 0)?, ecx.project_field(place, 1)?); - assert!( - phantom.layout.ty.ty_adt_def().is_some_and(|adt| adt.is_phantom_data()), - "2nd field of `Unique` should be `PhantomData` but is `{:?}`", - phantom.layout.ty, - ); - // Now down to `NonNull(*mut)` - assert_eq!(nonnull.layout.fields.count(), 1, "NonNull must have exactly 1 field"); - let ptr = ecx.project_field(&nonnull, 0)?; - // Finally a plain `*mut` - interp_ok(ptr) -} diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs index 5c12ce39d10d..087f6fc3f24b 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs @@ -8,6 +8,10 @@ use crate::borrow_tracker::tree_borrows::tree::AccessRelatedness; /// The activation states of a pointer. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] enum PermissionPriv { + /// represents: a shared reference to interior mutable data. + /// allows: all foreign and child accesses; + /// rejects: nothing + Cell, /// represents: a local mutable reference that has not yet been written to; /// allows: child reads, foreign reads; /// affected by: child writes (becomes Active), @@ -60,6 +64,14 @@ impl PartialOrd for PermissionPriv { use Ordering::*; Some(match (self, other) { (a, b) if a == b => Equal, + // Versions of `Reserved` with different interior mutability are incomparable with each + // other. + (ReservedIM, ReservedFrz { .. }) + | (ReservedFrz { .. }, ReservedIM) + // `Cell` is not comparable with any other permission + // since it never transitions to any other state and we + // can never get to `Cell` from another state. + | (Cell, _) | (_, Cell) => return None, (Disabled, _) => Greater, (_, Disabled) => Less, (Frozen, _) => Greater, @@ -71,9 +83,6 @@ impl PartialOrd for PermissionPriv { // `bool` is ordered such that `false <= true`, so this works as intended. c1.cmp(c2) } - // Versions of `Reserved` with different interior mutability are incomparable with each - // other. - (ReservedIM, ReservedFrz { .. }) | (ReservedFrz { .. }, ReservedIM) => return None, }) } } @@ -81,17 +90,22 @@ impl PartialOrd for PermissionPriv { impl PermissionPriv { /// Check if `self` can be the initial state of a pointer. fn is_initial(&self) -> bool { - matches!(self, ReservedFrz { conflicted: false } | Frozen | ReservedIM) + matches!(self, ReservedFrz { conflicted: false } | Frozen | ReservedIM | Cell) } /// Reject `ReservedIM` that cannot exist in the presence of a protector. fn compatible_with_protector(&self) -> bool { - !matches!(self, ReservedIM) + // FIXME(TB-Cell): It is unclear what to do here. + // `Cell` will occur with a protector but won't provide the guarantees + // of noalias (it will fail the `protected_enforces_noalias` test). + !matches!(self, ReservedIM | Cell) } /// See `foreign_access_skipping.rs`. Computes the SIFA of a permission. fn strongest_idempotent_foreign_access(&self, prot: bool) -> IdempotentForeignAccess { match self { + // Cell survives any foreign access + Cell => IdempotentForeignAccess::Write, // A protected non-conflicted Reserved will become conflicted under a foreign read, // and is hence not idempotent under it. ReservedFrz { conflicted } if prot && !conflicted => IdempotentForeignAccess::None, @@ -124,7 +138,7 @@ mod transition { Disabled => return None, // The inner data `ty_is_freeze` of `Reserved` is always irrelevant for Read // accesses, since the data is not being mutated. Hence the `{ .. }`. - readable @ (ReservedFrz { .. } | ReservedIM | Active | Frozen) => readable, + readable @ (Cell | ReservedFrz { .. } | ReservedIM | Active | Frozen) => readable, }) } @@ -132,6 +146,8 @@ mod transition { /// is protected; invalidate `Active`. fn foreign_read(state: PermissionPriv, protected: bool) -> Option { Some(match state { + // Cell ignores foreign reads. + Cell => Cell, // Non-writeable states just ignore foreign reads. non_writeable @ (Frozen | Disabled) => non_writeable, // Writeable states are more tricky, and depend on whether things are protected. @@ -167,6 +183,8 @@ mod transition { /// write permissions, `Frozen` and `Disabled` cannot obtain such permissions and produce UB. fn child_write(state: PermissionPriv, protected: bool) -> Option { Some(match state { + // Cell ignores child writes. + Cell => Cell, // If the `conflicted` flag is set, then there was a foreign read during // the function call that is still ongoing (still `protected`), // this is UB (`noalias` violation). @@ -185,6 +203,8 @@ mod transition { // types receive a `ReservedFrz` instead of `ReservedIM` when retagged under a protector, // so the result of this function does indirectly depend on (past) protector status. Some(match state { + // Cell ignores foreign writes. + Cell => Cell, res @ ReservedIM => { // We can never create a `ReservedIM` under a protector, only `ReservedFrz`. assert!(!protected); @@ -242,6 +262,11 @@ impl Permission { self.inner == Frozen } + /// Check if `self` is the shared-reference-to-interior-mutable-data state of a pointer. + pub fn is_cell(&self) -> bool { + self.inner == Cell + } + /// Default initial permission of the root of a new tree at inbounds positions. /// Must *only* be used for the root, this is not in general an "initial" permission! pub fn new_active() -> Self { @@ -278,11 +303,27 @@ impl Permission { Self { inner: Disabled } } + /// Default initial permission of a shared reference to interior mutable data. + pub fn new_cell() -> Self { + Self { inner: Cell } + } + /// Reject `ReservedIM` that cannot exist in the presence of a protector. pub fn compatible_with_protector(&self) -> bool { self.inner.compatible_with_protector() } + /// What kind of access to perform before releasing the protector. + pub fn protector_end_access(&self) -> Option { + match self.inner { + // Do not do perform access if it is a `Cell`, as this + // can cause data races when using thread-safe data types. + Cell => None, + Active => Some(AccessKind::Write), + _ => Some(AccessKind::Read), + } + } + /// Apply the transition to the inner PermissionPriv. pub fn perform_access( kind: AccessKind, @@ -306,30 +347,32 @@ impl Permission { /// remove protected parents. pub fn can_be_replaced_by_child(self, child: Self) -> bool { match (self.inner, child.inner) { - // ReservedIM can be replaced by anything, as it allows all - // transitions. + // Cell allows all transitions. + (Cell, _) => true, + // Cell is the most permissive, nothing can be replaced by Cell. + // (ReservedIM, Cell) => true, + (_, Cell) => false, + // ReservedIM can be replaced by anything besides Cell. + // ReservedIM allows all transitions, but unlike Cell, a local write + // to ReservedIM transitions to Active, while it is a no-op for Cell. (ReservedIM, _) => true, + (_, ReservedIM) => false, // Reserved (as parent, where conflictedness does not matter) - // can be replaced by all but ReservedIM, - // since ReservedIM alone would survive foreign writes - (ReservedFrz { .. }, ReservedIM) => false, + // can be replaced by all but ReservedIM and Cell, + // since ReservedIM and Cell alone would survive foreign writes (ReservedFrz { .. }, _) => true, + (_, ReservedFrz { .. }) => false, // Active can not be replaced by something surviving - // foreign reads and then remaining writable. - (Active, ReservedIM) => false, - (Active, ReservedFrz { .. }) => false, + // foreign reads and then remaining writable (i.e., Reserved*). // Replacing a state by itself is always okay, even if the child state is protected. - (Active, Active) => true, // Active can be replaced by Frozen, since it is not protected. - (Active, Frozen) => true, - (Active, Disabled) => true, + (Active, Active | Frozen | Disabled) => true, + (_, Active) => false, // Frozen can only be replaced by Disabled (and itself). - (Frozen, Frozen) => true, - (Frozen, Disabled) => true, - (Frozen, _) => false, + (Frozen, Frozen | Disabled) => true, + (_, Frozen) => false, // Disabled can not be replaced by anything else. (Disabled, Disabled) => true, - (Disabled, _) => false, } } @@ -383,6 +426,7 @@ pub mod diagnostics { f, "{}", match self { + Cell => "Cell", ReservedFrz { conflicted: false } => "Reserved", ReservedFrz { conflicted: true } => "Reserved (conflicted)", ReservedIM => "Reserved (interior mutable)", @@ -413,6 +457,7 @@ pub mod diagnostics { // and also as `diagnostics::DisplayFmtPermission.uninit` otherwise // alignment will be incorrect. match self.inner { + Cell => "Cel ", ReservedFrz { conflicted: false } => "Res ", ReservedFrz { conflicted: true } => "ResC", ReservedIM => "ReIM", @@ -459,7 +504,7 @@ pub mod diagnostics { /// (Reserved < Active < Frozen < Disabled); /// - between `self` and `err` the permission should also be increasing, /// so all permissions inside `err` should be greater than `self.1`; - /// - `Active` and `Reserved(conflicted=false)` cannot cause an error + /// - `Active`, `Reserved(conflicted=false)`, and `Cell` cannot cause an error /// due to insufficient permissions, so `err` cannot be a `ChildAccessForbidden(_)` /// of either of them; /// - `err` should not be `ProtectedDisabled(Disabled)`, because the protected @@ -492,13 +537,14 @@ pub mod diagnostics { (ReservedFrz { conflicted: true } | Active | Frozen, Disabled) => false, (ReservedFrz { conflicted: true }, Frozen) => false, - // `Active` and `Reserved` have all permissions, so a + // `Active`, `Reserved`, and `Cell` have all permissions, so a // `ChildAccessForbidden(Reserved | Active)` can never exist. - (_, Active) | (_, ReservedFrz { conflicted: false }) => + (_, Active) | (_, ReservedFrz { conflicted: false }) | (_, Cell) => unreachable!("this permission cannot cause an error"), // No transition has `Reserved { conflicted: false }` or `ReservedIM` - // as its `.to` unless it's a noop. - (ReservedFrz { conflicted: false } | ReservedIM, _) => + // as its `.to` unless it's a noop. `Cell` cannot be in its `.to` + // because all child accesses are a noop. + (ReservedFrz { conflicted: false } | ReservedIM | Cell, _) => unreachable!("self is a noop transition"), // All transitions produced in normal executions (using `apply_access`) // change permissions in the order `Reserved -> Active -> Frozen -> Disabled`. @@ -544,16 +590,17 @@ pub mod diagnostics { "permission that results in Disabled should not itself be Disabled in the first place" ), // No transition has `Reserved { conflicted: false }` or `ReservedIM` as its `.to` - // unless it's a noop. - (ReservedFrz { conflicted: false } | ReservedIM, _) => + // unless it's a noop. `Cell` cannot be in its `.to` because all child + // accesses are a noop. + (ReservedFrz { conflicted: false } | ReservedIM | Cell, _) => unreachable!("self is a noop transition"), // Permissions only evolve in the order `Reserved -> Active -> Frozen -> Disabled`, // so permissions found must be increasing in the order // `self.from < self.to <= forbidden.from < forbidden.to`. - (Disabled, ReservedFrz { .. } | ReservedIM | Active | Frozen) - | (Frozen, ReservedFrz { .. } | ReservedIM | Active) - | (Active, ReservedFrz { .. } | ReservedIM) => + (Disabled, Cell | ReservedFrz { .. } | ReservedIM | Active | Frozen) + | (Frozen, Cell | ReservedFrz { .. } | ReservedIM | Active) + | (Active, Cell | ReservedFrz { .. } | ReservedIM) => unreachable!("permissions between self and err must be increasing"), } } @@ -590,7 +637,7 @@ mod propagation_optimization_checks { impl Exhaustive for PermissionPriv { fn exhaustive() -> Box> { Box::new( - vec![Active, Frozen, Disabled, ReservedIM] + vec![Active, Frozen, Disabled, ReservedIM, Cell] .into_iter() .chain(::exhaustive().map(|conflicted| ReservedFrz { conflicted })), ) diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs index 3389b1c602c3..47ccaadbb9e3 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs @@ -721,9 +721,14 @@ impl<'tcx> Tree { // visit all children, skipping none |_| ContinueTraversal::Recurse, |args: NodeAppArgs<'_>| -> Result<(), TransitionError> { - let NodeAppArgs { node, .. } = args; + let NodeAppArgs { node, perm, .. } = args; + let perm = + perm.get().copied().unwrap_or_else(|| node.default_location_state()); if global.borrow().protected_tags.get(&node.tag) == Some(&ProtectorKind::StrongProtector) + // Don't check for protector if it is a Cell (see `unsafe_cell_deallocate` in `interior_mutability.rs`). + // Related to https://github.com/rust-lang/rust/issues/55005. + && !perm.permission().is_cell() { Err(TransitionError::ProtectedDealloc) } else { @@ -865,10 +870,9 @@ impl<'tcx> Tree { let idx = self.tag_mapping.get(&tag).unwrap(); // Only visit initialized permissions if let Some(p) = perms.get(idx) + && let Some(access_kind) = p.permission.protector_end_access() && p.initialized { - let access_kind = - if p.permission.is_active() { AccessKind::Write } else { AccessKind::Read }; let access_cause = diagnostics::AccessCause::FnExit(access_kind); TreeVisitor { nodes: &mut self.nodes, tag_mapping: &self.tag_mapping, perms } .traverse_nonchildren( diff --git a/src/tools/miri/src/concurrency/data_race.rs b/src/tools/miri/src/concurrency/data_race.rs index 847c68234759..714eb1fba91c 100644 --- a/src/tools/miri/src/concurrency/data_race.rs +++ b/src/tools/miri/src/concurrency/data_race.rs @@ -1,4 +1,4 @@ -//! Implementation of a data-race detector using Lamport Timestamps / Vector-clocks +//! Implementation of a data-race detector using Lamport Timestamps / Vector clocks //! based on the Dynamic Race Detection for C++: //! //! which does not report false-positives when fences are used, and gives better @@ -54,6 +54,7 @@ use rustc_span::Span; use super::vector_clock::{VClock, VTimestamp, VectorIdx}; use super::weak_memory::EvalContextExt as _; +use crate::concurrency::GlobalDataRaceHandler; use crate::diagnostics::RacingOp; use crate::*; @@ -259,7 +260,7 @@ enum AccessType { /// Per-byte vector clock metadata for data-race detection. #[derive(Clone, PartialEq, Eq, Debug)] struct MemoryCellClocks { - /// The vector-clock timestamp and the thread that did the last non-atomic write. We don't need + /// The vector clock timestamp and the thread that did the last non-atomic write. We don't need /// a full `VClock` here, it's always a single thread and nothing synchronizes, so the effective /// clock is all-0 except for the thread that did the write. write: (VectorIdx, VTimestamp), @@ -269,7 +270,7 @@ struct MemoryCellClocks { /// a deallocation of memory. write_type: NaWriteType, - /// The vector-clock of all non-atomic reads that happened since the last non-atomic write + /// The vector clock of all non-atomic reads that happened since the last non-atomic write /// (i.e., we join together the "singleton" clocks corresponding to each read). It is reset to /// zero on each write operation. read: VClock, @@ -298,7 +299,7 @@ struct ThreadExtraState { } /// Global data-race detection state, contains the currently -/// executing thread as well as the vector-clocks associated +/// executing thread as well as the vector clocks associated /// with each of the threads. // FIXME: it is probably better to have one large RefCell, than to have so many small ones. #[derive(Debug, Clone)] @@ -335,7 +336,7 @@ pub struct GlobalState { /// for use as the index for a new thread. /// Elements in this set may still require the vector index to /// report data-races, and can only be re-used after all - /// active vector-clocks catch up with the threads timestamp. + /// active vector clocks catch up with the threads timestamp. reuse_candidates: RefCell>, /// We make SC fences act like RMWs on a global location. @@ -348,6 +349,9 @@ pub struct GlobalState { /// Track when an outdated (weak memory) load happens. pub track_outdated_loads: bool, + + /// Whether weak memory emulation is enabled + pub weak_memory: bool, } impl VisitProvenance for GlobalState { @@ -680,6 +684,23 @@ impl MemoryCellClocks { } } +impl GlobalDataRaceHandler { + /// Select whether data race checking is disabled. This is solely an + /// implementation detail of `allow_data_races_*` and must not be used anywhere else! + fn set_ongoing_action_data_race_free(&self, enable: bool) { + match self { + GlobalDataRaceHandler::None => {} + GlobalDataRaceHandler::Vclocks(data_race) => { + let old = data_race.ongoing_action_data_race_free.replace(enable); + assert_ne!(old, enable, "cannot nest allow_data_races"); + } + GlobalDataRaceHandler::Genmc(genmc_ctx) => { + genmc_ctx.set_ongoing_action_data_race_free(enable); + } + } + } +} + /// Evaluation context extensions. impl<'tcx> EvalContextExt<'tcx> for MiriInterpCx<'tcx> {} pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { @@ -696,6 +717,19 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { // This is fine with StackedBorrow and race checks because they don't concern metadata on // the *value* (including the associated provenance if this is an AtomicPtr) at this location. // Only metadata on the location itself is used. + + if let Some(genmc_ctx) = this.machine.data_race.as_genmc_ref() { + // FIXME(GenMC): Inform GenMC what a non-atomic read here would return, to support mixed atomics/non-atomics + let old_val = None; + return genmc_ctx.atomic_load( + this, + place.ptr().addr(), + place.layout.size, + atomic, + old_val, + ); + } + let scalar = this.allow_data_races_ref(move |this| this.read_scalar(place))?; let buffered_scalar = this.buffered_atomic_read(place, atomic, scalar, || { this.validate_atomic_load(place, atomic) @@ -718,6 +752,12 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { // This is also a very special exception where we just ignore an error -- if this read // was UB e.g. because the memory is uninitialized, we don't want to know! let old_val = this.run_for_validation_mut(|this| this.read_scalar(dest)).discard_err(); + // Inform GenMC about the atomic store. + if let Some(genmc_ctx) = this.machine.data_race.as_genmc_ref() { + // FIXME(GenMC): Inform GenMC what a non-atomic read here would return, to support mixed atomics/non-atomics + genmc_ctx.atomic_store(this, dest.ptr().addr(), dest.layout.size, val, atomic)?; + return interp_ok(()); + } this.allow_data_races_mut(move |this| this.write_scalar(val, dest))?; this.validate_atomic_store(dest, atomic)?; this.buffered_atomic_write(val, dest, atomic, old_val) @@ -737,6 +777,21 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { let old = this.allow_data_races_mut(|this| this.read_immediate(place))?; + // Inform GenMC about the atomic rmw operation. + if let Some(genmc_ctx) = this.machine.data_race.as_genmc_ref() { + // FIXME(GenMC): Inform GenMC what a non-atomic read here would return, to support mixed atomics/non-atomics + let (old_val, new_val) = genmc_ctx.atomic_rmw_op( + this, + place.ptr().addr(), + place.layout.size, + atomic, + (op, not), + rhs.to_scalar(), + )?; + this.allow_data_races_mut(|this| this.write_scalar(new_val, place))?; + return interp_ok(ImmTy::from_scalar(old_val, old.layout)); + } + let val = this.binary_op(op, &old, rhs)?; let val = if not { this.unary_op(mir::UnOp::Not, &val)? } else { val }; this.allow_data_races_mut(|this| this.write_immediate(*val, place))?; @@ -761,6 +816,19 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { let old = this.allow_data_races_mut(|this| this.read_scalar(place))?; this.allow_data_races_mut(|this| this.write_scalar(new, place))?; + // Inform GenMC about the atomic atomic exchange. + if let Some(genmc_ctx) = this.machine.data_race.as_genmc_ref() { + // FIXME(GenMC): Inform GenMC what a non-atomic read here would return, to support mixed atomics/non-atomics + let (old_val, _is_success) = genmc_ctx.atomic_exchange( + this, + place.ptr().addr(), + place.layout.size, + new, + atomic, + )?; + return interp_ok(old_val); + } + this.validate_atomic_rmw(place, atomic)?; this.buffered_atomic_rmw(new, place, atomic, old)?; @@ -780,6 +848,23 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { this.atomic_access_check(place, AtomicAccessType::Rmw)?; let old = this.allow_data_races_mut(|this| this.read_immediate(place))?; + + // Inform GenMC about the atomic min/max operation. + if let Some(genmc_ctx) = this.machine.data_race.as_genmc_ref() { + // FIXME(GenMC): Inform GenMC what a non-atomic read here would return, to support mixed atomics/non-atomics + let (old_val, new_val) = genmc_ctx.atomic_min_max_op( + this, + place.ptr().addr(), + place.layout.size, + atomic, + min, + old.layout.backend_repr.is_signed(), + rhs.to_scalar(), + )?; + this.allow_data_races_mut(|this| this.write_scalar(new_val, place))?; + return interp_ok(ImmTy::from_scalar(old_val, old.layout)); + } + let lt = this.binary_op(mir::BinOp::Lt, &old, &rhs)?.to_scalar().to_bool()?; #[rustfmt::skip] // rustfmt makes this unreadable @@ -823,6 +908,25 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { // read ordering and write in the success case. // Read as immediate for the sake of `binary_op()` let old = this.allow_data_races_mut(|this| this.read_immediate(place))?; + + // Inform GenMC about the atomic atomic compare exchange. + if let Some(genmc_ctx) = this.machine.data_race.as_genmc_ref() { + let (old, cmpxchg_success) = genmc_ctx.atomic_compare_exchange( + this, + place.ptr().addr(), + place.layout.size, + this.read_scalar(expect_old)?, + new, + success, + fail, + can_fail_spuriously, + )?; + if cmpxchg_success { + this.allow_data_races_mut(|this| this.write_scalar(new, place))?; + } + return interp_ok(Immediate::ScalarPair(old, Scalar::from_bool(cmpxchg_success))); + } + // `binary_op` will bail if either of them is not a scalar. let eq = this.binary_op(mir::BinOp::Eq, &old, expect_old)?; // If the operation would succeed, but is "weak", fail some portion @@ -859,49 +963,11 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { /// Update the data-race detector for an atomic fence on the current thread. fn atomic_fence(&mut self, atomic: AtomicFenceOrd) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let current_span = this.machine.current_span(); - if let Some(data_race) = &mut this.machine.data_race { - data_race.maybe_perform_sync_operation( - &this.machine.threads, - current_span, - |index, mut clocks| { - trace!("Atomic fence on {:?} with ordering {:?}", index, atomic); - - // Apply data-race detection for the current fences - // this treats AcqRel and SeqCst as the same as an acquire - // and release fence applied in the same timestamp. - if atomic != AtomicFenceOrd::Release { - // Either Acquire | AcqRel | SeqCst - clocks.apply_acquire_fence(); - } - if atomic == AtomicFenceOrd::SeqCst { - // Behave like an RMW on the global fence location. This takes full care of - // all the SC fence requirements, including C++17 §32.4 [atomics.order] - // paragraph 6 (which would limit what future reads can see). It also rules - // out many legal behaviors, but we don't currently have a model that would - // be more precise. - // Also see the second bullet on page 10 of - // . - let mut sc_fence_clock = data_race.last_sc_fence.borrow_mut(); - sc_fence_clock.join(&clocks.clock); - clocks.clock.join(&sc_fence_clock); - // Also establish some sort of order with the last SC write that happened, globally - // (but this is only respected by future reads). - clocks.write_seqcst.join(&data_race.last_sc_write_per_thread.borrow()); - } - // The release fence is last, since both of the above could alter our clock, - // which should be part of what is being released. - if atomic != AtomicFenceOrd::Acquire { - // Either Release | AcqRel | SeqCst - clocks.apply_release_fence(); - } - - // Increment timestamp in case of release semantics. - interp_ok(atomic != AtomicFenceOrd::Acquire) - }, - ) - } else { - interp_ok(()) + let machine = &this.machine; + match &this.machine.data_race { + GlobalDataRaceHandler::None => interp_ok(()), + GlobalDataRaceHandler::Vclocks(data_race) => data_race.atomic_fence(machine, atomic), + GlobalDataRaceHandler::Genmc(genmc_ctx) => genmc_ctx.atomic_fence(machine, atomic), } } @@ -910,10 +976,7 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { fn allow_data_races_all_threads_done(&mut self) { let this = self.eval_context_ref(); assert!(this.have_all_terminated()); - if let Some(data_race) = &this.machine.data_race { - let old = data_race.ongoing_action_data_race_free.replace(true); - assert!(!old, "cannot nest allow_data_races"); - } + this.machine.data_race.set_ongoing_action_data_race_free(true); } /// Calls the callback with the "release" clock of the current thread. @@ -923,14 +986,16 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { /// The closure will only be invoked if data race handling is on. fn release_clock(&self, callback: impl FnOnce(&VClock) -> R) -> Option { let this = self.eval_context_ref(); - Some(this.machine.data_race.as_ref()?.release_clock(&this.machine.threads, callback)) + Some( + this.machine.data_race.as_vclocks_ref()?.release_clock(&this.machine.threads, callback), + ) } /// Acquire the given clock into the current thread, establishing synchronization with /// the moment when that clock snapshot was taken via `release_clock`. fn acquire_clock(&self, clock: &VClock) { let this = self.eval_context_ref(); - if let Some(data_race) = &this.machine.data_race { + if let Some(data_race) = this.machine.data_race.as_vclocks_ref() { data_race.acquire_clock(clock, &this.machine.threads); } } @@ -1132,7 +1197,7 @@ impl VClockAlloc { machine: &MiriMachine<'_>, ) -> InterpResult<'tcx> { let current_span = machine.current_span(); - let global = machine.data_race.as_ref().unwrap(); + let global = machine.data_race.as_vclocks_ref().unwrap(); if !global.race_detecting() { return interp_ok(()); } @@ -1174,7 +1239,7 @@ impl VClockAlloc { machine: &mut MiriMachine<'_>, ) -> InterpResult<'tcx> { let current_span = machine.current_span(); - let global = machine.data_race.as_mut().unwrap(); + let global = machine.data_race.as_vclocks_mut().unwrap(); if !global.race_detecting() { return interp_ok(()); } @@ -1228,7 +1293,7 @@ impl Default for LocalClocks { impl FrameState { pub fn local_write(&self, local: mir::Local, storage_live: bool, machine: &MiriMachine<'_>) { let current_span = machine.current_span(); - let global = machine.data_race.as_ref().unwrap(); + let global = machine.data_race.as_vclocks_ref().unwrap(); if !global.race_detecting() { return; } @@ -1258,7 +1323,7 @@ impl FrameState { pub fn local_read(&self, local: mir::Local, machine: &MiriMachine<'_>) { let current_span = machine.current_span(); - let global = machine.data_race.as_ref().unwrap(); + let global = machine.data_race.as_vclocks_ref().unwrap(); if !global.race_detecting() { return; } @@ -1281,7 +1346,7 @@ impl FrameState { alloc: &mut VClockAlloc, machine: &MiriMachine<'_>, ) { - let global = machine.data_race.as_ref().unwrap(); + let global = machine.data_race.as_vclocks_ref().unwrap(); if !global.race_detecting() { return; } @@ -1314,14 +1379,9 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { #[inline] fn allow_data_races_ref(&self, op: impl FnOnce(&MiriInterpCx<'tcx>) -> R) -> R { let this = self.eval_context_ref(); - if let Some(data_race) = &this.machine.data_race { - let old = data_race.ongoing_action_data_race_free.replace(true); - assert!(!old, "cannot nest allow_data_races"); - } + this.machine.data_race.set_ongoing_action_data_race_free(true); let result = op(this); - if let Some(data_race) = &this.machine.data_race { - data_race.ongoing_action_data_race_free.set(false); - } + this.machine.data_race.set_ongoing_action_data_race_free(false); result } @@ -1331,14 +1391,9 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { #[inline] fn allow_data_races_mut(&mut self, op: impl FnOnce(&mut MiriInterpCx<'tcx>) -> R) -> R { let this = self.eval_context_mut(); - if let Some(data_race) = &this.machine.data_race { - let old = data_race.ongoing_action_data_race_free.replace(true); - assert!(!old, "cannot nest allow_data_races"); - } + this.machine.data_race.set_ongoing_action_data_race_free(true); let result = op(this); - if let Some(data_race) = &this.machine.data_race { - data_race.ongoing_action_data_race_free.set(false); - } + this.machine.data_race.set_ongoing_action_data_race_free(false); result } @@ -1355,7 +1410,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); this.check_ptr_align(place.ptr(), align)?; // Ensure the allocation is mutable. Even failing (read-only) compare_exchange need mutable - // memory on many targets (i.e., they segfault if taht memory is mapped read-only), and + // memory on many targets (i.e., they segfault if that memory is mapped read-only), and // atomic loads can be implemented via compare_exchange on some targets. There could // possibly be some very specific exceptions to this, see // for details. @@ -1486,7 +1541,9 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { ) -> InterpResult<'tcx> { let this = self.eval_context_ref(); assert!(access.is_atomic()); - let Some(data_race) = &this.machine.data_race else { return interp_ok(()) }; + let Some(data_race) = this.machine.data_race.as_vclocks_ref() else { + return interp_ok(()); + }; if !data_race.race_detecting() { return interp_ok(()); } @@ -1494,7 +1551,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { let (alloc_id, base_offset, _prov) = this.ptr_get_alloc_id(place.ptr(), 0)?; // Load and log the atomic operation. // Note that atomic loads are possible even from read-only allocations, so `get_alloc_extra_mut` is not an option. - let alloc_meta = this.get_alloc_extra(alloc_id)?.data_race.as_ref().unwrap(); + let alloc_meta = this.get_alloc_extra(alloc_id)?.data_race.as_vclocks_ref().unwrap(); trace!( "Atomic op({}) with ordering {:?} on {:?} (size={})", access.description(None, None), @@ -1565,6 +1622,7 @@ impl GlobalState { last_sc_fence: RefCell::new(VClock::default()), last_sc_write_per_thread: RefCell::new(VClock::default()), track_outdated_loads: config.track_outdated_loads, + weak_memory: config.weak_memory_emulation, }; // Setup the main-thread since it is not explicitly created: @@ -1728,7 +1786,7 @@ impl GlobalState { } } - /// On thread termination, the vector-clock may re-used + /// On thread termination, the vector clock may be re-used /// in the future once all remaining thread-clocks catch /// up with the time index of the terminated thread. /// This assigns thread termination with a unique index @@ -1750,6 +1808,50 @@ impl GlobalState { reuse.insert(current_index); } + /// Update the data-race detector for an atomic fence on the current thread. + fn atomic_fence<'tcx>( + &self, + machine: &MiriMachine<'tcx>, + atomic: AtomicFenceOrd, + ) -> InterpResult<'tcx> { + let current_span = machine.current_span(); + self.maybe_perform_sync_operation(&machine.threads, current_span, |index, mut clocks| { + trace!("Atomic fence on {:?} with ordering {:?}", index, atomic); + + // Apply data-race detection for the current fences + // this treats AcqRel and SeqCst as the same as an acquire + // and release fence applied in the same timestamp. + if atomic != AtomicFenceOrd::Release { + // Either Acquire | AcqRel | SeqCst + clocks.apply_acquire_fence(); + } + if atomic == AtomicFenceOrd::SeqCst { + // Behave like an RMW on the global fence location. This takes full care of + // all the SC fence requirements, including C++17 §32.4 [atomics.order] + // paragraph 6 (which would limit what future reads can see). It also rules + // out many legal behaviors, but we don't currently have a model that would + // be more precise. + // Also see the second bullet on page 10 of + // . + let mut sc_fence_clock = self.last_sc_fence.borrow_mut(); + sc_fence_clock.join(&clocks.clock); + clocks.clock.join(&sc_fence_clock); + // Also establish some sort of order with the last SC write that happened, globally + // (but this is only respected by future reads). + clocks.write_seqcst.join(&self.last_sc_write_per_thread.borrow()); + } + // The release fence is last, since both of the above could alter our clock, + // which should be part of what is being released. + if atomic != AtomicFenceOrd::Acquire { + // Either Release | AcqRel | SeqCst + clocks.apply_release_fence(); + } + + // Increment timestamp in case of release semantics. + interp_ok(atomic != AtomicFenceOrd::Acquire) + }) + } + /// Attempt to perform a synchronized operation, this /// will perform no operation if multi-threading is /// not currently enabled. diff --git a/src/tools/miri/src/concurrency/data_race_handler.rs b/src/tools/miri/src/concurrency/data_race_handler.rs new file mode 100644 index 000000000000..047c37e56b8f --- /dev/null +++ b/src/tools/miri/src/concurrency/data_race_handler.rs @@ -0,0 +1,91 @@ +use std::rc::Rc; + +use super::{data_race, weak_memory}; +use crate::concurrency::GenmcCtx; +use crate::{VisitProvenance, VisitWith}; + +pub enum GlobalDataRaceHandler { + /// No data race detection will be done. + None, + /// State required to run in GenMC mode. + /// In this mode, the program will be executed repeatedly to explore different concurrent executions. + /// The `GenmcCtx` must persist across multiple executions, so it is behind an `Rc`. + /// + /// The `GenmcCtx` has several methods with which to inform it about events like atomic memory accesses. + /// In GenMC mode, some functionality is taken over by GenMC: + /// - Memory Allocation: Allocated addresses need to be consistent across executions, which Miri's allocator doesn't guarantee + /// - Scheduling: To influence which concurrent execution we will explore next, GenMC takes over scheduling + /// - Atomic operations: GenMC will ensure that we explore all possible values that the memory model allows + /// an atomic operation to see at any specific point of the program. + Genmc(Rc), + /// The default data race detector for Miri using vector clocks. + Vclocks(Box), +} + +#[derive(Debug)] +pub enum AllocDataRaceHandler { + None, + Genmc, + /// Data race detection via the use of vector clocks. + /// Weak memory emulation via the use of store buffers (if enabled). + Vclocks(data_race::AllocState, Option), +} + +impl GlobalDataRaceHandler { + pub fn is_none(&self) -> bool { + matches!(self, GlobalDataRaceHandler::None) + } + + pub fn as_vclocks_ref(&self) -> Option<&data_race::GlobalState> { + if let Self::Vclocks(data_race) = self { Some(data_race) } else { None } + } + + pub fn as_vclocks_mut(&mut self) -> Option<&mut data_race::GlobalState> { + if let Self::Vclocks(data_race) = self { Some(data_race) } else { None } + } + + pub fn as_genmc_ref(&self) -> Option<&GenmcCtx> { + if let Self::Genmc(genmc_ctx) = self { Some(genmc_ctx) } else { None } + } +} + +impl AllocDataRaceHandler { + pub fn as_vclocks_ref(&self) -> Option<&data_race::AllocState> { + if let Self::Vclocks(data_race, _weak_memory) = self { Some(data_race) } else { None } + } + + pub fn as_vclocks_mut(&mut self) -> Option<&mut data_race::AllocState> { + if let Self::Vclocks(data_race, _weak_memory) = self { Some(data_race) } else { None } + } + + pub fn as_weak_memory_ref(&self) -> Option<&weak_memory::AllocState> { + if let Self::Vclocks(_data_race, weak_memory) = self { weak_memory.as_ref() } else { None } + } + + pub fn as_weak_memory_mut(&mut self) -> Option<&mut weak_memory::AllocState> { + if let Self::Vclocks(_data_race, weak_memory) = self { weak_memory.as_mut() } else { None } + } +} + +impl VisitProvenance for GlobalDataRaceHandler { + fn visit_provenance(&self, visit: &mut VisitWith<'_>) { + match self { + GlobalDataRaceHandler::None => {} + GlobalDataRaceHandler::Vclocks(data_race) => data_race.visit_provenance(visit), + GlobalDataRaceHandler::Genmc(genmc_ctx) => genmc_ctx.visit_provenance(visit), + } + } +} + +impl VisitProvenance for AllocDataRaceHandler { + fn visit_provenance(&self, visit: &mut VisitWith<'_>) { + match self { + AllocDataRaceHandler::None => {} + AllocDataRaceHandler::Genmc => {} + AllocDataRaceHandler::Vclocks(data_race, weak_memory) => { + data_race.visit_provenance(visit); + weak_memory.visit_provenance(visit); + } + } + } +} diff --git a/src/tools/miri/src/concurrency/genmc/config.rs b/src/tools/miri/src/concurrency/genmc/config.rs new file mode 100644 index 000000000000..f91211a670f6 --- /dev/null +++ b/src/tools/miri/src/concurrency/genmc/config.rs @@ -0,0 +1,19 @@ +use crate::MiriConfig; + +#[derive(Debug, Default, Clone)] +pub struct GenmcConfig { + // TODO: add fields +} + +impl GenmcConfig { + /// Function for parsing command line options for GenMC mode. + /// All GenMC arguments start with the string "-Zmiri-genmc". + /// + /// `trimmed_arg` should be the argument to be parsed, with the suffix "-Zmiri-genmc" removed + pub fn parse_arg(genmc_config: &mut Option, trimmed_arg: &str) { + if genmc_config.is_none() { + *genmc_config = Some(Default::default()); + } + todo!("implement parsing of GenMC options") + } +} diff --git a/src/tools/miri/src/concurrency/genmc/dummy.rs b/src/tools/miri/src/concurrency/genmc/dummy.rs new file mode 100644 index 000000000000..3d0558fb6853 --- /dev/null +++ b/src/tools/miri/src/concurrency/genmc/dummy.rs @@ -0,0 +1,239 @@ +#![allow(unused)] + +use rustc_abi::{Align, Size}; +use rustc_const_eval::interpret::{InterpCx, InterpResult}; +use rustc_middle::mir; + +use crate::{ + AtomicFenceOrd, AtomicReadOrd, AtomicRwOrd, AtomicWriteOrd, MemoryKind, MiriConfig, + MiriMachine, Scalar, ThreadId, ThreadManager, VisitProvenance, VisitWith, +}; + +#[derive(Debug)] +pub struct GenmcCtx {} + +#[derive(Debug, Default, Clone)] +pub struct GenmcConfig {} + +impl GenmcCtx { + pub fn new(_miri_config: &MiriConfig, _genmc_config: &GenmcConfig) -> Self { + unreachable!() + } + + pub fn get_stuck_execution_count(&self) -> usize { + unreachable!() + } + + pub fn print_genmc_graph(&self) { + unreachable!() + } + + pub fn is_exploration_done(&self) -> bool { + unreachable!() + } + + /**** Memory access handling ****/ + + pub(crate) fn handle_execution_start(&self) { + unreachable!() + } + + pub(crate) fn handle_execution_end<'tcx>( + &self, + _ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, + ) -> Result<(), String> { + unreachable!() + } + + pub(super) fn set_ongoing_action_data_race_free(&self, _enable: bool) { + unreachable!() + } + + //* might fails if there's a race, load might also not read anything (returns None) */ + pub(crate) fn atomic_load<'tcx>( + &self, + _ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, + _address: Size, + _size: Size, + _ordering: AtomicReadOrd, + _old_val: Option, + ) -> InterpResult<'tcx, Scalar> { + unreachable!() + } + + pub(crate) fn atomic_store<'tcx>( + &self, + _ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, + _address: Size, + _size: Size, + _value: Scalar, + _ordering: AtomicWriteOrd, + ) -> InterpResult<'tcx, ()> { + unreachable!() + } + + pub(crate) fn atomic_fence<'tcx>( + &self, + _machine: &MiriMachine<'tcx>, + _ordering: AtomicFenceOrd, + ) -> InterpResult<'tcx, ()> { + unreachable!() + } + + pub(crate) fn atomic_rmw_op<'tcx>( + &self, + _ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, + _address: Size, + _size: Size, + _ordering: AtomicRwOrd, + (rmw_op, not): (mir::BinOp, bool), + _rhs_scalar: Scalar, + ) -> InterpResult<'tcx, (Scalar, Scalar)> { + unreachable!() + } + + pub(crate) fn atomic_min_max_op<'tcx>( + &self, + ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, + address: Size, + size: Size, + ordering: AtomicRwOrd, + min: bool, + is_signed: bool, + rhs_scalar: Scalar, + ) -> InterpResult<'tcx, (Scalar, Scalar)> { + unreachable!() + } + + pub(crate) fn atomic_exchange<'tcx>( + &self, + _ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, + _address: Size, + _size: Size, + _rhs_scalar: Scalar, + _ordering: AtomicRwOrd, + ) -> InterpResult<'tcx, (Scalar, bool)> { + unreachable!() + } + + pub(crate) fn atomic_compare_exchange<'tcx>( + &self, + _ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, + _address: Size, + _size: Size, + _expected_old_value: Scalar, + _new_value: Scalar, + _success: AtomicRwOrd, + _fail: AtomicReadOrd, + _can_fail_spuriously: bool, + ) -> InterpResult<'tcx, (Scalar, bool)> { + unreachable!() + } + + pub(crate) fn memory_load<'tcx>( + &self, + _machine: &MiriMachine<'tcx>, + _address: Size, + _size: Size, + ) -> InterpResult<'tcx, ()> { + unreachable!() + } + + pub(crate) fn memory_store<'tcx>( + &self, + _machine: &MiriMachine<'tcx>, + _address: Size, + _size: Size, + ) -> InterpResult<'tcx, ()> { + unreachable!() + } + + /**** Memory (de)allocation ****/ + + pub(crate) fn handle_alloc<'tcx>( + &self, + _machine: &MiriMachine<'tcx>, + _size: Size, + _alignment: Align, + _memory_kind: MemoryKind, + ) -> InterpResult<'tcx, u64> { + unreachable!() + } + + pub(crate) fn handle_dealloc<'tcx>( + &self, + _machine: &MiriMachine<'tcx>, + _address: Size, + _size: Size, + _align: Align, + _kind: MemoryKind, + ) -> InterpResult<'tcx, ()> { + unreachable!() + } + + /**** Thread management ****/ + + pub(crate) fn handle_thread_create<'tcx>( + &self, + _threads: &ThreadManager<'tcx>, + _new_thread_id: ThreadId, + ) -> InterpResult<'tcx, ()> { + unreachable!() + } + + pub(crate) fn handle_thread_join<'tcx>( + &self, + _active_thread_id: ThreadId, + _child_thread_id: ThreadId, + ) -> InterpResult<'tcx, ()> { + unreachable!() + } + + pub(crate) fn handle_thread_stack_empty(&self, _thread_id: ThreadId) { + unreachable!() + } + + pub(crate) fn handle_thread_finish<'tcx>( + &self, + _threads: &ThreadManager<'tcx>, + ) -> InterpResult<'tcx, ()> { + unreachable!() + } + + /**** Scheduling functionality ****/ + + pub(crate) fn schedule_thread<'tcx>( + &self, + _ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, + ) -> InterpResult<'tcx, ThreadId> { + unreachable!() + } + + /**** Blocking instructions ****/ + + pub(crate) fn handle_verifier_assume<'tcx>( + &self, + _machine: &MiriMachine<'tcx>, + _condition: bool, + ) -> InterpResult<'tcx, ()> { + unreachable!() + } +} + +impl VisitProvenance for GenmcCtx { + fn visit_provenance(&self, _visit: &mut VisitWith<'_>) { + unreachable!() + } +} + +impl GenmcConfig { + pub fn parse_arg(_genmc_config: &mut Option, trimmed_arg: &str) { + unimplemented!( + "GenMC feature im Miri is disabled, cannot handle argument: \"-Zmiri-genmc{trimmed_arg}\"" + ); + } + + pub fn should_print_graph(&self, _rep: usize) -> bool { + unreachable!() + } +} diff --git a/src/tools/miri/src/concurrency/genmc/mod.rs b/src/tools/miri/src/concurrency/genmc/mod.rs new file mode 100644 index 000000000000..0dfd4b9b80f9 --- /dev/null +++ b/src/tools/miri/src/concurrency/genmc/mod.rs @@ -0,0 +1,284 @@ +#![allow(unused)] // FIXME(GenMC): remove this + +use std::cell::Cell; + +use rustc_abi::{Align, Size}; +use rustc_const_eval::interpret::{InterpCx, InterpResult, interp_ok}; +use rustc_middle::mir; + +use crate::{ + AtomicFenceOrd, AtomicReadOrd, AtomicRwOrd, AtomicWriteOrd, MemoryKind, MiriConfig, + MiriMachine, Scalar, ThreadId, ThreadManager, VisitProvenance, VisitWith, +}; + +mod config; + +pub use self::config::GenmcConfig; + +// FIXME(GenMC): add fields +pub struct GenmcCtx { + /// Some actions Miri does are allowed to cause data races. + /// GenMC will not be informed about certain actions (e.g. non-atomic loads) when this flag is set. + allow_data_races: Cell, +} + +impl GenmcCtx { + /// Create a new `GenmcCtx` from a given config. + pub fn new(miri_config: &MiriConfig, genmc_config: &GenmcConfig) -> Self { + assert!(miri_config.genmc_mode); + todo!() + } + + pub fn get_stuck_execution_count(&self) -> usize { + todo!() + } + + pub fn print_genmc_graph(&self) { + todo!() + } + + /// This function determines if we should continue exploring executions or if we are done. + /// + /// In GenMC mode, the input program should be repeatedly executed until this function returns `true` or an error is found. + pub fn is_exploration_done(&self) -> bool { + todo!() + } + + /// Inform GenMC that a new program execution has started. + /// This function should be called at the start of every execution. + pub(crate) fn handle_execution_start(&self) { + todo!() + } + + /// Inform GenMC that the program's execution has ended. + /// + /// This function must be called even when the execution got stuck (i.e., it returned a `InterpErrorKind::MachineStop` with error kind `TerminationInfo::GenmcStuckExecution`). + pub(crate) fn handle_execution_end<'tcx>( + &self, + ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, + ) -> Result<(), String> { + todo!() + } + + /**** Memory access handling ****/ + + /// Select whether data race free actions should be allowed. This function should be used carefully! + /// + /// If `true` is passed, allow for data races to happen without triggering an error, until this function is called again with argument `false`. + /// This allows for racy non-atomic memory accesses to be ignored (GenMC is not informed about them at all). + /// + /// Certain operations are not permitted in GenMC mode with data races disabled and will cause a panic, e.g., atomic accesses or asking for scheduling decisions. + /// + /// # Panics + /// If data race free is attempted to be set more than once (i.e., no nesting allowed). + pub(super) fn set_ongoing_action_data_race_free(&self, enable: bool) { + let old = self.allow_data_races.replace(enable); + assert_ne!(old, enable, "cannot nest allow_data_races"); + } + + pub(crate) fn atomic_load<'tcx>( + &self, + ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, + address: Size, + size: Size, + ordering: AtomicReadOrd, + old_val: Option, + ) -> InterpResult<'tcx, Scalar> { + assert!(!self.allow_data_races.get()); + todo!() + } + + pub(crate) fn atomic_store<'tcx>( + &self, + ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, + address: Size, + size: Size, + value: Scalar, + ordering: AtomicWriteOrd, + ) -> InterpResult<'tcx, ()> { + assert!(!self.allow_data_races.get()); + todo!() + } + + pub(crate) fn atomic_fence<'tcx>( + &self, + machine: &MiriMachine<'tcx>, + ordering: AtomicFenceOrd, + ) -> InterpResult<'tcx, ()> { + assert!(!self.allow_data_races.get()); + todo!() + } + + /// Inform GenMC about an atomic read-modify-write operation. + /// + /// Returns `(old_val, new_val)`. + pub(crate) fn atomic_rmw_op<'tcx>( + &self, + ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, + address: Size, + size: Size, + ordering: AtomicRwOrd, + (rmw_op, not): (mir::BinOp, bool), + rhs_scalar: Scalar, + ) -> InterpResult<'tcx, (Scalar, Scalar)> { + assert!(!self.allow_data_races.get()); + todo!() + } + + /// Inform GenMC about an atomic `min` or `max` operation. + /// + /// Returns `(old_val, new_val)`. + pub(crate) fn atomic_min_max_op<'tcx>( + &self, + ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, + address: Size, + size: Size, + ordering: AtomicRwOrd, + min: bool, + is_signed: bool, + rhs_scalar: Scalar, + ) -> InterpResult<'tcx, (Scalar, Scalar)> { + assert!(!self.allow_data_races.get()); + todo!() + } + + pub(crate) fn atomic_exchange<'tcx>( + &self, + ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, + address: Size, + size: Size, + rhs_scalar: Scalar, + ordering: AtomicRwOrd, + ) -> InterpResult<'tcx, (Scalar, bool)> { + assert!(!self.allow_data_races.get()); + todo!() + } + + pub(crate) fn atomic_compare_exchange<'tcx>( + &self, + ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, + address: Size, + size: Size, + expected_old_value: Scalar, + new_value: Scalar, + success: AtomicRwOrd, + fail: AtomicReadOrd, + can_fail_spuriously: bool, + ) -> InterpResult<'tcx, (Scalar, bool)> { + assert!(!self.allow_data_races.get()); + todo!() + } + + /// Inform GenMC about a non-atomic memory load + /// + /// NOTE: Unlike for *atomic* loads, we don't return a value here. Non-atomic values are still handled by Miri. + pub(crate) fn memory_load<'tcx>( + &self, + machine: &MiriMachine<'tcx>, + address: Size, + size: Size, + ) -> InterpResult<'tcx, ()> { + todo!() + } + + pub(crate) fn memory_store<'tcx>( + &self, + machine: &MiriMachine<'tcx>, + address: Size, + size: Size, + ) -> InterpResult<'tcx, ()> { + todo!() + } + + /**** Memory (de)allocation ****/ + + pub(crate) fn handle_alloc<'tcx>( + &self, + machine: &MiriMachine<'tcx>, + size: Size, + alignment: Align, + memory_kind: MemoryKind, + ) -> InterpResult<'tcx, u64> { + todo!() + } + + pub(crate) fn handle_dealloc<'tcx>( + &self, + machine: &MiriMachine<'tcx>, + address: Size, + size: Size, + align: Align, + kind: MemoryKind, + ) -> InterpResult<'tcx, ()> { + todo!() + } + + /**** Thread management ****/ + + pub(crate) fn handle_thread_create<'tcx>( + &self, + threads: &ThreadManager<'tcx>, + new_thread_id: ThreadId, + ) -> InterpResult<'tcx, ()> { + assert!(!self.allow_data_races.get()); + todo!() + } + + pub(crate) fn handle_thread_join<'tcx>( + &self, + active_thread_id: ThreadId, + child_thread_id: ThreadId, + ) -> InterpResult<'tcx, ()> { + assert!(!self.allow_data_races.get()); + todo!() + } + + pub(crate) fn handle_thread_stack_empty(&self, thread_id: ThreadId) { + todo!() + } + + pub(crate) fn handle_thread_finish<'tcx>( + &self, + threads: &ThreadManager<'tcx>, + ) -> InterpResult<'tcx, ()> { + assert!(!self.allow_data_races.get()); + todo!() + } + + /**** Scheduling functionality ****/ + + /// Ask for a scheduling decision. This should be called before every MIR instruction. + /// + /// GenMC may realize that the execution got stuck, then this function will return a `InterpErrorKind::MachineStop` with error kind `TerminationInfo::GenmcStuckExecution`). + /// + /// This is **not** an error by iself! Treat this as if the program ended normally: `handle_execution_end` should be called next, which will determine if were are any actual errors. + pub(crate) fn schedule_thread<'tcx>( + &self, + ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, + ) -> InterpResult<'tcx, ThreadId> { + assert!(!self.allow_data_races.get()); + todo!() + } + + /**** Blocking instructions ****/ + + pub(crate) fn handle_verifier_assume<'tcx>( + &self, + machine: &MiriMachine<'tcx>, + condition: bool, + ) -> InterpResult<'tcx, ()> { + if condition { interp_ok(()) } else { self.handle_user_block(machine) } + } +} + +impl VisitProvenance for GenmcCtx { + fn visit_provenance(&self, _visit: &mut VisitWith<'_>) { + // We don't have any tags. + } +} + +impl GenmcCtx { + fn handle_user_block<'tcx>(&self, machine: &MiriMachine<'tcx>) -> InterpResult<'tcx, ()> { + todo!() + } +} diff --git a/src/tools/miri/src/concurrency/init_once.rs b/src/tools/miri/src/concurrency/init_once.rs index 534f02545bde..c26384f65f6c 100644 --- a/src/tools/miri/src/concurrency/init_once.rs +++ b/src/tools/miri/src/concurrency/init_once.rs @@ -72,7 +72,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { init_once.status = InitOnceStatus::Complete; // Each complete happens-before the end of the wait - if let Some(data_race) = &this.machine.data_race { + if let Some(data_race) = this.machine.data_race.as_vclocks_ref() { data_race .release_clock(&this.machine.threads, |clock| init_once.clock.clone_from(clock)); } @@ -99,7 +99,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { init_once.status = InitOnceStatus::Uninitialized; // Each complete happens-before the end of the wait - if let Some(data_race) = &this.machine.data_race { + if let Some(data_race) = this.machine.data_race.as_vclocks_ref() { data_race .release_clock(&this.machine.threads, |clock| init_once.clock.clone_from(clock)); } diff --git a/src/tools/miri/src/concurrency/mod.rs b/src/tools/miri/src/concurrency/mod.rs index c5082b4e40b4..dd33f90f153d 100644 --- a/src/tools/miri/src/concurrency/mod.rs +++ b/src/tools/miri/src/concurrency/mod.rs @@ -1,5 +1,6 @@ pub mod cpu_affinity; pub mod data_race; +mod data_race_handler; pub mod init_once; mod range_object_map; pub mod sync; @@ -7,4 +8,19 @@ pub mod thread; mod vector_clock; pub mod weak_memory; +// Import either the real genmc adapter or a dummy module. +cfg_match! { + feature = "genmc" => { + mod genmc; + pub use self::genmc::{GenmcCtx, GenmcConfig}; + } + _ => { + #[path = "genmc/dummy.rs"] + mod genmc_dummy; + use self::genmc_dummy as genmc; + pub use self::genmc::{GenmcCtx, GenmcConfig}; + } +} + +pub use self::data_race_handler::{AllocDataRaceHandler, GlobalDataRaceHandler}; pub use self::vector_clock::VClock; diff --git a/src/tools/miri/src/concurrency/sync.rs b/src/tools/miri/src/concurrency/sync.rs index 268268848ed2..64f34d3e21cc 100644 --- a/src/tools/miri/src/concurrency/sync.rs +++ b/src/tools/miri/src/concurrency/sync.rs @@ -361,7 +361,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { mutex.owner = Some(thread); } mutex.lock_count = mutex.lock_count.strict_add(1); - if let Some(data_race) = &this.machine.data_race { + if let Some(data_race) = this.machine.data_race.as_vclocks_ref() { data_race.acquire_clock(&mutex.clock, &this.machine.threads); } } @@ -385,7 +385,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { mutex.owner = None; // The mutex is completely unlocked. Try transferring ownership // to another thread. - if let Some(data_race) = &this.machine.data_race { + + if let Some(data_race) = this.machine.data_race.as_vclocks_ref() { data_race.release_clock(&this.machine.threads, |clock| { mutex.clock.clone_from(clock) }); @@ -477,7 +478,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let rwlock = &mut this.machine.sync.rwlocks[id]; let count = rwlock.readers.entry(thread).or_insert(0); *count = count.strict_add(1); - if let Some(data_race) = &this.machine.data_race { + if let Some(data_race) = this.machine.data_race.as_vclocks_ref() { data_race.acquire_clock(&rwlock.clock_unlocked, &this.machine.threads); } } @@ -502,7 +503,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } Entry::Vacant(_) => return interp_ok(false), // we did not even own this lock } - if let Some(data_race) = &this.machine.data_race { + if let Some(data_race) = this.machine.data_race.as_vclocks_ref() { // Add this to the shared-release clock of all concurrent readers. data_race.release_clock(&this.machine.threads, |clock| { rwlock.clock_current_readers.join(clock) @@ -565,7 +566,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { trace!("rwlock_writer_lock: {:?} now held by {:?}", id, thread); let rwlock = &mut this.machine.sync.rwlocks[id]; rwlock.writer = Some(thread); - if let Some(data_race) = &this.machine.data_race { + if let Some(data_race) = this.machine.data_race.as_vclocks_ref() { data_race.acquire_clock(&rwlock.clock_unlocked, &this.machine.threads); } } @@ -585,7 +586,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { rwlock.writer = None; trace!("rwlock_writer_unlock: {:?} unlocked by {:?}", id, thread); // Record release clock for next lock holder. - if let Some(data_race) = &this.machine.data_race { + if let Some(data_race) = this.machine.data_race.as_vclocks_ref() { data_race.release_clock(&this.machine.threads, |clock| { rwlock.clock_unlocked.clone_from(clock) }); @@ -691,7 +692,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { match unblock { UnblockKind::Ready => { // The condvar was signaled. Make sure we get the clock for that. - if let Some(data_race) = &this.machine.data_race { + if let Some(data_race) = this.machine.data_race.as_vclocks_ref() { data_race.acquire_clock( &this.machine.sync.condvars[condvar].clock, &this.machine.threads, @@ -721,10 +722,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn condvar_signal(&mut self, id: CondvarId) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); let condvar = &mut this.machine.sync.condvars[id]; - let data_race = &this.machine.data_race; // Each condvar signal happens-before the end of the condvar wake - if let Some(data_race) = data_race { + if let Some(data_race) = this.machine.data_race.as_vclocks_ref() { data_race.release_clock(&this.machine.threads, |clock| condvar.clock.clone_from(clock)); } let Some(waiter) = condvar.waiters.pop_front() else { @@ -764,7 +764,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { UnblockKind::Ready => { let futex = futex_ref.0.borrow(); // Acquire the clock of the futex. - if let Some(data_race) = &this.machine.data_race { + if let Some(data_race) = this.machine.data_race.as_vclocks_ref() { data_race.acquire_clock(&futex.clock, &this.machine.threads); } }, @@ -792,10 +792,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { ) -> InterpResult<'tcx, usize> { let this = self.eval_context_mut(); let mut futex = futex_ref.0.borrow_mut(); - let data_race = &this.machine.data_race; // Each futex-wake happens-before the end of the futex wait - if let Some(data_race) = data_race { + if let Some(data_race) = this.machine.data_race.as_vclocks_ref() { data_race.release_clock(&this.machine.threads, |clock| futex.clock.clone_from(clock)); } diff --git a/src/tools/miri/src/concurrency/thread.rs b/src/tools/miri/src/concurrency/thread.rs index 72fa918e8e51..8aa65e6cb612 100644 --- a/src/tools/miri/src/concurrency/thread.rs +++ b/src/tools/miri/src/concurrency/thread.rs @@ -6,6 +6,7 @@ use std::task::Poll; use std::time::{Duration, SystemTime}; use either::Either; +use rand::seq::IteratorRandom; use rustc_abi::ExternAbi; use rustc_const_eval::CTRL_C_RECEIVED; use rustc_data_structures::fx::FxHashMap; @@ -15,7 +16,7 @@ use rustc_middle::mir::Mutability; use rustc_middle::ty::layout::TyAndLayout; use rustc_span::Span; -use crate::concurrency::data_race; +use crate::concurrency::GlobalDataRaceHandler; use crate::shims::tls; use crate::*; @@ -401,6 +402,8 @@ pub struct ThreadManager<'tcx> { thread_local_allocs: FxHashMap<(DefId, ThreadId), StrictPointer>, /// A flag that indicates that we should change the active thread. yield_active_thread: bool, + /// A flag that indicates that we should do round robin scheduling of threads else randomized scheduling is used. + fixed_scheduling: bool, } impl VisitProvenance for ThreadManager<'_> { @@ -410,6 +413,7 @@ impl VisitProvenance for ThreadManager<'_> { thread_local_allocs, active_thread: _, yield_active_thread: _, + fixed_scheduling: _, } = self; for thread in threads { @@ -421,8 +425,8 @@ impl VisitProvenance for ThreadManager<'_> { } } -impl<'tcx> Default for ThreadManager<'tcx> { - fn default() -> Self { +impl<'tcx> ThreadManager<'tcx> { + pub(crate) fn new(config: &MiriConfig) -> Self { let mut threads = IndexVec::new(); // Create the main thread and add it to the list of threads. threads.push(Thread::new(Some("main"), None)); @@ -431,11 +435,10 @@ impl<'tcx> Default for ThreadManager<'tcx> { threads, thread_local_allocs: Default::default(), yield_active_thread: false, + fixed_scheduling: config.fixed_scheduling, } } -} -impl<'tcx> ThreadManager<'tcx> { pub(crate) fn init( ecx: &mut MiriInterpCx<'tcx>, on_main_stack_empty: StackEmptyCallback<'tcx>, @@ -580,13 +583,28 @@ impl<'tcx> ThreadManager<'tcx> { fn join_thread( &mut self, joined_thread_id: ThreadId, - data_race: Option<&mut data_race::GlobalState>, + data_race_handler: &mut GlobalDataRaceHandler, ) -> InterpResult<'tcx> { if self.threads[joined_thread_id].join_status == ThreadJoinStatus::Detached { // On Windows this corresponds to joining on a closed handle. throw_ub_format!("trying to join a detached thread"); } + fn after_join<'tcx>( + threads: &mut ThreadManager<'_>, + joined_thread_id: ThreadId, + data_race_handler: &mut GlobalDataRaceHandler, + ) -> InterpResult<'tcx> { + match data_race_handler { + GlobalDataRaceHandler::None => {} + GlobalDataRaceHandler::Vclocks(data_race) => + data_race.thread_joined(threads, joined_thread_id), + GlobalDataRaceHandler::Genmc(genmc_ctx) => + genmc_ctx.handle_thread_join(threads.active_thread, joined_thread_id)?, + } + interp_ok(()) + } + // Mark the joined thread as being joined so that we detect if other // threads try to join it. self.threads[joined_thread_id].join_status = ThreadJoinStatus::Joined; @@ -606,18 +624,13 @@ impl<'tcx> ThreadManager<'tcx> { } |this, unblock: UnblockKind| { assert_eq!(unblock, UnblockKind::Ready); - if let Some(data_race) = &mut this.machine.data_race { - data_race.thread_joined(&this.machine.threads, joined_thread_id); - } - interp_ok(()) + after_join(&mut this.machine.threads, joined_thread_id, &mut this.machine.data_race) } ), ); } else { // The thread has already terminated - establish happens-before - if let Some(data_race) = data_race { - data_race.thread_joined(self, joined_thread_id); - } + after_join(self, joined_thread_id, data_race_handler)?; } interp_ok(()) } @@ -627,7 +640,7 @@ impl<'tcx> ThreadManager<'tcx> { fn join_thread_exclusive( &mut self, joined_thread_id: ThreadId, - data_race: Option<&mut data_race::GlobalState>, + data_race_handler: &mut GlobalDataRaceHandler, ) -> InterpResult<'tcx> { if self.threads[joined_thread_id].join_status == ThreadJoinStatus::Joined { throw_ub_format!("trying to join an already joined thread"); @@ -645,7 +658,7 @@ impl<'tcx> ThreadManager<'tcx> { "this thread already has threads waiting for its termination" ); - self.join_thread(joined_thread_id, data_race) + self.join_thread(joined_thread_id, data_race_handler) } /// Set the name of the given thread. @@ -695,70 +708,6 @@ impl<'tcx> ThreadManager<'tcx> { }) .min() } - - /// Decide which action to take next and on which thread. - /// - /// The currently implemented scheduling policy is the one that is commonly - /// used in stateless model checkers such as Loom: run the active thread as - /// long as we can and switch only when we have to (the active thread was - /// blocked, terminated, or has explicitly asked to be preempted). - fn schedule(&mut self, clock: &MonotonicClock) -> InterpResult<'tcx, SchedulingAction> { - // This thread and the program can keep going. - if self.threads[self.active_thread].state.is_enabled() && !self.yield_active_thread { - // The currently active thread is still enabled, just continue with it. - return interp_ok(SchedulingAction::ExecuteStep); - } - // The active thread yielded or got terminated. Let's see if there are any timeouts to take - // care of. We do this *before* running any other thread, to ensure that timeouts "in the - // past" fire before any other thread can take an action. This ensures that for - // `pthread_cond_timedwait`, "an error is returned if [...] the absolute time specified by - // abstime has already been passed at the time of the call". - // - let potential_sleep_time = self.next_callback_wait_time(clock); - if potential_sleep_time == Some(Duration::ZERO) { - return interp_ok(SchedulingAction::ExecuteTimeoutCallback); - } - // No callbacks immediately scheduled, pick a regular thread to execute. - // The active thread blocked or yielded. So we go search for another enabled thread. - // Crucially, we start searching at the current active thread ID, rather than at 0, since we - // want to avoid always scheduling threads 0 and 1 without ever making progress in thread 2. - // - // `skip(N)` means we start iterating at thread N, so we skip 1 more to start just *after* - // the active thread. Then after that we look at `take(N)`, i.e., the threads *before* the - // active thread. - let threads = self - .threads - .iter_enumerated() - .skip(self.active_thread.index() + 1) - .chain(self.threads.iter_enumerated().take(self.active_thread.index())); - for (id, thread) in threads { - debug_assert_ne!(self.active_thread, id); - if thread.state.is_enabled() { - info!( - "---------- Now executing on thread `{}` (previous: `{}`) ----------------------------------------", - self.get_thread_display_name(id), - self.get_thread_display_name(self.active_thread) - ); - self.active_thread = id; - break; - } - } - self.yield_active_thread = false; - if self.threads[self.active_thread].state.is_enabled() { - return interp_ok(SchedulingAction::ExecuteStep); - } - // We have not found a thread to execute. - if self.threads.iter().all(|thread| thread.state.is_terminated()) { - unreachable!("all threads terminated without the main thread terminating?!"); - } else if let Some(sleep_time) = potential_sleep_time { - // All threads are currently blocked, but we have unexecuted - // timeout_callbacks, which may unblock some of the threads. Hence, - // sleep until the first callback. - interp_ok(SchedulingAction::Sleep(sleep_time)) - } else { - throw_machine_stop!(TerminationInfo::Deadlock); - } - } } impl<'tcx> EvalContextPrivExt<'tcx> for MiriInterpCx<'tcx> {} @@ -806,6 +755,11 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { #[inline] fn run_on_stack_empty(&mut self) -> InterpResult<'tcx, Poll<()>> { let this = self.eval_context_mut(); + // Inform GenMC that a thread has finished all user code. GenMC needs to know this for scheduling. + if let Some(genmc_ctx) = this.machine.data_race.as_genmc_ref() { + let thread_id = this.active_thread(); + genmc_ctx.handle_thread_stack_empty(thread_id); + } let mut callback = this .active_thread_mut() .on_stack_empty @@ -815,6 +769,102 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { this.active_thread_mut().on_stack_empty = Some(callback); interp_ok(res) } + + /// Decide which action to take next and on which thread. + /// + /// The currently implemented scheduling policy is the one that is commonly + /// used in stateless model checkers such as Loom: run the active thread as + /// long as we can and switch only when we have to (the active thread was + /// blocked, terminated, or has explicitly asked to be preempted). + /// + /// If GenMC mode is active, the scheduling is instead handled by GenMC. + fn schedule(&mut self) -> InterpResult<'tcx, SchedulingAction> { + let this = self.eval_context_mut(); + // In GenMC mode, we let GenMC do the scheduling + if let Some(genmc_ctx) = this.machine.data_race.as_genmc_ref() { + let next_thread_id = genmc_ctx.schedule_thread(this)?; + + let thread_manager = &mut this.machine.threads; + thread_manager.active_thread = next_thread_id; + thread_manager.yield_active_thread = false; + + assert!(thread_manager.threads[thread_manager.active_thread].state.is_enabled()); + return interp_ok(SchedulingAction::ExecuteStep); + } + + // We are not in GenMC mode, so we control the schedule + let thread_manager = &mut this.machine.threads; + let clock = &this.machine.monotonic_clock; + let rng = this.machine.rng.get_mut(); + // This thread and the program can keep going. + if thread_manager.threads[thread_manager.active_thread].state.is_enabled() + && !thread_manager.yield_active_thread + { + // The currently active thread is still enabled, just continue with it. + return interp_ok(SchedulingAction::ExecuteStep); + } + // The active thread yielded or got terminated. Let's see if there are any timeouts to take + // care of. We do this *before* running any other thread, to ensure that timeouts "in the + // past" fire before any other thread can take an action. This ensures that for + // `pthread_cond_timedwait`, "an error is returned if [...] the absolute time specified by + // abstime has already been passed at the time of the call". + // + let potential_sleep_time = thread_manager.next_callback_wait_time(clock); + if potential_sleep_time == Some(Duration::ZERO) { + return interp_ok(SchedulingAction::ExecuteTimeoutCallback); + } + // No callbacks immediately scheduled, pick a regular thread to execute. + // The active thread blocked or yielded. So we go search for another enabled thread. + // We build the list of threads by starting with the threads after the current one, followed by + // the threads before the current one and then the current thread itself (i.e., this iterator acts + // like `threads.rotate_left(self.active_thread.index() + 1)`. This ensures that if we pick the first + // eligible thread, we do regular round-robin scheduling, and all threads get a chance to take a step. + let mut threads_iter = thread_manager + .threads + .iter_enumerated() + .skip(thread_manager.active_thread.index() + 1) + .chain( + thread_manager + .threads + .iter_enumerated() + .take(thread_manager.active_thread.index() + 1), + ) + .filter(|(_id, thread)| thread.state.is_enabled()); + // Pick a new thread, and switch to it. + let new_thread = if thread_manager.fixed_scheduling { + threads_iter.next() + } else { + threads_iter.choose(rng) + }; + + if let Some((id, _thread)) = new_thread { + if thread_manager.active_thread != id { + info!( + "---------- Now executing on thread `{}` (previous: `{}`) ----------------------------------------", + thread_manager.get_thread_display_name(id), + thread_manager.get_thread_display_name(thread_manager.active_thread) + ); + thread_manager.active_thread = id; + } + } + // This completes the `yield`, if any was requested. + thread_manager.yield_active_thread = false; + + if thread_manager.threads[thread_manager.active_thread].state.is_enabled() { + return interp_ok(SchedulingAction::ExecuteStep); + } + // We have not found a thread to execute. + if thread_manager.threads.iter().all(|thread| thread.state.is_terminated()) { + unreachable!("all threads terminated without the main thread terminating?!"); + } else if let Some(sleep_time) = potential_sleep_time { + // All threads are currently blocked, but we have unexecuted + // timeout_callbacks, which may unblock some of the threads. Hence, + // sleep until the first callback. + interp_ok(SchedulingAction::Sleep(sleep_time)) + } else { + throw_machine_stop!(TerminationInfo::Deadlock); + } + } } // Public interface to thread management. @@ -880,10 +930,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Box::new(move |m| state.on_stack_empty(m)) }); let current_span = this.machine.current_span(); - if let Some(data_race) = &mut this.machine.data_race { - data_race.thread_created(&this.machine.threads, new_thread_id, current_span); + match &mut this.machine.data_race { + GlobalDataRaceHandler::None => {} + GlobalDataRaceHandler::Vclocks(data_race) => + data_race.thread_created(&this.machine.threads, new_thread_id, current_span), + GlobalDataRaceHandler::Genmc(genmc_ctx) => + genmc_ctx.handle_thread_create(&this.machine.threads, new_thread_id)?, } - // Write the current thread-id, switch to the next thread later // to treat this write operation as occurring on the current thread. if let Some(thread_info_place) = thread { @@ -930,12 +983,17 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// This is called by the eval loop when a thread's on_stack_empty returns `Ready`. fn terminate_active_thread(&mut self, tls_alloc_action: TlsAllocAction) -> InterpResult<'tcx> { let this = self.eval_context_mut(); + // Mark thread as terminated. let thread = this.active_thread_mut(); assert!(thread.stack.is_empty(), "only threads with an empty stack can be terminated"); thread.state = ThreadState::Terminated; - if let Some(ref mut data_race) = this.machine.data_race { - data_race.thread_terminated(&this.machine.threads); + match &mut this.machine.data_race { + GlobalDataRaceHandler::None => {} + GlobalDataRaceHandler::Vclocks(data_race) => + data_race.thread_terminated(&this.machine.threads), + GlobalDataRaceHandler::Genmc(genmc_ctx) => + genmc_ctx.handle_thread_finish(&this.machine.threads)?, } // Deallocate TLS. let gone_thread = this.active_thread(); @@ -1051,7 +1109,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { #[inline] fn join_thread(&mut self, joined_thread_id: ThreadId) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - this.machine.threads.join_thread(joined_thread_id, this.machine.data_race.as_mut())?; + this.machine.threads.join_thread(joined_thread_id, &mut this.machine.data_race)?; interp_ok(()) } @@ -1060,7 +1118,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let this = self.eval_context_mut(); this.machine .threads - .join_thread_exclusive(joined_thread_id, this.machine.data_race.as_mut())?; + .join_thread_exclusive(joined_thread_id, &mut this.machine.data_race)?; interp_ok(()) } @@ -1138,7 +1196,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { use rand::Rng as _; let this = self.eval_context_mut(); - if this.machine.rng.get_mut().random_bool(this.machine.preemption_rate) { + if !this.machine.threads.fixed_scheduling + && this.machine.rng.get_mut().random_bool(this.machine.preemption_rate) + { this.yield_active_thread(); } } @@ -1152,7 +1212,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.machine.handle_abnormal_termination(); throw_machine_stop!(TerminationInfo::Interrupted); } - match this.machine.threads.schedule(&this.machine.monotonic_clock)? { + match this.schedule()? { SchedulingAction::ExecuteStep => { if !this.step()? { // See if this thread can do something else. diff --git a/src/tools/miri/src/concurrency/vector_clock.rs b/src/tools/miri/src/concurrency/vector_clock.rs index 345726634299..78858fcedaec 100644 --- a/src/tools/miri/src/concurrency/vector_clock.rs +++ b/src/tools/miri/src/concurrency/vector_clock.rs @@ -40,8 +40,8 @@ impl From for VectorIdx { } } -/// The size of the vector-clock to store inline -/// clock vectors larger than this will be stored on the heap +/// The size of the vector clock to store inline. +/// Clock vectors larger than this will be stored on the heap. const SMALL_VECTOR: usize = 4; /// The time-stamps recorded in the data-race detector consist of both @@ -136,7 +136,7 @@ impl Ord for VTimestamp { pub struct VClock(SmallVec<[VTimestamp; SMALL_VECTOR]>); impl VClock { - /// Create a new vector-clock containing all zeros except + /// Create a new vector clock containing all zeros except /// for a value at the given index pub(super) fn new_with_index(index: VectorIdx, timestamp: VTimestamp) -> VClock { if timestamp.time() == 0 { @@ -185,8 +185,8 @@ impl VClock { } } - // Join the two vector-clocks together, this - // sets each vector-element to the maximum value + // Join the two vector clocks together, this + // sets each vector element to the maximum value // of that element in either of the two source elements. pub fn join(&mut self, other: &Self) { let rhs_slice = other.as_slice(); diff --git a/src/tools/miri/src/concurrency/weak_memory.rs b/src/tools/miri/src/concurrency/weak_memory.rs index 1a3e9614f8af..95c010be2fd2 100644 --- a/src/tools/miri/src/concurrency/weak_memory.rs +++ b/src/tools/miri/src/concurrency/weak_memory.rs @@ -77,7 +77,7 @@ // (https://github.com/ChrisLidbury/tsan11/blob/ecbd6b81e9b9454e01cba78eb9d88684168132c7/lib/tsan/rtl/tsan_relaxed.cc#L160-L167) // and here. // -// 4. W_SC ; R_SC case requires the SC load to ignore all but last store maked SC (stores not marked SC are not +// 4. W_SC ; R_SC case requires the SC load to ignore all but last store marked SC (stores not marked SC are not // affected). But this rule is applied to all loads in ReadsFromSet from the paper (last two lines of code), not just SC load. // This is implemented correctly in tsan11 // (https://github.com/ChrisLidbury/tsan11/blob/ecbd6b81e9b9454e01cba78eb9d88684168132c7/lib/tsan/rtl/tsan_relaxed.cc#L295) @@ -88,9 +88,11 @@ use std::collections::VecDeque; use rustc_data_structures::fx::FxHashMap; +use super::AllocDataRaceHandler; use super::data_race::{GlobalState as DataRaceState, ThreadClockSet}; use super::range_object_map::{AccessType, RangeObjectMap}; use super::vector_clock::{VClock, VTimestamp, VectorIdx}; +use crate::concurrency::GlobalDataRaceHandler; use crate::*; pub type AllocState = StoreBufferAlloc; @@ -459,8 +461,13 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let this = self.eval_context_mut(); let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr(), 0)?; if let ( - crate::AllocExtra { weak_memory: Some(alloc_buffers), .. }, - crate::MiriMachine { data_race: Some(global), threads, .. }, + crate::AllocExtra { + data_race: AllocDataRaceHandler::Vclocks(_, Some(alloc_buffers)), + .. + }, + crate::MiriMachine { + data_race: GlobalDataRaceHandler::Vclocks(global), threads, .. + }, ) = this.get_alloc_extra_mut(alloc_id)? { if atomic == AtomicRwOrd::SeqCst { @@ -484,9 +491,11 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { ) -> InterpResult<'tcx, Option> { let this = self.eval_context_ref(); 'fallback: { - if let Some(global) = &this.machine.data_race { + if let Some(global) = this.machine.data_race.as_vclocks_ref() { let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr(), 0)?; - if let Some(alloc_buffers) = this.get_alloc_extra(alloc_id)?.weak_memory.as_ref() { + if let Some(alloc_buffers) = + this.get_alloc_extra(alloc_id)?.data_race.as_weak_memory_ref() + { if atomic == AtomicReadOrd::SeqCst { global.sc_read(&this.machine.threads); } @@ -534,8 +543,13 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let this = self.eval_context_mut(); let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(dest.ptr(), 0)?; if let ( - crate::AllocExtra { weak_memory: Some(alloc_buffers), .. }, - crate::MiriMachine { data_race: Some(global), threads, .. }, + crate::AllocExtra { + data_race: AllocDataRaceHandler::Vclocks(_, Some(alloc_buffers)), + .. + }, + crate::MiriMachine { + data_race: GlobalDataRaceHandler::Vclocks(global), threads, .. + }, ) = this.get_alloc_extra_mut(alloc_id)? { if atomic == AtomicWriteOrd::SeqCst { @@ -561,13 +575,15 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { ) -> InterpResult<'tcx> { let this = self.eval_context_ref(); - if let Some(global) = &this.machine.data_race { + if let Some(global) = this.machine.data_race.as_vclocks_ref() { if atomic == AtomicReadOrd::SeqCst { global.sc_read(&this.machine.threads); } let size = place.layout.size; let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr(), 0)?; - if let Some(alloc_buffers) = this.get_alloc_extra(alloc_id)?.weak_memory.as_ref() { + if let Some(alloc_buffers) = + this.get_alloc_extra(alloc_id)?.data_race.as_weak_memory_ref() + { let Some(buffer) = alloc_buffers.get_store_buffer(alloc_range(base_offset, size))? else { diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs index 014b1299f2dd..89768077d878 100644 --- a/src/tools/miri/src/diagnostics.rs +++ b/src/tools/miri/src/diagnostics.rs @@ -31,6 +31,8 @@ pub enum TerminationInfo { }, Int2PtrWithStrictProvenance, Deadlock, + /// In GenMC mode, an execution can get stuck in certain cases. This is not an error. + GenmcStuckExecution, MultipleSymbolDefinitions { link_name: Symbol, first: SpanData, @@ -75,6 +77,7 @@ impl fmt::Display for TerminationInfo { StackedBorrowsUb { msg, .. } => write!(f, "{msg}"), TreeBorrowsUb { title, .. } => write!(f, "{title}"), Deadlock => write!(f, "the evaluated program deadlocked"), + GenmcStuckExecution => write!(f, "GenMC determined that the execution got stuck"), MultipleSymbolDefinitions { link_name, .. } => write!(f, "multiple definitions of symbol `{link_name}`"), SymbolShimClashing { link_name, .. } => @@ -235,6 +238,12 @@ pub fn report_error<'tcx>( StackedBorrowsUb { .. } | TreeBorrowsUb { .. } | DataRace { .. } => Some("Undefined Behavior"), Deadlock => Some("deadlock"), + GenmcStuckExecution => { + // This case should only happen in GenMC mode. We treat it like a normal program exit. + assert!(ecx.machine.data_race.as_genmc_ref().is_some()); + tracing::info!("GenMC: found stuck execution"); + return Some((0, true)); + } MultipleSymbolDefinitions { .. } | SymbolShimClashing { .. } => None, }; #[rustfmt::skip] diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs index 7586b5efd4b2..bb5e5d7ee814 100644 --- a/src/tools/miri/src/eval.rs +++ b/src/tools/miri/src/eval.rs @@ -3,6 +3,7 @@ use std::ffi::{OsStr, OsString}; use std::panic::{self, AssertUnwindSafe}; use std::path::PathBuf; +use std::rc::Rc; use std::task::Poll; use std::{iter, thread}; @@ -14,6 +15,7 @@ use rustc_middle::ty::layout::{LayoutCx, LayoutOf}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::config::EntryFnType; +use crate::concurrency::GenmcCtx; use crate::concurrency::thread::TlsAllocAction; use crate::diagnostics::report_leaks; use crate::shims::tls; @@ -99,10 +101,6 @@ pub struct MiriConfig { pub validation: ValidationMode, /// Determines if Stacked Borrows or Tree Borrows is enabled. pub borrow_tracker: Option, - /// Whether `core::ptr::Unique` receives special treatment. - /// If `true` then `Unique` is reborrowed with its own new tag and permission, - /// otherwise `Unique` is just another raw pointer. - pub unique_is_unique: bool, /// Controls alignment checking. pub check_alignment: AlignmentCheck, /// Action for an op requiring communication with the host. @@ -117,16 +115,18 @@ pub struct MiriConfig { pub args: Vec, /// The seed to use when non-determinism or randomness are required (e.g. ptr-to-int cast, `getrandom()`). pub seed: Option, - /// The stacked borrows pointer ids to report about + /// The stacked borrows pointer ids to report about. pub tracked_pointer_tags: FxHashSet, /// The allocation ids to report about. pub tracked_alloc_ids: FxHashSet, /// For the tracked alloc ids, also report read/write accesses. pub track_alloc_accesses: bool, - /// Determine if data race detection should be enabled + /// Determine if data race detection should be enabled. pub data_race_detector: bool, - /// Determine if weak memory emulation should be enabled. Requires data race detection to be enabled + /// Determine if weak memory emulation should be enabled. Requires data race detection to be enabled. pub weak_memory_emulation: bool, + /// Determine if we are running in GenMC mode. In this mode, Miri will explore multiple concurrent executions of the given program. + pub genmc_mode: bool, /// Track when an outdated (weak memory) load happens. pub track_outdated_loads: bool, /// Rate of spurious failures for compare_exchange_weak atomic operations, @@ -137,7 +137,7 @@ pub struct MiriConfig { pub measureme_out: Option, /// Which style to use for printing backtraces. pub backtrace_style: BacktraceStyle, - /// Which provenance to use for int2ptr casts + /// Which provenance to use for int2ptr casts. pub provenance_mode: ProvenanceMode, /// Whether to ignore any output by the program. This is helpful when debugging miri /// as its messages don't get intermingled with the program messages. @@ -155,7 +155,7 @@ pub struct MiriConfig { pub gc_interval: u32, /// The number of CPUs to be reported by miri. pub num_cpus: u32, - /// Requires Miri to emulate pages of a certain size + /// Requires Miri to emulate pages of a certain size. pub page_size: Option, /// Whether to collect a backtrace when each allocation is created, just in case it leaks. pub collect_leak_backtraces: bool, @@ -163,6 +163,8 @@ pub struct MiriConfig { pub address_reuse_rate: f64, /// Probability for address reuse across threads. pub address_reuse_cross_thread_rate: f64, + /// Round Robin scheduling with no preemption. + pub fixed_scheduling: bool, } impl Default for MiriConfig { @@ -171,7 +173,6 @@ impl Default for MiriConfig { env: vec![], validation: ValidationMode::Shallow, borrow_tracker: Some(BorrowTrackerMethod::StackedBorrows), - unique_is_unique: false, check_alignment: AlignmentCheck::Int, isolated_op: IsolatedOp::Reject(RejectOpWith::Abort), ignore_leaks: false, @@ -184,6 +185,7 @@ impl Default for MiriConfig { track_alloc_accesses: false, data_race_detector: true, weak_memory_emulation: true, + genmc_mode: false, track_outdated_loads: false, cmpxchg_weak_failure_rate: 0.8, // 80% measureme_out: None, @@ -200,6 +202,7 @@ impl Default for MiriConfig { collect_leak_backtraces: true, address_reuse_rate: 0.5, address_reuse_cross_thread_rate: 0.1, + fixed_scheduling: false, } } } @@ -230,16 +233,22 @@ impl<'tcx> MainThreadState<'tcx> { match state.on_stack_empty(this)? { Poll::Pending => {} // just keep going Poll::Ready(()) => { - // Give background threads a chance to finish by yielding the main thread a - // couple of times -- but only if we would also preempt threads randomly. - if this.machine.preemption_rate > 0.0 { - // There is a non-zero chance they will yield back to us often enough to - // make Miri terminate eventually. - *self = Yield { remaining: MAIN_THREAD_YIELDS_AT_SHUTDOWN }; - } else { - // The other threads did not get preempted, so no need to yield back to - // them. + if this.machine.data_race.as_genmc_ref().is_some() { + // In GenMC mode, we don't yield at the end of the main thread. + // Instead, the `GenmcCtx` will ensure that unfinished threads get a chance to run at this point. *self = Done; + } else { + // Give background threads a chance to finish by yielding the main thread a + // couple of times -- but only if we would also preempt threads randomly. + if this.machine.preemption_rate > 0.0 { + // There is a non-zero chance they will yield back to us often enough to + // make Miri terminate eventually. + *self = Yield { remaining: MAIN_THREAD_YIELDS_AT_SHUTDOWN }; + } else { + // The other threads did not get preempted, so no need to yield back to + // them. + *self = Done; + } } } }, @@ -265,6 +274,17 @@ impl<'tcx> MainThreadState<'tcx> { // Deal with our thread-local memory. We do *not* want to actually free it, instead we consider TLS // to be like a global `static`, so that all memory reached by it is considered to "not leak". this.terminate_active_thread(TlsAllocAction::Leak)?; + + // Machine cleanup. Only do this if all threads have terminated; threads that are still running + // might cause Stacked Borrows errors (https://github.com/rust-lang/miri/issues/2396). + if this.have_all_terminated() { + // Even if all threads have terminated, we have to beware of data races since some threads + // might not have joined the main thread (https://github.com/rust-lang/miri/issues/2020, + // https://github.com/rust-lang/miri/issues/2508). + this.allow_data_races_all_threads_done(); + EnvVars::cleanup(this).expect("error during env var cleanup"); + } + // Stop interpreter loop. throw_machine_stop!(TerminationInfo::Exit { code: exit_code, leak_check: true }); } @@ -280,11 +300,16 @@ pub fn create_ecx<'tcx>( entry_id: DefId, entry_type: MiriEntryFnType, config: &MiriConfig, + genmc_ctx: Option>, ) -> InterpResult<'tcx, InterpCx<'tcx, MiriMachine<'tcx>>> { let typing_env = ty::TypingEnv::fully_monomorphized(); let layout_cx = LayoutCx::new(tcx, typing_env); - let mut ecx = - InterpCx::new(tcx, rustc_span::DUMMY_SP, typing_env, MiriMachine::new(config, layout_cx)); + let mut ecx = InterpCx::new( + tcx, + rustc_span::DUMMY_SP, + typing_env, + MiriMachine::new(config, layout_cx, genmc_ctx), + ); // Some parts of initialization require a full `InterpCx`. MiriMachine::late_init(&mut ecx, config, { @@ -438,12 +463,17 @@ pub fn eval_entry<'tcx>( tcx: TyCtxt<'tcx>, entry_id: DefId, entry_type: MiriEntryFnType, - config: MiriConfig, + config: &MiriConfig, + genmc_ctx: Option>, ) -> Option { // Copy setting before we move `config`. let ignore_leaks = config.ignore_leaks; - let mut ecx = match create_ecx(tcx, entry_id, entry_type, &config).report_err() { + if let Some(genmc_ctx) = &genmc_ctx { + genmc_ctx.handle_execution_start(); + } + + let mut ecx = match create_ecx(tcx, entry_id, entry_type, config, genmc_ctx).report_err() { Ok(v) => v, Err(err) => { let (kind, backtrace) = err.into_parts(); @@ -462,21 +492,21 @@ pub fn eval_entry<'tcx>( // `Ok` can never happen; the interpreter loop always exits with an "error" // (but that "error" might be just "regular program termination"). let Err(err) = res.report_err(); + // Show diagnostic, if any. let (return_code, leak_check) = report_error(&ecx, err)?; - // If we get here there was no fatal error. - - // Machine cleanup. Only do this if all threads have terminated; threads that are still running - // might cause Stacked Borrows errors (https://github.com/rust-lang/miri/issues/2396). - if ecx.have_all_terminated() { - // Even if all threads have terminated, we have to beware of data races since some threads - // might not have joined the main thread (https://github.com/rust-lang/miri/issues/2020, - // https://github.com/rust-lang/miri/issues/2508). - ecx.allow_data_races_all_threads_done(); - EnvVars::cleanup(&mut ecx).expect("error during env var cleanup"); + // We inform GenMC that the execution is complete. + if let Some(genmc_ctx) = ecx.machine.data_race.as_genmc_ref() + && let Err(error) = genmc_ctx.handle_execution_end(&ecx) + { + // FIXME(GenMC): Improve error reporting. + tcx.dcx().err(format!("GenMC returned an error: \"{error}\"")); + return None; } + // If we get here there was no fatal error. + // Possibly check for memory leaks. if leak_check && !ignore_leaks { // Check for thread leaks. diff --git a/src/tools/miri/src/intrinsics/atomic.rs b/src/tools/miri/src/intrinsics/atomic.rs index dcafa7b6cabe..2eb8086f578f 100644 --- a/src/tools/miri/src/intrinsics/atomic.rs +++ b/src/tools/miri/src/intrinsics/atomic.rs @@ -149,7 +149,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { // Perform regular load. let val = this.read_scalar(val)?; - // Perform atomic store + // Perform atomic store. this.write_scalar_atomic(val, &place, atomic)?; interp_ok(()) } @@ -161,7 +161,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { ) -> InterpResult<'tcx> { let [] = check_intrinsic_arg_count(args)?; let _ = atomic; - //FIXME: compiler fences are currently ignored + // FIXME, FIXME(GenMC): compiler fences are currently ignored (also ignored in GenMC mode) interp_ok(()) } @@ -199,23 +199,16 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { span_bug!(this.cur_span(), "atomic arithmetic operation type mismatch"); } - match atomic_op { - AtomicOp::Min => { - let old = this.atomic_min_max_scalar(&place, rhs, true, atomic)?; - this.write_immediate(*old, dest)?; // old value is returned - interp_ok(()) - } - AtomicOp::Max => { - let old = this.atomic_min_max_scalar(&place, rhs, false, atomic)?; - this.write_immediate(*old, dest)?; // old value is returned - interp_ok(()) - } - AtomicOp::MirOp(op, not) => { - let old = this.atomic_rmw_op_immediate(&place, &rhs, op, not, atomic)?; - this.write_immediate(*old, dest)?; // old value is returned - interp_ok(()) - } - } + let old = match atomic_op { + AtomicOp::Min => + this.atomic_min_max_scalar(&place, rhs, /* min */ true, atomic)?, + AtomicOp::Max => + this.atomic_min_max_scalar(&place, rhs, /* min */ false, atomic)?, + AtomicOp::MirOp(op, not) => + this.atomic_rmw_op_immediate(&place, &rhs, op, not, atomic)?, + }; + this.write_immediate(*old, dest)?; // old value is returned + interp_ok(()) } fn atomic_exchange( diff --git a/src/tools/miri/src/intrinsics/simd.rs b/src/tools/miri/src/intrinsics/simd.rs index de5da6ec898a..c9250ba1b818 100644 --- a/src/tools/miri/src/intrinsics/simd.rs +++ b/src/tools/miri/src/intrinsics/simd.rs @@ -506,7 +506,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { }; let dest_len = u32::try_from(dest_len).unwrap(); - let bitmask_len = u32::try_from(bitmask_len).unwrap(); for i in 0..dest_len { let bit_i = simd_bitmask_index(i, dest_len, this.data_layout().endian); let mask = mask & 1u64.strict_shl(bit_i); @@ -517,17 +516,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let val = if mask != 0 { yes } else { no }; this.write_immediate(*val, &dest)?; } - for i in dest_len..bitmask_len { - // If the mask is "padded", ensure that padding is all-zero. - // This deliberately does not use `simd_bitmask_index`; these bits are outside - // the bitmask. It does not matter in which order we check them. - let mask = mask & 1u64.strict_shl(i); - if mask != 0 { - throw_ub_format!( - "a SIMD bitmask less than 8 bits long must be filled with 0s for the remaining bits" - ); - } - } + // The remaining bits of the mask are ignored. } // Converts a "vector of bool" into a bitmask. "bitmask" => { diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs index e03611e9b509..58b93ae82a1e 100644 --- a/src/tools/miri/src/lib.rs +++ b/src/tools/miri/src/lib.rs @@ -133,6 +133,7 @@ pub use crate::concurrency::thread::{ BlockReason, DynUnblockCallback, EvalContextExt as _, StackEmptyCallback, ThreadId, ThreadManager, TimeoutAnchor, TimeoutClock, UnblockKind, }; +pub use crate::concurrency::{GenmcConfig, GenmcCtx}; pub use crate::diagnostics::{ EvalContextExt as _, NonHaltingDiagnostic, TerminationInfo, report_error, }; diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index 55aa3d6fa687..6060d41dac59 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -6,6 +6,7 @@ use std::borrow::Cow; use std::cell::{Cell, RefCell}; use std::collections::hash_map::Entry; use std::path::Path; +use std::rc::Rc; use std::{fmt, process}; use rand::rngs::StdRng; @@ -27,9 +28,10 @@ use rustc_span::def_id::{CrateNum, DefId}; use rustc_span::{Span, SpanData, Symbol}; use rustc_target::callconv::FnAbi; +use crate::alloc_addresses::EvalContextExt; use crate::concurrency::cpu_affinity::{self, CpuAffinityMask}; use crate::concurrency::data_race::{self, NaReadType, NaWriteType}; -use crate::concurrency::weak_memory; +use crate::concurrency::{AllocDataRaceHandler, GenmcCtx, GlobalDataRaceHandler, weak_memory}; use crate::*; /// First real-time signal. @@ -332,12 +334,10 @@ impl ProvenanceExtra { pub struct AllocExtra<'tcx> { /// Global state of the borrow tracker, if enabled. pub borrow_tracker: Option, - /// Data race detection via the use of a vector-clock. - /// This is only added if it is enabled. - pub data_race: Option, - /// Weak memory emulation via the use of store buffers. - /// This is only added if it is enabled. - pub weak_memory: Option, + /// Extra state for data race detection. + /// + /// Invariant: The enum variant must match the enum variant in the `data_race` field on `MiriMachine` + pub data_race: AllocDataRaceHandler, /// A backtrace to where this allocation was allocated. /// As this is recorded for leak reports, it only exists /// if this allocation is leakable. The backtrace is not @@ -360,11 +360,10 @@ impl<'tcx> Clone for AllocExtra<'tcx> { impl VisitProvenance for AllocExtra<'_> { fn visit_provenance(&self, visit: &mut VisitWith<'_>) { - let AllocExtra { borrow_tracker, data_race, weak_memory, backtrace: _, sync: _ } = self; + let AllocExtra { borrow_tracker, data_race, backtrace: _, sync: _ } = self; borrow_tracker.visit_provenance(visit); data_race.visit_provenance(visit); - weak_memory.visit_provenance(visit); } } @@ -447,8 +446,12 @@ pub struct MiriMachine<'tcx> { /// Global data for borrow tracking. pub borrow_tracker: Option, - /// Data race detector global data. - pub data_race: Option, + /// Depending on settings, this will be `None`, + /// global data for a data race detector, + /// or the context required for running in GenMC mode. + /// + /// Invariant: The enum variant must match the enum variant of `AllocDataRaceHandler` in the `data_race` field of all `AllocExtra`. + pub data_race: GlobalDataRaceHandler, /// Ptr-int-cast module global data. pub alloc_addresses: alloc_addresses::GlobalState, @@ -544,9 +547,6 @@ pub struct MiriMachine<'tcx> { /// Corresponds to -Zmiri-mute-stdout-stderr and doesn't write the output but acts as if it succeeded. pub(crate) mute_stdout_stderr: bool, - /// Whether weak memory emulation is enabled - pub(crate) weak_memory: bool, - /// The probability of the active thread being preempted at the end of each basic block. pub(crate) preemption_rate: f64, @@ -617,7 +617,11 @@ pub struct MiriMachine<'tcx> { } impl<'tcx> MiriMachine<'tcx> { - pub(crate) fn new(config: &MiriConfig, layout_cx: LayoutCx<'tcx>) -> Self { + pub(crate) fn new( + config: &MiriConfig, + layout_cx: LayoutCx<'tcx>, + genmc_ctx: Option>, + ) -> Self { let tcx = layout_cx.tcx(); let local_crates = helpers::get_local_crates(tcx); let layouts = @@ -636,7 +640,14 @@ impl<'tcx> MiriMachine<'tcx> { }); let rng = StdRng::seed_from_u64(config.seed.unwrap_or(0)); let borrow_tracker = config.borrow_tracker.map(|bt| bt.instantiate_global_state(config)); - let data_race = config.data_race_detector.then(|| data_race::GlobalState::new(config)); + let data_race = if config.genmc_mode { + // `genmc_ctx` persists across executions, so we don't create a new one here. + GlobalDataRaceHandler::Genmc(genmc_ctx.unwrap()) + } else if config.data_race_detector { + GlobalDataRaceHandler::Vclocks(Box::new(data_race::GlobalState::new(config))) + } else { + GlobalDataRaceHandler::None + }; // Determine page size, stack address, and stack size. // These values are mostly meaningless, but the stack address is also where we start // allocating physical integer addresses for all allocations. @@ -669,7 +680,7 @@ impl<'tcx> MiriMachine<'tcx> { cpu_affinity::MAX_CPUS, config.num_cpus ); - let threads = ThreadManager::default(); + let threads = ThreadManager::new(config); let mut thread_cpu_affinity = FxHashMap::default(); if matches!(&*tcx.sess.target.os, "linux" | "freebsd" | "android") { thread_cpu_affinity @@ -709,7 +720,6 @@ impl<'tcx> MiriMachine<'tcx> { check_alignment: config.check_alignment, cmpxchg_weak_failure_rate: config.cmpxchg_weak_failure_rate, mute_stdout_stderr: config.mute_stdout_stderr, - weak_memory: config.weak_memory_emulation, preemption_rate: config.preemption_rate, report_progress: config.report_progress, basic_block_count: 0, @@ -835,16 +845,25 @@ impl<'tcx> MiriMachine<'tcx> { .as_ref() .map(|bt| bt.borrow_mut().new_allocation(id, size, kind, &ecx.machine)); - let data_race = ecx.machine.data_race.as_ref().map(|data_race| { - data_race::AllocState::new_allocation( - data_race, - &ecx.machine.threads, - size, - kind, - ecx.machine.current_span(), - ) - }); - let weak_memory = ecx.machine.weak_memory.then(weak_memory::AllocState::new_allocation); + let data_race = match &ecx.machine.data_race { + GlobalDataRaceHandler::None => AllocDataRaceHandler::None, + GlobalDataRaceHandler::Vclocks(data_race) => + AllocDataRaceHandler::Vclocks( + data_race::AllocState::new_allocation( + data_race, + &ecx.machine.threads, + size, + kind, + ecx.machine.current_span(), + ), + data_race.weak_memory.then(weak_memory::AllocState::new_allocation), + ), + GlobalDataRaceHandler::Genmc(_genmc_ctx) => { + // GenMC learns about new allocations directly from the alloc_addresses module, + // since it has to be able to control the address at which they are placed. + AllocDataRaceHandler::Genmc + } + }; // If an allocation is leaked, we want to report a backtrace to indicate where it was // allocated. We don't need to record a backtrace for allocations which are allowed to @@ -862,13 +881,7 @@ impl<'tcx> MiriMachine<'tcx> { .insert(id, (ecx.machine.current_span(), None)); } - interp_ok(AllocExtra { - borrow_tracker, - data_race, - weak_memory, - backtrace, - sync: FxHashMap::default(), - }) + interp_ok(AllocExtra { borrow_tracker, data_race, backtrace, sync: FxHashMap::default() }) } } @@ -909,7 +922,6 @@ impl VisitProvenance for MiriMachine<'_> { check_alignment: _, cmpxchg_weak_failure_rate: _, mute_stdout_stderr: _, - weak_memory: _, preemption_rate: _, report_progress: _, basic_block_count: _, @@ -1203,9 +1215,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { ecx: &mut InterpCx<'tcx, Self>, val: ImmTy<'tcx>, ) -> InterpResult<'tcx, ImmTy<'tcx>> { - crate::math::apply_random_float_error_to_imm( - ecx, val, 2 /* log2(4) */ - ) + crate::math::apply_random_float_error_to_imm(ecx, val, 2 /* log2(4) */) } #[inline(always)] @@ -1380,7 +1390,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { _tcx: TyCtxtAt<'tcx>, machine: &Self, alloc_extra: &AllocExtra<'tcx>, - _ptr: Pointer, + ptr: Pointer, (alloc_id, prov_extra): (AllocId, Self::ProvenanceExtra), range: AllocRange, ) -> InterpResult<'tcx> { @@ -1388,15 +1398,25 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { machine .emit_diagnostic(NonHaltingDiagnostic::AccessedAlloc(alloc_id, AccessKind::Read)); } - if let Some(data_race) = &alloc_extra.data_race { - data_race.read(alloc_id, range, NaReadType::Read, None, machine)?; + // The order of checks is deliberate, to prefer reporting a data race over a borrow tracker error. + match &machine.data_race { + GlobalDataRaceHandler::None => {} + GlobalDataRaceHandler::Genmc(genmc_ctx) => + genmc_ctx.memory_load(machine, ptr.addr(), range.size)?, + GlobalDataRaceHandler::Vclocks(_data_race) => { + let AllocDataRaceHandler::Vclocks(data_race, weak_memory) = &alloc_extra.data_race + else { + unreachable!(); + }; + data_race.read(alloc_id, range, NaReadType::Read, None, machine)?; + if let Some(weak_memory) = weak_memory { + weak_memory.memory_accessed(range, machine.data_race.as_vclocks_ref().unwrap()); + } + } } if let Some(borrow_tracker) = &alloc_extra.borrow_tracker { borrow_tracker.before_memory_read(alloc_id, prov_extra, range, machine)?; } - if let Some(weak_memory) = &alloc_extra.weak_memory { - weak_memory.memory_accessed(range, machine.data_race.as_ref().unwrap()); - } interp_ok(()) } @@ -1405,7 +1425,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { _tcx: TyCtxtAt<'tcx>, machine: &mut Self, alloc_extra: &mut AllocExtra<'tcx>, - _ptr: Pointer, + ptr: Pointer, (alloc_id, prov_extra): (AllocId, Self::ProvenanceExtra), range: AllocRange, ) -> InterpResult<'tcx> { @@ -1413,15 +1433,26 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { machine .emit_diagnostic(NonHaltingDiagnostic::AccessedAlloc(alloc_id, AccessKind::Write)); } - if let Some(data_race) = &mut alloc_extra.data_race { - data_race.write(alloc_id, range, NaWriteType::Write, None, machine)?; + match &machine.data_race { + GlobalDataRaceHandler::None => {} + GlobalDataRaceHandler::Genmc(genmc_ctx) => { + genmc_ctx.memory_store(machine, ptr.addr(), range.size)?; + } + GlobalDataRaceHandler::Vclocks(_global_state) => { + let AllocDataRaceHandler::Vclocks(data_race, weak_memory) = + &mut alloc_extra.data_race + else { + unreachable!() + }; + data_race.write(alloc_id, range, NaWriteType::Write, None, machine)?; + if let Some(weak_memory) = weak_memory { + weak_memory.memory_accessed(range, machine.data_race.as_vclocks_ref().unwrap()); + } + } } if let Some(borrow_tracker) = &mut alloc_extra.borrow_tracker { borrow_tracker.before_memory_write(alloc_id, prov_extra, range, machine)?; } - if let Some(weak_memory) = &alloc_extra.weak_memory { - weak_memory.memory_accessed(range, machine.data_race.as_ref().unwrap()); - } interp_ok(()) } @@ -1430,7 +1461,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { _tcx: TyCtxtAt<'tcx>, machine: &mut Self, alloc_extra: &mut AllocExtra<'tcx>, - _ptr: Pointer, + ptr: Pointer, (alloc_id, prove_extra): (AllocId, Self::ProvenanceExtra), size: Size, align: Align, @@ -1439,14 +1470,20 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { if machine.tracked_alloc_ids.contains(&alloc_id) { machine.emit_diagnostic(NonHaltingDiagnostic::FreedAlloc(alloc_id)); } - if let Some(data_race) = &mut alloc_extra.data_race { - data_race.write( - alloc_id, - alloc_range(Size::ZERO, size), - NaWriteType::Deallocate, - None, - machine, - )?; + match &machine.data_race { + GlobalDataRaceHandler::None => {} + GlobalDataRaceHandler::Genmc(genmc_ctx) => + genmc_ctx.handle_dealloc(machine, ptr.addr(), size, align, kind)?, + GlobalDataRaceHandler::Vclocks(_global_state) => { + let data_race = alloc_extra.data_race.as_vclocks_mut().unwrap(); + data_race.write( + alloc_id, + alloc_range(Size::ZERO, size), + NaWriteType::Deallocate, + None, + machine, + )?; + } } if let Some(borrow_tracker) = &mut alloc_extra.borrow_tracker { borrow_tracker.before_memory_deallocation(alloc_id, prove_extra, size, machine)?; @@ -1533,7 +1570,11 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { timing, is_user_relevant: ecx.machine.is_user_relevant(&frame), salt: ecx.machine.rng.borrow_mut().random_range(0..ADDRS_PER_ANON_GLOBAL), - data_race: ecx.machine.data_race.as_ref().map(|_| data_race::FrameState::default()), + data_race: ecx + .machine + .data_race + .as_vclocks_ref() + .map(|_| data_race::FrameState::default()), }; interp_ok(frame.with_extra(extra)) @@ -1679,7 +1720,11 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { if let Some(data_race) = &machine.threads.active_thread_stack().last().unwrap().extra.data_race { - data_race.local_moved_to_memory(local, alloc_info.data_race.as_mut().unwrap(), machine); + data_race.local_moved_to_memory( + local, + alloc_info.data_race.as_vclocks_mut().unwrap(), + machine, + ); } interp_ok(()) } diff --git a/src/tools/miri/src/shims/unix/android/thread.rs b/src/tools/miri/src/shims/unix/android/thread.rs index c7e2c4d507b2..30ec0aefcbf1 100644 --- a/src/tools/miri/src/shims/unix/android/thread.rs +++ b/src/tools/miri/src/shims/unix/android/thread.rs @@ -42,7 +42,7 @@ pub fn prctl<'tcx>( ecx.check_ptr_access( name.to_pointer(ecx)?, Size::from_bytes(TASK_COMM_LEN), - CheckInAllocMsg::MemoryAccessTest, + CheckInAllocMsg::MemoryAccess, )?; let res = ecx.pthread_getname_np(thread, name, len, /* truncate*/ false)?; assert_eq!(res, ThreadNameResult::Ok); diff --git a/src/tools/miri/src/shims/unix/fd.rs b/src/tools/miri/src/shims/unix/fd.rs index 41be9df7e2da..156814a26fa7 100644 --- a/src/tools/miri/src/shims/unix/fd.rs +++ b/src/tools/miri/src/shims/unix/fd.rs @@ -226,7 +226,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { trace!("Reading from FD {}, size {}", fd_num, count); // Check that the *entire* buffer is actually valid memory. - this.check_ptr_access(buf, Size::from_bytes(count), CheckInAllocMsg::MemoryAccessTest)?; + this.check_ptr_access(buf, Size::from_bytes(count), CheckInAllocMsg::MemoryAccess)?; // We cap the number of read bytes to the largest value that we are able to fit in both the // host's and target's `isize`. This saves us from having to handle overflows later. @@ -292,7 +292,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Isolation check is done via `FileDescription` trait. // Check that the *entire* buffer is actually valid memory. - this.check_ptr_access(buf, Size::from_bytes(count), CheckInAllocMsg::MemoryAccessTest)?; + this.check_ptr_access(buf, Size::from_bytes(count), CheckInAllocMsg::MemoryAccess)?; // We cap the number of written bytes to the largest value that we are able to fit in both the // host's and target's `isize`. This saves us from having to handle overflows later. diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_self.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_self.rs index 53760b05a312..f75f306e5a63 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_self.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_self.rs @@ -1,6 +1,6 @@ //@ignore-target: windows # No pthreads on Windows // We are making scheduler assumptions here. -//@compile-flags: -Zmiri-preemption-rate=0 +//@compile-flags: -Zmiri-deterministic-concurrency // Joining itself is undefined behavior. diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.rs index e3d5da26aeae..68dce8f86542 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.rs @@ -1,5 +1,7 @@ //@ignore-target: windows # No pthreads on Windows //@error-in-other-file: deadlock +// We are making scheduler assumptions here. +//@compile-flags: -Zmiri-deterministic-concurrency use std::cell::UnsafeCell; use std::sync::Arc; diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.rs index 3a985122e22e..3a932404238d 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.rs @@ -1,5 +1,7 @@ //@ignore-target: windows # No pthreads on Windows //@error-in-other-file: deadlock +// We are making scheduler assumptions here. +//@compile-flags: -Zmiri-deterministic-concurrency use std::cell::UnsafeCell; use std::sync::Arc; diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.rs index 6d7bb80d8e6c..3b2173884635 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.rs @@ -1,5 +1,7 @@ //@ignore-target: windows # No pthreads on Windows //@error-in-other-file: deadlock +// We are making scheduler assumptions here. +//@compile-flags: -Zmiri-deterministic-concurrency use std::cell::UnsafeCell; use std::sync::Arc; diff --git a/src/tools/miri/tests/fail-dep/concurrency/windows_join_main.rs b/src/tools/miri/tests/fail-dep/concurrency/windows_join_main.rs index 3ee2bf14f9fe..2980d257a292 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/windows_join_main.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/windows_join_main.rs @@ -1,6 +1,6 @@ //@only-target: windows # Uses win32 api functions // We are making scheduler assumptions here. -//@compile-flags: -Zmiri-preemption-rate=0 +//@compile-flags: -Zmiri-deterministic-concurrency //@error-in-other-file: deadlock // On windows, joining main is not UB, but it will block a thread forever. diff --git a/src/tools/miri/tests/fail-dep/concurrency/windows_join_self.rs b/src/tools/miri/tests/fail-dep/concurrency/windows_join_self.rs index eee2979f3cff..85672ec860f5 100644 --- a/src/tools/miri/tests/fail-dep/concurrency/windows_join_self.rs +++ b/src/tools/miri/tests/fail-dep/concurrency/windows_join_self.rs @@ -1,6 +1,6 @@ //@only-target: windows # Uses win32 api functions // We are making scheduler assumptions here. -//@compile-flags: -Zmiri-preemption-rate=0 +//@compile-flags: -Zmiri-deterministic-concurrency //@error-in-other-file: deadlock // On windows, a thread joining itself is not UB, but it will deadlock. diff --git a/src/tools/miri/tests/fail-dep/libc/affinity.stderr b/src/tools/miri/tests/fail-dep/libc/affinity.stderr index 5a226c6a44b8..cc3daa47e00b 100644 --- a/src/tools/miri/tests/fail-dep/libc/affinity.stderr +++ b/src/tools/miri/tests/fail-dep/libc/affinity.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: memory access failed: expected a pointer to 129 bytes of memory, but got ALLOC which is only 128 bytes from the end of the allocation +error: Undefined Behavior: memory access failed: attempting to access 129 bytes, but got ALLOC which is only 128 bytes from the end of the allocation --> tests/fail-dep/libc/affinity.rs:LL:CC | LL | let err = unsafe { sched_setaffinity(PID, size_of::() + 1, &cpuset) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 129 bytes of memory, but got ALLOC which is only 128 bytes from the end of the allocation + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: attempting to access 129 bytes, but got ALLOC which is only 128 bytes from the end of the allocation | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail-dep/libc/env-set_var-data-race.rs b/src/tools/miri/tests/fail-dep/libc/env-set_var-data-race.rs index 3a832bb0ce0c..5c80f6425eaa 100644 --- a/src/tools/miri/tests/fail-dep/libc/env-set_var-data-race.rs +++ b/src/tools/miri/tests/fail-dep/libc/env-set_var-data-race.rs @@ -1,4 +1,4 @@ -//@compile-flags: -Zmiri-disable-isolation -Zmiri-preemption-rate=0 +//@compile-flags: -Zmiri-disable-isolation -Zmiri-deterministic-concurrency //@ignore-target: windows # No libc env support on Windows use std::{env, thread}; diff --git a/src/tools/miri/tests/fail-dep/libc/eventfd_block_read_twice.rs b/src/tools/miri/tests/fail-dep/libc/eventfd_block_read_twice.rs index 0d893663fd6d..9dc554030c0e 100644 --- a/src/tools/miri/tests/fail-dep/libc/eventfd_block_read_twice.rs +++ b/src/tools/miri/tests/fail-dep/libc/eventfd_block_read_twice.rs @@ -1,7 +1,7 @@ //@only-target: linux android illumos //~^ERROR: deadlocked //~^^ERROR: deadlocked -//@compile-flags: -Zmiri-preemption-rate=0 +//@compile-flags: -Zmiri-deterministic-concurrency //@error-in-other-file: deadlock use std::thread; diff --git a/src/tools/miri/tests/fail-dep/libc/eventfd_block_write_twice.rs b/src/tools/miri/tests/fail-dep/libc/eventfd_block_write_twice.rs index 9fed47c17d40..5297a3297750 100644 --- a/src/tools/miri/tests/fail-dep/libc/eventfd_block_write_twice.rs +++ b/src/tools/miri/tests/fail-dep/libc/eventfd_block_write_twice.rs @@ -1,7 +1,7 @@ //@only-target: linux android illumos //~^ERROR: deadlocked //~^^ERROR: deadlocked -//@compile-flags: -Zmiri-preemption-rate=0 +//@compile-flags: -Zmiri-deterministic-concurrency //@error-in-other-file: deadlock use std::thread; diff --git a/src/tools/miri/tests/fail-dep/libc/libc-epoll-data-race.rs b/src/tools/miri/tests/fail-dep/libc/libc-epoll-data-race.rs index 45f6bf6da096..314ce90cfb5d 100644 --- a/src/tools/miri/tests/fail-dep/libc/libc-epoll-data-race.rs +++ b/src/tools/miri/tests/fail-dep/libc/libc-epoll-data-race.rs @@ -4,7 +4,7 @@ //! to be considered synchronized. //@only-target: linux android illumos // ensure deterministic schedule -//@compile-flags: -Zmiri-preemption-rate=0 +//@compile-flags: -Zmiri-deterministic-concurrency use std::convert::TryInto; use std::thread; diff --git a/src/tools/miri/tests/fail-dep/libc/libc_epoll_block_two_thread.rs b/src/tools/miri/tests/fail-dep/libc/libc_epoll_block_two_thread.rs index 059b24cb8c0b..f6f2e2b93121 100644 --- a/src/tools/miri/tests/fail-dep/libc/libc_epoll_block_two_thread.rs +++ b/src/tools/miri/tests/fail-dep/libc/libc_epoll_block_two_thread.rs @@ -1,4 +1,4 @@ -//@compile-flags: -Zmiri-preemption-rate=0 +//@compile-flags: -Zmiri-deterministic-concurrency //~^ERROR: deadlocked //~^^ERROR: deadlocked //@only-target: linux android illumos diff --git a/src/tools/miri/tests/fail-dep/libc/memchr_null.stderr b/src/tools/miri/tests/fail-dep/libc/memchr_null.stderr index 6d3ff176c355..5690277a0460 100644 --- a/src/tools/miri/tests/fail-dep/libc/memchr_null.stderr +++ b/src/tools/miri/tests/fail-dep/libc/memchr_null.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to some allocation, but got a null pointer +error: Undefined Behavior: pointer not dereferenceable: pointer must point to some allocation, but got null pointer --> tests/fail-dep/libc/memchr_null.rs:LL:CC | LL | libc::memchr(ptr::null(), 0, 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: expected a pointer to some allocation, but got a null pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer not dereferenceable: pointer must point to some allocation, but got null pointer | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail-dep/libc/memcmp_null.stderr b/src/tools/miri/tests/fail-dep/libc/memcmp_null.stderr index a4ca205c3770..bd3a0719fa33 100644 --- a/src/tools/miri/tests/fail-dep/libc/memcmp_null.stderr +++ b/src/tools/miri/tests/fail-dep/libc/memcmp_null.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to some allocation, but got a null pointer +error: Undefined Behavior: pointer not dereferenceable: pointer must point to some allocation, but got null pointer --> tests/fail-dep/libc/memcmp_null.rs:LL:CC | LL | libc::memcmp(ptr::null(), ptr::null(), 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: expected a pointer to some allocation, but got a null pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer not dereferenceable: pointer must point to some allocation, but got null pointer | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail-dep/libc/memcmp_zero.stderr b/src/tools/miri/tests/fail-dep/libc/memcmp_zero.stderr index d7b046c18235..2044c1547617 100644 --- a/src/tools/miri/tests/fail-dep/libc/memcmp_zero.stderr +++ b/src/tools/miri/tests/fail-dep/libc/memcmp_zero.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to some allocation, but got 0x2a[noalloc] which is a dangling pointer (it has no provenance) +error: Undefined Behavior: pointer not dereferenceable: pointer must point to some allocation, but got 0x2a[noalloc] which is a dangling pointer (it has no provenance) --> tests/fail-dep/libc/memcmp_zero.rs:LL:CC | LL | libc::memcmp(ptr.cast(), ptr.cast(), 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: expected a pointer to some allocation, but got 0x2a[noalloc] which is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer not dereferenceable: pointer must point to some allocation, but got 0x2a[noalloc] which is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail-dep/libc/memcpy_zero.stderr b/src/tools/miri/tests/fail-dep/libc/memcpy_zero.stderr index 336113e34408..789e9daf43bc 100644 --- a/src/tools/miri/tests/fail-dep/libc/memcpy_zero.stderr +++ b/src/tools/miri/tests/fail-dep/libc/memcpy_zero.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to some allocation, but got 0x17[noalloc] which is a dangling pointer (it has no provenance) +error: Undefined Behavior: pointer not dereferenceable: pointer must point to some allocation, but got 0x17[noalloc] which is a dangling pointer (it has no provenance) --> tests/fail-dep/libc/memcpy_zero.rs:LL:CC | LL | libc::memcpy(to.cast(), from.cast(), 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: expected a pointer to some allocation, but got 0x17[noalloc] which is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer not dereferenceable: pointer must point to some allocation, but got 0x17[noalloc] which is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail-dep/libc/memrchr_null.stderr b/src/tools/miri/tests/fail-dep/libc/memrchr_null.stderr index ce759f3e17a5..27e7a9855d10 100644 --- a/src/tools/miri/tests/fail-dep/libc/memrchr_null.stderr +++ b/src/tools/miri/tests/fail-dep/libc/memrchr_null.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to some allocation, but got a null pointer +error: Undefined Behavior: pointer not dereferenceable: pointer must point to some allocation, but got null pointer --> tests/fail-dep/libc/memrchr_null.rs:LL:CC | LL | libc::memrchr(ptr::null(), 0, 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: expected a pointer to some allocation, but got a null pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer not dereferenceable: pointer must point to some allocation, but got null pointer | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail-dep/libc/socketpair-close-while-blocked.rs b/src/tools/miri/tests/fail-dep/libc/socketpair-close-while-blocked.rs index 8413e118819c..0699dec6556d 100644 --- a/src/tools/miri/tests/fail-dep/libc/socketpair-close-while-blocked.rs +++ b/src/tools/miri/tests/fail-dep/libc/socketpair-close-while-blocked.rs @@ -2,7 +2,7 @@ //! faulty logic around `release_clock` that led to this code not reporting a data race. //~^^ERROR: deadlock //@ignore-target: windows # no libc socketpair on Windows -//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-address-reuse-rate=0 +//@compile-flags: -Zmiri-deterministic-concurrency //@error-in-other-file: deadlock use std::thread; diff --git a/src/tools/miri/tests/fail-dep/libc/socketpair-data-race.rs b/src/tools/miri/tests/fail-dep/libc/socketpair-data-race.rs index 55491da9f60d..37fac436ff3e 100644 --- a/src/tools/miri/tests/fail-dep/libc/socketpair-data-race.rs +++ b/src/tools/miri/tests/fail-dep/libc/socketpair-data-race.rs @@ -1,7 +1,7 @@ //! This is a regression test for : we had some //! faulty logic around `release_clock` that led to this code not reporting a data race. //@ignore-target: windows # no libc socketpair on Windows -//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-address-reuse-rate=0 +//@compile-flags: -Zmiri-deterministic-concurrency use std::thread; fn main() { diff --git a/src/tools/miri/tests/fail-dep/libc/socketpair_block_read_twice.rs b/src/tools/miri/tests/fail-dep/libc/socketpair_block_read_twice.rs index d3e4c43f2b75..b38398595002 100644 --- a/src/tools/miri/tests/fail-dep/libc/socketpair_block_read_twice.rs +++ b/src/tools/miri/tests/fail-dep/libc/socketpair_block_read_twice.rs @@ -2,7 +2,7 @@ //~^ERROR: deadlocked //~^^ERROR: deadlocked // test_race depends on a deterministic schedule. -//@compile-flags: -Zmiri-preemption-rate=0 +//@compile-flags: -Zmiri-deterministic-concurrency //@error-in-other-file: deadlock use std::thread; diff --git a/src/tools/miri/tests/fail-dep/libc/socketpair_block_write_twice.rs b/src/tools/miri/tests/fail-dep/libc/socketpair_block_write_twice.rs index 4f951acb2c31..7d84d87ebbb1 100644 --- a/src/tools/miri/tests/fail-dep/libc/socketpair_block_write_twice.rs +++ b/src/tools/miri/tests/fail-dep/libc/socketpair_block_write_twice.rs @@ -2,7 +2,7 @@ //~^ERROR: deadlocked //~^^ERROR: deadlocked // test_race depends on a deterministic schedule. -//@compile-flags: -Zmiri-preemption-rate=0 +//@compile-flags: -Zmiri-deterministic-concurrency //@error-in-other-file: deadlock use std::thread; diff --git a/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.rs b/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.rs index 49de3dd0b105..dd7dae9cecf9 100644 --- a/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.rs +++ b/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.rs @@ -1,6 +1,6 @@ //@revisions: stack tree //@[tree]compile-flags: -Zmiri-tree-borrows -//@error-in-other-file: expected a pointer to 4 bytes of memory +//@error-in-other-file: pointer not dereferenceable fn main() { unsafe { diff --git a/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.stack.stderr b/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.stack.stderr index cd27bb818e76..0e6d838dfff6 100644 --- a/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.stack.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to 4 bytes of memory, but got ALLOC which is only 2 bytes from the end of the allocation +error: Undefined Behavior: pointer not dereferenceable: pointer must be dereferenceable for 4 bytes, but got ALLOC which is only 2 bytes from the end of the allocation --> RUSTLIB/alloc/src/boxed.rs:LL:CC | LL | Box(unsafe { Unique::new_unchecked(raw) }, alloc) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: expected a pointer to 4 bytes of memory, but got ALLOC which is only 2 bytes from the end of the allocation + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer not dereferenceable: pointer must be dereferenceable for 4 bytes, but got ALLOC which is only 2 bytes from the end of the allocation | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.tree.stderr b/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.tree.stderr index cd27bb818e76..0e6d838dfff6 100644 --- a/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.tree.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to 4 bytes of memory, but got ALLOC which is only 2 bytes from the end of the allocation +error: Undefined Behavior: pointer not dereferenceable: pointer must be dereferenceable for 4 bytes, but got ALLOC which is only 2 bytes from the end of the allocation --> RUSTLIB/alloc/src/boxed.rs:LL:CC | LL | Box(unsafe { Unique::new_unchecked(raw) }, alloc) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: expected a pointer to 4 bytes of memory, but got ALLOC which is only 2 bytes from the end of the allocation + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer not dereferenceable: pointer must be dereferenceable for 4 bytes, but got ALLOC which is only 2 bytes from the end of the allocation | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-2.stack.stderr b/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-2.stack.stderr index 04e5765371e7..861173f54968 100644 --- a/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-2.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-2.stack.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to 4 bytes of memory, but got 0x4[noalloc] which is a dangling pointer (it has no provenance) +error: Undefined Behavior: pointer not dereferenceable: pointer must be dereferenceable for 4 bytes, but got 0x4[noalloc] which is a dangling pointer (it has no provenance) --> RUSTLIB/alloc/src/boxed.rs:LL:CC | LL | Box(unsafe { Unique::new_unchecked(raw) }, alloc) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: expected a pointer to 4 bytes of memory, but got 0x4[noalloc] which is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer not dereferenceable: pointer must be dereferenceable for 4 bytes, but got 0x4[noalloc] which is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-2.tree.stderr b/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-2.tree.stderr index 04e5765371e7..861173f54968 100644 --- a/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-2.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-2.tree.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to 4 bytes of memory, but got 0x4[noalloc] which is a dangling pointer (it has no provenance) +error: Undefined Behavior: pointer not dereferenceable: pointer must be dereferenceable for 4 bytes, but got 0x4[noalloc] which is a dangling pointer (it has no provenance) --> RUSTLIB/alloc/src/boxed.rs:LL:CC | LL | Box(unsafe { Unique::new_unchecked(raw) }, alloc) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: expected a pointer to 4 bytes of memory, but got 0x4[noalloc] which is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer not dereferenceable: pointer must be dereferenceable for 4 bytes, but got 0x4[noalloc] which is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.rs b/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.rs index 0061679eaa4e..31f1a22f9f6d 100644 --- a/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.rs +++ b/src/tools/miri/tests/fail/both_borrows/retag_data_race_write.rs @@ -1,8 +1,6 @@ //! Make sure that a retag acts like a write for the data race model. //@revisions: stack tree -//@compile-flags: -Zmiri-preemption-rate=0 -// Avoid accidental synchronization via address reuse inside `thread::spawn`. -//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 +//@compile-flags: -Zmiri-deterministic-concurrency //@[tree]compile-flags: -Zmiri-tree-borrows #[derive(Copy, Clone)] struct SendPtr(*mut u8); diff --git a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_offset.rs b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_offset.rs index 65eca07a0708..54b3280e71ac 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_offset.rs +++ b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_offset.rs @@ -6,6 +6,6 @@ fn main() { let b = Box::new(42); &*b as *const i32 }; - let x = unsafe { p.offset(42) }; //~ ERROR: /out-of-bounds pointer arithmetic: .* has been freed/ + let x = unsafe { p.offset(42) }; //~ ERROR: /in-bounds pointer arithmetic failed: .* has been freed/ panic!("this should never print: {:?}", x); } diff --git a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_offset.stderr b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_offset.stderr index 076d68804618..fd1a5e7faafe 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_offset.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_offset.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: out-of-bounds pointer arithmetic: ALLOC has been freed, so this pointer is dangling +error: Undefined Behavior: in-bounds pointer arithmetic failed: ALLOC has been freed, so this pointer is dangling --> tests/fail/dangling_pointers/dangling_pointer_offset.rs:LL:CC | LL | let x = unsafe { p.offset(42) }; - | ^^^^^^^^^^^^ out-of-bounds pointer arithmetic: ALLOC has been freed, so this pointer is dangling + | ^^^^^^^^^^^^ in-bounds pointer arithmetic failed: ALLOC has been freed, so this pointer is dangling | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_let.rs b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_let.rs index 22a5ce8ea741..02ea09efab63 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_let.rs +++ b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_let.rs @@ -7,6 +7,6 @@ fn main() { &*b as *const i32 as *const (u8, u8, u8, u8) }; unsafe { - let _ = (*p).1; //~ ERROR: out-of-bounds pointer arithmetic + let _ = (*p).1; //~ ERROR: in-bounds pointer arithmetic failed } } diff --git a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_let.stderr b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_let.stderr index ffb525e39814..ffb8bc9507b5 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_let.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_let.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: out-of-bounds pointer arithmetic: ALLOC has been freed, so this pointer is dangling +error: Undefined Behavior: in-bounds pointer arithmetic failed: ALLOC has been freed, so this pointer is dangling --> tests/fail/dangling_pointers/dangling_pointer_project_underscore_let.rs:LL:CC | LL | let _ = (*p).1; - | ^^^^^^ out-of-bounds pointer arithmetic: ALLOC has been freed, so this pointer is dangling + | ^^^^^^ in-bounds pointer arithmetic failed: ALLOC has been freed, so this pointer is dangling | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_let_type_annotation.rs b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_let_type_annotation.rs index fc10a826c1e1..7ab295cb6c6c 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_let_type_annotation.rs +++ b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_let_type_annotation.rs @@ -7,6 +7,6 @@ fn main() { &*b as *const i32 as *const (u8, u8, u8, u8) }; unsafe { - let _: u8 = (*p).1; //~ ERROR: out-of-bounds pointer arithmetic + let _: u8 = (*p).1; //~ ERROR: in-bounds pointer arithmetic failed } } diff --git a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_let_type_annotation.stderr b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_let_type_annotation.stderr index 14dfa43b2d68..cf3e1db13d3d 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_let_type_annotation.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_let_type_annotation.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: out-of-bounds pointer arithmetic: ALLOC has been freed, so this pointer is dangling +error: Undefined Behavior: in-bounds pointer arithmetic failed: ALLOC has been freed, so this pointer is dangling --> tests/fail/dangling_pointers/dangling_pointer_project_underscore_let_type_annotation.rs:LL:CC | LL | let _: u8 = (*p).1; - | ^^^^^^ out-of-bounds pointer arithmetic: ALLOC has been freed, so this pointer is dangling + | ^^^^^^ in-bounds pointer arithmetic failed: ALLOC has been freed, so this pointer is dangling | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_match.rs b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_match.rs index 8541da848578..2855dd13fdc4 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_match.rs +++ b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_match.rs @@ -8,7 +8,7 @@ fn main() { }; unsafe { match (*p).1 { - //~^ ERROR: out-of-bounds pointer arithmetic + //~^ ERROR: in-bounds pointer arithmetic failed _ => {} } } diff --git a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_match.stderr b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_match.stderr index ff39e1475738..e2d04433b639 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_match.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_project_underscore_match.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: out-of-bounds pointer arithmetic: ALLOC has been freed, so this pointer is dangling +error: Undefined Behavior: in-bounds pointer arithmetic failed: ALLOC has been freed, so this pointer is dangling --> tests/fail/dangling_pointers/dangling_pointer_project_underscore_match.rs:LL:CC | LL | match (*p).1 { - | ^^^^^^ out-of-bounds pointer arithmetic: ALLOC has been freed, so this pointer is dangling + | ^^^^^^ in-bounds pointer arithmetic failed: ALLOC has been freed, so this pointer is dangling | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_to_raw_pointer.stderr b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_to_raw_pointer.stderr index 99194d6e0725..5a2b85696abc 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_to_raw_pointer.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/dangling_pointer_to_raw_pointer.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to 4 bytes of memory, but got 0x10[noalloc] which is a dangling pointer (it has no provenance) +error: Undefined Behavior: pointer not dereferenceable: pointer must be dereferenceable for 4 bytes, but got 0x10[noalloc] which is a dangling pointer (it has no provenance) --> tests/fail/dangling_pointers/dangling_pointer_to_raw_pointer.rs:LL:CC | LL | unsafe { &(*x).0 as *const i32 } - | ^^^^^^^ out-of-bounds pointer use: expected a pointer to 4 bytes of memory, but got 0x10[noalloc] which is a dangling pointer (it has no provenance) + | ^^^^^^^ pointer not dereferenceable: pointer must be dereferenceable for 4 bytes, but got 0x10[noalloc] which is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/dangling_pointers/deref-invalid-ptr.stderr b/src/tools/miri/tests/fail/dangling_pointers/deref-invalid-ptr.stderr index 09a201983b1f..ad4280c2d744 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/deref-invalid-ptr.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/deref-invalid-ptr.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to 4 bytes of memory, but got 0x10[noalloc] which is a dangling pointer (it has no provenance) +error: Undefined Behavior: pointer not dereferenceable: pointer must be dereferenceable for 4 bytes, but got 0x10[noalloc] which is a dangling pointer (it has no provenance) --> tests/fail/dangling_pointers/deref-invalid-ptr.rs:LL:CC | LL | let _y = unsafe { &*x as *const u32 }; - | ^^^ out-of-bounds pointer use: expected a pointer to 4 bytes of memory, but got 0x10[noalloc] which is a dangling pointer (it has no provenance) + | ^^^ pointer not dereferenceable: pointer must be dereferenceable for 4 bytes, but got 0x10[noalloc] which is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/dangling_pointers/null_pointer_deref.stderr b/src/tools/miri/tests/fail/dangling_pointers/null_pointer_deref.stderr index d87a8bc59e95..3135db9dc6d5 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/null_pointer_deref.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/null_pointer_deref.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: memory access failed: expected a pointer to 4 bytes of memory, but got a null pointer +error: Undefined Behavior: memory access failed: attempting to access 4 bytes, but got null pointer --> tests/fail/dangling_pointers/null_pointer_deref.rs:LL:CC | LL | let x: i32 = unsafe { *std::ptr::null() }; - | ^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got a null pointer + | ^^^^^^^^^^^^^^^^^ memory access failed: attempting to access 4 bytes, but got null pointer | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/dangling_pointers/null_pointer_write.stderr b/src/tools/miri/tests/fail/dangling_pointers/null_pointer_write.stderr index 39d861a63882..012b38ee5a6c 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/null_pointer_write.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/null_pointer_write.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: memory access failed: expected a pointer to 4 bytes of memory, but got a null pointer +error: Undefined Behavior: memory access failed: attempting to access 4 bytes, but got null pointer --> tests/fail/dangling_pointers/null_pointer_write.rs:LL:CC | LL | unsafe { *std::ptr::null_mut() = 0i32 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got a null pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: attempting to access 4 bytes, but got null pointer | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_project.rs b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_project.rs index b596ba428ae5..7a2ad483d015 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_project.rs +++ b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_project.rs @@ -7,6 +7,6 @@ fn main() { let ptr = addr_of!(v).cast::<(u32, u32, u32)>(); unsafe { let _field = addr_of!((*ptr).1); // still just in-bounds - let _field = addr_of!((*ptr).2); //~ ERROR: out-of-bounds pointer arithmetic + let _field = addr_of!((*ptr).2); //~ ERROR: in-bounds pointer arithmetic failed } } diff --git a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_project.stderr b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_project.stderr index 27a437c7483d..c11ccdb45a7f 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_project.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_project.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: out-of-bounds pointer arithmetic: expected a pointer to 8 bytes of memory, but got ALLOC which is only 4 bytes from the end of the allocation +error: Undefined Behavior: in-bounds pointer arithmetic failed: attempting to offset pointer by 8 bytes, but got ALLOC which is only 4 bytes from the end of the allocation --> tests/fail/dangling_pointers/out_of_bounds_project.rs:LL:CC | LL | let _field = addr_of!((*ptr).2); - | ^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: expected a pointer to 8 bytes of memory, but got ALLOC which is only 4 bytes from the end of the allocation + | ^^^^^^^^^^^^^^^^^^ in-bounds pointer arithmetic failed: attempting to offset pointer by 8 bytes, but got ALLOC which is only 4 bytes from the end of the allocation | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read.rs b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read.rs index 595a229baa5a..78a7b7e460be 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read.rs +++ b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read.rs @@ -1,6 +1,6 @@ fn main() { let v: Vec = vec![1, 2]; // This read is also misaligned. We make sure that the OOB message has priority. - let x = unsafe { *v.as_ptr().wrapping_byte_add(5) }; //~ ERROR: expected a pointer to 2 bytes of memory + let x = unsafe { *v.as_ptr().wrapping_byte_add(5) }; //~ ERROR: attempting to access 2 bytes panic!("this should never print: {}", x); } diff --git a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read.stderr b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read.stderr index 813bcef54f12..1de4b806da20 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_read.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: memory access failed: expected a pointer to 2 bytes of memory, but got ALLOC+0x5 which is at or beyond the end of the allocation of size 4 bytes +error: Undefined Behavior: memory access failed: attempting to access 2 bytes, but got ALLOC+0x5 which is at or beyond the end of the allocation of size 4 bytes --> tests/fail/dangling_pointers/out_of_bounds_read.rs:LL:CC | LL | let x = unsafe { *v.as_ptr().wrapping_byte_add(5) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 2 bytes of memory, but got ALLOC+0x5 which is at or beyond the end of the allocation of size 4 bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: attempting to access 2 bytes, but got ALLOC+0x5 which is at or beyond the end of the allocation of size 4 bytes | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_write.rs b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_write.rs index 054e1c66cc18..f83601b44f8d 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_write.rs +++ b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_write.rs @@ -1,5 +1,5 @@ fn main() { let mut v: Vec = vec![1, 2]; // This read is also misaligned. We make sure that the OOB message has priority. - unsafe { *v.as_mut_ptr().wrapping_byte_add(5) = 0 }; //~ ERROR: expected a pointer to 2 bytes of memory + unsafe { *v.as_mut_ptr().wrapping_byte_add(5) = 0 }; //~ ERROR: attempting to access 2 bytes } diff --git a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_write.stderr b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_write.stderr index 1056a739a436..db16d70704e8 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_write.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/out_of_bounds_write.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: memory access failed: expected a pointer to 2 bytes of memory, but got ALLOC+0x5 which is at or beyond the end of the allocation of size 4 bytes +error: Undefined Behavior: memory access failed: attempting to access 2 bytes, but got ALLOC+0x5 which is at or beyond the end of the allocation of size 4 bytes --> tests/fail/dangling_pointers/out_of_bounds_write.rs:LL:CC | LL | unsafe { *v.as_mut_ptr().wrapping_byte_add(5) = 0 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 2 bytes of memory, but got ALLOC+0x5 which is at or beyond the end of the allocation of size 4 bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: attempting to access 2 bytes, but got ALLOC+0x5 which is at or beyond the end of the allocation of size 4 bytes | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/dangling_pointers/storage_dead_dangling.stderr b/src/tools/miri/tests/fail/dangling_pointers/storage_dead_dangling.stderr index 9061121494d0..e97427ab7ebc 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/storage_dead_dangling.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/storage_dead_dangling.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to 4 bytes of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) +error: Undefined Behavior: pointer not dereferenceable: pointer must be dereferenceable for 4 bytes, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) --> tests/fail/dangling_pointers/storage_dead_dangling.rs:LL:CC | LL | let _ref = unsafe { &mut *(LEAK as *mut i32) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: expected a pointer to 4 bytes of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^ pointer not dereferenceable: pointer must be dereferenceable for 4 bytes, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/dangling_pointers/wild_pointer_deref.stderr b/src/tools/miri/tests/fail/dangling_pointers/wild_pointer_deref.stderr index 3e7aac4724dc..79e27fa34617 100644 --- a/src/tools/miri/tests/fail/dangling_pointers/wild_pointer_deref.stderr +++ b/src/tools/miri/tests/fail/dangling_pointers/wild_pointer_deref.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: memory access failed: expected a pointer to 4 bytes of memory, but got 0x2c[noalloc] which is a dangling pointer (it has no provenance) +error: Undefined Behavior: memory access failed: attempting to access 4 bytes, but got 0x2c[noalloc] which is a dangling pointer (it has no provenance) --> tests/fail/dangling_pointers/wild_pointer_deref.rs:LL:CC | LL | let x = unsafe { *p }; - | ^^ memory access failed: expected a pointer to 4 bytes of memory, but got 0x2c[noalloc] which is a dangling pointer (it has no provenance) + | ^^ memory access failed: attempting to access 4 bytes, but got 0x2c[noalloc] which is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/data_race/alloc_read_race.rs b/src/tools/miri/tests/fail/data_race/alloc_read_race.rs index 312b7ba05d31..7c5116989943 100644 --- a/src/tools/miri/tests/fail/data_race/alloc_read_race.rs +++ b/src/tools/miri/tests/fail/data_race/alloc_read_race.rs @@ -1,6 +1,5 @@ -//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows -// Avoid accidental synchronization via address reuse inside `thread::spawn`. -//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 +// We want to control preemption here. Stacked borrows interferes by having its own accesses. +//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows use std::mem::MaybeUninit; use std::ptr::null_mut; diff --git a/src/tools/miri/tests/fail/data_race/alloc_write_race.rs b/src/tools/miri/tests/fail/data_race/alloc_write_race.rs index f1f308b37e7b..ba8a888de9ea 100644 --- a/src/tools/miri/tests/fail/data_race/alloc_write_race.rs +++ b/src/tools/miri/tests/fail/data_race/alloc_write_race.rs @@ -1,6 +1,5 @@ -//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows -// Avoid accidental synchronization via address reuse inside `thread::spawn`. -//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 +// We want to control preemption here. Stacked borrows interferes by having its own accesses. +//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows use std::ptr::null_mut; use std::sync::atomic::{AtomicPtr, Ordering}; diff --git a/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race1.rs b/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race1.rs index 4003892f0a60..8cce54603ce5 100644 --- a/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race1.rs +++ b/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race1.rs @@ -1,7 +1,5 @@ // We want to control preemption here. Stacked borrows interferes by having its own accesses. -//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows -// Avoid accidental synchronization via address reuse inside `thread::spawn`. -//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 +//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows use std::sync::atomic::{AtomicUsize, Ordering}; use std::thread::spawn; diff --git a/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race2.rs b/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race2.rs index c67ce65eb340..b6c0ef37cb92 100644 --- a/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race2.rs +++ b/src/tools/miri/tests/fail/data_race/atomic_read_na_write_race2.rs @@ -1,7 +1,5 @@ // We want to control preemption here. Stacked borrows interferes by having its own accesses. -//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows -// Avoid accidental synchronization via address reuse inside `thread::spawn`. -//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 +//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows use std::sync::atomic::{AtomicUsize, Ordering}; use std::thread::spawn; diff --git a/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race1.rs b/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race1.rs index 5e328740e851..03ae6895c574 100644 --- a/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race1.rs +++ b/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race1.rs @@ -1,7 +1,5 @@ // We want to control preemption here. Stacked borrows interferes by having its own accesses. -//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows -// Avoid accidental synchronization via address reuse inside `thread::spawn`. -//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 +//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows use std::sync::atomic::{AtomicUsize, Ordering}; use std::thread::spawn; diff --git a/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race2.rs b/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race2.rs index e0876a93fdd8..4a5edf5cc14d 100644 --- a/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race2.rs +++ b/src/tools/miri/tests/fail/data_race/atomic_write_na_read_race2.rs @@ -1,7 +1,5 @@ // We want to control preemption here. Stacked borrows interferes by having its own accesses. -//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows -// Avoid accidental synchronization via address reuse inside `thread::spawn`. -//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 +//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows use std::sync::atomic::{AtomicUsize, Ordering}; use std::thread::spawn; diff --git a/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race1.rs b/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race1.rs index 1010216a4976..e8d930a51dee 100644 --- a/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race1.rs +++ b/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race1.rs @@ -1,7 +1,5 @@ // We want to control preemption here. Stacked borrows interferes by having its own accesses. -//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows -// Avoid accidental synchronization via address reuse inside `thread::spawn`. -//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 +//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows use std::sync::atomic::{AtomicUsize, Ordering}; use std::thread::spawn; diff --git a/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race2.rs b/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race2.rs index fdc0f9e20f07..4c67d2d76541 100644 --- a/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race2.rs +++ b/src/tools/miri/tests/fail/data_race/atomic_write_na_write_race2.rs @@ -1,7 +1,5 @@ // We want to control preemption here. Stacked borrows interferes by having its own accesses. -//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows -// Avoid accidental synchronization via address reuse inside `thread::spawn`. -//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 +//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows use std::sync::atomic::{AtomicUsize, Ordering}; use std::thread::spawn; diff --git a/src/tools/miri/tests/fail/data_race/dangling_thread_async_race.rs b/src/tools/miri/tests/fail/data_race/dangling_thread_async_race.rs index dffafe3cfaa9..fbb2c01e5a9a 100644 --- a/src/tools/miri/tests/fail/data_race/dangling_thread_async_race.rs +++ b/src/tools/miri/tests/fail/data_race/dangling_thread_async_race.rs @@ -1,7 +1,5 @@ // We want to control preemption here. Stacked borrows interferes by having its own accesses. -//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows -// Avoid accidental synchronization via address reuse. -//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 +//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows use std::mem; use std::thread::{sleep, spawn}; diff --git a/src/tools/miri/tests/fail/data_race/dangling_thread_race.rs b/src/tools/miri/tests/fail/data_race/dangling_thread_race.rs index 8dc35c7ea720..7431bc589ff9 100644 --- a/src/tools/miri/tests/fail/data_race/dangling_thread_race.rs +++ b/src/tools/miri/tests/fail/data_race/dangling_thread_race.rs @@ -1,7 +1,5 @@ // We want to control preemption here. Stacked borrows interferes by having its own accesses. -//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows -// Avoid accidental synchronization via address reuse. -//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 +//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows use std::mem; use std::thread::{sleep, spawn}; diff --git a/src/tools/miri/tests/fail/data_race/dealloc_read_race1.rs b/src/tools/miri/tests/fail/data_race/dealloc_read_race1.rs index d0a284820541..999cc2392f5a 100644 --- a/src/tools/miri/tests/fail/data_race/dealloc_read_race1.rs +++ b/src/tools/miri/tests/fail/data_race/dealloc_read_race1.rs @@ -1,7 +1,5 @@ // We want to control preemption here. Stacked borrows interferes by having its own accesses. -//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows -// Avoid accidental synchronization via address reuse inside `thread::spawn`. -//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 +//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows #![feature(rustc_attrs)] diff --git a/src/tools/miri/tests/fail/data_race/dealloc_read_race2.rs b/src/tools/miri/tests/fail/data_race/dealloc_read_race2.rs index f56c44cabc23..bd3b037e5838 100644 --- a/src/tools/miri/tests/fail/data_race/dealloc_read_race2.rs +++ b/src/tools/miri/tests/fail/data_race/dealloc_read_race2.rs @@ -1,7 +1,5 @@ // We want to control preemption here. Stacked borrows interferes by having its own accesses. -//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows -// Avoid accidental synchronization via address reuse inside `thread::spawn`. -//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 +//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows #![feature(rustc_attrs)] diff --git a/src/tools/miri/tests/fail/data_race/dealloc_read_race_stack.rs b/src/tools/miri/tests/fail/data_race/dealloc_read_race_stack.rs index c67e03d362b0..e3d06660aab3 100644 --- a/src/tools/miri/tests/fail/data_race/dealloc_read_race_stack.rs +++ b/src/tools/miri/tests/fail/data_race/dealloc_read_race_stack.rs @@ -1,6 +1,5 @@ -//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows -// Avoid accidental synchronization via address reuse inside `thread::spawn`. -//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 +// We want to control preemption here. Stacked borrows interferes by having its own accesses. +//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows use std::ptr::null_mut; use std::sync::atomic::{AtomicPtr, Ordering}; diff --git a/src/tools/miri/tests/fail/data_race/dealloc_write_race1.rs b/src/tools/miri/tests/fail/data_race/dealloc_write_race1.rs index a16ea25e11ce..90e87f8c4956 100644 --- a/src/tools/miri/tests/fail/data_race/dealloc_write_race1.rs +++ b/src/tools/miri/tests/fail/data_race/dealloc_write_race1.rs @@ -1,7 +1,5 @@ // We want to control preemption here. Stacked borrows interferes by having its own accesses. -//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows -// Avoid accidental synchronization via address reuse inside `thread::spawn`. -//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 +//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows #![feature(rustc_attrs)] diff --git a/src/tools/miri/tests/fail/data_race/dealloc_write_race2.rs b/src/tools/miri/tests/fail/data_race/dealloc_write_race2.rs index f3855e33c98d..d9b1af80af49 100644 --- a/src/tools/miri/tests/fail/data_race/dealloc_write_race2.rs +++ b/src/tools/miri/tests/fail/data_race/dealloc_write_race2.rs @@ -1,7 +1,5 @@ // We want to control preemption here. Stacked borrows interferes by having its own accesses. -//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows -// Avoid accidental synchronization via address reuse inside `thread::spawn`. -//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 +//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows #![feature(rustc_attrs)] diff --git a/src/tools/miri/tests/fail/data_race/dealloc_write_race_stack.rs b/src/tools/miri/tests/fail/data_race/dealloc_write_race_stack.rs index 8e63bc1dc7b4..c1ab1942c688 100644 --- a/src/tools/miri/tests/fail/data_race/dealloc_write_race_stack.rs +++ b/src/tools/miri/tests/fail/data_race/dealloc_write_race_stack.rs @@ -1,6 +1,5 @@ -//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows -// Avoid accidental synchronization via address reuse inside `thread::spawn`. -//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 +// We want to control preemption here. Stacked borrows interferes by having its own accesses. +//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows use std::ptr::null_mut; use std::sync::atomic::{AtomicPtr, Ordering}; diff --git a/src/tools/miri/tests/fail/data_race/enable_after_join_to_main.rs b/src/tools/miri/tests/fail/data_race/enable_after_join_to_main.rs index 53050608d271..67af6862737d 100644 --- a/src/tools/miri/tests/fail/data_race/enable_after_join_to_main.rs +++ b/src/tools/miri/tests/fail/data_race/enable_after_join_to_main.rs @@ -1,7 +1,5 @@ // We want to control preemption here. Stacked borrows interferes by having its own accesses. -//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows -// Avoid accidental synchronization via address reuse inside `thread::spawn`. -//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 +//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows use std::thread::spawn; diff --git a/src/tools/miri/tests/fail/data_race/fence_after_load.rs b/src/tools/miri/tests/fail/data_race/fence_after_load.rs index 5dfb260c20bd..b1eb1dda6d88 100644 --- a/src/tools/miri/tests/fail/data_race/fence_after_load.rs +++ b/src/tools/miri/tests/fail/data_race/fence_after_load.rs @@ -1,7 +1,5 @@ // We want to control preemption here. Stacked borrows interferes by having its own accesses. -//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows -// Avoid accidental synchronization via address reuse inside `thread::spawn`. -//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 +//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows use std::sync::Arc; use std::sync::atomic::{AtomicUsize, Ordering, fence}; diff --git a/src/tools/miri/tests/fail/data_race/local_variable_alloc_race.rs b/src/tools/miri/tests/fail/data_race/local_variable_alloc_race.rs index 751a308a3999..647f209e8bf8 100644 --- a/src/tools/miri/tests/fail/data_race/local_variable_alloc_race.rs +++ b/src/tools/miri/tests/fail/data_race/local_variable_alloc_race.rs @@ -1,4 +1,4 @@ -//@compile-flags: -Zmiri-preemption-rate=0.0 -Zmiri-disable-weak-memory-emulation +//@compile-flags:-Zmiri-deterministic-concurrency #![feature(core_intrinsics)] #![feature(custom_mir)] diff --git a/src/tools/miri/tests/fail/data_race/local_variable_read_race.rs b/src/tools/miri/tests/fail/data_race/local_variable_read_race.rs index 16a23f595ee4..f83d6c89fe5f 100644 --- a/src/tools/miri/tests/fail/data_race/local_variable_read_race.rs +++ b/src/tools/miri/tests/fail/data_race/local_variable_read_race.rs @@ -1,4 +1,4 @@ -//@compile-flags: -Zmiri-preemption-rate=0.0 -Zmiri-disable-weak-memory-emulation +//@compile-flags:-Zmiri-deterministic-concurrency use std::sync::atomic::Ordering::*; use std::sync::atomic::*; diff --git a/src/tools/miri/tests/fail/data_race/local_variable_write_race.rs b/src/tools/miri/tests/fail/data_race/local_variable_write_race.rs index 7e00573146c2..ee1bef7ba5c0 100644 --- a/src/tools/miri/tests/fail/data_race/local_variable_write_race.rs +++ b/src/tools/miri/tests/fail/data_race/local_variable_write_race.rs @@ -1,4 +1,4 @@ -//@compile-flags: -Zmiri-preemption-rate=0.0 -Zmiri-disable-weak-memory-emulation +//@compile-flags:-Zmiri-deterministic-concurrency use std::sync::atomic::Ordering::*; use std::sync::atomic::*; diff --git a/src/tools/miri/tests/fail/data_race/mixed_size_read_read_write.rs b/src/tools/miri/tests/fail/data_race/mixed_size_read_read_write.rs index e76654806bb1..720602d011e3 100644 --- a/src/tools/miri/tests/fail/data_race/mixed_size_read_read_write.rs +++ b/src/tools/miri/tests/fail/data_race/mixed_size_read_read_write.rs @@ -1,6 +1,4 @@ -//@compile-flags: -Zmiri-preemption-rate=0.0 -Zmiri-disable-weak-memory-emulation -// Avoid accidental synchronization via address reuse inside `thread::spawn`. -//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 +//@compile-flags:-Zmiri-deterministic-concurrency // Two variants: the atomic store matches the size of the first or second atomic load. //@revisions: match_first_load match_second_load diff --git a/src/tools/miri/tests/fail/data_race/mixed_size_read_write.rs b/src/tools/miri/tests/fail/data_race/mixed_size_read_write.rs index 53016bab7804..78bba173ed7d 100644 --- a/src/tools/miri/tests/fail/data_race/mixed_size_read_write.rs +++ b/src/tools/miri/tests/fail/data_race/mixed_size_read_write.rs @@ -1,6 +1,4 @@ -//@compile-flags: -Zmiri-preemption-rate=0.0 -Zmiri-disable-weak-memory-emulation -// Avoid accidental synchronization via address reuse inside `thread::spawn`. -//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 +//@compile-flags:-Zmiri-deterministic-concurrency // Two revisions, depending on which access goes first. //@revisions: read_write write_read diff --git a/src/tools/miri/tests/fail/data_race/mixed_size_write_write.rs b/src/tools/miri/tests/fail/data_race/mixed_size_write_write.rs index 545e354a0372..808280a4b311 100644 --- a/src/tools/miri/tests/fail/data_race/mixed_size_write_write.rs +++ b/src/tools/miri/tests/fail/data_race/mixed_size_write_write.rs @@ -1,6 +1,4 @@ -//@compile-flags: -Zmiri-preemption-rate=0.0 -Zmiri-disable-weak-memory-emulation -// Avoid accidental synchronization via address reuse inside `thread::spawn`. -//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 +//@compile-flags:-Zmiri-deterministic-concurrency //@revisions: fst snd use std::sync::atomic::{AtomicU8, AtomicU16, Ordering}; diff --git a/src/tools/miri/tests/fail/data_race/read_write_race.rs b/src/tools/miri/tests/fail/data_race/read_write_race.rs index adf19dda9d3d..2aadef36c5b9 100644 --- a/src/tools/miri/tests/fail/data_race/read_write_race.rs +++ b/src/tools/miri/tests/fail/data_race/read_write_race.rs @@ -1,7 +1,5 @@ // We want to control preemption here. Stacked borrows interferes by having its own accesses. -//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows -// Avoid accidental synchronization via address reuse inside `thread::spawn`. -//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 +//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows use std::thread::spawn; diff --git a/src/tools/miri/tests/fail/data_race/read_write_race_stack.rs b/src/tools/miri/tests/fail/data_race/read_write_race_stack.rs index f411767f7b57..cca39bb002c1 100644 --- a/src/tools/miri/tests/fail/data_race/read_write_race_stack.rs +++ b/src/tools/miri/tests/fail/data_race/read_write_race_stack.rs @@ -1,6 +1,5 @@ -//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows -// Avoid accidental synchronization via address reuse inside `thread::spawn`. -//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 +// We want to control preemption here. Stacked borrows interferes by having its own accesses. +//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows use std::ptr::null_mut; use std::sync::atomic::{AtomicPtr, Ordering}; diff --git a/src/tools/miri/tests/fail/data_race/relax_acquire_race.rs b/src/tools/miri/tests/fail/data_race/relax_acquire_race.rs index c4f943808229..262c039e4ae1 100644 --- a/src/tools/miri/tests/fail/data_race/relax_acquire_race.rs +++ b/src/tools/miri/tests/fail/data_race/relax_acquire_race.rs @@ -1,6 +1,5 @@ -//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows -// Avoid accidental synchronization via address reuse inside `thread::spawn`. -//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 +// We want to control preemption here. Stacked borrows interferes by having its own accesses. +//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows use std::sync::atomic::{AtomicUsize, Ordering}; use std::thread::spawn; diff --git a/src/tools/miri/tests/fail/data_race/release_seq_race.rs b/src/tools/miri/tests/fail/data_race/release_seq_race.rs index f03ab3efa062..8aeb6ee6ef1d 100644 --- a/src/tools/miri/tests/fail/data_race/release_seq_race.rs +++ b/src/tools/miri/tests/fail/data_race/release_seq_race.rs @@ -1,6 +1,5 @@ -//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows -// Avoid accidental synchronization via address reuse inside `thread::spawn`. -//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 +// We want to control preemption here. Stacked borrows interferes by having its own accesses. +//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows use std::sync::atomic::{AtomicUsize, Ordering}; use std::thread::{sleep, spawn}; diff --git a/src/tools/miri/tests/fail/data_race/release_seq_race_same_thread.rs b/src/tools/miri/tests/fail/data_race/release_seq_race_same_thread.rs index 88ae01b3ca1c..f465160718f4 100644 --- a/src/tools/miri/tests/fail/data_race/release_seq_race_same_thread.rs +++ b/src/tools/miri/tests/fail/data_race/release_seq_race_same_thread.rs @@ -1,6 +1,5 @@ -//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows -// Avoid accidental synchronization via address reuse inside `thread::spawn`. -//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 +// We want to control preemption here. Stacked borrows interferes by having its own accesses. +//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows use std::sync::atomic::{AtomicUsize, Ordering}; use std::thread::spawn; diff --git a/src/tools/miri/tests/fail/data_race/rmw_race.rs b/src/tools/miri/tests/fail/data_race/rmw_race.rs index d738caa10587..39588c15ec7e 100644 --- a/src/tools/miri/tests/fail/data_race/rmw_race.rs +++ b/src/tools/miri/tests/fail/data_race/rmw_race.rs @@ -1,6 +1,5 @@ -//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows -// Avoid accidental synchronization via address reuse inside `thread::spawn`. -//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 +// We want to control preemption here. Stacked borrows interferes by having its own accesses. +//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows use std::sync::atomic::{AtomicUsize, Ordering}; use std::thread::spawn; diff --git a/src/tools/miri/tests/fail/data_race/stack_pop_race.rs b/src/tools/miri/tests/fail/data_race/stack_pop_race.rs index 762a8e51f692..5138bcbf8f74 100644 --- a/src/tools/miri/tests/fail/data_race/stack_pop_race.rs +++ b/src/tools/miri/tests/fail/data_race/stack_pop_race.rs @@ -1,6 +1,5 @@ -//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows -// Avoid accidental synchronization via address reuse inside `thread::spawn`. -//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 +// We want to control preemption here. Stacked borrows interferes by having its own accesses. +//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows use std::thread; diff --git a/src/tools/miri/tests/fail/data_race/write_write_race.rs b/src/tools/miri/tests/fail/data_race/write_write_race.rs index 993d8d25b4c1..b1a6b08b4c88 100644 --- a/src/tools/miri/tests/fail/data_race/write_write_race.rs +++ b/src/tools/miri/tests/fail/data_race/write_write_race.rs @@ -1,7 +1,5 @@ -// We want to control preemption here. -//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows -// Avoid accidental synchronization via address reuse inside `thread::spawn`. -//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 +// We want to control preemption here. Stacked borrows interferes by having its own accesses. +//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows use std::thread::spawn; diff --git a/src/tools/miri/tests/fail/data_race/write_write_race_stack.rs b/src/tools/miri/tests/fail/data_race/write_write_race_stack.rs index 8070a7f4fc2a..cd21b0a8fa6c 100644 --- a/src/tools/miri/tests/fail/data_race/write_write_race_stack.rs +++ b/src/tools/miri/tests/fail/data_race/write_write_race_stack.rs @@ -1,6 +1,5 @@ -//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 -Zmiri-disable-stacked-borrows -// Avoid accidental synchronization via address reuse inside `thread::spawn`. -//@compile-flags: -Zmiri-address-reuse-cross-thread-rate=0 +// We want to control preemption here. Stacked borrows interferes by having its own accesses. +//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-stacked-borrows use std::ptr::null_mut; use std::sync::atomic::{AtomicPtr, Ordering}; diff --git a/src/tools/miri/tests/fail/function_pointers/cast_int_to_fn_ptr.stderr b/src/tools/miri/tests/fail/function_pointers/cast_int_to_fn_ptr.stderr index f2d9933188d7..37d3beefcd7b 100644 --- a/src/tools/miri/tests/fail/function_pointers/cast_int_to_fn_ptr.stderr +++ b/src/tools/miri/tests/fail/function_pointers/cast_int_to_fn_ptr.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to some allocation, but got 0x2a[noalloc] which is a dangling pointer (it has no provenance) +error: Undefined Behavior: pointer not dereferenceable: pointer must point to some allocation, but got 0x2a[noalloc] which is a dangling pointer (it has no provenance) --> tests/fail/function_pointers/cast_int_to_fn_ptr.rs:LL:CC | LL | g(42) - | ^^^^^ out-of-bounds pointer use: expected a pointer to some allocation, but got 0x2a[noalloc] which is a dangling pointer (it has no provenance) + | ^^^^^ pointer not dereferenceable: pointer must point to some allocation, but got 0x2a[noalloc] which is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_int_plus_int.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_offset_int_plus_int.stderr index c87ce321784b..b7ed36f6428f 100644 --- a/src/tools/miri/tests/fail/intrinsics/ptr_offset_int_plus_int.stderr +++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_int_plus_int.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: out-of-bounds pointer arithmetic: expected a pointer to 1 byte of memory, but got 0x1[noalloc] which is a dangling pointer (it has no provenance) +error: Undefined Behavior: in-bounds pointer arithmetic failed: attempting to offset pointer by 1 byte, but got 0x1[noalloc] which is a dangling pointer (it has no provenance) --> tests/fail/intrinsics/ptr_offset_int_plus_int.rs:LL:CC | LL | let _val = (1 as *mut u8).offset(1); - | ^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: expected a pointer to 1 byte of memory, but got 0x1[noalloc] which is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^ in-bounds pointer arithmetic failed: attempting to offset pointer by 1 byte, but got 0x1[noalloc] which is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr index 78239d501378..29d9e1c64bd7 100644 --- a/src/tools/miri/tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr +++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: out-of-bounds pointer arithmetic: expected a pointer to $BYTES bytes of memory, but got 0x1[noalloc] which is a dangling pointer (it has no provenance) +error: Undefined Behavior: in-bounds pointer arithmetic failed: attempting to offset pointer by $BYTES bytes, but got 0x1[noalloc] which is a dangling pointer (it has no provenance) --> tests/fail/intrinsics/ptr_offset_int_plus_ptr.rs:LL:CC | LL | let _val = (1 as *mut u8).offset(ptr as isize); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: expected a pointer to $BYTES bytes of memory, but got 0x1[noalloc] which is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ in-bounds pointer arithmetic failed: attempting to offset pointer by $BYTES bytes, but got 0x1[noalloc] which is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds.rs b/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds.rs index 905fc678f6d5..e44d398c998c 100644 --- a/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds.rs +++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds.rs @@ -1,6 +1,6 @@ fn main() { let v = [0i8; 4]; let x = &v as *const i8; - let x = unsafe { x.offset(5) }; //~ERROR: expected a pointer to 5 bytes of memory + let x = unsafe { x.offset(5) }; //~ERROR: is only 4 bytes from the end of the allocation panic!("this should never print: {:?}", x); } diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds.stderr index 4f6b45b897b4..143fae8587b6 100644 --- a/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds.stderr +++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: out-of-bounds pointer arithmetic: expected a pointer to 5 bytes of memory, but got ALLOC which is only 4 bytes from the end of the allocation +error: Undefined Behavior: in-bounds pointer arithmetic failed: attempting to offset pointer by 5 bytes, but got ALLOC which is only 4 bytes from the end of the allocation --> tests/fail/intrinsics/ptr_offset_out_of_bounds.rs:LL:CC | LL | let x = unsafe { x.offset(5) }; - | ^^^^^^^^^^^ out-of-bounds pointer arithmetic: expected a pointer to 5 bytes of memory, but got ALLOC which is only 4 bytes from the end of the allocation + | ^^^^^^^^^^^ in-bounds pointer arithmetic failed: attempting to offset pointer by 5 bytes, but got ALLOC which is only 4 bytes from the end of the allocation | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds_neg.rs b/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds_neg.rs index bd1d5c064c06..5ad173735669 100644 --- a/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds_neg.rs +++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds_neg.rs @@ -1,6 +1,6 @@ fn main() { let v = [0i8; 4]; let x = &v as *const i8; - let x = unsafe { x.offset(-1) }; //~ERROR: expected a pointer to the end of 1 byte of memory + let x = unsafe { x.offset(-1) }; //~ERROR: is at the beginning of the allocation panic!("this should never print: {:?}", x); } diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds_neg.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds_neg.stderr index 2dd4c943e864..14163d924041 100644 --- a/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds_neg.stderr +++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_out_of_bounds_neg.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: out-of-bounds pointer arithmetic: expected a pointer to the end of 1 byte of memory, but got ALLOC which is at the beginning of the allocation +error: Undefined Behavior: in-bounds pointer arithmetic failed: attempting to offset pointer by -1 bytes, but got ALLOC which is at the beginning of the allocation --> tests/fail/intrinsics/ptr_offset_out_of_bounds_neg.rs:LL:CC | LL | let x = unsafe { x.offset(-1) }; - | ^^^^^^^^^^^^ out-of-bounds pointer arithmetic: expected a pointer to the end of 1 byte of memory, but got ALLOC which is at the beginning of the allocation + | ^^^^^^^^^^^^ in-bounds pointer arithmetic failed: attempting to offset pointer by -1 bytes, but got ALLOC which is at the beginning of the allocation | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_overflow.rs b/src/tools/miri/tests/fail/intrinsics/ptr_offset_overflow.rs index 683943122327..6767b1f117a8 100644 --- a/src/tools/miri/tests/fail/intrinsics/ptr_offset_overflow.rs +++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_overflow.rs @@ -3,6 +3,6 @@ fn main() { let v = [0i8; 4]; let x = &v as *const i8; - let x = unsafe { x.offset(isize::MIN) }; //~ERROR: out-of-bounds pointer arithmetic + let x = unsafe { x.offset(isize::MIN) }; //~ERROR: in-bounds pointer arithmetic failed panic!("this should never print: {:?}", x); } diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_overflow.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_offset_overflow.stderr index d03c9f870e24..af08bfb3c947 100644 --- a/src/tools/miri/tests/fail/intrinsics/ptr_offset_overflow.stderr +++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_overflow.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: out-of-bounds pointer arithmetic: expected a pointer to the end of $BYTES bytes of memory, but got ALLOC which is at the beginning of the allocation +error: Undefined Behavior: in-bounds pointer arithmetic failed: attempting to offset pointer by -$BYTES bytes, but got ALLOC which is at the beginning of the allocation --> tests/fail/intrinsics/ptr_offset_overflow.rs:LL:CC | LL | let x = unsafe { x.offset(isize::MIN) }; - | ^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: expected a pointer to the end of $BYTES bytes of memory, but got ALLOC which is at the beginning of the allocation + | ^^^^^^^^^^^^^^^^^^^^ in-bounds pointer arithmetic failed: attempting to offset pointer by -$BYTES bytes, but got ALLOC which is at the beginning of the allocation | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/intrinsics/simd-gather.rs b/src/tools/miri/tests/fail/intrinsics/simd-gather.rs index b83739524517..45a3dfa57724 100644 --- a/src/tools/miri/tests/fail/intrinsics/simd-gather.rs +++ b/src/tools/miri/tests/fail/intrinsics/simd-gather.rs @@ -6,6 +6,6 @@ fn main() { let vec: &[i8] = &[10, 11, 12, 13, 14, 15, 16, 17, 18]; let idxs = Simd::from_array([9, 3, 0, 17]); let _result = Simd::gather_select_unchecked(&vec, Mask::splat(true), idxs, Simd::splat(0)); - //~^ERROR: expected a pointer to 1 byte of memory + //~^ERROR: attempting to access 1 byte } } diff --git a/src/tools/miri/tests/fail/intrinsics/simd-gather.stderr b/src/tools/miri/tests/fail/intrinsics/simd-gather.stderr index ee1c90096108..e91d5d2185f3 100644 --- a/src/tools/miri/tests/fail/intrinsics/simd-gather.stderr +++ b/src/tools/miri/tests/fail/intrinsics/simd-gather.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: memory access failed: expected a pointer to 1 byte of memory, but got ALLOC+0x9 which is at or beyond the end of the allocation of size 9 bytes +error: Undefined Behavior: memory access failed: attempting to access 1 byte, but got ALLOC+0x9 which is at or beyond the end of the allocation of size 9 bytes --> tests/fail/intrinsics/simd-gather.rs:LL:CC | LL | let _result = Simd::gather_select_unchecked(&vec, Mask::splat(true), idxs, Simd::splat(0)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: expected a pointer to 1 byte of memory, but got ALLOC+0x9 which is at or beyond the end of the allocation of size 9 bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: attempting to access 1 byte, but got ALLOC+0x9 which is at or beyond the end of the allocation of size 9 bytes | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/intrinsics/simd-scatter.rs b/src/tools/miri/tests/fail/intrinsics/simd-scatter.rs index bb8c9dbe4c7a..4e727edd6244 100644 --- a/src/tools/miri/tests/fail/intrinsics/simd-scatter.rs +++ b/src/tools/miri/tests/fail/intrinsics/simd-scatter.rs @@ -6,7 +6,7 @@ fn main() { let mut vec: Vec = vec![10, 11, 12, 13, 14, 15, 16, 17, 18]; let idxs = Simd::from_array([9, 3, 0, 17]); Simd::from_array([-27, 82, -41, 124]).scatter_select_unchecked( - //~^ERROR: expected a pointer to 1 byte of memory + //~^ERROR: attempting to access 1 byte &mut vec, Mask::splat(true), idxs, diff --git a/src/tools/miri/tests/fail/intrinsics/simd-scatter.stderr b/src/tools/miri/tests/fail/intrinsics/simd-scatter.stderr index aaacb94f458d..56c8e7b38b64 100644 --- a/src/tools/miri/tests/fail/intrinsics/simd-scatter.stderr +++ b/src/tools/miri/tests/fail/intrinsics/simd-scatter.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: memory access failed: expected a pointer to 1 byte of memory, but got ALLOC+0x9 which is at or beyond the end of the allocation of size 9 bytes +error: Undefined Behavior: memory access failed: attempting to access 1 byte, but got ALLOC+0x9 which is at or beyond the end of the allocation of size 9 bytes --> tests/fail/intrinsics/simd-scatter.rs:LL:CC | LL | / Simd::from_array([-27, 82, -41, 124]).scatter_select_unchecked( @@ -7,7 +7,7 @@ LL | | &mut vec, LL | | Mask::splat(true), LL | | idxs, LL | | ); - | |_________^ memory access failed: expected a pointer to 1 byte of memory, but got ALLOC+0x9 which is at or beyond the end of the allocation of size 9 bytes + | |_________^ memory access failed: attempting to access 1 byte, but got ALLOC+0x9 which is at or beyond the end of the allocation of size 9 bytes | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/intrinsics/simd-select-bitmask-invalid.rs b/src/tools/miri/tests/fail/intrinsics/simd-select-bitmask-invalid.rs deleted file mode 100644 index 409098ac3b5d..000000000000 --- a/src/tools/miri/tests/fail/intrinsics/simd-select-bitmask-invalid.rs +++ /dev/null @@ -1,15 +0,0 @@ -#![feature(core_intrinsics, repr_simd)] - -use std::intrinsics::simd::simd_select_bitmask; - -#[repr(simd)] -#[allow(non_camel_case_types)] -#[derive(Copy, Clone)] -struct i32x2([i32; 2]); - -fn main() { - unsafe { - let x = i32x2([0, 1]); - simd_select_bitmask(0b11111111u8, x, x); //~ERROR: bitmask less than 8 bits long must be filled with 0s for the remaining bits - } -} diff --git a/src/tools/miri/tests/fail/intrinsics/simd-select-bitmask-invalid.stderr b/src/tools/miri/tests/fail/intrinsics/simd-select-bitmask-invalid.stderr deleted file mode 100644 index 9acb51d8c5f3..000000000000 --- a/src/tools/miri/tests/fail/intrinsics/simd-select-bitmask-invalid.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error: Undefined Behavior: a SIMD bitmask less than 8 bits long must be filled with 0s for the remaining bits - --> tests/fail/intrinsics/simd-select-bitmask-invalid.rs:LL:CC - | -LL | simd_select_bitmask(0b11111111u8, x, x); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ a SIMD bitmask less than 8 bits long must be filled with 0s for the remaining bits - | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE: - = note: inside `main` at tests/fail/intrinsics/simd-select-bitmask-invalid.rs:LL:CC - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to 1 previous error - diff --git a/src/tools/miri/tests/fail/provenance/int_copy_looses_provenance3.stderr b/src/tools/miri/tests/fail/provenance/int_copy_looses_provenance3.stderr index 62e3bd2e954c..4e741fe8329b 100644 --- a/src/tools/miri/tests/fail/provenance/int_copy_looses_provenance3.stderr +++ b/src/tools/miri/tests/fail/provenance/int_copy_looses_provenance3.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: memory access failed: expected a pointer to 4 bytes of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) +error: Undefined Behavior: memory access failed: attempting to access 4 bytes, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) --> tests/fail/provenance/int_copy_looses_provenance3.rs:LL:CC | LL | let _val = unsafe { *ptr }; - | ^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) + | ^^^^ memory access failed: attempting to access 4 bytes, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/provenance/pointer_partial_overwrite.stderr b/src/tools/miri/tests/fail/provenance/pointer_partial_overwrite.stderr index 6bc92fffd5af..370f9463b73c 100644 --- a/src/tools/miri/tests/fail/provenance/pointer_partial_overwrite.stderr +++ b/src/tools/miri/tests/fail/provenance/pointer_partial_overwrite.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: memory access failed: expected a pointer to 4 bytes of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) +error: Undefined Behavior: memory access failed: attempting to access 4 bytes, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) --> tests/fail/provenance/pointer_partial_overwrite.rs:LL:CC | LL | let x = *p; - | ^^ memory access failed: expected a pointer to 4 bytes of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) + | ^^ memory access failed: attempting to access 4 bytes, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/provenance/provenance_transmute.stderr b/src/tools/miri/tests/fail/provenance/provenance_transmute.stderr index 7403f4382de2..38e2e19009a9 100644 --- a/src/tools/miri/tests/fail/provenance/provenance_transmute.stderr +++ b/src/tools/miri/tests/fail/provenance/provenance_transmute.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: memory access failed: expected a pointer to 1 byte of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) +error: Undefined Behavior: memory access failed: attempting to access 1 byte, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) --> tests/fail/provenance/provenance_transmute.rs:LL:CC | LL | let _val = *left_ptr; - | ^^^^^^^^^ memory access failed: expected a pointer to 1 byte of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) + | ^^^^^^^^^ memory access failed: attempting to access 1 byte, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/provenance/ptr_copy_loses_partial_provenance0.stderr b/src/tools/miri/tests/fail/provenance/ptr_copy_loses_partial_provenance0.stderr index 5ed83951c60a..5225ab328652 100644 --- a/src/tools/miri/tests/fail/provenance/ptr_copy_loses_partial_provenance0.stderr +++ b/src/tools/miri/tests/fail/provenance/ptr_copy_loses_partial_provenance0.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: memory access failed: expected a pointer to 4 bytes of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) +error: Undefined Behavior: memory access failed: attempting to access 4 bytes, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) --> tests/fail/provenance/ptr_copy_loses_partial_provenance0.rs:LL:CC | LL | let _val = *ptr; - | ^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) + | ^^^^ memory access failed: attempting to access 4 bytes, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/provenance/ptr_copy_loses_partial_provenance1.stderr b/src/tools/miri/tests/fail/provenance/ptr_copy_loses_partial_provenance1.stderr index 3675653cbe79..c17c98fa1056 100644 --- a/src/tools/miri/tests/fail/provenance/ptr_copy_loses_partial_provenance1.stderr +++ b/src/tools/miri/tests/fail/provenance/ptr_copy_loses_partial_provenance1.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: memory access failed: expected a pointer to 4 bytes of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) +error: Undefined Behavior: memory access failed: attempting to access 4 bytes, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) --> tests/fail/provenance/ptr_copy_loses_partial_provenance1.rs:LL:CC | LL | let _val = *ptr; - | ^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) + | ^^^^ memory access failed: attempting to access 4 bytes, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/provenance/ptr_int_unexposed.stderr b/src/tools/miri/tests/fail/provenance/ptr_int_unexposed.stderr index 1b6518612efc..78290d4ed63b 100644 --- a/src/tools/miri/tests/fail/provenance/ptr_int_unexposed.stderr +++ b/src/tools/miri/tests/fail/provenance/ptr_int_unexposed.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: memory access failed: expected a pointer to 4 bytes of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) +error: Undefined Behavior: memory access failed: attempting to access 4 bytes, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) --> tests/fail/provenance/ptr_int_unexposed.rs:LL:CC | LL | assert_eq!(unsafe { *ptr }, 3); - | ^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) + | ^^^^ memory access failed: attempting to access 4 bytes, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/provenance/ptr_invalid.stderr b/src/tools/miri/tests/fail/provenance/ptr_invalid.stderr index 84347ec7a11d..ff73fbb9d1b3 100644 --- a/src/tools/miri/tests/fail/provenance/ptr_invalid.stderr +++ b/src/tools/miri/tests/fail/provenance/ptr_invalid.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: memory access failed: expected a pointer to 4 bytes of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) +error: Undefined Behavior: memory access failed: attempting to access 4 bytes, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) --> tests/fail/provenance/ptr_invalid.rs:LL:CC | LL | let _val = unsafe { *xptr_invalid }; - | ^^^^^^^^^^^^^ memory access failed: expected a pointer to 4 bytes of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^ memory access failed: attempting to access 4 bytes, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/provenance/ptr_invalid_offset.stderr b/src/tools/miri/tests/fail/provenance/ptr_invalid_offset.stderr index 3910bc4df4b0..07556540f13e 100644 --- a/src/tools/miri/tests/fail/provenance/ptr_invalid_offset.stderr +++ b/src/tools/miri/tests/fail/provenance/ptr_invalid_offset.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: out-of-bounds pointer arithmetic: expected a pointer to 1 byte of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) +error: Undefined Behavior: in-bounds pointer arithmetic failed: attempting to offset pointer by 1 byte, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) --> tests/fail/provenance/ptr_invalid_offset.rs:LL:CC | LL | let _ = unsafe { roundtrip.offset(1) }; - | ^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: expected a pointer to 1 byte of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) + | ^^^^^^^^^^^^^^^^^^^ in-bounds pointer arithmetic failed: attempting to offset pointer by 1 byte, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/rc_as_ptr.stderr b/src/tools/miri/tests/fail/rc_as_ptr.stderr index 0fcb0faf4971..e1d0e5780a07 100644 --- a/src/tools/miri/tests/fail/rc_as_ptr.stderr +++ b/src/tools/miri/tests/fail/rc_as_ptr.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: out-of-bounds pointer use: ALLOC has been freed, so this pointer is dangling +error: Undefined Behavior: pointer not dereferenceable: ALLOC has been freed, so this pointer is dangling --> tests/fail/rc_as_ptr.rs:LL:CC | LL | assert_eq!(42, **unsafe { &*Weak::as_ptr(&weak) }); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: ALLOC has been freed, so this pointer is dangling + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer not dereferenceable: ALLOC has been freed, so this pointer is dangling | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/reading_half_a_pointer.stderr b/src/tools/miri/tests/fail/reading_half_a_pointer.stderr index 921796441694..61fb9cd4e526 100644 --- a/src/tools/miri/tests/fail/reading_half_a_pointer.stderr +++ b/src/tools/miri/tests/fail/reading_half_a_pointer.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: memory access failed: expected a pointer to 1 byte of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) +error: Undefined Behavior: memory access failed: attempting to access 1 byte, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) --> tests/fail/reading_half_a_pointer.rs:LL:CC | LL | let _val = *x; - | ^^ memory access failed: expected a pointer to 1 byte of memory, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) + | ^^ memory access failed: attempting to access 1 byte, but got $HEX[noalloc] which is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-ptr.rs b/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-ptr.rs index 75f7aae9718d..a398eb1ae0c2 100644 --- a/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-ptr.rs +++ b/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-ptr.rs @@ -4,6 +4,6 @@ extern "Rust" { fn main() { unsafe { - miri_resolve_frame(std::ptr::null_mut(), 0); //~ ERROR: got a null pointer + miri_resolve_frame(std::ptr::null_mut(), 0); //~ ERROR: null pointer } } diff --git a/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-ptr.stderr b/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-ptr.stderr index 7ae9558fad70..126f41fbb0e6 100644 --- a/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-ptr.stderr +++ b/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-ptr.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: out-of-bounds pointer use: expected a pointer to some allocation, but got a null pointer +error: Undefined Behavior: pointer not dereferenceable: pointer must point to some allocation, but got null pointer --> tests/fail/shims/backtrace/bad-backtrace-ptr.rs:LL:CC | LL | miri_resolve_frame(std::ptr::null_mut(), 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: expected a pointer to some allocation, but got a null pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer not dereferenceable: pointer must point to some allocation, but got null pointer | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_protected_read.rs b/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_protected_read.rs index a6ee7b40c340..6ff69554387e 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_protected_read.rs +++ b/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_protected_read.rs @@ -1,5 +1,4 @@ -// Avoid accidental synchronization via address reuse. -//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-address-reuse-cross-thread-rate=0 +//@compile-flags:-Zmiri-deterministic-concurrency use std::thread; #[derive(Copy, Clone)] diff --git a/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.rs b/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.rs index 949f659e7e8e..f46f13a39e7a 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.rs +++ b/src/tools/miri/tests/fail/stacked_borrows/retag_data_race_read.rs @@ -1,6 +1,5 @@ //! Make sure that a retag acts like a read for the data race model. -// Avoid accidental synchronization via address reuse. -//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-address-reuse-cross-thread-rate=0 +//@compile-flags:-Zmiri-deterministic-concurrency #[derive(Copy, Clone)] struct SendPtr(*mut u8); diff --git a/src/tools/miri/tests/fail/tree_borrows/children-can-alias.default.stderr b/src/tools/miri/tests/fail/tree_borrows/children-can-alias.default.stderr deleted file mode 100644 index b9651e21ecec..000000000000 --- a/src/tools/miri/tests/fail/tree_borrows/children-can-alias.default.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error: Undefined Behavior: entering unreachable code - --> tests/fail/tree_borrows/children-can-alias.rs:LL:CC - | -LL | std::hint::unreachable_unchecked(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ entering unreachable code - | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE: - = note: inside `main` at tests/fail/tree_borrows/children-can-alias.rs:LL:CC - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to 1 previous error - diff --git a/src/tools/miri/tests/fail/tree_borrows/children-can-alias.rs b/src/tools/miri/tests/fail/tree_borrows/children-can-alias.rs deleted file mode 100644 index d3f272dfbf81..000000000000 --- a/src/tools/miri/tests/fail/tree_borrows/children-can-alias.rs +++ /dev/null @@ -1,58 +0,0 @@ -//@revisions: default uniq -//@compile-flags: -Zmiri-tree-borrows -//@[uniq]compile-flags: -Zmiri-unique-is-unique - -//! This is NOT intended behavior. -//! We should eventually find a solution so that the version with `Unique` passes too, -//! otherwise `Unique` is more strict than `&mut`! - -#![feature(ptr_internals)] - -use core::ptr::{Unique, addr_of_mut}; - -fn main() { - let mut data = 0u8; - let raw = addr_of_mut!(data); - unsafe { - raw_children_of_refmut_can_alias(&mut *raw); - raw_children_of_unique_can_alias(Unique::new_unchecked(raw)); - - // Ultimately the intended behavior is that both above tests would - // succeed. - std::hint::unreachable_unchecked(); - //~[default]^ ERROR: entering unreachable code - } -} - -unsafe fn raw_children_of_refmut_can_alias(x: &mut u8) { - let child1 = addr_of_mut!(*x); - let child2 = addr_of_mut!(*x); - // We create two raw aliases of `x`: they have the exact same - // tag and can be used interchangeably. - child1.write(1); - child2.write(2); - child1.write(1); - child2.write(2); -} - -unsafe fn raw_children_of_unique_can_alias(x: Unique) { - let child1 = x.as_ptr(); - let child2 = x.as_ptr(); - // Under `-Zmiri-unique-is-unique`, `Unique` accidentally offers more guarantees - // than `&mut`. Not because it responds differently to accesses but because - // there is no easy way to obtain a copy with the same tag. - // - // The closest (non-hack) attempt is two calls to `as_ptr`. - // - Without `-Zmiri-unique-is-unique`, independent `as_ptr` calls return pointers - // with the same tag that can thus be used interchangeably. - // - With the current implementation of `-Zmiri-unique-is-unique`, they return cousin - // tags with permissions that do not tolerate aliasing. - // Eventually we should make such aliasing allowed in some situations - // (e.g. when there is no protector), which will probably involve - // introducing a new kind of permission. - child1.write(1); - child2.write(2); - //~[uniq]^ ERROR: /write access through .* is forbidden/ - child1.write(1); - child2.write(2); -} diff --git a/src/tools/miri/tests/fail/tree_borrows/children-can-alias.uniq.stderr b/src/tools/miri/tests/fail/tree_borrows/children-can-alias.uniq.stderr deleted file mode 100644 index 83c506abb2d7..000000000000 --- a/src/tools/miri/tests/fail/tree_borrows/children-can-alias.uniq.stderr +++ /dev/null @@ -1,31 +0,0 @@ -error: Undefined Behavior: write access through at ALLOC[0x0] is forbidden - --> tests/fail/tree_borrows/children-can-alias.rs:LL:CC - | -LL | child2.write(2); - | ^^^^^^^^^^^^^^^ write access through at ALLOC[0x0] is forbidden - | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental - = help: the accessed tag has state Disabled which forbids this child write access -help: the accessed tag was created here, in the initial state Reserved - --> tests/fail/tree_borrows/children-can-alias.rs:LL:CC - | -LL | let child2 = x.as_ptr(); - | ^^^^^^^^^^ -help: the accessed tag later transitioned to Disabled due to a foreign write access at offsets [0x0..0x1] - --> tests/fail/tree_borrows/children-can-alias.rs:LL:CC - | -LL | child1.write(1); - | ^^^^^^^^^^^^^^^ - = help: this transition corresponds to a loss of read and write permissions - = note: BACKTRACE (of the first span): - = note: inside `raw_children_of_unique_can_alias` at tests/fail/tree_borrows/children-can-alias.rs:LL:CC -note: inside `main` - --> tests/fail/tree_borrows/children-can-alias.rs:LL:CC - | -LL | raw_children_of_unique_can_alias(Unique::new_unchecked(raw)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to 1 previous error - diff --git a/src/tools/miri/tests/fail/tree_borrows/reserved/cell-protected-write.rs b/src/tools/miri/tests/fail/tree_borrows/reserved/cell-protected-write.rs index 7af1a7636fad..bf963f6a8f77 100644 --- a/src/tools/miri/tests/fail/tree_borrows/reserved/cell-protected-write.rs +++ b/src/tools/miri/tests/fail/tree_borrows/reserved/cell-protected-write.rs @@ -12,16 +12,16 @@ use std::cell::UnsafeCell; fn main() { unsafe { let n = &mut UnsafeCell::new(0u8); - name!(n.get(), "base"); + name!(n as *mut _, "base"); let x = &mut *(n as *mut UnsafeCell<_>); - name!(x.get(), "x"); - let y = (&mut *n).get(); + name!(x as *mut _, "x"); + let y = (&mut *n) as *mut UnsafeCell<_> as *mut _; name!(y); write_second(x, y); unsafe fn write_second(x: &mut UnsafeCell, y: *mut u8) { let alloc_id = alloc_id!(x.get()); - name!(x.get(), "callee:x"); - name!(x.get()=>1, "caller:x"); + name!(x as *mut _, "callee:x"); + name!((x as *mut _)=>1, "caller:x"); name!(y, "callee:y"); name!(y, "caller:y"); print_state!(alloc_id); diff --git a/src/tools/miri/tests/fail/tree_borrows/reserved/cell-protected-write.stderr b/src/tools/miri/tests/fail/tree_borrows/reserved/cell-protected-write.stderr index 03f79fe0a5d7..10414df6a6a2 100644 --- a/src/tools/miri/tests/fail/tree_borrows/reserved/cell-protected-write.stderr +++ b/src/tools/miri/tests/fail/tree_borrows/reserved/cell-protected-write.stderr @@ -21,7 +21,7 @@ LL | *y = 1; help: the accessed tag was created here --> tests/fail/tree_borrows/reserved/cell-protected-write.rs:LL:CC | -LL | let y = (&mut *n).get(); +LL | let y = (&mut *n) as *mut UnsafeCell<_> as *mut _; | ^^^^^^^^^ help: the protected tag was created here, in the initial state Reserved --> tests/fail/tree_borrows/reserved/cell-protected-write.rs:LL:CC diff --git a/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.rs b/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.rs index 73f227fee2fc..024a14600b1b 100644 --- a/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.rs +++ b/src/tools/miri/tests/fail/tree_borrows/reservedim_spurious_write.rs @@ -1,7 +1,7 @@ // Illustrating a problematic interaction between Reserved, interior mutability, // and protectors, that makes spurious writes fail in the previous model of Tree Borrows. // As for all similar tests, we disable preemption so that the error message is deterministic. -//@compile-flags: -Zmiri-tree-borrows -Zmiri-preemption-rate=0 +//@compile-flags: -Zmiri-tree-borrows -Zmiri-deterministic-concurrency // // One revision without spurious read (default source code) and one with spurious read. // Both are expected to be UB. Both revisions are expected to have the *same* error diff --git a/src/tools/miri/tests/fail/tree_borrows/spurious_read.rs b/src/tools/miri/tests/fail/tree_borrows/spurious_read.rs index 50ef0ceef91e..4ca0fb943381 100644 --- a/src/tools/miri/tests/fail/tree_borrows/spurious_read.rs +++ b/src/tools/miri/tests/fail/tree_borrows/spurious_read.rs @@ -1,8 +1,8 @@ // We ensure a deterministic execution. // Note that we are *also* using barriers: the barriers enforce the -// specific interleaving of operations that we want, but only the preemption -// rate guarantees that the error message is also deterministic. -//@compile-flags: -Zmiri-preemption-rate=0 +// specific interleaving of operations that we want, but we need to disable +// preemption to ensure that the error message is also deterministic. +//@compile-flags: -Zmiri-deterministic-concurrency //@compile-flags: -Zmiri-tree-borrows use std::sync::{Arc, Barrier}; diff --git a/src/tools/miri/tests/fail/tree_borrows/unique.rs b/src/tools/miri/tests/fail/tree_borrows/unique.rs deleted file mode 100644 index 0844dd21a592..000000000000 --- a/src/tools/miri/tests/fail/tree_borrows/unique.rs +++ /dev/null @@ -1,27 +0,0 @@ -//@revisions: default uniq -//@compile-flags: -Zmiri-tree-borrows -//@[uniq]compile-flags: -Zmiri-unique-is-unique - -// A pattern that detects if `Unique` is treated as exclusive or not: -// activate the pointer behind a `Unique` then do a read that is parent -// iff `Unique` was specially reborrowed. - -#![feature(ptr_internals)] -use core::ptr::Unique; - -fn main() { - let mut data = 0u8; - let refmut = &mut data; - let rawptr = refmut as *mut u8; - - unsafe { - let uniq = Unique::new_unchecked(rawptr); - *uniq.as_ptr() = 1; // activation - let _maybe_parent = *rawptr; // maybe becomes Frozen - *uniq.as_ptr() = 2; - //~[uniq]^ ERROR: /write access through .* is forbidden/ - let _definitely_parent = data; // definitely Frozen by now - *uniq.as_ptr() = 3; - //~[default]^ ERROR: /write access through .* is forbidden/ - } -} diff --git a/src/tools/miri/tests/fail/tree_borrows/unique.uniq.stderr b/src/tools/miri/tests/fail/tree_borrows/unique.uniq.stderr deleted file mode 100644 index 4ecff3ea0e1f..000000000000 --- a/src/tools/miri/tests/fail/tree_borrows/unique.uniq.stderr +++ /dev/null @@ -1,38 +0,0 @@ -error: Undefined Behavior: write access through at ALLOC[0x0] is forbidden - --> tests/fail/tree_borrows/unique.rs:LL:CC - | -LL | *uniq.as_ptr() = 2; - | ^^^^^^^^^^^^^^^^^^ write access through at ALLOC[0x0] is forbidden - | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental - = help: the accessed tag is a child of the conflicting tag - = help: the conflicting tag has state Frozen which forbids this child write access -help: the accessed tag was created here - --> tests/fail/tree_borrows/unique.rs:LL:CC - | -LL | *uniq.as_ptr() = 2; - | ^^^^^^^^^^^^^ -help: the conflicting tag was created here, in the initial state Reserved - --> tests/fail/tree_borrows/unique.rs:LL:CC - | -LL | let uniq = Unique::new_unchecked(rawptr); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: the conflicting tag later transitioned to Active due to a child write access at offsets [0x0..0x1] - --> tests/fail/tree_borrows/unique.rs:LL:CC - | -LL | *uniq.as_ptr() = 1; // activation - | ^^^^^^^^^^^^^^^^^^ - = help: this transition corresponds to the first write to a 2-phase borrowed mutable reference -help: the conflicting tag later transitioned to Frozen due to a foreign read access at offsets [0x0..0x1] - --> tests/fail/tree_borrows/unique.rs:LL:CC - | -LL | let _maybe_parent = *rawptr; // maybe becomes Frozen - | ^^^^^^^ - = help: this transition corresponds to a loss of write permissions - = note: BACKTRACE (of the first span): - = note: inside `main` at tests/fail/tree_borrows/unique.rs:LL:CC - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to 1 previous error - diff --git a/src/tools/miri/tests/fail/weak_memory/weak_uninit.rs b/src/tools/miri/tests/fail/weak_memory/weak_uninit.rs index 79c97a5b7527..b4b4b0849877 100644 --- a/src/tools/miri/tests/fail/weak_memory/weak_uninit.rs +++ b/src/tools/miri/tests/fail/weak_memory/weak_uninit.rs @@ -1,4 +1,4 @@ -//@compile-flags: -Zmiri-ignore-leaks -Zmiri-preemption-rate=0 +//@compile-flags: -Zmiri-ignore-leaks -Zmiri-fixed-schedule // Tests showing weak memory behaviours are exhibited. All tests // return true when the desired behaviour is seen. diff --git a/src/tools/miri/tests/fail/zst_local_oob.rs b/src/tools/miri/tests/fail/zst_local_oob.rs index ab48b7d330b3..2bf184c72bae 100644 --- a/src/tools/miri/tests/fail/zst_local_oob.rs +++ b/src/tools/miri/tests/fail/zst_local_oob.rs @@ -1,5 +1,5 @@ fn main() { // make sure ZST locals cannot be accessed let x = &() as *const () as *const i8; - let _val = unsafe { *x }; //~ ERROR: expected a pointer to 1 byte of memory + let _val = unsafe { *x }; //~ ERROR: attempting to access 1 byte } diff --git a/src/tools/miri/tests/fail/zst_local_oob.stderr b/src/tools/miri/tests/fail/zst_local_oob.stderr index 26911948eff7..e9423096226e 100644 --- a/src/tools/miri/tests/fail/zst_local_oob.stderr +++ b/src/tools/miri/tests/fail/zst_local_oob.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: memory access failed: expected a pointer to 1 byte of memory, but got ALLOC which is at or beyond the end of the allocation of size 0 bytes +error: Undefined Behavior: memory access failed: attempting to access 1 byte, but got ALLOC which is at or beyond the end of the allocation of size 0 bytes --> tests/fail/zst_local_oob.rs:LL:CC | LL | let _val = unsafe { *x }; - | ^^ memory access failed: expected a pointer to 1 byte of memory, but got ALLOC which is at or beyond the end of the allocation of size 0 bytes + | ^^ memory access failed: attempting to access 1 byte, but got ALLOC which is at or beyond the end of the allocation of size 0 bytes | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/pass-dep/concurrency/apple-futex.rs b/src/tools/miri/tests/pass-dep/concurrency/apple-futex.rs index becb90eb9230..a28f08c3bb1a 100644 --- a/src/tools/miri/tests/pass-dep/concurrency/apple-futex.rs +++ b/src/tools/miri/tests/pass-dep/concurrency/apple-futex.rs @@ -1,5 +1,5 @@ //@only-target: darwin -//@compile-flags: -Zmiri-preemption-rate=0 +//@compile-flags: -Zmiri-deterministic-concurrency use std::time::{Duration, Instant}; use std::{io, ptr, thread}; diff --git a/src/tools/miri/tests/pass-dep/concurrency/env-cleanup-data-race.rs b/src/tools/miri/tests/pass-dep/concurrency/env-cleanup-data-race.rs index c9c9dc5dfd2a..91cf24a944ad 100644 --- a/src/tools/miri/tests/pass-dep/concurrency/env-cleanup-data-race.rs +++ b/src/tools/miri/tests/pass-dep/concurrency/env-cleanup-data-race.rs @@ -1,4 +1,4 @@ -//@compile-flags: -Zmiri-disable-isolation -Zmiri-preemption-rate=0 +//@compile-flags: -Zmiri-disable-isolation -Zmiri-deterministic-concurrency //@ignore-target: windows # No libc env support on Windows use std::ffi::CStr; diff --git a/src/tools/miri/tests/pass-dep/concurrency/freebsd-futex.rs b/src/tools/miri/tests/pass-dep/concurrency/freebsd-futex.rs index 38a0bf58148e..b10ded8e4d00 100644 --- a/src/tools/miri/tests/pass-dep/concurrency/freebsd-futex.rs +++ b/src/tools/miri/tests/pass-dep/concurrency/freebsd-futex.rs @@ -1,5 +1,5 @@ //@only-target: freebsd -//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-disable-isolation +//@compile-flags: -Zmiri-deterministic-concurrency -Zmiri-disable-isolation use std::mem::{self, MaybeUninit}; use std::ptr::{self, addr_of}; diff --git a/src/tools/miri/tests/pass-dep/concurrency/windows_detach_terminated.rs b/src/tools/miri/tests/pass-dep/concurrency/windows_detach_terminated.rs index fe2d20bb76f8..41b26c84393d 100644 --- a/src/tools/miri/tests/pass-dep/concurrency/windows_detach_terminated.rs +++ b/src/tools/miri/tests/pass-dep/concurrency/windows_detach_terminated.rs @@ -1,6 +1,6 @@ //@only-target: windows # Uses win32 api functions // We are making scheduler assumptions here. -//@compile-flags: -Zmiri-preemption-rate=0 +//@compile-flags: -Zmiri-deterministic-concurrency use std::os::windows::io::IntoRawHandle; use std::thread; diff --git a/src/tools/miri/tests/pass-dep/concurrency/windows_init_once.rs b/src/tools/miri/tests/pass-dep/concurrency/windows_init_once.rs index 6853395686aa..0a1fb1175079 100644 --- a/src/tools/miri/tests/pass-dep/concurrency/windows_init_once.rs +++ b/src/tools/miri/tests/pass-dep/concurrency/windows_init_once.rs @@ -1,6 +1,6 @@ //@only-target: windows # Uses win32 api functions // We are making scheduler assumptions here. -//@compile-flags: -Zmiri-preemption-rate=0 +//@compile-flags: -Zmiri-deterministic-concurrency use std::ptr::null_mut; use std::thread; diff --git a/src/tools/miri/tests/pass-dep/concurrency/windows_join_multiple.rs b/src/tools/miri/tests/pass-dep/concurrency/windows_join_multiple.rs index 2796541a3d72..acd9270ad16a 100644 --- a/src/tools/miri/tests/pass-dep/concurrency/windows_join_multiple.rs +++ b/src/tools/miri/tests/pass-dep/concurrency/windows_join_multiple.rs @@ -1,6 +1,6 @@ //@only-target: windows # Uses win32 api functions // We are making scheduler assumptions here. -//@compile-flags: -Zmiri-preemption-rate=0 +//@compile-flags: -Zmiri-deterministic-concurrency use std::os::windows::io::IntoRawHandle; use std::sync::atomic::{AtomicBool, Ordering}; diff --git a/src/tools/miri/tests/pass-dep/libc/libc-epoll-blocking.rs b/src/tools/miri/tests/pass-dep/libc/libc-epoll-blocking.rs index 825e1355848b..54ebfa9d198d 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-epoll-blocking.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-epoll-blocking.rs @@ -1,6 +1,6 @@ //@only-target: linux android illumos // test_epoll_block_then_unblock and test_epoll_race depend on a deterministic schedule. -//@compile-flags: -Zmiri-preemption-rate=0 +//@compile-flags: -Zmiri-deterministic-concurrency use std::convert::TryInto; use std::thread; diff --git a/src/tools/miri/tests/pass-dep/libc/libc-eventfd.rs b/src/tools/miri/tests/pass-dep/libc/libc-eventfd.rs index 30e1bbb8fa1b..56d215d0ed63 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-eventfd.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-eventfd.rs @@ -1,6 +1,6 @@ //@only-target: linux android illumos // test_race, test_blocking_read and test_blocking_write depend on a deterministic schedule. -//@compile-flags: -Zmiri-preemption-rate=0 +//@compile-flags: -Zmiri-deterministic-concurrency // FIXME(static_mut_refs): Do not allow `static_mut_refs` lint #![allow(static_mut_refs)] diff --git a/src/tools/miri/tests/pass-dep/libc/libc-pipe.rs b/src/tools/miri/tests/pass-dep/libc/libc-pipe.rs index d6072c2569e9..05f6c870c3d7 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-pipe.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-pipe.rs @@ -1,6 +1,6 @@ //@ignore-target: windows # No libc pipe on Windows // test_race depends on a deterministic schedule. -//@compile-flags: -Zmiri-preemption-rate=0 +//@compile-flags: -Zmiri-deterministic-concurrency use std::thread; fn main() { test_pipe(); diff --git a/src/tools/miri/tests/pass-dep/libc/libc-socketpair.rs b/src/tools/miri/tests/pass-dep/libc/libc-socketpair.rs index 9163fd3d06fa..9e48410f7045 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-socketpair.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-socketpair.rs @@ -1,6 +1,6 @@ //@ignore-target: windows # No libc socketpair on Windows // test_race depends on a deterministic schedule. -//@compile-flags: -Zmiri-preemption-rate=0 +//@compile-flags: -Zmiri-deterministic-concurrency // FIXME(static_mut_refs): Do not allow `static_mut_refs` lint #![allow(static_mut_refs)] diff --git a/src/tools/miri/tests/pass-dep/libc/pthread-sync.rs b/src/tools/miri/tests/pass-dep/libc/pthread-sync.rs index fa11b5b12990..255944662940 100644 --- a/src/tools/miri/tests/pass-dep/libc/pthread-sync.rs +++ b/src/tools/miri/tests/pass-dep/libc/pthread-sync.rs @@ -1,6 +1,6 @@ //@ignore-target: windows # No pthreads on Windows // We use `yield` to test specific interleavings, so disable automatic preemption. -//@compile-flags: -Zmiri-preemption-rate=0 +//@compile-flags: -Zmiri-deterministic-concurrency #![feature(sync_unsafe_cell)] use std::cell::SyncUnsafeCell; diff --git a/src/tools/miri/tests/pass/stacked-borrows/2phase.rs b/src/tools/miri/tests/pass/both_borrows/2phase.rs similarity index 55% rename from src/tools/miri/tests/pass/stacked-borrows/2phase.rs rename to src/tools/miri/tests/pass/both_borrows/2phase.rs index fb4ba6058373..7a3962a7c1a4 100644 --- a/src/tools/miri/tests/pass/stacked-borrows/2phase.rs +++ b/src/tools/miri/tests/pass/both_borrows/2phase.rs @@ -1,5 +1,5 @@ -// FIXME: this miscompiles with optimizations, see . -//@compile-flags: -Zmir-opt-level=0 +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows trait S: Sized { fn tpb(&mut self, _s: Self) {} @@ -31,9 +31,9 @@ fn two_phase3(b: bool) { )); } -#[allow(unreachable_code)] fn two_phase_raw() { let x: &mut Vec = &mut vec![]; + #[allow(unreachable_code)] // The `push` itself never gets reached. x.push({ // Unfortunately this does not trigger the problem of creating a // raw ponter from a pointer that had a two-phase borrow derived from @@ -59,52 +59,12 @@ fn two_phase_overlapping2() { x.add_assign(x + *l); } -fn with_interior_mutability() { - use std::cell::Cell; - - trait Thing: Sized { - fn do_the_thing(&mut self, _s: i32) {} - } - - impl Thing for Cell {} - - let mut x = Cell::new(1); - let l = &x; - - x.do_the_thing({ - x.set(3); - l.set(4); - x.get() + l.get() - }); -} - -// This one really shouldn't be accepted, but since we treat 2phase as raw, we do accept it. -// Tree Borrows rejects it. -fn aliasing_violation() { - struct Foo(u64); - impl Foo { - fn add(&mut self, n: u64) -> u64 { - self.0 + n - } - } - - let mut f = Foo(0); - let alias = &mut f.0 as *mut u64; - let res = f.add(unsafe { - *alias = 42; - 0 - }); - assert_eq!(res, 42); -} - fn main() { two_phase1(); two_phase2(); two_phase3(false); two_phase3(true); two_phase_raw(); - with_interior_mutability(); two_phase_overlapping1(); two_phase_overlapping2(); - aliasing_violation(); } diff --git a/src/tools/miri/tests/pass/stacked-borrows/stacked-borrows.rs b/src/tools/miri/tests/pass/both_borrows/basic_aliasing_model.rs similarity index 90% rename from src/tools/miri/tests/pass/stacked-borrows/stacked-borrows.rs rename to src/tools/miri/tests/pass/both_borrows/basic_aliasing_model.rs index 4261f411eea4..c2b6a7e68be5 100644 --- a/src/tools/miri/tests/pass/stacked-borrows/stacked-borrows.rs +++ b/src/tools/miri/tests/pass/both_borrows/basic_aliasing_model.rs @@ -1,14 +1,15 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows #![feature(allocator_api)] use std::ptr; -// Test various stacked-borrows-related things. +// Test various aliasing-model-related things. fn main() { read_does_not_invalidate1(); read_does_not_invalidate2(); mut_raw_then_mut_shr(); mut_shr_then_mut_raw(); mut_raw_mut(); - mut_raw_mut2(); partially_invalidate_mut(); drop_after_sharing(); // direct_mut_to_const_raw(); @@ -97,18 +98,6 @@ fn mut_raw_mut() { assert_eq!(x, 4); } -// A variant of `mut_raw_mut` that does *not* get accepted by Tree Borrows. -// It's kind of an accident that we accept it in Stacked Borrows... -fn mut_raw_mut2() { - unsafe { - let mut root = 0; - let to = &mut root as *mut i32; - *to = 0; - let _val = root; - *to = 0; - } -} - fn partially_invalidate_mut() { let data = &mut (0u8, 0u8); let reborrow = &mut *data as *mut (u8, u8); @@ -124,15 +113,6 @@ fn drop_after_sharing() { let _len = x.len(); } -// Make sure that coercing &mut T to *const T produces a writeable pointer. -// TODO: This is currently disabled, waiting on a decision on -/*fn direct_mut_to_const_raw() { - let x = &mut 0; - let y: *const i32 = x; - unsafe { *(y as *mut i32) = 1; } - assert_eq!(*x, 1); -}*/ - // Make sure that we can create two raw pointers from a mutable reference and use them both. fn two_raw() { unsafe { @@ -178,7 +158,7 @@ fn disjoint_mutable_subborrows() { let b = unsafe { borrow_field_b(ptr) }; b.push(4); a.push_str(" world"); - eprintln!("{:?} {:?}", a, b); + assert_eq!(format!("{:?} {:?}", a, b), r#""hello world" [0, 1, 2, 4]"#); } fn raw_ref_to_part() { @@ -243,7 +223,7 @@ fn not_unpin_not_protected() { pub struct NotUnpin(#[allow(dead_code)] i32, PhantomPinned); fn inner(x: &mut NotUnpin, f: fn(&mut NotUnpin)) { - // `f` may mutate, but it may not deallocate! + // `f` is allowed to deallocate `x`. f(x) } diff --git a/src/tools/miri/tests/pass/stacked-borrows/interior_mutability.rs b/src/tools/miri/tests/pass/both_borrows/interior_mutability.rs similarity index 84% rename from src/tools/miri/tests/pass/stacked-borrows/interior_mutability.rs rename to src/tools/miri/tests/pass/both_borrows/interior_mutability.rs index e86cb3711acb..f095e215e004 100644 --- a/src/tools/miri/tests/pass/stacked-borrows/interior_mutability.rs +++ b/src/tools/miri/tests/pass/both_borrows/interior_mutability.rs @@ -1,3 +1,5 @@ +//@revisions: stack tree +//@[tree]compile-flags: -Zmiri-tree-borrows #![allow(dangerous_implicit_autorefs)] use std::cell::{Cell, Ref, RefCell, RefMut, UnsafeCell}; @@ -14,6 +16,7 @@ fn main() { ref_protector(); ref_mut_protector(); rust_issue_68303(); + two_phase(); } fn aliasing_mut_and_shr() { @@ -102,7 +105,14 @@ fn unsafe_cell_invalidate() { let ref1 = unsafe { &mut *raw1 }; let raw2 = ref1 as *mut _; // Now the borrow stack is: raw1, ref2, raw2. - // So using raw1 invalidates raw2. + // + // For TB, the tree is + // + // Act x + // Res `- raw1 + // Res `- ref1, raw2 + // + // Either way, using raw1 invalidates raw2. f(unsafe { mem::transmute(raw2) }, raw1); } @@ -138,7 +148,7 @@ fn refcell_basic() { } } -// Adding a Stacked Borrows protector for `Ref` would break this +// Adding a protector for `Ref` would break this fn ref_protector() { fn break_it(rc: &RefCell, r: Ref<'_, i32>) { // `r` has a shared reference, it is passed in as argument and hence @@ -174,3 +184,27 @@ fn rust_issue_68303() { assert!(optional.is_some()); *handle = true; } + +fn two_phase() { + use std::cell::Cell; + + trait Thing: Sized { + fn do_the_thing(&mut self, _s: i32) {} + } + + impl Thing for Cell {} + + let mut x = Cell::new(1); + let l = &x; + + x.do_the_thing({ + // In TB terms: + // Several Foreign accesses (both Reads and Writes) to the location + // being reborrowed. Reserved + unprotected + interior mut + // makes the pointer immune to everything as long as all accesses + // are child accesses to its parent pointer x. + x.set(3); + l.set(4); + x.get() + l.get() + }); +} diff --git a/src/tools/miri/tests/pass/concurrency/data_race.rs b/src/tools/miri/tests/pass/concurrency/data_race.rs index d16de0ae8e23..d5dd1deb2d9d 100644 --- a/src/tools/miri/tests/pass/concurrency/data_race.rs +++ b/src/tools/miri/tests/pass/concurrency/data_race.rs @@ -1,4 +1,5 @@ -//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 +// This tests carefully crafted schedules to ensure they are not considered races. +//@compile-flags: -Zmiri-deterministic-concurrency use std::sync::atomic::*; use std::thread::{self, spawn}; diff --git a/src/tools/miri/tests/pass/concurrency/disable_data_race_detector.rs b/src/tools/miri/tests/pass/concurrency/disable_data_race_detector.rs index 354a4bef932e..ecc4ca59bd18 100644 --- a/src/tools/miri/tests/pass/concurrency/disable_data_race_detector.rs +++ b/src/tools/miri/tests/pass/concurrency/disable_data_race_detector.rs @@ -1,6 +1,6 @@ //@compile-flags: -Zmiri-disable-data-race-detector // Avoid non-determinism -//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-address-reuse-cross-thread-rate=0 +//@compile-flags: -Zmiri-deterministic-concurrency use std::thread::spawn; diff --git a/src/tools/miri/tests/pass/concurrency/spin_loops_nopreempt.rs b/src/tools/miri/tests/pass/concurrency/spin_loops_nopreempt.rs index 44b16e1ac74d..4361f1da9240 100644 --- a/src/tools/miri/tests/pass/concurrency/spin_loops_nopreempt.rs +++ b/src/tools/miri/tests/pass/concurrency/spin_loops_nopreempt.rs @@ -1,5 +1,5 @@ // This specifically tests behavior *without* preemption. -//@compile-flags: -Zmiri-preemption-rate=0 +//@compile-flags: -Zmiri-deterministic-concurrency use std::cell::Cell; use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; diff --git a/src/tools/miri/tests/pass/concurrency/sync.rs b/src/tools/miri/tests/pass/concurrency/sync.rs index 91c67b215a1a..a92359758dad 100644 --- a/src/tools/miri/tests/pass/concurrency/sync.rs +++ b/src/tools/miri/tests/pass/concurrency/sync.rs @@ -1,7 +1,7 @@ //@revisions: stack tree //@[tree]compile-flags: -Zmiri-tree-borrows // We use `yield` to test specific interleavings, so disable automatic preemption. -//@compile-flags: -Zmiri-disable-isolation -Zmiri-strict-provenance -Zmiri-preemption-rate=0 +//@compile-flags: -Zmiri-disable-isolation -Zmiri-deterministic-concurrency use std::sync::{Arc, Barrier, Condvar, Mutex, Once, RwLock}; use std::thread; diff --git a/src/tools/miri/tests/pass/concurrency/sync_nopreempt.rs b/src/tools/miri/tests/pass/concurrency/sync_nopreempt.rs index c6cff038f81e..bea8f87243aa 100644 --- a/src/tools/miri/tests/pass/concurrency/sync_nopreempt.rs +++ b/src/tools/miri/tests/pass/concurrency/sync_nopreempt.rs @@ -1,5 +1,5 @@ // We are making scheduler assumptions here. -//@compile-flags: -Zmiri-strict-provenance -Zmiri-preemption-rate=0 +//@compile-flags: -Zmiri-deterministic-concurrency use std::sync::{Arc, Condvar, Mutex, RwLock}; use std::thread; diff --git a/src/tools/miri/tests/pass/intrinsics/portable-simd.rs b/src/tools/miri/tests/pass/intrinsics/portable-simd.rs index cc753dac2156..e14ce51f35a3 100644 --- a/src/tools/miri/tests/pass/intrinsics/portable-simd.rs +++ b/src/tools/miri/tests/pass/intrinsics/portable-simd.rs @@ -331,6 +331,19 @@ fn simd_mask() { ); assert_eq!(selected1, i32x4::from_array([0, 0, 0, 1])); assert_eq!(selected2, selected1); + // Non-zero "padding" (the extra bits) is also allowed. + let selected1 = simd_select_bitmask::( + if cfg!(target_endian = "little") { 0b11111000 } else { 0b11110001 }, + i32x4::splat(1), // yes + i32x4::splat(0), // no + ); + let selected2 = simd_select_bitmask::<[u8; 1], _>( + if cfg!(target_endian = "little") { [0b11111000] } else { [0b11110001] }, + i32x4::splat(1), // yes + i32x4::splat(0), // no + ); + assert_eq!(selected1, i32x4::from_array([0, 0, 0, 1])); + assert_eq!(selected2, selected1); } // Non-power-of-2 multi-byte mask. diff --git a/src/tools/miri/tests/pass/panic/concurrent-panic.rs b/src/tools/miri/tests/pass/panic/concurrent-panic.rs index e804df90977a..4bf645960f70 100644 --- a/src/tools/miri/tests/pass/panic/concurrent-panic.rs +++ b/src/tools/miri/tests/pass/panic/concurrent-panic.rs @@ -1,5 +1,5 @@ // We are making scheduler assumptions here. -//@compile-flags: -Zmiri-preemption-rate=0 +//@compile-flags: -Zmiri-deterministic-concurrency //! Cause a panic in one thread while another thread is unwinding. This checks //! that separate threads have their own panicking state. diff --git a/src/tools/miri/tests/pass/shims/env/var.rs b/src/tools/miri/tests/pass/shims/env/var.rs index 655b29674e34..31e59c4a41cb 100644 --- a/src/tools/miri/tests/pass/shims/env/var.rs +++ b/src/tools/miri/tests/pass/shims/env/var.rs @@ -1,4 +1,4 @@ -//@compile-flags: -Zmiri-preemption-rate=0 +//@compile-flags: -Zmiri-deterministic-concurrency use std::{env, thread}; fn main() { diff --git a/src/tools/miri/tests/pass/stacked-borrows/stacked-borrows.stderr b/src/tools/miri/tests/pass/stacked-borrows/stacked-borrows.stderr deleted file mode 100644 index 8ee4e25dbef8..000000000000 --- a/src/tools/miri/tests/pass/stacked-borrows/stacked-borrows.stderr +++ /dev/null @@ -1 +0,0 @@ -"hello world" [0, 1, 2, 4] diff --git a/src/tools/miri/tests/pass/stacked-borrows/coroutine-self-referential.rs b/src/tools/miri/tests/pass/stacked_borrows/coroutine-self-referential.rs similarity index 100% rename from src/tools/miri/tests/pass/stacked-borrows/coroutine-self-referential.rs rename to src/tools/miri/tests/pass/stacked_borrows/coroutine-self-referential.rs diff --git a/src/tools/miri/tests/pass/stacked-borrows/int-to-ptr.rs b/src/tools/miri/tests/pass/stacked_borrows/int-to-ptr.rs similarity index 100% rename from src/tools/miri/tests/pass/stacked-borrows/int-to-ptr.rs rename to src/tools/miri/tests/pass/stacked_borrows/int-to-ptr.rs diff --git a/src/tools/miri/tests/pass/stacked-borrows/issue-miri-2389.rs b/src/tools/miri/tests/pass/stacked_borrows/issue-miri-2389.rs similarity index 100% rename from src/tools/miri/tests/pass/stacked-borrows/issue-miri-2389.rs rename to src/tools/miri/tests/pass/stacked_borrows/issue-miri-2389.rs diff --git a/src/tools/miri/tests/pass/stacked-borrows/issue-miri-2389.stderr b/src/tools/miri/tests/pass/stacked_borrows/issue-miri-2389.stderr similarity index 89% rename from src/tools/miri/tests/pass/stacked-borrows/issue-miri-2389.stderr rename to src/tools/miri/tests/pass/stacked_borrows/issue-miri-2389.stderr index bcb7a65e90f0..8ca3c6c618ea 100644 --- a/src/tools/miri/tests/pass/stacked-borrows/issue-miri-2389.stderr +++ b/src/tools/miri/tests/pass/stacked_borrows/issue-miri-2389.stderr @@ -1,5 +1,5 @@ warning: integer-to-pointer cast - --> tests/pass/stacked-borrows/issue-miri-2389.rs:LL:CC + --> tests/pass/stacked_borrows/issue-miri-2389.rs:LL:CC | LL | let wildcard = &root0 as *const Cell as usize as *const Cell; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ integer-to-pointer cast @@ -10,5 +10,5 @@ LL | let wildcard = &root0 as *const Cell as usize as *const Cell. +//@compile-flags: -Zmir-opt-level=0 + +// Test various stacked-borrows-specific things +// (i.e., these do not work the same under TB). +fn main() { + mut_raw_mut2(); + // direct_mut_to_const_raw(); + two_phase_aliasing_violation(); +} + +// A variant of `mut_raw_mut` that does *not* get accepted by Tree Borrows. +// It's kind of an accident that we accept it in Stacked Borrows... +fn mut_raw_mut2() { + unsafe { + let mut root = 0; + let to = &mut root as *mut i32; + *to = 0; + let _val = root; + *to = 0; + } +} + +// Make sure that coercing &mut T to *const T produces a writeable pointer. +// TODO: This is currently disabled, waiting on a decision on +/*fn direct_mut_to_const_raw() { + let x = &mut 0; + let y: *const i32 = x; + unsafe { *(y as *mut i32) = 1; } + assert_eq!(*x, 1); +}*/ + +// This one really shouldn't be accepted, but since we treat 2phase as raw, we do accept it. +// Tree Borrows rejects it. +fn two_phase_aliasing_violation() { + struct Foo(u64); + impl Foo { + fn add(&mut self, n: u64) -> u64 { + self.0 + n + } + } + + let mut f = Foo(0); + let alias = &mut f.0 as *mut u64; + let res = f.add(unsafe { + *alias = 42; + 0 + }); + assert_eq!(res, 42); +} diff --git a/src/tools/miri/tests/pass/stacked-borrows/unknown-bottom-gc.rs b/src/tools/miri/tests/pass/stacked_borrows/unknown-bottom-gc.rs similarity index 100% rename from src/tools/miri/tests/pass/stacked-borrows/unknown-bottom-gc.rs rename to src/tools/miri/tests/pass/stacked_borrows/unknown-bottom-gc.rs diff --git a/src/tools/miri/tests/pass/stacked-borrows/zst-field-retagging-terminates.rs b/src/tools/miri/tests/pass/stacked_borrows/zst-field-retagging-terminates.rs similarity index 100% rename from src/tools/miri/tests/pass/stacked-borrows/zst-field-retagging-terminates.rs rename to src/tools/miri/tests/pass/stacked_borrows/zst-field-retagging-terminates.rs diff --git a/src/tools/miri/tests/pass/tree_borrows/2phase-interiormut.rs b/src/tools/miri/tests/pass/tree_borrows/2phase-interiormut.rs deleted file mode 100644 index af52f53791a4..000000000000 --- a/src/tools/miri/tests/pass/tree_borrows/2phase-interiormut.rs +++ /dev/null @@ -1,27 +0,0 @@ -//@compile-flags: -Zmiri-tree-borrows - -// Counterpart to tests/fail/tree-borrows/write-during-2phase.rs, -// this is the opposite situation: the Write is not problematic because -// the Protector has not yet been added and the Reserved has interior -// mutability. -use core::cell::Cell; - -trait Thing: Sized { - fn do_the_thing(&mut self, _s: i32) {} -} -impl Thing for Cell {} - -fn main() { - let mut x = Cell::new(1); - let l = &x; - - x.do_the_thing({ - // Several Foreign accesses (both Reads and Writes) to the location - // being reborrowed. Reserved + unprotected + interior mut - // makes the pointer immune to everything as long as all accesses - // are child accesses to its parent pointer x. - x.set(3); - l.set(4); - x.get() + l.get() - }); -} diff --git a/src/tools/miri/tests/pass/tree_borrows/cell-alternate-writes.rs b/src/tools/miri/tests/pass/tree_borrows/cell-alternate-writes.rs index 3269acb51193..019ea369811d 100644 --- a/src/tools/miri/tests/pass/tree_borrows/cell-alternate-writes.rs +++ b/src/tools/miri/tests/pass/tree_borrows/cell-alternate-writes.rs @@ -6,16 +6,16 @@ mod utils; use std::cell::UnsafeCell; -// UnsafeCells use the parent tag, so it is possible to use them with +// UnsafeCells use the `Cell` state, so it is possible to use them with // few restrictions when only among themselves. fn main() { unsafe { let data = &mut UnsafeCell::new(0u8); - name!(data.get(), "data"); + name!(data as *mut _, "data"); let x = &*data; - name!(x.get(), "x"); + name!(x as *const _, "x"); let y = &*data; - name!(y.get(), "y"); + name!(y as *const _, "y"); let alloc_id = alloc_id!(data.get()); print_state!(alloc_id); // y and x tolerate alternating Writes diff --git a/src/tools/miri/tests/pass/tree_borrows/cell-alternate-writes.stderr b/src/tools/miri/tests/pass/tree_borrows/cell-alternate-writes.stderr index d13e9ad0215b..75a30c9a0837 100644 --- a/src/tools/miri/tests/pass/tree_borrows/cell-alternate-writes.stderr +++ b/src/tools/miri/tests/pass/tree_borrows/cell-alternate-writes.stderr @@ -2,11 +2,15 @@ Warning: this tree is indicative only. Some tags may have been hidden. 0.. 1 | Act | └─┬── -| ReIM| └──── +| ReIM| └─┬── +| Cel | ├──── +| Cel | └──── ────────────────────────────────────────────────── ────────────────────────────────────────────────── Warning: this tree is indicative only. Some tags may have been hidden. 0.. 1 | Act | └─┬── -| Act | └──── +| Act | └─┬── +| Cel | ├──── +| Cel | └──── ────────────────────────────────────────────────── diff --git a/src/tools/miri/tests/pass/tree_borrows/cell-inside-box.rs b/src/tools/miri/tests/pass/tree_borrows/cell-inside-box.rs new file mode 100644 index 000000000000..adf2f4e845b5 --- /dev/null +++ b/src/tools/miri/tests/pass/tree_borrows/cell-inside-box.rs @@ -0,0 +1,35 @@ +//@compile-flags: -Zmiri-tree-borrows +#![feature(box_as_ptr)] +#[path = "../../utils/mod.rs"] +#[macro_use] +mod utils; + +use std::cell::UnsafeCell; + +pub fn main() { + let cell = UnsafeCell::new(42); + let box1 = Box::new(cell); + + unsafe { + let ptr1: *mut UnsafeCell = Box::into_raw(box1); + name!(ptr1); + + let mut box2 = Box::from_raw(ptr1); + // `ptr2` will be a descendant of `ptr1`. + let ptr2: *mut UnsafeCell = Box::as_mut_ptr(&mut box2); + name!(ptr2); + + // We perform a write through `x`. + // Because `ptr1` is ReservedIM, a child write will make it transition to Active. + // Because `ptr2` is ReservedIM, a foreign write doesn't have any effect on it. + let x = (*ptr1).get(); + *x = 1; + + // We can still read from `ptr2`. + let val = *(*ptr2).get(); + assert_eq!(val, 1); + + let alloc_id = alloc_id!(ptr1); + print_state!(alloc_id); + } +} diff --git a/src/tools/miri/tests/pass/tree_borrows/vec_unique.uniq.stderr b/src/tools/miri/tests/pass/tree_borrows/cell-inside-box.stderr similarity index 67% rename from src/tools/miri/tests/pass/tree_borrows/vec_unique.uniq.stderr rename to src/tools/miri/tests/pass/tree_borrows/cell-inside-box.stderr index 7942e9884f40..5dbfff718b1e 100644 --- a/src/tools/miri/tests/pass/tree_borrows/vec_unique.uniq.stderr +++ b/src/tools/miri/tests/pass/tree_borrows/cell-inside-box.stderr @@ -1,8 +1,7 @@ ────────────────────────────────────────────────── Warning: this tree is indicative only. Some tags may have been hidden. -0.. 2 +0.. 4 | Act | └─┬── -|-----| └─┬── -|-----| └─┬── -|-----| └──── +| Act | └─┬── +| ReIM| └──── ────────────────────────────────────────────────── diff --git a/src/tools/miri/tests/pass/tree_borrows/interior_mutability.rs b/src/tools/miri/tests/pass/tree_borrows/interior_mutability.rs deleted file mode 100644 index 6dde593d2cfc..000000000000 --- a/src/tools/miri/tests/pass/tree_borrows/interior_mutability.rs +++ /dev/null @@ -1,178 +0,0 @@ -//@revisions: default uniq -//@compile-flags: -Zmiri-tree-borrows -//@[uniq]compile-flags: -Zmiri-unique-is-unique -#![allow(dangerous_implicit_autorefs)] -use std::cell::{Cell, Ref, RefCell, RefMut, UnsafeCell}; -use std::mem::{self, MaybeUninit}; - -fn main() { - aliasing_mut_and_shr(); - aliasing_frz_and_shr(); - into_interior_mutability(); - unsafe_cell_2phase(); - unsafe_cell_deallocate(); - unsafe_cell_invalidate(); - refcell_basic(); - ref_protector(); - ref_mut_protector(); - rust_issue_68303(); -} - -fn aliasing_mut_and_shr() { - fn inner(rc: &RefCell, aliasing: &mut i32) { - *aliasing += 4; - let _escape_to_raw = rc as *const _; - *aliasing += 4; - let _shr = &*rc; - *aliasing += 4; - // also turning this into a frozen ref now must work - let aliasing = &*aliasing; - let _val = *aliasing; - let _escape_to_raw = rc as *const _; // this must NOT unfreeze - let _val = *aliasing; - let _shr = &*rc; // this must NOT unfreeze - let _val = *aliasing; - } - - let rc = RefCell::new(23); - let mut bmut = rc.borrow_mut(); - inner(&rc, &mut *bmut); - drop(bmut); - assert_eq!(*rc.borrow(), 23 + 12); -} - -fn aliasing_frz_and_shr() { - fn inner(rc: &RefCell, aliasing: &i32) { - let _val = *aliasing; - let _escape_to_raw = rc as *const _; // this must NOT unfreeze - let _val = *aliasing; - let _shr = &*rc; // this must NOT unfreeze - let _val = *aliasing; - } - - let rc = RefCell::new(23); - let bshr = rc.borrow(); - inner(&rc, &*bshr); - assert_eq!(*rc.borrow(), 23); -} - -// Getting a pointer into a union with interior mutability used to be tricky -// business (https://github.com/rust-lang/miri/issues/615), but it should work -// now. -fn into_interior_mutability() { - let mut x: MaybeUninit<(Cell, u32)> = MaybeUninit::uninit(); - x.as_ptr(); - x.write((Cell::new(0), 1)); - let ptr = unsafe { x.assume_init_ref() }; - assert_eq!(ptr.1, 1); -} - -// Two-phase borrows of the pointer returned by UnsafeCell::get() should not -// invalidate aliases. -fn unsafe_cell_2phase() { - unsafe { - let x = &UnsafeCell::new(vec![]); - let x2 = &*x; - (*x.get()).push(0); - let _val = (*x2.get()).get(0); - } -} - -/// Make sure we can deallocate an UnsafeCell that was passed to an active fn call. -/// (This is the fix for https://github.com/rust-lang/rust/issues/55005.) -fn unsafe_cell_deallocate() { - fn f(x: &UnsafeCell) { - let b: Box = unsafe { Box::from_raw(x as *const _ as *mut i32) }; - drop(b) - } - - let b = Box::new(0i32); - f(unsafe { mem::transmute(Box::into_raw(b)) }); -} - -/// As a side-effect of the above, we also allow this -- at least for now. -fn unsafe_cell_invalidate() { - fn f(_x: &UnsafeCell, y: *mut i32) { - // Writing to y invalidates x, but that is okay. - unsafe { - *y += 1; - } - } - - let mut x = 0i32; - let raw1 = &mut x as *mut _; - let ref1 = unsafe { &mut *raw1 }; - let raw2 = ref1 as *mut _; - // Now the borrow stack is: raw1, ref2, raw2. - // So using raw1 invalidates raw2. - f(unsafe { mem::transmute(raw2) }, raw1); -} - -fn refcell_basic() { - let c = RefCell::new(42); - { - let s1 = c.borrow(); - let _x: i32 = *s1; - let s2 = c.borrow(); - let _x: i32 = *s1; - let _y: i32 = *s2; - let _x: i32 = *s1; - let _y: i32 = *s2; - } - { - let mut m = c.borrow_mut(); - let _z: i32 = *m; - { - let s: &i32 = &*m; - let _x = *s; - } - *m = 23; - let _z: i32 = *m; - } - { - let s1 = c.borrow(); - let _x: i32 = *s1; - let s2 = c.borrow(); - let _x: i32 = *s1; - let _y: i32 = *s2; - let _x: i32 = *s1; - let _y: i32 = *s2; - } -} - -// Adding a Stacked Borrows protector for `Ref` would break this -fn ref_protector() { - fn break_it(rc: &RefCell, r: Ref<'_, i32>) { - // `r` has a shared reference, it is passed in as argument and hence - // a protector is added that marks this memory as read-only for the entire - // duration of this function. - drop(r); - // *oops* here we can mutate that memory. - *rc.borrow_mut() = 2; - } - - let rc = RefCell::new(0); - break_it(&rc, rc.borrow()) -} - -fn ref_mut_protector() { - fn break_it(rc: &RefCell, r: RefMut<'_, i32>) { - // `r` has a shared reference, it is passed in as argument and hence - // a protector is added that marks this memory as inaccessible for the entire - // duration of this function - drop(r); - // *oops* here we can mutate that memory. - *rc.borrow_mut() = 2; - } - - let rc = RefCell::new(0); - break_it(&rc, rc.borrow_mut()) -} - -/// Make sure we do not have bad enum layout optimizations. -fn rust_issue_68303() { - let optional = Some(RefCell::new(false)); - let mut handle = optional.as_ref().unwrap().borrow_mut(); - assert!(optional.is_some()); - *handle = true; -} diff --git a/src/tools/miri/tests/pass/tree_borrows/read_retag_no_race.rs b/src/tools/miri/tests/pass/tree_borrows/read_retag_no_race.rs index d9897a1033fb..71b7817a9c70 100644 --- a/src/tools/miri/tests/pass/tree_borrows/read_retag_no_race.rs +++ b/src/tools/miri/tests/pass/tree_borrows/read_retag_no_race.rs @@ -2,7 +2,7 @@ // This test relies on a specific interleaving that cannot be enforced // with just barriers. We must remove preemption so that the execution and the // error messages are deterministic. -//@compile-flags: -Zmiri-preemption-rate=0 +//@compile-flags: -Zmiri-deterministic-concurrency use std::ptr::addr_of_mut; use std::sync::{Arc, Barrier}; use std::thread; diff --git a/src/tools/miri/tests/pass/tree_borrows/reserved.rs b/src/tools/miri/tests/pass/tree_borrows/reserved.rs index f93cac8361e3..c57cd7fcf0ab 100644 --- a/src/tools/miri/tests/pass/tree_borrows/reserved.rs +++ b/src/tools/miri/tests/pass/tree_borrows/reserved.rs @@ -43,11 +43,11 @@ unsafe fn read_second(x: &mut T, y: *mut u8) { unsafe fn cell_protected_read() { print("[interior mut + protected] Foreign Read: Re* -> Frz"); let base = &mut UnsafeCell::new(0u8); - name!(base.get(), "base"); + name!(base as *mut _, "base"); let alloc_id = alloc_id!(base.get()); let x = &mut *(base as *mut UnsafeCell); - name!(x.get(), "x"); - let y = (&mut *base).get(); + name!(x as *mut _, "x"); + let y = &mut *base as *mut UnsafeCell as *mut u8; name!(y); read_second(x, y); // Foreign Read for callee:x print_state!(alloc_id); @@ -57,11 +57,11 @@ unsafe fn cell_protected_read() { unsafe fn cell_unprotected_read() { print("[interior mut] Foreign Read: Re* -> Re*"); let base = &mut UnsafeCell::new(0u64); - name!(base.get(), "base"); + name!(base as *mut _, "base"); let alloc_id = alloc_id!(base.get()); let x = &mut *(base as *mut UnsafeCell<_>); - name!(x.get(), "x"); - let y = (&mut *base).get(); + name!(x as *mut _, "x"); + let y = &mut *base as *mut UnsafeCell as *mut u64; name!(y); let _val = *y; // Foreign Read for x print_state!(alloc_id); @@ -72,11 +72,11 @@ unsafe fn cell_unprotected_read() { unsafe fn cell_unprotected_write() { print("[interior mut] Foreign Write: Re* -> Re*"); let base = &mut UnsafeCell::new(0u64); - name!(base.get(), "base"); + name!(base as *mut _, "base"); let alloc_id = alloc_id!(base.get()); let x = &mut *(base as *mut UnsafeCell); - name!(x.get(), "x"); - let y = (&mut *base).get(); + name!(x as *mut _, "x"); + let y = &mut *base as *mut UnsafeCell as *mut u64; name!(y); *y = 1; // Foreign Write for x print_state!(alloc_id); diff --git a/src/tools/miri/tests/pass/tree_borrows/spurious_read.rs b/src/tools/miri/tests/pass/tree_borrows/spurious_read.rs index 71e93d2f84f5..840832c633cf 100644 --- a/src/tools/miri/tests/pass/tree_borrows/spurious_read.rs +++ b/src/tools/miri/tests/pass/tree_borrows/spurious_read.rs @@ -2,7 +2,7 @@ // Note that we are *also* using barriers: the barriers enforce the // specific interleaving of operations that we want, but only the preemption // rate guarantees that the error message is also deterministic. -//@compile-flags: -Zmiri-preemption-rate=0 +//@compile-flags: -Zmiri-deterministic-concurrency //@compile-flags: -Zmiri-tree-borrows use std::sync::{Arc, Barrier}; diff --git a/src/tools/miri/tests/pass/tree_borrows/tree-borrows.rs b/src/tools/miri/tests/pass/tree_borrows/tree-borrows.rs index b9d5ca06ed05..87eb447049d6 100644 --- a/src/tools/miri/tests/pass/tree_borrows/tree-borrows.rs +++ b/src/tools/miri/tests/pass/tree_borrows/tree-borrows.rs @@ -1,10 +1,10 @@ -//@revisions: default uniq //@compile-flags: -Zmiri-tree-borrows -//@[uniq]compile-flags: -Zmiri-unique-is-unique #![feature(allocator_api)] use std::{mem, ptr}; +// Test various tree-borrows-specific things +// (i.e., these do not work the same under SB). fn main() { aliasing_read_only_mutable_refs(); string_as_mut_ptr(); @@ -12,24 +12,6 @@ fn main() { direct_mut_to_const_raw(); local_addr_of_mut(); returned_mut_is_usable(); - - // Stacked Borrows tests - read_does_not_invalidate1(); - read_does_not_invalidate2(); - mut_raw_then_mut_shr(); - mut_shr_then_mut_raw(); - mut_raw_mut(); - partially_invalidate_mut(); - drop_after_sharing(); - two_raw(); - shr_and_raw(); - disjoint_mutable_subborrows(); - raw_ref_to_part(); - array_casts(); - mut_below_shr(); - wide_raw_ptr_in_tuple(); - not_unpin_not_protected(); - write_does_not_invalidate_all_aliases(); } #[allow(unused_assignments)] @@ -111,96 +93,6 @@ fn returned_mut_is_usable() { *y = 1; } -// ----- The tests below were taken from Stacked Borrows ---- - -// Make sure that reading from an `&mut` does, like reborrowing to `&`, -// NOT invalidate other reborrows. -fn read_does_not_invalidate1() { - fn foo(x: &mut (i32, i32)) -> &i32 { - let xraw = x as *mut (i32, i32); - let ret = unsafe { &(*xraw).1 }; - let _val = x.1; // we just read, this does NOT invalidate the reborrows. - ret - } - assert_eq!(*foo(&mut (1, 2)), 2); -} -// Same as above, but this time we first create a raw, then read from `&mut` -// and then freeze from the raw. -fn read_does_not_invalidate2() { - fn foo(x: &mut (i32, i32)) -> &i32 { - let xraw = x as *mut (i32, i32); - let _val = x.1; // we just read, this does NOT invalidate the raw reborrow. - let ret = unsafe { &(*xraw).1 }; - ret - } - assert_eq!(*foo(&mut (1, 2)), 2); -} - -// Escape a mut to raw, then share the same mut and use the share, then the raw. -// That should work. -fn mut_raw_then_mut_shr() { - let mut x = 2; - let xref = &mut x; - let xraw = &mut *xref as *mut _; - let xshr = &*xref; - assert_eq!(*xshr, 2); - unsafe { - *xraw = 4; - } - assert_eq!(x, 4); -} - -// Create first a shared reference and then a raw pointer from a `&mut` -// should permit mutation through that raw pointer. -fn mut_shr_then_mut_raw() { - let xref = &mut 2; - let _xshr = &*xref; - let xraw = xref as *mut _; - unsafe { - *xraw = 3; - } - assert_eq!(*xref, 3); -} - -// Ensure that if we derive from a mut a raw, and then from that a mut, -// and then read through the original mut, that does not invalidate the raw. -// This shows that the read-exception for `&mut` applies even if the `Shr` item -// on the stack is not at the top. -fn mut_raw_mut() { - let mut x = 2; - { - let xref1 = &mut x; - let xraw = xref1 as *mut _; - let _xref2 = unsafe { &mut *xraw }; - let _val = *xref1; - unsafe { - *xraw = 4; - } - // we can now use both xraw and xref1, for reading - assert_eq!(*xref1, 4); - assert_eq!(unsafe { *xraw }, 4); - assert_eq!(*xref1, 4); - assert_eq!(unsafe { *xraw }, 4); - // we cannot use xref2; see `compile-fail/stacked-borrows/illegal_read4.rs` - } - assert_eq!(x, 4); -} - -fn partially_invalidate_mut() { - let data = &mut (0u8, 0u8); - let reborrow = &mut *data as *mut (u8, u8); - let shard = unsafe { &mut (*reborrow).0 }; - data.1 += 1; // the deref overlaps with `shard`, but that is ok; the access does not overlap. - *shard += 1; // so we can still use `shard`. - assert_eq!(*data, (1, 1)); -} - -// Make sure that we can handle the situation where a location is frozen when being dropped. -fn drop_after_sharing() { - let x = String::from("hello!"); - let _len = x.len(); -} - // Make sure that coercing &mut T to *const T produces a writeable pointer. fn direct_mut_to_const_raw() { let x = &mut 0; @@ -210,150 +102,3 @@ fn direct_mut_to_const_raw() { } assert_eq!(*x, 1); } - -// Make sure that we can create two raw pointers from a mutable reference and use them both. -fn two_raw() { - unsafe { - let x = &mut 0; - let y1 = x as *mut _; - let y2 = x as *mut _; - *y1 += 2; - *y2 += 1; - } -} - -// Make sure that creating a *mut does not invalidate existing shared references. -fn shr_and_raw() { - unsafe { - let x = &mut 0; - let y1: &i32 = mem::transmute(&*x); // launder lifetimes - let y2 = x as *mut _; - let _val = *y1; - *y2 += 1; - } -} - -fn disjoint_mutable_subborrows() { - struct Foo { - a: String, - b: Vec, - } - - unsafe fn borrow_field_a<'a>(this: *mut Foo) -> &'a mut String { - &mut (*this).a - } - - unsafe fn borrow_field_b<'a>(this: *mut Foo) -> &'a mut Vec { - &mut (*this).b - } - - let mut foo = Foo { a: "hello".into(), b: vec![0, 1, 2] }; - - let ptr = &mut foo as *mut Foo; - - let a = unsafe { borrow_field_a(ptr) }; - let b = unsafe { borrow_field_b(ptr) }; - b.push(4); - a.push_str(" world"); - assert_eq!(format!("{:?} {:?}", a, b), r#""hello world" [0, 1, 2, 4]"#); -} - -fn raw_ref_to_part() { - struct Part { - _lame: i32, - } - - #[repr(C)] - struct Whole { - part: Part, - extra: i32, - } - - let it = Box::new(Whole { part: Part { _lame: 0 }, extra: 42 }); - let whole = ptr::addr_of_mut!(*Box::leak(it)); - let part = unsafe { ptr::addr_of_mut!((*whole).part) }; - let typed = unsafe { &mut *(part as *mut Whole) }; - assert!(typed.extra == 42); - drop(unsafe { Box::from_raw(whole) }); -} - -/// When casting an array reference to a raw element ptr, that should cover the whole array. -fn array_casts() { - let mut x: [usize; 2] = [0, 0]; - let p = &mut x as *mut usize; - unsafe { - *p.add(1) = 1; - } - - let x: [usize; 2] = [0, 1]; - let p = &x as *const usize; - assert_eq!(unsafe { *p.add(1) }, 1); -} - -/// Transmuting &&i32 to &&mut i32 is fine. -fn mut_below_shr() { - let x = 0; - let y = &x; - let p = unsafe { core::mem::transmute::<&&i32, &&mut i32>(&y) }; - let r = &**p; - let _val = *r; -} - -fn wide_raw_ptr_in_tuple() { - let mut x: Box = Box::new("ouch"); - let r = &mut *x as *mut dyn std::any::Any; - // This triggers the visitor-based recursive retagging. It is *not* supposed to retag raw - // pointers, but then the visitor might recurse into the "fields" of a wide raw pointer and - // finds a reference (to a vtable) there that it wants to retag... and that would be Wrong. - let pair = (r, &0); - let r = unsafe { &mut *pair.0 }; - // Make sure the fn ptr part of the vtable is still fine. - r.type_id(); -} - -fn not_unpin_not_protected() { - // `&mut !Unpin`, at least for now, does not get `noalias` nor `dereferenceable`, so we also - // don't add protectors. (We could, but until we have a better idea for where we want to go with - // the self-referential-coroutine situation, it does not seem worth the potential trouble.) - use std::marker::PhantomPinned; - - pub struct NotUnpin(#[allow(dead_code)] i32, PhantomPinned); - - fn inner(x: &mut NotUnpin, f: fn(&mut NotUnpin)) { - // `f` is allowed to deallocate `x`. - f(x) - } - - inner(Box::leak(Box::new(NotUnpin(0, PhantomPinned))), |x| { - let raw = x as *mut _; - drop(unsafe { Box::from_raw(raw) }); - }); -} - -fn write_does_not_invalidate_all_aliases() { - // In TB there are other ways to do that (`addr_of!(*x)` has the same tag as `x`), - // but let's still make sure this SB test keeps working. - - mod other { - /// Some private memory to store stuff in. - static mut S: *mut i32 = 0 as *mut i32; - - pub fn lib1(x: &&mut i32) { - unsafe { - S = (x as *const &mut i32).cast::<*mut i32>().read(); - } - } - - pub fn lib2() { - unsafe { - *S = 1337; - } - } - } - - let x = &mut 0; - other::lib1(&x); - *x = 42; // a write to x -- invalidates other pointers? - other::lib2(); - assert_eq!(*x, 1337); // oops, the value changed! I guess not all pointers were invalidated -} diff --git a/src/tools/miri/tests/pass/tree_borrows/unique.default.stderr b/src/tools/miri/tests/pass/tree_borrows/unique.default.stderr deleted file mode 100644 index 6098c855bde7..000000000000 --- a/src/tools/miri/tests/pass/tree_borrows/unique.default.stderr +++ /dev/null @@ -1,21 +0,0 @@ -────────────────────────────────────────────────── -Warning: this tree is indicative only. Some tags may have been hidden. -0.. 1 -| Act | └─┬── -| Res | └─┬── -| Res | └──── -────────────────────────────────────────────────── -────────────────────────────────────────────────── -Warning: this tree is indicative only. Some tags may have been hidden. -0.. 1 -| Act | └─┬── -| Act | └─┬── -| Act | └──── -────────────────────────────────────────────────── -────────────────────────────────────────────────── -Warning: this tree is indicative only. Some tags may have been hidden. -0.. 1 -| Act | └─┬── -| Act | └─┬── -| Act | └──── -────────────────────────────────────────────────── diff --git a/src/tools/miri/tests/pass/tree_borrows/unique.rs b/src/tools/miri/tests/pass/tree_borrows/unique.rs deleted file mode 100644 index f1ca1b51aa85..000000000000 --- a/src/tools/miri/tests/pass/tree_borrows/unique.rs +++ /dev/null @@ -1,67 +0,0 @@ -//@revisions: default uniq -// We disable the GC for this test because it would change what is printed. -//@compile-flags: -Zmiri-tree-borrows -Zmiri-provenance-gc=0 -//@[uniq]compile-flags: -Zmiri-unique-is-unique - -#![feature(ptr_internals)] - -#[path = "../../utils/mod.rs"] -#[macro_use] -mod utils; - -use core::ptr::Unique; - -// Check general handling of Unique - -fn main() { - unsafe { - let base = &mut 5u8; - let alloc_id = alloc_id!(base); - name!(base); - - let raw = &mut *base as *mut u8; - name!(raw); - - // We create a `Unique` and expect it to have a fresh tag - // and uninitialized permissions. - let uniq = Unique::new_unchecked(raw); - - // With `-Zmiri-unique-is-unique`, `Unique::as_ptr` (which is called by - // `Vec::as_ptr`) generates pointers with a fresh tag, so to name the actual - // `base` pointer we care about we have to walk up the tree a bit. - // - // We care about naming this specific parent tag because it is the one - // that stays `Active` during the entire execution, unlike the leaves - // that will be invalidated the next time `as_ptr` is called. - // - // (We name it twice so that we have an indicator in the output of - // whether we got the distance correct: - // If the output shows - // - // |- - // '- - // - // then `nth_parent` is not big enough. - // The correct value for `nth_parent` should be the minimum - // integer for which the output shows - // - // '- - // ) - // - // Ultimately we want pointers obtained through independent - // calls of `as_ptr` to be able to alias, which will probably involve - // a new permission that allows aliasing when there is no protector. - let nth_parent = if cfg!(uniq) { 2 } else { 0 }; - name!(uniq.as_ptr()=>nth_parent, "uniq"); - name!(uniq.as_ptr()=>nth_parent, "uniq"); - print_state!(alloc_id); - - // We can activate the Unique and use it mutably. - *uniq.as_ptr() = 42; - print_state!(alloc_id); - - // Write through the raw parent disables the Unique - *raw = 42; - print_state!(alloc_id); - } -} diff --git a/src/tools/miri/tests/pass/tree_borrows/unique.uniq.stderr b/src/tools/miri/tests/pass/tree_borrows/unique.uniq.stderr deleted file mode 100644 index 960c7e216e1d..000000000000 --- a/src/tools/miri/tests/pass/tree_borrows/unique.uniq.stderr +++ /dev/null @@ -1,24 +0,0 @@ -────────────────────────────────────────────────── -Warning: this tree is indicative only. Some tags may have been hidden. -0.. 1 -| Act | └─┬── -| Res | └─┬── -| Res | └─┬── -|-----| └──── -────────────────────────────────────────────────── -────────────────────────────────────────────────── -Warning: this tree is indicative only. Some tags may have been hidden. -0.. 1 -| Act | └─┬── -| Act | └─┬── -| Act | └─┬── -| Act | └──── -────────────────────────────────────────────────── -────────────────────────────────────────────────── -Warning: this tree is indicative only. Some tags may have been hidden. -0.. 1 -| Act | └─┬── -| Act | └─┬── -| Act | └─┬── -| Dis | └──── -────────────────────────────────────────────────── diff --git a/src/tools/miri/tests/pass/tree_borrows/vec_unique.rs b/src/tools/miri/tests/pass/tree_borrows/vec_unique.rs deleted file mode 100644 index af4c3b069319..000000000000 --- a/src/tools/miri/tests/pass/tree_borrows/vec_unique.rs +++ /dev/null @@ -1,69 +0,0 @@ -//@revisions: default uniq -// We disable the GC for this test because it would change what is printed. -//@compile-flags: -Zmiri-tree-borrows -Zmiri-provenance-gc=0 -//@[uniq]compile-flags: -Zmiri-unique-is-unique - -#![feature(vec_into_raw_parts)] - -#[path = "../../utils/mod.rs"] -#[macro_use] -mod utils; - -// Check general handling of `Unique`: -// there is no *explicit* `Unique` being used here, but there is one -// hidden a few layers inside `Vec` that should be reflected in the tree structure. - -fn main() { - unsafe { - let base = vec![0u8, 1]; - let alloc_id = alloc_id!(base.as_ptr()); - - // With `-Zmiri-unique-is-unique`, `Unique::as_ptr` (which is called by - // `Vec::as_ptr`) generates pointers with a fresh tag, so to name the actual - // `base` pointer we care about we have to walk up the tree a bit. - // - // We care about naming this specific parent tag because it is the one - // that stays `Active` during the entire execution, unlike the leaves - // that will be invalidated the next time `as_ptr` is called. - // - // (We name it twice so that we have an indicator in the output of - // whether we got the distance correct: - // If the output shows - // - // ├─ - // └─ - // - // then `nth_parent` is not big enough. - // The correct value for `nth_parent` should be the minimum - // integer for which the output shows - // - // └─ - // ) - // - // Ultimately we want pointers obtained through independent - // calls of `as_ptr` to be able to alias, which will probably involve - // a new permission that allows aliasing when there is no protector. - let nth_parent = if cfg!(uniq) { 9 } else { 0 }; - name!(base.as_ptr()=>nth_parent); - name!(base.as_ptr()=>nth_parent); - - // Destruct the `Vec` - let (ptr, len, cap) = base.into_raw_parts(); - - // Expect this to be again the same pointer as the one obtained from `as_ptr`. - // Under `-Zmiri-unique-is-unique`, this will be a strict child. - name!(ptr, "raw_parts.0"); - - // This is where the presence of `Unique` has implications, - // because there will be a reborrow here iff the exclusivity of `Unique` - // is enforced. - let reconstructed = Vec::from_raw_parts(ptr, len, cap); - - // The `as_ptr` here (twice for the same reason as above) return either - // the same pointer once more (default) or a strict child (uniq). - name!(reconstructed.as_ptr()=>nth_parent); - name!(reconstructed.as_ptr()=>nth_parent); - - print_state!(alloc_id, false); - } -} diff --git a/src/tools/miri/tests/pass/vec.rs b/src/tools/miri/tests/pass/vec.rs index 4ab2bcb7f228..3e526813bb45 100644 --- a/src/tools/miri/tests/pass/vec.rs +++ b/src/tools/miri/tests/pass/vec.rs @@ -1,7 +1,6 @@ -//@revisions: stack tree tree_uniq +//@revisions: stack tree //@compile-flags: -Zmiri-strict-provenance //@[tree]compile-flags: -Zmiri-tree-borrows -//@[tree_uniq]compile-flags: -Zmiri-tree-borrows -Zmiri-unique-is-unique #![feature(iter_advance_by, iter_next_chunk)] // Gather all references from a mutable iterator and make sure Miri notices if diff --git a/src/tools/miri/tests/pass/vecdeque.rs b/src/tools/miri/tests/pass/vecdeque.rs index 9153c428e184..bdf57f281a08 100644 --- a/src/tools/miri/tests/pass/vecdeque.rs +++ b/src/tools/miri/tests/pass/vecdeque.rs @@ -1,8 +1,6 @@ -//@revisions: stack tree tree_uniq +//@revisions: stack tree //@compile-flags: -Zmiri-strict-provenance //@[tree]compile-flags: -Zmiri-tree-borrows -//@[tree_uniq]compile-flags: -Zmiri-tree-borrows -Zmiri-unique-is-unique - use std::collections::VecDeque; fn test_all_refs<'a, T: 'a>(dummy: &mut T, iter: impl Iterator) { diff --git a/src/tools/miri/tests/pass/weak_memory/weak.rs b/src/tools/miri/tests/pass/weak_memory/weak.rs index 5d636431d867..eeab4ebf129e 100644 --- a/src/tools/miri/tests/pass/weak_memory/weak.rs +++ b/src/tools/miri/tests/pass/weak_memory/weak.rs @@ -1,4 +1,4 @@ -//@compile-flags: -Zmiri-ignore-leaks -Zmiri-preemption-rate=0 +//@compile-flags: -Zmiri-ignore-leaks -Zmiri-fixed-schedule // Tests showing weak memory behaviours are exhibited. All tests // return true when the desired behaviour is seen. diff --git a/src/tools/opt-dist/Cargo.toml b/src/tools/opt-dist/Cargo.toml index cea234cc74cb..b0db8346f7ed 100644 --- a/src/tools/opt-dist/Cargo.toml +++ b/src/tools/opt-dist/Cargo.toml @@ -10,7 +10,7 @@ log = "0.4" anyhow = "1" humantime = "2" humansize = "2" -sysinfo = { version = "0.31.2", default-features = false, features = ["disk"] } +sysinfo = { version = "0.35.0", default-features = false, features = ["disk"] } fs_extra = "1" camino = "1" tar = "0.4" diff --git a/src/tools/run-make-support/src/external_deps/cargo.rs b/src/tools/run-make-support/src/external_deps/cargo.rs index e91d101cb995..8da9f002c41b 100644 --- a/src/tools/run-make-support/src/external_deps/cargo.rs +++ b/src/tools/run-make-support/src/external_deps/cargo.rs @@ -1,8 +1,11 @@ use crate::command::Command; use crate::env_var; +use crate::util::set_host_compiler_dylib_path; /// Returns a command that can be used to invoke cargo. The cargo is provided by compiletest /// through the `CARGO` env var. pub fn cargo() -> Command { - Command::new(env_var("CARGO")) + let mut cmd = Command::new(env_var("CARGO")); + set_host_compiler_dylib_path(&mut cmd); + cmd } diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index 9f6b80c63790..8d6c8284e44e 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -85,6 +85,7 @@ dependencies = [ "query-group-macro", "rustc-hash 2.1.1", "salsa", + "salsa-macros", "semver", "span", "syntax", @@ -630,6 +631,7 @@ dependencies = [ "rustc-hash 2.1.1", "rustc_apfloat", "salsa", + "salsa-macros", "smallvec", "span", "stdx", @@ -660,6 +662,7 @@ dependencies = [ "query-group-macro", "rustc-hash 2.1.1", "salsa", + "salsa-macros", "smallvec", "span", "stdx", @@ -700,6 +703,7 @@ dependencies = [ "rustc-hash 2.1.1", "rustc_apfloat", "salsa", + "salsa-macros", "scoped-tls", "smallvec", "span", @@ -936,6 +940,7 @@ dependencies = [ "rayon", "rustc-hash 2.1.1", "salsa", + "salsa-macros", "span", "stdx", "syntax", @@ -1729,6 +1734,7 @@ dependencies = [ "proc-macro2", "quote", "salsa", + "salsa-macros", "syn", ] @@ -2033,9 +2039,9 @@ checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] name = "salsa" -version = "0.20.0" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1be22155f8d9732518b2db2bf379fe6f0b2375e76b08b7c8fe6c1b887d548c24" +checksum = "6f80d5cf3c3fcab2cef898012f242a670477a1baa609267376af9cb4409026c5" dependencies = [ "boxcar", "crossbeam-queue", @@ -2056,15 +2062,15 @@ dependencies = [ [[package]] name = "salsa-macro-rules" -version = "0.20.0" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f55a7ef0a84e336f7c5f0332d81727f5629fe042d2aa556c75307afebc9f78a5" +checksum = "05303d72606fbf2b9c9523cda2039bb8ecb00304027a3cd7e52b02a65c7d9185" [[package]] name = "salsa-macros" -version = "0.20.0" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d0e88a9c0c0d231a63f83dcd1a2c5e5d11044fac4b65bc9ad3b68ab48b0a0ab" +checksum = "eb2f0e2a30c65cb3cd63440c491dde68d9af7e1be2b77832ac7057141107db50" dependencies = [ "heck", "proc-macro2", diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml index 6fa171702dd4..c4c2fdf34bae 100644 --- a/src/tools/rust-analyzer/Cargo.toml +++ b/src/tools/rust-analyzer/Cargo.toml @@ -131,7 +131,9 @@ process-wrap = { version = "8.2.0", features = ["std"] } pulldown-cmark-to-cmark = "10.0.4" pulldown-cmark = { version = "0.9.6", default-features = false } rayon = "1.10.0" -salsa = "0.20.0" +rowan = "=0.15.15" +salsa = { version = "0.21.1", default-features = false, features = ["rayon","salsa_unstable"] } +salsa-macros = "0.21.1" semver = "1.0.26" serde = { version = "1.0.219" } serde_derive = { version = "1.0.219" } diff --git a/src/tools/rust-analyzer/crates/base-db/Cargo.toml b/src/tools/rust-analyzer/crates/base-db/Cargo.toml index 441434504c29..e2e3253773fe 100644 --- a/src/tools/rust-analyzer/crates/base-db/Cargo.toml +++ b/src/tools/rust-analyzer/crates/base-db/Cargo.toml @@ -15,6 +15,7 @@ rust-version.workspace = true la-arena.workspace = true dashmap.workspace = true salsa.workspace = true +salsa-macros.workspace = true query-group.workspace = true rustc-hash.workspace = true triomphe.workspace = true diff --git a/src/tools/rust-analyzer/crates/base-db/src/input.rs b/src/tools/rust-analyzer/crates/base-db/src/input.rs index 499c9b3716b2..9660e6e87cca 100644 --- a/src/tools/rust-analyzer/crates/base-db/src/input.rs +++ b/src/tools/rust-analyzer/crates/base-db/src/input.rs @@ -392,7 +392,7 @@ impl BuiltDependency { pub type CratesIdMap = FxHashMap; -#[salsa::input] +#[salsa_macros::input] #[derive(Debug)] pub struct Crate { #[return_ref] diff --git a/src/tools/rust-analyzer/crates/base-db/src/lib.rs b/src/tools/rust-analyzer/crates/base-db/src/lib.rs index 7f7a712577e4..a67fbf75c02f 100644 --- a/src/tools/rust-analyzer/crates/base-db/src/lib.rs +++ b/src/tools/rust-analyzer/crates/base-db/src/lib.rs @@ -1,9 +1,13 @@ //! base_db defines basic database traits. The concrete DB is defined by ide. + +pub use salsa; +pub use salsa_macros; + // FIXME: Rename this crate, base db is non descriptive mod change; mod input; -use std::hash::BuildHasherDefault; +use std::{cell::RefCell, hash::BuildHasherDefault, panic, sync::Once}; pub use crate::{ change::FileChange, @@ -17,7 +21,6 @@ pub use crate::{ use dashmap::{DashMap, mapref::entry::Entry}; pub use query_group::{self}; use rustc_hash::{FxHashSet, FxHasher}; -pub use salsa::{self}; use salsa::{Durability, Setter}; pub use semver::{BuildMetadata, Prerelease, Version, VersionReq}; use span::Edition; @@ -28,7 +31,7 @@ pub use vfs::{AnchoredPath, AnchoredPathBuf, FileId, VfsPath, file_set::FileSet} #[macro_export] macro_rules! impl_intern_key { ($id:ident, $loc:ident) => { - #[salsa::interned(no_lifetime)] + #[salsa_macros::interned(no_lifetime)] pub struct $id { pub loc: $loc, } @@ -57,7 +60,12 @@ pub struct Files { impl Files { pub fn file_text(&self, file_id: vfs::FileId) -> FileText { - *self.files.get(&file_id).expect("Unable to fetch file; this is a bug") + match self.files.get(&file_id) { + Some(text) => *text, + None => { + panic!("Unable to fetch file text for `vfs::FileId`: {file_id:?}; this is a bug") + } + } } pub fn set_file_text(&self, db: &mut dyn SourceDatabase, file_id: vfs::FileId, text: &str) { @@ -93,10 +101,12 @@ impl Files { /// Source root of the file. pub fn source_root(&self, source_root_id: SourceRootId) -> SourceRootInput { - let source_root = self - .source_roots - .get(&source_root_id) - .expect("Unable to fetch source root id; this is a bug"); + let source_root = match self.source_roots.get(&source_root_id) { + Some(source_root) => source_root, + None => panic!( + "Unable to fetch `SourceRootInput` with `SourceRootId` ({source_root_id:?}); this is a bug" + ), + }; *source_root } @@ -121,10 +131,12 @@ impl Files { } pub fn file_source_root(&self, id: vfs::FileId) -> FileSourceRootInput { - let file_source_root = self - .file_source_roots - .get(&id) - .expect("Unable to fetch FileSourceRootInput; this is a bug"); + let file_source_root = match self.file_source_roots.get(&id) { + Some(file_source_root) => file_source_root, + None => panic!( + "Unable to get `FileSourceRootInput` with `vfs::FileId` ({id:?}); this is a bug", + ), + }; *file_source_root } @@ -152,7 +164,7 @@ impl Files { } } -#[salsa::interned(no_lifetime, debug, constructor=from_span)] +#[salsa_macros::interned(no_lifetime, debug, constructor=from_span)] pub struct EditionedFileId { pub editioned_file_id: span::EditionedFileId, } @@ -187,18 +199,18 @@ impl EditionedFileId { } } -#[salsa::input(debug)] +#[salsa_macros::input(debug)] pub struct FileText { pub text: Arc, pub file_id: vfs::FileId, } -#[salsa::input(debug)] +#[salsa_macros::input(debug)] pub struct FileSourceRootInput { pub source_root_id: SourceRootId, } -#[salsa::input(debug)] +#[salsa_macros::input(debug)] pub struct SourceRootInput { pub source_root: Arc, } @@ -265,7 +277,7 @@ pub fn transitive_deps(db: &dyn SourceDatabase, crate_id: Crate) -> FxHashSet FileText; @@ -344,7 +356,7 @@ fn parse(db: &dyn RootQueryDb, file_id: EditionedFileId) -> Parse Option<&[SyntaxError]> { - #[salsa::tracked(return_ref)] + #[salsa_macros::tracked(return_ref)] fn parse_errors(db: &dyn RootQueryDb, file_id: EditionedFileId) -> Option> { let errors = db.parse(file_id).errors(); match &*errors { @@ -373,3 +385,49 @@ fn relevant_crates(db: &dyn RootQueryDb, file_id: FileId) -> Arc<[Crate]> { let source_root = db.file_source_root(file_id); db.source_root_crates(source_root.source_root_id(db)) } + +#[must_use] +#[non_exhaustive] +pub struct DbPanicContext; + +impl Drop for DbPanicContext { + fn drop(&mut self) { + Self::with_ctx(|ctx| assert!(ctx.pop().is_some())); + } +} + +impl DbPanicContext { + pub fn enter(frame: String) -> DbPanicContext { + #[expect(clippy::print_stderr, reason = "already panicking anyway")] + fn set_hook() { + let default_hook = panic::take_hook(); + panic::set_hook(Box::new(move |panic_info| { + default_hook(panic_info); + if let Some(backtrace) = salsa::Backtrace::capture() { + eprintln!("{backtrace:#}"); + } + DbPanicContext::with_ctx(|ctx| { + if !ctx.is_empty() { + eprintln!("additional context:"); + for (idx, frame) in ctx.iter().enumerate() { + eprintln!("{idx:>4}: {frame}\n"); + } + } + }); + })); + } + + static SET_HOOK: Once = Once::new(); + SET_HOOK.call_once(set_hook); + + Self::with_ctx(|ctx| ctx.push(frame)); + DbPanicContext + } + + fn with_ctx(f: impl FnOnce(&mut Vec)) { + thread_local! { + static CTX: RefCell> = const { RefCell::new(Vec::new()) }; + } + CTX.with(|ctx| f(&mut ctx.borrow_mut())); + } +} diff --git a/src/tools/rust-analyzer/crates/hir-def/Cargo.toml b/src/tools/rust-analyzer/crates/hir-def/Cargo.toml index f97597ffe5a6..c1c89e8d1cc3 100644 --- a/src/tools/rust-analyzer/crates/hir-def/Cargo.toml +++ b/src/tools/rust-analyzer/crates/hir-def/Cargo.toml @@ -28,6 +28,7 @@ triomphe.workspace = true rustc_apfloat = "0.2.2" text-size.workspace = true salsa.workspace = true +salsa-macros.workspace = true query-group.workspace = true ra-ap-rustc_parse_format.workspace = true diff --git a/src/tools/rust-analyzer/crates/hir-def/src/attr.rs b/src/tools/rust-analyzer/crates/hir-def/src/attr.rs index a80313aba3e4..bb6222b1d464 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/attr.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/attr.rs @@ -1,6 +1,6 @@ //! A higher level attributes based on TokenTree, with also some shortcuts. -use std::{borrow::Cow, hash::Hash, ops}; +use std::{borrow::Cow, convert::identity, hash::Hash, ops}; use base_db::Crate; use cfg::{CfgExpr, CfgOptions}; @@ -8,6 +8,7 @@ use either::Either; use hir_expand::{ HirFileId, InFile, attrs::{Attr, AttrId, RawAttrs, collect_attrs}, + span_map::SpanMapRef, }; use intern::{Symbol, sym}; use la_arena::{ArenaMap, Idx, RawIdx}; @@ -45,8 +46,27 @@ impl Attrs { (**self).iter().find(|attr| attr.id == id) } - pub(crate) fn filter(db: &dyn DefDatabase, krate: Crate, raw_attrs: RawAttrs) -> Attrs { - Attrs(raw_attrs.filter(db, krate)) + pub(crate) fn expand_cfg_attr( + db: &dyn DefDatabase, + krate: Crate, + raw_attrs: RawAttrs, + ) -> Attrs { + Attrs(raw_attrs.expand_cfg_attr(db, krate)) + } + + pub(crate) fn is_cfg_enabled_for( + db: &dyn DefDatabase, + owner: &dyn ast::HasAttrs, + span_map: SpanMapRef<'_>, + cfg_options: &CfgOptions, + ) -> Result<(), CfgExpr> { + RawAttrs::attrs_iter_expanded::(db, owner, span_map, cfg_options) + .filter_map(|attr| attr.cfg()) + .find_map(|cfg| match cfg_options.check(&cfg).is_none_or(identity) { + true => None, + false => Some(cfg), + }) + .map_or(Ok(()), Err) } } @@ -522,38 +542,41 @@ impl AttrsWithOwner { GenericParamId::ConstParamId(it) => { let src = it.parent().child_source(db); // FIXME: We should be never getting `None` here. - match src.value.get(it.local_id()) { - Some(val) => RawAttrs::from_attrs_owner( + return Attrs(match src.value.get(it.local_id()) { + Some(val) => RawAttrs::new_expanded( db, - src.with_value(val), + val, db.span_map(src.file_id).as_ref(), + def.krate(db).cfg_options(db), ), None => RawAttrs::EMPTY, - } + }); } GenericParamId::TypeParamId(it) => { let src = it.parent().child_source(db); // FIXME: We should be never getting `None` here. - match src.value.get(it.local_id()) { - Some(val) => RawAttrs::from_attrs_owner( + return Attrs(match src.value.get(it.local_id()) { + Some(val) => RawAttrs::new_expanded( db, - src.with_value(val), + val, db.span_map(src.file_id).as_ref(), + def.krate(db).cfg_options(db), ), None => RawAttrs::EMPTY, - } + }); } GenericParamId::LifetimeParamId(it) => { let src = it.parent.child_source(db); // FIXME: We should be never getting `None` here. - match src.value.get(it.local_id) { - Some(val) => RawAttrs::from_attrs_owner( + return Attrs(match src.value.get(it.local_id) { + Some(val) => RawAttrs::new_expanded( db, - src.with_value(val), + val, db.span_map(src.file_id).as_ref(), + def.krate(db).cfg_options(db), ), None => RawAttrs::EMPTY, - } + }); } }, AttrDefId::ExternBlockId(it) => attrs_from_item_tree_loc(db, it), @@ -561,7 +584,7 @@ impl AttrsWithOwner { AttrDefId::UseId(it) => attrs_from_item_tree_loc(db, it), }; - let attrs = raw_attrs.filter(db, def.krate(db)); + let attrs = raw_attrs.expand_cfg_attr(db, def.krate(db)); Attrs(attrs) } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/db.rs b/src/tools/rust-analyzer/crates/hir-def/src/db.rs index 34cf42d02bdb..2cbdbe16f9bb 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/db.rs @@ -22,7 +22,7 @@ use crate::{ hir::generics::GenericParams, import_map::ImportMap, item_tree::{AttrOwner, ItemTree}, - lang_item::{self, LangItem, LangItemTarget, LangItems}, + lang_item::{self, LangItem}, nameres::{ DefMap, LocalDefMap, assoc::{ImplItems, TraitItems}, @@ -325,9 +325,6 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + SourceDatabase { // endregion:attrs - #[salsa::invoke(LangItems::lang_item_query)] - fn lang_item(&self, start_crate: Crate, item: LangItem) -> Option; - #[salsa::invoke(ImportMap::import_map_query)] fn import_map(&self, krate: Crate) -> Arc; @@ -349,9 +346,6 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + SourceDatabase { // endregion:visibilities - #[salsa::invoke(LangItems::crate_lang_items_query)] - fn crate_lang_items(&self, krate: Crate) -> Option>; - #[salsa::invoke(crate::lang_item::notable_traits_in_deps)] fn notable_traits_in_deps(&self, krate: Crate) -> Arc<[Arc<[TraitId]>]>; #[salsa::invoke(crate::lang_item::crate_notable_traits)] diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/expander.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/expander.rs index 7eec913dd654..3823fb5a1e75 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/expander.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/expander.rs @@ -3,21 +3,24 @@ use std::mem; use base_db::Crate; +use cfg::CfgOptions; use drop_bomb::DropBomb; +use hir_expand::AstId; use hir_expand::{ ExpandError, ExpandErrorKind, ExpandResult, HirFileId, InFile, Lookup, MacroCallId, - attrs::RawAttrs, eager::EagerCallBackFn, mod_path::ModPath, span_map::SpanMap, + eager::EagerCallBackFn, mod_path::ModPath, span_map::SpanMap, }; use span::{AstIdMap, Edition, SyntaxContext}; use syntax::ast::HasAttrs; -use syntax::{Parse, ast}; +use syntax::{AstNode, Parse, ast}; use triomphe::Arc; use tt::TextRange; use crate::attr::Attrs; use crate::expr_store::HygieneId; +use crate::macro_call_as_call_id; use crate::nameres::DefMap; -use crate::{AsMacroCall, MacroId, UnresolvedMacro, db::DefDatabase}; +use crate::{MacroId, UnresolvedMacro, db::DefDatabase}; #[derive(Debug)] pub(super) struct Expander { @@ -64,22 +67,13 @@ impl Expander { } } - pub(super) fn attrs( - &self, - db: &dyn DefDatabase, - krate: Crate, - has_attrs: &dyn HasAttrs, - ) -> Attrs { - Attrs::filter(db, krate, RawAttrs::new(db, has_attrs, self.span_map.as_ref())) - } - pub(super) fn is_cfg_enabled( &self, db: &dyn DefDatabase, - krate: Crate, has_attrs: &dyn HasAttrs, - ) -> bool { - self.attrs(db, krate, has_attrs).is_cfg_enabled(krate.cfg_options(db)) + cfg_options: &CfgOptions, + ) -> Result<(), cfg::CfgExpr> { + Attrs::is_cfg_enabled_for(db, has_attrs, self.span_map.as_ref(), cfg_options) } pub(super) fn call_syntax_ctx(&self) -> SyntaxContext { @@ -100,8 +94,31 @@ impl Expander { let result = self.within_limit(db, |this| { let macro_call = this.in_file(¯o_call); - match macro_call.as_call_id_with_errors( + + let expands_to = hir_expand::ExpandTo::from_call_site(macro_call.value); + let ast_id = AstId::new(macro_call.file_id, this.ast_id_map().ast_id(macro_call.value)); + let path = macro_call.value.path().and_then(|path| { + let range = path.syntax().text_range(); + let mod_path = ModPath::from_src(db, path, &mut |range| { + this.span_map.span_for_range(range).ctx + })?; + let call_site = this.span_map.span_for_range(range); + Some((call_site, mod_path)) + }); + + let Some((call_site, path)) = path else { + return ExpandResult::only_err(ExpandError::other( + this.span_map.span_for_range(macro_call.value.syntax().text_range()), + "malformed macro invocation", + )); + }; + + match macro_call_as_call_id( db, + ast_id, + &path, + call_site.ctx, + expands_to, krate, |path| resolver(path).map(|it| db.macro_def(it)), eager_callback, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs index 7f907fdba8e3..50505d54ba2f 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs @@ -7,6 +7,7 @@ mod path; use std::mem; +use cfg::CfgOptions; use either::Either; use hir_expand::{ HirFileId, InFile, Lookup, MacroDefId, @@ -81,8 +82,6 @@ pub(super) fn lower_body( // even though they should be the same. Also, when the body comes from multiple expansions, their // hygiene is different. - let krate = module.krate(); - let mut self_param = None; let mut source_map_self_param = None; let mut params = vec![]; @@ -100,9 +99,8 @@ pub(super) fn lower_body( // and skip the body. if skip_body { if let Some(param_list) = parameters { - if let Some(self_param_syn) = param_list - .self_param() - .filter(|self_param| collector.expander.is_cfg_enabled(db, krate, self_param)) + if let Some(self_param_syn) = + param_list.self_param().filter(|self_param| collector.check_cfg(self_param)) { let is_mutable = self_param_syn.mut_token().is_some() && self_param_syn.amp_token().is_none(); @@ -119,10 +117,7 @@ pub(super) fn lower_body( source_map_self_param = Some(collector.expander.in_file(AstPtr::new(&self_param_syn))); } - let count = param_list - .params() - .filter(|it| collector.expander.is_cfg_enabled(db, krate, it)) - .count(); + let count = param_list.params().filter(|it| collector.check_cfg(it)).count(); params = (0..count).map(|_| collector.missing_pat()).collect(); }; let body_expr = collector.missing_expr(); @@ -138,9 +133,7 @@ pub(super) fn lower_body( } if let Some(param_list) = parameters { - if let Some(self_param_syn) = - param_list.self_param().filter(|it| collector.expander.is_cfg_enabled(db, krate, it)) - { + if let Some(self_param_syn) = param_list.self_param().filter(|it| collector.check_cfg(it)) { let is_mutable = self_param_syn.mut_token().is_some() && self_param_syn.amp_token().is_none(); let hygiene = self_param_syn @@ -157,7 +150,7 @@ pub(super) fn lower_body( } for param in param_list.params() { - if collector.expander.is_cfg_enabled(db, krate, ¶m) { + if collector.check_cfg(¶m) { let param_pat = collector.collect_pat_top(param.pat()); params.push(param_pat); } @@ -346,7 +339,7 @@ pub(crate) fn lower_function( collector.collect_impl_trait(&mut expr_collector, |collector, mut impl_trait_lower_fn| { if let Some(param_list) = fn_.value.param_list() { if let Some(param) = param_list.self_param() { - let enabled = collector.expander.is_cfg_enabled(db, module.krate(), ¶m); + let enabled = collector.check_cfg(¶m); if enabled { has_self_param = true; params.push(match param.ty() { @@ -381,7 +374,7 @@ pub(crate) fn lower_function( } let p = param_list .params() - .filter(|param| collector.expander.is_cfg_enabled(db, module.krate(), param)) + .filter(|param| collector.check_cfg(param)) .filter(|param| { let is_variadic = param.dotdotdot_token().is_some(); has_variadic |= is_variadic; @@ -441,6 +434,7 @@ pub(crate) fn lower_function( pub struct ExprCollector<'db> { db: &'db dyn DefDatabase, + cfg_options: &'db CfgOptions, expander: Expander, def_map: Arc, local_def_map: Arc, @@ -553,6 +547,7 @@ impl ExprCollector<'_> { let expander = Expander::new(db, current_file_id, &def_map); ExprCollector { db, + cfg_options: module.krate().cfg_options(db), module, def_map, local_def_map, @@ -1026,7 +1021,9 @@ impl ExprCollector<'_> { /// Returns `None` if and only if the expression is `#[cfg]`d out. fn maybe_collect_expr(&mut self, expr: ast::Expr) -> Option { let syntax_ptr = AstPtr::new(&expr); - self.check_cfg(&expr)?; + if !self.check_cfg(&expr) { + return None; + } // FIXME: Move some of these arms out into separate methods for clarity Some(match expr { @@ -1114,6 +1111,7 @@ impl ExprCollector<'_> { ast::Expr::WhileExpr(e) => self.collect_while_loop(syntax_ptr, e), ast::Expr::ForExpr(e) => self.collect_for_loop(syntax_ptr, e), ast::Expr::CallExpr(e) => { + // FIXME: Remove this once we drop support for <1.86, https://github.com/rust-lang/rust/commit/ac9cb908ac4301dfc25e7a2edee574320022ae2c let is_rustc_box = { let attrs = e.attrs(); attrs.filter_map(|it| it.as_simple_atom()).any(|it| it == "rustc_box") @@ -1156,13 +1154,17 @@ impl ExprCollector<'_> { match_arm_list .arms() .filter_map(|arm| { - self.check_cfg(&arm).map(|()| MatchArm { - pat: self.collect_pat_top(arm.pat()), - expr: self.collect_expr_opt(arm.expr()), - guard: arm - .guard() - .map(|guard| self.collect_expr_opt(guard.condition())), - }) + if self.check_cfg(&arm) { + Some(MatchArm { + pat: self.collect_pat_top(arm.pat()), + expr: self.collect_expr_opt(arm.expr()), + guard: arm + .guard() + .map(|guard| self.collect_expr_opt(guard.condition())), + }) + } else { + None + } }) .collect() } else { @@ -1230,7 +1232,9 @@ impl ExprCollector<'_> { let fields = nfl .fields() .filter_map(|field| { - self.check_cfg(&field)?; + if !self.check_cfg(&field) { + return None; + } let name = field.field_name()?.as_name(); @@ -1483,7 +1487,9 @@ impl ExprCollector<'_> { } fn maybe_collect_expr_as_pat(&mut self, expr: &ast::Expr) -> Option { - self.check_cfg(expr)?; + if !self.check_cfg(expr) { + return None; + } let syntax_ptr = AstPtr::new(expr); let result = match expr { @@ -1558,7 +1564,9 @@ impl ExprCollector<'_> { let args = record_field_list .fields() .filter_map(|f| { - self.check_cfg(&f)?; + if !self.check_cfg(&f) { + return None; + } let field_expr = f.expr()?; let pat = self.collect_expr_as_pat(field_expr); let name = f.field_name()?.as_name(); @@ -2044,7 +2052,7 @@ impl ExprCollector<'_> { fn collect_stmt(&mut self, statements: &mut Vec, s: ast::Stmt) { match s { ast::Stmt::LetStmt(stmt) => { - if self.check_cfg(&stmt).is_none() { + if !self.check_cfg(&stmt) { return; } let pat = self.collect_pat_top(stmt.pat()); @@ -2059,7 +2067,7 @@ impl ExprCollector<'_> { ast::Stmt::ExprStmt(stmt) => { let expr = stmt.expr(); match &expr { - Some(expr) if self.check_cfg(expr).is_none() => return, + Some(expr) if !self.check_cfg(expr) => return, _ => (), } let has_semi = stmt.semicolon_token().is_some(); @@ -2074,7 +2082,7 @@ impl ExprCollector<'_> { } } ast::Stmt::Item(ast::Item::MacroDef(macro_)) => { - if self.check_cfg(¯o_).is_none() { + if !self.check_cfg(¯o_) { return; } let Some(name) = macro_.name() else { @@ -2086,7 +2094,7 @@ impl ExprCollector<'_> { self.collect_macro_def(statements, macro_id); } ast::Stmt::Item(ast::Item::MacroRules(macro_)) => { - if self.check_cfg(¯o_).is_none() { + if !self.check_cfg(¯o_) { return; } let Some(name) = macro_.name() else { @@ -2360,7 +2368,9 @@ impl ExprCollector<'_> { let args = record_pat_field_list .fields() .filter_map(|f| { - self.check_cfg(&f)?; + if !self.check_cfg(&f) { + return None; + } let ast_pat = f.pat()?; let pat = self.collect_pat(ast_pat, binding_list); let name = f.field_name()?.as_name(); @@ -2536,25 +2546,18 @@ impl ExprCollector<'_> { /// Returns `None` (and emits diagnostics) when `owner` if `#[cfg]`d out, and `Some(())` when /// not. - fn check_cfg(&mut self, owner: &dyn ast::HasAttrs) -> Option<()> { - let attrs = self.expander.attrs(self.db, self.module.krate(), owner); - match attrs.cfg() { - Some(cfg) => { - let cfg_options = self.module.krate().cfg_options(self.db); - - if cfg_options.check(&cfg) != Some(false) { - return Some(()); - } - + fn check_cfg(&mut self, owner: &dyn ast::HasAttrs) -> bool { + let enabled = self.expander.is_cfg_enabled(self.db, owner, self.cfg_options); + match enabled { + Ok(()) => true, + Err(cfg) => { self.source_map.diagnostics.push(ExpressionStoreDiagnostics::InactiveCode { node: self.expander.in_file(SyntaxNodePtr::new(owner.syntax())), cfg, - opts: cfg_options.clone(), + opts: self.cfg_options.clone(), }); - - None + false } - None => Some(()), } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/asm.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/asm.rs index 9ef03065651a..d36e5205c739 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/asm.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/asm.rs @@ -224,7 +224,7 @@ impl ExprCollector<'_> { curarg = parser.curarg; - let to_span = |inner_span: rustc_parse_format::InnerSpan| { + let to_span = |inner_span: std::ops::Range| { is_direct_literal.then(|| { TextRange::new( inner_span.start.try_into().unwrap(), diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/generics.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/generics.rs index 9485e703d9cb..02a1d274fb5e 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/generics.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/generics.rs @@ -110,7 +110,7 @@ impl GenericParamsCollector { fn lower_param_list(&mut self, ec: &mut ExprCollector<'_>, params: ast::GenericParamList) { for generic_param in params.generic_params() { - let enabled = ec.expander.is_cfg_enabled(ec.db, ec.module.krate(), &generic_param); + let enabled = ec.check_cfg(&generic_param); if !enabled { continue; } @@ -270,7 +270,7 @@ impl GenericParamsCollector { let self_ = Name::new_symbol_root(sym::Self_); let idx = self.type_or_consts.alloc( TypeParamData { - name: Some(self_.clone()), + name: Some(self_), default: None, provenance: TypeParamProvenance::TraitSelf, } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/hir/format_args.rs b/src/tools/rust-analyzer/crates/hir-def/src/hir/format_args.rs index 2fd21bb0ed3a..f27a4062a63b 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/hir/format_args.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/hir/format_args.rs @@ -214,7 +214,7 @@ pub(crate) fn parse( }; } - let to_span = |inner_span: parse::InnerSpan| { + let to_span = |inner_span: std::ops::Range| { is_source_literal.then(|| { TextRange::new(inner_span.start.try_into().unwrap(), inner_span.end.try_into().unwrap()) }) @@ -297,7 +297,7 @@ pub(crate) fn parse( unfinished_literal.clear(); } - let span = parser.arg_places.get(placeholder_index).and_then(|&s| to_span(s)); + let span = parser.arg_places.get(placeholder_index).and_then(|s| to_span(s.clone())); placeholder_index += 1; let position_span = to_span(position_span); diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs index bece940950d8..5362c0588dbe 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs @@ -167,7 +167,7 @@ pub struct ItemScope { // the resolutions of the imports of this scope use_imports_types: FxHashMap, use_imports_values: FxHashMap, - use_imports_macros: FxHashMap, + use_imports_macros: FxHashMap, use_decls: Vec, extern_crate_decls: Vec, @@ -242,7 +242,7 @@ impl ItemScope { self.types.iter().map(|(n, &i)| (n, i)) } - pub fn macros(&self) -> impl Iterator)> + '_ { + pub fn macros(&self) -> impl Iterator)> + '_ { self.macros.iter().map(|(n, &i)| (n, i)) } @@ -250,9 +250,9 @@ impl ItemScope { self.use_imports_types .keys() .copied() + .chain(self.use_imports_macros.keys().copied()) .filter_map(ImportOrExternCrate::import_or_glob) .chain(self.use_imports_values.keys().copied()) - .chain(self.use_imports_macros.keys().copied()) .filter_map(ImportOrGlob::into_import) .sorted() .dedup() @@ -263,7 +263,7 @@ impl ItemScope { let mut def_map; let mut scope = self; - while let Some(&m) = scope.use_imports_macros.get(&ImportOrGlob::Import(import)) { + while let Some(&m) = scope.use_imports_macros.get(&ImportOrExternCrate::Import(import)) { match m { ImportOrDef::Import(i) => { let module_id = i.use_.lookup(db).container; @@ -682,7 +682,6 @@ impl ItemScope { } _ => _ = glob_imports.macros.remove(&lookup), } - let import = import.and_then(ImportOrExternCrate::import_or_glob); let prev = std::mem::replace(&mut fld.import, import); if let Some(import) = import { self.use_imports_macros.insert( @@ -698,7 +697,6 @@ impl ItemScope { { if glob_imports.macros.remove(&lookup) { cov_mark::hit!(import_shadowed); - let import = import.and_then(ImportOrExternCrate::import_or_glob); let prev = std::mem::replace(&mut fld.import, import); if let Some(import) = import { self.use_imports_macros.insert( @@ -783,8 +781,9 @@ impl ItemScope { if let Some(Item { import, .. }) = def.macros { buf.push_str(" m"); match import { - Some(ImportOrGlob::Import(_)) => buf.push('i'), - Some(ImportOrGlob::Glob(_)) => buf.push('g'), + Some(ImportOrExternCrate::Import(_)) => buf.push('i'), + Some(ImportOrExternCrate::Glob(_)) => buf.push('g'), + Some(ImportOrExternCrate::ExternCrate(_)) => buf.push('e'), None => (), } } @@ -893,9 +892,7 @@ impl PerNs { ModuleDefId::TraitAliasId(_) => PerNs::types(def, v, import), ModuleDefId::TypeAliasId(_) => PerNs::types(def, v, import), ModuleDefId::BuiltinType(_) => PerNs::types(def, v, import), - ModuleDefId::MacroId(mac) => { - PerNs::macros(mac, v, import.and_then(ImportOrExternCrate::import_or_glob)) - } + ModuleDefId::MacroId(mac) => PerNs::macros(mac, v, import), } } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs index 01d340cea6df..1b97eb72b6f2 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs @@ -179,7 +179,7 @@ impl ItemTree { /// Returns the inner attributes of the source file. pub fn top_level_attrs(&self, db: &dyn DefDatabase, krate: Crate) -> Attrs { - Attrs::filter( + Attrs::expand_cfg_attr( db, krate, self.attrs.get(&AttrOwner::TopLevel).unwrap_or(&RawAttrs::EMPTY).clone(), @@ -191,7 +191,7 @@ impl ItemTree { } pub(crate) fn attrs(&self, db: &dyn DefDatabase, krate: Crate, of: AttrOwner) -> Attrs { - Attrs::filter(db, krate, self.raw_attrs(of).clone()) + Attrs::expand_cfg_attr(db, krate, self.raw_attrs(of).clone()) } /// Returns a count of a few, expensive items. diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs b/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs index 5431ec9679c5..51a833b5f150 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs @@ -83,6 +83,91 @@ impl LangItemTarget { } } +/// Salsa query. This will look for lang items in a specific crate. +#[salsa_macros::tracked(return_ref)] +pub fn crate_lang_items(db: &dyn DefDatabase, krate: Crate) -> Option> { + let _p = tracing::info_span!("crate_lang_items_query").entered(); + + let mut lang_items = LangItems::default(); + + let crate_def_map = db.crate_def_map(krate); + + for (_, module_data) in crate_def_map.modules() { + for impl_def in module_data.scope.impls() { + lang_items.collect_lang_item(db, impl_def, LangItemTarget::ImplDef); + for &(_, assoc) in db.impl_items(impl_def).items.iter() { + match assoc { + AssocItemId::FunctionId(f) => { + lang_items.collect_lang_item(db, f, LangItemTarget::Function) + } + AssocItemId::TypeAliasId(t) => { + lang_items.collect_lang_item(db, t, LangItemTarget::TypeAlias) + } + AssocItemId::ConstId(_) => (), + } + } + } + + for def in module_data.scope.declarations() { + match def { + ModuleDefId::TraitId(trait_) => { + lang_items.collect_lang_item(db, trait_, LangItemTarget::Trait); + db.trait_items(trait_).items.iter().for_each(|&(_, assoc_id)| match assoc_id { + AssocItemId::FunctionId(f) => { + lang_items.collect_lang_item(db, f, LangItemTarget::Function); + } + AssocItemId::TypeAliasId(alias) => { + lang_items.collect_lang_item(db, alias, LangItemTarget::TypeAlias) + } + AssocItemId::ConstId(_) => {} + }); + } + ModuleDefId::AdtId(AdtId::EnumId(e)) => { + lang_items.collect_lang_item(db, e, LangItemTarget::EnumId); + db.enum_variants(e).variants.iter().for_each(|&(id, _)| { + lang_items.collect_lang_item(db, id, LangItemTarget::EnumVariant); + }); + } + ModuleDefId::AdtId(AdtId::StructId(s)) => { + lang_items.collect_lang_item(db, s, LangItemTarget::Struct); + } + ModuleDefId::AdtId(AdtId::UnionId(u)) => { + lang_items.collect_lang_item(db, u, LangItemTarget::Union); + } + ModuleDefId::FunctionId(f) => { + lang_items.collect_lang_item(db, f, LangItemTarget::Function); + } + ModuleDefId::StaticId(s) => { + lang_items.collect_lang_item(db, s, LangItemTarget::Static); + } + ModuleDefId::TypeAliasId(t) => { + lang_items.collect_lang_item(db, t, LangItemTarget::TypeAlias); + } + _ => {} + } + } + } + + if lang_items.items.is_empty() { None } else { Some(Box::new(lang_items)) } +} + +/// Salsa query. Look for a lang item, starting from the specified crate and recursively +/// traversing its dependencies. +#[salsa_macros::tracked] +pub fn lang_item( + db: &dyn DefDatabase, + start_crate: Crate, + item: LangItem, +) -> Option { + let _p = tracing::info_span!("lang_item_query").entered(); + if let Some(target) = + crate_lang_items(db, start_crate).as_ref().and_then(|it| it.items.get(&item).copied()) + { + return Some(target); + } + start_crate.data(db).dependencies.iter().find_map(|dep| lang_item(db, dep.crate_id, item)) +} + #[derive(Default, Debug, Clone, PartialEq, Eq)] pub struct LangItems { items: FxHashMap, @@ -93,96 +178,6 @@ impl LangItems { self.items.get(&item).copied() } - /// Salsa query. This will look for lang items in a specific crate. - pub(crate) fn crate_lang_items_query( - db: &dyn DefDatabase, - krate: Crate, - ) -> Option> { - let _p = tracing::info_span!("crate_lang_items_query").entered(); - - let mut lang_items = LangItems::default(); - - let crate_def_map = db.crate_def_map(krate); - - for (_, module_data) in crate_def_map.modules() { - for impl_def in module_data.scope.impls() { - lang_items.collect_lang_item(db, impl_def, LangItemTarget::ImplDef); - for &(_, assoc) in db.impl_items(impl_def).items.iter() { - match assoc { - AssocItemId::FunctionId(f) => { - lang_items.collect_lang_item(db, f, LangItemTarget::Function) - } - AssocItemId::TypeAliasId(t) => { - lang_items.collect_lang_item(db, t, LangItemTarget::TypeAlias) - } - AssocItemId::ConstId(_) => (), - } - } - } - - for def in module_data.scope.declarations() { - match def { - ModuleDefId::TraitId(trait_) => { - lang_items.collect_lang_item(db, trait_, LangItemTarget::Trait); - db.trait_items(trait_).items.iter().for_each( - |&(_, assoc_id)| match assoc_id { - AssocItemId::FunctionId(f) => { - lang_items.collect_lang_item(db, f, LangItemTarget::Function); - } - AssocItemId::TypeAliasId(alias) => lang_items.collect_lang_item( - db, - alias, - LangItemTarget::TypeAlias, - ), - AssocItemId::ConstId(_) => {} - }, - ); - } - ModuleDefId::AdtId(AdtId::EnumId(e)) => { - lang_items.collect_lang_item(db, e, LangItemTarget::EnumId); - db.enum_variants(e).variants.iter().for_each(|&(id, _)| { - lang_items.collect_lang_item(db, id, LangItemTarget::EnumVariant); - }); - } - ModuleDefId::AdtId(AdtId::StructId(s)) => { - lang_items.collect_lang_item(db, s, LangItemTarget::Struct); - } - ModuleDefId::AdtId(AdtId::UnionId(u)) => { - lang_items.collect_lang_item(db, u, LangItemTarget::Union); - } - ModuleDefId::FunctionId(f) => { - lang_items.collect_lang_item(db, f, LangItemTarget::Function); - } - ModuleDefId::StaticId(s) => { - lang_items.collect_lang_item(db, s, LangItemTarget::Static); - } - ModuleDefId::TypeAliasId(t) => { - lang_items.collect_lang_item(db, t, LangItemTarget::TypeAlias); - } - _ => {} - } - } - } - - if lang_items.items.is_empty() { None } else { Some(Arc::new(lang_items)) } - } - - /// Salsa query. Look for a lang item, starting from the specified crate and recursively - /// traversing its dependencies. - pub(crate) fn lang_item_query( - db: &dyn DefDatabase, - start_crate: Crate, - item: LangItem, - ) -> Option { - let _p = tracing::info_span!("lang_item_query").entered(); - if let Some(target) = - db.crate_lang_items(start_crate).and_then(|it| it.items.get(&item).copied()) - { - return Some(target); - } - start_crate.data(db).dependencies.iter().find_map(|dep| db.lang_item(dep.crate_id, item)) - } - fn collect_lang_item( &mut self, db: &dyn DefDatabase, @@ -269,18 +264,38 @@ macro_rules! language_item_table { } impl LangItem { + pub fn resolve_function(self, db: &dyn DefDatabase, start_crate: Crate) -> Option { + lang_item(db, start_crate, self).and_then(|t| t.as_function()) + } + + pub fn resolve_trait(self, db: &dyn DefDatabase, start_crate: Crate) -> Option { + lang_item(db, start_crate, self).and_then(|t| t.as_trait()) + } + + pub fn resolve_enum(self, db: &dyn DefDatabase, start_crate: Crate) -> Option { + lang_item(db, start_crate, self).and_then(|t| t.as_enum()) + } + + pub fn resolve_type_alias( + self, + db: &dyn DefDatabase, + start_crate: Crate, + ) -> Option { + lang_item(db, start_crate, self).and_then(|t| t.as_type_alias()) + } + /// Opposite of [`LangItem::name`] pub fn from_name(name: &hir_expand::name::Name) -> Option { Self::from_symbol(name.symbol()) } pub fn path(&self, db: &dyn DefDatabase, start_crate: Crate) -> Option { - let t = db.lang_item(start_crate, *self)?; + let t = lang_item(db, start_crate, *self)?; Some(Path::LangItem(t, None)) } pub fn ty_rel_path(&self, db: &dyn DefDatabase, start_crate: Crate, seg: Name) -> Option { - let t = db.lang_item(start_crate, *self)?; + let t = lang_item(db, start_crate, *self)?; Some(Path::LangItem(t, Some(seg))) } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs index 737941dba07e..28011bda7c54 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs @@ -64,8 +64,8 @@ use std::hash::{Hash, Hasher}; use base_db::{Crate, impl_intern_key}; use hir_expand::{ - AstId, ExpandError, ExpandResult, ExpandTo, HirFileId, InFile, MacroCallId, MacroCallKind, - MacroDefId, MacroDefKind, + AstId, ExpandResult, ExpandTo, HirFileId, InFile, MacroCallId, MacroCallKind, MacroDefId, + MacroDefKind, builtin::{BuiltinAttrExpander, BuiltinDeriveExpander, BuiltinFnLikeExpander, EagerExpander}, db::ExpandDatabase, eager::expand_eager_macro_input, @@ -79,7 +79,7 @@ use la_arena::Idx; use nameres::DefMap; use span::{AstIdNode, Edition, FileAstId, SyntaxContext}; use stdx::impl_from; -use syntax::{AstNode, ast}; +use syntax::ast; pub use hir_expand::{Intern, Lookup, tt}; @@ -554,7 +554,7 @@ pub enum ItemContainerId { impl_from!(ModuleId for ItemContainerId); /// A Data Type -#[derive(Debug, PartialOrd, Ord, Clone, Copy, PartialEq, Eq, Hash, salsa::Supertype)] +#[derive(Debug, PartialOrd, Ord, Clone, Copy, PartialEq, Eq, Hash, salsa_macros::Supertype)] pub enum AdtId { StructId(StructId), UnionId(UnionId), @@ -563,7 +563,7 @@ pub enum AdtId { impl_from!(StructId, UnionId, EnumId for AdtId); /// A macro -#[derive(Debug, PartialOrd, Ord, Clone, Copy, PartialEq, Eq, Hash, salsa::Supertype)] +#[derive(Debug, PartialOrd, Ord, Clone, Copy, PartialEq, Eq, Hash, salsa_macros::Supertype)] pub enum MacroId { Macro2Id(Macro2Id), MacroRulesId(MacroRulesId), @@ -619,7 +619,7 @@ impl_from!( /// A constant, which might appears as a const item, an anonymous const block in expressions /// or patterns, or as a constant in types with const generics. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, salsa::Supertype)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, salsa_macros::Supertype)] pub enum GeneralConstId { ConstId(ConstId), StaticId(StaticId), @@ -656,7 +656,7 @@ impl GeneralConstId { } /// The defs which have a body (have root expressions for type inference). -#[derive(Debug, PartialOrd, Ord, Clone, Copy, PartialEq, Eq, Hash, salsa::Supertype)] +#[derive(Debug, PartialOrd, Ord, Clone, Copy, PartialEq, Eq, Hash, salsa_macros::Supertype)] pub enum DefWithBodyId { FunctionId(FunctionId), StaticId(StaticId), @@ -701,7 +701,7 @@ pub enum AssocItemId { // casting them, and somehow making the constructors private, which would be annoying. impl_from!(FunctionId, ConstId, TypeAliasId for AssocItemId); -#[derive(Debug, PartialOrd, Ord, Clone, Copy, PartialEq, Eq, Hash, salsa::Supertype)] +#[derive(Debug, PartialOrd, Ord, Clone, Copy, PartialEq, Eq, Hash, salsa_macros::Supertype)] pub enum GenericDefId { AdtId(AdtId), // consts can have type parameters from their parents (i.e. associated consts of traits) @@ -790,7 +790,7 @@ impl From for GenericDefId { } } -#[derive(Debug, PartialOrd, Ord, Clone, Copy, PartialEq, Eq, Hash, salsa::Supertype)] +#[derive(Debug, PartialOrd, Ord, Clone, Copy, PartialEq, Eq, Hash, salsa_macros::Supertype)] pub enum CallableDefId { FunctionId(FunctionId), StructId(StructId), @@ -906,7 +906,7 @@ impl From for AttrDefId { } } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, salsa::Supertype)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, salsa_macros::Supertype)] pub enum VariantId { EnumVariantId(EnumVariantId), StructId(StructId), @@ -1166,66 +1166,6 @@ impl ModuleDefId { }) } } - -// FIXME: Replace this with a plain function, it only has one impl -/// A helper trait for converting to MacroCallId -trait AsMacroCall { - fn as_call_id_with_errors( - &self, - db: &dyn ExpandDatabase, - krate: Crate, - resolver: impl Fn(&ModPath) -> Option + Copy, - eager_callback: &mut dyn FnMut( - InFile<(syntax::AstPtr, span::FileAstId)>, - MacroCallId, - ), - ) -> Result>, UnresolvedMacro>; -} - -impl AsMacroCall for InFile<&ast::MacroCall> { - fn as_call_id_with_errors( - &self, - db: &dyn ExpandDatabase, - krate: Crate, - resolver: impl Fn(&ModPath) -> Option + Copy, - eager_callback: &mut dyn FnMut( - InFile<(syntax::AstPtr, span::FileAstId)>, - MacroCallId, - ), - ) -> Result>, UnresolvedMacro> { - let expands_to = hir_expand::ExpandTo::from_call_site(self.value); - let ast_id = AstId::new(self.file_id, db.ast_id_map(self.file_id).ast_id(self.value)); - let span_map = db.span_map(self.file_id); - let path = self.value.path().and_then(|path| { - let range = path.syntax().text_range(); - let mod_path = ModPath::from_src(db, path, &mut |range| { - span_map.as_ref().span_for_range(range).ctx - })?; - let call_site = span_map.span_for_range(range); - Some((call_site, mod_path)) - }); - - let Some((call_site, path)) = path else { - return Ok(ExpandResult::only_err(ExpandError::other( - span_map.span_for_range(self.value.syntax().text_range()), - "malformed macro invocation", - ))); - }; - - macro_call_as_call_id_with_eager( - db, - ast_id, - &path, - call_site.ctx, - expands_to, - krate, - resolver, - resolver, - eager_callback, - ) - } -} - /// Helper wrapper for `AstId` with `ModPath` #[derive(Clone, Debug, Eq, PartialEq)] struct AstIdWithPath { @@ -1239,41 +1179,14 @@ impl AstIdWithPath { } } -fn macro_call_as_call_id( - db: &dyn ExpandDatabase, - call: &AstIdWithPath, - call_site: SyntaxContext, - expand_to: ExpandTo, - krate: Crate, - resolver: impl Fn(&ModPath) -> Option + Copy, - eager_callback: &mut dyn FnMut( - InFile<(syntax::AstPtr, span::FileAstId)>, - MacroCallId, - ), -) -> Result, UnresolvedMacro> { - macro_call_as_call_id_with_eager( - db, - call.ast_id, - &call.path, - call_site, - expand_to, - krate, - resolver, - resolver, - eager_callback, - ) - .map(|res| res.value) -} - -fn macro_call_as_call_id_with_eager( +pub fn macro_call_as_call_id( db: &dyn ExpandDatabase, ast_id: AstId, path: &ModPath, call_site: SyntaxContext, expand_to: ExpandTo, krate: Crate, - resolver: impl FnOnce(&ModPath) -> Option, - eager_resolver: impl Fn(&ModPath) -> Option, + resolver: impl Fn(&ModPath) -> Option + Copy, eager_callback: &mut dyn FnMut( InFile<(syntax::AstPtr, span::FileAstId)>, MacroCallId, @@ -1289,7 +1202,7 @@ fn macro_call_as_call_id_with_eager( ast_id, def, call_site, - &|path| eager_resolver(path).filter(MacroDefId::is_fn_like), + &|path| resolver(path).filter(MacroDefId::is_fn_like), eager_callback, ), _ if def.is_fn_like() => ExpandResult { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs index a3b48831a0b0..e21d1415aa29 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs @@ -285,8 +285,6 @@ fn main() { /* parse error: expected expression */ builtin #format_args (x = ); /* parse error: expected expression */ -/* parse error: expected R_PAREN */ -/* parse error: expected expression, item or let statement */ builtin #format_args (x = , x = 2); /* parse error: expected expression */ builtin #format_args ("{}", x = ); diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs index abb5bd5ed726..38fc4b3d118a 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs @@ -2001,8 +2001,9 @@ macro_rules! bug { true }; } - -let _ = bug!(a;;;test); +fn f() { + let _ = bug!(a;;;test); +} "#, expect![[r#" macro_rules! bug { @@ -2022,8 +2023,9 @@ macro_rules! bug { true }; } - -let _ = true; +fn f() { + let _ = true; +} "#]], ); } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs index 143b5df77305..800c96ebdae0 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs @@ -19,7 +19,7 @@ use std::{iter, ops::Range, sync}; use base_db::RootQueryDb; use expect_test::Expect; use hir_expand::{ - InFile, MacroCallKind, MacroKind, + AstId, InFile, MacroCallId, MacroCallKind, MacroKind, db::ExpandDatabase, proc_macro::{ProcMacro, ProcMacroExpander, ProcMacroExpansionError, ProcMacroKind}, span_map::SpanMapRef, @@ -29,7 +29,7 @@ use itertools::Itertools; use span::{Edition, Span}; use stdx::{format_to, format_to_acc}; use syntax::{ - AstNode, + AstNode, AstPtr, SyntaxKind::{COMMENT, EOF, IDENT, LIFETIME_IDENT}, SyntaxNode, T, ast::{self, edit::IndentLevel}, @@ -37,10 +37,9 @@ use syntax::{ use test_fixture::WithFixture; use crate::{ - AdtId, AsMacroCall, Lookup, ModuleDefId, + AdtId, Lookup, ModuleDefId, db::DefDatabase, - nameres::{DefMap, MacroSubNs, ModuleSource}, - resolver::HasResolver, + nameres::{DefMap, ModuleSource}, src::HasSource, test_db::TestDB, tt::TopSubtree, @@ -78,7 +77,6 @@ fn check_errors(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) expect.assert_eq(&errors); } -#[track_caller] fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, mut expect: Expect) { let extra_proc_macros = vec![( r#" @@ -95,54 +93,59 @@ pub fn identity_when_valid(_attr: TokenStream, item: TokenStream) -> TokenStream disabled: false, }, )]; + + fn resolve( + db: &dyn DefDatabase, + def_map: &DefMap, + ast_id: AstId, + ast_ptr: InFile>, + ) -> Option { + def_map.modules().find_map(|module| { + for decl in + module.1.scope.declarations().chain(module.1.scope.unnamed_consts().map(Into::into)) + { + let body = match decl { + ModuleDefId::FunctionId(it) => it.into(), + ModuleDefId::ConstId(it) => it.into(), + ModuleDefId::StaticId(it) => it.into(), + _ => continue, + }; + + let (body, sm) = db.body_with_source_map(body); + if let Some(it) = + body.blocks(db).find_map(|block| resolve(db, &block.1, ast_id, ast_ptr)) + { + return Some(it); + } + if let Some((_, res)) = sm.macro_calls().find(|it| it.0 == ast_ptr) { + return Some(res); + } + } + module.1.scope.macro_invoc(ast_id) + }) + } + let db = TestDB::with_files_extra_proc_macros(ra_fixture, extra_proc_macros); let krate = db.fetch_test_crate(); let def_map = db.crate_def_map(krate); let local_id = DefMap::ROOT; - let module = def_map.module_id(local_id); - let resolver = module.resolver(&db); let source = def_map[local_id].definition_source(&db); let source_file = match source.value { ModuleSource::SourceFile(it) => it, ModuleSource::Module(_) | ModuleSource::BlockExpr(_) => panic!(), }; - // What we want to do is to replace all macros (fn-like, derive, attr) with - // their expansions. Turns out, we don't actually store enough information - // to do this precisely though! Specifically, if a macro expands to nothing, - // it leaves zero traces in def-map, so we can't get its expansion after the - // fact. - // - // This is the usual - // - // resolve/record tension! - // - // So here we try to do a resolve, which is necessary a heuristic. For macro - // calls, we use `as_call_id_with_errors`. For derives, we look at the impls - // in the module and assume that, if impls's source is a different - // `HirFileId`, than it came from macro expansion. - let mut text_edits = Vec::new(); let mut expansions = Vec::new(); - for macro_call in source_file.syntax().descendants().filter_map(ast::MacroCall::cast) { - let macro_call = InFile::new(source.file_id, ¯o_call); - let res = macro_call - .as_call_id_with_errors( - &db, - krate, - |path| { - resolver - .resolve_path_as_macro(&db, path, Some(MacroSubNs::Bang)) - .map(|(it, _)| db.macro_def(it)) - }, - &mut |_, _| (), - ) - .unwrap(); - let macro_call_id = res.value.unwrap(); - let mut expansion_result = db.parse_macro_expansion(macro_call_id); - expansion_result.err = expansion_result.err.or(res.err); - expansions.push((macro_call.value.clone(), expansion_result)); + for macro_call_node in source_file.syntax().descendants().filter_map(ast::MacroCall::cast) { + let ast_id = db.ast_id_map(source.file_id).ast_id(¯o_call_node); + let ast_id = InFile::new(source.file_id, ast_id); + let ptr = InFile::new(source.file_id, AstPtr::new(¯o_call_node)); + let macro_call_id = resolve(&db, &def_map, ast_id, ptr) + .unwrap_or_else(|| panic!("unable to find semantic macro call {macro_call_node}")); + let expansion_result = db.parse_macro_expansion(macro_call_id); + expansions.push((macro_call_node.clone(), expansion_result)); } for (call, exp) in expansions.into_iter().rev() { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/assoc.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/assoc.rs index b09706552947..448b908936a2 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/assoc.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/assoc.rs @@ -259,7 +259,8 @@ impl<'a> AssocItemCollector<'a> { }; match macro_call_as_call_id( self.db, - &AstIdWithPath::new(tree_id.file_id(), ast_id, Clone::clone(path)), + InFile::new(tree_id.file_id(), ast_id), + path, ctxt, expand_to, self.module_id.krate(), @@ -268,12 +269,15 @@ impl<'a> AssocItemCollector<'a> { self.macro_calls.push((ptr.map(|(_, it)| it.upcast()), call_id)) }, ) { - Ok(Some(call_id)) => { - self.macro_calls - .push((InFile::new(tree_id.file_id(), ast_id.upcast()), call_id)); - self.collect_macro_items(call_id); - } - Ok(None) => (), + // FIXME: Expansion error? + Ok(call_id) => match call_id.value { + Some(call_id) => { + self.macro_calls + .push((InFile::new(tree_id.file_id(), ast_id.upcast()), call_id)); + self.collect_macro_items(call_id); + } + None => (), + }, Err(_) => { self.diagnostics.push(DefDiagnostic::unresolved_macro_call( self.module_id.local_id, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs index 77effbcc8800..8df0f092cd0b 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs @@ -39,7 +39,7 @@ use crate::{ ItemTreeId, ItemTreeNode, Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, TreeId, UseTreeKind, }, - macro_call_as_call_id, macro_call_as_call_id_with_eager, + macro_call_as_call_id, nameres::{ BuiltinShadowMode, DefMap, LocalDefMap, MacroSubNs, ModuleData, ModuleOrigin, ResolveMode, attr_resolution::{attr_macro_as_call_id, derive_macro_as_call_id}, @@ -1256,7 +1256,8 @@ impl DefCollector<'_> { MacroDirectiveKind::FnLike { ast_id, expand_to, ctxt: call_site } => { let call_id = macro_call_as_call_id( self.db, - ast_id, + ast_id.ast_id, + &ast_id.path, *call_site, *expand_to, self.def_map.krate, @@ -1265,15 +1266,18 @@ impl DefCollector<'_> { eager_callback_buffer.push((directive.module_id, ptr, call_id)); }, ); - if let Ok(Some(call_id)) = call_id { - self.def_map.modules[directive.module_id] - .scope - .add_macro_invoc(ast_id.ast_id, call_id); + if let Ok(call_id) = call_id { + // FIXME: Expansion error + if let Some(call_id) = call_id.value { + self.def_map.modules[directive.module_id] + .scope + .add_macro_invoc(ast_id.ast_id, call_id); - push_resolved(directive, call_id); + push_resolved(directive, call_id); - res = ReachedFixedPoint::No; - return Resolved::Yes; + res = ReachedFixedPoint::No; + return Resolved::Yes; + } } } MacroDirectiveKind::Derive { @@ -1542,7 +1546,8 @@ impl DefCollector<'_> { // FIXME: we shouldn't need to re-resolve the macro here just to get the unresolved error! let macro_call_as_call_id = macro_call_as_call_id( self.db, - ast_id, + ast_id.ast_id, + &ast_id.path, *call_site, *expand_to, self.def_map.krate, @@ -2420,7 +2425,7 @@ impl ModCollector<'_, '_> { let mut eager_callback_buffer = vec![]; // Case 1: try to resolve macro calls with single-segment name and expand macro_rules - if let Ok(res) = macro_call_as_call_id_with_eager( + if let Ok(res) = macro_call_as_call_id( db, ast_id.ast_id, &ast_id.path, @@ -2445,21 +2450,6 @@ impl ModCollector<'_, '_> { .map(|it| self.def_collector.db.macro_def(it)) }) }, - |path| { - let resolved_res = self.def_collector.def_map.resolve_path_fp_with_macro( - self.def_collector - .crate_local_def_map - .as_deref() - .unwrap_or(&self.def_collector.local_def_map), - db, - ResolveMode::Other, - self.module_id, - path, - BuiltinShadowMode::Module, - Some(MacroSubNs::Bang), - ); - resolved_res.resolved_def.take_macros().map(|it| db.macro_def(it)) - }, &mut |ptr, call_id| eager_callback_buffer.push((ptr, call_id)), ) { for (ptr, call_id) in eager_callback_buffer { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/mod_resolution.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/mod_resolution.rs index d6c9f5a00c91..0c50f13edfb6 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/mod_resolution.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/mod_resolution.rs @@ -86,7 +86,7 @@ impl ModDir { let dir_path = if root_dir_owner { DirPath::empty() } else { - DirPath::new(format!("{}/", name)) + DirPath::new(format!("{name}/")) }; if let Some(mod_dir) = self.child(dir_path, !root_dir_owner) { return Ok(( diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs index f8b2c73a8f68..a49155d878ca 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs @@ -673,12 +673,11 @@ impl DefMap { } fn resolve_in_macro_use_prelude(&self, name: &Name) -> PerNs { - self.macro_use_prelude.get(name).map_or(PerNs::none(), |&(it, _extern_crate)| { + self.macro_use_prelude.get(name).map_or(PerNs::none(), |&(it, extern_crate)| { PerNs::macros( it, Visibility::Public, - // FIXME? - None, // extern_crate.map(ImportOrExternCrate::ExternCrate), + extern_crate.map(ImportOrExternCrate::ExternCrate), ) }) } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/per_ns.rs b/src/tools/rust-analyzer/crates/hir-def/src/per_ns.rs index 1f7dd6f0c407..8721cd65dbac 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/per_ns.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/per_ns.rs @@ -37,7 +37,8 @@ pub struct Item { pub type TypesItem = Item; pub type ValuesItem = Item; -pub type MacrosItem = Item; +// May be Externcrate for `[macro_use]`'d macros +pub type MacrosItem = Item; #[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)] pub struct PerNs { @@ -84,7 +85,7 @@ impl PerNs { } } - pub fn macros(def: MacroId, vis: Visibility, import: Option) -> PerNs { + pub fn macros(def: MacroId, vis: Visibility, import: Option) -> PerNs { PerNs { types: None, values: None, macros: Some(Item { def, vis, import }) } } @@ -116,7 +117,7 @@ impl PerNs { self.macros.map(|it| it.def) } - pub fn take_macros_import(self) -> Option<(MacroId, Option)> { + pub fn take_macros_import(self) -> Option<(MacroId, Option)> { self.macros.map(|it| (it.def, it.import)) } @@ -158,9 +159,6 @@ impl PerNs { self.values .map(|it| (ItemInNs::Values(it.def), it.import.map(ImportOrExternCrate::from))), ) - .chain( - self.macros - .map(|it| (ItemInNs::Macros(it.def), it.import.map(ImportOrExternCrate::from))), - ) + .chain(self.macros.map(|it| (ItemInNs::Macros(it.def), it.import))) } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs index 46c12574fded..8a8d17018c1b 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs @@ -493,7 +493,7 @@ impl Resolver { db: &dyn DefDatabase, path: &ModPath, expected_macro_kind: Option, - ) -> Option<(MacroId, Option)> { + ) -> Option<(MacroId, Option)> { let (item_map, item_local_map, module) = self.item_scope_(); item_map .resolve_path( diff --git a/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs b/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs index 2f7675134ca7..470975482951 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs @@ -19,7 +19,7 @@ use crate::{ src::HasSource, }; -#[salsa::db] +#[salsa_macros::db] #[derive(Clone)] pub(crate) struct TestDB { storage: salsa::Storage, @@ -44,7 +44,7 @@ impl Default for TestDB { } } -#[salsa::db] +#[salsa_macros::db] impl salsa::Database for TestDB { fn salsa_event(&self, event: &dyn std::ops::Fn() -> salsa::Event) { let mut events = self.events.lock().unwrap(); @@ -63,7 +63,7 @@ impl fmt::Debug for TestDB { impl panic::RefUnwindSafe for TestDB {} -#[salsa::db] +#[salsa_macros::db] impl SourceDatabase for TestDB { fn file_text(&self, file_id: base_db::FileId) -> FileText { self.files.file_text(file_id) diff --git a/src/tools/rust-analyzer/crates/hir-expand/Cargo.toml b/src/tools/rust-analyzer/crates/hir-expand/Cargo.toml index b83efca25528..ed818c5be3f7 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/Cargo.toml +++ b/src/tools/rust-analyzer/crates/hir-expand/Cargo.toml @@ -21,6 +21,7 @@ smallvec.workspace = true triomphe.workspace = true query-group.workspace = true salsa.workspace = true +salsa-macros.workspace = true # local deps stdx.workspace = true diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs b/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs index 5dae27f7a16c..bb17eb062760 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs @@ -2,7 +2,7 @@ use std::{borrow::Cow, fmt, ops}; use base_db::Crate; -use cfg::CfgExpr; +use cfg::{CfgExpr, CfgOptions}; use either::Either; use intern::{Interned, Symbol, sym}; @@ -14,11 +14,10 @@ use syntax::{AstNode, AstToken, SyntaxNode, ast, match_ast}; use syntax_bridge::{DocCommentDesugarMode, desugar_doc_comment_text, syntax_node_to_token_tree}; use triomphe::ThinArc; -use crate::name::Name; use crate::{ - InFile, db::ExpandDatabase, mod_path::ModPath, + name::Name, span_map::SpanMapRef, tt::{self, TopSubtree, token_to_literal}, }; @@ -49,29 +48,7 @@ impl RawAttrs { owner: &dyn ast::HasAttrs, span_map: SpanMapRef<'_>, ) -> Self { - let entries: Vec<_> = collect_attrs(owner) - .filter_map(|(id, attr)| match attr { - Either::Left(attr) => { - attr.meta().and_then(|meta| Attr::from_src(db, meta, span_map, id)) - } - Either::Right(comment) => comment.doc_comment().map(|doc| { - let span = span_map.span_for_range(comment.syntax().text_range()); - let (text, kind) = - desugar_doc_comment_text(doc, DocCommentDesugarMode::ProcMacro); - Attr { - id, - input: Some(Box::new(AttrInput::Literal(tt::Literal { - symbol: text, - span, - kind, - suffix: None, - }))), - path: Interned::new(ModPath::from(Name::new_symbol(sym::doc, span.ctx))), - ctxt: span.ctx, - } - }), - }) - .collect(); + let entries: Vec<_> = Self::attrs_iter::(db, owner, span_map).collect(); let entries = if entries.is_empty() { None @@ -82,12 +59,61 @@ impl RawAttrs { RawAttrs { entries } } - pub fn from_attrs_owner( + /// A [`RawAttrs`] that has its `#[cfg_attr(...)]` attributes expanded. + pub fn new_expanded( db: &dyn ExpandDatabase, - owner: InFile<&dyn ast::HasAttrs>, + owner: &dyn ast::HasAttrs, span_map: SpanMapRef<'_>, + cfg_options: &CfgOptions, ) -> Self { - Self::new(db, owner.value, span_map) + let entries: Vec<_> = + Self::attrs_iter_expanded::(db, owner, span_map, cfg_options).collect(); + + let entries = if entries.is_empty() { + None + } else { + Some(ThinArc::from_header_and_iter((), entries.into_iter())) + }; + + RawAttrs { entries } + } + + pub fn attrs_iter( + db: &dyn ExpandDatabase, + owner: &dyn ast::HasAttrs, + span_map: SpanMapRef<'_>, + ) -> impl Iterator { + collect_attrs(owner).filter_map(move |(id, attr)| match attr { + Either::Left(attr) => { + attr.meta().and_then(|meta| Attr::from_src(db, meta, span_map, id)) + } + Either::Right(comment) if DESUGAR_COMMENTS => comment.doc_comment().map(|doc| { + let span = span_map.span_for_range(comment.syntax().text_range()); + let (text, kind) = desugar_doc_comment_text(doc, DocCommentDesugarMode::ProcMacro); + Attr { + id, + input: Some(Box::new(AttrInput::Literal(tt::Literal { + symbol: text, + span, + kind, + suffix: None, + }))), + path: Interned::new(ModPath::from(Name::new_symbol(sym::doc, span.ctx))), + ctxt: span.ctx, + } + }), + Either::Right(_) => None, + }) + } + + pub fn attrs_iter_expanded( + db: &dyn ExpandDatabase, + owner: &dyn ast::HasAttrs, + span_map: SpanMapRef<'_>, + cfg_options: &CfgOptions, + ) -> impl Iterator { + Self::attrs_iter::(db, owner, span_map) + .flat_map(|attr| attr.expand_cfg_attr(db, cfg_options)) } pub fn merge(&self, other: Self) -> Self { @@ -114,9 +140,8 @@ impl RawAttrs { } } - /// Processes `cfg_attr`s, returning the resulting semantic `Attrs`. - // FIXME: This should return a different type, signaling it was filtered? - pub fn filter(self, db: &dyn ExpandDatabase, krate: Crate) -> RawAttrs { + /// Processes `cfg_attr`s + pub fn expand_cfg_attr(self, db: &dyn ExpandDatabase, krate: Crate) -> RawAttrs { let has_cfg_attrs = self.iter().any(|attr| attr.path.as_ident().is_some_and(|name| *name == sym::cfg_attr)); if !has_cfg_attrs { @@ -126,37 +151,8 @@ impl RawAttrs { let cfg_options = krate.cfg_options(db); let new_attrs = self .iter() - .flat_map(|attr| -> SmallVec<[_; 1]> { - let is_cfg_attr = attr.path.as_ident().is_some_and(|name| *name == sym::cfg_attr); - if !is_cfg_attr { - return smallvec![attr.clone()]; - } - - let subtree = match attr.token_tree_value() { - Some(it) => it, - _ => return smallvec![attr.clone()], - }; - - let (cfg, parts) = match parse_cfg_attr_input(subtree) { - Some(it) => it, - None => return smallvec![attr.clone()], - }; - let index = attr.id; - let attrs = parts - .enumerate() - .take(1 << AttrId::CFG_ATTR_BITS) - .filter_map(|(idx, attr)| Attr::from_tt(db, attr, index.with_cfg_attr(idx))); - - let cfg = TopSubtree::from_token_trees(subtree.top_subtree().delimiter, cfg); - let cfg = CfgExpr::parse(&cfg); - if cfg_options.check(&cfg) == Some(false) { - smallvec![] - } else { - cov_mark::hit!(cfg_attr_active); - - attrs.collect() - } - }) + .cloned() + .flat_map(|attr| attr.expand_cfg_attr(db, cfg_options)) .collect::>(); let entries = if new_attrs.is_empty() { None @@ -316,6 +312,42 @@ impl Attr { pub fn path(&self) -> &ModPath { &self.path } + + pub fn expand_cfg_attr( + self, + db: &dyn ExpandDatabase, + cfg_options: &CfgOptions, + ) -> impl IntoIterator { + let is_cfg_attr = self.path.as_ident().is_some_and(|name| *name == sym::cfg_attr); + if !is_cfg_attr { + return smallvec![self]; + } + + let subtree = match self.token_tree_value() { + Some(it) => it, + _ => return smallvec![self.clone()], + }; + + let (cfg, parts) = match parse_cfg_attr_input(subtree) { + Some(it) => it, + None => return smallvec![self.clone()], + }; + let index = self.id; + let attrs = parts + .enumerate() + .take(1 << AttrId::CFG_ATTR_BITS) + .filter_map(|(idx, attr)| Attr::from_tt(db, attr, index.with_cfg_attr(idx))); + + let cfg = TopSubtree::from_token_trees(subtree.top_subtree().delimiter, cfg); + let cfg = CfgExpr::parse(&cfg); + if cfg_options.check(&cfg) == Some(false) { + smallvec![] + } else { + cov_mark::hit!(cfg_attr_active); + + attrs.collect::>() + } + } } impl Attr { diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/change.rs b/src/tools/rust-analyzer/crates/hir-expand/src/change.rs index 6873cb7eaf9c..3959741e6f13 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/change.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/change.rs @@ -1,7 +1,6 @@ //! Defines a unit of change that can applied to the database to get the next //! state. Changes are transactional. -use base_db::{CrateGraphBuilder, FileChange, SourceRoot}; -use salsa::Durability; +use base_db::{CrateGraphBuilder, FileChange, SourceRoot, salsa::Durability}; use span::FileId; use triomphe::Arc; diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/db.rs b/src/tools/rust-analyzer/crates/hir-expand/src/db.rs index 29b7b33fd0fb..7cb1b6c02075 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/db.rs @@ -18,10 +18,7 @@ use crate::{ cfg_process, declarative::DeclarativeMacroExpander, fixup::{self, SyntaxFixupUndoInfo}, - hygiene::{ - SyntaxContextExt as _, span_with_call_site_ctxt, span_with_def_site_ctxt, - span_with_mixed_site_ctxt, - }, + hygiene::{span_with_call_site_ctxt, span_with_def_site_ctxt, span_with_mixed_site_ctxt}, proc_macro::{CrateProcMacros, CustomProcMacroExpander, ProcMacros}, span_map::{ExpansionSpanMap, RealSpanMap, SpanMap, SpanMapRef}, tt, @@ -147,7 +144,7 @@ pub trait ExpandDatabase: RootQueryDb { fn syntax_context(&self, file: HirFileId, edition: Edition) -> SyntaxContext; } -#[salsa::interned(no_lifetime, id = span::SyntaxContext)] +#[salsa_macros::interned(no_lifetime, id = span::SyntaxContext)] pub struct SyntaxContextWrapper { pub data: SyntaxContext, } @@ -752,8 +749,7 @@ fn check_tt_count(tt: &tt::TopSubtree) -> Result<(), ExpandResult<()>> { err: Some(ExpandError::other( tt.delimiter.open, format!( - "macro invocation exceeds token limit: produced {} tokens, limit is {}", - count, TOKEN_LIMIT, + "macro invocation exceeds token limit: produced {count} tokens, limit is {TOKEN_LIMIT}", ), )), }) diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/declarative.rs b/src/tools/rust-analyzer/crates/hir-expand/src/declarative.rs index 1fa682ce3a2d..0d100c1364ab 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/declarative.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/declarative.rs @@ -82,7 +82,7 @@ impl DeclarativeMacroExpander { let transparency = |node| { // ... would be nice to have the item tree here - let attrs = RawAttrs::new(db, node, map.as_ref()).filter(db, def_crate); + let attrs = RawAttrs::new_expanded(db, node, map.as_ref(), def_crate.cfg_options(db)); match attrs .iter() .find(|it| { diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs b/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs index e7856920bc42..28800c6fabdb 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs @@ -22,7 +22,7 @@ // FIXME: Move this into the span crate? Not quite possible today as that depends on `MacroCallLoc` // which contains a bunch of unrelated things -use std::{convert::identity, iter}; +use std::convert::identity; use span::{Edition, MacroCallId, Span, SyntaxContext}; @@ -141,61 +141,3 @@ fn apply_mark_internal( |_| opaque_and_semitransparent, ) } - -pub trait SyntaxContextExt { - fn normalize_to_macro_rules(self, db: &dyn ExpandDatabase) -> span::SyntaxContext; - fn normalize_to_macros_2_0(self, db: &dyn ExpandDatabase) -> span::SyntaxContext; - fn parent_ctxt(self, db: &dyn ExpandDatabase) -> span::SyntaxContext; - fn remove_mark(&mut self, db: &dyn ExpandDatabase) - -> (Option, Transparency); - fn outer_mark(self, db: &dyn ExpandDatabase) -> (Option, Transparency); - fn marks(self, db: &dyn ExpandDatabase) -> Vec<(span::MacroCallId, Transparency)>; - fn is_opaque(self, db: &dyn ExpandDatabase) -> bool; -} - -impl SyntaxContextExt for SyntaxContext { - fn normalize_to_macro_rules(self, db: &dyn ExpandDatabase) -> span::SyntaxContext { - self.opaque_and_semitransparent(db) - } - fn normalize_to_macros_2_0(self, db: &dyn ExpandDatabase) -> span::SyntaxContext { - self.opaque(db) - } - fn parent_ctxt(self, db: &dyn ExpandDatabase) -> span::SyntaxContext { - self.parent(db) - } - fn outer_mark(self, db: &dyn ExpandDatabase) -> (Option, Transparency) { - let data = self; - (data.outer_expn(db), data.outer_transparency(db)) - } - fn remove_mark( - &mut self, - db: &dyn ExpandDatabase, - ) -> (Option, Transparency) { - let data = *self; - *self = data.parent(db); - (data.outer_expn(db), data.outer_transparency(db)) - } - fn marks(self, db: &dyn ExpandDatabase) -> Vec<(span::MacroCallId, Transparency)> { - let mut marks = marks_rev(self, db).collect::>(); - marks.reverse(); - marks - } - fn is_opaque(self, db: &dyn ExpandDatabase) -> bool { - !self.is_root() && self.outer_transparency(db).is_opaque() - } -} - -// FIXME: Make this a SyntaxContextExt method once we have RPIT -pub fn marks_rev( - ctxt: SyntaxContext, - db: &dyn ExpandDatabase, -) -> impl Iterator + '_ { - iter::successors(Some(ctxt), move |&mark| Some(mark.parent_ctxt(db))) - .take_while(|&it| !it.is_root()) - .map(|ctx| { - let mark = ctx.outer_mark(db); - // We stop before taking the root expansion, as such we cannot encounter a `None` outer - // expansion, as only the ROOT has it. - (mark.0.unwrap(), mark.1) - }) -} diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs index f0a9a2ad52c8..d844d8f41eef 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs @@ -206,8 +206,7 @@ impl ExpandErrorKind { }, None => RenderedExpandError { message: format!( - "internal error: proc-macro map is missing error entry for crate {:?}", - def_crate + "internal error: proc-macro map is missing error entry for crate {def_crate:?}" ), error: true, kind: RenderedExpandError::GENERAL_KIND, @@ -1051,7 +1050,7 @@ impl ExpandTo { intern::impl_internable!(ModPath, attrs::AttrInput); -#[salsa::interned(no_lifetime, debug)] +#[salsa_macros::interned(no_lifetime, debug)] #[doc(alias = "MacroFileId")] pub struct MacroCallId { pub loc: MacroCallLoc, @@ -1071,7 +1070,7 @@ impl From for span::MacroCallId { } } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, salsa::Supertype)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, salsa_macros::Supertype)] pub enum HirFileId { FileId(EditionedFileId), MacroFile(MacroCallId), diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs b/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs index 72a5627636bf..9f1e3879e1ee 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs @@ -7,7 +7,7 @@ use std::{ use crate::{ db::ExpandDatabase, - hygiene::{SyntaxContextExt, Transparency, marks_rev}, + hygiene::Transparency, name::{AsName, Name}, tt, }; @@ -340,7 +340,7 @@ pub fn resolve_crate_root(db: &dyn ExpandDatabase, mut ctxt: SyntaxContext) -> O // definitions actually produced by `macro` and `macro` definitions produced by // `macro_rules!`, but at least such configurations are not stable yet. ctxt = ctxt.normalize_to_macro_rules(db); - let mut iter = marks_rev(ctxt, db).peekable(); + let mut iter = ctxt.marks_rev(db).peekable(); let mut result_mark = None; // Find the last opaque mark from the end if it exists. while let Some(&(mark, Transparency::Opaque)) = iter.peek() { diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/name.rs b/src/tools/rust-analyzer/crates/hir-expand/src/name.rs index d43ef38f291d..217d991d110d 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/name.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/name.rs @@ -191,7 +191,7 @@ impl Name { // FIXME: Remove this in favor of `display`, see fixme on `as_str` #[doc(hidden)] pub fn display_no_db(&self, edition: Edition) -> impl fmt::Display + '_ { - Display { name: self, needs_escaping: is_raw_identifier(self.symbol.as_str(), edition) } + Display { name: self, edition } } pub fn symbol(&self) -> &Symbol { @@ -201,15 +201,28 @@ impl Name { struct Display<'a> { name: &'a Name, - needs_escaping: bool, + edition: Edition, } impl fmt::Display for Display<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if self.needs_escaping { - write!(f, "r#")?; + let mut symbol = self.name.symbol.as_str(); + + if symbol == "'static" { + // FIXME: '`static` can also be a label, and there it does need escaping. + // But knowing where it is will require adding a parameter to `display()`, + // and that is an infectious change. + return f.write_str(symbol); } - fmt::Display::fmt(self.name.symbol.as_str(), f) + + if let Some(s) = symbol.strip_prefix('\'') { + f.write_str("'")?; + symbol = s; + } + if is_raw_identifier(symbol, self.edition) { + f.write_str("r#")?; + } + f.write_str(symbol) } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml b/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml index 69ad7703c2ca..efa544cf3965 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml +++ b/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml @@ -34,6 +34,7 @@ indexmap.workspace = true rustc_apfloat = "0.2.2" query-group.workspace = true salsa.workspace = true +salsa-macros.workspace = true ra-ap-rustc_abi.workspace = true ra-ap-rustc_index.workspace = true diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs b/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs index 711544545681..7acc9456ec9c 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs @@ -198,15 +198,13 @@ pub(crate) fn deref_by_trait( // blanked impl on `Deref`. #[expect(clippy::overly_complex_bool_expr)] if use_receiver_trait && false { - if let Some(receiver) = - db.lang_item(table.trait_env.krate, LangItem::Receiver).and_then(|l| l.as_trait()) - { + if let Some(receiver) = LangItem::Receiver.resolve_trait(db, table.trait_env.krate) { return Some(receiver); } } // Old rustc versions might not have `Receiver` trait. // Fallback to `Deref` if they don't - db.lang_item(table.trait_env.krate, LangItem::Deref).and_then(|l| l.as_trait()) + LangItem::Deref.resolve_trait(db, table.trait_env.krate) }; let trait_id = trait_id()?; let target = diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs index 2aa9401eefa9..cd799c03ddf7 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs @@ -16,7 +16,7 @@ use hir_def::{ AssocItemId, BlockId, CallableDefId, GenericDefId, HasModule, ItemContainerId, Lookup, TypeAliasId, VariantId, hir::Movability, - lang_item::{LangItem, LangItemTarget}, + lang_item::LangItem, signatures::{ImplFlags, StructFlags, TraitFlags}, }; @@ -262,10 +262,7 @@ impl chalk_solve::RustIrDatabase for ChalkContext<'_> { well_known_trait: rust_ir::WellKnownTrait, ) -> Option> { let lang_attr = lang_item_from_well_known_trait(well_known_trait); - let trait_ = match self.db.lang_item(self.krate, lang_attr) { - Some(LangItemTarget::Trait(trait_)) => trait_, - _ => return None, - }; + let trait_ = lang_attr.resolve_trait(self.db, self.krate)?; Some(to_chalk_trait_id(trait_)) } @@ -306,11 +303,8 @@ impl chalk_solve::RustIrDatabase for ChalkContext<'_> { chalk_ir::Binders::new(binders, bound) } crate::ImplTraitId::AsyncBlockTypeImplTrait(..) => { - if let Some((future_trait, future_output)) = self - .db - .lang_item(self.krate, LangItem::Future) - .and_then(|item| item.as_trait()) - .and_then(|trait_| { + if let Some((future_trait, future_output)) = + LangItem::Future.resolve_trait(self.db, self.krate).and_then(|trait_| { let alias = self .db .trait_items(trait_) @@ -338,10 +332,7 @@ impl chalk_solve::RustIrDatabase for ChalkContext<'_> { }); let mut binder = vec![]; binder.push(crate::wrap_empty_binders(impl_bound)); - let sized_trait = self - .db - .lang_item(self.krate, LangItem::Sized) - .and_then(|item| item.as_trait()); + let sized_trait = LangItem::Sized.resolve_trait(self.db, self.krate); if let Some(sized_trait_) = sized_trait { let sized_bound = WhereClause::Implemented(TraitRef { trait_id: to_chalk_trait_id(sized_trait_), @@ -646,7 +637,10 @@ pub(crate) fn associated_ty_data_query( .fill_with_bound_vars(crate::DebruijnIndex::INNERMOST, 0) .build(); let pro_ty = TyBuilder::assoc_type_projection(db, type_alias, Some(trait_subst)) - .fill_with_bound_vars(crate::DebruijnIndex::INNERMOST, generic_params.len_self()) + .fill_with_bound_vars( + crate::DebruijnIndex::INNERMOST, + generic_params.parent_generics().map_or(0, |it| it.len()), + ) .build(); let self_ty = TyKind::Alias(AliasTy::Projection(pro_ty)).intern(Interner); @@ -660,9 +654,8 @@ pub(crate) fn associated_ty_data_query( } if !ctx.unsized_types.contains(&self_ty) { - let sized_trait = db - .lang_item(resolver.krate(), LangItem::Sized) - .and_then(|lang_item| lang_item.as_trait().map(to_chalk_trait_id)); + let sized_trait = + LangItem::Sized.resolve_trait(db, resolver.krate()).map(to_chalk_trait_id); let sized_bound = sized_trait.into_iter().map(|sized_trait| { let trait_bound = rust_ir::TraitBound { trait_id: sized_trait, args_no_self: Default::default() }; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs index 0f0cf6ae7ae6..aabc4c4234db 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs @@ -251,9 +251,7 @@ impl TyExt for Ty { match db.lookup_intern_impl_trait_id((*opaque_ty_id).into()) { ImplTraitId::AsyncBlockTypeImplTrait(def, _expr) => { let krate = def.module(db).krate(); - if let Some(future_trait) = - db.lang_item(krate, LangItem::Future).and_then(|item| item.as_trait()) - { + if let Some(future_trait) = LangItem::Future.resolve_trait(db, krate) { // This is only used by type walking. // Parameters will be walked outside, and projection predicate is not used. // So just provide the Future trait. @@ -364,8 +362,7 @@ impl TyExt for Ty { fn is_copy(self, db: &dyn HirDatabase, owner: DefWithBodyId) -> bool { let crate_id = owner.module(db).krate(); - let Some(copy_trait) = db.lang_item(crate_id, LangItem::Copy).and_then(|it| it.as_trait()) - else { + let Some(copy_trait) = LangItem::Copy.resolve_trait(db, crate_id) else { return false; }; let trait_ref = TyBuilder::trait_ref(db, copy_trait).push(self).build(); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs index c24ef16b4969..980ee264b027 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs @@ -283,8 +283,9 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { #[salsa::invoke(crate::variance::variances_of)] #[salsa::cycle( - cycle_fn = crate::variance::variances_of_cycle_fn, - cycle_initial = crate::variance::variances_of_cycle_initial, + // cycle_fn = crate::variance::variances_of_cycle_fn, + // cycle_initial = crate::variance::variances_of_cycle_initial, + cycle_result = crate::variance::variances_of_cycle_initial, )] fn variances_of(&self, def: GenericDefId) -> Option>; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs index 5e3d88058962..57106412765a 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs @@ -482,9 +482,8 @@ struct FilterMapNextChecker { impl FilterMapNextChecker { fn new(resolver: &hir_def::resolver::Resolver, db: &dyn HirDatabase) -> Self { // Find and store the FunctionIds for Iterator::filter_map and Iterator::next - let (next_function_id, filter_map_function_id) = match db - .lang_item(resolver.krate(), LangItem::IteratorNext) - .and_then(|it| it.as_function()) + let (next_function_id, filter_map_function_id) = match LangItem::IteratorNext + .resolve_function(db, resolver.krate()) { Some(next_function_id) => ( Some(next_function_id), diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs index 6323d8b71b72..068fc22f2cac 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs @@ -301,6 +301,7 @@ impl<'db> MatchCheckCtx<'db> { // ignore this issue. Ref => PatKind::Deref { subpattern: subpatterns.next().unwrap() }, Slice(_) => unimplemented!(), + DerefPattern(_) => unimplemented!(), &Str(void) => match void {}, Wildcard | NonExhaustive | Hidden | PrivateUninhabited => PatKind::Wild, Never => PatKind::Never, @@ -351,6 +352,7 @@ impl PatCx for MatchCheckCtx<'_> { }, Ref => 1, Slice(..) => unimplemented!(), + DerefPattern(..) => unimplemented!(), Never | Bool(..) | IntRange(..) | F16Range(..) | F32Range(..) | F64Range(..) | F128Range(..) | Str(..) | Opaque(..) | NonExhaustive | PrivateUninhabited | Hidden | Missing | Wildcard => 0, @@ -411,6 +413,7 @@ impl PatCx for MatchCheckCtx<'_> { } }, Slice(_) => unreachable!("Found a `Slice` constructor in match checking"), + DerefPattern(_) => unreachable!("Found a `DerefPattern` constructor in match checking"), Never | Bool(..) | IntRange(..) | F16Range(..) | F32Range(..) | F64Range(..) | F128Range(..) | Str(..) | Opaque(..) | NonExhaustive | PrivateUninhabited | Hidden | Missing | Wildcard => { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs index f62e4bb4f806..f0989d9de91f 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs @@ -19,7 +19,7 @@ use hir_def::{ hir::generics::{TypeOrConstParamData, TypeParamProvenance, WherePredicate}, item_scope::ItemInNs, item_tree::FieldsShape, - lang_item::{LangItem, LangItemTarget}, + lang_item::LangItem, nameres::DefMap, signatures::VariantFields, type_ref::{ @@ -90,11 +90,26 @@ pub struct HirFormatter<'a> { show_container_bounds: bool, omit_verbose_types: bool, closure_style: ClosureStyle, + display_lifetimes: DisplayLifetime, display_kind: DisplayKind, display_target: DisplayTarget, bounds_formatting_ctx: BoundsFormattingCtx, } +// FIXME: To consider, ref and dyn trait lifetimes can be omitted if they are `'_`, path args should +// not be when in signatures +// So this enum does not encode this well enough +// Also 'static can be omitted for ref and dyn trait lifetimes in static/const item types +// FIXME: Also named lifetimes may be rendered in places where their name is not in scope? +#[derive(Copy, Clone)] +pub enum DisplayLifetime { + Always, + OnlyStatic, + OnlyNamed, + OnlyNamedOrStatic, + Never, +} + #[derive(Default)] enum BoundsFormattingCtx { Entered { @@ -155,6 +170,21 @@ impl HirFormatter<'_> { } } } + + fn render_lifetime(&self, lifetime: &Lifetime) -> bool { + match self.display_lifetimes { + DisplayLifetime::Always => true, + DisplayLifetime::OnlyStatic => matches!(***lifetime.interned(), LifetimeData::Static), + DisplayLifetime::OnlyNamed => { + matches!(***lifetime.interned(), LifetimeData::Placeholder(_)) + } + DisplayLifetime::OnlyNamedOrStatic => matches!( + ***lifetime.interned(), + LifetimeData::Static | LifetimeData::Placeholder(_) + ), + DisplayLifetime::Never => false, + } + } } pub trait HirDisplay { @@ -189,6 +219,7 @@ pub trait HirDisplay { display_kind, closure_style, show_container_bounds, + display_lifetimes: DisplayLifetime::OnlyNamedOrStatic, } } @@ -212,6 +243,7 @@ pub trait HirDisplay { display_target, display_kind: DisplayKind::Diagnostics, show_container_bounds: false, + display_lifetimes: DisplayLifetime::OnlyNamedOrStatic, } } @@ -236,6 +268,7 @@ pub trait HirDisplay { display_target, display_kind: DisplayKind::Diagnostics, show_container_bounds: false, + display_lifetimes: DisplayLifetime::OnlyNamedOrStatic, } } @@ -260,6 +293,7 @@ pub trait HirDisplay { display_target, display_kind: DisplayKind::Diagnostics, show_container_bounds: false, + display_lifetimes: DisplayLifetime::OnlyNamedOrStatic, } } @@ -284,6 +318,7 @@ pub trait HirDisplay { display_target: DisplayTarget::from_crate(db, module_id.krate()), display_kind: DisplayKind::SourceCode { target_module_id: module_id, allow_opaque }, show_container_bounds: false, + display_lifetimes: DisplayLifetime::OnlyNamedOrStatic, bounds_formatting_ctx: Default::default(), }) { Ok(()) => {} @@ -312,6 +347,7 @@ pub trait HirDisplay { display_target, display_kind: DisplayKind::Test, show_container_bounds: false, + display_lifetimes: DisplayLifetime::Always, } } @@ -336,6 +372,7 @@ pub trait HirDisplay { display_target, display_kind: DisplayKind::Diagnostics, show_container_bounds, + display_lifetimes: DisplayLifetime::OnlyNamedOrStatic, } } } @@ -480,6 +517,7 @@ pub struct HirDisplayWrapper<'a, T> { display_kind: DisplayKind, display_target: DisplayTarget, show_container_bounds: bool, + display_lifetimes: DisplayLifetime, } #[derive(Debug, PartialEq, Eq, Clone, Copy)] @@ -502,7 +540,7 @@ impl HirDisplayWrapper<'_, T> { self.t.hir_fmt(&mut HirFormatter { db: self.db, fmt: f, - buf: String::with_capacity(20), + buf: String::with_capacity(self.max_size.unwrap_or(20)), curr_size: 0, max_size: self.max_size, entity_limit: self.limited_size, @@ -511,6 +549,7 @@ impl HirDisplayWrapper<'_, T> { display_target: self.display_target, closure_style: self.closure_style, show_container_bounds: self.show_container_bounds, + display_lifetimes: self.display_lifetimes, bounds_formatting_ctx: Default::default(), }) } @@ -519,6 +558,11 @@ impl HirDisplayWrapper<'_, T> { self.closure_style = c; self } + + pub fn with_lifetime_display(mut self, l: DisplayLifetime) -> Self { + self.display_lifetimes = l; + self + } } impl fmt::Display for HirDisplayWrapper<'_, T> @@ -1022,9 +1066,7 @@ impl HirDisplay for Ty { kind @ (TyKind::Raw(m, t) | TyKind::Ref(m, _, t)) => { if let TyKind::Ref(_, l, _) = kind { f.write_char('&')?; - if cfg!(test) { - // rendering these unconditionally is probably too much (at least for inlay - // hints) so we gate it to testing only for the time being + if f.render_lifetime(l) { l.hir_fmt(f)?; f.write_char(' ')?; } @@ -1055,9 +1097,10 @@ impl HirDisplay for Ty { }) }; let (preds_to_print, has_impl_fn_pred) = match t.kind(Interner) { - TyKind::Dyn(dyn_ty) if dyn_ty.bounds.skip_binders().interned().len() > 1 => { + TyKind::Dyn(dyn_ty) => { let bounds = dyn_ty.bounds.skip_binders().interned(); - (bounds.len(), contains_impl_fn(bounds)) + let render_lifetime = f.render_lifetime(&dyn_ty.lifetime); + (bounds.len() + render_lifetime as usize, contains_impl_fn(bounds)) } TyKind::Alias(AliasTy::Opaque(OpaqueTy { opaque_ty_id, @@ -1348,9 +1391,8 @@ impl HirDisplay for Ty { )?; } ImplTraitId::AsyncBlockTypeImplTrait(body, ..) => { - let future_trait = db - .lang_item(body.module(db).krate(), LangItem::Future) - .and_then(LangItemTarget::as_trait); + let future_trait = + LangItem::Future.resolve_trait(db, body.module(db).krate()); let output = future_trait.and_then(|t| { db.trait_items(t) .associated_type_by_name(&Name::new_symbol_root(sym::Output)) @@ -1480,7 +1522,7 @@ impl HirDisplay for Ty { TyKind::BoundVar(idx) => idx.hir_fmt(f)?, TyKind::Dyn(dyn_ty) => { // Reorder bounds to satisfy `write_bounds_like_dyn_trait()`'s expectation. - // FIXME: `Iterator::partition_in_place()` or `Vec::drain_filter()` may make it + // FIXME: `Iterator::partition_in_place()` or `Vec::extract_if()` may make it // more efficient when either of them hits stable. let mut bounds: SmallVec<[_; 4]> = dyn_ty.bounds.skip_binders().iter(Interner).cloned().collect(); @@ -1489,6 +1531,17 @@ impl HirDisplay for Ty { bounds.extend(others); bounds.extend(auto_traits); + if f.render_lifetime(&dyn_ty.lifetime) { + // we skip the binders in `write_bounds_like_dyn_trait_with_prefix` + bounds.push(Binders::empty( + Interner, + chalk_ir::WhereClause::TypeOutlives(chalk_ir::TypeOutlives { + ty: self.clone(), + lifetime: dyn_ty.lifetime.clone(), + }), + )); + } + write_bounds_like_dyn_trait_with_prefix( f, "dyn", @@ -1728,9 +1781,7 @@ impl SizedByDefault { match self { Self::NotSized => false, Self::Sized { anchor } => { - let sized_trait = db - .lang_item(anchor, LangItem::Sized) - .and_then(|lang_item| lang_item.as_trait()); + let sized_trait = LangItem::Sized.resolve_trait(db, anchor); Some(trait_) == sized_trait } } @@ -1895,8 +1946,7 @@ fn write_bounds_like_dyn_trait( write!(f, ">")?; } if let SizedByDefault::Sized { anchor } = default_sized { - let sized_trait = - f.db.lang_item(anchor, LangItem::Sized).and_then(|lang_item| lang_item.as_trait()); + let sized_trait = LangItem::Sized.resolve_trait(f.db, anchor); if !is_sized { if !first { write!(f, " + ")?; @@ -1993,7 +2043,6 @@ impl HirDisplay for LifetimeData { write!(f, "{}", param_data.name.display(f.db, f.edition()))?; Ok(()) } - _ if f.display_kind.is_source_code() => write!(f, "'_"), LifetimeData::BoundVar(idx) => idx.hir_fmt(f), LifetimeData::InferenceVar(_) => write!(f, "_"), LifetimeData::Static => write!(f, "'static"), diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/drop.rs b/src/tools/rust-analyzer/crates/hir-ty/src/drop.rs index 9823c854d5b3..70763759ef0e 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/drop.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/drop.rs @@ -19,9 +19,7 @@ fn has_destructor(db: &dyn HirDatabase, adt: AdtId) -> bool { AdtId::StructId(id) => db.lookup_intern_struct(id).container, AdtId::UnionId(id) => db.lookup_intern_union(id).container, }; - let Some(drop_trait) = - db.lang_item(module.krate(), LangItem::Drop).and_then(|it| it.as_trait()) - else { + let Some(drop_trait) = LangItem::Drop.resolve_trait(db, module.krate()) else { return false; }; let impls = match module.containing_block() { @@ -181,8 +179,7 @@ fn projection_has_drop_glue( } fn is_copy(db: &dyn HirDatabase, ty: Ty, env: Arc) -> bool { - let Some(copy_trait) = db.lang_item(env.krate, LangItem::Copy).and_then(|it| it.as_trait()) - else { + let Some(copy_trait) = LangItem::Copy.resolve_trait(db, env.krate) else { return false; }; let trait_ref = TyBuilder::trait_ref(db, copy_trait).push(ty).build(); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs index 80b18473907d..106b996b13ef 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs @@ -124,7 +124,7 @@ pub fn dyn_compatibility_of_trait_query( fn generics_require_sized_self(db: &dyn HirDatabase, def: GenericDefId) -> bool { let krate = def.module(db).krate(); - let Some(sized) = db.lang_item(krate, LangItem::Sized).and_then(|l| l.as_trait()) else { + let Some(sized) = LangItem::Sized.resolve_trait(db, krate) else { return false; }; @@ -491,8 +491,8 @@ fn receiver_is_dispatchable( let krate = func.module(db).krate(); let traits = ( - db.lang_item(krate, LangItem::Unsize).and_then(|it| it.as_trait()), - db.lang_item(krate, LangItem::DispatchFromDyn).and_then(|it| it.as_trait()), + LangItem::Unsize.resolve_trait(db, krate), + LangItem::DispatchFromDyn.resolve_trait(db, krate), ); let (Some(unsize_did), Some(dispatch_from_dyn_did)) = traits else { return false; @@ -515,7 +515,7 @@ fn receiver_is_dispatchable( trait_id: to_chalk_trait_id(trait_), substitution: Substitution::from_iter( Interner, - std::iter::once(unsized_self_ty.clone().cast(Interner)) + std::iter::once(unsized_self_ty.cast(Interner)) .chain(placeholder_subst.iter(Interner).skip(1).cloned()), ), }); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs index 790914fdaf2a..f0ec31db8bb9 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs @@ -39,7 +39,7 @@ use hir_def::{ builtin_type::{BuiltinInt, BuiltinType, BuiltinUint}, expr_store::{Body, ExpressionStore, HygieneId, path::Path}, hir::{BindingAnnotation, BindingId, ExprId, ExprOrPatId, LabelId, PatId}, - lang_item::{LangItem, LangItemTarget}, + lang_item::{LangItem, LangItemTarget, lang_item}, layout::Integer, resolver::{HasResolver, ResolveValueResult, Resolver, TypeNs, ValueNs}, signatures::{ConstSignature, StaticSignature}, @@ -1801,7 +1801,7 @@ impl<'a> InferenceContext<'a> { fn resolve_lang_item(&self, item: LangItem) -> Option { let krate = self.resolver.krate(); - self.db.lang_item(krate, item) + lang_item(self.db, krate, item) } fn resolve_output_on(&self, trait_: TraitId) -> Option { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs index cf3b15d2a679..800897c6fc3a 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs @@ -127,7 +127,7 @@ impl InferenceContext<'_> { let prev_diverges = mem::replace(&mut self.diverges, Diverges::Maybe); let prev_closure = mem::replace(&mut self.current_closure, id); let prev_ret_ty = mem::replace(&mut self.return_ty, body_ret_ty.clone()); - let prev_ret_coercion = self.return_coercion.replace(CoerceMany::new(body_ret_ty.clone())); + let prev_ret_coercion = self.return_coercion.replace(CoerceMany::new(body_ret_ty)); let prev_resume_yield_tys = mem::replace(&mut self.resume_yield_tys, resume_yield_tys); self.with_breakable_ctx(BreakableKind::Border, None, None, |this| { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs index 847dd43a02d6..39bd90849fe8 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs @@ -8,10 +8,7 @@ use std::iter; use chalk_ir::{BoundVar, Goal, Mutability, TyKind, TyVariableKind, cast::Cast}; -use hir_def::{ - hir::ExprId, - lang_item::{LangItem, LangItemTarget}, -}; +use hir_def::{hir::ExprId, lang_item::LangItem}; use stdx::always; use triomphe::Arc; @@ -701,8 +698,8 @@ impl InferenceTable<'_> { reborrow.as_ref().map_or_else(|| from_ty.clone(), |(_, adj)| adj.target.clone()); let krate = self.trait_env.krate; - let coerce_unsized_trait = match self.db.lang_item(krate, LangItem::CoerceUnsized) { - Some(LangItemTarget::Trait(trait_)) => trait_, + let coerce_unsized_trait = match LangItem::CoerceUnsized.resolve_trait(self.db, krate) { + Some(trait_) => trait_, _ => return Err(TypeError), }; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs index 5468254ab910..8084b394d044 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs @@ -827,9 +827,9 @@ impl InferenceContext<'_> { } let assoc = self.resolve_ops_index_output(); self.resolve_associated_type_with_params( - self_ty.clone(), + self_ty, assoc, - &[index_ty.clone().cast(Interner)], + &[index_ty.cast(Interner)], ) } else { self.err_ty() diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs index cf0152ecd263..ac450c0b5591 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/mutability.rs @@ -126,10 +126,8 @@ impl InferenceContext<'_> { &Expr::Index { base, index } => { if mutability == Mutability::Mut { if let Some((f, _)) = self.result.method_resolutions.get_mut(&tgt_expr) { - if let Some(index_trait) = self - .db - .lang_item(self.table.trait_env.krate, LangItem::IndexMut) - .and_then(|l| l.as_trait()) + if let Some(index_trait) = + LangItem::IndexMut.resolve_trait(self.db, self.table.trait_env.krate) { if let Some(index_fn) = self .db @@ -183,10 +181,8 @@ impl InferenceContext<'_> { let mut mutability = mutability; if let Some((f, _)) = self.result.method_resolutions.get_mut(&tgt_expr) { if mutability == Mutability::Mut { - if let Some(deref_trait) = self - .db - .lang_item(self.table.trait_env.krate, LangItem::DerefMut) - .and_then(|l| l.as_trait()) + if let Some(deref_trait) = + LangItem::DerefMut.resolve_trait(self.db, self.table.trait_env.krate) { let ty = self.result.type_of_expr.get(*expr); let is_mut_ptr = ty.is_some_and(|ty| { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs index dc1de3b9e851..a9a3265858e4 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs @@ -435,7 +435,7 @@ impl InferenceContext<'_> { decl: Option, ) -> Ty { let (expectation_type, expectation_lt) = match expected.as_reference() { - Some((inner_ty, lifetime, _exp_mut)) => (inner_ty.clone(), lifetime.clone()), + Some((inner_ty, lifetime, _exp_mut)) => (inner_ty.clone(), lifetime), None => { let inner_ty = self.table.new_type_var(); let inner_lt = self.table.new_lifetime_var(); @@ -597,7 +597,7 @@ impl InferenceContext<'_> { let size = consteval::usize_const(self.db, Some(len as u128), self.owner.krate(self.db)); let elem_ty = self.table.new_type_var(); - let array_ty = TyKind::Array(elem_ty.clone(), size).intern(Interner); + let array_ty = TyKind::Array(elem_ty, size).intern(Interner); Some(array_ty) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs index 60aa9b5a17a8..631b571465fe 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs @@ -1024,16 +1024,12 @@ impl<'a> InferenceTable<'a> { } } - let Some(sized) = self - .db - .lang_item(self.trait_env.krate, LangItem::Sized) - .and_then(|sized| sized.as_trait()) - else { + let Some(sized) = LangItem::Sized.resolve_trait(self.db, self.trait_env.krate) else { return false; }; let sized_pred = WhereClause::Implemented(TraitRef { trait_id: to_chalk_trait_id(sized), - substitution: Substitution::from1(Interner, ty.clone()), + substitution: Substitution::from1(Interner, ty), }); let goal = GoalData::DomainGoal(chalk_ir::DomainGoal::Holds(sized_pred)).intern(Interner); matches!(self.try_obligation(goal), Some(Solution::Unique(_))) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs index e4688d044e98..9def39d5f979 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs @@ -590,10 +590,7 @@ impl<'a> TyLoweringContext<'a> { } } &TypeBound::Path(path, TraitBoundModifier::Maybe) => { - let sized_trait = self - .db - .lang_item(self.resolver.krate(), LangItem::Sized) - .and_then(|lang_item| lang_item.as_trait()); + let sized_trait = LangItem::Sized.resolve_trait(self.db, self.resolver.krate()); // Don't lower associated type bindings as the only possible relaxed trait bound // `?Sized` has no of them. // If we got another trait here ignore the bound completely. @@ -736,10 +733,8 @@ impl<'a> TyLoweringContext<'a> { } if !ctx.unsized_types.contains(&self_ty) { - let sized_trait = ctx - .db - .lang_item(krate, LangItem::Sized) - .and_then(|lang_item| lang_item.as_trait().map(to_chalk_trait_id)); + let sized_trait = + LangItem::Sized.resolve_trait(ctx.db, krate).map(to_chalk_trait_id); let sized_clause = sized_trait.map(|trait_id| { let clause = WhereClause::Implemented(TraitRef { trait_id, @@ -1188,9 +1183,7 @@ fn implicitly_sized_clauses<'a, 'subst: 'a>( substitution: &'subst Substitution, resolver: &Resolver, ) -> Option + Captures<'a> + Captures<'subst>> { - let sized_trait = db - .lang_item(resolver.krate(), LangItem::Sized) - .and_then(|lang_item| lang_item.as_trait().map(to_chalk_trait_id))?; + let sized_trait = LangItem::Sized.resolve_trait(db, resolver.krate()).map(to_chalk_trait_id)?; let trait_self_idx = trait_self_param_idx(db, def); @@ -1475,7 +1468,7 @@ fn type_for_enum_variant_constructor( } } -#[salsa::tracked(cycle_result = type_for_adt_cycle_result)] +#[salsa_macros::tracked(cycle_result = type_for_adt_cycle_result)] fn type_for_adt_tracked(db: &dyn HirDatabase, adt: AdtId) -> Binders { type_for_adt(db, adt) } @@ -1540,7 +1533,7 @@ pub enum TyDefId { } impl_from!(BuiltinType, AdtId(StructId, EnumId, UnionId), TypeAliasId for TyDefId); -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, salsa::Supertype)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, salsa_macros::Supertype)] pub enum ValueTyDefId { FunctionId(FunctionId), StructId(StructId), diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs index 8f8e26eca2ae..8e549ca0cbd5 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs @@ -515,9 +515,15 @@ impl From> for VisibleFromModule { } } +#[derive(Debug, Clone)] +pub enum AutorefOrPtrAdjustment { + Autoref(Mutability), + ToConstPtr, +} + #[derive(Debug, Clone, Default)] pub struct ReceiverAdjustments { - autoref: Option, + autoref: Option, autoderefs: usize, unsize_array: bool, } @@ -535,10 +541,15 @@ impl ReceiverAdjustments { } Some((kind, new_ty)) => { ty = new_ty.clone(); + let mutbl = match self.autoref { + Some(AutorefOrPtrAdjustment::Autoref(m)) => Some(m), + Some(AutorefOrPtrAdjustment::ToConstPtr) => Some(Mutability::Not), + // FIXME should we know the mutability here, when autoref is `None`? + None => None, + }; adjust.push(Adjustment { kind: Adjust::Deref(match kind { - // FIXME should we know the mutability here, when autoref is `None`? - AutoderefKind::Overloaded => Some(OverloadedDeref(self.autoref)), + AutoderefKind::Overloaded => Some(OverloadedDeref(mutbl)), AutoderefKind::Builtin => None, }), target: new_ty, @@ -546,11 +557,27 @@ impl ReceiverAdjustments { } } } - if let Some(m) = self.autoref { + if let Some(autoref) = &self.autoref { let lt = table.new_lifetime_var(); - let a = Adjustment::borrow(m, ty, lt); - ty = a.target.clone(); - adjust.push(a); + match autoref { + AutorefOrPtrAdjustment::Autoref(m) => { + let a = Adjustment::borrow(*m, ty, lt); + ty = a.target.clone(); + adjust.push(a); + } + AutorefOrPtrAdjustment::ToConstPtr => { + if let TyKind::Raw(Mutability::Mut, pointee) = ty.kind(Interner) { + let a = Adjustment { + kind: Adjust::Pointer(PointerCast::MutToConstPointer), + target: TyKind::Raw(Mutability::Not, pointee.clone()).intern(Interner), + }; + ty = a.target.clone(); + adjust.push(a); + } else { + never!("`ToConstPtr` target is not a raw mutable pointer"); + } + } + }; } if self.unsize_array { ty = 'it: { @@ -575,8 +602,8 @@ impl ReceiverAdjustments { (ty, adjust) } - fn with_autoref(&self, m: Mutability) -> ReceiverAdjustments { - Self { autoref: Some(m), ..*self } + fn with_autoref(&self, a: AutorefOrPtrAdjustment) -> ReceiverAdjustments { + Self { autoref: Some(a), ..*self } } } @@ -1051,7 +1078,7 @@ fn iterate_method_candidates_with_autoref( let mut maybe_reborrowed = first_adjustment.clone(); if let Some((_, _, m)) = receiver_ty.value.as_reference() { // Prefer reborrow of references to move - maybe_reborrowed.autoref = Some(m); + maybe_reborrowed.autoref = Some(AutorefOrPtrAdjustment::Autoref(m)); maybe_reborrowed.autoderefs += 1; } @@ -1063,15 +1090,34 @@ fn iterate_method_candidates_with_autoref( binders: receiver_ty.binders.clone(), }; - iterate_method_candidates_by_receiver(refed, first_adjustment.with_autoref(Mutability::Not))?; + iterate_method_candidates_by_receiver( + refed, + first_adjustment.with_autoref(AutorefOrPtrAdjustment::Autoref(Mutability::Not)), + )?; let ref_muted = Canonical { value: TyKind::Ref(Mutability::Mut, error_lifetime(), receiver_ty.value.clone()) .intern(Interner), - binders: receiver_ty.binders, + binders: receiver_ty.binders.clone(), }; - iterate_method_candidates_by_receiver(ref_muted, first_adjustment.with_autoref(Mutability::Mut)) + iterate_method_candidates_by_receiver( + ref_muted, + first_adjustment.with_autoref(AutorefOrPtrAdjustment::Autoref(Mutability::Mut)), + )?; + + if let Some((ty, Mutability::Mut)) = receiver_ty.value.as_raw_ptr() { + let const_ptr_ty = Canonical { + value: TyKind::Raw(Mutability::Not, ty.clone()).intern(Interner), + binders: receiver_ty.binders, + }; + iterate_method_candidates_by_receiver( + const_ptr_ty, + first_adjustment.with_autoref(AutorefOrPtrAdjustment::ToConstPtr), + )?; + } + + ControlFlow::Continue(()) } pub trait MethodCandidateCallback { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs index 6dc20203e0ee..bf80ed7967aa 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs @@ -77,7 +77,14 @@ pub struct Local { /// currently implements it, but it seems like this may be something to check against in the /// validator. #[derive(Debug, PartialEq, Eq, Clone)] -pub enum Operand { +pub struct Operand { + kind: OperandKind, + // FIXME : This should actually just be of type `MirSpan`. + span: Option, +} + +#[derive(Debug, PartialEq, Eq, Clone)] +pub enum OperandKind { /// Creates a value by loading the given place. /// /// Before drop elaboration, the type of the place must be `Copy`. After drop elaboration there @@ -101,7 +108,13 @@ pub enum Operand { impl Operand { fn from_concrete_const(data: Box<[u8]>, memory_map: MemoryMap, ty: Ty) -> Self { - Operand::Constant(intern_const_scalar(ConstScalar::Bytes(data, memory_map), ty)) + Operand { + kind: OperandKind::Constant(intern_const_scalar( + ConstScalar::Bytes(data, memory_map), + ty, + )), + span: None, + } } fn from_bytes(data: Box<[u8]>, ty: Ty) -> Self { @@ -1076,11 +1089,11 @@ impl MirBody { f: &mut impl FnMut(&mut Place, &mut ProjectionStore), store: &mut ProjectionStore, ) { - match op { - Operand::Copy(p) | Operand::Move(p) => { + match &mut op.kind { + OperandKind::Copy(p) | OperandKind::Move(p) => { f(p, store); } - Operand::Constant(_) | Operand::Static(_) => (), + OperandKind::Constant(_) | OperandKind::Static(_) => (), } } for (_, block) in self.basic_blocks.iter_mut() { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs index eca6f4692a4c..fb0c0dee095f 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs @@ -15,13 +15,13 @@ use crate::{ ClosureId, Interner, Substitution, Ty, TyExt, TypeFlags, db::{HirDatabase, InternedClosure}, display::DisplayTarget, - mir::Operand, + mir::OperandKind, utils::ClosureSubst, }; use super::{ - BasicBlockId, BorrowKind, LocalId, MirBody, MirLowerError, MirSpan, MutBorrowKind, Place, - ProjectionElem, Rvalue, StatementKind, TerminatorKind, + BasicBlockId, BorrowKind, LocalId, MirBody, MirLowerError, MirSpan, MutBorrowKind, Operand, + Place, ProjectionElem, Rvalue, StatementKind, TerminatorKind, }; #[derive(Debug, Clone, PartialEq, Eq)] @@ -120,8 +120,8 @@ fn make_fetch_closure_field( fn moved_out_of_ref(db: &dyn HirDatabase, body: &MirBody) -> Vec { let mut result = vec![]; - let mut for_operand = |op: &Operand, span: MirSpan| match op { - Operand::Copy(p) | Operand::Move(p) => { + let mut for_operand = |op: &Operand, span: MirSpan| match op.kind { + OperandKind::Copy(p) | OperandKind::Move(p) => { let mut ty: Ty = body.locals[p.local].ty.clone(); let mut is_dereference_of_ref = false; for proj in p.projection.lookup(&body.projection_store) { @@ -139,10 +139,10 @@ fn moved_out_of_ref(db: &dyn HirDatabase, body: &MirBody) -> Vec && !ty.clone().is_copy(db, body.owner) && !ty.data(Interner).flags.intersects(TypeFlags::HAS_ERROR) { - result.push(MovedOutOfRef { span, ty }); + result.push(MovedOutOfRef { span: op.span.unwrap_or(span), ty }); } } - Operand::Constant(_) | Operand::Static(_) => (), + OperandKind::Constant(_) | OperandKind::Static(_) => (), }; for (_, block) in body.basic_blocks.iter() { db.unwind_if_revision_cancelled(); @@ -215,8 +215,8 @@ fn moved_out_of_ref(db: &dyn HirDatabase, body: &MirBody) -> Vec fn partially_moved(db: &dyn HirDatabase, body: &MirBody) -> Vec { let mut result = vec![]; - let mut for_operand = |op: &Operand, span: MirSpan| match op { - Operand::Copy(p) | Operand::Move(p) => { + let mut for_operand = |op: &Operand, span: MirSpan| match op.kind { + OperandKind::Copy(p) | OperandKind::Move(p) => { let mut ty: Ty = body.locals[p.local].ty.clone(); for proj in p.projection.lookup(&body.projection_store) { ty = proj.projected_ty( @@ -232,7 +232,7 @@ fn partially_moved(db: &dyn HirDatabase, body: &MirBody) -> Vec result.push(PartiallyMoved { span, ty, local: p.local }); } } - Operand::Constant(_) | Operand::Static(_) => (), + OperandKind::Constant(_) | OperandKind::Static(_) => (), }; for (_, block) in body.basic_blocks.iter() { db.unwind_if_revision_cancelled(); @@ -492,7 +492,7 @@ fn record_usage(local: LocalId, result: &mut ArenaMap } fn record_usage_for_operand(arg: &Operand, result: &mut ArenaMap) { - if let Operand::Copy(p) | Operand::Move(p) = arg { + if let OperandKind::Copy(p) | OperandKind::Move(p) = arg.kind { record_usage(p.local, result); } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs index 386226b16d5d..21e5428520e2 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs @@ -47,7 +47,7 @@ use crate::{ use super::{ AggregateKind, BasicBlockId, BinOp, CastKind, LocalId, MirBody, MirLowerError, MirSpan, - Operand, Place, PlaceElem, ProjectionElem, ProjectionStore, Rvalue, StatementKind, + Operand, OperandKind, Place, PlaceElem, ProjectionElem, ProjectionStore, Rvalue, StatementKind, TerminatorKind, UnOp, return_slot, }; @@ -655,22 +655,15 @@ impl Evaluator<'_> { mir_or_dyn_index_cache: RefCell::new(Default::default()), unused_locals_store: RefCell::new(Default::default()), cached_ptr_size, - cached_fn_trait_func: db - .lang_item(crate_id, LangItem::Fn) - .and_then(|x| x.as_trait()) + cached_fn_trait_func: LangItem::Fn + .resolve_trait(db, crate_id) .and_then(|x| db.trait_items(x).method_by_name(&Name::new_symbol_root(sym::call))), - cached_fn_mut_trait_func: db - .lang_item(crate_id, LangItem::FnMut) - .and_then(|x| x.as_trait()) - .and_then(|x| { - db.trait_items(x).method_by_name(&Name::new_symbol_root(sym::call_mut)) - }), - cached_fn_once_trait_func: db - .lang_item(crate_id, LangItem::FnOnce) - .and_then(|x| x.as_trait()) - .and_then(|x| { - db.trait_items(x).method_by_name(&Name::new_symbol_root(sym::call_once)) - }), + cached_fn_mut_trait_func: LangItem::FnMut.resolve_trait(db, crate_id).and_then(|x| { + db.trait_items(x).method_by_name(&Name::new_symbol_root(sym::call_mut)) + }), + cached_fn_once_trait_func: LangItem::FnOnce.resolve_trait(db, crate_id).and_then(|x| { + db.trait_items(x).method_by_name(&Name::new_symbol_root(sym::call_once)) + }), }) } @@ -863,10 +856,10 @@ impl Evaluator<'_> { } fn operand_ty(&self, o: &Operand, locals: &Locals) -> Result { - Ok(match o { - Operand::Copy(p) | Operand::Move(p) => self.place_ty(p, locals)?, - Operand::Constant(c) => c.data(Interner).ty.clone(), - &Operand::Static(s) => { + Ok(match &o.kind { + OperandKind::Copy(p) | OperandKind::Move(p) => self.place_ty(p, locals)?, + OperandKind::Constant(c) => c.data(Interner).ty.clone(), + &OperandKind::Static(s) => { let ty = self.db.infer(s.into())[self.db.body(s.into()).body_expr].clone(); TyKind::Ref(Mutability::Not, static_lifetime(), ty).intern(Interner) } @@ -1880,16 +1873,16 @@ impl Evaluator<'_> { } fn eval_operand(&mut self, it: &Operand, locals: &mut Locals) -> Result { - Ok(match it { - Operand::Copy(p) | Operand::Move(p) => { + Ok(match &it.kind { + OperandKind::Copy(p) | OperandKind::Move(p) => { locals.drop_flags.remove_place(p, &locals.body.projection_store); self.eval_place(p, locals)? } - Operand::Static(st) => { + OperandKind::Static(st) => { let addr = self.eval_static(*st, locals)?; Interval::new(addr, self.ptr_size()) } - Operand::Constant(konst) => self.allocate_const_in_heap(locals, konst)?, + OperandKind::Constant(konst) => self.allocate_const_in_heap(locals, konst)?, }) } @@ -2811,7 +2804,7 @@ impl Evaluator<'_> { span: MirSpan, ) -> Result<()> { let Some(drop_fn) = (|| { - let drop_trait = self.db.lang_item(self.crate_id, LangItem::Drop)?.as_trait()?; + let drop_trait = LangItem::Drop.resolve_trait(self.db, self.crate_id)?; self.db.trait_items(drop_trait).method_by_name(&Name::new_symbol_root(sym::drop)) })() else { // in some tests we don't have drop trait in minicore, and diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs index 4de44cfd02e9..26ef95d264be 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs @@ -6,7 +6,6 @@ use std::cmp::{self, Ordering}; use chalk_ir::TyKind; use hir_def::{ builtin_type::{BuiltinInt, BuiltinUint}, - lang_item::LangItemTarget, resolver::HasResolver, }; use hir_expand::name::Name; @@ -156,8 +155,8 @@ impl Evaluator<'_> { if let Some(LangItem::PanicFmt) = self.db.lang_attr(def.into()) { let resolver = self.db.crate_def_map(self.crate_id).crate_root().resolver(self.db); - let Some(hir_def::lang_item::LangItemTarget::Function(const_panic_fmt)) = - self.db.lang_item(resolver.krate(), LangItem::ConstPanicFmt) + let Some(const_panic_fmt) = + LangItem::ConstPanicFmt.resolve_function(self.db, resolver.krate()) else { not_supported!("const_panic_fmt lang item not found or not a function"); }; @@ -1257,12 +1256,12 @@ impl Evaluator<'_> { let addr = tuple.interval.addr.offset(offset); args.push(IntervalAndTy::new(addr, field, self, locals)?); } - if let Some(target) = self.db.lang_item(self.crate_id, LangItem::FnOnce) { - if let Some(def) = target.as_trait().and_then(|it| { - self.db - .trait_items(it) - .method_by_name(&Name::new_symbol_root(sym::call_once)) - }) { + if let Some(target) = LangItem::FnOnce.resolve_trait(self.db, self.crate_id) { + if let Some(def) = self + .db + .trait_items(target) + .method_by_name(&Name::new_symbol_root(sym::call_once)) + { self.exec_fn_trait( def, &args, @@ -1376,9 +1375,7 @@ impl Evaluator<'_> { } } } - if let Some(LangItemTarget::EnumId(e)) = - self.db.lang_item(self.crate_id, LangItem::Ordering) - { + if let Some(e) = LangItem::Ordering.resolve_enum(self.db, self.crate_id) { let ty = self.db.ty(e.into()); let r = self .compute_discriminant(ty.skip_binders().clone(), &[result as i8 as u8])?; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs index 557027756f39..7b48b15d9ea9 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs @@ -13,7 +13,7 @@ use hir_def::{ Pat, PatId, RecordFieldPat, RecordLitField, }, item_tree::FieldsShape, - lang_item::{LangItem, LangItemTarget}, + lang_item::{LangItem, LangItemTarget, lang_item}, resolver::{HasResolver, ResolveValueResult, Resolver, ValueNs}, }; use hir_expand::name::Name; @@ -48,6 +48,8 @@ use crate::{ utils::ClosureSubst, }; +use super::OperandKind; + mod as_place; mod pattern_matching; @@ -324,7 +326,7 @@ impl<'ctx> MirLowerCtx<'ctx> { let Some((p, current)) = self.lower_expr_as_place(current, expr_id, true)? else { return Ok(None); }; - Ok(Some((Operand::Copy(p), current))) + Ok(Some((Operand { kind: OperandKind::Copy(p), span: Some(expr_id.into()) }, current))) } fn lower_expr_to_place_with_adjust( @@ -347,7 +349,12 @@ impl<'ctx> MirLowerCtx<'ctx> { else { return Ok(None); }; - self.push_assignment(current, place, Operand::Copy(p).into(), expr_id.into()); + self.push_assignment( + current, + place, + Operand { kind: OperandKind::Copy(p), span: None }.into(), + expr_id.into(), + ); Ok(Some(current)) } Adjust::Borrow(AutoBorrow::Ref(_, m) | AutoBorrow::RawPtr(m)) => { @@ -371,7 +378,7 @@ impl<'ctx> MirLowerCtx<'ctx> { place, Rvalue::Cast( CastKind::PointerCoercion(*cast), - Operand::Copy(p), + Operand { kind: OperandKind::Copy(p), span: None }, last.target.clone(), ), expr_id.into(), @@ -476,7 +483,7 @@ impl<'ctx> MirLowerCtx<'ctx> { self.push_assignment( current, place, - Operand::Copy(temp).into(), + Operand { kind: OperandKind::Copy(temp), span: None }.into(), expr_id.into(), ); Ok(Some(current)) @@ -517,21 +524,23 @@ impl<'ctx> MirLowerCtx<'ctx> { self.push_assignment( current, place, - Operand::Constant( - ConstData { - ty, - value: chalk_ir::ConstValue::BoundVar(BoundVar::new( - DebruijnIndex::INNERMOST, - generics.type_or_const_param_idx(p.into()).ok_or( - MirLowerError::TypeError( - "fail to lower const generic param", - ), - )?, - )), - } - .intern(Interner), - ) - .into(), + Rvalue::from(Operand { + kind: OperandKind::Constant( + ConstData { + ty, + value: chalk_ir::ConstValue::BoundVar(BoundVar::new( + DebruijnIndex::INNERMOST, + generics.type_or_const_param_idx(p.into()).ok_or( + MirLowerError::TypeError( + "fail to lower const generic param", + ), + )?, + )), + } + .intern(Interner), + ), + span: None, + }), expr_id.into(), ); Ok(Some(current)) @@ -876,7 +885,7 @@ impl<'ctx> MirLowerCtx<'ctx> { })), &mut self.result.projection_store, ); - Operand::Copy(p) + Operand { kind: OperandKind::Copy(p), span: None } } }) .collect(), @@ -979,7 +988,12 @@ impl<'ctx> MirLowerCtx<'ctx> { else { return Ok(None); }; - self.push_assignment(current, place, Operand::Copy(p).into(), expr_id.into()); + self.push_assignment( + current, + place, + Operand { kind: OperandKind::Copy(p), span: None }.into(), + expr_id.into(), + ); Ok(Some(current)) } Expr::UnaryOp { @@ -1056,8 +1070,11 @@ impl<'ctx> MirLowerCtx<'ctx> { else { return Ok(None); }; - let r_value = - Rvalue::CheckedBinaryOp(op.into(), Operand::Copy(lhs_place), rhs_op); + let r_value = Rvalue::CheckedBinaryOp( + op.into(), + Operand { kind: OperandKind::Copy(lhs_place), span: None }, + rhs_op, + ); self.push_assignment(current, lhs_place, r_value, expr_id.into()); return Ok(Some(current)); } @@ -1232,9 +1249,11 @@ impl<'ctx> MirLowerCtx<'ctx> { Rvalue::Ref(*bk, p), capture_spans[0], ); - operands.push(Operand::Move(tmp)); + operands.push(Operand { kind: OperandKind::Move(tmp), span: None }); + } + CaptureKind::ByValue => { + operands.push(Operand { kind: OperandKind::Move(p), span: None }) } - CaptureKind::ByValue => operands.push(Operand::Move(p)), } } self.push_assignment( @@ -1476,7 +1495,7 @@ impl<'ctx> MirLowerCtx<'ctx> { .const_eval(const_id, subst, None) .map_err(|e| MirLowerError::ConstEvalError(name.into(), Box::new(e)))? }; - Ok(Operand::Constant(c)) + Ok(Operand { kind: OperandKind::Constant(c), span: None }) } fn write_bytes_to_place( @@ -1727,7 +1746,7 @@ impl<'ctx> MirLowerCtx<'ctx> { fn resolve_lang_item(&self, item: LangItem) -> Result { let crate_id = self.owner.module(self.db).krate(); - self.db.lang_item(crate_id, item).ok_or(MirLowerError::LangItemNotFound(item)) + lang_item(self.db, crate_id, item).ok_or(MirLowerError::LangItemNotFound(item)) } fn lower_block_to_place( diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs index d3cd0099246a..c22bada7a903 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs @@ -1,6 +1,6 @@ //! MIR lowering for places -use crate::mir::MutBorrowKind; +use crate::mir::{MutBorrowKind, Operand, OperandKind}; use super::*; use hir_def::FunctionId; @@ -155,7 +155,7 @@ impl MirLowerCtx<'_> { self.push_assignment( current, temp, - Operand::Static(s).into(), + Operand { kind: OperandKind::Static(s), span: None }.into(), expr_id.into(), ); Ok(Some(( @@ -305,7 +305,7 @@ impl MirLowerCtx<'_> { ); let Some(current) = self.lower_call( index_fn_op, - Box::new([Operand::Copy(place), index_operand]), + Box::new([Operand { kind: OperandKind::Copy(place), span: None }, index_operand]), result, current, false, @@ -365,7 +365,7 @@ impl MirLowerCtx<'_> { let mut result: Place = self.temp(target_ty_ref, current, span)?.into(); let Some(current) = self.lower_call( deref_fn_op, - Box::new([Operand::Copy(ref_place)]), + Box::new([Operand { kind: OperandKind::Copy(ref_place), span: None }]), result, current, false, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs index abfa7aee04f7..b3c1f6f387f2 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/pattern_matching.rs @@ -5,10 +5,10 @@ use hir_def::{AssocItemId, hir::ExprId, signatures::VariantFields}; use crate::{ BindingMode, mir::{ - LocalId, MutBorrowKind, + LocalId, MutBorrowKind, Operand, OperandKind, lower::{ BasicBlockId, BinOp, BindingId, BorrowKind, Either, Expr, FieldId, Idx, Interner, - MemoryMap, MirLowerCtx, MirLowerError, MirSpan, Mutability, Operand, Pat, PatId, Place, + MemoryMap, MirLowerCtx, MirLowerError, MirSpan, Mutability, Pat, PatId, Place, PlaceElem, ProjectionElem, RecordFieldPat, ResolveValueResult, Result, Rvalue, Substitution, SwitchTargets, TerminatorKind, TupleFieldId, TupleId, TyBuilder, TyKind, ValueNs, VariantId, @@ -217,10 +217,14 @@ impl MirLowerCtx<'_> { self.push_assignment( current, discr, - Rvalue::CheckedBinaryOp(binop, lv, Operand::Copy(cond_place)), + Rvalue::CheckedBinaryOp( + binop, + lv, + Operand { kind: OperandKind::Copy(cond_place), span: None }, + ), pattern.into(), ); - let discr = Operand::Copy(discr); + let discr = Operand { kind: OperandKind::Copy(discr), span: None }; self.set_terminator( current, TerminatorKind::SwitchInt { @@ -262,7 +266,10 @@ impl MirLowerCtx<'_> { self.set_terminator( current, TerminatorKind::SwitchInt { - discr: Operand::Copy(place_len), + discr: Operand { + kind: OperandKind::Copy(place_len), + span: None, + }, targets: SwitchTargets::static_if( pattern_len as u128, next, @@ -282,10 +289,14 @@ impl MirLowerCtx<'_> { self.push_assignment( current, discr, - Rvalue::CheckedBinaryOp(BinOp::Le, c, Operand::Copy(place_len)), + Rvalue::CheckedBinaryOp( + BinOp::Le, + c, + Operand { kind: OperandKind::Copy(place_len), span: None }, + ), pattern.into(), ); - let discr = Operand::Copy(discr); + let discr = Operand { kind: OperandKind::Copy(discr), span: None }; self.set_terminator( current, TerminatorKind::SwitchInt { @@ -407,8 +418,8 @@ impl MirLowerCtx<'_> { tmp2, Rvalue::CheckedBinaryOp( BinOp::Eq, - Operand::Copy(tmp), - Operand::Copy(cond_place), + Operand { kind: OperandKind::Copy(tmp), span: None }, + Operand { kind: OperandKind::Copy(cond_place), span: None }, ), span, ); @@ -417,7 +428,7 @@ impl MirLowerCtx<'_> { self.set_terminator( current, TerminatorKind::SwitchInt { - discr: Operand::Copy(tmp2), + discr: Operand { kind: OperandKind::Copy(tmp2), span: None }, targets: SwitchTargets::static_if(1, next, else_target), }, span, @@ -486,7 +497,7 @@ impl MirLowerCtx<'_> { self.push_assignment( current, lhs_place, - Operand::Copy(cond_place).into(), + Operand { kind: OperandKind::Copy(cond_place), span: None }.into(), expr.into(), ); (current, current_else) @@ -523,7 +534,9 @@ impl MirLowerCtx<'_> { current, target_place.into(), match mode { - BindingMode::Move => Operand::Copy(cond_place).into(), + BindingMode::Move => { + Operand { kind: OperandKind::Copy(cond_place), span: None }.into() + } BindingMode::Ref(Mutability::Not) => Rvalue::Ref(BorrowKind::Shared, cond_place), BindingMode::Ref(Mutability::Mut) => { Rvalue::Ref(BorrowKind::Mut { kind: MutBorrowKind::Default }, cond_place) @@ -547,10 +560,14 @@ impl MirLowerCtx<'_> { self.push_assignment( current, discr, - Rvalue::CheckedBinaryOp(BinOp::Eq, c, Operand::Copy(cond_place)), + Rvalue::CheckedBinaryOp( + BinOp::Eq, + c, + Operand { kind: OperandKind::Copy(cond_place), span: None }, + ), pattern.into(), ); - let discr = Operand::Copy(discr); + let discr = Operand { kind: OperandKind::Copy(discr), span: None }; self.set_terminator( current, TerminatorKind::SwitchInt { @@ -583,7 +600,7 @@ impl MirLowerCtx<'_> { self.set_terminator( current, TerminatorKind::SwitchInt { - discr: Operand::Copy(tmp), + discr: Operand { kind: OperandKind::Copy(tmp), span: None }, targets: SwitchTargets::static_if(e, next, *else_target), }, span, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs index d4f10c032cb1..d8f443145ca0 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs @@ -25,7 +25,7 @@ use crate::{ infer::normalize, }; -use super::{MirBody, MirLowerError, Operand, Rvalue, StatementKind, TerminatorKind}; +use super::{MirBody, MirLowerError, Operand, OperandKind, Rvalue, StatementKind, TerminatorKind}; macro_rules! not_supported { ($it: expr) => { @@ -170,8 +170,8 @@ impl Filler<'_> { } fn fill_operand(&mut self, op: &mut Operand) -> Result<(), MirLowerError> { - match op { - Operand::Constant(c) => { + match &mut op.kind { + OperandKind::Constant(c) => { match &c.data(Interner).value { chalk_ir::ConstValue::BoundVar(b) => { let resolved = self @@ -215,7 +215,7 @@ impl Filler<'_> { } self.fill_const(c)?; } - Operand::Copy(_) | Operand::Move(_) | Operand::Static(_) => (), + OperandKind::Copy(_) | OperandKind::Move(_) | OperandKind::Static(_) => (), } Ok(()) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs index f71e29789766..7ae6e907e7ad 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs @@ -18,8 +18,8 @@ use crate::{ }; use super::{ - AggregateKind, BasicBlockId, BorrowKind, LocalId, MirBody, MutBorrowKind, Operand, Place, - Rvalue, UnOp, + AggregateKind, BasicBlockId, BorrowKind, LocalId, MirBody, MutBorrowKind, Operand, OperandKind, + Place, Rvalue, UnOp, }; macro_rules! w { @@ -374,14 +374,14 @@ impl<'a> MirPrettyCtx<'a> { } fn operand(&mut self, r: &Operand) { - match r { - Operand::Copy(p) | Operand::Move(p) => { + match &r.kind { + OperandKind::Copy(p) | OperandKind::Move(p) => { // MIR at the time of writing doesn't have difference between move and copy, so we show them // equally. Feel free to change it. self.place(p); } - Operand::Constant(c) => w!(self, "Const({})", self.hir_display(c)), - Operand::Static(s) => w!(self, "Static({:?})", s), + OperandKind::Constant(c) => w!(self, "Const({})", self.hir_display(c)), + OperandKind::Static(s) => w!(self, "Static({:?})", s), } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs index d2bba120b68e..bcd8aa6c4e95 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs @@ -16,7 +16,7 @@ use syntax::TextRange; use test_utils::extract_annotations; use triomphe::Arc; -#[salsa::db] +#[salsa_macros::db] #[derive(Clone)] pub(crate) struct TestDB { storage: salsa::Storage, @@ -47,7 +47,7 @@ impl fmt::Debug for TestDB { } } -#[salsa::db] +#[salsa_macros::db] impl SourceDatabase for TestDB { fn file_text(&self, file_id: base_db::FileId) -> FileText { self.files.file_text(file_id) @@ -102,7 +102,7 @@ impl SourceDatabase for TestDB { } } -#[salsa::db] +#[salsa_macros::db] impl salsa::Database for TestDB { fn salsa_event(&self, event: &dyn std::ops::Fn() -> salsa::Event) { let mut events = self.events.lock().unwrap(); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs index eeaacbf12eac..ddc5b715194d 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs @@ -561,7 +561,7 @@ trait Foo {} fn test(f: impl Foo, g: &(impl Foo + ?Sized)) { let _: &dyn Foo = &f; let _: &dyn Foo = g; - //^ expected &'? dyn Foo, got &'? impl Foo + ?Sized + //^ expected &'? (dyn Foo + 'static), got &'? impl Foo + ?Sized } "#, ); @@ -827,11 +827,11 @@ struct V { t: T } fn main() { let a: V<&dyn Tr>; (a,) = V { t: &S }; - //^^^^expected V<&'? S>, got (V<&'? dyn Tr>,) + //^^^^expected V<&'? S>, got (V<&'? (dyn Tr + '?)>,) let mut a: V<&dyn Tr> = V { t: &S }; (a,) = V { t: &S }; - //^^^^expected V<&'? S>, got (V<&'? dyn Tr>,) + //^^^^expected V<&'? S>, got (V<&'? (dyn Tr + '?)>,) } "#, ); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/display_source_code.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/display_source_code.rs index 60c03b52246c..a986b54a7b06 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/display_source_code.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/display_source_code.rs @@ -65,13 +65,13 @@ trait A { } trait B: A {} -fn test( +fn test<'a>( _: &(dyn A + Send), - //^ &'_ (dyn A + Send) - _: &(dyn Send + A), - //^ &'_ (dyn A + Send) + //^ &(dyn A + Send + 'static) + _: &'a (dyn Send + A), + //^ &'a (dyn A + Send + 'static) _: &dyn B, - //^ &'_ (dyn B) + //^ &(dyn B + 'static) ) {} "#, ); @@ -85,7 +85,7 @@ fn render_dyn_for_ty() { trait Foo<'a> {} fn foo(foo: &dyn for<'a> Foo<'a>) {} - // ^^^ &'_ dyn Foo<'_> + // ^^^ &(dyn Foo<'?> + 'static) "#, ); } @@ -111,11 +111,11 @@ fn test( b; //^ impl Foo c; - //^ &'_ impl Foo + ?Sized + //^ &impl Foo + ?Sized d; //^ S ref_any; - //^^^^^^^ &'_ impl ?Sized + //^^^^^^^ &impl ?Sized empty; } //^^^^^ impl Sized "#, @@ -192,7 +192,7 @@ fn test( b; //^ fn(impl Foo) -> impl Foo c; -} //^ fn(&'_ impl Foo + ?Sized) -> &'_ impl Foo + ?Sized +} //^ fn(&impl Foo + ?Sized) -> &impl Foo + ?Sized "#, ); } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs index 3a258ecad10a..94826acca305 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs @@ -1153,9 +1153,9 @@ fn dyn_trait_super_trait_not_in_scope() { 51..55 'self': &'? Self 64..69 '{ 0 }': u32 66..67 '0': u32 - 176..177 'd': &'? dyn Trait + 176..177 'd': &'? (dyn Trait + 'static) 191..207 '{ ...o(); }': () - 197..198 'd': &'? dyn Trait + 197..198 'd': &'? (dyn Trait + 'static) 197..204 'd.foo()': u32 "#]], ); @@ -2019,10 +2019,10 @@ impl dyn Error + Send { /// Attempts to downcast the box to a concrete type. pub fn downcast(self: Box) -> Result, Box> { let err: Box = self; - // ^^^^ expected Box, got Box + // ^^^^ expected Box, got Box // FIXME, type mismatch should not occur ::downcast(err).map_err(|_| loop {}) - //^^^^^^^^^^^^^^^^^^^^^ type: fn downcast<{unknown}>(Box) -> Result, Box> + //^^^^^^^^^^^^^^^^^^^^^ type: fn downcast<{unknown}>(Box) -> Result, Box> } } "#, @@ -2170,3 +2170,26 @@ fn main() { "#, ); } + +#[test] +fn mut_to_const_pointer() { + check( + r#" +pub trait X { + fn perform(self) -> u64; +} + +impl X for *const u8 { + fn perform(self) -> u64 { + 42 + } +} + +fn test(x: *mut u8) { + let _v = x.perform(); + // ^ adjustments: Pointer(MutToConstPointer) + // ^^^^^^^^^^^ type: u64 +} +"#, + ); +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs index 638306054a9d..47c695c69748 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs @@ -629,7 +629,7 @@ fn issue_4053_diesel_where_clauses() { 488..522 '{ ... }': () 498..502 'self': SelectStatement 498..508 'self.order': O - 498..515 'self.o...into()': dyn QueryFragment + 498..515 'self.o...into()': dyn QueryFragment + 'static "#]], ); } @@ -773,7 +773,7 @@ fn issue_4800() { "#, expect![[r#" 379..383 'self': &'? mut PeerSet - 401..424 '{ ... }': dyn Future + 401..424 '{ ... }': dyn Future + 'static 411..418 'loop {}': ! 416..418 '{}': () 575..579 'self': &'? mut Self @@ -2278,3 +2278,26 @@ fn test(x: bool) { "#]], ); } + +#[test] +fn issue_19730() { + check_infer( + r#" +trait Trait {} + +trait Foo { + type Bar: Trait; + + fn foo(bar: Self::Bar) { + let _ = bar; + } +} +"#, + expect![[r#" + 83..86 'bar': Foo::Bar + 105..133 '{ ... }': () + 119..120 '_': Foo::Bar + 123..126 'bar': Foo::Bar + "#]], + ); +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs index 0f5e44151de2..eeebe38f1826 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs @@ -2741,11 +2741,11 @@ impl B for Astruct {} 715..744 '#[rust...1i32])': Box<[i32; 1], Global> 737..743 '[1i32]': [i32; 1] 738..742 '1i32': i32 - 755..756 'v': Vec, Global> - 776..793 '<[_]> ...to_vec': fn into_vec, Global>(Box<[Box], Global>) -> Vec, Global> - 776..850 '<[_]> ...ct)]))': Vec, Global> - 794..849 '#[rust...uct)])': Box<[Box; 1], Global> - 816..848 '[#[rus...ruct)]': [Box; 1] + 755..756 'v': Vec, Global> + 776..793 '<[_]> ...to_vec': fn into_vec, Global>(Box<[Box], Global>) -> Vec, Global> + 776..850 '<[_]> ...ct)]))': Vec, Global> + 794..849 '#[rust...uct)])': Box<[Box; 1], Global> + 816..848 '[#[rus...ruct)]': [Box; 1] 817..847 '#[rust...truct)': Box 839..846 'Astruct': Astruct "#]], diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs index 2fb51acea873..14137605c9f2 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs @@ -1475,26 +1475,26 @@ fn test(x: Box>, y: &dyn Trait) { expect![[r#" 29..33 'self': &'? Self 54..58 'self': &'? Self - 198..200 '{}': Box> - 210..211 'x': Box> - 234..235 'y': &'? dyn Trait + 198..200 '{}': Box + 'static> + 210..211 'x': Box + 'static> + 234..235 'y': &'? (dyn Trait + 'static) 254..371 '{ ...2(); }': () - 260..261 'x': Box> - 267..268 'y': &'? dyn Trait - 278..279 'z': Box> - 282..285 'bar': fn bar() -> Box> - 282..287 'bar()': Box> - 293..294 'x': Box> + 260..261 'x': Box + 'static> + 267..268 'y': &'? (dyn Trait + 'static) + 278..279 'z': Box + 'static> + 282..285 'bar': fn bar() -> Box + 'static> + 282..287 'bar()': Box + 'static> + 293..294 'x': Box + 'static> 293..300 'x.foo()': u64 - 306..307 'y': &'? dyn Trait + 306..307 'y': &'? (dyn Trait + 'static) 306..313 'y.foo()': u64 - 319..320 'z': Box> + 319..320 'z': Box + 'static> 319..326 'z.foo()': u64 - 332..333 'x': Box> + 332..333 'x': Box + 'static> 332..340 'x.foo2()': i64 - 346..347 'y': &'? dyn Trait + 346..347 'y': &'? (dyn Trait + 'static) 346..354 'y.foo2()': i64 - 360..361 'z': Box> + 360..361 'z': Box + 'static> 360..368 'z.foo2()': i64 "#]], ); @@ -1523,14 +1523,14 @@ fn test(s: S) { expect![[r#" 32..36 'self': &'? Self 102..106 'self': &'? S - 128..139 '{ loop {} }': &'? dyn Trait + 128..139 '{ loop {} }': &'? (dyn Trait + 'static) 130..137 'loop {}': ! 135..137 '{}': () 175..179 'self': &'? Self 251..252 's': S 267..289 '{ ...z(); }': () 273..274 's': S - 273..280 's.bar()': &'? dyn Trait + 273..280 's.bar()': &'? (dyn Trait + 'static) 273..286 's.bar().baz()': (u32, i32) "#]], ); @@ -1556,20 +1556,20 @@ fn test(x: Trait, y: &Trait) -> u64 { }"#, expect![[r#" 26..30 'self': &'? Self - 60..62 '{}': dyn Trait - 72..73 'x': dyn Trait - 82..83 'y': &'? dyn Trait + 60..62 '{}': dyn Trait + 'static + 72..73 'x': dyn Trait + 'static + 82..83 'y': &'? (dyn Trait + 'static) 100..175 '{ ...o(); }': u64 - 106..107 'x': dyn Trait - 113..114 'y': &'? dyn Trait - 124..125 'z': dyn Trait - 128..131 'bar': fn bar() -> dyn Trait - 128..133 'bar()': dyn Trait - 139..140 'x': dyn Trait + 106..107 'x': dyn Trait + 'static + 113..114 'y': &'? (dyn Trait + 'static) + 124..125 'z': dyn Trait + 'static + 128..131 'bar': fn bar() -> dyn Trait + 'static + 128..133 'bar()': dyn Trait + 'static + 139..140 'x': dyn Trait + 'static 139..146 'x.foo()': u64 - 152..153 'y': &'? dyn Trait + 152..153 'y': &'? (dyn Trait + 'static) 152..159 'y.foo()': u64 - 165..166 'z': dyn Trait + 165..166 'z': dyn Trait + 'static 165..172 'z.foo()': u64 "#]], ); @@ -1589,10 +1589,10 @@ fn main() { expect![[r#" 31..35 'self': &'? S 37..39 '{}': () - 47..48 '_': &'? dyn Fn(S) + 47..48 '_': &'? (dyn Fn(S) + 'static) 58..60 '{}': () 71..105 '{ ...()); }': () - 77..78 'f': fn f(&'? dyn Fn(S)) + 77..78 'f': fn f(&'? (dyn Fn(S) + 'static)) 77..102 'f(&|nu...foo())': () 79..101 '&|numb....foo()': &'? impl Fn(S) 80..101 '|numbe....foo()': impl Fn(S) @@ -2927,13 +2927,13 @@ fn test(x: &dyn Foo) { foo(x); }"#, expect![[r#" - 21..22 'x': &'? dyn Foo + 21..22 'x': &'? (dyn Foo + 'static) 34..36 '{}': () - 46..47 'x': &'? dyn Foo + 46..47 'x': &'? (dyn Foo + 'static) 59..74 '{ foo(x); }': () - 65..68 'foo': fn foo(&'? dyn Foo) + 65..68 'foo': fn foo(&'? (dyn Foo + 'static)) 65..71 'foo(x)': () - 69..70 'x': &'? dyn Foo + 69..70 'x': &'? (dyn Foo + 'static) "#]], ); } @@ -3210,13 +3210,13 @@ fn foo() { 218..324 '{ ...&s); }': () 228..229 's': Option 232..236 'None': Option - 246..247 'f': Box)> - 281..310 'Box { ... {}) }': Box)> + 246..247 'f': Box) + 'static> + 281..310 'Box { ... {}) }': Box) + 'static> 294..308 '&mut (|ps| {})': &'? mut impl FnOnce(&'? Option) 300..307 '|ps| {}': impl FnOnce(&'? Option) 301..303 'ps': &'? Option 305..307 '{}': () - 316..317 'f': Box)> + 316..317 'f': Box) + 'static> 316..321 'f(&s)': () 318..320 '&s': &'? Option 319..320 's': Option @@ -4252,9 +4252,9 @@ fn f<'a>(v: &dyn Trait = &'a i32>) { "#, expect![[r#" 90..94 'self': &'? Self - 127..128 'v': &'? (dyn Trait = &'a i32>) + 127..128 'v': &'? (dyn Trait = &'a i32> + 'static) 164..195 '{ ...f(); }': () - 170..171 'v': &'? (dyn Trait = &'a i32>) + 170..171 'v': &'? (dyn Trait = &'a i32> + 'static) 170..184 'v.get::()': &'? i32 170..192 'v.get:...eref()': &'? i32 "#]], @@ -4735,7 +4735,7 @@ pub async fn foo_async<'a>() -> Box { fn foo() { foo_async(); - //^^^^^^^^^^^impl Future> + ?Sized + //^^^^^^^^^^^impl Future> + ?Sized } "#, ) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs index a5c195d4086a..f9f8776cff7c 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs @@ -8,10 +8,7 @@ use chalk_recursive::Cache; use chalk_solve::{Solver, logging_db::LoggingRustIrDatabase, rust_ir}; use base_db::Crate; -use hir_def::{ - BlockId, TraitId, - lang_item::{LangItem, LangItemTarget}, -}; +use hir_def::{BlockId, TraitId, lang_item::LangItem}; use hir_expand::name::Name; use intern::sym; use span::Edition; @@ -292,10 +289,6 @@ impl FnTrait { } pub fn get_id(self, db: &dyn HirDatabase, krate: Crate) -> Option { - let target = db.lang_item(krate, self.lang_item())?; - match target { - LangItemTarget::Trait(t) => Some(t), - _ => None, - } + self.lang_item().resolve_trait(db, krate) } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs index 198f715a6db2..1e0ff423ded6 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs @@ -36,8 +36,7 @@ use crate::{ pub(crate) fn fn_traits(db: &dyn DefDatabase, krate: Crate) -> impl Iterator + '_ { [LangItem::Fn, LangItem::FnMut, LangItem::FnOnce] .into_iter() - .filter_map(move |lang| db.lang_item(krate, lang)) - .flat_map(|it| it.as_trait()) + .filter_map(move |lang| lang.resolve_trait(db, krate)) } /// Returns an iterator over the direct super traits (including the trait itself). diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs b/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs index 4e9aa5610a52..6e1cd9a310f1 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs @@ -22,7 +22,6 @@ use crate::{ use chalk_ir::Mutability; use hir_def::signatures::StructFlags; use hir_def::{AdtId, GenericDefId, GenericParamId, VariantId}; -use salsa::CycleRecoveryAction; use std::fmt; use std::ops::Not; use stdx::never; @@ -55,14 +54,14 @@ pub(crate) fn variances_of(db: &dyn HirDatabase, def: GenericDefId) -> Option>, - _count: u32, - _def: GenericDefId, -) -> CycleRecoveryAction>> { - CycleRecoveryAction::Iterate -} +// pub(crate) fn variances_of_cycle_fn( +// _db: &dyn HirDatabase, +// _result: &Option>, +// _count: u32, +// _def: GenericDefId, +// ) -> salsa::CycleRecoveryAction>> { +// salsa::CycleRecoveryAction::Iterate +// } pub(crate) fn variances_of_cycle_initial( db: &dyn HirDatabase, @@ -966,7 +965,7 @@ struct S3(S); struct FixedPoint(&'static FixedPoint<(), T, U>, V); "#, expect![[r#" - FixedPoint[T: covariant, U: covariant, V: covariant] + FixedPoint[T: bivariant, U: bivariant, V: bivariant] "#]], ); } diff --git a/src/tools/rust-analyzer/crates/hir/src/display.rs b/src/tools/rust-analyzer/crates/hir/src/display.rs index 53817f37aa66..124ab8e274af 100644 --- a/src/tools/rust-analyzer/crates/hir/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir/src/display.rs @@ -516,8 +516,7 @@ impl HirDisplay for TypeParam { return Ok(()); } - let sized_trait = - f.db.lang_item(krate, LangItem::Sized).and_then(|lang_item| lang_item.as_trait()); + let sized_trait = LangItem::Sized.resolve_trait(f.db, krate); let has_only_sized_bound = predicates.iter().all(move |pred| match pred.skip_binders() { WhereClause::Implemented(it) => Some(it.hir_trait_id()) == sized_trait, _ => false, diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index 143c13069e42..3f1d5bb01f2a 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -53,7 +53,6 @@ use hir_def::{ generics::{LifetimeParamData, TypeOrConstParamData, TypeParamProvenance}, }, item_tree::{AttrOwner, FieldParent, ImportAlias, ItemTreeFieldId, ItemTreeNode}, - lang_item::LangItemTarget, layout::{self, ReprOptions, TargetDataLayout}, nameres::{self, diagnostics::DefDiagnostic}, per_ns::PerNs, @@ -137,7 +136,6 @@ pub use { HirFileRange, InFile, InFileWrapper, InMacroFile, InRealFile, MacroFilePosition, MacroFileRange, }, - hygiene::{SyntaxContextExt, marks_rev}, inert_attr_macro::AttributeTemplate, mod_path::{ModPath, PathKind, tool_path}, name::Name, @@ -781,7 +779,7 @@ impl Module { let drop_maybe_dangle = (|| { // FIXME: This can be simplified a lot by exposing hir-ty's utils.rs::Generics helper let trait_ = trait_?; - let drop_trait = db.lang_item(self.krate().into(), LangItem::Drop)?.as_trait()?; + let drop_trait = LangItem::Drop.resolve_trait(db, self.krate().into())?; if drop_trait != trait_.into() { return None; } @@ -2388,14 +2386,11 @@ impl Function { } let Some(impl_traits) = self.ret_type(db).as_impl_traits(db) else { return false }; - let Some(future_trait_id) = - db.lang_item(self.ty(db).env.krate, LangItem::Future).and_then(|t| t.as_trait()) + let Some(future_trait_id) = LangItem::Future.resolve_trait(db, self.ty(db).env.krate) else { return false; }; - let Some(sized_trait_id) = - db.lang_item(self.ty(db).env.krate, LangItem::Sized).and_then(|t| t.as_trait()) - else { + let Some(sized_trait_id) = LangItem::Sized.resolve_trait(db, self.ty(db).env.krate) else { return false; }; @@ -2861,9 +2856,7 @@ pub struct Trait { impl Trait { pub fn lang(db: &dyn HirDatabase, krate: Crate, name: &Name) -> Option { - db.lang_item(krate.into(), LangItem::from_name(name)?) - .and_then(LangItemTarget::as_trait) - .map(Into::into) + LangItem::from_name(name)?.resolve_trait(db, krate.into()).map(Into::into) } pub fn module(self, db: &dyn HirDatabase) -> Module { @@ -3692,24 +3685,16 @@ impl GenericDef { } let source_map = match def { - GenericDefId::AdtId(AdtId::EnumId(it)) => { - db.enum_signature_with_source_map(it).1.clone() - } - GenericDefId::AdtId(AdtId::StructId(it)) => { - db.struct_signature_with_source_map(it).1.clone() - } - GenericDefId::AdtId(AdtId::UnionId(it)) => { - db.union_signature_with_source_map(it).1.clone() - } + GenericDefId::AdtId(AdtId::EnumId(it)) => db.enum_signature_with_source_map(it).1, + GenericDefId::AdtId(AdtId::StructId(it)) => db.struct_signature_with_source_map(it).1, + GenericDefId::AdtId(AdtId::UnionId(it)) => db.union_signature_with_source_map(it).1, GenericDefId::ConstId(_) => return, - GenericDefId::FunctionId(it) => db.function_signature_with_source_map(it).1.clone(), - GenericDefId::ImplId(it) => db.impl_signature_with_source_map(it).1.clone(), + GenericDefId::FunctionId(it) => db.function_signature_with_source_map(it).1, + GenericDefId::ImplId(it) => db.impl_signature_with_source_map(it).1, GenericDefId::StaticId(_) => return, - GenericDefId::TraitAliasId(it) => { - db.trait_alias_signature_with_source_map(it).1.clone() - } - GenericDefId::TraitId(it) => db.trait_signature_with_source_map(it).1.clone(), - GenericDefId::TypeAliasId(it) => db.type_alias_signature_with_source_map(it).1.clone(), + GenericDefId::TraitAliasId(it) => db.trait_alias_signature_with_source_map(it).1, + GenericDefId::TraitId(it) => db.trait_signature_with_source_map(it).1, + GenericDefId::TypeAliasId(it) => db.type_alias_signature_with_source_map(it).1, }; expr_store_diagnostics(db, acc, &source_map); @@ -3809,7 +3794,7 @@ impl GenericSubstitution { container_params .chain(self_params) .filter_map(|(ty, name)| { - Some((name?.symbol().clone(), Type { ty: ty.clone(), env: self.env.clone() })) + Some((name?.symbol().clone(), Type { ty, env: self.env.clone() })) }) .collect() } @@ -4989,18 +4974,14 @@ impl Type { /// `std::future::Future` and returns the `Output` associated type. /// This function is used in `.await` syntax completion. pub fn into_future_output(&self, db: &dyn HirDatabase) -> Option { - let trait_ = db - .lang_item(self.env.krate, LangItem::IntoFutureIntoFuture) - .and_then(|it| { - let into_future_fn = it.as_function()?; + let trait_ = LangItem::IntoFutureIntoFuture + .resolve_function(db, self.env.krate) + .and_then(|into_future_fn| { let assoc_item = as_assoc_item(db, AssocItem::Function, into_future_fn)?; let into_future_trait = assoc_item.container_or_implemented_trait(db)?; Some(into_future_trait.id) }) - .or_else(|| { - let future_trait = db.lang_item(self.env.krate, LangItem::Future)?; - future_trait.as_trait() - })?; + .or_else(|| LangItem::Future.resolve_trait(db, self.env.krate))?; let canonical_ty = Canonical { value: self.ty.clone(), binders: CanonicalVarKinds::empty(Interner) }; @@ -5015,14 +4996,13 @@ impl Type { /// This does **not** resolve `IntoFuture`, only `Future`. pub fn future_output(self, db: &dyn HirDatabase) -> Option { - let future_output = - db.lang_item(self.env.krate, LangItem::FutureOutput)?.as_type_alias()?; + let future_output = LangItem::FutureOutput.resolve_type_alias(db, self.env.krate)?; self.normalize_trait_assoc_type(db, &[], future_output.into()) } /// This does **not** resolve `IntoIterator`, only `Iterator`. pub fn iterator_item(self, db: &dyn HirDatabase) -> Option { - let iterator_trait = db.lang_item(self.env.krate, LangItem::Iterator)?.as_trait()?; + let iterator_trait = LangItem::Iterator.resolve_trait(db, self.env.krate)?; let iterator_item = db .trait_items(iterator_trait) .associated_type_by_name(&Name::new_symbol_root(sym::Item))?; @@ -5030,9 +5010,7 @@ impl Type { } pub fn impls_iterator(self, db: &dyn HirDatabase) -> bool { - let Some(iterator_trait) = - db.lang_item(self.env.krate, LangItem::Iterator).and_then(|it| it.as_trait()) - else { + let Some(iterator_trait) = LangItem::Iterator.resolve_trait(db, self.env.krate) else { return false; }; let canonical_ty = @@ -5042,12 +5020,13 @@ impl Type { /// Resolves the projection `::IntoIter` and returns the resulting type pub fn into_iterator_iter(self, db: &dyn HirDatabase) -> Option { - let trait_ = db.lang_item(self.env.krate, LangItem::IntoIterIntoIter).and_then(|it| { - let into_iter_fn = it.as_function()?; - let assoc_item = as_assoc_item(db, AssocItem::Function, into_iter_fn)?; - let into_iter_trait = assoc_item.container_or_implemented_trait(db)?; - Some(into_iter_trait.id) - })?; + let trait_ = LangItem::IntoIterIntoIter.resolve_function(db, self.env.krate).and_then( + |into_iter_fn| { + let assoc_item = as_assoc_item(db, AssocItem::Function, into_iter_fn)?; + let into_iter_trait = assoc_item.container_or_implemented_trait(db)?; + Some(into_iter_trait.id) + }, + )?; let canonical_ty = Canonical { value: self.ty.clone(), binders: CanonicalVarKinds::empty(Interner) }; @@ -5133,10 +5112,8 @@ impl Type { } pub fn is_copy(&self, db: &dyn HirDatabase) -> bool { - let lang_item = db.lang_item(self.env.krate, LangItem::Copy); - let copy_trait = match lang_item { - Some(LangItemTarget::Trait(it)) => it, - _ => return false, + let Some(copy_trait) = LangItem::Copy.resolve_trait(db, self.env.krate) else { + return false; }; self.impls_trait(db, copy_trait.into(), &[]) } diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs index f708f2e16673..4d092c1f0bb0 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs @@ -25,7 +25,6 @@ use hir_expand::{ builtin::{BuiltinFnLikeExpander, EagerExpander}, db::ExpandDatabase, files::{FileRangeWrapper, InRealFile}, - hygiene::SyntaxContextExt as _, inert_attr_macro::find_builtin_attr_idx, mod_path::{ModPath, PathKind}, name::AsName, @@ -927,7 +926,7 @@ impl<'db> SemanticsImpl<'db> { token: InRealFile, mut cb: impl FnMut(InFile, SyntaxContext) -> ControlFlow, ) -> Option { - self.descend_into_macros_impl(token.clone(), &mut cb) + self.descend_into_macros_impl(token, &mut cb) } /// Descends the token into expansions, returning the tokens that matches the input @@ -959,17 +958,13 @@ impl<'db> SemanticsImpl<'db> { let text = token.text(); let kind = token.kind(); if let Ok(token) = self.wrap_token_infile(token.clone()).into_real_file() { - self.descend_into_macros_breakable( - token.clone(), - |InFile { value, file_id: _ }, _ctx| { - let mapped_kind = value.kind(); - let any_ident_match = - || kind.is_any_identifier() && value.kind().is_any_identifier(); - let matches = - (kind == mapped_kind || any_ident_match()) && text == value.text(); - if matches { ControlFlow::Break(value) } else { ControlFlow::Continue(()) } - }, - ) + self.descend_into_macros_breakable(token, |InFile { value, file_id: _ }, _ctx| { + let mapped_kind = value.kind(); + let any_ident_match = + || kind.is_any_identifier() && value.kind().is_any_identifier(); + let matches = (kind == mapped_kind || any_ident_match()) && text == value.text(); + if matches { ControlFlow::Break(value) } else { ControlFlow::Continue(()) } + }) } else { None } diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs b/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs index 466bf7f6c826..587c51d8cc99 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs @@ -559,7 +559,7 @@ impl SourceToDefCtx<'_, '_> { let item = match ast::Item::cast(value.clone()) { Some(it) => it, None => { - let variant = ast::Variant::cast(value.clone())?; + let variant = ast::Variant::cast(value)?; return this .enum_variant_to_def(InFile::new(file_id, &variant)) .map(Into::into); diff --git a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs index 666efe8ec645..c1a75ce7e574 100644 --- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs +++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs @@ -556,8 +556,8 @@ impl SourceAnalyzer { } } - let future_trait = db.lang_item(self.resolver.krate(), LangItem::Future)?.as_trait()?; - let poll_fn = db.lang_item(self.resolver.krate(), LangItem::FuturePoll)?.as_function()?; + let future_trait = LangItem::Future.resolve_trait(db, self.resolver.krate())?; + let poll_fn = LangItem::FuturePoll.resolve_function(db, self.resolver.krate())?; // HACK: subst for `poll()` coincides with that for `Future` because `poll()` itself // doesn't have any generic parameters, so we skip building another subst for `poll()`. let substs = hir_ty::TyBuilder::subst_for_def(db, future_trait, None).push(ty).build(); @@ -666,7 +666,7 @@ impl SourceAnalyzer { ) -> Option { let ty = self.ty_of_expr(try_expr.expr()?)?; - let op_fn = db.lang_item(self.resolver.krate(), LangItem::TryTraitBranch)?.as_function()?; + let op_fn = LangItem::TryTraitBranch.resolve_function(db, self.resolver.krate())?; let op_trait = match op_fn.lookup(db).container { ItemContainerId::TraitId(id) => id, _ => return None, @@ -1425,13 +1425,13 @@ impl SourceAnalyzer { lang_trait: LangItem, method_name: &Name, ) -> Option<(TraitId, FunctionId)> { - let trait_id = db.lang_item(self.resolver.krate(), lang_trait)?.as_trait()?; + let trait_id = lang_trait.resolve_trait(db, self.resolver.krate())?; let fn_id = db.trait_items(trait_id).method_by_name(method_name)?; Some((trait_id, fn_id)) } fn ty_of_expr(&self, expr: ast::Expr) -> Option<&Ty> { - self.infer()?.type_of_expr_or_pat(self.expr_id(expr.clone())?) + self.infer()?.type_of_expr_or_pat(self.expr_id(expr)?) } } diff --git a/src/tools/rust-analyzer/crates/hir/src/symbols.rs b/src/tools/rust-analyzer/crates/hir/src/symbols.rs index 41064d047a5a..e87ab87407ff 100644 --- a/src/tools/rust-analyzer/crates/hir/src/symbols.rs +++ b/src/tools/rust-analyzer/crates/hir/src/symbols.rs @@ -13,13 +13,13 @@ use hir_def::{ use hir_expand::{HirFileId, name::Name}; use hir_ty::{ db::HirDatabase, - display::{DisplayTarget, HirDisplay, hir_display_with_store}, + display::{HirDisplay, hir_display_with_store}, }; use intern::Symbol; use rustc_hash::FxHashMap; use syntax::{AstNode, AstPtr, SmolStr, SyntaxNode, SyntaxNodePtr, ToSmolStr, ast::HasName}; -use crate::{Module, ModuleDef, Semantics}; +use crate::{HasCrate, Module, ModuleDef, Semantics}; pub type FxIndexSet = indexmap::IndexSet>; @@ -66,7 +66,6 @@ pub struct SymbolCollector<'a> { symbols: FxIndexSet, work: Vec, current_container_name: Option, - display_target: DisplayTarget, } /// Given a [`ModuleId`] and a [`HirDatabase`], use the DefMap for the module's crate to collect @@ -78,10 +77,6 @@ impl<'a> SymbolCollector<'a> { symbols: Default::default(), work: Default::default(), current_container_name: None, - display_target: DisplayTarget::from_crate( - db, - *db.all_crates().last().expect("no crate graph present"), - ), } } @@ -93,8 +88,7 @@ impl<'a> SymbolCollector<'a> { pub fn collect(&mut self, module: Module) { let _p = tracing::info_span!("SymbolCollector::collect", ?module).entered(); - tracing::info!(?module, "SymbolCollector::collect",); - self.display_target = module.krate().to_display_target(self.db); + tracing::info!(?module, "SymbolCollector::collect"); // The initial work is the root module we're collecting, additional work will // be populated as we traverse the module's definitions. @@ -263,8 +257,9 @@ impl<'a> SymbolCollector<'a> { for (name, Item { def, vis, import }) in scope.macros() { if let Some(i) = import { match i { - ImportOrGlob::Import(i) => push_import(self, i, name, def.into(), vis), - ImportOrGlob::Glob(_) => (), + ImportOrExternCrate::Import(i) => push_import(self, i, name, def.into(), vis), + ImportOrExternCrate::Glob(_) => (), + ImportOrExternCrate::ExternCrate(_) => (), } continue; } @@ -320,7 +315,10 @@ impl<'a> SymbolCollector<'a> { let impl_data = self.db.impl_signature(impl_id); let impl_name = Some( hir_display_with_store(impl_data.self_ty, &impl_data.store) - .display(self.db, self.display_target) + .display( + self.db, + crate::Impl::from(impl_id).krate(self.db).to_display_target(self.db), + ) .to_smolstr(), ); self.with_container_name(impl_name, |s| { diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/assist_config.rs b/src/tools/rust-analyzer/crates/ide-assists/src/assist_config.rs index 2de0013bb126..fb569f8cdae0 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/assist_config.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/assist_config.rs @@ -5,7 +5,7 @@ //! assists if we are allowed to. use hir::ImportPathConfig; -use ide_db::{SnippetCap, imports::insert_use::InsertUseConfig}; +use ide_db::{SnippetCap, assists::ExprFillDefaultMode, imports::insert_use::InsertUseConfig}; use crate::AssistKind; @@ -21,6 +21,7 @@ pub struct AssistConfig { pub term_search_fuel: u64, pub term_search_borrowck: bool, pub code_action_grouping: bool, + pub expr_fill_default: ExprFillDefaultMode, } impl AssistConfig { diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs index 887ec5aeec9a..6a55f39e6934 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs @@ -150,6 +150,7 @@ fn add_missing_impl_members_inner( let new_impl_def = edit.make_mut(impl_def.clone()); let first_new_item = add_trait_assoc_items_to_impl( &ctx.sema, + ctx.config, &missing_items, trait_, &new_impl_def, diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs index 8c1c83e3f716..858d4369914a 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs @@ -3,6 +3,7 @@ use std::iter::{self, Peekable}; use either::Either; use hir::{Adt, Crate, HasAttrs, ImportPathConfig, ModuleDef, Semantics, sym}; use ide_db::RootDatabase; +use ide_db::assists::ExprFillDefaultMode; use ide_db::syntax_helpers::suggest_name; use ide_db::{famous_defs::FamousDefs, helpers::mod_path_to_ast}; use itertools::Itertools; @@ -216,7 +217,17 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>) // filter out hidden patterns because they're handled by the catch-all arm !hidden }) - .map(|(pat, _)| make.match_arm(pat, None, make::ext::expr_todo())); + .map(|(pat, _)| { + make.match_arm( + pat, + None, + match ctx.config.expr_fill_default { + ExprFillDefaultMode::Todo => make::ext::expr_todo(), + ExprFillDefaultMode::Underscore => make::ext::expr_underscore(), + ExprFillDefaultMode::Default => make::ext::expr_todo(), + }, + ) + }); let mut arms: Vec<_> = match_arm_list .arms() @@ -246,7 +257,15 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>) if needs_catch_all_arm && !has_catch_all_arm { cov_mark::hit!(added_wildcard_pattern); - let arm = make.match_arm(make.wildcard_pat().into(), None, make::ext::expr_todo()); + let arm = make.match_arm( + make.wildcard_pat().into(), + None, + match ctx.config.expr_fill_default { + ExprFillDefaultMode::Todo => make::ext::expr_todo(), + ExprFillDefaultMode::Underscore => make::ext::expr_underscore(), + ExprFillDefaultMode::Default => make::ext::expr_todo(), + }, + ); arms.push(arm); } @@ -474,8 +493,8 @@ fn build_pat( hir::StructKind::Record => { let fields = fields .into_iter() - .map(|f| make.name_ref(f.name(db).as_str())) - .map(|name_ref| make.record_pat_field_shorthand(name_ref)); + .map(|f| make.ident_pat(false, false, make.name(f.name(db).as_str()))) + .map(|ident| make.record_pat_field_shorthand(ident.into())); let fields = make.record_pat_field_list(fields, None); make.record_pat_with_fields(path, fields).into() } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs index cd23ad223729..bcd06c1ef725 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs @@ -196,7 +196,7 @@ pub(crate) fn convert_bool_then_to_if(acc: &mut Assists, ctx: &AssistContext<'_> // Wrap all tails in `Some(...)` let none_path = mapless_make.expr_path(mapless_make.ident_path("None")); let some_path = mapless_make.expr_path(mapless_make.ident_path("Some")); - for_each_tail_expr(&ast::Expr::BlockExpr(closure_body.clone()), &mut |e| { + for_each_tail_expr(&ast::Expr::BlockExpr(closure_body), &mut |e| { let e = match e { ast::Expr::BreakExpr(e) => e.expr(), ast::Expr::ReturnExpr(e) => e.expr(), diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_closure_to_fn.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_closure_to_fn.rs index 1d3a2db3352b..43515de71e20 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_closure_to_fn.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_closure_to_fn.rs @@ -1066,7 +1066,7 @@ fn foo() { r#" fn foo() { let (mut a, b) = (0.1, "abc"); - fn closure(p1: i32, p2: &mut bool, a: &mut f64, b: &&str) { + fn closure(p1: i32, p2: &mut bool, a: &mut f64, b: &&'static str) { *a = 1.2; let c = *b; } @@ -1098,7 +1098,7 @@ fn foo() { r#" fn foo() { let (mut a, b) = (0.1, "abc"); - fn closure(p1: i32, p2: &mut bool, a: &mut f64, b: &&str) { + fn closure(p1: i32, p2: &mut bool, a: &mut f64, b: &&'static str) { let _: &mut bool = p2; *a = 1.2; let c = *b; @@ -1136,7 +1136,7 @@ fn foo() { r#" fn foo() { let (mut a, b) = (0.1, "abc"); - fn closure(p1: i32, p2: &mut bool, a: &mut f64, b: &&str) { + fn closure(p1: i32, p2: &mut bool, a: &mut f64, b: &&'static str) { let _: &mut bool = p2; *a = 1.2; let c = *b; diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_from_to_tryfrom.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_from_to_tryfrom.rs index 24cc32d10d88..db41927f1df2 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_from_to_tryfrom.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_from_to_tryfrom.rs @@ -80,7 +80,7 @@ pub(crate) fn convert_from_to_tryfrom(acc: &mut Assists, ctx: &AssistContext<'_> let from_fn_name = builder.make_mut(from_fn_name); let tail_expr = builder.make_mut(tail_expr); let return_exprs = return_exprs.map(|r| builder.make_mut(r)).collect_vec(); - let associated_items = builder.make_mut(associated_items).clone(); + let associated_items = builder.make_mut(associated_items); ted::replace( trait_ty.syntax(), diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_let_else_to_match.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_let_else_to_match.rs index df92b07cba7c..ebfed9f9ca99 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_let_else_to_match.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_let_else_to_match.rs @@ -1,8 +1,9 @@ -use hir::Semantics; -use ide_db::RootDatabase; use syntax::T; use syntax::ast::RangeItem; -use syntax::ast::{AstNode, HasName, LetStmt, Name, Pat, edit::AstNodeEdit}; +use syntax::ast::edit::IndentLevel; +use syntax::ast::edit_in_place::Indent; +use syntax::ast::syntax_factory::SyntaxFactory; +use syntax::ast::{self, AstNode, HasName, LetStmt, Pat}; use crate::{AssistContext, AssistId, Assists}; @@ -25,155 +26,205 @@ use crate::{AssistContext, AssistId, Assists}; // } // ``` pub(crate) fn convert_let_else_to_match(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { - // should focus on else token to trigger + // Should focus on the `else` token to trigger let let_stmt = ctx .find_token_syntax_at_offset(T![else]) .and_then(|it| it.parent()?.parent()) .or_else(|| ctx.find_token_syntax_at_offset(T![let])?.parent())?; let let_stmt = LetStmt::cast(let_stmt)?; - let let_else_block = let_stmt.let_else()?.block_expr()?; - let let_init = let_stmt.initializer()?; + let else_block = let_stmt.let_else()?.block_expr()?; + let else_expr = if else_block.statements().next().is_none() { + else_block.tail_expr()? + } else { + else_block.into() + }; + let init = let_stmt.initializer()?; + // Ignore let stmt with type annotation if let_stmt.ty().is_some() { - // don't support let with type annotation return None; } let pat = let_stmt.pat()?; - let mut binders = Vec::new(); - binders_in_pat(&mut binders, &pat, &ctx.sema)?; - let target = let_stmt.syntax().text_range(); + let make = SyntaxFactory::with_mappings(); + let mut idents = Vec::default(); + let pat_without_mut = remove_mut_and_collect_idents(&make, &pat, &mut idents)?; + let bindings = idents + .into_iter() + .filter_map(|ref pat| { + // Identifiers which resolve to constants are not bindings + if ctx.sema.resolve_bind_pat_to_const(pat).is_none() { + Some((pat.name()?, pat.ref_token().is_none() && pat.mut_token().is_some())) + } else { + None + } + }) + .collect::>(); + acc.add( AssistId::refactor_rewrite("convert_let_else_to_match"), - "Convert let-else to let and match", - target, - |edit| { - let indent_level = let_stmt.indent_level().0 as usize; - let indent = " ".repeat(indent_level); - let indent1 = " ".repeat(indent_level + 1); + if bindings.is_empty() { + "Convert let-else to match" + } else { + "Convert let-else to let and match" + }, + let_stmt.syntax().text_range(), + |builder| { + let mut editor = builder.make_editor(let_stmt.syntax()); - let binders_str = binders_to_str(&binders, false); - let binders_str_mut = binders_to_str(&binders, true); + let binding_paths = bindings + .iter() + .map(|(name, _)| make.expr_path(make.ident_path(&name.to_string()))) + .collect::>(); - let init_expr = let_init.syntax().text(); - let mut pat_no_mut = pat.syntax().text().to_string(); - // remove the mut from the pattern - for (b, ismut) in binders.iter() { - if *ismut { - pat_no_mut = pat_no_mut.replace(&format!("mut {b}"), &b.to_string()); - } + let binding_arm = make.match_arm( + pat_without_mut, + None, + // There are three possible cases: + // + // - No bindings: `None => {}` + // - Single binding: `Some(it) => it` + // - Multiple bindings: `Foo::Bar { a, b, .. } => (a, b)` + match binding_paths.len() { + 0 => make.expr_empty_block().into(), + + 1 => binding_paths[0].clone(), + _ => make.expr_tuple(binding_paths).into(), + }, + ); + let else_arm = make.match_arm(make.wildcard_pat().into(), None, else_expr); + let match_ = make.expr_match(init, make.match_arm_list([binding_arm, else_arm])); + match_.reindent_to(IndentLevel::from_node(let_stmt.syntax())); + + if bindings.is_empty() { + editor.replace(let_stmt.syntax(), match_.syntax()); + } else { + let ident_pats = bindings + .into_iter() + .map(|(name, is_mut)| make.ident_pat(false, is_mut, name).into()) + .collect::>(); + let new_let_stmt = make.let_stmt( + if ident_pats.len() == 1 { + ident_pats[0].clone() + } else { + make.tuple_pat(ident_pats).into() + }, + None, + Some(match_.into()), + ); + editor.replace(let_stmt.syntax(), new_let_stmt.syntax()); } - let only_expr = let_else_block.statements().next().is_none(); - let branch2 = match &let_else_block.tail_expr() { - Some(tail) if only_expr => format!("{tail},"), - _ => let_else_block.syntax().text().to_string(), - }; - let replace = if binders.is_empty() { - format!( - "match {init_expr} {{ -{indent1}{pat_no_mut} => {binders_str} -{indent1}_ => {branch2} -{indent}}}" - ) - } else { - format!( - "let {binders_str_mut} = match {init_expr} {{ -{indent1}{pat_no_mut} => {binders_str}, -{indent1}_ => {branch2} -{indent}}};" - ) - }; - edit.replace(target, replace); + editor.add_mappings(make.finish_with_mappings()); + builder.add_file_edits(ctx.vfs_file_id(), editor); }, ) } -/// Gets a list of binders in a pattern, and whether they are mut. -fn binders_in_pat( - acc: &mut Vec<(Name, bool)>, - pat: &Pat, - sem: &Semantics<'_, RootDatabase>, -) -> Option<()> { - use Pat::*; - match pat { - IdentPat(p) => { - let ident = p.name()?; - let ismut = p.ref_token().is_none() && p.mut_token().is_some(); - // check for const reference - if sem.resolve_bind_pat_to_const(p).is_none() { - acc.push((ident, ismut)); - } +fn remove_mut_and_collect_idents( + make: &SyntaxFactory, + pat: &ast::Pat, + acc: &mut Vec, +) -> Option { + Some(match pat { + ast::Pat::IdentPat(p) => { + acc.push(p.clone()); + let non_mut_pat = make.ident_pat( + p.ref_token().is_some(), + p.ref_token().is_some() && p.mut_token().is_some(), + p.name()?, + ); if let Some(inner) = p.pat() { - binders_in_pat(acc, &inner, sem)?; + non_mut_pat.set_pat(remove_mut_and_collect_idents(make, &inner, acc)); } - Some(()) + non_mut_pat.into() } - BoxPat(p) => p.pat().and_then(|p| binders_in_pat(acc, &p, sem)), - RestPat(_) | LiteralPat(_) | PathPat(_) | WildcardPat(_) | ConstBlockPat(_) => Some(()), - OrPat(p) => { - for p in p.pats() { - binders_in_pat(acc, &p, sem)?; - } - Some(()) + ast::Pat::BoxPat(p) => { + make.box_pat(remove_mut_and_collect_idents(make, &p.pat()?, acc)?).into() } - ParenPat(p) => p.pat().and_then(|p| binders_in_pat(acc, &p, sem)), - RangePat(p) => { - if let Some(st) = p.start() { - binders_in_pat(acc, &st, sem)? - } - if let Some(ed) = p.end() { - binders_in_pat(acc, &ed, sem)? - } - Some(()) + ast::Pat::OrPat(p) => make + .or_pat( + p.pats() + .map(|pat| remove_mut_and_collect_idents(make, &pat, acc)) + .collect::>>()?, + p.leading_pipe().is_some(), + ) + .into(), + ast::Pat::ParenPat(p) => { + make.paren_pat(remove_mut_and_collect_idents(make, &p.pat()?, acc)?).into() } - RecordPat(p) => { - for f in p.record_pat_field_list()?.fields() { - let pat = f.pat()?; - binders_in_pat(acc, &pat, sem)?; + ast::Pat::RangePat(p) => make + .range_pat( + if let Some(start) = p.start() { + Some(remove_mut_and_collect_idents(make, &start, acc)?) + } else { + None + }, + if let Some(end) = p.end() { + Some(remove_mut_and_collect_idents(make, &end, acc)?) + } else { + None + }, + ) + .into(), + ast::Pat::RecordPat(p) => make + .record_pat_with_fields( + p.path()?, + make.record_pat_field_list( + p.record_pat_field_list()? + .fields() + .map(|field| { + remove_mut_and_collect_idents(make, &field.pat()?, acc).map(|pat| { + if let Some(name_ref) = field.name_ref() { + make.record_pat_field(name_ref, pat) + } else { + make.record_pat_field_shorthand(pat) + } + }) + }) + .collect::>>()?, + p.record_pat_field_list()?.rest_pat(), + ), + ) + .into(), + ast::Pat::RefPat(p) => { + let inner = p.pat()?; + if let ast::Pat::IdentPat(ident) = inner { + acc.push(ident); + p.clone_for_update().into() + } else { + make.ref_pat(remove_mut_and_collect_idents(make, &inner, acc)?).into() } - Some(()) - } - RefPat(p) => p.pat().and_then(|p| binders_in_pat(acc, &p, sem)), - SlicePat(p) => { - for p in p.pats() { - binders_in_pat(acc, &p, sem)?; - } - Some(()) - } - TuplePat(p) => { - for p in p.fields() { - binders_in_pat(acc, &p, sem)?; - } - Some(()) - } - TupleStructPat(p) => { - for p in p.fields() { - binders_in_pat(acc, &p, sem)?; - } - Some(()) } + ast::Pat::SlicePat(p) => make + .slice_pat( + p.pats() + .map(|pat| remove_mut_and_collect_idents(make, &pat, acc)) + .collect::>>()?, + ) + .into(), + ast::Pat::TuplePat(p) => make + .tuple_pat( + p.fields() + .map(|field| remove_mut_and_collect_idents(make, &field, acc)) + .collect::>>()?, + ) + .into(), + ast::Pat::TupleStructPat(p) => make + .tuple_struct_pat( + p.path()?, + p.fields() + .map(|field| remove_mut_and_collect_idents(make, &field, acc)) + .collect::>>()?, + ) + .into(), + ast::Pat::RestPat(_) + | ast::Pat::LiteralPat(_) + | ast::Pat::PathPat(_) + | ast::Pat::WildcardPat(_) + | ast::Pat::ConstBlockPat(_) => pat.clone(), // don't support macro pat yet - MacroPat(_) => None, - } -} - -fn binders_to_str(binders: &[(Name, bool)], addmut: bool) -> String { - let vars = binders - .iter() - .map( - |(ident, ismut)| { - if *ismut && addmut { format!("mut {ident}") } else { ident.to_string() } - }, - ) - .collect::>() - .join(", "); - if binders.is_empty() { - String::from("{}") - } else if binders.len() == 1 { - vars - } else { - format!("({vars})") - } + ast::Pat::MacroPat(_) => return None, + }) } #[cfg(test)] diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs index 800ef89ac6ed..b8c647ac8b71 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_struct_binding.rs @@ -196,7 +196,9 @@ fn destructure_pat( let fields = field_names.iter().map(|(old_name, new_name)| { // Use shorthand syntax if possible if old_name == new_name && !is_mut { - make.record_pat_field_shorthand(make.name_ref(old_name)) + make.record_pat_field_shorthand( + make.ident_pat(false, false, make.name(old_name)).into(), + ) } else { make.record_pat_field( make.name_ref(old_name), diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs index adf0f0997b39..f09389f8302f 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs @@ -142,7 +142,7 @@ fn collect_data(ident_pat: IdentPat, ctx: &AssistContext<'_>) -> Option name, - None => name_generator.suggest_name(&format!("_{}", id)), + None => name_generator.suggest_name(&format!("_{id}")), } .to_string() }) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_rest_pattern.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_rest_pattern.rs index 4e487e216264..b71de5e00c6a 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_rest_pattern.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/expand_rest_pattern.rs @@ -56,7 +56,12 @@ fn expand_record_rest_pattern( let new_field_list = make.record_pat_field_list(old_field_list.fields(), None); for (f, _) in missing_fields.iter() { let field = make.record_pat_field_shorthand( - make.name_ref(&f.name(ctx.sema.db).display_no_db(edition).to_smolstr()), + make.ident_pat( + false, + false, + make.name(&f.name(ctx.sema.db).display_no_db(edition).to_smolstr()), + ) + .into(), ); new_field_list.add_field(field); } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs index 046af71a9dc0..e977798c4fd0 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs @@ -5033,7 +5033,7 @@ fn main() { fun_name(bar); } -fn $0fun_name(bar: &str) { +fn $0fun_name(bar: &'static str) { m!(bar); } "#, diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs index 3971b60f2532..31e84e9adcf4 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs @@ -631,7 +631,7 @@ fn main() { "#, r#" fn main() { - const $0HELLO: &str = "hello"; + const $0HELLO: &'static str = "hello"; } "#, "Extract into constant", @@ -726,7 +726,7 @@ fn main() { "#, r#" fn main() { - static $0HELLO: &str = "hello"; + static $0HELLO: &'static str = "hello"; } "#, "Extract into static", @@ -2528,13 +2528,13 @@ fn foo() { check_assist_by_label( extract_variable, r#" -struct Entry(&str); +struct Entry<'a>(&'a str); fn foo() { let entry = Entry($0"Hello"$0); } "#, r#" -struct Entry(&str); +struct Entry<'a>(&'a str); fn foo() { let $0hello = "Hello"; let entry = Entry(hello); @@ -2546,13 +2546,13 @@ fn foo() { check_assist_by_label( extract_variable, r#" -struct Entry(&str); +struct Entry<'a>(&'a str); fn foo() { let entry = Entry($0"Hello"$0); } "#, r#" -struct Entry(&str); +struct Entry<'a>(&'a str); fn foo() { const $0HELLO: &str = "Hello"; let entry = Entry(HELLO); @@ -2564,13 +2564,13 @@ fn foo() { check_assist_by_label( extract_variable, r#" -struct Entry(&str); +struct Entry<'a>(&'a str); fn foo() { let entry = Entry($0"Hello"$0); } "#, r#" -struct Entry(&str); +struct Entry<'a>(&'a str); fn foo() { static $0HELLO: &str = "Hello"; let entry = Entry(HELLO); @@ -2587,13 +2587,13 @@ fn foo() { check_assist_by_label( extract_variable, r#" -struct Entry { message: &str } +struct Entry<'a> { message: &'a str } fn foo() { let entry = Entry { message: $0"Hello"$0 }; } "#, r#" -struct Entry { message: &str } +struct Entry<'a> { message: &'a str } fn foo() { let $0message = "Hello"; let entry = Entry { message }; @@ -2605,13 +2605,13 @@ fn foo() { check_assist_by_label( extract_variable, r#" -struct Entry { message: &str } +struct Entry<'a> { message: &'a str } fn foo() { let entry = Entry { message: $0"Hello"$0 }; } "#, r#" -struct Entry { message: &str } +struct Entry<'a> { message: &'a str } fn foo() { const $0HELLO: &str = "Hello"; let entry = Entry { message: HELLO }; @@ -2623,13 +2623,13 @@ fn foo() { check_assist_by_label( extract_variable, r#" -struct Entry { message: &str } +struct Entry<'a> { message: &'a str } fn foo() { let entry = Entry { message: $0"Hello"$0 }; } "#, r#" -struct Entry { message: &str } +struct Entry<'a> { message: &'a str } fn foo() { static $0HELLO: &str = "Hello"; let entry = Entry { message: HELLO }; diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs index 824380253ae5..30084d23d1fb 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs @@ -4,6 +4,7 @@ use hir::{ }; use ide_db::{ FileId, FxHashMap, FxHashSet, RootDatabase, SnippetCap, + assists::ExprFillDefaultMode, defs::{Definition, NameRefClass}, famous_defs::FamousDefs, helpers::is_editable_crate, @@ -46,7 +47,7 @@ use crate::{ // bar("", baz()); // } // -// fn bar(arg: &str, baz: Baz) ${0:-> _} { +// fn bar(arg: &'static str, baz: Baz) ${0:-> _} { // todo!() // } // @@ -276,7 +277,11 @@ impl FunctionBuilder { target_module, &mut necessary_generic_params, ); - let placeholder_expr = make::ext::expr_todo(); + let placeholder_expr = match ctx.config.expr_fill_default { + ExprFillDefaultMode::Todo => make::ext::expr_todo(), + ExprFillDefaultMode::Underscore => make::ext::expr_underscore(), + ExprFillDefaultMode::Default => make::ext::expr_todo(), + }; fn_body = make::block_expr(vec![], Some(placeholder_expr)); }; @@ -331,7 +336,11 @@ impl FunctionBuilder { let (generic_param_list, where_clause) = fn_generic_params(ctx, necessary_generic_params, &target)?; - let placeholder_expr = make::ext::expr_todo(); + let placeholder_expr = match ctx.config.expr_fill_default { + ExprFillDefaultMode::Todo => make::ext::expr_todo(), + ExprFillDefaultMode::Underscore => make::ext::expr_underscore(), + ExprFillDefaultMode::Default => make::ext::expr_todo(), + }; let fn_body = make::block_expr(vec![], Some(placeholder_expr)); Some(Self { @@ -383,14 +392,14 @@ impl FunctionBuilder { // Focus the return type if there is one match ret_type { Some(ret_type) => { - edit.add_placeholder_snippet(cap, ret_type.clone()); + edit.add_placeholder_snippet(cap, ret_type); } None => { - edit.add_placeholder_snippet(cap, tail_expr.clone()); + edit.add_placeholder_snippet(cap, tail_expr); } } } else { - edit.add_placeholder_snippet(cap, tail_expr.clone()); + edit.add_placeholder_snippet(cap, tail_expr); } } @@ -444,7 +453,11 @@ fn make_fn_body_as_new_function( let adt_info = adt_info.as_ref()?; let path_self = make::ext::ident_path("Self"); - let placeholder_expr = make::ext::expr_todo(); + let placeholder_expr = match ctx.config.expr_fill_default { + ExprFillDefaultMode::Todo => make::ext::expr_todo(), + ExprFillDefaultMode::Underscore => make::ext::expr_underscore(), + ExprFillDefaultMode::Default => make::ext::expr_todo(), + }; let tail_expr = if let Some(strukt) = adt_info.adt.as_struct() { match strukt.kind(ctx.db()) { StructKind::Record => { @@ -1505,7 +1518,7 @@ fn foo() { bar("bar") } -fn bar(arg: &str) { +fn bar(arg: &'static str) { ${0:todo!()} } "#, @@ -2122,7 +2135,7 @@ fn foo() { bar(baz(), baz(), "foo", "bar") } -fn bar(baz_1: Baz, baz_2: Baz, arg_1: &str, arg_2: &str) { +fn bar(baz_1: Baz, baz_2: Baz, arg_1: &'static str, arg_2: &'static str) { ${0:todo!()} } "#, @@ -3090,7 +3103,7 @@ pub struct Foo { field_2: String, } impl Foo { - fn new(baz_1: Baz, baz_2: Baz, arg_1: &str, arg_2: &str) -> Self { + fn new(baz_1: Baz, baz_2: Baz, arg_1: &'static str, arg_2: &'static str) -> Self { ${0:Self { field_1: todo!(), field_2: todo!() }} } } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_imports.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_imports.rs index b7f7cb9cb01c..6bf7f5849148 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_imports.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_imports.rs @@ -1,14 +1,14 @@ use either::Either; use ide_db::imports::{ insert_use::{ImportGranularity, InsertUseConfig}, - merge_imports::{MergeBehavior, try_merge_imports, try_merge_trees, try_normalize_use_tree}, + merge_imports::{MergeBehavior, try_merge_imports, try_merge_trees}, }; -use itertools::Itertools; use syntax::{ AstNode, SyntaxElement, SyntaxNode, algo::neighbor, - ast::{self, edit_in_place::Removable}, - match_ast, ted, + ast::{self, syntax_factory::SyntaxFactory}, + match_ast, + syntax_editor::Removable, }; use crate::{ @@ -69,49 +69,32 @@ pub(crate) fn merge_imports(acc: &mut Assists, ctx: &AssistContext<'_>) -> Optio (selection_range, edits?) }; - acc.add(AssistId::refactor_rewrite("merge_imports"), "Merge imports", target, |builder| { - let edits_mut: Vec = edits - .into_iter() - .map(|it| match it { - Remove(Either::Left(it)) => Remove(Either::Left(builder.make_mut(it))), - Remove(Either::Right(it)) => Remove(Either::Right(builder.make_mut(it))), - Replace(old, new) => Replace(builder.make_syntax_mut(old), new), - }) - .collect(); - for edit in edits_mut { - match edit { - Remove(it) => it.as_ref().either(Removable::remove, Removable::remove), - Replace(old, new) => { - ted::replace(old, &new); + let parent_node = match ctx.covering_element() { + SyntaxElement::Node(n) => n, + SyntaxElement::Token(t) => t.parent()?, + }; - // If there's a selection and we're replacing a use tree in a tree list, - // normalize the parent use tree if it only contains the merged subtree. - if !ctx.has_empty_selection() { - let normalized_use_tree = ast::UseTree::cast(new) - .as_ref() - .and_then(ast::UseTree::parent_use_tree_list) - .and_then(|use_tree_list| { - if use_tree_list.use_trees().collect_tuple::<(_,)>().is_some() { - Some(use_tree_list.parent_use_tree()) - } else { - None - } - }) - .and_then(|target_tree| { - try_normalize_use_tree( - &target_tree, - ctx.config.insert_use.granularity.into(), - ) - .map(|top_use_tree_flat| (target_tree, top_use_tree_flat)) - }); - if let Some((old_tree, new_tree)) = normalized_use_tree { - cov_mark::hit!(replace_parent_with_normalized_use_tree); - ted::replace(old_tree.syntax(), new_tree.syntax()); - } + acc.add(AssistId::refactor_rewrite("merge_imports"), "Merge imports", target, |builder| { + let make = SyntaxFactory::with_mappings(); + let mut editor = builder.make_editor(&parent_node); + + for edit in edits { + match edit { + Remove(it) => { + let node = it.as_ref(); + if let Some(left) = node.left() { + left.remove(&mut editor); + } else if let Some(right) = node.right() { + right.remove(&mut editor); } } + Replace(old, new) => { + editor.replace(old, &new); + } } } + editor.add_mappings(make.finish_with_mappings()); + builder.add_file_edits(ctx.vfs_file_id(), editor); }) } @@ -723,11 +706,10 @@ use std::{ ); cov_mark::check!(merge_with_selected_use_tree_neighbors); - cov_mark::check!(replace_parent_with_normalized_use_tree); check_assist( merge_imports, r"use std::$0{fmt::Display, fmt::Debug}$0;", - r"use std::fmt::{Debug, Display};", + r"use std::{fmt::{Debug, Display}};", ); } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs index 6dcdf5edbd63..806c8fba9ea4 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs @@ -9,7 +9,7 @@ use syntax::{ }; use crate::{ - AssistId, + AssistConfig, AssistId, assist_context::{AssistContext, Assists, SourceChangeBuilder}, utils::{ DefaultMethods, IgnoreAssocItems, add_trait_assoc_items_to_impl, filter_assoc_items, @@ -128,8 +128,14 @@ fn add_assist( acc.add(AssistId::refactor("replace_derive_with_manual_impl"), label, target, |builder| { let insert_after = ted::Position::after(builder.make_mut(adt.clone()).syntax()); let impl_is_unsafe = trait_.map(|s| s.is_unsafe(ctx.db())).unwrap_or(false); - let impl_def_with_items = - impl_def_from_trait(&ctx.sema, adt, &annotated_name, trait_, replace_trait_path); + let impl_def_with_items = impl_def_from_trait( + &ctx.sema, + ctx.config, + adt, + &annotated_name, + trait_, + replace_trait_path, + ); update_attribute(builder, old_derives, old_tree, old_trait_path, attr); let trait_path = make::ty_path(replace_trait_path.clone()); @@ -217,6 +223,7 @@ fn add_assist( fn impl_def_from_trait( sema: &hir::Semantics<'_, ide_db::RootDatabase>, + config: &AssistConfig, adt: &ast::Adt, annotated_name: &ast::Name, trait_: Option, @@ -241,7 +248,7 @@ fn impl_def_from_trait( let impl_def = generate_trait_impl(adt, make::ty_path(trait_path.clone())); let first_assoc_item = - add_trait_assoc_items_to_impl(sema, &trait_items, trait_, &impl_def, &target_scope); + add_trait_assoc_items_to_impl(sema, config, &trait_items, trait_, &impl_def, &target_scope); // Generate a default `impl` function body for the derived trait. if let ast::AssocItem::Fn(ref func) = first_assoc_item { diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_use.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_imports.rs similarity index 57% rename from src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_use.rs rename to src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_imports.rs index 805a7344494a..c066f41ca47b 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_use.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_imports.rs @@ -1,7 +1,10 @@ use syntax::{ AstNode, SyntaxKind, - ast::{self, HasVisibility, edit_in_place::Removable, make}, - ted::{self, Position}, + ast::{ + self, HasAttrs, HasVisibility, edit::IndentLevel, edit_in_place::AttrsOwnerEdit, make, + syntax_factory::SyntaxFactory, + }, + syntax_editor::{Element, Position, Removable}, }; use crate::{ @@ -9,9 +12,9 @@ use crate::{ assist_context::{AssistContext, Assists}, }; -// Assist: unmerge_use +// Assist: unmerge_imports // -// Extracts single use item from use list. +// Extracts a use item from a use list into a standalone use list. // // ``` // use std::fmt::{Debug, Display$0}; @@ -21,21 +24,18 @@ use crate::{ // use std::fmt::{Debug}; // use std::fmt::Display; // ``` -pub(crate) fn unmerge_use(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { - let tree: ast::UseTree = ctx.find_node_at_offset::()?.clone_for_update(); +pub(crate) fn unmerge_imports(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { + let tree = ctx.find_node_at_offset::()?; let tree_list = tree.syntax().parent().and_then(ast::UseTreeList::cast)?; if tree_list.use_trees().count() < 2 { - cov_mark::hit!(skip_single_use_item); + cov_mark::hit!(skip_single_import); return None; } - let use_: ast::Use = tree_list.syntax().ancestors().find_map(ast::Use::cast)?; + let use_ = tree_list.syntax().ancestors().find_map(ast::Use::cast)?; let path = resolve_full_path(&tree)?; - let old_parent_range = use_.syntax().parent()?.text_range(); - let new_parent = use_.syntax().parent()?; - // If possible, explain what is going to be done. let label = match tree.path().and_then(|path| path.first_segment()) { Some(name) => format!("Unmerge use of `{name}`"), @@ -43,17 +43,31 @@ pub(crate) fn unmerge_use(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option< }; let target = tree.syntax().text_range(); - acc.add(AssistId::refactor_rewrite("unmerge_use"), label, target, |builder| { - let new_use = make::use_( + acc.add(AssistId::refactor_rewrite("unmerge_imports"), label, target, |builder| { + let make = SyntaxFactory::with_mappings(); + let new_use = make.use_( use_.visibility(), - make::use_tree(path, tree.use_tree_list(), tree.rename(), tree.star_token().is_some()), - ) - .clone_for_update(); + make.use_tree(path, tree.use_tree_list(), tree.rename(), tree.star_token().is_some()), + ); + // Add any attributes that are present on the use tree + use_.attrs().for_each(|attr| { + new_use.add_attr(attr.clone_for_update()); + }); - tree.remove(); - ted::insert(Position::after(use_.syntax()), new_use.syntax()); - - builder.replace(old_parent_range, new_parent.to_string()); + let mut editor = builder.make_editor(use_.syntax()); + // Remove the use tree from the current use item + tree.remove(&mut editor); + // Insert a newline and indentation, followed by the new use item + editor.insert_all( + Position::after(use_.syntax()), + vec![ + make.whitespace(&format!("\n{}", IndentLevel::from_node(use_.syntax()))) + .syntax_element(), + new_use.syntax().syntax_element(), + ], + ); + editor.add_mappings(make.finish_with_mappings()); + builder.add_file_edits(ctx.vfs_file_id(), editor); }) } @@ -80,22 +94,22 @@ mod tests { use super::*; #[test] - fn skip_single_use_item() { - cov_mark::check!(skip_single_use_item); + fn skip_single_import() { + cov_mark::check!(skip_single_import); check_assist_not_applicable( - unmerge_use, + unmerge_imports, r" use std::fmt::Debug$0; ", ); check_assist_not_applicable( - unmerge_use, + unmerge_imports, r" use std::fmt::{Debug$0}; ", ); check_assist_not_applicable( - unmerge_use, + unmerge_imports, r" use std::fmt::Debug as Dbg$0; ", @@ -105,7 +119,7 @@ use std::fmt::Debug as Dbg$0; #[test] fn skip_single_glob_import() { check_assist_not_applicable( - unmerge_use, + unmerge_imports, r" use std::fmt::*$0; ", @@ -113,9 +127,9 @@ use std::fmt::*$0; } #[test] - fn unmerge_use_item() { + fn unmerge_import() { check_assist( - unmerge_use, + unmerge_imports, r" use std::fmt::{Debug, Display$0}; ", @@ -126,7 +140,7 @@ use std::fmt::Display; ); check_assist( - unmerge_use, + unmerge_imports, r" use std::fmt::{Debug, format$0, Display}; ", @@ -140,7 +154,7 @@ use std::fmt::format; #[test] fn unmerge_glob_import() { check_assist( - unmerge_use, + unmerge_imports, r" use std::fmt::{*$0, Display}; ", @@ -152,9 +166,9 @@ use std::fmt::*; } #[test] - fn unmerge_renamed_use_item() { + fn unmerge_renamed_import() { check_assist( - unmerge_use, + unmerge_imports, r" use std::fmt::{Debug, Display as Disp$0}; ", @@ -166,9 +180,9 @@ use std::fmt::Display as Disp; } #[test] - fn unmerge_indented_use_item() { + fn unmerge_indented_import() { check_assist( - unmerge_use, + unmerge_imports, r" mod format { use std::fmt::{Debug, Display$0 as Disp, format}; @@ -184,9 +198,9 @@ mod format { } #[test] - fn unmerge_nested_use_item() { + fn unmerge_nested_import() { check_assist( - unmerge_use, + unmerge_imports, r" use foo::bar::{baz::{qux$0, foobar}, barbaz}; ", @@ -196,7 +210,7 @@ use foo::bar::baz::qux; ", ); check_assist( - unmerge_use, + unmerge_imports, r" use foo::bar::{baz$0::{qux, foobar}, barbaz}; ", @@ -208,9 +222,9 @@ use foo::bar::baz::{qux, foobar}; } #[test] - fn unmerge_use_item_with_visibility() { + fn unmerge_import_with_visibility() { check_assist( - unmerge_use, + unmerge_imports, r" pub use std::fmt::{Debug, Display$0}; ", @@ -222,12 +236,27 @@ pub use std::fmt::Display; } #[test] - fn unmerge_use_item_on_self() { + fn unmerge_import_on_self() { check_assist( - unmerge_use, + unmerge_imports, r"use std::process::{Command, self$0};", r"use std::process::{Command}; use std::process;", ); } + + #[test] + fn unmerge_import_with_attributes() { + check_assist( + unmerge_imports, + r" +#[allow(deprecated)] +use foo::{bar, baz$0};", + r" +#[allow(deprecated)] +use foo::{bar}; +#[allow(deprecated)] +use foo::baz;", + ); + } } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_match_arm.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_match_arm.rs index 31ff47a05492..5aedff5cc775 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_match_arm.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_match_arm.rs @@ -53,8 +53,14 @@ pub(crate) fn unmerge_match_arm(acc: &mut Assists, ctx: &AssistContext<'_>) -> O |edit| { let pats_after = pipe_token .siblings_with_tokens(Direction::Next) - .filter_map(|it| ast::Pat::cast(it.into_node()?)); - let new_pat = make::or_pat(pats_after, or_pat.leading_pipe().is_some()); + .filter_map(|it| ast::Pat::cast(it.into_node()?)) + .collect::>(); + // It is guaranteed that `pats_after` has at least one element + let new_pat = if pats_after.len() == 1 { + pats_after[0].clone() + } else { + make::or_pat(pats_after, or_pat.leading_pipe().is_some()).into() + }; let new_match_arm = make::match_arm(new_pat, match_arm.guard(), match_arm_body).clone_for_update(); diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_unwrap_cfg_attr.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_unwrap_cfg_attr.rs index 1068d5d4cd57..e1b94673e775 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_unwrap_cfg_attr.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_unwrap_cfg_attr.rs @@ -116,7 +116,7 @@ pub(crate) fn wrap_unwrap_cfg_attr(acc: &mut Assists, ctx: &AssistContext<'_>) - (Some(attr), Some(ident)) if attr.simple_name().map(|v| v.eq("derive")).unwrap_or_default() => { - Some(attempt_get_derive(attr.clone(), ident)) + Some(attempt_get_derive(attr, ident)) } (Some(attr), _) => Some(WrapUnwrapOption::WrapAttr(attr)), @@ -128,7 +128,7 @@ pub(crate) fn wrap_unwrap_cfg_attr(acc: &mut Assists, ctx: &AssistContext<'_>) - NodeOrToken::Node(node) => ast::Attr::cast(node).map(WrapUnwrapOption::WrapAttr), NodeOrToken::Token(ident) if ident.kind() == syntax::T![ident] => { let attr = ident.parent_ancestors().find_map(ast::Attr::cast)?; - Some(attempt_get_derive(attr.clone(), ident)) + Some(attempt_get_derive(attr, ident)) } _ => None, } @@ -233,7 +233,7 @@ fn wrap_cfg_attr(acc: &mut Assists, ctx: &AssistContext<'_>, attr: ast::Attr) -> if let Some(meta) = attr.meta() { if let (Some(eq), Some(expr)) = (meta.eq_token(), meta.expr()) { raw_tokens.push(NodeOrToken::Token(make::tokens::whitespace(" "))); - raw_tokens.push(NodeOrToken::Token(eq.clone())); + raw_tokens.push(NodeOrToken::Token(eq)); raw_tokens.push(NodeOrToken::Token(make::tokens::whitespace(" "))); expr.syntax().descendants_with_tokens().for_each(|it| { diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs b/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs index a157483a449c..627ed37b04e5 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs @@ -222,8 +222,8 @@ mod handlers { mod toggle_async_sugar; mod toggle_ignore; mod toggle_macro_delimiter; + mod unmerge_imports; mod unmerge_match_arm; - mod unmerge_use; mod unnecessary_async; mod unqualify_method_call; mod unwrap_block; @@ -363,7 +363,7 @@ mod handlers { toggle_ignore::toggle_ignore, toggle_macro_delimiter::toggle_macro_delimiter, unmerge_match_arm::unmerge_match_arm, - unmerge_use::unmerge_use, + unmerge_imports::unmerge_imports, unnecessary_async::unnecessary_async, unqualify_method_call::unqualify_method_call, unwrap_block::unwrap_block, diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs b/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs index 0593e6930dca..5e6889792db6 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs @@ -4,6 +4,7 @@ use expect_test::expect; use hir::Semantics; use ide_db::{ EditionedFileId, FileRange, RootDatabase, SnippetCap, + assists::ExprFillDefaultMode, base_db::SourceDatabase, imports::insert_use::{ImportGranularity, InsertUseConfig}, source_change::FileSystemEdit, @@ -35,6 +36,7 @@ pub(crate) const TEST_CONFIG: AssistConfig = AssistConfig { term_search_fuel: 400, term_search_borrowck: true, code_action_grouping: true, + expr_fill_default: ExprFillDefaultMode::Todo, }; pub(crate) const TEST_CONFIG_NO_GROUPING: AssistConfig = AssistConfig { @@ -54,6 +56,7 @@ pub(crate) const TEST_CONFIG_NO_GROUPING: AssistConfig = AssistConfig { term_search_fuel: 400, term_search_borrowck: true, code_action_grouping: false, + expr_fill_default: ExprFillDefaultMode::Todo, }; pub(crate) const TEST_CONFIG_NO_SNIPPET_CAP: AssistConfig = AssistConfig { @@ -73,6 +76,7 @@ pub(crate) const TEST_CONFIG_NO_SNIPPET_CAP: AssistConfig = AssistConfig { term_search_fuel: 400, term_search_borrowck: true, code_action_grouping: true, + expr_fill_default: ExprFillDefaultMode::Todo, }; pub(crate) const TEST_CONFIG_IMPORT_ONE: AssistConfig = AssistConfig { @@ -92,6 +96,7 @@ pub(crate) const TEST_CONFIG_IMPORT_ONE: AssistConfig = AssistConfig { term_search_fuel: 400, term_search_borrowck: true, code_action_grouping: true, + expr_fill_default: ExprFillDefaultMode::Todo, }; pub(crate) fn with_single_file(text: &str) -> (RootDatabase, EditionedFileId) { diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs index 00a9d35c3107..01ab0be34b28 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs @@ -1737,7 +1737,7 @@ fn foo() { bar("", baz()); } -fn bar(arg: &str, baz: Baz) ${0:-> _} { +fn bar(arg: &'static str, baz: Baz) ${0:-> _} { todo!() } @@ -3339,6 +3339,20 @@ sth!{ } ) } +#[test] +fn doctest_unmerge_imports() { + check_doc_test( + "unmerge_imports", + r#####" +use std::fmt::{Debug, Display$0}; +"#####, + r#####" +use std::fmt::{Debug}; +use std::fmt::Display; +"#####, + ) +} + #[test] fn doctest_unmerge_match_arm() { check_doc_test( @@ -3365,20 +3379,6 @@ fn handle(action: Action) { ) } -#[test] -fn doctest_unmerge_use() { - check_doc_test( - "unmerge_use", - r#####" -use std::fmt::{Debug, Display$0}; -"#####, - r#####" -use std::fmt::{Debug}; -use std::fmt::Display; -"#####, - ) -} - #[test] fn doctest_unnecessary_async() { check_doc_test( diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs index 0471998f0b14..ef6914fda1d5 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs @@ -8,6 +8,7 @@ use hir::{ }; use ide_db::{ RootDatabase, + assists::ExprFillDefaultMode, famous_defs::FamousDefs, path_transform::PathTransform, syntax_helpers::{node_ext::preorder_expr, prettify_macro_expansion}, @@ -27,7 +28,10 @@ use syntax::{ ted, }; -use crate::assist_context::{AssistContext, SourceChangeBuilder}; +use crate::{ + AssistConfig, + assist_context::{AssistContext, SourceChangeBuilder}, +}; mod gen_trait_fn_body; pub(crate) mod ref_field_expr; @@ -174,6 +178,7 @@ pub fn filter_assoc_items( /// inserted. pub fn add_trait_assoc_items_to_impl( sema: &Semantics<'_, RootDatabase>, + config: &AssistConfig, original_items: &[InFile], trait_: hir::Trait, impl_: &ast::Impl, @@ -219,7 +224,14 @@ pub fn add_trait_assoc_items_to_impl( match &item { ast::AssocItem::Fn(fn_) if fn_.body().is_none() => { let body = AstNodeEdit::indent( - &make::block_expr(None, Some(make::ext::expr_todo())), + &make::block_expr( + None, + Some(match config.expr_fill_default { + ExprFillDefaultMode::Todo => make::ext::expr_todo(), + ExprFillDefaultMode::Underscore => make::ext::expr_underscore(), + ExprFillDefaultMode::Default => make::ext::expr_todo(), + }), + ), new_indent_level, ); ted::replace(fn_.get_or_create_body().syntax(), body.clone_for_update().syntax()) diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs index ee1a21f9a1a6..7fbd1fbc1af4 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs @@ -363,9 +363,14 @@ pub(crate) fn complete_expr_path( add_keyword("true", "true"); add_keyword("false", "false"); - if in_condition || in_block_expr { - add_keyword("letm", "let mut $0"); - add_keyword("let", "let $0"); + if in_condition { + add_keyword("letm", "let mut $1 = $0"); + add_keyword("let", "let $1 = $0"); + } + + if in_block_expr { + add_keyword("letm", "let mut $1 = $0;"); + add_keyword("let", "let $1 = $0;"); } if after_if_expr { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/keyword.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/keyword.rs index 039742463c81..64bb1fce6ba0 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/keyword.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/keyword.rs @@ -336,7 +336,7 @@ fn main() { } #[test] - fn completes_let_with_space() { + fn completes_let_in_block() { check_edit( "let", r#" @@ -346,7 +346,7 @@ fn main() { "#, r#" fn main() { - let $0 + let $1 = $0; } "#, ); @@ -359,7 +359,97 @@ fn main() { "#, r#" fn main() { - let mut $0 + let mut $1 = $0; +} +"#, + ); + } + + #[test] + fn completes_let_in_condition() { + check_edit( + "let", + r#" +fn main() { + if $0 {} +} +"#, + r#" +fn main() { + if let $1 = $0 {} +} +"#, + ); + check_edit( + "letm", + r#" +fn main() { + if $0 {} +} +"#, + r#" +fn main() { + if let mut $1 = $0 {} +} +"#, + ); + } + + #[test] + fn completes_let_in_no_empty_condition() { + check_edit( + "let", + r#" +fn main() { + if $0x {} +} +"#, + r#" +fn main() { + if let $1 = $0x {} +} +"#, + ); + check_edit( + "letm", + r#" +fn main() { + if $0x {} +} +"#, + r#" +fn main() { + if let mut $1 = $0x {} +} +"#, + ); + } + + #[test] + fn completes_let_in_condition_block() { + check_edit( + "let", + r#" +fn main() { + if { $0 } {} +} +"#, + r#" +fn main() { + if { let $1 = $0; } {} +} +"#, + ); + check_edit( + "letm", + r#" +fn main() { + if { $0 } {} +} +"#, + r#" +fn main() { + if { let mut $1 = $0; } {} } "#, ); diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/lifetime.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/lifetime.rs index b02f079b7213..8902cd09cec0 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/lifetime.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/lifetime.rs @@ -116,13 +116,13 @@ fn foo<'lifetime>(foo: &'a$0) {} check( r#" struct Foo; -impl<'impl> Foo { +impl<'r#impl> Foo { fn foo<'func>(&'a$0 self) {} } "#, expect![[r#" lt 'func - lt 'impl + lt 'r#impl lt 'static "#]], ); diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs index 595997358966..391e2379dcd5 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs @@ -387,11 +387,7 @@ fn expand( match ( sema.expand_macro_call(&actual_macro_call), - sema.speculative_expand_macro_call( - &actual_macro_call, - &speculative_args, - fake_ident_token.clone(), - ), + sema.speculative_expand_macro_call(&actual_macro_call, &speculative_args, fake_ident_token), ) { // successful expansions (Some(actual_expansion), Some((fake_expansion, fake_mapped_tokens))) => { @@ -661,9 +657,8 @@ fn expected_type_and_name( )) } else { cov_mark::hit!(expected_type_struct_field_without_leading_char); - let expr_field = token.prev_sibling_or_token()? - .into_node() - .and_then(ast::RecordExprField::cast)?; + cov_mark::hit!(expected_type_struct_field_followed_by_comma); + let expr_field = previous_non_trivia_token(token.clone())?.parent().and_then(ast::RecordExprField::cast)?; let (_, _, ty) = sema.resolve_record_field(&expr_field)?; Some(( Some(ty), @@ -681,7 +676,6 @@ fn expected_type_and_name( .or_else(|| sema.type_of_expr(&expr).map(TypeInfo::original)); (ty, field_name) } else { - cov_mark::hit!(expected_type_struct_field_followed_by_comma); (field_ty, field_name) } }, diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/item.rs b/src/tools/rust-analyzer/crates/ide-completion/src/item.rs index e208b9fd41ae..19cdef30bd96 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/item.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/item.rs @@ -135,7 +135,7 @@ impl fmt::Debug for CompletionItem { }, CompletionItemRefMode::Dereference => "*", }; - s.field("ref_match", &format!("{}@{offset:?}", prefix)); + s.field("ref_match", &format!("{prefix}@{offset:?}")); } if self.trigger_call_info { s.field("trigger_call_info", &true); diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs index b30ac43bf8fb..d5137949d42f 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs @@ -1517,7 +1517,7 @@ fn main() { en Enum Enum fn function() fn() fn main() fn() - lc variable &str + lc variable &'static str ma helper!(…) macro_rules! helper ma m!(…) macro_rules! m ma makro!(…) macro_rules! makro @@ -2110,3 +2110,19 @@ fn foo() { "#]], ); } + +#[test] +fn escaped_label() { + check( + r#" +fn main() { + 'r#break: { + break '$0; + } +} + "#, + expect![[r#" + lb 'r#break + "#]], + ); +} diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs index 15518e98370e..148203107c4c 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs @@ -1358,7 +1358,7 @@ pub fn foo<'x, T>(x: &'x mut T) -> u8 where T: Clone, { 0u8 } fn main() { fo$0 } "#, CompletionItemKind::SymbolKind(ide_db::SymbolKind::Function), - expect!("fn(&mut T) -> u8"), + expect!("fn(&'x mut T) -> u8"), expect!("pub fn foo<'x, T>(x: &'x mut T) -> u8 where T: Clone,"), ); @@ -1391,7 +1391,7 @@ fn main() { } "#, CompletionItemKind::SymbolKind(SymbolKind::Method), - expect!("const fn(&'foo mut self, &Foo) -> !"), + expect!("const fn(&'foo mut self, &'foo Foo) -> !"), expect!("pub const fn baz<'foo>(&'foo mut self, x: &'foo Foo) -> !"), ); } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/type_pos.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/type_pos.rs index c7e2d058257e..125e11e9e358 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/type_pos.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/type_pos.rs @@ -429,18 +429,18 @@ trait Tr { impl Tr<$0 "#, expect![[r#" - en Enum Enum - ma makro!(…) macro_rules! makro + en Enum Enum + ma makro!(…) macro_rules! makro md module - sp Self dyn Tr<{unknown}> - st Record Record - st S S - st Tuple Tuple - st Unit Unit + sp Self dyn Tr<{unknown}> + 'static + st Record Record + st S S + st Tuple Tuple + st Unit Unit tt Tr tt Trait - un Union Union - bt u32 u32 + un Union Union + bt u32 u32 kw crate:: kw self:: "#]], diff --git a/src/tools/rust-analyzer/crates/ide-db/Cargo.toml b/src/tools/rust-analyzer/crates/ide-db/Cargo.toml index f1d6b605b002..583318de26df 100644 --- a/src/tools/rust-analyzer/crates/ide-db/Cargo.toml +++ b/src/tools/rust-analyzer/crates/ide-db/Cargo.toml @@ -24,6 +24,7 @@ arrayvec.workspace = true indexmap.workspace = true memchr = "2.7.4" salsa.workspace = true +salsa-macros.workspace = true query-group.workspace = true triomphe.workspace = true nohash-hasher.workspace = true diff --git a/src/tools/rust-analyzer/crates/ide-db/src/assists.rs b/src/tools/rust-analyzer/crates/ide-db/src/assists.rs index 90ae4a3b5b3a..384eb57c0fd5 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/assists.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/assists.rs @@ -169,3 +169,15 @@ impl AssistResolveStrategy { #[derive(Clone, Debug)] pub struct GroupLabel(pub String); + +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum ExprFillDefaultMode { + Todo, + Default, + Underscore, +} +impl Default for ExprFillDefaultMode { + fn default() -> Self { + Self::Todo + } +} diff --git a/src/tools/rust-analyzer/crates/ide-db/src/items_locator.rs b/src/tools/rust-analyzer/crates/ide-db/src/items_locator.rs index e9385253250a..4b0a84a559e2 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/items_locator.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/items_locator.rs @@ -86,7 +86,7 @@ pub fn items_with_name_in_module( let local_query = match name { NameToImport::Prefix(exact_name, case_sensitive) | NameToImport::Exact(exact_name, case_sensitive) => { - let mut local_query = symbol_index::Query::new(exact_name.clone()); + let mut local_query = symbol_index::Query::new(exact_name); local_query.assoc_search_mode(assoc_item_search); if prefix { local_query.prefix(); @@ -99,7 +99,7 @@ pub fn items_with_name_in_module( local_query } NameToImport::Fuzzy(fuzzy_search_string, case_sensitive) => { - let mut local_query = symbol_index::Query::new(fuzzy_search_string.clone()); + let mut local_query = symbol_index::Query::new(fuzzy_search_string); local_query.fuzzy(); local_query.assoc_search_mode(assoc_item_search); diff --git a/src/tools/rust-analyzer/crates/ide-db/src/lib.rs b/src/tools/rust-analyzer/crates/ide-db/src/lib.rs index d3934e14abf9..63cc7cde2808 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/lib.rs @@ -76,8 +76,10 @@ pub type FxIndexMap = pub type FilePosition = FilePositionWrapper; pub type FileRange = FileRangeWrapper; -#[salsa::db] +#[salsa_macros::db] pub struct RootDatabase { + // FIXME: Revisit this commit now that we migrated to the new salsa, given we store arcs in this + // db directly now // We use `ManuallyDrop` here because every codegen unit that contains a // `&RootDatabase -> &dyn OtherDatabase` cast will instantiate its drop glue in the vtable, // which duplicates `Weak::drop` and `Arc::drop` tens of thousands of times, which makes @@ -89,7 +91,7 @@ pub struct RootDatabase { impl std::panic::RefUnwindSafe for RootDatabase {} -#[salsa::db] +#[salsa_macros::db] impl salsa::Database for RootDatabase { fn salsa_event(&self, _event: &dyn Fn() -> salsa::Event) {} } @@ -116,7 +118,7 @@ impl fmt::Debug for RootDatabase { } } -#[salsa::db] +#[salsa_macros::db] impl SourceDatabase for RootDatabase { fn file_text(&self, file_id: vfs::FileId) -> FileText { self.files.file_text(file_id) @@ -234,14 +236,6 @@ impl RootDatabase { // ); // hir::db::BodyWithSourceMapQuery.in_db_mut(self).set_lru_capacity(2048); } - - pub fn snapshot(&self) -> Self { - Self { - storage: self.storage.clone(), - files: self.files.clone(), - crates_map: self.crates_map.clone(), - } - } } #[query_group::query_group] diff --git a/src/tools/rust-analyzer/crates/ide-db/src/prime_caches.rs b/src/tools/rust-analyzer/crates/ide-db/src/prime_caches.rs index 17c3f75ce173..cbe31405ab78 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/prime_caches.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/prime_caches.rs @@ -51,6 +51,7 @@ pub fn parallel_prime_caches( enum ParallelPrimeCacheWorkerProgress { BeginCrate { crate_id: Crate, crate_name: Symbol }, EndCrate { crate_id: Crate }, + Cancelled(Cancelled), } // We split off def map computation from other work, @@ -71,27 +72,35 @@ pub fn parallel_prime_caches( progress_sender .send(ParallelPrimeCacheWorkerProgress::BeginCrate { crate_id, crate_name })?; - match kind { + let cancelled = Cancelled::catch(|| match kind { PrimingPhase::DefMap => _ = db.crate_def_map(crate_id), PrimingPhase::ImportMap => _ = db.import_map(crate_id), PrimingPhase::CrateSymbols => _ = db.crate_symbols(crate_id.into()), - } + }); - progress_sender.send(ParallelPrimeCacheWorkerProgress::EndCrate { crate_id })?; + match cancelled { + Ok(()) => progress_sender + .send(ParallelPrimeCacheWorkerProgress::EndCrate { crate_id })?, + Err(cancelled) => progress_sender + .send(ParallelPrimeCacheWorkerProgress::Cancelled(cancelled))?, + } } Ok::<_, crossbeam_channel::SendError<_>>(()) }; for id in 0..num_worker_threads { - let worker = prime_caches_worker.clone(); - let db = db.snapshot(); - - stdx::thread::Builder::new(stdx::thread::ThreadIntent::Worker) - .allow_leak(true) - .name(format!("PrimeCaches#{id}")) - .spawn(move || Cancelled::catch(|| worker(db.snapshot()))) - .expect("failed to spawn thread"); + stdx::thread::Builder::new( + stdx::thread::ThreadIntent::Worker, + format!("PrimeCaches#{id}"), + ) + .allow_leak(true) + .spawn({ + let worker = prime_caches_worker.clone(); + let db = db.clone(); + move || worker(db) + }) + .expect("failed to spawn thread"); } (work_sender, progress_receiver) @@ -142,9 +151,14 @@ pub fn parallel_prime_caches( continue; } Err(crossbeam_channel::RecvTimeoutError::Disconnected) => { - // our workers may have died from a cancelled task, so we'll check and re-raise here. - db.unwind_if_revision_cancelled(); - break; + // all our workers have exited, mark us as finished and exit + cb(ParallelPrimeCachesProgress { + crates_currently_indexing: vec![], + crates_done, + crates_total: crates_done, + work_type: "Indexing", + }); + return; } }; match worker_progress { @@ -156,6 +170,10 @@ pub fn parallel_prime_caches( crates_to_prime.mark_done(crate_id); crates_done += 1; } + ParallelPrimeCacheWorkerProgress::Cancelled(cancelled) => { + // Cancelled::throw should probably be public + std::panic::resume_unwind(Box::new(cancelled)); + } }; let progress = ParallelPrimeCachesProgress { @@ -186,9 +204,14 @@ pub fn parallel_prime_caches( continue; } Err(crossbeam_channel::RecvTimeoutError::Disconnected) => { - // our workers may have died from a cancelled task, so we'll check and re-raise here. - db.unwind_if_revision_cancelled(); - break; + // all our workers have exited, mark us as finished and exit + cb(ParallelPrimeCachesProgress { + crates_currently_indexing: vec![], + crates_done, + crates_total: crates_done, + work_type: "Populating symbols", + }); + return; } }; match worker_progress { @@ -199,6 +222,10 @@ pub fn parallel_prime_caches( crates_currently_indexing.swap_remove(&crate_id); crates_done += 1; } + ParallelPrimeCacheWorkerProgress::Cancelled(cancelled) => { + // Cancelled::throw should probably be public + std::panic::resume_unwind(Box::new(cancelled)); + } }; let progress = ParallelPrimeCachesProgress { diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/expected_function.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/expected_function.rs index af25c2b2e332..a6da0fd9c5e3 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/expected_function.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/expected_function.rs @@ -31,7 +31,7 @@ fn foo() { x(); // ^^^ error: expected function, found i32 ""(); - // ^^^^ error: expected function, found &str + // ^^^^ error: expected function, found &'static str foo(); } "#, diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/invalid_cast.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/invalid_cast.rs index b56255b1fde4..d72b21099ce3 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/invalid_cast.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/invalid_cast.rs @@ -166,7 +166,7 @@ fn main() { let _ = ptr as bool; //^^^^^^^^^^^ error: cannot cast `*const ()` as `bool` let v = "hello" as bool; - //^^^^^^^^^^^^^^^ error: casting `&str` as `bool` is invalid: needs casting through a raw pointer first + //^^^^^^^^^^^^^^^ error: casting `&'static str` as `bool` is invalid: needs casting through a raw pointer first } "#, ); @@ -956,7 +956,7 @@ fn main() { fn main() { let pointer: usize = &1_i32 as *const i32 as usize; let _reference: &'static i32 = unsafe { pointer as *const i32 as &'static i32 }; - //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: non-primitive cast: `*const i32` as `&i32` + //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: non-primitive cast: `*const i32` as `&'static i32` } "#, ); @@ -992,7 +992,7 @@ impl Deref for Foo { fn main() { let _ = "foo" as bool; - //^^^^^^^^^^^^^ error: casting `&str` as `bool` is invalid: needs casting through a raw pointer first + //^^^^^^^^^^^^^ error: casting `&'static str` as `bool` is invalid: needs casting through a raw pointer first let _ = Foo as bool; //^^^^^^^^^^^ error: non-primitive cast: `Foo` as `bool` diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs index 6b02111016c0..a354d123f5ab 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs @@ -5,9 +5,13 @@ use hir::{ sym, }; use ide_db::{ - FxHashMap, assists::Assist, famous_defs::FamousDefs, - imports::import_assets::item_for_path_search, source_change::SourceChange, - syntax_helpers::tree_diff::diff, text_edit::TextEdit, + FxHashMap, + assists::{Assist, ExprFillDefaultMode}, + famous_defs::FamousDefs, + imports::import_assets::item_for_path_search, + source_change::SourceChange, + syntax_helpers::tree_diff::diff, + text_edit::TextEdit, use_trivial_constructor::use_trivial_constructor, }; use stdx::format_to; @@ -102,8 +106,9 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Option make::ext::expr_todo(), - crate::ExprFillDefaultMode::Default => { + ExprFillDefaultMode::Todo => make::ext::expr_todo(), + ExprFillDefaultMode::Underscore => make::ext::expr_underscore(), + ExprFillDefaultMode::Default => { get_default_constructor(ctx, d, ty).unwrap_or_else(make::ext::expr_todo) } }; @@ -158,9 +163,14 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Option, d: &hir::MovedOutOf mod tests { use crate::tests::check_diagnostics; - // FIXME: spans are broken + #[test] + fn operand_field_span_respected() { + check_diagnostics( + r#" +struct NotCopy; +struct S { + field: NotCopy, +} + +fn f(s: &S) -> S { + S { field: s.field } + //^^^^^^^ error: cannot move `NotCopy` out of reference +} + "#, + ); + } #[test] fn move_by_explicit_deref() { @@ -85,7 +100,7 @@ fn consume(_: X) { fn main() { let a = &X(Y); consume(*a); - //^^^^^^^^^^^ error: cannot move `X` out of reference + //^^ error: cannot move `X` out of reference let a = &X(5); consume(*a); } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs index 8f6ed1a7bdbd..500c5de791dc 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs @@ -195,7 +195,7 @@ fn remove_unnecessary_wrapper( let db = ctx.sema.db; let root = db.parse_or_expand(expr_ptr.file_id); let expr = expr_ptr.value.to_node(&root); - let expr = ctx.sema.original_ast_node(expr.clone())?; + let expr = ctx.sema.original_ast_node(expr)?; let Expr::CallExpr(call_expr) = expr else { return None; @@ -306,10 +306,9 @@ fn str_ref_to_owned( acc: &mut Vec, ) -> Option<()> { let expected = d.expected.display(ctx.sema.db, ctx.display_target); - let actual = d.actual.display(ctx.sema.db, ctx.display_target); - // FIXME do this properly - if expected.to_string() != "String" || actual.to_string() != "&str" { + let is_applicable = d.actual.strip_reference().is_str() && expected.to_string() == "String"; + if !is_applicable { return None; } @@ -1176,7 +1175,7 @@ trait B {} fn test(a: &dyn A) -> &dyn B { a - //^ error: expected &dyn B, found &dyn A + //^ error: expected &(dyn B + 'static), found &(dyn A + 'static) } "#, ); diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs index 277aff2e08f4..a933f1b42611 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs @@ -1,3 +1,5 @@ +use std::ops::Not; + use hir::{ ClosureStyle, HirDisplay, ImportPathConfig, db::ExpandDatabase, @@ -60,9 +62,13 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::TypedHole) -> Option let mut formatter = |_: &hir::Type| String::from("_"); - let assists: Vec = paths + let assists: Vec = d + .expected + .is_unknown() + .not() + .then(|| "todo!()".to_owned()) .into_iter() - .filter_map(|path| { + .chain(paths.into_iter().filter_map(|path| { path.gen_source_code( &scope, &mut formatter, @@ -75,7 +81,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::TypedHole) -> Option ctx.display_target, ) .ok() - }) + })) .unique() .map(|code| Assist { id: AssistId::quick_fix("typed-hole"), @@ -95,9 +101,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::TypedHole) -> Option #[cfg(test)] mod tests { - use crate::tests::{ - check_diagnostics, check_fixes_unordered, check_has_fix, check_has_single_fix, - }; + use crate::tests::{check_diagnostics, check_fixes_unordered, check_has_fix}; #[test] fn unknown() { @@ -119,9 +123,9 @@ fn main() { if _ {} //^ 💡 error: invalid `_` expression, expected type `bool` let _: fn() -> i32 = _; - //^ error: invalid `_` expression, expected type `fn() -> i32` + //^ 💡 error: invalid `_` expression, expected type `fn() -> i32` let _: fn() -> () = _; // FIXME: This should trigger an assist because `main` matches via *coercion* - //^ error: invalid `_` expression, expected type `fn()` + //^ 💡 error: invalid `_` expression, expected type `fn()` } "#, ); @@ -147,7 +151,7 @@ fn main() { fn main() { let mut x = t(); x = _; - //^ error: invalid `_` expression, expected type `&str` + //^ 💡 error: invalid `_` expression, expected type `&'static str` x = ""; } fn t() -> T { loop {} } @@ -308,7 +312,7 @@ fn main() { #[test] fn ignore_impl_func_with_incorrect_return() { - check_has_single_fix( + check_fixes_unordered( r#" struct Bar {} trait Foo { @@ -323,7 +327,8 @@ fn main() { let a: i32 = 1; let c: Bar = _$0; }"#, - r#" + vec![ + r#" struct Bar {} trait Foo { type Res; @@ -337,6 +342,21 @@ fn main() { let a: i32 = 1; let c: Bar = Bar { }; }"#, + r#" +struct Bar {} +trait Foo { + type Res; + fn foo(&self) -> Self::Res; +} +impl Foo for i32 { + type Res = Self; + fn foo(&self) -> Self::Res { 1 } +} +fn main() { + let a: i32 = 1; + let c: Bar = todo!(); +}"#, + ], ); } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs index 4422d8f8262f..7f07009dc561 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs @@ -269,7 +269,7 @@ impl A { } fn main() { let a = A {a: 0, b: ""}; - A::::foo(); + A::::foo(); } "#, ); diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs index 11efedd8a59d..607721d611d7 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs @@ -92,7 +92,7 @@ use hir::{ }; use ide_db::{ EditionedFileId, FileId, FileRange, FxHashMap, FxHashSet, RootDatabase, Severity, SnippetCap, - assists::{Assist, AssistId, AssistResolveStrategy}, + assists::{Assist, AssistId, AssistResolveStrategy, ExprFillDefaultMode}, base_db::{ReleaseChannel, RootQueryDb as _}, generated::lints::{CLIPPY_LINT_GROUPS, DEFAULT_LINT_GROUPS, DEFAULT_LINTS, Lint, LintGroup}, imports::insert_use::InsertUseConfig, @@ -219,17 +219,6 @@ impl Diagnostic { } } -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum ExprFillDefaultMode { - Todo, - Default, -} -impl Default for ExprFillDefaultMode { - fn default() -> Self { - Self::Todo - } -} - #[derive(Debug, Clone)] pub struct DiagnosticsConfig { /// Whether native diagnostics are enabled. diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs index 13d08d46dedd..4e4bd47e1c2f 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs @@ -3,14 +3,16 @@ mod overly_long_real_world_cases; use ide_db::{ - LineIndexDatabase, RootDatabase, assists::AssistResolveStrategy, base_db::SourceDatabase, + LineIndexDatabase, RootDatabase, + assists::{AssistResolveStrategy, ExprFillDefaultMode}, + base_db::SourceDatabase, }; use itertools::Itertools; use stdx::trim_indent; use test_fixture::WithFixture; use test_utils::{MiniCore, assert_eq_text, extract_annotations}; -use crate::{DiagnosticsConfig, ExprFillDefaultMode, Severity}; +use crate::{DiagnosticsConfig, Severity}; /// Takes a multi-file input fixture with annotated cursor positions, /// and checks that: @@ -160,55 +162,6 @@ pub(crate) fn check_has_fix( assert!(fix.is_some(), "no diagnostic with desired fix"); } -#[track_caller] -pub(crate) fn check_has_single_fix( - #[rust_analyzer::rust_fixture] ra_fixture_before: &str, - #[rust_analyzer::rust_fixture] ra_fixture_after: &str, -) { - let after = trim_indent(ra_fixture_after); - - let (db, file_position) = RootDatabase::with_position(ra_fixture_before); - let mut conf = DiagnosticsConfig::test_sample(); - conf.expr_fill_default = ExprFillDefaultMode::Default; - let mut n_fixes = 0; - let fix = super::full_diagnostics( - &db, - &conf, - &AssistResolveStrategy::All, - file_position.file_id.file_id(&db), - ) - .into_iter() - .find(|d| { - d.fixes - .as_ref() - .and_then(|fixes| { - n_fixes += fixes.len(); - fixes.iter().find(|fix| { - if !fix.target.contains_inclusive(file_position.offset) { - return false; - } - let actual = { - let source_change = fix.source_change.as_ref().unwrap(); - let file_id = *source_change.source_file_edits.keys().next().unwrap(); - let mut actual = db.file_text(file_id).text(&db).to_string(); - - for (edit, snippet_edit) in source_change.source_file_edits.values() { - edit.apply(&mut actual); - if let Some(snippet_edit) = snippet_edit { - snippet_edit.apply(&mut actual); - } - } - actual - }; - after == actual - }) - }) - .is_some() - }); - assert!(fix.is_some(), "no diagnostic with desired fix"); - assert!(n_fixes == 1, "Too many fixes suggested"); -} - /// Checks that there's a diagnostic *without* fix at `$0`. pub(crate) fn check_no_fix(#[rust_analyzer::rust_fixture] ra_fixture: &str) { let (db, file_position) = RootDatabase::with_position(ra_fixture); diff --git a/src/tools/rust-analyzer/crates/ide/src/doc_links.rs b/src/tools/rust-analyzer/crates/ide/src/doc_links.rs index ebbd68bcdf74..f0247f32d7ec 100644 --- a/src/tools/rust-analyzer/crates/ide/src/doc_links.rs +++ b/src/tools/rust-analyzer/crates/ide/src/doc_links.rs @@ -599,7 +599,7 @@ fn filename_and_frag_for_def( Some(name) => { match m.attrs(db).by_key(sym::doc).find_string_value_in_tt(sym::keyword) { Some(kw) => { - format!("keyword.{}.html", kw) + format!("keyword.{kw}.html") } None => format!("{}/index.html", name.as_str()), } diff --git a/src/tools/rust-analyzer/crates/ide/src/hover.rs b/src/tools/rust-analyzer/crates/ide/src/hover.rs index 2f2d2252f844..075afcec019f 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover.rs @@ -634,9 +634,7 @@ fn walk_and_push_ty( } else if let Some(trait_) = t.as_associated_type_parent_trait(db) { push_new_def(trait_.into()); } else if let Some(tp) = t.as_type_param(db) { - let sized_trait = db - .lang_item(t.krate(db).into(), LangItem::Sized) - .and_then(|lang_item| lang_item.as_trait()); + let sized_trait = LangItem::Sized.resolve_trait(db, t.krate(db).into()); tp.trait_bounds(db) .into_iter() .filter(|&it| Some(it.into()) != sized_trait) diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs index d469cd7c0cd5..7b7eef9d5793 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs @@ -7085,9 +7085,9 @@ fn foo() { } "#, expect![[r#" - ```rust - &str - ```"#]], + ```rust + &'static str + ```"#]], ); } @@ -8228,7 +8228,7 @@ format_args!("{aaaaa$0}"); *aaaaa* ```rust - let aaaaa: &str + let aaaaa: &'static str ``` "#]], ); @@ -8248,7 +8248,7 @@ format_args!("{$0aaaaa}"); *aaaaa* ```rust - let aaaaa: &str + let aaaaa: &'static str ``` "#]], ); @@ -8268,7 +8268,7 @@ format_args!(r"{$0aaaaa}"); *aaaaa* ```rust - let aaaaa: &str + let aaaaa: &'static str ``` "#]], ); @@ -8293,7 +8293,7 @@ foo!(r"{$0aaaaa}"); *aaaaa* ```rust - let aaaaa: &str + let aaaaa: &'static str ``` "#]], ); @@ -8337,7 +8337,7 @@ fn main() { expect![[r#" *"🦀\u{1f980}\\\x41"* ```rust - &str + &'static str ``` ___ @@ -8353,7 +8353,7 @@ fn main() { expect![[r#" *r"🦀\u{1f980}\\\x41"* ```rust - &str + &'static str ``` ___ @@ -8375,7 +8375,7 @@ fsdghs"; fsdghs"* ```rust - &str + &'static str ``` ___ @@ -8395,7 +8395,7 @@ fn main() { expect![[r#" *c"🦀\u{1f980}\\\x41"* ```rust - &{unknown} + &'static {unknown} ``` ___ @@ -8414,7 +8414,7 @@ fn main() { expect![[r#" *r"`[^`]*`"* ```rust - &str + &'static str ``` ___ @@ -8429,7 +8429,7 @@ fn main() { expect![[r#" *r"`"* ```rust - &str + &'static str ``` ___ @@ -8444,7 +8444,7 @@ fn main() { expect![[r#" *r" "* ```rust - &str + &'static str ``` ___ @@ -8460,12 +8460,12 @@ fn main() { expect![[r#" *r" Hello World "* ```rust - &str + &'static str ``` ___ value of literal: ` Hello World ` -"#]], + "#]], ) } @@ -8480,7 +8480,7 @@ fn main() { expect![[r#" *b"\xF0\x9F\xA6\x80\\"* ```rust - &[u8; 5] + &'static [u8; 5] ``` ___ @@ -8496,7 +8496,7 @@ fn main() { expect![[r#" *br"\xF0\x9F\xA6\x80\\"* ```rust - &[u8; 18] + &'static [u8; 18] ``` ___ @@ -9070,7 +9070,7 @@ struct Pedro$0<'a> { ```rust struct Pedro<'a> { - hola: &str, + hola: &'a str, } ``` @@ -9937,7 +9937,7 @@ fn baz() { --- - `U` = `i32`, `T` = `&str` + `U` = `i32`, `T` = `&'static str` "#]], ); } @@ -10030,7 +10030,7 @@ fn bar() { --- - `T` = `i8`, `U` = `&str` + `T` = `i8`, `U` = `&'static str` "#]], ); } diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs index 52ea2e5ec58b..36fdd90e8aea 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs @@ -380,9 +380,9 @@ fn main() { let foo = foo3(); // ^^^ impl Fn(f64, f64) -> u32 let foo = foo4(); - // ^^^ &dyn Fn(f64, f64) -> u32 + // ^^^ &'static (dyn Fn(f64, f64) -> u32 + 'static) let foo = foo5(); - // ^^^ &dyn Fn(&dyn Fn(f64, f64) -> u32, f64) -> u32 + // ^^^ &'static (dyn Fn(&(dyn Fn(f64, f64) -> u32 + 'static), f64) -> u32 + 'static) let foo = foo6(); // ^^^ impl Fn(f64, f64) -> u32 let foo = foo7(); @@ -413,7 +413,7 @@ fn main() { let foo = foo3(); // ^^^ impl Fn(f64, f64) -> u32 let foo = foo4(); - // ^^^ &dyn Fn(f64, f64) -> u32 + // ^^^ &'static (dyn Fn(f64, f64) -> u32 + 'static) let foo = foo5(); let foo = foo6(); let foo = foo7(); @@ -528,7 +528,7 @@ fn main() { //^^^^ i32 let _ = 22; let test = "test"; - //^^^^ &str + //^^^^ &'static str let test = InnerStruct {}; //^^^^ InnerStruct @@ -618,12 +618,12 @@ impl Iterator for IntoIter { fn main() { let mut data = Vec::new(); - //^^^^ Vec<&str> + //^^^^ Vec<&'static str> data.push("foo"); for i in data { - //^ &str + //^ &'static str let z = i; - //^ &str + //^ &'static str } } "#, @@ -651,8 +651,8 @@ fn main() { //^^ Vec> let _v = { Vec::>::new() }; //^^ Vec> - let _v = { Vec::>::new() }; - //^^ Vec> + let _v = { Vec::>::new() }; + //^^ Vec> } "#, ); @@ -1017,7 +1017,7 @@ fn test(t: T) { "#, expect![[r#" fn test(t: T) { - let f = |a: i32, b: &str, c: T| {}; + let f = |a: i32, b: &'static str, c: T| {}; let result: () = f(42, "", t); } "#]], diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs index de9ca8c000f0..2ec85da4a429 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs @@ -194,7 +194,7 @@ impl Tr for () { //^ impl Tr for () impl dyn Tr { } -//^ impl dyn Tr +//^ impl dyn Tr + 'static static S0: () = 0; static S1: () = {}; diff --git a/src/tools/rust-analyzer/crates/ide/src/lib.rs b/src/tools/rust-analyzer/crates/ide/src/lib.rs index a13be6c4927f..aa525a86123d 100644 --- a/src/tools/rust-analyzer/crates/ide/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide/src/lib.rs @@ -123,9 +123,9 @@ pub use ide_completion::{ CallableSnippets, CompletionConfig, CompletionFieldsToResolve, CompletionItem, CompletionItemKind, CompletionItemRefMode, CompletionRelevance, Snippet, SnippetScope, }; -pub use ide_db::text_edit::{Indel, TextEdit}; pub use ide_db::{ FileId, FilePosition, FileRange, RootDatabase, Severity, SymbolKind, + assists::ExprFillDefaultMode, base_db::{Crate, CrateGraphBuilder, FileChange, SourceRoot, SourceRootId}, documentation::Documentation, label::Label, @@ -134,8 +134,9 @@ pub use ide_db::{ search::{ReferenceCategory, SearchScope}, source_change::{FileSystemEdit, SnippetEdit, SourceChange}, symbol_index::Query, + text_edit::{Indel, TextEdit}, }; -pub use ide_diagnostics::{Diagnostic, DiagnosticCode, DiagnosticsConfig, ExprFillDefaultMode}; +pub use ide_diagnostics::{Diagnostic, DiagnosticCode, DiagnosticsConfig}; pub use ide_ssr::SsrError; pub use span::Edition; pub use syntax::{TextRange, TextSize}; @@ -181,7 +182,7 @@ impl AnalysisHost { /// Returns a snapshot of the current state, which you can query for /// semantic information. pub fn analysis(&self) -> Analysis { - Analysis { db: self.db.snapshot() } + Analysis { db: self.db.clone() } } /// Applies changes to the current state of the world. If there are @@ -863,7 +864,7 @@ impl Analysis { where F: FnOnce(&RootDatabase) -> T + std::panic::UnwindSafe, { - let snap = self.db.snapshot(); + let snap = self.db.clone(); Cancelled::catch(|| f(&snap)) } } diff --git a/src/tools/rust-analyzer/crates/ide/src/moniker.rs b/src/tools/rust-analyzer/crates/ide/src/moniker.rs index 4a06cd919fc3..795c1f2ca3c0 100644 --- a/src/tools/rust-analyzer/crates/ide/src/moniker.rs +++ b/src/tools/rust-analyzer/crates/ide/src/moniker.rs @@ -451,7 +451,7 @@ mod tests { assert_eq!(x.len(), 1); match x.into_iter().next().unwrap() { MonikerResult::Local { enclosing_moniker } => { - panic!("Unexpected local enclosed in {:?}", enclosing_moniker); + panic!("Unexpected local enclosed in {enclosing_moniker:?}"); } MonikerResult::Moniker(x) => { assert_eq!(identifier, x.identifier.to_string()); diff --git a/src/tools/rust-analyzer/crates/ide/src/status.rs b/src/tools/rust-analyzer/crates/ide/src/status.rs index 55a0db2d8204..cfcd76d2aa3b 100644 --- a/src/tools/rust-analyzer/crates/ide/src/status.rs +++ b/src/tools/rust-analyzer/crates/ide/src/status.rs @@ -51,8 +51,8 @@ pub(crate) fn status(db: &RootDatabase, file_id: Option) -> String { buf, "Crate: {}\n", match display_name { - Some(it) => format!("{it}({:?})", crate_id), - None => format!("{:?}", crate_id), + Some(it) => format!("{it}({crate_id:?})"), + None => format!("{crate_id:?}"), } ); format_to!(buf, " Root module file id: {}\n", root_file_id.index()); diff --git a/src/tools/rust-analyzer/crates/ide/src/view_crate_graph.rs b/src/tools/rust-analyzer/crates/ide/src/view_crate_graph.rs index 4696fef3209a..7985279679c4 100644 --- a/src/tools/rust-analyzer/crates/ide/src/view_crate_graph.rs +++ b/src/tools/rust-analyzer/crates/ide/src/view_crate_graph.rs @@ -80,7 +80,7 @@ impl<'a> dot::Labeller<'a, Crate, Edge<'a>> for DotCrateGraph<'_> { fn node_id(&'a self, n: &Crate) -> Id<'a> { let id = n.as_id().as_u32(); - Id::new(format!("_{:?}", id)).unwrap() + Id::new(format!("_{id:?}")).unwrap() } fn node_shape(&'a self, _node: &Crate) -> Option> { diff --git a/src/tools/rust-analyzer/crates/intern/src/symbol.rs b/src/tools/rust-analyzer/crates/intern/src/symbol.rs index 89c3be96fcb9..8b2d6e8717d2 100644 --- a/src/tools/rust-analyzer/crates/intern/src/symbol.rs +++ b/src/tools/rust-analyzer/crates/intern/src/symbol.rs @@ -163,28 +163,28 @@ impl Symbol { pub fn integer(i: usize) -> Self { match i { - 0 => symbols::INTEGER_0.clone(), - 1 => symbols::INTEGER_1.clone(), - 2 => symbols::INTEGER_2.clone(), - 3 => symbols::INTEGER_3.clone(), - 4 => symbols::INTEGER_4.clone(), - 5 => symbols::INTEGER_5.clone(), - 6 => symbols::INTEGER_6.clone(), - 7 => symbols::INTEGER_7.clone(), - 8 => symbols::INTEGER_8.clone(), - 9 => symbols::INTEGER_9.clone(), - 10 => symbols::INTEGER_10.clone(), - 11 => symbols::INTEGER_11.clone(), - 12 => symbols::INTEGER_12.clone(), - 13 => symbols::INTEGER_13.clone(), - 14 => symbols::INTEGER_14.clone(), - 15 => symbols::INTEGER_15.clone(), + 0 => symbols::INTEGER_0, + 1 => symbols::INTEGER_1, + 2 => symbols::INTEGER_2, + 3 => symbols::INTEGER_3, + 4 => symbols::INTEGER_4, + 5 => symbols::INTEGER_5, + 6 => symbols::INTEGER_6, + 7 => symbols::INTEGER_7, + 8 => symbols::INTEGER_8, + 9 => symbols::INTEGER_9, + 10 => symbols::INTEGER_10, + 11 => symbols::INTEGER_11, + 12 => symbols::INTEGER_12, + 13 => symbols::INTEGER_13, + 14 => symbols::INTEGER_14, + 15 => symbols::INTEGER_15, i => Symbol::intern(&format!("{i}")), } } pub fn empty() -> Self { - symbols::__empty.clone() + symbols::__empty } #[inline] diff --git a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs index 3e52dbaea654..2686a75c7c86 100644 --- a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs +++ b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs @@ -292,7 +292,7 @@ impl ProjectFolders { }; let file_set_roots = vec![VfsPath::from(ratoml_path.to_owned())]; - let entry = vfs::loader::Entry::Files(vec![ratoml_path.to_owned()]); + let entry = vfs::loader::Entry::Files(vec![ratoml_path]); res.watch.push(res.load.len()); res.load.push(entry); diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs index 34dcf2a18229..0ac25da32941 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs @@ -4,7 +4,7 @@ use crate::grammar::attributes::ATTRIBUTE_FIRST; use super::*; -pub(super) use atom::{LITERAL_FIRST, literal}; +pub(super) use atom::{EXPR_RECOVERY_SET, LITERAL_FIRST, literal}; pub(crate) use atom::{block_expr, match_arm_list}; #[derive(PartialEq, Eq)] diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs index c66afed91c51..5faf6fc2759e 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs @@ -46,7 +46,6 @@ pub(super) const ATOM_EXPR_FIRST: TokenSet = T!['['], T![|], T![async], - T![box], T![break], T![const], T![continue], @@ -68,7 +67,8 @@ pub(super) const ATOM_EXPR_FIRST: TokenSet = LIFETIME_IDENT, ])); -pub(super) const EXPR_RECOVERY_SET: TokenSet = TokenSet::new(&[T![')'], T![']']]); +pub(in crate::grammar) const EXPR_RECOVERY_SET: TokenSet = + TokenSet::new(&[T!['}'], T![')'], T![']'], T![,]]); pub(super) fn atom_expr( p: &mut Parser<'_>, diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/items.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/items.rs index f5f003be4891..b9f4866574a6 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/items.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/items.rs @@ -32,6 +32,9 @@ pub(super) const ITEM_RECOVERY_SET: TokenSet = TokenSet::new(&[ T![impl], T![trait], T![const], + T![async], + T![unsafe], + T![extern], T![static], T![let], T![mod], diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/paths.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/paths.rs index 3410505cd46d..770827c6b0d4 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/paths.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/paths.rs @@ -81,7 +81,7 @@ fn path_for_qualifier( } const EXPR_PATH_SEGMENT_RECOVERY_SET: TokenSet = - items::ITEM_RECOVERY_SET.union(TokenSet::new(&[T![')'], T![,], T![let]])); + expressions::EXPR_RECOVERY_SET.union(items::ITEM_RECOVERY_SET); const TYPE_PATH_SEGMENT_RECOVERY_SET: TokenSet = types::TYPE_RECOVERY_SET; fn path_segment(p: &mut Parser<'_>, mode: Mode, first: bool) -> Option { diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/patterns.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/patterns.rs index 460051a0f4a5..4dd44c030f30 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/patterns.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/patterns.rs @@ -199,8 +199,19 @@ fn pattern_single_r(p: &mut Parser<'_>, recovery_set: TokenSet) { } } -const PAT_RECOVERY_SET: TokenSet = - TokenSet::new(&[T![let], T![if], T![while], T![loop], T![match], T![')'], T![,], T![=]]); +const PAT_RECOVERY_SET: TokenSet = TokenSet::new(&[ + T![let], + T![if], + T![while], + T![loop], + T![match], + T![')'], + T![']'], + T!['}'], + T![,], + T![=], + T![&], +]); fn atom_pat(p: &mut Parser<'_>, recovery_set: TokenSet) -> Option { let m = match p.current() { diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/types.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/types.rs index 0133b7d5d820..9d31e435cf98 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/types.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/types.rs @@ -20,10 +20,15 @@ pub(super) const TYPE_FIRST: TokenSet = paths::PATH_FIRST.union(TokenSet::new(&[ pub(super) const TYPE_RECOVERY_SET: TokenSet = TokenSet::new(&[ T![')'], + // test_err type_in_array_recover + // const _: [&]; + T![']'], + T!['}'], T![>], T![,], // test_err struct_field_recover // struct S { f pub g: () } + // struct S { f: pub g: () } T![pub], ]); diff --git a/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs b/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs index 585e7ffb1aef..0a5c16dc4c49 100644 --- a/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs +++ b/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs @@ -179,6 +179,15 @@ impl<'a> Converter<'a> { COMMENT } + rustc_lexer::TokenKind::Frontmatter { has_invalid_preceding_whitespace, invalid_infostring } => { + if *has_invalid_preceding_whitespace { + err = "invalid preceding whitespace for frontmatter opening" + } else if *invalid_infostring { + err = "invalid infostring for frontmatter" + } + FRONTMATTER + } + rustc_lexer::TokenKind::Whitespace => WHITESPACE, rustc_lexer::TokenKind::Ident if token_text == "_" => UNDERSCORE, diff --git a/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs b/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs index e6f93a1fbda5..b1727509b137 100644 --- a/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs +++ b/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs @@ -150,6 +150,7 @@ pub enum SyntaxKind { STRING, COMMENT, ERROR, + FRONTMATTER, IDENT, LIFETIME_IDENT, NEWLINE, @@ -483,6 +484,7 @@ impl SyntaxKind { | YIELD_EXPR | COMMENT | ERROR + | FRONTMATTER | IDENT | LIFETIME_IDENT | NEWLINE @@ -994,7 +996,7 @@ impl SyntaxKind { } } #[macro_export] -macro_rules ! T_ { [$] => { $ crate :: SyntaxKind :: DOLLAR } ; [;] => { $ crate :: SyntaxKind :: SEMICOLON } ; [,] => { $ crate :: SyntaxKind :: COMMA } ; ['('] => { $ crate :: SyntaxKind :: L_PAREN } ; [')'] => { $ crate :: SyntaxKind :: R_PAREN } ; ['{'] => { $ crate :: SyntaxKind :: L_CURLY } ; ['}'] => { $ crate :: SyntaxKind :: R_CURLY } ; ['['] => { $ crate :: SyntaxKind :: L_BRACK } ; [']'] => { $ crate :: SyntaxKind :: R_BRACK } ; [<] => { $ crate :: SyntaxKind :: L_ANGLE } ; [>] => { $ crate :: SyntaxKind :: R_ANGLE } ; [@] => { $ crate :: SyntaxKind :: AT } ; [#] => { $ crate :: SyntaxKind :: POUND } ; [~] => { $ crate :: SyntaxKind :: TILDE } ; [?] => { $ crate :: SyntaxKind :: QUESTION } ; [&] => { $ crate :: SyntaxKind :: AMP } ; [|] => { $ crate :: SyntaxKind :: PIPE } ; [+] => { $ crate :: SyntaxKind :: PLUS } ; [*] => { $ crate :: SyntaxKind :: STAR } ; [/] => { $ crate :: SyntaxKind :: SLASH } ; [^] => { $ crate :: SyntaxKind :: CARET } ; [%] => { $ crate :: SyntaxKind :: PERCENT } ; [_] => { $ crate :: SyntaxKind :: UNDERSCORE } ; [.] => { $ crate :: SyntaxKind :: DOT } ; [..] => { $ crate :: SyntaxKind :: DOT2 } ; [...] => { $ crate :: SyntaxKind :: DOT3 } ; [..=] => { $ crate :: SyntaxKind :: DOT2EQ } ; [:] => { $ crate :: SyntaxKind :: COLON } ; [::] => { $ crate :: SyntaxKind :: COLON2 } ; [=] => { $ crate :: SyntaxKind :: EQ } ; [==] => { $ crate :: SyntaxKind :: EQ2 } ; [=>] => { $ crate :: SyntaxKind :: FAT_ARROW } ; [!] => { $ crate :: SyntaxKind :: BANG } ; [!=] => { $ crate :: SyntaxKind :: NEQ } ; [-] => { $ crate :: SyntaxKind :: MINUS } ; [->] => { $ crate :: SyntaxKind :: THIN_ARROW } ; [<=] => { $ crate :: SyntaxKind :: LTEQ } ; [>=] => { $ crate :: SyntaxKind :: GTEQ } ; [+=] => { $ crate :: SyntaxKind :: PLUSEQ } ; [-=] => { $ crate :: SyntaxKind :: MINUSEQ } ; [|=] => { $ crate :: SyntaxKind :: PIPEEQ } ; [&=] => { $ crate :: SyntaxKind :: AMPEQ } ; [^=] => { $ crate :: SyntaxKind :: CARETEQ } ; [/=] => { $ crate :: SyntaxKind :: SLASHEQ } ; [*=] => { $ crate :: SyntaxKind :: STAREQ } ; [%=] => { $ crate :: SyntaxKind :: PERCENTEQ } ; [&&] => { $ crate :: SyntaxKind :: AMP2 } ; [||] => { $ crate :: SyntaxKind :: PIPE2 } ; [<<] => { $ crate :: SyntaxKind :: SHL } ; [>>] => { $ crate :: SyntaxKind :: SHR } ; [<<=] => { $ crate :: SyntaxKind :: SHLEQ } ; [>>=] => { $ crate :: SyntaxKind :: SHREQ } ; [Self] => { $ crate :: SyntaxKind :: SELF_TYPE_KW } ; [abstract] => { $ crate :: SyntaxKind :: ABSTRACT_KW } ; [as] => { $ crate :: SyntaxKind :: AS_KW } ; [become] => { $ crate :: SyntaxKind :: BECOME_KW } ; [box] => { $ crate :: SyntaxKind :: BOX_KW } ; [break] => { $ crate :: SyntaxKind :: BREAK_KW } ; [const] => { $ crate :: SyntaxKind :: CONST_KW } ; [continue] => { $ crate :: SyntaxKind :: CONTINUE_KW } ; [crate] => { $ crate :: SyntaxKind :: CRATE_KW } ; [do] => { $ crate :: SyntaxKind :: DO_KW } ; [else] => { $ crate :: SyntaxKind :: ELSE_KW } ; [enum] => { $ crate :: SyntaxKind :: ENUM_KW } ; [extern] => { $ crate :: SyntaxKind :: EXTERN_KW } ; [false] => { $ crate :: SyntaxKind :: FALSE_KW } ; [final] => { $ crate :: SyntaxKind :: FINAL_KW } ; [fn] => { $ crate :: SyntaxKind :: FN_KW } ; [for] => { $ crate :: SyntaxKind :: FOR_KW } ; [if] => { $ crate :: SyntaxKind :: IF_KW } ; [impl] => { $ crate :: SyntaxKind :: IMPL_KW } ; [in] => { $ crate :: SyntaxKind :: IN_KW } ; [let] => { $ crate :: SyntaxKind :: LET_KW } ; [loop] => { $ crate :: SyntaxKind :: LOOP_KW } ; [macro] => { $ crate :: SyntaxKind :: MACRO_KW } ; [match] => { $ crate :: SyntaxKind :: MATCH_KW } ; [mod] => { $ crate :: SyntaxKind :: MOD_KW } ; [move] => { $ crate :: SyntaxKind :: MOVE_KW } ; [mut] => { $ crate :: SyntaxKind :: MUT_KW } ; [override] => { $ crate :: SyntaxKind :: OVERRIDE_KW } ; [priv] => { $ crate :: SyntaxKind :: PRIV_KW } ; [pub] => { $ crate :: SyntaxKind :: PUB_KW } ; [ref] => { $ crate :: SyntaxKind :: REF_KW } ; [return] => { $ crate :: SyntaxKind :: RETURN_KW } ; [self] => { $ crate :: SyntaxKind :: SELF_KW } ; [static] => { $ crate :: SyntaxKind :: STATIC_KW } ; [struct] => { $ crate :: SyntaxKind :: STRUCT_KW } ; [super] => { $ crate :: SyntaxKind :: SUPER_KW } ; [trait] => { $ crate :: SyntaxKind :: TRAIT_KW } ; [true] => { $ crate :: SyntaxKind :: TRUE_KW } ; [type] => { $ crate :: SyntaxKind :: TYPE_KW } ; [typeof] => { $ crate :: SyntaxKind :: TYPEOF_KW } ; [unsafe] => { $ crate :: SyntaxKind :: UNSAFE_KW } ; [unsized] => { $ crate :: SyntaxKind :: UNSIZED_KW } ; [use] => { $ crate :: SyntaxKind :: USE_KW } ; [virtual] => { $ crate :: SyntaxKind :: VIRTUAL_KW } ; [where] => { $ crate :: SyntaxKind :: WHERE_KW } ; [while] => { $ crate :: SyntaxKind :: WHILE_KW } ; [yield] => { $ crate :: SyntaxKind :: YIELD_KW } ; [asm] => { $ crate :: SyntaxKind :: ASM_KW } ; [att_syntax] => { $ crate :: SyntaxKind :: ATT_SYNTAX_KW } ; [auto] => { $ crate :: SyntaxKind :: AUTO_KW } ; [builtin] => { $ crate :: SyntaxKind :: BUILTIN_KW } ; [clobber_abi] => { $ crate :: SyntaxKind :: CLOBBER_ABI_KW } ; [default] => { $ crate :: SyntaxKind :: DEFAULT_KW } ; [dyn] => { $ crate :: SyntaxKind :: DYN_KW } ; [format_args] => { $ crate :: SyntaxKind :: FORMAT_ARGS_KW } ; [inlateout] => { $ crate :: SyntaxKind :: INLATEOUT_KW } ; [inout] => { $ crate :: SyntaxKind :: INOUT_KW } ; [label] => { $ crate :: SyntaxKind :: LABEL_KW } ; [lateout] => { $ crate :: SyntaxKind :: LATEOUT_KW } ; [macro_rules] => { $ crate :: SyntaxKind :: MACRO_RULES_KW } ; [may_unwind] => { $ crate :: SyntaxKind :: MAY_UNWIND_KW } ; [nomem] => { $ crate :: SyntaxKind :: NOMEM_KW } ; [noreturn] => { $ crate :: SyntaxKind :: NORETURN_KW } ; [nostack] => { $ crate :: SyntaxKind :: NOSTACK_KW } ; [offset_of] => { $ crate :: SyntaxKind :: OFFSET_OF_KW } ; [options] => { $ crate :: SyntaxKind :: OPTIONS_KW } ; [out] => { $ crate :: SyntaxKind :: OUT_KW } ; [preserves_flags] => { $ crate :: SyntaxKind :: PRESERVES_FLAGS_KW } ; [pure] => { $ crate :: SyntaxKind :: PURE_KW } ; [raw] => { $ crate :: SyntaxKind :: RAW_KW } ; [readonly] => { $ crate :: SyntaxKind :: READONLY_KW } ; [safe] => { $ crate :: SyntaxKind :: SAFE_KW } ; [sym] => { $ crate :: SyntaxKind :: SYM_KW } ; [union] => { $ crate :: SyntaxKind :: UNION_KW } ; [yeet] => { $ crate :: SyntaxKind :: YEET_KW } ; [async] => { $ crate :: SyntaxKind :: ASYNC_KW } ; [await] => { $ crate :: SyntaxKind :: AWAIT_KW } ; [dyn] => { $ crate :: SyntaxKind :: DYN_KW } ; [gen] => { $ crate :: SyntaxKind :: GEN_KW } ; [try] => { $ crate :: SyntaxKind :: TRY_KW } ; [lifetime_ident] => { $ crate :: SyntaxKind :: LIFETIME_IDENT } ; [int_number] => { $ crate :: SyntaxKind :: INT_NUMBER } ; [ident] => { $ crate :: SyntaxKind :: IDENT } ; [string] => { $ crate :: SyntaxKind :: STRING } ; [shebang] => { $ crate :: SyntaxKind :: SHEBANG } ; } +macro_rules ! T_ { [$] => { $ crate :: SyntaxKind :: DOLLAR } ; [;] => { $ crate :: SyntaxKind :: SEMICOLON } ; [,] => { $ crate :: SyntaxKind :: COMMA } ; ['('] => { $ crate :: SyntaxKind :: L_PAREN } ; [')'] => { $ crate :: SyntaxKind :: R_PAREN } ; ['{'] => { $ crate :: SyntaxKind :: L_CURLY } ; ['}'] => { $ crate :: SyntaxKind :: R_CURLY } ; ['['] => { $ crate :: SyntaxKind :: L_BRACK } ; [']'] => { $ crate :: SyntaxKind :: R_BRACK } ; [<] => { $ crate :: SyntaxKind :: L_ANGLE } ; [>] => { $ crate :: SyntaxKind :: R_ANGLE } ; [@] => { $ crate :: SyntaxKind :: AT } ; [#] => { $ crate :: SyntaxKind :: POUND } ; [~] => { $ crate :: SyntaxKind :: TILDE } ; [?] => { $ crate :: SyntaxKind :: QUESTION } ; [&] => { $ crate :: SyntaxKind :: AMP } ; [|] => { $ crate :: SyntaxKind :: PIPE } ; [+] => { $ crate :: SyntaxKind :: PLUS } ; [*] => { $ crate :: SyntaxKind :: STAR } ; [/] => { $ crate :: SyntaxKind :: SLASH } ; [^] => { $ crate :: SyntaxKind :: CARET } ; [%] => { $ crate :: SyntaxKind :: PERCENT } ; [_] => { $ crate :: SyntaxKind :: UNDERSCORE } ; [.] => { $ crate :: SyntaxKind :: DOT } ; [..] => { $ crate :: SyntaxKind :: DOT2 } ; [...] => { $ crate :: SyntaxKind :: DOT3 } ; [..=] => { $ crate :: SyntaxKind :: DOT2EQ } ; [:] => { $ crate :: SyntaxKind :: COLON } ; [::] => { $ crate :: SyntaxKind :: COLON2 } ; [=] => { $ crate :: SyntaxKind :: EQ } ; [==] => { $ crate :: SyntaxKind :: EQ2 } ; [=>] => { $ crate :: SyntaxKind :: FAT_ARROW } ; [!] => { $ crate :: SyntaxKind :: BANG } ; [!=] => { $ crate :: SyntaxKind :: NEQ } ; [-] => { $ crate :: SyntaxKind :: MINUS } ; [->] => { $ crate :: SyntaxKind :: THIN_ARROW } ; [<=] => { $ crate :: SyntaxKind :: LTEQ } ; [>=] => { $ crate :: SyntaxKind :: GTEQ } ; [+=] => { $ crate :: SyntaxKind :: PLUSEQ } ; [-=] => { $ crate :: SyntaxKind :: MINUSEQ } ; [|=] => { $ crate :: SyntaxKind :: PIPEEQ } ; [&=] => { $ crate :: SyntaxKind :: AMPEQ } ; [^=] => { $ crate :: SyntaxKind :: CARETEQ } ; [/=] => { $ crate :: SyntaxKind :: SLASHEQ } ; [*=] => { $ crate :: SyntaxKind :: STAREQ } ; [%=] => { $ crate :: SyntaxKind :: PERCENTEQ } ; [&&] => { $ crate :: SyntaxKind :: AMP2 } ; [||] => { $ crate :: SyntaxKind :: PIPE2 } ; [<<] => { $ crate :: SyntaxKind :: SHL } ; [>>] => { $ crate :: SyntaxKind :: SHR } ; [<<=] => { $ crate :: SyntaxKind :: SHLEQ } ; [>>=] => { $ crate :: SyntaxKind :: SHREQ } ; [Self] => { $ crate :: SyntaxKind :: SELF_TYPE_KW } ; [abstract] => { $ crate :: SyntaxKind :: ABSTRACT_KW } ; [as] => { $ crate :: SyntaxKind :: AS_KW } ; [become] => { $ crate :: SyntaxKind :: BECOME_KW } ; [box] => { $ crate :: SyntaxKind :: BOX_KW } ; [break] => { $ crate :: SyntaxKind :: BREAK_KW } ; [const] => { $ crate :: SyntaxKind :: CONST_KW } ; [continue] => { $ crate :: SyntaxKind :: CONTINUE_KW } ; [crate] => { $ crate :: SyntaxKind :: CRATE_KW } ; [do] => { $ crate :: SyntaxKind :: DO_KW } ; [else] => { $ crate :: SyntaxKind :: ELSE_KW } ; [enum] => { $ crate :: SyntaxKind :: ENUM_KW } ; [extern] => { $ crate :: SyntaxKind :: EXTERN_KW } ; [false] => { $ crate :: SyntaxKind :: FALSE_KW } ; [final] => { $ crate :: SyntaxKind :: FINAL_KW } ; [fn] => { $ crate :: SyntaxKind :: FN_KW } ; [for] => { $ crate :: SyntaxKind :: FOR_KW } ; [if] => { $ crate :: SyntaxKind :: IF_KW } ; [impl] => { $ crate :: SyntaxKind :: IMPL_KW } ; [in] => { $ crate :: SyntaxKind :: IN_KW } ; [let] => { $ crate :: SyntaxKind :: LET_KW } ; [loop] => { $ crate :: SyntaxKind :: LOOP_KW } ; [macro] => { $ crate :: SyntaxKind :: MACRO_KW } ; [match] => { $ crate :: SyntaxKind :: MATCH_KW } ; [mod] => { $ crate :: SyntaxKind :: MOD_KW } ; [move] => { $ crate :: SyntaxKind :: MOVE_KW } ; [mut] => { $ crate :: SyntaxKind :: MUT_KW } ; [override] => { $ crate :: SyntaxKind :: OVERRIDE_KW } ; [priv] => { $ crate :: SyntaxKind :: PRIV_KW } ; [pub] => { $ crate :: SyntaxKind :: PUB_KW } ; [ref] => { $ crate :: SyntaxKind :: REF_KW } ; [return] => { $ crate :: SyntaxKind :: RETURN_KW } ; [self] => { $ crate :: SyntaxKind :: SELF_KW } ; [static] => { $ crate :: SyntaxKind :: STATIC_KW } ; [struct] => { $ crate :: SyntaxKind :: STRUCT_KW } ; [super] => { $ crate :: SyntaxKind :: SUPER_KW } ; [trait] => { $ crate :: SyntaxKind :: TRAIT_KW } ; [true] => { $ crate :: SyntaxKind :: TRUE_KW } ; [type] => { $ crate :: SyntaxKind :: TYPE_KW } ; [typeof] => { $ crate :: SyntaxKind :: TYPEOF_KW } ; [unsafe] => { $ crate :: SyntaxKind :: UNSAFE_KW } ; [unsized] => { $ crate :: SyntaxKind :: UNSIZED_KW } ; [use] => { $ crate :: SyntaxKind :: USE_KW } ; [virtual] => { $ crate :: SyntaxKind :: VIRTUAL_KW } ; [where] => { $ crate :: SyntaxKind :: WHERE_KW } ; [while] => { $ crate :: SyntaxKind :: WHILE_KW } ; [yield] => { $ crate :: SyntaxKind :: YIELD_KW } ; [asm] => { $ crate :: SyntaxKind :: ASM_KW } ; [att_syntax] => { $ crate :: SyntaxKind :: ATT_SYNTAX_KW } ; [auto] => { $ crate :: SyntaxKind :: AUTO_KW } ; [builtin] => { $ crate :: SyntaxKind :: BUILTIN_KW } ; [clobber_abi] => { $ crate :: SyntaxKind :: CLOBBER_ABI_KW } ; [default] => { $ crate :: SyntaxKind :: DEFAULT_KW } ; [dyn] => { $ crate :: SyntaxKind :: DYN_KW } ; [format_args] => { $ crate :: SyntaxKind :: FORMAT_ARGS_KW } ; [inlateout] => { $ crate :: SyntaxKind :: INLATEOUT_KW } ; [inout] => { $ crate :: SyntaxKind :: INOUT_KW } ; [label] => { $ crate :: SyntaxKind :: LABEL_KW } ; [lateout] => { $ crate :: SyntaxKind :: LATEOUT_KW } ; [macro_rules] => { $ crate :: SyntaxKind :: MACRO_RULES_KW } ; [may_unwind] => { $ crate :: SyntaxKind :: MAY_UNWIND_KW } ; [nomem] => { $ crate :: SyntaxKind :: NOMEM_KW } ; [noreturn] => { $ crate :: SyntaxKind :: NORETURN_KW } ; [nostack] => { $ crate :: SyntaxKind :: NOSTACK_KW } ; [offset_of] => { $ crate :: SyntaxKind :: OFFSET_OF_KW } ; [options] => { $ crate :: SyntaxKind :: OPTIONS_KW } ; [out] => { $ crate :: SyntaxKind :: OUT_KW } ; [preserves_flags] => { $ crate :: SyntaxKind :: PRESERVES_FLAGS_KW } ; [pure] => { $ crate :: SyntaxKind :: PURE_KW } ; [raw] => { $ crate :: SyntaxKind :: RAW_KW } ; [readonly] => { $ crate :: SyntaxKind :: READONLY_KW } ; [safe] => { $ crate :: SyntaxKind :: SAFE_KW } ; [sym] => { $ crate :: SyntaxKind :: SYM_KW } ; [union] => { $ crate :: SyntaxKind :: UNION_KW } ; [yeet] => { $ crate :: SyntaxKind :: YEET_KW } ; [async] => { $ crate :: SyntaxKind :: ASYNC_KW } ; [await] => { $ crate :: SyntaxKind :: AWAIT_KW } ; [dyn] => { $ crate :: SyntaxKind :: DYN_KW } ; [gen] => { $ crate :: SyntaxKind :: GEN_KW } ; [try] => { $ crate :: SyntaxKind :: TRY_KW } ; [lifetime_ident] => { $ crate :: SyntaxKind :: LIFETIME_IDENT } ; [int_number] => { $ crate :: SyntaxKind :: INT_NUMBER } ; [ident] => { $ crate :: SyntaxKind :: IDENT } ; [string] => { $ crate :: SyntaxKind :: STRING } ; [shebang] => { $ crate :: SyntaxKind :: SHEBANG } ; [frontmatter] => { $ crate :: SyntaxKind :: FRONTMATTER } ; } impl ::core::marker::Copy for SyntaxKind {} impl ::core::clone::Clone for SyntaxKind { #[inline] diff --git a/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs b/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs index 6c9d02aaa8f8..24db9478ee56 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs +++ b/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs @@ -870,6 +870,10 @@ mod err { run_and_expect_errors("test_data/parser/inline/err/tuple_pat_leading_comma.rs"); } #[test] + fn type_in_array_recover() { + run_and_expect_errors("test_data/parser/inline/err/type_in_array_recover.rs"); + } + #[test] fn unsafe_block_in_mod() { run_and_expect_errors("test_data/parser/inline/err/unsafe_block_in_mod.rs"); } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0022_bad_exprs.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0022_bad_exprs.rast index d97fc6c72091..1a8e881dd9e0 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0022_bad_exprs.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0022_bad_exprs.rast @@ -35,8 +35,8 @@ SOURCE_FILE WHITESPACE " " LET_STMT LET_KW "let" - ERROR - R_BRACK "]" + ERROR + R_BRACK "]" WHITESPACE " " R_CURLY "}" WHITESPACE "\n" @@ -149,7 +149,8 @@ error 17: expected expression, item or let statement error 25: expected a name error 26: expected `;`, `{`, or `(` error 30: expected pattern -error 31: expected SEMICOLON +error 30: expected SEMICOLON +error 30: expected expression, item or let statement error 53: expected expression error 54: expected R_PAREN error 54: expected SEMICOLON diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/comma_after_default_values_syntax.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/comma_after_default_values_syntax.rast index feb617e1aa2a..b57066f2fb38 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/comma_after_default_values_syntax.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/comma_after_default_values_syntax.rast @@ -23,8 +23,7 @@ SOURCE_FILE L_CURLY "{" WHITESPACE " " DOT2 ".." - ERROR - COMMA "," + COMMA "," WHITESPACE " " R_CURLY "}" SEMICOLON ";" @@ -39,8 +38,7 @@ SOURCE_FILE L_CURLY "{" WHITESPACE " " DOT2 ".." - ERROR - COMMA "," + COMMA "," WHITESPACE " " RECORD_EXPR_FIELD NAME_REF @@ -55,5 +53,6 @@ SOURCE_FILE R_CURLY "}" WHITESPACE "\n" error 21: expected expression +error 21: cannot use a comma after the base struct error 36: expected expression -error 37: expected COMMA +error 36: cannot use a comma after the base struct diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/struct_field_recover.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/struct_field_recover.rast index 458d7f4e2fa2..5a12c21b647d 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/struct_field_recover.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/struct_field_recover.rast @@ -26,6 +26,36 @@ SOURCE_FILE WHITESPACE " " R_CURLY "}" WHITESPACE "\n" + STRUCT + STRUCT_KW "struct" + WHITESPACE " " + NAME + IDENT "S" + WHITESPACE " " + RECORD_FIELD_LIST + L_CURLY "{" + WHITESPACE " " + RECORD_FIELD + NAME + IDENT "f" + COLON ":" + WHITESPACE " " + RECORD_FIELD + VISIBILITY + PUB_KW "pub" + WHITESPACE " " + NAME + IDENT "g" + COLON ":" + WHITESPACE " " + TUPLE_TYPE + L_PAREN "(" + R_PAREN ")" + WHITESPACE " " + R_CURLY "}" + WHITESPACE "\n" error 12: expected COLON error 12: expected type error 12: expected COMMA +error 38: expected type +error 38: expected COMMA diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/struct_field_recover.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/struct_field_recover.rs index da32227adcd7..5b1e5a5b8a21 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/struct_field_recover.rs +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/struct_field_recover.rs @@ -1 +1,2 @@ struct S { f pub g: () } +struct S { f: pub g: () } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/type_in_array_recover.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/type_in_array_recover.rast new file mode 100644 index 000000000000..db76e8d7c88a --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/type_in_array_recover.rast @@ -0,0 +1,15 @@ +SOURCE_FILE + CONST + CONST_KW "const" + WHITESPACE " " + UNDERSCORE "_" + COLON ":" + WHITESPACE " " + SLICE_TYPE + L_BRACK "[" + REF_TYPE + AMP "&" + R_BRACK "]" + SEMICOLON ";" + WHITESPACE "\n" +error 11: expected type diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/type_in_array_recover.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/type_in_array_recover.rs new file mode 100644 index 000000000000..039bf8299779 --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/type_in_array_recover.rs @@ -0,0 +1 @@ +const _: [&]; diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/build.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/build.rs index 07a10aaae578..97c0c4bda7df 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/build.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/build.rs @@ -12,5 +12,5 @@ fn main() { let version_string = std::str::from_utf8(&output.stdout[..]) .expect("rustc --version output must be UTF-8") .trim(); - println!("cargo::rustc-env=RUSTC_VERSION={}", version_string); + println!("cargo::rustc-env=RUSTC_VERSION={version_string}"); } diff --git a/src/tools/rust-analyzer/crates/project-model/src/env.rs b/src/tools/rust-analyzer/crates/project-model/src/env.rs index f2e5df171ae3..e7293b0b2ef6 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/env.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/env.rs @@ -25,7 +25,7 @@ pub(crate) fn inject_cargo_package_env(env: &mut Env, package: &PackageData) { env.set("CARGO_PKG_VERSION_PATCH", package.version.patch.to_string()); env.set("CARGO_PKG_VERSION_PRE", package.version.pre.to_string()); - env.set("CARGO_PKG_AUTHORS", package.authors.join(":").clone()); + env.set("CARGO_PKG_AUTHORS", package.authors.join(":")); env.set("CARGO_PKG_NAME", package.name.clone()); env.set("CARGO_PKG_DESCRIPTION", package.description.as_deref().unwrap_or_default()); diff --git a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs index c6e0cf36aff2..eec0077ea6e2 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs @@ -1370,7 +1370,7 @@ fn detached_file_to_crate_graph( Edition::CURRENT, display_name.clone(), None, - cfg_options.clone(), + cfg_options, None, Env::default(), CrateOrigin::Local { diff --git a/src/tools/rust-analyzer/crates/query-group-macro/Cargo.toml b/src/tools/rust-analyzer/crates/query-group-macro/Cargo.toml index 8aeb26294231..8b03d8f8cc7a 100644 --- a/src/tools/rust-analyzer/crates/query-group-macro/Cargo.toml +++ b/src/tools/rust-analyzer/crates/query-group-macro/Cargo.toml @@ -20,3 +20,4 @@ syn = { version = "2.0", features = ["full", "extra-traits", "visit-mut"] } [dev-dependencies] expect-test = "1.5.1" salsa.workspace = true +salsa-macros.workspace = true diff --git a/src/tools/rust-analyzer/crates/query-group-macro/src/lib.rs b/src/tools/rust-analyzer/crates/query-group-macro/src/lib.rs index f4f316c1ac1e..ec4b6b2a4ac3 100644 --- a/src/tools/rust-analyzer/crates/query-group-macro/src/lib.rs +++ b/src/tools/rust-analyzer/crates/query-group-macro/src/lib.rs @@ -178,7 +178,7 @@ pub(crate) fn query_group_impl( let supertraits = &item_trait.supertraits; let db_attr: Attribute = parse_quote! { - #[salsa::db] + #[salsa_macros::db] }; item_trait.attrs.push(db_attr); @@ -210,7 +210,7 @@ pub(crate) fn query_group_impl( .into_iter() .filter(|fn_arg| matches!(fn_arg, FnArg::Typed(_))) .map(|fn_arg| match fn_arg { - FnArg::Typed(pat_type) => pat_type.clone(), + FnArg::Typed(pat_type) => pat_type, FnArg::Receiver(_) => unreachable!("this should have been filtered out"), }) .collect::>(); @@ -407,7 +407,7 @@ pub(crate) fn query_group_impl( .collect::>(); let input_struct = quote! { - #[salsa::input] + #[salsa_macros::input] pub(crate) struct #input_struct_name { #(#fields),* } @@ -418,7 +418,7 @@ pub(crate) fn query_group_impl( let create_data_method = quote! { #[allow(non_snake_case)] - #[salsa::tracked] + #[salsa_macros::tracked] fn #create_data_ident(db: &dyn #trait_name_ident) -> #input_struct_name { #input_struct_name::new(db, #(#field_params),*) } @@ -443,7 +443,7 @@ pub(crate) fn query_group_impl( item_trait.items.append(&mut lookup_signatures); let trait_impl = quote! { - #[salsa::db] + #[salsa_macros::db] impl #trait_name_ident for DB where DB: #supertraits, diff --git a/src/tools/rust-analyzer/crates/query-group-macro/src/queries.rs b/src/tools/rust-analyzer/crates/query-group-macro/src/queries.rs index d4d40588bfc7..baac3e8bbfe7 100644 --- a/src/tools/rust-analyzer/crates/query-group-macro/src/queries.rs +++ b/src/tools/rust-analyzer/crates/query-group-macro/src/queries.rs @@ -49,7 +49,7 @@ impl ToTokens for TrackedQuery { }) .into_iter() .chain(self.lru.map(|lru| quote!(lru = #lru))); - let annotation = quote!(#[salsa::tracked( #(#options),* )]); + let annotation = quote!(#[salsa_macros::tracked( #(#options),* )]); let pat_and_tys = &self.pat_and_tys; let params = self diff --git a/src/tools/rust-analyzer/crates/query-group-macro/tests/interned.rs b/src/tools/rust-analyzer/crates/query-group-macro/tests/interned.rs index 26ed316122a5..f738185b1fe7 100644 --- a/src/tools/rust-analyzer/crates/query-group-macro/tests/interned.rs +++ b/src/tools/rust-analyzer/crates/query-group-macro/tests/interned.rs @@ -6,7 +6,7 @@ use salsa::plumbing::AsId; mod logger_db; use logger_db::LoggerDb; -#[salsa::interned(no_lifetime)] +#[salsa_macros::interned(no_lifetime)] pub struct InternedString { data: String, } diff --git a/src/tools/rust-analyzer/crates/query-group-macro/tests/logger_db.rs b/src/tools/rust-analyzer/crates/query-group-macro/tests/logger_db.rs index 5cf9be36f70c..bade0c2cd6fa 100644 --- a/src/tools/rust-analyzer/crates/query-group-macro/tests/logger_db.rs +++ b/src/tools/rust-analyzer/crates/query-group-macro/tests/logger_db.rs @@ -1,6 +1,6 @@ use std::sync::{Arc, Mutex}; -#[salsa::db] +#[salsa_macros::db] #[derive(Default, Clone)] pub(crate) struct LoggerDb { storage: salsa::Storage, @@ -12,7 +12,7 @@ struct Logger { logs: Arc>>, } -#[salsa::db] +#[salsa_macros::db] impl salsa::Database for LoggerDb { fn salsa_event(&self, event: &dyn Fn() -> salsa::Event) { let event = event(); @@ -40,7 +40,7 @@ impl LoggerDb { /// it is meant to be run from outside any tracked functions. pub(crate) fn assert_logs(&self, expected: expect_test::Expect) { let logs = std::mem::take(&mut *self.logger.logs.lock().unwrap()); - expected.assert_eq(&format!("{:#?}", logs)); + expected.assert_eq(&format!("{logs:#?}")); } } diff --git a/src/tools/rust-analyzer/crates/query-group-macro/tests/old_and_new.rs b/src/tools/rust-analyzer/crates/query-group-macro/tests/old_and_new.rs index a18b23a7d8a9..cc57ba78455f 100644 --- a/src/tools/rust-analyzer/crates/query-group-macro/tests/old_and_new.rs +++ b/src/tools/rust-analyzer/crates/query-group-macro/tests/old_and_new.rs @@ -4,7 +4,7 @@ mod logger_db; use logger_db::LoggerDb; use query_group_macro::query_group; -#[salsa::input] +#[salsa_macros::input] struct Input { str: String, } @@ -30,7 +30,7 @@ fn invoke_length_query_actual(db: &dyn PartialMigrationDatabase, input: Input) - input.str(db).len() } -#[salsa::tracked] +#[salsa_macros::tracked] fn invoke_length_tracked_actual(db: &dyn PartialMigrationDatabase, input: Input) -> usize { input.str(db).len() } @@ -87,12 +87,12 @@ fn invoke_tracked_query() { fn new_salsa_baseline() { let db = LoggerDb::default(); - #[salsa::input] + #[salsa_macros::input] struct Input { str: String, } - #[salsa::tracked] + #[salsa_macros::tracked] fn new_salsa_length_query(db: &dyn PartialMigrationDatabase, input: Input) -> usize { input.str(db).len() } diff --git a/src/tools/rust-analyzer/crates/query-group-macro/tests/supertrait.rs b/src/tools/rust-analyzer/crates/query-group-macro/tests/supertrait.rs index 70073ac1de32..ad8ada3ef153 100644 --- a/src/tools/rust-analyzer/crates/query-group-macro/tests/supertrait.rs +++ b/src/tools/rust-analyzer/crates/query-group-macro/tests/supertrait.rs @@ -1,6 +1,6 @@ use query_group_macro::query_group; -#[salsa::db] +#[salsa_macros::db] pub trait SourceDb: salsa::Database { /// Text of the file. fn file_text(&self, id: usize) -> String; diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs index ea5a5eaa6a44..4dba97c8ec49 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs @@ -182,10 +182,8 @@ fn with_extra_thread( thread_intent: stdx::thread::ThreadIntent, f: impl FnOnce() -> anyhow::Result<()> + Send + 'static, ) -> anyhow::Result<()> { - let handle = stdx::thread::Builder::new(thread_intent) - .name(thread_name.into()) - .stack_size(STACK_SIZE) - .spawn(f)?; + let handle = + stdx::thread::Builder::new(thread_intent, thread_name).stack_size(STACK_SIZE).spawn(f)?; handle.join()?; diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs index a62005e3c085..a1e4adf0844a 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs @@ -175,7 +175,7 @@ impl flags::AnalysisStats { UsizeWithUnderscore(dep_loc), UsizeWithUnderscore(dep_item_trees), ); - eprintln!(" dependency item stats: {}", dep_item_stats); + eprintln!(" dependency item stats: {dep_item_stats}"); // FIXME(salsa-transition): bring back stats for ParseQuery (file size) // and ParseMacroExpansionQuery (macro expansion "file") size whenever we implement @@ -295,7 +295,7 @@ impl flags::AnalysisStats { UsizeWithUnderscore(workspace_loc), UsizeWithUnderscore(workspace_item_trees), ); - eprintln!(" usages: {}", workspace_item_stats); + eprintln!(" usages: {workspace_item_stats}"); eprintln!(" Dependencies:"); eprintln!( @@ -303,7 +303,7 @@ impl flags::AnalysisStats { UsizeWithUnderscore(dep_loc), UsizeWithUnderscore(dep_item_trees), ); - eprintln!(" declarations: {}", dep_item_stats); + eprintln!(" declarations: {dep_item_stats}"); let crate_def_map_time = crate_def_map_sw.elapsed(); eprintln!("{:<20} {}", "Item Collection:", crate_def_map_time); @@ -701,10 +701,9 @@ impl flags::AnalysisStats { if self.parallel { let mut inference_sw = self.stop_watch(); - let snap = db.snapshot(); bodies .par_iter() - .map_with(snap, |snap, &body| { + .map_with(db.clone(), |snap, &body| { snap.body(body.into()); snap.infer(body.into()); }) @@ -1294,7 +1293,7 @@ impl fmt::Display for UsizeWithUnderscore { let num_str = self.0.to_string(); if num_str.len() <= 3 { - return write!(f, "{}", num_str); + return write!(f, "{num_str}"); } let mut result = String::new(); @@ -1307,7 +1306,7 @@ impl fmt::Display for UsizeWithUnderscore { } let result = result.chars().rev().collect::(); - write!(f, "{}", result) + write!(f, "{result}") } } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/diagnostics.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/diagnostics.rs index 7c4eeebdfa31..7b12cb14009f 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/diagnostics.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/diagnostics.rs @@ -15,11 +15,13 @@ impl flags::Diagnostics { pub fn run(self) -> anyhow::Result<()> { const STACK_SIZE: usize = 1024 * 1024 * 8; - let handle = stdx::thread::Builder::new(stdx::thread::ThreadIntent::LatencySensitive) - .name("BIG_STACK_THREAD".into()) - .stack_size(STACK_SIZE) - .spawn(|| self.run_()) - .unwrap(); + let handle = stdx::thread::Builder::new( + stdx::thread::ThreadIntent::LatencySensitive, + "BIG_STACK_THREAD", + ) + .stack_size(STACK_SIZE) + .spawn(|| self.run_()) + .unwrap(); handle.join() } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs index c042c26bd188..e3b372c91494 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs @@ -7,6 +7,7 @@ use std::{cell::RefCell, fs::read_to_string, panic::AssertUnwindSafe, path::Path use hir::{ChangeWithProcMacros, Crate}; use ide::{AnalysisHost, DiagnosticCode, DiagnosticsConfig}; +use ide_db::base_db; use itertools::Either; use paths::Utf8PathBuf; use profile::StopWatch; @@ -310,7 +311,7 @@ impl flags::RustcTests { let tester = AssertUnwindSafe(&mut tester); let p = p.clone(); move || { - let _guard = stdx::panic_context::enter(p.display().to_string()); + let _guard = base_db::DbPanicContext::enter(p.display().to_string()); { tester }.0.test(p); } }) { diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs index 2062294f807c..d258c5d8191f 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs @@ -265,10 +265,10 @@ impl flags::Scip { }; if !duplicate_symbol_errors.is_empty() { - eprintln!("{}", DUPLICATE_SYMBOLS_MESSAGE); + eprintln!("{DUPLICATE_SYMBOLS_MESSAGE}"); for (source_location, symbol) in duplicate_symbol_errors { - eprintln!("{}", source_location); - eprintln!(" Duplicate symbol: {}", symbol); + eprintln!("{source_location}"); + eprintln!(" Duplicate symbol: {symbol}"); eprintln!(); } } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/unresolved_references.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/unresolved_references.rs index bca7c8a098c2..0362e13b88b7 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/unresolved_references.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/unresolved_references.rs @@ -15,11 +15,13 @@ impl flags::UnresolvedReferences { pub fn run(self) -> anyhow::Result<()> { const STACK_SIZE: usize = 1024 * 1024 * 8; - let handle = stdx::thread::Builder::new(stdx::thread::ThreadIntent::LatencySensitive) - .name("BIG_STACK_THREAD".into()) - .stack_size(STACK_SIZE) - .spawn(|| self.run_()) - .unwrap(); + let handle = stdx::thread::Builder::new( + stdx::thread::ThreadIntent::LatencySensitive, + "BIG_STACK_THREAD", + ) + .stack_size(STACK_SIZE) + .spawn(|| self.run_()) + .unwrap(); handle.join() } @@ -28,7 +30,7 @@ impl flags::UnresolvedReferences { let root = vfs::AbsPathBuf::assert_utf8(std::env::current_dir()?.join(&self.path)).normalize(); let config = crate::config::Config::new( - root.clone(), + root, lsp_types::ClientCapabilities::default(), vec![], None, diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/command.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/command.rs index 0035d941e2c6..d6c80c399ba2 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/command.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/command.rs @@ -148,10 +148,10 @@ impl CommandHandle { let stderr = child.0.stderr().take().unwrap(); let actor = CargoActor::::new(parser, sender, stdout, stderr); - let thread = stdx::thread::Builder::new(stdx::thread::ThreadIntent::Worker) - .name("CommandHandle".to_owned()) - .spawn(move || actor.run()) - .expect("failed to spawn thread"); + let thread = + stdx::thread::Builder::new(stdx::thread::ThreadIntent::Worker, "CommandHandle") + .spawn(move || actor.run()) + .expect("failed to spawn thread"); Ok(CommandHandle { program, arguments, current_dir, child, thread, _phantom: PhantomData }) } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs index dd827949a9c2..03e5b1f6f4b6 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs @@ -9,13 +9,14 @@ use cfg::{CfgAtom, CfgDiff}; use hir::Symbol; use ide::{ AssistConfig, CallHierarchyConfig, CallableSnippets, CompletionConfig, - CompletionFieldsToResolve, DiagnosticsConfig, ExprFillDefaultMode, GenericParameterHints, - HighlightConfig, HighlightRelatedConfig, HoverConfig, HoverDocFormat, InlayFieldsToResolve, - InlayHintsConfig, JoinLinesConfig, MemoryLayoutHoverConfig, MemoryLayoutHoverRenderKind, - Snippet, SnippetScope, SourceRootId, + CompletionFieldsToResolve, DiagnosticsConfig, GenericParameterHints, HighlightConfig, + HighlightRelatedConfig, HoverConfig, HoverDocFormat, InlayFieldsToResolve, InlayHintsConfig, + JoinLinesConfig, MemoryLayoutHoverConfig, MemoryLayoutHoverRenderKind, Snippet, SnippetScope, + SourceRootId, }; use ide_db::{ SnippetCap, + assists::ExprFillDefaultMode, imports::insert_use::{ImportGranularity, InsertUseConfig, PrefixKind}, }; use itertools::{Either, Itertools}; @@ -1182,7 +1183,7 @@ impl ConfigChange { source_root_map: Arc>, ) { assert!(self.source_map_change.is_none()); - self.source_map_change = Some(source_root_map.clone()); + self.source_map_change = Some(source_root_map); } } @@ -1493,6 +1494,11 @@ impl Config { term_search_fuel: self.assist_termSearch_fuel(source_root).to_owned() as u64, term_search_borrowck: self.assist_termSearch_borrowcheck(source_root).to_owned(), code_action_grouping: self.code_action_group(), + expr_fill_default: match self.assist_expressionFillDefault(source_root) { + ExprFillDefaultDef::Todo => ExprFillDefaultMode::Todo, + ExprFillDefaultDef::Default => ExprFillDefaultMode::Default, + ExprFillDefaultDef::Underscore => ExprFillDefaultMode::Underscore, + }, } } @@ -1577,6 +1583,7 @@ impl Config { expr_fill_default: match self.assist_expressionFillDefault(source_root) { ExprFillDefaultDef::Todo => ExprFillDefaultMode::Todo, ExprFillDefaultDef::Default => ExprFillDefaultMode::Default, + ExprFillDefaultDef::Underscore => ExprFillDefaultMode::Underscore, }, snippet_cap: self.snippet_cap(), insert_use: self.insert_use_config(source_root), @@ -2527,6 +2534,7 @@ where enum ExprFillDefaultDef { Todo, Default, + Underscore, } #[derive(Serialize, Deserialize, Debug, Clone)] diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs index 9b1463b1126b..438a2a0ba1ea 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs @@ -5,7 +5,7 @@ use std::mem; use cargo_metadata::PackageId; use ide::FileId; -use ide_db::FxHashMap; +use ide_db::{FxHashMap, base_db::DbPanicContext}; use itertools::Itertools; use rustc_hash::FxHashSet; use stdx::iter_eq_by; @@ -215,7 +215,7 @@ pub(crate) fn fetch_native_diagnostics( kind: NativeDiagnosticsFetchKind, ) -> Vec<(FileId, Vec)> { let _p = tracing::info_span!("fetch_native_diagnostics").entered(); - let _ctx = stdx::panic_context::enter("fetch_native_diagnostics".to_owned()); + let _ctx = DbPanicContext::enter("fetch_native_diagnostics".to_owned()); // the diagnostics produced may point to different files not requested by the concrete request, // put those into here and filter later diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/discover.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/discover.rs index 67ddc41f3b21..24c433610f1a 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/discover.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/discover.rs @@ -126,10 +126,8 @@ impl CargoParser for DiscoverProjectParser { Some(msg) } Err(err) => { - let err = DiscoverProjectData::Error { - error: format!("{:#?}\n{}", err, line), - source: None, - }; + let err = + DiscoverProjectData::Error { error: format!("{err:#?}\n{line}"), source: None }; Some(DiscoverProjectMessage::new(err)) } } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs index 2778b311e1e3..fc312439d58c 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs @@ -133,10 +133,10 @@ impl FlycheckHandle { let actor = FlycheckActor::new(id, sender, config, sysroot_root, workspace_root, manifest_path); let (sender, receiver) = unbounded::(); - let thread = stdx::thread::Builder::new(stdx::thread::ThreadIntent::Worker) - .name("Flycheck".to_owned()) - .spawn(move || actor.run(receiver)) - .expect("failed to spawn thread"); + let thread = + stdx::thread::Builder::new(stdx::thread::ThreadIntent::Worker, format!("Flycheck{id}")) + .spawn(move || actor.run(receiver)) + .expect("failed to spawn thread"); FlycheckHandle { id, sender, _thread: thread } } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs index 820276e8aea2..3b3b9c879754 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs @@ -511,7 +511,7 @@ impl GlobalState { self.fetch_workspaces_queue.request_op( format!("workspace vfs file change: {path}"), - FetchWorkspaceRequest { path: Some(path.to_owned()), force_crate_graph_reload }, + FetchWorkspaceRequest { path: Some(path), force_crate_graph_reload }, ); } } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/dispatch.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/dispatch.rs index 3b76edf528b6..f04ada38893a 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/dispatch.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/dispatch.rs @@ -4,7 +4,10 @@ use std::{ panic, thread, }; -use ide_db::base_db::salsa::{self, Cancelled}; +use ide_db::base_db::{ + DbPanicContext, + salsa::{self, Cancelled}, +}; use lsp_server::{ExtractError, Response, ResponseError}; use serde::{Serialize, de::DeserializeOwned}; use stdx::thread::ThreadIntent; @@ -56,7 +59,7 @@ impl RequestDispatcher<'_> { tracing::info_span!("request", method = ?req.method, "request_id" = ?req.id).entered(); tracing::debug!(?params); let result = { - let _pctx = stdx::panic_context::enter(panic_context); + let _pctx = DbPanicContext::enter(panic_context); f(self.global_state, params) }; if let Ok(response) = result_to_response::(req.id, result) { @@ -86,7 +89,7 @@ impl RequestDispatcher<'_> { let global_state_snapshot = self.global_state.snapshot(); let result = panic::catch_unwind(move || { - let _pctx = stdx::panic_context::enter(panic_context); + let _pctx = DbPanicContext::enter(panic_context); f(global_state_snapshot, params) }); @@ -257,7 +260,7 @@ impl RequestDispatcher<'_> { } .spawn(intent, move || { let result = panic::catch_unwind(move || { - let _pctx = stdx::panic_context::enter(panic_context); + let _pctx = DbPanicContext::enter(panic_context); f(world, params) }); match thread_result_to_response::(req.id.clone(), result) { @@ -421,11 +424,8 @@ impl NotificationDispatcher<'_> { tracing::debug!(?params); - let _pctx = stdx::panic_context::enter(format!( - "\nversion: {}\nnotification: {}", - version(), - N::METHOD - )); + let _pctx = + DbPanicContext::enter(format!("\nversion: {}\nnotification: {}", version(), N::METHOD)); if let Err(e) = f(self.global_state, params) { tracing::error!(handler = %N::METHOD, error = %e, "notification handler failed"); } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs index a30e5d8ce268..b7373f274f05 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs @@ -309,7 +309,7 @@ fn run_flycheck(state: &mut GlobalState, vfs_path: VfsPath) -> bool { let task = move || -> std::result::Result<(), Cancelled> { if invocation_strategy_once { let saved_file = vfs_path.as_path().map(|p| p.to_owned()); - world.flycheck[0].restart_workspace(saved_file.clone()); + world.flycheck[0].restart_workspace(saved_file); } let target = TargetSpec::for_file(&world, file_id)?.and_then(|it| { diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs index e08dd80973a7..69983a676261 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs @@ -2210,7 +2210,7 @@ fn runnable_action_links( let label = update_test.label(); if let Some(r) = to_proto::make_update_runnable(&r, update_test) { let update_command = to_proto::command::run_single(&r, label.unwrap().as_str()); - group.commands.push(to_command_link(update_command, r.label.clone())); + group.commands.push(to_command_link(update_command, r.label)); } } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs index 96c2ceef6ba1..f6bcb5642c3b 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs @@ -1064,7 +1064,7 @@ fn main() { ), work_done_progress_params: Default::default(), }); - assert!(res.to_string().contains("&str")); + assert!(res.to_string().contains("&'static str")); let res = server.send_request::(HoverParams { text_document_position_params: TextDocumentPositionParams::new( @@ -1073,7 +1073,7 @@ fn main() { ), work_done_progress_params: Default::default(), }); - assert!(res.to_string().contains("&str")); + assert!(res.to_string().contains("&'static str")); server.request::( GotoDefinitionParams { diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/ratoml.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/ratoml.rs index 3f313b7e57fe..485f32281dde 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/ratoml.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/ratoml.rs @@ -82,11 +82,8 @@ impl RatomlTest { } Url::parse( - format!( - "file://{}", - path.into_string().to_owned().replace("C:\\", "/c:/").replace('\\', "/") - ) - .as_str(), + format!("file://{}", path.into_string().replace("C:\\", "/c:/").replace('\\', "/")) + .as_str(), ) .unwrap() } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs index 3f97952365f3..2bebb0c1b970 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs @@ -202,7 +202,7 @@ impl Project<'_> { } let mut config = Config::new( - tmp_dir_path.clone(), + tmp_dir_path, lsp_types::ClientCapabilities { workspace: Some(lsp_types::WorkspaceClientCapabilities { did_change_watched_files: Some( @@ -298,8 +298,7 @@ impl Server { ) -> Server { let (connection, client) = Connection::memory(); - let _thread = stdx::thread::Builder::new(stdx::thread::ThreadIntent::Worker) - .name("test server".to_owned()) + let _thread = stdx::thread::Builder::new(stdx::thread::ThreadIntent::Worker, "test server") .spawn(move || main_loop(config, connection).unwrap()) .expect("failed to spawn a thread"); diff --git a/src/tools/rust-analyzer/crates/span/src/hygiene.rs b/src/tools/rust-analyzer/crates/span/src/hygiene.rs index b21102f2db71..7bb88ac3658c 100644 --- a/src/tools/rust-analyzer/crates/span/src/hygiene.rs +++ b/src/tools/rust-analyzer/crates/span/src/hygiene.rs @@ -94,16 +94,11 @@ const _: () = { } } impl zalsa_struct_::Configuration for SyntaxContext { + const LOCATION: salsa::plumbing::Location = + salsa::plumbing::Location { file: file!(), line: line!() }; const DEBUG_NAME: &'static str = "SyntaxContextData"; type Fields<'a> = SyntaxContextData; type Struct<'a> = SyntaxContext; - fn struct_from_id<'db>(id: salsa::Id) -> Self::Struct<'db> { - SyntaxContext::from_salsa_id(id) - } - fn deref_struct(s: Self::Struct<'_>) -> salsa::Id { - s.as_salsa_id() - .expect("`SyntaxContext::deref_structs()` called on a root `SyntaxContext`") - } } impl SyntaxContext { pub fn ingredient(db: &Db) -> &zalsa_struct_::IngredientImpl @@ -308,7 +303,7 @@ impl SyntaxContext { } #[cfg(feature = "salsa")] -impl SyntaxContext { +impl<'db> SyntaxContext { const MAX_ID: u32 = salsa::Id::MAX_U32 - 1; #[inline] @@ -340,6 +335,60 @@ impl SyntaxContext { // SAFETY: This comes from a Salsa ID. unsafe { Self::from_u32(id.as_u32()) } } + + #[inline] + pub fn outer_mark( + self, + db: &'db dyn salsa::Database, + ) -> (Option, Transparency) { + (self.outer_expn(db), self.outer_transparency(db)) + } + + #[inline] + pub fn normalize_to_macros_2_0(self, db: &'db dyn salsa::Database) -> SyntaxContext { + self.opaque(db) + } + + #[inline] + pub fn normalize_to_macro_rules(self, db: &'db dyn salsa::Database) -> SyntaxContext { + self.opaque_and_semitransparent(db) + } + + pub fn is_opaque(self, db: &'db dyn salsa::Database) -> bool { + !self.is_root() && self.outer_transparency(db).is_opaque() + } + + pub fn remove_mark( + &mut self, + db: &'db dyn salsa::Database, + ) -> (Option, Transparency) { + let data = *self; + *self = data.parent(db); + (data.outer_expn(db), data.outer_transparency(db)) + } + + pub fn marks( + self, + db: &'db dyn salsa::Database, + ) -> impl Iterator { + let mut marks = self.marks_rev(db).collect::>(); + marks.reverse(); + marks.into_iter() + } + + pub fn marks_rev( + self, + db: &'db dyn salsa::Database, + ) -> impl Iterator { + std::iter::successors(Some(self), move |&mark| Some(mark.parent(db))) + .take_while(|&it| !it.is_root()) + .map(|ctx| { + let mark = ctx.outer_mark(db); + // We stop before taking the root expansion, as such we cannot encounter a `None` outer + // expansion, as only the ROOT has it. + (mark.0.unwrap(), mark.1) + }) + } } #[cfg(not(feature = "salsa"))] #[derive(Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] diff --git a/src/tools/rust-analyzer/crates/stdx/src/thread.rs b/src/tools/rust-analyzer/crates/stdx/src/thread.rs index 6c742fecf1b6..a34e9e4a6551 100644 --- a/src/tools/rust-analyzer/crates/stdx/src/thread.rs +++ b/src/tools/rust-analyzer/crates/stdx/src/thread.rs @@ -26,12 +26,12 @@ pub use pool::Pool; /// # Panics /// /// Panics if failed to spawn the thread. -pub fn spawn(intent: ThreadIntent, f: F) -> JoinHandle +pub fn spawn(intent: ThreadIntent, name: String, f: F) -> JoinHandle where F: (FnOnce() -> T) + Send + 'static, T: Send + 'static, { - Builder::new(intent).spawn(f).expect("failed to spawn thread") + Builder::new(intent, name).spawn(f).expect("failed to spawn thread") } pub struct Builder { @@ -42,13 +42,8 @@ pub struct Builder { impl Builder { #[must_use] - pub fn new(intent: ThreadIntent) -> Self { - Self { intent, inner: jod_thread::Builder::new(), allow_leak: false } - } - - #[must_use] - pub fn name(self, name: String) -> Self { - Self { inner: self.inner.name(name), ..self } + pub fn new(intent: ThreadIntent, name: impl Into) -> Self { + Self { intent, inner: jod_thread::Builder::new().name(name.into()), allow_leak: false } } #[must_use] @@ -56,6 +51,8 @@ impl Builder { Self { inner: self.inner.stack_size(size), ..self } } + /// Whether dropping should detach the thread + /// instead of joining it. #[must_use] pub fn allow_leak(self, allow_leak: bool) -> Self { Self { allow_leak, ..self } diff --git a/src/tools/rust-analyzer/crates/stdx/src/thread/pool.rs b/src/tools/rust-analyzer/crates/stdx/src/thread/pool.rs index 074cd747dacc..a8de4db624f1 100644 --- a/src/tools/rust-analyzer/crates/stdx/src/thread/pool.rs +++ b/src/tools/rust-analyzer/crates/stdx/src/thread/pool.rs @@ -50,10 +50,9 @@ impl Pool { let extant_tasks = Arc::new(AtomicUsize::new(0)); let mut handles = Vec::with_capacity(threads); - for _ in 0..threads { - let handle = Builder::new(INITIAL_INTENT) + for idx in 0..threads { + let handle = Builder::new(INITIAL_INTENT, format!("Worker{idx}",)) .stack_size(STACK_SIZE) - .name("Worker".into()) .allow_leak(true) .spawn({ let extant_tasks = Arc::clone(&extant_tasks); diff --git a/src/tools/rust-analyzer/crates/syntax/Cargo.toml b/src/tools/rust-analyzer/crates/syntax/Cargo.toml index 510d44d00917..4c7704803ef3 100644 --- a/src/tools/rust-analyzer/crates/syntax/Cargo.toml +++ b/src/tools/rust-analyzer/crates/syntax/Cargo.toml @@ -14,7 +14,7 @@ rust-version.workspace = true [dependencies] either.workspace = true itertools.workspace = true -rowan = "=0.15.15" +rowan.workspace = true rustc-hash.workspace = true rustc-literal-escaper.workspace = true smol_str.workspace = true diff --git a/src/tools/rust-analyzer/crates/syntax/rust.ungram b/src/tools/rust-analyzer/crates/syntax/rust.ungram index a0ae0d68581a..10abca7d35d9 100644 --- a/src/tools/rust-analyzer/crates/syntax/rust.ungram +++ b/src/tools/rust-analyzer/crates/syntax/rust.ungram @@ -133,6 +133,7 @@ Meta = SourceFile = '#shebang'? + '#frontmatter'? Attr* Item* diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs index 1243f6418fe2..cd9f4dba8908 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs @@ -1524,6 +1524,10 @@ impl ast::HasAttrs for SourceFile {} impl ast::HasDocComments for SourceFile {} impl ast::HasModuleItem for SourceFile {} impl SourceFile { + #[inline] + pub fn frontmatter_token(&self) -> Option { + support::token(&self.syntax, T![frontmatter]) + } #[inline] pub fn shebang_token(&self) -> Option { support::token(&self.syntax, T![shebang]) } } diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs index d608a35effa1..596f73e0b103 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs @@ -69,6 +69,9 @@ pub mod ext { pub fn expr_todo() -> ast::Expr { expr_from_text("todo!()") } + pub fn expr_underscore() -> ast::Expr { + expr_from_text("_") + } pub fn expr_ty_default(ty: &ast::Type) -> ast::Expr { expr_from_text(&format!("{ty}::default()")) } @@ -706,7 +709,7 @@ pub fn wildcard_pat() -> ast::WildcardPat { } pub fn rest_pat() -> ast::RestPat { - ast_from_text("fn f(..)") + ast_from_text("fn f() { let ..; }") } pub fn literal_pat(lit: &str) -> ast::LiteralPat { @@ -785,8 +788,8 @@ pub fn record_pat_field(name_ref: ast::NameRef, pat: ast::Pat) -> ast::RecordPat ast_from_text(&format!("fn f(S {{ {name_ref}: {pat} }}: ()))")) } -pub fn record_pat_field_shorthand(name_ref: ast::NameRef) -> ast::RecordPatField { - ast_from_text(&format!("fn f(S {{ {name_ref} }}: ()))")) +pub fn record_pat_field_shorthand(pat: ast::Pat) -> ast::RecordPatField { + ast_from_text(&format!("fn f(S {{ {pat} }}: ()))")) } /// Returns a `IdentPat` if the path has just one segment, a `PathPat` otherwise. @@ -798,16 +801,38 @@ pub fn path_pat(path: ast::Path) -> ast::Pat { } /// Returns a `Pat` if the path has just one segment, an `OrPat` otherwise. -pub fn or_pat(pats: impl IntoIterator, leading_pipe: bool) -> ast::Pat { +/// +/// Invariant: `pats` must be length > 1. +pub fn or_pat(pats: impl IntoIterator, leading_pipe: bool) -> ast::OrPat { let leading_pipe = if leading_pipe { "| " } else { "" }; let pats = pats.into_iter().join(" | "); return from_text(&format!("{leading_pipe}{pats}")); - fn from_text(text: &str) -> ast::Pat { + fn from_text(text: &str) -> ast::OrPat { ast_from_text(&format!("fn f({text}: ())")) } } +pub fn box_pat(pat: ast::Pat) -> ast::BoxPat { + ast_from_text(&format!("fn f(box {pat}: ())")) +} + +pub fn paren_pat(pat: ast::Pat) -> ast::ParenPat { + ast_from_text(&format!("fn f(({pat}): ())")) +} + +pub fn range_pat(start: Option, end: Option) -> ast::RangePat { + ast_from_text(&format!( + "fn f({}..{}: ())", + start.map(|e| e.to_string()).unwrap_or_default(), + end.map(|e| e.to_string()).unwrap_or_default() + )) +} + +pub fn ref_pat(pat: ast::Pat) -> ast::RefPat { + ast_from_text(&format!("fn f(&{pat}: ())")) +} + pub fn match_arm(pat: ast::Pat, guard: Option, expr: ast::Expr) -> ast::MatchArm { return match guard { Some(guard) => from_text(&format!("{pat} {guard} => {expr}")), diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs index 1854000d3db2..8dee3964d448 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs @@ -3,7 +3,7 @@ use crate::{ AstNode, NodeOrToken, SyntaxKind, SyntaxNode, SyntaxToken, ast::{ self, HasArgList, HasGenericArgs, HasGenericParams, HasLoopBody, HasName, HasTypeBounds, - HasVisibility, make, + HasVisibility, RangeItem, make, }, syntax_editor::SyntaxMappingBuilder, }; @@ -107,6 +107,20 @@ impl SyntaxFactory { ast } + pub fn use_(&self, visibility: Option, use_tree: ast::UseTree) -> ast::Use { + make::use_(visibility, use_tree).clone_for_update() + } + + pub fn use_tree( + &self, + path: ast::Path, + use_tree_list: Option, + alias: Option, + add_star: bool, + ) -> ast::UseTree { + make::use_tree(path, use_tree_list, alias, add_star).clone_for_update() + } + pub fn path_unqualified(&self, segment: ast::PathSegment) -> ast::Path { let ast = make::path_unqualified(segment.clone()).clone_for_update(); @@ -254,12 +268,12 @@ impl SyntaxFactory { ast } - pub fn record_pat_field_shorthand(&self, name_ref: ast::NameRef) -> ast::RecordPatField { - let ast = make::record_pat_field_shorthand(name_ref.clone()).clone_for_update(); + pub fn record_pat_field_shorthand(&self, pat: ast::Pat) -> ast::RecordPatField { + let ast = make::record_pat_field_shorthand(pat.clone()).clone_for_update(); if let Some(mut mapping) = self.mappings() { let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); - builder.map_node(name_ref.syntax().clone(), ast.pat().unwrap().syntax().clone()); + builder.map_node(pat.syntax().clone(), ast.pat().unwrap().syntax().clone()); builder.finish(&mut mapping); } @@ -294,6 +308,76 @@ impl SyntaxFactory { make::rest_pat().clone_for_update() } + pub fn or_pat( + &self, + pats: impl IntoIterator, + leading_pipe: bool, + ) -> ast::OrPat { + let (pats, input) = iterator_input(pats); + let ast = make::or_pat(pats, leading_pipe).clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_children(input, ast.pats().map(|it| it.syntax().clone())); + builder.finish(&mut mapping); + } + + ast + } + + pub fn box_pat(&self, pat: ast::Pat) -> ast::BoxPat { + let ast = make::box_pat(pat.clone()).clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_node(pat.syntax().clone(), ast.pat().unwrap().syntax().clone()); + builder.finish(&mut mapping); + } + + ast + } + + pub fn paren_pat(&self, pat: ast::Pat) -> ast::ParenPat { + let ast = make::paren_pat(pat.clone()).clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_node(pat.syntax().clone(), ast.pat().unwrap().syntax().clone()); + builder.finish(&mut mapping); + } + + ast + } + + pub fn range_pat(&self, start: Option, end: Option) -> ast::RangePat { + let ast = make::range_pat(start.clone(), end.clone()).clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + if let Some(start) = start { + builder.map_node(start.syntax().clone(), ast.start().unwrap().syntax().clone()); + } + if let Some(end) = end { + builder.map_node(end.syntax().clone(), ast.end().unwrap().syntax().clone()); + } + builder.finish(&mut mapping); + } + + ast + } + + pub fn ref_pat(&self, pat: ast::Pat) -> ast::RefPat { + let ast = make::ref_pat(pat.clone()).clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_node(pat.syntax().clone(), ast.pat().unwrap().syntax().clone()); + builder.finish(&mut mapping); + } + + ast + } + pub fn block_expr( &self, statements: impl IntoIterator, @@ -673,6 +757,38 @@ impl SyntaxFactory { ast } + pub fn let_else_stmt( + &self, + pattern: ast::Pat, + ty: Option, + initializer: ast::Expr, + diverging: ast::BlockExpr, + ) -> ast::LetStmt { + let ast = make::let_else_stmt( + pattern.clone(), + ty.clone(), + initializer.clone(), + diverging.clone(), + ) + .clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_node(pattern.syntax().clone(), ast.pat().unwrap().syntax().clone()); + if let Some(input) = ty { + builder.map_node(input.syntax().clone(), ast.ty().unwrap().syntax().clone()); + } + builder.map_node( + initializer.syntax().clone(), + ast.initializer().unwrap().syntax().clone(), + ); + builder.map_node(diverging.syntax().clone(), ast.let_else().unwrap().syntax().clone()); + builder.finish(&mut mapping); + } + + ast + } + pub fn type_arg(&self, ty: ast::Type) -> ast::TypeArg { let ast = make::type_arg(ty.clone()).clone_for_update(); diff --git a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs index 58200189c46b..31caf618be90 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs @@ -20,6 +20,7 @@ mod edit_algo; mod edits; mod mapping; +pub use edits::Removable; pub use mapping::{SyntaxMapping, SyntaxMappingBuilder}; #[derive(Debug)] diff --git a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edit_algo.rs b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edit_algo.rs index 6a9c88b55d7e..01c1f0d49bfd 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edit_algo.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edit_algo.rs @@ -391,7 +391,7 @@ fn report_intersecting_changes( fn to_owning_node(element: &SyntaxElement) -> SyntaxNode { match element { SyntaxElement::Node(node) => node.clone(), - SyntaxElement::Token(token) => token.parent().unwrap().clone(), + SyntaxElement::Token(token) => token.parent().unwrap(), } } diff --git a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edits.rs b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edits.rs index 350cb3e2544f..d66ea8aa28cf 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edits.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor/edits.rs @@ -1,7 +1,8 @@ //! Structural editing for ast using `SyntaxEditor` use crate::{ - Direction, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken, T, + AstToken, Direction, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken, T, + algo::neighbor, ast::{ self, AstNode, Fn, GenericParam, HasGenericParams, HasName, edit::IndentLevel, make, syntax_factory::SyntaxFactory, @@ -143,6 +144,53 @@ fn normalize_ws_between_braces(editor: &mut SyntaxEditor, node: &SyntaxNode) -> Some(()) } +pub trait Removable: AstNode { + fn remove(&self, editor: &mut SyntaxEditor); +} + +impl Removable for ast::Use { + fn remove(&self, editor: &mut SyntaxEditor) { + let make = SyntaxFactory::without_mappings(); + + let next_ws = self + .syntax() + .next_sibling_or_token() + .and_then(|it| it.into_token()) + .and_then(ast::Whitespace::cast); + if let Some(next_ws) = next_ws { + let ws_text = next_ws.syntax().text(); + if let Some(rest) = ws_text.strip_prefix('\n') { + if rest.is_empty() { + editor.delete(next_ws.syntax()); + } else { + editor.replace(next_ws.syntax(), make.whitespace(rest)); + } + } + } + + editor.delete(self.syntax()); + } +} + +impl Removable for ast::UseTree { + fn remove(&self, editor: &mut SyntaxEditor) { + for dir in [Direction::Next, Direction::Prev] { + if let Some(next_use_tree) = neighbor(self, dir) { + let separators = self + .syntax() + .siblings_with_tokens(dir) + .skip(1) + .take_while(|it| it.as_node() != Some(next_use_tree.syntax())); + for sep in separators { + editor.delete(sep); + } + break; + } + } + editor.delete(self.syntax()); + } +} + #[cfg(test)] mod tests { use parser::Edition; diff --git a/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs b/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs index 2f379d419e8f..f6ca5ab6c8c5 100644 --- a/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs +++ b/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs @@ -353,7 +353,7 @@ impl ChangeFixture { )]), CrateOrigin::Local { repo: None, name: None }, true, - proc_macro_cwd.clone(), + proc_macro_cwd, crate_ws_data, ); proc_macros.insert(proc_macros_crate, Ok(proc_macro)); diff --git a/src/tools/rust-analyzer/crates/tt/src/lib.rs b/src/tools/rust-analyzer/crates/tt/src/lib.rs index 36ccb67f3b8d..1dbc07c0929c 100644 --- a/src/tools/rust-analyzer/crates/tt/src/lib.rs +++ b/src/tools/rust-analyzer/crates/tt/src/lib.rs @@ -728,9 +728,9 @@ fn print_debug_subtree( }; write!(f, "{align}SUBTREE {delim} ",)?; - write!(f, "{:#?}", open)?; + write!(f, "{open:#?}")?; write!(f, " ")?; - write!(f, "{:#?}", close)?; + write!(f, "{close:#?}")?; for child in iter { writeln!(f)?; print_debug_token(f, level + 1, child)?; @@ -855,7 +855,7 @@ impl fmt::Display for Literal { } }?; if let Some(suffix) = &self.suffix { - write!(f, "{}", suffix)?; + write!(f, "{suffix}")?; } Ok(()) } diff --git a/src/tools/rust-analyzer/crates/vfs-notify/src/lib.rs b/src/tools/rust-analyzer/crates/vfs-notify/src/lib.rs index e918fd0887db..a03337dbc51e 100644 --- a/src/tools/rust-analyzer/crates/vfs-notify/src/lib.rs +++ b/src/tools/rust-analyzer/crates/vfs-notify/src/lib.rs @@ -38,8 +38,7 @@ impl loader::Handle for NotifyHandle { fn spawn(sender: loader::Sender) -> NotifyHandle { let actor = NotifyActor::new(sender); let (sender, receiver) = unbounded::(); - let thread = stdx::thread::Builder::new(stdx::thread::ThreadIntent::Worker) - .name("VfsLoader".to_owned()) + let thread = stdx::thread::Builder::new(stdx::thread::ThreadIntent::Worker, "VfsLoader") .spawn(move || actor.run(receiver)) .expect("failed to spawn thread"); NotifyHandle { sender, _thread: thread } diff --git a/src/tools/rust-analyzer/rust-version b/src/tools/rust-analyzer/rust-version index 09c127f6bcd8..90e4d65bf961 100644 --- a/src/tools/rust-analyzer/rust-version +++ b/src/tools/rust-analyzer/rust-version @@ -1 +1 @@ -21079f53a359d9fc82668d4175d49dafdb600563 +6e23095adf9209614a45f7f75fea36dad7b92afb diff --git a/src/tools/rust-analyzer/xtask/src/codegen/grammar.rs b/src/tools/rust-analyzer/xtask/src/codegen/grammar.rs index 82df78c1a898..824b38fc872d 100644 --- a/src/tools/rust-analyzer/xtask/src/codegen/grammar.rs +++ b/src/tools/rust-analyzer/xtask/src/codegen/grammar.rs @@ -414,7 +414,7 @@ fn generate_nodes(kinds: KindsSrc, grammar: &AstSrc) -> String { .map(|kind| to_pascal_case(kind)) .filter(|name| !defined_nodes.iter().any(|&it| it == name)) { - eprintln!("Warning: node {} not defined in AST source", node); + eprintln!("Warning: node {node} not defined in AST source"); drop(node); } @@ -670,6 +670,7 @@ fn generate_syntax_kinds(grammar: KindsSrc) -> String { [ident] => { $crate::SyntaxKind::IDENT }; [string] => { $crate::SyntaxKind::STRING }; [shebang] => { $crate::SyntaxKind::SHEBANG }; + [frontmatter] => { $crate::SyntaxKind::FRONTMATTER }; } impl ::core::marker::Copy for SyntaxKind {} diff --git a/src/tools/rust-analyzer/xtask/src/codegen/parser_inline_tests.rs b/src/tools/rust-analyzer/xtask/src/codegen/parser_inline_tests.rs index f3b786b9d867..ae53771fe8e5 100644 --- a/src/tools/rust-analyzer/xtask/src/codegen/parser_inline_tests.rs +++ b/src/tools/rust-analyzer/xtask/src/codegen/parser_inline_tests.rs @@ -159,7 +159,7 @@ fn collect_tests(s: &str) -> Vec { (name.to_owned(), Some(edition.to_owned())) } [name] => (name.to_owned(), None), - _ => panic!("invalid test name: {:?}", name), + _ => panic!("invalid test name: {name:?}"), }; let text: String = edition .as_ref() @@ -212,7 +212,7 @@ fn existing_tests(dir: &Path, ok: TestKind) -> Result( ) } -/// Decorates `ra_build_cmd` to add PGO instrumentation, and then runs the PGO instrumented -/// Rust Analyzer on itself to gather a PGO profile. -fn gather_pgo_profile<'a>( - sh: &'a Shell, - ra_build_cmd: Cmd<'a>, - target: &str, - train_crate: PgoTrainingCrate, -) -> anyhow::Result { - let pgo_dir = std::path::absolute("rust-analyzer-pgo")?; - // Clear out any stale profiles - if pgo_dir.is_dir() { - std::fs::remove_dir_all(&pgo_dir)?; - } - std::fs::create_dir_all(&pgo_dir)?; - - // Figure out a path to `llvm-profdata` - let target_libdir = cmd!(sh, "rustc --print=target-libdir") - .read() - .context("cannot resolve target-libdir from rustc")?; - let target_bindir = PathBuf::from(target_libdir).parent().unwrap().join("bin"); - let llvm_profdata = target_bindir.join("llvm-profdata").with_extension(EXE_EXTENSION); - - // Build RA with PGO instrumentation - let cmd_gather = - ra_build_cmd.env("RUSTFLAGS", format!("-Cprofile-generate={}", pgo_dir.to_str().unwrap())); - cmd_gather.run().context("cannot build rust-analyzer with PGO instrumentation")?; - - let (train_path, label) = match &train_crate { - PgoTrainingCrate::RustAnalyzer => (PathBuf::from("."), "itself"), - PgoTrainingCrate::GitHub(repo) => { - (download_crate_for_training(sh, &pgo_dir, repo)?, repo.as_str()) - } - }; - - // Run RA either on itself or on a downloaded crate - eprintln!("Training RA on {label}..."); - cmd!( - sh, - "target/{target}/release/rust-analyzer analysis-stats -q --run-all-ide-things {train_path}" - ) - .run() - .context("cannot generate PGO profiles")?; - - // Merge profiles into a single file - let merged_profile = pgo_dir.join("merged.profdata"); - let profile_files = std::fs::read_dir(pgo_dir)?.filter_map(|entry| { - let entry = entry.ok()?; - if entry.path().extension() == Some(OsStr::new("profraw")) { - Some(entry.path().to_str().unwrap().to_owned()) - } else { - None - } - }); - cmd!(sh, "{llvm_profdata} merge {profile_files...} -o {merged_profile}").run().context( - "cannot merge PGO profiles. Do you have the rustup `llvm-tools` component installed?", - )?; - - Ok(merged_profile) -} - -/// Downloads a crate from GitHub, stores it into `pgo_dir` and returns a path to it. -fn download_crate_for_training(sh: &Shell, pgo_dir: &Path, repo: &str) -> anyhow::Result { - let mut it = repo.splitn(2, '@'); - let repo = it.next().unwrap(); - let revision = it.next(); - - // FIXME: switch to `--revision` here around 2035 or so - let revision = - if let Some(revision) = revision { &["--branch", revision] as &[&str] } else { &[] }; - - let normalized_path = repo.replace("/", "-"); - let target_path = pgo_dir.join(normalized_path); - cmd!(sh, "git clone --depth 1 https://github.com/{repo} {revision...} {target_path}") - .run() - .with_context(|| "cannot download PGO training crate from {repo}")?; - - Ok(target_path) -} - fn gzip(src_path: &Path, dest_path: &Path) -> anyhow::Result<()> { let mut encoder = GzEncoder::new(File::create(dest_path)?, Compression::best()); let mut input = io::BufReader::new(File::open(src_path)?); @@ -283,21 +201,8 @@ struct Target { } impl Target { - fn get(project_root: &Path) -> Self { - let name = match env::var("RA_TARGET") { - Ok(target) => target, - _ => { - if cfg!(target_os = "linux") { - "x86_64-unknown-linux-gnu".to_owned() - } else if cfg!(target_os = "windows") { - "x86_64-pc-windows-msvc".to_owned() - } else if cfg!(target_os = "macos") { - "x86_64-apple-darwin".to_owned() - } else { - panic!("Unsupported OS, maybe try setting RA_TARGET") - } - } - }; + fn get(project_root: &Path, sh: &Shell) -> Self { + let name = detect_target(sh); let (name, libc_suffix) = match name.split_once('.') { Some((l, r)) => (l.to_owned(), Some(r.to_owned())), None => (name, None), diff --git a/src/tools/rust-analyzer/xtask/src/flags.rs b/src/tools/rust-analyzer/xtask/src/flags.rs index 700806d178c3..2fd471b35c7e 100644 --- a/src/tools/rust-analyzer/xtask/src/flags.rs +++ b/src/tools/rust-analyzer/xtask/src/flags.rs @@ -4,6 +4,25 @@ use std::{fmt, str::FromStr}; use crate::install::{ClientOpt, ProcMacroServerOpt, ServerOpt}; +#[derive(Debug, Clone)] +pub enum PgoTrainingCrate { + // Use RA's own sources for PGO training + RustAnalyzer, + // Download a Rust crate from `https://github.com/{0}` and use it for PGO training. + GitHub(String), +} + +impl FromStr for PgoTrainingCrate { + type Err = String; + + fn from_str(s: &str) -> Result { + match s { + "rust-analyzer" => Ok(Self::RustAnalyzer), + url => Ok(Self::GitHub(url.to_owned())), + } + } +} + xflags::xflags! { src "./src/flags.rs" @@ -29,6 +48,9 @@ xflags::xflags! { /// build in release with debug info set to 2. optional --dev-rel + + /// Apply PGO optimizations + optional --pgo pgo: PgoTrainingCrate } cmd fuzz-tests {} @@ -109,18 +131,16 @@ pub enum XtaskCmd { Tidy(Tidy), } -#[derive(Debug)] -pub struct Tidy {} - #[derive(Debug)] pub struct Install { pub client: bool, pub code_bin: Option, pub server: bool, - pub proc_macro_server: bool, pub mimalloc: bool, pub jemalloc: bool, + pub proc_macro_server: bool, pub dev_rel: bool, + pub pgo: Option, } #[derive(Debug)] @@ -143,25 +163,6 @@ pub struct RustcPush { pub branch: Option, } -#[derive(Debug)] -pub enum PgoTrainingCrate { - // Use RA's own sources for PGO training - RustAnalyzer, - // Download a Rust crate from `https://github.com/{0}` and use it for PGO training. - GitHub(String), -} - -impl FromStr for PgoTrainingCrate { - type Err = String; - - fn from_str(s: &str) -> Result { - match s { - "rust-analyzer" => Ok(Self::RustAnalyzer), - url => Ok(Self::GitHub(url.to_owned())), - } - } -} - #[derive(Debug)] pub struct Dist { pub mimalloc: bool, @@ -195,6 +196,9 @@ pub struct Codegen { pub check: bool, } +#[derive(Debug)] +pub struct Tidy; + impl Xtask { #[allow(dead_code)] pub fn from_env_or_exit() -> Self { @@ -324,7 +328,7 @@ impl Install { } else { Malloc::System }; - Some(ServerOpt { malloc, dev_rel: self.dev_rel }) + Some(ServerOpt { malloc, dev_rel: self.dev_rel, pgo: self.pgo.clone() }) } pub(crate) fn proc_macro_server(&self) -> Option { if !self.proc_macro_server { diff --git a/src/tools/rust-analyzer/xtask/src/install.rs b/src/tools/rust-analyzer/xtask/src/install.rs index 4e2093f0691b..f0cc445dfa23 100644 --- a/src/tools/rust-analyzer/xtask/src/install.rs +++ b/src/tools/rust-analyzer/xtask/src/install.rs @@ -5,7 +5,10 @@ use std::{env, path::PathBuf, str}; use anyhow::{Context, bail, format_err}; use xshell::{Shell, cmd}; -use crate::flags::{self, Malloc}; +use crate::{ + flags::{self, Malloc, PgoTrainingCrate}, + util::detect_target, +}; impl flags::Install { pub(crate) fn run(self, sh: &Shell) -> anyhow::Result<()> { @@ -35,6 +38,7 @@ const VS_CODES: &[&str] = &["code", "code-exploration", "code-insiders", "codium pub(crate) struct ServerOpt { pub(crate) malloc: Malloc, pub(crate) dev_rel: bool, + pub(crate) pgo: Option, } pub(crate) struct ProcMacroServerOpt { @@ -135,21 +139,33 @@ fn install_server(sh: &Shell, opts: ServerOpt) -> anyhow::Result<()> { let features = opts.malloc.to_features(); let profile = if opts.dev_rel { "dev-rel" } else { "release" }; - let cmd = cmd!( + let mut install_cmd = cmd!( sh, "cargo install --path crates/rust-analyzer --profile={profile} --locked --force --features force-always-assert {features...}" ); - cmd.run()?; + + if let Some(train_crate) = opts.pgo { + let build_cmd = cmd!( + sh, + "cargo build --manifest-path ./crates/rust-analyzer/Cargo.toml --bin rust-analyzer --profile={profile} --locked --features force-always-assert {features...}" + ); + + let target = detect_target(sh); + let profile = crate::pgo::gather_pgo_profile(sh, build_cmd, &target, train_crate)?; + install_cmd = crate::pgo::apply_pgo_to_cmd(install_cmd, &profile); + } + + install_cmd.run()?; Ok(()) } fn install_proc_macro_server(sh: &Shell, opts: ProcMacroServerOpt) -> anyhow::Result<()> { let profile = if opts.dev_rel { "dev-rel" } else { "release" }; - let cmd = cmd!( + cmd!( sh, "cargo +nightly install --path crates/proc-macro-srv-cli --profile={profile} --locked --force --features sysroot-abi" - ); - cmd.run()?; + ).run()?; + Ok(()) } diff --git a/src/tools/rust-analyzer/xtask/src/main.rs b/src/tools/rust-analyzer/xtask/src/main.rs index 52ea896c734d..aaa8d0e1d4d4 100644 --- a/src/tools/rust-analyzer/xtask/src/main.rs +++ b/src/tools/rust-analyzer/xtask/src/main.rs @@ -22,6 +22,7 @@ mod codegen; mod dist; mod install; mod metrics; +mod pgo; mod publish; mod release; mod tidy; diff --git a/src/tools/rust-analyzer/xtask/src/pgo.rs b/src/tools/rust-analyzer/xtask/src/pgo.rs new file mode 100644 index 000000000000..7f7b3311d962 --- /dev/null +++ b/src/tools/rust-analyzer/xtask/src/pgo.rs @@ -0,0 +1,105 @@ +//! PGO (Profile-Guided Optimization) utilities. + +use anyhow::Context; +use std::env::consts::EXE_EXTENSION; +use std::ffi::OsStr; +use std::path::{Path, PathBuf}; +use xshell::{Cmd, Shell, cmd}; + +use crate::flags::PgoTrainingCrate; + +/// Decorates `ra_build_cmd` to add PGO instrumentation, and then runs the PGO instrumented +/// Rust Analyzer on itself to gather a PGO profile. +pub(crate) fn gather_pgo_profile<'a>( + sh: &'a Shell, + ra_build_cmd: Cmd<'a>, + target: &str, + train_crate: PgoTrainingCrate, +) -> anyhow::Result { + let pgo_dir = std::path::absolute("rust-analyzer-pgo")?; + // Clear out any stale profiles + if pgo_dir.is_dir() { + std::fs::remove_dir_all(&pgo_dir)?; + } + std::fs::create_dir_all(&pgo_dir)?; + + // Figure out a path to `llvm-profdata` + let target_libdir = cmd!(sh, "rustc --print=target-libdir") + .read() + .context("cannot resolve target-libdir from rustc")?; + let target_bindir = PathBuf::from(target_libdir).parent().unwrap().join("bin"); + let llvm_profdata = target_bindir.join("llvm-profdata").with_extension(EXE_EXTENSION); + + // Build RA with PGO instrumentation + let cmd_gather = + ra_build_cmd.env("RUSTFLAGS", format!("-Cprofile-generate={}", pgo_dir.to_str().unwrap())); + cmd_gather.run().context("cannot build rust-analyzer with PGO instrumentation")?; + + let (train_path, label) = match &train_crate { + PgoTrainingCrate::RustAnalyzer => (PathBuf::from("."), "itself"), + PgoTrainingCrate::GitHub(repo) => { + (download_crate_for_training(sh, &pgo_dir, repo)?, repo.as_str()) + } + }; + + // Run RA either on itself or on a downloaded crate + eprintln!("Training RA on {label}..."); + cmd!( + sh, + "target/{target}/release/rust-analyzer analysis-stats -q --run-all-ide-things {train_path}" + ) + .run() + .context("cannot generate PGO profiles")?; + + // Merge profiles into a single file + let merged_profile = pgo_dir.join("merged.profdata"); + let profile_files = std::fs::read_dir(pgo_dir)?.filter_map(|entry| { + let entry = entry.ok()?; + if entry.path().extension() == Some(OsStr::new("profraw")) { + Some(entry.path().to_str().unwrap().to_owned()) + } else { + None + } + }); + cmd!(sh, "{llvm_profdata} merge {profile_files...} -o {merged_profile}").run().context( + "cannot merge PGO profiles. Do you have the rustup `llvm-tools` component installed?", + )?; + + Ok(merged_profile) +} + +/// Downloads a crate from GitHub, stores it into `pgo_dir` and returns a path to it. +fn download_crate_for_training(sh: &Shell, pgo_dir: &Path, repo: &str) -> anyhow::Result { + let mut it = repo.splitn(2, '@'); + let repo = it.next().unwrap(); + let revision = it.next(); + + // FIXME: switch to `--revision` here around 2035 or so + let revision = + if let Some(revision) = revision { &["--branch", revision] as &[&str] } else { &[] }; + + let normalized_path = repo.replace("/", "-"); + let target_path = pgo_dir.join(normalized_path); + cmd!(sh, "git clone --depth 1 https://github.com/{repo} {revision...} {target_path}") + .run() + .with_context(|| "cannot download PGO training crate from {repo}")?; + + Ok(target_path) +} + +/// Helper function to create a build command for rust-analyzer +pub(crate) fn build_command<'a>( + sh: &'a Shell, + command: &str, + target_name: &str, + features: &[&str], +) -> Cmd<'a> { + cmd!( + sh, + "cargo {command} --manifest-path ./crates/rust-analyzer/Cargo.toml --bin rust-analyzer --target {target_name} {features...} --release" + ) +} + +pub(crate) fn apply_pgo_to_cmd<'a>(cmd: Cmd<'a>, profile_path: &Path) -> Cmd<'a> { + cmd.env("RUSTFLAGS", format!("-Cprofile-use={}", profile_path.to_str().unwrap())) +} diff --git a/src/tools/rust-analyzer/xtask/src/util.rs b/src/tools/rust-analyzer/xtask/src/util.rs index 39f52938c8c6..e5404d571717 100644 --- a/src/tools/rust-analyzer/xtask/src/util.rs +++ b/src/tools/rust-analyzer/xtask/src/util.rs @@ -1,5 +1,7 @@ use std::path::{Path, PathBuf}; +use xshell::{Shell, cmd}; + pub(crate) fn list_rust_files(dir: &Path) -> Vec { let mut res = list_files(dir); res.retain(|it| { @@ -29,3 +31,13 @@ pub(crate) fn list_files(dir: &Path) -> Vec { } res } + +pub(crate) fn detect_target(sh: &Shell) -> String { + match std::env::var("RA_TARGET") { + Ok(target) => target, + _ => match cmd!(sh, "rustc --print=host-tuple").read() { + Ok(target) => target, + Err(e) => panic!("Failed to detect target: {e}\nPlease set RA_TARGET explicitly"), + }, + } +} diff --git a/src/tools/rustbook/Cargo.lock b/src/tools/rustbook/Cargo.lock index fb584103df5d..3b5b31bed14a 100644 --- a/src/tools/rustbook/Cargo.lock +++ b/src/tools/rustbook/Cargo.lock @@ -19,13 +19,13 @@ dependencies = [ [[package]] name = "ammonia" -version = "4.0.0" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ab99eae5ee58501ab236beb6f20f6ca39be615267b014899c89b2f0bc18a459" +checksum = "3ada2ee439075a3e70b6992fce18ac4e407cd05aea9ca3f75d2c0b0c20bbb364" dependencies = [ + "cssparser", "html5ever", "maplit", - "once_cell", "tendril", "url", ] @@ -97,9 +97,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.97" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f" +checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" [[package]] name = "autocfg" @@ -156,9 +156,9 @@ checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" [[package]] name = "cc" -version = "1.2.19" +version = "1.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e3a13707ac958681c13b39b458c073d0d9bc8a22cb1b2f4c8e55eb72c13f362" +checksum = "8691782945451c1c383942c4874dbe63814f61cb57ef773cda2972682b7bb3c0" dependencies = [ "shlex", ] @@ -171,9 +171,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.40" +version = "0.4.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c" +checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" dependencies = [ "android-tzdata", "iana-time-zone", @@ -185,9 +185,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.36" +version = "4.5.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2df961d8c8a0d08aa9945718ccf584145eee3f3aa06cddbeac12933781102e04" +checksum = "eccb054f56cbd38340b380d4a8e69ef1f02f1af43db2f0cc817a4774d80ae071" dependencies = [ "clap_builder", "clap_derive", @@ -195,9 +195,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.36" +version = "4.5.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "132dbda40fb6753878316a489d5a1242a8ef2f0d9e47ba01c951ea8aa7d013a5" +checksum = "efd9466fac8543255d3b1fcad4762c5e116ffe808c8a3043d4263cd4fd4862a2" dependencies = [ "anstream", "anstyle", @@ -208,9 +208,9 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.5.47" +version = "4.5.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06f5378ea264ad4f82bbc826628b5aad714a75abf6ece087e923010eb937fb6" +checksum = "be8c97f3a6f02b9e24cadc12aaba75201d18754b53ea0a9d99642f806ccdb4c9" dependencies = [ "clap", ] @@ -273,6 +273,29 @@ dependencies = [ "typenum", ] +[[package]] +name = "cssparser" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e901edd733a1472f944a45116df3f846f54d37e67e68640ac8bb69689aca2aa" +dependencies = [ + "cssparser-macros", + "dtoa-short", + "itoa", + "phf", + "smallvec", +] + +[[package]] +name = "cssparser-macros" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" +dependencies = [ + "quote", + "syn", +] + [[package]] name = "darling" version = "0.20.11" @@ -389,6 +412,21 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" +[[package]] +name = "dtoa" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6add3b8cff394282be81f3fc1a0605db594ed69890078ca6e2cab1c408bcf04" + +[[package]] +name = "dtoa-short" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd1511a7b6a56299bd043a9c167a6d2bfb37bf84a6dfceaba651168adfb43c87" +dependencies = [ + "dtoa", +] + [[package]] name = "elasticlunr-rs" version = "3.0.2" @@ -537,9 +575,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.2" +version = "0.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3" [[package]] name = "heck" @@ -555,16 +593,14 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "html5ever" -version = "0.27.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c13771afe0e6e846f1e67d038d4cb29998a6779f93c809212e4e9c32efd244d4" +checksum = "953cbbe631aae7fc0a112702ad5d3aaf09da38beaf45ea84610d6e1c358f569c" dependencies = [ "log", "mac", "markup5ever", - "proc-macro2", - "quote", - "syn", + "match_token", ] [[package]] @@ -775,9 +811,9 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "jiff" -version = "0.2.6" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f33145a5cbea837164362c7bd596106eb7c5198f97d1ba6f6ebb3223952e488" +checksum = "d07d8d955d798e7a4d6f9c58cd1f1916e790b42b092758a9ef6e16fef9f1b3fd" dependencies = [ "jiff-static", "log", @@ -788,9 +824,9 @@ dependencies = [ [[package]] name = "jiff-static" -version = "0.2.6" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43ce13c40ec6956157a3635d97a1ee2df323b263f09ea14165131289cb0f5c19" +checksum = "f244cfe006d98d26f859c7abd1318d85327e1882dc9cef80f62daeeb0adcf300" dependencies = [ "proc-macro2", "quote", @@ -815,9 +851,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.171" +version = "0.2.172" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" +checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" [[package]] name = "libdbus-sys" @@ -880,23 +916,31 @@ checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" [[package]] name = "markup5ever" -version = "0.12.1" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16ce3abbeba692c8b8441d036ef91aea6df8da2c6b6e21c7e14d3c18e526be45" +checksum = "d0a8096766c229e8c88a3900c9b44b7e06aa7f7343cc229158c3e58ef8f9973a" dependencies = [ "log", - "phf", - "phf_codegen", - "string_cache", - "string_cache_codegen", "tendril", + "web_atoms", +] + +[[package]] +name = "match_token" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88a9689d8d44bf9964484516275f5cd4c9b59457a6940c1d5d0ecbb94510a36b" +dependencies = [ + "proc-macro2", + "quote", + "syn", ] [[package]] name = "mdbook" -version = "0.4.48" +version = "0.4.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b6fbb4ac2d9fd7aa987c3510309ea3c80004a968d063c42f0d34fea070817c1" +checksum = "d1daacee059634081dee4250d2814763a365b92dfe14bfdef964bc27835209d4" dependencies = [ "ammonia", "anyhow", @@ -971,7 +1015,7 @@ dependencies = [ "pulldown-cmark-to-cmark 19.0.1", "serde_json", "thiserror 1.0.69", - "toml 0.8.20", + "toml 0.8.22", ] [[package]] @@ -1154,6 +1198,7 @@ version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" dependencies = [ + "phf_macros", "phf_shared", ] @@ -1177,6 +1222,19 @@ dependencies = [ "rand", ] +[[package]] +name = "phf_macros" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216" +dependencies = [ + "phf_generator", + "phf_shared", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "phf_shared" version = "0.11.3" @@ -1224,9 +1282,9 @@ checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" [[package]] name = "proc-macro2" -version = "1.0.94" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" dependencies = [ "unicode-ident", ] @@ -1327,9 +1385,9 @@ checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" [[package]] name = "redox_syscall" -version = "0.5.11" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2f103c6d277498fbceb16e84d317e2a400f160f46904d5f5410848c829511a3" +checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af" dependencies = [ "bitflags 2.9.0", ] @@ -1377,9 +1435,9 @@ dependencies = [ [[package]] name = "rustix" -version = "1.0.5" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d97817398dd4bb2e6da002002db259209759911da105da92bec29ccb12cf58bf" +checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" dependencies = [ "bitflags 2.9.0", "errno", @@ -1464,9 +1522,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.8" +version = "0.10.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", "cpufeatures", @@ -1530,9 +1588,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" -version = "2.0.100" +version = "2.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" +checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" dependencies = [ "proc-macro2", "quote", @@ -1541,9 +1599,9 @@ dependencies = [ [[package]] name = "synstructure" -version = "0.13.1" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", @@ -1671,9 +1729,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.20" +version = "0.8.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148" +checksum = "05ae329d1f08c4d17a59bed7ff5b5a769d062e64a62d34a3261b219e62cd5aae" dependencies = [ "serde", "serde_spanned", @@ -1683,26 +1741,33 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.8" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +checksum = "3da5db5a963e24bc68be8b17b6fa82814bb22ee8660f192bb182771d498f09a3" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.22.24" +version = "0.22.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474" +checksum = "310068873db2c5b3e7659d2cc35d21855dbafa50d1ce336397c666e3cb08137e" dependencies = [ "indexmap", "serde", "serde_spanned", "toml_datetime", + "toml_write", "winnow", ] +[[package]] +name = "toml_write" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfb942dfe1d8e29a7ee7fcbde5bd2b9a25fb89aa70caea2eba3bee836ff41076" + [[package]] name = "topological-sort" version = "0.2.2" @@ -1857,6 +1922,18 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "web_atoms" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08bcbdcad8fb2e316072ba6bbe09419afdb550285668ac2534f4230a6f2da0ee" +dependencies = [ + "phf", + "phf_codegen", + "string_cache", + "string_cache_codegen", +] + [[package]] name = "winapi" version = "0.3.9" @@ -2022,9 +2099,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.7.6" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63d3fcd9bba44b03821e7d699eeee959f3126dcc4aa8e4ae18ec617c2a5cea10" +checksum = "d9fb597c990f03753e08d3c29efbfcf2019a003b4bf4ba19225c158e1549f0f3" dependencies = [ "memchr", ] diff --git a/src/tools/rustbook/Cargo.toml b/src/tools/rustbook/Cargo.toml index a0b220c3557d..10fde31306df 100644 --- a/src/tools/rustbook/Cargo.toml +++ b/src/tools/rustbook/Cargo.toml @@ -15,6 +15,6 @@ mdbook-i18n-helpers = "0.3.3" mdbook-spec = { path = "../../doc/reference/mdbook-spec" } [dependencies.mdbook] -version = "0.4.48" +version = "0.4.49" default-features = false features = ["search"] diff --git a/src/tools/rustdoc-gui-test/src/config.rs b/src/tools/rustdoc-gui-test/src/config.rs index 950e2fa478dc..b9d08a0a2950 100644 --- a/src/tools/rustdoc-gui-test/src/config.rs +++ b/src/tools/rustdoc-gui-test/src/config.rs @@ -20,8 +20,8 @@ pub(crate) struct Config { impl Config { pub(crate) fn from_args(args: Vec) -> Self { let mut opts = Options::new(); - opts.reqopt("", "nodejs", "absolute path of nodejs", "PATH") - .reqopt("", "npm", "absolute path of npm", "PATH") + opts.optopt("", "nodejs", "absolute path of nodejs", "PATH") + .optopt("", "npm", "absolute path of npm", "PATH") .reqopt("", "out-dir", "output path of doc compilation", "PATH") .reqopt("", "rust-src", "root source of the rust source", "PATH") .reqopt( @@ -47,9 +47,18 @@ impl Config { Err(f) => panic!("{:?}", f), }; + let Some(nodejs) = matches.opt_str("nodejs").map(PathBuf::from) else { + eprintln!("`nodejs` was not provided. If not available, please install it"); + std::process::exit(1); + }; + let Some(npm) = matches.opt_str("npm").map(PathBuf::from) else { + eprintln!("`npm` was not provided. If not available, please install it"); + std::process::exit(1); + }; + Self { - nodejs: matches.opt_str("nodejs").map(PathBuf::from).expect("nodejs isn't available"), - npm: matches.opt_str("npm").map(PathBuf::from).expect("npm isn't available"), + nodejs, + npm, rust_src: matches.opt_str("rust-src").map(PathBuf::from).unwrap(), out_dir: matches.opt_str("out-dir").map(PathBuf::from).unwrap(), initial_cargo: matches.opt_str("initial-cargo").map(PathBuf::from).unwrap(), diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 3c3ebf556c52..4195258af885 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -175,6 +175,9 @@ const EXCEPTIONS_RUSTC_PERF: ExceptionList = &[ const EXCEPTIONS_RUSTBOOK: ExceptionList = &[ // tidy-alphabetical-start + ("cssparser", "MPL-2.0"), + ("cssparser-macros", "MPL-2.0"), + ("dtoa-short", "MPL-2.0"), ("mdbook", "MPL-2.0"), ("ryu", "Apache-2.0 OR BSL-1.0"), // tidy-alphabetical-end @@ -459,7 +462,6 @@ const PERMITTED_STDLIB_DEPENDENCIES: &[&str] = &[ // tidy-alphabetical-start "addr2line", "adler2", - "allocator-api2", "cc", "cfg-if", "compiler_builtins", @@ -473,8 +475,6 @@ const PERMITTED_STDLIB_DEPENDENCIES: &[&str] = &[ "memchr", "miniz_oxide", "object", - "proc-macro2", - "quote", "r-efi", "r-efi-alloc", "rand", @@ -483,8 +483,6 @@ const PERMITTED_STDLIB_DEPENDENCIES: &[&str] = &[ "rustc-demangle", "rustc-literal-escaper", "shlex", - "syn", - "unicode-ident", "unicode-width", "unwinding", "wasi", @@ -498,8 +496,6 @@ const PERMITTED_STDLIB_DEPENDENCIES: &[&str] = &[ "windows_x86_64_gnu", "windows_x86_64_gnullvm", "windows_x86_64_msvc", - "zerocopy", - "zerocopy-derive", // tidy-alphabetical-end ]; diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index e6b5aa59622d..2f0158609e08 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -276,13 +276,7 @@ ui/auto-traits/issue-23080-2.rs ui/auto-traits/issue-23080.rs ui/auto-traits/issue-83857-ub.rs ui/auto-traits/issue-84075.rs -ui/auxiliary/issue-13560-1.rs -ui/auxiliary/issue-13560-2.rs -ui/auxiliary/issue-13560-3.rs ui/auxiliary/issue-16822.rs -ui/auxiliary/issue-18502.rs -ui/auxiliary/issue-24106.rs -ui/auxiliary/issue-76387.rs ui/bench/issue-32062.rs ui/binding/issue-40402-1.rs ui/binding/issue-40402-2.rs @@ -1378,12 +1372,8 @@ ui/intrinsics/issue-28575.rs ui/intrinsics/issue-84297-reifying-copy.rs ui/invalid/issue-114435-layout-type-err.rs ui/issue-11881.rs -ui/issue-13560.rs ui/issue-15924.rs ui/issue-16822.rs -ui/issue-18502.rs -ui/issue-24106.rs -ui/issue-76387-llvm-miscompile.rs ui/issues-71798.rs ui/issues/auxiliary/issue-11224.rs ui/issues/auxiliary/issue-11508.rs diff --git a/tests/codegen/const-vector.rs b/tests/codegen/const-vector.rs index 289b67371ce4..42921442e039 100644 --- a/tests/codegen/const-vector.rs +++ b/tests/codegen/const-vector.rs @@ -1,4 +1,8 @@ -//@ compile-flags: -C no-prepopulate-passes -Copt-level=0 +//@ revisions: OPT0 OPT0_S390X +//@ [OPT0] ignore-s390x +//@ [OPT0_S390X] only-s390x +//@ [OPT0] compile-flags: -C no-prepopulate-passes -Copt-level=0 +//@ [OPT0_S390X] compile-flags: -C no-prepopulate-passes -Copt-level=0 -C target-cpu=z13 // This test checks that constants of SIMD type are passed as immediate vectors. // We ensure that both vector representations (struct with fields and struct wrapping array) work. diff --git a/tests/codegen/intrinsics/select_unpredictable.rs b/tests/codegen/intrinsics/select_unpredictable.rs index 2db4ae174b33..ad7120c6fb8b 100644 --- a/tests/codegen/intrinsics/select_unpredictable.rs +++ b/tests/codegen/intrinsics/select_unpredictable.rs @@ -1,7 +1,6 @@ //@ compile-flags: -Copt-level=3 -Zmerge-functions=disabled #![feature(core_intrinsics)] -#![feature(select_unpredictable)] #![crate_type = "lib"] /* Test the intrinsic */ diff --git a/tests/codegen/simd/extract-insert-dyn.rs b/tests/codegen/simd/extract-insert-dyn.rs index 7d032c6bb3ef..729f0145314a 100644 --- a/tests/codegen/simd/extract-insert-dyn.rs +++ b/tests/codegen/simd/extract-insert-dyn.rs @@ -1,6 +1,12 @@ //@compile-flags: -C opt-level=3 -C no-prepopulate-passes -#![feature(core_intrinsics, repr_simd, arm_target_feature, mips_target_feature)] +#![feature( + core_intrinsics, + repr_simd, + arm_target_feature, + mips_target_feature, + s390x_target_feature +)] #![no_std] #![crate_type = "lib"] #![allow(non_camel_case_types)] @@ -25,6 +31,7 @@ pub struct i8x16([i8; 16]); #[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))] #[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))] #[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))] +#[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))] unsafe extern "C" fn dyn_simd_extract(x: i8x16, idx: u32) -> i8 { simd_extract_dyn(x, idx) } @@ -36,6 +43,7 @@ unsafe extern "C" fn dyn_simd_extract(x: i8x16, idx: u32) -> i8 { #[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))] #[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))] #[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))] +#[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))] unsafe extern "C" fn literal_dyn_simd_extract(x: i8x16) -> i8 { simd_extract_dyn(x, 7) } @@ -47,6 +55,7 @@ unsafe extern "C" fn literal_dyn_simd_extract(x: i8x16) -> i8 { #[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))] #[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))] #[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))] +#[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))] unsafe extern "C" fn const_dyn_simd_extract(x: i8x16) -> i8 { simd_extract_dyn(x, const { 3 + 4 }) } @@ -58,6 +67,7 @@ unsafe extern "C" fn const_dyn_simd_extract(x: i8x16) -> i8 { #[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))] #[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))] #[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))] +#[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))] unsafe extern "C" fn const_simd_extract(x: i8x16) -> i8 { simd_extract(x, const { 3 + 4 }) } @@ -69,6 +79,7 @@ unsafe extern "C" fn const_simd_extract(x: i8x16) -> i8 { #[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))] #[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))] #[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))] +#[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))] unsafe extern "C" fn dyn_simd_insert(x: i8x16, e: i8, idx: u32) -> i8x16 { simd_insert_dyn(x, idx, e) } @@ -80,6 +91,7 @@ unsafe extern "C" fn dyn_simd_insert(x: i8x16, e: i8, idx: u32) -> i8x16 { #[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))] #[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))] #[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))] +#[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))] unsafe extern "C" fn literal_dyn_simd_insert(x: i8x16, e: i8) -> i8x16 { simd_insert_dyn(x, 7, e) } @@ -91,6 +103,7 @@ unsafe extern "C" fn literal_dyn_simd_insert(x: i8x16, e: i8) -> i8x16 { #[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))] #[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))] #[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))] +#[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))] unsafe extern "C" fn const_dyn_simd_insert(x: i8x16, e: i8) -> i8x16 { simd_insert_dyn(x, const { 3 + 4 }, e) } @@ -102,6 +115,7 @@ unsafe extern "C" fn const_dyn_simd_insert(x: i8x16, e: i8) -> i8x16 { #[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))] #[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))] #[cfg_attr(target_arch = "mips", target_feature(enable = "msa"))] +#[cfg_attr(target_arch = "s390x", target_feature(enable = "vector"))] unsafe extern "C" fn const_simd_insert(x: i8x16, e: i8) -> i8x16 { simd_insert(x, const { 3 + 4 }, e) } diff --git a/tests/coverage/abort.cov-map b/tests/coverage/abort.cov-map index 26536caeba52..4d8ea874bd79 100644 --- a/tests/coverage/abort.cov-map +++ b/tests/coverage/abort.cov-map @@ -1,7 +1,7 @@ Function name: abort::main -Raw bytes (83): 0x[01, 01, 07, 05, 01, 05, 0b, 01, 09, 05, 13, 01, 0d, 05, 1b, 01, 11, 0d, 01, 0d, 01, 01, 1b, 05, 02, 0b, 00, 18, 02, 01, 0c, 00, 19, 09, 00, 1a, 02, 0a, 06, 02, 09, 00, 0a, 02, 02, 0c, 00, 19, 0d, 00, 1a, 00, 31, 0e, 00, 30, 00, 31, 02, 04, 0c, 00, 19, 11, 00, 1a, 00, 31, 16, 00, 30, 00, 31, 02, 01, 09, 00, 17, 01, 02, 05, 01, 02] +Raw bytes (98): 0x[01, 01, 07, 05, 01, 05, 0b, 01, 09, 05, 13, 01, 0d, 05, 1b, 01, 11, 10, 01, 0d, 01, 00, 1c, 01, 01, 09, 00, 16, 01, 00, 19, 00, 1b, 05, 01, 0b, 00, 18, 02, 01, 0c, 00, 19, 09, 00, 1a, 02, 0a, 06, 02, 09, 00, 0a, 02, 02, 0c, 00, 19, 0d, 00, 1a, 00, 31, 0e, 00, 30, 00, 31, 02, 04, 0c, 00, 19, 11, 00, 1a, 00, 31, 16, 00, 30, 00, 31, 02, 01, 09, 00, 17, 01, 02, 05, 00, 0b, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/abort.rs Number of expressions: 7 - expression 0 operands: lhs = Counter(1), rhs = Counter(0) - expression 1 operands: lhs = Counter(1), rhs = Expression(2, Add) @@ -10,9 +10,11 @@ Number of expressions: 7 - expression 4 operands: lhs = Counter(0), rhs = Counter(3) - expression 5 operands: lhs = Counter(1), rhs = Expression(6, Add) - expression 6 operands: lhs = Counter(0), rhs = Counter(4) -Number of file 0 mappings: 13 -- Code(Counter(0)) at (prev + 13, 1) to (start + 1, 27) -- Code(Counter(1)) at (prev + 2, 11) to (start + 0, 24) +Number of file 0 mappings: 16 +- Code(Counter(0)) at (prev + 13, 1) to (start + 0, 28) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 22) +- Code(Counter(0)) at (prev + 0, 25) to (start + 0, 27) +- Code(Counter(1)) at (prev + 1, 11) to (start + 0, 24) - Code(Expression(0, Sub)) at (prev + 1, 12) to (start + 0, 25) = (c1 - c0) - Code(Counter(2)) at (prev + 0, 26) to (start + 2, 10) @@ -30,19 +32,25 @@ Number of file 0 mappings: 13 = (c1 - (c0 + c4)) - Code(Expression(0, Sub)) at (prev + 1, 9) to (start + 0, 23) = (c1 - c0) -- Code(Counter(0)) at (prev + 2, 5) to (start + 1, 2) +- Code(Counter(0)) at (prev + 2, 5) to (start + 0, 11) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c4 Function name: abort::might_abort -Raw bytes (21): 0x[01, 01, 01, 01, 05, 03, 01, 03, 01, 01, 14, 05, 02, 09, 01, 0f, 02, 02, 0c, 03, 02] +Raw bytes (41): 0x[01, 01, 01, 01, 05, 07, 01, 03, 01, 00, 2e, 01, 01, 08, 00, 14, 05, 01, 09, 00, 11, 05, 00, 12, 00, 1f, 05, 01, 09, 00, 0f, 02, 01, 0c, 02, 06, 02, 03, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/abort.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 3 -- Code(Counter(0)) at (prev + 3, 1) to (start + 1, 20) -- Code(Counter(1)) at (prev + 2, 9) to (start + 1, 15) -- Code(Expression(0, Sub)) at (prev + 2, 12) to (start + 3, 2) +Number of file 0 mappings: 7 +- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 46) +- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 20) +- Code(Counter(1)) at (prev + 1, 9) to (start + 0, 17) +- Code(Counter(1)) at (prev + 0, 18) to (start + 0, 31) +- Code(Counter(1)) at (prev + 1, 9) to (start + 0, 15) +- Code(Expression(0, Sub)) at (prev + 1, 12) to (start + 2, 6) + = (c0 - c1) +- Code(Expression(0, Sub)) at (prev + 3, 1) to (start + 0, 2) = (c0 - c1) Highest counter ID seen: c1 diff --git a/tests/coverage/assert-ne.cov-map b/tests/coverage/assert-ne.cov-map index 27d4b0382dec..fde0d5184d67 100644 --- a/tests/coverage/assert-ne.cov-map +++ b/tests/coverage/assert-ne.cov-map @@ -1,16 +1,23 @@ Function name: assert_ne::main -Raw bytes (28): 0x[01, 01, 02, 01, 05, 01, 09, 04, 01, 08, 01, 03, 15, 05, 04, 0d, 00, 13, 02, 02, 0d, 00, 13, 06, 03, 05, 01, 02] +Raw bytes (55): 0x[01, 01, 03, 01, 05, 01, 09, 01, 09, 09, 01, 08, 01, 00, 0a, 01, 01, 05, 00, 0f, 01, 01, 09, 00, 12, 01, 00, 13, 00, 19, 01, 01, 0c, 00, 15, 05, 01, 0d, 00, 13, 02, 02, 0d, 00, 13, 0a, 03, 05, 00, 07, 0a, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 -Number of expressions: 2 +- file 0 => $DIR/assert-ne.rs +Number of expressions: 3 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(0), rhs = Counter(2) -Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 8, 1) to (start + 3, 21) -- Code(Counter(1)) at (prev + 4, 13) to (start + 0, 19) +- expression 2 operands: lhs = Counter(0), rhs = Counter(2) +Number of file 0 mappings: 9 +- Code(Counter(0)) at (prev + 8, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 15) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 18) +- Code(Counter(0)) at (prev + 0, 19) to (start + 0, 25) +- Code(Counter(0)) at (prev + 1, 12) to (start + 0, 21) +- Code(Counter(1)) at (prev + 1, 13) to (start + 0, 19) - Code(Expression(0, Sub)) at (prev + 2, 13) to (start + 0, 19) = (c0 - c1) -- Code(Expression(1, Sub)) at (prev + 3, 5) to (start + 1, 2) +- Code(Expression(2, Sub)) at (prev + 3, 5) to (start + 0, 7) + = (c0 - c2) +- Code(Expression(2, Sub)) at (prev + 1, 1) to (start + 0, 2) = (c0 - c2) Highest counter ID seen: c1 diff --git a/tests/coverage/assert.cov-map b/tests/coverage/assert.cov-map index 903cccfe9cbc..07a0d4c8c27e 100644 --- a/tests/coverage/assert.cov-map +++ b/tests/coverage/assert.cov-map @@ -1,7 +1,7 @@ Function name: assert::main -Raw bytes (61): 0x[01, 01, 06, 05, 01, 05, 17, 01, 09, 05, 13, 17, 0d, 01, 09, 09, 01, 09, 01, 01, 1b, 05, 02, 0b, 00, 18, 02, 01, 0c, 00, 1a, 09, 00, 1b, 02, 0a, 06, 02, 13, 00, 20, 0d, 00, 21, 02, 0a, 0e, 02, 09, 00, 0a, 02, 01, 09, 00, 17, 01, 02, 05, 01, 02] +Raw bytes (76): 0x[01, 01, 06, 05, 01, 05, 17, 01, 09, 05, 13, 17, 0d, 01, 09, 0c, 01, 09, 01, 00, 1c, 01, 01, 09, 00, 16, 01, 00, 19, 00, 1b, 05, 01, 0b, 00, 18, 02, 01, 0c, 00, 1a, 09, 00, 1b, 02, 0a, 06, 02, 13, 00, 20, 0d, 00, 21, 02, 0a, 0e, 02, 09, 00, 0a, 02, 01, 09, 00, 17, 01, 02, 05, 00, 0b, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/assert.rs Number of expressions: 6 - expression 0 operands: lhs = Counter(1), rhs = Counter(0) - expression 1 operands: lhs = Counter(1), rhs = Expression(5, Add) @@ -9,9 +9,11 @@ Number of expressions: 6 - expression 3 operands: lhs = Counter(1), rhs = Expression(4, Add) - expression 4 operands: lhs = Expression(5, Add), rhs = Counter(3) - expression 5 operands: lhs = Counter(0), rhs = Counter(2) -Number of file 0 mappings: 9 -- Code(Counter(0)) at (prev + 9, 1) to (start + 1, 27) -- Code(Counter(1)) at (prev + 2, 11) to (start + 0, 24) +Number of file 0 mappings: 12 +- Code(Counter(0)) at (prev + 9, 1) to (start + 0, 28) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 22) +- Code(Counter(0)) at (prev + 0, 25) to (start + 0, 27) +- Code(Counter(1)) at (prev + 1, 11) to (start + 0, 24) - Code(Expression(0, Sub)) at (prev + 1, 12) to (start + 0, 26) = (c1 - c0) - Code(Counter(2)) at (prev + 0, 27) to (start + 2, 10) @@ -22,18 +24,22 @@ Number of file 0 mappings: 9 = (c1 - ((c0 + c2) + c3)) - Code(Expression(0, Sub)) at (prev + 1, 9) to (start + 0, 23) = (c1 - c0) -- Code(Counter(0)) at (prev + 2, 5) to (start + 1, 2) +- Code(Counter(0)) at (prev + 2, 5) to (start + 0, 11) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c3 Function name: assert::might_fail_assert -Raw bytes (21): 0x[01, 01, 01, 01, 05, 03, 01, 04, 01, 02, 0f, 02, 02, 25, 00, 3d, 05, 01, 01, 00, 02] +Raw bytes (36): 0x[01, 01, 01, 01, 05, 06, 01, 04, 01, 00, 28, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 20, 01, 01, 05, 00, 0f, 02, 00, 25, 00, 3d, 05, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/assert.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 3 -- Code(Counter(0)) at (prev + 4, 1) to (start + 2, 15) -- Code(Expression(0, Sub)) at (prev + 2, 37) to (start + 0, 61) +Number of file 0 mappings: 6 +- Code(Counter(0)) at (prev + 4, 1) to (start + 0, 40) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 32) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 15) +- Code(Expression(0, Sub)) at (prev + 0, 37) to (start + 0, 61) = (c0 - c1) - Code(Counter(1)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c1 diff --git a/tests/coverage/assert_not.cov-map b/tests/coverage/assert_not.cov-map index 3aef4274edc3..e0ec3815244e 100644 --- a/tests/coverage/assert_not.cov-map +++ b/tests/coverage/assert_not.cov-map @@ -1,13 +1,18 @@ Function name: assert_not::main -Raw bytes (29): 0x[01, 01, 00, 05, 01, 06, 01, 01, 11, 01, 02, 05, 00, 13, 01, 01, 05, 00, 13, 01, 01, 05, 00, 15, 01, 01, 01, 00, 02] +Raw bytes (54): 0x[01, 01, 00, 0a, 01, 06, 01, 00, 0a, 01, 01, 05, 00, 0c, 01, 00, 0d, 00, 11, 01, 01, 05, 00, 0c, 01, 00, 0d, 00, 13, 01, 01, 05, 00, 0c, 01, 00, 0d, 00, 13, 01, 01, 05, 00, 0c, 01, 00, 0d, 00, 15, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/assert_not.rs Number of expressions: 0 -Number of file 0 mappings: 5 -- Code(Counter(0)) at (prev + 6, 1) to (start + 1, 17) -- Code(Counter(0)) at (prev + 2, 5) to (start + 0, 19) -- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 19) -- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 21) +Number of file 0 mappings: 10 +- Code(Counter(0)) at (prev + 6, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 12) +- Code(Counter(0)) at (prev + 0, 13) to (start + 0, 17) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 12) +- Code(Counter(0)) at (prev + 0, 13) to (start + 0, 19) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 12) +- Code(Counter(0)) at (prev + 0, 13) to (start + 0, 19) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 12) +- Code(Counter(0)) at (prev + 0, 13) to (start + 0, 21) - Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 diff --git a/tests/coverage/async.cov-map b/tests/coverage/async.cov-map index 521562f6b912..c528ad525b5f 100644 --- a/tests/coverage/async.cov-map +++ b/tests/coverage/async.cov-map @@ -1,115 +1,125 @@ Function name: async::c -Raw bytes (9): 0x[01, 01, 00, 01, 01, 0b, 01, 00, 19] +Raw bytes (9): 0x[01, 01, 00, 01, 01, 0b, 01, 00, 18] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/async.rs Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 11, 1) to (start + 0, 25) +- Code(Counter(0)) at (prev + 11, 1) to (start + 0, 24) Highest counter ID seen: c0 Function name: async::c::{closure#0} -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 0b, 19, 01, 0e, 05, 02, 09, 00, 0a, 02, 02, 09, 00, 0a, 01, 02, 01, 00, 02] +Raw bytes (31): 0x[01, 01, 01, 01, 05, 05, 01, 0b, 19, 00, 1a, 01, 01, 08, 00, 0e, 05, 01, 09, 00, 0a, 02, 02, 09, 00, 0a, 01, 02, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/async.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 11, 25) to (start + 1, 14) -- Code(Counter(1)) at (prev + 2, 9) to (start + 0, 10) +Number of file 0 mappings: 5 +- Code(Counter(0)) at (prev + 11, 25) to (start + 0, 26) +- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 14) +- Code(Counter(1)) at (prev + 1, 9) to (start + 0, 10) - Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 10) = (c0 - c1) - Code(Counter(0)) at (prev + 2, 1) to (start + 0, 2) Highest counter ID seen: c1 Function name: async::d -Raw bytes (9): 0x[01, 01, 00, 01, 01, 13, 01, 00, 14] +Raw bytes (9): 0x[01, 01, 00, 01, 01, 13, 01, 00, 13] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/async.rs Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 19, 1) to (start + 0, 20) +- Code(Counter(0)) at (prev + 19, 1) to (start + 0, 19) Highest counter ID seen: c0 Function name: async::d::{closure#0} -Raw bytes (9): 0x[01, 01, 00, 01, 01, 13, 14, 00, 19] +Raw bytes (19): 0x[01, 01, 00, 03, 01, 13, 14, 00, 15, 01, 00, 16, 00, 17, 01, 00, 18, 00, 19] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/async.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 19, 20) to (start + 0, 25) +Number of file 0 mappings: 3 +- Code(Counter(0)) at (prev + 19, 20) to (start + 0, 21) +- Code(Counter(0)) at (prev + 0, 22) to (start + 0, 23) +- Code(Counter(0)) at (prev + 0, 24) to (start + 0, 25) Highest counter ID seen: c0 Function name: async::e (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 15, 01, 00, 14] +Raw bytes (9): 0x[01, 01, 00, 01, 00, 15, 01, 00, 13] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/async.rs Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Zero) at (prev + 21, 1) to (start + 0, 20) +- Code(Zero) at (prev + 21, 1) to (start + 0, 19) Highest counter ID seen: (none) Function name: async::e::{closure#0} (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 15, 14, 00, 19] +Raw bytes (19): 0x[01, 01, 00, 03, 00, 15, 14, 00, 15, 00, 00, 16, 00, 17, 00, 00, 18, 00, 19] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/async.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 21, 20) to (start + 0, 25) +Number of file 0 mappings: 3 +- Code(Zero) at (prev + 21, 20) to (start + 0, 21) +- Code(Zero) at (prev + 0, 22) to (start + 0, 23) +- Code(Zero) at (prev + 0, 24) to (start + 0, 25) Highest counter ID seen: (none) Function name: async::f -Raw bytes (9): 0x[01, 01, 00, 01, 01, 17, 01, 00, 14] +Raw bytes (9): 0x[01, 01, 00, 01, 01, 17, 01, 00, 13] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/async.rs Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 23, 1) to (start + 0, 20) +- Code(Counter(0)) at (prev + 23, 1) to (start + 0, 19) Highest counter ID seen: c0 Function name: async::f::{closure#0} -Raw bytes (9): 0x[01, 01, 00, 01, 01, 17, 14, 00, 19] +Raw bytes (19): 0x[01, 01, 00, 03, 01, 17, 14, 00, 15, 01, 00, 16, 00, 17, 01, 00, 18, 00, 19] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/async.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 23, 20) to (start + 0, 25) +Number of file 0 mappings: 3 +- Code(Counter(0)) at (prev + 23, 20) to (start + 0, 21) +- Code(Counter(0)) at (prev + 0, 22) to (start + 0, 23) +- Code(Counter(0)) at (prev + 0, 24) to (start + 0, 25) Highest counter ID seen: c0 Function name: async::foo (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 19, 01, 00, 1e] +Raw bytes (9): 0x[01, 01, 00, 01, 00, 19, 01, 00, 1d] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/async.rs Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Zero) at (prev + 25, 1) to (start + 0, 30) +- Code(Zero) at (prev + 25, 1) to (start + 0, 29) Highest counter ID seen: (none) Function name: async::foo::{closure#0} (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 19, 1e, 00, 2d] +Raw bytes (19): 0x[01, 01, 00, 03, 00, 19, 1e, 00, 1f, 00, 00, 20, 00, 2b, 00, 00, 2c, 00, 2d] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/async.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 25, 30) to (start + 0, 45) +Number of file 0 mappings: 3 +- Code(Zero) at (prev + 25, 30) to (start + 0, 31) +- Code(Zero) at (prev + 0, 32) to (start + 0, 43) +- Code(Zero) at (prev + 0, 44) to (start + 0, 45) Highest counter ID seen: (none) Function name: async::g -Raw bytes (9): 0x[01, 01, 00, 01, 01, 1b, 01, 00, 17] +Raw bytes (9): 0x[01, 01, 00, 01, 01, 1b, 01, 00, 16] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/async.rs Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 27, 1) to (start + 0, 23) +- Code(Counter(0)) at (prev + 27, 1) to (start + 0, 22) Highest counter ID seen: c0 Function name: async::g::{closure#0} (unused) -Raw bytes (59): 0x[01, 01, 00, 0b, 00, 1b, 17, 01, 0c, 00, 02, 09, 00, 0a, 00, 00, 0e, 00, 17, 00, 00, 1b, 00, 1c, 00, 00, 20, 00, 22, 00, 01, 09, 00, 0a, 00, 00, 0e, 00, 17, 00, 00, 1b, 00, 1c, 00, 00, 20, 00, 22, 00, 01, 0e, 00, 10, 00, 02, 01, 00, 02] +Raw bytes (64): 0x[01, 01, 00, 0c, 00, 1b, 17, 00, 18, 00, 01, 0b, 00, 0c, 00, 01, 09, 00, 0a, 00, 00, 0e, 00, 17, 00, 00, 1b, 00, 1c, 00, 00, 20, 00, 22, 00, 01, 09, 00, 0a, 00, 00, 0e, 00, 17, 00, 00, 1b, 00, 1c, 00, 00, 20, 00, 22, 00, 01, 0e, 00, 10, 00, 02, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/async.rs Number of expressions: 0 -Number of file 0 mappings: 11 -- Code(Zero) at (prev + 27, 23) to (start + 1, 12) -- Code(Zero) at (prev + 2, 9) to (start + 0, 10) +Number of file 0 mappings: 12 +- Code(Zero) at (prev + 27, 23) to (start + 0, 24) +- Code(Zero) at (prev + 1, 11) to (start + 0, 12) +- Code(Zero) at (prev + 1, 9) to (start + 0, 10) - Code(Zero) at (prev + 0, 14) to (start + 0, 23) - Code(Zero) at (prev + 0, 27) to (start + 0, 28) - Code(Zero) at (prev + 0, 32) to (start + 0, 34) @@ -122,22 +132,23 @@ Number of file 0 mappings: 11 Highest counter ID seen: (none) Function name: async::h -Raw bytes (9): 0x[01, 01, 00, 01, 01, 23, 01, 00, 16] +Raw bytes (9): 0x[01, 01, 00, 01, 01, 23, 01, 00, 15] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/async.rs Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 35, 1) to (start + 0, 22) +- Code(Counter(0)) at (prev + 35, 1) to (start + 0, 21) Highest counter ID seen: c0 Function name: async::h::{closure#0} (unused) -Raw bytes (39): 0x[01, 01, 00, 07, 00, 23, 16, 03, 0c, 00, 04, 09, 00, 0a, 00, 00, 0e, 00, 19, 00, 00, 1a, 00, 1b, 00, 00, 20, 00, 22, 00, 01, 0e, 00, 10, 00, 02, 01, 00, 02] +Raw bytes (44): 0x[01, 01, 00, 08, 00, 23, 16, 00, 17, 00, 03, 0b, 00, 0c, 00, 01, 09, 00, 0a, 00, 00, 0e, 00, 19, 00, 00, 1a, 00, 1b, 00, 00, 20, 00, 22, 00, 01, 0e, 00, 10, 00, 02, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/async.rs Number of expressions: 0 -Number of file 0 mappings: 7 -- Code(Zero) at (prev + 35, 22) to (start + 3, 12) -- Code(Zero) at (prev + 4, 9) to (start + 0, 10) +Number of file 0 mappings: 8 +- Code(Zero) at (prev + 35, 22) to (start + 0, 23) +- Code(Zero) at (prev + 3, 11) to (start + 0, 12) +- Code(Zero) at (prev + 1, 9) to (start + 0, 10) - Code(Zero) at (prev + 0, 14) to (start + 0, 25) - Code(Zero) at (prev + 0, 26) to (start + 0, 27) - Code(Zero) at (prev + 0, 32) to (start + 0, 34) @@ -146,25 +157,27 @@ Number of file 0 mappings: 7 Highest counter ID seen: (none) Function name: async::i -Raw bytes (9): 0x[01, 01, 00, 01, 01, 2c, 01, 00, 13] +Raw bytes (9): 0x[01, 01, 00, 01, 01, 2c, 01, 00, 12] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/async.rs Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 44, 1) to (start + 0, 19) +- Code(Counter(0)) at (prev + 44, 1) to (start + 0, 18) Highest counter ID seen: c0 Function name: async::i::{closure#0} -Raw bytes (65): 0x[01, 01, 03, 05, 09, 11, 15, 0d, 11, 0b, 01, 2c, 13, 04, 0c, 09, 05, 09, 00, 0a, 01, 00, 0e, 00, 18, 05, 00, 1c, 00, 21, 09, 00, 27, 00, 30, 15, 01, 09, 00, 0a, 02, 00, 0e, 00, 17, 11, 00, 1b, 00, 20, 15, 00, 24, 00, 26, 06, 01, 0e, 00, 10, 0b, 02, 01, 00, 02] +Raw bytes (75): 0x[01, 01, 03, 05, 09, 11, 15, 0d, 11, 0d, 01, 2c, 13, 00, 14, 01, 04, 0b, 00, 0c, 09, 01, 09, 00, 0a, 01, 00, 0e, 00, 0f, 01, 00, 0e, 00, 18, 05, 00, 1c, 00, 21, 09, 00, 27, 00, 30, 15, 01, 09, 00, 0a, 02, 00, 0e, 00, 17, 11, 00, 1b, 00, 20, 15, 00, 24, 00, 26, 06, 01, 0e, 00, 10, 0b, 02, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/async.rs Number of expressions: 3 - expression 0 operands: lhs = Counter(1), rhs = Counter(2) - expression 1 operands: lhs = Counter(4), rhs = Counter(5) - expression 2 operands: lhs = Counter(3), rhs = Counter(4) -Number of file 0 mappings: 11 -- Code(Counter(0)) at (prev + 44, 19) to (start + 4, 12) -- Code(Counter(2)) at (prev + 5, 9) to (start + 0, 10) +Number of file 0 mappings: 13 +- Code(Counter(0)) at (prev + 44, 19) to (start + 0, 20) +- Code(Counter(0)) at (prev + 4, 11) to (start + 0, 12) +- Code(Counter(2)) at (prev + 1, 9) to (start + 0, 10) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 15) - Code(Counter(0)) at (prev + 0, 14) to (start + 0, 24) - Code(Counter(1)) at (prev + 0, 28) to (start + 0, 33) - Code(Counter(2)) at (prev + 0, 39) to (start + 0, 48) @@ -180,17 +193,18 @@ Number of file 0 mappings: 11 Highest counter ID seen: c5 Function name: async::j -Raw bytes (60): 0x[01, 01, 03, 01, 05, 01, 0b, 05, 09, 0a, 01, 37, 01, 00, 0d, 01, 0b, 0b, 00, 0c, 05, 01, 09, 00, 0a, 01, 00, 0e, 00, 1b, 05, 00, 1f, 00, 27, 09, 01, 09, 00, 0a, 02, 00, 0e, 00, 1a, 09, 00, 1e, 00, 20, 06, 01, 0e, 00, 10, 01, 02, 01, 00, 02] +Raw bytes (65): 0x[01, 01, 03, 01, 05, 01, 0b, 05, 09, 0b, 01, 37, 01, 00, 0c, 01, 0b, 0b, 00, 0c, 05, 01, 09, 00, 0a, 01, 00, 0e, 00, 0f, 01, 00, 0e, 00, 1b, 05, 00, 1f, 00, 27, 09, 01, 09, 00, 0a, 02, 00, 0e, 00, 1a, 09, 00, 1e, 00, 20, 06, 01, 0e, 00, 10, 01, 02, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/async.rs Number of expressions: 3 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(0), rhs = Expression(2, Add) - expression 2 operands: lhs = Counter(1), rhs = Counter(2) -Number of file 0 mappings: 10 -- Code(Counter(0)) at (prev + 55, 1) to (start + 0, 13) +Number of file 0 mappings: 11 +- Code(Counter(0)) at (prev + 55, 1) to (start + 0, 12) - Code(Counter(0)) at (prev + 11, 11) to (start + 0, 12) - Code(Counter(1)) at (prev + 1, 9) to (start + 0, 10) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 15) - Code(Counter(0)) at (prev + 0, 14) to (start + 0, 27) - Code(Counter(1)) at (prev + 0, 31) to (start + 0, 39) - Code(Counter(2)) at (prev + 1, 9) to (start + 0, 10) @@ -203,60 +217,67 @@ Number of file 0 mappings: 10 Highest counter ID seen: c2 Function name: async::j::c -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 39, 05, 01, 12, 05, 02, 0d, 00, 0e, 02, 02, 0d, 00, 0e, 01, 02, 05, 00, 06] +Raw bytes (31): 0x[01, 01, 01, 01, 05, 05, 01, 39, 05, 00, 16, 01, 01, 0c, 00, 12, 05, 01, 0d, 00, 0e, 02, 02, 0d, 00, 0e, 01, 02, 05, 00, 06] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/async.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 57, 5) to (start + 1, 18) -- Code(Counter(1)) at (prev + 2, 13) to (start + 0, 14) +Number of file 0 mappings: 5 +- Code(Counter(0)) at (prev + 57, 5) to (start + 0, 22) +- Code(Counter(0)) at (prev + 1, 12) to (start + 0, 18) +- Code(Counter(1)) at (prev + 1, 13) to (start + 0, 14) - Code(Expression(0, Sub)) at (prev + 2, 13) to (start + 0, 14) = (c0 - c1) - Code(Counter(0)) at (prev + 2, 5) to (start + 0, 6) Highest counter ID seen: c1 Function name: async::j::d -Raw bytes (9): 0x[01, 01, 00, 01, 01, 40, 05, 00, 17] +Raw bytes (19): 0x[01, 01, 00, 03, 01, 40, 05, 00, 11, 01, 00, 14, 00, 15, 01, 00, 16, 00, 17] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/async.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 64, 5) to (start + 0, 23) +Number of file 0 mappings: 3 +- Code(Counter(0)) at (prev + 64, 5) to (start + 0, 17) +- Code(Counter(0)) at (prev + 0, 20) to (start + 0, 21) +- Code(Counter(0)) at (prev + 0, 22) to (start + 0, 23) Highest counter ID seen: c0 Function name: async::j::f -Raw bytes (9): 0x[01, 01, 00, 01, 01, 41, 05, 00, 17] +Raw bytes (19): 0x[01, 01, 00, 03, 01, 41, 05, 00, 11, 01, 00, 14, 00, 15, 01, 00, 16, 00, 17] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/async.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 65, 5) to (start + 0, 23) +Number of file 0 mappings: 3 +- Code(Counter(0)) at (prev + 65, 5) to (start + 0, 17) +- Code(Counter(0)) at (prev + 0, 20) to (start + 0, 21) +- Code(Counter(0)) at (prev + 0, 22) to (start + 0, 23) Highest counter ID seen: c0 Function name: async::k (unused) -Raw bytes (29): 0x[01, 01, 00, 05, 00, 49, 01, 01, 0c, 00, 02, 0e, 00, 10, 00, 01, 0e, 00, 10, 00, 01, 0e, 00, 10, 00, 02, 01, 00, 02] +Raw bytes (34): 0x[01, 01, 00, 06, 00, 49, 01, 00, 0c, 00, 01, 0b, 00, 0c, 00, 01, 0e, 00, 10, 00, 01, 0e, 00, 10, 00, 01, 0e, 00, 10, 00, 02, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/async.rs Number of expressions: 0 -Number of file 0 mappings: 5 -- Code(Zero) at (prev + 73, 1) to (start + 1, 12) -- Code(Zero) at (prev + 2, 14) to (start + 0, 16) +Number of file 0 mappings: 6 +- Code(Zero) at (prev + 73, 1) to (start + 0, 12) +- Code(Zero) at (prev + 1, 11) to (start + 0, 12) +- Code(Zero) at (prev + 1, 14) to (start + 0, 16) - Code(Zero) at (prev + 1, 14) to (start + 0, 16) - Code(Zero) at (prev + 1, 14) to (start + 0, 16) - Code(Zero) at (prev + 2, 1) to (start + 0, 2) Highest counter ID seen: (none) Function name: async::l -Raw bytes (33): 0x[01, 01, 02, 01, 07, 05, 09, 05, 01, 51, 01, 01, 0c, 02, 02, 0e, 00, 10, 09, 01, 0e, 00, 10, 05, 01, 0e, 00, 10, 01, 02, 01, 00, 02] +Raw bytes (38): 0x[01, 01, 02, 01, 07, 05, 09, 06, 01, 51, 01, 00, 0c, 01, 01, 0b, 00, 0c, 02, 01, 0e, 00, 10, 09, 01, 0e, 00, 10, 05, 01, 0e, 00, 10, 01, 02, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/async.rs Number of expressions: 2 - expression 0 operands: lhs = Counter(0), rhs = Expression(1, Add) - expression 1 operands: lhs = Counter(1), rhs = Counter(2) -Number of file 0 mappings: 5 -- Code(Counter(0)) at (prev + 81, 1) to (start + 1, 12) -- Code(Expression(0, Sub)) at (prev + 2, 14) to (start + 0, 16) +Number of file 0 mappings: 6 +- Code(Counter(0)) at (prev + 81, 1) to (start + 0, 12) +- Code(Counter(0)) at (prev + 1, 11) to (start + 0, 12) +- Code(Expression(0, Sub)) at (prev + 1, 14) to (start + 0, 16) = (c0 - (c1 + c2)) - Code(Counter(2)) at (prev + 1, 14) to (start + 0, 16) - Code(Counter(1)) at (prev + 1, 14) to (start + 0, 16) @@ -264,29 +285,43 @@ Number of file 0 mappings: 5 Highest counter ID seen: c2 Function name: async::m -Raw bytes (9): 0x[01, 01, 00, 01, 01, 59, 01, 00, 19] +Raw bytes (9): 0x[01, 01, 00, 01, 01, 59, 01, 00, 18] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/async.rs Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 89, 1) to (start + 0, 25) +- Code(Counter(0)) at (prev + 89, 1) to (start + 0, 24) Highest counter ID seen: c0 Function name: async::m::{closure#0} (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 59, 19, 00, 22] +Raw bytes (19): 0x[01, 01, 00, 03, 00, 59, 19, 00, 1a, 00, 00, 1b, 00, 20, 00, 00, 21, 00, 22] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/async.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 89, 25) to (start + 0, 34) +Number of file 0 mappings: 3 +- Code(Zero) at (prev + 89, 25) to (start + 0, 26) +- Code(Zero) at (prev + 0, 27) to (start + 0, 32) +- Code(Zero) at (prev + 0, 33) to (start + 0, 34) Highest counter ID seen: (none) Function name: async::main -Raw bytes (9): 0x[01, 01, 00, 01, 01, 5b, 01, 08, 02] +Raw bytes (69): 0x[01, 01, 00, 0d, 01, 5b, 01, 00, 0a, 01, 01, 0d, 00, 12, 01, 01, 0d, 00, 11, 01, 01, 09, 00, 13, 01, 00, 16, 00, 1e, 01, 00, 1f, 00, 20, 01, 01, 05, 00, 06, 01, 01, 05, 00, 06, 01, 01, 0d, 00, 11, 01, 01, 05, 00, 17, 01, 00, 18, 00, 1e, 01, 00, 1f, 00, 25, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/async.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 91, 1) to (start + 8, 2) +Number of file 0 mappings: 13 +- Code(Counter(0)) at (prev + 91, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 1, 13) to (start + 0, 18) +- Code(Counter(0)) at (prev + 1, 13) to (start + 0, 17) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 19) +- Code(Counter(0)) at (prev + 0, 22) to (start + 0, 30) +- Code(Counter(0)) at (prev + 0, 31) to (start + 0, 32) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 6) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 6) +- Code(Counter(0)) at (prev + 1, 13) to (start + 0, 17) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 23) +- Code(Counter(0)) at (prev + 0, 24) to (start + 0, 30) +- Code(Counter(0)) at (prev + 0, 31) to (start + 0, 37) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 diff --git a/tests/coverage/async.coverage b/tests/coverage/async.coverage index aee76b05fb74..9fca1b6997d0 100644 --- a/tests/coverage/async.coverage +++ b/tests/coverage/async.coverage @@ -25,6 +25,7 @@ LL| 0|async fn foo() -> [bool; 10] { [false; 10] } // unused function; executor does not block on `h()` LL| | LL| 1|pub async fn g(x: u8) { + ^0 LL| 0| match x { LL| 0| y if e().await == y => (), LL| 0| y if f().await == y => (), @@ -33,8 +34,9 @@ LL| 0|} LL| | LL| 1|async fn h(x: usize) { // The function signature is counted when called, but the body is not - LL| 0| // executed (not awaited) so the open brace has a `0` count (at least when - LL| 0| // displayed with `llvm-cov show` in color-mode). + ^0 + LL| | // executed (not awaited) so the open brace has a `0` count (at least when + LL| | // displayed with `llvm-cov show` in color-mode). LL| 0| match x { LL| 0| y if foo().await[y] => (), LL| 0| _ => (), @@ -42,9 +44,9 @@ LL| 0|} LL| | LL| 1|async fn i(x: u8) { // line coverage is 1, but there are 2 regions: - LL| 1| // (a) the function signature, counted when the function is called; and - LL| 1| // (b) the open brace for the function body, counted once when the body is - LL| 1| // executed asynchronously. + LL| | // (a) the function signature, counted when the function is called; and + LL| | // (b) the open brace for the function body, counted once when the body is + LL| | // executed asynchronously. LL| 1| match x { LL| 1| y if c(x).await == y + 1 => { d().await; } ^0 ^0 @@ -91,7 +93,7 @@ LL| 1|} LL| | LL| 1|async fn m(x: u8) -> u8 { x - 1 } - ^0 + ^0^0 ^0 LL| | LL| 1|fn main() { LL| 1| let _ = g(10); diff --git a/tests/coverage/async2.cov-map b/tests/coverage/async2.cov-map index c2a0645ee9a8..cc6295170980 100644 --- a/tests/coverage/async2.cov-map +++ b/tests/coverage/async2.cov-map @@ -1,59 +1,80 @@ Function name: async2::async_func -Raw bytes (9): 0x[01, 01, 00, 01, 01, 0f, 01, 00, 17] +Raw bytes (9): 0x[01, 01, 00, 01, 01, 0f, 01, 00, 16] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/async2.rs Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 15, 1) to (start + 0, 23) +- Code(Counter(0)) at (prev + 15, 1) to (start + 0, 22) Highest counter ID seen: c0 Function name: async2::async_func::{closure#0} -Raw bytes (24): 0x[01, 01, 00, 04, 01, 0f, 17, 03, 09, 01, 03, 0a, 02, 06, 00, 02, 05, 00, 06, 01, 01, 01, 00, 02] +Raw bytes (49): 0x[01, 01, 00, 09, 01, 0f, 17, 00, 18, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 26, 01, 01, 09, 00, 0a, 01, 00, 0d, 00, 11, 01, 01, 08, 00, 09, 01, 00, 0a, 02, 06, 00, 02, 05, 00, 06, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/async2.rs Number of expressions: 0 -Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 15, 23) to (start + 3, 9) -- Code(Counter(0)) at (prev + 3, 10) to (start + 2, 6) +Number of file 0 mappings: 9 +- Code(Counter(0)) at (prev + 15, 23) to (start + 0, 24) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 38) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 10) +- Code(Counter(0)) at (prev + 0, 13) to (start + 0, 17) +- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 9) +- Code(Counter(0)) at (prev + 0, 10) to (start + 2, 6) - Code(Zero) at (prev + 2, 5) to (start + 0, 6) - Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: async2::async_func_just_println -Raw bytes (9): 0x[01, 01, 00, 01, 01, 17, 01, 00, 24] +Raw bytes (9): 0x[01, 01, 00, 01, 01, 17, 01, 00, 23] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/async2.rs Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 23, 1) to (start + 0, 36) +- Code(Counter(0)) at (prev + 23, 1) to (start + 0, 35) Highest counter ID seen: c0 Function name: async2::async_func_just_println::{closure#0} -Raw bytes (9): 0x[01, 01, 00, 01, 01, 17, 24, 02, 02] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 17, 24, 00, 25, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 33, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/async2.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 23, 36) to (start + 2, 2) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 23, 36) to (start + 0, 37) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 51) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: async2::main -Raw bytes (9): 0x[01, 01, 00, 01, 01, 1b, 01, 07, 02] +Raw bytes (49): 0x[01, 01, 00, 09, 01, 1b, 01, 00, 0a, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 23, 01, 02, 05, 00, 13, 01, 02, 05, 00, 17, 01, 00, 18, 00, 22, 01, 01, 05, 00, 17, 01, 00, 18, 00, 2f, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/async2.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 27, 1) to (start + 7, 2) +Number of file 0 mappings: 9 +- Code(Counter(0)) at (prev + 27, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 35) +- Code(Counter(0)) at (prev + 2, 5) to (start + 0, 19) +- Code(Counter(0)) at (prev + 2, 5) to (start + 0, 23) +- Code(Counter(0)) at (prev + 0, 24) to (start + 0, 34) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 23) +- Code(Counter(0)) at (prev + 0, 24) to (start + 0, 47) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: async2::non_async_func -Raw bytes (24): 0x[01, 01, 00, 04, 01, 07, 01, 03, 09, 01, 03, 0a, 02, 06, 00, 02, 05, 00, 06, 01, 01, 01, 00, 02] +Raw bytes (49): 0x[01, 01, 00, 09, 01, 07, 01, 00, 14, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 2a, 01, 01, 09, 00, 0a, 01, 00, 0d, 00, 11, 01, 01, 08, 00, 09, 01, 00, 0a, 02, 06, 00, 02, 05, 00, 06, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/async2.rs Number of expressions: 0 -Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 7, 1) to (start + 3, 9) -- Code(Counter(0)) at (prev + 3, 10) to (start + 2, 6) +Number of file 0 mappings: 9 +- Code(Counter(0)) at (prev + 7, 1) to (start + 0, 20) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 42) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 10) +- Code(Counter(0)) at (prev + 0, 13) to (start + 0, 17) +- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 9) +- Code(Counter(0)) at (prev + 0, 10) to (start + 2, 6) - Code(Zero) at (prev + 2, 5) to (start + 0, 6) - Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 diff --git a/tests/coverage/async2.coverage b/tests/coverage/async2.coverage index fa56072924bb..e9ed8253093d 100644 --- a/tests/coverage/async2.coverage +++ b/tests/coverage/async2.coverage @@ -28,9 +28,9 @@ LL| | LL| 1|fn main() { LL| 1| println!("codecovsample::main"); - LL| 1| + LL| | LL| 1| non_async_func(); - LL| 1| + LL| | LL| 1| executor::block_on(async_func()); LL| 1| executor::block_on(async_func_just_println()); LL| 1|} diff --git a/tests/coverage/async_block.cov-map b/tests/coverage/async_block.cov-map index d9196f446f13..07d4c0eb3cd6 100644 --- a/tests/coverage/async_block.cov-map +++ b/tests/coverage/async_block.cov-map @@ -1,30 +1,33 @@ Function name: async_block::main -Raw bytes (36): 0x[01, 01, 01, 05, 01, 06, 01, 07, 01, 00, 0b, 02, 01, 09, 00, 0a, 05, 00, 0e, 00, 13, 02, 01, 0d, 00, 13, 02, 07, 09, 00, 22, 01, 02, 01, 00, 02] +Raw bytes (41): 0x[01, 01, 01, 05, 01, 07, 01, 07, 01, 00, 0a, 02, 01, 09, 00, 0a, 05, 00, 0e, 00, 13, 02, 01, 0d, 00, 13, 02, 07, 09, 00, 1b, 02, 00, 1c, 00, 22, 01, 02, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/async_block.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(1), rhs = Counter(0) -Number of file 0 mappings: 6 -- Code(Counter(0)) at (prev + 7, 1) to (start + 0, 11) +Number of file 0 mappings: 7 +- Code(Counter(0)) at (prev + 7, 1) to (start + 0, 10) - Code(Expression(0, Sub)) at (prev + 1, 9) to (start + 0, 10) = (c1 - c0) - Code(Counter(1)) at (prev + 0, 14) to (start + 0, 19) - Code(Expression(0, Sub)) at (prev + 1, 13) to (start + 0, 19) = (c1 - c0) -- Code(Expression(0, Sub)) at (prev + 7, 9) to (start + 0, 34) +- Code(Expression(0, Sub)) at (prev + 7, 9) to (start + 0, 27) + = (c1 - c0) +- Code(Expression(0, Sub)) at (prev + 0, 28) to (start + 0, 34) = (c1 - c0) - Code(Counter(0)) at (prev + 2, 1) to (start + 0, 2) Highest counter ID seen: c1 Function name: async_block::main::{closure#0} -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 09, 1c, 01, 17, 05, 01, 18, 02, 0e, 02, 02, 14, 02, 0e, 01, 03, 09, 00, 0a] +Raw bytes (31): 0x[01, 01, 01, 01, 05, 05, 01, 09, 1c, 00, 1d, 01, 01, 10, 00, 17, 05, 00, 18, 02, 0e, 02, 02, 14, 02, 0e, 01, 03, 09, 00, 0a] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/async_block.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 9, 28) to (start + 1, 23) -- Code(Counter(1)) at (prev + 1, 24) to (start + 2, 14) +Number of file 0 mappings: 5 +- Code(Counter(0)) at (prev + 9, 28) to (start + 0, 29) +- Code(Counter(0)) at (prev + 1, 16) to (start + 0, 23) +- Code(Counter(1)) at (prev + 0, 24) to (start + 2, 14) - Code(Expression(0, Sub)) at (prev + 2, 20) to (start + 2, 14) = (c0 - c1) - Code(Counter(0)) at (prev + 3, 9) to (start + 0, 10) diff --git a/tests/coverage/async_closure.cov-map b/tests/coverage/async_closure.cov-map index a4ef0ceeb6df..9f8dc8d6cbba 100644 --- a/tests/coverage/async_closure.cov-map +++ b/tests/coverage/async_closure.cov-map @@ -1,38 +1,45 @@ Function name: async_closure::call_once:: -Raw bytes (9): 0x[01, 01, 00, 01, 01, 06, 01, 00, 2b] +Raw bytes (9): 0x[01, 01, 00, 01, 01, 06, 01, 00, 2a] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/async_closure.rs Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 6, 1) to (start + 0, 43) +- Code(Counter(0)) at (prev + 6, 1) to (start + 0, 42) Highest counter ID seen: c0 Function name: async_closure::call_once::::{closure#0} -Raw bytes (16): 0x[01, 01, 01, 05, 09, 02, 01, 06, 2b, 01, 0e, 02, 02, 01, 00, 02] +Raw bytes (21): 0x[01, 01, 01, 05, 09, 03, 01, 06, 2b, 00, 2c, 01, 01, 05, 00, 0e, 02, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/async_closure.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(1), rhs = Counter(2) -Number of file 0 mappings: 2 -- Code(Counter(0)) at (prev + 6, 43) to (start + 1, 14) -- Code(Expression(0, Sub)) at (prev + 2, 1) to (start + 0, 2) +Number of file 0 mappings: 3 +- Code(Counter(0)) at (prev + 6, 43) to (start + 0, 44) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Code(Expression(0, Sub)) at (prev + 1, 1) to (start + 0, 2) = (c1 - c2) Highest counter ID seen: c0 Function name: async_closure::main -Raw bytes (14): 0x[01, 01, 00, 02, 01, 0a, 01, 01, 16, 01, 02, 05, 02, 02] +Raw bytes (44): 0x[01, 01, 00, 08, 01, 0a, 01, 00, 0e, 01, 01, 09, 00, 16, 01, 01, 05, 00, 17, 01, 00, 18, 00, 27, 01, 01, 05, 00, 17, 01, 00, 18, 00, 21, 01, 00, 22, 00, 2f, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/async_closure.rs Number of expressions: 0 -Number of file 0 mappings: 2 -- Code(Counter(0)) at (prev + 10, 1) to (start + 1, 22) -- Code(Counter(0)) at (prev + 2, 5) to (start + 2, 2) +Number of file 0 mappings: 8 +- Code(Counter(0)) at (prev + 10, 1) to (start + 0, 14) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 22) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 23) +- Code(Counter(0)) at (prev + 0, 24) to (start + 0, 39) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 23) +- Code(Counter(0)) at (prev + 0, 24) to (start + 0, 33) +- Code(Counter(0)) at (prev + 0, 34) to (start + 0, 47) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: async_closure::main::{closure#0} Raw bytes (14): 0x[01, 01, 00, 02, 01, 0b, 22, 00, 23, 01, 00, 23, 00, 24] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/async_closure.rs Number of expressions: 0 Number of file 0 mappings: 2 - Code(Counter(0)) at (prev + 11, 34) to (start + 0, 35) @@ -42,7 +49,7 @@ Highest counter ID seen: c0 Function name: async_closure::main::{closure#0} Raw bytes (14): 0x[01, 01, 00, 02, 01, 0b, 22, 00, 23, 01, 00, 23, 00, 24] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/async_closure.rs Number of expressions: 0 Number of file 0 mappings: 2 - Code(Counter(0)) at (prev + 11, 34) to (start + 0, 35) @@ -50,11 +57,12 @@ Number of file 0 mappings: 2 Highest counter ID seen: c0 Function name: async_closure::main::{closure#0}::{closure#0}:: -Raw bytes (9): 0x[01, 01, 00, 01, 01, 0b, 22, 00, 24] +Raw bytes (14): 0x[01, 01, 00, 02, 01, 0b, 22, 00, 23, 01, 00, 23, 00, 24] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/async_closure.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 11, 34) to (start + 0, 36) +Number of file 0 mappings: 2 +- Code(Counter(0)) at (prev + 11, 34) to (start + 0, 35) +- Code(Counter(0)) at (prev + 0, 35) to (start + 0, 36) Highest counter ID seen: c0 diff --git a/tests/coverage/async_closure.coverage b/tests/coverage/async_closure.coverage index 5aed131de2e5..14f043415eac 100644 --- a/tests/coverage/async_closure.coverage +++ b/tests/coverage/async_closure.coverage @@ -8,7 +8,8 @@ LL| 1|} LL| | LL| 1|pub fn main() { - LL| 2| let async_closure = async || {}; + LL| 3| let async_closure = async || {}; + ^1 ------------------ | async_closure::main::{closure#0}: | LL| 1| let async_closure = async || {}; diff --git a/tests/coverage/attr/impl.cov-map b/tests/coverage/attr/impl.cov-map index 8a23c082082e..0562c291e6c1 100644 --- a/tests/coverage/attr/impl.cov-map +++ b/tests/coverage/attr/impl.cov-map @@ -1,27 +1,30 @@ Function name: ::off_on (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 0f, 05, 00, 13] +Raw bytes (14): 0x[01, 01, 00, 02, 00, 0f, 05, 00, 10, 00, 00, 12, 00, 13] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/impl.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 15, 5) to (start + 0, 19) +Number of file 0 mappings: 2 +- Code(Zero) at (prev + 15, 5) to (start + 0, 16) +- Code(Zero) at (prev + 0, 18) to (start + 0, 19) Highest counter ID seen: (none) Function name: ::on_inherit (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 17, 05, 00, 17] +Raw bytes (14): 0x[01, 01, 00, 02, 00, 17, 05, 00, 14, 00, 00, 16, 00, 17] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/impl.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 23, 5) to (start + 0, 23) +Number of file 0 mappings: 2 +- Code(Zero) at (prev + 23, 5) to (start + 0, 20) +- Code(Zero) at (prev + 0, 22) to (start + 0, 23) Highest counter ID seen: (none) Function name: ::on_on (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 1a, 05, 00, 12] +Raw bytes (14): 0x[01, 01, 00, 02, 00, 1a, 05, 00, 0f, 00, 00, 11, 00, 12] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/impl.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 26, 5) to (start + 0, 18) +Number of file 0 mappings: 2 +- Code(Zero) at (prev + 26, 5) to (start + 0, 15) +- Code(Zero) at (prev + 0, 17) to (start + 0, 18) Highest counter ID seen: (none) diff --git a/tests/coverage/attr/module.cov-map b/tests/coverage/attr/module.cov-map index 81e20a2c2649..88f4915bfe8f 100644 --- a/tests/coverage/attr/module.cov-map +++ b/tests/coverage/attr/module.cov-map @@ -1,27 +1,30 @@ Function name: module::off::on (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 0d, 05, 00, 0f] +Raw bytes (14): 0x[01, 01, 00, 02, 00, 0d, 05, 00, 0c, 00, 00, 0e, 00, 0f] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/module.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 13, 5) to (start + 0, 15) +Number of file 0 mappings: 2 +- Code(Zero) at (prev + 13, 5) to (start + 0, 12) +- Code(Zero) at (prev + 0, 14) to (start + 0, 15) Highest counter ID seen: (none) Function name: module::on::inherit (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 15, 05, 00, 14] +Raw bytes (14): 0x[01, 01, 00, 02, 00, 15, 05, 00, 11, 00, 00, 13, 00, 14] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/module.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 21, 5) to (start + 0, 20) +Number of file 0 mappings: 2 +- Code(Zero) at (prev + 21, 5) to (start + 0, 17) +- Code(Zero) at (prev + 0, 19) to (start + 0, 20) Highest counter ID seen: (none) Function name: module::on::on (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 18, 05, 00, 0f] +Raw bytes (14): 0x[01, 01, 00, 02, 00, 18, 05, 00, 0c, 00, 00, 0e, 00, 0f] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/module.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 24, 5) to (start + 0, 15) +Number of file 0 mappings: 2 +- Code(Zero) at (prev + 24, 5) to (start + 0, 12) +- Code(Zero) at (prev + 0, 14) to (start + 0, 15) Highest counter ID seen: (none) diff --git a/tests/coverage/attr/nested.cov-map b/tests/coverage/attr/nested.cov-map index 138b3159ea5c..8ca218f7267f 100644 --- a/tests/coverage/attr/nested.cov-map +++ b/tests/coverage/attr/nested.cov-map @@ -1,20 +1,24 @@ Function name: nested::closure_expr -Raw bytes (14): 0x[01, 01, 00, 02, 01, 40, 01, 01, 0f, 01, 0b, 05, 01, 02] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 40, 01, 00, 12, 01, 01, 09, 00, 0f, 01, 0a, 05, 00, 0d, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/nested.rs Number of expressions: 0 -Number of file 0 mappings: 2 -- Code(Counter(0)) at (prev + 64, 1) to (start + 1, 15) -- Code(Counter(0)) at (prev + 11, 5) to (start + 1, 2) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 64, 1) to (start + 0, 18) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 15) +- Code(Counter(0)) at (prev + 10, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: nested::closure_tail -Raw bytes (14): 0x[01, 01, 00, 02, 01, 4f, 01, 01, 0f, 01, 11, 05, 01, 02] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 4f, 01, 00, 12, 01, 01, 09, 00, 0f, 01, 10, 05, 00, 0d, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/nested.rs Number of expressions: 0 -Number of file 0 mappings: 2 -- Code(Counter(0)) at (prev + 79, 1) to (start + 1, 15) -- Code(Counter(0)) at (prev + 17, 5) to (start + 1, 2) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 79, 1) to (start + 0, 18) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 15) +- Code(Counter(0)) at (prev + 16, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 diff --git a/tests/coverage/attr/off-on-sandwich.cov-map b/tests/coverage/attr/off-on-sandwich.cov-map index c55c5897d8ba..c0c6eab57108 100644 --- a/tests/coverage/attr/off-on-sandwich.cov-map +++ b/tests/coverage/attr/off-on-sandwich.cov-map @@ -1,30 +1,36 @@ Function name: off_on_sandwich::dense_a::dense_b -Raw bytes (14): 0x[01, 01, 00, 02, 01, 10, 05, 02, 10, 01, 07, 05, 00, 06] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 10, 05, 00, 11, 01, 01, 09, 00, 10, 01, 01, 09, 00, 10, 01, 05, 05, 00, 06] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/off-on-sandwich.rs Number of expressions: 0 -Number of file 0 mappings: 2 -- Code(Counter(0)) at (prev + 16, 5) to (start + 2, 16) -- Code(Counter(0)) at (prev + 7, 5) to (start + 0, 6) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 16, 5) to (start + 0, 17) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 16) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 16) +- Code(Counter(0)) at (prev + 5, 5) to (start + 0, 6) Highest counter ID seen: c0 Function name: off_on_sandwich::sparse_a::sparse_b::sparse_c -Raw bytes (14): 0x[01, 01, 00, 02, 01, 22, 09, 02, 15, 01, 0b, 09, 00, 0a] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 22, 09, 00, 16, 01, 01, 0d, 00, 15, 01, 01, 0d, 00, 15, 01, 09, 09, 00, 0a] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/off-on-sandwich.rs Number of expressions: 0 -Number of file 0 mappings: 2 -- Code(Counter(0)) at (prev + 34, 9) to (start + 2, 21) -- Code(Counter(0)) at (prev + 11, 9) to (start + 0, 10) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 34, 9) to (start + 0, 22) +- Code(Counter(0)) at (prev + 1, 13) to (start + 0, 21) +- Code(Counter(0)) at (prev + 1, 13) to (start + 0, 21) +- Code(Counter(0)) at (prev + 9, 9) to (start + 0, 10) Highest counter ID seen: c0 Function name: off_on_sandwich::sparse_a::sparse_b::sparse_c::sparse_d -Raw bytes (14): 0x[01, 01, 00, 02, 01, 25, 0d, 02, 19, 01, 07, 0d, 00, 0e] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 25, 0d, 00, 1a, 01, 01, 11, 00, 19, 01, 01, 11, 00, 19, 01, 05, 0d, 00, 0e] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/off-on-sandwich.rs Number of expressions: 0 -Number of file 0 mappings: 2 -- Code(Counter(0)) at (prev + 37, 13) to (start + 2, 25) -- Code(Counter(0)) at (prev + 7, 13) to (start + 0, 14) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 37, 13) to (start + 0, 26) +- Code(Counter(0)) at (prev + 1, 17) to (start + 0, 25) +- Code(Counter(0)) at (prev + 1, 17) to (start + 0, 25) +- Code(Counter(0)) at (prev + 5, 13) to (start + 0, 14) Highest counter ID seen: c0 diff --git a/tests/coverage/attr/trait-impl-inherit.cov-map b/tests/coverage/attr/trait-impl-inherit.cov-map index eab9f926bb77..bf10083dd290 100644 --- a/tests/coverage/attr/trait-impl-inherit.cov-map +++ b/tests/coverage/attr/trait-impl-inherit.cov-map @@ -1,9 +1,12 @@ Function name: ::f -Raw bytes (9): 0x[01, 01, 00, 01, 01, 11, 05, 02, 06] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 11, 05, 00, 10, 01, 01, 09, 00, 11, 01, 00, 12, 00, 1a, 01, 01, 05, 00, 06] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/trait-impl-inherit.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 17, 5) to (start + 2, 6) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 17, 5) to (start + 0, 16) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 17) +- Code(Counter(0)) at (prev + 0, 18) to (start + 0, 26) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 6) Highest counter ID seen: c0 diff --git a/tests/coverage/await_ready.cov-map b/tests/coverage/await_ready.cov-map index 61fd4c7814d8..a7eb051ff093 100644 --- a/tests/coverage/await_ready.cov-map +++ b/tests/coverage/await_ready.cov-map @@ -1,21 +1,22 @@ Function name: await_ready::await_ready -Raw bytes (9): 0x[01, 01, 00, 01, 01, 0e, 01, 00, 1e] +Raw bytes (9): 0x[01, 01, 00, 01, 01, 0e, 01, 00, 1d] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/await_ready.rs Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 14, 1) to (start + 0, 30) +- Code(Counter(0)) at (prev + 14, 1) to (start + 0, 29) Highest counter ID seen: c0 Function name: await_ready::await_ready::{closure#0} -Raw bytes (16): 0x[01, 01, 01, 05, 09, 02, 01, 0e, 1e, 03, 0f, 02, 04, 01, 00, 02] +Raw bytes (21): 0x[01, 01, 01, 05, 09, 03, 01, 0e, 1e, 00, 1f, 01, 02, 05, 01, 0f, 02, 02, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/await_ready.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(1), rhs = Counter(2) -Number of file 0 mappings: 2 -- Code(Counter(0)) at (prev + 14, 30) to (start + 3, 15) -- Code(Expression(0, Sub)) at (prev + 4, 1) to (start + 0, 2) +Number of file 0 mappings: 3 +- Code(Counter(0)) at (prev + 14, 30) to (start + 0, 31) +- Code(Counter(0)) at (prev + 2, 5) to (start + 1, 15) +- Code(Expression(0, Sub)) at (prev + 2, 1) to (start + 0, 2) = (c1 - c2) Highest counter ID seen: c0 diff --git a/tests/coverage/await_ready.coverage b/tests/coverage/await_ready.coverage index 1150d807e763..9a2d8f5a4fdf 100644 --- a/tests/coverage/await_ready.coverage +++ b/tests/coverage/await_ready.coverage @@ -12,7 +12,7 @@ LL| |#[coverage(on)] LL| |#[rustfmt::skip] LL| 1|async fn await_ready() -> u8 { - LL| 1| // await should be covered even if the function never yields + LL| | // await should be covered even if the function never yields LL| 1| ready() LL| 1| .await LL| 1|} diff --git a/tests/coverage/bad_counter_ids.cov-map b/tests/coverage/bad_counter_ids.cov-map index f08a70a899d0..8b1b177f906e 100644 --- a/tests/coverage/bad_counter_ids.cov-map +++ b/tests/coverage/bad_counter_ids.cov-map @@ -1,84 +1,108 @@ Function name: bad_counter_ids::eq_bad -Raw bytes (14): 0x[01, 01, 00, 02, 01, 24, 01, 02, 0f, 00, 03, 01, 00, 02] +Raw bytes (29): 0x[01, 01, 00, 05, 01, 24, 01, 00, 0c, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 11, 01, 01, 05, 00, 0f, 00, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/bad_counter_ids.rs Number of expressions: 0 -Number of file 0 mappings: 2 -- Code(Counter(0)) at (prev + 36, 1) to (start + 2, 15) -- Code(Zero) at (prev + 3, 1) to (start + 0, 2) +Number of file 0 mappings: 5 +- Code(Counter(0)) at (prev + 36, 1) to (start + 0, 12) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 17) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 15) +- Code(Zero) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: bad_counter_ids::eq_bad_message -Raw bytes (19): 0x[01, 01, 00, 03, 01, 29, 01, 02, 0f, 01, 02, 20, 00, 2b, 00, 01, 01, 00, 02] +Raw bytes (34): 0x[01, 01, 00, 06, 01, 29, 01, 00, 14, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 11, 01, 01, 05, 00, 0f, 01, 00, 20, 00, 2b, 00, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/bad_counter_ids.rs Number of expressions: 0 -Number of file 0 mappings: 3 -- Code(Counter(0)) at (prev + 41, 1) to (start + 2, 15) -- Code(Counter(0)) at (prev + 2, 32) to (start + 0, 43) +Number of file 0 mappings: 6 +- Code(Counter(0)) at (prev + 41, 1) to (start + 0, 20) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 17) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 15) +- Code(Counter(0)) at (prev + 0, 32) to (start + 0, 43) - Code(Zero) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: bad_counter_ids::eq_good -Raw bytes (14): 0x[01, 01, 00, 02, 01, 10, 01, 02, 0f, 01, 03, 01, 00, 02] +Raw bytes (29): 0x[01, 01, 00, 05, 01, 10, 01, 00, 0d, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 11, 01, 01, 05, 00, 0f, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/bad_counter_ids.rs Number of expressions: 0 -Number of file 0 mappings: 2 -- Code(Counter(0)) at (prev + 16, 1) to (start + 2, 15) -- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2) +Number of file 0 mappings: 5 +- Code(Counter(0)) at (prev + 16, 1) to (start + 0, 13) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 17) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 15) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: bad_counter_ids::eq_good_message -Raw bytes (19): 0x[01, 01, 00, 03, 01, 15, 01, 02, 0f, 00, 02, 20, 00, 2b, 01, 01, 01, 00, 02] +Raw bytes (34): 0x[01, 01, 00, 06, 01, 15, 01, 00, 15, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 11, 01, 01, 05, 00, 0f, 00, 00, 20, 00, 2b, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/bad_counter_ids.rs Number of expressions: 0 -Number of file 0 mappings: 3 -- Code(Counter(0)) at (prev + 21, 1) to (start + 2, 15) -- Code(Zero) at (prev + 2, 32) to (start + 0, 43) +Number of file 0 mappings: 6 +- Code(Counter(0)) at (prev + 21, 1) to (start + 0, 21) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 17) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 15) +- Code(Zero) at (prev + 0, 32) to (start + 0, 43) - Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: bad_counter_ids::ne_bad -Raw bytes (14): 0x[01, 01, 00, 02, 01, 2e, 01, 02, 0f, 00, 03, 01, 00, 02] +Raw bytes (29): 0x[01, 01, 00, 05, 01, 2e, 01, 00, 0c, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 11, 01, 01, 05, 00, 0f, 00, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/bad_counter_ids.rs Number of expressions: 0 -Number of file 0 mappings: 2 -- Code(Counter(0)) at (prev + 46, 1) to (start + 2, 15) -- Code(Zero) at (prev + 3, 1) to (start + 0, 2) +Number of file 0 mappings: 5 +- Code(Counter(0)) at (prev + 46, 1) to (start + 0, 12) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 17) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 15) +- Code(Zero) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: bad_counter_ids::ne_bad_message -Raw bytes (19): 0x[01, 01, 00, 03, 01, 33, 01, 02, 0f, 01, 02, 20, 00, 2b, 00, 01, 01, 00, 02] +Raw bytes (34): 0x[01, 01, 00, 06, 01, 33, 01, 00, 14, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 11, 01, 01, 05, 00, 0f, 01, 00, 20, 00, 2b, 00, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/bad_counter_ids.rs Number of expressions: 0 -Number of file 0 mappings: 3 -- Code(Counter(0)) at (prev + 51, 1) to (start + 2, 15) -- Code(Counter(0)) at (prev + 2, 32) to (start + 0, 43) +Number of file 0 mappings: 6 +- Code(Counter(0)) at (prev + 51, 1) to (start + 0, 20) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 17) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 15) +- Code(Counter(0)) at (prev + 0, 32) to (start + 0, 43) - Code(Zero) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: bad_counter_ids::ne_good -Raw bytes (14): 0x[01, 01, 00, 02, 01, 1a, 01, 02, 0f, 01, 03, 01, 00, 02] +Raw bytes (29): 0x[01, 01, 00, 05, 01, 1a, 01, 00, 0d, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 11, 01, 01, 05, 00, 0f, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/bad_counter_ids.rs Number of expressions: 0 -Number of file 0 mappings: 2 -- Code(Counter(0)) at (prev + 26, 1) to (start + 2, 15) -- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2) -Highest counter ID seen: c0 - -Function name: bad_counter_ids::ne_good_message -Raw bytes (19): 0x[01, 01, 00, 03, 01, 1f, 01, 02, 0f, 00, 02, 20, 00, 2b, 01, 01, 01, 00, 02] -Number of files: 1 -- file 0 => global file 1 -Number of expressions: 0 -Number of file 0 mappings: 3 -- Code(Counter(0)) at (prev + 31, 1) to (start + 2, 15) -- Code(Zero) at (prev + 2, 32) to (start + 0, 43) +Number of file 0 mappings: 5 +- Code(Counter(0)) at (prev + 26, 1) to (start + 0, 13) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 17) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 15) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) +Highest counter ID seen: c0 + +Function name: bad_counter_ids::ne_good_message +Raw bytes (34): 0x[01, 01, 00, 06, 01, 1f, 01, 00, 15, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 11, 01, 01, 05, 00, 0f, 00, 00, 20, 00, 2b, 01, 01, 01, 00, 02] +Number of files: 1 +- file 0 => $DIR/bad_counter_ids.rs +Number of expressions: 0 +Number of file 0 mappings: 6 +- Code(Counter(0)) at (prev + 31, 1) to (start + 0, 21) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 17) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 15) +- Code(Zero) at (prev + 0, 32) to (start + 0, 43) - Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 diff --git a/tests/coverage/bench.cov-map b/tests/coverage/bench.cov-map index 9ee6510f6904..f2b21ddb70bb 100644 --- a/tests/coverage/bench.cov-map +++ b/tests/coverage/bench.cov-map @@ -1,9 +1,10 @@ Function name: bench::my_bench -Raw bytes (9): 0x[01, 01, 00, 01, 01, 08, 01, 00, 27] +Raw bytes (14): 0x[01, 01, 00, 02, 01, 08, 01, 00, 24, 01, 00, 26, 00, 27] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/bench.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 8, 1) to (start + 0, 39) +Number of file 0 mappings: 2 +- Code(Counter(0)) at (prev + 8, 1) to (start + 0, 36) +- Code(Counter(0)) at (prev + 0, 38) to (start + 0, 39) Highest counter ID seen: c0 diff --git a/tests/coverage/branch/generics.cov-map b/tests/coverage/branch/generics.cov-map index 656890634ff4..cb03f2a79f76 100644 --- a/tests/coverage/branch/generics.cov-map +++ b/tests/coverage/branch/generics.cov-map @@ -1,12 +1,13 @@ Function name: generics::print_size::<()> -Raw bytes (33): 0x[01, 01, 01, 01, 05, 05, 01, 06, 01, 01, 24, 20, 05, 02, 01, 08, 00, 24, 05, 00, 25, 02, 06, 02, 02, 0c, 02, 06, 01, 03, 01, 00, 02] +Raw bytes (38): 0x[01, 01, 01, 01, 05, 06, 01, 06, 01, 00, 13, 01, 01, 08, 00, 24, 20, 05, 02, 00, 08, 00, 24, 05, 00, 25, 02, 06, 02, 02, 0c, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/generics.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 5 -- Code(Counter(0)) at (prev + 6, 1) to (start + 1, 36) -- Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 1, 8) to (start + 0, 36) +Number of file 0 mappings: 6 +- Code(Counter(0)) at (prev + 6, 1) to (start + 0, 19) +- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 36) +- Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 0, 8) to (start + 0, 36) true = c1 false = (c0 - c1) - Code(Counter(1)) at (prev + 0, 37) to (start + 2, 6) @@ -16,14 +17,15 @@ Number of file 0 mappings: 5 Highest counter ID seen: c1 Function name: generics::print_size:: -Raw bytes (33): 0x[01, 01, 01, 01, 05, 05, 01, 06, 01, 01, 24, 20, 05, 02, 01, 08, 00, 24, 05, 00, 25, 02, 06, 02, 02, 0c, 02, 06, 01, 03, 01, 00, 02] +Raw bytes (38): 0x[01, 01, 01, 01, 05, 06, 01, 06, 01, 00, 13, 01, 01, 08, 00, 24, 20, 05, 02, 00, 08, 00, 24, 05, 00, 25, 02, 06, 02, 02, 0c, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/generics.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 5 -- Code(Counter(0)) at (prev + 6, 1) to (start + 1, 36) -- Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 1, 8) to (start + 0, 36) +Number of file 0 mappings: 6 +- Code(Counter(0)) at (prev + 6, 1) to (start + 0, 19) +- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 36) +- Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 0, 8) to (start + 0, 36) true = c1 false = (c0 - c1) - Code(Counter(1)) at (prev + 0, 37) to (start + 2, 6) @@ -33,14 +35,15 @@ Number of file 0 mappings: 5 Highest counter ID seen: c1 Function name: generics::print_size:: -Raw bytes (33): 0x[01, 01, 01, 01, 05, 05, 01, 06, 01, 01, 24, 20, 05, 02, 01, 08, 00, 24, 05, 00, 25, 02, 06, 02, 02, 0c, 02, 06, 01, 03, 01, 00, 02] +Raw bytes (38): 0x[01, 01, 01, 01, 05, 06, 01, 06, 01, 00, 13, 01, 01, 08, 00, 24, 20, 05, 02, 00, 08, 00, 24, 05, 00, 25, 02, 06, 02, 02, 0c, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/generics.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 5 -- Code(Counter(0)) at (prev + 6, 1) to (start + 1, 36) -- Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 1, 8) to (start + 0, 36) +Number of file 0 mappings: 6 +- Code(Counter(0)) at (prev + 6, 1) to (start + 0, 19) +- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 36) +- Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 0, 8) to (start + 0, 36) true = c1 false = (c0 - c1) - Code(Counter(1)) at (prev + 0, 37) to (start + 2, 6) diff --git a/tests/coverage/branch/guard.cov-map b/tests/coverage/branch/guard.cov-map index 46533df00f71..9c6a9bf40fd1 100644 --- a/tests/coverage/branch/guard.cov-map +++ b/tests/coverage/branch/guard.cov-map @@ -1,7 +1,7 @@ Function name: guard::branch_match_guard -Raw bytes (89): 0x[01, 01, 08, 05, 0d, 09, 05, 05, 0f, 0d, 11, 17, 1b, 01, 05, 1f, 11, 09, 0d, 0d, 01, 0c, 01, 01, 0e, 02, 03, 0b, 00, 0c, 06, 01, 14, 02, 0a, 0d, 03, 0e, 00, 0f, 05, 00, 14, 00, 19, 20, 0d, 02, 00, 14, 00, 1e, 0d, 00, 1d, 02, 0a, 11, 03, 0e, 00, 0f, 02, 00, 14, 00, 19, 20, 11, 0a, 00, 14, 00, 1e, 11, 00, 1d, 02, 0a, 12, 03, 0e, 02, 0a, 01, 04, 01, 00, 02] +Raw bytes (104): 0x[01, 01, 08, 05, 0d, 09, 05, 05, 0f, 0d, 11, 17, 1b, 01, 05, 1f, 11, 09, 0d, 10, 01, 0c, 01, 00, 26, 01, 01, 05, 00, 0e, 02, 02, 0b, 00, 0c, 06, 01, 14, 02, 0a, 0d, 03, 0e, 00, 0f, 05, 00, 14, 00, 19, 20, 0d, 02, 00, 14, 00, 1e, 0d, 00, 1d, 00, 1e, 0d, 00, 22, 02, 0a, 11, 03, 0e, 00, 0f, 02, 00, 14, 00, 19, 20, 11, 0a, 00, 14, 00, 1e, 11, 00, 1d, 00, 1e, 11, 00, 22, 02, 0a, 12, 03, 0e, 02, 0a, 01, 04, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/guard.rs Number of expressions: 8 - expression 0 operands: lhs = Counter(1), rhs = Counter(3) - expression 1 operands: lhs = Counter(2), rhs = Counter(1) @@ -11,9 +11,10 @@ Number of expressions: 8 - expression 5 operands: lhs = Counter(0), rhs = Counter(1) - expression 6 operands: lhs = Expression(7, Add), rhs = Counter(4) - expression 7 operands: lhs = Counter(2), rhs = Counter(3) -Number of file 0 mappings: 13 -- Code(Counter(0)) at (prev + 12, 1) to (start + 1, 14) -- Code(Expression(0, Sub)) at (prev + 3, 11) to (start + 0, 12) +Number of file 0 mappings: 16 +- Code(Counter(0)) at (prev + 12, 1) to (start + 0, 38) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Code(Expression(0, Sub)) at (prev + 2, 11) to (start + 0, 12) = (c1 - c3) - Code(Expression(1, Sub)) at (prev + 1, 20) to (start + 2, 10) = (c2 - c1) @@ -22,14 +23,16 @@ Number of file 0 mappings: 13 - Branch { true: Counter(3), false: Expression(0, Sub) } at (prev + 0, 20) to (start + 0, 30) true = c3 false = (c1 - c3) -- Code(Counter(3)) at (prev + 0, 29) to (start + 2, 10) +- Code(Counter(3)) at (prev + 0, 29) to (start + 0, 30) +- Code(Counter(3)) at (prev + 0, 34) to (start + 2, 10) - Code(Counter(4)) at (prev + 3, 14) to (start + 0, 15) - Code(Expression(0, Sub)) at (prev + 0, 20) to (start + 0, 25) = (c1 - c3) - Branch { true: Counter(4), false: Expression(2, Sub) } at (prev + 0, 20) to (start + 0, 30) true = c4 false = (c1 - (c3 + c4)) -- Code(Counter(4)) at (prev + 0, 29) to (start + 2, 10) +- Code(Counter(4)) at (prev + 0, 29) to (start + 0, 30) +- Code(Counter(4)) at (prev + 0, 34) to (start + 2, 10) - Code(Expression(4, Sub)) at (prev + 3, 14) to (start + 2, 10) = ((c0 + c1) - ((c2 + c3) + c4)) - Code(Counter(0)) at (prev + 4, 1) to (start + 0, 2) diff --git a/tests/coverage/branch/guard.coverage b/tests/coverage/branch/guard.coverage index f89b965b5d0f..465aefbf0665 100644 --- a/tests/coverage/branch/guard.coverage +++ b/tests/coverage/branch/guard.coverage @@ -17,7 +17,7 @@ LL| 1| println!("zero"); LL| 1| } LL| 3| Some(x) if x % 2 == 0 => { - ^2 + ^2 ^2 ------------------ | Branch (LL:20): [True: 2, False: 1] ------------------ diff --git a/tests/coverage/branch/if-let.cov-map b/tests/coverage/branch/if-let.cov-map index 7f6b174615a9..86bfcadb1255 100644 --- a/tests/coverage/branch/if-let.cov-map +++ b/tests/coverage/branch/if-let.cov-map @@ -1,12 +1,13 @@ Function name: if_let::if_let -Raw bytes (43): 0x[01, 01, 01, 01, 05, 07, 01, 0c, 01, 01, 0e, 20, 02, 05, 03, 0c, 00, 13, 02, 00, 11, 00, 12, 01, 00, 16, 00, 1b, 02, 00, 1c, 02, 06, 05, 02, 0c, 02, 06, 01, 03, 05, 01, 02] +Raw bytes (58): 0x[01, 01, 01, 01, 05, 0a, 01, 0c, 01, 00, 1f, 01, 01, 05, 00, 0e, 20, 02, 05, 02, 0c, 00, 13, 02, 00, 11, 00, 12, 01, 00, 16, 00, 1b, 02, 00, 1c, 02, 06, 05, 02, 0c, 02, 06, 01, 03, 05, 00, 08, 01, 00, 09, 00, 0f, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/if-let.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 7 -- Code(Counter(0)) at (prev + 12, 1) to (start + 1, 14) -- Branch { true: Expression(0, Sub), false: Counter(1) } at (prev + 3, 12) to (start + 0, 19) +Number of file 0 mappings: 10 +- Code(Counter(0)) at (prev + 12, 1) to (start + 0, 31) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Branch { true: Expression(0, Sub), false: Counter(1) } at (prev + 2, 12) to (start + 0, 19) true = (c0 - c1) false = c1 - Code(Expression(0, Sub)) at (prev + 0, 17) to (start + 0, 18) @@ -15,41 +16,53 @@ Number of file 0 mappings: 7 - Code(Expression(0, Sub)) at (prev + 0, 28) to (start + 2, 6) = (c0 - c1) - Code(Counter(1)) at (prev + 2, 12) to (start + 2, 6) -- Code(Counter(0)) at (prev + 3, 5) to (start + 1, 2) +- Code(Counter(0)) at (prev + 3, 5) to (start + 0, 8) +- Code(Counter(0)) at (prev + 0, 9) to (start + 0, 15) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c1 Function name: if_let::if_let_chain -Raw bytes (74): 0x[01, 01, 08, 01, 05, 01, 1f, 05, 09, 01, 1f, 05, 09, 01, 1f, 05, 09, 05, 09, 0a, 01, 17, 01, 00, 33, 20, 02, 05, 01, 0c, 00, 13, 02, 00, 11, 00, 12, 01, 00, 16, 00, 17, 20, 16, 09, 01, 10, 00, 17, 16, 00, 15, 00, 16, 02, 00, 1a, 00, 1b, 16, 01, 05, 03, 06, 1f, 03, 0c, 02, 06, 01, 03, 05, 01, 02] +Raw bytes (102): 0x[01, 01, 0c, 01, 05, 01, 2f, 05, 09, 01, 2f, 05, 09, 01, 2f, 05, 09, 01, 2f, 05, 09, 01, 2f, 05, 09, 05, 09, 0e, 01, 17, 01, 00, 32, 20, 02, 05, 01, 0c, 00, 13, 02, 00, 11, 00, 12, 01, 00, 16, 00, 17, 20, 26, 09, 01, 10, 00, 17, 26, 00, 15, 00, 16, 02, 00, 1a, 00, 1b, 26, 01, 05, 03, 06, 26, 01, 09, 00, 0c, 26, 00, 0d, 00, 0e, 2f, 02, 0c, 02, 06, 01, 03, 05, 00, 08, 01, 00, 09, 00, 0f, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 -Number of expressions: 8 +- file 0 => $DIR/if-let.rs +Number of expressions: 12 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -- expression 1 operands: lhs = Counter(0), rhs = Expression(7, Add) +- expression 1 operands: lhs = Counter(0), rhs = Expression(11, Add) - expression 2 operands: lhs = Counter(1), rhs = Counter(2) -- expression 3 operands: lhs = Counter(0), rhs = Expression(7, Add) +- expression 3 operands: lhs = Counter(0), rhs = Expression(11, Add) - expression 4 operands: lhs = Counter(1), rhs = Counter(2) -- expression 5 operands: lhs = Counter(0), rhs = Expression(7, Add) +- expression 5 operands: lhs = Counter(0), rhs = Expression(11, Add) - expression 6 operands: lhs = Counter(1), rhs = Counter(2) -- expression 7 operands: lhs = Counter(1), rhs = Counter(2) -Number of file 0 mappings: 10 -- Code(Counter(0)) at (prev + 23, 1) to (start + 0, 51) +- expression 7 operands: lhs = Counter(0), rhs = Expression(11, Add) +- expression 8 operands: lhs = Counter(1), rhs = Counter(2) +- expression 9 operands: lhs = Counter(0), rhs = Expression(11, Add) +- expression 10 operands: lhs = Counter(1), rhs = Counter(2) +- expression 11 operands: lhs = Counter(1), rhs = Counter(2) +Number of file 0 mappings: 14 +- Code(Counter(0)) at (prev + 23, 1) to (start + 0, 50) - Branch { true: Expression(0, Sub), false: Counter(1) } at (prev + 1, 12) to (start + 0, 19) true = (c0 - c1) false = c1 - Code(Expression(0, Sub)) at (prev + 0, 17) to (start + 0, 18) = (c0 - c1) - Code(Counter(0)) at (prev + 0, 22) to (start + 0, 23) -- Branch { true: Expression(5, Sub), false: Counter(2) } at (prev + 1, 16) to (start + 0, 23) +- Branch { true: Expression(9, Sub), false: Counter(2) } at (prev + 1, 16) to (start + 0, 23) true = (c0 - (c1 + c2)) false = c2 -- Code(Expression(5, Sub)) at (prev + 0, 21) to (start + 0, 22) +- Code(Expression(9, Sub)) at (prev + 0, 21) to (start + 0, 22) = (c0 - (c1 + c2)) - Code(Expression(0, Sub)) at (prev + 0, 26) to (start + 0, 27) = (c0 - c1) -- Code(Expression(5, Sub)) at (prev + 1, 5) to (start + 3, 6) +- Code(Expression(9, Sub)) at (prev + 1, 5) to (start + 3, 6) = (c0 - (c1 + c2)) -- Code(Expression(7, Add)) at (prev + 3, 12) to (start + 2, 6) +- Code(Expression(9, Sub)) at (prev + 1, 9) to (start + 0, 12) + = (c0 - (c1 + c2)) +- Code(Expression(9, Sub)) at (prev + 0, 13) to (start + 0, 14) + = (c0 - (c1 + c2)) +- Code(Expression(11, Add)) at (prev + 2, 12) to (start + 2, 6) = (c1 + c2) -- Code(Counter(0)) at (prev + 3, 5) to (start + 1, 2) +- Code(Counter(0)) at (prev + 3, 5) to (start + 0, 8) +- Code(Counter(0)) at (prev + 0, 9) to (start + 0, 15) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c2 diff --git a/tests/coverage/branch/if.cov-map b/tests/coverage/branch/if.cov-map index 1d40f032aa87..09a014ce8a1a 100644 --- a/tests/coverage/branch/if.cov-map +++ b/tests/coverage/branch/if.cov-map @@ -1,14 +1,15 @@ Function name: if::branch_and -Raw bytes (54): 0x[01, 01, 03, 01, 05, 05, 09, 01, 09, 08, 01, 2b, 01, 01, 0e, 01, 03, 08, 00, 09, 20, 05, 02, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 20, 09, 06, 00, 0d, 00, 0e, 09, 00, 0f, 02, 06, 0a, 02, 0c, 02, 06, 01, 03, 01, 00, 02] +Raw bytes (59): 0x[01, 01, 03, 01, 05, 05, 09, 01, 09, 09, 01, 2b, 01, 00, 20, 01, 01, 05, 00, 0e, 01, 02, 08, 00, 09, 20, 05, 02, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 20, 09, 06, 00, 0d, 00, 0e, 09, 00, 0f, 02, 06, 0a, 02, 0c, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/if.rs Number of expressions: 3 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Counter(2) - expression 2 operands: lhs = Counter(0), rhs = Counter(2) -Number of file 0 mappings: 8 -- Code(Counter(0)) at (prev + 43, 1) to (start + 1, 14) -- Code(Counter(0)) at (prev + 3, 8) to (start + 0, 9) +Number of file 0 mappings: 9 +- Code(Counter(0)) at (prev + 43, 1) to (start + 0, 32) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 2, 8) to (start + 0, 9) - Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 0, 8) to (start + 0, 9) true = c1 false = (c0 - c1) @@ -23,9 +24,9 @@ Number of file 0 mappings: 8 Highest counter ID seen: c2 Function name: if::branch_not -Raw bytes (116): 0x[01, 01, 07, 01, 05, 01, 09, 01, 09, 01, 0d, 01, 0d, 01, 11, 01, 11, 12, 01, 0c, 01, 01, 0e, 01, 03, 08, 00, 09, 20, 05, 02, 00, 08, 00, 09, 05, 01, 09, 00, 10, 02, 01, 05, 00, 06, 01, 01, 08, 00, 0a, 20, 0a, 09, 00, 08, 00, 0a, 0a, 00, 0b, 02, 06, 09, 02, 05, 00, 06, 01, 01, 08, 00, 0b, 20, 0d, 12, 00, 08, 00, 0b, 0d, 00, 0c, 02, 06, 12, 02, 05, 00, 06, 01, 01, 08, 00, 0c, 20, 1a, 11, 00, 08, 00, 0c, 1a, 00, 0d, 02, 06, 11, 02, 05, 00, 06, 01, 01, 01, 00, 02] +Raw bytes (126): 0x[01, 01, 07, 01, 05, 01, 09, 01, 09, 01, 0d, 01, 0d, 01, 11, 01, 11, 14, 01, 0c, 01, 00, 17, 01, 01, 05, 00, 0e, 01, 02, 08, 00, 09, 20, 05, 02, 00, 08, 00, 09, 05, 01, 09, 00, 0c, 05, 00, 0d, 00, 10, 02, 01, 05, 00, 06, 01, 01, 08, 00, 0a, 20, 0a, 09, 00, 08, 00, 0a, 0a, 00, 0b, 02, 06, 09, 02, 05, 00, 06, 01, 01, 08, 00, 0b, 20, 0d, 12, 00, 08, 00, 0b, 0d, 00, 0c, 02, 06, 12, 02, 05, 00, 06, 01, 01, 08, 00, 0c, 20, 1a, 11, 00, 08, 00, 0c, 1a, 00, 0d, 02, 06, 11, 02, 05, 00, 06, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/if.rs Number of expressions: 7 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(0), rhs = Counter(2) @@ -34,13 +35,15 @@ Number of expressions: 7 - expression 4 operands: lhs = Counter(0), rhs = Counter(3) - expression 5 operands: lhs = Counter(0), rhs = Counter(4) - expression 6 operands: lhs = Counter(0), rhs = Counter(4) -Number of file 0 mappings: 18 -- Code(Counter(0)) at (prev + 12, 1) to (start + 1, 14) -- Code(Counter(0)) at (prev + 3, 8) to (start + 0, 9) +Number of file 0 mappings: 20 +- Code(Counter(0)) at (prev + 12, 1) to (start + 0, 23) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 2, 8) to (start + 0, 9) - Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 0, 8) to (start + 0, 9) true = c1 false = (c0 - c1) -- Code(Counter(1)) at (prev + 1, 9) to (start + 0, 16) +- Code(Counter(1)) at (prev + 1, 9) to (start + 0, 12) +- Code(Counter(1)) at (prev + 0, 13) to (start + 0, 16) - Code(Expression(0, Sub)) at (prev + 1, 5) to (start + 0, 6) = (c0 - c1) - Code(Counter(0)) at (prev + 1, 8) to (start + 0, 10) @@ -68,18 +71,19 @@ Number of file 0 mappings: 18 Highest counter ID seen: c4 Function name: if::branch_not_as -Raw bytes (90): 0x[01, 01, 05, 01, 05, 01, 09, 01, 09, 01, 0d, 01, 0d, 0e, 01, 1d, 01, 01, 0e, 01, 03, 08, 00, 14, 20, 02, 05, 00, 08, 00, 14, 02, 00, 15, 02, 06, 05, 02, 05, 00, 06, 01, 01, 08, 00, 15, 20, 09, 0a, 00, 08, 00, 15, 09, 00, 16, 02, 06, 0a, 02, 05, 00, 06, 01, 01, 08, 00, 16, 20, 12, 0d, 00, 08, 00, 16, 12, 00, 17, 02, 06, 0d, 02, 05, 00, 06, 01, 01, 01, 00, 02] +Raw bytes (95): 0x[01, 01, 05, 01, 05, 01, 09, 01, 09, 01, 0d, 01, 0d, 0f, 01, 1d, 01, 00, 1a, 01, 01, 05, 00, 0e, 01, 02, 08, 00, 14, 20, 02, 05, 00, 08, 00, 14, 02, 00, 15, 02, 06, 05, 02, 05, 00, 06, 01, 01, 08, 00, 15, 20, 09, 0a, 00, 08, 00, 15, 09, 00, 16, 02, 06, 0a, 02, 05, 00, 06, 01, 01, 08, 00, 16, 20, 12, 0d, 00, 08, 00, 16, 12, 00, 17, 02, 06, 0d, 02, 05, 00, 06, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/if.rs Number of expressions: 5 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(0), rhs = Counter(2) - expression 2 operands: lhs = Counter(0), rhs = Counter(2) - expression 3 operands: lhs = Counter(0), rhs = Counter(3) - expression 4 operands: lhs = Counter(0), rhs = Counter(3) -Number of file 0 mappings: 14 -- Code(Counter(0)) at (prev + 29, 1) to (start + 1, 14) -- Code(Counter(0)) at (prev + 3, 8) to (start + 0, 20) +Number of file 0 mappings: 15 +- Code(Counter(0)) at (prev + 29, 1) to (start + 0, 26) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 2, 8) to (start + 0, 20) - Branch { true: Expression(0, Sub), false: Counter(1) } at (prev + 0, 8) to (start + 0, 20) true = (c0 - c1) false = c1 @@ -104,9 +108,9 @@ Number of file 0 mappings: 14 Highest counter ID seen: c3 Function name: if::branch_or -Raw bytes (60): 0x[01, 01, 06, 01, 05, 01, 17, 05, 09, 05, 09, 01, 17, 05, 09, 08, 01, 35, 01, 01, 0e, 01, 03, 08, 00, 09, 20, 05, 02, 00, 08, 00, 09, 02, 00, 0d, 00, 0e, 20, 09, 12, 00, 0d, 00, 0e, 17, 00, 0f, 02, 06, 12, 02, 0c, 02, 06, 01, 03, 01, 00, 02] +Raw bytes (65): 0x[01, 01, 06, 01, 05, 01, 17, 05, 09, 05, 09, 01, 17, 05, 09, 09, 01, 35, 01, 00, 1f, 01, 01, 05, 00, 0e, 01, 02, 08, 00, 09, 20, 05, 02, 00, 08, 00, 09, 02, 00, 0d, 00, 0e, 20, 09, 12, 00, 0d, 00, 0e, 17, 00, 0f, 02, 06, 12, 02, 0c, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/if.rs Number of expressions: 6 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(0), rhs = Expression(5, Add) @@ -114,9 +118,10 @@ Number of expressions: 6 - expression 3 operands: lhs = Counter(1), rhs = Counter(2) - expression 4 operands: lhs = Counter(0), rhs = Expression(5, Add) - expression 5 operands: lhs = Counter(1), rhs = Counter(2) -Number of file 0 mappings: 8 -- Code(Counter(0)) at (prev + 53, 1) to (start + 1, 14) -- Code(Counter(0)) at (prev + 3, 8) to (start + 0, 9) +Number of file 0 mappings: 9 +- Code(Counter(0)) at (prev + 53, 1) to (start + 0, 31) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 2, 8) to (start + 0, 9) - Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 0, 8) to (start + 0, 9) true = c1 false = (c0 - c1) diff --git a/tests/coverage/branch/lazy-boolean.cov-map b/tests/coverage/branch/lazy-boolean.cov-map index 5d4fc57eb8f7..9ec7c9a7f42b 100644 --- a/tests/coverage/branch/lazy-boolean.cov-map +++ b/tests/coverage/branch/lazy-boolean.cov-map @@ -1,42 +1,48 @@ Function name: lazy_boolean::branch_and -Raw bytes (38): 0x[01, 01, 01, 01, 05, 06, 01, 13, 01, 01, 0e, 01, 04, 09, 00, 0a, 01, 00, 0d, 00, 0e, 20, 05, 02, 00, 0d, 00, 0e, 05, 00, 12, 00, 13, 01, 01, 05, 01, 02] +Raw bytes (53): 0x[01, 01, 01, 01, 05, 09, 01, 13, 01, 00, 20, 01, 01, 05, 00, 0e, 01, 03, 09, 00, 0a, 01, 00, 0d, 00, 0e, 20, 05, 02, 00, 0d, 00, 0e, 05, 00, 12, 00, 13, 01, 01, 05, 00, 0e, 01, 00, 0f, 00, 10, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/lazy-boolean.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 6 -- Code(Counter(0)) at (prev + 19, 1) to (start + 1, 14) -- Code(Counter(0)) at (prev + 4, 9) to (start + 0, 10) +Number of file 0 mappings: 9 +- Code(Counter(0)) at (prev + 19, 1) to (start + 0, 32) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 3, 9) to (start + 0, 10) - Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14) - Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 0, 13) to (start + 0, 14) true = c1 false = (c0 - c1) - Code(Counter(1)) at (prev + 0, 18) to (start + 0, 19) -- Code(Counter(0)) at (prev + 1, 5) to (start + 1, 2) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 16) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c1 Function name: lazy_boolean::branch_or -Raw bytes (38): 0x[01, 01, 01, 01, 05, 06, 01, 1b, 01, 01, 0e, 01, 04, 09, 00, 0a, 01, 00, 0d, 00, 0e, 20, 05, 02, 00, 0d, 00, 0e, 02, 00, 12, 00, 13, 01, 01, 05, 01, 02] +Raw bytes (53): 0x[01, 01, 01, 01, 05, 09, 01, 1b, 01, 00, 1f, 01, 01, 05, 00, 0e, 01, 03, 09, 00, 0a, 01, 00, 0d, 00, 0e, 20, 05, 02, 00, 0d, 00, 0e, 02, 00, 12, 00, 13, 01, 01, 05, 00, 0e, 01, 00, 0f, 00, 10, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/lazy-boolean.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 6 -- Code(Counter(0)) at (prev + 27, 1) to (start + 1, 14) -- Code(Counter(0)) at (prev + 4, 9) to (start + 0, 10) +Number of file 0 mappings: 9 +- Code(Counter(0)) at (prev + 27, 1) to (start + 0, 31) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 3, 9) to (start + 0, 10) - Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14) - Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 0, 13) to (start + 0, 14) true = c1 false = (c0 - c1) - Code(Expression(0, Sub)) at (prev + 0, 18) to (start + 0, 19) = (c0 - c1) -- Code(Counter(0)) at (prev + 1, 5) to (start + 1, 2) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 16) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c1 Function name: lazy_boolean::chain -Raw bytes (141): 0x[01, 01, 0f, 01, 05, 05, 09, 09, 0d, 01, 11, 01, 11, 01, 3b, 11, 15, 01, 3b, 11, 15, 01, 37, 3b, 19, 11, 15, 01, 37, 3b, 19, 11, 15, 13, 01, 24, 01, 01, 0e, 01, 04, 09, 00, 0a, 01, 00, 0d, 00, 12, 20, 05, 02, 00, 0d, 00, 12, 05, 00, 16, 00, 1b, 20, 09, 06, 00, 16, 00, 1b, 09, 00, 1f, 00, 24, 20, 0d, 0a, 00, 1f, 00, 24, 0d, 00, 28, 00, 2d, 01, 01, 05, 00, 10, 01, 03, 09, 00, 0a, 01, 00, 0d, 00, 12, 20, 11, 12, 00, 0d, 00, 12, 12, 00, 16, 00, 1b, 20, 15, 1e, 00, 16, 00, 1b, 1e, 00, 1f, 00, 24, 20, 19, 32, 00, 1f, 00, 24, 32, 00, 28, 00, 2d, 01, 01, 05, 01, 02] +Raw bytes (161): 0x[01, 01, 0f, 01, 05, 05, 09, 09, 0d, 01, 11, 01, 11, 01, 3b, 11, 15, 01, 3b, 11, 15, 01, 37, 3b, 19, 11, 15, 01, 37, 3b, 19, 11, 15, 17, 01, 24, 01, 00, 11, 01, 01, 05, 00, 0e, 01, 03, 09, 00, 0a, 01, 00, 0d, 00, 12, 20, 05, 02, 00, 0d, 00, 12, 05, 00, 16, 00, 1b, 20, 09, 06, 00, 16, 00, 1b, 09, 00, 1f, 00, 24, 20, 0d, 0a, 00, 1f, 00, 24, 0d, 00, 28, 00, 2d, 01, 01, 05, 00, 0e, 01, 00, 0f, 00, 10, 01, 03, 09, 00, 0a, 01, 00, 0d, 00, 12, 20, 11, 12, 00, 0d, 00, 12, 12, 00, 16, 00, 1b, 20, 15, 1e, 00, 16, 00, 1b, 1e, 00, 1f, 00, 24, 20, 19, 32, 00, 1f, 00, 24, 32, 00, 28, 00, 2d, 01, 01, 05, 00, 0e, 01, 00, 0f, 00, 10, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/lazy-boolean.rs Number of expressions: 15 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Counter(2) @@ -53,9 +59,10 @@ Number of expressions: 15 - expression 12 operands: lhs = Counter(0), rhs = Expression(13, Add) - expression 13 operands: lhs = Expression(14, Add), rhs = Counter(6) - expression 14 operands: lhs = Counter(4), rhs = Counter(5) -Number of file 0 mappings: 19 -- Code(Counter(0)) at (prev + 36, 1) to (start + 1, 14) -- Code(Counter(0)) at (prev + 4, 9) to (start + 0, 10) +Number of file 0 mappings: 23 +- Code(Counter(0)) at (prev + 36, 1) to (start + 0, 17) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 3, 9) to (start + 0, 10) - Code(Counter(0)) at (prev + 0, 13) to (start + 0, 18) - Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 0, 13) to (start + 0, 18) true = c1 @@ -69,7 +76,8 @@ Number of file 0 mappings: 19 true = c3 false = (c2 - c3) - Code(Counter(3)) at (prev + 0, 40) to (start + 0, 45) -- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 16) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 16) - Code(Counter(0)) at (prev + 3, 9) to (start + 0, 10) - Code(Counter(0)) at (prev + 0, 13) to (start + 0, 18) - Branch { true: Counter(4), false: Expression(4, Sub) } at (prev + 0, 13) to (start + 0, 18) @@ -87,13 +95,15 @@ Number of file 0 mappings: 19 false = (c0 - ((c4 + c5) + c6)) - Code(Expression(12, Sub)) at (prev + 0, 40) to (start + 0, 45) = (c0 - ((c4 + c5) + c6)) -- Code(Counter(0)) at (prev + 1, 5) to (start + 1, 2) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 16) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c6 Function name: lazy_boolean::nested_mixed -Raw bytes (137): 0x[01, 01, 0d, 01, 05, 01, 1f, 05, 09, 05, 09, 1f, 0d, 05, 09, 1f, 0d, 05, 09, 01, 11, 11, 15, 01, 15, 01, 33, 15, 19, 13, 01, 31, 01, 01, 0e, 01, 04, 09, 00, 0a, 01, 00, 0e, 00, 13, 20, 05, 02, 00, 0e, 00, 13, 02, 00, 17, 00, 1d, 20, 09, 06, 00, 17, 00, 1d, 1f, 00, 23, 00, 28, 20, 0d, 1a, 00, 23, 00, 28, 1a, 00, 2c, 00, 33, 01, 01, 05, 00, 10, 01, 03, 09, 00, 0a, 01, 00, 0e, 00, 13, 20, 11, 22, 00, 0e, 00, 13, 11, 00, 17, 00, 1c, 20, 15, 26, 00, 17, 00, 1c, 2a, 00, 22, 00, 28, 20, 19, 2e, 00, 22, 00, 28, 19, 00, 2c, 00, 33, 01, 01, 05, 01, 02] +Raw bytes (157): 0x[01, 01, 0d, 01, 05, 01, 1f, 05, 09, 05, 09, 1f, 0d, 05, 09, 1f, 0d, 05, 09, 01, 11, 11, 15, 01, 15, 01, 33, 15, 19, 17, 01, 31, 01, 00, 18, 01, 01, 05, 00, 0e, 01, 03, 09, 00, 0a, 01, 00, 0e, 00, 13, 20, 05, 02, 00, 0e, 00, 13, 02, 00, 17, 00, 1d, 20, 09, 06, 00, 17, 00, 1d, 1f, 00, 23, 00, 28, 20, 0d, 1a, 00, 23, 00, 28, 1a, 00, 2c, 00, 33, 01, 01, 05, 00, 0e, 01, 00, 0f, 00, 10, 01, 03, 09, 00, 0a, 01, 00, 0e, 00, 13, 20, 11, 22, 00, 0e, 00, 13, 11, 00, 17, 00, 1c, 20, 15, 26, 00, 17, 00, 1c, 2a, 00, 22, 00, 28, 20, 19, 2e, 00, 22, 00, 28, 19, 00, 2c, 00, 33, 01, 01, 05, 00, 0e, 01, 00, 0f, 00, 10, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/lazy-boolean.rs Number of expressions: 13 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(0), rhs = Expression(7, Add) @@ -108,9 +118,10 @@ Number of expressions: 13 - expression 10 operands: lhs = Counter(0), rhs = Counter(5) - expression 11 operands: lhs = Counter(0), rhs = Expression(12, Add) - expression 12 operands: lhs = Counter(5), rhs = Counter(6) -Number of file 0 mappings: 19 -- Code(Counter(0)) at (prev + 49, 1) to (start + 1, 14) -- Code(Counter(0)) at (prev + 4, 9) to (start + 0, 10) +Number of file 0 mappings: 23 +- Code(Counter(0)) at (prev + 49, 1) to (start + 0, 24) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 3, 9) to (start + 0, 10) - Code(Counter(0)) at (prev + 0, 14) to (start + 0, 19) - Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 0, 14) to (start + 0, 19) true = c1 @@ -127,7 +138,8 @@ Number of file 0 mappings: 19 false = ((c1 + c2) - c3) - Code(Expression(6, Sub)) at (prev + 0, 44) to (start + 0, 51) = ((c1 + c2) - c3) -- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 16) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 16) - Code(Counter(0)) at (prev + 3, 9) to (start + 0, 10) - Code(Counter(0)) at (prev + 0, 14) to (start + 0, 19) - Branch { true: Counter(4), false: Expression(8, Sub) } at (prev + 0, 14) to (start + 0, 19) @@ -143,6 +155,8 @@ Number of file 0 mappings: 19 true = c6 false = (c0 - (c5 + c6)) - Code(Counter(6)) at (prev + 0, 44) to (start + 0, 51) -- Code(Counter(0)) at (prev + 1, 5) to (start + 1, 2) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 16) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c6 diff --git a/tests/coverage/branch/let-else.cov-map b/tests/coverage/branch/let-else.cov-map index 78507a326388..61bedbfbff0c 100644 --- a/tests/coverage/branch/let-else.cov-map +++ b/tests/coverage/branch/let-else.cov-map @@ -1,19 +1,24 @@ Function name: let_else::let_else -Raw bytes (43): 0x[01, 01, 01, 01, 05, 07, 01, 0c, 01, 01, 0e, 20, 02, 05, 03, 09, 00, 10, 02, 00, 0e, 00, 0f, 01, 00, 13, 00, 18, 05, 01, 09, 01, 0f, 02, 04, 05, 00, 0a, 01, 01, 01, 00, 02] +Raw bytes (63): 0x[01, 01, 01, 01, 05, 0b, 01, 0c, 01, 00, 21, 01, 01, 05, 00, 0e, 20, 02, 05, 02, 09, 00, 10, 02, 00, 0e, 00, 0f, 01, 00, 13, 00, 18, 05, 01, 09, 00, 0c, 05, 00, 0d, 00, 13, 05, 01, 09, 00, 0f, 02, 03, 05, 00, 08, 02, 00, 09, 00, 0a, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/let-else.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 7 -- Code(Counter(0)) at (prev + 12, 1) to (start + 1, 14) -- Branch { true: Expression(0, Sub), false: Counter(1) } at (prev + 3, 9) to (start + 0, 16) +Number of file 0 mappings: 11 +- Code(Counter(0)) at (prev + 12, 1) to (start + 0, 33) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Branch { true: Expression(0, Sub), false: Counter(1) } at (prev + 2, 9) to (start + 0, 16) true = (c0 - c1) false = c1 - Code(Expression(0, Sub)) at (prev + 0, 14) to (start + 0, 15) = (c0 - c1) - Code(Counter(0)) at (prev + 0, 19) to (start + 0, 24) -- Code(Counter(1)) at (prev + 1, 9) to (start + 1, 15) -- Code(Expression(0, Sub)) at (prev + 4, 5) to (start + 0, 10) +- Code(Counter(1)) at (prev + 1, 9) to (start + 0, 12) +- Code(Counter(1)) at (prev + 0, 13) to (start + 0, 19) +- Code(Counter(1)) at (prev + 1, 9) to (start + 0, 15) +- Code(Expression(0, Sub)) at (prev + 3, 5) to (start + 0, 8) + = (c0 - c1) +- Code(Expression(0, Sub)) at (prev + 0, 9) to (start + 0, 10) = (c0 - c1) - Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c1 diff --git a/tests/coverage/branch/match-arms.cov-map b/tests/coverage/branch/match-arms.cov-map index ef71d12c8af1..a2ed0d84ed61 100644 --- a/tests/coverage/branch/match-arms.cov-map +++ b/tests/coverage/branch/match-arms.cov-map @@ -1,7 +1,7 @@ Function name: match_arms::guards -Raw bytes (88): 0x[01, 01, 08, 15, 05, 19, 09, 1d, 0d, 21, 11, 01, 17, 1b, 11, 1f, 0d, 05, 09, 0c, 01, 30, 01, 01, 0e, 21, 03, 0b, 00, 10, 05, 01, 11, 00, 28, 20, 05, 02, 00, 17, 00, 1b, 09, 01, 11, 00, 28, 20, 09, 06, 00, 17, 00, 1b, 0d, 01, 11, 00, 28, 20, 0d, 0a, 00, 17, 00, 1b, 11, 01, 11, 00, 28, 20, 11, 0e, 00, 17, 00, 1b, 12, 01, 0e, 00, 15, 01, 03, 05, 01, 02] +Raw bytes (158): 0x[01, 01, 08, 15, 05, 19, 09, 1d, 0d, 21, 11, 01, 17, 1b, 11, 1f, 0d, 05, 09, 1a, 01, 30, 01, 00, 23, 01, 01, 05, 00, 0e, 21, 02, 0b, 00, 10, 05, 01, 11, 00, 12, 20, 05, 02, 00, 17, 00, 1b, 05, 00, 1a, 00, 1b, 05, 00, 1f, 00, 26, 05, 00, 27, 00, 28, 09, 01, 11, 00, 12, 20, 09, 06, 00, 17, 00, 1b, 09, 00, 1a, 00, 1b, 09, 00, 1f, 00, 26, 09, 00, 27, 00, 28, 0d, 01, 11, 00, 12, 20, 0d, 0a, 00, 17, 00, 1b, 0d, 00, 1a, 00, 1b, 0d, 00, 1f, 00, 26, 0d, 00, 27, 00, 28, 11, 01, 11, 00, 12, 20, 11, 0e, 00, 17, 00, 1b, 11, 00, 1a, 00, 1b, 11, 00, 1f, 00, 26, 11, 00, 27, 00, 28, 12, 01, 0e, 00, 15, 01, 03, 05, 00, 0c, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/match-arms.rs Number of expressions: 8 - expression 0 operands: lhs = Counter(5), rhs = Counter(1) - expression 1 operands: lhs = Counter(6), rhs = Counter(2) @@ -11,70 +11,103 @@ Number of expressions: 8 - expression 5 operands: lhs = Expression(6, Add), rhs = Counter(4) - expression 6 operands: lhs = Expression(7, Add), rhs = Counter(3) - expression 7 operands: lhs = Counter(1), rhs = Counter(2) -Number of file 0 mappings: 12 -- Code(Counter(0)) at (prev + 48, 1) to (start + 1, 14) -- Code(Counter(8)) at (prev + 3, 11) to (start + 0, 16) -- Code(Counter(1)) at (prev + 1, 17) to (start + 0, 40) +Number of file 0 mappings: 26 +- Code(Counter(0)) at (prev + 48, 1) to (start + 0, 35) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Code(Counter(8)) at (prev + 2, 11) to (start + 0, 16) +- Code(Counter(1)) at (prev + 1, 17) to (start + 0, 18) - Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 0, 23) to (start + 0, 27) true = c1 false = (c5 - c1) -- Code(Counter(2)) at (prev + 1, 17) to (start + 0, 40) +- Code(Counter(1)) at (prev + 0, 26) to (start + 0, 27) +- Code(Counter(1)) at (prev + 0, 31) to (start + 0, 38) +- Code(Counter(1)) at (prev + 0, 39) to (start + 0, 40) +- Code(Counter(2)) at (prev + 1, 17) to (start + 0, 18) - Branch { true: Counter(2), false: Expression(1, Sub) } at (prev + 0, 23) to (start + 0, 27) true = c2 false = (c6 - c2) -- Code(Counter(3)) at (prev + 1, 17) to (start + 0, 40) +- Code(Counter(2)) at (prev + 0, 26) to (start + 0, 27) +- Code(Counter(2)) at (prev + 0, 31) to (start + 0, 38) +- Code(Counter(2)) at (prev + 0, 39) to (start + 0, 40) +- Code(Counter(3)) at (prev + 1, 17) to (start + 0, 18) - Branch { true: Counter(3), false: Expression(2, Sub) } at (prev + 0, 23) to (start + 0, 27) true = c3 false = (c7 - c3) -- Code(Counter(4)) at (prev + 1, 17) to (start + 0, 40) +- Code(Counter(3)) at (prev + 0, 26) to (start + 0, 27) +- Code(Counter(3)) at (prev + 0, 31) to (start + 0, 38) +- Code(Counter(3)) at (prev + 0, 39) to (start + 0, 40) +- Code(Counter(4)) at (prev + 1, 17) to (start + 0, 18) - Branch { true: Counter(4), false: Expression(3, Sub) } at (prev + 0, 23) to (start + 0, 27) true = c4 false = (c8 - c4) +- Code(Counter(4)) at (prev + 0, 26) to (start + 0, 27) +- Code(Counter(4)) at (prev + 0, 31) to (start + 0, 38) +- Code(Counter(4)) at (prev + 0, 39) to (start + 0, 40) - Code(Expression(4, Sub)) at (prev + 1, 14) to (start + 0, 21) = (c0 - (((c1 + c2) + c3) + c4)) -- Code(Counter(0)) at (prev + 3, 5) to (start + 1, 2) +- Code(Counter(0)) at (prev + 3, 5) to (start + 0, 12) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c8 Function name: match_arms::match_arms -Raw bytes (45): 0x[01, 01, 03, 01, 07, 0b, 0d, 05, 09, 07, 01, 18, 01, 01, 0e, 01, 03, 0b, 00, 10, 05, 01, 11, 00, 20, 09, 01, 11, 00, 20, 0d, 01, 11, 00, 20, 02, 01, 11, 00, 20, 01, 03, 05, 01, 02] +Raw bytes (95): 0x[01, 01, 03, 01, 07, 0b, 0d, 05, 09, 11, 01, 18, 01, 00, 1b, 01, 01, 05, 00, 0e, 01, 02, 0b, 00, 10, 05, 01, 11, 00, 12, 05, 00, 17, 00, 1e, 05, 00, 1f, 00, 20, 09, 01, 11, 00, 12, 09, 00, 17, 00, 1e, 09, 00, 1f, 00, 20, 0d, 01, 11, 00, 12, 0d, 00, 17, 00, 1e, 0d, 00, 1f, 00, 20, 02, 01, 11, 00, 12, 02, 00, 17, 00, 1e, 02, 00, 1f, 00, 20, 01, 03, 05, 00, 0c, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/match-arms.rs Number of expressions: 3 - expression 0 operands: lhs = Counter(0), rhs = Expression(1, Add) - expression 1 operands: lhs = Expression(2, Add), rhs = Counter(3) - expression 2 operands: lhs = Counter(1), rhs = Counter(2) -Number of file 0 mappings: 7 -- Code(Counter(0)) at (prev + 24, 1) to (start + 1, 14) -- Code(Counter(0)) at (prev + 3, 11) to (start + 0, 16) -- Code(Counter(1)) at (prev + 1, 17) to (start + 0, 32) -- Code(Counter(2)) at (prev + 1, 17) to (start + 0, 32) -- Code(Counter(3)) at (prev + 1, 17) to (start + 0, 32) -- Code(Expression(0, Sub)) at (prev + 1, 17) to (start + 0, 32) +Number of file 0 mappings: 17 +- Code(Counter(0)) at (prev + 24, 1) to (start + 0, 27) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 2, 11) to (start + 0, 16) +- Code(Counter(1)) at (prev + 1, 17) to (start + 0, 18) +- Code(Counter(1)) at (prev + 0, 23) to (start + 0, 30) +- Code(Counter(1)) at (prev + 0, 31) to (start + 0, 32) +- Code(Counter(2)) at (prev + 1, 17) to (start + 0, 18) +- Code(Counter(2)) at (prev + 0, 23) to (start + 0, 30) +- Code(Counter(2)) at (prev + 0, 31) to (start + 0, 32) +- Code(Counter(3)) at (prev + 1, 17) to (start + 0, 18) +- Code(Counter(3)) at (prev + 0, 23) to (start + 0, 30) +- Code(Counter(3)) at (prev + 0, 31) to (start + 0, 32) +- Code(Expression(0, Sub)) at (prev + 1, 17) to (start + 0, 18) = (c0 - ((c1 + c2) + c3)) -- Code(Counter(0)) at (prev + 3, 5) to (start + 1, 2) +- Code(Expression(0, Sub)) at (prev + 0, 23) to (start + 0, 30) + = (c0 - ((c1 + c2) + c3)) +- Code(Expression(0, Sub)) at (prev + 0, 31) to (start + 0, 32) + = (c0 - ((c1 + c2) + c3)) +- Code(Counter(0)) at (prev + 3, 5) to (start + 0, 12) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c3 Function name: match_arms::or_patterns -Raw bytes (57): 0x[01, 01, 04, 05, 09, 01, 0b, 03, 0d, 01, 03, 09, 01, 25, 01, 01, 0e, 01, 03, 0b, 00, 10, 05, 01, 11, 00, 12, 09, 00, 1e, 00, 1f, 03, 00, 24, 00, 2d, 0d, 01, 11, 00, 12, 06, 00, 1e, 00, 1f, 0e, 00, 24, 00, 2d, 01, 03, 05, 01, 02] +Raw bytes (79): 0x[01, 01, 05, 05, 09, 01, 0b, 03, 0d, 01, 03, 01, 03, 0d, 01, 25, 01, 00, 1c, 01, 01, 05, 00, 0e, 01, 02, 0b, 00, 10, 05, 01, 11, 00, 12, 09, 00, 1e, 00, 1f, 03, 00, 24, 00, 2b, 03, 00, 2c, 00, 2d, 0d, 01, 11, 00, 12, 06, 00, 1e, 00, 1f, 12, 00, 24, 00, 2b, 12, 00, 2c, 00, 2d, 01, 03, 05, 00, 0c, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 -Number of expressions: 4 +- file 0 => $DIR/match-arms.rs +Number of expressions: 5 - expression 0 operands: lhs = Counter(1), rhs = Counter(2) - expression 1 operands: lhs = Counter(0), rhs = Expression(2, Add) - expression 2 operands: lhs = Expression(0, Add), rhs = Counter(3) - expression 3 operands: lhs = Counter(0), rhs = Expression(0, Add) -Number of file 0 mappings: 9 -- Code(Counter(0)) at (prev + 37, 1) to (start + 1, 14) -- Code(Counter(0)) at (prev + 3, 11) to (start + 0, 16) +- expression 4 operands: lhs = Counter(0), rhs = Expression(0, Add) +Number of file 0 mappings: 13 +- Code(Counter(0)) at (prev + 37, 1) to (start + 0, 28) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 2, 11) to (start + 0, 16) - Code(Counter(1)) at (prev + 1, 17) to (start + 0, 18) - Code(Counter(2)) at (prev + 0, 30) to (start + 0, 31) -- Code(Expression(0, Add)) at (prev + 0, 36) to (start + 0, 45) +- Code(Expression(0, Add)) at (prev + 0, 36) to (start + 0, 43) + = (c1 + c2) +- Code(Expression(0, Add)) at (prev + 0, 44) to (start + 0, 45) = (c1 + c2) - Code(Counter(3)) at (prev + 1, 17) to (start + 0, 18) - Code(Expression(1, Sub)) at (prev + 0, 30) to (start + 0, 31) = (c0 - ((c1 + c2) + c3)) -- Code(Expression(3, Sub)) at (prev + 0, 36) to (start + 0, 45) +- Code(Expression(4, Sub)) at (prev + 0, 36) to (start + 0, 43) = (c0 - (c1 + c2)) -- Code(Counter(0)) at (prev + 3, 5) to (start + 1, 2) +- Code(Expression(4, Sub)) at (prev + 0, 44) to (start + 0, 45) + = (c0 - (c1 + c2)) +- Code(Counter(0)) at (prev + 3, 5) to (start + 0, 12) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c3 diff --git a/tests/coverage/branch/match-trivial.cov-map b/tests/coverage/branch/match-trivial.cov-map index 1b0c6d12e3dc..a88e89523ae2 100644 --- a/tests/coverage/branch/match-trivial.cov-map +++ b/tests/coverage/branch/match-trivial.cov-map @@ -1,19 +1,24 @@ Function name: match_trivial::_uninhabited (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 16, 01, 01, 0e] +Raw bytes (14): 0x[01, 01, 00, 02, 00, 16, 01, 00, 20, 00, 01, 05, 00, 0e] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/match-trivial.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 22, 1) to (start + 1, 14) +Number of file 0 mappings: 2 +- Code(Zero) at (prev + 22, 1) to (start + 0, 32) +- Code(Zero) at (prev + 1, 5) to (start + 0, 14) Highest counter ID seen: (none) Function name: match_trivial::trivial -Raw bytes (14): 0x[01, 01, 00, 02, 01, 1e, 01, 01, 0e, 01, 03, 0b, 05, 02] +Raw bytes (34): 0x[01, 01, 00, 06, 01, 1e, 01, 00, 17, 01, 01, 05, 00, 0e, 01, 02, 0b, 00, 0c, 01, 01, 1b, 00, 22, 01, 03, 05, 00, 0c, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/match-trivial.rs Number of expressions: 0 -Number of file 0 mappings: 2 -- Code(Counter(0)) at (prev + 30, 1) to (start + 1, 14) -- Code(Counter(0)) at (prev + 3, 11) to (start + 5, 2) +Number of file 0 mappings: 6 +- Code(Counter(0)) at (prev + 30, 1) to (start + 0, 23) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 2, 11) to (start + 0, 12) +- Code(Counter(0)) at (prev + 1, 27) to (start + 0, 34) +- Code(Counter(0)) at (prev + 3, 5) to (start + 0, 12) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 diff --git a/tests/coverage/branch/match-trivial.coverage b/tests/coverage/branch/match-trivial.coverage index 4ffb172e1b67..6e7bf2d29abc 100644 --- a/tests/coverage/branch/match-trivial.coverage +++ b/tests/coverage/branch/match-trivial.coverage @@ -32,8 +32,8 @@ LL| | LL| 1| match x { LL| 1| Trivial::Value => consume("trivial"), - LL| 1| } - LL| 1| + LL| | } + LL| | LL| 1| consume("done"); LL| 1|} LL| | diff --git a/tests/coverage/branch/no-mir-spans.cov-map b/tests/coverage/branch/no-mir-spans.cov-map index 8fb44ef30fdb..4f893cba1f81 100644 --- a/tests/coverage/branch/no-mir-spans.cov-map +++ b/tests/coverage/branch/no-mir-spans.cov-map @@ -1,40 +1,40 @@ Function name: no_mir_spans::while_cond -Raw bytes (18): 0x[01, 01, 01, 05, 01, 02, 01, 10, 01, 00, 11, 20, 02, 01, 04, 0b, 00, 10] +Raw bytes (18): 0x[01, 01, 01, 05, 01, 02, 01, 10, 01, 00, 10, 20, 02, 01, 04, 0b, 00, 10] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/no-mir-spans.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(1), rhs = Counter(0) Number of file 0 mappings: 2 -- Code(Counter(0)) at (prev + 16, 1) to (start + 0, 17) +- Code(Counter(0)) at (prev + 16, 1) to (start + 0, 16) - Branch { true: Expression(0, Sub), false: Counter(0) } at (prev + 4, 11) to (start + 0, 16) true = (c1 - c0) false = c0 Highest counter ID seen: c0 Function name: no_mir_spans::while_cond_not -Raw bytes (18): 0x[01, 01, 01, 05, 01, 02, 01, 19, 01, 00, 15, 20, 02, 01, 04, 0b, 00, 14] +Raw bytes (18): 0x[01, 01, 01, 05, 01, 02, 01, 19, 01, 00, 14, 20, 02, 01, 04, 0b, 00, 14] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/no-mir-spans.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(1), rhs = Counter(0) Number of file 0 mappings: 2 -- Code(Counter(0)) at (prev + 25, 1) to (start + 0, 21) +- Code(Counter(0)) at (prev + 25, 1) to (start + 0, 20) - Branch { true: Expression(0, Sub), false: Counter(0) } at (prev + 4, 11) to (start + 0, 20) true = (c1 - c0) false = c0 Highest counter ID seen: c0 Function name: no_mir_spans::while_op_and -Raw bytes (31): 0x[01, 01, 04, 09, 05, 09, 01, 0f, 09, 01, 05, 03, 01, 22, 01, 00, 13, 20, 05, 02, 05, 0b, 00, 10, 20, 06, 0a, 00, 14, 00, 19] +Raw bytes (31): 0x[01, 01, 04, 09, 05, 09, 01, 0f, 09, 01, 05, 03, 01, 22, 01, 00, 12, 20, 05, 02, 05, 0b, 00, 10, 20, 06, 0a, 00, 14, 00, 19] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/no-mir-spans.rs Number of expressions: 4 - expression 0 operands: lhs = Counter(2), rhs = Counter(1) - expression 1 operands: lhs = Counter(2), rhs = Counter(0) - expression 2 operands: lhs = Expression(3, Add), rhs = Counter(2) - expression 3 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 3 -- Code(Counter(0)) at (prev + 34, 1) to (start + 0, 19) +- Code(Counter(0)) at (prev + 34, 1) to (start + 0, 18) - Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 5, 11) to (start + 0, 16) true = c1 false = (c2 - c1) @@ -44,15 +44,15 @@ Number of file 0 mappings: 3 Highest counter ID seen: c1 Function name: no_mir_spans::while_op_or -Raw bytes (29): 0x[01, 01, 03, 09, 05, 09, 0b, 01, 05, 03, 01, 2d, 01, 00, 12, 20, 05, 02, 05, 0b, 00, 10, 20, 06, 01, 00, 14, 00, 19] +Raw bytes (29): 0x[01, 01, 03, 09, 05, 09, 0b, 01, 05, 03, 01, 2d, 01, 00, 11, 20, 05, 02, 05, 0b, 00, 10, 20, 06, 01, 00, 14, 00, 19] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/no-mir-spans.rs Number of expressions: 3 - expression 0 operands: lhs = Counter(2), rhs = Counter(1) - expression 1 operands: lhs = Counter(2), rhs = Expression(2, Add) - expression 2 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 3 -- Code(Counter(0)) at (prev + 45, 1) to (start + 0, 18) +- Code(Counter(0)) at (prev + 45, 1) to (start + 0, 17) - Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 5, 11) to (start + 0, 16) true = c1 false = (c2 - c1) diff --git a/tests/coverage/branch/while.cov-map b/tests/coverage/branch/while.cov-map index 67746af051b6..767a7e46495f 100644 --- a/tests/coverage/branch/while.cov-map +++ b/tests/coverage/branch/while.cov-map @@ -1,12 +1,14 @@ Function name: while::while_cond -Raw bytes (38): 0x[01, 01, 01, 05, 01, 06, 01, 0c, 01, 01, 0e, 01, 03, 09, 00, 12, 05, 01, 0b, 00, 10, 20, 02, 01, 00, 0b, 00, 10, 02, 00, 11, 02, 06, 01, 03, 01, 00, 02] +Raw bytes (48): 0x[01, 01, 01, 05, 01, 08, 01, 0c, 01, 00, 10, 01, 01, 05, 00, 0e, 01, 02, 09, 00, 0e, 01, 00, 11, 00, 12, 05, 01, 0b, 00, 10, 20, 02, 01, 00, 0b, 00, 10, 02, 00, 11, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/while.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(1), rhs = Counter(0) -Number of file 0 mappings: 6 -- Code(Counter(0)) at (prev + 12, 1) to (start + 1, 14) -- Code(Counter(0)) at (prev + 3, 9) to (start + 0, 18) +Number of file 0 mappings: 8 +- Code(Counter(0)) at (prev + 12, 1) to (start + 0, 16) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 2, 9) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 17) to (start + 0, 18) - Code(Counter(1)) at (prev + 1, 11) to (start + 0, 16) - Branch { true: Expression(0, Sub), false: Counter(0) } at (prev + 0, 11) to (start + 0, 16) true = (c1 - c0) @@ -17,14 +19,16 @@ Number of file 0 mappings: 6 Highest counter ID seen: c1 Function name: while::while_cond_not -Raw bytes (38): 0x[01, 01, 01, 05, 01, 06, 01, 15, 01, 01, 0e, 01, 03, 09, 00, 12, 05, 01, 0b, 00, 14, 20, 02, 01, 00, 0b, 00, 14, 02, 00, 15, 02, 06, 01, 03, 01, 00, 02] +Raw bytes (48): 0x[01, 01, 01, 05, 01, 08, 01, 15, 01, 00, 14, 01, 01, 05, 00, 0e, 01, 02, 09, 00, 0e, 01, 00, 11, 00, 12, 05, 01, 0b, 00, 14, 20, 02, 01, 00, 0b, 00, 14, 02, 00, 15, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/while.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(1), rhs = Counter(0) -Number of file 0 mappings: 6 -- Code(Counter(0)) at (prev + 21, 1) to (start + 1, 14) -- Code(Counter(0)) at (prev + 3, 9) to (start + 0, 18) +Number of file 0 mappings: 8 +- Code(Counter(0)) at (prev + 21, 1) to (start + 0, 20) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 2, 9) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 17) to (start + 0, 18) - Code(Counter(1)) at (prev + 1, 11) to (start + 0, 20) - Branch { true: Expression(0, Sub), false: Counter(0) } at (prev + 0, 11) to (start + 0, 20) true = (c1 - c0) @@ -35,19 +39,23 @@ Number of file 0 mappings: 6 Highest counter ID seen: c1 Function name: while::while_op_and -Raw bytes (58): 0x[01, 01, 05, 05, 09, 05, 01, 0f, 05, 01, 09, 05, 01, 08, 01, 1e, 01, 01, 0e, 01, 03, 09, 01, 12, 05, 02, 0b, 00, 10, 20, 09, 02, 00, 0b, 00, 10, 09, 00, 14, 00, 19, 20, 12, 0a, 00, 14, 00, 19, 12, 00, 1a, 03, 06, 01, 04, 01, 00, 02] +Raw bytes (78): 0x[01, 01, 05, 05, 09, 05, 01, 0f, 05, 01, 09, 05, 01, 0c, 01, 1e, 01, 00, 12, 01, 01, 05, 00, 0e, 01, 02, 09, 00, 0e, 01, 00, 11, 00, 12, 01, 01, 09, 00, 0e, 01, 00, 11, 00, 12, 05, 01, 0b, 00, 10, 20, 09, 02, 00, 0b, 00, 10, 09, 00, 14, 00, 19, 20, 12, 0a, 00, 14, 00, 19, 12, 00, 1a, 03, 06, 01, 04, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/while.rs Number of expressions: 5 - expression 0 operands: lhs = Counter(1), rhs = Counter(2) - expression 1 operands: lhs = Counter(1), rhs = Counter(0) - expression 2 operands: lhs = Expression(3, Add), rhs = Counter(1) - expression 3 operands: lhs = Counter(0), rhs = Counter(2) - expression 4 operands: lhs = Counter(1), rhs = Counter(0) -Number of file 0 mappings: 8 -- Code(Counter(0)) at (prev + 30, 1) to (start + 1, 14) -- Code(Counter(0)) at (prev + 3, 9) to (start + 1, 18) -- Code(Counter(1)) at (prev + 2, 11) to (start + 0, 16) +Number of file 0 mappings: 12 +- Code(Counter(0)) at (prev + 30, 1) to (start + 0, 18) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 2, 9) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 17) to (start + 0, 18) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 17) to (start + 0, 18) +- Code(Counter(1)) at (prev + 1, 11) to (start + 0, 16) - Branch { true: Counter(2), false: Expression(0, Sub) } at (prev + 0, 11) to (start + 0, 16) true = c2 false = (c1 - c2) @@ -61,18 +69,22 @@ Number of file 0 mappings: 8 Highest counter ID seen: c2 Function name: while::while_op_or -Raw bytes (56): 0x[01, 01, 04, 05, 09, 05, 0b, 01, 09, 05, 01, 08, 01, 29, 01, 01, 0e, 01, 03, 09, 01, 12, 05, 02, 0b, 00, 10, 20, 09, 02, 00, 0b, 00, 10, 02, 00, 14, 00, 19, 20, 06, 01, 00, 14, 00, 19, 0e, 00, 1a, 03, 06, 01, 04, 01, 00, 02] +Raw bytes (76): 0x[01, 01, 04, 05, 09, 05, 0b, 01, 09, 05, 01, 0c, 01, 29, 01, 00, 11, 01, 01, 05, 00, 0e, 01, 02, 09, 00, 0e, 01, 00, 11, 00, 12, 01, 01, 09, 00, 0e, 01, 00, 11, 00, 12, 05, 01, 0b, 00, 10, 20, 09, 02, 00, 0b, 00, 10, 02, 00, 14, 00, 19, 20, 06, 01, 00, 14, 00, 19, 0e, 00, 1a, 03, 06, 01, 04, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/while.rs Number of expressions: 4 - expression 0 operands: lhs = Counter(1), rhs = Counter(2) - expression 1 operands: lhs = Counter(1), rhs = Expression(2, Add) - expression 2 operands: lhs = Counter(0), rhs = Counter(2) - expression 3 operands: lhs = Counter(1), rhs = Counter(0) -Number of file 0 mappings: 8 -- Code(Counter(0)) at (prev + 41, 1) to (start + 1, 14) -- Code(Counter(0)) at (prev + 3, 9) to (start + 1, 18) -- Code(Counter(1)) at (prev + 2, 11) to (start + 0, 16) +Number of file 0 mappings: 12 +- Code(Counter(0)) at (prev + 41, 1) to (start + 0, 17) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 2, 9) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 17) to (start + 0, 18) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 17) to (start + 0, 18) +- Code(Counter(1)) at (prev + 1, 11) to (start + 0, 16) - Branch { true: Counter(2), false: Expression(0, Sub) } at (prev + 0, 11) to (start + 0, 16) true = c2 false = (c1 - c2) diff --git a/tests/coverage/closure.cov-map b/tests/coverage/closure.cov-map index 2d784ba09b60..5f7e4ce58e97 100644 --- a/tests/coverage/closure.cov-map +++ b/tests/coverage/closure.cov-map @@ -1,18 +1,56 @@ Function name: closure::main -Raw bytes (126): 0x[01, 01, 01, 01, 05, 18, 01, 09, 01, 0d, 1b, 01, 1a, 05, 02, 0a, 01, 0c, 05, 11, 1b, 01, 1e, 05, 02, 0a, 01, 0c, 05, 0c, 16, 01, 16, 05, 0d, 18, 01, 19, 09, 01, 1e, 01, 04, 09, 00, 29, 01, 01, 09, 00, 2d, 01, 01, 09, 00, 24, 01, 05, 09, 00, 24, 01, 02, 09, 00, 21, 01, 04, 09, 00, 21, 01, 04, 09, 00, 28, 01, 09, 09, 00, 32, 01, 04, 09, 00, 33, 01, 07, 09, 00, 4b, 01, 08, 09, 00, 48, 01, 0a, 09, 00, 47, 01, 08, 09, 00, 44, 01, 0a, 08, 00, 10, 05, 00, 11, 04, 06, 02, 04, 05, 00, 06, 01, 01, 05, 03, 02] +Raw bytes (336): 0x[01, 01, 01, 01, 05, 42, 01, 09, 01, 00, 0a, 01, 04, 09, 00, 10, 01, 00, 13, 00, 2e, 01, 01, 09, 00, 11, 01, 00, 14, 00, 1c, 01, 02, 09, 00, 18, 01, 00, 1b, 00, 43, 01, 01, 05, 00, 0d, 01, 01, 09, 00, 20, 01, 02, 09, 00, 14, 01, 02, 0d, 00, 1b, 01, 0d, 05, 00, 10, 01, 00, 13, 00, 3b, 01, 02, 09, 00, 0a, 01, 0a, 05, 00, 0d, 01, 01, 09, 00, 20, 01, 02, 09, 00, 14, 01, 02, 0d, 00, 1b, 01, 02, 0d, 00, 0e, 01, 04, 05, 00, 10, 01, 00, 13, 00, 17, 01, 01, 05, 00, 0d, 01, 01, 09, 00, 20, 01, 02, 09, 00, 14, 01, 02, 0d, 00, 1b, 01, 0d, 05, 00, 10, 01, 00, 13, 00, 17, 01, 02, 09, 00, 0a, 01, 0a, 05, 00, 0d, 01, 01, 09, 00, 20, 01, 02, 09, 00, 14, 01, 02, 0d, 00, 1b, 01, 02, 0d, 00, 0e, 01, 05, 09, 00, 16, 01, 0a, 05, 00, 0d, 01, 01, 09, 00, 28, 01, 02, 09, 00, 1a, 01, 01, 0e, 00, 12, 01, 01, 0e, 00, 11, 01, 02, 0d, 00, 1a, 01, 02, 0e, 00, 15, 01, 04, 09, 00, 18, 01, 0c, 09, 00, 16, 01, 00, 19, 00, 1b, 01, 01, 09, 00, 1e, 01, 03, 09, 00, 29, 01, 01, 09, 00, 2d, 01, 01, 09, 00, 24, 01, 05, 09, 00, 24, 01, 02, 09, 00, 21, 01, 04, 09, 00, 21, 01, 04, 09, 00, 28, 01, 09, 09, 00, 32, 01, 04, 09, 00, 33, 01, 07, 09, 00, 4b, 01, 08, 09, 00, 48, 01, 0a, 09, 00, 47, 01, 08, 09, 00, 44, 01, 0a, 08, 00, 10, 05, 00, 11, 04, 06, 05, 01, 09, 00, 30, 02, 03, 05, 00, 06, 01, 01, 05, 00, 28, 01, 01, 05, 00, 46, 01, 01, 05, 00, 43, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/closure.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 24 -- Code(Counter(0)) at (prev + 9, 1) to (start + 13, 27) -- Code(Counter(0)) at (prev + 26, 5) to (start + 2, 10) -- Code(Counter(0)) at (prev + 12, 5) to (start + 17, 27) -- Code(Counter(0)) at (prev + 30, 5) to (start + 2, 10) -- Code(Counter(0)) at (prev + 12, 5) to (start + 12, 22) -- Code(Counter(0)) at (prev + 22, 5) to (start + 13, 24) -- Code(Counter(0)) at (prev + 25, 9) to (start + 1, 30) -- Code(Counter(0)) at (prev + 4, 9) to (start + 0, 41) +Number of file 0 mappings: 66 +- Code(Counter(0)) at (prev + 9, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 4, 9) to (start + 0, 16) +- Code(Counter(0)) at (prev + 0, 19) to (start + 0, 46) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 17) +- Code(Counter(0)) at (prev + 0, 20) to (start + 0, 28) +- Code(Counter(0)) at (prev + 2, 9) to (start + 0, 24) +- Code(Counter(0)) at (prev + 0, 27) to (start + 0, 67) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 32) +- Code(Counter(0)) at (prev + 2, 9) to (start + 0, 20) +- Code(Counter(0)) at (prev + 2, 13) to (start + 0, 27) +- Code(Counter(0)) at (prev + 13, 5) to (start + 0, 16) +- Code(Counter(0)) at (prev + 0, 19) to (start + 0, 59) +- Code(Counter(0)) at (prev + 2, 9) to (start + 0, 10) +- Code(Counter(0)) at (prev + 10, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 32) +- Code(Counter(0)) at (prev + 2, 9) to (start + 0, 20) +- Code(Counter(0)) at (prev + 2, 13) to (start + 0, 27) +- Code(Counter(0)) at (prev + 2, 13) to (start + 0, 14) +- Code(Counter(0)) at (prev + 4, 5) to (start + 0, 16) +- Code(Counter(0)) at (prev + 0, 19) to (start + 0, 23) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 32) +- Code(Counter(0)) at (prev + 2, 9) to (start + 0, 20) +- Code(Counter(0)) at (prev + 2, 13) to (start + 0, 27) +- Code(Counter(0)) at (prev + 13, 5) to (start + 0, 16) +- Code(Counter(0)) at (prev + 0, 19) to (start + 0, 23) +- Code(Counter(0)) at (prev + 2, 9) to (start + 0, 10) +- Code(Counter(0)) at (prev + 10, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 32) +- Code(Counter(0)) at (prev + 2, 9) to (start + 0, 20) +- Code(Counter(0)) at (prev + 2, 13) to (start + 0, 27) +- Code(Counter(0)) at (prev + 2, 13) to (start + 0, 14) +- Code(Counter(0)) at (prev + 5, 9) to (start + 0, 22) +- Code(Counter(0)) at (prev + 10, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 40) +- Code(Counter(0)) at (prev + 2, 9) to (start + 0, 26) +- Code(Counter(0)) at (prev + 1, 14) to (start + 0, 18) +- Code(Counter(0)) at (prev + 1, 14) to (start + 0, 17) +- Code(Counter(0)) at (prev + 2, 13) to (start + 0, 26) +- Code(Counter(0)) at (prev + 2, 14) to (start + 0, 21) +- Code(Counter(0)) at (prev + 4, 9) to (start + 0, 24) +- Code(Counter(0)) at (prev + 12, 9) to (start + 0, 22) +- Code(Counter(0)) at (prev + 0, 25) to (start + 0, 27) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 30) +- Code(Counter(0)) at (prev + 3, 9) to (start + 0, 41) - Code(Counter(0)) at (prev + 1, 9) to (start + 0, 45) - Code(Counter(0)) at (prev + 1, 9) to (start + 0, 36) - Code(Counter(0)) at (prev + 5, 9) to (start + 0, 36) @@ -27,238 +65,277 @@ Number of file 0 mappings: 24 - Code(Counter(0)) at (prev + 8, 9) to (start + 0, 68) - Code(Counter(0)) at (prev + 10, 8) to (start + 0, 16) - Code(Counter(1)) at (prev + 0, 17) to (start + 4, 6) -- Code(Expression(0, Sub)) at (prev + 4, 5) to (start + 0, 6) +- Code(Counter(1)) at (prev + 1, 9) to (start + 0, 48) +- Code(Expression(0, Sub)) at (prev + 3, 5) to (start + 0, 6) = (c0 - c1) -- Code(Counter(0)) at (prev + 1, 5) to (start + 3, 2) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 40) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 70) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 67) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c1 Function name: closure::main::{closure#0} -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 28, 05, 02, 14, 05, 02, 15, 02, 0a, 02, 02, 09, 00, 0a, 01, 01, 09, 01, 06] +Raw bytes (51): 0x[01, 01, 01, 01, 05, 09, 01, 28, 05, 00, 06, 01, 01, 0d, 00, 1a, 01, 00, 1d, 00, 1e, 01, 01, 0c, 00, 14, 05, 00, 15, 02, 0a, 02, 02, 09, 00, 0a, 01, 01, 09, 00, 17, 01, 00, 18, 00, 20, 01, 01, 05, 00, 06] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/closure.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 40, 5) to (start + 2, 20) -- Code(Counter(1)) at (prev + 2, 21) to (start + 2, 10) +Number of file 0 mappings: 9 +- Code(Counter(0)) at (prev + 40, 5) to (start + 0, 6) +- Code(Counter(0)) at (prev + 1, 13) to (start + 0, 26) +- Code(Counter(0)) at (prev + 0, 29) to (start + 0, 30) +- Code(Counter(0)) at (prev + 1, 12) to (start + 0, 20) +- Code(Counter(1)) at (prev + 0, 21) to (start + 2, 10) - Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 10) = (c0 - c1) -- Code(Counter(0)) at (prev + 1, 9) to (start + 1, 6) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 23) +- Code(Counter(0)) at (prev + 0, 24) to (start + 0, 32) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 6) Highest counter ID seen: c1 Function name: closure::main::{closure#10} (unused) -Raw bytes (10): 0x[01, 01, 00, 01, 00, 9b, 01, 07, 00, 21] +Raw bytes (25): 0x[01, 01, 00, 04, 00, 9b, 01, 07, 00, 08, 00, 00, 09, 00, 11, 00, 00, 12, 00, 1e, 00, 00, 20, 00, 21] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/closure.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 155, 7) to (start + 0, 33) +Number of file 0 mappings: 4 +- Code(Zero) at (prev + 155, 7) to (start + 0, 8) +- Code(Zero) at (prev + 0, 9) to (start + 0, 17) +- Code(Zero) at (prev + 0, 18) to (start + 0, 30) +- Code(Zero) at (prev + 0, 32) to (start + 0, 33) Highest counter ID seen: (none) Function name: closure::main::{closure#11} (unused) -Raw bytes (10): 0x[01, 01, 00, 01, 00, 9f, 01, 07, 00, 21] +Raw bytes (25): 0x[01, 01, 00, 04, 00, 9f, 01, 07, 00, 08, 00, 00, 09, 00, 11, 00, 00, 12, 00, 1e, 00, 00, 20, 00, 21] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/closure.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 159, 7) to (start + 0, 33) +Number of file 0 mappings: 4 +- Code(Zero) at (prev + 159, 7) to (start + 0, 8) +- Code(Zero) at (prev + 0, 9) to (start + 0, 17) +- Code(Zero) at (prev + 0, 18) to (start + 0, 30) +- Code(Zero) at (prev + 0, 32) to (start + 0, 33) Highest counter ID seen: (none) Function name: closure::main::{closure#12} (unused) -Raw bytes (10): 0x[01, 01, 00, 01, 00, a7, 01, 01, 00, 17] +Raw bytes (10): 0x[01, 01, 00, 01, 00, a7, 01, 0a, 00, 16] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/closure.rs Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Zero) at (prev + 167, 1) to (start + 0, 23) +- Code(Zero) at (prev + 167, 10) to (start + 0, 22) Highest counter ID seen: (none) Function name: closure::main::{closure#13} (unused) -Raw bytes (10): 0x[01, 01, 00, 01, 00, ac, 01, 0d, 02, 0e] +Raw bytes (10): 0x[01, 01, 00, 01, 00, ad, 01, 11, 00, 1d] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/closure.rs Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Zero) at (prev + 172, 13) to (start + 2, 14) +- Code(Zero) at (prev + 173, 17) to (start + 0, 29) Highest counter ID seen: (none) Function name: closure::main::{closure#14} -Raw bytes (22): 0x[01, 01, 01, 01, 05, 03, 01, b3, 01, 0d, 02, 1b, 05, 02, 1e, 00, 25, 02, 00, 2f, 00, 33] +Raw bytes (27): 0x[01, 01, 01, 01, 05, 04, 01, b4, 01, 11, 00, 21, 01, 01, 14, 00, 1b, 05, 00, 1e, 00, 25, 02, 00, 2f, 00, 33] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/closure.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 3 -- Code(Counter(0)) at (prev + 179, 13) to (start + 2, 27) -- Code(Counter(1)) at (prev + 2, 30) to (start + 0, 37) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 180, 17) to (start + 0, 33) +- Code(Counter(0)) at (prev + 1, 20) to (start + 0, 27) +- Code(Counter(1)) at (prev + 0, 30) to (start + 0, 37) - Code(Expression(0, Sub)) at (prev + 0, 47) to (start + 0, 51) = (c0 - c1) Highest counter ID seen: c1 Function name: closure::main::{closure#15} -Raw bytes (37): 0x[01, 01, 01, 01, 05, 06, 01, bb, 01, 09, 00, 0a, 01, 01, 0d, 00, 15, 01, 01, 11, 01, 1b, 05, 01, 1e, 00, 25, 02, 00, 2f, 00, 33, 01, 02, 09, 00, 0a] +Raw bytes (42): 0x[01, 01, 01, 01, 05, 07, 01, bb, 01, 09, 00, 0a, 01, 01, 0d, 00, 15, 01, 01, 11, 00, 21, 01, 01, 14, 00, 1b, 05, 00, 1e, 00, 25, 02, 00, 2f, 00, 33, 01, 02, 09, 00, 0a] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/closure.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 6 +Number of file 0 mappings: 7 - Code(Counter(0)) at (prev + 187, 9) to (start + 0, 10) - Code(Counter(0)) at (prev + 1, 13) to (start + 0, 21) -- Code(Counter(0)) at (prev + 1, 17) to (start + 1, 27) -- Code(Counter(1)) at (prev + 1, 30) to (start + 0, 37) +- Code(Counter(0)) at (prev + 1, 17) to (start + 0, 33) +- Code(Counter(0)) at (prev + 1, 20) to (start + 0, 27) +- Code(Counter(1)) at (prev + 0, 30) to (start + 0, 37) - Code(Expression(0, Sub)) at (prev + 0, 47) to (start + 0, 51) = (c0 - c1) - Code(Counter(0)) at (prev + 2, 9) to (start + 0, 10) Highest counter ID seen: c1 Function name: closure::main::{closure#16} -Raw bytes (22): 0x[01, 01, 01, 01, 05, 03, 01, c5, 01, 0d, 02, 1b, 05, 02, 1e, 00, 25, 02, 00, 2f, 00, 33] +Raw bytes (27): 0x[01, 01, 01, 01, 05, 04, 01, c6, 01, 11, 00, 21, 01, 01, 14, 00, 1b, 05, 00, 1e, 00, 25, 02, 00, 2f, 00, 33] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/closure.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 3 -- Code(Counter(0)) at (prev + 197, 13) to (start + 2, 27) -- Code(Counter(1)) at (prev + 2, 30) to (start + 0, 37) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 198, 17) to (start + 0, 33) +- Code(Counter(0)) at (prev + 1, 20) to (start + 0, 27) +- Code(Counter(1)) at (prev + 0, 30) to (start + 0, 37) - Code(Expression(0, Sub)) at (prev + 0, 47) to (start + 0, 51) = (c0 - c1) Highest counter ID seen: c1 Function name: closure::main::{closure#17} -Raw bytes (37): 0x[01, 01, 01, 01, 05, 06, 01, cd, 01, 09, 00, 0a, 01, 01, 0d, 00, 15, 01, 01, 11, 01, 1b, 05, 01, 1e, 00, 25, 02, 00, 2f, 00, 33, 01, 02, 09, 00, 0a] +Raw bytes (42): 0x[01, 01, 01, 01, 05, 07, 01, cd, 01, 09, 00, 0a, 01, 01, 0d, 00, 15, 01, 01, 11, 00, 21, 01, 01, 14, 00, 1b, 05, 00, 1e, 00, 25, 02, 00, 2f, 00, 33, 01, 02, 09, 00, 0a] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/closure.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 6 +Number of file 0 mappings: 7 - Code(Counter(0)) at (prev + 205, 9) to (start + 0, 10) - Code(Counter(0)) at (prev + 1, 13) to (start + 0, 21) -- Code(Counter(0)) at (prev + 1, 17) to (start + 1, 27) -- Code(Counter(1)) at (prev + 1, 30) to (start + 0, 37) +- Code(Counter(0)) at (prev + 1, 17) to (start + 0, 33) +- Code(Counter(0)) at (prev + 1, 20) to (start + 0, 27) +- Code(Counter(1)) at (prev + 0, 30) to (start + 0, 37) - Code(Expression(0, Sub)) at (prev + 0, 47) to (start + 0, 51) = (c0 - c1) - Code(Counter(0)) at (prev + 2, 9) to (start + 0, 10) Highest counter ID seen: c1 Function name: closure::main::{closure#18} -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 19, 0d, 02, 1c, 05, 02, 1d, 02, 12, 02, 02, 11, 00, 12, 01, 01, 11, 01, 0e] +Raw bytes (51): 0x[01, 01, 01, 01, 05, 09, 01, 19, 0d, 00, 0e, 01, 01, 15, 00, 22, 01, 00, 25, 00, 26, 01, 01, 14, 00, 1c, 05, 00, 1d, 02, 12, 02, 02, 11, 00, 12, 01, 01, 11, 00, 1f, 01, 00, 20, 00, 28, 01, 01, 0d, 00, 0e] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/closure.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 25, 13) to (start + 2, 28) -- Code(Counter(1)) at (prev + 2, 29) to (start + 2, 18) +Number of file 0 mappings: 9 +- Code(Counter(0)) at (prev + 25, 13) to (start + 0, 14) +- Code(Counter(0)) at (prev + 1, 21) to (start + 0, 34) +- Code(Counter(0)) at (prev + 0, 37) to (start + 0, 38) +- Code(Counter(0)) at (prev + 1, 20) to (start + 0, 28) +- Code(Counter(1)) at (prev + 0, 29) to (start + 2, 18) - Code(Expression(0, Sub)) at (prev + 2, 17) to (start + 0, 18) = (c0 - c1) -- Code(Counter(0)) at (prev + 1, 17) to (start + 1, 14) +- Code(Counter(0)) at (prev + 1, 17) to (start + 0, 31) +- Code(Counter(0)) at (prev + 0, 32) to (start + 0, 40) +- Code(Counter(0)) at (prev + 1, 13) to (start + 0, 14) Highest counter ID seen: c1 Function name: closure::main::{closure#19} -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 43, 0d, 02, 1c, 05, 02, 1d, 02, 12, 02, 02, 11, 00, 12, 01, 01, 11, 01, 0e] +Raw bytes (51): 0x[01, 01, 01, 01, 05, 09, 01, 43, 0d, 00, 0e, 01, 01, 15, 00, 22, 01, 00, 25, 00, 26, 01, 01, 14, 00, 1c, 05, 00, 1d, 02, 12, 02, 02, 11, 00, 12, 01, 01, 11, 00, 1f, 01, 00, 20, 00, 28, 01, 01, 0d, 00, 0e] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/closure.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 67, 13) to (start + 2, 28) -- Code(Counter(1)) at (prev + 2, 29) to (start + 2, 18) +Number of file 0 mappings: 9 +- Code(Counter(0)) at (prev + 67, 13) to (start + 0, 14) +- Code(Counter(0)) at (prev + 1, 21) to (start + 0, 34) +- Code(Counter(0)) at (prev + 0, 37) to (start + 0, 38) +- Code(Counter(0)) at (prev + 1, 20) to (start + 0, 28) +- Code(Counter(1)) at (prev + 0, 29) to (start + 2, 18) - Code(Expression(0, Sub)) at (prev + 2, 17) to (start + 0, 18) = (c0 - c1) -- Code(Counter(0)) at (prev + 1, 17) to (start + 1, 14) +- Code(Counter(0)) at (prev + 1, 17) to (start + 0, 31) +- Code(Counter(0)) at (prev + 0, 32) to (start + 0, 40) +- Code(Counter(0)) at (prev + 1, 13) to (start + 0, 14) Highest counter ID seen: c1 Function name: closure::main::{closure#1} -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 52, 05, 02, 14, 05, 02, 15, 02, 0a, 02, 02, 09, 00, 0a, 01, 01, 09, 01, 06] +Raw bytes (51): 0x[01, 01, 01, 01, 05, 09, 01, 52, 05, 00, 06, 01, 01, 0d, 00, 1a, 01, 00, 1d, 00, 1e, 01, 01, 0c, 00, 14, 05, 00, 15, 02, 0a, 02, 02, 09, 00, 0a, 01, 01, 09, 00, 17, 01, 00, 18, 00, 20, 01, 01, 05, 00, 06] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/closure.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 82, 5) to (start + 2, 20) -- Code(Counter(1)) at (prev + 2, 21) to (start + 2, 10) +Number of file 0 mappings: 9 +- Code(Counter(0)) at (prev + 82, 5) to (start + 0, 6) +- Code(Counter(0)) at (prev + 1, 13) to (start + 0, 26) +- Code(Counter(0)) at (prev + 0, 29) to (start + 0, 30) +- Code(Counter(0)) at (prev + 1, 12) to (start + 0, 20) +- Code(Counter(1)) at (prev + 0, 21) to (start + 2, 10) - Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 10) = (c0 - c1) -- Code(Counter(0)) at (prev + 1, 9) to (start + 1, 6) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 23) +- Code(Counter(0)) at (prev + 0, 24) to (start + 0, 32) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 6) Highest counter ID seen: c1 Function name: closure::main::{closure#2} -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 68, 05, 02, 14, 05, 02, 15, 02, 0a, 02, 02, 09, 00, 0a, 01, 01, 09, 01, 06] +Raw bytes (51): 0x[01, 01, 01, 01, 05, 09, 01, 68, 05, 00, 06, 01, 01, 0d, 00, 1a, 01, 00, 1d, 00, 1e, 01, 01, 0c, 00, 14, 05, 00, 15, 02, 0a, 02, 02, 09, 00, 0a, 01, 01, 09, 00, 10, 01, 00, 11, 00, 17, 01, 01, 05, 00, 06] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/closure.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 104, 5) to (start + 2, 20) -- Code(Counter(1)) at (prev + 2, 21) to (start + 2, 10) +Number of file 0 mappings: 9 +- Code(Counter(0)) at (prev + 104, 5) to (start + 0, 6) +- Code(Counter(0)) at (prev + 1, 13) to (start + 0, 26) +- Code(Counter(0)) at (prev + 0, 29) to (start + 0, 30) +- Code(Counter(0)) at (prev + 1, 12) to (start + 0, 20) +- Code(Counter(1)) at (prev + 0, 21) to (start + 2, 10) - Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 10) = (c0 - c1) -- Code(Counter(0)) at (prev + 1, 9) to (start + 1, 6) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 16) +- Code(Counter(0)) at (prev + 0, 17) to (start + 0, 23) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 6) Highest counter ID seen: c1 Function name: closure::main::{closure#3} (unused) -Raw bytes (25): 0x[01, 01, 00, 04, 00, 81, 01, 05, 01, 14, 00, 01, 15, 02, 0a, 00, 02, 09, 00, 0a, 00, 01, 09, 01, 06] +Raw bytes (40): 0x[01, 01, 00, 07, 00, 81, 01, 05, 00, 06, 00, 01, 0c, 00, 14, 00, 00, 15, 02, 0a, 00, 02, 09, 00, 0a, 00, 01, 09, 00, 23, 00, 00, 24, 00, 2c, 00, 01, 05, 00, 06] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/closure.rs Number of expressions: 0 -Number of file 0 mappings: 4 -- Code(Zero) at (prev + 129, 5) to (start + 1, 20) -- Code(Zero) at (prev + 1, 21) to (start + 2, 10) +Number of file 0 mappings: 7 +- Code(Zero) at (prev + 129, 5) to (start + 0, 6) +- Code(Zero) at (prev + 1, 12) to (start + 0, 20) +- Code(Zero) at (prev + 0, 21) to (start + 2, 10) - Code(Zero) at (prev + 2, 9) to (start + 0, 10) -- Code(Zero) at (prev + 1, 9) to (start + 1, 6) -Highest counter ID seen: (none) - -Function name: closure::main::{closure#4} (unused) -Raw bytes (10): 0x[01, 01, 00, 01, 00, 89, 01, 35, 00, 43] -Number of files: 1 -- file 0 => global file 1 -Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 137, 53) to (start + 0, 67) +- Code(Zero) at (prev + 1, 9) to (start + 0, 35) +- Code(Zero) at (prev + 0, 36) to (start + 0, 44) +- Code(Zero) at (prev + 1, 5) to (start + 0, 6) Highest counter ID seen: (none) Function name: closure::main::{closure#5} -Raw bytes (10): 0x[01, 01, 00, 01, 01, 8c, 01, 3d, 00, 4f] +Raw bytes (10): 0x[01, 01, 00, 01, 01, 8c, 01, 46, 00, 4e] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/closure.rs Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 140, 61) to (start + 0, 79) +- Code(Counter(0)) at (prev + 140, 70) to (start + 0, 78) Highest counter ID seen: c0 Function name: closure::main::{closure#6} -Raw bytes (10): 0x[01, 01, 00, 01, 01, 8d, 01, 41, 00, 57] +Raw bytes (10): 0x[01, 01, 00, 01, 01, 8d, 01, 4a, 00, 56] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/closure.rs Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 141, 65) to (start + 0, 87) +- Code(Counter(0)) at (prev + 141, 74) to (start + 0, 86) Highest counter ID seen: c0 Function name: closure::main::{closure#7} (unused) -Raw bytes (10): 0x[01, 01, 00, 01, 00, 8e, 01, 3b, 00, 51] +Raw bytes (10): 0x[01, 01, 00, 01, 00, 8e, 01, 44, 00, 50] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/closure.rs Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Zero) at (prev + 142, 59) to (start + 0, 81) +- Code(Zero) at (prev + 142, 68) to (start + 0, 80) Highest counter ID seen: (none) Function name: closure::main::{closure#8} (unused) -Raw bytes (10): 0x[01, 01, 00, 01, 00, 93, 01, 3b, 00, 55] +Raw bytes (25): 0x[01, 01, 00, 04, 00, 93, 01, 3b, 00, 3c, 00, 00, 3d, 00, 45, 00, 00, 46, 00, 52, 00, 00, 54, 00, 55] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/closure.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 147, 59) to (start + 0, 85) +Number of file 0 mappings: 4 +- Code(Zero) at (prev + 147, 59) to (start + 0, 60) +- Code(Zero) at (prev + 0, 61) to (start + 0, 69) +- Code(Zero) at (prev + 0, 70) to (start + 0, 82) +- Code(Zero) at (prev + 0, 84) to (start + 0, 85) Highest counter ID seen: (none) Function name: closure::main::{closure#9} (unused) -Raw bytes (10): 0x[01, 01, 00, 01, 00, 95, 01, 38, 02, 06] +Raw bytes (25): 0x[01, 01, 00, 04, 00, 95, 01, 38, 00, 39, 00, 01, 09, 00, 11, 00, 00, 12, 00, 1e, 00, 01, 05, 00, 06] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/closure.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 149, 56) to (start + 2, 6) +Number of file 0 mappings: 4 +- Code(Zero) at (prev + 149, 56) to (start + 0, 57) +- Code(Zero) at (prev + 1, 9) to (start + 0, 17) +- Code(Zero) at (prev + 0, 18) to (start + 0, 30) +- Code(Zero) at (prev + 1, 5) to (start + 0, 6) Highest counter ID seen: (none) diff --git a/tests/coverage/closure.coverage b/tests/coverage/closure.coverage index 2deeb9806c4d..142852692289 100644 --- a/tests/coverage/closure.coverage +++ b/tests/coverage/closure.coverage @@ -7,18 +7,18 @@ LL| | LL| |#[rustfmt::skip] LL| 1|fn main() { - LL| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure - LL| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - LL| 1| // dependent conditions. + LL| | // Initialize test constants in a way that cannot be determined at compile time, to ensure + LL| | // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + LL| | // dependent conditions. LL| 1| let is_true = std::env::args().len() == 1; LL| 1| let is_false = !is_true; - LL| 1| + LL| | LL| 1| let mut some_string = Some(String::from("the string content")); LL| 1| println!( LL| 1| "The string or alt: {}" - LL| 1| , + LL| | , LL| 1| some_string - LL| 1| . + LL| | . LL| 1| unwrap_or_else LL| | ( LL| | || @@ -33,7 +33,7 @@ LL| | ); LL| | LL| 1| some_string = Some(String::from("the string content")); - LL| 1| let + LL| | let LL| 1| a LL| | = LL| | || @@ -46,21 +46,21 @@ LL| 0| }; LL| 1| println!( LL| 1| "The string or alt: {}" - LL| 1| , + LL| | , LL| 1| some_string - LL| 1| . + LL| | . LL| 1| unwrap_or_else - LL| 1| ( + LL| | ( LL| 1| a - LL| 1| ) - LL| 1| ); - LL| 1| + LL| | ) + LL| | ); + LL| | LL| 1| some_string = None; LL| 1| println!( LL| 1| "The string or alt: {}" - LL| 1| , + LL| | , LL| 1| some_string - LL| 1| . + LL| | . LL| 1| unwrap_or_else LL| | ( LL| | || @@ -75,7 +75,7 @@ LL| | ); LL| | LL| 1| some_string = None; - LL| 1| let + LL| | let LL| 1| a LL| | = LL| | || @@ -88,16 +88,16 @@ LL| 1| }; LL| 1| println!( LL| 1| "The string or alt: {}" - LL| 1| , + LL| | , LL| 1| some_string - LL| 1| . + LL| | . LL| 1| unwrap_or_else - LL| 1| ( + LL| | ( LL| 1| a - LL| 1| ) - LL| 1| ); - LL| 1| - LL| 1| let + LL| | ) + LL| | ); + LL| | + LL| | let LL| 1| quote_closure LL| | = LL| | |val| @@ -110,17 +110,17 @@ LL| 5| }; LL| 1| println!( LL| 1| "Repeated, quoted string: {:?}" - LL| 1| , + LL| | , LL| 1| std::iter::repeat("repeat me") LL| 1| .take(5) LL| 1| .map - LL| 1| ( + LL| | ( LL| 1| quote_closure - LL| 1| ) + LL| | ) LL| 1| .collect::>() - LL| 1| ); - LL| 1| - LL| 1| let + LL| | ); + LL| | + LL| | let LL| 1| _unused_closure LL| | = LL| | | @@ -135,22 +135,22 @@ LL| | LL| 1| let mut countdown = 10; LL| 1| let _short_unused_closure = | _unused_arg: u8 | countdown += 1; - ^0 LL| | LL| | LL| 1| let short_used_covered_closure_macro = | used_arg: u8 | println!("called"); LL| 1| let short_used_not_covered_closure_macro = | used_arg: u8 | println!("not called"); - ^0 + ^0 LL| 1| let _short_unused_closure_macro = | _unused_arg: u8 | println!("not called"); - ^0 + ^0 LL| | LL| | LL| | LL| | LL| 1| let _short_unused_closure_block = | _unused_arg: u8 | { println!("not called") }; - ^0 + ^0^0 ^0 ^0 LL| | LL| 1| let _shortish_unused_closure = | _unused_arg: u8 | { + ^0 LL| 0| println!("not called") LL| 0| }; LL| | @@ -173,14 +173,14 @@ LL| | LL| 1| let _short_unused_closure_line_break_no_block2 = LL| | | _unused_arg: u8 | - LL| 0| println!( + LL| | println!( LL| 0| "not called" - LL| 0| ) + LL| | ) LL| | ; LL| | LL| 1| let short_used_not_covered_closure_line_break_no_block_embedded_branch = LL| | | _unused_arg: u8 | - LL| 0| println!( + LL| | println!( LL| 0| "not called: {}", LL| 0| if is_true { "check" } else { "me" } LL| | ) @@ -198,7 +198,7 @@ LL| | LL| 1| let short_used_covered_closure_line_break_no_block_embedded_branch = LL| | | _unused_arg: u8 | - LL| 1| println!( + LL| | println!( LL| 1| "not called: {}", LL| 1| if is_true { "check" } else { "me" } ^0 diff --git a/tests/coverage/closure_bug.cov-map b/tests/coverage/closure_bug.cov-map index 40a8bdf9c1d6..a7087c69dcba 100644 --- a/tests/coverage/closure_bug.cov-map +++ b/tests/coverage/closure_bug.cov-map @@ -1,44 +1,51 @@ Function name: closure_bug::main -Raw bytes (97): 0x[01, 01, 04, 01, 05, 01, 09, 01, 0d, 01, 11, 11, 01, 07, 01, 03, 0a, 01, 09, 05, 01, 0e, 05, 01, 0f, 00, 17, 02, 00, 16, 00, 17, 01, 02, 09, 00, 0a, 01, 06, 05, 01, 0e, 09, 01, 0f, 00, 17, 06, 00, 16, 00, 17, 01, 02, 09, 00, 0a, 01, 06, 05, 01, 0e, 0d, 01, 0f, 00, 17, 0a, 00, 16, 00, 17, 01, 02, 09, 00, 0a, 01, 06, 05, 01, 0e, 11, 01, 0f, 00, 17, 0e, 00, 16, 00, 17, 01, 01, 01, 00, 02] +Raw bytes (132): 0x[01, 01, 04, 01, 05, 01, 09, 01, 0d, 01, 11, 18, 01, 07, 01, 00, 0a, 01, 01, 09, 00, 0f, 01, 00, 12, 00, 2d, 01, 02, 09, 00, 0a, 01, 06, 05, 00, 08, 01, 01, 08, 00, 0e, 05, 00, 0f, 00, 17, 02, 00, 16, 00, 17, 01, 02, 09, 00, 0a, 01, 06, 05, 00, 08, 01, 01, 08, 00, 0e, 09, 00, 0f, 00, 17, 06, 00, 16, 00, 17, 01, 02, 09, 00, 0a, 01, 06, 05, 00, 08, 01, 01, 08, 00, 0e, 0d, 00, 0f, 00, 17, 0a, 00, 16, 00, 17, 01, 02, 09, 00, 0a, 01, 06, 05, 00, 08, 01, 01, 08, 00, 0e, 11, 00, 0f, 00, 17, 0e, 00, 16, 00, 17, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/closure_bug.rs Number of expressions: 4 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(0), rhs = Counter(2) - expression 2 operands: lhs = Counter(0), rhs = Counter(3) - expression 3 operands: lhs = Counter(0), rhs = Counter(4) -Number of file 0 mappings: 17 -- Code(Counter(0)) at (prev + 7, 1) to (start + 3, 10) -- Code(Counter(0)) at (prev + 9, 5) to (start + 1, 14) -- Code(Counter(1)) at (prev + 1, 15) to (start + 0, 23) +Number of file 0 mappings: 24 +- Code(Counter(0)) at (prev + 7, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 15) +- Code(Counter(0)) at (prev + 0, 18) to (start + 0, 45) +- Code(Counter(0)) at (prev + 2, 9) to (start + 0, 10) +- Code(Counter(0)) at (prev + 6, 5) to (start + 0, 8) +- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 14) +- Code(Counter(1)) at (prev + 0, 15) to (start + 0, 23) - Code(Expression(0, Sub)) at (prev + 0, 22) to (start + 0, 23) = (c0 - c1) - Code(Counter(0)) at (prev + 2, 9) to (start + 0, 10) -- Code(Counter(0)) at (prev + 6, 5) to (start + 1, 14) -- Code(Counter(2)) at (prev + 1, 15) to (start + 0, 23) +- Code(Counter(0)) at (prev + 6, 5) to (start + 0, 8) +- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 14) +- Code(Counter(2)) at (prev + 0, 15) to (start + 0, 23) - Code(Expression(1, Sub)) at (prev + 0, 22) to (start + 0, 23) = (c0 - c2) - Code(Counter(0)) at (prev + 2, 9) to (start + 0, 10) -- Code(Counter(0)) at (prev + 6, 5) to (start + 1, 14) -- Code(Counter(3)) at (prev + 1, 15) to (start + 0, 23) +- Code(Counter(0)) at (prev + 6, 5) to (start + 0, 8) +- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 14) +- Code(Counter(3)) at (prev + 0, 15) to (start + 0, 23) - Code(Expression(2, Sub)) at (prev + 0, 22) to (start + 0, 23) = (c0 - c3) - Code(Counter(0)) at (prev + 2, 9) to (start + 0, 10) -- Code(Counter(0)) at (prev + 6, 5) to (start + 1, 14) -- Code(Counter(4)) at (prev + 1, 15) to (start + 0, 23) +- Code(Counter(0)) at (prev + 6, 5) to (start + 0, 8) +- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 14) +- Code(Counter(4)) at (prev + 0, 15) to (start + 0, 23) - Code(Expression(3, Sub)) at (prev + 0, 22) to (start + 0, 23) = (c0 - c4) - Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c4 Function name: closure_bug::main::{closure#0} -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 0e, 09, 00, 12, 05, 00, 15, 00, 19, 02, 00, 23, 00, 28, 01, 00, 29, 00, 2a] +Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 0e, 0c, 00, 12, 05, 00, 15, 00, 19, 02, 00, 23, 00, 28, 01, 00, 29, 00, 2a] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/closure_bug.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 14, 9) to (start + 0, 18) +- Code(Counter(0)) at (prev + 14, 12) to (start + 0, 18) - Code(Counter(1)) at (prev + 0, 21) to (start + 0, 25) - Code(Expression(0, Sub)) at (prev + 0, 35) to (start + 0, 40) = (c0 - c1) @@ -46,13 +53,13 @@ Number of file 0 mappings: 4 Highest counter ID seen: c1 Function name: closure_bug::main::{closure#1} -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 17, 09, 00, 12, 05, 00, 15, 00, 19, 02, 00, 23, 00, 28, 01, 00, 29, 00, 2a] +Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 17, 0c, 00, 12, 05, 00, 15, 00, 19, 02, 00, 23, 00, 28, 01, 00, 29, 00, 2a] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/closure_bug.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 23, 9) to (start + 0, 18) +- Code(Counter(0)) at (prev + 23, 12) to (start + 0, 18) - Code(Counter(1)) at (prev + 0, 21) to (start + 0, 25) - Code(Expression(0, Sub)) at (prev + 0, 35) to (start + 0, 40) = (c0 - c1) @@ -60,13 +67,13 @@ Number of file 0 mappings: 4 Highest counter ID seen: c1 Function name: closure_bug::main::{closure#2} -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 20, 09, 00, 12, 05, 00, 15, 00, 19, 02, 00, 23, 00, 28, 01, 00, 29, 00, 2a] +Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 20, 0c, 00, 12, 05, 00, 15, 00, 19, 02, 00, 23, 00, 28, 01, 00, 29, 00, 2a] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/closure_bug.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 32, 9) to (start + 0, 18) +- Code(Counter(0)) at (prev + 32, 12) to (start + 0, 18) - Code(Counter(1)) at (prev + 0, 21) to (start + 0, 25) - Code(Expression(0, Sub)) at (prev + 0, 35) to (start + 0, 40) = (c0 - c1) @@ -74,13 +81,13 @@ Number of file 0 mappings: 4 Highest counter ID seen: c1 Function name: closure_bug::main::{closure#3} -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 29, 09, 00, 12, 05, 00, 15, 00, 19, 02, 00, 23, 00, 28, 01, 00, 29, 00, 2a] +Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 29, 0c, 00, 12, 05, 00, 15, 00, 19, 02, 00, 23, 00, 28, 01, 00, 29, 00, 2a] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/closure_bug.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 41, 9) to (start + 0, 18) +- Code(Counter(0)) at (prev + 41, 12) to (start + 0, 18) - Code(Counter(1)) at (prev + 0, 21) to (start + 0, 25) - Code(Expression(0, Sub)) at (prev + 0, 35) to (start + 0, 40) = (c0 - c1) diff --git a/tests/coverage/closure_bug.coverage b/tests/coverage/closure_bug.coverage index cc64470baa77..b85375d1850b 100644 --- a/tests/coverage/closure_bug.coverage +++ b/tests/coverage/closure_bug.coverage @@ -6,7 +6,7 @@ LL| |#[rustfmt::skip] LL| 1|fn main() { LL| 1| let truthy = std::env::args().len() == 1; - LL| 1| + LL| | LL| 1| let a LL| | = LL| | | diff --git a/tests/coverage/closure_macro.cov-map b/tests/coverage/closure_macro.cov-map index 9dd99c8fab3f..3ab1d7f5fba8 100644 --- a/tests/coverage/closure_macro.cov-map +++ b/tests/coverage/closure_macro.cov-map @@ -1,41 +1,57 @@ Function name: closure_macro::load_configuration_files -Raw bytes (9): 0x[01, 01, 00, 01, 01, 1d, 01, 02, 02] +Raw bytes (19): 0x[01, 01, 00, 03, 01, 1d, 01, 00, 38, 01, 01, 05, 00, 1f, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/closure_macro.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 29, 1) to (start + 2, 2) +Number of file 0 mappings: 3 +- Code(Counter(0)) at (prev + 29, 1) to (start + 0, 56) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 31) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: closure_macro::main -Raw bytes (36): 0x[01, 01, 01, 01, 05, 06, 01, 21, 01, 01, 20, 02, 02, 09, 00, 0f, 01, 00, 12, 00, 34, 05, 00, 54, 00, 55, 02, 02, 09, 02, 0b, 01, 03, 01, 00, 02] +Raw bytes (66): 0x[01, 01, 01, 01, 05, 0c, 01, 21, 01, 00, 24, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 20, 02, 01, 09, 00, 0f, 01, 00, 12, 00, 1b, 01, 00, 1c, 00, 34, 05, 00, 54, 00, 55, 02, 02, 09, 00, 1f, 02, 00, 22, 00, 2e, 02, 01, 0d, 00, 2d, 02, 01, 05, 00, 0b, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/closure_macro.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 6 -- Code(Counter(0)) at (prev + 33, 1) to (start + 1, 32) -- Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 15) +Number of file 0 mappings: 12 +- Code(Counter(0)) at (prev + 33, 1) to (start + 0, 36) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 32) +- Code(Expression(0, Sub)) at (prev + 1, 9) to (start + 0, 15) = (c0 - c1) -- Code(Counter(0)) at (prev + 0, 18) to (start + 0, 52) +- Code(Counter(0)) at (prev + 0, 18) to (start + 0, 27) +- Code(Counter(0)) at (prev + 0, 28) to (start + 0, 52) - Code(Counter(1)) at (prev + 0, 84) to (start + 0, 85) -- Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 2, 11) +- Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 31) = (c0 - c1) -- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2) +- Code(Expression(0, Sub)) at (prev + 0, 34) to (start + 0, 46) + = (c0 - c1) +- Code(Expression(0, Sub)) at (prev + 1, 13) to (start + 0, 45) + = (c0 - c1) +- Code(Expression(0, Sub)) at (prev + 1, 5) to (start + 0, 11) + = (c0 - c1) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c1 Function name: closure_macro::main::{closure#0} -Raw bytes (35): 0x[01, 01, 03, 01, 05, 01, 0b, 05, 09, 05, 01, 10, 1c, 03, 21, 05, 04, 11, 01, 27, 02, 03, 11, 00, 16, 06, 00, 17, 00, 1e, 01, 02, 09, 00, 0a] +Raw bytes (60): 0x[01, 01, 03, 01, 05, 01, 0b, 05, 09, 0a, 01, 10, 1c, 00, 1d, 01, 02, 11, 00, 18, 01, 00, 1b, 00, 22, 01, 01, 10, 00, 21, 05, 01, 11, 00, 19, 05, 00, 1a, 00, 1e, 05, 01, 11, 00, 27, 02, 02, 11, 00, 16, 06, 00, 17, 00, 1e, 01, 02, 09, 00, 0a] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/closure_macro.rs Number of expressions: 3 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(0), rhs = Expression(2, Add) - expression 2 operands: lhs = Counter(1), rhs = Counter(2) -Number of file 0 mappings: 5 -- Code(Counter(0)) at (prev + 16, 28) to (start + 3, 33) -- Code(Counter(1)) at (prev + 4, 17) to (start + 1, 39) -- Code(Expression(0, Sub)) at (prev + 3, 17) to (start + 0, 22) +Number of file 0 mappings: 10 +- Code(Counter(0)) at (prev + 16, 28) to (start + 0, 29) +- Code(Counter(0)) at (prev + 2, 17) to (start + 0, 24) +- Code(Counter(0)) at (prev + 0, 27) to (start + 0, 34) +- Code(Counter(0)) at (prev + 1, 16) to (start + 0, 33) +- Code(Counter(1)) at (prev + 1, 17) to (start + 0, 25) +- Code(Counter(1)) at (prev + 0, 26) to (start + 0, 30) +- Code(Counter(1)) at (prev + 1, 17) to (start + 0, 39) +- Code(Expression(0, Sub)) at (prev + 2, 17) to (start + 0, 22) = (c0 - c1) - Code(Expression(1, Sub)) at (prev + 0, 23) to (start + 0, 30) = (c0 - (c1 + c2)) diff --git a/tests/coverage/closure_macro.coverage b/tests/coverage/closure_macro.coverage index 00022bbff89f..b1d7a8327a4e 100644 --- a/tests/coverage/closure_macro.coverage +++ b/tests/coverage/closure_macro.coverage @@ -14,7 +14,7 @@ LL| |macro_rules! on_error { LL| | ($value:expr, $error_message:expr) => { LL| 0| $value.or_else(|e| { - LL| 0| // This closure, which is declared in a macro, should be instrumented. + LL| | // This closure, which is declared in a macro, should be instrumented. LL| 0| let message = format!($error_message, e); LL| 0| if message.len() > 0 { LL| 0| println!("{}", message); diff --git a/tests/coverage/closure_macro_async.cov-map b/tests/coverage/closure_macro_async.cov-map index 2548754d754c..b5f4cee0ec44 100644 --- a/tests/coverage/closure_macro_async.cov-map +++ b/tests/coverage/closure_macro_async.cov-map @@ -1,50 +1,66 @@ Function name: closure_macro_async::load_configuration_files -Raw bytes (9): 0x[01, 01, 00, 01, 01, 21, 01, 02, 02] +Raw bytes (19): 0x[01, 01, 00, 03, 01, 21, 01, 00, 38, 01, 01, 05, 00, 1f, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/closure_macro_async.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 33, 1) to (start + 2, 2) +Number of file 0 mappings: 3 +- Code(Counter(0)) at (prev + 33, 1) to (start + 0, 56) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 31) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: closure_macro_async::test -Raw bytes (9): 0x[01, 01, 00, 01, 01, 25, 01, 00, 2b] +Raw bytes (9): 0x[01, 01, 00, 01, 01, 25, 01, 00, 2a] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/closure_macro_async.rs Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 37, 1) to (start + 0, 43) +- Code(Counter(0)) at (prev + 37, 1) to (start + 0, 42) Highest counter ID seen: c0 Function name: closure_macro_async::test::{closure#0} -Raw bytes (36): 0x[01, 01, 01, 01, 05, 06, 01, 25, 2b, 01, 20, 02, 02, 09, 00, 0f, 01, 00, 12, 00, 34, 05, 00, 54, 00, 55, 02, 02, 09, 02, 0b, 01, 03, 01, 00, 02] +Raw bytes (66): 0x[01, 01, 01, 01, 05, 0c, 01, 25, 2b, 00, 2c, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 20, 02, 01, 09, 00, 0f, 01, 00, 12, 00, 1b, 01, 00, 1c, 00, 34, 05, 00, 54, 00, 55, 02, 02, 09, 00, 1f, 02, 00, 22, 00, 2e, 02, 01, 0d, 00, 2d, 02, 01, 05, 00, 0b, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/closure_macro_async.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 6 -- Code(Counter(0)) at (prev + 37, 43) to (start + 1, 32) -- Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 15) +Number of file 0 mappings: 12 +- Code(Counter(0)) at (prev + 37, 43) to (start + 0, 44) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 32) +- Code(Expression(0, Sub)) at (prev + 1, 9) to (start + 0, 15) = (c0 - c1) -- Code(Counter(0)) at (prev + 0, 18) to (start + 0, 52) +- Code(Counter(0)) at (prev + 0, 18) to (start + 0, 27) +- Code(Counter(0)) at (prev + 0, 28) to (start + 0, 52) - Code(Counter(1)) at (prev + 0, 84) to (start + 0, 85) -- Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 2, 11) +- Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 31) = (c0 - c1) -- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2) +- Code(Expression(0, Sub)) at (prev + 0, 34) to (start + 0, 46) + = (c0 - c1) +- Code(Expression(0, Sub)) at (prev + 1, 13) to (start + 0, 45) + = (c0 - c1) +- Code(Expression(0, Sub)) at (prev + 1, 5) to (start + 0, 11) + = (c0 - c1) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c1 Function name: closure_macro_async::test::{closure#0}::{closure#0} -Raw bytes (35): 0x[01, 01, 03, 01, 05, 01, 0b, 05, 09, 05, 01, 14, 1c, 03, 21, 05, 04, 11, 01, 27, 02, 03, 11, 00, 16, 06, 00, 17, 00, 1e, 01, 02, 09, 00, 0a] +Raw bytes (60): 0x[01, 01, 03, 01, 05, 01, 0b, 05, 09, 0a, 01, 14, 1c, 00, 1d, 01, 02, 11, 00, 18, 01, 00, 1b, 00, 22, 01, 01, 10, 00, 21, 05, 01, 11, 00, 19, 05, 00, 1a, 00, 1e, 05, 01, 11, 00, 27, 02, 02, 11, 00, 16, 06, 00, 17, 00, 1e, 01, 02, 09, 00, 0a] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/closure_macro_async.rs Number of expressions: 3 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(0), rhs = Expression(2, Add) - expression 2 operands: lhs = Counter(1), rhs = Counter(2) -Number of file 0 mappings: 5 -- Code(Counter(0)) at (prev + 20, 28) to (start + 3, 33) -- Code(Counter(1)) at (prev + 4, 17) to (start + 1, 39) -- Code(Expression(0, Sub)) at (prev + 3, 17) to (start + 0, 22) +Number of file 0 mappings: 10 +- Code(Counter(0)) at (prev + 20, 28) to (start + 0, 29) +- Code(Counter(0)) at (prev + 2, 17) to (start + 0, 24) +- Code(Counter(0)) at (prev + 0, 27) to (start + 0, 34) +- Code(Counter(0)) at (prev + 1, 16) to (start + 0, 33) +- Code(Counter(1)) at (prev + 1, 17) to (start + 0, 25) +- Code(Counter(1)) at (prev + 0, 26) to (start + 0, 30) +- Code(Counter(1)) at (prev + 1, 17) to (start + 0, 39) +- Code(Expression(0, Sub)) at (prev + 2, 17) to (start + 0, 22) = (c0 - c1) - Code(Expression(1, Sub)) at (prev + 0, 23) to (start + 0, 30) = (c0 - (c1 + c2)) diff --git a/tests/coverage/closure_macro_async.coverage b/tests/coverage/closure_macro_async.coverage index 1e1ffec9f761..7bfea3c9bb3b 100644 --- a/tests/coverage/closure_macro_async.coverage +++ b/tests/coverage/closure_macro_async.coverage @@ -18,7 +18,7 @@ LL| |macro_rules! on_error { LL| | ($value:expr, $error_message:expr) => { LL| 0| $value.or_else(|e| { - LL| 0| // This closure, which is declared in a macro, should be instrumented. + LL| | // This closure, which is declared in a macro, should be instrumented. LL| 0| let message = format!($error_message, e); LL| 0| if message.len() > 0 { LL| 0| println!("{}", message); diff --git a/tests/coverage/closure_unit_return.cov-map b/tests/coverage/closure_unit_return.cov-map index 9a66e0b0e772..f665d93e6e1c 100644 --- a/tests/coverage/closure_unit_return.cov-map +++ b/tests/coverage/closure_unit_return.cov-map @@ -1,38 +1,49 @@ Function name: closure_unit_return::explicit_unit -Raw bytes (14): 0x[01, 01, 00, 02, 01, 07, 01, 01, 10, 01, 05, 05, 02, 02] +Raw bytes (34): 0x[01, 01, 00, 06, 01, 07, 01, 00, 13, 01, 01, 09, 00, 10, 01, 04, 05, 00, 09, 01, 00, 0a, 00, 11, 01, 01, 05, 00, 07, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/closure_unit_return.rs Number of expressions: 0 -Number of file 0 mappings: 2 -- Code(Counter(0)) at (prev + 7, 1) to (start + 1, 16) -- Code(Counter(0)) at (prev + 5, 5) to (start + 2, 2) +Number of file 0 mappings: 6 +- Code(Counter(0)) at (prev + 7, 1) to (start + 0, 19) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 16) +- Code(Counter(0)) at (prev + 4, 5) to (start + 0, 9) +- Code(Counter(0)) at (prev + 0, 10) to (start + 0, 17) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 7) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: closure_unit_return::explicit_unit::{closure#0} (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 08, 16, 02, 06] +Raw bytes (19): 0x[01, 01, 00, 03, 00, 08, 16, 00, 17, 00, 01, 09, 00, 0b, 00, 01, 05, 00, 06] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/closure_unit_return.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 8, 22) to (start + 2, 6) +Number of file 0 mappings: 3 +- Code(Zero) at (prev + 8, 22) to (start + 0, 23) +- Code(Zero) at (prev + 1, 9) to (start + 0, 11) +- Code(Zero) at (prev + 1, 5) to (start + 0, 6) Highest counter ID seen: (none) Function name: closure_unit_return::implicit_unit -Raw bytes (14): 0x[01, 01, 00, 02, 01, 10, 01, 01, 10, 01, 05, 05, 02, 02] +Raw bytes (29): 0x[01, 01, 00, 05, 01, 10, 01, 00, 13, 01, 01, 09, 00, 10, 01, 04, 05, 00, 09, 01, 00, 0a, 00, 11, 01, 02, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/closure_unit_return.rs Number of expressions: 0 -Number of file 0 mappings: 2 -- Code(Counter(0)) at (prev + 16, 1) to (start + 1, 16) -- Code(Counter(0)) at (prev + 5, 5) to (start + 2, 2) +Number of file 0 mappings: 5 +- Code(Counter(0)) at (prev + 16, 1) to (start + 0, 19) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 16) +- Code(Counter(0)) at (prev + 4, 5) to (start + 0, 9) +- Code(Counter(0)) at (prev + 0, 10) to (start + 0, 17) +- Code(Counter(0)) at (prev + 2, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: closure_unit_return::implicit_unit::{closure#0} (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 11, 16, 02, 06] +Raw bytes (19): 0x[01, 01, 00, 03, 00, 11, 16, 00, 17, 00, 01, 09, 00, 0b, 00, 01, 05, 00, 06] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/closure_unit_return.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 17, 22) to (start + 2, 6) +Number of file 0 mappings: 3 +- Code(Zero) at (prev + 17, 22) to (start + 0, 23) +- Code(Zero) at (prev + 1, 9) to (start + 0, 11) +- Code(Zero) at (prev + 1, 5) to (start + 0, 6) Highest counter ID seen: (none) diff --git a/tests/coverage/closure_unit_return.coverage b/tests/coverage/closure_unit_return.coverage index 5e57e0db1600..02ea63b6dc39 100644 --- a/tests/coverage/closure_unit_return.coverage +++ b/tests/coverage/closure_unit_return.coverage @@ -6,6 +6,7 @@ LL| | LL| 1|fn explicit_unit() { LL| 1| let closure = || { + ^0 LL| 0| (); LL| 0| }; LL| | @@ -15,11 +16,12 @@ LL| | LL| 1|fn implicit_unit() { LL| 1| let closure = || { + ^0 LL| 0| (); LL| 0| }; LL| | LL| 1| drop(closure); - LL| 1| // implicit return of `()` + LL| | // implicit return of `()` LL| 1|} LL| | LL| |#[coverage(off)] diff --git a/tests/coverage/condition/conditions.cov-map b/tests/coverage/condition/conditions.cov-map index c34075a0bcfc..fda5dd1b97d1 100644 --- a/tests/coverage/condition/conditions.cov-map +++ b/tests/coverage/condition/conditions.cov-map @@ -1,15 +1,15 @@ Function name: conditions::assign_3_and_or -Raw bytes (65): 0x[01, 01, 05, 01, 05, 05, 09, 01, 09, 01, 13, 09, 0d, 09, 01, 1c, 01, 00, 2f, 01, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 20, 05, 02, 00, 0d, 00, 0e, 05, 00, 12, 00, 13, 20, 09, 06, 00, 12, 00, 13, 0a, 00, 17, 00, 18, 20, 0d, 0e, 00, 17, 00, 18, 01, 01, 05, 01, 02] +Raw bytes (75): 0x[01, 01, 05, 01, 05, 05, 09, 01, 09, 01, 13, 09, 0d, 0b, 01, 1c, 01, 00, 2e, 01, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 20, 05, 02, 00, 0d, 00, 0e, 05, 00, 12, 00, 13, 20, 09, 06, 00, 12, 00, 13, 0a, 00, 17, 00, 18, 20, 0d, 0e, 00, 17, 00, 18, 01, 01, 05, 00, 0e, 01, 00, 0f, 00, 10, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/conditions.rs Number of expressions: 5 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Counter(2) - expression 2 operands: lhs = Counter(0), rhs = Counter(2) - expression 3 operands: lhs = Counter(0), rhs = Expression(4, Add) - expression 4 operands: lhs = Counter(2), rhs = Counter(3) -Number of file 0 mappings: 9 -- Code(Counter(0)) at (prev + 28, 1) to (start + 0, 47) +Number of file 0 mappings: 11 +- Code(Counter(0)) at (prev + 28, 1) to (start + 0, 46) - Code(Counter(0)) at (prev + 1, 9) to (start + 0, 10) - Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14) - Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 0, 13) to (start + 0, 14) @@ -24,20 +24,22 @@ Number of file 0 mappings: 9 - Branch { true: Counter(3), false: Expression(3, Sub) } at (prev + 0, 23) to (start + 0, 24) true = c3 false = (c0 - (c2 + c3)) -- Code(Counter(0)) at (prev + 1, 5) to (start + 1, 2) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 16) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c3 Function name: conditions::assign_3_or_and -Raw bytes (63): 0x[01, 01, 04, 01, 05, 01, 0b, 05, 09, 09, 0d, 09, 01, 17, 01, 00, 2f, 01, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 20, 05, 02, 00, 0d, 00, 0e, 02, 00, 12, 00, 13, 20, 09, 06, 00, 12, 00, 13, 09, 00, 17, 00, 18, 20, 0d, 0e, 00, 17, 00, 18, 01, 01, 05, 01, 02] +Raw bytes (73): 0x[01, 01, 04, 01, 05, 01, 0b, 05, 09, 09, 0d, 0b, 01, 17, 01, 00, 2e, 01, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 20, 05, 02, 00, 0d, 00, 0e, 02, 00, 12, 00, 13, 20, 09, 06, 00, 12, 00, 13, 09, 00, 17, 00, 18, 20, 0d, 0e, 00, 17, 00, 18, 01, 01, 05, 00, 0e, 01, 00, 0f, 00, 10, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/conditions.rs Number of expressions: 4 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(0), rhs = Expression(2, Add) - expression 2 operands: lhs = Counter(1), rhs = Counter(2) - expression 3 operands: lhs = Counter(2), rhs = Counter(3) -Number of file 0 mappings: 9 -- Code(Counter(0)) at (prev + 23, 1) to (start + 0, 47) +Number of file 0 mappings: 11 +- Code(Counter(0)) at (prev + 23, 1) to (start + 0, 46) - Code(Counter(0)) at (prev + 1, 9) to (start + 0, 10) - Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14) - Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 0, 13) to (start + 0, 14) @@ -52,18 +54,20 @@ Number of file 0 mappings: 9 - Branch { true: Counter(3), false: Expression(3, Sub) } at (prev + 0, 23) to (start + 0, 24) true = c3 false = (c2 - c3) -- Code(Counter(0)) at (prev + 1, 5) to (start + 1, 2) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 16) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c3 Function name: conditions::assign_and -Raw bytes (47): 0x[01, 01, 02, 01, 05, 05, 09, 07, 01, 0d, 01, 00, 21, 01, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 20, 05, 02, 00, 0d, 00, 0e, 05, 00, 12, 00, 13, 20, 09, 06, 00, 12, 00, 13, 01, 01, 05, 01, 02] +Raw bytes (57): 0x[01, 01, 02, 01, 05, 05, 09, 09, 01, 0d, 01, 00, 20, 01, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 20, 05, 02, 00, 0d, 00, 0e, 05, 00, 12, 00, 13, 20, 09, 06, 00, 12, 00, 13, 01, 01, 05, 00, 0e, 01, 00, 0f, 00, 10, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/conditions.rs Number of expressions: 2 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Counter(2) -Number of file 0 mappings: 7 -- Code(Counter(0)) at (prev + 13, 1) to (start + 0, 33) +Number of file 0 mappings: 9 +- Code(Counter(0)) at (prev + 13, 1) to (start + 0, 32) - Code(Counter(0)) at (prev + 1, 9) to (start + 0, 10) - Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14) - Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 0, 13) to (start + 0, 14) @@ -73,19 +77,21 @@ Number of file 0 mappings: 7 - Branch { true: Counter(2), false: Expression(1, Sub) } at (prev + 0, 18) to (start + 0, 19) true = c2 false = (c1 - c2) -- Code(Counter(0)) at (prev + 1, 5) to (start + 1, 2) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 16) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c2 Function name: conditions::assign_or -Raw bytes (49): 0x[01, 01, 03, 01, 05, 01, 0b, 05, 09, 07, 01, 12, 01, 00, 20, 01, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 20, 05, 02, 00, 0d, 00, 0e, 02, 00, 12, 00, 13, 20, 09, 06, 00, 12, 00, 13, 01, 01, 05, 01, 02] +Raw bytes (59): 0x[01, 01, 03, 01, 05, 01, 0b, 05, 09, 09, 01, 12, 01, 00, 1f, 01, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 20, 05, 02, 00, 0d, 00, 0e, 02, 00, 12, 00, 13, 20, 09, 06, 00, 12, 00, 13, 01, 01, 05, 00, 0e, 01, 00, 0f, 00, 10, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/conditions.rs Number of expressions: 3 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(0), rhs = Expression(2, Add) - expression 2 operands: lhs = Counter(1), rhs = Counter(2) -Number of file 0 mappings: 7 -- Code(Counter(0)) at (prev + 18, 1) to (start + 0, 32) +Number of file 0 mappings: 9 +- Code(Counter(0)) at (prev + 18, 1) to (start + 0, 31) - Code(Counter(0)) at (prev + 1, 9) to (start + 0, 10) - Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14) - Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 0, 13) to (start + 0, 14) @@ -96,27 +102,32 @@ Number of file 0 mappings: 7 - Branch { true: Counter(2), false: Expression(1, Sub) } at (prev + 0, 18) to (start + 0, 19) true = c2 false = (c0 - (c1 + c2)) -- Code(Counter(0)) at (prev + 1, 5) to (start + 1, 2) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 16) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c2 Function name: conditions::foo -Raw bytes (9): 0x[01, 01, 00, 01, 01, 21, 01, 02, 02] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 21, 01, 00, 18, 01, 01, 05, 00, 0e, 01, 00, 0f, 00, 10, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/conditions.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 33, 1) to (start + 2, 2) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 33, 1) to (start + 0, 24) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 16) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: conditions::func_call -Raw bytes (47): 0x[01, 01, 02, 01, 05, 05, 09, 07, 01, 25, 01, 00, 20, 01, 01, 05, 00, 08, 01, 00, 09, 00, 0a, 20, 05, 02, 00, 09, 00, 0a, 05, 00, 0e, 00, 0f, 20, 09, 06, 00, 0e, 00, 0f, 01, 01, 01, 00, 02] +Raw bytes (47): 0x[01, 01, 02, 01, 05, 05, 09, 07, 01, 25, 01, 00, 1f, 01, 01, 05, 00, 08, 01, 00, 09, 00, 0a, 20, 05, 02, 00, 09, 00, 0a, 05, 00, 0e, 00, 0f, 20, 09, 06, 00, 0e, 00, 0f, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/conditions.rs Number of expressions: 2 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Counter(2) Number of file 0 mappings: 7 -- Code(Counter(0)) at (prev + 37, 1) to (start + 0, 32) +- Code(Counter(0)) at (prev + 37, 1) to (start + 0, 31) - Code(Counter(0)) at (prev + 1, 5) to (start + 0, 8) - Code(Counter(0)) at (prev + 0, 9) to (start + 0, 10) - Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 0, 9) to (start + 0, 10) @@ -130,11 +141,16 @@ Number of file 0 mappings: 7 Highest counter ID seen: c2 Function name: conditions::simple_assign -Raw bytes (9): 0x[01, 01, 00, 01, 01, 08, 01, 03, 02] +Raw bytes (34): 0x[01, 01, 00, 06, 01, 08, 01, 00, 1a, 01, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 01, 01, 05, 00, 0e, 01, 00, 0f, 00, 10, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/conditions.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 8, 1) to (start + 3, 2) +Number of file 0 mappings: 6 +- Code(Counter(0)) at (prev + 8, 1) to (start + 0, 26) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 10) +- Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 16) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 diff --git a/tests/coverage/conditions.cov-map b/tests/coverage/conditions.cov-map index 2d12f4bf7744..29d9604085ed 100644 --- a/tests/coverage/conditions.cov-map +++ b/tests/coverage/conditions.cov-map @@ -1,8 +1,8 @@ Function name: conditions::main -Raw bytes (533): 0x[01, 01, 47, 05, 09, 01, 05, 09, 5d, 09, 27, 5d, 61, 27, 65, 5d, 61, 09, 23, 27, 65, 5d, 61, 01, 03, 03, 0d, 11, 51, 11, 4f, 51, 55, 4f, 59, 51, 55, 11, 4b, 4f, 59, 51, 55, 03, 97, 01, 0d, 11, 0d, 11, 0d, 11, 0d, 11, 0d, 11, 97, 01, 15, 0d, 11, 19, 45, 19, 8f, 01, 45, 49, 8f, 01, 4d, 45, 49, 19, 8b, 01, 8f, 01, 4d, 45, 49, 97, 01, db, 01, 0d, 11, 15, 19, 15, 19, 15, 19, 1d, 21, 15, 19, db, 01, 1d, 15, 19, 21, 39, 21, d3, 01, 39, 3d, d3, 01, 41, 39, 3d, 21, cf, 01, d3, 01, 41, 39, 3d, db, 01, 97, 02, 15, 19, 1d, 21, 25, 29, 1d, 21, 97, 02, 25, 1d, 21, 29, 2d, 29, 8f, 02, 2d, 31, 8f, 02, 35, 2d, 31, 29, 8b, 02, 8f, 02, 35, 2d, 31, 97, 02, 9b, 02, 1d, 21, 25, 29, 44, 01, 03, 01, 02, 0c, 01, 02, 0d, 02, 06, 00, 02, 05, 00, 06, 03, 03, 09, 00, 0a, 01, 00, 10, 00, 1d, 05, 01, 09, 01, 0a, 06, 02, 0f, 00, 1c, 09, 01, 0c, 00, 19, 0a, 00, 1d, 00, 2a, 0e, 00, 2e, 00, 3c, 23, 00, 3d, 02, 0a, 1e, 02, 09, 00, 0a, 09, 01, 09, 01, 12, 2a, 03, 09, 00, 0f, 03, 03, 09, 01, 0c, 03, 01, 0d, 02, 06, 00, 02, 05, 00, 06, 03, 02, 08, 00, 15, 0d, 00, 16, 02, 06, 2e, 02, 0f, 00, 1c, 11, 01, 0c, 00, 19, 32, 00, 1d, 00, 2a, 36, 00, 2e, 00, 3c, 4b, 00, 3d, 02, 0a, 46, 02, 09, 00, 0a, 11, 01, 09, 00, 17, 52, 02, 09, 00, 0f, 97, 01, 03, 08, 00, 0c, 97, 01, 01, 0d, 01, 10, 97, 01, 01, 11, 02, 0a, 00, 02, 09, 00, 0a, 97, 01, 02, 0c, 00, 19, 15, 00, 1a, 02, 0a, 6a, 04, 11, 00, 1e, 19, 01, 10, 00, 1d, 72, 00, 21, 00, 2e, 76, 00, 32, 00, 40, 8b, 01, 00, 41, 02, 0e, 86, 01, 02, 0d, 00, 0e, 19, 01, 0d, 00, 1b, 92, 01, 02, 0d, 00, 13, 00, 02, 05, 00, 06, db, 01, 02, 09, 01, 0c, db, 01, 01, 0d, 02, 06, 00, 02, 05, 00, 06, 97, 02, 02, 09, 00, 0a, db, 01, 00, 10, 00, 1d, 1d, 00, 1e, 02, 06, ae, 01, 02, 0f, 00, 1c, 21, 01, 0c, 00, 19, b6, 01, 00, 1d, 00, 2a, ba, 01, 00, 2e, 00, 3c, cf, 01, 00, 3d, 02, 0a, ca, 01, 02, 09, 00, 0a, 21, 01, 09, 00, 17, d6, 01, 02, 0d, 02, 0f, 9b, 02, 05, 09, 00, 0a, 97, 02, 00, 10, 00, 1d, 25, 00, 1e, 02, 06, ea, 01, 02, 0f, 00, 1c, 29, 01, 0c, 00, 19, f2, 01, 00, 1d, 00, 2a, f6, 01, 00, 2e, 00, 3c, 8b, 02, 00, 3d, 02, 0a, 86, 02, 02, 09, 00, 0a, 29, 01, 09, 00, 17, 92, 02, 02, 09, 00, 0f, 01, 02, 01, 00, 02] +Raw bytes (656): 0x[01, 01, 57, 05, 09, 01, 05, 09, 5d, 09, 27, 5d, 61, 27, 65, 5d, 61, 09, 23, 27, 65, 5d, 61, 01, 03, 03, 0d, 11, 51, 11, 4f, 51, 55, 4f, 59, 51, 55, 11, 4b, 4f, 59, 51, 55, 03, 9f, 01, 0d, 11, 0d, 11, 0d, 11, 0d, 11, 0d, 11, 0d, 11, 0d, 11, 9f, 01, 15, 0d, 11, 19, 45, 19, 97, 01, 45, 49, 97, 01, 4d, 45, 49, 19, 93, 01, 97, 01, 4d, 45, 49, 9f, 01, 9b, 02, 0d, 11, 15, 19, 15, 19, 15, 19, 15, 19, 15, 19, 1d, 21, 15, 19, 9b, 02, 1d, 15, 19, 21, 39, 21, e3, 01, 39, 3d, e3, 01, 41, 39, 3d, 21, df, 01, e3, 01, 41, 39, 3d, 9b, 02, d7, 02, 15, 19, 1d, 21, 9b, 02, d7, 02, 15, 19, 1d, 21, 9b, 02, d7, 02, 15, 19, 1d, 21, 9b, 02, d7, 02, 15, 19, 1d, 21, 9b, 02, d7, 02, 15, 19, 1d, 21, 25, 29, 1d, 21, d7, 02, 25, 1d, 21, 29, 2d, 29, cf, 02, 2d, 31, cf, 02, 35, 2d, 31, 29, cb, 02, cf, 02, 35, 2d, 31, d7, 02, db, 02, 1d, 21, 25, 29, 53, 01, 03, 01, 00, 0a, 01, 01, 09, 00, 16, 01, 00, 19, 00, 1a, 01, 01, 08, 00, 0c, 01, 00, 0d, 02, 06, 00, 02, 05, 00, 06, 03, 03, 09, 00, 0a, 01, 00, 10, 00, 1d, 05, 01, 09, 00, 17, 05, 01, 09, 00, 0a, 06, 01, 0f, 00, 1c, 09, 01, 0c, 00, 19, 0a, 00, 1d, 00, 2a, 0e, 00, 2e, 00, 3c, 23, 00, 3d, 02, 0a, 1e, 02, 09, 00, 0a, 09, 01, 09, 00, 17, 09, 01, 09, 00, 12, 2a, 02, 09, 00, 0f, 03, 03, 09, 00, 16, 03, 00, 19, 00, 1a, 03, 01, 08, 00, 0c, 03, 00, 0d, 02, 06, 00, 02, 05, 00, 06, 03, 02, 08, 00, 15, 0d, 00, 16, 02, 06, 2e, 02, 0f, 00, 1c, 11, 01, 0c, 00, 19, 32, 00, 1d, 00, 2a, 36, 00, 2e, 00, 3c, 4b, 00, 3d, 02, 0a, 46, 02, 09, 00, 0a, 11, 01, 09, 00, 17, 52, 02, 09, 00, 0f, 9f, 01, 03, 08, 00, 0c, 9f, 01, 01, 0d, 00, 1a, 9f, 01, 00, 1d, 00, 1e, 9f, 01, 01, 0c, 00, 10, 9f, 01, 00, 11, 02, 0a, 00, 02, 09, 00, 0a, 9f, 01, 02, 0c, 00, 19, 15, 00, 1a, 02, 0a, 72, 04, 11, 00, 1e, 19, 01, 10, 00, 1d, 7a, 00, 21, 00, 2e, 7e, 00, 32, 00, 40, 93, 01, 00, 41, 02, 0e, 8e, 01, 02, 0d, 00, 0e, 19, 01, 0d, 00, 1b, 9a, 01, 02, 0d, 00, 13, 00, 02, 05, 00, 06, 9b, 02, 02, 09, 00, 16, 9b, 02, 00, 19, 00, 1a, 9b, 02, 01, 08, 00, 0c, 9b, 02, 00, 0d, 02, 06, 00, 02, 05, 00, 06, d7, 02, 02, 09, 00, 0a, 9b, 02, 00, 10, 00, 1d, 1d, 00, 1e, 02, 06, be, 01, 02, 0f, 00, 1c, 21, 01, 0c, 00, 19, c6, 01, 00, 1d, 00, 2a, ca, 01, 00, 2e, 00, 3c, df, 01, 00, 3d, 02, 0a, da, 01, 02, 09, 00, 0a, 21, 01, 09, 00, 17, 96, 02, 02, 0d, 00, 20, 96, 02, 00, 23, 00, 2c, 96, 02, 01, 09, 00, 11, 96, 02, 00, 12, 00, 1b, 96, 02, 01, 09, 00, 0f, db, 02, 03, 09, 00, 0a, d7, 02, 00, 10, 00, 1d, 25, 00, 1e, 02, 06, aa, 02, 02, 0f, 00, 1c, 29, 01, 0c, 00, 19, b2, 02, 00, 1d, 00, 2a, b6, 02, 00, 2e, 00, 3c, cb, 02, 00, 3d, 02, 0a, c6, 02, 02, 09, 00, 0a, 29, 01, 09, 00, 17, d2, 02, 02, 09, 00, 0f, 01, 02, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 -Number of expressions: 71 +- file 0 => $DIR/conditions.rs +Number of expressions: 87 - expression 0 operands: lhs = Counter(1), rhs = Counter(2) - expression 1 operands: lhs = Counter(0), rhs = Counter(1) - expression 2 operands: lhs = Counter(2), rhs = Counter(23) @@ -23,66 +23,86 @@ Number of expressions: 71 - expression 17 operands: lhs = Counter(4), rhs = Expression(18, Add) - expression 18 operands: lhs = Expression(19, Add), rhs = Counter(22) - expression 19 operands: lhs = Counter(20), rhs = Counter(21) -- expression 20 operands: lhs = Expression(0, Add), rhs = Expression(37, Add) +- expression 20 operands: lhs = Expression(0, Add), rhs = Expression(39, Add) - expression 21 operands: lhs = Counter(3), rhs = Counter(4) - expression 22 operands: lhs = Counter(3), rhs = Counter(4) - expression 23 operands: lhs = Counter(3), rhs = Counter(4) - expression 24 operands: lhs = Counter(3), rhs = Counter(4) - expression 25 operands: lhs = Counter(3), rhs = Counter(4) -- expression 26 operands: lhs = Expression(37, Add), rhs = Counter(5) +- expression 26 operands: lhs = Counter(3), rhs = Counter(4) - expression 27 operands: lhs = Counter(3), rhs = Counter(4) -- expression 28 operands: lhs = Counter(6), rhs = Counter(17) -- expression 29 operands: lhs = Counter(6), rhs = Expression(35, Add) -- expression 30 operands: lhs = Counter(17), rhs = Counter(18) -- expression 31 operands: lhs = Expression(35, Add), rhs = Counter(19) +- expression 28 operands: lhs = Expression(39, Add), rhs = Counter(5) +- expression 29 operands: lhs = Counter(3), rhs = Counter(4) +- expression 30 operands: lhs = Counter(6), rhs = Counter(17) +- expression 31 operands: lhs = Counter(6), rhs = Expression(37, Add) - expression 32 operands: lhs = Counter(17), rhs = Counter(18) -- expression 33 operands: lhs = Counter(6), rhs = Expression(34, Add) -- expression 34 operands: lhs = Expression(35, Add), rhs = Counter(19) -- expression 35 operands: lhs = Counter(17), rhs = Counter(18) -- expression 36 operands: lhs = Expression(37, Add), rhs = Expression(54, Add) -- expression 37 operands: lhs = Counter(3), rhs = Counter(4) -- expression 38 operands: lhs = Counter(5), rhs = Counter(6) -- expression 39 operands: lhs = Counter(5), rhs = Counter(6) +- expression 33 operands: lhs = Expression(37, Add), rhs = Counter(19) +- expression 34 operands: lhs = Counter(17), rhs = Counter(18) +- expression 35 operands: lhs = Counter(6), rhs = Expression(36, Add) +- expression 36 operands: lhs = Expression(37, Add), rhs = Counter(19) +- expression 37 operands: lhs = Counter(17), rhs = Counter(18) +- expression 38 operands: lhs = Expression(39, Add), rhs = Expression(70, Add) +- expression 39 operands: lhs = Counter(3), rhs = Counter(4) - expression 40 operands: lhs = Counter(5), rhs = Counter(6) -- expression 41 operands: lhs = Counter(7), rhs = Counter(8) +- expression 41 operands: lhs = Counter(5), rhs = Counter(6) - expression 42 operands: lhs = Counter(5), rhs = Counter(6) -- expression 43 operands: lhs = Expression(54, Add), rhs = Counter(7) +- expression 43 operands: lhs = Counter(5), rhs = Counter(6) - expression 44 operands: lhs = Counter(5), rhs = Counter(6) -- expression 45 operands: lhs = Counter(8), rhs = Counter(14) -- expression 46 operands: lhs = Counter(8), rhs = Expression(52, Add) -- expression 47 operands: lhs = Counter(14), rhs = Counter(15) -- expression 48 operands: lhs = Expression(52, Add), rhs = Counter(16) -- expression 49 operands: lhs = Counter(14), rhs = Counter(15) -- expression 50 operands: lhs = Counter(8), rhs = Expression(51, Add) -- expression 51 operands: lhs = Expression(52, Add), rhs = Counter(16) -- expression 52 operands: lhs = Counter(14), rhs = Counter(15) -- expression 53 operands: lhs = Expression(54, Add), rhs = Expression(69, Add) -- expression 54 operands: lhs = Counter(5), rhs = Counter(6) -- expression 55 operands: lhs = Counter(7), rhs = Counter(8) -- expression 56 operands: lhs = Counter(9), rhs = Counter(10) -- expression 57 operands: lhs = Counter(7), rhs = Counter(8) -- expression 58 operands: lhs = Expression(69, Add), rhs = Counter(9) +- expression 45 operands: lhs = Counter(7), rhs = Counter(8) +- expression 46 operands: lhs = Counter(5), rhs = Counter(6) +- expression 47 operands: lhs = Expression(70, Add), rhs = Counter(7) +- expression 48 operands: lhs = Counter(5), rhs = Counter(6) +- expression 49 operands: lhs = Counter(8), rhs = Counter(14) +- expression 50 operands: lhs = Counter(8), rhs = Expression(56, Add) +- expression 51 operands: lhs = Counter(14), rhs = Counter(15) +- expression 52 operands: lhs = Expression(56, Add), rhs = Counter(16) +- expression 53 operands: lhs = Counter(14), rhs = Counter(15) +- expression 54 operands: lhs = Counter(8), rhs = Expression(55, Add) +- expression 55 operands: lhs = Expression(56, Add), rhs = Counter(16) +- expression 56 operands: lhs = Counter(14), rhs = Counter(15) +- expression 57 operands: lhs = Expression(70, Add), rhs = Expression(85, Add) +- expression 58 operands: lhs = Counter(5), rhs = Counter(6) - expression 59 operands: lhs = Counter(7), rhs = Counter(8) -- expression 60 operands: lhs = Counter(10), rhs = Counter(11) -- expression 61 operands: lhs = Counter(10), rhs = Expression(67, Add) -- expression 62 operands: lhs = Counter(11), rhs = Counter(12) -- expression 63 operands: lhs = Expression(67, Add), rhs = Counter(13) -- expression 64 operands: lhs = Counter(11), rhs = Counter(12) -- expression 65 operands: lhs = Counter(10), rhs = Expression(66, Add) -- expression 66 operands: lhs = Expression(67, Add), rhs = Counter(13) -- expression 67 operands: lhs = Counter(11), rhs = Counter(12) -- expression 68 operands: lhs = Expression(69, Add), rhs = Expression(70, Add) -- expression 69 operands: lhs = Counter(7), rhs = Counter(8) -- expression 70 operands: lhs = Counter(9), rhs = Counter(10) -Number of file 0 mappings: 68 -- Code(Counter(0)) at (prev + 3, 1) to (start + 2, 12) -- Code(Counter(0)) at (prev + 2, 13) to (start + 2, 6) +- expression 60 operands: lhs = Expression(70, Add), rhs = Expression(85, Add) +- expression 61 operands: lhs = Counter(5), rhs = Counter(6) +- expression 62 operands: lhs = Counter(7), rhs = Counter(8) +- expression 63 operands: lhs = Expression(70, Add), rhs = Expression(85, Add) +- expression 64 operands: lhs = Counter(5), rhs = Counter(6) +- expression 65 operands: lhs = Counter(7), rhs = Counter(8) +- expression 66 operands: lhs = Expression(70, Add), rhs = Expression(85, Add) +- expression 67 operands: lhs = Counter(5), rhs = Counter(6) +- expression 68 operands: lhs = Counter(7), rhs = Counter(8) +- expression 69 operands: lhs = Expression(70, Add), rhs = Expression(85, Add) +- expression 70 operands: lhs = Counter(5), rhs = Counter(6) +- expression 71 operands: lhs = Counter(7), rhs = Counter(8) +- expression 72 operands: lhs = Counter(9), rhs = Counter(10) +- expression 73 operands: lhs = Counter(7), rhs = Counter(8) +- expression 74 operands: lhs = Expression(85, Add), rhs = Counter(9) +- expression 75 operands: lhs = Counter(7), rhs = Counter(8) +- expression 76 operands: lhs = Counter(10), rhs = Counter(11) +- expression 77 operands: lhs = Counter(10), rhs = Expression(83, Add) +- expression 78 operands: lhs = Counter(11), rhs = Counter(12) +- expression 79 operands: lhs = Expression(83, Add), rhs = Counter(13) +- expression 80 operands: lhs = Counter(11), rhs = Counter(12) +- expression 81 operands: lhs = Counter(10), rhs = Expression(82, Add) +- expression 82 operands: lhs = Expression(83, Add), rhs = Counter(13) +- expression 83 operands: lhs = Counter(11), rhs = Counter(12) +- expression 84 operands: lhs = Expression(85, Add), rhs = Expression(86, Add) +- expression 85 operands: lhs = Counter(7), rhs = Counter(8) +- expression 86 operands: lhs = Counter(9), rhs = Counter(10) +Number of file 0 mappings: 83 +- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 22) +- Code(Counter(0)) at (prev + 0, 25) to (start + 0, 26) +- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 12) +- Code(Counter(0)) at (prev + 0, 13) to (start + 2, 6) - Code(Zero) at (prev + 2, 5) to (start + 0, 6) - Code(Expression(0, Add)) at (prev + 3, 9) to (start + 0, 10) = (c1 + c2) - Code(Counter(0)) at (prev + 0, 16) to (start + 0, 29) -- Code(Counter(1)) at (prev + 1, 9) to (start + 1, 10) -- Code(Expression(1, Sub)) at (prev + 2, 15) to (start + 0, 28) +- Code(Counter(1)) at (prev + 1, 9) to (start + 0, 23) +- Code(Counter(1)) at (prev + 1, 9) to (start + 0, 10) +- Code(Expression(1, Sub)) at (prev + 1, 15) to (start + 0, 28) = (c0 - c1) - Code(Counter(2)) at (prev + 1, 12) to (start + 0, 25) - Code(Expression(2, Sub)) at (prev + 0, 29) to (start + 0, 42) @@ -93,12 +113,17 @@ Number of file 0 mappings: 68 = ((c23 + c24) + c25) - Code(Expression(7, Sub)) at (prev + 2, 9) to (start + 0, 10) = (c2 - ((c23 + c24) + c25)) -- Code(Counter(2)) at (prev + 1, 9) to (start + 1, 18) -- Code(Expression(10, Sub)) at (prev + 3, 9) to (start + 0, 15) +- Code(Counter(2)) at (prev + 1, 9) to (start + 0, 23) +- Code(Counter(2)) at (prev + 1, 9) to (start + 0, 18) +- Code(Expression(10, Sub)) at (prev + 2, 9) to (start + 0, 15) = (c0 - (c1 + c2)) -- Code(Expression(0, Add)) at (prev + 3, 9) to (start + 1, 12) +- Code(Expression(0, Add)) at (prev + 3, 9) to (start + 0, 22) = (c1 + c2) -- Code(Expression(0, Add)) at (prev + 1, 13) to (start + 2, 6) +- Code(Expression(0, Add)) at (prev + 0, 25) to (start + 0, 26) + = (c1 + c2) +- Code(Expression(0, Add)) at (prev + 1, 8) to (start + 0, 12) + = (c1 + c2) +- Code(Expression(0, Add)) at (prev + 0, 13) to (start + 2, 6) = (c1 + c2) - Code(Zero) at (prev + 2, 5) to (start + 0, 6) - Code(Expression(0, Add)) at (prev + 2, 8) to (start + 0, 21) @@ -118,73 +143,89 @@ Number of file 0 mappings: 68 - Code(Counter(4)) at (prev + 1, 9) to (start + 0, 23) - Code(Expression(20, Sub)) at (prev + 2, 9) to (start + 0, 15) = ((c1 + c2) - (c3 + c4)) -- Code(Expression(37, Add)) at (prev + 3, 8) to (start + 0, 12) +- Code(Expression(39, Add)) at (prev + 3, 8) to (start + 0, 12) = (c3 + c4) -- Code(Expression(37, Add)) at (prev + 1, 13) to (start + 1, 16) +- Code(Expression(39, Add)) at (prev + 1, 13) to (start + 0, 26) = (c3 + c4) -- Code(Expression(37, Add)) at (prev + 1, 17) to (start + 2, 10) +- Code(Expression(39, Add)) at (prev + 0, 29) to (start + 0, 30) + = (c3 + c4) +- Code(Expression(39, Add)) at (prev + 1, 12) to (start + 0, 16) + = (c3 + c4) +- Code(Expression(39, Add)) at (prev + 0, 17) to (start + 2, 10) = (c3 + c4) - Code(Zero) at (prev + 2, 9) to (start + 0, 10) -- Code(Expression(37, Add)) at (prev + 2, 12) to (start + 0, 25) +- Code(Expression(39, Add)) at (prev + 2, 12) to (start + 0, 25) = (c3 + c4) - Code(Counter(5)) at (prev + 0, 26) to (start + 2, 10) -- Code(Expression(26, Sub)) at (prev + 4, 17) to (start + 0, 30) +- Code(Expression(28, Sub)) at (prev + 4, 17) to (start + 0, 30) = ((c3 + c4) - c5) - Code(Counter(6)) at (prev + 1, 16) to (start + 0, 29) -- Code(Expression(28, Sub)) at (prev + 0, 33) to (start + 0, 46) +- Code(Expression(30, Sub)) at (prev + 0, 33) to (start + 0, 46) = (c6 - c17) -- Code(Expression(29, Sub)) at (prev + 0, 50) to (start + 0, 64) +- Code(Expression(31, Sub)) at (prev + 0, 50) to (start + 0, 64) = (c6 - (c17 + c18)) -- Code(Expression(34, Add)) at (prev + 0, 65) to (start + 2, 14) +- Code(Expression(36, Add)) at (prev + 0, 65) to (start + 2, 14) = ((c17 + c18) + c19) -- Code(Expression(33, Sub)) at (prev + 2, 13) to (start + 0, 14) +- Code(Expression(35, Sub)) at (prev + 2, 13) to (start + 0, 14) = (c6 - ((c17 + c18) + c19)) - Code(Counter(6)) at (prev + 1, 13) to (start + 0, 27) -- Code(Expression(36, Sub)) at (prev + 2, 13) to (start + 0, 19) +- Code(Expression(38, Sub)) at (prev + 2, 13) to (start + 0, 19) = ((c3 + c4) - (c5 + c6)) - Code(Zero) at (prev + 2, 5) to (start + 0, 6) -- Code(Expression(54, Add)) at (prev + 2, 9) to (start + 1, 12) +- Code(Expression(70, Add)) at (prev + 2, 9) to (start + 0, 22) = (c5 + c6) -- Code(Expression(54, Add)) at (prev + 1, 13) to (start + 2, 6) +- Code(Expression(70, Add)) at (prev + 0, 25) to (start + 0, 26) + = (c5 + c6) +- Code(Expression(70, Add)) at (prev + 1, 8) to (start + 0, 12) + = (c5 + c6) +- Code(Expression(70, Add)) at (prev + 0, 13) to (start + 2, 6) = (c5 + c6) - Code(Zero) at (prev + 2, 5) to (start + 0, 6) -- Code(Expression(69, Add)) at (prev + 2, 9) to (start + 0, 10) +- Code(Expression(85, Add)) at (prev + 2, 9) to (start + 0, 10) = (c7 + c8) -- Code(Expression(54, Add)) at (prev + 0, 16) to (start + 0, 29) +- Code(Expression(70, Add)) at (prev + 0, 16) to (start + 0, 29) = (c5 + c6) - Code(Counter(7)) at (prev + 0, 30) to (start + 2, 6) -- Code(Expression(43, Sub)) at (prev + 2, 15) to (start + 0, 28) +- Code(Expression(47, Sub)) at (prev + 2, 15) to (start + 0, 28) = ((c5 + c6) - c7) - Code(Counter(8)) at (prev + 1, 12) to (start + 0, 25) -- Code(Expression(45, Sub)) at (prev + 0, 29) to (start + 0, 42) +- Code(Expression(49, Sub)) at (prev + 0, 29) to (start + 0, 42) = (c8 - c14) -- Code(Expression(46, Sub)) at (prev + 0, 46) to (start + 0, 60) +- Code(Expression(50, Sub)) at (prev + 0, 46) to (start + 0, 60) = (c8 - (c14 + c15)) -- Code(Expression(51, Add)) at (prev + 0, 61) to (start + 2, 10) +- Code(Expression(55, Add)) at (prev + 0, 61) to (start + 2, 10) = ((c14 + c15) + c16) -- Code(Expression(50, Sub)) at (prev + 2, 9) to (start + 0, 10) +- Code(Expression(54, Sub)) at (prev + 2, 9) to (start + 0, 10) = (c8 - ((c14 + c15) + c16)) - Code(Counter(8)) at (prev + 1, 9) to (start + 0, 23) -- Code(Expression(53, Sub)) at (prev + 2, 13) to (start + 2, 15) +- Code(Expression(69, Sub)) at (prev + 2, 13) to (start + 0, 32) = ((c5 + c6) - (c7 + c8)) -- Code(Expression(70, Add)) at (prev + 5, 9) to (start + 0, 10) +- Code(Expression(69, Sub)) at (prev + 0, 35) to (start + 0, 44) + = ((c5 + c6) - (c7 + c8)) +- Code(Expression(69, Sub)) at (prev + 1, 9) to (start + 0, 17) + = ((c5 + c6) - (c7 + c8)) +- Code(Expression(69, Sub)) at (prev + 0, 18) to (start + 0, 27) + = ((c5 + c6) - (c7 + c8)) +- Code(Expression(69, Sub)) at (prev + 1, 9) to (start + 0, 15) + = ((c5 + c6) - (c7 + c8)) +- Code(Expression(86, Add)) at (prev + 3, 9) to (start + 0, 10) = (c9 + c10) -- Code(Expression(69, Add)) at (prev + 0, 16) to (start + 0, 29) +- Code(Expression(85, Add)) at (prev + 0, 16) to (start + 0, 29) = (c7 + c8) - Code(Counter(9)) at (prev + 0, 30) to (start + 2, 6) -- Code(Expression(58, Sub)) at (prev + 2, 15) to (start + 0, 28) +- Code(Expression(74, Sub)) at (prev + 2, 15) to (start + 0, 28) = ((c7 + c8) - c9) - Code(Counter(10)) at (prev + 1, 12) to (start + 0, 25) -- Code(Expression(60, Sub)) at (prev + 0, 29) to (start + 0, 42) +- Code(Expression(76, Sub)) at (prev + 0, 29) to (start + 0, 42) = (c10 - c11) -- Code(Expression(61, Sub)) at (prev + 0, 46) to (start + 0, 60) +- Code(Expression(77, Sub)) at (prev + 0, 46) to (start + 0, 60) = (c10 - (c11 + c12)) -- Code(Expression(66, Add)) at (prev + 0, 61) to (start + 2, 10) +- Code(Expression(82, Add)) at (prev + 0, 61) to (start + 2, 10) = ((c11 + c12) + c13) -- Code(Expression(65, Sub)) at (prev + 2, 9) to (start + 0, 10) +- Code(Expression(81, Sub)) at (prev + 2, 9) to (start + 0, 10) = (c10 - ((c11 + c12) + c13)) - Code(Counter(10)) at (prev + 1, 9) to (start + 0, 23) -- Code(Expression(68, Sub)) at (prev + 2, 9) to (start + 0, 15) +- Code(Expression(84, Sub)) at (prev + 2, 9) to (start + 0, 15) = ((c7 + c8) - (c9 + c10)) - Code(Counter(0)) at (prev + 2, 1) to (start + 0, 2) Highest counter ID seen: c10 diff --git a/tests/coverage/continue.cov-map b/tests/coverage/continue.cov-map index d926741cbcb3..1a839f19a0f5 100644 --- a/tests/coverage/continue.cov-map +++ b/tests/coverage/continue.cov-map @@ -1,75 +1,88 @@ Function name: continue::main -Raw bytes (198): 0x[01, 01, 16, 05, 01, 05, 0b, 01, 09, 0d, 01, 0d, 1f, 01, 11, 0d, 1f, 01, 11, 15, 01, 15, 2b, 01, 19, 1d, 01, 1d, 37, 01, 21, 25, 01, 25, 43, 01, 29, 25, 01, 2d, 01, 53, 2d, 01, 31, 2d, 01, 1e, 01, 03, 01, 03, 12, 05, 04, 0e, 00, 13, 02, 01, 0f, 00, 16, 09, 02, 11, 00, 19, 06, 02, 12, 04, 0e, 0d, 06, 0e, 00, 13, 0e, 01, 0f, 00, 16, 1a, 01, 16, 02, 0e, 11, 04, 11, 00, 19, 1a, 03, 09, 00, 0e, 15, 02, 0e, 00, 13, 22, 01, 0f, 00, 16, 19, 01, 15, 02, 0e, 26, 04, 11, 00, 19, 19, 03, 09, 00, 0e, 1d, 02, 0e, 00, 13, 2e, 01, 0c, 00, 13, 21, 01, 0d, 00, 15, 32, 01, 0a, 01, 0e, 25, 03, 0e, 00, 13, 46, 01, 0f, 00, 16, 3e, 01, 16, 02, 0e, 29, 03, 12, 02, 0e, 46, 04, 09, 00, 0e, 2d, 02, 0e, 00, 13, 31, 01, 0f, 00, 16, 56, 01, 16, 02, 0e, 4e, 04, 11, 00, 16, 56, 03, 09, 00, 0e, 01, 02, 0d, 01, 02] +Raw bytes (241): 0x[01, 01, 1a, 05, 01, 05, 13, 01, 09, 05, 13, 01, 09, 0d, 01, 0d, 27, 01, 11, 0d, 27, 01, 11, 15, 01, 15, 33, 01, 19, 1d, 01, 1d, 47, 01, 21, 1d, 47, 01, 21, 25, 01, 25, 53, 01, 29, 25, 01, 2d, 01, 63, 2d, 01, 31, 2d, 01, 25, 01, 03, 01, 00, 0a, 01, 01, 09, 00, 10, 01, 00, 13, 00, 2e, 01, 02, 09, 00, 0e, 01, 00, 11, 00, 12, 05, 01, 0e, 00, 13, 02, 01, 0f, 00, 16, 09, 02, 11, 00, 19, 0e, 02, 12, 02, 0e, 0e, 04, 09, 00, 0e, 0d, 02, 0e, 00, 13, 16, 01, 0f, 00, 16, 22, 01, 16, 02, 0e, 11, 04, 11, 00, 19, 22, 03, 09, 00, 0e, 15, 02, 0e, 00, 13, 2a, 01, 0f, 00, 16, 19, 01, 15, 02, 0e, 2e, 04, 11, 00, 19, 19, 03, 09, 00, 0e, 1d, 02, 0e, 00, 13, 36, 01, 0c, 00, 13, 21, 01, 0d, 00, 15, 42, 01, 09, 00, 0a, 42, 01, 09, 00, 0e, 25, 02, 0e, 00, 13, 56, 01, 0f, 00, 16, 4e, 01, 16, 02, 0e, 29, 03, 12, 02, 0e, 56, 04, 09, 00, 0e, 2d, 02, 0e, 00, 13, 31, 01, 0f, 00, 16, 66, 01, 16, 02, 0e, 5e, 04, 11, 00, 16, 66, 03, 09, 00, 0e, 01, 02, 0d, 00, 0e, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 -Number of expressions: 22 +- file 0 => $DIR/continue.rs +Number of expressions: 26 - expression 0 operands: lhs = Counter(1), rhs = Counter(0) -- expression 1 operands: lhs = Counter(1), rhs = Expression(2, Add) +- expression 1 operands: lhs = Counter(1), rhs = Expression(4, Add) - expression 2 operands: lhs = Counter(0), rhs = Counter(2) -- expression 3 operands: lhs = Counter(3), rhs = Counter(0) -- expression 4 operands: lhs = Counter(3), rhs = Expression(7, Add) -- expression 5 operands: lhs = Counter(0), rhs = Counter(4) -- expression 6 operands: lhs = Counter(3), rhs = Expression(7, Add) +- expression 3 operands: lhs = Counter(1), rhs = Expression(4, Add) +- expression 4 operands: lhs = Counter(0), rhs = Counter(2) +- expression 5 operands: lhs = Counter(3), rhs = Counter(0) +- expression 6 operands: lhs = Counter(3), rhs = Expression(9, Add) - expression 7 operands: lhs = Counter(0), rhs = Counter(4) -- expression 8 operands: lhs = Counter(5), rhs = Counter(0) -- expression 9 operands: lhs = Counter(5), rhs = Expression(10, Add) -- expression 10 operands: lhs = Counter(0), rhs = Counter(6) -- expression 11 operands: lhs = Counter(7), rhs = Counter(0) -- expression 12 operands: lhs = Counter(7), rhs = Expression(13, Add) -- expression 13 operands: lhs = Counter(0), rhs = Counter(8) -- expression 14 operands: lhs = Counter(9), rhs = Counter(0) -- expression 15 operands: lhs = Counter(9), rhs = Expression(16, Add) -- expression 16 operands: lhs = Counter(0), rhs = Counter(10) -- expression 17 operands: lhs = Counter(9), rhs = Counter(0) -- expression 18 operands: lhs = Counter(11), rhs = Counter(0) -- expression 19 operands: lhs = Expression(20, Add), rhs = Counter(11) -- expression 20 operands: lhs = Counter(0), rhs = Counter(12) -- expression 21 operands: lhs = Counter(11), rhs = Counter(0) -Number of file 0 mappings: 30 -- Code(Counter(0)) at (prev + 3, 1) to (start + 3, 18) -- Code(Counter(1)) at (prev + 4, 14) to (start + 0, 19) +- expression 8 operands: lhs = Counter(3), rhs = Expression(9, Add) +- expression 9 operands: lhs = Counter(0), rhs = Counter(4) +- expression 10 operands: lhs = Counter(5), rhs = Counter(0) +- expression 11 operands: lhs = Counter(5), rhs = Expression(12, Add) +- expression 12 operands: lhs = Counter(0), rhs = Counter(6) +- expression 13 operands: lhs = Counter(7), rhs = Counter(0) +- expression 14 operands: lhs = Counter(7), rhs = Expression(17, Add) +- expression 15 operands: lhs = Counter(0), rhs = Counter(8) +- expression 16 operands: lhs = Counter(7), rhs = Expression(17, Add) +- expression 17 operands: lhs = Counter(0), rhs = Counter(8) +- expression 18 operands: lhs = Counter(9), rhs = Counter(0) +- expression 19 operands: lhs = Counter(9), rhs = Expression(20, Add) +- expression 20 operands: lhs = Counter(0), rhs = Counter(10) +- expression 21 operands: lhs = Counter(9), rhs = Counter(0) +- expression 22 operands: lhs = Counter(11), rhs = Counter(0) +- expression 23 operands: lhs = Expression(24, Add), rhs = Counter(11) +- expression 24 operands: lhs = Counter(0), rhs = Counter(12) +- expression 25 operands: lhs = Counter(11), rhs = Counter(0) +Number of file 0 mappings: 37 +- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 16) +- Code(Counter(0)) at (prev + 0, 19) to (start + 0, 46) +- Code(Counter(0)) at (prev + 2, 9) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 17) to (start + 0, 18) +- Code(Counter(1)) at (prev + 1, 14) to (start + 0, 19) - Code(Expression(0, Sub)) at (prev + 1, 15) to (start + 0, 22) = (c1 - c0) - Code(Counter(2)) at (prev + 2, 17) to (start + 0, 25) -- Code(Expression(1, Sub)) at (prev + 2, 18) to (start + 4, 14) +- Code(Expression(3, Sub)) at (prev + 2, 18) to (start + 2, 14) = (c1 - (c0 + c2)) -- Code(Counter(3)) at (prev + 6, 14) to (start + 0, 19) -- Code(Expression(3, Sub)) at (prev + 1, 15) to (start + 0, 22) +- Code(Expression(3, Sub)) at (prev + 4, 9) to (start + 0, 14) + = (c1 - (c0 + c2)) +- Code(Counter(3)) at (prev + 2, 14) to (start + 0, 19) +- Code(Expression(5, Sub)) at (prev + 1, 15) to (start + 0, 22) = (c3 - c0) -- Code(Expression(6, Sub)) at (prev + 1, 22) to (start + 2, 14) +- Code(Expression(8, Sub)) at (prev + 1, 22) to (start + 2, 14) = (c3 - (c0 + c4)) - Code(Counter(4)) at (prev + 4, 17) to (start + 0, 25) -- Code(Expression(6, Sub)) at (prev + 3, 9) to (start + 0, 14) +- Code(Expression(8, Sub)) at (prev + 3, 9) to (start + 0, 14) = (c3 - (c0 + c4)) - Code(Counter(5)) at (prev + 2, 14) to (start + 0, 19) -- Code(Expression(8, Sub)) at (prev + 1, 15) to (start + 0, 22) +- Code(Expression(10, Sub)) at (prev + 1, 15) to (start + 0, 22) = (c5 - c0) - Code(Counter(6)) at (prev + 1, 21) to (start + 2, 14) -- Code(Expression(9, Sub)) at (prev + 4, 17) to (start + 0, 25) +- Code(Expression(11, Sub)) at (prev + 4, 17) to (start + 0, 25) = (c5 - (c0 + c6)) - Code(Counter(6)) at (prev + 3, 9) to (start + 0, 14) - Code(Counter(7)) at (prev + 2, 14) to (start + 0, 19) -- Code(Expression(11, Sub)) at (prev + 1, 12) to (start + 0, 19) +- Code(Expression(13, Sub)) at (prev + 1, 12) to (start + 0, 19) = (c7 - c0) - Code(Counter(8)) at (prev + 1, 13) to (start + 0, 21) -- Code(Expression(12, Sub)) at (prev + 1, 10) to (start + 1, 14) +- Code(Expression(16, Sub)) at (prev + 1, 9) to (start + 0, 10) = (c7 - (c0 + c8)) -- Code(Counter(9)) at (prev + 3, 14) to (start + 0, 19) -- Code(Expression(17, Sub)) at (prev + 1, 15) to (start + 0, 22) +- Code(Expression(16, Sub)) at (prev + 1, 9) to (start + 0, 14) + = (c7 - (c0 + c8)) +- Code(Counter(9)) at (prev + 2, 14) to (start + 0, 19) +- Code(Expression(21, Sub)) at (prev + 1, 15) to (start + 0, 22) = (c9 - c0) -- Code(Expression(15, Sub)) at (prev + 1, 22) to (start + 2, 14) +- Code(Expression(19, Sub)) at (prev + 1, 22) to (start + 2, 14) = (c9 - (c0 + c10)) - Code(Counter(10)) at (prev + 3, 18) to (start + 2, 14) -- Code(Expression(17, Sub)) at (prev + 4, 9) to (start + 0, 14) +- Code(Expression(21, Sub)) at (prev + 4, 9) to (start + 0, 14) = (c9 - c0) - Code(Counter(11)) at (prev + 2, 14) to (start + 0, 19) - Code(Counter(12)) at (prev + 1, 15) to (start + 0, 22) -- Code(Expression(21, Sub)) at (prev + 1, 22) to (start + 2, 14) +- Code(Expression(25, Sub)) at (prev + 1, 22) to (start + 2, 14) = (c11 - c0) -- Code(Expression(19, Sub)) at (prev + 4, 17) to (start + 0, 22) +- Code(Expression(23, Sub)) at (prev + 4, 17) to (start + 0, 22) = ((c0 + c12) - c11) -- Code(Expression(21, Sub)) at (prev + 3, 9) to (start + 0, 14) +- Code(Expression(25, Sub)) at (prev + 3, 9) to (start + 0, 14) = (c11 - c0) -- Code(Counter(0)) at (prev + 2, 13) to (start + 1, 2) +- Code(Counter(0)) at (prev + 2, 13) to (start + 0, 14) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c12 diff --git a/tests/coverage/continue.coverage b/tests/coverage/continue.coverage index 4916cac0038e..17fe4874d151 100644 --- a/tests/coverage/continue.coverage +++ b/tests/coverage/continue.coverage @@ -2,7 +2,7 @@ LL| | LL| 1|fn main() { LL| 1| let is_true = std::env::args().len() == 1; - LL| 1| + LL| | LL| 1| let mut x = 0; LL| 11| for _ in 0..10 { LL| 10| match is_true { @@ -12,7 +12,7 @@ LL| 0| _ => { LL| 0| x = 1; LL| 0| } - LL| 0| } + LL| | } LL| 0| x = 3; LL| | } LL| 11| for _ in 0..10 { diff --git a/tests/coverage/coroutine.cov-map b/tests/coverage/coroutine.cov-map index fee32376d831..daa42915a4af 100644 --- a/tests/coverage/coroutine.cov-map +++ b/tests/coverage/coroutine.cov-map @@ -1,31 +1,40 @@ Function name: coroutine::get_u32 -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 0b, 01, 01, 0b, 05, 02, 09, 00, 0e, 02, 02, 09, 00, 28, 01, 02, 01, 00, 02] +Raw bytes (31): 0x[01, 01, 01, 01, 05, 05, 01, 0b, 01, 00, 2d, 01, 01, 08, 00, 0b, 05, 01, 09, 00, 0e, 02, 02, 09, 00, 28, 01, 02, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/coroutine.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 11, 1) to (start + 1, 11) -- Code(Counter(1)) at (prev + 2, 9) to (start + 0, 14) +Number of file 0 mappings: 5 +- Code(Counter(0)) at (prev + 11, 1) to (start + 0, 45) +- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 11) +- Code(Counter(1)) at (prev + 1, 9) to (start + 0, 14) - Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 40) = (c0 - c1) - Code(Counter(0)) at (prev + 2, 1) to (start + 0, 2) Highest counter ID seen: c1 Function name: coroutine::main -Raw bytes (53): 0x[01, 01, 02, 01, 05, 05, 09, 09, 01, 13, 01, 02, 16, 01, 08, 0b, 00, 2d, 05, 01, 2b, 00, 2d, 02, 01, 0e, 00, 14, 05, 02, 0b, 00, 2e, 0d, 01, 22, 00, 27, 09, 00, 2c, 00, 2e, 06, 01, 0e, 00, 14, 09, 02, 01, 00, 02] +Raw bytes (93): 0x[01, 01, 02, 01, 05, 05, 09, 11, 01, 13, 01, 00, 0a, 01, 01, 09, 00, 10, 01, 00, 13, 00, 2e, 01, 01, 09, 00, 16, 01, 06, 0b, 00, 13, 01, 00, 14, 00, 22, 01, 00, 24, 00, 2a, 01, 00, 2b, 00, 2d, 05, 01, 2b, 00, 2d, 02, 01, 0e, 00, 14, 05, 02, 0b, 00, 13, 05, 00, 0b, 00, 2e, 05, 00, 14, 00, 22, 0d, 01, 22, 00, 27, 09, 00, 2c, 00, 2e, 06, 01, 0e, 00, 14, 09, 02, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/coroutine.rs Number of expressions: 2 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Counter(2) -Number of file 0 mappings: 9 -- Code(Counter(0)) at (prev + 19, 1) to (start + 2, 22) -- Code(Counter(0)) at (prev + 8, 11) to (start + 0, 45) +Number of file 0 mappings: 17 +- Code(Counter(0)) at (prev + 19, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 16) +- Code(Counter(0)) at (prev + 0, 19) to (start + 0, 46) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 22) +- Code(Counter(0)) at (prev + 6, 11) to (start + 0, 19) +- Code(Counter(0)) at (prev + 0, 20) to (start + 0, 34) +- Code(Counter(0)) at (prev + 0, 36) to (start + 0, 42) +- Code(Counter(0)) at (prev + 0, 43) to (start + 0, 45) - Code(Counter(1)) at (prev + 1, 43) to (start + 0, 45) - Code(Expression(0, Sub)) at (prev + 1, 14) to (start + 0, 20) = (c0 - c1) -- Code(Counter(1)) at (prev + 2, 11) to (start + 0, 46) +- Code(Counter(1)) at (prev + 2, 11) to (start + 0, 19) +- Code(Counter(1)) at (prev + 0, 11) to (start + 0, 46) +- Code(Counter(1)) at (prev + 0, 20) to (start + 0, 34) - Code(Counter(3)) at (prev + 1, 34) to (start + 0, 39) - Code(Counter(2)) at (prev + 0, 44) to (start + 0, 46) - Code(Expression(1, Sub)) at (prev + 1, 14) to (start + 0, 20) @@ -34,12 +43,14 @@ Number of file 0 mappings: 9 Highest counter ID seen: c3 Function name: coroutine::main::{closure#0} -Raw bytes (14): 0x[01, 01, 00, 02, 01, 16, 08, 01, 1f, 05, 02, 10, 01, 06] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 16, 08, 00, 09, 01, 01, 09, 00, 1f, 05, 01, 10, 00, 15, 05, 01, 05, 00, 06] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/coroutine.rs Number of expressions: 0 -Number of file 0 mappings: 2 -- Code(Counter(0)) at (prev + 22, 8) to (start + 1, 31) -- Code(Counter(1)) at (prev + 2, 16) to (start + 1, 6) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 22, 8) to (start + 0, 9) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 31) +- Code(Counter(1)) at (prev + 1, 16) to (start + 0, 21) +- Code(Counter(1)) at (prev + 1, 5) to (start + 0, 6) Highest counter ID seen: c1 diff --git a/tests/coverage/coverage_attr_closure.cov-map b/tests/coverage/coverage_attr_closure.cov-map index fb861996a0d2..deba65f22cca 100644 --- a/tests/coverage/coverage_attr_closure.cov-map +++ b/tests/coverage/coverage_attr_closure.cov-map @@ -1,38 +1,48 @@ Function name: coverage_attr_closure::GLOBAL_CLOSURE_ON::{closure#0} -Raw bytes (9): 0x[01, 01, 00, 01, 01, 06, 0f, 02, 02] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 06, 0f, 00, 10, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 17, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/coverage_attr_closure.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 6, 15) to (start + 2, 2) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 6, 15) to (start + 0, 16) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 23) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: coverage_attr_closure::contains_closures_off::{closure#0} (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 1d, 13, 02, 06] +Raw bytes (24): 0x[01, 01, 00, 04, 00, 1d, 13, 00, 14, 00, 01, 09, 00, 11, 00, 00, 12, 00, 1b, 00, 01, 05, 00, 06] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/coverage_attr_closure.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 29, 19) to (start + 2, 6) +Number of file 0 mappings: 4 +- Code(Zero) at (prev + 29, 19) to (start + 0, 20) +- Code(Zero) at (prev + 1, 9) to (start + 0, 17) +- Code(Zero) at (prev + 0, 18) to (start + 0, 27) +- Code(Zero) at (prev + 1, 5) to (start + 0, 6) Highest counter ID seen: (none) Function name: coverage_attr_closure::contains_closures_on -Raw bytes (19): 0x[01, 01, 00, 03, 01, 0f, 01, 01, 1a, 01, 05, 09, 00, 1b, 01, 04, 01, 00, 02] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 0f, 01, 00, 1a, 01, 01, 09, 00, 1a, 01, 04, 09, 00, 1b, 01, 04, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/coverage_attr_closure.rs Number of expressions: 0 -Number of file 0 mappings: 3 -- Code(Counter(0)) at (prev + 15, 1) to (start + 1, 26) -- Code(Counter(0)) at (prev + 5, 9) to (start + 0, 27) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 15, 1) to (start + 0, 26) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 26) +- Code(Counter(0)) at (prev + 4, 9) to (start + 0, 27) - Code(Counter(0)) at (prev + 4, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: coverage_attr_closure::contains_closures_on::{closure#0} (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 11, 13, 02, 06] +Raw bytes (24): 0x[01, 01, 00, 04, 00, 11, 13, 00, 14, 00, 01, 09, 00, 11, 00, 00, 12, 00, 1b, 00, 01, 05, 00, 06] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/coverage_attr_closure.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 17, 19) to (start + 2, 6) +Number of file 0 mappings: 4 +- Code(Zero) at (prev + 17, 19) to (start + 0, 20) +- Code(Zero) at (prev + 1, 9) to (start + 0, 17) +- Code(Zero) at (prev + 0, 18) to (start + 0, 27) +- Code(Zero) at (prev + 1, 5) to (start + 0, 6) Highest counter ID seen: (none) diff --git a/tests/coverage/dead_code.cov-map b/tests/coverage/dead_code.cov-map index 897372fe0b5e..ae4146dc2467 100644 --- a/tests/coverage/dead_code.cov-map +++ b/tests/coverage/dead_code.cov-map @@ -1,37 +1,52 @@ Function name: dead_code::main -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 1b, 01, 07, 0f, 05, 07, 10, 02, 06, 02, 02, 05, 00, 06, 01, 01, 01, 00, 02] +Raw bytes (51): 0x[01, 01, 01, 01, 05, 09, 01, 1b, 01, 00, 0a, 01, 04, 09, 00, 10, 01, 00, 13, 00, 2e, 01, 02, 09, 00, 16, 01, 00, 19, 00, 1a, 01, 01, 08, 00, 0f, 05, 00, 10, 02, 06, 02, 02, 05, 00, 06, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/dead_code.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 27, 1) to (start + 7, 15) -- Code(Counter(1)) at (prev + 7, 16) to (start + 2, 6) +Number of file 0 mappings: 9 +- Code(Counter(0)) at (prev + 27, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 4, 9) to (start + 0, 16) +- Code(Counter(0)) at (prev + 0, 19) to (start + 0, 46) +- Code(Counter(0)) at (prev + 2, 9) to (start + 0, 22) +- Code(Counter(0)) at (prev + 0, 25) to (start + 0, 26) +- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 15) +- Code(Counter(1)) at (prev + 0, 16) to (start + 2, 6) - Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 0, 6) = (c0 - c1) - Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c1 Function name: dead_code::unused_fn (unused) -Raw bytes (24): 0x[01, 01, 00, 04, 00, 0f, 01, 07, 0f, 00, 07, 10, 02, 06, 00, 02, 05, 00, 06, 00, 01, 01, 00, 02] +Raw bytes (49): 0x[01, 01, 00, 09, 00, 0f, 01, 00, 0f, 00, 04, 09, 00, 10, 00, 00, 13, 00, 2e, 00, 02, 09, 00, 16, 00, 00, 19, 00, 1a, 00, 01, 08, 00, 0f, 00, 00, 10, 02, 06, 00, 02, 05, 00, 06, 00, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/dead_code.rs Number of expressions: 0 -Number of file 0 mappings: 4 -- Code(Zero) at (prev + 15, 1) to (start + 7, 15) -- Code(Zero) at (prev + 7, 16) to (start + 2, 6) +Number of file 0 mappings: 9 +- Code(Zero) at (prev + 15, 1) to (start + 0, 15) +- Code(Zero) at (prev + 4, 9) to (start + 0, 16) +- Code(Zero) at (prev + 0, 19) to (start + 0, 46) +- Code(Zero) at (prev + 2, 9) to (start + 0, 22) +- Code(Zero) at (prev + 0, 25) to (start + 0, 26) +- Code(Zero) at (prev + 1, 8) to (start + 0, 15) +- Code(Zero) at (prev + 0, 16) to (start + 2, 6) - Code(Zero) at (prev + 2, 5) to (start + 0, 6) - Code(Zero) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: (none) Function name: dead_code::unused_pub_fn_not_in_library (unused) -Raw bytes (24): 0x[01, 01, 00, 04, 00, 03, 01, 07, 0f, 00, 07, 10, 02, 06, 00, 02, 05, 00, 06, 00, 01, 01, 00, 02] +Raw bytes (49): 0x[01, 01, 00, 09, 00, 03, 01, 00, 26, 00, 04, 09, 00, 10, 00, 00, 13, 00, 2e, 00, 02, 09, 00, 16, 00, 00, 19, 00, 1a, 00, 01, 08, 00, 0f, 00, 00, 10, 02, 06, 00, 02, 05, 00, 06, 00, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/dead_code.rs Number of expressions: 0 -Number of file 0 mappings: 4 -- Code(Zero) at (prev + 3, 1) to (start + 7, 15) -- Code(Zero) at (prev + 7, 16) to (start + 2, 6) +Number of file 0 mappings: 9 +- Code(Zero) at (prev + 3, 1) to (start + 0, 38) +- Code(Zero) at (prev + 4, 9) to (start + 0, 16) +- Code(Zero) at (prev + 0, 19) to (start + 0, 46) +- Code(Zero) at (prev + 2, 9) to (start + 0, 22) +- Code(Zero) at (prev + 0, 25) to (start + 0, 26) +- Code(Zero) at (prev + 1, 8) to (start + 0, 15) +- Code(Zero) at (prev + 0, 16) to (start + 2, 6) - Code(Zero) at (prev + 2, 5) to (start + 0, 6) - Code(Zero) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: (none) diff --git a/tests/coverage/dead_code.coverage b/tests/coverage/dead_code.coverage index 55d196f81604..fbb4a001d959 100644 --- a/tests/coverage/dead_code.coverage +++ b/tests/coverage/dead_code.coverage @@ -1,11 +1,11 @@ LL| |#![allow(dead_code, unused_assignments, unused_variables)] LL| | LL| 0|pub fn unused_pub_fn_not_in_library() { - LL| 0| // Initialize test constants in a way that cannot be determined at compile time, to ensure - LL| 0| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - LL| 0| // dependent conditions. + LL| | // Initialize test constants in a way that cannot be determined at compile time, to ensure + LL| | // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + LL| | // dependent conditions. LL| 0| let is_true = std::env::args().len() == 1; - LL| 0| + LL| | LL| 0| let mut countdown = 0; LL| 0| if is_true { LL| 0| countdown = 10; @@ -13,11 +13,11 @@ LL| 0|} LL| | LL| 0|fn unused_fn() { - LL| 0| // Initialize test constants in a way that cannot be determined at compile time, to ensure - LL| 0| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - LL| 0| // dependent conditions. + LL| | // Initialize test constants in a way that cannot be determined at compile time, to ensure + LL| | // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + LL| | // dependent conditions. LL| 0| let is_true = std::env::args().len() == 1; - LL| 0| + LL| | LL| 0| let mut countdown = 0; LL| 0| if is_true { LL| 0| countdown = 10; @@ -25,11 +25,11 @@ LL| 0|} LL| | LL| 1|fn main() { - LL| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure - LL| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - LL| 1| // dependent conditions. + LL| | // Initialize test constants in a way that cannot be determined at compile time, to ensure + LL| | // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + LL| | // dependent conditions. LL| 1| let is_true = std::env::args().len() == 1; - LL| 1| + LL| | LL| 1| let mut countdown = 0; LL| 1| if is_true { LL| 1| countdown = 10; diff --git a/tests/coverage/drop_trait.cov-map b/tests/coverage/drop_trait.cov-map index 16facf2eddf2..dcf9dbd8c647 100644 --- a/tests/coverage/drop_trait.cov-map +++ b/tests/coverage/drop_trait.cov-map @@ -1,21 +1,33 @@ Function name: ::drop -Raw bytes (9): 0x[01, 01, 00, 01, 01, 09, 05, 02, 06] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 09, 05, 00, 17, 01, 01, 09, 00, 11, 01, 00, 12, 00, 24, 01, 01, 05, 00, 06] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/drop_trait.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 9, 5) to (start + 2, 6) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 9, 5) to (start + 0, 23) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 17) +- Code(Counter(0)) at (prev + 0, 18) to (start + 0, 36) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 6) Highest counter ID seen: c0 Function name: drop_trait::main -Raw bytes (24): 0x[01, 01, 00, 04, 01, 0e, 01, 05, 0c, 01, 06, 09, 01, 16, 00, 02, 06, 04, 0b, 01, 05, 01, 00, 02] +Raw bytes (69): 0x[01, 01, 00, 0d, 01, 0e, 01, 00, 1c, 01, 01, 09, 00, 15, 01, 00, 18, 00, 30, 01, 02, 09, 00, 0d, 01, 00, 10, 00, 2a, 01, 02, 08, 00, 0c, 01, 01, 09, 00, 11, 01, 00, 12, 00, 29, 01, 01, 10, 00, 16, 00, 01, 05, 00, 06, 00, 02, 0d, 00, 28, 00, 02, 05, 00, 0b, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/drop_trait.rs Number of expressions: 0 -Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 14, 1) to (start + 5, 12) -- Code(Counter(0)) at (prev + 6, 9) to (start + 1, 22) -- Code(Zero) at (prev + 2, 6) to (start + 4, 11) -- Code(Counter(0)) at (prev + 5, 1) to (start + 0, 2) +Number of file 0 mappings: 13 +- Code(Counter(0)) at (prev + 14, 1) to (start + 0, 28) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 21) +- Code(Counter(0)) at (prev + 0, 24) to (start + 0, 48) +- Code(Counter(0)) at (prev + 2, 9) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 16) to (start + 0, 42) +- Code(Counter(0)) at (prev + 2, 8) to (start + 0, 12) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 17) +- Code(Counter(0)) at (prev + 0, 18) to (start + 0, 41) +- Code(Counter(0)) at (prev + 1, 16) to (start + 0, 22) +- Code(Zero) at (prev + 1, 5) to (start + 0, 6) +- Code(Zero) at (prev + 2, 13) to (start + 0, 40) +- Code(Zero) at (prev + 2, 5) to (start + 0, 11) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 diff --git a/tests/coverage/drop_trait.coverage b/tests/coverage/drop_trait.coverage index 85d557573cf3..10ed8c0f154f 100644 --- a/tests/coverage/drop_trait.coverage +++ b/tests/coverage/drop_trait.coverage @@ -13,16 +13,16 @@ LL| | LL| 1|fn main() -> Result<(), u8> { LL| 1| let _firecracker = Firework { strength: 1 }; - LL| 1| + LL| | LL| 1| let _tnt = Firework { strength: 100 }; - LL| 1| + LL| | LL| 1| if true { LL| 1| println!("Exiting with error..."); LL| 1| return Err(1); LL| 0| } - LL| 0| + LL| | LL| 0| let _ = Firework { strength: 1000 }; - LL| 0| + LL| | LL| 0| Ok(()) LL| 1|} LL| | diff --git a/tests/coverage/fn_sig_into_try.cov-map b/tests/coverage/fn_sig_into_try.cov-map index 6d6034928c9a..fc57a4892be4 100644 --- a/tests/coverage/fn_sig_into_try.cov-map +++ b/tests/coverage/fn_sig_into_try.cov-map @@ -1,44 +1,52 @@ Function name: fn_sig_into_try::a -Raw bytes (9): 0x[01, 01, 00, 01, 01, 0a, 01, 05, 02] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 0a, 01, 00, 16, 01, 03, 05, 00, 0f, 01, 01, 05, 00, 0c, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/fn_sig_into_try.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 10, 1) to (start + 5, 2) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 10, 1) to (start + 0, 22) +- Code(Counter(0)) at (prev + 3, 5) to (start + 0, 15) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 12) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: fn_sig_into_try::b -Raw bytes (24): 0x[01, 01, 00, 04, 01, 11, 01, 03, 0f, 00, 03, 0f, 00, 10, 01, 01, 05, 00, 0c, 01, 01, 01, 00, 02] +Raw bytes (29): 0x[01, 01, 00, 05, 01, 11, 01, 00, 16, 01, 03, 05, 00, 0f, 00, 00, 0f, 00, 10, 01, 01, 05, 00, 0c, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/fn_sig_into_try.rs Number of expressions: 0 -Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 17, 1) to (start + 3, 15) -- Code(Zero) at (prev + 3, 15) to (start + 0, 16) +Number of file 0 mappings: 5 +- Code(Counter(0)) at (prev + 17, 1) to (start + 0, 22) +- Code(Counter(0)) at (prev + 3, 5) to (start + 0, 15) +- Code(Zero) at (prev + 0, 15) to (start + 0, 16) - Code(Counter(0)) at (prev + 1, 5) to (start + 0, 12) - Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: fn_sig_into_try::c -Raw bytes (24): 0x[01, 01, 00, 04, 01, 18, 01, 03, 17, 00, 03, 17, 00, 18, 01, 01, 05, 00, 0c, 01, 01, 01, 00, 02] +Raw bytes (29): 0x[01, 01, 00, 05, 01, 18, 01, 00, 16, 01, 03, 0d, 00, 17, 00, 00, 17, 00, 18, 01, 01, 05, 00, 0c, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/fn_sig_into_try.rs Number of expressions: 0 -Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 24, 1) to (start + 3, 23) -- Code(Zero) at (prev + 3, 23) to (start + 0, 24) +Number of file 0 mappings: 5 +- Code(Counter(0)) at (prev + 24, 1) to (start + 0, 22) +- Code(Counter(0)) at (prev + 3, 13) to (start + 0, 23) +- Code(Zero) at (prev + 0, 23) to (start + 0, 24) - Code(Counter(0)) at (prev + 1, 5) to (start + 0, 12) - Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: fn_sig_into_try::d -Raw bytes (24): 0x[01, 01, 00, 04, 01, 1f, 01, 04, 0f, 00, 04, 0f, 00, 10, 01, 01, 05, 00, 0c, 01, 01, 01, 00, 02] +Raw bytes (39): 0x[01, 01, 00, 07, 01, 1f, 01, 00, 16, 01, 03, 0c, 00, 0e, 01, 00, 11, 00, 13, 01, 01, 05, 00, 0f, 00, 00, 0f, 00, 10, 01, 01, 05, 00, 0c, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/fn_sig_into_try.rs Number of expressions: 0 -Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 31, 1) to (start + 4, 15) -- Code(Zero) at (prev + 4, 15) to (start + 0, 16) +Number of file 0 mappings: 7 +- Code(Counter(0)) at (prev + 31, 1) to (start + 0, 22) +- Code(Counter(0)) at (prev + 3, 12) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 17) to (start + 0, 19) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 15) +- Code(Zero) at (prev + 0, 15) to (start + 0, 16) - Code(Counter(0)) at (prev + 1, 5) to (start + 0, 12) - Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 diff --git a/tests/coverage/fn_sig_into_try.coverage b/tests/coverage/fn_sig_into_try.coverage index cabe747ce5ac..bc744db4b69c 100644 --- a/tests/coverage/fn_sig_into_try.coverage +++ b/tests/coverage/fn_sig_into_try.coverage @@ -8,31 +8,31 @@ LL| |// signature should be handled in the same way. LL| | LL| 1|fn a() -> Option - LL| 1|// - LL| 1|{ + LL| |// + LL| |{ LL| 1| Some(7i32); LL| 1| Some(0) LL| 1|} LL| | LL| 1|fn b() -> Option - LL| 1|// - LL| 1|{ + LL| |// + LL| |{ LL| 1| Some(7i32)?; ^0 LL| 1| Some(0) LL| 1|} LL| | LL| 1|fn c() -> Option - LL| 1|// - LL| 1|{ + LL| |// + LL| |{ LL| 1| let _ = Some(7i32)?; ^0 LL| 1| Some(0) LL| 1|} LL| | LL| 1|fn d() -> Option - LL| 1|// - LL| 1|{ + LL| |// + LL| |{ LL| 1| let _: () = (); LL| 1| Some(7i32)?; ^0 diff --git a/tests/coverage/generic-unused-impl.cov-map b/tests/coverage/generic-unused-impl.cov-map index 5878de231bad..da9e5495a72b 100644 --- a/tests/coverage/generic-unused-impl.cov-map +++ b/tests/coverage/generic-unused-impl.cov-map @@ -1,18 +1,23 @@ Function name: as core::convert::From<[<_ as generic_unused_impl::Foo>::Assoc; 1]>>::from (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 0b, 05, 03, 06] +Raw bytes (29): 0x[01, 01, 00, 05, 00, 0b, 05, 00, 29, 00, 01, 0e, 00, 12, 00, 00, 16, 00, 1a, 00, 01, 09, 00, 1b, 00, 01, 05, 00, 06] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/generic-unused-impl.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 11, 5) to (start + 3, 6) +Number of file 0 mappings: 5 +- Code(Zero) at (prev + 11, 5) to (start + 0, 41) +- Code(Zero) at (prev + 1, 14) to (start + 0, 18) +- Code(Zero) at (prev + 0, 22) to (start + 0, 26) +- Code(Zero) at (prev + 1, 9) to (start + 0, 27) +- Code(Zero) at (prev + 1, 5) to (start + 0, 6) Highest counter ID seen: (none) Function name: generic_unused_impl::main -Raw bytes (9): 0x[01, 01, 00, 01, 01, 11, 01, 00, 0d] +Raw bytes (14): 0x[01, 01, 00, 02, 01, 11, 01, 00, 0a, 01, 00, 0c, 00, 0d] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/generic-unused-impl.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 17, 1) to (start + 0, 13) +Number of file 0 mappings: 2 +- Code(Counter(0)) at (prev + 17, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 0, 12) to (start + 0, 13) Highest counter ID seen: c0 diff --git a/tests/coverage/generics.cov-map b/tests/coverage/generics.cov-map index bc5661afdc19..7f9b7ee0f471 100644 --- a/tests/coverage/generics.cov-map +++ b/tests/coverage/generics.cov-map @@ -1,48 +1,73 @@ Function name: as core::ops::drop::Drop>::drop -Raw bytes (9): 0x[01, 01, 00, 01, 01, 11, 05, 02, 06] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 11, 05, 00, 17, 01, 01, 09, 00, 11, 01, 00, 12, 00, 24, 01, 01, 05, 00, 06] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/generics.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 17, 5) to (start + 2, 6) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 17, 5) to (start + 0, 23) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 17) +- Code(Counter(0)) at (prev + 0, 18) to (start + 0, 36) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 6) Highest counter ID seen: c0 Function name: >::set_strength -Raw bytes (9): 0x[01, 01, 00, 01, 01, 0a, 05, 02, 06] +Raw bytes (19): 0x[01, 01, 00, 03, 01, 0a, 05, 00, 30, 01, 01, 09, 00, 25, 01, 01, 05, 00, 06] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/generics.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 10, 5) to (start + 2, 6) +Number of file 0 mappings: 3 +- Code(Counter(0)) at (prev + 10, 5) to (start + 0, 48) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 37) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 6) Highest counter ID seen: c0 Function name: as core::ops::drop::Drop>::drop -Raw bytes (9): 0x[01, 01, 00, 01, 01, 11, 05, 02, 06] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 11, 05, 00, 17, 01, 01, 09, 00, 11, 01, 00, 12, 00, 24, 01, 01, 05, 00, 06] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/generics.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 17, 5) to (start + 2, 6) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 17, 5) to (start + 0, 23) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 17) +- Code(Counter(0)) at (prev + 0, 18) to (start + 0, 36) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 6) Highest counter ID seen: c0 Function name: >::set_strength -Raw bytes (9): 0x[01, 01, 00, 01, 01, 0a, 05, 02, 06] +Raw bytes (19): 0x[01, 01, 00, 03, 01, 0a, 05, 00, 30, 01, 01, 09, 00, 25, 01, 01, 05, 00, 06] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/generics.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 10, 5) to (start + 2, 6) +Number of file 0 mappings: 3 +- Code(Counter(0)) at (prev + 10, 5) to (start + 0, 48) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 37) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 6) Highest counter ID seen: c0 Function name: generics::main -Raw bytes (24): 0x[01, 01, 00, 04, 01, 16, 01, 08, 0c, 01, 09, 09, 01, 16, 00, 02, 06, 04, 0b, 01, 05, 01, 00, 02] +Raw bytes (99): 0x[01, 01, 00, 13, 01, 16, 01, 00, 1c, 01, 01, 09, 00, 18, 01, 00, 1b, 00, 33, 01, 01, 05, 00, 10, 01, 00, 11, 00, 1d, 01, 02, 09, 00, 10, 01, 00, 13, 00, 2f, 01, 01, 05, 00, 08, 01, 00, 09, 00, 15, 01, 01, 05, 00, 08, 01, 00, 09, 00, 15, 01, 02, 08, 00, 0c, 01, 01, 09, 00, 11, 01, 00, 12, 00, 29, 01, 01, 10, 00, 16, 00, 01, 05, 00, 06, 00, 02, 0d, 00, 28, 00, 02, 05, 00, 0b, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/generics.rs Number of expressions: 0 -Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 22, 1) to (start + 8, 12) -- Code(Counter(0)) at (prev + 9, 9) to (start + 1, 22) -- Code(Zero) at (prev + 2, 6) to (start + 4, 11) -- Code(Counter(0)) at (prev + 5, 1) to (start + 0, 2) +Number of file 0 mappings: 19 +- Code(Counter(0)) at (prev + 22, 1) to (start + 0, 28) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 24) +- Code(Counter(0)) at (prev + 0, 27) to (start + 0, 51) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 16) +- Code(Counter(0)) at (prev + 0, 17) to (start + 0, 29) +- Code(Counter(0)) at (prev + 2, 9) to (start + 0, 16) +- Code(Counter(0)) at (prev + 0, 19) to (start + 0, 47) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 8) +- Code(Counter(0)) at (prev + 0, 9) to (start + 0, 21) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 8) +- Code(Counter(0)) at (prev + 0, 9) to (start + 0, 21) +- Code(Counter(0)) at (prev + 2, 8) to (start + 0, 12) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 17) +- Code(Counter(0)) at (prev + 0, 18) to (start + 0, 41) +- Code(Counter(0)) at (prev + 1, 16) to (start + 0, 22) +- Code(Zero) at (prev + 1, 5) to (start + 0, 6) +- Code(Zero) at (prev + 2, 13) to (start + 0, 40) +- Code(Zero) at (prev + 2, 5) to (start + 0, 11) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 diff --git a/tests/coverage/generics.coverage b/tests/coverage/generics.coverage index a2cd1465d26f..43697cacb9a5 100644 --- a/tests/coverage/generics.coverage +++ b/tests/coverage/generics.coverage @@ -44,18 +44,18 @@ LL| 1|fn main() -> Result<(), u8> { LL| 1| let mut firecracker = Firework { strength: 1 }; LL| 1| firecracker.set_strength(2); - LL| 1| + LL| | LL| 1| let mut tnt = Firework { strength: 100.1 }; LL| 1| tnt.set_strength(200.1); LL| 1| tnt.set_strength(300.3); - LL| 1| + LL| | LL| 1| if true { LL| 1| println!("Exiting with error..."); LL| 1| return Err(1); LL| 0| } - LL| 0| + LL| | LL| 0| let _ = Firework { strength: 1000 }; - LL| 0| + LL| | LL| 0| Ok(()) LL| 1|} LL| | diff --git a/tests/coverage/holes.cov-map b/tests/coverage/holes.cov-map index 6e2d243e8dd2..c2158c441506 100644 --- a/tests/coverage/holes.cov-map +++ b/tests/coverage/holes.cov-map @@ -1,57 +1,81 @@ Function name: ::_method (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 2b, 09, 00, 1d] +Raw bytes (14): 0x[01, 01, 00, 02, 00, 2b, 09, 00, 1a, 00, 00, 1c, 00, 1d] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/holes.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 43, 9) to (start + 0, 29) +Number of file 0 mappings: 2 +- Code(Zero) at (prev + 43, 9) to (start + 0, 26) +- Code(Zero) at (prev + 0, 28) to (start + 0, 29) Highest counter ID seen: (none) Function name: holes::main -Raw bytes (69): 0x[01, 01, 00, 0d, 01, 08, 01, 01, 11, 01, 05, 05, 00, 11, 01, 07, 09, 00, 11, 01, 09, 05, 00, 11, 01, 04, 05, 00, 11, 01, 07, 05, 00, 11, 01, 06, 05, 00, 11, 01, 04, 05, 00, 11, 01, 04, 05, 00, 11, 01, 06, 05, 03, 0f, 01, 0a, 05, 03, 0f, 01, 0a, 05, 06, 27, 01, 13, 05, 01, 02] +Raw bytes (154): 0x[01, 01, 00, 1e, 01, 08, 01, 00, 0a, 01, 01, 05, 00, 0e, 01, 00, 0f, 00, 11, 01, 04, 05, 00, 0e, 01, 00, 0f, 00, 11, 01, 07, 09, 00, 11, 01, 09, 05, 00, 0e, 01, 00, 0f, 00, 11, 01, 04, 05, 00, 0e, 01, 00, 0f, 00, 11, 01, 07, 05, 00, 0e, 01, 00, 0f, 00, 11, 01, 06, 05, 00, 0e, 01, 00, 0f, 00, 11, 01, 04, 05, 00, 0e, 01, 00, 0f, 00, 11, 01, 04, 05, 00, 0e, 01, 00, 0f, 00, 11, 01, 06, 05, 00, 0e, 01, 00, 0f, 00, 11, 01, 03, 09, 00, 0f, 01, 07, 05, 00, 0e, 01, 00, 0f, 00, 11, 01, 03, 09, 00, 0f, 01, 07, 05, 00, 0e, 01, 00, 0f, 00, 11, 01, 06, 09, 00, 27, 01, 0d, 05, 00, 0e, 01, 00, 0f, 00, 11, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/holes.rs Number of expressions: 0 -Number of file 0 mappings: 13 -- Code(Counter(0)) at (prev + 8, 1) to (start + 1, 17) -- Code(Counter(0)) at (prev + 5, 5) to (start + 0, 17) +Number of file 0 mappings: 30 +- Code(Counter(0)) at (prev + 8, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 17) +- Code(Counter(0)) at (prev + 4, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 17) - Code(Counter(0)) at (prev + 7, 9) to (start + 0, 17) -- Code(Counter(0)) at (prev + 9, 5) to (start + 0, 17) -- Code(Counter(0)) at (prev + 4, 5) to (start + 0, 17) -- Code(Counter(0)) at (prev + 7, 5) to (start + 0, 17) -- Code(Counter(0)) at (prev + 6, 5) to (start + 0, 17) -- Code(Counter(0)) at (prev + 4, 5) to (start + 0, 17) -- Code(Counter(0)) at (prev + 4, 5) to (start + 0, 17) -- Code(Counter(0)) at (prev + 6, 5) to (start + 3, 15) -- Code(Counter(0)) at (prev + 10, 5) to (start + 3, 15) -- Code(Counter(0)) at (prev + 10, 5) to (start + 6, 39) -- Code(Counter(0)) at (prev + 19, 5) to (start + 1, 2) +- Code(Counter(0)) at (prev + 9, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 17) +- Code(Counter(0)) at (prev + 4, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 17) +- Code(Counter(0)) at (prev + 7, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 17) +- Code(Counter(0)) at (prev + 6, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 17) +- Code(Counter(0)) at (prev + 4, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 17) +- Code(Counter(0)) at (prev + 4, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 17) +- Code(Counter(0)) at (prev + 6, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 17) +- Code(Counter(0)) at (prev + 3, 9) to (start + 0, 15) +- Code(Counter(0)) at (prev + 7, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 17) +- Code(Counter(0)) at (prev + 3, 9) to (start + 0, 15) +- Code(Counter(0)) at (prev + 7, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 17) +- Code(Counter(0)) at (prev + 6, 9) to (start + 0, 39) +- Code(Counter(0)) at (prev + 13, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 17) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: holes::main::_unused_fn (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 1f, 05, 00, 17] +Raw bytes (14): 0x[01, 01, 00, 02, 00, 1f, 05, 00, 14, 00, 00, 16, 00, 17] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/holes.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 31, 5) to (start + 0, 23) +Number of file 0 mappings: 2 +- Code(Zero) at (prev + 31, 5) to (start + 0, 20) +- Code(Zero) at (prev + 0, 22) to (start + 0, 23) Highest counter ID seen: (none) Function name: holes::main::{closure#0} (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 18, 09, 02, 0a] +Raw bytes (24): 0x[01, 01, 00, 04, 00, 18, 09, 00, 0a, 00, 01, 0d, 00, 16, 00, 00, 17, 00, 19, 00, 01, 09, 00, 0a] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/holes.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 24, 9) to (start + 2, 10) +Number of file 0 mappings: 4 +- Code(Zero) at (prev + 24, 9) to (start + 0, 10) +- Code(Zero) at (prev + 1, 13) to (start + 0, 22) +- Code(Zero) at (prev + 0, 23) to (start + 0, 25) +- Code(Zero) at (prev + 1, 9) to (start + 0, 10) Highest counter ID seen: (none) Function name: holes::main::{closure#1} (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 4b, 09, 02, 0a] +Raw bytes (19): 0x[01, 01, 00, 03, 00, 4b, 09, 00, 0a, 00, 01, 0d, 00, 12, 00, 01, 09, 00, 0a] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/holes.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 75, 9) to (start + 2, 10) +Number of file 0 mappings: 3 +- Code(Zero) at (prev + 75, 9) to (start + 0, 10) +- Code(Zero) at (prev + 1, 13) to (start + 0, 18) +- Code(Zero) at (prev + 1, 9) to (start + 0, 10) Highest counter ID seen: (none) diff --git a/tests/coverage/holes.coverage b/tests/coverage/holes.coverage index a6a02f1b9d08..1ea60491800d 100644 --- a/tests/coverage/holes.coverage +++ b/tests/coverage/holes.coverage @@ -58,8 +58,8 @@ LL| | } LL| | LL| 1| black_box(()); - LL| 1| - LL| 1| #[rustfmt::skip] + LL| | + LL| | #[rustfmt::skip] LL| 1| let _const = LL| | const LL| | { @@ -68,8 +68,8 @@ LL| | ; LL| | LL| 1| black_box(()); - LL| 1| - LL| 1| #[rustfmt::skip] + LL| | + LL| | #[rustfmt::skip] LL| 1| let _async = LL| | async LL| 0| { @@ -78,11 +78,11 @@ LL| | ; LL| | LL| 1| black_box(()); - LL| 1| - LL| 1| // This tests the edge case of a const block nested inside an "anon const", - LL| 1| // such as the length of an array literal. Handling this case requires - LL| 1| // `nested_filter::OnlyBodies` or equivalent. - LL| 1| #[rustfmt::skip] + LL| | + LL| | // This tests the edge case of a const block nested inside an "anon const", + LL| | // such as the length of an array literal. Handling this case requires + LL| | // `nested_filter::OnlyBodies` or equivalent. + LL| | #[rustfmt::skip] LL| 1| let _const_block_inside_anon_const = LL| | [ LL| | 0 diff --git a/tests/coverage/if.cov-map b/tests/coverage/if.cov-map index a77ba8194a44..044c0f2ba089 100644 --- a/tests/coverage/if.cov-map +++ b/tests/coverage/if.cov-map @@ -1,12 +1,17 @@ Function name: if::main -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 04, 01, 12, 10, 05, 13, 05, 05, 06, 02, 05, 05, 00, 06, 01, 01, 01, 00, 02] +Raw bytes (51): 0x[01, 01, 01, 01, 05, 09, 01, 04, 01, 00, 0a, 01, 05, 05, 00, 0c, 01, 02, 09, 02, 0a, 01, 05, 09, 01, 0e, 01, 03, 09, 00, 0a, 01, 03, 09, 00, 10, 05, 01, 05, 05, 06, 02, 05, 05, 00, 06, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/if.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 4, 1) to (start + 18, 16) -- Code(Counter(1)) at (prev + 19, 5) to (start + 5, 6) +Number of file 0 mappings: 9 +- Code(Counter(0)) at (prev + 4, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 5, 5) to (start + 0, 12) +- Code(Counter(0)) at (prev + 2, 9) to (start + 2, 10) +- Code(Counter(0)) at (prev + 5, 9) to (start + 1, 14) +- Code(Counter(0)) at (prev + 3, 9) to (start + 0, 10) +- Code(Counter(0)) at (prev + 3, 9) to (start + 0, 16) +- Code(Counter(1)) at (prev + 1, 5) to (start + 5, 6) - Code(Expression(0, Sub)) at (prev + 5, 5) to (start + 0, 6) = (c0 - c1) - Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) diff --git a/tests/coverage/if.coverage b/tests/coverage/if.coverage index 0762418347c2..c3c8a1bf38a4 100644 --- a/tests/coverage/if.coverage +++ b/tests/coverage/if.coverage @@ -2,23 +2,23 @@ LL| | LL| |#[rustfmt::skip] LL| 1|fn main() { - LL| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure - LL| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - LL| 1| // dependent conditions. - LL| 1| let + LL| | // Initialize test constants in a way that cannot be determined at compile time, to ensure + LL| | // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + LL| | // dependent conditions. + LL| | let LL| 1| is_true - LL| 1| = + LL| | = LL| 1| std::env::args().len() LL| 1| == LL| 1| 1 - LL| 1| ; - LL| 1| let + LL| | ; + LL| | let LL| 1| mut LL| 1| countdown - LL| 1| = + LL| | = LL| 1| 0 - LL| 1| ; - LL| 1| if + LL| | ; + LL| | if LL| 1| is_true LL| 1| { LL| 1| countdown diff --git a/tests/coverage/if_else.cov-map b/tests/coverage/if_else.cov-map index 194ad6ca71f8..1d8ca1809532 100644 --- a/tests/coverage/if_else.cov-map +++ b/tests/coverage/if_else.cov-map @@ -1,13 +1,18 @@ Function name: if_else::main -Raw bytes (43): 0x[01, 01, 02, 01, 05, 01, 09, 07, 01, 04, 01, 08, 10, 05, 09, 05, 05, 06, 02, 08, 09, 02, 10, 01, 06, 09, 00, 10, 09, 01, 05, 05, 06, 06, 07, 05, 05, 06, 01, 06, 01, 00, 02] +Raw bytes (68): 0x[01, 01, 02, 01, 05, 01, 09, 0c, 01, 04, 01, 00, 0a, 01, 04, 09, 00, 10, 01, 00, 13, 00, 2e, 01, 02, 09, 00, 16, 01, 00, 19, 00, 1a, 01, 02, 09, 00, 10, 05, 01, 05, 05, 06, 02, 08, 09, 02, 10, 01, 06, 09, 00, 10, 09, 01, 05, 05, 06, 06, 07, 05, 05, 06, 01, 06, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/if_else.rs Number of expressions: 2 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(0), rhs = Counter(2) -Number of file 0 mappings: 7 -- Code(Counter(0)) at (prev + 4, 1) to (start + 8, 16) -- Code(Counter(1)) at (prev + 9, 5) to (start + 5, 6) +Number of file 0 mappings: 12 +- Code(Counter(0)) at (prev + 4, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 4, 9) to (start + 0, 16) +- Code(Counter(0)) at (prev + 0, 19) to (start + 0, 46) +- Code(Counter(0)) at (prev + 2, 9) to (start + 0, 22) +- Code(Counter(0)) at (prev + 0, 25) to (start + 0, 26) +- Code(Counter(0)) at (prev + 2, 9) to (start + 0, 16) +- Code(Counter(1)) at (prev + 1, 5) to (start + 5, 6) - Code(Expression(0, Sub)) at (prev + 8, 9) to (start + 2, 16) = (c0 - c1) - Code(Counter(0)) at (prev + 6, 9) to (start + 0, 16) diff --git a/tests/coverage/if_else.coverage b/tests/coverage/if_else.coverage index 2bf93487cec2..148e2b195173 100644 --- a/tests/coverage/if_else.coverage +++ b/tests/coverage/if_else.coverage @@ -2,13 +2,13 @@ LL| | LL| |#[rustfmt::skip] LL| 1|fn main() { - LL| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure - LL| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - LL| 1| // dependent conditions. + LL| | // Initialize test constants in a way that cannot be determined at compile time, to ensure + LL| | // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + LL| | // dependent conditions. LL| 1| let is_true = std::env::args().len() == 1; - LL| 1| + LL| | LL| 1| let mut countdown = 0; - LL| 1| if + LL| | if LL| 1| is_true LL| 1| { LL| 1| countdown diff --git a/tests/coverage/if_not.cov-map b/tests/coverage/if_not.cov-map index f47139ce5a48..1b1a1b30e934 100644 --- a/tests/coverage/if_not.cov-map +++ b/tests/coverage/if_not.cov-map @@ -1,14 +1,15 @@ Function name: if_not::if_not -Raw bytes (60): 0x[01, 01, 03, 01, 05, 01, 09, 01, 0d, 0a, 01, 05, 01, 03, 0d, 02, 04, 05, 02, 06, 05, 02, 05, 00, 06, 01, 03, 09, 01, 0d, 06, 02, 05, 02, 06, 09, 02, 05, 00, 06, 01, 03, 09, 01, 0d, 0a, 02, 05, 02, 06, 0d, 02, 0c, 02, 06, 01, 03, 01, 00, 02] +Raw bytes (65): 0x[01, 01, 03, 01, 05, 01, 09, 01, 0d, 0b, 01, 05, 01, 00, 16, 01, 02, 09, 01, 0d, 02, 02, 05, 02, 06, 05, 02, 05, 00, 06, 01, 03, 09, 01, 0d, 06, 02, 05, 02, 06, 09, 02, 05, 00, 06, 01, 03, 09, 01, 0d, 0a, 02, 05, 02, 06, 0d, 02, 0c, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/if_not.rs Number of expressions: 3 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(0), rhs = Counter(2) - expression 2 operands: lhs = Counter(0), rhs = Counter(3) -Number of file 0 mappings: 10 -- Code(Counter(0)) at (prev + 5, 1) to (start + 3, 13) -- Code(Expression(0, Sub)) at (prev + 4, 5) to (start + 2, 6) +Number of file 0 mappings: 11 +- Code(Counter(0)) at (prev + 5, 1) to (start + 0, 22) +- Code(Counter(0)) at (prev + 2, 9) to (start + 1, 13) +- Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 2, 6) = (c0 - c1) - Code(Counter(1)) at (prev + 2, 5) to (start + 0, 6) - Code(Counter(0)) at (prev + 3, 9) to (start + 1, 13) diff --git a/tests/coverage/if_not.coverage b/tests/coverage/if_not.coverage index 678ccf9f2f85..8478e861a3aa 100644 --- a/tests/coverage/if_not.coverage +++ b/tests/coverage/if_not.coverage @@ -3,7 +3,7 @@ LL| | LL| |#[rustfmt::skip] LL| 12|fn if_not(cond: bool) { - LL| 12| if + LL| | if LL| 12| ! LL| 12| cond LL| 4| { diff --git a/tests/coverage/ignore_run.cov-map b/tests/coverage/ignore_run.cov-map index c8ad3821e16f..0d8245c54dc4 100644 --- a/tests/coverage/ignore_run.cov-map +++ b/tests/coverage/ignore_run.cov-map @@ -1,9 +1,10 @@ Function name: ignore_run::main -Raw bytes (9): 0x[01, 01, 00, 01, 01, 03, 01, 00, 0d] +Raw bytes (14): 0x[01, 01, 00, 02, 01, 03, 01, 00, 0a, 01, 00, 0c, 00, 0d] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/ignore_run.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 13) +Number of file 0 mappings: 2 +- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 0, 12) to (start + 0, 13) Highest counter ID seen: c0 diff --git a/tests/coverage/inline-dead.cov-map b/tests/coverage/inline-dead.cov-map index 65cefe76c29a..95a5f6bf68b7 100644 --- a/tests/coverage/inline-dead.cov-map +++ b/tests/coverage/inline-dead.cov-map @@ -1,44 +1,53 @@ Function name: inline_dead::dead (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 17, 01, 02, 02] +Raw bytes (19): 0x[01, 01, 00, 03, 00, 17, 01, 00, 11, 00, 01, 05, 00, 07, 00, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/inline-dead.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 23, 1) to (start + 2, 2) +Number of file 0 mappings: 3 +- Code(Zero) at (prev + 23, 1) to (start + 0, 17) +- Code(Zero) at (prev + 1, 5) to (start + 0, 7) +- Code(Zero) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: (none) Function name: inline_dead::live:: -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 0e, 01, 01, 09, 05, 02, 09, 00, 0d, 02, 02, 09, 00, 0a, 01, 02, 01, 00, 02] +Raw bytes (31): 0x[01, 01, 01, 01, 05, 05, 01, 0e, 01, 00, 20, 01, 01, 08, 00, 09, 05, 01, 09, 00, 0d, 02, 02, 09, 00, 0a, 01, 02, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/inline-dead.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 14, 1) to (start + 1, 9) -- Code(Counter(1)) at (prev + 2, 9) to (start + 0, 13) +Number of file 0 mappings: 5 +- Code(Counter(0)) at (prev + 14, 1) to (start + 0, 32) +- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 9) +- Code(Counter(1)) at (prev + 1, 9) to (start + 0, 13) - Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 10) = (c0 - c1) - Code(Counter(0)) at (prev + 2, 1) to (start + 0, 2) Highest counter ID seen: c1 Function name: inline_dead::main -Raw bytes (14): 0x[01, 01, 00, 02, 01, 04, 01, 03, 0a, 01, 06, 05, 01, 02] +Raw bytes (39): 0x[01, 01, 00, 07, 01, 04, 01, 00, 0a, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 12, 01, 00, 14, 00, 21, 01, 02, 09, 00, 0a, 01, 03, 05, 00, 0d, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/inline-dead.rs Number of expressions: 0 -Number of file 0 mappings: 2 -- Code(Counter(0)) at (prev + 4, 1) to (start + 3, 10) -- Code(Counter(0)) at (prev + 6, 5) to (start + 1, 2) +Number of file 0 mappings: 7 +- Code(Counter(0)) at (prev + 4, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 18) +- Code(Counter(0)) at (prev + 0, 20) to (start + 0, 33) +- Code(Counter(0)) at (prev + 2, 9) to (start + 0, 10) +- Code(Counter(0)) at (prev + 3, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: inline_dead::main::{closure#0} -Raw bytes (19): 0x[01, 01, 00, 03, 01, 07, 17, 01, 16, 00, 01, 17, 00, 18, 01, 01, 05, 00, 06] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 07, 17, 00, 18, 01, 01, 09, 00, 16, 00, 00, 17, 00, 18, 01, 01, 05, 00, 06] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/inline-dead.rs Number of expressions: 0 -Number of file 0 mappings: 3 -- Code(Counter(0)) at (prev + 7, 23) to (start + 1, 22) -- Code(Zero) at (prev + 1, 23) to (start + 0, 24) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 7, 23) to (start + 0, 24) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 22) +- Code(Zero) at (prev + 0, 23) to (start + 0, 24) - Code(Counter(0)) at (prev + 1, 5) to (start + 0, 6) Highest counter ID seen: c0 diff --git a/tests/coverage/inline-dead.coverage b/tests/coverage/inline-dead.coverage index c12668ce89a2..d75aaf300623 100644 --- a/tests/coverage/inline-dead.coverage +++ b/tests/coverage/inline-dead.coverage @@ -3,7 +3,7 @@ LL| | LL| 1|fn main() { LL| 1| println!("{}", live::()); - LL| 1| + LL| | LL| 1| let f = |x: bool| { LL| 1| debug_assert!(x); ^0 diff --git a/tests/coverage/inline.cov-map b/tests/coverage/inline.cov-map index 7264391baaf7..4c67dd96ac2f 100644 --- a/tests/coverage/inline.cov-map +++ b/tests/coverage/inline.cov-map @@ -1,86 +1,137 @@ Function name: inline::display:: -Raw bytes (31): 0x[01, 01, 01, 05, 01, 05, 01, 29, 01, 00, 22, 02, 01, 09, 00, 0a, 05, 00, 0e, 00, 10, 02, 00, 11, 02, 06, 01, 03, 05, 01, 02] +Raw bytes (36): 0x[01, 01, 01, 05, 01, 06, 01, 29, 01, 00, 21, 02, 01, 09, 00, 0a, 05, 00, 0e, 00, 10, 02, 00, 11, 02, 06, 01, 03, 05, 00, 0d, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/inline.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(1), rhs = Counter(0) -Number of file 0 mappings: 5 -- Code(Counter(0)) at (prev + 41, 1) to (start + 0, 34) +Number of file 0 mappings: 6 +- Code(Counter(0)) at (prev + 41, 1) to (start + 0, 33) - Code(Expression(0, Sub)) at (prev + 1, 9) to (start + 0, 10) = (c1 - c0) - Code(Counter(1)) at (prev + 0, 14) to (start + 0, 16) - Code(Expression(0, Sub)) at (prev + 0, 17) to (start + 2, 6) = (c1 - c0) -- Code(Counter(0)) at (prev + 3, 5) to (start + 1, 2) +- Code(Counter(0)) at (prev + 3, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c1 Function name: inline::error -Raw bytes (9): 0x[01, 01, 00, 01, 01, 31, 01, 01, 0b] +Raw bytes (14): 0x[01, 01, 00, 02, 01, 31, 01, 00, 0b, 01, 01, 05, 00, 0b] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/inline.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 49, 1) to (start + 1, 11) +Number of file 0 mappings: 2 +- Code(Counter(0)) at (prev + 49, 1) to (start + 0, 11) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 11) Highest counter ID seen: c0 Function name: inline::length:: -Raw bytes (9): 0x[01, 01, 00, 01, 01, 1e, 01, 02, 02] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 1e, 01, 00, 20, 01, 01, 05, 00, 07, 01, 00, 08, 00, 0b, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/inline.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 30, 1) to (start + 2, 2) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 30, 1) to (start + 0, 32) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 7) +- Code(Counter(0)) at (prev + 0, 8) to (start + 0, 11) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: inline::main -Raw bytes (9): 0x[01, 01, 00, 01, 01, 05, 01, 02, 02] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 05, 01, 00, 0a, 01, 01, 05, 00, 11, 01, 00, 12, 00, 22, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/inline.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 5, 1) to (start + 2, 2) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 5, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 17) +- Code(Counter(0)) at (prev + 0, 18) to (start + 0, 34) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: inline::permutate:: -Raw bytes (54): 0x[01, 01, 05, 01, 05, 0d, 09, 0d, 09, 01, 13, 05, 09, 08, 01, 0f, 01, 02, 0e, 05, 02, 0f, 02, 06, 02, 02, 0f, 00, 14, 0a, 01, 0d, 00, 0e, 09, 00, 12, 00, 16, 0a, 00, 17, 04, 0a, 0e, 05, 0c, 02, 06, 01, 03, 01, 00, 02] +Raw bytes (142): 0x[01, 01, 0e, 01, 05, 0d, 09, 0d, 09, 0d, 09, 0d, 09, 0d, 09, 0d, 09, 0d, 09, 0d, 09, 0d, 09, 0d, 09, 0d, 09, 01, 37, 05, 09, 16, 01, 0f, 01, 00, 38, 01, 01, 09, 00, 0a, 01, 00, 0d, 00, 13, 01, 00, 14, 00, 16, 01, 01, 08, 00, 0e, 05, 00, 0f, 02, 06, 02, 02, 0f, 00, 14, 2e, 01, 0d, 00, 0e, 09, 00, 12, 00, 13, 09, 00, 15, 00, 16, 2e, 00, 17, 04, 0a, 2e, 01, 0d, 00, 11, 2e, 00, 12, 00, 14, 2e, 00, 16, 00, 17, 2e, 00, 19, 00, 1a, 2e, 01, 0d, 00, 16, 2e, 00, 17, 00, 19, 2e, 00, 1b, 00, 20, 2e, 01, 0d, 00, 11, 2e, 00, 12, 00, 14, 32, 02, 0c, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 -Number of expressions: 5 +- file 0 => $DIR/inline.rs +Number of expressions: 14 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(3), rhs = Counter(2) - expression 2 operands: lhs = Counter(3), rhs = Counter(2) -- expression 3 operands: lhs = Counter(0), rhs = Expression(4, Add) -- expression 4 operands: lhs = Counter(1), rhs = Counter(2) -Number of file 0 mappings: 8 -- Code(Counter(0)) at (prev + 15, 1) to (start + 2, 14) -- Code(Counter(1)) at (prev + 2, 15) to (start + 2, 6) +- expression 3 operands: lhs = Counter(3), rhs = Counter(2) +- expression 4 operands: lhs = Counter(3), rhs = Counter(2) +- expression 5 operands: lhs = Counter(3), rhs = Counter(2) +- expression 6 operands: lhs = Counter(3), rhs = Counter(2) +- expression 7 operands: lhs = Counter(3), rhs = Counter(2) +- expression 8 operands: lhs = Counter(3), rhs = Counter(2) +- expression 9 operands: lhs = Counter(3), rhs = Counter(2) +- expression 10 operands: lhs = Counter(3), rhs = Counter(2) +- expression 11 operands: lhs = Counter(3), rhs = Counter(2) +- expression 12 operands: lhs = Counter(0), rhs = Expression(13, Add) +- expression 13 operands: lhs = Counter(1), rhs = Counter(2) +Number of file 0 mappings: 22 +- Code(Counter(0)) at (prev + 15, 1) to (start + 0, 56) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 10) +- Code(Counter(0)) at (prev + 0, 13) to (start + 0, 19) +- Code(Counter(0)) at (prev + 0, 20) to (start + 0, 22) +- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 14) +- Code(Counter(1)) at (prev + 0, 15) to (start + 2, 6) - Code(Expression(0, Sub)) at (prev + 2, 15) to (start + 0, 20) = (c0 - c1) -- Code(Expression(2, Sub)) at (prev + 1, 13) to (start + 0, 14) +- Code(Expression(11, Sub)) at (prev + 1, 13) to (start + 0, 14) = (c3 - c2) -- Code(Counter(2)) at (prev + 0, 18) to (start + 0, 22) -- Code(Expression(2, Sub)) at (prev + 0, 23) to (start + 4, 10) +- Code(Counter(2)) at (prev + 0, 18) to (start + 0, 19) +- Code(Counter(2)) at (prev + 0, 21) to (start + 0, 22) +- Code(Expression(11, Sub)) at (prev + 0, 23) to (start + 4, 10) = (c3 - c2) -- Code(Expression(3, Sub)) at (prev + 5, 12) to (start + 2, 6) +- Code(Expression(11, Sub)) at (prev + 1, 13) to (start + 0, 17) + = (c3 - c2) +- Code(Expression(11, Sub)) at (prev + 0, 18) to (start + 0, 20) + = (c3 - c2) +- Code(Expression(11, Sub)) at (prev + 0, 22) to (start + 0, 23) + = (c3 - c2) +- Code(Expression(11, Sub)) at (prev + 0, 25) to (start + 0, 26) + = (c3 - c2) +- Code(Expression(11, Sub)) at (prev + 1, 13) to (start + 0, 22) + = (c3 - c2) +- Code(Expression(11, Sub)) at (prev + 0, 23) to (start + 0, 25) + = (c3 - c2) +- Code(Expression(11, Sub)) at (prev + 0, 27) to (start + 0, 32) + = (c3 - c2) +- Code(Expression(11, Sub)) at (prev + 1, 13) to (start + 0, 17) + = (c3 - c2) +- Code(Expression(11, Sub)) at (prev + 0, 18) to (start + 0, 20) + = (c3 - c2) +- Code(Expression(12, Sub)) at (prev + 2, 12) to (start + 2, 6) = (c0 - (c1 + c2)) - Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2) Highest counter ID seen: c2 Function name: inline::permutations:: -Raw bytes (9): 0x[01, 01, 00, 01, 01, 0a, 01, 03, 02] +Raw bytes (39): 0x[01, 01, 00, 07, 01, 0a, 01, 00, 2d, 01, 01, 09, 00, 0f, 01, 00, 12, 00, 14, 01, 00, 15, 00, 1d, 01, 01, 05, 00, 0e, 01, 00, 0f, 00, 16, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/inline.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 10, 1) to (start + 3, 2) +Number of file 0 mappings: 7 +- Code(Counter(0)) at (prev + 10, 1) to (start + 0, 45) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 15) +- Code(Counter(0)) at (prev + 0, 18) to (start + 0, 20) +- Code(Counter(0)) at (prev + 0, 21) to (start + 0, 29) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 22) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: inline::swap:: -Raw bytes (9): 0x[01, 01, 00, 01, 01, 23, 01, 04, 02] +Raw bytes (34): 0x[01, 01, 00, 06, 01, 23, 01, 00, 33, 01, 01, 09, 00, 0a, 01, 00, 0d, 00, 12, 01, 01, 05, 00, 12, 01, 01, 05, 00, 0e, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/inline.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 35, 1) to (start + 4, 2) +Number of file 0 mappings: 6 +- Code(Counter(0)) at (prev + 35, 1) to (start + 0, 51) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 10) +- Code(Counter(0)) at (prev + 0, 13) to (start + 0, 18) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 18) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 diff --git a/tests/coverage/inline.coverage b/tests/coverage/inline.coverage index 3d322126a38b..5fe069d5389d 100644 --- a/tests/coverage/inline.coverage +++ b/tests/coverage/inline.coverage @@ -18,7 +18,7 @@ LL| 6| display(xs); LL| 10| } else if k < n { LL| 15| for i in k..n { - ^10 + ^10^10 LL| 15| swap(xs, i, k); LL| 15| permutate(xs, k + 1); LL| 15| swap(xs, i, k); diff --git a/tests/coverage/inner_items.cov-map b/tests/coverage/inner_items.cov-map index a12cce25b643..ca6ddfda2ddf 100644 --- a/tests/coverage/inner_items.cov-map +++ b/tests/coverage/inner_items.cov-map @@ -1,46 +1,70 @@ Function name: ::default_trait_func -Raw bytes (9): 0x[01, 01, 00, 01, 01, 21, 09, 03, 0a] +Raw bytes (29): 0x[01, 01, 00, 05, 01, 21, 09, 00, 29, 01, 01, 0d, 00, 14, 01, 01, 0d, 00, 11, 01, 00, 12, 00, 1c, 01, 01, 09, 00, 0a] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/inner_items.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 33, 9) to (start + 3, 10) +Number of file 0 mappings: 5 +- Code(Counter(0)) at (prev + 33, 9) to (start + 0, 41) +- Code(Counter(0)) at (prev + 1, 13) to (start + 0, 20) +- Code(Counter(0)) at (prev + 1, 13) to (start + 0, 17) +- Code(Counter(0)) at (prev + 0, 18) to (start + 0, 28) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 10) Highest counter ID seen: c0 Function name: ::trait_func -Raw bytes (9): 0x[01, 01, 00, 01, 01, 28, 09, 03, 0a] +Raw bytes (29): 0x[01, 01, 00, 05, 01, 28, 09, 00, 2c, 01, 01, 0d, 00, 29, 01, 01, 0d, 00, 14, 01, 00, 15, 00, 29, 01, 01, 09, 00, 0a] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/inner_items.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 40, 9) to (start + 3, 10) +Number of file 0 mappings: 5 +- Code(Counter(0)) at (prev + 40, 9) to (start + 0, 44) +- Code(Counter(0)) at (prev + 1, 13) to (start + 0, 41) +- Code(Counter(0)) at (prev + 1, 13) to (start + 0, 20) +- Code(Counter(0)) at (prev + 0, 21) to (start + 0, 41) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 10) Highest counter ID seen: c0 Function name: inner_items::main -Raw bytes (43): 0x[01, 01, 02, 01, 05, 01, 09, 07, 01, 03, 01, 07, 0f, 05, 07, 10, 02, 06, 02, 02, 05, 00, 06, 01, 24, 08, 00, 0f, 09, 00, 10, 02, 06, 06, 02, 05, 00, 06, 01, 02, 09, 05, 02] +Raw bytes (88): 0x[01, 01, 02, 01, 05, 01, 09, 10, 01, 03, 01, 00, 0a, 01, 04, 09, 00, 10, 01, 00, 13, 00, 2e, 01, 02, 09, 00, 16, 01, 00, 19, 00, 1a, 01, 01, 08, 00, 0f, 05, 00, 10, 02, 06, 02, 02, 05, 00, 06, 01, 24, 08, 00, 0f, 09, 00, 10, 02, 06, 06, 02, 05, 00, 06, 01, 02, 09, 00, 10, 01, 00, 13, 02, 06, 01, 04, 05, 00, 08, 01, 00, 09, 00, 1b, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/inner_items.rs Number of expressions: 2 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(0), rhs = Counter(2) -Number of file 0 mappings: 7 -- Code(Counter(0)) at (prev + 3, 1) to (start + 7, 15) -- Code(Counter(1)) at (prev + 7, 16) to (start + 2, 6) +Number of file 0 mappings: 16 +- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 4, 9) to (start + 0, 16) +- Code(Counter(0)) at (prev + 0, 19) to (start + 0, 46) +- Code(Counter(0)) at (prev + 2, 9) to (start + 0, 22) +- Code(Counter(0)) at (prev + 0, 25) to (start + 0, 26) +- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 15) +- Code(Counter(1)) at (prev + 0, 16) to (start + 2, 6) - Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 0, 6) = (c0 - c1) - Code(Counter(0)) at (prev + 36, 8) to (start + 0, 15) - Code(Counter(2)) at (prev + 0, 16) to (start + 2, 6) - Code(Expression(1, Sub)) at (prev + 2, 5) to (start + 0, 6) = (c0 - c2) -- Code(Counter(0)) at (prev + 2, 9) to (start + 5, 2) +- Code(Counter(0)) at (prev + 2, 9) to (start + 0, 16) +- Code(Counter(0)) at (prev + 0, 19) to (start + 2, 6) +- Code(Counter(0)) at (prev + 4, 5) to (start + 0, 8) +- Code(Counter(0)) at (prev + 0, 9) to (start + 0, 27) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c2 Function name: inner_items::main::in_func -Raw bytes (9): 0x[01, 01, 00, 01, 01, 12, 05, 04, 06] +Raw bytes (44): 0x[01, 01, 00, 08, 01, 12, 05, 00, 17, 01, 01, 0d, 00, 0e, 01, 00, 11, 00, 12, 01, 01, 0d, 00, 0e, 01, 00, 11, 00, 16, 01, 01, 09, 00, 11, 01, 00, 12, 00, 1a, 01, 01, 05, 00, 06] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/inner_items.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 18, 5) to (start + 4, 6) +Number of file 0 mappings: 8 +- Code(Counter(0)) at (prev + 18, 5) to (start + 0, 23) +- Code(Counter(0)) at (prev + 1, 13) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 17) to (start + 0, 18) +- Code(Counter(0)) at (prev + 1, 13) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 17) to (start + 0, 22) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 17) +- Code(Counter(0)) at (prev + 0, 18) to (start + 0, 26) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 6) Highest counter ID seen: c0 diff --git a/tests/coverage/inner_items.coverage b/tests/coverage/inner_items.coverage index 8244d347b59c..8503cc12f233 100644 --- a/tests/coverage/inner_items.coverage +++ b/tests/coverage/inner_items.coverage @@ -1,11 +1,11 @@ LL| |#![allow(unused_assignments, unused_variables, dead_code)] LL| | LL| 1|fn main() { - LL| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure - LL| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - LL| 1| // dependent conditions. + LL| | // Initialize test constants in a way that cannot be determined at compile time, to ensure + LL| | // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + LL| | // dependent conditions. LL| 1| let is_true = std::env::args().len() == 1; - LL| 1| + LL| | LL| 1| let mut countdown = 0; LL| 1| if is_true { LL| 1| countdown = 10; @@ -54,7 +54,7 @@ LL| 1| let mut val = InStruct { LL| 1| in_struct_field: 101, // LL| 1| }; - LL| 1| + LL| | LL| 1| val.default_trait_func(); LL| 1|} diff --git a/tests/coverage/issue-83601.cov-map b/tests/coverage/issue-83601.cov-map index f10231090089..d1d751ff24b8 100644 --- a/tests/coverage/issue-83601.cov-map +++ b/tests/coverage/issue-83601.cov-map @@ -1,13 +1,30 @@ Function name: issue_83601::main -Raw bytes (21): 0x[01, 01, 01, 05, 09, 03, 01, 06, 01, 02, 0f, 05, 03, 09, 01, 0f, 02, 02, 05, 03, 02] +Raw bytes (76): 0x[01, 01, 01, 05, 09, 0e, 01, 06, 01, 00, 0a, 01, 01, 09, 00, 0c, 01, 00, 0f, 00, 15, 01, 01, 05, 00, 0f, 05, 01, 09, 00, 0c, 05, 00, 0f, 00, 15, 05, 01, 05, 00, 0f, 02, 01, 05, 00, 0d, 02, 00, 0e, 00, 14, 02, 01, 05, 00, 0d, 02, 00, 0e, 00, 14, 02, 01, 05, 00, 0d, 02, 00, 0e, 00, 14, 02, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/issue-83601.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(1), rhs = Counter(2) -Number of file 0 mappings: 3 -- Code(Counter(0)) at (prev + 6, 1) to (start + 2, 15) -- Code(Counter(1)) at (prev + 3, 9) to (start + 1, 15) -- Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 3, 2) +Number of file 0 mappings: 14 +- Code(Counter(0)) at (prev + 6, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 12) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 21) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 15) +- Code(Counter(1)) at (prev + 1, 9) to (start + 0, 12) +- Code(Counter(1)) at (prev + 0, 15) to (start + 0, 21) +- Code(Counter(1)) at (prev + 1, 5) to (start + 0, 15) +- Code(Expression(0, Sub)) at (prev + 1, 5) to (start + 0, 13) + = (c1 - c2) +- Code(Expression(0, Sub)) at (prev + 0, 14) to (start + 0, 20) + = (c1 - c2) +- Code(Expression(0, Sub)) at (prev + 1, 5) to (start + 0, 13) + = (c1 - c2) +- Code(Expression(0, Sub)) at (prev + 0, 14) to (start + 0, 20) + = (c1 - c2) +- Code(Expression(0, Sub)) at (prev + 1, 5) to (start + 0, 13) + = (c1 - c2) +- Code(Expression(0, Sub)) at (prev + 0, 14) to (start + 0, 20) + = (c1 - c2) +- Code(Expression(0, Sub)) at (prev + 1, 1) to (start + 0, 2) = (c1 - c2) Highest counter ID seen: c1 diff --git a/tests/coverage/issue-84561.cov-map b/tests/coverage/issue-84561.cov-map index 47e2922a805a..2b643ea599ed 100644 --- a/tests/coverage/issue-84561.cov-map +++ b/tests/coverage/issue-84561.cov-map @@ -1,67 +1,81 @@ Function name: ::fmt -Raw bytes (27): 0x[01, 01, 01, 01, 05, 04, 01, 8a, 01, 05, 01, 24, 05, 01, 25, 00, 26, 02, 01, 09, 00, 0f, 01, 01, 05, 00, 06] +Raw bytes (42): 0x[01, 01, 01, 01, 05, 07, 01, 8a, 01, 05, 00, 43, 01, 01, 09, 00, 0f, 01, 00, 10, 00, 11, 01, 00, 13, 00, 24, 05, 00, 25, 00, 26, 02, 01, 09, 00, 0f, 01, 01, 05, 00, 06] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/issue-84561.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 138, 5) to (start + 1, 36) -- Code(Counter(1)) at (prev + 1, 37) to (start + 0, 38) +Number of file 0 mappings: 7 +- Code(Counter(0)) at (prev + 138, 5) to (start + 0, 67) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 15) +- Code(Counter(0)) at (prev + 0, 16) to (start + 0, 17) +- Code(Counter(0)) at (prev + 0, 19) to (start + 0, 36) +- Code(Counter(1)) at (prev + 0, 37) to (start + 0, 38) - Code(Expression(0, Sub)) at (prev + 1, 9) to (start + 0, 15) = (c0 - c1) - Code(Counter(0)) at (prev + 1, 5) to (start + 0, 6) Highest counter ID seen: c1 Function name: issue_84561::main -Raw bytes (10): 0x[01, 01, 00, 01, 01, b4, 01, 01, 04, 02] +Raw bytes (30): 0x[01, 01, 00, 05, 01, b4, 01, 01, 00, 0a, 01, 01, 05, 00, 0a, 01, 01, 05, 00, 0a, 01, 01, 05, 00, 0a, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/issue-84561.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 180, 1) to (start + 4, 2) +Number of file 0 mappings: 5 +- Code(Counter(0)) at (prev + 180, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 10) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 10) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 10) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: issue_84561::test1 -Raw bytes (50): 0x[01, 01, 00, 09, 01, 9a, 01, 01, 01, 0b, 05, 01, 0c, 00, 1e, 01, 01, 05, 00, 0b, 09, 00, 0c, 00, 1e, 01, 01, 0d, 01, 0b, 0d, 01, 0c, 00, 1e, 01, 01, 05, 03, 0b, 11, 03, 0c, 00, 1e, 01, 01, 01, 00, 02] +Raw bytes (65): 0x[01, 01, 00, 0c, 01, 9a, 01, 01, 00, 0b, 01, 01, 05, 00, 0b, 05, 00, 0c, 00, 1e, 01, 01, 05, 00, 0b, 09, 00, 0c, 00, 1e, 01, 01, 0d, 00, 0e, 01, 01, 05, 00, 0b, 0d, 00, 0c, 00, 1e, 01, 01, 05, 02, 06, 01, 03, 05, 00, 0b, 11, 00, 0c, 00, 1e, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/issue-84561.rs Number of expressions: 0 -Number of file 0 mappings: 9 -- Code(Counter(0)) at (prev + 154, 1) to (start + 1, 11) -- Code(Counter(1)) at (prev + 1, 12) to (start + 0, 30) +Number of file 0 mappings: 12 +- Code(Counter(0)) at (prev + 154, 1) to (start + 0, 11) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 11) +- Code(Counter(1)) at (prev + 0, 12) to (start + 0, 30) - Code(Counter(0)) at (prev + 1, 5) to (start + 0, 11) - Code(Counter(2)) at (prev + 0, 12) to (start + 0, 30) -- Code(Counter(0)) at (prev + 1, 13) to (start + 1, 11) -- Code(Counter(3)) at (prev + 1, 12) to (start + 0, 30) -- Code(Counter(0)) at (prev + 1, 5) to (start + 3, 11) -- Code(Counter(4)) at (prev + 3, 12) to (start + 0, 30) +- Code(Counter(0)) at (prev + 1, 13) to (start + 0, 14) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 11) +- Code(Counter(3)) at (prev + 0, 12) to (start + 0, 30) +- Code(Counter(0)) at (prev + 1, 5) to (start + 2, 6) +- Code(Counter(0)) at (prev + 3, 5) to (start + 0, 11) +- Code(Counter(4)) at (prev + 0, 12) to (start + 0, 30) - Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c4 Function name: issue_84561::test2 -Raw bytes (20): 0x[01, 01, 00, 03, 01, b0, 01, 01, 01, 10, 05, 01, 11, 00, 23, 01, 01, 01, 00, 02] +Raw bytes (25): 0x[01, 01, 00, 04, 01, b0, 01, 01, 00, 0b, 01, 01, 05, 00, 10, 05, 00, 11, 00, 23, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/issue-84561.rs Number of expressions: 0 -Number of file 0 mappings: 3 -- Code(Counter(0)) at (prev + 176, 1) to (start + 1, 16) -- Code(Counter(1)) at (prev + 1, 17) to (start + 0, 35) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 176, 1) to (start + 0, 11) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 16) +- Code(Counter(1)) at (prev + 0, 17) to (start + 0, 35) - Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c1 Function name: issue_84561::test2::call_print -Raw bytes (10): 0x[01, 01, 00, 01, 01, a7, 01, 09, 02, 0a] +Raw bytes (25): 0x[01, 01, 00, 04, 01, a7, 01, 09, 00, 1f, 01, 01, 0d, 00, 13, 01, 00, 14, 00, 18, 01, 01, 09, 00, 0a] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/issue-84561.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 167, 9) to (start + 2, 10) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 167, 9) to (start + 0, 31) +- Code(Counter(0)) at (prev + 1, 13) to (start + 0, 19) +- Code(Counter(0)) at (prev + 0, 20) to (start + 0, 24) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 10) Highest counter ID seen: c0 Function name: issue_84561::test3 -Raw bytes (279): 0x[01, 01, 0a, 0d, 11, 0d, 15, 0d, 19, 1d, 21, 29, 2d, 25, 29, 25, 29, 25, 29, 27, 31, 29, 2d, 33, 01, 08, 01, 03, 0f, 05, 04, 09, 01, 0f, 09, 02, 05, 04, 0f, 09, 05, 05, 00, 0f, 09, 01, 05, 00, 0f, 09, 01, 09, 01, 0f, 0d, 02, 05, 00, 0f, 0d, 01, 05, 00, 0f, 00, 00, 20, 00, 30, 0d, 01, 05, 03, 0f, 00, 03, 20, 00, 30, 00, 00, 33, 00, 41, 00, 00, 4b, 00, 5a, 0d, 01, 05, 00, 0f, 00, 05, 09, 03, 10, 00, 05, 0d, 00, 1b, 00, 02, 0d, 00, 1c, 0d, 04, 09, 02, 0f, 0d, 06, 05, 00, 0f, 0d, 04, 05, 00, 0f, 0d, 04, 09, 01, 0f, 0d, 05, 08, 00, 0f, 11, 01, 09, 00, 13, 02, 05, 09, 00, 13, 0d, 05, 08, 00, 0f, 15, 01, 09, 00, 13, 00, 03, 0d, 00, 1d, 06, 03, 09, 00, 13, 00, 03, 0d, 00, 1d, 0d, 03, 05, 00, 0f, 0d, 01, 0c, 00, 13, 19, 01, 0d, 00, 13, 0a, 02, 0d, 00, 13, 1d, 04, 05, 02, 13, 21, 03, 0d, 00, 13, 0e, 02, 0d, 00, 13, 27, 03, 05, 00, 0f, 25, 01, 0c, 00, 13, 29, 01, 0d, 00, 17, 29, 04, 0d, 00, 13, 1e, 02, 0d, 00, 17, 1e, 01, 14, 00, 1b, 00, 01, 15, 00, 1b, 1e, 02, 15, 00, 1b, 2d, 04, 0d, 00, 13, 22, 03, 09, 00, 19, 31, 02, 05, 00, 0f, 31, 03, 09, 00, 22, 00, 02, 05, 00, 0f, 00, 03, 09, 00, 2c, 00, 02, 01, 00, 02] +Raw bytes (409): 0x[01, 01, 0a, 0d, 11, 0d, 15, 0d, 19, 1d, 21, 29, 2d, 25, 29, 25, 29, 25, 29, 27, 31, 29, 2d, 4d, 01, 08, 01, 00, 0b, 01, 01, 09, 00, 10, 01, 00, 13, 00, 2e, 01, 01, 09, 00, 0c, 01, 00, 0f, 00, 15, 01, 01, 05, 00, 0f, 05, 01, 09, 00, 0c, 05, 00, 0f, 00, 15, 05, 01, 05, 00, 0f, 09, 01, 05, 00, 0d, 09, 00, 0e, 00, 14, 09, 01, 05, 00, 0d, 09, 00, 0e, 00, 14, 09, 01, 05, 00, 0d, 09, 00, 0e, 00, 14, 09, 02, 05, 00, 0f, 09, 01, 05, 00, 0f, 09, 01, 05, 00, 0f, 09, 01, 09, 00, 0c, 09, 00, 0f, 00, 15, 09, 01, 05, 00, 0f, 0d, 01, 05, 00, 0f, 0d, 01, 05, 00, 0f, 00, 00, 20, 00, 30, 0d, 01, 05, 00, 0d, 0d, 00, 0e, 00, 14, 0d, 01, 05, 00, 0d, 0d, 00, 0e, 00, 14, 0d, 02, 05, 00, 0f, 00, 00, 20, 00, 24, 00, 00, 29, 00, 30, 00, 00, 33, 00, 41, 00, 00, 4b, 00, 5a, 0d, 01, 05, 00, 0f, 00, 05, 09, 00, 0d, 00, 03, 09, 00, 10, 00, 02, 0d, 00, 1b, 00, 02, 0d, 00, 1c, 0d, 04, 09, 00, 10, 0d, 00, 13, 00, 2e, 0d, 02, 05, 00, 0f, 0d, 04, 05, 00, 0f, 0d, 04, 05, 00, 0f, 0d, 04, 09, 00, 0c, 0d, 00, 0f, 00, 15, 0d, 01, 05, 00, 0f, 0d, 04, 08, 00, 0f, 11, 01, 09, 00, 13, 02, 05, 09, 00, 13, 0d, 05, 08, 00, 0f, 15, 01, 09, 00, 13, 00, 03, 0d, 00, 1d, 06, 03, 09, 00, 13, 00, 03, 0d, 00, 1d, 0d, 03, 05, 00, 0f, 0d, 01, 0c, 00, 13, 19, 01, 0d, 00, 13, 0a, 02, 0d, 00, 13, 1d, 04, 05, 00, 0f, 1d, 02, 0c, 00, 13, 21, 01, 0d, 00, 13, 0e, 02, 0d, 00, 13, 27, 03, 05, 00, 0f, 25, 01, 0c, 00, 13, 29, 01, 0d, 00, 17, 29, 04, 0d, 00, 13, 1e, 02, 0d, 00, 17, 1e, 01, 14, 00, 1b, 00, 01, 15, 00, 1b, 1e, 02, 15, 00, 1b, 2d, 04, 0d, 00, 13, 22, 03, 09, 00, 19, 31, 02, 05, 00, 0f, 31, 03, 09, 00, 22, 00, 02, 05, 00, 0f, 00, 03, 09, 00, 2c, 00, 02, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/issue-84561.rs Number of expressions: 10 - expression 0 operands: lhs = Counter(3), rhs = Counter(4) - expression 1 operands: lhs = Counter(3), rhs = Counter(5) @@ -73,29 +87,54 @@ Number of expressions: 10 - expression 7 operands: lhs = Counter(9), rhs = Counter(10) - expression 8 operands: lhs = Expression(9, Add), rhs = Counter(12) - expression 9 operands: lhs = Counter(10), rhs = Counter(11) -Number of file 0 mappings: 51 -- Code(Counter(0)) at (prev + 8, 1) to (start + 3, 15) -- Code(Counter(1)) at (prev + 4, 9) to (start + 1, 15) -- Code(Counter(2)) at (prev + 2, 5) to (start + 4, 15) -- Code(Counter(2)) at (prev + 5, 5) to (start + 0, 15) +Number of file 0 mappings: 77 +- Code(Counter(0)) at (prev + 8, 1) to (start + 0, 11) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 16) +- Code(Counter(0)) at (prev + 0, 19) to (start + 0, 46) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 12) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 21) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 15) +- Code(Counter(1)) at (prev + 1, 9) to (start + 0, 12) +- Code(Counter(1)) at (prev + 0, 15) to (start + 0, 21) +- Code(Counter(1)) at (prev + 1, 5) to (start + 0, 15) +- Code(Counter(2)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(2)) at (prev + 0, 14) to (start + 0, 20) +- Code(Counter(2)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(2)) at (prev + 0, 14) to (start + 0, 20) +- Code(Counter(2)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(2)) at (prev + 0, 14) to (start + 0, 20) +- Code(Counter(2)) at (prev + 2, 5) to (start + 0, 15) - Code(Counter(2)) at (prev + 1, 5) to (start + 0, 15) -- Code(Counter(2)) at (prev + 1, 9) to (start + 1, 15) -- Code(Counter(3)) at (prev + 2, 5) to (start + 0, 15) +- Code(Counter(2)) at (prev + 1, 5) to (start + 0, 15) +- Code(Counter(2)) at (prev + 1, 9) to (start + 0, 12) +- Code(Counter(2)) at (prev + 0, 15) to (start + 0, 21) +- Code(Counter(2)) at (prev + 1, 5) to (start + 0, 15) +- Code(Counter(3)) at (prev + 1, 5) to (start + 0, 15) - Code(Counter(3)) at (prev + 1, 5) to (start + 0, 15) - Code(Zero) at (prev + 0, 32) to (start + 0, 48) -- Code(Counter(3)) at (prev + 1, 5) to (start + 3, 15) -- Code(Zero) at (prev + 3, 32) to (start + 0, 48) +- Code(Counter(3)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(3)) at (prev + 0, 14) to (start + 0, 20) +- Code(Counter(3)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(3)) at (prev + 0, 14) to (start + 0, 20) +- Code(Counter(3)) at (prev + 2, 5) to (start + 0, 15) +- Code(Zero) at (prev + 0, 32) to (start + 0, 36) +- Code(Zero) at (prev + 0, 41) to (start + 0, 48) - Code(Zero) at (prev + 0, 51) to (start + 0, 65) - Code(Zero) at (prev + 0, 75) to (start + 0, 90) - Code(Counter(3)) at (prev + 1, 5) to (start + 0, 15) -- Code(Zero) at (prev + 5, 9) to (start + 3, 16) -- Code(Zero) at (prev + 5, 13) to (start + 0, 27) +- Code(Zero) at (prev + 5, 9) to (start + 0, 13) +- Code(Zero) at (prev + 3, 9) to (start + 0, 16) +- Code(Zero) at (prev + 2, 13) to (start + 0, 27) - Code(Zero) at (prev + 2, 13) to (start + 0, 28) -- Code(Counter(3)) at (prev + 4, 9) to (start + 2, 15) -- Code(Counter(3)) at (prev + 6, 5) to (start + 0, 15) +- Code(Counter(3)) at (prev + 4, 9) to (start + 0, 16) +- Code(Counter(3)) at (prev + 0, 19) to (start + 0, 46) +- Code(Counter(3)) at (prev + 2, 5) to (start + 0, 15) - Code(Counter(3)) at (prev + 4, 5) to (start + 0, 15) -- Code(Counter(3)) at (prev + 4, 9) to (start + 1, 15) -- Code(Counter(3)) at (prev + 5, 8) to (start + 0, 15) +- Code(Counter(3)) at (prev + 4, 5) to (start + 0, 15) +- Code(Counter(3)) at (prev + 4, 9) to (start + 0, 12) +- Code(Counter(3)) at (prev + 0, 15) to (start + 0, 21) +- Code(Counter(3)) at (prev + 1, 5) to (start + 0, 15) +- Code(Counter(3)) at (prev + 4, 8) to (start + 0, 15) - Code(Counter(4)) at (prev + 1, 9) to (start + 0, 19) - Code(Expression(0, Sub)) at (prev + 5, 9) to (start + 0, 19) = (c3 - c4) @@ -110,8 +149,9 @@ Number of file 0 mappings: 51 - Code(Counter(6)) at (prev + 1, 13) to (start + 0, 19) - Code(Expression(2, Sub)) at (prev + 2, 13) to (start + 0, 19) = (c3 - c6) -- Code(Counter(7)) at (prev + 4, 5) to (start + 2, 19) -- Code(Counter(8)) at (prev + 3, 13) to (start + 0, 19) +- Code(Counter(7)) at (prev + 4, 5) to (start + 0, 15) +- Code(Counter(7)) at (prev + 2, 12) to (start + 0, 19) +- Code(Counter(8)) at (prev + 1, 13) to (start + 0, 19) - Code(Expression(3, Sub)) at (prev + 2, 13) to (start + 0, 19) = (c7 - c8) - Code(Expression(9, Add)) at (prev + 3, 5) to (start + 0, 15) diff --git a/tests/coverage/issue-84561.coverage b/tests/coverage/issue-84561.coverage index a55f42a696e6..781f1e97f5ab 100644 --- a/tests/coverage/issue-84561.coverage +++ b/tests/coverage/issue-84561.coverage @@ -14,7 +14,7 @@ LL| 1| println!("{:?}", Foo(1)); LL| 1| println!("{:?}", bar); LL| 1| println!("{:?}", baz); - LL| 1| + LL| | LL| 1| assert_eq!(Foo(1), Foo(1)); LL| 1| assert_ne!(Foo(0), Foo(1)); LL| 1| assert_eq!(Foo(2), Foo(2)); @@ -25,17 +25,17 @@ ^0 LL| 1| println!("{:?}", bar); LL| 1| println!("{:?}", Foo(1)); - LL| 1| + LL| | LL| 1| assert_ne!(Foo(0), Foo(5), "{}", if is_true { "true message" } else { "false message" }); - ^0 ^0 ^0 + ^0 ^0 ^0 ^0 LL| 1| assert_ne!( LL| | Foo(0) LL| | , LL| | Foo(5) LL| | , LL| 0| "{}" - LL| 0| , - LL| 0| if + LL| | , + LL| | if LL| 0| is_true LL| | { LL| 0| "true message" @@ -45,7 +45,7 @@ LL| | ); LL| | LL| 1| let is_true = std::env::args().len() == 1; - LL| 1| + LL| | LL| 1| assert_eq!( LL| | Foo(1), LL| | Foo(1) @@ -96,7 +96,7 @@ LL| | Foo(5) LL| | ); LL| 1| assert_ne!( - LL| 1| Foo(5), + LL| | Foo(5), LL| 1| if is_true { LL| 1| Foo(0) LL| | } else { diff --git a/tests/coverage/issue-85461.cov-map b/tests/coverage/issue-85461.cov-map index 349bc2cab803..b08d70336930 100644 --- a/tests/coverage/issue-85461.cov-map +++ b/tests/coverage/issue-85461.cov-map @@ -1,9 +1,12 @@ Function name: issue_85461::main -Raw bytes (9): 0x[01, 01, 00, 01, 01, 08, 01, 03, 02] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 08, 01, 00, 0a, 01, 01, 05, 00, 11, 01, 01, 05, 00, 11, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/issue-85461.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 8, 1) to (start + 3, 2) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 8, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 17) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 17) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 diff --git a/tests/coverage/issue-93054.cov-map b/tests/coverage/issue-93054.cov-map index 38cb70a3f97a..17f3dafce1d7 100644 --- a/tests/coverage/issue-93054.cov-map +++ b/tests/coverage/issue-93054.cov-map @@ -1,27 +1,30 @@ Function name: issue_93054::foo2 (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 15, 01, 00, 1d] +Raw bytes (9): 0x[01, 01, 00, 01, 00, 15, 01, 00, 1c] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/issue-93054.rs Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Zero) at (prev + 21, 1) to (start + 0, 29) +- Code(Zero) at (prev + 21, 1) to (start + 0, 28) Highest counter ID seen: (none) Function name: issue_93054::main -Raw bytes (9): 0x[01, 01, 00, 01, 01, 1d, 01, 00, 0d] +Raw bytes (14): 0x[01, 01, 00, 02, 01, 1d, 01, 00, 0a, 01, 00, 0c, 00, 0d] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/issue-93054.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 29, 1) to (start + 0, 13) +Number of file 0 mappings: 2 +- Code(Counter(0)) at (prev + 29, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 0, 12) to (start + 0, 13) Highest counter ID seen: c0 Function name: issue_93054::make (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 19, 01, 02, 02] +Raw bytes (19): 0x[01, 01, 00, 03, 00, 19, 01, 00, 1b, 00, 01, 05, 00, 09, 00, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/issue-93054.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 25, 1) to (start + 2, 2) +Number of file 0 mappings: 3 +- Code(Zero) at (prev + 25, 1) to (start + 0, 27) +- Code(Zero) at (prev + 1, 5) to (start + 0, 9) +- Code(Zero) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: (none) diff --git a/tests/coverage/lazy_boolean.cov-map b/tests/coverage/lazy_boolean.cov-map index 3f7788da1ebc..cbbe6a89fb0f 100644 --- a/tests/coverage/lazy_boolean.cov-map +++ b/tests/coverage/lazy_boolean.cov-map @@ -1,7 +1,7 @@ Function name: lazy_boolean::main -Raw bytes (158): 0x[01, 01, 07, 01, 05, 01, 25, 01, 21, 01, 11, 01, 15, 01, 19, 01, 1d, 1c, 01, 04, 01, 07, 0f, 05, 07, 10, 04, 06, 02, 04, 05, 00, 06, 01, 02, 09, 00, 11, 01, 02, 0d, 00, 12, 06, 02, 0d, 00, 12, 01, 03, 09, 00, 11, 01, 02, 0d, 00, 12, 0a, 02, 0d, 00, 12, 01, 02, 09, 00, 11, 01, 00, 14, 00, 19, 09, 00, 1d, 00, 22, 01, 01, 09, 00, 11, 01, 00, 14, 00, 19, 0d, 00, 1d, 00, 22, 01, 03, 09, 01, 10, 0e, 02, 05, 03, 06, 11, 03, 05, 00, 06, 01, 03, 09, 00, 10, 15, 01, 05, 03, 06, 12, 05, 05, 03, 06, 01, 05, 08, 00, 10, 16, 00, 11, 02, 06, 19, 02, 05, 00, 06, 01, 02, 08, 00, 0f, 1d, 00, 10, 02, 06, 1a, 02, 0c, 02, 06, 01, 03, 01, 00, 02] +Raw bytes (198): 0x[01, 01, 07, 01, 05, 01, 25, 01, 21, 01, 11, 01, 15, 01, 19, 01, 1d, 24, 01, 04, 01, 00, 0a, 01, 04, 09, 00, 10, 01, 00, 13, 00, 2e, 01, 02, 0a, 00, 0f, 01, 00, 11, 00, 16, 01, 00, 18, 00, 1d, 01, 00, 21, 00, 2a, 01, 01, 08, 00, 0f, 05, 00, 10, 04, 06, 05, 01, 09, 00, 0e, 02, 03, 05, 00, 06, 01, 02, 09, 00, 11, 01, 02, 0d, 00, 12, 06, 02, 0d, 00, 12, 01, 03, 09, 00, 11, 01, 02, 0d, 00, 12, 0a, 02, 0d, 00, 12, 01, 02, 09, 00, 11, 01, 00, 14, 00, 19, 09, 00, 1d, 00, 22, 01, 01, 09, 00, 11, 01, 00, 14, 00, 19, 0d, 00, 1d, 00, 22, 01, 03, 09, 01, 10, 0e, 02, 05, 03, 06, 11, 03, 05, 00, 06, 01, 03, 09, 00, 10, 15, 01, 05, 03, 06, 12, 05, 05, 03, 06, 01, 05, 08, 00, 10, 16, 00, 11, 02, 06, 19, 02, 05, 00, 06, 01, 02, 08, 00, 0f, 1d, 00, 10, 02, 06, 1a, 02, 0c, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/lazy_boolean.rs Number of expressions: 7 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(0), rhs = Counter(9) @@ -10,10 +10,18 @@ Number of expressions: 7 - expression 4 operands: lhs = Counter(0), rhs = Counter(5) - expression 5 operands: lhs = Counter(0), rhs = Counter(6) - expression 6 operands: lhs = Counter(0), rhs = Counter(7) -Number of file 0 mappings: 28 -- Code(Counter(0)) at (prev + 4, 1) to (start + 7, 15) -- Code(Counter(1)) at (prev + 7, 16) to (start + 4, 6) -- Code(Expression(0, Sub)) at (prev + 4, 5) to (start + 0, 6) +Number of file 0 mappings: 36 +- Code(Counter(0)) at (prev + 4, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 4, 9) to (start + 0, 16) +- Code(Counter(0)) at (prev + 0, 19) to (start + 0, 46) +- Code(Counter(0)) at (prev + 2, 10) to (start + 0, 15) +- Code(Counter(0)) at (prev + 0, 17) to (start + 0, 22) +- Code(Counter(0)) at (prev + 0, 24) to (start + 0, 29) +- Code(Counter(0)) at (prev + 0, 33) to (start + 0, 42) +- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 15) +- Code(Counter(1)) at (prev + 0, 16) to (start + 4, 6) +- Code(Counter(1)) at (prev + 1, 9) to (start + 0, 14) +- Code(Expression(0, Sub)) at (prev + 3, 5) to (start + 0, 6) = (c0 - c1) - Code(Counter(0)) at (prev + 2, 9) to (start + 0, 17) - Code(Counter(0)) at (prev + 2, 13) to (start + 0, 18) diff --git a/tests/coverage/lazy_boolean.coverage b/tests/coverage/lazy_boolean.coverage index 828ba2a58116..0a30038e02fa 100644 --- a/tests/coverage/lazy_boolean.coverage +++ b/tests/coverage/lazy_boolean.coverage @@ -2,11 +2,11 @@ LL| | LL| |#[rustfmt::skip] LL| 1|fn main() { - LL| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure - LL| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - LL| 1| // dependent conditions. + LL| | // Initialize test constants in a way that cannot be determined at compile time, to ensure + LL| | // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + LL| | // dependent conditions. LL| 1| let is_true = std::env::args().len() == 1; - LL| 1| + LL| | LL| 1| let (mut a, mut b, mut c) = (0, 0, 0); LL| 1| if is_true { LL| 1| a = 1; diff --git a/tests/coverage/let_else_loop.cov-map b/tests/coverage/let_else_loop.cov-map index 7789114c2395..169d4a5c0961 100644 --- a/tests/coverage/let_else_loop.cov-map +++ b/tests/coverage/let_else_loop.cov-map @@ -1,33 +1,36 @@ Function name: let_else_loop::_if (unused) -Raw bytes (19): 0x[01, 01, 00, 03, 00, 16, 01, 01, 0c, 00, 01, 0f, 00, 16, 00, 00, 20, 00, 27] +Raw bytes (24): 0x[01, 01, 00, 04, 00, 16, 01, 00, 13, 00, 01, 08, 00, 0c, 00, 00, 0f, 00, 16, 00, 00, 20, 00, 27] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/let_else_loop.rs Number of expressions: 0 -Number of file 0 mappings: 3 -- Code(Zero) at (prev + 22, 1) to (start + 1, 12) -- Code(Zero) at (prev + 1, 15) to (start + 0, 22) +Number of file 0 mappings: 4 +- Code(Zero) at (prev + 22, 1) to (start + 0, 19) +- Code(Zero) at (prev + 1, 8) to (start + 0, 12) +- Code(Zero) at (prev + 0, 15) to (start + 0, 22) - Code(Zero) at (prev + 0, 32) to (start + 0, 39) Highest counter ID seen: (none) Function name: let_else_loop::_loop_either_way (unused) -Raw bytes (19): 0x[01, 01, 00, 03, 00, 0f, 01, 01, 14, 00, 01, 1c, 00, 23, 00, 01, 05, 00, 0c] +Raw bytes (24): 0x[01, 01, 00, 04, 00, 0f, 01, 00, 20, 00, 01, 10, 00, 14, 00, 00, 1c, 00, 23, 00, 01, 05, 00, 0c] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/let_else_loop.rs Number of expressions: 0 -Number of file 0 mappings: 3 -- Code(Zero) at (prev + 15, 1) to (start + 1, 20) -- Code(Zero) at (prev + 1, 28) to (start + 0, 35) +Number of file 0 mappings: 4 +- Code(Zero) at (prev + 15, 1) to (start + 0, 32) +- Code(Zero) at (prev + 1, 16) to (start + 0, 20) +- Code(Zero) at (prev + 0, 28) to (start + 0, 35) - Code(Zero) at (prev + 1, 5) to (start + 0, 12) Highest counter ID seen: (none) Function name: let_else_loop::loopy -Raw bytes (19): 0x[01, 01, 00, 03, 01, 09, 01, 01, 14, 09, 01, 1c, 00, 23, 05, 01, 01, 00, 02] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 09, 01, 00, 15, 01, 01, 10, 00, 14, 09, 00, 1c, 00, 23, 05, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/let_else_loop.rs Number of expressions: 0 -Number of file 0 mappings: 3 -- Code(Counter(0)) at (prev + 9, 1) to (start + 1, 20) -- Code(Counter(2)) at (prev + 1, 28) to (start + 0, 35) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 9, 1) to (start + 0, 21) +- Code(Counter(0)) at (prev + 1, 16) to (start + 0, 20) +- Code(Counter(2)) at (prev + 0, 28) to (start + 0, 35) - Code(Counter(1)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c2 diff --git a/tests/coverage/long_and_wide.cov-map b/tests/coverage/long_and_wide.cov-map index 032b7fe102e8..93466a98eaf3 100644 --- a/tests/coverage/long_and_wide.cov-map +++ b/tests/coverage/long_and_wide.cov-map @@ -1,36 +1,44 @@ Function name: long_and_wide::far_function -Raw bytes (10): 0x[01, 01, 00, 01, 01, 96, 01, 01, 00, 15] +Raw bytes (15): 0x[01, 01, 00, 02, 01, 96, 01, 01, 00, 12, 01, 00, 14, 00, 15] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/long_and_wide.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 150, 1) to (start + 0, 21) +Number of file 0 mappings: 2 +- Code(Counter(0)) at (prev + 150, 1) to (start + 0, 18) +- Code(Counter(0)) at (prev + 0, 20) to (start + 0, 21) Highest counter ID seen: c0 Function name: long_and_wide::long_function -Raw bytes (10): 0x[01, 01, 00, 01, 01, 10, 01, 84, 01, 02] +Raw bytes (15): 0x[01, 01, 00, 02, 01, 10, 01, 00, 13, 01, 84, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/long_and_wide.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 16, 1) to (start + 132, 2) +Number of file 0 mappings: 2 +- Code(Counter(0)) at (prev + 16, 1) to (start + 0, 19) +- Code(Counter(0)) at (prev + 132, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: long_and_wide::main -Raw bytes (9): 0x[01, 01, 00, 01, 01, 07, 01, 04, 02] +Raw bytes (29): 0x[01, 01, 00, 05, 01, 07, 01, 00, 0a, 01, 01, 05, 00, 12, 01, 01, 05, 00, 12, 01, 01, 05, 00, 11, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/long_and_wide.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 7, 1) to (start + 4, 2) +Number of file 0 mappings: 5 +- Code(Counter(0)) at (prev + 7, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 18) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 18) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 17) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: long_and_wide::wide_function -Raw bytes (10): 0x[01, 01, 00, 01, 01, 0e, 01, 00, 8b, 01] +Raw bytes (23): 0x[01, 01, 00, 03, 01, 0e, 01, 00, 13, 01, 00, 86, 01, 00, 88, 01, 01, 00, 8a, 01, 00, 8b, 01] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/long_and_wide.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 14, 1) to (start + 0, 139) +Number of file 0 mappings: 3 +- Code(Counter(0)) at (prev + 14, 1) to (start + 0, 19) +- Code(Counter(0)) at (prev + 0, 134) to (start + 0, 136) +- Code(Counter(0)) at (prev + 0, 138) to (start + 0, 139) Highest counter ID seen: c0 diff --git a/tests/coverage/long_and_wide.coverage b/tests/coverage/long_and_wide.coverage index f0898d9f4662..d9bacdf9eed3 100644 --- a/tests/coverage/long_and_wide.coverage +++ b/tests/coverage/long_and_wide.coverage @@ -14,137 +14,137 @@ LL| 1|fn wide_function() { /* */ (); } LL| | LL| 1|fn long_function() { - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // - LL| 1| // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // + LL| | // LL| 1|} LL| | LL| 1|fn far_function() {} diff --git a/tests/coverage/loop-break.cov-map b/tests/coverage/loop-break.cov-map index fccc4d64395b..3981623550dd 100644 --- a/tests/coverage/loop-break.cov-map +++ b/tests/coverage/loop-break.cov-map @@ -1,11 +1,11 @@ Function name: loop_break::main -Raw bytes (31): 0x[01, 01, 01, 05, 01, 05, 01, 03, 01, 00, 0b, 05, 02, 0c, 00, 21, 01, 01, 0d, 00, 12, 02, 01, 09, 00, 0a, 01, 02, 01, 00, 02] +Raw bytes (31): 0x[01, 01, 01, 05, 01, 05, 01, 03, 01, 00, 0a, 05, 02, 0c, 00, 21, 01, 01, 0d, 00, 12, 02, 01, 09, 00, 0a, 01, 02, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/loop-break.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(1), rhs = Counter(0) Number of file 0 mappings: 5 -- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 11) +- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 10) - Code(Counter(1)) at (prev + 2, 12) to (start + 0, 33) - Code(Counter(0)) at (prev + 1, 13) to (start + 0, 18) - Code(Expression(0, Sub)) at (prev + 1, 9) to (start + 0, 10) diff --git a/tests/coverage/loop_break_value.cov-map b/tests/coverage/loop_break_value.cov-map index e48d078f6722..cf355eceb2c1 100644 --- a/tests/coverage/loop_break_value.cov-map +++ b/tests/coverage/loop_break_value.cov-map @@ -1,9 +1,12 @@ Function name: loop_break_value::main -Raw bytes (9): 0x[01, 01, 00, 01, 01, 04, 01, 0a, 02] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 04, 01, 00, 0a, 01, 01, 09, 00, 0f, 01, 02, 0d, 05, 0a, 01, 07, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/loop_break_value.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 4, 1) to (start + 10, 2) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 4, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 15) +- Code(Counter(0)) at (prev + 2, 13) to (start + 5, 10) +- Code(Counter(0)) at (prev + 7, 1) to (start + 0, 2) Highest counter ID seen: c0 diff --git a/tests/coverage/loop_break_value.coverage b/tests/coverage/loop_break_value.coverage index 7d4533987594..5e80168b958b 100644 --- a/tests/coverage/loop_break_value.coverage +++ b/tests/coverage/loop_break_value.coverage @@ -3,13 +3,13 @@ LL| |#[rustfmt::skip] LL| 1|fn main() { LL| 1| let result - LL| 1| = + LL| | = LL| 1| loop LL| 1| { LL| 1| break LL| 1| 10 LL| 1| ; LL| 1| } - LL| 1| ; + LL| | ; LL| 1|} diff --git a/tests/coverage/loops_branches.cov-map b/tests/coverage/loops_branches.cov-map index 2157cd6ee3f8..78fdaa53f46f 100644 --- a/tests/coverage/loops_branches.cov-map +++ b/tests/coverage/loops_branches.cov-map @@ -1,19 +1,22 @@ Function name: ::fmt -Raw bytes (112): 0x[01, 01, 04, 07, 0b, 01, 0d, 05, 09, 09, 0d, 14, 01, 09, 05, 01, 10, 01, 02, 10, 00, 15, 00, 01, 17, 00, 1b, 00, 00, 1c, 00, 1e, 01, 01, 0d, 00, 0e, 01, 01, 0d, 00, 1d, 05, 00, 1e, 00, 1f, 00, 01, 10, 01, 0a, 0d, 03, 0d, 00, 0e, 09, 00, 12, 00, 17, 0d, 01, 10, 00, 14, 0d, 01, 14, 00, 19, 00, 01, 1b, 00, 1f, 00, 00, 20, 00, 22, 0d, 01, 11, 00, 12, 0d, 01, 11, 00, 21, 02, 00, 22, 00, 23, 00, 01, 14, 01, 0e, 0e, 03, 09, 00, 0f, 01, 01, 05, 00, 06] +Raw bytes (137): 0x[01, 01, 04, 07, 0b, 01, 0d, 05, 09, 09, 0d, 19, 01, 09, 05, 00, 43, 01, 01, 0c, 00, 10, 01, 01, 10, 00, 15, 00, 01, 17, 00, 1b, 00, 00, 1c, 00, 1e, 01, 01, 0d, 00, 0e, 01, 01, 0d, 00, 13, 01, 00, 14, 00, 15, 01, 00, 17, 00, 1d, 05, 00, 1e, 00, 1f, 00, 01, 10, 01, 0a, 0d, 03, 0d, 00, 0e, 09, 00, 12, 00, 17, 0d, 01, 10, 00, 14, 0d, 01, 14, 00, 19, 00, 01, 1b, 00, 1f, 00, 00, 20, 00, 22, 0d, 01, 11, 00, 12, 0d, 01, 11, 00, 17, 0d, 00, 18, 00, 19, 0d, 00, 1b, 00, 21, 02, 00, 22, 00, 23, 00, 01, 14, 01, 0e, 0e, 03, 09, 00, 0f, 01, 01, 05, 00, 06] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/loops_branches.rs Number of expressions: 4 - expression 0 operands: lhs = Expression(1, Add), rhs = Expression(2, Add) - expression 1 operands: lhs = Counter(0), rhs = Counter(3) - expression 2 operands: lhs = Counter(1), rhs = Counter(2) - expression 3 operands: lhs = Counter(2), rhs = Counter(3) -Number of file 0 mappings: 20 -- Code(Counter(0)) at (prev + 9, 5) to (start + 1, 16) -- Code(Counter(0)) at (prev + 2, 16) to (start + 0, 21) +Number of file 0 mappings: 25 +- Code(Counter(0)) at (prev + 9, 5) to (start + 0, 67) +- Code(Counter(0)) at (prev + 1, 12) to (start + 0, 16) +- Code(Counter(0)) at (prev + 1, 16) to (start + 0, 21) - Code(Zero) at (prev + 1, 23) to (start + 0, 27) - Code(Zero) at (prev + 0, 28) to (start + 0, 30) - Code(Counter(0)) at (prev + 1, 13) to (start + 0, 14) -- Code(Counter(0)) at (prev + 1, 13) to (start + 0, 29) +- Code(Counter(0)) at (prev + 1, 13) to (start + 0, 19) +- Code(Counter(0)) at (prev + 0, 20) to (start + 0, 21) +- Code(Counter(0)) at (prev + 0, 23) to (start + 0, 29) - Code(Counter(1)) at (prev + 0, 30) to (start + 0, 31) - Code(Zero) at (prev + 1, 16) to (start + 1, 10) - Code(Counter(3)) at (prev + 3, 13) to (start + 0, 14) @@ -23,7 +26,9 @@ Number of file 0 mappings: 20 - Code(Zero) at (prev + 1, 27) to (start + 0, 31) - Code(Zero) at (prev + 0, 32) to (start + 0, 34) - Code(Counter(3)) at (prev + 1, 17) to (start + 0, 18) -- Code(Counter(3)) at (prev + 1, 17) to (start + 0, 33) +- Code(Counter(3)) at (prev + 1, 17) to (start + 0, 23) +- Code(Counter(3)) at (prev + 0, 24) to (start + 0, 25) +- Code(Counter(3)) at (prev + 0, 27) to (start + 0, 33) - Code(Expression(0, Sub)) at (prev + 0, 34) to (start + 0, 35) = ((c0 + c3) - (c1 + c2)) - Code(Zero) at (prev + 1, 20) to (start + 1, 14) @@ -33,22 +38,25 @@ Number of file 0 mappings: 20 Highest counter ID seen: c3 Function name: ::fmt -Raw bytes (112): 0x[01, 01, 04, 07, 0b, 01, 09, 05, 0d, 05, 09, 14, 01, 22, 05, 01, 11, 00, 01, 12, 01, 0a, 01, 02, 10, 00, 15, 00, 01, 17, 00, 1b, 00, 00, 1c, 00, 1e, 01, 01, 0d, 00, 0e, 01, 01, 0d, 00, 1d, 0d, 00, 1e, 00, 1f, 09, 02, 0d, 00, 0e, 05, 00, 12, 00, 17, 09, 01, 10, 00, 15, 00, 00, 16, 01, 0e, 09, 02, 14, 00, 19, 00, 01, 1b, 00, 1f, 00, 00, 20, 00, 22, 09, 01, 11, 00, 12, 09, 01, 11, 00, 21, 02, 00, 22, 00, 23, 0e, 03, 09, 00, 0f, 01, 01, 05, 00, 06] +Raw bytes (137): 0x[01, 01, 04, 07, 0b, 01, 09, 05, 0d, 05, 09, 19, 01, 22, 05, 00, 43, 01, 01, 0c, 00, 11, 00, 00, 12, 01, 0a, 01, 02, 10, 00, 15, 00, 01, 17, 00, 1b, 00, 00, 1c, 00, 1e, 01, 01, 0d, 00, 0e, 01, 01, 0d, 00, 13, 01, 00, 14, 00, 15, 01, 00, 17, 00, 1d, 0d, 00, 1e, 00, 1f, 09, 02, 0d, 00, 0e, 05, 00, 12, 00, 17, 09, 01, 10, 00, 15, 00, 00, 16, 01, 0e, 09, 02, 14, 00, 19, 00, 01, 1b, 00, 1f, 00, 00, 20, 00, 22, 09, 01, 11, 00, 12, 09, 01, 11, 00, 17, 09, 00, 18, 00, 19, 09, 00, 1b, 00, 21, 02, 00, 22, 00, 23, 0e, 03, 09, 00, 0f, 01, 01, 05, 00, 06] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/loops_branches.rs Number of expressions: 4 - expression 0 operands: lhs = Expression(1, Add), rhs = Expression(2, Add) - expression 1 operands: lhs = Counter(0), rhs = Counter(2) - expression 2 operands: lhs = Counter(1), rhs = Counter(3) - expression 3 operands: lhs = Counter(1), rhs = Counter(2) -Number of file 0 mappings: 20 -- Code(Counter(0)) at (prev + 34, 5) to (start + 1, 17) -- Code(Zero) at (prev + 1, 18) to (start + 1, 10) +Number of file 0 mappings: 25 +- Code(Counter(0)) at (prev + 34, 5) to (start + 0, 67) +- Code(Counter(0)) at (prev + 1, 12) to (start + 0, 17) +- Code(Zero) at (prev + 0, 18) to (start + 1, 10) - Code(Counter(0)) at (prev + 2, 16) to (start + 0, 21) - Code(Zero) at (prev + 1, 23) to (start + 0, 27) - Code(Zero) at (prev + 0, 28) to (start + 0, 30) - Code(Counter(0)) at (prev + 1, 13) to (start + 0, 14) -- Code(Counter(0)) at (prev + 1, 13) to (start + 0, 29) +- Code(Counter(0)) at (prev + 1, 13) to (start + 0, 19) +- Code(Counter(0)) at (prev + 0, 20) to (start + 0, 21) +- Code(Counter(0)) at (prev + 0, 23) to (start + 0, 29) - Code(Counter(3)) at (prev + 0, 30) to (start + 0, 31) - Code(Counter(2)) at (prev + 2, 13) to (start + 0, 14) - Code(Counter(1)) at (prev + 0, 18) to (start + 0, 23) @@ -58,7 +66,9 @@ Number of file 0 mappings: 20 - Code(Zero) at (prev + 1, 27) to (start + 0, 31) - Code(Zero) at (prev + 0, 32) to (start + 0, 34) - Code(Counter(2)) at (prev + 1, 17) to (start + 0, 18) -- Code(Counter(2)) at (prev + 1, 17) to (start + 0, 33) +- Code(Counter(2)) at (prev + 1, 17) to (start + 0, 23) +- Code(Counter(2)) at (prev + 0, 24) to (start + 0, 25) +- Code(Counter(2)) at (prev + 0, 27) to (start + 0, 33) - Code(Expression(0, Sub)) at (prev + 0, 34) to (start + 0, 35) = ((c0 + c2) - (c1 + c3)) - Code(Expression(3, Sub)) at (prev + 3, 9) to (start + 0, 15) @@ -67,11 +77,20 @@ Number of file 0 mappings: 20 Highest counter ID seen: c3 Function name: loops_branches::main -Raw bytes (9): 0x[01, 01, 00, 01, 01, 37, 01, 05, 02] +Raw bytes (54): 0x[01, 01, 00, 0a, 01, 37, 01, 00, 0a, 01, 01, 09, 00, 13, 01, 00, 16, 00, 1f, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 14, 01, 01, 09, 00, 15, 01, 00, 18, 00, 23, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 12, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/loops_branches.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 55, 1) to (start + 5, 2) +Number of file 0 mappings: 10 +- Code(Counter(0)) at (prev + 55, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 19) +- Code(Counter(0)) at (prev + 0, 22) to (start + 0, 31) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 20) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 21) +- Code(Counter(0)) at (prev + 0, 24) to (start + 0, 35) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 18) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 diff --git a/tests/coverage/macro_in_closure.cov-map b/tests/coverage/macro_in_closure.cov-map index 9614154a3668..4544aa50143e 100644 --- a/tests/coverage/macro_in_closure.cov-map +++ b/tests/coverage/macro_in_closure.cov-map @@ -1,18 +1,21 @@ Function name: macro_in_closure::NO_BLOCK::{closure#0} -Raw bytes (9): 0x[01, 01, 00, 01, 01, 07, 1c, 00, 2d] +Raw bytes (9): 0x[01, 01, 00, 01, 01, 07, 25, 00, 2c] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/macro_in_closure.rs Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 7, 28) to (start + 0, 45) +- Code(Counter(0)) at (prev + 7, 37) to (start + 0, 44) Highest counter ID seen: c0 Function name: macro_in_closure::WITH_BLOCK::{closure#0} -Raw bytes (9): 0x[01, 01, 00, 01, 01, 09, 1e, 02, 02] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 09, 1e, 00, 1f, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 15, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/macro_in_closure.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 9, 30) to (start + 2, 2) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 9, 30) to (start + 0, 31) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 21) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 diff --git a/tests/coverage/macro_name_span.cov-map b/tests/coverage/macro_name_span.cov-map index bd033faa5510..c96cb75846b2 100644 --- a/tests/coverage/macro_name_span.cov-map +++ b/tests/coverage/macro_name_span.cov-map @@ -1,18 +1,21 @@ Function name: macro_name_span::affected_function -Raw bytes (9): 0x[01, 01, 00, 01, 01, 16, 1c, 01, 3e] +Raw bytes (14): 0x[01, 01, 00, 02, 01, 16, 1c, 00, 1d, 01, 01, 09, 00, 3e] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/macro_name_span.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 22, 28) to (start + 1, 62) +Number of file 0 mappings: 2 +- Code(Counter(0)) at (prev + 22, 28) to (start + 0, 29) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 62) Highest counter ID seen: c0 Function name: macro_name_span::main -Raw bytes (9): 0x[01, 01, 00, 01, 01, 0b, 01, 02, 02] +Raw bytes (19): 0x[01, 01, 00, 03, 01, 0b, 01, 00, 0a, 01, 01, 05, 00, 16, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/macro_name_span.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 11, 1) to (start + 2, 2) +Number of file 0 mappings: 3 +- Code(Counter(0)) at (prev + 11, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 22) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 diff --git a/tests/coverage/match_or_pattern.cov-map b/tests/coverage/match_or_pattern.cov-map index ae77eedfe72e..0bb126bc09b1 100644 --- a/tests/coverage/match_or_pattern.cov-map +++ b/tests/coverage/match_or_pattern.cov-map @@ -1,7 +1,7 @@ Function name: match_or_pattern::main -Raw bytes (145): 0x[01, 01, 08, 01, 05, 01, 09, 01, 0d, 01, 11, 01, 15, 01, 19, 01, 1d, 01, 21, 19, 01, 01, 01, 08, 0f, 05, 08, 10, 03, 06, 02, 03, 05, 00, 06, 01, 01, 0b, 00, 11, 06, 03, 1b, 00, 1d, 09, 01, 0e, 00, 10, 01, 02, 08, 00, 0f, 0d, 00, 10, 03, 06, 0a, 03, 05, 00, 06, 01, 01, 0b, 00, 11, 0e, 01, 1b, 00, 1d, 11, 01, 0e, 00, 10, 01, 02, 08, 00, 0f, 15, 00, 10, 03, 06, 12, 03, 05, 00, 06, 01, 01, 0b, 00, 11, 16, 01, 1b, 00, 1d, 19, 01, 0e, 00, 10, 01, 02, 08, 00, 0f, 1d, 00, 10, 03, 06, 1a, 03, 05, 00, 06, 01, 01, 0b, 00, 11, 1e, 01, 1b, 00, 1d, 21, 01, 0e, 00, 10, 01, 02, 01, 00, 02] +Raw bytes (190): 0x[01, 01, 08, 01, 05, 01, 09, 01, 0d, 01, 11, 01, 15, 01, 19, 01, 1d, 01, 21, 22, 01, 01, 01, 00, 0a, 01, 04, 09, 00, 10, 01, 00, 13, 00, 2e, 01, 02, 09, 00, 0e, 01, 00, 10, 00, 12, 01, 00, 15, 00, 16, 01, 01, 09, 00, 0e, 01, 00, 10, 00, 12, 01, 00, 15, 00, 16, 01, 01, 08, 00, 0f, 05, 00, 10, 03, 06, 02, 03, 05, 00, 06, 01, 01, 0b, 00, 11, 06, 03, 1b, 00, 1d, 09, 01, 0e, 00, 10, 01, 02, 08, 00, 0f, 0d, 00, 10, 03, 06, 0a, 03, 05, 00, 06, 01, 01, 0b, 00, 11, 0e, 01, 1b, 00, 1d, 11, 01, 0e, 00, 10, 01, 02, 08, 00, 0f, 15, 00, 10, 03, 06, 12, 03, 05, 00, 06, 01, 01, 0b, 00, 11, 16, 01, 1b, 00, 1d, 19, 01, 0e, 00, 10, 01, 02, 08, 00, 0f, 1d, 00, 10, 03, 06, 1a, 03, 05, 00, 06, 01, 01, 0b, 00, 11, 1e, 01, 1b, 00, 1d, 21, 01, 0e, 00, 10, 01, 02, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/match_or_pattern.rs Number of expressions: 8 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(0), rhs = Counter(2) @@ -11,9 +11,18 @@ Number of expressions: 8 - expression 5 operands: lhs = Counter(0), rhs = Counter(6) - expression 6 operands: lhs = Counter(0), rhs = Counter(7) - expression 7 operands: lhs = Counter(0), rhs = Counter(8) -Number of file 0 mappings: 25 -- Code(Counter(0)) at (prev + 1, 1) to (start + 8, 15) -- Code(Counter(1)) at (prev + 8, 16) to (start + 3, 6) +Number of file 0 mappings: 34 +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 4, 9) to (start + 0, 16) +- Code(Counter(0)) at (prev + 0, 19) to (start + 0, 46) +- Code(Counter(0)) at (prev + 2, 9) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 16) to (start + 0, 18) +- Code(Counter(0)) at (prev + 0, 21) to (start + 0, 22) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 16) to (start + 0, 18) +- Code(Counter(0)) at (prev + 0, 21) to (start + 0, 22) +- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 15) +- Code(Counter(1)) at (prev + 0, 16) to (start + 3, 6) - Code(Expression(0, Sub)) at (prev + 3, 5) to (start + 0, 6) = (c0 - c1) - Code(Counter(0)) at (prev + 1, 11) to (start + 0, 17) diff --git a/tests/coverage/match_or_pattern.coverage b/tests/coverage/match_or_pattern.coverage index a65c226e5672..50540bc5614a 100644 --- a/tests/coverage/match_or_pattern.coverage +++ b/tests/coverage/match_or_pattern.coverage @@ -1,9 +1,9 @@ LL| 1|fn main() { - LL| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure - LL| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - LL| 1| // dependent conditions. + LL| | // Initialize test constants in a way that cannot be determined at compile time, to ensure + LL| | // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + LL| | // dependent conditions. LL| 1| let is_true = std::env::args().len() == 1; - LL| 1| + LL| | LL| 1| let mut a: u8 = 0; LL| 1| let mut b: u8 = 0; LL| 1| if is_true { diff --git a/tests/coverage/mcdc/condition-limit.cov-map b/tests/coverage/mcdc/condition-limit.cov-map index befe8866a592..ffee97cfbc50 100644 --- a/tests/coverage/mcdc/condition-limit.cov-map +++ b/tests/coverage/mcdc/condition-limit.cov-map @@ -1,7 +1,7 @@ Function name: condition_limit::accept_7_conditions -Raw bytes (147): 0x[01, 01, 08, 01, 05, 05, 09, 09, 0d, 0d, 11, 11, 15, 15, 19, 19, 1d, 01, 1d, 12, 01, 06, 01, 02, 09, 28, 08, 07, 02, 08, 00, 27, 30, 05, 02, 01, 07, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 09, 06, 07, 06, 00, 00, 0d, 00, 0e, 09, 00, 12, 00, 13, 30, 0d, 0a, 06, 05, 00, 00, 12, 00, 13, 0d, 00, 17, 00, 18, 30, 11, 0e, 05, 04, 00, 00, 17, 00, 18, 11, 00, 1c, 00, 1d, 30, 15, 12, 04, 03, 00, 00, 1c, 00, 1d, 15, 00, 21, 00, 22, 30, 19, 16, 03, 02, 00, 00, 21, 00, 22, 19, 00, 26, 00, 27, 30, 1d, 1a, 02, 00, 00, 00, 26, 00, 27, 1d, 00, 28, 02, 06, 1e, 02, 05, 00, 06, 01, 01, 01, 00, 02] +Raw bytes (192): 0x[01, 01, 08, 01, 05, 05, 09, 09, 0d, 0d, 11, 11, 15, 15, 19, 19, 1d, 01, 1d, 1b, 01, 06, 01, 00, 2c, 01, 01, 0a, 00, 0b, 01, 00, 0d, 00, 0e, 01, 00, 10, 00, 11, 01, 00, 13, 00, 14, 01, 00, 16, 00, 17, 01, 00, 19, 00, 1a, 01, 00, 1c, 00, 1d, 01, 00, 21, 00, 29, 01, 01, 08, 00, 09, 28, 08, 07, 00, 08, 00, 27, 30, 05, 02, 01, 07, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 09, 06, 07, 06, 00, 00, 0d, 00, 0e, 09, 00, 12, 00, 13, 30, 0d, 0a, 06, 05, 00, 00, 12, 00, 13, 0d, 00, 17, 00, 18, 30, 11, 0e, 05, 04, 00, 00, 17, 00, 18, 11, 00, 1c, 00, 1d, 30, 15, 12, 04, 03, 00, 00, 1c, 00, 1d, 15, 00, 21, 00, 22, 30, 19, 16, 03, 02, 00, 00, 21, 00, 22, 19, 00, 26, 00, 27, 30, 1d, 1a, 02, 00, 00, 00, 26, 00, 27, 1d, 00, 28, 02, 06, 1e, 02, 05, 00, 06, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/condition-limit.rs Number of expressions: 8 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Counter(2) @@ -11,9 +11,18 @@ Number of expressions: 8 - expression 5 operands: lhs = Counter(5), rhs = Counter(6) - expression 6 operands: lhs = Counter(6), rhs = Counter(7) - expression 7 operands: lhs = Counter(0), rhs = Counter(7) -Number of file 0 mappings: 18 -- Code(Counter(0)) at (prev + 6, 1) to (start + 2, 9) -- MCDCDecision { bitmap_idx: 8, conditions_num: 7 } at (prev + 2, 8) to (start + 0, 39) +Number of file 0 mappings: 27 +- Code(Counter(0)) at (prev + 6, 1) to (start + 0, 44) +- Code(Counter(0)) at (prev + 1, 10) to (start + 0, 11) +- Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 16) to (start + 0, 17) +- Code(Counter(0)) at (prev + 0, 19) to (start + 0, 20) +- Code(Counter(0)) at (prev + 0, 22) to (start + 0, 23) +- Code(Counter(0)) at (prev + 0, 25) to (start + 0, 26) +- Code(Counter(0)) at (prev + 0, 28) to (start + 0, 29) +- Code(Counter(0)) at (prev + 0, 33) to (start + 0, 41) +- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 9) +- MCDCDecision { bitmap_idx: 8, conditions_num: 7 } at (prev + 0, 8) to (start + 0, 39) - MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 7, false_next_id: 0 } at (prev + 0, 8) to (start + 0, 9) true = c1 false = (c0 - c1) diff --git a/tests/coverage/mcdc/if.cov-map b/tests/coverage/mcdc/if.cov-map index 1b038f48429e..dac1eb4c94bd 100644 --- a/tests/coverage/mcdc/if.cov-map +++ b/tests/coverage/mcdc/if.cov-map @@ -1,14 +1,15 @@ Function name: if::mcdc_check_a -Raw bytes (62): 0x[01, 01, 03, 01, 05, 05, 09, 01, 09, 08, 01, 0e, 01, 01, 09, 28, 03, 02, 01, 08, 00, 0e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 09, 06, 02, 00, 00, 00, 0d, 00, 0e, 09, 00, 0f, 02, 06, 0a, 02, 0c, 02, 06, 01, 03, 01, 00, 02] +Raw bytes (67): 0x[01, 01, 03, 01, 05, 05, 09, 01, 09, 09, 01, 0e, 01, 00, 22, 01, 01, 08, 00, 09, 28, 03, 02, 00, 08, 00, 0e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 09, 06, 02, 00, 00, 00, 0d, 00, 0e, 09, 00, 0f, 02, 06, 0a, 02, 0c, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/if.rs Number of expressions: 3 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Counter(2) - expression 2 operands: lhs = Counter(0), rhs = Counter(2) -Number of file 0 mappings: 8 -- Code(Counter(0)) at (prev + 14, 1) to (start + 1, 9) -- MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 1, 8) to (start + 0, 14) +Number of file 0 mappings: 9 +- Code(Counter(0)) at (prev + 14, 1) to (start + 0, 34) +- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 9) +- MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 0, 8) to (start + 0, 14) - MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 8) to (start + 0, 9) true = c1 false = (c0 - c1) @@ -23,16 +24,17 @@ Number of file 0 mappings: 8 Highest counter ID seen: c2 Function name: if::mcdc_check_b -Raw bytes (62): 0x[01, 01, 03, 01, 05, 05, 09, 01, 09, 08, 01, 16, 01, 01, 09, 28, 03, 02, 01, 08, 00, 0e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 09, 06, 02, 00, 00, 00, 0d, 00, 0e, 09, 00, 0f, 02, 06, 0a, 02, 0c, 02, 06, 01, 03, 01, 00, 02] +Raw bytes (67): 0x[01, 01, 03, 01, 05, 05, 09, 01, 09, 09, 01, 16, 01, 00, 22, 01, 01, 08, 00, 09, 28, 03, 02, 00, 08, 00, 0e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 09, 06, 02, 00, 00, 00, 0d, 00, 0e, 09, 00, 0f, 02, 06, 0a, 02, 0c, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/if.rs Number of expressions: 3 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Counter(2) - expression 2 operands: lhs = Counter(0), rhs = Counter(2) -Number of file 0 mappings: 8 -- Code(Counter(0)) at (prev + 22, 1) to (start + 1, 9) -- MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 1, 8) to (start + 0, 14) +Number of file 0 mappings: 9 +- Code(Counter(0)) at (prev + 22, 1) to (start + 0, 34) +- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 9) +- MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 0, 8) to (start + 0, 14) - MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 8) to (start + 0, 9) true = c1 false = (c0 - c1) @@ -47,16 +49,17 @@ Number of file 0 mappings: 8 Highest counter ID seen: c2 Function name: if::mcdc_check_both -Raw bytes (62): 0x[01, 01, 03, 01, 05, 05, 09, 01, 09, 08, 01, 1e, 01, 01, 09, 28, 03, 02, 01, 08, 00, 0e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 09, 06, 02, 00, 00, 00, 0d, 00, 0e, 09, 00, 0f, 02, 06, 0a, 02, 0c, 02, 06, 01, 03, 01, 00, 02] +Raw bytes (67): 0x[01, 01, 03, 01, 05, 05, 09, 01, 09, 09, 01, 1e, 01, 00, 25, 01, 01, 08, 00, 09, 28, 03, 02, 00, 08, 00, 0e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 09, 06, 02, 00, 00, 00, 0d, 00, 0e, 09, 00, 0f, 02, 06, 0a, 02, 0c, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/if.rs Number of expressions: 3 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Counter(2) - expression 2 operands: lhs = Counter(0), rhs = Counter(2) -Number of file 0 mappings: 8 -- Code(Counter(0)) at (prev + 30, 1) to (start + 1, 9) -- MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 1, 8) to (start + 0, 14) +Number of file 0 mappings: 9 +- Code(Counter(0)) at (prev + 30, 1) to (start + 0, 37) +- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 9) +- MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 0, 8) to (start + 0, 14) - MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 8) to (start + 0, 9) true = c1 false = (c0 - c1) @@ -71,16 +74,17 @@ Number of file 0 mappings: 8 Highest counter ID seen: c2 Function name: if::mcdc_check_neither -Raw bytes (62): 0x[01, 01, 03, 01, 05, 05, 09, 01, 09, 08, 01, 06, 01, 01, 09, 28, 03, 02, 01, 08, 00, 0e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 09, 06, 02, 00, 00, 00, 0d, 00, 0e, 09, 00, 0f, 02, 06, 0a, 02, 0c, 02, 06, 01, 03, 01, 00, 02] +Raw bytes (67): 0x[01, 01, 03, 01, 05, 05, 09, 01, 09, 09, 01, 06, 01, 00, 28, 01, 01, 08, 00, 09, 28, 03, 02, 00, 08, 00, 0e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 05, 00, 0d, 00, 0e, 30, 09, 06, 02, 00, 00, 00, 0d, 00, 0e, 09, 00, 0f, 02, 06, 0a, 02, 0c, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/if.rs Number of expressions: 3 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Counter(2) - expression 2 operands: lhs = Counter(0), rhs = Counter(2) -Number of file 0 mappings: 8 -- Code(Counter(0)) at (prev + 6, 1) to (start + 1, 9) -- MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 1, 8) to (start + 0, 14) +Number of file 0 mappings: 9 +- Code(Counter(0)) at (prev + 6, 1) to (start + 0, 40) +- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 9) +- MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 0, 8) to (start + 0, 14) - MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 8) to (start + 0, 9) true = c1 false = (c0 - c1) @@ -95,9 +99,9 @@ Number of file 0 mappings: 8 Highest counter ID seen: c2 Function name: if::mcdc_check_not_tree_decision -Raw bytes (85): 0x[01, 01, 07, 01, 05, 01, 17, 05, 09, 05, 09, 17, 0d, 05, 09, 01, 0d, 0a, 01, 30, 01, 03, 0a, 28, 05, 03, 03, 08, 00, 15, 30, 05, 02, 01, 02, 03, 00, 09, 00, 0a, 02, 00, 0e, 00, 0f, 30, 09, 06, 03, 02, 00, 00, 0e, 00, 0f, 17, 00, 14, 00, 15, 30, 0d, 12, 02, 00, 00, 00, 14, 00, 15, 0d, 00, 16, 02, 06, 1a, 02, 0c, 02, 06, 01, 03, 01, 00, 02] +Raw bytes (90): 0x[01, 01, 07, 01, 05, 01, 17, 05, 09, 05, 09, 17, 0d, 05, 09, 01, 0d, 0b, 01, 30, 01, 00, 3b, 28, 05, 03, 03, 08, 00, 15, 01, 00, 09, 00, 0a, 30, 05, 02, 01, 02, 03, 00, 09, 00, 0a, 02, 00, 0e, 00, 0f, 30, 09, 06, 03, 02, 00, 00, 0e, 00, 0f, 17, 00, 14, 00, 15, 30, 0d, 12, 02, 00, 00, 00, 14, 00, 15, 0d, 00, 16, 02, 06, 1a, 02, 0c, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/if.rs Number of expressions: 7 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(0), rhs = Expression(5, Add) @@ -106,9 +110,10 @@ Number of expressions: 7 - expression 4 operands: lhs = Expression(5, Add), rhs = Counter(3) - expression 5 operands: lhs = Counter(1), rhs = Counter(2) - expression 6 operands: lhs = Counter(0), rhs = Counter(3) -Number of file 0 mappings: 10 -- Code(Counter(0)) at (prev + 48, 1) to (start + 3, 10) +Number of file 0 mappings: 11 +- Code(Counter(0)) at (prev + 48, 1) to (start + 0, 59) - MCDCDecision { bitmap_idx: 5, conditions_num: 3 } at (prev + 3, 8) to (start + 0, 21) +- Code(Counter(0)) at (prev + 0, 9) to (start + 0, 10) - MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 2, false_next_id: 3 } at (prev + 0, 9) to (start + 0, 10) true = c1 false = (c0 - c1) @@ -129,9 +134,9 @@ Number of file 0 mappings: 10 Highest counter ID seen: c3 Function name: if::mcdc_check_tree_decision -Raw bytes (87): 0x[01, 01, 08, 01, 05, 05, 09, 05, 09, 05, 1f, 09, 0d, 09, 0d, 01, 1f, 09, 0d, 0a, 01, 26, 01, 03, 09, 28, 04, 03, 03, 08, 00, 15, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 05, 00, 0e, 00, 0f, 30, 09, 0a, 02, 00, 03, 00, 0e, 00, 0f, 0a, 00, 13, 00, 14, 30, 0d, 0e, 03, 00, 00, 00, 13, 00, 14, 1f, 00, 16, 02, 06, 1a, 02, 0c, 02, 06, 01, 03, 01, 00, 02] +Raw bytes (92): 0x[01, 01, 08, 01, 05, 05, 09, 05, 09, 05, 1f, 09, 0d, 09, 0d, 01, 1f, 09, 0d, 0b, 01, 26, 01, 00, 37, 01, 03, 08, 00, 09, 28, 04, 03, 00, 08, 00, 15, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 05, 00, 0e, 00, 0f, 30, 09, 0a, 02, 00, 03, 00, 0e, 00, 0f, 0a, 00, 13, 00, 14, 30, 0d, 0e, 03, 00, 00, 00, 13, 00, 14, 1f, 00, 16, 02, 06, 1a, 02, 0c, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/if.rs Number of expressions: 8 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Counter(2) @@ -141,9 +146,10 @@ Number of expressions: 8 - expression 5 operands: lhs = Counter(2), rhs = Counter(3) - expression 6 operands: lhs = Counter(0), rhs = Expression(7, Add) - expression 7 operands: lhs = Counter(2), rhs = Counter(3) -Number of file 0 mappings: 10 -- Code(Counter(0)) at (prev + 38, 1) to (start + 3, 9) -- MCDCDecision { bitmap_idx: 4, conditions_num: 3 } at (prev + 3, 8) to (start + 0, 21) +Number of file 0 mappings: 11 +- Code(Counter(0)) at (prev + 38, 1) to (start + 0, 55) +- Code(Counter(0)) at (prev + 3, 8) to (start + 0, 9) +- MCDCDecision { bitmap_idx: 4, conditions_num: 3 } at (prev + 0, 8) to (start + 0, 21) - MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 8) to (start + 0, 9) true = c1 false = (c0 - c1) @@ -164,46 +170,53 @@ Number of file 0 mappings: 10 Highest counter ID seen: c3 Function name: if::mcdc_nested_if -Raw bytes (120): 0x[01, 01, 0b, 01, 05, 01, 2b, 05, 09, 05, 09, 2b, 0d, 05, 09, 0d, 11, 2b, 11, 05, 09, 01, 2b, 05, 09, 0e, 01, 3a, 01, 01, 09, 28, 03, 02, 01, 08, 00, 0e, 30, 05, 02, 01, 00, 02, 00, 08, 00, 09, 02, 00, 0d, 00, 0e, 30, 09, 26, 02, 00, 00, 00, 0d, 00, 0e, 2b, 01, 09, 01, 0d, 28, 06, 02, 01, 0c, 00, 12, 30, 0d, 12, 01, 02, 00, 00, 0c, 00, 0d, 0d, 00, 11, 00, 12, 30, 11, 1a, 02, 00, 00, 00, 11, 00, 12, 11, 00, 13, 02, 0a, 1e, 02, 09, 00, 0a, 26, 01, 0c, 02, 06, 01, 03, 01, 00, 02] +Raw bytes (139): 0x[01, 01, 0d, 01, 05, 01, 33, 05, 09, 05, 09, 05, 09, 05, 09, 33, 0d, 05, 09, 0d, 11, 33, 11, 05, 09, 01, 33, 05, 09, 11, 01, 3a, 01, 00, 2d, 01, 01, 08, 00, 09, 28, 03, 02, 00, 08, 00, 0e, 30, 05, 02, 01, 00, 02, 00, 08, 00, 09, 02, 00, 0d, 00, 0e, 30, 09, 2e, 02, 00, 00, 00, 0d, 00, 0e, 33, 01, 09, 00, 0c, 33, 00, 0d, 00, 15, 33, 01, 0c, 00, 0d, 28, 06, 02, 00, 0c, 00, 12, 30, 0d, 1a, 01, 02, 00, 00, 0c, 00, 0d, 0d, 00, 11, 00, 12, 30, 11, 22, 02, 00, 00, 00, 11, 00, 12, 11, 00, 13, 02, 0a, 26, 02, 09, 00, 0a, 2e, 01, 0c, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 -Number of expressions: 11 +- file 0 => $DIR/if.rs +Number of expressions: 13 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -- expression 1 operands: lhs = Counter(0), rhs = Expression(10, Add) +- expression 1 operands: lhs = Counter(0), rhs = Expression(12, Add) - expression 2 operands: lhs = Counter(1), rhs = Counter(2) - expression 3 operands: lhs = Counter(1), rhs = Counter(2) -- expression 4 operands: lhs = Expression(10, Add), rhs = Counter(3) +- expression 4 operands: lhs = Counter(1), rhs = Counter(2) - expression 5 operands: lhs = Counter(1), rhs = Counter(2) -- expression 6 operands: lhs = Counter(3), rhs = Counter(4) -- expression 7 operands: lhs = Expression(10, Add), rhs = Counter(4) -- expression 8 operands: lhs = Counter(1), rhs = Counter(2) -- expression 9 operands: lhs = Counter(0), rhs = Expression(10, Add) +- expression 6 operands: lhs = Expression(12, Add), rhs = Counter(3) +- expression 7 operands: lhs = Counter(1), rhs = Counter(2) +- expression 8 operands: lhs = Counter(3), rhs = Counter(4) +- expression 9 operands: lhs = Expression(12, Add), rhs = Counter(4) - expression 10 operands: lhs = Counter(1), rhs = Counter(2) -Number of file 0 mappings: 14 -- Code(Counter(0)) at (prev + 58, 1) to (start + 1, 9) -- MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 1, 8) to (start + 0, 14) +- expression 11 operands: lhs = Counter(0), rhs = Expression(12, Add) +- expression 12 operands: lhs = Counter(1), rhs = Counter(2) +Number of file 0 mappings: 17 +- Code(Counter(0)) at (prev + 58, 1) to (start + 0, 45) +- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 9) +- MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 0, 8) to (start + 0, 14) - MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 0, false_next_id: 2 } at (prev + 0, 8) to (start + 0, 9) true = c1 false = (c0 - c1) - Code(Expression(0, Sub)) at (prev + 0, 13) to (start + 0, 14) = (c0 - c1) -- MCDCBranch { true: Counter(2), false: Expression(9, Sub), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 13) to (start + 0, 14) +- MCDCBranch { true: Counter(2), false: Expression(11, Sub), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 13) to (start + 0, 14) true = c2 false = (c0 - (c1 + c2)) -- Code(Expression(10, Add)) at (prev + 1, 9) to (start + 1, 13) +- Code(Expression(12, Add)) at (prev + 1, 9) to (start + 0, 12) = (c1 + c2) -- MCDCDecision { bitmap_idx: 6, conditions_num: 2 } at (prev + 1, 12) to (start + 0, 18) -- MCDCBranch { true: Counter(3), false: Expression(4, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 12) to (start + 0, 13) +- Code(Expression(12, Add)) at (prev + 0, 13) to (start + 0, 21) + = (c1 + c2) +- Code(Expression(12, Add)) at (prev + 1, 12) to (start + 0, 13) + = (c1 + c2) +- MCDCDecision { bitmap_idx: 6, conditions_num: 2 } at (prev + 0, 12) to (start + 0, 18) +- MCDCBranch { true: Counter(3), false: Expression(6, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 12) to (start + 0, 13) true = c3 false = ((c1 + c2) - c3) - Code(Counter(3)) at (prev + 0, 17) to (start + 0, 18) -- MCDCBranch { true: Counter(4), false: Expression(6, Sub), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 17) to (start + 0, 18) +- MCDCBranch { true: Counter(4), false: Expression(8, Sub), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 17) to (start + 0, 18) true = c4 false = (c3 - c4) - Code(Counter(4)) at (prev + 0, 19) to (start + 2, 10) -- Code(Expression(7, Sub)) at (prev + 2, 9) to (start + 0, 10) +- Code(Expression(9, Sub)) at (prev + 2, 9) to (start + 0, 10) = ((c1 + c2) - c4) -- Code(Expression(9, Sub)) at (prev + 1, 12) to (start + 2, 6) +- Code(Expression(11, Sub)) at (prev + 1, 12) to (start + 2, 6) = (c0 - (c1 + c2)) - Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2) Highest counter ID seen: c4 diff --git a/tests/coverage/mcdc/if.coverage b/tests/coverage/mcdc/if.coverage index 51917d060454..fda5525c472c 100644 --- a/tests/coverage/mcdc/if.coverage +++ b/tests/coverage/mcdc/if.coverage @@ -123,8 +123,8 @@ LL| 3|} LL| | LL| 4|fn mcdc_check_tree_decision(a: bool, b: bool, c: bool) { - LL| 4| // This expression is intentionally written in a way - LL| 4| // where 100% branch coverage indicates 100% mcdc coverage. + LL| | // This expression is intentionally written in a way + LL| | // where 100% branch coverage indicates 100% mcdc coverage. LL| 4| if a && (b || c) { ^3 ^2 ------------------ @@ -160,8 +160,8 @@ LL| 4|} LL| | LL| 4|fn mcdc_check_not_tree_decision(a: bool, b: bool, c: bool) { - LL| 4| // Contradict to `mcdc_check_tree_decision`, - LL| 4| // 100% branch coverage of this expression does not indicate 100% mcdc coverage. + LL| | // Contradict to `mcdc_check_tree_decision`, + LL| | // 100% branch coverage of this expression does not indicate 100% mcdc coverage. LL| 4| if (a || b) && c { ^1 ------------------ diff --git a/tests/coverage/mcdc/inlined_expressions.cov-map b/tests/coverage/mcdc/inlined_expressions.cov-map index 7d78e572a3b0..d05ef368ba4a 100644 --- a/tests/coverage/mcdc/inlined_expressions.cov-map +++ b/tests/coverage/mcdc/inlined_expressions.cov-map @@ -1,13 +1,14 @@ Function name: inlined_expressions::inlined_instance -Raw bytes (50): 0x[01, 01, 02, 01, 05, 05, 09, 06, 01, 07, 01, 01, 06, 28, 03, 02, 01, 05, 00, 0b, 30, 05, 02, 01, 02, 00, 00, 05, 00, 06, 05, 00, 0a, 00, 0b, 30, 09, 06, 02, 00, 00, 00, 0a, 00, 0b, 01, 01, 01, 00, 02] +Raw bytes (55): 0x[01, 01, 02, 01, 05, 05, 09, 07, 01, 07, 01, 00, 2e, 01, 01, 05, 00, 06, 28, 03, 02, 00, 05, 00, 0b, 30, 05, 02, 01, 02, 00, 00, 05, 00, 06, 05, 00, 0a, 00, 0b, 30, 09, 06, 02, 00, 00, 00, 0a, 00, 0b, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/inlined_expressions.rs Number of expressions: 2 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Counter(2) -Number of file 0 mappings: 6 -- Code(Counter(0)) at (prev + 7, 1) to (start + 1, 6) -- MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 1, 5) to (start + 0, 11) +Number of file 0 mappings: 7 +- Code(Counter(0)) at (prev + 7, 1) to (start + 0, 46) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 6) +- MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 0, 5) to (start + 0, 11) - MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 5) to (start + 0, 6) true = c1 false = (c0 - c1) diff --git a/tests/coverage/mcdc/nested_if.cov-map b/tests/coverage/mcdc/nested_if.cov-map index 83d0739aaf59..853cdf2c5760 100644 --- a/tests/coverage/mcdc/nested_if.cov-map +++ b/tests/coverage/mcdc/nested_if.cov-map @@ -1,7 +1,7 @@ Function name: nested_if::doubly_nested_if_in_condition -Raw bytes (170): 0x[01, 01, 0f, 01, 05, 05, 11, 05, 09, 05, 37, 09, 0d, 05, 09, 05, 1f, 09, 15, 15, 19, 05, 2b, 09, 19, 09, 0d, 05, 37, 09, 0d, 01, 11, 14, 01, 0e, 01, 01, 09, 28, 09, 02, 01, 08, 00, 4e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 30, 11, 06, 02, 00, 00, 00, 0d, 00, 4e, 05, 00, 10, 00, 11, 28, 06, 02, 00, 10, 00, 36, 30, 09, 16, 01, 00, 02, 00, 10, 00, 11, 30, 0d, 32, 02, 00, 00, 00, 15, 00, 36, 16, 00, 18, 00, 19, 28, 03, 02, 00, 18, 00, 1e, 30, 15, 1a, 01, 02, 00, 00, 18, 00, 19, 15, 00, 1d, 00, 1e, 30, 19, 22, 02, 00, 00, 00, 1d, 00, 1e, 19, 00, 21, 00, 25, 26, 00, 2f, 00, 34, 37, 00, 39, 00, 3e, 32, 00, 48, 00, 4c, 11, 00, 4f, 02, 06, 3a, 02, 0c, 02, 06, 01, 03, 01, 00, 02] +Raw bytes (175): 0x[01, 01, 0f, 01, 05, 05, 11, 05, 09, 05, 37, 09, 0d, 05, 09, 05, 1f, 09, 15, 15, 19, 05, 2b, 09, 19, 09, 0d, 05, 37, 09, 0d, 01, 11, 15, 01, 0e, 01, 00, 45, 01, 01, 08, 00, 09, 28, 09, 02, 00, 08, 00, 4e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 30, 11, 06, 02, 00, 00, 00, 0d, 00, 4e, 05, 00, 10, 00, 11, 28, 06, 02, 00, 10, 00, 36, 30, 09, 16, 01, 00, 02, 00, 10, 00, 11, 30, 0d, 32, 02, 00, 00, 00, 15, 00, 36, 16, 00, 18, 00, 19, 28, 03, 02, 00, 18, 00, 1e, 30, 15, 1a, 01, 02, 00, 00, 18, 00, 19, 15, 00, 1d, 00, 1e, 30, 19, 22, 02, 00, 00, 00, 1d, 00, 1e, 19, 00, 21, 00, 25, 26, 00, 2f, 00, 34, 37, 00, 39, 00, 3e, 32, 00, 48, 00, 4c, 11, 00, 4f, 02, 06, 3a, 02, 0c, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/nested_if.rs Number of expressions: 15 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Counter(4) @@ -18,9 +18,10 @@ Number of expressions: 15 - expression 12 operands: lhs = Counter(1), rhs = Expression(13, Add) - expression 13 operands: lhs = Counter(2), rhs = Counter(3) - expression 14 operands: lhs = Counter(0), rhs = Counter(4) -Number of file 0 mappings: 20 -- Code(Counter(0)) at (prev + 14, 1) to (start + 1, 9) -- MCDCDecision { bitmap_idx: 9, conditions_num: 2 } at (prev + 1, 8) to (start + 0, 78) +Number of file 0 mappings: 21 +- Code(Counter(0)) at (prev + 14, 1) to (start + 0, 69) +- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 9) +- MCDCDecision { bitmap_idx: 9, conditions_num: 2 } at (prev + 0, 8) to (start + 0, 78) - MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 8) to (start + 0, 9) true = c1 false = (c0 - c1) @@ -59,9 +60,9 @@ Number of file 0 mappings: 20 Highest counter ID seen: c6 Function name: nested_if::nested_if_in_condition -Raw bytes (118): 0x[01, 01, 0a, 01, 05, 05, 11, 05, 09, 05, 09, 05, 23, 09, 0d, 09, 0d, 05, 23, 09, 0d, 01, 11, 0e, 01, 06, 01, 01, 09, 28, 06, 02, 01, 08, 00, 2e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 30, 11, 06, 02, 00, 00, 00, 0d, 00, 2e, 05, 00, 10, 00, 11, 28, 03, 02, 00, 10, 00, 16, 30, 09, 0e, 01, 00, 02, 00, 10, 00, 11, 0e, 00, 15, 00, 16, 30, 0d, 1e, 02, 00, 00, 00, 15, 00, 16, 23, 00, 19, 00, 1d, 1e, 00, 27, 00, 2c, 11, 00, 2f, 02, 06, 26, 02, 0c, 02, 06, 01, 03, 01, 00, 02] +Raw bytes (123): 0x[01, 01, 0a, 01, 05, 05, 11, 05, 09, 05, 09, 05, 23, 09, 0d, 09, 0d, 05, 23, 09, 0d, 01, 11, 0f, 01, 06, 01, 00, 35, 01, 01, 08, 00, 09, 28, 06, 02, 00, 08, 00, 2e, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 30, 11, 06, 02, 00, 00, 00, 0d, 00, 2e, 05, 00, 10, 00, 11, 28, 03, 02, 00, 10, 00, 16, 30, 09, 0e, 01, 00, 02, 00, 10, 00, 11, 0e, 00, 15, 00, 16, 30, 0d, 1e, 02, 00, 00, 00, 15, 00, 16, 23, 00, 19, 00, 1d, 1e, 00, 27, 00, 2c, 11, 00, 2f, 02, 06, 26, 02, 0c, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/nested_if.rs Number of expressions: 10 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Counter(4) @@ -73,9 +74,10 @@ Number of expressions: 10 - expression 7 operands: lhs = Counter(1), rhs = Expression(8, Add) - expression 8 operands: lhs = Counter(2), rhs = Counter(3) - expression 9 operands: lhs = Counter(0), rhs = Counter(4) -Number of file 0 mappings: 14 -- Code(Counter(0)) at (prev + 6, 1) to (start + 1, 9) -- MCDCDecision { bitmap_idx: 6, conditions_num: 2 } at (prev + 1, 8) to (start + 0, 46) +Number of file 0 mappings: 15 +- Code(Counter(0)) at (prev + 6, 1) to (start + 0, 53) +- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 9) +- MCDCDecision { bitmap_idx: 6, conditions_num: 2 } at (prev + 0, 8) to (start + 0, 46) - MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 8) to (start + 0, 9) true = c1 false = (c0 - c1) @@ -103,9 +105,9 @@ Number of file 0 mappings: 14 Highest counter ID seen: c4 Function name: nested_if::nested_in_then_block_in_condition -Raw bytes (170): 0x[01, 01, 0f, 01, 05, 05, 19, 05, 09, 05, 09, 05, 37, 09, 0d, 09, 0d, 37, 11, 09, 0d, 11, 15, 37, 15, 09, 0d, 05, 37, 09, 0d, 01, 19, 14, 01, 21, 01, 01, 09, 28, 09, 02, 01, 08, 00, 4b, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 30, 19, 06, 02, 00, 00, 00, 0d, 00, 4b, 05, 00, 10, 00, 11, 28, 03, 02, 00, 10, 00, 16, 30, 09, 0e, 01, 00, 02, 00, 10, 00, 11, 0e, 00, 15, 00, 16, 30, 0d, 32, 02, 00, 00, 00, 15, 00, 16, 37, 00, 1c, 00, 1d, 28, 06, 02, 00, 1c, 00, 22, 30, 11, 1e, 01, 02, 00, 00, 1c, 00, 1d, 11, 00, 21, 00, 22, 30, 15, 26, 02, 00, 00, 00, 21, 00, 22, 15, 00, 25, 00, 29, 2a, 00, 33, 00, 38, 32, 00, 44, 00, 49, 19, 00, 4c, 02, 06, 3a, 02, 0c, 02, 06, 01, 03, 01, 00, 02] +Raw bytes (175): 0x[01, 01, 0f, 01, 05, 05, 19, 05, 09, 05, 09, 05, 37, 09, 0d, 09, 0d, 37, 11, 09, 0d, 11, 15, 37, 15, 09, 0d, 05, 37, 09, 0d, 01, 19, 15, 01, 21, 01, 00, 52, 01, 01, 08, 00, 09, 28, 09, 02, 00, 08, 00, 4b, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 30, 19, 06, 02, 00, 00, 00, 0d, 00, 4b, 05, 00, 10, 00, 11, 28, 03, 02, 00, 10, 00, 16, 30, 09, 0e, 01, 00, 02, 00, 10, 00, 11, 0e, 00, 15, 00, 16, 30, 0d, 32, 02, 00, 00, 00, 15, 00, 16, 37, 00, 1c, 00, 1d, 28, 06, 02, 00, 1c, 00, 22, 30, 11, 1e, 01, 02, 00, 00, 1c, 00, 1d, 11, 00, 21, 00, 22, 30, 15, 26, 02, 00, 00, 00, 21, 00, 22, 15, 00, 25, 00, 29, 2a, 00, 33, 00, 38, 32, 00, 44, 00, 49, 19, 00, 4c, 02, 06, 3a, 02, 0c, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/nested_if.rs Number of expressions: 15 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Counter(6) @@ -122,9 +124,10 @@ Number of expressions: 15 - expression 12 operands: lhs = Counter(1), rhs = Expression(13, Add) - expression 13 operands: lhs = Counter(2), rhs = Counter(3) - expression 14 operands: lhs = Counter(0), rhs = Counter(6) -Number of file 0 mappings: 20 -- Code(Counter(0)) at (prev + 33, 1) to (start + 1, 9) -- MCDCDecision { bitmap_idx: 9, conditions_num: 2 } at (prev + 1, 8) to (start + 0, 75) +Number of file 0 mappings: 21 +- Code(Counter(0)) at (prev + 33, 1) to (start + 0, 82) +- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 9) +- MCDCDecision { bitmap_idx: 9, conditions_num: 2 } at (prev + 0, 8) to (start + 0, 75) - MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 8) to (start + 0, 9) true = c1 false = (c0 - c1) @@ -163,18 +166,19 @@ Number of file 0 mappings: 20 Highest counter ID seen: c6 Function name: nested_if::nested_single_condition_decision -Raw bytes (83): 0x[01, 01, 05, 01, 05, 05, 0d, 05, 09, 05, 09, 01, 0d, 0b, 01, 16, 01, 04, 09, 28, 03, 02, 04, 08, 00, 29, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 30, 0d, 06, 02, 00, 00, 00, 0d, 00, 29, 05, 00, 10, 00, 11, 20, 09, 0e, 00, 10, 00, 11, 09, 00, 14, 00, 19, 0e, 00, 23, 00, 27, 0d, 00, 2a, 02, 06, 12, 02, 0c, 02, 06, 01, 03, 01, 00, 02] +Raw bytes (88): 0x[01, 01, 05, 01, 05, 05, 0d, 05, 09, 05, 09, 01, 0d, 0c, 01, 16, 01, 00, 36, 01, 04, 08, 00, 09, 28, 03, 02, 00, 08, 00, 29, 30, 05, 02, 01, 02, 00, 00, 08, 00, 09, 30, 0d, 06, 02, 00, 00, 00, 0d, 00, 29, 05, 00, 10, 00, 11, 20, 09, 0e, 00, 10, 00, 11, 09, 00, 14, 00, 19, 0e, 00, 23, 00, 27, 0d, 00, 2a, 02, 06, 12, 02, 0c, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/nested_if.rs Number of expressions: 5 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Counter(3) - expression 2 operands: lhs = Counter(1), rhs = Counter(2) - expression 3 operands: lhs = Counter(1), rhs = Counter(2) - expression 4 operands: lhs = Counter(0), rhs = Counter(3) -Number of file 0 mappings: 11 -- Code(Counter(0)) at (prev + 22, 1) to (start + 4, 9) -- MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 4, 8) to (start + 0, 41) +Number of file 0 mappings: 12 +- Code(Counter(0)) at (prev + 22, 1) to (start + 0, 54) +- Code(Counter(0)) at (prev + 4, 8) to (start + 0, 9) +- MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 0, 8) to (start + 0, 41) - MCDCBranch { true: Counter(1), false: Expression(0, Sub), condition_id: 1, true_next_id: 2, false_next_id: 0 } at (prev + 0, 8) to (start + 0, 9) true = c1 false = (c0 - c1) diff --git a/tests/coverage/mcdc/nested_if.coverage b/tests/coverage/mcdc/nested_if.coverage index c3ac30d22bf8..8b5179b34fee 100644 --- a/tests/coverage/mcdc/nested_if.coverage +++ b/tests/coverage/mcdc/nested_if.coverage @@ -122,9 +122,9 @@ LL| 4|} LL| | LL| 3|fn nested_single_condition_decision(a: bool, b: bool) { - LL| 3| // Decision with only 1 decision should not be instrumented by MCDC because - LL| 3| // branch-coverage is equivalent to MCDC coverage in this case, and we don't - LL| 3| // want to waste bitmap space for this. + LL| | // Decision with only 1 decision should not be instrumented by MCDC because + LL| | // branch-coverage is equivalent to MCDC coverage in this case, and we don't + LL| | // want to waste bitmap space for this. LL| 3| if a && if b { false } else { true } { ^2 ^1 ^1 ------------------ diff --git a/tests/coverage/mcdc/non_control_flow.cov-map b/tests/coverage/mcdc/non_control_flow.cov-map index 48a103b2c7d7..f06bc2ed8168 100644 --- a/tests/coverage/mcdc/non_control_flow.cov-map +++ b/tests/coverage/mcdc/non_control_flow.cov-map @@ -1,14 +1,14 @@ Function name: non_control_flow::assign_3 -Raw bytes (79): 0x[01, 01, 04, 01, 05, 01, 0b, 05, 09, 09, 0d, 0a, 01, 15, 01, 00, 28, 01, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 04, 03, 00, 0d, 00, 18, 30, 05, 02, 01, 00, 02, 00, 0d, 00, 0e, 02, 00, 12, 00, 13, 30, 09, 06, 02, 03, 00, 00, 12, 00, 13, 09, 00, 17, 00, 18, 30, 0d, 0e, 03, 00, 00, 00, 17, 00, 18, 01, 01, 05, 01, 02] +Raw bytes (89): 0x[01, 01, 04, 01, 05, 01, 0b, 05, 09, 09, 0d, 0c, 01, 15, 01, 00, 27, 01, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 04, 03, 00, 0d, 00, 18, 30, 05, 02, 01, 00, 02, 00, 0d, 00, 0e, 02, 00, 12, 00, 13, 30, 09, 06, 02, 03, 00, 00, 12, 00, 13, 09, 00, 17, 00, 18, 30, 0d, 0e, 03, 00, 00, 00, 17, 00, 18, 01, 01, 05, 00, 0e, 01, 00, 0f, 00, 10, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/non_control_flow.rs Number of expressions: 4 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(0), rhs = Expression(2, Add) - expression 2 operands: lhs = Counter(1), rhs = Counter(2) - expression 3 operands: lhs = Counter(2), rhs = Counter(3) -Number of file 0 mappings: 10 -- Code(Counter(0)) at (prev + 21, 1) to (start + 0, 40) +Number of file 0 mappings: 12 +- Code(Counter(0)) at (prev + 21, 1) to (start + 0, 39) - Code(Counter(0)) at (prev + 1, 9) to (start + 0, 10) - Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14) - MCDCDecision { bitmap_idx: 4, conditions_num: 3 } at (prev + 0, 13) to (start + 0, 24) @@ -24,21 +24,23 @@ Number of file 0 mappings: 10 - MCDCBranch { true: Counter(3), false: Expression(3, Sub), condition_id: 3, true_next_id: 0, false_next_id: 0 } at (prev + 0, 23) to (start + 0, 24) true = c3 false = (c2 - c3) -- Code(Counter(0)) at (prev + 1, 5) to (start + 1, 2) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 16) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c3 Function name: non_control_flow::assign_3_bis -Raw bytes (81): 0x[01, 01, 05, 01, 05, 05, 09, 01, 09, 01, 13, 09, 0d, 0a, 01, 1a, 01, 00, 2c, 01, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 05, 03, 00, 0d, 00, 18, 30, 05, 02, 01, 03, 02, 00, 0d, 00, 0e, 05, 00, 12, 00, 13, 30, 09, 06, 03, 00, 02, 00, 12, 00, 13, 0a, 00, 17, 00, 18, 30, 0d, 0e, 02, 00, 00, 00, 17, 00, 18, 01, 01, 05, 01, 02] +Raw bytes (91): 0x[01, 01, 05, 01, 05, 05, 09, 01, 09, 01, 13, 09, 0d, 0c, 01, 1a, 01, 00, 2b, 01, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 05, 03, 00, 0d, 00, 18, 30, 05, 02, 01, 03, 02, 00, 0d, 00, 0e, 05, 00, 12, 00, 13, 30, 09, 06, 03, 00, 02, 00, 12, 00, 13, 0a, 00, 17, 00, 18, 30, 0d, 0e, 02, 00, 00, 00, 17, 00, 18, 01, 01, 05, 00, 0e, 01, 00, 0f, 00, 10, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/non_control_flow.rs Number of expressions: 5 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Counter(2) - expression 2 operands: lhs = Counter(0), rhs = Counter(2) - expression 3 operands: lhs = Counter(0), rhs = Expression(4, Add) - expression 4 operands: lhs = Counter(2), rhs = Counter(3) -Number of file 0 mappings: 10 -- Code(Counter(0)) at (prev + 26, 1) to (start + 0, 44) +Number of file 0 mappings: 12 +- Code(Counter(0)) at (prev + 26, 1) to (start + 0, 43) - Code(Counter(0)) at (prev + 1, 9) to (start + 0, 10) - Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14) - MCDCDecision { bitmap_idx: 5, conditions_num: 3 } at (prev + 0, 13) to (start + 0, 24) @@ -54,18 +56,20 @@ Number of file 0 mappings: 10 - MCDCBranch { true: Counter(3), false: Expression(3, Sub), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 23) to (start + 0, 24) true = c3 false = (c0 - (c2 + c3)) -- Code(Counter(0)) at (prev + 1, 5) to (start + 1, 2) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 16) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c3 Function name: non_control_flow::assign_and -Raw bytes (60): 0x[01, 01, 02, 01, 05, 05, 09, 08, 01, 0b, 01, 00, 21, 01, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 03, 02, 00, 0d, 00, 13, 30, 05, 02, 01, 02, 00, 00, 0d, 00, 0e, 05, 00, 12, 00, 13, 30, 09, 06, 02, 00, 00, 00, 12, 00, 13, 01, 01, 05, 01, 02] +Raw bytes (70): 0x[01, 01, 02, 01, 05, 05, 09, 0a, 01, 0b, 01, 00, 20, 01, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 03, 02, 00, 0d, 00, 13, 30, 05, 02, 01, 02, 00, 00, 0d, 00, 0e, 05, 00, 12, 00, 13, 30, 09, 06, 02, 00, 00, 00, 12, 00, 13, 01, 01, 05, 00, 0e, 01, 00, 0f, 00, 10, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/non_control_flow.rs Number of expressions: 2 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Counter(2) -Number of file 0 mappings: 8 -- Code(Counter(0)) at (prev + 11, 1) to (start + 0, 33) +Number of file 0 mappings: 10 +- Code(Counter(0)) at (prev + 11, 1) to (start + 0, 32) - Code(Counter(0)) at (prev + 1, 9) to (start + 0, 10) - Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14) - MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 0, 13) to (start + 0, 19) @@ -76,19 +80,21 @@ Number of file 0 mappings: 8 - MCDCBranch { true: Counter(2), false: Expression(1, Sub), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 18) to (start + 0, 19) true = c2 false = (c1 - c2) -- Code(Counter(0)) at (prev + 1, 5) to (start + 1, 2) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 16) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c2 Function name: non_control_flow::assign_or -Raw bytes (62): 0x[01, 01, 03, 01, 05, 01, 0b, 05, 09, 08, 01, 10, 01, 00, 20, 01, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 03, 02, 00, 0d, 00, 13, 30, 05, 02, 01, 00, 02, 00, 0d, 00, 0e, 02, 00, 12, 00, 13, 30, 09, 06, 02, 00, 00, 00, 12, 00, 13, 01, 01, 05, 01, 02] +Raw bytes (72): 0x[01, 01, 03, 01, 05, 01, 0b, 05, 09, 0a, 01, 10, 01, 00, 1f, 01, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 03, 02, 00, 0d, 00, 13, 30, 05, 02, 01, 00, 02, 00, 0d, 00, 0e, 02, 00, 12, 00, 13, 30, 09, 06, 02, 00, 00, 00, 12, 00, 13, 01, 01, 05, 00, 0e, 01, 00, 0f, 00, 10, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/non_control_flow.rs Number of expressions: 3 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(0), rhs = Expression(2, Add) - expression 2 operands: lhs = Counter(1), rhs = Counter(2) -Number of file 0 mappings: 8 -- Code(Counter(0)) at (prev + 16, 1) to (start + 0, 32) +Number of file 0 mappings: 10 +- Code(Counter(0)) at (prev + 16, 1) to (start + 0, 31) - Code(Counter(0)) at (prev + 1, 9) to (start + 0, 10) - Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14) - MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 0, 13) to (start + 0, 19) @@ -100,27 +106,32 @@ Number of file 0 mappings: 8 - MCDCBranch { true: Counter(2), false: Expression(1, Sub), condition_id: 2, true_next_id: 0, false_next_id: 0 } at (prev + 0, 18) to (start + 0, 19) true = c2 false = (c0 - (c1 + c2)) -- Code(Counter(0)) at (prev + 1, 5) to (start + 1, 2) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 16) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c2 Function name: non_control_flow::foo -Raw bytes (9): 0x[01, 01, 00, 01, 01, 24, 01, 02, 02] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 24, 01, 00, 18, 01, 01, 05, 00, 0e, 01, 00, 0f, 00, 10, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/non_control_flow.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 36, 1) to (start + 2, 2) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 36, 1) to (start + 0, 24) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 16) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: non_control_flow::func_call -Raw bytes (60): 0x[01, 01, 02, 01, 05, 05, 09, 08, 01, 28, 01, 00, 20, 01, 01, 05, 00, 08, 01, 00, 09, 00, 0a, 28, 03, 02, 00, 09, 00, 0f, 30, 05, 02, 01, 02, 00, 00, 09, 00, 0a, 05, 00, 0e, 00, 0f, 30, 09, 06, 02, 00, 00, 00, 0e, 00, 0f, 01, 01, 01, 00, 02] +Raw bytes (60): 0x[01, 01, 02, 01, 05, 05, 09, 08, 01, 28, 01, 00, 1f, 01, 01, 05, 00, 08, 01, 00, 09, 00, 0a, 28, 03, 02, 00, 09, 00, 0f, 30, 05, 02, 01, 02, 00, 00, 09, 00, 0a, 05, 00, 0e, 00, 0f, 30, 09, 06, 02, 00, 00, 00, 0e, 00, 0f, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/non_control_flow.rs Number of expressions: 2 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Counter(2) Number of file 0 mappings: 8 -- Code(Counter(0)) at (prev + 40, 1) to (start + 0, 32) +- Code(Counter(0)) at (prev + 40, 1) to (start + 0, 31) - Code(Counter(0)) at (prev + 1, 5) to (start + 0, 8) - Code(Counter(0)) at (prev + 0, 9) to (start + 0, 10) - MCDCDecision { bitmap_idx: 3, conditions_num: 2 } at (prev + 0, 9) to (start + 0, 15) @@ -135,17 +146,17 @@ Number of file 0 mappings: 8 Highest counter ID seen: c2 Function name: non_control_flow::right_comb_tree -Raw bytes (111): 0x[01, 01, 05, 01, 05, 05, 09, 09, 0d, 0d, 11, 11, 15, 0e, 01, 1f, 01, 00, 41, 01, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 06, 05, 00, 0d, 00, 2a, 30, 05, 02, 01, 02, 00, 00, 0d, 00, 0e, 05, 00, 13, 00, 14, 30, 09, 06, 02, 03, 00, 00, 13, 00, 14, 09, 00, 19, 00, 1a, 30, 0d, 0a, 03, 04, 00, 00, 19, 00, 1a, 0d, 00, 1f, 00, 20, 30, 11, 0e, 04, 05, 00, 00, 1f, 00, 20, 11, 00, 24, 00, 27, 30, 15, 12, 05, 00, 00, 00, 24, 00, 27, 01, 01, 05, 01, 02] +Raw bytes (121): 0x[01, 01, 05, 01, 05, 05, 09, 09, 0d, 0d, 11, 11, 15, 10, 01, 1f, 01, 00, 40, 01, 01, 09, 00, 0a, 01, 00, 0d, 00, 0e, 28, 06, 05, 00, 0d, 00, 2a, 30, 05, 02, 01, 02, 00, 00, 0d, 00, 0e, 05, 00, 13, 00, 14, 30, 09, 06, 02, 03, 00, 00, 13, 00, 14, 09, 00, 19, 00, 1a, 30, 0d, 0a, 03, 04, 00, 00, 19, 00, 1a, 0d, 00, 1f, 00, 20, 30, 11, 0e, 04, 05, 00, 00, 1f, 00, 20, 11, 00, 24, 00, 27, 30, 15, 12, 05, 00, 00, 00, 24, 00, 27, 01, 01, 05, 00, 0e, 01, 00, 0f, 00, 10, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/non_control_flow.rs Number of expressions: 5 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Counter(2) - expression 2 operands: lhs = Counter(2), rhs = Counter(3) - expression 3 operands: lhs = Counter(3), rhs = Counter(4) - expression 4 operands: lhs = Counter(4), rhs = Counter(5) -Number of file 0 mappings: 14 -- Code(Counter(0)) at (prev + 31, 1) to (start + 0, 65) +Number of file 0 mappings: 16 +- Code(Counter(0)) at (prev + 31, 1) to (start + 0, 64) - Code(Counter(0)) at (prev + 1, 9) to (start + 0, 10) - Code(Counter(0)) at (prev + 0, 13) to (start + 0, 14) - MCDCDecision { bitmap_idx: 6, conditions_num: 5 } at (prev + 0, 13) to (start + 0, 42) @@ -168,6 +179,8 @@ Number of file 0 mappings: 14 - MCDCBranch { true: Counter(5), false: Expression(4, Sub), condition_id: 5, true_next_id: 0, false_next_id: 0 } at (prev + 0, 36) to (start + 0, 39) true = c5 false = (c4 - c5) -- Code(Counter(0)) at (prev + 1, 5) to (start + 1, 2) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 16) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c5 diff --git a/tests/coverage/nested_loops.cov-map b/tests/coverage/nested_loops.cov-map index e9e41bd53e78..649c65d8590b 100644 --- a/tests/coverage/nested_loops.cov-map +++ b/tests/coverage/nested_loops.cov-map @@ -1,40 +1,60 @@ Function name: nested_loops::main -Raw bytes (97): 0x[01, 01, 0e, 07, 2f, 05, 11, 01, 0d, 2f, 05, 01, 0d, 27, 05, 01, 09, 33, 27, 05, 15, 01, 09, 2f, 33, 01, 0d, 05, 15, 05, 01, 0d, 01, 01, 01, 02, 1b, 05, 04, 13, 00, 20, 09, 01, 0d, 01, 18, 0d, 02, 12, 00, 17, 11, 01, 10, 00, 16, 02, 01, 11, 00, 16, 0e, 01, 0e, 03, 16, 15, 04, 11, 01, 1b, 16, 02, 15, 00, 21, 1e, 01, 18, 02, 12, 2a, 03, 0d, 00, 0e, 36, 02, 09, 00, 17, 01, 02, 01, 00, 02] +Raw bytes (164): 0x[01, 01, 14, 07, 47, 05, 11, 01, 0d, 47, 05, 01, 0d, 47, 05, 01, 0d, 47, 05, 01, 0d, 47, 05, 01, 0d, 3f, 05, 01, 09, 4b, 3f, 05, 15, 01, 09, 47, 4b, 01, 0d, 05, 15, 05, 01, 18, 01, 01, 01, 00, 0a, 01, 01, 09, 00, 10, 01, 00, 13, 00, 2e, 01, 01, 09, 00, 16, 01, 00, 19, 00, 1b, 05, 02, 13, 00, 20, 09, 01, 0d, 00, 12, 09, 00, 15, 00, 18, 09, 01, 0d, 00, 12, 09, 00, 15, 00, 18, 0d, 01, 12, 00, 17, 11, 01, 10, 00, 16, 02, 01, 11, 00, 16, 26, 01, 0d, 00, 0e, 26, 01, 0d, 00, 13, 26, 01, 0d, 00, 13, 26, 01, 10, 00, 16, 15, 01, 11, 00, 18, 15, 01, 14, 00, 1b, 2e, 01, 15, 00, 21, 36, 01, 18, 02, 12, 42, 03, 0d, 00, 0e, 4e, 02, 09, 00, 17, 01, 02, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 -Number of expressions: 14 -- expression 0 operands: lhs = Expression(1, Add), rhs = Expression(11, Add) +- file 0 => $DIR/nested_loops.rs +Number of expressions: 20 +- expression 0 operands: lhs = Expression(1, Add), rhs = Expression(17, Add) - expression 1 operands: lhs = Counter(1), rhs = Counter(4) - expression 2 operands: lhs = Counter(0), rhs = Counter(3) -- expression 3 operands: lhs = Expression(11, Add), rhs = Counter(1) +- expression 3 operands: lhs = Expression(17, Add), rhs = Counter(1) - expression 4 operands: lhs = Counter(0), rhs = Counter(3) -- expression 5 operands: lhs = Expression(9, Add), rhs = Counter(1) -- expression 6 operands: lhs = Counter(0), rhs = Counter(2) -- expression 7 operands: lhs = Expression(12, Add), rhs = Expression(9, Add) -- expression 8 operands: lhs = Counter(1), rhs = Counter(5) -- expression 9 operands: lhs = Counter(0), rhs = Counter(2) -- expression 10 operands: lhs = Expression(11, Add), rhs = Expression(12, Add) -- expression 11 operands: lhs = Counter(0), rhs = Counter(3) -- expression 12 operands: lhs = Counter(1), rhs = Counter(5) -- expression 13 operands: lhs = Counter(1), rhs = Counter(0) -Number of file 0 mappings: 13 -- Code(Counter(0)) at (prev + 1, 1) to (start + 2, 27) -- Code(Counter(1)) at (prev + 4, 19) to (start + 0, 32) -- Code(Counter(2)) at (prev + 1, 13) to (start + 1, 24) -- Code(Counter(3)) at (prev + 2, 18) to (start + 0, 23) +- expression 5 operands: lhs = Expression(17, Add), rhs = Counter(1) +- expression 6 operands: lhs = Counter(0), rhs = Counter(3) +- expression 7 operands: lhs = Expression(17, Add), rhs = Counter(1) +- expression 8 operands: lhs = Counter(0), rhs = Counter(3) +- expression 9 operands: lhs = Expression(17, Add), rhs = Counter(1) +- expression 10 operands: lhs = Counter(0), rhs = Counter(3) +- expression 11 operands: lhs = Expression(15, Add), rhs = Counter(1) +- expression 12 operands: lhs = Counter(0), rhs = Counter(2) +- expression 13 operands: lhs = Expression(18, Add), rhs = Expression(15, Add) +- expression 14 operands: lhs = Counter(1), rhs = Counter(5) +- expression 15 operands: lhs = Counter(0), rhs = Counter(2) +- expression 16 operands: lhs = Expression(17, Add), rhs = Expression(18, Add) +- expression 17 operands: lhs = Counter(0), rhs = Counter(3) +- expression 18 operands: lhs = Counter(1), rhs = Counter(5) +- expression 19 operands: lhs = Counter(1), rhs = Counter(0) +Number of file 0 mappings: 24 +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 16) +- Code(Counter(0)) at (prev + 0, 19) to (start + 0, 46) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 22) +- Code(Counter(0)) at (prev + 0, 25) to (start + 0, 27) +- Code(Counter(1)) at (prev + 2, 19) to (start + 0, 32) +- Code(Counter(2)) at (prev + 1, 13) to (start + 0, 18) +- Code(Counter(2)) at (prev + 0, 21) to (start + 0, 24) +- Code(Counter(2)) at (prev + 1, 13) to (start + 0, 18) +- Code(Counter(2)) at (prev + 0, 21) to (start + 0, 24) +- Code(Counter(3)) at (prev + 1, 18) to (start + 0, 23) - Code(Counter(4)) at (prev + 1, 16) to (start + 0, 22) - Code(Expression(0, Sub)) at (prev + 1, 17) to (start + 0, 22) = ((c1 + c4) - (c0 + c3)) -- Code(Expression(3, Sub)) at (prev + 1, 14) to (start + 3, 22) +- Code(Expression(9, Sub)) at (prev + 1, 13) to (start + 0, 14) = ((c0 + c3) - c1) -- Code(Counter(5)) at (prev + 4, 17) to (start + 1, 27) -- Code(Expression(5, Sub)) at (prev + 2, 21) to (start + 0, 33) +- Code(Expression(9, Sub)) at (prev + 1, 13) to (start + 0, 19) + = ((c0 + c3) - c1) +- Code(Expression(9, Sub)) at (prev + 1, 13) to (start + 0, 19) + = ((c0 + c3) - c1) +- Code(Expression(9, Sub)) at (prev + 1, 16) to (start + 0, 22) + = ((c0 + c3) - c1) +- Code(Counter(5)) at (prev + 1, 17) to (start + 0, 24) +- Code(Counter(5)) at (prev + 1, 20) to (start + 0, 27) +- Code(Expression(11, Sub)) at (prev + 1, 21) to (start + 0, 33) = ((c0 + c2) - c1) -- Code(Expression(7, Sub)) at (prev + 1, 24) to (start + 2, 18) +- Code(Expression(13, Sub)) at (prev + 1, 24) to (start + 2, 18) = ((c1 + c5) - (c0 + c2)) -- Code(Expression(10, Sub)) at (prev + 3, 13) to (start + 0, 14) +- Code(Expression(16, Sub)) at (prev + 3, 13) to (start + 0, 14) = ((c0 + c3) - (c1 + c5)) -- Code(Expression(13, Sub)) at (prev + 2, 9) to (start + 0, 23) +- Code(Expression(19, Sub)) at (prev + 2, 9) to (start + 0, 23) = (c1 - c0) - Code(Counter(0)) at (prev + 2, 1) to (start + 0, 2) Highest counter ID seen: c5 diff --git a/tests/coverage/no-core.cov-map b/tests/coverage/no-core.cov-map index 3a1ca4745c73..f2867008127b 100644 --- a/tests/coverage/no-core.cov-map +++ b/tests/coverage/no-core.cov-map @@ -1,9 +1,10 @@ Function name: no_core::main -Raw bytes (9): 0x[01, 01, 00, 01, 01, 0c, 01, 00, 0d] +Raw bytes (14): 0x[01, 01, 00, 02, 01, 0c, 01, 00, 0a, 01, 00, 0c, 00, 0d] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/no-core.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 12, 1) to (start + 0, 13) +Number of file 0 mappings: 2 +- Code(Counter(0)) at (prev + 12, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 0, 12) to (start + 0, 13) Highest counter ID seen: c0 diff --git a/tests/coverage/no_cov_crate.cov-map b/tests/coverage/no_cov_crate.cov-map index 244b0099544b..ca3c95fe84c4 100644 --- a/tests/coverage/no_cov_crate.cov-map +++ b/tests/coverage/no_cov_crate.cov-map @@ -1,68 +1,99 @@ Function name: no_cov_crate::add_coverage_1 -Raw bytes (9): 0x[01, 01, 00, 01, 01, 16, 01, 02, 02] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 16, 01, 00, 14, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 22, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/no_cov_crate.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 22, 1) to (start + 2, 2) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 22, 1) to (start + 0, 20) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 34) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: no_cov_crate::add_coverage_2 -Raw bytes (9): 0x[01, 01, 00, 01, 01, 1a, 01, 02, 02] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 1a, 01, 00, 14, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 22, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/no_cov_crate.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 26, 1) to (start + 2, 2) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 26, 1) to (start + 0, 20) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 34) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: no_cov_crate::add_coverage_not_called (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 1f, 01, 02, 02] +Raw bytes (24): 0x[01, 01, 00, 04, 00, 1f, 01, 00, 1d, 00, 01, 05, 00, 0d, 00, 00, 0e, 00, 26, 00, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/no_cov_crate.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 31, 1) to (start + 2, 2) +Number of file 0 mappings: 4 +- Code(Zero) at (prev + 31, 1) to (start + 0, 29) +- Code(Zero) at (prev + 1, 5) to (start + 0, 13) +- Code(Zero) at (prev + 0, 14) to (start + 0, 38) +- Code(Zero) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: (none) Function name: no_cov_crate::main -Raw bytes (9): 0x[01, 01, 00, 01, 01, 4f, 01, 0b, 02] +Raw bytes (74): 0x[01, 01, 00, 0e, 01, 4f, 01, 00, 0a, 01, 01, 09, 00, 10, 01, 00, 13, 00, 2e, 01, 02, 05, 00, 1a, 01, 01, 05, 00, 1a, 01, 01, 05, 00, 13, 01, 01, 05, 00, 13, 01, 02, 05, 00, 22, 01, 00, 23, 00, 2a, 01, 01, 05, 00, 16, 01, 00, 17, 00, 1e, 01, 01, 05, 00, 23, 01, 00, 24, 00, 2b, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/no_cov_crate.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 79, 1) to (start + 11, 2) +Number of file 0 mappings: 14 +- Code(Counter(0)) at (prev + 79, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 16) +- Code(Counter(0)) at (prev + 0, 19) to (start + 0, 46) +- Code(Counter(0)) at (prev + 2, 5) to (start + 0, 26) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 26) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 19) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 19) +- Code(Counter(0)) at (prev + 2, 5) to (start + 0, 34) +- Code(Counter(0)) at (prev + 0, 35) to (start + 0, 42) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 22) +- Code(Counter(0)) at (prev + 0, 23) to (start + 0, 30) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 35) +- Code(Counter(0)) at (prev + 0, 36) to (start + 0, 43) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: no_cov_crate::nested_fns::outer -Raw bytes (14): 0x[01, 01, 00, 02, 01, 33, 05, 02, 22, 01, 0c, 05, 00, 06] +Raw bytes (34): 0x[01, 01, 00, 06, 01, 33, 05, 00, 20, 01, 01, 09, 00, 11, 01, 00, 12, 00, 26, 01, 01, 09, 00, 1a, 01, 00, 1b, 00, 22, 01, 0a, 05, 00, 06] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/no_cov_crate.rs Number of expressions: 0 -Number of file 0 mappings: 2 -- Code(Counter(0)) at (prev + 51, 5) to (start + 2, 34) -- Code(Counter(0)) at (prev + 12, 5) to (start + 0, 6) +Number of file 0 mappings: 6 +- Code(Counter(0)) at (prev + 51, 5) to (start + 0, 32) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 17) +- Code(Counter(0)) at (prev + 0, 18) to (start + 0, 38) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 26) +- Code(Counter(0)) at (prev + 0, 27) to (start + 0, 34) +- Code(Counter(0)) at (prev + 10, 5) to (start + 0, 6) Highest counter ID seen: c0 Function name: no_cov_crate::nested_fns::outer_both_covered -Raw bytes (14): 0x[01, 01, 00, 02, 01, 41, 05, 02, 16, 01, 0b, 05, 00, 06] +Raw bytes (34): 0x[01, 01, 00, 06, 01, 41, 05, 00, 2d, 01, 01, 09, 00, 11, 01, 00, 12, 00, 26, 01, 01, 09, 00, 0e, 01, 00, 0f, 00, 16, 01, 09, 05, 00, 06] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/no_cov_crate.rs Number of expressions: 0 -Number of file 0 mappings: 2 -- Code(Counter(0)) at (prev + 65, 5) to (start + 2, 22) -- Code(Counter(0)) at (prev + 11, 5) to (start + 0, 6) +Number of file 0 mappings: 6 +- Code(Counter(0)) at (prev + 65, 5) to (start + 0, 45) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 17) +- Code(Counter(0)) at (prev + 0, 18) to (start + 0, 38) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 22) +- Code(Counter(0)) at (prev + 9, 5) to (start + 0, 6) Highest counter ID seen: c0 Function name: no_cov_crate::nested_fns::outer_both_covered::inner -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 45, 09, 01, 17, 05, 01, 18, 02, 0e, 02, 02, 14, 02, 0e, 01, 03, 09, 00, 0a] +Raw bytes (31): 0x[01, 01, 01, 01, 05, 05, 01, 45, 09, 00, 20, 01, 01, 10, 00, 17, 05, 00, 18, 02, 0e, 02, 02, 14, 02, 0e, 01, 03, 09, 00, 0a] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/no_cov_crate.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 69, 9) to (start + 1, 23) -- Code(Counter(1)) at (prev + 1, 24) to (start + 2, 14) +Number of file 0 mappings: 5 +- Code(Counter(0)) at (prev + 69, 9) to (start + 0, 32) +- Code(Counter(0)) at (prev + 1, 16) to (start + 0, 23) +- Code(Counter(1)) at (prev + 0, 24) to (start + 2, 14) - Code(Expression(0, Sub)) at (prev + 2, 20) to (start + 2, 14) = (c0 - c1) - Code(Counter(0)) at (prev + 3, 9) to (start + 0, 10) diff --git a/tests/coverage/no_cov_crate.coverage b/tests/coverage/no_cov_crate.coverage index 2a8961e6c93a..c6453e60a1a4 100644 --- a/tests/coverage/no_cov_crate.coverage +++ b/tests/coverage/no_cov_crate.coverage @@ -78,12 +78,12 @@ LL| | LL| 1|fn main() { LL| 1| let is_true = std::env::args().len() == 1; - LL| 1| + LL| | LL| 1| do_not_add_coverage_1(); LL| 1| do_not_add_coverage_2(); LL| 1| add_coverage_1(); LL| 1| add_coverage_2(); - LL| 1| + LL| | LL| 1| nested_fns::outer_not_covered(is_true); LL| 1| nested_fns::outer(is_true); LL| 1| nested_fns::outer_both_covered(is_true); diff --git a/tests/coverage/no_spans.cov-map b/tests/coverage/no_spans.cov-map index 7f43b68fa904..821976b0fab0 100644 --- a/tests/coverage/no_spans.cov-map +++ b/tests/coverage/no_spans.cov-map @@ -1,18 +1,20 @@ Function name: no_spans::affected_function -Raw bytes (9): 0x[01, 01, 00, 01, 01, 1a, 1c, 00, 1d] +Raw bytes (9): 0x[01, 01, 00, 01, 01, 15, 1c, 00, 1d] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/no_spans.rs Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 26, 28) to (start + 0, 29) +- Code(Counter(0)) at (prev + 21, 28) to (start + 0, 29) Highest counter ID seen: c0 -Function name: no_spans::affected_function::{closure#0} -Raw bytes (9): 0x[01, 01, 00, 01, 01, 1b, 0c, 00, 0e] +Function name: no_spans::main +Raw bytes (19): 0x[01, 01, 00, 03, 01, 0a, 01, 00, 0a, 01, 01, 05, 00, 1a, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/no_spans.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 27, 12) to (start + 0, 14) +Number of file 0 mappings: 3 +- Code(Counter(0)) at (prev + 10, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 26) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 diff --git a/tests/coverage/no_spans.coverage b/tests/coverage/no_spans.coverage index 19e8c2fe5b6b..cf0e47677e9a 100644 --- a/tests/coverage/no_spans.coverage +++ b/tests/coverage/no_spans.coverage @@ -1,20 +1,15 @@ LL| |#![feature(coverage_attribute)] LL| |//@ edition: 2021 LL| | - LL| |// If the span extractor can't find any relevant spans for a function, the - LL| |// refinement loop will terminate with nothing in its `prev` slot. If the - LL| |// subsequent code tries to unwrap `prev`, it will panic. + LL| |// Test that coverage instrumentation can gracefully handle functions that end + LL| |// up having no relevant spans, without crashing the compiler or causing + LL| |// `llvm-cov` to fail. LL| |// - LL| |// This scenario became more likely after #118525 started discarding spans that - LL| |// can't be un-expanded back to within the function body. - LL| |// - LL| |// Regression test for "invalid attempt to unwrap a None some_prev", as seen - LL| |// in issues such as #118643 and #118662. + LL| |// This was originally a regression test for issues such as #118643 and #118662. LL| | - LL| |#[coverage(off)] - LL| |fn main() { - LL| | affected_function()(); - LL| |} + LL| 1|fn main() { + LL| 1| affected_function()(); + LL| 1|} LL| | LL| |macro_rules! macro_that_defines_a_function { LL| | (fn $name:ident () $body:tt) => { @@ -24,7 +19,7 @@ LL| | LL| |macro_that_defines_a_function! { LL| 1| fn affected_function() { - LL| 1| || () + LL| | || () LL| | } LL| |} diff --git a/tests/coverage/no_spans.rs b/tests/coverage/no_spans.rs index e5312406f8a1..979b40719277 100644 --- a/tests/coverage/no_spans.rs +++ b/tests/coverage/no_spans.rs @@ -1,17 +1,12 @@ #![feature(coverage_attribute)] //@ edition: 2021 -// If the span extractor can't find any relevant spans for a function, the -// refinement loop will terminate with nothing in its `prev` slot. If the -// subsequent code tries to unwrap `prev`, it will panic. +// Test that coverage instrumentation can gracefully handle functions that end +// up having no relevant spans, without crashing the compiler or causing +// `llvm-cov` to fail. // -// This scenario became more likely after #118525 started discarding spans that -// can't be un-expanded back to within the function body. -// -// Regression test for "invalid attempt to unwrap a None some_prev", as seen -// in issues such as #118643 and #118662. +// This was originally a regression test for issues such as #118643 and #118662. -#[coverage(off)] fn main() { affected_function()(); } diff --git a/tests/coverage/no_spans_if_not.cov-map b/tests/coverage/no_spans_if_not.cov-map index 6c389a243172..c8aa5c7527d2 100644 --- a/tests/coverage/no_spans_if_not.cov-map +++ b/tests/coverage/no_spans_if_not.cov-map @@ -1,20 +1,23 @@ Function name: no_spans_if_not::affected_function -Raw bytes (19): 0x[01, 01, 00, 03, 01, 16, 1c, 01, 12, 01, 02, 0d, 00, 0f, 00, 02, 0d, 00, 0f] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 16, 1c, 00, 1d, 01, 01, 0c, 00, 12, 01, 01, 0d, 00, 0f, 00, 02, 0d, 00, 0f] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/no_spans_if_not.rs Number of expressions: 0 -Number of file 0 mappings: 3 -- Code(Counter(0)) at (prev + 22, 28) to (start + 1, 18) -- Code(Counter(0)) at (prev + 2, 13) to (start + 0, 15) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 22, 28) to (start + 0, 29) +- Code(Counter(0)) at (prev + 1, 12) to (start + 0, 18) +- Code(Counter(0)) at (prev + 1, 13) to (start + 0, 15) - Code(Zero) at (prev + 2, 13) to (start + 0, 15) Highest counter ID seen: c0 Function name: no_spans_if_not::main -Raw bytes (9): 0x[01, 01, 00, 01, 01, 0b, 01, 02, 02] +Raw bytes (19): 0x[01, 01, 00, 03, 01, 0b, 01, 00, 0a, 01, 01, 05, 00, 16, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/no_spans_if_not.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 11, 1) to (start + 2, 2) +Number of file 0 mappings: 3 +- Code(Counter(0)) at (prev + 11, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 22) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 diff --git a/tests/coverage/overflow.cov-map b/tests/coverage/overflow.cov-map index 1178d65de102..18b0503b9e7c 100644 --- a/tests/coverage/overflow.cov-map +++ b/tests/coverage/overflow.cov-map @@ -1,7 +1,7 @@ Function name: overflow::main -Raw bytes (61): 0x[01, 01, 06, 05, 01, 05, 17, 01, 09, 05, 13, 17, 0d, 01, 09, 09, 01, 10, 01, 01, 1b, 05, 02, 0b, 00, 18, 02, 01, 0c, 00, 1a, 09, 00, 1b, 03, 0a, 06, 03, 13, 00, 20, 0d, 00, 21, 03, 0a, 0e, 03, 09, 00, 0a, 02, 01, 09, 00, 17, 01, 02, 05, 01, 02] +Raw bytes (96): 0x[01, 01, 06, 05, 01, 05, 17, 01, 09, 05, 13, 17, 0d, 01, 09, 10, 01, 10, 01, 00, 1c, 01, 01, 09, 00, 16, 01, 00, 19, 00, 1b, 05, 01, 0b, 00, 18, 02, 01, 0c, 00, 1a, 09, 00, 1b, 03, 0a, 09, 01, 11, 00, 17, 09, 00, 1a, 00, 28, 06, 02, 13, 00, 20, 0d, 00, 21, 03, 0a, 0d, 01, 11, 00, 17, 0d, 00, 1a, 00, 28, 0e, 02, 09, 00, 0a, 02, 01, 09, 00, 17, 01, 02, 05, 00, 0b, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/overflow.rs Number of expressions: 6 - expression 0 operands: lhs = Counter(1), rhs = Counter(0) - expression 1 operands: lhs = Counter(1), rhs = Expression(5, Add) @@ -9,33 +9,50 @@ Number of expressions: 6 - expression 3 operands: lhs = Counter(1), rhs = Expression(4, Add) - expression 4 operands: lhs = Expression(5, Add), rhs = Counter(3) - expression 5 operands: lhs = Counter(0), rhs = Counter(2) -Number of file 0 mappings: 9 -- Code(Counter(0)) at (prev + 16, 1) to (start + 1, 27) -- Code(Counter(1)) at (prev + 2, 11) to (start + 0, 24) +Number of file 0 mappings: 16 +- Code(Counter(0)) at (prev + 16, 1) to (start + 0, 28) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 22) +- Code(Counter(0)) at (prev + 0, 25) to (start + 0, 27) +- Code(Counter(1)) at (prev + 1, 11) to (start + 0, 24) - Code(Expression(0, Sub)) at (prev + 1, 12) to (start + 0, 26) = (c1 - c0) - Code(Counter(2)) at (prev + 0, 27) to (start + 3, 10) -- Code(Expression(1, Sub)) at (prev + 3, 19) to (start + 0, 32) +- Code(Counter(2)) at (prev + 1, 17) to (start + 0, 23) +- Code(Counter(2)) at (prev + 0, 26) to (start + 0, 40) +- Code(Expression(1, Sub)) at (prev + 2, 19) to (start + 0, 32) = (c1 - (c0 + c2)) - Code(Counter(3)) at (prev + 0, 33) to (start + 3, 10) -- Code(Expression(3, Sub)) at (prev + 3, 9) to (start + 0, 10) +- Code(Counter(3)) at (prev + 1, 17) to (start + 0, 23) +- Code(Counter(3)) at (prev + 0, 26) to (start + 0, 40) +- Code(Expression(3, Sub)) at (prev + 2, 9) to (start + 0, 10) = (c1 - ((c0 + c2) + c3)) - Code(Expression(0, Sub)) at (prev + 1, 9) to (start + 0, 23) = (c1 - c0) -- Code(Counter(0)) at (prev + 2, 5) to (start + 1, 2) +- Code(Counter(0)) at (prev + 2, 5) to (start + 0, 11) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c3 Function name: overflow::might_overflow -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 05, 01, 01, 12, 05, 01, 13, 02, 06, 02, 02, 05, 00, 06, 01, 01, 09, 05, 02] +Raw bytes (76): 0x[01, 01, 01, 01, 05, 0e, 01, 05, 01, 00, 26, 01, 01, 08, 00, 12, 05, 00, 13, 02, 06, 02, 02, 05, 00, 06, 01, 01, 09, 00, 0f, 01, 00, 12, 00, 1e, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 26, 01, 01, 09, 00, 0f, 01, 00, 12, 00, 21, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 2f, 01, 01, 05, 00, 0b, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/overflow.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 5, 1) to (start + 1, 18) -- Code(Counter(1)) at (prev + 1, 19) to (start + 2, 6) +Number of file 0 mappings: 14 +- Code(Counter(0)) at (prev + 5, 1) to (start + 0, 38) +- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 18) +- Code(Counter(1)) at (prev + 0, 19) to (start + 2, 6) - Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 0, 6) = (c0 - c1) -- Code(Counter(0)) at (prev + 1, 9) to (start + 5, 2) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 15) +- Code(Counter(0)) at (prev + 0, 18) to (start + 0, 30) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 38) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 15) +- Code(Counter(0)) at (prev + 0, 18) to (start + 0, 33) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 47) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 11) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c1 diff --git a/tests/coverage/panic_unwind.cov-map b/tests/coverage/panic_unwind.cov-map index 18b13919fe5e..ff656d3d8d58 100644 --- a/tests/coverage/panic_unwind.cov-map +++ b/tests/coverage/panic_unwind.cov-map @@ -1,7 +1,7 @@ Function name: panic_unwind::main -Raw bytes (61): 0x[01, 01, 06, 05, 01, 05, 17, 01, 09, 05, 13, 17, 0d, 01, 09, 09, 01, 0d, 01, 01, 1b, 05, 02, 0b, 00, 18, 02, 01, 0c, 00, 1a, 09, 00, 1b, 02, 0a, 06, 02, 13, 00, 20, 0d, 00, 21, 02, 0a, 0e, 02, 09, 00, 0a, 02, 01, 09, 00, 17, 01, 02, 05, 01, 02] +Raw bytes (76): 0x[01, 01, 06, 05, 01, 05, 17, 01, 09, 05, 13, 17, 0d, 01, 09, 0c, 01, 0d, 01, 00, 1c, 01, 01, 09, 00, 16, 01, 00, 19, 00, 1b, 05, 01, 0b, 00, 18, 02, 01, 0c, 00, 1a, 09, 00, 1b, 02, 0a, 06, 02, 13, 00, 20, 0d, 00, 21, 02, 0a, 0e, 02, 09, 00, 0a, 02, 01, 09, 00, 17, 01, 02, 05, 00, 0b, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/panic_unwind.rs Number of expressions: 6 - expression 0 operands: lhs = Counter(1), rhs = Counter(0) - expression 1 operands: lhs = Counter(1), rhs = Expression(5, Add) @@ -9,9 +9,11 @@ Number of expressions: 6 - expression 3 operands: lhs = Counter(1), rhs = Expression(4, Add) - expression 4 operands: lhs = Expression(5, Add), rhs = Counter(3) - expression 5 operands: lhs = Counter(0), rhs = Counter(2) -Number of file 0 mappings: 9 -- Code(Counter(0)) at (prev + 13, 1) to (start + 1, 27) -- Code(Counter(1)) at (prev + 2, 11) to (start + 0, 24) +Number of file 0 mappings: 12 +- Code(Counter(0)) at (prev + 13, 1) to (start + 0, 28) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 22) +- Code(Counter(0)) at (prev + 0, 25) to (start + 0, 27) +- Code(Counter(1)) at (prev + 1, 11) to (start + 0, 24) - Code(Expression(0, Sub)) at (prev + 1, 12) to (start + 0, 26) = (c1 - c0) - Code(Counter(2)) at (prev + 0, 27) to (start + 2, 10) @@ -22,19 +24,25 @@ Number of file 0 mappings: 9 = (c1 - ((c0 + c2) + c3)) - Code(Expression(0, Sub)) at (prev + 1, 9) to (start + 0, 23) = (c1 - c0) -- Code(Counter(0)) at (prev + 2, 5) to (start + 1, 2) +- Code(Counter(0)) at (prev + 2, 5) to (start + 0, 11) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c3 Function name: panic_unwind::might_panic -Raw bytes (21): 0x[01, 01, 01, 01, 05, 03, 01, 04, 01, 01, 14, 05, 02, 09, 01, 0f, 02, 02, 0c, 03, 02] +Raw bytes (41): 0x[01, 01, 01, 01, 05, 07, 01, 04, 01, 00, 23, 01, 01, 08, 00, 14, 05, 01, 09, 00, 11, 05, 00, 12, 00, 20, 05, 01, 09, 00, 0f, 02, 01, 0c, 02, 06, 02, 03, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/panic_unwind.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 3 -- Code(Counter(0)) at (prev + 4, 1) to (start + 1, 20) -- Code(Counter(1)) at (prev + 2, 9) to (start + 1, 15) -- Code(Expression(0, Sub)) at (prev + 2, 12) to (start + 3, 2) +Number of file 0 mappings: 7 +- Code(Counter(0)) at (prev + 4, 1) to (start + 0, 35) +- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 20) +- Code(Counter(1)) at (prev + 1, 9) to (start + 0, 17) +- Code(Counter(1)) at (prev + 0, 18) to (start + 0, 32) +- Code(Counter(1)) at (prev + 1, 9) to (start + 0, 15) +- Code(Expression(0, Sub)) at (prev + 1, 12) to (start + 2, 6) + = (c0 - c1) +- Code(Expression(0, Sub)) at (prev + 3, 1) to (start + 0, 2) = (c0 - c1) Highest counter ID seen: c1 diff --git a/tests/coverage/partial_eq.cov-map b/tests/coverage/partial_eq.cov-map index 21c8714ac99b..0a81be749128 100644 --- a/tests/coverage/partial_eq.cov-map +++ b/tests/coverage/partial_eq.cov-map @@ -1,18 +1,29 @@ Function name: ::new -Raw bytes (9): 0x[01, 01, 00, 01, 01, 0c, 05, 02, 06] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 0c, 05, 00, 41, 01, 01, 09, 00, 25, 01, 00, 10, 00, 15, 01, 01, 05, 00, 06] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/partial_eq.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 12, 5) to (start + 2, 6) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 12, 5) to (start + 0, 65) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 37) +- Code(Counter(0)) at (prev + 0, 16) to (start + 0, 21) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 6) Highest counter ID seen: c0 Function name: partial_eq::main -Raw bytes (9): 0x[01, 01, 00, 01, 01, 11, 01, 0a, 02] +Raw bytes (49): 0x[01, 01, 00, 09, 01, 11, 01, 00, 0a, 01, 01, 09, 00, 16, 01, 00, 19, 00, 25, 01, 01, 09, 00, 16, 01, 00, 19, 00, 25, 01, 02, 05, 00, 0d, 01, 01, 09, 00, 1b, 01, 03, 09, 00, 26, 01, 02, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/partial_eq.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 17, 1) to (start + 10, 2) +Number of file 0 mappings: 9 +- Code(Counter(0)) at (prev + 17, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 22) +- Code(Counter(0)) at (prev + 0, 25) to (start + 0, 37) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 22) +- Code(Counter(0)) at (prev + 0, 25) to (start + 0, 37) +- Code(Counter(0)) at (prev + 2, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 27) +- Code(Counter(0)) at (prev + 3, 9) to (start + 0, 38) +- Code(Counter(0)) at (prev + 2, 1) to (start + 0, 2) Highest counter ID seen: c0 diff --git a/tests/coverage/partial_eq.coverage b/tests/coverage/partial_eq.coverage index dc5b82b3c5f1..0662ce2c3000 100644 --- a/tests/coverage/partial_eq.coverage +++ b/tests/coverage/partial_eq.coverage @@ -17,13 +17,13 @@ LL| 1|fn main() { LL| 1| let version_3_2_1 = Version::new(3, 2, 1); LL| 1| let version_3_3_0 = Version::new(3, 3, 0); - LL| 1| + LL| | LL| 1| println!( LL| 1| "{:?} < {:?} = {}", - LL| 1| version_3_2_1, - LL| 1| version_3_3_0, + LL| | version_3_2_1, + LL| | version_3_3_0, LL| 1| version_3_2_1 < version_3_3_0, // - LL| 1| ); + LL| | ); LL| 1|} LL| | LL| |/* diff --git a/tests/coverage/simple_loop.cov-map b/tests/coverage/simple_loop.cov-map index 8e428b267d56..5447ffdb6e7c 100644 --- a/tests/coverage/simple_loop.cov-map +++ b/tests/coverage/simple_loop.cov-map @@ -1,19 +1,27 @@ Function name: simple_loop::main -Raw bytes (43): 0x[01, 01, 02, 01, 05, 09, 01, 07, 01, 04, 01, 09, 10, 05, 0a, 05, 05, 06, 02, 05, 05, 00, 06, 09, 05, 0d, 02, 0e, 01, 04, 0d, 00, 12, 06, 02, 0a, 03, 0a, 01, 06, 01, 00, 02] +Raw bytes (75): 0x[01, 01, 03, 01, 05, 09, 01, 09, 01, 0d, 01, 04, 01, 00, 0a, 01, 04, 09, 00, 10, 01, 00, 13, 00, 2e, 01, 02, 09, 00, 16, 01, 00, 19, 00, 1a, 01, 03, 09, 00, 10, 05, 01, 05, 05, 06, 02, 05, 05, 00, 06, 09, 05, 0d, 02, 0e, 01, 04, 0d, 00, 12, 0a, 02, 09, 00, 0a, 0a, 01, 09, 02, 0a, 01, 05, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 -Number of expressions: 2 +- file 0 => $DIR/simple_loop.rs +Number of expressions: 3 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(2), rhs = Counter(0) -Number of file 0 mappings: 7 -- Code(Counter(0)) at (prev + 4, 1) to (start + 9, 16) -- Code(Counter(1)) at (prev + 10, 5) to (start + 5, 6) +- expression 2 operands: lhs = Counter(2), rhs = Counter(0) +Number of file 0 mappings: 13 +- Code(Counter(0)) at (prev + 4, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 4, 9) to (start + 0, 16) +- Code(Counter(0)) at (prev + 0, 19) to (start + 0, 46) +- Code(Counter(0)) at (prev + 2, 9) to (start + 0, 22) +- Code(Counter(0)) at (prev + 0, 25) to (start + 0, 26) +- Code(Counter(0)) at (prev + 3, 9) to (start + 0, 16) +- Code(Counter(1)) at (prev + 1, 5) to (start + 5, 6) - Code(Expression(0, Sub)) at (prev + 5, 5) to (start + 0, 6) = (c0 - c1) - Code(Counter(2)) at (prev + 5, 13) to (start + 2, 14) - Code(Counter(0)) at (prev + 4, 13) to (start + 0, 18) -- Code(Expression(1, Sub)) at (prev + 2, 10) to (start + 3, 10) +- Code(Expression(2, Sub)) at (prev + 2, 9) to (start + 0, 10) = (c2 - c0) -- Code(Counter(0)) at (prev + 6, 1) to (start + 0, 2) +- Code(Expression(2, Sub)) at (prev + 1, 9) to (start + 2, 10) + = (c2 - c0) +- Code(Counter(0)) at (prev + 5, 1) to (start + 0, 2) Highest counter ID seen: c2 diff --git a/tests/coverage/simple_loop.coverage b/tests/coverage/simple_loop.coverage index 237e509f42e1..a75263f633e5 100644 --- a/tests/coverage/simple_loop.coverage +++ b/tests/coverage/simple_loop.coverage @@ -2,14 +2,14 @@ LL| | LL| |#[rustfmt::skip] LL| 1|fn main() { - LL| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure - LL| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - LL| 1| // dependent conditions. + LL| | // Initialize test constants in a way that cannot be determined at compile time, to ensure + LL| | // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + LL| | // dependent conditions. LL| 1| let is_true = std::env::args().len() == 1; - LL| 1| + LL| | LL| 1| let mut countdown = 0; - LL| 1| - LL| 1| if + LL| | + LL| | if LL| 1| is_true LL| 1| { LL| 1| countdown diff --git a/tests/coverage/simple_match.cov-map b/tests/coverage/simple_match.cov-map index 15f114daa7fb..cbd6c7ca52fd 100644 --- a/tests/coverage/simple_match.cov-map +++ b/tests/coverage/simple_match.cov-map @@ -1,16 +1,21 @@ Function name: simple_match::main -Raw bytes (64): 0x[01, 01, 05, 01, 05, 09, 01, 09, 01, 09, 13, 01, 0d, 0a, 01, 04, 01, 07, 0f, 05, 07, 10, 02, 06, 02, 02, 05, 00, 06, 09, 05, 09, 00, 0d, 0a, 05, 0d, 00, 16, 0d, 02, 0d, 00, 0e, 0a, 02, 11, 02, 12, 0d, 04, 0d, 07, 0e, 0e, 0a, 0d, 00, 0f, 01, 03, 01, 00, 02] +Raw bytes (99): 0x[01, 01, 05, 01, 05, 09, 01, 09, 01, 09, 13, 01, 0d, 11, 01, 04, 01, 00, 0a, 01, 04, 09, 00, 10, 01, 00, 13, 00, 2e, 01, 02, 09, 00, 16, 01, 00, 19, 00, 1a, 01, 01, 08, 00, 0f, 05, 00, 10, 02, 06, 02, 02, 05, 00, 06, 09, 05, 09, 00, 0d, 0a, 05, 0d, 00, 16, 0d, 02, 0d, 00, 0e, 0a, 02, 11, 02, 12, 0d, 04, 0d, 07, 0e, 0d, 01, 11, 00, 1e, 0d, 02, 15, 00, 16, 0e, 07, 0d, 00, 0f, 01, 03, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/simple_match.rs Number of expressions: 5 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(2), rhs = Counter(0) - expression 2 operands: lhs = Counter(2), rhs = Counter(0) - expression 3 operands: lhs = Counter(2), rhs = Expression(4, Add) - expression 4 operands: lhs = Counter(0), rhs = Counter(3) -Number of file 0 mappings: 10 -- Code(Counter(0)) at (prev + 4, 1) to (start + 7, 15) -- Code(Counter(1)) at (prev + 7, 16) to (start + 2, 6) +Number of file 0 mappings: 17 +- Code(Counter(0)) at (prev + 4, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 4, 9) to (start + 0, 16) +- Code(Counter(0)) at (prev + 0, 19) to (start + 0, 46) +- Code(Counter(0)) at (prev + 2, 9) to (start + 0, 22) +- Code(Counter(0)) at (prev + 0, 25) to (start + 0, 26) +- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 15) +- Code(Counter(1)) at (prev + 0, 16) to (start + 2, 6) - Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 0, 6) = (c0 - c1) - Code(Counter(2)) at (prev + 5, 9) to (start + 0, 13) @@ -20,7 +25,9 @@ Number of file 0 mappings: 10 - Code(Expression(2, Sub)) at (prev + 2, 17) to (start + 2, 18) = (c2 - c0) - Code(Counter(3)) at (prev + 4, 13) to (start + 7, 14) -- Code(Expression(3, Sub)) at (prev + 10, 13) to (start + 0, 15) +- Code(Counter(3)) at (prev + 1, 17) to (start + 0, 30) +- Code(Counter(3)) at (prev + 2, 21) to (start + 0, 22) +- Code(Expression(3, Sub)) at (prev + 7, 13) to (start + 0, 15) = (c2 - (c0 + c3)) - Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2) Highest counter ID seen: c3 diff --git a/tests/coverage/simple_match.coverage b/tests/coverage/simple_match.coverage index e1d5e48a2bf1..0ed7e8dc7887 100644 --- a/tests/coverage/simple_match.coverage +++ b/tests/coverage/simple_match.coverage @@ -2,11 +2,11 @@ LL| | LL| |#[rustfmt::skip] LL| 1|fn main() { - LL| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure - LL| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - LL| 1| // dependent conditions. + LL| | // Initialize test constants in a way that cannot be determined at compile time, to ensure + LL| | // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + LL| | // dependent conditions. LL| 1| let is_true = std::env::args().len() == 1; - LL| 1| + LL| | LL| 1| let mut countdown = 1; LL| 1| if is_true { LL| 1| countdown = 0; diff --git a/tests/coverage/sort_groups.cov-map b/tests/coverage/sort_groups.cov-map index 898d68171c50..70cf7cff4b67 100644 --- a/tests/coverage/sort_groups.cov-map +++ b/tests/coverage/sort_groups.cov-map @@ -1,79 +1,98 @@ Function name: sort_groups::generic_fn::<&str> -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 11, 01, 01, 0c, 05, 01, 0d, 02, 06, 02, 02, 05, 00, 06, 01, 01, 01, 00, 02] +Raw bytes (36): 0x[01, 01, 01, 01, 05, 06, 01, 11, 01, 00, 1d, 01, 01, 08, 00, 0c, 05, 00, 0d, 02, 06, 05, 01, 09, 00, 11, 02, 01, 05, 00, 06, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/sort_groups.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 17, 1) to (start + 1, 12) -- Code(Counter(1)) at (prev + 1, 13) to (start + 2, 6) -- Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 0, 6) +Number of file 0 mappings: 6 +- Code(Counter(0)) at (prev + 17, 1) to (start + 0, 29) +- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 12) +- Code(Counter(1)) at (prev + 0, 13) to (start + 2, 6) +- Code(Counter(1)) at (prev + 1, 9) to (start + 0, 17) +- Code(Expression(0, Sub)) at (prev + 1, 5) to (start + 0, 6) = (c0 - c1) - Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c1 Function name: sort_groups::generic_fn::<()> -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 11, 01, 01, 0c, 05, 01, 0d, 02, 06, 02, 02, 05, 00, 06, 01, 01, 01, 00, 02] +Raw bytes (36): 0x[01, 01, 01, 01, 05, 06, 01, 11, 01, 00, 1d, 01, 01, 08, 00, 0c, 05, 00, 0d, 02, 06, 05, 01, 09, 00, 11, 02, 01, 05, 00, 06, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/sort_groups.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 17, 1) to (start + 1, 12) -- Code(Counter(1)) at (prev + 1, 13) to (start + 2, 6) -- Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 0, 6) +Number of file 0 mappings: 6 +- Code(Counter(0)) at (prev + 17, 1) to (start + 0, 29) +- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 12) +- Code(Counter(1)) at (prev + 0, 13) to (start + 2, 6) +- Code(Counter(1)) at (prev + 1, 9) to (start + 0, 17) +- Code(Expression(0, Sub)) at (prev + 1, 5) to (start + 0, 6) = (c0 - c1) - Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c1 Function name: sort_groups::generic_fn:: -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 11, 01, 01, 0c, 05, 01, 0d, 02, 06, 02, 02, 05, 00, 06, 01, 01, 01, 00, 02] +Raw bytes (36): 0x[01, 01, 01, 01, 05, 06, 01, 11, 01, 00, 1d, 01, 01, 08, 00, 0c, 05, 00, 0d, 02, 06, 05, 01, 09, 00, 11, 02, 01, 05, 00, 06, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/sort_groups.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 17, 1) to (start + 1, 12) -- Code(Counter(1)) at (prev + 1, 13) to (start + 2, 6) -- Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 0, 6) +Number of file 0 mappings: 6 +- Code(Counter(0)) at (prev + 17, 1) to (start + 0, 29) +- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 12) +- Code(Counter(1)) at (prev + 0, 13) to (start + 2, 6) +- Code(Counter(1)) at (prev + 1, 9) to (start + 0, 17) +- Code(Expression(0, Sub)) at (prev + 1, 5) to (start + 0, 6) = (c0 - c1) - Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c1 Function name: sort_groups::generic_fn:: -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 11, 01, 01, 0c, 05, 01, 0d, 02, 06, 02, 02, 05, 00, 06, 01, 01, 01, 00, 02] +Raw bytes (36): 0x[01, 01, 01, 01, 05, 06, 01, 11, 01, 00, 1d, 01, 01, 08, 00, 0c, 05, 00, 0d, 02, 06, 05, 01, 09, 00, 11, 02, 01, 05, 00, 06, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/sort_groups.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 17, 1) to (start + 1, 12) -- Code(Counter(1)) at (prev + 1, 13) to (start + 2, 6) -- Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 0, 6) +Number of file 0 mappings: 6 +- Code(Counter(0)) at (prev + 17, 1) to (start + 0, 29) +- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 12) +- Code(Counter(1)) at (prev + 0, 13) to (start + 2, 6) +- Code(Counter(1)) at (prev + 1, 9) to (start + 0, 17) +- Code(Expression(0, Sub)) at (prev + 1, 5) to (start + 0, 6) = (c0 - c1) - Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c1 Function name: sort_groups::main -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 06, 01, 04, 1c, 05, 04, 24, 02, 06, 02, 02, 05, 00, 06, 01, 01, 05, 02, 02] +Raw bytes (76): 0x[01, 01, 01, 01, 05, 0e, 01, 06, 01, 00, 0a, 01, 01, 09, 00, 0d, 01, 00, 10, 00, 2a, 01, 01, 05, 00, 15, 01, 00, 16, 00, 1a, 01, 01, 05, 00, 1f, 01, 00, 20, 00, 25, 01, 01, 08, 00, 1c, 05, 00, 24, 02, 06, 02, 02, 05, 00, 06, 01, 01, 05, 00, 16, 01, 00, 17, 00, 1b, 01, 01, 05, 00, 0d, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/sort_groups.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 6, 1) to (start + 4, 28) -- Code(Counter(1)) at (prev + 4, 36) to (start + 2, 6) +Number of file 0 mappings: 14 +- Code(Counter(0)) at (prev + 6, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 16) to (start + 0, 42) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 21) +- Code(Counter(0)) at (prev + 0, 22) to (start + 0, 26) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 31) +- Code(Counter(0)) at (prev + 0, 32) to (start + 0, 37) +- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 28) +- Code(Counter(1)) at (prev + 0, 36) to (start + 2, 6) - Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 0, 6) = (c0 - c1) -- Code(Counter(0)) at (prev + 1, 5) to (start + 2, 2) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 22) +- Code(Counter(0)) at (prev + 0, 23) to (start + 0, 27) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c1 Function name: sort_groups::other_fn -Raw bytes (9): 0x[01, 01, 00, 01, 01, 17, 01, 00, 11] +Raw bytes (14): 0x[01, 01, 00, 02, 01, 17, 01, 00, 0e, 01, 00, 10, 00, 11] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/sort_groups.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 23, 1) to (start + 0, 17) +Number of file 0 mappings: 2 +- Code(Counter(0)) at (prev + 23, 1) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 16) to (start + 0, 17) Highest counter ID seen: c0 diff --git a/tests/coverage/test_harness.cov-map b/tests/coverage/test_harness.cov-map index b513b3d05494..691332a1c420 100644 --- a/tests/coverage/test_harness.cov-map +++ b/tests/coverage/test_harness.cov-map @@ -1,18 +1,20 @@ Function name: test_harness::my_test -Raw bytes (9): 0x[01, 01, 00, 01, 01, 0a, 01, 00, 10] +Raw bytes (14): 0x[01, 01, 00, 02, 01, 0a, 01, 00, 0d, 01, 00, 0f, 00, 10] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/test_harness.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 10, 1) to (start + 0, 16) +Number of file 0 mappings: 2 +- Code(Counter(0)) at (prev + 10, 1) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 16) Highest counter ID seen: c0 Function name: test_harness::unused (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 07, 01, 00, 0f] +Raw bytes (14): 0x[01, 01, 00, 02, 00, 07, 01, 00, 0c, 00, 00, 0e, 00, 0f] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/test_harness.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 7, 1) to (start + 0, 15) +Number of file 0 mappings: 2 +- Code(Zero) at (prev + 7, 1) to (start + 0, 12) +- Code(Zero) at (prev + 0, 14) to (start + 0, 15) Highest counter ID seen: (none) diff --git a/tests/coverage/tight_inf_loop.cov-map b/tests/coverage/tight_inf_loop.cov-map index 77a8ffb83581..c6bee3bd7ad9 100644 --- a/tests/coverage/tight_inf_loop.cov-map +++ b/tests/coverage/tight_inf_loop.cov-map @@ -1,11 +1,13 @@ Function name: tight_inf_loop::main -Raw bytes (19): 0x[01, 01, 00, 03, 01, 01, 01, 01, 0d, 00, 02, 09, 00, 10, 01, 01, 06, 01, 02] +Raw bytes (29): 0x[01, 01, 00, 05, 01, 01, 01, 00, 0a, 01, 01, 08, 00, 0d, 00, 01, 09, 00, 10, 01, 01, 05, 00, 06, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/tight_inf_loop.rs Number of expressions: 0 -Number of file 0 mappings: 3 -- Code(Counter(0)) at (prev + 1, 1) to (start + 1, 13) -- Code(Zero) at (prev + 2, 9) to (start + 0, 16) -- Code(Counter(0)) at (prev + 1, 6) to (start + 1, 2) +Number of file 0 mappings: 5 +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 13) +- Code(Zero) at (prev + 1, 9) to (start + 0, 16) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 6) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 diff --git a/tests/coverage/trivial.cov-map b/tests/coverage/trivial.cov-map index 05f64896d9ec..fff10df9aee5 100644 --- a/tests/coverage/trivial.cov-map +++ b/tests/coverage/trivial.cov-map @@ -1,9 +1,10 @@ Function name: trivial::main -Raw bytes (9): 0x[01, 01, 00, 01, 01, 03, 01, 00, 0d] +Raw bytes (14): 0x[01, 01, 00, 02, 01, 03, 01, 00, 0a, 01, 00, 0c, 00, 0d] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/trivial.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 13) +Number of file 0 mappings: 2 +- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 0, 12) to (start + 0, 13) Highest counter ID seen: c0 diff --git a/tests/coverage/try_error_result.cov-map b/tests/coverage/try_error_result.cov-map index e45f3de10815..e08f42961532 100644 --- a/tests/coverage/try_error_result.cov-map +++ b/tests/coverage/try_error_result.cov-map @@ -1,73 +1,83 @@ Function name: ::get_thing_2 -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 29, 05, 01, 18, 05, 02, 0d, 00, 14, 02, 02, 0d, 00, 1a, 01, 02, 05, 00, 06] +Raw bytes (31): 0x[01, 01, 01, 01, 05, 05, 01, 29, 05, 00, 44, 01, 01, 0c, 00, 18, 05, 01, 0d, 00, 14, 02, 02, 0d, 00, 1a, 01, 02, 05, 00, 06] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/try_error_result.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 41, 5) to (start + 1, 24) -- Code(Counter(1)) at (prev + 2, 13) to (start + 0, 20) +Number of file 0 mappings: 5 +- Code(Counter(0)) at (prev + 41, 5) to (start + 0, 68) +- Code(Counter(0)) at (prev + 1, 12) to (start + 0, 24) +- Code(Counter(1)) at (prev + 1, 13) to (start + 0, 20) - Code(Expression(0, Sub)) at (prev + 2, 13) to (start + 0, 26) = (c0 - c1) - Code(Counter(0)) at (prev + 2, 5) to (start + 0, 6) Highest counter ID seen: c1 Function name: ::call -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 34, 05, 01, 18, 05, 02, 0d, 00, 14, 02, 02, 0d, 00, 13, 01, 02, 05, 00, 06] +Raw bytes (31): 0x[01, 01, 01, 01, 05, 05, 01, 34, 05, 00, 3a, 01, 01, 0c, 00, 18, 05, 01, 0d, 00, 14, 02, 02, 0d, 00, 13, 01, 02, 05, 00, 06] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/try_error_result.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 52, 5) to (start + 1, 24) -- Code(Counter(1)) at (prev + 2, 13) to (start + 0, 20) +Number of file 0 mappings: 5 +- Code(Counter(0)) at (prev + 52, 5) to (start + 0, 58) +- Code(Counter(0)) at (prev + 1, 12) to (start + 0, 24) +- Code(Counter(1)) at (prev + 1, 13) to (start + 0, 20) - Code(Expression(0, Sub)) at (prev + 2, 13) to (start + 0, 19) = (c0 - c1) - Code(Counter(0)) at (prev + 2, 5) to (start + 0, 6) Highest counter ID seen: c1 Function name: try_error_result::call -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 05, 01, 01, 14, 05, 02, 09, 00, 10, 02, 02, 09, 00, 0f, 01, 02, 01, 00, 02] +Raw bytes (31): 0x[01, 01, 01, 01, 05, 05, 01, 05, 01, 00, 2e, 01, 01, 08, 00, 14, 05, 01, 09, 00, 10, 02, 02, 09, 00, 0f, 01, 02, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/try_error_result.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 5, 1) to (start + 1, 20) -- Code(Counter(1)) at (prev + 2, 9) to (start + 0, 16) +Number of file 0 mappings: 5 +- Code(Counter(0)) at (prev + 5, 1) to (start + 0, 46) +- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 20) +- Code(Counter(1)) at (prev + 1, 9) to (start + 0, 16) - Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 15) = (c0 - c1) - Code(Counter(0)) at (prev + 2, 1) to (start + 0, 2) Highest counter ID seen: c1 Function name: try_error_result::main -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 71, 01, 02, 0a, 05, 03, 05, 00, 06, 02, 02, 05, 00, 0b, 01, 01, 01, 00, 02] +Raw bytes (46): 0x[01, 01, 01, 01, 05, 08, 01, 71, 01, 00, 1c, 01, 01, 05, 00, 0a, 01, 00, 0d, 00, 17, 01, 00, 18, 00, 2b, 01, 01, 05, 00, 0a, 05, 01, 05, 00, 06, 02, 02, 05, 00, 0b, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/try_error_result.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 113, 1) to (start + 2, 10) -- Code(Counter(1)) at (prev + 3, 5) to (start + 0, 6) +Number of file 0 mappings: 8 +- Code(Counter(0)) at (prev + 113, 1) to (start + 0, 28) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 10) +- Code(Counter(0)) at (prev + 0, 13) to (start + 0, 23) +- Code(Counter(0)) at (prev + 0, 24) to (start + 0, 43) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 10) +- Code(Counter(1)) at (prev + 1, 5) to (start + 0, 6) - Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 0, 11) = (c0 - c1) - Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c1 Function name: try_error_result::test1 -Raw bytes (67): 0x[01, 01, 04, 07, 05, 01, 09, 05, 01, 05, 09, 0b, 01, 0d, 01, 02, 17, 05, 07, 09, 00, 0e, 09, 02, 09, 04, 1a, 02, 06, 0d, 00, 11, 02, 00, 29, 00, 2a, 00, 01, 0d, 00, 11, 00, 00, 2a, 00, 2b, 0a, 04, 0d, 00, 11, 00, 00, 2a, 00, 2b, 0e, 03, 05, 00, 0b, 01, 01, 01, 00, 02] +Raw bytes (82): 0x[01, 01, 04, 07, 05, 01, 09, 05, 01, 05, 09, 0e, 01, 0d, 01, 00, 1d, 01, 01, 09, 01, 12, 01, 01, 15, 00, 17, 05, 05, 09, 00, 0e, 09, 02, 09, 01, 11, 09, 04, 0d, 00, 1a, 02, 02, 0d, 00, 11, 02, 00, 29, 00, 2a, 00, 01, 0d, 00, 11, 00, 00, 2a, 00, 2b, 0a, 04, 0d, 00, 11, 00, 00, 2a, 00, 2b, 0e, 03, 05, 00, 0b, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/try_error_result.rs Number of expressions: 4 - expression 0 operands: lhs = Expression(1, Add), rhs = Counter(1) - expression 1 operands: lhs = Counter(0), rhs = Counter(2) - expression 2 operands: lhs = Counter(1), rhs = Counter(0) - expression 3 operands: lhs = Counter(1), rhs = Counter(2) -Number of file 0 mappings: 11 -- Code(Counter(0)) at (prev + 13, 1) to (start + 2, 23) -- Code(Counter(1)) at (prev + 7, 9) to (start + 0, 14) -- Code(Counter(2)) at (prev + 2, 9) to (start + 4, 26) -- Code(Expression(0, Sub)) at (prev + 6, 13) to (start + 0, 17) +Number of file 0 mappings: 14 +- Code(Counter(0)) at (prev + 13, 1) to (start + 0, 29) +- Code(Counter(0)) at (prev + 1, 9) to (start + 1, 18) +- Code(Counter(0)) at (prev + 1, 21) to (start + 0, 23) +- Code(Counter(1)) at (prev + 5, 9) to (start + 0, 14) +- Code(Counter(2)) at (prev + 2, 9) to (start + 1, 17) +- Code(Counter(2)) at (prev + 4, 13) to (start + 0, 26) +- Code(Expression(0, Sub)) at (prev + 2, 13) to (start + 0, 17) = ((c0 + c2) - c1) - Code(Expression(0, Sub)) at (prev + 0, 41) to (start + 0, 42) = ((c0 + c2) - c1) @@ -82,125 +92,157 @@ Number of file 0 mappings: 11 Highest counter ID seen: c2 Function name: try_error_result::test2 -Raw bytes (336): 0x[01, 01, 36, 0d, 11, 0d, 3f, 11, 15, 0d, 37, 3b, 1d, 3f, 19, 11, 15, 0d, 3f, 11, 15, 0d, 3b, 3f, 19, 11, 15, 0d, 37, 3b, 1d, 3f, 19, 11, 15, 41, 53, 21, 25, 41, 21, 41, 53, 21, 25, 09, 73, 77, 2d, 0d, 29, 09, 0d, 09, 77, 0d, 29, 09, 73, 77, 2d, 0d, 29, 45, 8b, 01, 31, 35, 45, 31, 45, 8b, 01, 31, 35, 49, 9f, 01, 39, 3d, 49, 39, 49, 9f, 01, 39, 3d, 05, 09, ab, 01, 09, af, 01, 3d, b3, 01, 39, b7, 01, 35, bb, 01, 31, bf, 01, 2d, c3, 01, 29, c7, 01, 25, cb, 01, 21, cf, 01, 1d, d3, 01, 19, d7, 01, 15, 05, 11, 28, 01, 3d, 01, 03, 17, 05, 08, 09, 00, 0e, 09, 02, 09, 04, 1a, 0d, 06, 0d, 00, 1f, 11, 00, 2f, 00, 30, 02, 00, 31, 03, 1c, 15, 04, 11, 00, 12, 1e, 02, 11, 03, 27, 32, 05, 11, 00, 14, 1e, 00, 17, 00, 29, 19, 00, 41, 00, 42, 26, 00, 43, 00, 47, 1d, 00, 5f, 00, 60, 32, 01, 0d, 00, 17, 4e, 01, 11, 00, 14, 41, 00, 17, 00, 29, 21, 00, 41, 00, 42, 4a, 00, 43, 00, 47, 25, 00, 60, 00, 61, 4e, 01, 0d, 00, 17, 6e, 04, 11, 00, 14, 62, 00, 17, 00, 29, 29, 00, 42, 00, 43, 66, 00, 44, 00, 48, 2d, 00, 61, 00, 62, 6e, 01, 0d, 00, 17, 86, 01, 01, 11, 00, 14, 45, 00, 17, 01, 1d, 31, 01, 36, 00, 37, 82, 01, 01, 12, 00, 16, 35, 00, 2f, 00, 30, 86, 01, 01, 0d, 00, 17, 9a, 01, 01, 11, 00, 14, 49, 00, 17, 01, 1d, 39, 02, 11, 00, 12, 96, 01, 01, 12, 00, 16, 3d, 01, 11, 00, 12, 9a, 01, 02, 0d, 00, 17, a2, 01, 03, 05, 00, 0b, a6, 01, 01, 01, 00, 02] +Raw bytes (443): 0x[01, 01, 3d, 0d, 11, 0d, 57, 11, 15, 0d, 57, 11, 15, 0d, 57, 11, 15, 0d, 4f, 53, 1d, 57, 19, 11, 15, 0d, 57, 11, 15, 0d, 57, 11, 15, 0d, 53, 57, 19, 11, 15, 0d, 4f, 53, 1d, 57, 19, 11, 15, 41, 6b, 21, 25, 41, 21, 41, 6b, 21, 25, 09, 8f, 01, 93, 01, 2d, 0d, 29, 09, 0d, 09, 0d, 09, 93, 01, 0d, 29, 09, 8f, 01, 93, 01, 2d, 0d, 29, 45, a7, 01, 31, 35, 45, 31, 45, a7, 01, 31, 35, 49, bb, 01, 39, 3d, 49, 39, 49, bb, 01, 39, 3d, 05, 09, c7, 01, 09, cb, 01, 3d, cf, 01, 39, d3, 01, 35, d7, 01, 31, db, 01, 2d, df, 01, 29, e3, 01, 25, e7, 01, 21, eb, 01, 1d, ef, 01, 19, f3, 01, 15, 05, 11, 39, 01, 3d, 01, 00, 1d, 01, 01, 09, 00, 0f, 01, 00, 12, 00, 1a, 01, 01, 09, 01, 12, 01, 01, 15, 00, 17, 05, 05, 09, 00, 0e, 09, 02, 09, 01, 11, 09, 04, 0d, 00, 1a, 0d, 02, 0d, 00, 13, 0d, 00, 14, 00, 1f, 11, 00, 2f, 00, 30, 02, 00, 31, 00, 35, 02, 00, 45, 00, 4f, 02, 00, 50, 00, 62, 02, 01, 0d, 00, 13, 02, 02, 11, 00, 1c, 15, 01, 11, 00, 12, 36, 02, 11, 00, 15, 36, 02, 11, 00, 1b, 36, 01, 15, 00, 27, 4a, 02, 11, 00, 14, 36, 00, 17, 00, 1d, 36, 00, 1e, 00, 29, 19, 00, 41, 00, 42, 3e, 00, 43, 00, 47, 1d, 00, 5f, 00, 60, 4a, 01, 0d, 00, 17, 66, 01, 11, 00, 14, 41, 00, 17, 00, 1d, 41, 00, 1e, 00, 29, 21, 00, 41, 00, 42, 62, 00, 43, 00, 47, 25, 00, 60, 00, 61, 66, 01, 0d, 00, 17, 8a, 01, 04, 11, 00, 14, 7e, 00, 17, 00, 1d, 7e, 00, 1e, 00, 29, 29, 00, 42, 00, 43, 82, 01, 00, 44, 00, 48, 2d, 00, 61, 00, 62, 8a, 01, 01, 0d, 00, 17, a2, 01, 01, 11, 00, 14, 45, 00, 17, 00, 1d, 45, 01, 12, 00, 1d, 31, 00, 36, 00, 37, 9e, 01, 01, 12, 00, 16, 35, 00, 2f, 00, 30, a2, 01, 01, 0d, 00, 17, b6, 01, 01, 11, 00, 14, 49, 00, 17, 00, 1d, 49, 01, 12, 00, 1d, 39, 01, 11, 00, 12, b2, 01, 01, 12, 00, 16, 3d, 01, 11, 00, 12, b6, 01, 02, 0d, 00, 17, be, 01, 03, 05, 00, 0b, c2, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 -Number of expressions: 54 +- file 0 => $DIR/try_error_result.rs +Number of expressions: 61 - expression 0 operands: lhs = Counter(3), rhs = Counter(4) -- expression 1 operands: lhs = Counter(3), rhs = Expression(15, Add) +- expression 1 operands: lhs = Counter(3), rhs = Expression(21, Add) - expression 2 operands: lhs = Counter(4), rhs = Counter(5) -- expression 3 operands: lhs = Counter(3), rhs = Expression(13, Add) -- expression 4 operands: lhs = Expression(14, Add), rhs = Counter(7) -- expression 5 operands: lhs = Expression(15, Add), rhs = Counter(6) +- expression 3 operands: lhs = Counter(3), rhs = Expression(21, Add) +- expression 4 operands: lhs = Counter(4), rhs = Counter(5) +- expression 5 operands: lhs = Counter(3), rhs = Expression(21, Add) - expression 6 operands: lhs = Counter(4), rhs = Counter(5) -- expression 7 operands: lhs = Counter(3), rhs = Expression(15, Add) -- expression 8 operands: lhs = Counter(4), rhs = Counter(5) -- expression 9 operands: lhs = Counter(3), rhs = Expression(14, Add) -- expression 10 operands: lhs = Expression(15, Add), rhs = Counter(6) -- expression 11 operands: lhs = Counter(4), rhs = Counter(5) -- expression 12 operands: lhs = Counter(3), rhs = Expression(13, Add) -- expression 13 operands: lhs = Expression(14, Add), rhs = Counter(7) -- expression 14 operands: lhs = Expression(15, Add), rhs = Counter(6) -- expression 15 operands: lhs = Counter(4), rhs = Counter(5) -- expression 16 operands: lhs = Counter(16), rhs = Expression(20, Add) -- expression 17 operands: lhs = Counter(8), rhs = Counter(9) -- expression 18 operands: lhs = Counter(16), rhs = Counter(8) -- expression 19 operands: lhs = Counter(16), rhs = Expression(20, Add) -- expression 20 operands: lhs = Counter(8), rhs = Counter(9) -- expression 21 operands: lhs = Counter(2), rhs = Expression(28, Add) -- expression 22 operands: lhs = Expression(29, Add), rhs = Counter(11) -- expression 23 operands: lhs = Counter(3), rhs = Counter(10) -- expression 24 operands: lhs = Counter(2), rhs = Counter(3) -- expression 25 operands: lhs = Counter(2), rhs = Expression(29, Add) -- expression 26 operands: lhs = Counter(3), rhs = Counter(10) -- expression 27 operands: lhs = Counter(2), rhs = Expression(28, Add) -- expression 28 operands: lhs = Expression(29, Add), rhs = Counter(11) +- expression 7 operands: lhs = Counter(3), rhs = Expression(19, Add) +- expression 8 operands: lhs = Expression(20, Add), rhs = Counter(7) +- expression 9 operands: lhs = Expression(21, Add), rhs = Counter(6) +- expression 10 operands: lhs = Counter(4), rhs = Counter(5) +- expression 11 operands: lhs = Counter(3), rhs = Expression(21, Add) +- expression 12 operands: lhs = Counter(4), rhs = Counter(5) +- expression 13 operands: lhs = Counter(3), rhs = Expression(21, Add) +- expression 14 operands: lhs = Counter(4), rhs = Counter(5) +- expression 15 operands: lhs = Counter(3), rhs = Expression(20, Add) +- expression 16 operands: lhs = Expression(21, Add), rhs = Counter(6) +- expression 17 operands: lhs = Counter(4), rhs = Counter(5) +- expression 18 operands: lhs = Counter(3), rhs = Expression(19, Add) +- expression 19 operands: lhs = Expression(20, Add), rhs = Counter(7) +- expression 20 operands: lhs = Expression(21, Add), rhs = Counter(6) +- expression 21 operands: lhs = Counter(4), rhs = Counter(5) +- expression 22 operands: lhs = Counter(16), rhs = Expression(26, Add) +- expression 23 operands: lhs = Counter(8), rhs = Counter(9) +- expression 24 operands: lhs = Counter(16), rhs = Counter(8) +- expression 25 operands: lhs = Counter(16), rhs = Expression(26, Add) +- expression 26 operands: lhs = Counter(8), rhs = Counter(9) +- expression 27 operands: lhs = Counter(2), rhs = Expression(35, Add) +- expression 28 operands: lhs = Expression(36, Add), rhs = Counter(11) - expression 29 operands: lhs = Counter(3), rhs = Counter(10) -- expression 30 operands: lhs = Counter(17), rhs = Expression(34, Add) -- expression 31 operands: lhs = Counter(12), rhs = Counter(13) -- expression 32 operands: lhs = Counter(17), rhs = Counter(12) -- expression 33 operands: lhs = Counter(17), rhs = Expression(34, Add) -- expression 34 operands: lhs = Counter(12), rhs = Counter(13) -- expression 35 operands: lhs = Counter(18), rhs = Expression(39, Add) -- expression 36 operands: lhs = Counter(14), rhs = Counter(15) -- expression 37 operands: lhs = Counter(18), rhs = Counter(14) -- expression 38 operands: lhs = Counter(18), rhs = Expression(39, Add) -- expression 39 operands: lhs = Counter(14), rhs = Counter(15) -- expression 40 operands: lhs = Counter(1), rhs = Counter(2) -- expression 41 operands: lhs = Expression(42, Add), rhs = Counter(2) -- expression 42 operands: lhs = Expression(43, Add), rhs = Counter(15) -- expression 43 operands: lhs = Expression(44, Add), rhs = Counter(14) -- expression 44 operands: lhs = Expression(45, Add), rhs = Counter(13) -- expression 45 operands: lhs = Expression(46, Add), rhs = Counter(12) -- expression 46 operands: lhs = Expression(47, Add), rhs = Counter(11) -- expression 47 operands: lhs = Expression(48, Add), rhs = Counter(10) -- expression 48 operands: lhs = Expression(49, Add), rhs = Counter(9) -- expression 49 operands: lhs = Expression(50, Add), rhs = Counter(8) -- expression 50 operands: lhs = Expression(51, Add), rhs = Counter(7) -- expression 51 operands: lhs = Expression(52, Add), rhs = Counter(6) -- expression 52 operands: lhs = Expression(53, Add), rhs = Counter(5) -- expression 53 operands: lhs = Counter(1), rhs = Counter(4) -Number of file 0 mappings: 40 -- Code(Counter(0)) at (prev + 61, 1) to (start + 3, 23) -- Code(Counter(1)) at (prev + 8, 9) to (start + 0, 14) -- Code(Counter(2)) at (prev + 2, 9) to (start + 4, 26) -- Code(Counter(3)) at (prev + 6, 13) to (start + 0, 31) +- expression 30 operands: lhs = Counter(2), rhs = Counter(3) +- expression 31 operands: lhs = Counter(2), rhs = Counter(3) +- expression 32 operands: lhs = Counter(2), rhs = Expression(36, Add) +- expression 33 operands: lhs = Counter(3), rhs = Counter(10) +- expression 34 operands: lhs = Counter(2), rhs = Expression(35, Add) +- expression 35 operands: lhs = Expression(36, Add), rhs = Counter(11) +- expression 36 operands: lhs = Counter(3), rhs = Counter(10) +- expression 37 operands: lhs = Counter(17), rhs = Expression(41, Add) +- expression 38 operands: lhs = Counter(12), rhs = Counter(13) +- expression 39 operands: lhs = Counter(17), rhs = Counter(12) +- expression 40 operands: lhs = Counter(17), rhs = Expression(41, Add) +- expression 41 operands: lhs = Counter(12), rhs = Counter(13) +- expression 42 operands: lhs = Counter(18), rhs = Expression(46, Add) +- expression 43 operands: lhs = Counter(14), rhs = Counter(15) +- expression 44 operands: lhs = Counter(18), rhs = Counter(14) +- expression 45 operands: lhs = Counter(18), rhs = Expression(46, Add) +- expression 46 operands: lhs = Counter(14), rhs = Counter(15) +- expression 47 operands: lhs = Counter(1), rhs = Counter(2) +- expression 48 operands: lhs = Expression(49, Add), rhs = Counter(2) +- expression 49 operands: lhs = Expression(50, Add), rhs = Counter(15) +- expression 50 operands: lhs = Expression(51, Add), rhs = Counter(14) +- expression 51 operands: lhs = Expression(52, Add), rhs = Counter(13) +- expression 52 operands: lhs = Expression(53, Add), rhs = Counter(12) +- expression 53 operands: lhs = Expression(54, Add), rhs = Counter(11) +- expression 54 operands: lhs = Expression(55, Add), rhs = Counter(10) +- expression 55 operands: lhs = Expression(56, Add), rhs = Counter(9) +- expression 56 operands: lhs = Expression(57, Add), rhs = Counter(8) +- expression 57 operands: lhs = Expression(58, Add), rhs = Counter(7) +- expression 58 operands: lhs = Expression(59, Add), rhs = Counter(6) +- expression 59 operands: lhs = Expression(60, Add), rhs = Counter(5) +- expression 60 operands: lhs = Counter(1), rhs = Counter(4) +Number of file 0 mappings: 57 +- Code(Counter(0)) at (prev + 61, 1) to (start + 0, 29) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 15) +- Code(Counter(0)) at (prev + 0, 18) to (start + 0, 26) +- Code(Counter(0)) at (prev + 1, 9) to (start + 1, 18) +- Code(Counter(0)) at (prev + 1, 21) to (start + 0, 23) +- Code(Counter(1)) at (prev + 5, 9) to (start + 0, 14) +- Code(Counter(2)) at (prev + 2, 9) to (start + 1, 17) +- Code(Counter(2)) at (prev + 4, 13) to (start + 0, 26) +- Code(Counter(3)) at (prev + 2, 13) to (start + 0, 19) +- Code(Counter(3)) at (prev + 0, 20) to (start + 0, 31) - Code(Counter(4)) at (prev + 0, 47) to (start + 0, 48) -- Code(Expression(0, Sub)) at (prev + 0, 49) to (start + 3, 28) +- Code(Expression(0, Sub)) at (prev + 0, 49) to (start + 0, 53) = (c3 - c4) -- Code(Counter(5)) at (prev + 4, 17) to (start + 0, 18) -- Code(Expression(7, Sub)) at (prev + 2, 17) to (start + 3, 39) +- Code(Expression(0, Sub)) at (prev + 0, 69) to (start + 0, 79) + = (c3 - c4) +- Code(Expression(0, Sub)) at (prev + 0, 80) to (start + 0, 98) + = (c3 - c4) +- Code(Expression(0, Sub)) at (prev + 1, 13) to (start + 0, 19) + = (c3 - c4) +- Code(Expression(0, Sub)) at (prev + 2, 17) to (start + 0, 28) + = (c3 - c4) +- Code(Counter(5)) at (prev + 1, 17) to (start + 0, 18) +- Code(Expression(13, Sub)) at (prev + 2, 17) to (start + 0, 21) = (c3 - (c4 + c5)) -- Code(Expression(12, Sub)) at (prev + 5, 17) to (start + 0, 20) +- Code(Expression(13, Sub)) at (prev + 2, 17) to (start + 0, 27) + = (c3 - (c4 + c5)) +- Code(Expression(13, Sub)) at (prev + 1, 21) to (start + 0, 39) + = (c3 - (c4 + c5)) +- Code(Expression(18, Sub)) at (prev + 2, 17) to (start + 0, 20) = (c3 - (((c4 + c5) + c6) + c7)) -- Code(Expression(7, Sub)) at (prev + 0, 23) to (start + 0, 41) +- Code(Expression(13, Sub)) at (prev + 0, 23) to (start + 0, 29) + = (c3 - (c4 + c5)) +- Code(Expression(13, Sub)) at (prev + 0, 30) to (start + 0, 41) = (c3 - (c4 + c5)) - Code(Counter(6)) at (prev + 0, 65) to (start + 0, 66) -- Code(Expression(9, Sub)) at (prev + 0, 67) to (start + 0, 71) +- Code(Expression(15, Sub)) at (prev + 0, 67) to (start + 0, 71) = (c3 - ((c4 + c5) + c6)) - Code(Counter(7)) at (prev + 0, 95) to (start + 0, 96) -- Code(Expression(12, Sub)) at (prev + 1, 13) to (start + 0, 23) +- Code(Expression(18, Sub)) at (prev + 1, 13) to (start + 0, 23) = (c3 - (((c4 + c5) + c6) + c7)) -- Code(Expression(19, Sub)) at (prev + 1, 17) to (start + 0, 20) +- Code(Expression(25, Sub)) at (prev + 1, 17) to (start + 0, 20) = (c16 - (c8 + c9)) -- Code(Counter(16)) at (prev + 0, 23) to (start + 0, 41) +- Code(Counter(16)) at (prev + 0, 23) to (start + 0, 29) +- Code(Counter(16)) at (prev + 0, 30) to (start + 0, 41) - Code(Counter(8)) at (prev + 0, 65) to (start + 0, 66) -- Code(Expression(18, Sub)) at (prev + 0, 67) to (start + 0, 71) +- Code(Expression(24, Sub)) at (prev + 0, 67) to (start + 0, 71) = (c16 - c8) - Code(Counter(9)) at (prev + 0, 96) to (start + 0, 97) -- Code(Expression(19, Sub)) at (prev + 1, 13) to (start + 0, 23) +- Code(Expression(25, Sub)) at (prev + 1, 13) to (start + 0, 23) = (c16 - (c8 + c9)) -- Code(Expression(27, Sub)) at (prev + 4, 17) to (start + 0, 20) +- Code(Expression(34, Sub)) at (prev + 4, 17) to (start + 0, 20) = (c2 - ((c3 + c10) + c11)) -- Code(Expression(24, Sub)) at (prev + 0, 23) to (start + 0, 41) +- Code(Expression(31, Sub)) at (prev + 0, 23) to (start + 0, 29) + = (c2 - c3) +- Code(Expression(31, Sub)) at (prev + 0, 30) to (start + 0, 41) = (c2 - c3) - Code(Counter(10)) at (prev + 0, 66) to (start + 0, 67) -- Code(Expression(25, Sub)) at (prev + 0, 68) to (start + 0, 72) +- Code(Expression(32, Sub)) at (prev + 0, 68) to (start + 0, 72) = (c2 - (c3 + c10)) - Code(Counter(11)) at (prev + 0, 97) to (start + 0, 98) -- Code(Expression(27, Sub)) at (prev + 1, 13) to (start + 0, 23) +- Code(Expression(34, Sub)) at (prev + 1, 13) to (start + 0, 23) = (c2 - ((c3 + c10) + c11)) -- Code(Expression(33, Sub)) at (prev + 1, 17) to (start + 0, 20) +- Code(Expression(40, Sub)) at (prev + 1, 17) to (start + 0, 20) = (c17 - (c12 + c13)) -- Code(Counter(17)) at (prev + 0, 23) to (start + 1, 29) -- Code(Counter(12)) at (prev + 1, 54) to (start + 0, 55) -- Code(Expression(32, Sub)) at (prev + 1, 18) to (start + 0, 22) +- Code(Counter(17)) at (prev + 0, 23) to (start + 0, 29) +- Code(Counter(17)) at (prev + 1, 18) to (start + 0, 29) +- Code(Counter(12)) at (prev + 0, 54) to (start + 0, 55) +- Code(Expression(39, Sub)) at (prev + 1, 18) to (start + 0, 22) = (c17 - c12) - Code(Counter(13)) at (prev + 0, 47) to (start + 0, 48) -- Code(Expression(33, Sub)) at (prev + 1, 13) to (start + 0, 23) +- Code(Expression(40, Sub)) at (prev + 1, 13) to (start + 0, 23) = (c17 - (c12 + c13)) -- Code(Expression(38, Sub)) at (prev + 1, 17) to (start + 0, 20) +- Code(Expression(45, Sub)) at (prev + 1, 17) to (start + 0, 20) = (c18 - (c14 + c15)) -- Code(Counter(18)) at (prev + 0, 23) to (start + 1, 29) -- Code(Counter(14)) at (prev + 2, 17) to (start + 0, 18) -- Code(Expression(37, Sub)) at (prev + 1, 18) to (start + 0, 22) +- Code(Counter(18)) at (prev + 0, 23) to (start + 0, 29) +- Code(Counter(18)) at (prev + 1, 18) to (start + 0, 29) +- Code(Counter(14)) at (prev + 1, 17) to (start + 0, 18) +- Code(Expression(44, Sub)) at (prev + 1, 18) to (start + 0, 22) = (c18 - c14) - Code(Counter(15)) at (prev + 1, 17) to (start + 0, 18) -- Code(Expression(38, Sub)) at (prev + 2, 13) to (start + 0, 23) +- Code(Expression(45, Sub)) at (prev + 2, 13) to (start + 0, 23) = (c18 - (c14 + c15)) -- Code(Expression(40, Sub)) at (prev + 3, 5) to (start + 0, 11) +- Code(Expression(47, Sub)) at (prev + 3, 5) to (start + 0, 11) = (c1 - c2) -- Code(Expression(41, Sub)) at (prev + 1, 1) to (start + 0, 2) +- Code(Expression(48, Sub)) at (prev + 1, 1) to (start + 0, 2) = (((((((((((((c1 + c4) + c5) + c6) + c7) + c8) + c9) + c10) + c11) + c12) + c13) + c14) + c15) - c2) Highest counter ID seen: c18 diff --git a/tests/coverage/try_error_result.coverage b/tests/coverage/try_error_result.coverage index 7a89c0452ac4..f2ec82f20fa2 100644 --- a/tests/coverage/try_error_result.coverage +++ b/tests/coverage/try_error_result.coverage @@ -21,8 +21,8 @@ LL| | { LL| 6| countdown LL| 6| -= 1 - LL| 6| ; - LL| 6| if + LL| | ; + LL| | if LL| 6| countdown < 5 LL| | { LL| 1| call(/*return_error=*/ true)?; @@ -71,19 +71,19 @@ LL| | { LL| 6| countdown LL| 6| -= 1 - LL| 6| ; - LL| 6| if + LL| | ; + LL| | if LL| 6| countdown < 5 LL| | { LL| 1| thing1.get_thing_2(/*err=*/ false)?.call(/*err=*/ true).expect_err("call should fail"); ^0 LL| 1| thing1 - LL| 1| . + LL| | . LL| 1| get_thing_2(/*return_error=*/ false) LL| 0| ? LL| | . LL| 1| call(/*return_error=*/ true) - LL| 1| . + LL| | . LL| 1| expect_err( LL| 1| "call should fail" LL| | ); diff --git a/tests/coverage/unicode.cov-map b/tests/coverage/unicode.cov-map index 29d40a055130..bbfa8b940c6d 100644 --- a/tests/coverage/unicode.cov-map +++ b/tests/coverage/unicode.cov-map @@ -1,12 +1,12 @@ Function name: unicode::main -Raw bytes (53): 0x[01, 01, 02, 05, 01, 01, 0d, 09, 01, 0e, 01, 00, 0b, 02, 01, 09, 00, 0c, 05, 00, 10, 00, 1b, 02, 00, 1c, 00, 28, 01, 02, 08, 00, 23, 09, 00, 29, 00, 44, 0d, 00, 47, 02, 06, 06, 02, 05, 00, 06, 01, 02, 05, 01, 02] +Raw bytes (58): 0x[01, 01, 02, 05, 01, 01, 0d, 0a, 01, 0e, 01, 00, 0a, 02, 01, 09, 00, 0c, 05, 00, 10, 00, 1b, 02, 00, 1c, 00, 28, 01, 02, 08, 00, 23, 09, 00, 29, 00, 44, 0d, 00, 47, 02, 06, 06, 02, 05, 00, 06, 01, 02, 05, 00, 0b, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/unicode.rs Number of expressions: 2 - expression 0 operands: lhs = Counter(1), rhs = Counter(0) - expression 1 operands: lhs = Counter(0), rhs = Counter(3) -Number of file 0 mappings: 9 -- Code(Counter(0)) at (prev + 14, 1) to (start + 0, 11) +Number of file 0 mappings: 10 +- Code(Counter(0)) at (prev + 14, 1) to (start + 0, 10) - Code(Expression(0, Sub)) at (prev + 1, 9) to (start + 0, 12) = (c1 - c0) - Code(Counter(1)) at (prev + 0, 16) to (start + 0, 27) @@ -17,24 +17,28 @@ Number of file 0 mappings: 9 - Code(Counter(3)) at (prev + 0, 71) to (start + 2, 6) - Code(Expression(1, Sub)) at (prev + 2, 5) to (start + 0, 6) = (c0 - c3) -- Code(Counter(0)) at (prev + 2, 5) to (start + 1, 2) +- Code(Counter(0)) at (prev + 2, 5) to (start + 0, 11) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c3 Function name: unicode::他 (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 1e, 19, 00, 25] +Raw bytes (14): 0x[01, 01, 00, 02, 00, 1e, 19, 00, 22, 00, 00, 24, 00, 25] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/unicode.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 30, 25) to (start + 0, 37) +Number of file 0 mappings: 2 +- Code(Zero) at (prev + 30, 25) to (start + 0, 34) +- Code(Zero) at (prev + 0, 36) to (start + 0, 37) Highest counter ID seen: (none) Function name: unicode::申し訳ございません -Raw bytes (9): 0x[01, 01, 00, 01, 01, 18, 01, 02, 02] +Raw bytes (19): 0x[01, 01, 00, 03, 01, 18, 01, 00, 29, 01, 01, 05, 00, 19, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/unicode.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 24, 1) to (start + 2, 2) +Number of file 0 mappings: 3 +- Code(Counter(0)) at (prev + 24, 1) to (start + 0, 41) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 25) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 diff --git a/tests/coverage/unicode.coverage b/tests/coverage/unicode.coverage index 443499545500..4646cc92e8e4 100644 --- a/tests/coverage/unicode.coverage +++ b/tests/coverage/unicode.coverage @@ -29,7 +29,7 @@ LL| | LL| |macro_rules! macro_that_defines_a_function { LL| | (fn $名:ident () $体:tt) => { - LL| 0| fn $名 () $体 fn 他 () {} + LL| 0| fn $名 () $体 fn 他 () {} LL| | } LL| |} LL| | diff --git a/tests/coverage/unreachable.cov-map b/tests/coverage/unreachable.cov-map index 0bc18bfcbd31..c38786ee664c 100644 --- a/tests/coverage/unreachable.cov-map +++ b/tests/coverage/unreachable.cov-map @@ -1,27 +1,29 @@ Function name: unreachable::UNREACHABLE_CLOSURE::{closure#0} (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 0e, 27, 00, 45] +Raw bytes (9): 0x[01, 01, 00, 01, 00, 0e, 30, 00, 45] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/unreachable.rs Number of expressions: 0 Number of file 0 mappings: 1 -- Code(Zero) at (prev + 14, 39) to (start + 0, 69) +- Code(Zero) at (prev + 14, 48) to (start + 0, 69) Highest counter ID seen: (none) Function name: unreachable::unreachable_function (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 10, 01, 01, 23] +Raw bytes (14): 0x[01, 01, 00, 02, 00, 10, 01, 00, 1a, 00, 01, 0e, 00, 23] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/unreachable.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 16, 1) to (start + 1, 35) +Number of file 0 mappings: 2 +- Code(Zero) at (prev + 16, 1) to (start + 0, 26) +- Code(Zero) at (prev + 1, 14) to (start + 0, 35) Highest counter ID seen: (none) Function name: unreachable::unreachable_intrinsic (unused) -Raw bytes (9): 0x[01, 01, 00, 01, 00, 15, 01, 01, 2a] +Raw bytes (14): 0x[01, 01, 00, 02, 00, 15, 01, 00, 1b, 00, 01, 0e, 00, 2a] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/unreachable.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 21, 1) to (start + 1, 42) +Number of file 0 mappings: 2 +- Code(Zero) at (prev + 21, 1) to (start + 0, 27) +- Code(Zero) at (prev + 1, 14) to (start + 0, 42) Highest counter ID seen: (none) diff --git a/tests/coverage/unused.cov-map b/tests/coverage/unused.cov-map index c18d331ec2e0..3380997b921e 100644 --- a/tests/coverage/unused.cov-map +++ b/tests/coverage/unused.cov-map @@ -1,14 +1,16 @@ Function name: unused::foo:: -Raw bytes (40): 0x[01, 01, 03, 05, 01, 05, 0b, 01, 09, 06, 01, 03, 01, 01, 12, 05, 02, 0b, 00, 11, 02, 01, 09, 00, 0f, 06, 00, 13, 00, 19, 02, 01, 09, 00, 0f, 01, 02, 01, 00, 02] +Raw bytes (50): 0x[01, 01, 03, 05, 01, 05, 0b, 01, 09, 08, 01, 03, 01, 00, 10, 01, 01, 09, 00, 0e, 01, 00, 11, 00, 12, 05, 01, 0b, 00, 11, 02, 01, 09, 00, 0f, 06, 00, 13, 00, 19, 02, 01, 09, 00, 0f, 01, 02, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/unused.rs Number of expressions: 3 - expression 0 operands: lhs = Counter(1), rhs = Counter(0) - expression 1 operands: lhs = Counter(1), rhs = Expression(2, Add) - expression 2 operands: lhs = Counter(0), rhs = Counter(2) -Number of file 0 mappings: 6 -- Code(Counter(0)) at (prev + 3, 1) to (start + 1, 18) -- Code(Counter(1)) at (prev + 2, 11) to (start + 0, 17) +Number of file 0 mappings: 8 +- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 16) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 17) to (start + 0, 18) +- Code(Counter(1)) at (prev + 1, 11) to (start + 0, 17) - Code(Expression(0, Sub)) at (prev + 1, 9) to (start + 0, 15) = (c1 - c0) - Code(Expression(1, Sub)) at (prev + 0, 19) to (start + 0, 25) @@ -19,16 +21,18 @@ Number of file 0 mappings: 6 Highest counter ID seen: c1 Function name: unused::foo:: -Raw bytes (40): 0x[01, 01, 03, 05, 01, 05, 0b, 01, 09, 06, 01, 03, 01, 01, 12, 05, 02, 0b, 00, 11, 02, 01, 09, 00, 0f, 06, 00, 13, 00, 19, 02, 01, 09, 00, 0f, 01, 02, 01, 00, 02] +Raw bytes (50): 0x[01, 01, 03, 05, 01, 05, 0b, 01, 09, 08, 01, 03, 01, 00, 10, 01, 01, 09, 00, 0e, 01, 00, 11, 00, 12, 05, 01, 0b, 00, 11, 02, 01, 09, 00, 0f, 06, 00, 13, 00, 19, 02, 01, 09, 00, 0f, 01, 02, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/unused.rs Number of expressions: 3 - expression 0 operands: lhs = Counter(1), rhs = Counter(0) - expression 1 operands: lhs = Counter(1), rhs = Expression(2, Add) - expression 2 operands: lhs = Counter(0), rhs = Counter(2) -Number of file 0 mappings: 6 -- Code(Counter(0)) at (prev + 3, 1) to (start + 1, 18) -- Code(Counter(1)) at (prev + 2, 11) to (start + 0, 17) +Number of file 0 mappings: 8 +- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 16) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 14) +- Code(Counter(0)) at (prev + 0, 17) to (start + 0, 18) +- Code(Counter(1)) at (prev + 1, 11) to (start + 0, 17) - Code(Expression(0, Sub)) at (prev + 1, 9) to (start + 0, 15) = (c1 - c0) - Code(Expression(1, Sub)) at (prev + 0, 19) to (start + 0, 25) @@ -39,58 +43,67 @@ Number of file 0 mappings: 6 Highest counter ID seen: c1 Function name: unused::main -Raw bytes (9): 0x[01, 01, 00, 01, 01, 25, 01, 04, 02] +Raw bytes (29): 0x[01, 01, 00, 05, 01, 25, 01, 00, 1c, 01, 01, 05, 00, 0f, 01, 01, 05, 00, 0f, 01, 01, 05, 00, 0b, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/unused.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 37, 1) to (start + 4, 2) +Number of file 0 mappings: 5 +- Code(Counter(0)) at (prev + 37, 1) to (start + 0, 28) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 15) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 15) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 11) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: unused::unused_func (unused) -Raw bytes (24): 0x[01, 01, 00, 04, 00, 13, 01, 01, 0e, 00, 01, 0f, 02, 06, 00, 02, 05, 00, 06, 00, 01, 01, 00, 02] +Raw bytes (29): 0x[01, 01, 00, 05, 00, 13, 01, 00, 1b, 00, 01, 08, 00, 0e, 00, 00, 0f, 02, 06, 00, 02, 05, 00, 06, 00, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/unused.rs Number of expressions: 0 -Number of file 0 mappings: 4 -- Code(Zero) at (prev + 19, 1) to (start + 1, 14) -- Code(Zero) at (prev + 1, 15) to (start + 2, 6) +Number of file 0 mappings: 5 +- Code(Zero) at (prev + 19, 1) to (start + 0, 27) +- Code(Zero) at (prev + 1, 8) to (start + 0, 14) +- Code(Zero) at (prev + 0, 15) to (start + 2, 6) - Code(Zero) at (prev + 2, 5) to (start + 0, 6) - Code(Zero) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: (none) Function name: unused::unused_func2 (unused) -Raw bytes (24): 0x[01, 01, 00, 04, 00, 19, 01, 01, 0e, 00, 01, 0f, 02, 06, 00, 02, 05, 00, 06, 00, 01, 01, 00, 02] +Raw bytes (29): 0x[01, 01, 00, 05, 00, 19, 01, 00, 1c, 00, 01, 08, 00, 0e, 00, 00, 0f, 02, 06, 00, 02, 05, 00, 06, 00, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/unused.rs Number of expressions: 0 -Number of file 0 mappings: 4 -- Code(Zero) at (prev + 25, 1) to (start + 1, 14) -- Code(Zero) at (prev + 1, 15) to (start + 2, 6) +Number of file 0 mappings: 5 +- Code(Zero) at (prev + 25, 1) to (start + 0, 28) +- Code(Zero) at (prev + 1, 8) to (start + 0, 14) +- Code(Zero) at (prev + 0, 15) to (start + 2, 6) - Code(Zero) at (prev + 2, 5) to (start + 0, 6) - Code(Zero) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: (none) Function name: unused::unused_func3 (unused) -Raw bytes (24): 0x[01, 01, 00, 04, 00, 1f, 01, 01, 0e, 00, 01, 0f, 02, 06, 00, 02, 05, 00, 06, 00, 01, 01, 00, 02] +Raw bytes (29): 0x[01, 01, 00, 05, 00, 1f, 01, 00, 1c, 00, 01, 08, 00, 0e, 00, 00, 0f, 02, 06, 00, 02, 05, 00, 06, 00, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/unused.rs Number of expressions: 0 -Number of file 0 mappings: 4 -- Code(Zero) at (prev + 31, 1) to (start + 1, 14) -- Code(Zero) at (prev + 1, 15) to (start + 2, 6) +Number of file 0 mappings: 5 +- Code(Zero) at (prev + 31, 1) to (start + 0, 28) +- Code(Zero) at (prev + 1, 8) to (start + 0, 14) +- Code(Zero) at (prev + 0, 15) to (start + 2, 6) - Code(Zero) at (prev + 2, 5) to (start + 0, 6) - Code(Zero) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: (none) Function name: unused::unused_template_func::<_> (unused) -Raw bytes (34): 0x[01, 01, 00, 06, 00, 0b, 01, 01, 12, 00, 02, 0b, 00, 11, 00, 01, 09, 00, 0f, 00, 00, 13, 00, 19, 00, 01, 09, 00, 0f, 00, 02, 01, 00, 02] +Raw bytes (44): 0x[01, 01, 00, 08, 00, 0b, 01, 00, 21, 00, 01, 09, 00, 0e, 00, 00, 11, 00, 12, 00, 01, 0b, 00, 11, 00, 01, 09, 00, 0f, 00, 00, 13, 00, 19, 00, 01, 09, 00, 0f, 00, 02, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/unused.rs Number of expressions: 0 -Number of file 0 mappings: 6 -- Code(Zero) at (prev + 11, 1) to (start + 1, 18) -- Code(Zero) at (prev + 2, 11) to (start + 0, 17) +Number of file 0 mappings: 8 +- Code(Zero) at (prev + 11, 1) to (start + 0, 33) +- Code(Zero) at (prev + 1, 9) to (start + 0, 14) +- Code(Zero) at (prev + 0, 17) to (start + 0, 18) +- Code(Zero) at (prev + 1, 11) to (start + 0, 17) - Code(Zero) at (prev + 1, 9) to (start + 0, 15) - Code(Zero) at (prev + 0, 19) to (start + 0, 25) - Code(Zero) at (prev + 1, 9) to (start + 0, 15) diff --git a/tests/coverage/unused_mod.cov-map b/tests/coverage/unused_mod.cov-map index 5e8b69fcdba9..ea419edbdafe 100644 --- a/tests/coverage/unused_mod.cov-map +++ b/tests/coverage/unused_mod.cov-map @@ -1,18 +1,24 @@ Function name: unused_mod::main -Raw bytes (9): 0x[01, 01, 00, 01, 01, 04, 01, 02, 02] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 04, 01, 00, 0a, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 1c, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/unused_mod.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 4, 1) to (start + 2, 2) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 4, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 28) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: unused_mod::unused_module::never_called_function (unused) -Raw bytes (9): 0x[01, 02, 00, 01, 00, 02, 01, 02, 02] +Raw bytes (24): 0x[01, 02, 00, 04, 00, 02, 01, 00, 1f, 00, 01, 05, 00, 0d, 00, 00, 0e, 00, 21, 00, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 2 +- file 0 => $DIR/auxiliary/unused_mod_helper.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Zero) at (prev + 2, 1) to (start + 2, 2) +Number of file 0 mappings: 4 +- Code(Zero) at (prev + 2, 1) to (start + 0, 31) +- Code(Zero) at (prev + 1, 5) to (start + 0, 13) +- Code(Zero) at (prev + 0, 14) to (start + 0, 33) +- Code(Zero) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: (none) diff --git a/tests/coverage/uses_crate.cov-map b/tests/coverage/uses_crate.cov-map index 5c23f8826971..8f3c63aba5ce 100644 --- a/tests/coverage/uses_crate.cov-map +++ b/tests/coverage/uses_crate.cov-map @@ -1,45 +1,67 @@ Function name: used_crate::used_from_bin_crate_and_lib_crate_generic_function::> -Raw bytes (9): 0x[01, 01, 00, 01, 01, 1b, 01, 02, 02] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 1b, 01, 00, 4c, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 4f, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/auxiliary/used_crate.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 27, 1) to (start + 2, 2) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 27, 1) to (start + 0, 76) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 79) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: used_crate::used_only_from_bin_crate_generic_function::<&alloc::vec::Vec> -Raw bytes (9): 0x[01, 01, 00, 01, 01, 13, 01, 02, 02] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 13, 01, 00, 43, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 46, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/auxiliary/used_crate.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 19, 1) to (start + 2, 2) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 19, 1) to (start + 0, 67) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 70) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: used_crate::used_only_from_bin_crate_generic_function::<&str> -Raw bytes (9): 0x[01, 01, 00, 01, 01, 13, 01, 02, 02] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 13, 01, 00, 43, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 46, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/auxiliary/used_crate.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 19, 1) to (start + 2, 2) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 19, 1) to (start + 0, 67) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 70) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: used_crate::used_with_same_type_from_bin_crate_and_lib_crate_generic_function::<&str> -Raw bytes (9): 0x[01, 01, 00, 01, 01, 1f, 01, 02, 02] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 1f, 01, 00, 5b, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 5e, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/auxiliary/used_crate.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 31, 1) to (start + 2, 2) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 31, 1) to (start + 0, 91) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 94) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: uses_crate::main -Raw bytes (9): 0x[01, 02, 00, 01, 01, 0c, 01, 07, 02] +Raw bytes (59): 0x[01, 02, 00, 0b, 01, 0c, 01, 00, 0a, 01, 01, 05, 00, 1e, 01, 01, 09, 00, 11, 01, 00, 14, 00, 18, 01, 01, 05, 00, 3a, 01, 00, 3b, 00, 44, 01, 01, 05, 00, 3a, 01, 01, 05, 00, 43, 01, 00, 44, 00, 4c, 01, 01, 05, 00, 52, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 2 +- file 0 => $DIR/uses_crate.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 12, 1) to (start + 7, 2) +Number of file 0 mappings: 11 +- Code(Counter(0)) at (prev + 12, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 30) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 17) +- Code(Counter(0)) at (prev + 0, 20) to (start + 0, 24) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 58) +- Code(Counter(0)) at (prev + 0, 59) to (start + 0, 68) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 58) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 67) +- Code(Counter(0)) at (prev + 0, 68) to (start + 0, 76) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 82) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 diff --git a/tests/coverage/uses_crate.coverage b/tests/coverage/uses_crate.coverage index d1b0dadda768..145c0649ac7b 100644 --- a/tests/coverage/uses_crate.coverage +++ b/tests/coverage/uses_crate.coverage @@ -6,9 +6,9 @@ $DIR/auxiliary/used_crate.rs: LL| |use std::fmt::Debug; LL| | LL| 1|pub fn used_function() { - LL| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure - LL| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - LL| 1| // dependent conditions. + LL| | // Initialize test constants in a way that cannot be determined at compile time, to ensure + LL| | // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + LL| | // dependent conditions. LL| 1| let is_true = std::env::args().len() == 1; LL| 1| let mut countdown = 0; LL| 1| if is_true { @@ -104,8 +104,8 @@ $DIR/auxiliary/used_crate.rs: LL| 1|fn use_this_lib_crate() { LL| 1| used_from_bin_crate_and_lib_crate_generic_function("used from library used_crate.rs"); LL| 1| used_with_same_type_from_bin_crate_and_lib_crate_generic_function( - LL| 1| "used from library used_crate.rs", - LL| 1| ); + LL| | "used from library used_crate.rs", + LL| | ); LL| 1| let some_vec = vec![5, 6, 7, 8]; LL| 1| used_only_from_this_lib_crate_generic_function(some_vec); LL| 1| used_only_from_this_lib_crate_generic_function("used ONLY from library used_crate.rs"); diff --git a/tests/coverage/uses_inline_crate.cov-map b/tests/coverage/uses_inline_crate.cov-map index a482d20e3b4b..52f3f94ce642 100644 --- a/tests/coverage/uses_inline_crate.cov-map +++ b/tests/coverage/uses_inline_crate.cov-map @@ -1,59 +1,88 @@ Function name: used_inline_crate::used_from_bin_crate_and_lib_crate_generic_function::> -Raw bytes (9): 0x[01, 01, 00, 01, 01, 2c, 01, 02, 02] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 2c, 01, 00, 4c, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 4f, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/auxiliary/used_inline_crate.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 44, 1) to (start + 2, 2) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 44, 1) to (start + 0, 76) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 79) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: used_inline_crate::used_inline_function -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 14, 01, 06, 0f, 05, 06, 10, 02, 06, 02, 02, 05, 00, 06, 01, 01, 05, 01, 02] +Raw bytes (56): 0x[01, 01, 01, 01, 05, 0a, 01, 14, 01, 00, 1e, 01, 04, 09, 00, 10, 01, 00, 13, 00, 2e, 01, 01, 09, 00, 16, 01, 00, 19, 00, 1a, 01, 01, 08, 00, 0f, 05, 00, 10, 02, 06, 02, 02, 05, 00, 06, 01, 01, 05, 00, 17, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/auxiliary/used_inline_crate.rs Number of expressions: 1 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) -Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 20, 1) to (start + 6, 15) -- Code(Counter(1)) at (prev + 6, 16) to (start + 2, 6) +Number of file 0 mappings: 10 +- Code(Counter(0)) at (prev + 20, 1) to (start + 0, 30) +- Code(Counter(0)) at (prev + 4, 9) to (start + 0, 16) +- Code(Counter(0)) at (prev + 0, 19) to (start + 0, 46) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 22) +- Code(Counter(0)) at (prev + 0, 25) to (start + 0, 26) +- Code(Counter(0)) at (prev + 1, 8) to (start + 0, 15) +- Code(Counter(1)) at (prev + 0, 16) to (start + 2, 6) - Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 0, 6) = (c0 - c1) -- Code(Counter(0)) at (prev + 1, 5) to (start + 1, 2) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 23) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c1 Function name: used_inline_crate::used_only_from_bin_crate_generic_function::<&alloc::vec::Vec> -Raw bytes (9): 0x[01, 01, 00, 01, 01, 21, 01, 02, 02] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 21, 01, 00, 43, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 46, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/auxiliary/used_inline_crate.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 33, 1) to (start + 2, 2) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 33, 1) to (start + 0, 67) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 70) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: used_inline_crate::used_only_from_bin_crate_generic_function::<&str> -Raw bytes (9): 0x[01, 01, 00, 01, 01, 21, 01, 02, 02] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 21, 01, 00, 43, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 46, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/auxiliary/used_inline_crate.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 33, 1) to (start + 2, 2) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 33, 1) to (start + 0, 67) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 70) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: used_inline_crate::used_with_same_type_from_bin_crate_and_lib_crate_generic_function::<&str> -Raw bytes (9): 0x[01, 01, 00, 01, 01, 31, 01, 02, 02] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 31, 01, 00, 5b, 01, 01, 05, 00, 0d, 01, 00, 0e, 00, 5e, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/auxiliary/used_inline_crate.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 49, 1) to (start + 2, 2) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 49, 1) to (start + 0, 91) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 13) +- Code(Counter(0)) at (prev + 0, 14) to (start + 0, 94) +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c0 Function name: uses_inline_crate::main -Raw bytes (9): 0x[01, 02, 00, 01, 01, 0c, 01, 0a, 02] +Raw bytes (64): 0x[01, 02, 00, 0c, 01, 0c, 01, 00, 0a, 01, 01, 05, 00, 25, 01, 01, 05, 00, 2c, 01, 01, 09, 00, 11, 01, 00, 14, 00, 18, 01, 01, 05, 00, 41, 01, 00, 42, 00, 4b, 01, 01, 05, 00, 41, 01, 01, 05, 00, 4a, 01, 00, 4b, 00, 53, 01, 01, 05, 00, 59, 01, 03, 01, 00, 02] Number of files: 1 -- file 0 => global file 2 +- file 0 => $DIR/uses_inline_crate.rs Number of expressions: 0 -Number of file 0 mappings: 1 -- Code(Counter(0)) at (prev + 12, 1) to (start + 10, 2) +Number of file 0 mappings: 12 +- Code(Counter(0)) at (prev + 12, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 37) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 44) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 17) +- Code(Counter(0)) at (prev + 0, 20) to (start + 0, 24) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 65) +- Code(Counter(0)) at (prev + 0, 66) to (start + 0, 75) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 65) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 74) +- Code(Counter(0)) at (prev + 0, 75) to (start + 0, 83) +- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 89) +- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2) Highest counter ID seen: c0 diff --git a/tests/coverage/uses_inline_crate.coverage b/tests/coverage/uses_inline_crate.coverage index 4671c95aefa4..15084bcf7ea9 100644 --- a/tests/coverage/uses_inline_crate.coverage +++ b/tests/coverage/uses_inline_crate.coverage @@ -6,9 +6,9 @@ $DIR/auxiliary/used_inline_crate.rs: LL| |use std::fmt::Debug; LL| | LL| 1|pub fn used_function() { - LL| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure - LL| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - LL| 1| // dependent conditions. + LL| | // Initialize test constants in a way that cannot be determined at compile time, to ensure + LL| | // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + LL| | // dependent conditions. LL| 1| let is_true = std::env::args().len() == 1; LL| 1| let mut countdown = 0; LL| 1| if is_true { @@ -20,9 +20,9 @@ $DIR/auxiliary/used_inline_crate.rs: LL| | LL| |#[inline(always)] LL| 1|pub fn used_inline_function() { - LL| 1| // Initialize test constants in a way that cannot be determined at compile time, to ensure - LL| 1| // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from - LL| 1| // dependent conditions. + LL| | // Initialize test constants in a way that cannot be determined at compile time, to ensure + LL| | // rustc and LLVM cannot optimize out statements (or coverage counters) downstream from + LL| | // dependent conditions. LL| 1| let is_true = std::env::args().len() == 1; LL| 1| let mut countdown = 0; LL| 1| if is_true { @@ -126,8 +126,8 @@ $DIR/auxiliary/used_inline_crate.rs: LL| 2|fn use_this_lib_crate() { LL| 2| used_from_bin_crate_and_lib_crate_generic_function("used from library used_crate.rs"); LL| 2| used_with_same_type_from_bin_crate_and_lib_crate_generic_function( - LL| 2| "used from library used_crate.rs", - LL| 2| ); + LL| | "used from library used_crate.rs", + LL| | ); LL| 2| let some_vec = vec![5, 6, 7, 8]; LL| 2| used_only_from_this_lib_crate_generic_function(some_vec); LL| 2| used_only_from_this_lib_crate_generic_function("used ONLY from library used_crate.rs"); @@ -153,7 +153,7 @@ $DIR/uses_inline_crate.rs: LL| 1| used_inline_crate::used_only_from_bin_crate_generic_function("used from bin uses_crate.rs"); LL| 1| used_inline_crate::used_from_bin_crate_and_lib_crate_generic_function(some_vec); LL| 1| used_inline_crate::used_with_same_type_from_bin_crate_and_lib_crate_generic_function( - LL| 1| "interesting?", - LL| 1| ); + LL| | "interesting?", + LL| | ); LL| 1|} diff --git a/tests/coverage/while.cov-map b/tests/coverage/while.cov-map index 5a6698128cbd..c4183e18e021 100644 --- a/tests/coverage/while.cov-map +++ b/tests/coverage/while.cov-map @@ -1,11 +1,13 @@ Function name: while::main -Raw bytes (24): 0x[01, 01, 00, 04, 01, 01, 01, 01, 10, 01, 02, 0b, 00, 14, 00, 00, 15, 02, 06, 01, 03, 01, 00, 02] +Raw bytes (34): 0x[01, 01, 00, 06, 01, 01, 01, 00, 0a, 01, 01, 09, 00, 0c, 01, 00, 0f, 00, 10, 01, 01, 0b, 00, 14, 00, 00, 15, 02, 06, 01, 03, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/while.rs Number of expressions: 0 -Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 1, 1) to (start + 1, 16) -- Code(Counter(0)) at (prev + 2, 11) to (start + 0, 20) +Number of file 0 mappings: 6 +- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 12) +- Code(Counter(0)) at (prev + 0, 15) to (start + 0, 16) +- Code(Counter(0)) at (prev + 1, 11) to (start + 0, 20) - Code(Zero) at (prev + 0, 21) to (start + 2, 6) - Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2) Highest counter ID seen: c0 diff --git a/tests/coverage/while_early_ret.cov-map b/tests/coverage/while_early_ret.cov-map index 69b51bf9ca34..b29b5d40c4df 100644 --- a/tests/coverage/while_early_ret.cov-map +++ b/tests/coverage/while_early_ret.cov-map @@ -1,27 +1,32 @@ Function name: while_early_ret::main -Raw bytes (63): 0x[01, 01, 07, 0f, 05, 01, 09, 0f, 13, 01, 09, 05, 0d, 05, 01, 05, 09, 09, 01, 05, 01, 01, 1b, 05, 03, 09, 02, 0a, 09, 05, 0d, 02, 0e, 02, 06, 15, 02, 16, 0d, 04, 15, 00, 1b, 0a, 04, 15, 00, 1b, 16, 03, 0a, 03, 0a, 1a, 06, 05, 00, 0b, 01, 01, 01, 00, 02] +Raw bytes (80): 0x[01, 01, 08, 0f, 05, 01, 09, 0f, 13, 01, 09, 05, 0d, 05, 01, 05, 01, 05, 09, 0c, 01, 05, 01, 00, 1c, 01, 01, 09, 00, 16, 01, 00, 19, 00, 1b, 05, 02, 09, 02, 0a, 09, 05, 0d, 02, 0e, 02, 06, 15, 02, 16, 0d, 04, 15, 00, 1b, 0a, 04, 15, 00, 1b, 1a, 03, 09, 00, 0a, 1a, 01, 09, 02, 0a, 1e, 05, 05, 00, 0b, 01, 01, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 -Number of expressions: 7 +- file 0 => $DIR/while_early_ret.rs +Number of expressions: 8 - expression 0 operands: lhs = Expression(3, Add), rhs = Counter(1) - expression 1 operands: lhs = Counter(0), rhs = Counter(2) - expression 2 operands: lhs = Expression(3, Add), rhs = Expression(4, Add) - expression 3 operands: lhs = Counter(0), rhs = Counter(2) - expression 4 operands: lhs = Counter(1), rhs = Counter(3) - expression 5 operands: lhs = Counter(1), rhs = Counter(0) -- expression 6 operands: lhs = Counter(1), rhs = Counter(2) -Number of file 0 mappings: 9 -- Code(Counter(0)) at (prev + 5, 1) to (start + 1, 27) -- Code(Counter(1)) at (prev + 3, 9) to (start + 2, 10) +- expression 6 operands: lhs = Counter(1), rhs = Counter(0) +- expression 7 operands: lhs = Counter(1), rhs = Counter(2) +Number of file 0 mappings: 12 +- Code(Counter(0)) at (prev + 5, 1) to (start + 0, 28) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 22) +- Code(Counter(0)) at (prev + 0, 25) to (start + 0, 27) +- Code(Counter(1)) at (prev + 2, 9) to (start + 2, 10) - Code(Counter(2)) at (prev + 5, 13) to (start + 2, 14) - Code(Expression(0, Sub)) at (prev + 6, 21) to (start + 2, 22) = ((c0 + c2) - c1) - Code(Counter(3)) at (prev + 4, 21) to (start + 0, 27) - Code(Expression(2, Sub)) at (prev + 4, 21) to (start + 0, 27) = ((c0 + c2) - (c1 + c3)) -- Code(Expression(5, Sub)) at (prev + 3, 10) to (start + 3, 10) +- Code(Expression(6, Sub)) at (prev + 3, 9) to (start + 0, 10) = (c1 - c0) -- Code(Expression(6, Sub)) at (prev + 6, 5) to (start + 0, 11) +- Code(Expression(6, Sub)) at (prev + 1, 9) to (start + 2, 10) + = (c1 - c0) +- Code(Expression(7, Sub)) at (prev + 5, 5) to (start + 0, 11) = (c1 - c2) - Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2) Highest counter ID seen: c3 diff --git a/tests/coverage/yield.cov-map b/tests/coverage/yield.cov-map index bf0916e5503a..87d0a0472615 100644 --- a/tests/coverage/yield.cov-map +++ b/tests/coverage/yield.cov-map @@ -1,30 +1,39 @@ Function name: yield::main -Raw bytes (94): 0x[01, 01, 05, 01, 05, 05, 09, 09, 11, 11, 15, 11, 15, 10, 01, 07, 01, 01, 16, 01, 07, 0b, 00, 2e, 05, 01, 27, 00, 29, 02, 01, 0e, 00, 14, 05, 02, 0b, 00, 2e, 0d, 01, 22, 00, 27, 09, 00, 2c, 00, 2e, 06, 01, 0e, 00, 14, 09, 03, 09, 00, 16, 09, 08, 0b, 00, 2e, 11, 01, 27, 00, 29, 0a, 01, 0e, 00, 14, 11, 02, 0b, 00, 2e, 12, 01, 27, 00, 29, 15, 01, 0e, 00, 14, 12, 02, 01, 00, 02] +Raw bytes (139): 0x[01, 01, 05, 01, 05, 05, 09, 09, 11, 11, 15, 11, 15, 19, 01, 07, 01, 00, 0a, 01, 01, 09, 00, 16, 01, 06, 0b, 00, 13, 01, 00, 0b, 00, 2e, 01, 00, 14, 00, 22, 05, 01, 27, 00, 29, 02, 01, 0e, 00, 14, 05, 02, 0b, 00, 13, 05, 00, 0b, 00, 2e, 05, 00, 14, 00, 22, 0d, 01, 22, 00, 27, 09, 00, 2c, 00, 2e, 06, 01, 0e, 00, 14, 09, 03, 09, 00, 16, 09, 08, 0b, 00, 13, 09, 00, 0b, 00, 2e, 09, 00, 14, 00, 22, 11, 01, 27, 00, 29, 0a, 01, 0e, 00, 14, 11, 02, 0b, 00, 13, 11, 00, 0b, 00, 2e, 11, 00, 14, 00, 22, 12, 01, 27, 00, 29, 15, 01, 0e, 00, 14, 12, 02, 01, 00, 02] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/yield.rs Number of expressions: 5 - expression 0 operands: lhs = Counter(0), rhs = Counter(1) - expression 1 operands: lhs = Counter(1), rhs = Counter(2) - expression 2 operands: lhs = Counter(2), rhs = Counter(4) - expression 3 operands: lhs = Counter(4), rhs = Counter(5) - expression 4 operands: lhs = Counter(4), rhs = Counter(5) -Number of file 0 mappings: 16 -- Code(Counter(0)) at (prev + 7, 1) to (start + 1, 22) -- Code(Counter(0)) at (prev + 7, 11) to (start + 0, 46) +Number of file 0 mappings: 25 +- Code(Counter(0)) at (prev + 7, 1) to (start + 0, 10) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 22) +- Code(Counter(0)) at (prev + 6, 11) to (start + 0, 19) +- Code(Counter(0)) at (prev + 0, 11) to (start + 0, 46) +- Code(Counter(0)) at (prev + 0, 20) to (start + 0, 34) - Code(Counter(1)) at (prev + 1, 39) to (start + 0, 41) - Code(Expression(0, Sub)) at (prev + 1, 14) to (start + 0, 20) = (c0 - c1) -- Code(Counter(1)) at (prev + 2, 11) to (start + 0, 46) +- Code(Counter(1)) at (prev + 2, 11) to (start + 0, 19) +- Code(Counter(1)) at (prev + 0, 11) to (start + 0, 46) +- Code(Counter(1)) at (prev + 0, 20) to (start + 0, 34) - Code(Counter(3)) at (prev + 1, 34) to (start + 0, 39) - Code(Counter(2)) at (prev + 0, 44) to (start + 0, 46) - Code(Expression(1, Sub)) at (prev + 1, 14) to (start + 0, 20) = (c1 - c2) - Code(Counter(2)) at (prev + 3, 9) to (start + 0, 22) -- Code(Counter(2)) at (prev + 8, 11) to (start + 0, 46) +- Code(Counter(2)) at (prev + 8, 11) to (start + 0, 19) +- Code(Counter(2)) at (prev + 0, 11) to (start + 0, 46) +- Code(Counter(2)) at (prev + 0, 20) to (start + 0, 34) - Code(Counter(4)) at (prev + 1, 39) to (start + 0, 41) - Code(Expression(2, Sub)) at (prev + 1, 14) to (start + 0, 20) = (c2 - c4) -- Code(Counter(4)) at (prev + 2, 11) to (start + 0, 46) +- Code(Counter(4)) at (prev + 2, 11) to (start + 0, 19) +- Code(Counter(4)) at (prev + 0, 11) to (start + 0, 46) +- Code(Counter(4)) at (prev + 0, 20) to (start + 0, 34) - Code(Expression(4, Sub)) at (prev + 1, 39) to (start + 0, 41) = (c4 - c5) - Code(Counter(5)) at (prev + 1, 14) to (start + 0, 20) @@ -33,24 +42,28 @@ Number of file 0 mappings: 16 Highest counter ID seen: c5 Function name: yield::main::{closure#0} -Raw bytes (14): 0x[01, 01, 00, 02, 01, 09, 08, 01, 10, 05, 02, 10, 01, 06] +Raw bytes (24): 0x[01, 01, 00, 04, 01, 09, 08, 00, 09, 01, 01, 09, 00, 10, 05, 01, 10, 00, 15, 05, 01, 05, 00, 06] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/yield.rs Number of expressions: 0 -Number of file 0 mappings: 2 -- Code(Counter(0)) at (prev + 9, 8) to (start + 1, 16) -- Code(Counter(1)) at (prev + 2, 16) to (start + 1, 6) +Number of file 0 mappings: 4 +- Code(Counter(0)) at (prev + 9, 8) to (start + 0, 9) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 16) +- Code(Counter(1)) at (prev + 1, 16) to (start + 0, 21) +- Code(Counter(1)) at (prev + 1, 5) to (start + 0, 6) Highest counter ID seen: c1 Function name: yield::main::{closure#1} -Raw bytes (24): 0x[01, 01, 00, 04, 01, 18, 08, 01, 10, 05, 02, 09, 00, 10, 09, 01, 09, 00, 10, 0d, 01, 10, 01, 06] +Raw bytes (34): 0x[01, 01, 00, 06, 01, 18, 08, 00, 09, 01, 01, 09, 00, 10, 05, 01, 09, 00, 10, 09, 01, 09, 00, 10, 0d, 01, 10, 00, 15, 0d, 01, 05, 00, 06] Number of files: 1 -- file 0 => global file 1 +- file 0 => $DIR/yield.rs Number of expressions: 0 -Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 24, 8) to (start + 1, 16) -- Code(Counter(1)) at (prev + 2, 9) to (start + 0, 16) +Number of file 0 mappings: 6 +- Code(Counter(0)) at (prev + 24, 8) to (start + 0, 9) +- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 16) +- Code(Counter(1)) at (prev + 1, 9) to (start + 0, 16) - Code(Counter(2)) at (prev + 1, 9) to (start + 0, 16) -- Code(Counter(3)) at (prev + 1, 16) to (start + 1, 6) +- Code(Counter(3)) at (prev + 1, 16) to (start + 0, 21) +- Code(Counter(3)) at (prev + 1, 5) to (start + 0, 6) Highest counter ID seen: c3 diff --git a/tests/crashes/127643.rs b/tests/crashes/127643.rs index a4db9397bdef..b5ec58b70e93 100644 --- a/tests/crashes/127643.rs +++ b/tests/crashes/127643.rs @@ -1,18 +1,18 @@ //@ known-bug: #127643 -#![feature(associated_const_equality)] +#![feature(generic_const_items, associated_const_equality)] +#![expect(incomplete_features)] -fn user() -> impl Owner {} - -trait Owner { - const C: K; -} -impl Owner for () { - const C: K = K::DEFAULT; +trait Foo { + const ASSOC: u32; } -trait ConstDefault { - const DEFAULT: Self; +impl Foo for () { + const ASSOC: u32 = N; } -fn main() {} +fn bar = { N }>>() {} + +fn main() { + bar::<10_u64, ()>(); +} diff --git a/tests/crashes/131758.rs b/tests/crashes/131758.rs deleted file mode 100644 index 942c5fd7a502..000000000000 --- a/tests/crashes/131758.rs +++ /dev/null @@ -1,11 +0,0 @@ -//@ known-bug: #131758 -#![feature(unboxed_closures)] -trait Foo {} - -impl> Foo for T {} - -fn baz(_: T) {} - -fn main() { - baz(|x| ()); -} diff --git a/tests/crashes/133066.rs b/tests/crashes/133066.rs deleted file mode 100644 index 732ebb7079fd..000000000000 --- a/tests/crashes/133066.rs +++ /dev/null @@ -1,12 +0,0 @@ -//@ known-bug: #133066 -trait Owner { - const C: u32; -} - -impl Owner for () {;} - -fn take0(_: impl Owner = { N }>) {} - -fn main() { - take0::(()); -} diff --git a/tests/crashes/138156.rs b/tests/crashes/138156.rs new file mode 100644 index 000000000000..48c6455627f0 --- /dev/null +++ b/tests/crashes/138156.rs @@ -0,0 +1,42 @@ +//@ known-bug: #138156 + +#![feature(generic_const_exprs)] + +#[derive(Default)] +pub struct GenId; + +pub trait IndexTrait: Default { + const IDX: usize; +} +pub trait ToplogyIndex { + type Idx: IndexTrait; +} + +#[derive(Default)] +pub struct Expression { + pub data: T, +} + +fn i(s: Expression) -> + Expression> +where + GenId<{ IDX0 | IDX1 }>: ToplogyIndex, +{ + Expression::default() +} + +pub fn sum(s: Expression) -> Expression +where + [(); In::Idx::IDX]:, +{ + s +} + +fn param_position(s: Expression) +where + GenId<{ 1 | 2 }>: ToplogyIndex, +{ + sum(i::<_, 1, 2>(s)); +} + +fn main() {} diff --git a/tests/crashes/138240.rs b/tests/crashes/138240.rs new file mode 100644 index 000000000000..6ffb7868bd5d --- /dev/null +++ b/tests/crashes/138240.rs @@ -0,0 +1,9 @@ +//@ known-bug: #138240 +//@edition:2024 +#![feature(min_generic_const_args)] +#![feature(inherent_associated_types)] +async fn _CF() -> Box<[u8; Box::b]> { + Box::new(true) +} + +fn main() {} diff --git a/tests/crashes/138265.rs b/tests/crashes/138265.rs new file mode 100644 index 000000000000..f6c8ea748895 --- /dev/null +++ b/tests/crashes/138265.rs @@ -0,0 +1,12 @@ +//@ known-bug: #138265 + +#![feature(coerce_unsized)] +#![crate_type = "lib"] +impl std::ops::CoerceUnsized for A {} +pub fn f() { + [0; { + let mut c = &0; + c = &0; + 0 + }] +} diff --git a/tests/crashes/138266.rs b/tests/crashes/138266.rs new file mode 100644 index 000000000000..9a4de9abcff5 --- /dev/null +++ b/tests/crashes/138266.rs @@ -0,0 +1,7 @@ +//@ known-bug: #138266 +//@compile-flags: --crate-type=lib +#![feature(min_generic_const_args)] +#![feature(inherent_associated_types)] +pub fn f(mut x: [u8; Box::b]) { + x[72] = 1; +} diff --git a/tests/crashes/138359.rs b/tests/crashes/138359.rs new file mode 100644 index 000000000000..d4376d536eec --- /dev/null +++ b/tests/crashes/138359.rs @@ -0,0 +1,8 @@ +//@ known-bug: #138359 +#![feature(min_generic_const_args)] +#![feature(inherent_associated_types)] +struct a(Box<[u8; Box::b]>); +impl a { + fn c(self) { self.0.da } +} +fn main() {} diff --git a/tests/crashes/138361.rs b/tests/crashes/138361.rs new file mode 100644 index 000000000000..8661ed374744 --- /dev/null +++ b/tests/crashes/138361.rs @@ -0,0 +1,6 @@ +//@ known-bug: #138361 + +fn main() { + [0; loop{}]; + std::mem::transmute(4) +} diff --git a/tests/crashes/138510.rs b/tests/crashes/138510.rs new file mode 100644 index 000000000000..f429e8bb33b5 --- /dev/null +++ b/tests/crashes/138510.rs @@ -0,0 +1,7 @@ +//@ known-bug: #138510 +fn main() +where + #[repr()] + _: Sized, +{ +} diff --git a/tests/crashes/138534.rs b/tests/crashes/138534.rs new file mode 100644 index 000000000000..80f9cd225183 --- /dev/null +++ b/tests/crashes/138534.rs @@ -0,0 +1,6 @@ +//@ known-bug: #138534 +//@compile-flags: -Zunpretty=expanded +#[repr(bool)] +pub enum TopFg { + Bar, +} diff --git a/tests/crashes/138564.rs b/tests/crashes/138564.rs new file mode 100644 index 000000000000..b10f75f8cdd0 --- /dev/null +++ b/tests/crashes/138564.rs @@ -0,0 +1,26 @@ +//@ known-bug: #138564 +//@compile-flags: -Copt-level=0 -Cdebuginfo=2 --crate-type lib +#![feature(unsize, dispatch_from_dyn, arbitrary_self_types)] + +use std::marker::Unsize; +use std::ops::{Deref, DispatchFromDyn}; + +#[repr(align(16))] +pub struct MyPointer(*const T); + +impl, U: ?Sized> DispatchFromDyn> for MyPointer {} +impl Deref for MyPointer { + type Target = T; + fn deref(&self) -> &T { + unimplemented!() + } +} + +pub trait Trait { + fn foo(self: MyPointer) {} +} + +// make sure some usage of `::foo` makes it to codegen +pub fn user() -> *const () { + ::foo as *const () +} diff --git a/tests/crashes/138707.rs b/tests/crashes/138707.rs new file mode 100644 index 000000000000..4d9a82500ec4 --- /dev/null +++ b/tests/crashes/138707.rs @@ -0,0 +1,37 @@ +//@ known-bug: #138707 +//@edition:2024 +//@compile-flags: --crate-type lib +use core::marker::PhantomData; + +struct LeftReflector { + _phantom: PhantomData, +} + +struct DefaultAllocator {} + +trait Allocator { + type Buffer; +} + +struct U2 {} + +impl Allocator for DefaultAllocator { + type Buffer = [u8; 2]; +} + +impl From for LeftReflector<>::Buffer> +where + DefaultAllocator: Allocator, +{ + fn from(_: R) -> Self { + todo!() + } +} + +fn ice(a: U2) +where + DefaultAllocator: Allocator, +{ + // ICE + let _ = LeftReflector::from(a); +} diff --git a/tests/crashes/138738.rs b/tests/crashes/138738.rs new file mode 100644 index 000000000000..74e5effa56f5 --- /dev/null +++ b/tests/crashes/138738.rs @@ -0,0 +1,7 @@ +//@ known-bug: #138738 +//@ only-x86_64 + +#![feature(abi_ptx)] +fn main() { + let a = unsafe { core::mem::transmute::(4) }(2); +} diff --git a/tests/crashes/139089.rs b/tests/crashes/139089.rs new file mode 100644 index 000000000000..3326aa6ad984 --- /dev/null +++ b/tests/crashes/139089.rs @@ -0,0 +1,2 @@ +//@ known-bug: #139089 +pub fn foo3(x: &Vec) { x.push(0); } diff --git a/tests/crashes/139120.rs b/tests/crashes/139120.rs new file mode 100644 index 000000000000..f946f010c44e --- /dev/null +++ b/tests/crashes/139120.rs @@ -0,0 +1,29 @@ +//@ known-bug: #139120 + + + +pub trait Foo { + type Bar<'a>; +} + +pub struct FooImpl {} + +impl Foo for FooImpl { + type Bar<'a> = (); +} + +pub trait FooFn { + fn bar(&self); +} + +impl FooFn for fn(T, T::Bar<'_>) { + fn bar(&self) {} +} + +fn foo(f: fn(T, T::Bar<'_>)) { + let _: &dyn FooFn = &f; +} + +fn main() { + foo(|_: FooImpl, _| {}); +} diff --git a/tests/crashes/139381.rs b/tests/crashes/139381.rs new file mode 100644 index 000000000000..6757b584e82a --- /dev/null +++ b/tests/crashes/139381.rs @@ -0,0 +1,13 @@ +//@ known-bug: #139381 +//@ needs-rustc-debug-assertions +trait A<'a> { + type Assoc: ?Sized; +} + +impl<'a> A<'a> for () { + type Assoc = &'a (); +} + +fn hello() -> impl for<'a> A<'a, Assoc: Into + 'static + Copy> { + () +} diff --git a/tests/crashes/139387.rs b/tests/crashes/139387.rs new file mode 100644 index 000000000000..133643ad084b --- /dev/null +++ b/tests/crashes/139387.rs @@ -0,0 +1,15 @@ +//@ known-bug: #139387 +//@ needs-rustc-debug-assertions + +trait A { + fn method() -> impl Sized; +} +trait B { + fn method(Hash: Wrap Epsilon<'_, SI1: Eta>>>) -> impl Sized; +} + +fn ambiguous() +where + T::method(..): Send, +{ +} diff --git a/tests/crashes/139409.rs b/tests/crashes/139409.rs new file mode 100644 index 000000000000..68cbfa153deb --- /dev/null +++ b/tests/crashes/139409.rs @@ -0,0 +1,12 @@ +//@ known-bug: #139409 +//@ compile-flags: -Znext-solver=globally + +fn main() { + trait B {} + impl B for () {} + trait D: B + B { + fn f(&self) {} + } + impl D for () {} + (&() as &dyn D<&(), &()>).f() +} diff --git a/tests/crashes/139462.rs b/tests/crashes/139462.rs new file mode 100644 index 000000000000..05bb246d7be0 --- /dev/null +++ b/tests/crashes/139462.rs @@ -0,0 +1,8 @@ +//@ known-bug: #139462 +//@ compile-flags: -Cdebuginfo=2 +#![feature(unsafe_binders)] +use std::unsafe_binder::wrap_binder; +fn main() { + let foo = 0; + let foo: unsafe<'a> &'a u32 = unsafe { wrap_binder!(&foo) }; +} diff --git a/tests/crashes/139556.rs b/tests/crashes/139556.rs new file mode 100644 index 000000000000..60dc8d7c3afc --- /dev/null +++ b/tests/crashes/139556.rs @@ -0,0 +1,13 @@ +//@ known-bug: #139556 + +trait T {} + +type Alias<'a> = impl T; + +struct S; +impl<'a> T for &'a S {} + +#[define_opaque(Alias)] +fn with_positive(fun: impl Fn(Alias<'_>)) { + with_positive(|&n| ()); +} diff --git a/tests/crashes/139570.rs b/tests/crashes/139570.rs new file mode 100644 index 000000000000..9c001aaf848a --- /dev/null +++ b/tests/crashes/139570.rs @@ -0,0 +1,4 @@ +//@ known-bug: #139570 +fn main() { + |(1, 42), ()| yield; +} diff --git a/tests/crashes/139596.rs b/tests/crashes/139596.rs new file mode 100644 index 000000000000..590cfddf83e2 --- /dev/null +++ b/tests/crashes/139596.rs @@ -0,0 +1,10 @@ +//@ known-bug: #139596 + +#![feature(min_generic_const_args)] +struct Colour; + +struct Led; + +fn main() { + Led::<{ Colour}>; +} diff --git a/tests/crashes/139659.rs b/tests/crashes/139659.rs new file mode 100644 index 000000000000..7fc33f7e6a7c --- /dev/null +++ b/tests/crashes/139659.rs @@ -0,0 +1,29 @@ +//@ known-bug: #139659 +//@compile-flags: -Cdebuginfo=2 -Copt-level=0 --crate-type lib +trait Trait { + type Output; +} + +impl O> Trait for F { + type Output = O; +} + +struct Wrap