diff options
961 files changed, 16842 insertions, 8757 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e5054a07567..841bc39bf1e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -64,12 +64,18 @@ jobs: uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2.7.8 with: workspaces: src/ci/citool + - name: Test citool + # Only test citool on the auto branch, to reduce latency of the calculate matrix job + # on PR/try builds. + if: ${{ github.ref == 'refs/heads/auto' }} + run: | + cd src/ci/citool + CARGO_INCREMENTAL=0 cargo test - name: Calculate the CI job matrix env: COMMIT_MESSAGE: ${{ github.event.head_commit.message }} run: | cd src/ci/citool - CARGO_INCREMENTAL=0 cargo test CARGO_INCREMENTAL=0 cargo run calculate-job-matrix >> $GITHUB_OUTPUT id: jobs job: diff --git a/Cargo.lock b/Cargo.lock index 93abab8469a..9c0978b92f7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -80,9 +80,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.18" +version = "0.6.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" +checksum = "301af1932e46185686725e0fad2f8f2aa7da69dd70bf6ecc44d6b703844a3933" dependencies = [ "anstyle", "anstyle-parse", @@ -95,58 +95,58 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" +checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" [[package]] name = "anstyle-lossy" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "934ff8719effd2023a48cf63e69536c1c3ced9d3895068f6f5cc9a4ff845e59b" +checksum = "04d3a5dc826f84d0ea11882bb8054ff7f3d482602e11bb181101303a279ea01f" dependencies = [ "anstyle", ] [[package]] name = "anstyle-parse" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" +checksum = "6c8bdeb6047d8983be085bab0ba1472e6dc604e7041dbf6fcd5e71523014fae9" dependencies = [ "windows-sys 0.59.0", ] [[package]] name = "anstyle-svg" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3607949e9f6de49ea4bafe12f5e4fd73613ebf24795e48587302a8cc0e4bb35" +checksum = "c681338396641f4e32a29f045d0c70950da7207b4376685b51396c481ee36f1a" dependencies = [ - "anstream", "anstyle", "anstyle-lossy", + "anstyle-parse", "html-escape", "unicode-width 0.2.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.7" +version = "3.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" +checksum = "403f75924867bb1033c59fbf0797484329750cfbe3c4325cd33127941fabc882" dependencies = [ "anstyle", - "once_cell", + "once_cell_polyfill", "windows-sys 0.59.0", ] @@ -266,9 +266,9 @@ dependencies = [ [[package]] name = "bitflags" -version = "2.9.0" +version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" +checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" [[package]] name = "blake3" @@ -341,15 +341,15 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.17.0" +version = "3.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" +checksum = "793db76d6187cd04dff33004d8e6c9cc4e05cd330500379d2394209271b4aeee" [[package]] name = "bytecount" -version = "0.6.8" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ce89b21cab1437276d2650d57e971f9d548a2d9037cc231abdc0562b97498ce" +checksum = "175812e0be2bccb6abe50bb8d566126198344f707e304f45c648fd8f2cc0365e" [[package]] name = "bytes" @@ -359,9 +359,9 @@ checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" [[package]] name = "camino" -version = "1.1.9" +version = "1.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3" +checksum = "0da45bc31171d8d6960122e222a67740df867c1dd53b4d51caa297084c185cab" dependencies = [ "serde", ] @@ -487,9 +487,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.38" +version = "4.5.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed93b9805f8ba930df42c2590f05453d5ec36cbb85d018868a5b24d31f6ac000" +checksum = "fd60e63e9be68e5fb56422e397cf9baddded06dae1d2e523401542383bc72a9f" dependencies = [ "clap_builder", "clap_derive", @@ -507,9 +507,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.38" +version = "4.5.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "379026ff283facf611b0ea629334361c4211d1b12ee01024eec1591133b04120" +checksum = "89cc6392a1f72bbeb820d71f32108f61fdaf18bc526e1d23954168a67759ef51" dependencies = [ "anstream", "anstyle", @@ -642,16 +642,16 @@ dependencies = [ [[package]] name = "color-eyre" -version = "0.6.4" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6e1761c0e16f8883bbbb8ce5990867f4f06bf11a0253da6495a04ce4b6ef0ec" +checksum = "e5920befb47832a6d61ee3a3a846565cfa39b331331e68a3b1d1116630f2f26d" dependencies = [ "backtrace", "color-spantrace", "eyre", "indenter", "once_cell", - "owo-colors 4.2.0", + "owo-colors 4.2.1", "tracing-error", ] @@ -678,21 +678,21 @@ dependencies = [ [[package]] name = "color-spantrace" -version = "0.2.2" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ddd8d5bfda1e11a501d0a7303f3bfed9aa632ebdb859be40d0fd70478ed70d5" +checksum = "b8b88ea9df13354b55bc7234ebcce36e6ef896aca2e42a15de9e10edce01b427" dependencies = [ "once_cell", - "owo-colors 4.2.0", + "owo-colors 4.2.1", "tracing-core", "tracing-error", ] [[package]] name = "colorchoice" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" [[package]] name = "colored" @@ -851,9 +851,9 @@ dependencies = [ [[package]] name = "curl" -version = "0.4.47" +version = "0.4.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9fb4d13a1be2b58f14d60adba57c9834b78c62fd86c3e76a148f732686e9265" +checksum = "9e2d5c8f48d9c0c23250e52b55e82a6ab4fdba6650c931f5a0a57a43abda812b" dependencies = [ "curl-sys", "libc", @@ -861,14 +861,14 @@ dependencies = [ "openssl-sys", "schannel", "socket2", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "curl-sys" -version = "0.4.80+curl-8.12.1" +version = "0.4.82+curl-8.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55f7df2eac63200c3ab25bde3b2268ef2ee56af3d238e76d61f01c3c49bff734" +checksum = "c4d63638b5ec65f1a4ae945287b3fd035be4554bbaf211901159c9a2a74fb5be" dependencies = [ "cc", "libc", @@ -876,7 +876,7 @@ dependencies = [ "openssl-sys", "pkg-config", "vcpkg", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -1142,9 +1142,9 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" -version = "0.3.11" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e" +checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18" dependencies = [ "libc", "windows-sys 0.59.0", @@ -1207,9 +1207,9 @@ dependencies = [ [[package]] name = "flate2" -version = "1.1.1" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece" +checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d" dependencies = [ "crc32fast", "miniz_oxide", @@ -1487,9 +1487,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.3" +version = "0.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3" +checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" dependencies = [ "allocator-api2", "equivalent", @@ -1511,9 +1511,9 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hermit-abi" -version = "0.3.9" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +checksum = "f154ce46856750ed433c8649605bf7ed2de3bc35fd9d2a9f30cddd873c80cb08" [[package]] name = "hex" @@ -1700,9 +1700,9 @@ checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" [[package]] name = "icu_properties" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2549ca8c7241c82f59c80ba2a6f415d931c5b58d24fb8412caa1a1f02c49139a" +checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" dependencies = [ "displaydoc", "icu_collections", @@ -1716,9 +1716,9 @@ dependencies = [ [[package]] name = "icu_properties_data" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8197e866e47b68f8f7d95249e172903bec06004b18b2937f1095d40a0c57de04" +checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" [[package]] name = "icu_provider" @@ -1933,9 +1933,9 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "jiff" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f02000660d30638906021176af16b17498bd0d12813dbfe7b276d8bc7f3c0806" +checksum = "a194df1107f33c79f4f93d02c80798520551949d59dfad22b6157048a88cca93" dependencies = [ "jiff-static", "log", @@ -1946,9 +1946,9 @@ dependencies = [ [[package]] name = "jiff-static" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3c30758ddd7188629c6713fc45d1188af4f44c90582311d0c8d8c9907f60c48" +checksum = "6c6e1db7ed32c6c71b759497fae34bf7933636f75a251b9e736555da426f6442" dependencies = [ "proc-macro2", "quote", @@ -2002,9 +2002,9 @@ dependencies = [ [[package]] name = "jsonpath-rust" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a37c2c87b8d16e788ce359660fead0ea5f4ed29ff400d55be74a4e01d1817d9" +checksum = "5b37465feaf9d41f74df7da98c6c1c31ca8ea06d11b5bf7869c8f1ccc51a793f" dependencies = [ "pest", "pest_derive", @@ -2080,9 +2080,9 @@ dependencies = [ [[package]] name = "libloading" -version = "0.8.7" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a793df0d7afeac54f95b471d3af7f0d4fb975699f972341a4b76988d49cdf0c" +checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" dependencies = [ "cfg-if", "windows-targets 0.53.0", @@ -2170,9 +2170,9 @@ dependencies = [ [[package]] name = "lock_api" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" dependencies = [ "autocfg", "scopeguard", @@ -2463,9 +2463,9 @@ dependencies = [ [[package]] name = "num_cpus" -version = "1.16.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" dependencies = [ "hermit-abi", "libc", @@ -2539,6 +2539,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] +name = "once_cell_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" + +[[package]] name = "opener" version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2558,9 +2564,9 @@ checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" [[package]] name = "openssl-sys" -version = "0.9.108" +version = "0.9.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e145e1651e858e820e4860f7b9c5e169bc1d8ce1c86043be79fa7b7634821847" +checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571" dependencies = [ "cc", "libc", @@ -2611,9 +2617,9 @@ checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" [[package]] name = "owo-colors" -version = "4.2.0" +version = "4.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1036865bb9422d3300cf723f657c2851d0e9ab12567854b1f4eba3d77decf564" +checksum = "26995317201fa17f3656c36716aed4a7c81743a9634ac4c99c0eeda495db0cec" [[package]] name = "pad" @@ -2637,9 +2643,9 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.12.3" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" dependencies = [ "lock_api", "parking_lot_core", @@ -2647,9 +2653,9 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.10" +version = "0.9.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" dependencies = [ "cfg-if", "libc", @@ -2802,9 +2808,9 @@ dependencies = [ [[package]] name = "portable-atomic" -version = "1.11.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e" +checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" [[package]] name = "portable-atomic-util" @@ -3228,9 +3234,9 @@ dependencies = [ [[package]] name = "rustc_apfloat" -version = "0.2.2+llvm-462a31f5a5ab" +version = "0.2.3+llvm-462a31f5a5ab" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "121e2195ff969977a4e2b5c9965ea867fce7e4cb5aee5b09dee698a7932d574f" +checksum = "486c2179b4796f65bfe2ee33679acf0927ac83ecf583ad6c91c3b4570911b9ad" dependencies = [ "bitflags", "smallvec", @@ -3787,6 +3793,7 @@ dependencies = [ "rustc_arena", "rustc_ast", "rustc_attr_data_structures", + "rustc_attr_parsing", "rustc_data_structures", "rustc_errors", "rustc_feature", @@ -4768,9 +4775,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.20" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" +checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" [[package]] name = "ruzstd" @@ -4866,9 +4873,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.8" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" dependencies = [ "serde", ] @@ -4933,15 +4940,15 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.15.0" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "socket2" -version = "0.5.9" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f5fd57c80058a56cf5c777ab8a126398ece8e442983605d280a44ce79d0edef" +checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" dependencies = [ "libc", "windows-sys 0.52.0", @@ -5111,9 +5118,9 @@ dependencies = [ [[package]] name = "sysinfo" -version = "0.35.0" +version = "0.35.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b897c8ea620e181c7955369a31be5f48d9a9121cb59fd33ecef9ff2a34323422" +checksum = "3c3ffa3e4ff2b324a57f7aeb3c349656c7b127c3c189520251a648102a92496e" dependencies = [ "libc", "objc2-core-foundation", @@ -5354,9 +5361,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.45.0" +version = "1.45.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2513ca694ef9ede0fb23fe71a4ee4107cb102b9dc1930f6d0fd77aae068ae165" +checksum = "75ef51a33ef1da925cea3e4eb122833cb377c61439ca401b770f54902b806779" dependencies = [ "backtrace", "bytes", @@ -5386,9 +5393,9 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.9" +version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3da5db5a963e24bc68be8b17b6fa82814bb22ee8660f192bb182771d498f09a3" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" dependencies = [ "serde", ] @@ -5420,9 +5427,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.28" +version = "0.1.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" +checksum = "1b1ffbcf9c6f6b99d386e7444eb608ba646ae452a36b39737deb9663b610f662" dependencies = [ "proc-macro2", "quote", @@ -5504,11 +5511,11 @@ dependencies = [ [[package]] name = "type-map" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "deb68604048ff8fa93347f02441e4487594adc20bb8a084f9e564d2b827a0a9f" +checksum = "cb30dbbd9036155e74adad6812e9898d03ec374946234fbcebd5dfc7b9187b90" dependencies = [ - "rustc-hash 1.1.0", + "rustc-hash 2.1.1", ] [[package]] @@ -5729,11 +5736,13 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.16.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9" +checksum = "3cf4199d1e5d15ddd86a694e4d0dffa9c323ce759fea589f00fef9d81cc1931d" dependencies = [ "getrandom 0.3.3", + "js-sys", + "wasm-bindgen", ] [[package]] @@ -5892,12 +5901,12 @@ dependencies = [ [[package]] name = "wasm-encoder" -version = "0.230.0" +version = "0.233.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4349d0943718e6e434b51b9639e876293093dca4b96384fb136ab5bd5ce6660" +checksum = "9679ae3cf7cfa2ca3a327f7fab97f27f3294d402fd1a76ca8ab514e17973e4d3" dependencies = [ "leb128fmt", - "wasmparser 0.230.0", + "wasmparser 0.233.0", ] [[package]] @@ -5937,42 +5946,42 @@ dependencies = [ [[package]] name = "wasmparser" -version = "0.230.0" +version = "0.232.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "808198a69b5a0535583370a51d459baa14261dfab04800c4864ee9e1a14346ed" +checksum = "917739b33bb1eb0e9a49bcd2637a351931be4578d0cc4d37b908d7a797784fbb" dependencies = [ "bitflags", - "indexmap", - "semver", ] [[package]] name = "wasmparser" -version = "0.232.0" +version = "0.233.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "917739b33bb1eb0e9a49bcd2637a351931be4578d0cc4d37b908d7a797784fbb" +checksum = "b51cb03afce7964bbfce46602d6cb358726f36430b6ba084ac6020d8ce5bc102" dependencies = [ "bitflags", + "indexmap", + "semver", ] [[package]] name = "wast" -version = "230.0.0" +version = "233.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8edac03c5fa691551531533928443faf3dc61a44f814a235c7ec5d17b7b34f1" +checksum = "2eaf4099d8d0c922b83bf3c90663f5666f0769db9e525184284ebbbdb1dd2180" dependencies = [ "bumpalo", "leb128fmt", "memchr", "unicode-width 0.2.0", - "wasm-encoder 0.230.0", + "wasm-encoder 0.233.0", ] [[package]] name = "wat" -version = "1.230.0" +version = "1.233.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d77d62229e38db83eac32bacb5f61ebb952366ab0dae90cf2b3c07a65eea894" +checksum = "3d9bc80f5e4b25ea086ef41b91ccd244adde45d931c384d94a8ff64ab8bd7d87" dependencies = [ "wast", ] @@ -6033,13 +6042,13 @@ dependencies = [ [[package]] name = "windows-bindgen" -version = "0.61.0" +version = "0.61.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac1c59c20569610dd9ed784d5f003fb493ec57b4cf39d974eb03a84bb7156c90" +checksum = "9b4e97b01190d32f268a2dfbd3f006f77840633746707fbe40bcee588108a231" dependencies = [ - "rayon", "serde", "serde_json", + "windows-threading", ] [[package]] @@ -6053,9 +6062,9 @@ dependencies = [ [[package]] name = "windows-core" -version = "0.61.0" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980" +checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" dependencies = [ "windows-implement", "windows-interface", @@ -6066,12 +6075,13 @@ dependencies = [ [[package]] name = "windows-future" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a1d6bbefcb7b60acd19828e1bc965da6fcf18a7e39490c5f8be71e54a19ba32" +checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" dependencies = [ "windows-core", "windows-link", + "windows-threading", ] [[package]] @@ -6114,18 +6124,18 @@ dependencies = [ [[package]] name = "windows-result" -version = "0.3.2" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" dependencies = [ "windows-link", ] [[package]] name = "windows-strings" -version = "0.4.0" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" dependencies = [ "windows-link", ] @@ -6205,6 +6215,15 @@ dependencies = [ ] [[package]] +name = "windows-threading" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6" +dependencies = [ + "windows-link", +] + +[[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/bootstrap.example.toml b/bootstrap.example.toml index 1371fd6442f..19cf360b0fb 100644 --- a/bootstrap.example.toml +++ b/bootstrap.example.toml @@ -381,6 +381,15 @@ # "miri", "cargo-miri" # for dev/nightly channels #] +# Specify build configuration specific for some tool, such as enabled features. +# This option has no effect on which tools are enabled: refer to the `tools` option for that. +# +# For example, to build Miri with tracing support, use `tool.miri.features = ["tracing"]` +# +# The default value for the `features` array is `[]`. However, please note that other flags in +# `bootstrap.toml` might influence the features enabled for some tools. +#tool.TOOL_NAME.features = [FEATURE1, FEATURE2] + # Verbosity level: 0 == not verbose, 1 == verbose, 2 == very verbose, 3 == print environment variables on each rustc invocation #verbose = 0 diff --git a/compiler/rustc_abi/src/canon_abi.rs b/compiler/rustc_abi/src/canon_abi.rs index 03eeb645489..7c020be6761 100644 --- a/compiler/rustc_abi/src/canon_abi.rs +++ b/compiler/rustc_abi/src/canon_abi.rs @@ -28,6 +28,9 @@ pub enum CanonAbi { Rust, RustCold, + /// An ABI that rustc does not know how to call or define. + Custom, + /// ABIs relevant to 32-bit Arm targets Arm(ArmCall), /// ABI relevant to GPUs: the entry point for a GPU kernel @@ -57,6 +60,7 @@ impl fmt::Display for CanonAbi { CanonAbi::C => ExternAbi::C { unwind: false }, CanonAbi::Rust => ExternAbi::Rust, CanonAbi::RustCold => ExternAbi::RustCold, + CanonAbi::Custom => ExternAbi::Custom, CanonAbi::Arm(arm_call) => match arm_call { ArmCall::Aapcs => ExternAbi::Aapcs { unwind: false }, ArmCall::CCmseNonSecureCall => ExternAbi::CCmseNonSecureCall, diff --git a/compiler/rustc_abi/src/extern_abi.rs b/compiler/rustc_abi/src/extern_abi.rs index 0bc1c8a0930..7457ae1f033 100644 --- a/compiler/rustc_abi/src/extern_abi.rs +++ b/compiler/rustc_abi/src/extern_abi.rs @@ -40,6 +40,11 @@ pub enum ExternAbi { /// Even normally-compatible Rust types can become ABI-incompatible with this ABI! Unadjusted, + /// An ABI that rustc does not know how to call or define. Functions with this ABI can + /// only be created using `#[naked]` functions or `extern "custom"` blocks, and can only + /// be called from inline assembly. + Custom, + /// UEFI ABI, usually an alias of C, but sometimes an arch-specific alias /// and only valid on platforms that have a UEFI standard EfiApi, @@ -141,6 +146,7 @@ abi_impls! { AvrNonBlockingInterrupt =><= "avr-non-blocking-interrupt", Cdecl { unwind: false } =><= "cdecl", Cdecl { unwind: true } =><= "cdecl-unwind", + Custom =><= "custom", EfiApi =><= "efiapi", Fastcall { unwind: false } =><= "fastcall", Fastcall { unwind: true } =><= "fastcall-unwind", diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index cf40c3f7f6f..6b51cbd7fbe 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -97,12 +97,12 @@ pub struct Path { pub tokens: Option<LazyAttrTokenStream>, } +// Succeeds if the path has a single segment that is arg-free and matches the given symbol. impl PartialEq<Symbol> for Path { #[inline] fn eq(&self, name: &Symbol) -> bool { if let [segment] = self.segments.as_ref() - && segment.args.is_none() - && segment.ident.name == *name + && segment == name { true } else { @@ -111,6 +111,15 @@ impl PartialEq<Symbol> for Path { } } +// Succeeds if the path has segments that are arg-free and match the given symbols. +impl PartialEq<&[Symbol]> for Path { + #[inline] + fn eq(&self, names: &&[Symbol]) -> bool { + self.segments.len() == names.len() + && self.segments.iter().zip(names.iter()).all(|(s1, s2)| s1 == s2) + } +} + impl<CTX: rustc_span::HashStableContext> HashStable<CTX> for Path { fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { self.segments.len().hash_stable(hcx, hasher); @@ -166,6 +175,14 @@ pub struct PathSegment { pub args: Option<P<GenericArgs>>, } +// Succeeds if the path segment is arg-free and matches the given symbol. +impl PartialEq<Symbol> for PathSegment { + #[inline] + fn eq(&self, name: &Symbol) -> bool { + self.args.is_none() && self.ident.name == *name + } +} + impl PathSegment { pub fn from_ident(ident: Ident) -> Self { PathSegment { ident, id: DUMMY_NODE_ID, args: None } @@ -1441,11 +1458,15 @@ impl Expr { } } - ExprKind::Break(..) - | ExprKind::Ret(..) - | ExprKind::Yield(..) - | ExprKind::Yeet(..) - | ExprKind::Become(..) => ExprPrecedence::Jump, + ExprKind::Break(_ /*label*/, value) + | ExprKind::Ret(value) + | ExprKind::Yield(YieldKind::Prefix(value)) + | ExprKind::Yeet(value) => match value { + Some(_) => ExprPrecedence::Jump, + None => ExprPrecedence::Unambiguous, + }, + + ExprKind::Become(_) => ExprPrecedence::Jump, // `Range` claims to have higher precedence than `Assign`, but `x .. x = x` fails to // parse, instead of parsing as `(x .. x) = x`. Giving `Range` a lower precedence @@ -1502,6 +1523,7 @@ impl Expr { | ExprKind::Underscore | ExprKind::UnsafeBinderCast(..) | ExprKind::While(..) + | ExprKind::Yield(YieldKind::Postfix(..)) | ExprKind::Err(_) | ExprKind::Dummy => ExprPrecedence::Unambiguous, } @@ -3520,6 +3542,38 @@ impl FnHeader { || matches!(constness, Const::Yes(_)) || !matches!(ext, Extern::None) } + + /// Return a span encompassing the header, or none if all options are default. + pub fn span(&self) -> Option<Span> { + fn append(a: &mut Option<Span>, b: Span) { + *a = match a { + None => Some(b), + Some(x) => Some(x.to(b)), + } + } + + let mut full_span = None; + + match self.safety { + Safety::Unsafe(span) | Safety::Safe(span) => append(&mut full_span, span), + Safety::Default => {} + }; + + if let Some(coroutine_kind) = self.coroutine_kind { + append(&mut full_span, coroutine_kind.span()); + } + + if let Const::Yes(span) = self.constness { + append(&mut full_span, span); + } + + match self.ext { + Extern::Implicit(span) | Extern::Explicit(_, span) => append(&mut full_span, span), + Extern::None => {} + } + + full_span + } } impl Default for FnHeader { diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 77cbdde61a4..71a47dcfcba 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -11,7 +11,7 @@ use std::ops::DerefMut; use std::panic; use rustc_data_structures::flat_map_in_place::FlatMapInPlace; -use rustc_data_structures::stack::ensure_sufficient_stack; +use rustc_span::source_map::Spanned; use rustc_span::{Ident, Span}; use smallvec::{Array, SmallVec, smallvec}; use thin_vec::ThinVec; @@ -19,7 +19,7 @@ use thin_vec::ThinVec; use crate::ast::*; use crate::ptr::P; use crate::tokenstream::*; -use crate::visit::{AssocCtxt, BoundKind, FnCtxt, try_visit, visit_opt, walk_list}; +use crate::visit::{AssocCtxt, BoundKind, FnCtxt, VisitorResult, try_visit, visit_opt, walk_list}; pub trait ExpectOne<A: Array> { fn expect_one(self, err: &'static str) -> A::Item; @@ -32,7 +32,22 @@ impl<A: Array> ExpectOne<A> for SmallVec<A> { } } -pub trait MutVisitor: Sized { +mod sealed { + use rustc_ast_ir::visit::VisitorResult; + + /// This is for compatibility with the regular `Visitor`. + pub trait MutVisitorResult { + type Result: VisitorResult; + } + + impl<T> MutVisitorResult for T { + type Result = (); + } +} + +use sealed::MutVisitorResult; + +pub trait MutVisitor: Sized + MutVisitorResult<Result = ()> { // Methods in this trait have one of three forms: // // fn visit_t(&mut self, t: &mut T); // common @@ -227,14 +242,6 @@ pub trait MutVisitor: Sized { walk_generic_args(self, p); } - fn visit_angle_bracketed_parameter_data(&mut self, p: &mut AngleBracketedArgs) { - walk_angle_bracketed_parameter_data(self, p); - } - - fn visit_parenthesized_parameter_data(&mut self, p: &mut ParenthesizedArgs) { - walk_parenthesized_parameter_data(self, p); - } - fn visit_local(&mut self, l: &mut Local) { walk_local(self, l); } @@ -303,10 +310,6 @@ pub trait MutVisitor: Sized { walk_flat_map_expr_field(self, f) } - fn visit_where_clause(&mut self, where_clause: &mut WhereClause) { - walk_where_clause(self, where_clause); - } - fn flat_map_where_predicate( &mut self, where_predicate: WherePredicate, @@ -385,19 +388,14 @@ generate_flat_map_visitor_fns! { visit_generic_params, GenericParam, flat_map_generic_param; visit_stmts, Stmt, flat_map_stmt; visit_exprs, P<Expr>, filter_map_expr; + visit_expr_fields, ExprField, flat_map_expr_field; visit_pat_fields, PatField, flat_map_pat_field; visit_variants, Variant, flat_map_variant; visit_assoc_items, P<AssocItem>, flat_map_assoc_item, ctxt: AssocCtxt; -} - -#[inline] -fn visit_vec<T, F>(elems: &mut Vec<T>, mut visit_elem: F) -where - F: FnMut(&mut T), -{ - for elem in elems { - visit_elem(elem); - } + visit_where_predicates, WherePredicate, flat_map_where_predicate; + visit_params, Param, flat_map_param; + visit_field_defs, FieldDef, flat_map_field_def; + visit_arms, Arm, flat_map_arm; } #[inline] @@ -410,40 +408,12 @@ where } } -#[inline] -fn visit_opt<T, F>(opt: &mut Option<T>, mut visit_elem: F) -where - F: FnMut(&mut T), -{ - if let Some(elem) = opt { - visit_elem(elem); - } -} - fn visit_attrs<T: MutVisitor>(vis: &mut T, attrs: &mut AttrVec) { for attr in attrs.iter_mut() { vis.visit_attribute(attr); } } -fn visit_attr_args<T: MutVisitor>(vis: &mut T, args: &mut AttrArgs) { - match args { - AttrArgs::Empty => {} - AttrArgs::Delimited(args) => visit_delim_args(vis, args), - AttrArgs::Eq { eq_span, expr } => { - vis.visit_expr(expr); - vis.visit_span(eq_span); - } - } -} - -fn visit_delim_args<T: MutVisitor>(vis: &mut T, args: &mut DelimArgs) { - let DelimArgs { dspan, delim: _, tokens: _ } = args; - let DelimSpan { open, close } = dspan; - vis.visit_span(open); - vis.visit_span(close); -} - pub fn walk_flat_map_pat_field<T: MutVisitor>( vis: &mut T, mut fp: PatField, @@ -461,40 +431,11 @@ fn visit_nested_use_tree<V: MutVisitor>( vis.visit_use_tree(nested_tree); } -pub fn walk_arm<T: MutVisitor>(vis: &mut T, arm: &mut Arm) { - let Arm { attrs, pat, guard, body, span, id, is_placeholder: _ } = arm; - vis.visit_id(id); - visit_attrs(vis, attrs); - vis.visit_pat(pat); - visit_opt(guard, |guard| vis.visit_expr(guard)); - visit_opt(body, |body| vis.visit_expr(body)); - vis.visit_span(span); -} - pub fn walk_flat_map_arm<T: MutVisitor>(vis: &mut T, mut arm: Arm) -> SmallVec<[Arm; 1]> { vis.visit_arm(&mut arm); smallvec![arm] } -fn walk_assoc_item_constraint<T: MutVisitor>( - vis: &mut T, - AssocItemConstraint { id, ident, gen_args, kind, span }: &mut AssocItemConstraint, -) { - vis.visit_id(id); - vis.visit_ident(ident); - if let Some(gen_args) = gen_args { - vis.visit_generic_args(gen_args); - } - match kind { - AssocItemConstraintKind::Equality { term } => match term { - Term::Ty(ty) => vis.visit_ty(ty), - Term::Const(c) => vis.visit_anon_const(c), - }, - AssocItemConstraintKind::Bound { bounds } => visit_bounds(vis, bounds, BoundKind::Bound), - } - vis.visit_span(span); -} - pub fn walk_flat_map_variant<T: MutVisitor>( vis: &mut T, mut variant: Variant, @@ -503,64 +444,6 @@ pub fn walk_flat_map_variant<T: MutVisitor>( smallvec![variant] } -fn walk_generic_args<T: MutVisitor>(vis: &mut T, generic_args: &mut GenericArgs) { - match generic_args { - GenericArgs::AngleBracketed(data) => vis.visit_angle_bracketed_parameter_data(data), - GenericArgs::Parenthesized(data) => vis.visit_parenthesized_parameter_data(data), - GenericArgs::ParenthesizedElided(span) => vis.visit_span(span), - } -} - -fn walk_generic_arg<T: MutVisitor>(vis: &mut T, arg: &mut GenericArg) { - match arg { - GenericArg::Lifetime(lt) => vis.visit_lifetime(lt), - GenericArg::Type(ty) => vis.visit_ty(ty), - GenericArg::Const(ct) => vis.visit_anon_const(ct), - } -} - -fn walk_angle_bracketed_parameter_data<T: MutVisitor>(vis: &mut T, data: &mut AngleBracketedArgs) { - let AngleBracketedArgs { args, span } = data; - visit_thin_vec(args, |arg| match arg { - AngleBracketedArg::Arg(arg) => vis.visit_generic_arg(arg), - AngleBracketedArg::Constraint(constraint) => vis.visit_assoc_item_constraint(constraint), - }); - vis.visit_span(span); -} - -fn walk_parenthesized_parameter_data<T: MutVisitor>(vis: &mut T, args: &mut ParenthesizedArgs) { - let ParenthesizedArgs { inputs, output, span, inputs_span } = args; - visit_thin_vec(inputs, |input| vis.visit_ty(input)); - vis.visit_fn_ret_ty(output); - vis.visit_span(span); - vis.visit_span(inputs_span); -} - -fn walk_attribute<T: MutVisitor>(vis: &mut T, attr: &mut Attribute) { - let Attribute { kind, id: _, style: _, span } = attr; - match kind { - AttrKind::Normal(normal) => { - let NormalAttr { item: AttrItem { unsafety: _, path, args, tokens: _ }, tokens: _ } = - &mut **normal; - vis.visit_path(path); - visit_attr_args(vis, args); - } - AttrKind::DocComment(_kind, _sym) => {} - } - vis.visit_span(span); -} - -fn walk_mac<T: MutVisitor>(vis: &mut T, mac: &mut MacCall) { - let MacCall { path, args } = mac; - vis.visit_path(path); - visit_delim_args(vis, args); -} - -fn walk_macro_def<T: MutVisitor>(vis: &mut T, macro_def: &mut MacroDef) { - let MacroDef { body, macro_rules: _ } = macro_def; - visit_delim_args(vis, body); -} - fn walk_meta_list_item<T: MutVisitor>(vis: &mut T, li: &mut MetaItemInner) { match li { MetaItemInner::MetaItem(mi) => vis.visit_meta_item(mi), @@ -578,138 +461,11 @@ fn walk_meta_item<T: MutVisitor>(vis: &mut T, mi: &mut MetaItem) { vis.visit_span(span); } -pub fn walk_param<T: MutVisitor>(vis: &mut T, param: &mut Param) { - let Param { attrs, id, pat, span, ty, is_placeholder: _ } = param; - vis.visit_id(id); - visit_attrs(vis, attrs); - vis.visit_pat(pat); - vis.visit_ty(ty); - vis.visit_span(span); -} - pub fn walk_flat_map_param<T: MutVisitor>(vis: &mut T, mut param: Param) -> SmallVec<[Param; 1]> { vis.visit_param(&mut param); smallvec![param] } -fn walk_closure_binder<T: MutVisitor>(vis: &mut T, binder: &mut ClosureBinder) { - match binder { - ClosureBinder::NotPresent => {} - ClosureBinder::For { span: _, generic_params } => { - generic_params.flat_map_in_place(|param| vis.flat_map_generic_param(param)); - } - } -} - -fn walk_fn<T: MutVisitor>(vis: &mut T, kind: FnKind<'_>) { - match kind { - FnKind::Fn( - _ctxt, - _vis, - Fn { - defaultness, - ident, - generics, - contract, - body, - sig: FnSig { header, decl, span }, - define_opaque, - }, - ) => { - // Visibility is visited as a part of the item. - visit_defaultness(vis, defaultness); - vis.visit_ident(ident); - vis.visit_fn_header(header); - vis.visit_generics(generics); - vis.visit_fn_decl(decl); - if let Some(contract) = contract { - vis.visit_contract(contract); - } - if let Some(body) = body { - vis.visit_block(body); - } - vis.visit_span(span); - - walk_define_opaques(vis, define_opaque); - } - FnKind::Closure(binder, coroutine_kind, decl, body) => { - vis.visit_closure_binder(binder); - coroutine_kind.as_mut().map(|coroutine_kind| vis.visit_coroutine_kind(coroutine_kind)); - vis.visit_fn_decl(decl); - vis.visit_expr(body); - } - } -} - -fn walk_contract<T: MutVisitor>(vis: &mut T, contract: &mut FnContract) { - let FnContract { requires, ensures } = contract; - if let Some(pred) = requires { - vis.visit_expr(pred); - } - if let Some(pred) = ensures { - vis.visit_expr(pred); - } -} - -fn walk_fn_decl<T: MutVisitor>(vis: &mut T, decl: &mut FnDecl) { - let FnDecl { inputs, output } = decl; - inputs.flat_map_in_place(|param| vis.flat_map_param(param)); - vis.visit_fn_ret_ty(output); -} - -fn walk_fn_ret_ty<T: MutVisitor>(vis: &mut T, fn_ret_ty: &mut FnRetTy) { - match fn_ret_ty { - FnRetTy::Default(span) => vis.visit_span(span), - FnRetTy::Ty(ty) => vis.visit_ty(ty), - } -} - -fn walk_param_bound<T: MutVisitor>(vis: &mut T, pb: &mut GenericBound) { - match pb { - GenericBound::Trait(trait_ref) => vis.visit_poly_trait_ref(trait_ref), - GenericBound::Outlives(lifetime) => walk_lifetime(vis, lifetime), - GenericBound::Use(args, span) => { - for arg in args { - vis.visit_precise_capturing_arg(arg); - } - vis.visit_span(span); - } - } -} - -fn walk_precise_capturing_arg<T: MutVisitor>(vis: &mut T, arg: &mut PreciseCapturingArg) { - match arg { - PreciseCapturingArg::Lifetime(lt) => { - vis.visit_lifetime(lt); - } - PreciseCapturingArg::Arg(path, id) => { - vis.visit_id(id); - vis.visit_path(path); - } - } -} - -pub fn walk_generic_param<T: MutVisitor>(vis: &mut T, param: &mut GenericParam) { - let GenericParam { id, ident, attrs, bounds, kind, colon_span, is_placeholder: _ } = param; - vis.visit_id(id); - visit_attrs(vis, attrs); - vis.visit_ident(ident); - visit_vec(bounds, |bound| vis.visit_param_bound(bound, BoundKind::Bound)); - match kind { - GenericParamKind::Lifetime => {} - GenericParamKind::Type { default } => { - visit_opt(default, |default| vis.visit_ty(default)); - } - GenericParamKind::Const { ty, kw_span: _, default } => { - vis.visit_ty(ty); - visit_opt(default, |default| vis.visit_anon_const(default)); - } - } - if let Some(colon_span) = colon_span { - vis.visit_span(colon_span); - } -} - pub fn walk_flat_map_generic_param<T: MutVisitor>( vis: &mut T, mut param: GenericParam, @@ -718,13 +474,6 @@ pub fn walk_flat_map_generic_param<T: MutVisitor>( smallvec![param] } -fn walk_generics<T: MutVisitor>(vis: &mut T, generics: &mut Generics) { - let Generics { params, where_clause, span } = generics; - params.flat_map_in_place(|param| vis.flat_map_generic_param(param)); - vis.visit_where_clause(where_clause); - vis.visit_span(span); -} - fn walk_ty_alias_where_clauses<T: MutVisitor>(vis: &mut T, tawcs: &mut TyAliasWhereClauses) { let TyAliasWhereClauses { before, after, split: _ } = tawcs; let TyAliasWhereClause { has_where_token: _, span: span_before } = before; @@ -733,70 +482,14 @@ fn walk_ty_alias_where_clauses<T: MutVisitor>(vis: &mut T, tawcs: &mut TyAliasWh vis.visit_span(span_after); } -fn walk_where_clause<T: MutVisitor>(vis: &mut T, wc: &mut WhereClause) { - let WhereClause { has_where_token: _, predicates, span } = wc; - predicates.flat_map_in_place(|predicate| vis.flat_map_where_predicate(predicate)); - vis.visit_span(span); -} - pub fn walk_flat_map_where_predicate<T: MutVisitor>( vis: &mut T, mut pred: WherePredicate, ) -> SmallVec<[WherePredicate; 1]> { - let WherePredicate { attrs, kind, id, span, is_placeholder: _ } = &mut pred; - vis.visit_id(id); - visit_attrs(vis, attrs); - vis.visit_where_predicate_kind(kind); - vis.visit_span(span); + walk_where_predicate(vis, &mut pred); smallvec![pred] } -pub fn walk_where_predicate_kind<T: MutVisitor>(vis: &mut T, kind: &mut WherePredicateKind) { - match kind { - WherePredicateKind::BoundPredicate(bp) => { - let WhereBoundPredicate { bound_generic_params, bounded_ty, bounds } = bp; - bound_generic_params.flat_map_in_place(|param| vis.flat_map_generic_param(param)); - vis.visit_ty(bounded_ty); - visit_vec(bounds, |bound| vis.visit_param_bound(bound, BoundKind::Bound)); - } - WherePredicateKind::RegionPredicate(rp) => { - let WhereRegionPredicate { lifetime, bounds } = rp; - vis.visit_lifetime(lifetime); - visit_vec(bounds, |bound| vis.visit_param_bound(bound, BoundKind::Bound)); - } - WherePredicateKind::EqPredicate(ep) => { - let WhereEqPredicate { lhs_ty, rhs_ty } = ep; - vis.visit_ty(lhs_ty); - vis.visit_ty(rhs_ty); - } - } -} - -fn walk_variant_data<T: MutVisitor>(vis: &mut T, vdata: &mut VariantData) { - match vdata { - VariantData::Struct { fields, recovered: _ } => { - fields.flat_map_in_place(|field| vis.flat_map_field_def(field)); - } - VariantData::Tuple(fields, id) => { - vis.visit_id(id); - fields.flat_map_in_place(|field| vis.flat_map_field_def(field)); - } - VariantData::Unit(id) => vis.visit_id(id), - } -} - -pub fn walk_field_def<T: MutVisitor>(visitor: &mut T, fd: &mut FieldDef) { - let FieldDef { span, ident, vis, id, ty, attrs, is_placeholder: _, safety, default } = fd; - visitor.visit_id(id); - visit_attrs(visitor, attrs); - visitor.visit_vis(vis); - visit_safety(visitor, safety); - visit_opt(ident, |ident| visitor.visit_ident(ident)); - visitor.visit_ty(ty); - visit_opt(default, |default| visitor.visit_anon_const(default)); - visitor.visit_span(span); -} - pub fn walk_flat_map_field_def<T: MutVisitor>( vis: &mut T, mut fd: FieldDef, @@ -846,255 +539,6 @@ pub fn walk_flat_map_assoc_item( smallvec![item] } -fn walk_inline_asm<T: MutVisitor>(vis: &mut T, asm: &mut InlineAsm) { - // FIXME: Visit spans inside all this currently ignored stuff. - let InlineAsm { - asm_macro: _, - template: _, - template_strs: _, - operands, - clobber_abis: _, - options: _, - line_spans: _, - } = asm; - for (op, span) in operands { - match op { - InlineAsmOperand::In { expr, reg: _ } - | InlineAsmOperand::Out { expr: Some(expr), reg: _, late: _ } - | InlineAsmOperand::InOut { expr, reg: _, late: _ } => vis.visit_expr(expr), - InlineAsmOperand::Out { expr: None, reg: _, late: _ } => {} - InlineAsmOperand::SplitInOut { in_expr, out_expr, reg: _, late: _ } => { - vis.visit_expr(in_expr); - if let Some(out_expr) = out_expr { - vis.visit_expr(out_expr); - } - } - InlineAsmOperand::Const { anon_const } => vis.visit_anon_const(anon_const), - InlineAsmOperand::Sym { sym } => vis.visit_inline_asm_sym(sym), - InlineAsmOperand::Label { block } => vis.visit_block(block), - } - vis.visit_span(span); - } -} - -fn walk_inline_asm_sym<T: MutVisitor>( - vis: &mut T, - InlineAsmSym { id, qself, path }: &mut InlineAsmSym, -) { - vis.visit_id(id); - vis.visit_qself(qself); - vis.visit_path(path); -} - -fn walk_format_args<T: MutVisitor>(vis: &mut T, fmt: &mut FormatArgs) { - // FIXME: visit the template exhaustively. - let FormatArgs { span, template: _, arguments, uncooked_fmt_str: _ } = fmt; - for FormatArgument { kind, expr } in arguments.all_args_mut() { - match kind { - FormatArgumentKind::Named(ident) | FormatArgumentKind::Captured(ident) => { - vis.visit_ident(ident) - } - FormatArgumentKind::Normal => {} - } - vis.visit_expr(expr); - } - vis.visit_span(span); -} - -pub fn walk_expr<T: MutVisitor>(vis: &mut T, Expr { kind, id, span, attrs, tokens: _ }: &mut Expr) { - vis.visit_id(id); - visit_attrs(vis, attrs); - match kind { - ExprKind::Array(exprs) => visit_exprs(vis, exprs), - ExprKind::ConstBlock(anon_const) => { - vis.visit_anon_const(anon_const); - } - ExprKind::Repeat(expr, count) => { - vis.visit_expr(expr); - vis.visit_anon_const(count); - } - ExprKind::Tup(exprs) => visit_exprs(vis, exprs), - ExprKind::Call(f, args) => { - vis.visit_expr(f); - visit_exprs(vis, args); - } - ExprKind::MethodCall(box MethodCall { - seg: PathSegment { ident, id, args: seg_args }, - receiver, - args: call_args, - span, - }) => { - vis.visit_method_receiver_expr(receiver); - vis.visit_id(id); - vis.visit_ident(ident); - visit_opt(seg_args, |args| vis.visit_generic_args(args)); - visit_exprs(vis, call_args); - vis.visit_span(span); - } - ExprKind::Binary(binop, lhs, rhs) => { - vis.visit_expr(lhs); - vis.visit_expr(rhs); - vis.visit_span(&mut binop.span); - } - ExprKind::Unary(_unop, ohs) => vis.visit_expr(ohs), - ExprKind::Cast(expr, ty) => { - vis.visit_expr(expr); - vis.visit_ty(ty); - } - ExprKind::Type(expr, ty) => { - vis.visit_expr(expr); - vis.visit_ty(ty); - } - ExprKind::AddrOf(_kind, _mut, ohs) => vis.visit_expr(ohs), - ExprKind::Let(pat, scrutinee, span, _recovered) => { - vis.visit_pat(pat); - vis.visit_expr(scrutinee); - vis.visit_span(span); - } - ExprKind::If(cond, tr, fl) => { - vis.visit_expr(cond); - vis.visit_block(tr); - visit_opt(fl, |fl| ensure_sufficient_stack(|| vis.visit_expr(fl))); - } - ExprKind::While(cond, body, label) => { - visit_opt(label, |label| vis.visit_label(label)); - vis.visit_expr(cond); - vis.visit_block(body); - } - ExprKind::ForLoop { pat, iter, body, label, kind: _ } => { - visit_opt(label, |label| vis.visit_label(label)); - vis.visit_pat(pat); - vis.visit_expr(iter); - vis.visit_block(body); - } - ExprKind::Loop(body, label, span) => { - visit_opt(label, |label| vis.visit_label(label)); - vis.visit_block(body); - vis.visit_span(span); - } - ExprKind::Match(expr, arms, _kind) => { - vis.visit_expr(expr); - arms.flat_map_in_place(|arm| vis.flat_map_arm(arm)); - } - ExprKind::Closure(box Closure { - binder, - capture_clause, - constness, - coroutine_kind, - movability: _, - fn_decl, - body, - fn_decl_span, - fn_arg_span, - }) => { - visit_constness(vis, constness); - vis.visit_capture_by(capture_clause); - vis.visit_fn(FnKind::Closure(binder, coroutine_kind, fn_decl, body), *span, *id); - vis.visit_span(fn_decl_span); - vis.visit_span(fn_arg_span); - } - ExprKind::Block(blk, label) => { - visit_opt(label, |label| vis.visit_label(label)); - vis.visit_block(blk); - } - ExprKind::Gen(_capture_by, body, _kind, decl_span) => { - vis.visit_block(body); - vis.visit_span(decl_span); - } - ExprKind::Await(expr, await_kw_span) => { - vis.visit_expr(expr); - vis.visit_span(await_kw_span); - } - ExprKind::Use(expr, use_kw_span) => { - vis.visit_expr(expr); - vis.visit_span(use_kw_span); - } - ExprKind::Assign(el, er, span) => { - vis.visit_expr(el); - vis.visit_expr(er); - vis.visit_span(span); - } - ExprKind::AssignOp(_op, el, er) => { - vis.visit_expr(el); - vis.visit_expr(er); - } - ExprKind::Field(el, ident) => { - vis.visit_expr(el); - vis.visit_ident(ident); - } - ExprKind::Index(el, er, brackets_span) => { - vis.visit_expr(el); - vis.visit_expr(er); - vis.visit_span(brackets_span); - } - ExprKind::Range(e1, e2, _lim) => { - visit_opt(e1, |e1| vis.visit_expr(e1)); - visit_opt(e2, |e2| vis.visit_expr(e2)); - } - ExprKind::Underscore => {} - ExprKind::Path(qself, path) => { - vis.visit_qself(qself); - vis.visit_path(path); - } - ExprKind::Break(label, expr) => { - visit_opt(label, |label| vis.visit_label(label)); - visit_opt(expr, |expr| vis.visit_expr(expr)); - } - ExprKind::Continue(label) => { - visit_opt(label, |label| vis.visit_label(label)); - } - ExprKind::Ret(expr) => { - visit_opt(expr, |expr| vis.visit_expr(expr)); - } - ExprKind::Yeet(expr) => { - visit_opt(expr, |expr| vis.visit_expr(expr)); - } - ExprKind::Become(expr) => vis.visit_expr(expr), - ExprKind::InlineAsm(asm) => vis.visit_inline_asm(asm), - ExprKind::FormatArgs(fmt) => vis.visit_format_args(fmt), - ExprKind::OffsetOf(container, fields) => { - vis.visit_ty(container); - for field in fields.iter_mut() { - vis.visit_ident(field); - } - } - ExprKind::MacCall(mac) => vis.visit_mac_call(mac), - ExprKind::Struct(se) => { - let StructExpr { qself, path, fields, rest } = se.deref_mut(); - vis.visit_qself(qself); - vis.visit_path(path); - fields.flat_map_in_place(|field| vis.flat_map_expr_field(field)); - match rest { - StructRest::Base(expr) => vis.visit_expr(expr), - StructRest::Rest(_span) => {} - StructRest::None => {} - } - } - ExprKind::Paren(expr) => { - vis.visit_expr(expr); - } - ExprKind::Yield(kind) => { - let expr = kind.expr_mut(); - if let Some(expr) = expr { - vis.visit_expr(expr); - } - } - ExprKind::Try(expr) => vis.visit_expr(expr), - ExprKind::TryBlock(body) => vis.visit_block(body), - ExprKind::Lit(_token) => {} - ExprKind::IncludedBytes(_bytes) => {} - ExprKind::UnsafeBinderCast(_kind, expr, ty) => { - vis.visit_expr(expr); - if let Some(ty) = ty { - vis.visit_ty(ty); - } - } - ExprKind::Err(_guar) => {} - ExprKind::Dummy => {} - } - vis.visit_span(span); -} - pub fn walk_filter_map_expr<T: MutVisitor>(vis: &mut T, mut e: P<Expr>) -> Option<P<Expr>> { vis.visit_expr(&mut e); Some(e) @@ -1139,18 +583,6 @@ fn walk_flat_map_stmt_kind<T: MutVisitor>(vis: &mut T, kind: StmtKind) -> SmallV } } -fn walk_vis<T: MutVisitor>(vis: &mut T, visibility: &mut Visibility) { - let Visibility { kind, span, tokens: _ } = visibility; - match kind { - VisibilityKind::Public | VisibilityKind::Inherited => {} - VisibilityKind::Restricted { path, id, shorthand: _ } => { - vis.visit_id(id); - vis.visit_path(path); - } - } - vis.visit_span(span); -} - fn walk_capture_by<T: MutVisitor>(vis: &mut T, capture_by: &mut CaptureBy) { match capture_by { CaptureBy::Ref => {} diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index d2f22b04a67..c88aa5c33ea 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -15,11 +15,13 @@ pub use rustc_ast_ir::visit::VisitorResult; pub use rustc_ast_ir::{try_visit, visit_opt, walk_list, walk_visitable_list}; +use rustc_span::source_map::Spanned; use rustc_span::{Ident, Span}; use thin_vec::ThinVec; use crate::ast::*; use crate::ptr::P; +use crate::tokenstream::DelimSpan; #[derive(Copy, Clone, Debug, PartialEq)] pub enum AssocCtxt { @@ -237,8 +239,8 @@ pub trait Visitor<'ast>: Sized { fn visit_id(&mut self, _id: NodeId) -> Self::Result { Self::Result::output() } - fn visit_macro_def(&mut self, _mac: &'ast MacroDef) -> Self::Result { - Self::Result::output() + fn visit_macro_def(&mut self, macro_def: &'ast MacroDef) -> Self::Result { + walk_macro_def(self, macro_def) } fn visit_path(&mut self, path: &'ast Path) -> Self::Result { walk_path(self, path) @@ -320,8 +322,8 @@ macro_rules! common_visitor_and_walkers { id: NodeId, visibility: &$($lt)? $($mut)? Visibility, ctxt: Self::Ctxt, - visitor: &mut V, - ) $(-> <V as Visitor<$lt>>::Result)?; + vis: &mut V, + ) -> V::Result; } // this is only used by the MutVisitor. We include this symmetry here to make writing other functions easier @@ -329,12 +331,12 @@ macro_rules! common_visitor_and_walkers { #[expect(unused, rustc::pass_by_value)] #[inline] )? - fn visit_span<$($lt,)? V: $Visitor$(<$lt>)?>(visitor: &mut V, span: &$($lt)? $($mut)? Span) $(-> <V as Visitor<$lt>>::Result)? { + fn visit_span<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, span: &$($lt)? $($mut)? Span) -> V::Result { $( ${ignore($mut)} - visitor.visit_span(span); + vis.visit_span(span); )? - $(${ignore($lt)}V::Result::output())? + V::Result::output() } /// helper since `Visitor` wants `NodeId` but `MutVisitor` wants `&mut NodeId` @@ -342,34 +344,34 @@ macro_rules! common_visitor_and_walkers { #[expect(rustc::pass_by_value)] )? #[inline] - fn visit_id<$($lt,)? V: $Visitor$(<$lt>)?>(visitor: &mut V, id: &$($lt)? $($mut)? NodeId) $(-> <V as Visitor<$lt>>::Result)? { + fn visit_id<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, id: &$($lt)? $($mut)? NodeId) -> V::Result { // deref `&NodeId` into `NodeId` only for `Visitor` - visitor.visit_id( $(${ignore($lt)} * )? id) + vis.visit_id( $(${ignore($lt)} * )? id) } // this is only used by the MutVisitor. We include this symmetry here to make writing other functions easier - fn visit_safety<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, safety: &$($lt)? $($mut)? Safety) $(-> <V as Visitor<$lt>>::Result)? { + fn visit_safety<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, safety: &$($lt)? $($mut)? Safety) -> V::Result { match safety { Safety::Unsafe(span) => visit_span(vis, span), Safety::Safe(span) => visit_span(vis, span), - Safety::Default => { $(${ignore($lt)}V::Result::output())? } + Safety::Default => { V::Result::output() } } } - fn visit_constness<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, constness: &$($lt)? $($mut)? Const) $(-> <V as Visitor<$lt>>::Result)? { + fn visit_constness<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, constness: &$($lt)? $($mut)? Const) -> V::Result { match constness { Const::Yes(span) => visit_span(vis, span), Const::No => { - $(<V as Visitor<$lt>>::Result::output())? + V::Result::output() } } } - fn visit_defaultness<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, defaultness: &$($lt)? $($mut)? Defaultness) $(-> <V as Visitor<$lt>>::Result)? { + fn visit_defaultness<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, defaultness: &$($lt)? $($mut)? Defaultness) -> V::Result { match defaultness { Defaultness::Default(span) => visit_span(vis, span), Defaultness::Final => { - $(<V as Visitor<$lt>>::Result::output())? + V::Result::output() } } } @@ -377,9 +379,9 @@ macro_rules! common_visitor_and_walkers { fn visit_polarity<$($lt,)? V: $Visitor$(<$lt>)?>( vis: &mut V, polarity: &$($lt)? $($mut)? ImplPolarity, - ) $(-> <V as Visitor<$lt>>::Result)? { + ) -> V::Result { match polarity { - ImplPolarity::Positive => { $(<V as Visitor<$lt>>::Result::output())? } + ImplPolarity::Positive => { V::Result::output() } ImplPolarity::Negative(span) => visit_span(vis, span), } } @@ -390,7 +392,7 @@ macro_rules! common_visitor_and_walkers { fn visit_modifiers<$($lt,)? V: $Visitor$(<$lt>)?>( vis: &mut V, m: &$($lt)? $($mut)? TraitBoundModifiers - ) $(-> <V as Visitor<$lt>>::Result)? { + ) -> V::Result { let TraitBoundModifiers { constness, asyncness, polarity } = m; match constness { BoundConstness::Never => {} @@ -404,26 +406,26 @@ macro_rules! common_visitor_and_walkers { BoundPolarity::Positive => {} BoundPolarity::Negative(span) | BoundPolarity::Maybe(span) => try_visit!(visit_span(vis, span)), } - $(<V as Visitor<$lt>>::Result::output())? + V::Result::output() } - fn visit_bounds<$($lt,)? V: $Visitor$(<$lt>)?>(visitor: &mut V, bounds: &$($lt)? $($mut)? GenericBounds, ctxt: BoundKind) $(-> <V as Visitor<$lt>>::Result)? { + fn visit_bounds<$($lt,)? V: $Visitor$(<$lt>)?>(visitor: &mut V, bounds: &$($lt)? $($mut)? GenericBounds, ctxt: BoundKind) -> V::Result { walk_list!(visitor, visit_param_bound, bounds, ctxt); - $(<V as Visitor<$lt>>::Result::output())? + V::Result::output() } - pub fn walk_label<$($lt,)? V: $Visitor$(<$lt>)?>(visitor: &mut V, Label { ident }: &$($lt)? $($mut)? Label) $(-> <V as Visitor<$lt>>::Result)? { + pub fn walk_label<$($lt,)? V: $Visitor$(<$lt>)?>(visitor: &mut V, Label { ident }: &$($lt)? $($mut)? Label) -> V::Result { visitor.visit_ident(ident) } - pub fn walk_fn_header<$($lt,)? V: $Visitor$(<$lt>)?>(visitor: &mut V, header: &$($lt)? $($mut)? FnHeader) $(-> <V as Visitor<$lt>>::Result)? { + pub fn walk_fn_header<$($lt,)? V: $Visitor$(<$lt>)?>(visitor: &mut V, header: &$($lt)? $($mut)? FnHeader) -> V::Result { let FnHeader { safety, coroutine_kind, constness, ext: _ } = header; try_visit!(visit_constness(visitor, constness)); visit_opt!(visitor, visit_coroutine_kind, coroutine_kind); visit_safety(visitor, safety) } - pub fn walk_lifetime<$($lt,)? V: $Visitor$(<$lt>)?>(visitor: &mut V, Lifetime { id, ident }: &$($lt)? $($mut)? Lifetime) $(-> <V as Visitor<$lt>>::Result)? { + pub fn walk_lifetime<$($lt,)? V: $Visitor$(<$lt>)?>(visitor: &mut V, Lifetime { id, ident }: &$($lt)? $($mut)? Lifetime) -> V::Result { try_visit!(visit_id(visitor, id)); visitor.visit_ident(ident) } @@ -432,7 +434,7 @@ macro_rules! common_visitor_and_walkers { visitor: &mut V, item: &$($mut)? $($lt)? Item<K>, ctxt: K::Ctxt, - ) $(-> <V as Visitor<$lt>>::Result)? { + ) -> V::Result { let Item { attrs, id, kind, vis, span, tokens: _ } = item; try_visit!(visit_id(visitor, id)); walk_list!(visitor, visit_attribute, attrs); @@ -444,7 +446,7 @@ macro_rules! common_visitor_and_walkers { pub fn walk_item<$($lt,)? V: $Visitor$(<$lt>)?, K: WalkItemKind<Ctxt = ()>>( visitor: &mut V, item: &$($mut)? $($lt)? Item<K>, - ) $(-> <V as Visitor<$lt>>::Result)? { + ) -> V::Result { walk_item_ctxt(visitor, item, ()) } @@ -452,7 +454,7 @@ macro_rules! common_visitor_and_walkers { visitor: &mut V, item: &$($mut)? $($lt)? AssocItem, ctxt: AssocCtxt, - ) $(-> <V as Visitor<$lt>>::Result)? { + ) -> V::Result { walk_item_ctxt(visitor, item, ctxt) } @@ -465,7 +467,7 @@ macro_rules! common_visitor_and_walkers { visibility: &$($lt)? $($mut)? Visibility, _ctxt: Self::Ctxt, vis: &mut V, - ) $(-> <V as Visitor<$lt>>::Result)? { + ) -> V::Result { match self { ItemKind::ExternCrate(_orig_name, ident) => vis.visit_ident(ident), ItemKind::Use(use_tree) => vis.visit_use_tree(use_tree), @@ -505,7 +507,7 @@ macro_rules! common_visitor_and_walkers { } ModKind::Unloaded => {} } - $(<V as Visitor<$lt>>::Result::output())? + V::Result::output() } ItemKind::ForeignMod(nm) => vis.visit_foreign_mod(nm), ItemKind::GlobalAsm(asm) => vis.visit_inline_asm(asm), @@ -526,7 +528,7 @@ macro_rules! common_visitor_and_walkers { $(${ignore($mut)} walk_ty_alias_where_clauses(vis, where_clauses); )? - $(<V as Visitor<$lt>>::Result::output())? + V::Result::output() } ItemKind::Enum(ident, generics, enum_definition) => { try_visit!(vis.visit_ident(ident)); @@ -590,7 +592,7 @@ macro_rules! common_visitor_and_walkers { try_visit!(vis.visit_ident(ident)); visit_opt!(vis, visit_ident, rename); visit_opt!(vis, visit_block, body); - $(<V as Visitor<$lt>>::Result::output())? + V::Result::output() } ItemKind::DelegationMac(box DelegationMac { qself, prefix, suffixes, body }) => { try_visit!(vis.visit_qself(qself)); @@ -602,7 +604,7 @@ macro_rules! common_visitor_and_walkers { } } visit_opt!(vis, visit_block, body); - $(<V as Visitor<$lt>>::Result::output())? + V::Result::output() } } } @@ -611,7 +613,7 @@ macro_rules! common_visitor_and_walkers { fn walk_const_item<$($lt,)? V: $Visitor$(<$lt>)?>( vis: &mut V, item: &$($lt)? $($mut)? ConstItem, - ) $(-> <V as Visitor<$lt>>::Result)? { + ) -> V::Result { let ConstItem { defaultness, ident, generics, ty, expr, define_opaque } = item; try_visit!(visit_defaultness(vis, defaultness)); try_visit!(vis.visit_ident(ident)); @@ -621,7 +623,7 @@ macro_rules! common_visitor_and_walkers { walk_define_opaques(vis, define_opaque) } - fn walk_foreign_mod<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, foreign_mod: &$($lt)? $($mut)? ForeignMod) $(-> <V as Visitor<$lt>>::Result)? { + fn walk_foreign_mod<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, foreign_mod: &$($lt)? $($mut)? ForeignMod) -> V::Result { let ForeignMod { extern_span: _, safety, abi: _, items } = foreign_mod; try_visit!(visit_safety(vis, safety)); visit_foreign_items(vis, items) @@ -630,14 +632,14 @@ macro_rules! common_visitor_and_walkers { fn walk_define_opaques<$($lt,)? V: $Visitor$(<$lt>)?>( visitor: &mut V, define_opaque: &$($lt)? $($mut)? Option<ThinVec<(NodeId, Path)>>, - ) $(-> <V as Visitor<$lt>>::Result)? { + ) -> V::Result { if let Some(define_opaque) = define_opaque { for (id, path) in define_opaque { try_visit!(visit_id(visitor, id)); try_visit!(visitor.visit_path(path)); } } - $(<V as Visitor<$lt>>::Result::output())? + V::Result::output() } impl WalkItemKind for AssocItemKind { @@ -649,7 +651,7 @@ macro_rules! common_visitor_and_walkers { visibility: &$($lt)? $($mut)? Visibility, ctxt: Self::Ctxt, vis: &mut V, - ) $(-> <V as Visitor<$lt>>::Result)? { + ) -> V::Result { match self { AssocItemKind::Const(item) => { walk_const_item(vis, item) @@ -674,7 +676,7 @@ macro_rules! common_visitor_and_walkers { $(${ignore($mut)} walk_ty_alias_where_clauses(vis, where_clauses); )? - $(<V as Visitor<$lt>>::Result::output())? + V::Result::output() } AssocItemKind::MacCall(mac) => { vis.visit_mac_call(mac) @@ -694,7 +696,7 @@ macro_rules! common_visitor_and_walkers { try_visit!(vis.visit_ident(ident)); visit_opt!(vis, visit_ident, rename); visit_opt!(vis, visit_block, body); - $(<V as Visitor<$lt>>::Result::output())? + V::Result::output() } AssocItemKind::DelegationMac(box DelegationMac { qself, prefix, suffixes, body }) => { try_visit!(vis.visit_qself(qself)); @@ -706,7 +708,7 @@ macro_rules! common_visitor_and_walkers { } } visit_opt!(vis, visit_block, body); - $(<V as Visitor<$lt>>::Result::output())? + V::Result::output() } } } @@ -721,7 +723,7 @@ macro_rules! common_visitor_and_walkers { visibility: &$($lt)? $($mut)? Visibility, _ctxt: Self::Ctxt, vis: &mut V, - ) $(-> <V as Visitor<$lt>>::Result)? { + ) -> V::Result { match self { ForeignItemKind::Static(box StaticItem { ident, @@ -756,7 +758,7 @@ macro_rules! common_visitor_and_walkers { $(${ignore($mut)} walk_ty_alias_where_clauses(vis, where_clauses); )? - $(<V as Visitor<$lt>>::Result::output())? + V::Result::output() } ForeignItemKind::MacCall(mac) => { vis.visit_mac_call(mac) @@ -768,7 +770,7 @@ macro_rules! common_visitor_and_walkers { fn walk_coroutine_kind<$($lt,)? V: $Visitor$(<$lt>)?>( vis: &mut V, coroutine_kind: &$($lt)? $($mut)? CoroutineKind, - ) $(-> <V as Visitor<$lt>>::Result)? { + ) -> V::Result { let (CoroutineKind::Async { span, closure_id, return_impl_trait_id } | CoroutineKind::Gen { span, closure_id, return_impl_trait_id } | CoroutineKind::AsyncGen { span, closure_id, return_impl_trait_id }) @@ -781,7 +783,7 @@ macro_rules! common_visitor_and_walkers { pub fn walk_pat<$($lt,)? V: $Visitor$(<$lt>)?>( vis: &mut V, pattern: &$($lt)? $($mut)? Pat - ) $(-> <V as Visitor<$lt>>::Result)? { + ) -> V::Result { let Pat { id, kind, span, tokens: _ } = pattern; try_visit!(visit_id(vis, id)); match kind { @@ -832,7 +834,7 @@ macro_rules! common_visitor_and_walkers { pub fn walk_anon_const<$($lt,)? V: $Visitor$(<$lt>)?>( vis: &mut V, constant: &$($lt)? $($mut)? AnonConst, - ) $(-> <V as Visitor<$lt>>::Result)? { + ) -> V::Result { let AnonConst { id, value } = constant; try_visit!(visit_id(vis, id)); vis.visit_expr(value) @@ -841,18 +843,18 @@ macro_rules! common_visitor_and_walkers { pub fn walk_path_segment<$($lt,)? V: $Visitor$(<$lt>)?>( vis: &mut V, segment: &$($lt)? $($mut)? PathSegment, - ) $(-> <V as Visitor<$lt>>::Result)? { + ) -> V::Result { let PathSegment { ident, id, args } = segment; try_visit!(visit_id(vis, id)); try_visit!(vis.visit_ident(ident)); visit_opt!(vis, visit_generic_args, args); - $(<V as Visitor<$lt>>::Result::output())? + V::Result::output() } pub fn walk_block<$($lt,)? V: $Visitor$(<$lt>)?>( vis: &mut V, block: &$($lt)? $($mut)? Block - ) $(-> <V as Visitor<$lt>>::Result)? { + ) -> V::Result { let Block { stmts, id, rules: _, span, tokens: _ } = block; try_visit!(visit_id(vis, id)); try_visit!(visit_stmts(vis, stmts)); @@ -862,7 +864,7 @@ macro_rules! common_visitor_and_walkers { pub fn walk_ty<$($lt,)? V: $Visitor$(<$lt>)?>( vis: &mut V, ty: &$($lt)? $($mut)? Ty - ) $(-> <V as Visitor<$lt>>::Result)? { + ) -> V::Result { let Ty { id, kind, span, tokens: _ } = ty; try_visit!(visit_id(vis, id)); match kind { @@ -920,7 +922,7 @@ macro_rules! common_visitor_and_walkers { pub fn walk_crate<$($lt,)? V: $Visitor$(<$lt>)?>( vis: &mut V, krate: &$($lt)? $($mut)? Crate, - ) $(-> <V as Visitor<$lt>>::Result)? { + ) -> V::Result { let Crate { attrs, items, spans, id, is_placeholder: _ } = krate; try_visit!(visit_id(vis, id)); walk_list!(vis, visit_attribute, attrs); @@ -933,7 +935,7 @@ macro_rules! common_visitor_and_walkers { pub fn walk_local<$($lt,)? V: $Visitor$(<$lt>)?>( vis: &mut V, local: &$($lt)? $($mut)? Local, - ) $(-> <V as Visitor<$lt>>::Result)? { + ) -> V::Result { let Local { id, super_, pat, ty, kind, span, colon_sp, attrs, tokens: _ } = local; if let Some(sp) = super_ { try_visit!(visit_span(vis, sp)); @@ -961,7 +963,7 @@ macro_rules! common_visitor_and_walkers { pub fn walk_poly_trait_ref<$($lt,)? V: $Visitor$(<$lt>)?>( vis: &mut V, p: &$($lt)? $($mut)? PolyTraitRef, - ) $(-> <V as Visitor<$lt>>::Result)? { + ) -> V::Result { let PolyTraitRef { bound_generic_params, modifiers, trait_ref, span } = p; try_visit!(visit_modifiers(vis, modifiers)); try_visit!(visit_generic_params(vis, bound_generic_params)); @@ -972,7 +974,7 @@ macro_rules! common_visitor_and_walkers { pub fn walk_trait_ref<$($lt,)? V: $Visitor$(<$lt>)?>( vis: &mut V, TraitRef { path, ref_id }: &$($lt)? $($mut)? TraitRef, - ) $(-> <V as Visitor<$lt>>::Result)? { + ) -> V::Result { try_visit!(vis.visit_path(path)); visit_id(vis, ref_id) } @@ -980,7 +982,7 @@ macro_rules! common_visitor_and_walkers { pub fn walk_variant<$($lt,)? V: $Visitor$(<$lt>)?>( vis: &mut V, variant: &$($lt)? $($mut)? Variant, - ) $(-> <V as Visitor<$lt>>::Result)? { + ) -> V::Result { let Variant { attrs, id, span, vis: visibility, ident, data, disr_expr, is_placeholder: _ } = variant; try_visit!(visit_id(vis, id)); walk_list!(vis, visit_attribute, attrs); @@ -995,7 +997,7 @@ macro_rules! common_visitor_and_walkers { pub fn walk_expr_field<$($lt,)? V: $Visitor$(<$lt>)?>( vis: &mut V, f: &$($lt)? $($mut)? ExprField, - ) $(-> <V as Visitor<$lt>>::Result)? { + ) -> V::Result { let ExprField { attrs, id, span, ident, expr, is_shorthand: _, is_placeholder: _ } = f; try_visit!(visit_id(vis, id)); walk_list!(vis, visit_attribute, attrs); @@ -1007,7 +1009,7 @@ macro_rules! common_visitor_and_walkers { pub fn walk_pat_field<$($lt,)? V: $Visitor$(<$lt>)?>( vis: &mut V, fp: &$($lt)? $($mut)? PatField, - ) $(-> <V as Visitor<$lt>>::Result)? { + ) -> V::Result { let PatField { ident, pat, is_shorthand: _, attrs, id, span, is_placeholder: _ } = fp; try_visit!(visit_id(vis, id)); walk_list!(vis, visit_attribute, attrs); @@ -1019,7 +1021,7 @@ macro_rules! common_visitor_and_walkers { pub fn walk_ty_pat<$($lt,)? V: $Visitor$(<$lt>)?>( vis: &mut V, tp: &$($lt)? $($mut)? TyPat, - ) $(-> <V as Visitor<$lt>>::Result)? { + ) -> V::Result { let TyPat { id, kind, span, tokens: _ } = tp; try_visit!(visit_id(vis, id)); match kind { @@ -1036,19 +1038,19 @@ macro_rules! common_visitor_and_walkers { fn walk_qself<$($lt,)? V: $Visitor$(<$lt>)?>( vis: &mut V, qself: &$($lt)? $($mut)? Option<P<QSelf>>, - ) $(-> <V as Visitor<$lt>>::Result)? { + ) -> V::Result { if let Some(qself) = qself { let QSelf { ty, path_span, position: _ } = &$($mut)? **qself; try_visit!(vis.visit_ty(ty)); try_visit!(visit_span(vis, path_span)); } - $(<V as Visitor<$lt>>::Result::output())? + V::Result::output() } pub fn walk_path<$($lt,)? V: $Visitor$(<$lt>)?>( vis: &mut V, path: &$($lt)? $($mut)? Path, - ) $(-> <V as Visitor<$lt>>::Result)? { + ) -> V::Result { let Path { span, segments, tokens: _ } = path; walk_list!(vis, visit_path_segment, segments); visit_span(vis, span) @@ -1057,7 +1059,7 @@ macro_rules! common_visitor_and_walkers { pub fn walk_use_tree<$($lt,)? V: $Visitor$(<$lt>)?>( vis: &mut V, use_tree: &$($lt)? $($mut)? UseTree, - ) $(-> <V as Visitor<$lt>>::Result)? { + ) -> V::Result { let UseTree { prefix, kind, span } = use_tree; try_visit!(vis.visit_path(prefix)); match kind { @@ -1075,573 +1077,640 @@ macro_rules! common_visitor_and_walkers { } visit_span(vis, span) } - }; -} - -common_visitor_and_walkers!(Visitor<'a>); -macro_rules! generate_list_visit_fns { - ($($name:ident, $Ty:ty, $visit_fn:ident$(, $param:ident: $ParamTy:ty)*;)+) => { - $( - fn $name<'a, V: Visitor<'a>>( - vis: &mut V, - values: &'a ThinVec<$Ty>, - $( - $param: $ParamTy, - )* - ) -> V::Result { - walk_list!(vis, $visit_fn, values$(,$param)*); - V::Result::output() + pub fn walk_generic_args<$($lt,)? V: $Visitor$(<$lt>)?>( + vis: &mut V, + generic_args: &$($lt)? $($mut)? GenericArgs + ) -> V::Result { + match generic_args { + GenericArgs::AngleBracketed(AngleBracketedArgs { span, args }) => { + for arg in args { + match arg { + AngleBracketedArg::Arg(a) => try_visit!(vis.visit_generic_arg(a)), + AngleBracketedArg::Constraint(c) => { + try_visit!(vis.visit_assoc_item_constraint(c)) + } + } + } + visit_span(vis, span) + } + GenericArgs::Parenthesized(data) => { + let ParenthesizedArgs { span, inputs, inputs_span, output } = data; + walk_list!(vis, visit_ty, inputs); + try_visit!(vis.visit_fn_ret_ty(output)); + try_visit!(visit_span(vis, span)); + visit_span(vis, inputs_span) + } + GenericArgs::ParenthesizedElided(span) => visit_span(vis, span) } - )+ - } -} + } -generate_list_visit_fns! { - visit_items, P<Item>, visit_item; - visit_foreign_items, P<ForeignItem>, visit_foreign_item; - visit_generic_params, GenericParam, visit_generic_param; - visit_stmts, Stmt, visit_stmt; - visit_pat_fields, PatField, visit_pat_field; - visit_variants, Variant, visit_variant; - visit_assoc_items, P<AssocItem>, visit_assoc_item, ctxt: AssocCtxt; -} + pub fn walk_generic_arg<$($lt,)? V: $Visitor$(<$lt>)?>( + vis: &mut V, + generic_arg: &$($lt)? $($mut)? GenericArg, + ) -> V::Result { + match generic_arg { + GenericArg::Lifetime(lt) => vis.visit_lifetime(lt, $(${ignore($lt)} LifetimeCtxt::GenericArg)? ), + GenericArg::Type(ty) => vis.visit_ty(ty), + GenericArg::Const(ct) => vis.visit_anon_const(ct), + } + } -#[expect(rustc::pass_by_value)] // needed for symmetry with mut_visit -fn visit_nested_use_tree<'a, V: Visitor<'a>>( - vis: &mut V, - nested_tree: &'a UseTree, - &nested_id: &NodeId, -) -> V::Result { - vis.visit_nested_use_tree(nested_tree, nested_id) -} + pub fn walk_assoc_item_constraint<$($lt,)? V: $Visitor$(<$lt>)?>( + vis: &mut V, + constraint: &$($lt)? $($mut)? AssocItemConstraint, + ) -> V::Result { + let AssocItemConstraint { id, ident, gen_args, kind, span } = constraint; + try_visit!(visit_id(vis, id)); + try_visit!(vis.visit_ident(ident)); + visit_opt!(vis, visit_generic_args, gen_args); + match kind { + AssocItemConstraintKind::Equality { term } => match term { + Term::Ty(ty) => try_visit!(vis.visit_ty(ty)), + Term::Const(c) => try_visit!(vis.visit_anon_const(c)), + }, + AssocItemConstraintKind::Bound { bounds } => { + try_visit!(visit_bounds(vis, bounds, BoundKind::Bound)); + } + } + visit_span(vis, span) + } -pub fn walk_generic_args<'a, V>(visitor: &mut V, generic_args: &'a GenericArgs) -> V::Result -where - V: Visitor<'a>, -{ - match generic_args { - GenericArgs::AngleBracketed(AngleBracketedArgs { span: _, args }) => { - for arg in args { - match arg { - AngleBracketedArg::Arg(a) => try_visit!(visitor.visit_generic_arg(a)), - AngleBracketedArg::Constraint(c) => { - try_visit!(visitor.visit_assoc_item_constraint(c)) - } + pub fn walk_param_bound<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, bound: &$($lt)? $($mut)? GenericBound) -> V::Result { + match bound { + GenericBound::Trait(trait_ref) => vis.visit_poly_trait_ref(trait_ref), + GenericBound::Outlives(lifetime) => vis.visit_lifetime(lifetime, $(${ignore($lt)} LifetimeCtxt::Bound)?), + GenericBound::Use(args, span) => { + walk_list!(vis, visit_precise_capturing_arg, args); + visit_span(vis, span) } } } - GenericArgs::Parenthesized(data) => { - let ParenthesizedArgs { span: _, inputs, inputs_span: _, output } = data; - walk_list!(visitor, visit_ty, inputs); - try_visit!(visitor.visit_fn_ret_ty(output)); + + pub fn walk_precise_capturing_arg<$($lt,)? V: $Visitor$(<$lt>)?>( + vis: &mut V, + arg: &$($lt)? $($mut)? PreciseCapturingArg, + ) -> V::Result { + match arg { + PreciseCapturingArg::Lifetime(lt) => vis.visit_lifetime(lt, $(${ignore($lt)} LifetimeCtxt::GenericArg)?), + PreciseCapturingArg::Arg(path, id) => { + try_visit!(visit_id(vis, id)); + vis.visit_path(path) + } + } } - GenericArgs::ParenthesizedElided(_span) => {} - } - V::Result::output() -} -pub fn walk_generic_arg<'a, V>(visitor: &mut V, generic_arg: &'a GenericArg) -> V::Result -where - V: Visitor<'a>, -{ - match generic_arg { - GenericArg::Lifetime(lt) => visitor.visit_lifetime(lt, LifetimeCtxt::GenericArg), - GenericArg::Type(ty) => visitor.visit_ty(ty), - GenericArg::Const(ct) => visitor.visit_anon_const(ct), - } -} + pub fn walk_generic_param<$($lt,)? V: $Visitor$(<$lt>)?>( + vis: &mut V, + param: &$($lt)? $($mut)? GenericParam, + ) -> V::Result { + let GenericParam { id, ident, attrs, bounds, is_placeholder: _, kind, colon_span } = + param; + try_visit!(visit_id(vis, id)); + walk_list!(vis, visit_attribute, attrs); + try_visit!(vis.visit_ident(ident)); + walk_list!(vis, visit_param_bound, bounds, BoundKind::Bound); + match kind { + GenericParamKind::Lifetime => (), + GenericParamKind::Type { default } => visit_opt!(vis, visit_ty, default), + GenericParamKind::Const { ty, default, kw_span: _ } => { + try_visit!(vis.visit_ty(ty)); + visit_opt!(vis, visit_anon_const, default); + } + } + if let Some(sp) = colon_span { + try_visit!(visit_span(vis, sp)) + } + V::Result::output() + } -pub fn walk_assoc_item_constraint<'a, V: Visitor<'a>>( - visitor: &mut V, - constraint: &'a AssocItemConstraint, -) -> V::Result { - let AssocItemConstraint { id: _, ident, gen_args, kind, span: _ } = constraint; - try_visit!(visitor.visit_ident(ident)); - visit_opt!(visitor, visit_generic_args, gen_args); - match kind { - AssocItemConstraintKind::Equality { term } => match term { - Term::Ty(ty) => try_visit!(visitor.visit_ty(ty)), - Term::Const(c) => try_visit!(visitor.visit_anon_const(c)), - }, - AssocItemConstraintKind::Bound { bounds } => { - walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound); + pub fn walk_generics<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, generics: &$($lt)? $($mut)? Generics) -> V::Result { + let Generics { params, where_clause, span } = generics; + let WhereClause { has_where_token: _, predicates, span: where_clause_span } = where_clause; + try_visit!(visit_generic_params(vis, params)); + try_visit!(visit_where_predicates(vis, predicates)); + try_visit!(visit_span(vis, span)); + visit_span(vis, where_clause_span) } - } - V::Result::output() -} -pub fn walk_param_bound<'a, V: Visitor<'a>>(visitor: &mut V, bound: &'a GenericBound) -> V::Result { - match bound { - GenericBound::Trait(trait_ref) => visitor.visit_poly_trait_ref(trait_ref), - GenericBound::Outlives(lifetime) => visitor.visit_lifetime(lifetime, LifetimeCtxt::Bound), - GenericBound::Use(args, _span) => { - walk_list!(visitor, visit_precise_capturing_arg, args); + pub fn walk_contract<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, c: &$($lt)? $($mut)? FnContract) -> V::Result { + let FnContract { requires, ensures } = c; + visit_opt!(vis, visit_expr, requires); + visit_opt!(vis, visit_expr, ensures); V::Result::output() } - } -} -pub fn walk_precise_capturing_arg<'a, V: Visitor<'a>>( - visitor: &mut V, - arg: &'a PreciseCapturingArg, -) -> V::Result { - match arg { - PreciseCapturingArg::Lifetime(lt) => visitor.visit_lifetime(lt, LifetimeCtxt::GenericArg), - PreciseCapturingArg::Arg(path, id) => { - try_visit!(visitor.visit_id(*id)); - visitor.visit_path(path) + pub fn walk_where_predicate<$($lt,)? V: $Visitor$(<$lt>)?>( + vis: &mut V, + predicate: &$($lt)? $($mut)? WherePredicate, + ) -> V::Result { + let WherePredicate { attrs, kind, id, span, is_placeholder: _ } = predicate; + try_visit!(visit_id(vis, id)); + walk_list!(vis, visit_attribute, attrs); + try_visit!(visit_span(vis, span)); + vis.visit_where_predicate_kind(kind) } - } -} -pub fn walk_generic_param<'a, V: Visitor<'a>>( - visitor: &mut V, - param: &'a GenericParam, -) -> V::Result { - let GenericParam { id: _, ident, attrs, bounds, is_placeholder: _, kind, colon_span: _ } = - param; - walk_list!(visitor, visit_attribute, attrs); - try_visit!(visitor.visit_ident(ident)); - walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound); - match kind { - GenericParamKind::Lifetime => (), - GenericParamKind::Type { default } => visit_opt!(visitor, visit_ty, default), - GenericParamKind::Const { ty, default, kw_span: _ } => { - try_visit!(visitor.visit_ty(ty)); - visit_opt!(visitor, visit_anon_const, default); + pub fn walk_closure_binder<$($lt,)? V: $Visitor$(<$lt>)?>( + vis: &mut V, + binder: &$($lt)? $($mut)? ClosureBinder, + ) -> V::Result { + match binder { + ClosureBinder::NotPresent => {} + ClosureBinder::For { generic_params, span } => { + try_visit!(visit_generic_params(vis, generic_params)); + try_visit!(visit_span(vis, span)); + } + } + V::Result::output() } - } - V::Result::output() -} - -pub fn walk_generics<'a, V: Visitor<'a>>(visitor: &mut V, generics: &'a Generics) -> V::Result { - let Generics { params, where_clause, span: _ } = generics; - let WhereClause { has_where_token: _, predicates, span: _ } = where_clause; - walk_list!(visitor, visit_generic_param, params); - walk_list!(visitor, visit_where_predicate, predicates); - V::Result::output() -} -pub fn walk_closure_binder<'a, V: Visitor<'a>>( - visitor: &mut V, - binder: &'a ClosureBinder, -) -> V::Result { - match binder { - ClosureBinder::NotPresent => {} - ClosureBinder::For { generic_params, span: _ } => { - walk_list!(visitor, visit_generic_param, generic_params) + pub fn walk_where_predicate_kind<$($lt,)? V: $Visitor$(<$lt>)?>( + vis: &mut V, + kind: &$($lt)? $($mut)? WherePredicateKind, + ) -> V::Result { + match kind { + WherePredicateKind::BoundPredicate(WhereBoundPredicate { + bounded_ty, + bounds, + bound_generic_params, + }) => { + visit_generic_params(vis, bound_generic_params); + try_visit!(vis.visit_ty(bounded_ty)); + walk_list!(vis, visit_param_bound, bounds, BoundKind::Bound); + } + WherePredicateKind::RegionPredicate(WhereRegionPredicate { lifetime, bounds }) => { + try_visit!(vis.visit_lifetime(lifetime, $(${ignore($lt)} LifetimeCtxt::Bound )?)); + walk_list!(vis, visit_param_bound, bounds, BoundKind::Bound); + } + WherePredicateKind::EqPredicate(WhereEqPredicate { lhs_ty, rhs_ty }) => { + try_visit!(vis.visit_ty(lhs_ty)); + try_visit!(vis.visit_ty(rhs_ty)); + } + } + V::Result::output() } - } - V::Result::output() -} -pub fn walk_contract<'a, V: Visitor<'a>>(visitor: &mut V, c: &'a FnContract) -> V::Result { - let FnContract { requires, ensures } = c; - if let Some(pred) = requires { - visitor.visit_expr(pred); - } - if let Some(pred) = ensures { - visitor.visit_expr(pred); - } - V::Result::output() -} + pub fn walk_fn_decl<$($lt,)? V: $Visitor$(<$lt>)?>( + vis: &mut V, + FnDecl { inputs, output }: &$($lt)? $($mut)? FnDecl, + ) -> V::Result { + try_visit!(visit_params(vis, inputs)); + vis.visit_fn_ret_ty(output) + } -pub fn walk_where_predicate<'a, V: Visitor<'a>>( - visitor: &mut V, - predicate: &'a WherePredicate, -) -> V::Result { - let WherePredicate { attrs, kind, id: _, span: _, is_placeholder: _ } = predicate; - walk_list!(visitor, visit_attribute, attrs); - visitor.visit_where_predicate_kind(kind) -} + pub fn walk_fn_ret_ty<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, ret_ty: &$($lt)? $($mut)? FnRetTy) -> V::Result { + match ret_ty { + FnRetTy::Default(span) => visit_span(vis, span), + FnRetTy::Ty(output_ty) => vis.visit_ty(output_ty), + } + } -pub fn walk_where_predicate_kind<'a, V: Visitor<'a>>( - visitor: &mut V, - kind: &'a WherePredicateKind, -) -> V::Result { - match kind { - WherePredicateKind::BoundPredicate(WhereBoundPredicate { - bounded_ty, - bounds, - bound_generic_params, - }) => { - walk_list!(visitor, visit_generic_param, bound_generic_params); - try_visit!(visitor.visit_ty(bounded_ty)); - walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound); + pub fn walk_fn<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, kind: FnKind<$($lt)? $(${ignore($mut)} '_)?>) -> V::Result { + match kind { + FnKind::Fn( + _ctxt, + _vis, + Fn { + defaultness, + ident, + sig: FnSig { header, decl, span }, + generics, + contract, + body, + define_opaque, + }, + ) => { + // Visibility is visited as a part of the item. + try_visit!(visit_defaultness(vis, defaultness)); + try_visit!(vis.visit_ident(ident)); + try_visit!(vis.visit_fn_header(header)); + try_visit!(vis.visit_generics(generics)); + try_visit!(vis.visit_fn_decl(decl)); + visit_opt!(vis, visit_contract, contract); + visit_opt!(vis, visit_block, body); + try_visit!(visit_span(vis, span)); + walk_define_opaques(vis, define_opaque) + } + FnKind::Closure(binder, coroutine_kind, decl, body) => { + try_visit!(vis.visit_closure_binder(binder)); + visit_opt!(vis, visit_coroutine_kind, coroutine_kind); + try_visit!(vis.visit_fn_decl(decl)); + vis.visit_expr(body) + } + } } - WherePredicateKind::RegionPredicate(WhereRegionPredicate { lifetime, bounds }) => { - try_visit!(visitor.visit_lifetime(lifetime, LifetimeCtxt::Bound)); - walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound); + + pub fn walk_variant_data<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, data: &$($lt)? $($mut)? VariantData) -> V::Result { + match data { + VariantData::Struct { fields, recovered: _ } => { + visit_field_defs(vis, fields) + } + VariantData::Tuple(fields, id) => { + try_visit!(visit_id(vis, id)); + visit_field_defs(vis, fields) + } + VariantData::Unit(id) => visit_id(vis, id), + } } - WherePredicateKind::EqPredicate(WhereEqPredicate { lhs_ty, rhs_ty }) => { - try_visit!(visitor.visit_ty(lhs_ty)); - try_visit!(visitor.visit_ty(rhs_ty)); + + pub fn walk_field_def<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, field: &$($lt)? $($mut)? FieldDef) -> V::Result { + let FieldDef { attrs, id, span, vis: visibility, ident, ty, is_placeholder: _, safety: _, default } = + field; + try_visit!(visit_id(vis, id)); + walk_list!(vis, visit_attribute, attrs); + try_visit!(vis.visit_vis(visibility)); + visit_opt!(vis, visit_ident, ident); + try_visit!(vis.visit_ty(ty)); + visit_opt!(vis, visit_anon_const, default); + visit_span(vis, span) } - } - V::Result::output() -} -pub fn walk_fn_ret_ty<'a, V: Visitor<'a>>(visitor: &mut V, ret_ty: &'a FnRetTy) -> V::Result { - match ret_ty { - FnRetTy::Default(_span) => {} - FnRetTy::Ty(output_ty) => try_visit!(visitor.visit_ty(output_ty)), - } - V::Result::output() -} + fn visit_delim_args<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, args: &$($lt)? $($mut)? DelimArgs) -> V::Result { + let DelimArgs { dspan, delim: _, tokens: _ } = args; + let DelimSpan { open, close } = dspan; + try_visit!(visit_span(vis, open)); + visit_span(vis, close) + } -pub fn walk_fn_decl<'a, V: Visitor<'a>>( - visitor: &mut V, - FnDecl { inputs, output }: &'a FnDecl, -) -> V::Result { - walk_list!(visitor, visit_param, inputs); - visitor.visit_fn_ret_ty(output) -} + pub fn walk_mac<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, mac: &$($lt)? $($mut)? MacCall) -> V::Result { + let MacCall { path, args } = mac; + try_visit!(vis.visit_path(path)); + visit_delim_args(vis, args) + } + + fn walk_macro_def<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, macro_def: &$($lt)? $($mut)? MacroDef) -> V::Result { + let MacroDef { body, macro_rules: _ } = macro_def; + visit_delim_args(vis, body) + } + + pub fn walk_inline_asm<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, asm: &$($lt)? $($mut)? InlineAsm) -> V::Result { + // FIXME: Visit spans inside all this currently ignored stuff. + let InlineAsm { + asm_macro: _, + template: _, + template_strs: _, + operands, + clobber_abis: _, + options: _, + line_spans: _, + } = asm; + for (op, span) in operands { + match op { + InlineAsmOperand::In { expr, reg: _ } + | InlineAsmOperand::Out { expr: Some(expr), reg: _, late: _ } + | InlineAsmOperand::InOut { expr, reg: _, late: _ } => { + try_visit!(vis.visit_expr(expr)) + } + InlineAsmOperand::Out { expr: None, reg: _, late: _ } => {} + InlineAsmOperand::SplitInOut { in_expr, out_expr, reg: _, late: _ } => { + try_visit!(vis.visit_expr(in_expr)); + visit_opt!(vis, visit_expr, out_expr); + } + InlineAsmOperand::Const { anon_const } => { + try_visit!(vis.visit_anon_const(anon_const)) + } + InlineAsmOperand::Sym { sym } => try_visit!(vis.visit_inline_asm_sym(sym)), + InlineAsmOperand::Label { block } => try_visit!(vis.visit_block(block)), + } + try_visit!(visit_span(vis, span)); + } + V::Result::output() + } -pub fn walk_fn<'a, V: Visitor<'a>>(visitor: &mut V, kind: FnKind<'a>) -> V::Result { - match kind { - FnKind::Fn( - _ctxt, - _vis, - Fn { - defaultness: _, - ident, - sig: FnSig { header, decl, span: _ }, - generics, - contract, - body, - define_opaque, - }, - ) => { - // Visibility is visited as a part of the item. - try_visit!(visitor.visit_ident(ident)); - try_visit!(visitor.visit_fn_header(header)); - try_visit!(visitor.visit_generics(generics)); - try_visit!(visitor.visit_fn_decl(decl)); - visit_opt!(visitor, visit_contract, contract); - visit_opt!(visitor, visit_block, body); - try_visit!(walk_define_opaques(visitor, define_opaque)); - } - FnKind::Closure(binder, coroutine_kind, decl, body) => { - try_visit!(visitor.visit_closure_binder(binder)); - visit_opt!(visitor, visit_coroutine_kind, coroutine_kind.as_ref()); - try_visit!(visitor.visit_fn_decl(decl)); - try_visit!(visitor.visit_expr(body)); + pub fn walk_inline_asm_sym<$($lt,)? V: $Visitor$(<$lt>)?>( + vis: &mut V, + InlineAsmSym { id, qself, path }: &$($lt)? $($mut)? InlineAsmSym, + ) -> V::Result { + try_visit!(visit_id(vis, id)); + try_visit!(vis.visit_qself(qself)); + vis.visit_path(path) + } + + // FIXME: visit the template exhaustively. + pub fn walk_format_args<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, fmt: &$($lt)? $($mut)? FormatArgs) -> V::Result { + let FormatArgs { span, template: _, arguments, uncooked_fmt_str: _ } = fmt; + let args = $(${ignore($mut)} arguments.all_args_mut())? $(${ignore($lt)} arguments.all_args())? ; + for FormatArgument { kind, expr } in args { + match kind { + FormatArgumentKind::Named(ident) | FormatArgumentKind::Captured(ident) => { + try_visit!(vis.visit_ident(ident)) + } + FormatArgumentKind::Normal => {} + } + try_visit!(vis.visit_expr(expr)); + } + visit_span(vis, span) } - } - V::Result::output() -} -pub fn walk_variant_data<'a, V: Visitor<'a>>(visitor: &mut V, data: &'a VariantData) -> V::Result { - visit_opt!(visitor, visit_id, data.ctor_node_id()); - walk_list!(visitor, visit_field_def, data.fields()); - V::Result::output() -} + pub fn walk_expr<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, expression: &$($lt)? $($mut)? Expr) -> V::Result { + let Expr { id, kind, span, attrs, tokens: _ } = expression; + try_visit!(visit_id(vis, id)); + walk_list!(vis, visit_attribute, attrs); + match kind { + ExprKind::Array(exprs) => { + try_visit!(visit_exprs(vis, exprs)); + } + ExprKind::ConstBlock(anon_const) => try_visit!(vis.visit_anon_const(anon_const)), + ExprKind::Repeat(element, count) => { + try_visit!(vis.visit_expr(element)); + try_visit!(vis.visit_anon_const(count)); + } + ExprKind::Struct(se) => { + let StructExpr { qself, path, fields, rest } = &$($mut)?**se; + try_visit!(vis.visit_qself(qself)); + try_visit!(vis.visit_path(path)); + visit_expr_fields(vis, fields); + match rest { + StructRest::Base(expr) => try_visit!(vis.visit_expr(expr)), + StructRest::Rest(_span) => {} + StructRest::None => {} + } + } + ExprKind::Tup(exprs) => { + try_visit!(visit_exprs(vis, exprs)); + } + ExprKind::Call(callee_expression, arguments) => { + try_visit!(vis.visit_expr(callee_expression)); + try_visit!(visit_exprs(vis, arguments)); + } + ExprKind::MethodCall(box MethodCall { seg, receiver, args, span }) => { + try_visit!(vis.visit_method_receiver_expr(receiver)); + try_visit!(vis.visit_path_segment(seg)); + try_visit!(visit_exprs(vis, args)); + try_visit!(visit_span(vis, span)); + } + ExprKind::Binary(Spanned { span, node: _ }, left_expression, right_expression) => { + try_visit!(vis.visit_expr(left_expression)); + try_visit!(vis.visit_expr(right_expression)); + try_visit!(visit_span(vis, span)) + } + ExprKind::AddrOf(_kind, _mutbl, subexpression) => { + try_visit!(vis.visit_expr(subexpression)); + } + ExprKind::Unary(_op, subexpression) => { + try_visit!(vis.visit_expr(subexpression)); + } + ExprKind::Cast(subexpression, typ) | ExprKind::Type(subexpression, typ) => { + try_visit!(vis.visit_expr(subexpression)); + try_visit!(vis.visit_ty(typ)); + } + ExprKind::Let(pat, expr, span, _recovered) => { + try_visit!(vis.visit_pat(pat)); + try_visit!(vis.visit_expr(expr)); + try_visit!(visit_span(vis, span)) + } + ExprKind::If(head_expression, if_block, optional_else) => { + try_visit!(vis.visit_expr(head_expression)); + try_visit!(vis.visit_block(if_block)); + visit_opt!(vis, visit_expr, optional_else); + } + ExprKind::While(subexpression, block, opt_label) => { + visit_opt!(vis, visit_label, opt_label); + try_visit!(vis.visit_expr(subexpression)); + try_visit!(vis.visit_block(block)); + } + ExprKind::ForLoop { pat, iter, body, label, kind: _ } => { + visit_opt!(vis, visit_label, label); + try_visit!(vis.visit_pat(pat)); + try_visit!(vis.visit_expr(iter)); + try_visit!(vis.visit_block(body)); + } + ExprKind::Loop(block, opt_label, span) => { + visit_opt!(vis, visit_label, opt_label); + try_visit!(vis.visit_block(block)); + try_visit!(visit_span(vis, span)) + } + ExprKind::Match(subexpression, arms, _kind) => { + try_visit!(vis.visit_expr(subexpression)); + try_visit!(visit_arms(vis, arms)); + } + ExprKind::Closure(box Closure { + binder, + capture_clause, + coroutine_kind, + constness, + movability: _, + fn_decl, + body, + fn_decl_span, + fn_arg_span, + }) => { + try_visit!(visit_constness(vis, constness)); + try_visit!(vis.visit_capture_by(capture_clause)); + try_visit!(vis.visit_fn( + FnKind::Closure(binder, coroutine_kind, fn_decl, body), + *span, + *id + )); + try_visit!(visit_span(vis, fn_decl_span)); + try_visit!(visit_span(vis, fn_arg_span)); + } + ExprKind::Block(block, opt_label) => { + visit_opt!(vis, visit_label, opt_label); + try_visit!(vis.visit_block(block)); + } + ExprKind::Gen(_capt, body, _kind, decl_span) => { + try_visit!(vis.visit_block(body)); + try_visit!(visit_span(vis, decl_span)); + } + ExprKind::Await(expr, span) => { + try_visit!(vis.visit_expr(expr)); + try_visit!(visit_span(vis, span)); + } + ExprKind::Use(expr, span) => { + try_visit!(vis.visit_expr(expr)); + try_visit!(visit_span(vis, span)); + } + ExprKind::Assign(lhs, rhs, span) => { + try_visit!(vis.visit_expr(lhs)); + try_visit!(vis.visit_expr(rhs)); + try_visit!(visit_span(vis, span)); + } + ExprKind::AssignOp(_op, left_expression, right_expression) => { + try_visit!(vis.visit_expr(left_expression)); + try_visit!(vis.visit_expr(right_expression)); + } + ExprKind::Field(subexpression, ident) => { + try_visit!(vis.visit_expr(subexpression)); + try_visit!(vis.visit_ident(ident)); + } + ExprKind::Index(main_expression, index_expression, span) => { + try_visit!(vis.visit_expr(main_expression)); + try_visit!(vis.visit_expr(index_expression)); + try_visit!(visit_span(vis, span)); + } + ExprKind::Range(start, end, _limit) => { + visit_opt!(vis, visit_expr, start); + visit_opt!(vis, visit_expr, end); + } + ExprKind::Underscore => {} + ExprKind::Path(maybe_qself, path) => { + try_visit!(vis.visit_qself(maybe_qself)); + try_visit!(vis.visit_path(path)); + } + ExprKind::Break(opt_label, opt_expr) => { + visit_opt!(vis, visit_label, opt_label); + visit_opt!(vis, visit_expr, opt_expr); + } + ExprKind::Continue(opt_label) => { + visit_opt!(vis, visit_label, opt_label); + } + ExprKind::Ret(optional_expression) => { + visit_opt!(vis, visit_expr, optional_expression); + } + ExprKind::Yeet(optional_expression) => { + visit_opt!(vis, visit_expr, optional_expression); + } + ExprKind::Become(expr) => try_visit!(vis.visit_expr(expr)), + ExprKind::MacCall(mac) => try_visit!(vis.visit_mac_call(mac)), + ExprKind::Paren(subexpression) => try_visit!(vis.visit_expr(subexpression)), + ExprKind::InlineAsm(asm) => try_visit!(vis.visit_inline_asm(asm)), + ExprKind::FormatArgs(f) => try_visit!(vis.visit_format_args(f)), + ExprKind::OffsetOf(container, fields) => { + try_visit!(vis.visit_ty(container)); + walk_list!(vis, visit_ident, fields); + } + ExprKind::Yield(kind) => { + match kind { + YieldKind::Postfix(expr) => { + try_visit!(vis.visit_expr(expr)); + } + YieldKind::Prefix(expr) => { + visit_opt!(vis, visit_expr, expr); + } + } + } + ExprKind::Try(subexpression) => try_visit!(vis.visit_expr(subexpression)), + ExprKind::TryBlock(body) => try_visit!(vis.visit_block(body)), + ExprKind::Lit(_token) => {} + ExprKind::IncludedBytes(_bytes) => {} + ExprKind::UnsafeBinderCast(_kind, expr, ty) => { + try_visit!(vis.visit_expr(expr)); + visit_opt!(vis, visit_ty, ty); + } + ExprKind::Err(_guar) => {} + ExprKind::Dummy => {} + } -pub fn walk_field_def<'a, V: Visitor<'a>>(visitor: &mut V, field: &'a FieldDef) -> V::Result { - let FieldDef { attrs, id: _, span: _, vis, ident, ty, is_placeholder: _, safety: _, default } = - field; - walk_list!(visitor, visit_attribute, attrs); - try_visit!(visitor.visit_vis(vis)); - visit_opt!(visitor, visit_ident, ident); - try_visit!(visitor.visit_ty(ty)); - visit_opt!(visitor, visit_anon_const, &*default); - V::Result::output() -} + visit_span(vis, span) + } -pub fn walk_stmt<'a, V: Visitor<'a>>(visitor: &mut V, statement: &'a Stmt) -> V::Result { - let Stmt { id: _, kind, span: _ } = statement; - match kind { - StmtKind::Let(local) => try_visit!(visitor.visit_local(local)), - StmtKind::Item(item) => try_visit!(visitor.visit_item(item)), - StmtKind::Expr(expr) | StmtKind::Semi(expr) => try_visit!(visitor.visit_expr(expr)), - StmtKind::Empty => {} - StmtKind::MacCall(mac) => { - let MacCallStmt { mac, attrs, style: _, tokens: _ } = &**mac; - walk_list!(visitor, visit_attribute, attrs); - try_visit!(visitor.visit_mac_call(mac)); + pub fn walk_param<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, param: &$($lt)? $($mut)? Param) -> V::Result { + let Param { attrs, ty, pat, id, span, is_placeholder: _ } = param; + try_visit!(visit_id(vis, id)); + walk_list!(vis, visit_attribute, attrs); + try_visit!(vis.visit_pat(pat)); + try_visit!(vis.visit_ty(ty)); + visit_span(vis, span) } - } - V::Result::output() -} -pub fn walk_mac<'a, V: Visitor<'a>>(visitor: &mut V, mac: &'a MacCall) -> V::Result { - let MacCall { path, args: _ } = mac; - visitor.visit_path(path) -} + pub fn walk_arm<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, arm: &$($lt)? $($mut)? Arm) -> V::Result { + let Arm { attrs, pat, guard, body, span, id, is_placeholder: _ } = arm; + try_visit!(visit_id(vis, id)); + walk_list!(vis, visit_attribute, attrs); + try_visit!(vis.visit_pat(pat)); + visit_opt!(vis, visit_expr, guard); + visit_opt!(vis, visit_expr, body); + visit_span(vis, span) + } -pub fn walk_inline_asm<'a, V: Visitor<'a>>(visitor: &mut V, asm: &'a InlineAsm) -> V::Result { - let InlineAsm { - asm_macro: _, - template: _, - template_strs: _, - operands, - clobber_abis: _, - options: _, - line_spans: _, - } = asm; - for (op, _span) in operands { - match op { - InlineAsmOperand::In { expr, reg: _ } - | InlineAsmOperand::Out { expr: Some(expr), reg: _, late: _ } - | InlineAsmOperand::InOut { expr, reg: _, late: _ } => { - try_visit!(visitor.visit_expr(expr)) - } - InlineAsmOperand::Out { expr: None, reg: _, late: _ } => {} - InlineAsmOperand::SplitInOut { in_expr, out_expr, reg: _, late: _ } => { - try_visit!(visitor.visit_expr(in_expr)); - visit_opt!(visitor, visit_expr, out_expr); - } - InlineAsmOperand::Const { anon_const } => { - try_visit!(visitor.visit_anon_const(anon_const)) + pub fn walk_vis<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, visibility: &$($lt)? $($mut)? Visibility) -> V::Result { + let Visibility { kind, span, tokens: _ } = visibility; + match kind { + VisibilityKind::Restricted { path, id, shorthand: _ } => { + try_visit!(visit_id(vis, id)); + try_visit!(vis.visit_path(path)); + } + VisibilityKind::Public | VisibilityKind::Inherited => {} } - InlineAsmOperand::Sym { sym } => try_visit!(visitor.visit_inline_asm_sym(sym)), - InlineAsmOperand::Label { block } => try_visit!(visitor.visit_block(block)), + visit_span(vis, span) } - } - V::Result::output() -} -pub fn walk_inline_asm_sym<'a, V: Visitor<'a>>( - visitor: &mut V, - InlineAsmSym { id, qself, path }: &'a InlineAsmSym, -) -> V::Result { - try_visit!(visitor.visit_qself(qself)); - try_visit!(visitor.visit_id(*id)); - visitor.visit_path(path) -} - -pub fn walk_format_args<'a, V: Visitor<'a>>(visitor: &mut V, fmt: &'a FormatArgs) -> V::Result { - let FormatArgs { span: _, template: _, arguments, uncooked_fmt_str: _ } = fmt; - for FormatArgument { kind, expr } in arguments.all_args() { - match kind { - FormatArgumentKind::Named(ident) | FormatArgumentKind::Captured(ident) => { - try_visit!(visitor.visit_ident(ident)) + pub fn walk_attribute<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, attr: &$($lt)? $($mut)? Attribute) -> V::Result { + let Attribute { kind, id: _, style: _, span } = attr; + match kind { + AttrKind::Normal(normal) => { + let NormalAttr { item, tokens: _ } = &$($mut)?**normal; + let AttrItem { unsafety: _, path, args, tokens: _ } = item; + try_visit!(vis.visit_path(path)); + try_visit!(walk_attr_args(vis, args)); + } + AttrKind::DocComment(_kind, _sym) => {} } - FormatArgumentKind::Normal => {} + visit_span(vis, span) } - try_visit!(visitor.visit_expr(expr)); - } - V::Result::output() -} -pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) -> V::Result { - let Expr { id, kind, span, attrs, tokens: _ } = expression; - walk_list!(visitor, visit_attribute, attrs); - match kind { - ExprKind::Array(subexpressions) => { - walk_list!(visitor, visit_expr, subexpressions); - } - ExprKind::ConstBlock(anon_const) => try_visit!(visitor.visit_anon_const(anon_const)), - ExprKind::Repeat(element, count) => { - try_visit!(visitor.visit_expr(element)); - try_visit!(visitor.visit_anon_const(count)); - } - ExprKind::Struct(se) => { - let StructExpr { qself, path, fields, rest } = &**se; - try_visit!(visitor.visit_qself(qself)); - try_visit!(visitor.visit_id(*id)); - try_visit!(visitor.visit_path(path)); - walk_list!(visitor, visit_expr_field, fields); - match rest { - StructRest::Base(expr) => try_visit!(visitor.visit_expr(expr)), - StructRest::Rest(_span) => {} - StructRest::None => {} + pub fn walk_attr_args<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, args: &$($lt)? $($mut)? AttrArgs) -> V::Result { + match args { + AttrArgs::Empty => {} + AttrArgs::Delimited(args) => try_visit!(visit_delim_args(vis, args)), + AttrArgs::Eq { eq_span, expr } => { + try_visit!(vis.visit_expr(expr)); + try_visit!(visit_span(vis, eq_span)); + } } + V::Result::output() } - ExprKind::Tup(subexpressions) => { - walk_list!(visitor, visit_expr, subexpressions); - } - ExprKind::Call(callee_expression, arguments) => { - try_visit!(visitor.visit_expr(callee_expression)); - walk_list!(visitor, visit_expr, arguments); - } - ExprKind::MethodCall(box MethodCall { seg, receiver, args, span: _ }) => { - try_visit!(visitor.visit_expr(receiver)); - try_visit!(visitor.visit_path_segment(seg)); - walk_list!(visitor, visit_expr, args); - } - ExprKind::Binary(_op, left_expression, right_expression) => { - try_visit!(visitor.visit_expr(left_expression)); - try_visit!(visitor.visit_expr(right_expression)); - } - ExprKind::AddrOf(_kind, _mutbl, subexpression) => { - try_visit!(visitor.visit_expr(subexpression)); - } - ExprKind::Unary(_op, subexpression) => { - try_visit!(visitor.visit_expr(subexpression)); - } - ExprKind::Cast(subexpression, typ) | ExprKind::Type(subexpression, typ) => { - try_visit!(visitor.visit_expr(subexpression)); - try_visit!(visitor.visit_ty(typ)); - } - ExprKind::Let(pat, expr, _span, _recovered) => { - try_visit!(visitor.visit_pat(pat)); - try_visit!(visitor.visit_expr(expr)); - } - ExprKind::If(head_expression, if_block, optional_else) => { - try_visit!(visitor.visit_expr(head_expression)); - try_visit!(visitor.visit_block(if_block)); - visit_opt!(visitor, visit_expr, optional_else); - } - ExprKind::While(subexpression, block, opt_label) => { - visit_opt!(visitor, visit_label, opt_label); - try_visit!(visitor.visit_expr(subexpression)); - try_visit!(visitor.visit_block(block)); - } - ExprKind::ForLoop { pat, iter, body, label, kind: _ } => { - visit_opt!(visitor, visit_label, label); - try_visit!(visitor.visit_pat(pat)); - try_visit!(visitor.visit_expr(iter)); - try_visit!(visitor.visit_block(body)); - } - ExprKind::Loop(block, opt_label, _span) => { - visit_opt!(visitor, visit_label, opt_label); - try_visit!(visitor.visit_block(block)); - } - ExprKind::Match(subexpression, arms, _kind) => { - try_visit!(visitor.visit_expr(subexpression)); - walk_list!(visitor, visit_arm, arms); - } - ExprKind::Closure(box Closure { - binder, - capture_clause, - coroutine_kind, - constness: _, - movability: _, - fn_decl, - body, - fn_decl_span: _, - fn_arg_span: _, - }) => { - try_visit!(visitor.visit_capture_by(capture_clause)); - try_visit!(visitor.visit_fn( - FnKind::Closure(binder, coroutine_kind, fn_decl, body), - *span, - *id - )); - } - ExprKind::Block(block, opt_label) => { - visit_opt!(visitor, visit_label, opt_label); - try_visit!(visitor.visit_block(block)); - } - ExprKind::Gen(_capt, body, _kind, _decl_span) => try_visit!(visitor.visit_block(body)), - ExprKind::Await(expr, _span) => try_visit!(visitor.visit_expr(expr)), - ExprKind::Use(expr, _span) => try_visit!(visitor.visit_expr(expr)), - ExprKind::Assign(lhs, rhs, _span) => { - try_visit!(visitor.visit_expr(lhs)); - try_visit!(visitor.visit_expr(rhs)); - } - ExprKind::AssignOp(_op, left_expression, right_expression) => { - try_visit!(visitor.visit_expr(left_expression)); - try_visit!(visitor.visit_expr(right_expression)); - } - ExprKind::Field(subexpression, ident) => { - try_visit!(visitor.visit_expr(subexpression)); - try_visit!(visitor.visit_ident(ident)); - } - ExprKind::Index(main_expression, index_expression, _span) => { - try_visit!(visitor.visit_expr(main_expression)); - try_visit!(visitor.visit_expr(index_expression)); - } - ExprKind::Range(start, end, _limit) => { - visit_opt!(visitor, visit_expr, start); - visit_opt!(visitor, visit_expr, end); - } - ExprKind::Underscore => {} - ExprKind::Path(maybe_qself, path) => { - try_visit!(visitor.visit_qself(maybe_qself)); - try_visit!(visitor.visit_id(*id)); - try_visit!(visitor.visit_path(path)); - } - ExprKind::Break(opt_label, opt_expr) => { - visit_opt!(visitor, visit_label, opt_label); - visit_opt!(visitor, visit_expr, opt_expr); - } - ExprKind::Continue(opt_label) => { - visit_opt!(visitor, visit_label, opt_label); - } - ExprKind::Ret(optional_expression) => { - visit_opt!(visitor, visit_expr, optional_expression); - } - ExprKind::Yeet(optional_expression) => { - visit_opt!(visitor, visit_expr, optional_expression); - } - ExprKind::Become(expr) => try_visit!(visitor.visit_expr(expr)), - ExprKind::MacCall(mac) => try_visit!(visitor.visit_mac_call(mac)), - ExprKind::Paren(subexpression) => try_visit!(visitor.visit_expr(subexpression)), - ExprKind::InlineAsm(asm) => try_visit!(visitor.visit_inline_asm(asm)), - ExprKind::FormatArgs(f) => try_visit!(visitor.visit_format_args(f)), - ExprKind::OffsetOf(container, fields) => { - try_visit!(visitor.visit_ty(container)); - walk_list!(visitor, visit_ident, fields.iter()); - } - ExprKind::Yield(kind) => { - visit_opt!(visitor, visit_expr, kind.expr()); - } - ExprKind::Try(subexpression) => try_visit!(visitor.visit_expr(subexpression)), - ExprKind::TryBlock(body) => try_visit!(visitor.visit_block(body)), - ExprKind::Lit(_token) => {} - ExprKind::IncludedBytes(_bytes) => {} - ExprKind::UnsafeBinderCast(_kind, expr, ty) => { - try_visit!(visitor.visit_expr(expr)); - visit_opt!(visitor, visit_ty, ty); - } - ExprKind::Err(_guar) => {} - ExprKind::Dummy => {} - } - - V::Result::output() + }; } -pub fn walk_param<'a, V: Visitor<'a>>(visitor: &mut V, param: &'a Param) -> V::Result { - let Param { attrs, ty, pat, id: _, span: _, is_placeholder: _ } = param; - walk_list!(visitor, visit_attribute, attrs); - try_visit!(visitor.visit_pat(pat)); - try_visit!(visitor.visit_ty(ty)); - V::Result::output() +common_visitor_and_walkers!(Visitor<'a>); + +macro_rules! generate_list_visit_fns { + ($($name:ident, $Ty:ty, $visit_fn:ident$(, $param:ident: $ParamTy:ty)*;)+) => { + $( + fn $name<'a, V: Visitor<'a>>( + vis: &mut V, + values: &'a ThinVec<$Ty>, + $( + $param: $ParamTy, + )* + ) -> V::Result { + walk_list!(vis, $visit_fn, values$(,$param)*); + V::Result::output() + } + )+ + } } -pub fn walk_arm<'a, V: Visitor<'a>>(visitor: &mut V, arm: &'a Arm) -> V::Result { - let Arm { attrs, pat, guard, body, span: _, id: _, is_placeholder: _ } = arm; - walk_list!(visitor, visit_attribute, attrs); - try_visit!(visitor.visit_pat(pat)); - visit_opt!(visitor, visit_expr, guard); - visit_opt!(visitor, visit_expr, body); - V::Result::output() +generate_list_visit_fns! { + visit_items, P<Item>, visit_item; + visit_foreign_items, P<ForeignItem>, visit_foreign_item; + visit_generic_params, GenericParam, visit_generic_param; + visit_stmts, Stmt, visit_stmt; + visit_exprs, P<Expr>, visit_expr; + visit_expr_fields, ExprField, visit_expr_field; + visit_pat_fields, PatField, visit_pat_field; + visit_variants, Variant, visit_variant; + visit_assoc_items, P<AssocItem>, visit_assoc_item, ctxt: AssocCtxt; + visit_where_predicates, WherePredicate, visit_where_predicate; + visit_params, Param, visit_param; + visit_field_defs, FieldDef, visit_field_def; + visit_arms, Arm, visit_arm; } -pub fn walk_vis<'a, V: Visitor<'a>>(visitor: &mut V, vis: &'a Visibility) -> V::Result { - let Visibility { kind, span: _, tokens: _ } = vis; - match kind { - VisibilityKind::Restricted { path, id, shorthand: _ } => { - try_visit!(visitor.visit_id(*id)); - try_visit!(visitor.visit_path(path)); - } - VisibilityKind::Public | VisibilityKind::Inherited => {} - } - V::Result::output() +#[expect(rustc::pass_by_value)] // needed for symmetry with mut_visit +fn visit_nested_use_tree<'a, V: Visitor<'a>>( + vis: &mut V, + nested_tree: &'a UseTree, + &nested_id: &NodeId, +) -> V::Result { + vis.visit_nested_use_tree(nested_tree, nested_id) } -pub fn walk_attribute<'a, V: Visitor<'a>>(visitor: &mut V, attr: &'a Attribute) -> V::Result { - let Attribute { kind, id: _, style: _, span: _ } = attr; +pub fn walk_stmt<'a, V: Visitor<'a>>(visitor: &mut V, statement: &'a Stmt) -> V::Result { + let Stmt { id: _, kind, span: _ } = statement; match kind { - AttrKind::Normal(normal) => { - let NormalAttr { item, tokens: _ } = &**normal; - let AttrItem { unsafety: _, path, args, tokens: _ } = item; - try_visit!(visitor.visit_path(path)); - try_visit!(walk_attr_args(visitor, args)); + StmtKind::Let(local) => try_visit!(visitor.visit_local(local)), + StmtKind::Item(item) => try_visit!(visitor.visit_item(item)), + StmtKind::Expr(expr) | StmtKind::Semi(expr) => try_visit!(visitor.visit_expr(expr)), + StmtKind::Empty => {} + StmtKind::MacCall(mac) => { + let MacCallStmt { mac, attrs, style: _, tokens: _ } = &**mac; + walk_list!(visitor, visit_attribute, attrs); + try_visit!(visitor.visit_mac_call(mac)); } - AttrKind::DocComment(_kind, _sym) => {} - } - V::Result::output() -} - -pub fn walk_attr_args<'a, V: Visitor<'a>>(visitor: &mut V, args: &'a AttrArgs) -> V::Result { - match args { - AttrArgs::Empty => {} - AttrArgs::Delimited(_args) => {} - AttrArgs::Eq { expr, .. } => try_visit!(visitor.visit_expr(expr)), } V::Result::output() } diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 537d4a2a6af..718edad0cc6 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -73,16 +73,15 @@ impl<'hir> LoweringContext<'_, 'hir> { // Merge attributes into the inner expression. if !e.attrs.is_empty() { let old_attrs = self.attrs.get(&ex.hir_id.local_id).copied().unwrap_or(&[]); - let attrs = &*self.arena.alloc_from_iter( - self.lower_attrs_vec(&e.attrs, e.span) - .into_iter() - .chain(old_attrs.iter().cloned()), - ); - if attrs.is_empty() { + let new_attrs = self + .lower_attrs_vec(&e.attrs, e.span, ex.hir_id) + .into_iter() + .chain(old_attrs.iter().cloned()); + let new_attrs = &*self.arena.alloc_from_iter(new_attrs); + if new_attrs.is_empty() { return ex; } - - self.attrs.insert(ex.hir_id.local_id, attrs); + self.attrs.insert(ex.hir_id.local_id, new_attrs); } return ex; } @@ -2035,7 +2034,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let ret_expr = self.checked_return(Some(from_residual_expr)); self.arena.alloc(self.expr(try_span, ret_expr)) }; - self.lower_attrs(ret_expr.hir_id, &attrs, ret_expr.span); + self.lower_attrs(ret_expr.hir_id, &attrs, span); let break_pat = self.pat_cf_break(try_span, residual_local); self.arm(break_pat, ret_expr) diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index d1a2ddbdb34..e2d291a536d 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -63,7 +63,7 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> { for (def_id, info) in lctx.children { let owner = self.owners.ensure_contains_elem(def_id, || hir::MaybeOwner::Phantom); - debug_assert!( + assert!( matches!(owner, hir::MaybeOwner::Phantom), "duplicate copy of {def_id:?} in lctx.children" ); @@ -78,7 +78,7 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> { match node { AstOwner::NonOwner => {} AstOwner::Crate(c) => { - debug_assert_eq!(self.resolver.node_id_to_def_id[&CRATE_NODE_ID], CRATE_DEF_ID); + assert_eq!(self.resolver.node_id_to_def_id[&CRATE_NODE_ID], CRATE_DEF_ID); self.with_lctx(CRATE_NODE_ID, |lctx| { let module = lctx.lower_mod(&c.items, &c.spans); // FIXME(jdonszelman): is dummy span ever a problem here? @@ -1160,7 +1160,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ) -> hir::BodyId { let body = hir::Body { params, value: self.arena.alloc(value) }; let id = body.id(); - debug_assert_eq!(id.hir_id.owner, self.current_hir_id_owner); + assert_eq!(id.hir_id.owner, self.current_hir_id_owner); self.bodies.push((id.hir_id.local_id, self.arena.alloc(body))); id } @@ -1673,8 +1673,8 @@ impl<'hir> LoweringContext<'_, 'hir> { itctx: ImplTraitContext, f: impl FnOnce(&mut Self) -> T, ) -> (&'hir hir::Generics<'hir>, T) { - debug_assert!(self.impl_trait_defs.is_empty()); - debug_assert!(self.impl_trait_bounds.is_empty()); + assert!(self.impl_trait_defs.is_empty()); + assert!(self.impl_trait_bounds.is_empty()); // Error if `?Trait` bounds in where clauses don't refer directly to type parameters. // Note: we used to clone these bounds directly onto the type parameter (and avoid lowering diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index b99df8bd7e5..4f0368bcb01 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -51,6 +51,7 @@ use rustc_data_structures::tagged_ptr::TaggedRef; 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::lints::DelayedLint; use rustc_hir::{ self as hir, AngleBrackets, ConstArg, GenericArg, HirId, ItemLocalMap, LangItem, LifetimeSource, LifetimeSyntax, ParamName, TraitCandidate, @@ -141,6 +142,8 @@ struct LoweringContext<'a, 'hir> { allow_for_await: Arc<[Symbol]>, allow_async_fn_traits: Arc<[Symbol]>, + delayed_lints: Vec<DelayedLint>, + attribute_parser: AttributeParser<'hir>, } @@ -190,6 +193,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { allow_async_iterator: [sym::gen_future, sym::async_iterator].into(), attribute_parser: AttributeParser::new(tcx.sess, tcx.features(), registered_tools), + delayed_lints: Vec::new(), } } @@ -198,6 +202,22 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } +struct SpanLowerer { + is_incremental: bool, + def_id: LocalDefId, +} + +impl SpanLowerer { + fn lower(&self, span: Span) -> Span { + if self.is_incremental { + span.with_parent(Some(self.def_id)) + } else { + // Do not make spans relative when not using incremental compilation. + span + } + } +} + #[extension(trait ResolverAstLoweringExt)] impl ResolverAstLowering { fn legacy_const_generic_args(&self, expr: &Expr) -> Option<Vec<usize>> { @@ -503,7 +523,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { span: Span, ) -> LocalDefId { let parent = self.current_hir_id_owner.def_id; - debug_assert_ne!(node_id, ast::DUMMY_NODE_ID); + assert_ne!(node_id, ast::DUMMY_NODE_ID); assert!( self.opt_local_def_id(node_id).is_none(), "adding a def'n for node-id {:?} and def kind {:?} but a previous def'n exists: {:?}", @@ -573,6 +593,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { std::mem::replace(&mut self.item_local_id_counter, hir::ItemLocalId::new(1)); let current_impl_trait_defs = std::mem::take(&mut self.impl_trait_defs); let current_impl_trait_bounds = std::mem::take(&mut self.impl_trait_bounds); + let current_delayed_lints = std::mem::take(&mut self.delayed_lints); // Do not reset `next_node_id` and `node_id_to_def_id`: // we want `f` to be able to refer to the `LocalDefId`s that the caller created. @@ -586,10 +607,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } let item = f(self); - debug_assert_eq!(owner_id, item.def_id()); + assert_eq!(owner_id, item.def_id()); // `f` should have consumed all the elements in these vectors when constructing `item`. - debug_assert!(self.impl_trait_defs.is_empty()); - debug_assert!(self.impl_trait_bounds.is_empty()); + assert!(self.impl_trait_defs.is_empty()); + assert!(self.impl_trait_bounds.is_empty()); let info = self.make_owner_info(item); self.attrs = current_attrs; @@ -606,6 +627,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.item_local_id_counter = current_local_counter; self.impl_trait_defs = current_impl_trait_defs; self.impl_trait_bounds = current_impl_trait_bounds; + self.delayed_lints = current_delayed_lints; debug_assert!(!self.children.iter().any(|(id, _)| id == &owner_id.def_id)); self.children.push((owner_id.def_id, hir::MaybeOwner::Owner(info))); @@ -616,6 +638,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let mut bodies = std::mem::take(&mut self.bodies); let define_opaque = std::mem::take(&mut self.define_opaque); let trait_map = std::mem::take(&mut self.trait_map); + let delayed_lints = std::mem::take(&mut self.delayed_lints).into_boxed_slice(); #[cfg(debug_assertions)] for (id, attrs) in attrs.iter() { @@ -629,14 +652,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let bodies = SortedMap::from_presorted_elements(bodies); // Don't hash unless necessary, because it's expensive. - let (opt_hash_including_bodies, attrs_hash) = - self.tcx.hash_owner_nodes(node, &bodies, &attrs, define_opaque); + let (opt_hash_including_bodies, attrs_hash, delayed_lints_hash) = + self.tcx.hash_owner_nodes(node, &bodies, &attrs, &delayed_lints, define_opaque); let num_nodes = self.item_local_id_counter.as_usize(); let (nodes, parenting) = index::index_hir(self.tcx, node, &bodies, num_nodes); let nodes = hir::OwnerNodes { opt_hash_including_bodies, nodes, bodies }; let attrs = hir::AttributeMap { map: attrs, opt_hash: attrs_hash, define_opaque }; + let delayed_lints = + hir::lints::DelayedLints { lints: delayed_lints, opt_hash: delayed_lints_hash }; - self.arena.alloc(hir::OwnerInfo { nodes, parenting, attrs, trait_map }) + self.arena.alloc(hir::OwnerInfo { nodes, parenting, attrs, trait_map, delayed_lints }) } /// This method allocates a new `HirId` for the given `NodeId`. @@ -759,15 +784,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { }) } + fn span_lowerer(&self) -> SpanLowerer { + SpanLowerer { + is_incremental: self.tcx.sess.opts.incremental.is_some(), + def_id: self.current_hir_id_owner.def_id, + } + } + /// Intercept all spans entering HIR. /// Mark a span as relative to the current owning item. fn lower_span(&self, span: Span) -> Span { - if self.tcx.sess.opts.incremental.is_some() { - span.with_parent(Some(self.current_hir_id_owner.def_id)) - } else { - // Do not make spans relative when not using incremental compilation. - span - } + self.span_lowerer().lower(span) } fn lower_ident(&self, ident: Ident) -> Ident { @@ -889,9 +916,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { if attrs.is_empty() { &[] } else { - let lowered_attrs = self.lower_attrs_vec(attrs, self.lower_span(target_span)); + let lowered_attrs = self.lower_attrs_vec(attrs, self.lower_span(target_span), id); - debug_assert_eq!(id.owner, self.current_hir_id_owner); + assert_eq!(id.owner, self.current_hir_id_owner); let ret = self.arena.alloc_from_iter(lowered_attrs); // this is possible if an item contained syntactical attribute, @@ -909,16 +936,30 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } - fn lower_attrs_vec(&self, attrs: &[Attribute], target_span: Span) -> Vec<hir::Attribute> { - self.attribute_parser - .parse_attribute_list(attrs, target_span, OmitDoc::Lower, |s| self.lower_span(s)) + fn lower_attrs_vec( + &mut self, + attrs: &[Attribute], + target_span: Span, + target_hir_id: HirId, + ) -> Vec<hir::Attribute> { + let l = self.span_lowerer(); + self.attribute_parser.parse_attribute_list( + attrs, + target_span, + target_hir_id, + OmitDoc::Lower, + |s| l.lower(s), + |l| { + self.delayed_lints.push(DelayedLint::AttributeParsing(l)); + }, + ) } fn alias_attrs(&mut self, id: HirId, target_id: HirId) { - debug_assert_eq!(id.owner, self.current_hir_id_owner); - debug_assert_eq!(target_id.owner, self.current_hir_id_owner); + assert_eq!(id.owner, self.current_hir_id_owner); + assert_eq!(target_id.owner, self.current_hir_id_owner); if let Some(&a) = self.attrs.get(&target_id.local_id) { - debug_assert!(!a.is_empty()); + assert!(!a.is_empty()); self.attrs.insert(id.local_id, a); } } @@ -1397,7 +1438,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let id = if let Some(LifetimeRes::ElidedAnchor { start, end }) = self.resolver.get_lifetime_res(t.id) { - debug_assert_eq!(start.plus(1), end); + assert_eq!(start.plus(1), end); start } else { self.next_node_id() @@ -1805,16 +1846,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let res = match res { LifetimeRes::Param { param, .. } => hir::LifetimeKind::Param(param), LifetimeRes::Fresh { param, .. } => { - debug_assert_eq!(ident.name, kw::UnderscoreLifetime); + assert_eq!(ident.name, kw::UnderscoreLifetime); let param = self.local_def_id(param); hir::LifetimeKind::Param(param) } LifetimeRes::Infer => { - debug_assert_eq!(ident.name, kw::UnderscoreLifetime); + assert_eq!(ident.name, kw::UnderscoreLifetime); hir::LifetimeKind::Infer } LifetimeRes::Static { .. } => { - debug_assert!(matches!(ident.name, kw::StaticLifetime | kw::UnderscoreLifetime)); + assert!(matches!(ident.name, kw::StaticLifetime | kw::UnderscoreLifetime)); hir::LifetimeKind::Static } LifetimeRes::Error => hir::LifetimeKind::Error, @@ -2244,7 +2285,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ) -> hir::Stmt<'hir> { let hir_id = self.next_id(); if let Some(a) = attrs { - debug_assert!(!a.is_empty()); + assert!(!a.is_empty()); self.attrs.insert(hir_id.local_id, a); } let local = hir::LetStmt { diff --git a/compiler/rustc_ast_lowering/src/stability.rs b/compiler/rustc_ast_lowering/src/stability.rs index eb052ba1c6d..b8fa2dd3dd6 100644 --- a/compiler/rustc_ast_lowering/src/stability.rs +++ b/compiler/rustc_ast_lowering/src/stability.rs @@ -134,5 +134,8 @@ pub fn extern_abi_stability(abi: ExternAbi) -> Result<(), UnstableAbi> { feature: sym::cmse_nonsecure_entry, explain: GateReason::Experimental, }), + ExternAbi::Custom => { + Err(UnstableAbi { abi, feature: sym::abi_custom, explain: GateReason::Experimental }) + } } } diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index 80754a8f65a..9a267501230 100644 --- a/compiler/rustc_ast_passes/messages.ftl +++ b/compiler/rustc_ast_passes/messages.ftl @@ -1,3 +1,20 @@ +ast_passes_abi_custom_coroutine = + functions with the `"custom"` ABI cannot be `{$coroutine_kind_str}` + .suggestion = remove the `{$coroutine_kind_str}` keyword from this definiton + +ast_passes_abi_custom_invalid_signature = + invalid signature for `extern "custom"` function + .note = functions with the `"custom"` ABI cannot have any parameters or return type + .suggestion = remove the parameters and return type + +ast_passes_abi_custom_safe_foreign_function = + foreign functions with the `"custom"` ABI cannot be safe + .suggestion = remove the `safe` keyword from this definition + +ast_passes_abi_custom_safe_function = + functions with the `"custom"` ABI must be unsafe + .suggestion = add the `unsafe` keyword to this definition + ast_passes_assoc_const_without_body = associated constant in `impl` without body .suggestion = provide a definition for the constant diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index d6fe04d2994..018887d0e8e 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -18,6 +18,7 @@ use std::mem; use std::ops::{Deref, DerefMut}; +use std::str::FromStr; use itertools::{Either, Itertools}; use rustc_abi::ExternAbi; @@ -81,6 +82,7 @@ struct AstValidator<'a> { /// Used to ban explicit safety on foreign items when the extern block is not marked as unsafe. extern_mod_safety: Option<Safety>, + extern_mod_abi: Option<ExternAbi>, lint_node_id: NodeId, @@ -121,10 +123,17 @@ impl<'a> AstValidator<'a> { self.outer_trait_or_trait_impl = old; } - fn with_in_extern_mod(&mut self, extern_mod_safety: Safety, f: impl FnOnce(&mut Self)) { - let old = mem::replace(&mut self.extern_mod_safety, Some(extern_mod_safety)); + fn with_in_extern_mod( + &mut self, + extern_mod_safety: Safety, + abi: Option<ExternAbi>, + f: impl FnOnce(&mut Self), + ) { + let old_safety = mem::replace(&mut self.extern_mod_safety, Some(extern_mod_safety)); + let old_abi = mem::replace(&mut self.extern_mod_abi, abi); f(self); - self.extern_mod_safety = old; + self.extern_mod_safety = old_safety; + self.extern_mod_abi = old_abi; } fn with_tilde_const( @@ -370,6 +379,65 @@ impl<'a> AstValidator<'a> { } } + /// An `extern "custom"` function must be unsafe, and must not have any parameters or return + /// type. + fn check_custom_abi(&self, ctxt: FnCtxt, ident: &Ident, sig: &FnSig) { + let dcx = self.dcx(); + + // An `extern "custom"` function must be unsafe. + match sig.header.safety { + Safety::Unsafe(_) => { /* all good */ } + Safety::Safe(safe_span) => { + let safe_span = + self.sess.psess.source_map().span_until_non_whitespace(safe_span.to(sig.span)); + dcx.emit_err(errors::AbiCustomSafeForeignFunction { span: sig.span, safe_span }); + } + Safety::Default => match ctxt { + FnCtxt::Foreign => { /* all good */ } + FnCtxt::Free | FnCtxt::Assoc(_) => { + self.dcx().emit_err(errors::AbiCustomSafeFunction { + span: sig.span, + unsafe_span: sig.span.shrink_to_lo(), + }); + } + }, + } + + // An `extern "custom"` function cannot be `async` and/or `gen`. + if let Some(coroutine_kind) = sig.header.coroutine_kind { + let coroutine_kind_span = self + .sess + .psess + .source_map() + .span_until_non_whitespace(coroutine_kind.span().to(sig.span)); + + self.dcx().emit_err(errors::AbiCustomCoroutine { + span: sig.span, + coroutine_kind_span, + coroutine_kind_str: coroutine_kind.as_str(), + }); + } + + // An `extern "custom"` function must not have any parameters or return type. + let mut spans: Vec<_> = sig.decl.inputs.iter().map(|p| p.span).collect(); + if let FnRetTy::Ty(ref ret_ty) = sig.decl.output { + spans.push(ret_ty.span); + } + + if !spans.is_empty() { + let header_span = sig.header.span().unwrap_or(sig.span.shrink_to_lo()); + let suggestion_span = header_span.shrink_to_hi().to(sig.decl.output.span()); + let padding = if header_span.is_empty() { "" } else { " " }; + + self.dcx().emit_err(errors::AbiCustomInvalidSignature { + spans, + symbol: ident.name, + suggestion_span, + padding, + }); + } + } + /// This ensures that items can only be `unsafe` (or unmarked) outside of extern /// blocks. /// @@ -1005,7 +1073,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> { if abi.is_none() { self.handle_missing_abi(*extern_span, item.id); } - self.with_in_extern_mod(*safety, |this| { + + let extern_abi = abi.and_then(|abi| ExternAbi::from_str(abi.symbol.as_str()).ok()); + self.with_in_extern_mod(*safety, extern_abi, |this| { visit::walk_item(this, item); }); self.extern_mod_span = old_item; @@ -1145,6 +1215,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.check_foreign_fn_bodyless(*ident, body.as_deref()); self.check_foreign_fn_headerless(sig.header); self.check_foreign_item_ascii_only(*ident); + if self.extern_mod_abi == Some(ExternAbi::Custom) { + self.check_custom_abi(FnCtxt::Foreign, ident, sig); + } } ForeignItemKind::TyAlias(box TyAlias { defaultness, @@ -1352,6 +1425,13 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.check_item_safety(span, safety); } + if let FnKind::Fn(ctxt, _, fun) = fk + && let Extern::Explicit(str_lit, _) = fun.sig.header.ext + && let Ok(ExternAbi::Custom) = ExternAbi::from_str(str_lit.symbol.as_str()) + { + self.check_custom_abi(ctxt, &fun.ident, &fun.sig); + } + self.check_c_variadic_type(fk); // Functions cannot both be `const async` or `const gen` @@ -1703,6 +1783,7 @@ pub fn check_crate( outer_impl_trait_span: None, disallow_tilde_const: Some(TildeConstReason::Item), extern_mod_safety: None, + extern_mod_abi: None, lint_node_id: CRATE_NODE_ID, is_sdylib_interface, lint_buffer: lints, diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index 6f9737e0831..c437e62f4d3 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -824,3 +824,67 @@ pub(crate) struct MissingAbi { #[suggestion(code = "extern \"<abi>\"", applicability = "has-placeholders")] pub span: Span, } + +#[derive(Diagnostic)] +#[diag(ast_passes_abi_custom_safe_foreign_function)] +pub(crate) struct AbiCustomSafeForeignFunction { + #[primary_span] + pub span: Span, + + #[suggestion( + ast_passes_suggestion, + applicability = "maybe-incorrect", + code = "", + style = "verbose" + )] + pub safe_span: Span, +} + +#[derive(Diagnostic)] +#[diag(ast_passes_abi_custom_safe_function)] +pub(crate) struct AbiCustomSafeFunction { + #[primary_span] + pub span: Span, + + #[suggestion( + ast_passes_suggestion, + applicability = "maybe-incorrect", + code = "unsafe ", + style = "verbose" + )] + pub unsafe_span: Span, +} + +#[derive(Diagnostic)] +#[diag(ast_passes_abi_custom_coroutine)] +pub(crate) struct AbiCustomCoroutine { + #[primary_span] + pub span: Span, + + #[suggestion( + ast_passes_suggestion, + applicability = "maybe-incorrect", + code = "", + style = "verbose" + )] + pub coroutine_kind_span: Span, + pub coroutine_kind_str: &'static str, +} + +#[derive(Diagnostic)] +#[diag(ast_passes_abi_custom_invalid_signature)] +#[note] +pub(crate) struct AbiCustomInvalidSignature { + #[primary_span] + pub spans: Vec<Span>, + + #[suggestion( + ast_passes_suggestion, + applicability = "maybe-incorrect", + code = "{padding}fn {symbol}()", + style = "verbose" + )] + pub suggestion_span: Span, + pub symbol: Symbol, + pub padding: &'static str, +} diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 3682d25d341..1ec56868f37 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -36,6 +36,16 @@ macro_rules! gate_alt { feature_err(&$visitor.sess, $name, $span, $explain).emit(); } }}; + ($visitor:expr, $has_feature:expr, $name:expr, $span:expr, $explain:expr, $notes: expr) => {{ + if !$has_feature && !$span.allows_unstable($name) { + #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable + let mut diag = feature_err(&$visitor.sess, $name, $span, $explain); + for note in $notes { + diag.note(*note); + } + diag.emit(); + } + }}; } /// The case involving a multispan. @@ -154,11 +164,11 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { let attr_info = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)); // Check feature gates for built-in attributes. if let Some(BuiltinAttribute { - gate: AttributeGate::Gated(_, name, descr, has_feature), + gate: AttributeGate::Gated { feature, message, check, notes, .. }, .. }) = attr_info { - gate_alt!(self, has_feature(self.features), *name, attr.span, *descr); + gate_alt!(self, check(self.features), *feature, attr.span, *message, *notes); } // Check unstable flavors of the `#[doc]` attribute. if attr.has_name(sym::doc) { diff --git a/compiler/rustc_ast_pretty/src/pprust/mod.rs b/compiler/rustc_ast_pretty/src/pprust/mod.rs index a05e2bd6a5d..a766e2006e5 100644 --- a/compiler/rustc_ast_pretty/src/pprust/mod.rs +++ b/compiler/rustc_ast_pretty/src/pprust/mod.rs @@ -53,6 +53,18 @@ pub fn item_to_string(i: &ast::Item) -> String { State::new().item_to_string(i) } +pub fn assoc_item_to_string(i: &ast::AssocItem) -> String { + State::new().assoc_item_to_string(i) +} + +pub fn foreign_item_to_string(i: &ast::ForeignItem) -> String { + State::new().foreign_item_to_string(i) +} + +pub fn stmt_to_string(s: &ast::Stmt) -> String { + State::new().stmt_to_string(s) +} + pub fn path_to_string(p: &ast::Path) -> String { State::new().path_to_string(p) } diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 0990c9b27eb..3d738fa31f2 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1063,6 +1063,14 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere Self::to_string(|s| s.print_item(i)) } + fn assoc_item_to_string(&self, i: &ast::AssocItem) -> String { + Self::to_string(|s| s.print_assoc_item(i)) + } + + fn foreign_item_to_string(&self, i: &ast::ForeignItem) -> String { + Self::to_string(|s| s.print_foreign_item(i)) + } + fn path_to_string(&self, p: &ast::Path) -> String { Self::to_string(|s| s.print_path(p, false, 0)) } diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs index c9a7e2aebd0..ee49246a4bb 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs @@ -7,8 +7,8 @@ use rustc_ast::util::classify; use rustc_ast::util::literal::escape_byte_str_symbol; use rustc_ast::util::parser::{self, ExprPrecedence, Fixity}; use rustc_ast::{ - self as ast, BlockCheckMode, FormatAlignment, FormatArgPosition, FormatArgsPiece, FormatCount, - FormatDebugHex, FormatSign, FormatTrait, YieldKind, token, + self as ast, BinOpKind, BlockCheckMode, FormatAlignment, FormatArgPosition, FormatArgsPiece, + FormatCount, FormatDebugHex, FormatSign, FormatTrait, YieldKind, token, }; use crate::pp::Breaks::Inconsistent; @@ -214,13 +214,6 @@ impl<'a> State<'a> { } fn print_expr_call(&mut self, func: &ast::Expr, args: &[P<ast::Expr>], fixup: FixupContext) { - let needs_paren = match func.kind { - // In order to call a named field, needs parens: `(self.fun)()` - // But not for an unnamed field: `self.0()` - ast::ExprKind::Field(_, name) => !name.is_numeric(), - _ => func.precedence() < ExprPrecedence::Unambiguous, - }; - // Independent of parenthesization related to precedence, we must // parenthesize `func` if this is a statement context in which without // parentheses, a statement boundary would occur inside `func` or @@ -237,8 +230,16 @@ impl<'a> State<'a> { // because the latter is valid syntax but with the incorrect meaning. // It's a match-expression followed by tuple-expression, not a function // call. - self.print_expr_cond_paren(func, needs_paren, fixup.leftmost_subexpression()); + let func_fixup = fixup.leftmost_subexpression_with_operator(true); + + let needs_paren = match func.kind { + // In order to call a named field, needs parens: `(self.fun)()` + // But not for an unnamed field: `self.0()` + ast::ExprKind::Field(_, name) => !name.is_numeric(), + _ => func_fixup.precedence(func) < ExprPrecedence::Unambiguous, + }; + self.print_expr_cond_paren(func, needs_paren, func_fixup); self.print_call_post(args) } @@ -281,9 +282,24 @@ impl<'a> State<'a> { rhs: &ast::Expr, fixup: FixupContext, ) { + let operator_can_begin_expr = match op { + | BinOpKind::Sub // -x + | BinOpKind::Mul // *x + | BinOpKind::And // &&x + | BinOpKind::Or // || x + | BinOpKind::BitAnd // &x + | BinOpKind::BitOr // |x| x + | BinOpKind::Shl // <<T as Trait>::Type as Trait>::CONST + | BinOpKind::Lt // <T as Trait>::CONST + => true, + _ => false, + }; + + let left_fixup = fixup.leftmost_subexpression_with_operator(operator_can_begin_expr); + let binop_prec = op.precedence(); - let left_prec = lhs.precedence(); - let right_prec = rhs.precedence(); + let left_prec = left_fixup.precedence(lhs); + let right_prec = fixup.precedence(rhs); let (mut left_needs_paren, right_needs_paren) = match op.fixity() { Fixity::Left => (left_prec < binop_prec, right_prec <= binop_prec), @@ -312,18 +328,18 @@ impl<'a> State<'a> { _ => {} } - self.print_expr_cond_paren(lhs, left_needs_paren, fixup.leftmost_subexpression()); + self.print_expr_cond_paren(lhs, left_needs_paren, left_fixup); self.space(); self.word_space(op.as_str()); - self.print_expr_cond_paren(rhs, right_needs_paren, fixup.subsequent_subexpression()); + self.print_expr_cond_paren(rhs, right_needs_paren, fixup.rightmost_subexpression()); } fn print_expr_unary(&mut self, op: ast::UnOp, expr: &ast::Expr, fixup: FixupContext) { self.word(op.as_str()); self.print_expr_cond_paren( expr, - expr.precedence() < ExprPrecedence::Prefix, - fixup.subsequent_subexpression(), + fixup.precedence(expr) < ExprPrecedence::Prefix, + fixup.rightmost_subexpression(), ); } @@ -344,8 +360,8 @@ impl<'a> State<'a> { } self.print_expr_cond_paren( expr, - expr.precedence() < ExprPrecedence::Prefix, - fixup.subsequent_subexpression(), + fixup.precedence(expr) < ExprPrecedence::Prefix, + fixup.rightmost_subexpression(), ); } @@ -590,8 +606,8 @@ impl<'a> State<'a> { self.word_space("="); self.print_expr_cond_paren( rhs, - rhs.precedence() < ExprPrecedence::Assign, - fixup.subsequent_subexpression(), + fixup.precedence(rhs) < ExprPrecedence::Assign, + fixup.rightmost_subexpression(), ); } ast::ExprKind::AssignOp(op, lhs, rhs) => { @@ -604,8 +620,8 @@ impl<'a> State<'a> { self.word_space(op.node.as_str()); self.print_expr_cond_paren( rhs, - rhs.precedence() < ExprPrecedence::Assign, - fixup.subsequent_subexpression(), + fixup.precedence(rhs) < ExprPrecedence::Assign, + fixup.rightmost_subexpression(), ); } ast::ExprKind::Field(expr, ident) => { @@ -618,10 +634,11 @@ impl<'a> State<'a> { self.print_ident(*ident); } ast::ExprKind::Index(expr, index, _) => { + let expr_fixup = fixup.leftmost_subexpression_with_operator(true); self.print_expr_cond_paren( expr, - expr.precedence() < ExprPrecedence::Unambiguous, - fixup.leftmost_subexpression(), + expr_fixup.precedence(expr) < ExprPrecedence::Unambiguous, + expr_fixup, ); self.word("["); self.print_expr(index, FixupContext::default()); @@ -634,10 +651,11 @@ impl<'a> State<'a> { // a "normal" binop gets parenthesized. (`LOr` is the lowest-precedence binop.) let fake_prec = ExprPrecedence::LOr; if let Some(e) = start { + let start_fixup = fixup.leftmost_subexpression_with_operator(true); self.print_expr_cond_paren( e, - e.precedence() < fake_prec, - fixup.leftmost_subexpression(), + start_fixup.precedence(e) < fake_prec, + start_fixup, ); } match limits { @@ -647,8 +665,8 @@ impl<'a> State<'a> { if let Some(e) = end { self.print_expr_cond_paren( e, - e.precedence() < fake_prec, - fixup.subsequent_subexpression(), + fixup.precedence(e) < fake_prec, + fixup.rightmost_subexpression(), ); } } @@ -665,11 +683,10 @@ impl<'a> State<'a> { self.space(); self.print_expr_cond_paren( expr, - // Parenthesize if required by precedence, or in the - // case of `break 'inner: loop { break 'inner 1 } + 1` - expr.precedence() < ExprPrecedence::Jump - || (opt_label.is_none() && classify::leading_labeled_expr(expr)), - fixup.subsequent_subexpression(), + // Parenthesize `break 'inner: loop { break 'inner 1 } + 1` + // ^---------------------------------^ + opt_label.is_none() && classify::leading_labeled_expr(expr), + fixup.rightmost_subexpression(), ); } } @@ -684,11 +701,7 @@ impl<'a> State<'a> { self.word("return"); if let Some(expr) = result { self.word(" "); - self.print_expr_cond_paren( - expr, - expr.precedence() < ExprPrecedence::Jump, - fixup.subsequent_subexpression(), - ); + self.print_expr(expr, fixup.rightmost_subexpression()); } } ast::ExprKind::Yeet(result) => { @@ -697,21 +710,13 @@ impl<'a> State<'a> { self.word("yeet"); if let Some(expr) = result { self.word(" "); - self.print_expr_cond_paren( - expr, - expr.precedence() < ExprPrecedence::Jump, - fixup.subsequent_subexpression(), - ); + self.print_expr(expr, fixup.rightmost_subexpression()); } } ast::ExprKind::Become(result) => { self.word("become"); self.word(" "); - self.print_expr_cond_paren( - result, - result.precedence() < ExprPrecedence::Jump, - fixup.subsequent_subexpression(), - ); + self.print_expr(result, fixup.rightmost_subexpression()); } ast::ExprKind::InlineAsm(a) => { // FIXME: Print `builtin # asm` once macro `asm` uses `builtin_syntax`. @@ -761,11 +766,7 @@ impl<'a> State<'a> { if let Some(expr) = e { self.space(); - self.print_expr_cond_paren( - expr, - expr.precedence() < ExprPrecedence::Jump, - fixup.subsequent_subexpression(), - ); + self.print_expr(expr, fixup.rightmost_subexpression()); } } ast::ExprKind::Yield(YieldKind::Postfix(e)) => { diff --git a/compiler/rustc_ast_pretty/src/pprust/state/fixup.rs b/compiler/rustc_ast_pretty/src/pprust/state/fixup.rs index 3ef21f5cb29..eb5ac8b78a8 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/fixup.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/fixup.rs @@ -1,5 +1,6 @@ -use rustc_ast::Expr; -use rustc_ast::util::{classify, parser}; +use rustc_ast::util::classify; +use rustc_ast::util::parser::{self, ExprPrecedence}; +use rustc_ast::{Expr, ExprKind, YieldKind}; // The default amount of fixing is minimal fixing, so all fixups are set to `false` by `Default`. // Fixups should be turned on in a targeted fashion where needed. @@ -93,6 +94,24 @@ pub(crate) struct FixupContext { /// } /// ``` parenthesize_exterior_struct_lit: bool, + + /// This is the difference between: + /// + /// ```ignore (illustrative) + /// let _ = (return) - 1; // without paren, this would return -1 + /// + /// let _ = return + 1; // no paren because '+' cannot begin expr + /// ``` + next_operator_can_begin_expr: bool, + + /// This is the difference between: + /// + /// ```ignore (illustrative) + /// let _ = 1 + return 1; // no parens if rightmost subexpression + /// + /// let _ = 1 + (return 1) + 1; // needs parens + /// ``` + next_operator_can_continue_expr: bool, } impl FixupContext { @@ -134,6 +153,8 @@ impl FixupContext { match_arm: false, leftmost_subexpression_in_match_arm: self.match_arm || self.leftmost_subexpression_in_match_arm, + next_operator_can_begin_expr: false, + next_operator_can_continue_expr: true, ..self } } @@ -148,19 +169,34 @@ impl FixupContext { leftmost_subexpression_in_stmt: false, match_arm: self.match_arm || self.leftmost_subexpression_in_match_arm, leftmost_subexpression_in_match_arm: false, + next_operator_can_begin_expr: false, + next_operator_can_continue_expr: true, ..self } } - /// Transform this fixup into the one that should apply when printing any - /// subexpression that is neither a leftmost subexpression nor surrounded in - /// delimiters. + /// Transform this fixup into the one that should apply when printing a + /// leftmost subexpression followed by punctuation that is legal as the + /// first token of an expression. + pub(crate) fn leftmost_subexpression_with_operator( + self, + next_operator_can_begin_expr: bool, + ) -> Self { + FixupContext { next_operator_can_begin_expr, ..self.leftmost_subexpression() } + } + + /// Transform this fixup into the one that should apply when printing the + /// rightmost subexpression of the current expression. + /// + /// The rightmost subexpression is any subexpression that has a different + /// first token than the current expression, but has the same last token. + /// + /// For example in `$a + $b` and `-$b`, the subexpression `$b` is a + /// rightmost subexpression. /// - /// This is for any subexpression that has a different first token than the - /// current expression, and is not surrounded by a paren/bracket/brace. For - /// example the `$b` in `$a + $b` and `-$b`, but not the one in `[$b]` or - /// `$a.f($b)`. - pub(crate) fn subsequent_subexpression(self) -> Self { + /// Not every expression has a rightmost subexpression. For example neither + /// `[$b]` nor `$a.f($b)` have one. + pub(crate) fn rightmost_subexpression(self) -> Self { FixupContext { stmt: false, leftmost_subexpression_in_stmt: false, @@ -193,6 +229,39 @@ impl FixupContext { /// "let chain". pub(crate) fn needs_par_as_let_scrutinee(self, expr: &Expr) -> bool { self.parenthesize_exterior_struct_lit && parser::contains_exterior_struct_lit(expr) - || parser::needs_par_as_let_scrutinee(expr.precedence()) + || parser::needs_par_as_let_scrutinee(self.precedence(expr)) + } + + /// Determines the effective precedence of a subexpression. Some expressions + /// have higher or lower precedence when adjacent to particular operators. + pub(crate) fn precedence(self, expr: &Expr) -> ExprPrecedence { + if self.next_operator_can_begin_expr { + // Decrease precedence of value-less jumps when followed by an + // operator that would otherwise get interpreted as beginning a + // value for the jump. + if let ExprKind::Break(..) + | ExprKind::Ret(..) + | ExprKind::Yeet(..) + | ExprKind::Yield(YieldKind::Prefix(..)) = expr.kind + { + return ExprPrecedence::Jump; + } + } + + if !self.next_operator_can_continue_expr { + // Increase precedence of expressions that extend to the end of + // current statement or group. + if let ExprKind::Break(..) + | ExprKind::Closure(..) + | ExprKind::Ret(..) + | ExprKind::Yeet(..) + | ExprKind::Yield(YieldKind::Prefix(..)) + | ExprKind::Range(None, ..) = expr.kind + { + return ExprPrecedence::Prefix; + } + } + + expr.precedence() } } diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index 3638eb31c61..6c442553976 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -28,7 +28,7 @@ impl<'a> State<'a> { } } - fn print_foreign_item(&mut self, item: &ast::ForeignItem) { + pub(crate) fn print_foreign_item(&mut self, item: &ast::ForeignItem) { let ast::Item { id, span, ref attrs, ref kind, ref vis, tokens: _ } = *item; self.ann.pre(self, AnnNode::SubItem(id)); self.hardbreak_if_not_bol(); @@ -548,7 +548,7 @@ impl<'a> State<'a> { } } - fn print_assoc_item(&mut self, item: &ast::AssocItem) { + pub(crate) fn print_assoc_item(&mut self, item: &ast::AssocItem) { let ast::Item { id, span, ref attrs, ref kind, ref vis, tokens: _ } = *item; self.ann.pre(self, AnnNode::SubItem(id)); self.hardbreak_if_not_bol(); diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs index d2d1285b075..845e4d5e5d0 100644 --- a/compiler/rustc_attr_data_structures/src/attributes.rs +++ b/compiler/rustc_attr_data_structures/src/attributes.rs @@ -57,14 +57,6 @@ impl OptimizeAttr { } } -#[derive(Clone, Debug, Encodable, Decodable, HashStable_Generic, PrintAttribute)] -pub enum DiagnosticAttribute { - // tidy-alphabetical-start - DoNotRecommend, - OnUnimplemented, - // tidy-alphabetical-end -} - #[derive(PartialEq, Debug, Encodable, Decodable, Copy, Clone, HashStable_Generic, PrintAttribute)] pub enum ReprAttr { ReprInt(IntType), @@ -160,40 +152,52 @@ impl Deprecation { #[derive(Clone, Debug, HashStable_Generic, Encodable, Decodable, PrintAttribute)] pub enum AttributeKind { // tidy-alphabetical-start + /// Represents `#[rustc_allow_const_fn_unstable]`. AllowConstFnUnstable(ThinVec<Symbol>), + + /// Represents `#[allow_internal_unstable]`. AllowInternalUnstable(ThinVec<(Symbol, Span)>), + + /// Represents `#[rustc_default_body_unstable]`. BodyStability { stability: DefaultBodyStability, /// Span of the `#[rustc_default_body_unstable(...)]` attribute span: Span, }, + + /// Represents `#[rustc_confusables]`. Confusables { symbols: ThinVec<Symbol>, // FIXME(jdonszelmann): remove when target validation code is moved first_span: Span, }, + + /// Represents `#[rustc_const_stable]` and `#[rustc_const_unstable]`. ConstStability { stability: PartialConstStability, /// Span of the `#[rustc_const_stable(...)]` or `#[rustc_const_unstable(...)]` attribute span: Span, }, + + /// Represents `#[rustc_const_stable_indirect]`. ConstStabilityIndirect, - Deprecation { - deprecation: Deprecation, - span: Span, - }, - Diagnostic(DiagnosticAttribute), - DocComment { - style: AttrStyle, - kind: CommentKind, - span: Span, - comment: Symbol, - }, + + /// Represents [`#[deprecated]`](https://doc.rust-lang.org/stable/reference/attributes/diagnostics.html#the-deprecated-attribute). + Deprecation { deprecation: Deprecation, span: Span }, + + /// Represents [`#[doc]`](https://doc.rust-lang.org/stable/rustdoc/write-documentation/the-doc-attribute.html). + DocComment { style: AttrStyle, kind: CommentKind, span: Span, comment: Symbol }, + + /// Represents `#[rustc_macro_transparency]`. MacroTransparency(Transparency), + + /// Represents [`#[repr]`](https://doc.rust-lang.org/stable/reference/type-layout.html#representations). Repr(ThinVec<(ReprAttr, Span)>), + + /// Represents `#[stable]`, `#[unstable]` and `#[rustc_allowed_through_unstable_modules]`. Stability { stability: Stability, - /// Span of the `#[stable(...)]` or `#[unstable(...)]` attribute + /// Span of the attribute. span: Span, }, // tidy-alphabetical-end diff --git a/compiler/rustc_attr_data_structures/src/lib.rs b/compiler/rustc_attr_data_structures/src/lib.rs index dbfc95b047a..b0fc19d1cd7 100644 --- a/compiler/rustc_attr_data_structures/src/lib.rs +++ b/compiler/rustc_attr_data_structures/src/lib.rs @@ -8,6 +8,8 @@ mod attributes; mod stability; mod version; +pub mod lints; + use std::num::NonZero; pub use attributes::*; diff --git a/compiler/rustc_attr_data_structures/src/lints.rs b/compiler/rustc_attr_data_structures/src/lints.rs new file mode 100644 index 00000000000..7e3664b2263 --- /dev/null +++ b/compiler/rustc_attr_data_structures/src/lints.rs @@ -0,0 +1,14 @@ +use rustc_macros::HashStable_Generic; +use rustc_span::Span; + +#[derive(Clone, Debug, HashStable_Generic)] +pub struct AttributeLint<Id> { + pub id: Id, + pub span: Span, + pub kind: AttributeLintKind, +} + +#[derive(Clone, Debug, HashStable_Generic)] +pub enum AttributeLintKind { + UnusedDuplicate { this: Span, other: Span, warning: bool }, +} diff --git a/compiler/rustc_attr_data_structures/src/stability.rs b/compiler/rustc_attr_data_structures/src/stability.rs index c0ca08a60f8..218e771c745 100644 --- a/compiler/rustc_attr_data_structures/src/stability.rs +++ b/compiler/rustc_attr_data_structures/src/stability.rs @@ -132,6 +132,7 @@ pub enum StabilityLevel { /// fn foobar() {} /// ``` implied_by: Option<Symbol>, + old_name: Option<Symbol>, }, /// `#[stable]` Stable { diff --git a/compiler/rustc_attr_parsing/messages.ftl b/compiler/rustc_attr_parsing/messages.ftl index 45174c9582d..c9443feb021 100644 --- a/compiler/rustc_attr_parsing/messages.ftl +++ b/compiler/rustc_attr_parsing/messages.ftl @@ -131,7 +131,15 @@ attr_parsing_unsupported_literal_generic = attr_parsing_unsupported_literal_suggestion = consider removing the prefix +attr_parsing_unused_duplicate = + unused attribute + .suggestion = remove this attribute + .note = attribute also specified here + .warn = {-passes_previously_accepted} attr_parsing_unused_multiple = multiple `{$name}` attributes .suggestion = remove this attribute .note = attribute also specified here + +-attr_parsing_perviously_accepted = + this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! diff --git a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs index d0465546b73..81192f902a2 100644 --- a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs +++ b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs @@ -4,41 +4,43 @@ use rustc_attr_data_structures::AttributeKind; use rustc_span::{Span, Symbol, sym}; use super::{CombineAttributeParser, ConvertFn}; -use crate::context::AcceptContext; +use crate::context::{AcceptContext, Stage}; use crate::parser::ArgParser; use crate::session_diagnostics; pub(crate) struct AllowInternalUnstableParser; -impl CombineAttributeParser for AllowInternalUnstableParser { - const PATH: &'static [Symbol] = &[sym::allow_internal_unstable]; +impl<S: Stage> CombineAttributeParser<S> for AllowInternalUnstableParser { + const PATH: &[Symbol] = &[sym::allow_internal_unstable]; type Item = (Symbol, Span); const CONVERT: ConvertFn<Self::Item> = AttributeKind::AllowInternalUnstable; - fn extend<'a>( - cx: &'a AcceptContext<'a>, - args: &'a ArgParser<'a>, - ) -> impl IntoIterator<Item = Self::Item> + 'a { - parse_unstable(cx, args, Self::PATH[0]).into_iter().zip(iter::repeat(cx.attr_span)) + fn extend<'c>( + cx: &'c mut AcceptContext<'_, '_, S>, + args: &'c ArgParser<'_>, + ) -> impl IntoIterator<Item = Self::Item> { + parse_unstable(cx, args, <Self as CombineAttributeParser<S>>::PATH[0]) + .into_iter() + .zip(iter::repeat(cx.attr_span)) } } pub(crate) struct AllowConstFnUnstableParser; -impl CombineAttributeParser for AllowConstFnUnstableParser { - const PATH: &'static [Symbol] = &[sym::rustc_allow_const_fn_unstable]; +impl<S: Stage> CombineAttributeParser<S> for AllowConstFnUnstableParser { + const PATH: &[Symbol] = &[sym::rustc_allow_const_fn_unstable]; type Item = Symbol; const CONVERT: ConvertFn<Self::Item> = AttributeKind::AllowConstFnUnstable; - fn extend<'a>( - cx: &'a AcceptContext<'a>, - args: &'a ArgParser<'a>, - ) -> impl IntoIterator<Item = Self::Item> + 'a { - parse_unstable(cx, args, Self::PATH[0]) + fn extend<'c>( + cx: &'c mut AcceptContext<'_, '_, S>, + args: &'c ArgParser<'_>, + ) -> impl IntoIterator<Item = Self::Item> + 'c { + parse_unstable(cx, args, <Self as CombineAttributeParser<S>>::PATH[0]) } } -fn parse_unstable<'a>( - cx: &AcceptContext<'_>, - args: &'a ArgParser<'a>, +fn parse_unstable<S: Stage>( + cx: &AcceptContext<'_, '_, S>, + args: &ArgParser<'_>, symbol: Symbol, ) -> impl IntoIterator<Item = Symbol> { let mut res = Vec::new(); diff --git a/compiler/rustc_attr_parsing/src/attributes/confusables.rs b/compiler/rustc_attr_parsing/src/attributes/confusables.rs index 6cff952fcf2..afd3c012f05 100644 --- a/compiler/rustc_attr_parsing/src/attributes/confusables.rs +++ b/compiler/rustc_attr_parsing/src/attributes/confusables.rs @@ -3,7 +3,7 @@ use rustc_span::{Span, Symbol, sym}; use thin_vec::ThinVec; use super::{AcceptMapping, AttributeParser}; -use crate::context::FinalizeContext; +use crate::context::{FinalizeContext, Stage}; use crate::session_diagnostics; #[derive(Default)] @@ -12,8 +12,8 @@ pub(crate) struct ConfusablesParser { first_span: Option<Span>, } -impl AttributeParser for ConfusablesParser { - const ATTRIBUTES: AcceptMapping<Self> = &[(&[sym::rustc_confusables], |this, cx, args| { +impl<S: Stage> AttributeParser<S> for ConfusablesParser { + const ATTRIBUTES: AcceptMapping<Self, S> = &[(&[sym::rustc_confusables], |this, cx, args| { let Some(list) = args.list() else { // FIXME(jdonszelmann): error when not a list? Bring validation code here. // NOTE: currently subsequent attributes are silently ignored using @@ -45,7 +45,7 @@ impl AttributeParser for ConfusablesParser { this.first_span.get_or_insert(cx.attr_span); })]; - fn finalize(self, _cx: &FinalizeContext<'_>) -> Option<AttributeKind> { + fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> { if self.confusables.is_empty() { return None; } diff --git a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs index 006c1fe3b9c..1faee41c2a9 100644 --- a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs +++ b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs @@ -1,17 +1,17 @@ use rustc_attr_data_structures::{AttributeKind, DeprecatedSince, Deprecation}; use rustc_span::{Span, Symbol, sym}; -use super::SingleAttributeParser; use super::util::parse_version; -use crate::context::AcceptContext; +use super::{AttributeOrder, OnDuplicate, SingleAttributeParser}; +use crate::context::{AcceptContext, Stage}; use crate::parser::ArgParser; use crate::session_diagnostics; use crate::session_diagnostics::UnsupportedLiteralReason; pub(crate) struct DeprecationParser; -fn get( - cx: &AcceptContext<'_>, +fn get<S: Stage>( + cx: &AcceptContext<'_, '_, S>, name: Symbol, param_span: Span, arg: &ArgParser<'_>, @@ -41,19 +41,12 @@ fn get( } } -impl SingleAttributeParser for DeprecationParser { - const PATH: &'static [Symbol] = &[sym::deprecated]; +impl<S: Stage> SingleAttributeParser<S> for DeprecationParser { + const PATH: &[Symbol] = &[sym::deprecated]; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst; + const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error; - fn on_duplicate(cx: &AcceptContext<'_>, first_span: Span) { - // FIXME(jdonszelmann): merge with errors from check_attrs.rs - cx.emit_err(session_diagnostics::UnusedMultiple { - this: cx.attr_span, - other: first_span, - name: sym::deprecated, - }); - } - - fn convert(cx: &AcceptContext<'_>, args: &ArgParser<'_>) -> Option<AttributeKind> { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> { let features = cx.features(); let mut since = None; diff --git a/compiler/rustc_attr_parsing/src/attributes/inline.rs b/compiler/rustc_attr_parsing/src/attributes/inline.rs new file mode 100644 index 00000000000..c7f82082c2e --- /dev/null +++ b/compiler/rustc_attr_parsing/src/attributes/inline.rs @@ -0,0 +1,97 @@ +// FIXME(jdonszelmann): merge these two parsers and error when both attributes are present here. +// note: need to model better how duplicate attr errors work when not using +// SingleAttributeParser which is what we have two of here. + +use rustc_attr_data_structures::lints::AttributeLintKind; +use rustc_attr_data_structures::{AttributeKind, InlineAttr}; +use rustc_feature::{AttributeTemplate, template}; +use rustc_span::{Symbol, sym}; + +use super::{AcceptContext, AttributeOrder, OnDuplicate}; +use crate::attributes::SingleAttributeParser; +use crate::context::Stage; +use crate::parser::ArgParser; + +pub(crate) struct InlineParser; + +impl<S: Stage> SingleAttributeParser<S> for InlineParser { + const PATH: &'static [Symbol] = &[sym::inline]; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepLast; + const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError; + const TEMPLATE: AttributeTemplate = template!(Word, List: "always|never"); + + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> { + match args { + ArgParser::NoArgs => Some(AttributeKind::Inline(InlineAttr::Hint, cx.attr_span)), + ArgParser::List(list) => { + let Some(l) = list.single() else { + cx.expected_single_argument(list.span); + return None; + }; + + match l.meta_item().and_then(|i| i.word_without_args().map(|i| i.name)) { + Some(sym::always) => { + Some(AttributeKind::Inline(InlineAttr::Always, cx.attr_span)) + } + Some(sym::never) => { + Some(AttributeKind::Inline(InlineAttr::Never, cx.attr_span)) + } + _ => { + cx.expected_specific_argument(l.span(), vec!["always", "never"]); + return None; + } + } + } + ArgParser::NameValue(_) => { + let suggestions = + <Self as SingleAttributeParser<S>>::TEMPLATE.suggestions(false, "inline"); + cx.emit_lint( + AttributeLintKind::IllFormedAttributeInput { suggestions }, + cx.attr_span, + ); + return None; + } + } + } +} + +pub(crate) struct RustcForceInlineParser; + +impl<S: Stage> SingleAttributeParser<S> for RustcForceInlineParser { + const PATH: &'static [Symbol] = &[sym::rustc_force_inline]; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepLast; + const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError; + const TEMPLATE: AttributeTemplate = template!(Word, List: "reason", NameValueStr: "reason"); + + fn convert(cx: &AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> { + let reason = match args { + ArgParser::NoArgs => None, + ArgParser::List(list) => { + let Some(l) = list.single() else { + cx.expected_single_argument(list.span); + return None; + }; + + let Some(reason) = l.lit().and_then(|i| i.kind.str()) else { + cx.expected_string_literal(l.span()); + return None; + }; + + Some(reason) + } + ArgParser::NameValue(v) => { + let Some(reason) = v.value_as_str() else { + cx.expected_string_literal(v.value_span); + return None; + }; + + Some(reason) + } + }; + + Some(AttributeKind::Inline( + InlineAttr::Force { attr_span: cx.attr_span, reason }, + cx.attr_span, + )) + } +} diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index bf18e10e19f..caf55e6685e 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -12,16 +12,18 @@ //! - [`CombineAttributeParser`]: makes it easy to implement an attribute which should combine the //! contents of attributes, if an attribute appear multiple times in a list //! -//! Attributes should be added to [`ATTRIBUTE_MAPPING`](crate::context::ATTRIBUTE_MAPPING) to be parsed. +//! Attributes should be added to `crate::context::ATTRIBUTE_PARSERS` to be parsed. use std::marker::PhantomData; use rustc_attr_data_structures::AttributeKind; +use rustc_attr_data_structures::lints::AttributeLintKind; use rustc_span::{Span, Symbol}; use thin_vec::ThinVec; -use crate::context::{AcceptContext, FinalizeContext}; +use crate::context::{AcceptContext, FinalizeContext, Stage}; use crate::parser::ArgParser; +use crate::session_diagnostics::UnusedMultiple; pub(crate) mod allow_unstable; pub(crate) mod cfg; @@ -32,8 +34,8 @@ pub(crate) mod stability; pub(crate) mod transparency; pub(crate) mod util; -type AcceptFn<T> = fn(&mut T, &AcceptContext<'_>, &ArgParser<'_>); -type AcceptMapping<T> = &'static [(&'static [Symbol], AcceptFn<T>)]; +type AcceptFn<T, S> = for<'sess> fn(&mut T, &mut AcceptContext<'_, 'sess, S>, &ArgParser<'_>); +type AcceptMapping<T, S> = &'static [(&'static [Symbol], AcceptFn<T, S>)]; /// An [`AttributeParser`] is a type which searches for syntactic attributes. /// @@ -51,15 +53,24 @@ type AcceptMapping<T> = &'static [(&'static [Symbol], AcceptFn<T>)]; /// whether it has seen the attribute it has been looking for. /// /// The state machine is automatically reset to parse attributes on the next item. -pub(crate) trait AttributeParser: Default + 'static { +/// +/// For a simpler attribute parsing interface, consider using [`SingleAttributeParser`] +/// or [`CombineAttributeParser`] instead. +pub(crate) trait AttributeParser<S: Stage>: Default + 'static { /// The symbols for the attributes that this parser is interested in. /// /// If an attribute has this symbol, the `accept` function will be called on it. - const ATTRIBUTES: AcceptMapping<Self>; + const ATTRIBUTES: AcceptMapping<Self, S>; /// The parser has gotten a chance to accept the attributes on an item, /// here it can produce an attribute. - fn finalize(self, cx: &FinalizeContext<'_>) -> Option<AttributeKind>; + /// + /// All finalize methods of all parsers are unconditionally called. + /// This means you can't unconditionally return `Some` here, + /// that'd be equivalent to unconditionally applying an attribute to + /// every single syntax item that could have attributes applied to it. + /// Your accept mappings should determine whether this returns something. + fn finalize(self, cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind>; } /// Alternative to [`AttributeParser`] that automatically handles state management. @@ -71,43 +82,130 @@ pub(crate) trait AttributeParser: Default + 'static { /// /// [`SingleAttributeParser`] can only convert attributes one-to-one, and cannot combine multiple /// attributes together like is necessary for `#[stable()]` and `#[unstable()]` for example. -pub(crate) trait SingleAttributeParser: 'static { - const PATH: &'static [Symbol]; - - /// Called when a duplicate attribute is found. - /// - /// `first_span` is the span of the first occurrence of this attribute. - // FIXME(jdonszelmann): default error - fn on_duplicate(cx: &AcceptContext<'_>, first_span: Span); +pub(crate) trait SingleAttributeParser<S: Stage>: 'static { + const PATH: &[Symbol]; + const ATTRIBUTE_ORDER: AttributeOrder; + const ON_DUPLICATE: OnDuplicate<S>; /// Converts a single syntactical attribute to a single semantic attribute, or [`AttributeKind`] - fn convert(cx: &AcceptContext<'_>, args: &ArgParser<'_>) -> Option<AttributeKind>; + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind>; } -pub(crate) struct Single<T: SingleAttributeParser>(PhantomData<T>, Option<(AttributeKind, Span)>); +pub(crate) struct Single<T: SingleAttributeParser<S>, S: Stage>( + PhantomData<(S, T)>, + Option<(AttributeKind, Span)>, +); -impl<T: SingleAttributeParser> Default for Single<T> { +impl<T: SingleAttributeParser<S>, S: Stage> Default for Single<T, S> { fn default() -> Self { Self(Default::default(), Default::default()) } } -impl<T: SingleAttributeParser> AttributeParser for Single<T> { - const ATTRIBUTES: AcceptMapping<Self> = &[(T::PATH, |group: &mut Single<T>, cx, args| { - if let Some((_, s)) = group.1 { - T::on_duplicate(cx, s); - return; - } +impl<T: SingleAttributeParser<S>, S: Stage> AttributeParser<S> for Single<T, S> { + const ATTRIBUTES: AcceptMapping<Self, S> = + &[(T::PATH, |group: &mut Single<T, S>, cx, args| { + if let Some(pa) = T::convert(cx, args) { + match T::ATTRIBUTE_ORDER { + // keep the first and report immediately. ignore this attribute + AttributeOrder::KeepFirst => { + if let Some((_, unused)) = group.1 { + T::ON_DUPLICATE.exec::<T>(cx, cx.attr_span, unused); + return; + } + } + // keep the new one and warn about the previous, + // then replace + AttributeOrder::KeepLast => { + if let Some((_, used)) = group.1 { + T::ON_DUPLICATE.exec::<T>(cx, used, cx.attr_span); + } + } + } + + group.1 = Some((pa, cx.attr_span)); + } + })]; + + fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> { + Some(self.1?.0) + } +} - if let Some(pa) = T::convert(cx, args) { - group.1 = Some((pa, cx.attr_span)); - } - })]; +// FIXME(jdonszelmann): logic is implemented but the attribute parsers needing +// them will be merged in another PR +#[allow(unused)] +pub(crate) enum OnDuplicate<S: Stage> { + /// Give a default warning + Warn, - fn finalize(self, _cx: &FinalizeContext<'_>) -> Option<AttributeKind> { - Some(self.1?.0) + /// Duplicates will be a warning, with a note that this will be an error in the future. + WarnButFutureError, + + /// Give a default error + Error, + + /// Ignore duplicates + Ignore, + + /// Custom function called when a duplicate attribute is found. + /// + /// - `unused` is the span of the attribute that was unused or bad because of some + /// duplicate reason (see [`AttributeOrder`]) + /// - `used` is the span of the attribute that was used in favor of the unused attribute + Custom(fn(cx: &AcceptContext<'_, '_, S>, used: Span, unused: Span)), +} + +impl<S: Stage> OnDuplicate<S> { + fn exec<P: SingleAttributeParser<S>>( + &self, + cx: &mut AcceptContext<'_, '_, S>, + used: Span, + unused: Span, + ) { + match self { + OnDuplicate::Warn => cx.emit_lint( + AttributeLintKind::UnusedDuplicate { this: unused, other: used, warning: false }, + unused, + ), + OnDuplicate::WarnButFutureError => cx.emit_lint( + AttributeLintKind::UnusedDuplicate { this: unused, other: used, warning: true }, + unused, + ), + OnDuplicate::Error => { + cx.emit_err(UnusedMultiple { + this: used, + other: unused, + name: Symbol::intern( + &P::PATH.into_iter().map(|i| i.to_string()).collect::<Vec<_>>().join(".."), + ), + }); + } + OnDuplicate::Ignore => {} + OnDuplicate::Custom(f) => f(cx, used, unused), + } } } +// +// FIXME(jdonszelmann): logic is implemented but the attribute parsers needing +// them will be merged in another PR +#[allow(unused)] +pub(crate) enum AttributeOrder { + /// Duplicates after the first attribute will be an error. + /// + /// This should be used where duplicates would be ignored, but carry extra + /// meaning that could cause confusion. For example, `#[stable(since="1.0")] + /// #[stable(since="2.0")]`, which version should be used for `stable`? + KeepFirst, + + /// Duplicates preceding the last instance of the attribute will be a + /// warning, with a note that this will be an error in the future. + /// + /// This is the same as `FutureWarnFollowing`, except the last attribute is + /// the one that is "used". Ideally these can eventually migrate to + /// `ErrorPreceding`. + KeepLast, +} type ConvertFn<E> = fn(ThinVec<E>) -> AttributeKind; @@ -118,35 +216,35 @@ type ConvertFn<E> = fn(ThinVec<E>) -> AttributeKind; /// /// [`CombineAttributeParser`] can only convert a single kind of attribute, and cannot combine multiple /// attributes together like is necessary for `#[stable()]` and `#[unstable()]` for example. -pub(crate) trait CombineAttributeParser: 'static { - const PATH: &'static [Symbol]; +pub(crate) trait CombineAttributeParser<S: Stage>: 'static { + const PATH: &[rustc_span::Symbol]; type Item; const CONVERT: ConvertFn<Self::Item>; /// Converts a single syntactical attribute to a number of elements of the semantic attribute, or [`AttributeKind`] - fn extend<'a>( - cx: &'a AcceptContext<'a>, - args: &'a ArgParser<'a>, - ) -> impl IntoIterator<Item = Self::Item> + 'a; + fn extend<'c>( + cx: &'c mut AcceptContext<'_, '_, S>, + args: &'c ArgParser<'_>, + ) -> impl IntoIterator<Item = Self::Item> + 'c; } -pub(crate) struct Combine<T: CombineAttributeParser>( - PhantomData<T>, - ThinVec<<T as CombineAttributeParser>::Item>, +pub(crate) struct Combine<T: CombineAttributeParser<S>, S: Stage>( + PhantomData<(S, T)>, + ThinVec<<T as CombineAttributeParser<S>>::Item>, ); -impl<T: CombineAttributeParser> Default for Combine<T> { +impl<T: CombineAttributeParser<S>, S: Stage> Default for Combine<T, S> { fn default() -> Self { Self(Default::default(), Default::default()) } } -impl<T: CombineAttributeParser> AttributeParser for Combine<T> { - const ATTRIBUTES: AcceptMapping<Self> = - &[(T::PATH, |group: &mut Combine<T>, cx, args| group.1.extend(T::extend(cx, args)))]; +impl<T: CombineAttributeParser<S>, S: Stage> AttributeParser<S> for Combine<T, S> { + const ATTRIBUTES: AcceptMapping<Self, S> = + &[(T::PATH, |group: &mut Combine<T, S>, cx, args| group.1.extend(T::extend(cx, args)))]; - fn finalize(self, _cx: &FinalizeContext<'_>) -> Option<AttributeKind> { + fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> { if self.1.is_empty() { None } else { Some(T::CONVERT(self.1)) } } } diff --git a/compiler/rustc_attr_parsing/src/attributes/repr.rs b/compiler/rustc_attr_parsing/src/attributes/repr.rs index 69316541e19..753b2366b41 100644 --- a/compiler/rustc_attr_parsing/src/attributes/repr.rs +++ b/compiler/rustc_attr_parsing/src/attributes/repr.rs @@ -4,7 +4,7 @@ use rustc_attr_data_structures::{AttributeKind, IntType, ReprAttr}; use rustc_span::{DUMMY_SP, Span, Symbol, sym}; use super::{CombineAttributeParser, ConvertFn}; -use crate::context::AcceptContext; +use crate::context::{AcceptContext, Stage}; use crate::parser::{ArgParser, MetaItemListParser, MetaItemParser}; use crate::session_diagnostics; use crate::session_diagnostics::IncorrectReprFormatGenericCause; @@ -19,15 +19,15 @@ use crate::session_diagnostics::IncorrectReprFormatGenericCause; // FIXME(jdonszelmann): is a vec the right representation here even? isn't it just a struct? pub(crate) struct ReprParser; -impl CombineAttributeParser for ReprParser { +impl<S: Stage> CombineAttributeParser<S> for ReprParser { type Item = (ReprAttr, Span); - const PATH: &'static [Symbol] = &[sym::repr]; + const PATH: &[Symbol] = &[sym::repr]; const CONVERT: ConvertFn<Self::Item> = AttributeKind::Repr; - fn extend<'a>( - cx: &'a AcceptContext<'a>, - args: &'a ArgParser<'a>, - ) -> impl IntoIterator<Item = Self::Item> + 'a { + fn extend<'c>( + cx: &'c mut AcceptContext<'_, '_, S>, + args: &'c ArgParser<'_>, + ) -> impl IntoIterator<Item = Self::Item> + 'c { let mut reprs = Vec::new(); let Some(list) = args.list() else { @@ -91,7 +91,10 @@ fn int_type_of_word(s: Symbol) -> Option<IntType> { } } -fn parse_repr(cx: &AcceptContext<'_>, param: &MetaItemParser<'_>) -> Option<ReprAttr> { +fn parse_repr<S: Stage>( + cx: &AcceptContext<'_, '_, S>, + param: &MetaItemParser<'_>, +) -> Option<ReprAttr> { use ReprAttr::*; // FIXME(jdonszelmann): invert the parsing here to match on the word first and then the @@ -180,8 +183,8 @@ enum AlignKind { Align, } -fn parse_repr_align( - cx: &AcceptContext<'_>, +fn parse_repr_align<S: Stage>( + cx: &AcceptContext<'_, '_, S>, list: &MetaItemListParser<'_>, param_span: Span, align_kind: AlignKind, diff --git a/compiler/rustc_attr_parsing/src/attributes/stability.rs b/compiler/rustc_attr_parsing/src/attributes/stability.rs index ce69a54513d..6589a51db2b 100644 --- a/compiler/rustc_attr_parsing/src/attributes/stability.rs +++ b/compiler/rustc_attr_parsing/src/attributes/stability.rs @@ -8,8 +8,8 @@ use rustc_errors::ErrorGuaranteed; use rustc_span::{Span, Symbol, sym}; use super::util::parse_version; -use super::{AcceptMapping, AttributeParser, SingleAttributeParser}; -use crate::context::{AcceptContext, FinalizeContext}; +use super::{AcceptMapping, AttributeOrder, AttributeParser, OnDuplicate, SingleAttributeParser}; +use crate::context::{AcceptContext, FinalizeContext, Stage}; use crate::parser::{ArgParser, MetaItemParser}; use crate::session_diagnostics::{self, UnsupportedLiteralReason}; @@ -31,7 +31,7 @@ pub(crate) struct StabilityParser { impl StabilityParser { /// Checks, and emits an error when a stability (or unstability) was already set, which would be a duplicate. - fn check_duplicate(&self, cx: &AcceptContext<'_>) -> bool { + fn check_duplicate<S: Stage>(&self, cx: &AcceptContext<'_, '_, S>) -> bool { if let Some((_, _)) = self.stability { cx.emit_err(session_diagnostics::MultipleStabilityLevels { span: cx.attr_span }); true @@ -41,8 +41,8 @@ impl StabilityParser { } } -impl AttributeParser for StabilityParser { - const ATTRIBUTES: AcceptMapping<Self> = &[ +impl<S: Stage> AttributeParser<S> for StabilityParser { + const ATTRIBUTES: AcceptMapping<Self, S> = &[ (&[sym::stable], |this, cx, args| { reject_outside_std!(cx); if !this.check_duplicate(cx) @@ -65,7 +65,7 @@ impl AttributeParser for StabilityParser { }), ]; - fn finalize(mut self, cx: &FinalizeContext<'_>) -> Option<AttributeKind> { + fn finalize(mut self, cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> { if let Some(atum) = self.allowed_through_unstable_modules { if let Some(( Stability { @@ -95,8 +95,8 @@ pub(crate) struct BodyStabilityParser { stability: Option<(DefaultBodyStability, Span)>, } -impl AttributeParser for BodyStabilityParser { - const ATTRIBUTES: AcceptMapping<Self> = +impl<S: Stage> AttributeParser<S> for BodyStabilityParser { + const ATTRIBUTES: AcceptMapping<Self, S> = &[(&[sym::rustc_default_body_unstable], |this, cx, args| { reject_outside_std!(cx); if this.stability.is_some() { @@ -107,7 +107,7 @@ impl AttributeParser for BodyStabilityParser { } })]; - fn finalize(self, _cx: &FinalizeContext<'_>) -> Option<AttributeKind> { + fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> { let (stability, span) = self.stability?; Some(AttributeKind::BodyStability { stability, span }) @@ -116,13 +116,12 @@ impl AttributeParser for BodyStabilityParser { pub(crate) struct ConstStabilityIndirectParser; // FIXME(jdonszelmann): single word attribute group when we have these -impl SingleAttributeParser for ConstStabilityIndirectParser { - const PATH: &'static [Symbol] = &[sym::rustc_const_stable_indirect]; +impl<S: Stage> SingleAttributeParser<S> for ConstStabilityIndirectParser { + const PATH: &[Symbol] = &[sym::rustc_const_stable_indirect]; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst; + const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Ignore; - // ignore - fn on_duplicate(_cx: &AcceptContext<'_>, _first_span: Span) {} - - fn convert(_cx: &AcceptContext<'_>, _args: &ArgParser<'_>) -> Option<AttributeKind> { + fn convert(_cx: &mut AcceptContext<'_, '_, S>, _args: &ArgParser<'_>) -> Option<AttributeKind> { Some(AttributeKind::ConstStabilityIndirect) } } @@ -135,7 +134,7 @@ pub(crate) struct ConstStabilityParser { impl ConstStabilityParser { /// Checks, and emits an error when a stability (or unstability) was already set, which would be a duplicate. - fn check_duplicate(&self, cx: &AcceptContext<'_>) -> bool { + fn check_duplicate<S: Stage>(&self, cx: &AcceptContext<'_, '_, S>) -> bool { if let Some((_, _)) = self.stability { cx.emit_err(session_diagnostics::MultipleStabilityLevels { span: cx.attr_span }); true @@ -145,8 +144,8 @@ impl ConstStabilityParser { } } -impl AttributeParser for ConstStabilityParser { - const ATTRIBUTES: AcceptMapping<Self> = &[ +impl<S: Stage> AttributeParser<S> for ConstStabilityParser { + const ATTRIBUTES: AcceptMapping<Self, S> = &[ (&[sym::rustc_const_stable], |this, cx, args| { reject_outside_std!(cx); @@ -176,7 +175,7 @@ impl AttributeParser for ConstStabilityParser { }), ]; - fn finalize(mut self, cx: &FinalizeContext<'_>) -> Option<AttributeKind> { + fn finalize(mut self, cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> { if self.promotable { if let Some((ref mut stab, _)) = self.stability { stab.promotable = true; @@ -196,8 +195,8 @@ impl AttributeParser for ConstStabilityParser { /// /// Emits an error when either the option was already Some, or the arguments weren't of form /// `name = value` -fn insert_value_into_option_or_error( - cx: &AcceptContext<'_>, +fn insert_value_into_option_or_error<S: Stage>( + cx: &AcceptContext<'_, '_, S>, param: &MetaItemParser<'_>, item: &mut Option<Symbol>, ) -> Option<()> { @@ -223,8 +222,8 @@ fn insert_value_into_option_or_error( /// Read the content of a `stable`/`rustc_const_stable` attribute, and return the feature name and /// its stability information. -pub(crate) fn parse_stability( - cx: &AcceptContext<'_>, +pub(crate) fn parse_stability<S: Stage>( + cx: &AcceptContext<'_, '_, S>, args: &ArgParser<'_>, ) -> Option<(Symbol, StabilityLevel)> { let mut feature = None; @@ -289,8 +288,8 @@ pub(crate) fn parse_stability( // Read the content of a `unstable`/`rustc_const_unstable`/`rustc_default_body_unstable` /// attribute, and return the feature name and its stability information. -pub(crate) fn parse_unstability( - cx: &AcceptContext<'_>, +pub(crate) fn parse_unstability<S: Stage>( + cx: &AcceptContext<'_, '_, S>, args: &ArgParser<'_>, ) -> Option<(Symbol, StabilityLevel)> { let mut feature = None; @@ -299,6 +298,7 @@ pub(crate) fn parse_unstability( let mut issue_num = None; let mut is_soft = false; let mut implied_by = None; + let mut old_name = None; for param in args.list()?.mixed() { let Some(param) = param.meta_item() else { cx.emit_err(session_diagnostics::UnsupportedLiteral { @@ -346,11 +346,12 @@ pub(crate) fn parse_unstability( Some(sym::implied_by) => { insert_value_into_option_or_error(cx, ¶m, &mut implied_by)? } + Some(sym::old_name) => insert_value_into_option_or_error(cx, ¶m, &mut old_name)?, _ => { cx.emit_err(session_diagnostics::UnknownMetaItem { span: param.span(), item: param.path().to_string(), - expected: &["feature", "reason", "issue", "soft", "implied_by"], + expected: &["feature", "reason", "issue", "soft", "implied_by", "old_name"], }); return None; } @@ -375,6 +376,7 @@ pub(crate) fn parse_unstability( issue: issue_num, is_soft, implied_by, + old_name, }; Some((feature, level)) } diff --git a/compiler/rustc_attr_parsing/src/attributes/transparency.rs b/compiler/rustc_attr_parsing/src/attributes/transparency.rs index d229fc09740..16ad9d03e50 100644 --- a/compiler/rustc_attr_parsing/src/attributes/transparency.rs +++ b/compiler/rustc_attr_parsing/src/attributes/transparency.rs @@ -1,8 +1,9 @@ use rustc_attr_data_structures::AttributeKind; use rustc_span::hygiene::Transparency; -use rustc_span::{Span, Symbol, sym}; +use rustc_span::{Symbol, sym}; -use super::{AcceptContext, SingleAttributeParser}; +use super::{AttributeOrder, OnDuplicate, SingleAttributeParser}; +use crate::context::{AcceptContext, Stage}; use crate::parser::ArgParser; pub(crate) struct TransparencyParser; @@ -10,14 +11,14 @@ pub(crate) struct TransparencyParser; // FIXME(jdonszelmann): make these proper diagnostics #[allow(rustc::untranslatable_diagnostic)] #[allow(rustc::diagnostic_outside_of_impl)] -impl SingleAttributeParser for TransparencyParser { - const PATH: &'static [Symbol] = &[sym::rustc_macro_transparency]; +impl<S: Stage> SingleAttributeParser<S> for TransparencyParser { + const PATH: &[Symbol] = &[sym::rustc_macro_transparency]; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst; + const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Custom(|cx, used, unused| { + cx.dcx().span_err(vec![used, unused], "multiple macro transparency attributes"); + }); - fn on_duplicate(cx: &crate::context::AcceptContext<'_>, first_span: Span) { - cx.dcx().span_err(vec![first_span, cx.attr_span], "multiple macro transparency attributes"); - } - - fn convert(cx: &AcceptContext<'_>, args: &ArgParser<'_>) -> Option<AttributeKind> { + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> { match args.name_value().and_then(|nv| nv.value_as_str()) { Some(sym::transparent) => Some(Transparency::Transparent), Some(sym::semiopaque | sym::semitransparent) => Some(Transparency::SemiOpaque), diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index c02760d830c..47f72232828 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -1,13 +1,17 @@ use std::cell::RefCell; use std::collections::BTreeMap; -use std::ops::Deref; +use std::marker::PhantomData; +use std::ops::{Deref, DerefMut}; use std::sync::LazyLock; +use private::Sealed; use rustc_ast as ast; +use rustc_ast::NodeId; use rustc_attr_data_structures::AttributeKind; +use rustc_attr_data_structures::lints::{AttributeLint, AttributeLintKind}; use rustc_errors::{DiagCtxtHandle, Diagnostic}; use rustc_feature::Features; -use rustc_hir::{AttrArgs, AttrItem, AttrPath, Attribute, HashIgnoredAttrId}; +use rustc_hir::{AttrArgs, AttrItem, AttrPath, Attribute, HashIgnoredAttrId, HirId}; use rustc_session::Session; use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym}; @@ -22,20 +26,40 @@ use crate::attributes::transparency::TransparencyParser; use crate::attributes::{AttributeParser as _, Combine, Single}; use crate::parser::{ArgParser, MetaItemParser}; -macro_rules! attribute_groups { +macro_rules! group_type { + ($stage: ty) => { + LazyLock<( + BTreeMap<&'static [Symbol], Box<dyn for<'sess, 'a> Fn(&mut AcceptContext<'_, 'sess, $stage>, &ArgParser<'a>) + Send + Sync>>, + Vec<Box<dyn Send + Sync + Fn(&mut FinalizeContext<'_, '_, $stage>) -> Option<AttributeKind>>> + )> + }; +} + +macro_rules! attribute_parsers { ( pub(crate) static $name: ident = [$($names: ty),* $(,)?]; ) => { - type Accepts = BTreeMap< - &'static [Symbol], - Box<dyn Send + Sync + Fn(&AcceptContext<'_>, &ArgParser<'_>)> - >; - type Finalizes = Vec< - Box<dyn Send + Sync + Fn(&FinalizeContext<'_>) -> Option<AttributeKind>> - >; - pub(crate) static $name: LazyLock<(Accepts, Finalizes)> = LazyLock::new(|| { - let mut accepts = Accepts::new(); - let mut finalizes = Finalizes::new(); + mod early { + use super::*; + type Combine<T> = super::Combine<T, Early>; + type Single<T> = super::Single<T, Early>; + + attribute_parsers!(@[Early] pub(crate) static $name = [$($names),*];); + } + mod late { + use super::*; + type Combine<T> = super::Combine<T, Late>; + type Single<T> = super::Single<T, Late>; + + attribute_parsers!(@[Late] pub(crate) static $name = [$($names),*];); + } + }; + ( + @[$ty: ty] pub(crate) static $name: ident = [$($names: ty),* $(,)?]; + ) => { + pub(crate) static $name: group_type!($ty) = LazyLock::new(|| { + let mut accepts = BTreeMap::<_, Box<dyn for<'sess, 'a> Fn(&mut AcceptContext<'_, 'sess, $ty>, &ArgParser<'a>) + Send + Sync>>::new(); + let mut finalizes = Vec::<Box<dyn Send + Sync + Fn(&mut FinalizeContext<'_, '_, $ty>) -> Option<AttributeKind>>>::new(); $( { thread_local! { @@ -62,9 +86,8 @@ macro_rules! attribute_groups { }); }; } - -attribute_groups!( - pub(crate) static ATTRIBUTE_MAPPING = [ +attribute_parsers!( + pub(crate) static ATTRIBUTE_PARSERS = [ // tidy-alphabetical-start BodyStabilityParser, ConfusablesParser, @@ -86,30 +109,84 @@ attribute_groups!( ]; ); +mod private { + pub trait Sealed {} + impl Sealed for super::Early {} + impl Sealed for super::Late {} +} + +// allow because it's a sealed trait +#[allow(private_interfaces)] +pub trait Stage: Sized + 'static + Sealed { + type Id: Copy; + + fn parsers() -> &'static group_type!(Self); + + fn emit_err<'sess>(sess: &'sess Session, diag: impl for<'x> Diagnostic<'x>) -> ErrorGuaranteed; +} + +// allow because it's a sealed trait +#[allow(private_interfaces)] +impl Stage for Early { + type Id = NodeId; + + fn parsers() -> &'static group_type!(Self) { + &early::ATTRIBUTE_PARSERS + } + fn emit_err<'sess>(sess: &'sess Session, diag: impl for<'x> Diagnostic<'x>) -> ErrorGuaranteed { + sess.dcx().create_err(diag).delay_as_bug() + } +} + +// allow because it's a sealed trait +#[allow(private_interfaces)] +impl Stage for Late { + type Id = HirId; + + fn parsers() -> &'static group_type!(Self) { + &late::ATTRIBUTE_PARSERS + } + fn emit_err<'sess>(tcx: &'sess Session, diag: impl for<'x> Diagnostic<'x>) -> ErrorGuaranteed { + tcx.dcx().emit_err(diag) + } +} + +/// used when parsing attributes for miscelaneous things *before* ast lowering +pub struct Early; +/// used when parsing attributes during ast lowering +pub struct Late; + /// Context given to every attribute parser when accepting /// /// Gives [`AttributeParser`]s enough information to create errors, for example. -pub(crate) struct AcceptContext<'a> { - pub(crate) group_cx: &'a FinalizeContext<'a>, +pub(crate) struct AcceptContext<'f, 'sess, S: Stage> { + pub(crate) finalize_cx: FinalizeContext<'f, 'sess, S>, /// The span of the attribute currently being parsed pub(crate) attr_span: Span, } -impl<'a> AcceptContext<'a> { - pub(crate) fn emit_err(&self, diag: impl Diagnostic<'a>) -> ErrorGuaranteed { - if self.limit_diagnostics { - self.dcx().create_err(diag).delay_as_bug() - } else { - self.dcx().emit_err(diag) - } +impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { + pub(crate) fn emit_err(&self, diag: impl for<'x> Diagnostic<'x>) -> ErrorGuaranteed { + S::emit_err(&self.sess, diag) + } + + pub(crate) fn emit_lint(&mut self, lint: AttributeLintKind, span: Span) { + let id = self.target_id; + (self.emit_lint)(AttributeLint { id, span, kind: lint }); } } -impl<'a> Deref for AcceptContext<'a> { - type Target = FinalizeContext<'a>; +impl<'f, 'sess, S: Stage> Deref for AcceptContext<'f, 'sess, S> { + type Target = FinalizeContext<'f, 'sess, S>; fn deref(&self) -> &Self::Target { - &self.group_cx + &self.finalize_cx + } +} + +impl<'f, 'sess, S: Stage> DerefMut for AcceptContext<'f, 'sess, S> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.finalize_cx } } @@ -117,19 +194,29 @@ impl<'a> Deref for AcceptContext<'a> { /// /// Gives [`AttributeParser`](crate::attributes::AttributeParser)s enough information to create /// errors, for example. -pub(crate) struct FinalizeContext<'a> { +pub(crate) struct FinalizeContext<'p, 'sess, S: Stage> { /// The parse context, gives access to the session and the /// diagnostics context. - pub(crate) cx: &'a AttributeParser<'a>, + pub(crate) cx: &'p mut AttributeParser<'sess, S>, /// The span of the syntactical component this attribute was applied to pub(crate) target_span: Span, + /// The id ([`NodeId`] if `S` is `Early`, [`HirId`] if `S` is `Late`) of the syntactical component this attribute was applied to + pub(crate) target_id: S::Id, + + pub(crate) emit_lint: &'p mut dyn FnMut(AttributeLint<S::Id>), } -impl<'a> Deref for FinalizeContext<'a> { - type Target = AttributeParser<'a>; +impl<'p, 'sess: 'p, S: Stage> Deref for FinalizeContext<'p, 'sess, S> { + type Target = AttributeParser<'sess, S>; fn deref(&self) -> &Self::Target { - &self.cx + self.cx + } +} + +impl<'p, 'sess: 'p, S: Stage> DerefMut for FinalizeContext<'p, 'sess, S> { + fn deref_mut(&mut self) -> &mut Self::Target { + self.cx } } @@ -141,23 +228,20 @@ pub enum OmitDoc { /// Context created once, for example as part of the ast lowering /// context, through which all attributes can be lowered. -pub struct AttributeParser<'sess> { +pub struct AttributeParser<'sess, S: Stage = Late> { #[expect(dead_code)] // FIXME(jdonszelmann): needed later to verify we parsed all attributes tools: Vec<Symbol>, - sess: &'sess Session, features: Option<&'sess Features>, + sess: &'sess Session, + stage: PhantomData<S>, /// *Only* parse attributes with this symbol. /// /// Used in cases where we want the lowering infrastructure for parse just a single attribute. parse_only: Option<Symbol>, - - /// Can be used to instruct parsers to reduce the number of diagnostics it emits. - /// Useful when using `parse_limited` and you know the attr will be reparsed later. - pub(crate) limit_diagnostics: bool, } -impl<'sess> AttributeParser<'sess> { +impl<'sess> AttributeParser<'sess, Early> { /// This method allows you to parse attributes *before* you have access to features or tools. /// One example where this is necessary, is to parse `feature` attributes themselves for /// example. @@ -168,33 +252,53 @@ impl<'sess> AttributeParser<'sess> { /// /// To make sure use is limited, supply a `Symbol` you'd like to parse. Only attributes with /// that symbol are picked out of the list of instructions and parsed. Those are returned. + /// + /// No diagnostics will be emitted when parsing limited. Lints are not emitted at all, while + /// errors will be emitted as a delayed bugs. in other words, we *expect* attributes parsed + /// with `parse_limited` to be reparsed later during ast lowering where we *do* emit the errors pub fn parse_limited( sess: &'sess Session, attrs: &[ast::Attribute], sym: Symbol, target_span: Span, - limit_diagnostics: bool, + target_node_id: NodeId, ) -> Option<Attribute> { - let mut parsed = Self { - sess, + let mut p = Self { features: None, tools: Vec::new(), parse_only: Some(sym), - limit_diagnostics, - } - .parse_attribute_list(attrs, target_span, OmitDoc::Skip, std::convert::identity); - + sess, + stage: PhantomData, + }; + let mut parsed = p.parse_attribute_list( + attrs, + target_span, + target_node_id, + OmitDoc::Skip, + std::convert::identity, + |_lint| { + panic!("can't emit lints here for now (nothing uses this atm)"); + }, + ); assert!(parsed.len() <= 1); parsed.pop() } + pub fn new_early(sess: &'sess Session, features: &'sess Features, tools: Vec<Symbol>) -> Self { + Self { features: Some(features), tools, parse_only: None, sess, stage: PhantomData } + } +} + +impl<'sess> AttributeParser<'sess, Late> { pub fn new(sess: &'sess Session, features: &'sess Features, tools: Vec<Symbol>) -> Self { - Self { sess, features: Some(features), tools, parse_only: None, limit_diagnostics: false } + Self { features: Some(features), tools, parse_only: None, sess, stage: PhantomData } } +} +impl<'sess, S: Stage> AttributeParser<'sess, S> { pub(crate) fn sess(&self) -> &'sess Session { - self.sess + &self.sess } pub(crate) fn features(&self) -> &'sess Features { @@ -202,25 +306,25 @@ impl<'sess> AttributeParser<'sess> { } pub(crate) fn dcx(&self) -> DiagCtxtHandle<'sess> { - self.sess.dcx() + self.sess().dcx() } /// Parse a list of attributes. /// /// `target_span` is the span of the thing this list of attributes is applied to, /// and when `omit_doc` is set, doc attributes are filtered out. - pub fn parse_attribute_list<'a>( - &'a self, - attrs: &'a [ast::Attribute], + pub fn parse_attribute_list( + &mut self, + attrs: &[ast::Attribute], target_span: Span, + target_id: S::Id, omit_doc: OmitDoc, lower_span: impl Copy + Fn(Span) -> Span, + mut emit_lint: impl FnMut(AttributeLint<S::Id>), ) -> Vec<Attribute> { let mut attributes = Vec::new(); - let group_cx = FinalizeContext { cx: self, target_span }; - for attr in attrs { // If we're only looking for a single attribute, skip all the ones we don't care about. if let Some(expected) = self.parse_only { @@ -268,11 +372,18 @@ impl<'sess> AttributeParser<'sess> { let args = parser.args(); let parts = path.segments().map(|i| i.name).collect::<Vec<_>>(); - if let Some(accept) = ATTRIBUTE_MAPPING.0.get(parts.as_slice()) { - let cx = - AcceptContext { group_cx: &group_cx, attr_span: lower_span(attr.span) }; - - accept(&cx, &args) + if let Some(accept) = S::parsers().0.get(parts.as_slice()) { + let mut cx: AcceptContext<'_, 'sess, S> = AcceptContext { + finalize_cx: FinalizeContext { + cx: self, + target_span, + target_id, + emit_lint: &mut emit_lint, + }, + attr_span: lower_span(attr.span), + }; + + accept(&mut cx, args) } else { // If we're here, we must be compiling a tool attribute... Or someone // forgot to parse their fancy new attribute. Let's warn them in any case. @@ -302,8 +413,13 @@ impl<'sess> AttributeParser<'sess> { } let mut parsed_attributes = Vec::new(); - for f in &ATTRIBUTE_MAPPING.1 { - if let Some(attr) = f(&group_cx) { + for f in &S::parsers().1 { + if let Some(attr) = f(&mut FinalizeContext { + cx: self, + target_span, + target_id, + emit_lint: &mut emit_lint, + }) { parsed_attributes.push(Attribute::Parsed(attr)); } } diff --git a/compiler/rustc_attr_parsing/src/lib.rs b/compiler/rustc_attr_parsing/src/lib.rs index 15037e802ff..47eeb63bad3 100644 --- a/compiler/rustc_attr_parsing/src/lib.rs +++ b/compiler/rustc_attr_parsing/src/lib.rs @@ -85,7 +85,8 @@ #[macro_use] mod attributes; -mod context; +pub(crate) mod context; +mod lints; pub mod parser; mod session_diagnostics; @@ -93,6 +94,7 @@ pub use attributes::cfg::*; pub use attributes::util::{ find_crate_name, is_builtin_attr, is_doc_alias_attrs_contain_symbol, parse_version, }; -pub use context::{AttributeParser, OmitDoc}; +pub use context::{AttributeParser, Early, Late, OmitDoc}; +pub use lints::emit_attribute_lint; rustc_fluent_macro::fluent_messages! { "../messages.ftl" } diff --git a/compiler/rustc_attr_parsing/src/lints.rs b/compiler/rustc_attr_parsing/src/lints.rs new file mode 100644 index 00000000000..d0d112446b4 --- /dev/null +++ b/compiler/rustc_attr_parsing/src/lints.rs @@ -0,0 +1,19 @@ +use rustc_attr_data_structures::lints::{AttributeLint, AttributeLintKind}; +use rustc_errors::LintEmitter; +use rustc_hir::HirId; + +use crate::session_diagnostics; + +pub fn emit_attribute_lint<L: LintEmitter>(lint: &AttributeLint<HirId>, lint_emitter: L) { + let AttributeLint { id, span, kind } = lint; + + match kind { + &AttributeLintKind::UnusedDuplicate { this, other, warning } => lint_emitter + .emit_node_span_lint( + rustc_session::lint::builtin::UNUSED_ATTRIBUTES, + *id, + *span, + session_diagnostics::UnusedDuplicate { this, other, warning }, + ), + } +} diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs index e10e3b511db..1edbe3a9d27 100644 --- a/compiler/rustc_attr_parsing/src/parser.rs +++ b/compiler/rustc_attr_parsing/src/parser.rs @@ -115,7 +115,7 @@ impl<'a> ArgParser<'a> { } } - pub fn from_attr_args(value: &'a AttrArgs, dcx: DiagCtxtHandle<'a>) -> Self { + pub fn from_attr_args<'sess>(value: &'a AttrArgs, dcx: DiagCtxtHandle<'sess>) -> Self { match value { AttrArgs::Empty => Self::NoArgs, AttrArgs::Delimited(args) if args.delim == Delimiter::Parenthesis => { @@ -235,7 +235,7 @@ impl<'a> Debug for MetaItemParser<'a> { impl<'a> MetaItemParser<'a> { /// Create a new parser from a [`NormalAttr`], which is stored inside of any /// [`ast::Attribute`](rustc_ast::Attribute) - pub fn from_attr(attr: &'a NormalAttr, dcx: DiagCtxtHandle<'a>) -> Self { + pub fn from_attr<'sess>(attr: &'a NormalAttr, dcx: DiagCtxtHandle<'sess>) -> Self { Self { path: PathParser::Ast(&attr.item.path), args: ArgParser::from_attr_args(&attr.item.args, dcx), @@ -320,13 +320,13 @@ fn expr_to_lit(dcx: DiagCtxtHandle<'_>, expr: &Expr, span: Span) -> MetaItemLit } } -struct MetaItemListParserContext<'a> { +struct MetaItemListParserContext<'a, 'sess> { // the tokens inside the delimiters, so `#[some::attr(a b c)]` would have `a b c` inside inside_delimiters: Peekable<TokenStreamIter<'a>>, - dcx: DiagCtxtHandle<'a>, + dcx: DiagCtxtHandle<'sess>, } -impl<'a> MetaItemListParserContext<'a> { +impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> { fn done(&mut self) -> bool { self.inside_delimiters.peek().is_none() } @@ -507,11 +507,11 @@ pub struct MetaItemListParser<'a> { } impl<'a> MetaItemListParser<'a> { - fn new(delim: &'a DelimArgs, dcx: DiagCtxtHandle<'a>) -> MetaItemListParser<'a> { + fn new<'sess>(delim: &'a DelimArgs, dcx: DiagCtxtHandle<'sess>) -> Self { MetaItemListParser::new_tts(delim.tokens.iter(), delim.dspan.entire(), dcx) } - fn new_tts(tts: TokenStreamIter<'a>, span: Span, dcx: DiagCtxtHandle<'a>) -> Self { + fn new_tts<'sess>(tts: TokenStreamIter<'a>, span: Span, dcx: DiagCtxtHandle<'sess>) -> Self { MetaItemListParserContext { inside_delimiters: tts.peekable(), dcx }.parse(span) } diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index 2c434175b4b..7f847d3dd4c 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -3,7 +3,7 @@ use std::num::IntErrorKind; use rustc_ast as ast; use rustc_errors::codes::*; use rustc_errors::{Applicability, Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level}; -use rustc_macros::{Diagnostic, Subdiagnostic}; +use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_span::{Span, Symbol}; use crate::fluent_generated as fluent; @@ -451,6 +451,17 @@ pub(crate) struct UnusedMultiple { pub name: Symbol, } +#[derive(LintDiagnostic)] +#[diag(attr_parsing_unused_duplicate)] +pub(crate) struct UnusedDuplicate { + #[suggestion(code = "", applicability = "machine-applicable")] + pub this: Span, + #[note] + pub other: Span, + #[warning] + pub warning: bool, +} + #[derive(Diagnostic)] #[diag(attr_parsing_stability_outside_std, code = E0734)] pub(crate) struct StabilityOutsideStd { diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 1b4bb11d87b..34d36849939 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -3229,8 +3229,20 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { Applicability::MaybeIncorrect, ); } + + let mutability = if matches!(borrow.kind(), BorrowKind::Mut { .. }) { + "mut " + } else { + "" + }; + if !is_format_arguments_item { - let addition = format!("let binding = {};\n{}", s, " ".repeat(p)); + let addition = format!( + "let {}binding = {};\n{}", + mutability, + s, + " ".repeat(p) + ); err.multipart_suggestion_verbose( msg, vec![ diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs index a1c74672157..0a114467f43 100644 --- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs +++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs @@ -141,8 +141,11 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { } if !tcx.recursion_limit().value_within_limit(iteration) { + // This may actually be reachable. If so, we should convert + // this to a proper error/consider whether we should detect + // this somewhere else. bug!( - "FIXME(-Znext-solver): Overflowed when processing region obligations: {outlives_predicates:#?}" + "unexpected overflowed when processing region obligations: {outlives_predicates:#?}" ); } diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index 6dd3adf750d..d642851bb77 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -484,7 +484,7 @@ impl<'a> TraitDef<'a> { match item { Annotatable::Item(item) => { let is_packed = matches!( - AttributeParser::parse_limited(cx.sess, &item.attrs, sym::repr, item.span, true), + AttributeParser::parse_limited(cx.sess, &item.attrs, sym::repr, item.span, item.id), Some(Attribute::Parsed(AttributeKind::Repr(r))) if r.iter().any(|(x, _)| matches!(x, ReprPacked(..))) ); diff --git a/compiler/rustc_codegen_cranelift/example/mini_core.rs b/compiler/rustc_codegen_cranelift/example/mini_core.rs index 1dc799c0aee..012e4dbc3ec 100644 --- a/compiler/rustc_codegen_cranelift/example/mini_core.rs +++ b/compiler/rustc_codegen_cranelift/example/mini_core.rs @@ -644,9 +644,9 @@ pub mod intrinsics { #[rustc_intrinsic] pub unsafe fn size_of_val<T: ?::Sized>(val: *const T) -> usize; #[rustc_intrinsic] - pub fn min_align_of<T>() -> usize; + pub fn align_of<T>() -> usize; #[rustc_intrinsic] - pub unsafe fn min_align_of_val<T: ?::Sized>(val: *const T) -> usize; + pub unsafe fn align_of_val<T: ?::Sized>(val: *const T) -> usize; #[rustc_intrinsic] pub unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize); #[rustc_intrinsic] diff --git a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs index 93ca2e0e421..1499f948deb 100644 --- a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs +++ b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs @@ -204,11 +204,8 @@ fn main() { assert_eq!(intrinsics::size_of_val(a) as u8, 16); assert_eq!(intrinsics::size_of_val(&0u32) as u8, 4); - assert_eq!(intrinsics::min_align_of::<u16>() as u8, 2); - assert_eq!( - intrinsics::min_align_of_val(&a) as u8, - intrinsics::min_align_of::<&str>() as u8 - ); + assert_eq!(intrinsics::align_of::<u16>() as u8, 2); + assert_eq!(intrinsics::align_of_val(&a) as u8, intrinsics::align_of::<&str>() as u8); assert!(!intrinsics::needs_drop::<u8>()); assert!(!intrinsics::needs_drop::<[u8]>()); diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs index fe5b220117f..4c6fd907815 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs @@ -51,6 +51,11 @@ pub(crate) fn conv_to_call_conv( CanonAbi::Rust | CanonAbi::C => default_call_conv, CanonAbi::RustCold => CallConv::Cold, + // Functions with this calling convention can only be called from assembly, but it is + // possible to declare an `extern "custom"` block, so the backend still needs a calling + // convention for declaring foreign functions. + CanonAbi::Custom => default_call_conv, + CanonAbi::X86(x86_call) => match x86_call { X86Call::SysV64 => CallConv::SystemV, X86Call::Win64 => CallConv::WindowsFastcall, diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs index 1d1cf884e48..df5748c34d1 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs @@ -586,7 +586,7 @@ fn codegen_regular_intrinsic_call<'tcx>( let (size, _align) = crate::unsize::size_and_align_of(fx, layout, meta); ret.write_cvalue(fx, CValue::by_val(size, usize_layout)); } - sym::min_align_of_val => { + sym::align_of_val => { intrinsic_args!(fx, args => (ptr); intrinsic); let layout = fx.layout_of(generic_args.type_at(0)); @@ -613,7 +613,7 @@ fn codegen_regular_intrinsic_call<'tcx>( intrinsic_args!(fx, args => (vtable); intrinsic); let vtable = vtable.load_scalar(fx); - let align = crate::vtable::min_align_of_obj(fx, vtable); + let align = crate::vtable::align_of_obj(fx, vtable); ret.write_cvalue(fx, CValue::by_val(align, usize_layout)); } diff --git a/compiler/rustc_codegen_cranelift/src/unsize.rs b/compiler/rustc_codegen_cranelift/src/unsize.rs index 662546e4999..df60b05c463 100644 --- a/compiler/rustc_codegen_cranelift/src/unsize.rs +++ b/compiler/rustc_codegen_cranelift/src/unsize.rs @@ -212,7 +212,7 @@ pub(crate) fn size_and_align_of<'tcx>( // load size/align from vtable ( crate::vtable::size_of_obj(fx, info.unwrap()), - crate::vtable::min_align_of_obj(fx, info.unwrap()), + crate::vtable::align_of_obj(fx, info.unwrap()), ) } ty::Slice(_) | ty::Str => { diff --git a/compiler/rustc_codegen_cranelift/src/vtable.rs b/compiler/rustc_codegen_cranelift/src/vtable.rs index 05a8e3c3342..1fae56949bc 100644 --- a/compiler/rustc_codegen_cranelift/src/vtable.rs +++ b/compiler/rustc_codegen_cranelift/src/vtable.rs @@ -31,7 +31,7 @@ pub(crate) fn size_of_obj(fx: &mut FunctionCx<'_, '_, '_>, vtable: Value) -> Val ) } -pub(crate) fn min_align_of_obj(fx: &mut FunctionCx<'_, '_, '_>, vtable: Value) -> Value { +pub(crate) fn align_of_obj(fx: &mut FunctionCx<'_, '_, '_>, vtable: Value) -> Value { let usize_size = fx.layout_of(fx.tcx.types.usize).size.bytes() as usize; fx.bcx.ins().load( fx.pointer_type, diff --git a/compiler/rustc_codegen_gcc/example/mini_core.rs b/compiler/rustc_codegen_gcc/example/mini_core.rs index d1d8e8fd5bc..aca1f0080ef 100644 --- a/compiler/rustc_codegen_gcc/example/mini_core.rs +++ b/compiler/rustc_codegen_gcc/example/mini_core.rs @@ -655,9 +655,9 @@ pub mod intrinsics { #[rustc_intrinsic] pub unsafe fn size_of_val<T: ?::Sized>(val: *const T) -> usize; #[rustc_intrinsic] - pub fn min_align_of<T>() -> usize; + pub fn align_of<T>() -> usize; #[rustc_intrinsic] - pub unsafe fn min_align_of_val<T: ?::Sized>(val: *const T) -> usize; + pub unsafe fn align_of_val<T: ?::Sized>(val: *const T) -> usize; #[rustc_intrinsic] pub unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize); #[rustc_intrinsic] diff --git a/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs b/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs index 4cbe66c5e4c..c3bd62e5897 100644 --- a/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs +++ b/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs @@ -153,7 +153,7 @@ fn main() { let slice = &[0, 1] as &[i32]; let slice_ptr = slice as *const [i32] as *const i32; - let align = intrinsics::min_align_of::<*const i32>(); + let align = intrinsics::align_of::<*const i32>(); assert_eq!(slice_ptr as usize % align, 0); //return; @@ -194,8 +194,8 @@ fn main() { assert_eq!(intrinsics::size_of_val(a) as u8, 8); assert_eq!(intrinsics::size_of_val(&0u32) as u8, 4); - assert_eq!(intrinsics::min_align_of::<u16>() as u8, 2); - assert_eq!(intrinsics::min_align_of_val(&a) as u8, intrinsics::min_align_of::<&str>() as u8); + assert_eq!(intrinsics::align_of::<u16>() as u8, 2); + assert_eq!(intrinsics::align_of_val(&a) as u8, intrinsics::align_of::<&str>() as u8); assert!(!intrinsics::needs_drop::<u8>()); assert!(!intrinsics::needs_drop::<[u8]>()); diff --git a/compiler/rustc_codegen_gcc/messages.ftl b/compiler/rustc_codegen_gcc/messages.ftl index 546bfc87b68..18a8a5a1e04 100644 --- a/compiler/rustc_codegen_gcc/messages.ftl +++ b/compiler/rustc_codegen_gcc/messages.ftl @@ -2,9 +2,6 @@ codegen_gcc_unknown_ctarget_feature_prefix = unknown feature specified for `-Ctarget-feature`: `{$feature}` .note = features must begin with a `+` to enable or `-` to disable it -codegen_gcc_forbidden_ctarget_feature = - target feature `{$feature}` cannot be toggled with `-Ctarget-feature`: {$reason} - codegen_gcc_unwinding_inline_asm = GCC backend does not support unwinding from inline asm @@ -26,10 +23,6 @@ codegen_gcc_unknown_ctarget_feature = .possible_feature = you might have meant: `{$rust_feature}` .consider_filing_feature_request = consider filing a feature request -codegen_gcc_unstable_ctarget_feature = - unstable feature specified for `-Ctarget-feature`: `{$feature}` - .note = this feature is not stably supported; its behavior can change in the future - codegen_gcc_missing_features = add the missing features in a `target_feature` attribute diff --git a/compiler/rustc_codegen_gcc/src/abi.rs b/compiler/rustc_codegen_gcc/src/abi.rs index 3d0c258f576..08f3d281904 100644 --- a/compiler/rustc_codegen_gcc/src/abi.rs +++ b/compiler/rustc_codegen_gcc/src/abi.rs @@ -239,12 +239,16 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> { pub fn conv_to_fn_attribute<'gcc>(conv: CanonAbi, arch: &str) -> Option<FnAttribute<'gcc>> { let attribute = match conv { CanonAbi::C | CanonAbi::Rust => return None, + CanonAbi::RustCold => FnAttribute::Cold, + // Functions with this calling convention can only be called from assembly, but it is + // possible to declare an `extern "custom"` block, so the backend still needs a calling + // convention for declaring foreign functions. + CanonAbi::Custom => return None, CanonAbi::Arm(arm_call) => match arm_call { ArmCall::CCmseNonSecureCall => FnAttribute::ArmCmseNonsecureCall, ArmCall::CCmseNonSecureEntry => FnAttribute::ArmCmseNonsecureEntry, ArmCall::Aapcs => FnAttribute::ArmPcs("aapcs"), }, - CanonAbi::RustCold => FnAttribute::Cold, CanonAbi::GpuKernel => { if arch == "amdgpu" { FnAttribute::GcnAmdGpuHsaKernel diff --git a/compiler/rustc_codegen_gcc/src/errors.rs b/compiler/rustc_codegen_gcc/src/errors.rs index ccd9abe3804..7786be9ae5d 100644 --- a/compiler/rustc_codegen_gcc/src/errors.rs +++ b/compiler/rustc_codegen_gcc/src/errors.rs @@ -17,21 +17,6 @@ pub(crate) struct UnknownCTargetFeature<'a> { pub rust_feature: PossibleFeature<'a>, } -#[derive(Diagnostic)] -#[diag(codegen_gcc_unstable_ctarget_feature)] -#[note] -pub(crate) struct UnstableCTargetFeature<'a> { - pub feature: &'a str, -} - -#[derive(Diagnostic)] -#[diag(codegen_gcc_forbidden_ctarget_feature)] -pub(crate) struct ForbiddenCTargetFeature<'a> { - pub feature: &'a str, - pub enabled: &'a str, - pub reason: &'a str, -} - #[derive(Subdiagnostic)] pub(crate) enum PossibleFeature<'a> { #[help(codegen_gcc_possible_feature)] diff --git a/compiler/rustc_codegen_gcc/src/gcc_util.rs b/compiler/rustc_codegen_gcc/src/gcc_util.rs index 2b053abdd19..d90e66aea31 100644 --- a/compiler/rustc_codegen_gcc/src/gcc_util.rs +++ b/compiler/rustc_codegen_gcc/src/gcc_util.rs @@ -5,13 +5,17 @@ use rustc_codegen_ssa::errors::TargetFeatureDisableOrEnable; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::unord::UnordSet; use rustc_session::Session; +use rustc_session::features::{StabilityExt, retpoline_features_by_flags}; use rustc_target::target_features::RUSTC_SPECIFIC_FEATURES; use smallvec::{SmallVec, smallvec}; -use crate::errors::{ - ForbiddenCTargetFeature, PossibleFeature, UnknownCTargetFeature, UnknownCTargetFeaturePrefix, - UnstableCTargetFeature, -}; +use crate::errors::{PossibleFeature, UnknownCTargetFeature, UnknownCTargetFeaturePrefix}; + +fn gcc_features_by_flags(sess: &Session) -> Vec<&str> { + let mut features: Vec<&str> = Vec::new(); + retpoline_features_by_flags(sess, &mut features); + features +} /// The list of GCC features computed from CLI flags (`-Ctarget-cpu`, `-Ctarget-feature`, /// `--target` and similar). @@ -45,7 +49,7 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec<Stri // Compute implied features let mut all_rust_features = vec![]; - for feature in sess.opts.cg.target_feature.split(',') { + for feature in sess.opts.cg.target_feature.split(',').chain(gcc_features_by_flags(sess)) { if let Some(feature) = feature.strip_prefix('+') { all_rust_features.extend( UnordSet::from(sess.target.implied_target_features(feature)) @@ -94,18 +98,7 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec<Stri sess.dcx().emit_warn(unknown_feature); } Some(&(_, stability, _)) => { - if let Err(reason) = stability.toggle_allowed() { - sess.dcx().emit_warn(ForbiddenCTargetFeature { - feature, - enabled: if enable { "enabled" } else { "disabled" }, - reason, - }); - } else if stability.requires_nightly().is_some() { - // An unstable feature. Warn about using it. (It makes little sense - // to hard-error here since we just warn about fully unknown - // features above). - sess.dcx().emit_warn(UnstableCTargetFeature { feature }); - } + stability.verify_feature_enabled_by_flag(sess, enable, feature); } } diff --git a/compiler/rustc_codegen_llvm/messages.ftl b/compiler/rustc_codegen_llvm/messages.ftl index bda121c67fb..3faeb9b3b22 100644 --- a/compiler/rustc_codegen_llvm/messages.ftl +++ b/compiler/rustc_codegen_llvm/messages.ftl @@ -10,11 +10,6 @@ codegen_llvm_dynamic_linking_with_lto = codegen_llvm_fixed_x18_invalid_arch = the `-Zfixed-x18` flag is not supported on the `{$arch}` architecture -codegen_llvm_forbidden_ctarget_feature = - target feature `{$feature}` cannot be {$enabled} with `-Ctarget-feature`: {$reason} - .note = this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! -codegen_llvm_forbidden_ctarget_feature_issue = for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344> - codegen_llvm_from_llvm_diag = {$message} codegen_llvm_from_llvm_optimization_diag = {$filename}:{$line}:{$column} {$pass_name} ({$kind}): {$message} @@ -76,10 +71,6 @@ codegen_llvm_unknown_ctarget_feature_prefix = codegen_llvm_unknown_debuginfo_compression = unknown debuginfo compression algorithm {$algorithm} - will fall back to uncompressed debuginfo -codegen_llvm_unstable_ctarget_feature = - unstable feature specified for `-Ctarget-feature`: `{$feature}` - .note = this feature is not stably supported; its behavior can change in the future - codegen_llvm_write_bytecode = failed to write bytecode to {$path}: {$err} codegen_llvm_write_ir = failed to write LLVM IR to {$path} diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index 119cd634f98..aba63d75f1d 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -649,6 +649,10 @@ impl llvm::CallConv { match conv { CanonAbi::C | CanonAbi::Rust => llvm::CCallConv, CanonAbi::RustCold => llvm::PreserveMost, + // Functions with this calling convention can only be called from assembly, but it is + // possible to declare an `extern "custom"` block, so the backend still needs a calling + // convention for declaring foreign functions. + CanonAbi::Custom => llvm::CCallConv, CanonAbi::GpuKernel => { if arch == "amdgpu" { llvm::AmdgpuKernel diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index 443c2eace55..27fd09745ff 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -5,6 +5,7 @@ use rustc_hir::def_id::DefId; use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, PatchableFunctionEntry}; use rustc_middle::ty::{self, TyCtxt}; use rustc_session::config::{BranchProtection, FunctionReturn, OptLevel, PAuthKey, PacRet}; +use rustc_symbol_mangling::mangle_internal_symbol; use rustc_target::spec::{FramePointer, SanitizerSet, StackProbeType, StackProtector}; use smallvec::SmallVec; @@ -256,11 +257,11 @@ fn probestack_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> { StackProbeType::Inline => "inline-asm", // Flag our internal `__rust_probestack` function as the stack probe symbol. // This is defined in the `compiler-builtins` crate for each architecture. - StackProbeType::Call => "__rust_probestack", + StackProbeType::Call => &mangle_internal_symbol(cx.tcx, "__rust_probestack"), // Pick from the two above based on the LLVM version. StackProbeType::InlineOrCall { min_llvm_version_for_inline } => { if llvm_util::get_version() < min_llvm_version_for_inline { - "__rust_probestack" + &mangle_internal_symbol(cx.tcx, "__rust_probestack") } else { "inline-asm" } diff --git a/compiler/rustc_codegen_llvm/src/errors.rs b/compiler/rustc_codegen_llvm/src/errors.rs index eaafc680712..8bc74fbec7e 100644 --- a/compiler/rustc_codegen_llvm/src/errors.rs +++ b/compiler/rustc_codegen_llvm/src/errors.rs @@ -24,23 +24,6 @@ pub(crate) struct UnknownCTargetFeature<'a> { pub rust_feature: PossibleFeature<'a>, } -#[derive(Diagnostic)] -#[diag(codegen_llvm_unstable_ctarget_feature)] -#[note] -pub(crate) struct UnstableCTargetFeature<'a> { - pub feature: &'a str, -} - -#[derive(Diagnostic)] -#[diag(codegen_llvm_forbidden_ctarget_feature)] -#[note] -#[note(codegen_llvm_forbidden_ctarget_feature_issue)] -pub(crate) struct ForbiddenCTargetFeature<'a> { - pub feature: &'a str, - pub enabled: &'a str, - pub reason: &'a str, -} - #[derive(Subdiagnostic)] pub(crate) enum PossibleFeature<'a> { #[help(codegen_llvm_possible_feature)] diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 9718c95f38a..0e77bc43df8 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -16,6 +16,7 @@ use rustc_fs_util::path_to_c_string; use rustc_middle::bug; use rustc_session::Session; use rustc_session::config::{PrintKind, PrintRequest}; +use rustc_session::features::{StabilityExt, retpoline_features_by_flags}; use rustc_span::Symbol; use rustc_target::spec::{MergeFunctions, PanicStrategy, SmallDataThresholdSupport}; use rustc_target::target_features::{RUSTC_SPECIAL_FEATURES, RUSTC_SPECIFIC_FEATURES}; @@ -23,8 +24,7 @@ use smallvec::{SmallVec, smallvec}; use crate::back::write::create_informational_target_machine; use crate::errors::{ - FixedX18InvalidArch, ForbiddenCTargetFeature, PossibleFeature, UnknownCTargetFeature, - UnknownCTargetFeaturePrefix, UnstableCTargetFeature, + FixedX18InvalidArch, PossibleFeature, UnknownCTargetFeature, UnknownCTargetFeaturePrefix, }; use crate::llvm; @@ -707,6 +707,12 @@ pub(crate) fn target_cpu(sess: &Session) -> &str { handle_native(cpu_name) } +fn llvm_features_by_flags(sess: &Session) -> Vec<&str> { + let mut features: Vec<&str> = Vec::new(); + retpoline_features_by_flags(sess, &mut features); + features +} + /// The list of LLVM features computed from CLI flags (`-Ctarget-cpu`, `-Ctarget-feature`, /// `--target` and similar). pub(crate) fn global_llvm_features( @@ -787,7 +793,7 @@ pub(crate) fn global_llvm_features( // Compute implied features let mut all_rust_features = vec![]; - for feature in sess.opts.cg.target_feature.split(',') { + for feature in sess.opts.cg.target_feature.split(',').chain(llvm_features_by_flags(sess)) { if let Some(feature) = feature.strip_prefix('+') { all_rust_features.extend( UnordSet::from(sess.target.implied_target_features(feature)) @@ -840,18 +846,7 @@ pub(crate) fn global_llvm_features( sess.dcx().emit_warn(unknown_feature); } Some((_, stability, _)) => { - if let Err(reason) = stability.toggle_allowed() { - sess.dcx().emit_warn(ForbiddenCTargetFeature { - feature, - enabled: if enable { "enabled" } else { "disabled" }, - reason, - }); - } else if stability.requires_nightly().is_some() { - // An unstable feature. Warn about using it. It makes little sense - // to hard-error here since we just warn about fully unknown - // features above. - sess.dcx().emit_warn(UnstableCTargetFeature { feature }); - } + stability.verify_feature_enabled_by_flag(sess, enable, feature); } } diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 168077260a6..18b76b33757 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -1065,11 +1065,11 @@ fn link_natively( match strip { Strip::Debuginfo => { // FIXME: AIX's strip utility only offers option to strip line number information. - strip_with_external_utility(sess, stripcmd, out_filename, &["-X32_64", "-l"]) + strip_with_external_utility(sess, stripcmd, temp_filename, &["-X32_64", "-l"]) } Strip::Symbols => { // Must be noted this option might remove symbol __aix_rust_metadata and thus removes .info section which contains metadata. - strip_with_external_utility(sess, stripcmd, out_filename, &["-X32_64", "-r"]) + strip_with_external_utility(sess, stripcmd, temp_filename, &["-X32_64", "-r"]) } Strip::None => {} } diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs index e217c09939e..27fcab8ed2d 100644 --- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs @@ -118,7 +118,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let (llsize, _) = size_of_val::size_and_align_of_dst(bx, tp_ty, meta); llsize } - sym::min_align_of_val => { + sym::align_of_val => { let tp_ty = fn_args.type_at(0); let (_, meta) = args[0].val.pointer_parts(); let (_, llalign) = size_of_val::size_and_align_of_dst(bx, tp_ty, meta); diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 5c14fe5cd10..b62ac89661f 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -278,7 +278,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { { let from_backend_ty = bx.backend_type(operand.layout); let to_backend_ty = bx.backend_type(cast); - Some(OperandValue::Immediate(self.transmute_immediate( + Some(OperandValue::Immediate(transmute_immediate( bx, imm, from_scalar, @@ -303,8 +303,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let out_a_ibty = bx.scalar_pair_element_backend_type(cast, 0, false); let out_b_ibty = bx.scalar_pair_element_backend_type(cast, 1, false); Some(OperandValue::Pair( - self.transmute_immediate(bx, imm_a, in_a, in_a_ibty, out_a, out_a_ibty), - self.transmute_immediate(bx, imm_b, in_b, in_b_ibty, out_b, out_b_ibty), + transmute_immediate(bx, imm_a, in_a, in_a_ibty, out_a, out_a_ibty), + transmute_immediate(bx, imm_b, in_b, in_b_ibty, out_b, out_b_ibty), )) } else { None @@ -332,7 +332,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // valid ranges. For example, `char`s are passed as just `i32`, with no // way for LLVM to know that they're 0x10FFFF at most. Thus we assume // the range of the input value too, not just the output range. - self.assume_scalar_range(bx, imm, from_scalar, from_backend_ty); + assume_scalar_range(bx, imm, from_scalar, from_backend_ty); imm = match (from_scalar.primitive(), to_scalar.primitive()) { (Int(_, is_signed), Int(..)) => bx.intcast(imm, to_backend_ty, is_signed), @@ -365,98 +365,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { Some(imm) } - /// Transmutes one of the immediates from an [`OperandValue::Immediate`] - /// or an [`OperandValue::Pair`] to an immediate of the target type. - /// - /// `to_backend_ty` must be the *non*-immediate backend type (so it will be - /// `i8`, not `i1`, for `bool`-like types.) - fn transmute_immediate( - &self, - bx: &mut Bx, - mut imm: Bx::Value, - from_scalar: abi::Scalar, - from_backend_ty: Bx::Type, - to_scalar: abi::Scalar, - to_backend_ty: Bx::Type, - ) -> Bx::Value { - assert_eq!(from_scalar.size(self.cx), to_scalar.size(self.cx)); - - // While optimizations will remove no-op transmutes, they might still be - // there in debug or things that aren't no-op in MIR because they change - // the Rust type but not the underlying layout/niche. - if from_scalar == to_scalar && from_backend_ty == to_backend_ty { - return imm; - } - - use abi::Primitive::*; - imm = bx.from_immediate(imm); - - // If we have a scalar, we must already know its range. Either - // - // 1) It's a parameter with `range` parameter metadata, - // 2) It's something we `load`ed with `!range` metadata, or - // 3) After a transmute we `assume`d the range (see below). - // - // That said, last time we tried removing this, it didn't actually help - // the rustc-perf results, so might as well keep doing it - // <https://github.com/rust-lang/rust/pull/135610#issuecomment-2599275182> - self.assume_scalar_range(bx, imm, from_scalar, from_backend_ty); - - imm = match (from_scalar.primitive(), to_scalar.primitive()) { - (Int(..) | Float(_), Int(..) | Float(_)) => bx.bitcast(imm, to_backend_ty), - (Pointer(..), Pointer(..)) => bx.pointercast(imm, to_backend_ty), - (Int(..), Pointer(..)) => bx.ptradd(bx.const_null(bx.type_ptr()), imm), - (Pointer(..), Int(..)) => { - // FIXME: this exposes the provenance, which shouldn't be necessary. - bx.ptrtoint(imm, to_backend_ty) - } - (Float(_), Pointer(..)) => { - let int_imm = bx.bitcast(imm, bx.cx().type_isize()); - bx.ptradd(bx.const_null(bx.type_ptr()), int_imm) - } - (Pointer(..), Float(_)) => { - // FIXME: this exposes the provenance, which shouldn't be necessary. - let int_imm = bx.ptrtoint(imm, bx.cx().type_isize()); - bx.bitcast(int_imm, to_backend_ty) - } - }; - - // This `assume` remains important for cases like (a conceptual) - // transmute::<u32, NonZeroU32>(x) == 0 - // since it's never passed to something with parameter metadata (especially - // after MIR inlining) so the only way to tell the backend about the - // constraint that the `transmute` introduced is to `assume` it. - self.assume_scalar_range(bx, imm, to_scalar, to_backend_ty); - - imm = bx.to_immediate_scalar(imm, to_scalar); - imm - } - - fn assume_scalar_range( - &self, - bx: &mut Bx, - imm: Bx::Value, - scalar: abi::Scalar, - backend_ty: Bx::Type, - ) { - if matches!(self.cx.sess().opts.optimize, OptLevel::No) || scalar.is_always_valid(self.cx) { - return; - } - - match scalar.primitive() { - abi::Primitive::Int(..) => { - let range = scalar.valid_range(self.cx); - bx.assume_integer_range(imm, backend_ty, range); - } - abi::Primitive::Pointer(abi::AddressSpace::DATA) - if !scalar.valid_range(self.cx).contains(0) => - { - bx.assume_nonnull(imm); - } - abi::Primitive::Pointer(..) | abi::Primitive::Float(..) => {} - } - } - pub(crate) fn codegen_rvalue_unsized( &mut self, bx: &mut Bx, @@ -1231,3 +1139,93 @@ impl OperandValueKind { }) } } + +/// Transmutes one of the immediates from an [`OperandValue::Immediate`] +/// or an [`OperandValue::Pair`] to an immediate of the target type. +/// +/// `to_backend_ty` must be the *non*-immediate backend type (so it will be +/// `i8`, not `i1`, for `bool`-like types.) +fn transmute_immediate<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( + bx: &mut Bx, + mut imm: Bx::Value, + from_scalar: abi::Scalar, + from_backend_ty: Bx::Type, + to_scalar: abi::Scalar, + to_backend_ty: Bx::Type, +) -> Bx::Value { + assert_eq!(from_scalar.size(bx.cx()), to_scalar.size(bx.cx())); + + // While optimizations will remove no-op transmutes, they might still be + // there in debug or things that aren't no-op in MIR because they change + // the Rust type but not the underlying layout/niche. + if from_scalar == to_scalar && from_backend_ty == to_backend_ty { + return imm; + } + + use abi::Primitive::*; + imm = bx.from_immediate(imm); + + // If we have a scalar, we must already know its range. Either + // + // 1) It's a parameter with `range` parameter metadata, + // 2) It's something we `load`ed with `!range` metadata, or + // 3) After a transmute we `assume`d the range (see below). + // + // That said, last time we tried removing this, it didn't actually help + // the rustc-perf results, so might as well keep doing it + // <https://github.com/rust-lang/rust/pull/135610#issuecomment-2599275182> + assume_scalar_range(bx, imm, from_scalar, from_backend_ty); + + imm = match (from_scalar.primitive(), to_scalar.primitive()) { + (Int(..) | Float(_), Int(..) | Float(_)) => bx.bitcast(imm, to_backend_ty), + (Pointer(..), Pointer(..)) => bx.pointercast(imm, to_backend_ty), + (Int(..), Pointer(..)) => bx.ptradd(bx.const_null(bx.type_ptr()), imm), + (Pointer(..), Int(..)) => { + // FIXME: this exposes the provenance, which shouldn't be necessary. + bx.ptrtoint(imm, to_backend_ty) + } + (Float(_), Pointer(..)) => { + let int_imm = bx.bitcast(imm, bx.cx().type_isize()); + bx.ptradd(bx.const_null(bx.type_ptr()), int_imm) + } + (Pointer(..), Float(_)) => { + // FIXME: this exposes the provenance, which shouldn't be necessary. + let int_imm = bx.ptrtoint(imm, bx.cx().type_isize()); + bx.bitcast(int_imm, to_backend_ty) + } + }; + + // This `assume` remains important for cases like (a conceptual) + // transmute::<u32, NonZeroU32>(x) == 0 + // since it's never passed to something with parameter metadata (especially + // after MIR inlining) so the only way to tell the backend about the + // constraint that the `transmute` introduced is to `assume` it. + assume_scalar_range(bx, imm, to_scalar, to_backend_ty); + + imm = bx.to_immediate_scalar(imm, to_scalar); + imm +} + +fn assume_scalar_range<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( + bx: &mut Bx, + imm: Bx::Value, + scalar: abi::Scalar, + backend_ty: Bx::Type, +) { + if matches!(bx.cx().sess().opts.optimize, OptLevel::No) || scalar.is_always_valid(bx.cx()) { + return; + } + + match scalar.primitive() { + abi::Primitive::Int(..) => { + let range = scalar.valid_range(bx.cx()); + bx.assume_integer_range(imm, backend_ty, range); + } + abi::Primitive::Pointer(abi::AddressSpace::DATA) + if !scalar.valid_range(bx.cx()).contains(0) => + { + bx.assume_nonnull(imm); + } + abi::Primitive::Pointer(..) | abi::Primitive::Float(..) => {} + } +} diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index 6bb3150c1c5..640d197c219 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -8,6 +8,7 @@ use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId}; use rustc_middle::middle::codegen_fn_attrs::TargetFeature; use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; +use rustc_session::features::StabilityExt; use rustc_session::lint::builtin::AARCH64_SOFTFLOAT_NEON; use rustc_session::parse::feature_err; use rustc_span::{Span, Symbol, sym}; @@ -66,7 +67,7 @@ pub(crate) fn from_target_feature_attr( // Only allow target features whose feature gates have been enabled // and which are permitted to be toggled. - if let Err(reason) = stability.toggle_allowed() { + if let Err(reason) = stability.is_toggle_permitted(tcx.sess) { tcx.dcx().emit_err(errors::ForbiddenTargetFeatureAttr { span: item.span(), feature, diff --git a/compiler/rustc_codegen_ssa/src/traits/type_.rs b/compiler/rustc_codegen_ssa/src/traits/type_.rs index c3fc21a9285..70331b72353 100644 --- a/compiler/rustc_codegen_ssa/src/traits/type_.rs +++ b/compiler/rustc_codegen_ssa/src/traits/type_.rs @@ -44,10 +44,10 @@ pub trait DerivedTypeCodegenMethods<'tcx>: BaseTypeCodegenMethods + MiscCodegenMethods<'tcx> + HasTyCtxt<'tcx> + HasTypingEnv<'tcx> { fn type_int(&self) -> Self::Type { - match &self.sess().target.c_int_width[..] { - "16" => self.type_i16(), - "32" => self.type_i32(), - "64" => self.type_i64(), + match &self.sess().target.c_int_width { + 16 => self.type_i16(), + 32 => self.type_i32(), + 64 => self.type_i64(), width => bug!("Unsupported c_int_width: {}", width), } } diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs index 9719d405259..4f252f3ccd4 100644 --- a/compiler/rustc_const_eval/src/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/check_consts/check.rs @@ -356,10 +356,7 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> { hir::ConstContext::ConstFn => true, _ => { // For indirect places, we are not creating a new permanent borrow, it's just as - // transient as the already existing one. For reborrowing references this is handled - // at the top of `visit_rvalue`, but for raw pointers we handle it here. - // Pointers/references to `static mut` and cases where the `*` is not the first - // projection also end up here. + // transient as the already existing one. // Locals with StorageDead do not live beyond the evaluation and can // thus safely be borrowed without being able to be leaked to the final // value of the constant. diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs index 1dd96297d1f..f0f958d069e 100644 --- a/compiler/rustc_const_eval/src/interpret/intern.rs +++ b/compiler/rustc_const_eval/src/interpret/intern.rs @@ -227,12 +227,11 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx, const_eval // Keep interning as long as there are things to intern. // We show errors if there are dangling pointers, or mutable pointers in immutable contexts - // (i.e., everything except for `static mut`). When these errors affect references, it is - // unfortunate that we show these errors here and not during validation, since validation can - // show much nicer errors. However, we do need these checks to be run on all pointers, including - // raw pointers, so we cannot rely on validation to catch them -- and since interning runs - // before validation, and interning doesn't know the type of anything, this means we can't show - // better errors. Maybe we should consider doing validation before interning in the future. + // (i.e., everything except for `static mut`). We only return these errors as a `Result` + // so that the caller can run validation, and subsequently only report interning errors + // if validation fails. Validation has the better error messages so we prefer those, but + // interning has better coverage since it "sees" *all* pointers, including raw pointers and + // references stored in unions. while let Some(prov) = todo.pop() { trace!(?prov); let alloc_id = prov.alloc_id(); @@ -279,12 +278,12 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx, const_eval // when there is memory there that someone might expect to be mutable, but we make it immutable. let dangling = !is_already_global && !ecx.memory.alloc_map.contains_key(&alloc_id); if !dangling { - // Found a mutable reference inside a const where inner allocations should be + // Found a mutable pointer inside a const where inner allocations should be // immutable. if !ecx.tcx.sess.opts.unstable_opts.unleash_the_miri_inside_of_you { span_bug!( ecx.tcx.span, - "the static const safety checks accepted mutable references they should not have accepted" + "the static const safety checks accepted a mutable pointer they should not have accepted" ); } // Prefer dangling pointer errors over mutable pointer errors diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index ab27182c211..754b2ba0d76 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -120,7 +120,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { self.copy_op(&val, dest)?; } - sym::min_align_of_val | sym::size_of_val => { + sym::align_of_val | sym::size_of_val => { // Avoid `deref_pointer` -- this is not a deref, the ptr does not have to be // dereferenceable! let place = self.ref_to_mplace(&self.read_immediate(&args[0])?)?; @@ -129,7 +129,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { .ok_or_else(|| err_unsup_format!("`extern type` does not have known layout"))?; let result = match intrinsic_name { - sym::min_align_of_val => align.bytes(), + sym::align_of_val => align.bytes(), sym::size_of_val => size.bytes(), _ => bug!(), }; diff --git a/compiler/rustc_const_eval/src/interpret/util.rs b/compiler/rustc_const_eval/src/interpret/util.rs index 83a17092619..99add01f95c 100644 --- a/compiler/rustc_const_eval/src/interpret/util.rs +++ b/compiler/rustc_const_eval/src/interpret/util.rs @@ -58,9 +58,9 @@ pub enum MaybeEnteredSpan { macro_rules! enter_trace_span { ($machine:ident, $($tt:tt)*) => { if $machine::TRACING_ENABLED { - $crate::interpret::tracing_utils::MaybeEnteredSpan::Some(tracing::info_span!($($tt)*).entered()) + $crate::interpret::util::MaybeEnteredSpan::Some(tracing::info_span!($($tt)*).entered()) } else { - $crate::interpret::tracing_utils::MaybeEnteredSpan::None + $crate::interpret::util::MaybeEnteredSpan::None } } } diff --git a/compiler/rustc_data_structures/src/thousands/mod.rs b/compiler/rustc_data_structures/src/thousands/mod.rs index e7ab7ec2932..b251ebe58f6 100644 --- a/compiler/rustc_data_structures/src/thousands/mod.rs +++ b/compiler/rustc_data_structures/src/thousands/mod.rs @@ -1,16 +1,37 @@ -//! This is an extremely bare-bones alternative to the `thousands` crate on -//! crates.io, for printing large numbers in a readable fashion. +//! This is a bare-bones alternative to the `thousands` crate on crates.io, for +//! printing large numbers in a readable fashion. #[cfg(test)] mod tests; -// Converts the number to a string, with underscores as the thousands separator. -pub fn format_with_underscores(n: usize) -> String { - let mut s = n.to_string(); - let mut i = s.len(); - while i > 3 { +fn format_with_underscores(mut s: String) -> String { + // Ignore a leading '-'. + let start = if s.starts_with('-') { 1 } else { 0 }; + + // Stop after the first non-digit, e.g. '.' or 'e' for floats. + let non_digit = s[start..].find(|c: char| !c.is_digit(10)); + let end = if let Some(non_digit) = non_digit { start + non_digit } else { s.len() }; + + // Insert underscores within `start..end`. + let mut i = end; + while i > start + 3 { i -= 3; s.insert(i, '_'); } s } + +/// Print a `usize` with underscore separators. +pub fn usize_with_underscores(n: usize) -> String { + format_with_underscores(format!("{n}")) +} + +/// Print an `isize` with underscore separators. +pub fn isize_with_underscores(n: isize) -> String { + format_with_underscores(format!("{n}")) +} + +/// Print an `f64` with precision 1 (one decimal place) and underscore separators. +pub fn f64p1_with_underscores(n: f64) -> String { + format_with_underscores(format!("{n:.1}")) +} diff --git a/compiler/rustc_data_structures/src/thousands/tests.rs b/compiler/rustc_data_structures/src/thousands/tests.rs index 906605d9a93..0f9a648802b 100644 --- a/compiler/rustc_data_structures/src/thousands/tests.rs +++ b/compiler/rustc_data_structures/src/thousands/tests.rs @@ -2,13 +2,51 @@ use super::*; #[test] fn test_format_with_underscores() { - assert_eq!("0", format_with_underscores(0)); - assert_eq!("1", format_with_underscores(1)); - assert_eq!("99", format_with_underscores(99)); - assert_eq!("345", format_with_underscores(345)); - assert_eq!("1_000", format_with_underscores(1_000)); - assert_eq!("12_001", format_with_underscores(12_001)); - assert_eq!("999_999", format_with_underscores(999_999)); - assert_eq!("1_000_000", format_with_underscores(1_000_000)); - assert_eq!("12_345_678", format_with_underscores(12_345_678)); + assert_eq!("", format_with_underscores("".to_string())); + assert_eq!("0", format_with_underscores("0".to_string())); + assert_eq!("12_345.67e14", format_with_underscores("12345.67e14".to_string())); + assert_eq!("-1_234.5678e10", format_with_underscores("-1234.5678e10".to_string())); + assert_eq!("------", format_with_underscores("------".to_string())); + assert_eq!("abcdefgh", format_with_underscores("abcdefgh".to_string())); + assert_eq!("-1b", format_with_underscores("-1b".to_string())); + assert_eq!("-3_456xyz", format_with_underscores("-3456xyz".to_string())); +} + +#[test] +fn test_usize_with_underscores() { + assert_eq!("0", usize_with_underscores(0)); + assert_eq!("1", usize_with_underscores(1)); + assert_eq!("99", usize_with_underscores(99)); + assert_eq!("345", usize_with_underscores(345)); + assert_eq!("1_000", usize_with_underscores(1_000)); + assert_eq!("12_001", usize_with_underscores(12_001)); + assert_eq!("999_999", usize_with_underscores(999_999)); + assert_eq!("1_000_000", usize_with_underscores(1_000_000)); + assert_eq!("12_345_678", usize_with_underscores(12_345_678)); +} + +#[test] +fn test_isize_with_underscores() { + assert_eq!("0", isize_with_underscores(0)); + assert_eq!("-1", isize_with_underscores(-1)); + assert_eq!("99", isize_with_underscores(99)); + assert_eq!("345", isize_with_underscores(345)); + assert_eq!("-1_000", isize_with_underscores(-1_000)); + assert_eq!("12_001", isize_with_underscores(12_001)); + assert_eq!("-999_999", isize_with_underscores(-999_999)); + assert_eq!("1_000_000", isize_with_underscores(1_000_000)); + assert_eq!("-12_345_678", isize_with_underscores(-12_345_678)); +} + +#[test] +fn test_f64p1_with_underscores() { + assert_eq!("0.0", f64p1_with_underscores(0f64)); + assert_eq!("0.0", f64p1_with_underscores(0.00000001)); + assert_eq!("-0.0", f64p1_with_underscores(-0.00000001)); + assert_eq!("1.0", f64p1_with_underscores(0.9999999)); + assert_eq!("-1.0", f64p1_with_underscores(-0.9999999)); + assert_eq!("345.5", f64p1_with_underscores(345.4999999)); + assert_eq!("-100_000.0", f64p1_with_underscores(-100_000f64)); + assert_eq!("123_456_789.1", f64p1_with_underscores(123456789.123456789)); + assert_eq!("-123_456_789.1", f64p1_with_underscores(-123456789.123456789)); } diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 133bd361ee7..9f72fc4705a 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -60,8 +60,9 @@ pub use rustc_error_messages::{ SubdiagMessage, fallback_fluent_bundle, fluent_bundle, }; use rustc_hashes::Hash128; -use rustc_lint_defs::LintExpectationId; +use rustc_hir::HirId; pub use rustc_lint_defs::{Applicability, listify, pluralize}; +use rustc_lint_defs::{Lint, LintExpectationId}; use rustc_macros::{Decodable, Encodable}; pub use rustc_span::ErrorGuaranteed; pub use rustc_span::fatal_error::{FatalError, FatalErrorMarker}; @@ -101,6 +102,19 @@ rustc_data_structures::static_assert_size!(PResult<'_, ()>, 24); #[cfg(target_pointer_width = "64")] rustc_data_structures::static_assert_size!(PResult<'_, bool>, 24); +/// Used to avoid depending on `rustc_middle` in `rustc_attr_parsing`. +/// Always the `TyCtxt`. +pub trait LintEmitter: Copy { + #[track_caller] + fn emit_node_span_lint( + self, + lint: &'static Lint, + hir_id: HirId, + span: impl Into<MultiSpan>, + decorator: impl for<'a> LintDiagnostic<'a, ()>, + ); +} + #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Encodable, Decodable)] pub enum SuggestionStyle { /// Hide the suggested code when displaying this suggestion inline. diff --git a/compiler/rustc_expand/messages.ftl b/compiler/rustc_expand/messages.ftl index f26c7c1ba0b..8b7c47dad99 100644 --- a/compiler/rustc_expand/messages.ftl +++ b/compiler/rustc_expand/messages.ftl @@ -62,6 +62,7 @@ expand_feature_not_allowed = expand_feature_removed = feature has been removed .label = feature has been removed + .note = removed in {$removed_rustc_version} (you are using {$current_rustc_version}){$pull_note} .reason = {$reason} expand_glob_delegation_outside_impls = @@ -112,7 +113,7 @@ expand_meta_var_expr_unrecognized_var = variable `{$key}` is not recognized in meta-variable expression expand_missing_fragment_specifier = missing fragment specifier - .note = fragment specifiers must be specified in the 2024 edition + .note = fragment specifiers must be provided .suggestion_add_fragspec = try adding a specifier here .valid = {$valid} diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index c7b975d8f3e..311dadb53c4 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -12,7 +12,7 @@ use rustc_ast::tokenstream::TokenStream; use rustc_ast::visit::{AssocCtxt, Visitor}; use rustc_ast::{self as ast, AttrVec, Attribute, HasAttrs, Item, NodeId, PatKind}; use rustc_attr_data_structures::{AttributeKind, Deprecation, Stability, find_attr}; -use rustc_data_structures::fx::FxIndexMap; +use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_data_structures::sync; use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed, PResult}; use rustc_feature::Features; @@ -727,6 +727,7 @@ pub enum SyntaxExtensionKind { /// A trivial attribute "macro" that does nothing, /// only keeps the attribute and marks it as inert, /// thus making it ineligible for further expansion. + /// E.g. `#[default]`, `#[rustfmt::skip]`. NonMacroAttr, /// A token-based derive macro. @@ -1189,6 +1190,8 @@ pub struct ExtCtxt<'a> { /// in the AST, but insert it here so that we know /// not to expand it again. pub(super) expanded_inert_attrs: MarkedAttrs, + /// `-Zmacro-stats` data. + pub macro_stats: FxHashMap<(Symbol, MacroKind), crate::stats::MacroStat>, // njn: quals } impl<'a> ExtCtxt<'a> { @@ -1218,6 +1221,7 @@ impl<'a> ExtCtxt<'a> { expansions: FxIndexMap::default(), expanded_inert_attrs: MarkedAttrs::new(), buffered_early_lint: vec![], + macro_stats: Default::default(), } } diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index c50ab5959e2..9a359e9b031 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -80,9 +80,20 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute], crate_name: Symbol) - // If the enabled feature has been removed, issue an error. if let Some(f) = REMOVED_LANG_FEATURES.iter().find(|f| name == f.feature.name) { + let pull_note = if let Some(pull) = f.pull { + format!( + "; see <https://github.com/rust-lang/rust/pull/{}> for more information", + pull + ) + } else { + "".to_owned() + }; sess.dcx().emit_err(FeatureRemoved { span: mi.span(), reason: f.reason.map(|reason| FeatureRemovedReason { reason }), + removed_rustc_version: f.feature.since, + current_rustc_version: sess.cfg_version, + pull_note, }); continue; } diff --git a/compiler/rustc_expand/src/errors.rs b/compiler/rustc_expand/src/errors.rs index 89bdc7b6dfa..ec0af67c046 100644 --- a/compiler/rustc_expand/src/errors.rs +++ b/compiler/rustc_expand/src/errors.rs @@ -154,12 +154,16 @@ pub(crate) struct HelperAttributeNameInvalid { #[derive(Diagnostic)] #[diag(expand_feature_removed, code = E0557)] +#[note] pub(crate) struct FeatureRemoved<'a> { #[primary_span] #[label] pub span: Span, #[subdiagnostic] pub reason: Option<FeatureRemovedReason<'a>>, + pub removed_rustc_version: &'a str, + pub current_rustc_version: &'a str, + pub pull_note: String, } #[derive(Subdiagnostic)] diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 569165a64e5..3cfeb01ea47 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -42,13 +42,22 @@ use crate::module::{ DirOwnership, ParsedExternalMod, mod_dir_path, mod_file_path_from_attr, parse_external_mod, }; use crate::placeholders::{PlaceholderExpander, placeholder}; +use crate::stats::*; macro_rules! ast_fragments { ( $($Kind:ident($AstTy:ty) { $kind_name:expr; - $(one fn $mut_visit_ast:ident; fn $visit_ast:ident;)? - $(many fn $flat_map_ast_elt:ident; fn $visit_ast_elt:ident($($args:tt)*);)? + $(one + fn $mut_visit_ast:ident; + fn $visit_ast:ident; + fn $ast_to_string:path; + )? + $(many + fn $flat_map_ast_elt:ident; + fn $visit_ast_elt:ident($($args:tt)*); + fn $ast_to_string_elt:path; + )? fn $make_ast:ident; })* ) => { @@ -61,7 +70,7 @@ macro_rules! ast_fragments { } /// "Discriminant" of an AST fragment. - #[derive(Copy, Clone, PartialEq, Eq)] + #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum AstFragmentKind { OptExpr, MethodReceiverExpr, @@ -151,6 +160,21 @@ macro_rules! ast_fragments { } V::Result::output() } + + pub(crate) fn to_string(&self) -> String { + match self { + AstFragment::OptExpr(Some(expr)) => pprust::expr_to_string(expr), + AstFragment::OptExpr(None) => unreachable!(), + AstFragment::MethodReceiverExpr(expr) => pprust::expr_to_string(expr), + $($(AstFragment::$Kind(ast) => $ast_to_string(ast),)?)* + $($( + AstFragment::$Kind(ast) => { + // The closure unwraps a `P` if present, or does nothing otherwise. + elems_to_string(&*ast, |ast| $ast_to_string_elt(&*ast)) + } + )?)* + } + } } impl<'a> MacResult for crate::mbe::macro_rules::ParserAnyMacro<'a> { @@ -163,76 +187,98 @@ macro_rules! ast_fragments { } ast_fragments! { - Expr(P<ast::Expr>) { "expression"; one fn visit_expr; fn visit_expr; fn make_expr; } - Pat(P<ast::Pat>) { "pattern"; one fn visit_pat; fn visit_pat; fn make_pat; } - Ty(P<ast::Ty>) { "type"; one fn visit_ty; fn visit_ty; fn make_ty; } + Expr(P<ast::Expr>) { + "expression"; + one fn visit_expr; fn visit_expr; fn pprust::expr_to_string; + fn make_expr; + } + Pat(P<ast::Pat>) { + "pattern"; + one fn visit_pat; fn visit_pat; fn pprust::pat_to_string; + fn make_pat; + } + Ty(P<ast::Ty>) { + "type"; + one fn visit_ty; fn visit_ty; fn pprust::ty_to_string; + fn make_ty; + } Stmts(SmallVec<[ast::Stmt; 1]>) { - "statement"; many fn flat_map_stmt; fn visit_stmt(); fn make_stmts; + "statement"; + many fn flat_map_stmt; fn visit_stmt(); fn pprust::stmt_to_string; + fn make_stmts; } Items(SmallVec<[P<ast::Item>; 1]>) { - "item"; many fn flat_map_item; fn visit_item(); fn make_items; + "item"; + many fn flat_map_item; fn visit_item(); fn pprust::item_to_string; + fn make_items; } TraitItems(SmallVec<[P<ast::AssocItem>; 1]>) { "trait item"; - many fn flat_map_assoc_item; - fn visit_assoc_item(AssocCtxt::Trait); + many fn flat_map_assoc_item; fn visit_assoc_item(AssocCtxt::Trait); + fn pprust::assoc_item_to_string; fn make_trait_items; } ImplItems(SmallVec<[P<ast::AssocItem>; 1]>) { "impl item"; - many fn flat_map_assoc_item; - fn visit_assoc_item(AssocCtxt::Impl { of_trait: false }); + many fn flat_map_assoc_item; fn visit_assoc_item(AssocCtxt::Impl { of_trait: false }); + fn pprust::assoc_item_to_string; fn make_impl_items; } TraitImplItems(SmallVec<[P<ast::AssocItem>; 1]>) { "impl item"; - many fn flat_map_assoc_item; - fn visit_assoc_item(AssocCtxt::Impl { of_trait: true }); + many fn flat_map_assoc_item; fn visit_assoc_item(AssocCtxt::Impl { of_trait: true }); + fn pprust::assoc_item_to_string; fn make_trait_impl_items; } ForeignItems(SmallVec<[P<ast::ForeignItem>; 1]>) { "foreign item"; - many fn flat_map_foreign_item; - fn visit_foreign_item(); + many fn flat_map_foreign_item; fn visit_foreign_item(); fn pprust::foreign_item_to_string; fn make_foreign_items; } Arms(SmallVec<[ast::Arm; 1]>) { - "match arm"; many fn flat_map_arm; fn visit_arm(); fn make_arms; + "match arm"; + many fn flat_map_arm; fn visit_arm(); fn unreachable_to_string; + fn make_arms; } ExprFields(SmallVec<[ast::ExprField; 1]>) { - "field expression"; many fn flat_map_expr_field; fn visit_expr_field(); fn make_expr_fields; + "field expression"; + many fn flat_map_expr_field; fn visit_expr_field(); fn unreachable_to_string; + fn make_expr_fields; } PatFields(SmallVec<[ast::PatField; 1]>) { "field pattern"; - many fn flat_map_pat_field; - fn visit_pat_field(); + many fn flat_map_pat_field; fn visit_pat_field(); fn unreachable_to_string; fn make_pat_fields; } GenericParams(SmallVec<[ast::GenericParam; 1]>) { "generic parameter"; - many fn flat_map_generic_param; - fn visit_generic_param(); + many fn flat_map_generic_param; fn visit_generic_param(); fn unreachable_to_string; fn make_generic_params; } Params(SmallVec<[ast::Param; 1]>) { - "function parameter"; many fn flat_map_param; fn visit_param(); fn make_params; + "function parameter"; + many fn flat_map_param; fn visit_param(); fn unreachable_to_string; + fn make_params; } FieldDefs(SmallVec<[ast::FieldDef; 1]>) { "field"; - many fn flat_map_field_def; - fn visit_field_def(); + many fn flat_map_field_def; fn visit_field_def(); fn unreachable_to_string; fn make_field_defs; } Variants(SmallVec<[ast::Variant; 1]>) { - "variant"; many fn flat_map_variant; fn visit_variant(); fn make_variants; + "variant"; many fn flat_map_variant; fn visit_variant(); fn unreachable_to_string; + fn make_variants; } WherePredicates(SmallVec<[ast::WherePredicate; 1]>) { "where predicate"; - many fn flat_map_where_predicate; - fn visit_where_predicate(); + many fn flat_map_where_predicate; fn visit_where_predicate(); fn unreachable_to_string; fn make_where_predicates; - } - Crate(ast::Crate) { "crate"; one fn visit_crate; fn visit_crate; fn make_crate; } + } + Crate(ast::Crate) { + "crate"; + one fn visit_crate; fn visit_crate; fn unreachable_to_string; + fn make_crate; + } } pub enum SupportsMacroExpansion { @@ -270,7 +316,7 @@ impl AstFragmentKind { } } - fn expect_from_annotatables<I: IntoIterator<Item = Annotatable>>( + pub(crate) fn expect_from_annotatables<I: IntoIterator<Item = Annotatable>>( self, items: I, ) -> AstFragment { @@ -686,13 +732,26 @@ impl<'a, 'b> MacroExpander<'a, 'b> { return ExpandResult::Ready(invoc.fragment_kind.dummy(invoc.span(), guar)); } + let macro_stats = self.cx.sess.opts.unstable_opts.macro_stats; + let (fragment_kind, span) = (invoc.fragment_kind, invoc.span()); ExpandResult::Ready(match invoc.kind { InvocationKind::Bang { mac, span } => match ext { SyntaxExtensionKind::Bang(expander) => { match expander.expand(self.cx, span, mac.args.tokens.clone()) { Ok(tok_result) => { - self.parse_ast_fragment(tok_result, fragment_kind, &mac.path, span) + let fragment = + self.parse_ast_fragment(tok_result, fragment_kind, &mac.path, span); + if macro_stats { + update_bang_macro_stats( + self.cx, + fragment_kind, + span, + mac, + &fragment, + ); + } + fragment } Err(guar) => return ExpandResult::Ready(fragment_kind.dummy(span, guar)), } @@ -708,13 +767,15 @@ impl<'a, 'b> MacroExpander<'a, 'b> { }); } }; - let result = if let Some(result) = fragment_kind.make_from(tok_result) { - result + if let Some(fragment) = fragment_kind.make_from(tok_result) { + if macro_stats { + update_bang_macro_stats(self.cx, fragment_kind, span, mac, &fragment); + } + fragment } else { let guar = self.error_wrong_fragment_kind(fragment_kind, &mac, span); fragment_kind.dummy(span, guar) - }; - result + } } _ => unreachable!(), }, @@ -746,24 +807,39 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } _ => item.to_tokens(), }; - let attr_item = attr.unwrap_normal_item(); + let attr_item = attr.get_normal_item(); if let AttrArgs::Eq { .. } = attr_item.args { self.cx.dcx().emit_err(UnsupportedKeyValue { span }); } let inner_tokens = attr_item.args.inner_tokens(); match expander.expand(self.cx, span, inner_tokens, tokens) { - Ok(tok_result) => self.parse_ast_fragment( - tok_result, - fragment_kind, - &attr_item.path, - span, - ), + Ok(tok_result) => { + let fragment = self.parse_ast_fragment( + tok_result, + fragment_kind, + &attr_item.path, + span, + ); + if macro_stats { + update_attr_macro_stats( + self.cx, + fragment_kind, + span, + &attr_item.path, + &attr, + item, + &fragment, + ); + } + fragment + } Err(guar) => return ExpandResult::Ready(fragment_kind.dummy(span, guar)), } } SyntaxExtensionKind::LegacyAttr(expander) => { match validate_attr::parse_meta(&self.cx.sess.psess, &attr) { Ok(meta) => { + let item_clone = macro_stats.then(|| item.clone()); let items = match expander.expand(self.cx, span, &meta, item, false) { ExpandResult::Ready(items) => items, ExpandResult::Retry(item) => { @@ -782,7 +858,19 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let guar = self.cx.dcx().emit_err(RemoveExprNotSupported { span }); fragment_kind.dummy(span, guar) } else { - fragment_kind.expect_from_annotatables(items) + let fragment = fragment_kind.expect_from_annotatables(items); + if macro_stats { + update_attr_macro_stats( + self.cx, + fragment_kind, + span, + &meta.path, + &attr, + item_clone.unwrap(), + &fragment, + ); + } + fragment } } Err(err) => { @@ -792,6 +880,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } } SyntaxExtensionKind::NonMacroAttr => { + // `-Zmacro-stats` ignores these because they don't do any real expansion. self.cx.expanded_inert_attrs.mark(&attr); item.visit_attrs(|attrs| attrs.insert(pos, attr)); fragment_kind.expect_from_annotatables(iter::once(item)) @@ -822,7 +911,17 @@ impl<'a, 'b> MacroExpander<'a, 'b> { }); } }; - fragment_kind.expect_from_annotatables(items) + let fragment = fragment_kind.expect_from_annotatables(items); + if macro_stats { + update_derive_macro_stats( + self.cx, + fragment_kind, + span, + &meta.path, + &fragment, + ); + } + fragment } _ => unreachable!(), }, @@ -852,6 +951,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let single_delegations = build_single_delegations::<Node>( self.cx, deleg, &item, &suffixes, item.span, true, ); + // `-Zmacro-stats` ignores these because they don't seem important. fragment_kind.expect_from_annotatables( single_delegations .map(|item| Annotatable::AssocItem(P(item), AssocCtxt::Impl { of_trait })), diff --git a/compiler/rustc_expand/src/lib.rs b/compiler/rustc_expand/src/lib.rs index 515d82296ca..64be7649775 100644 --- a/compiler/rustc_expand/src/lib.rs +++ b/compiler/rustc_expand/src/lib.rs @@ -20,6 +20,7 @@ mod errors; mod mbe; mod placeholders; mod proc_macro_server; +mod stats; pub use mbe::macro_rules::compile_declarative_macro; pub mod base; diff --git a/compiler/rustc_expand/src/mbe/macro_check.rs b/compiler/rustc_expand/src/mbe/macro_check.rs index 1a2db233b7a..3cd803c3e84 100644 --- a/compiler/rustc_expand/src/mbe/macro_check.rs +++ b/compiler/rustc_expand/src/mbe/macro_check.rs @@ -112,9 +112,8 @@ use rustc_ast::{DUMMY_NODE_ID, NodeId}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::MultiSpan; use rustc_lint_defs::BuiltinLintDiag; -use rustc_session::lint::builtin::{META_VARIABLE_MISUSE, MISSING_FRAGMENT_SPECIFIER}; +use rustc_session::lint::builtin::META_VARIABLE_MISUSE; use rustc_session::parse::ParseSess; -use rustc_span::edition::Edition; use rustc_span::{ErrorGuaranteed, MacroRulesNormalizedIdent, Span, kw}; use smallvec::SmallVec; @@ -266,23 +265,11 @@ fn check_binders( // Similarly, this can only happen when checking a toplevel macro. TokenTree::MetaVarDecl(span, name, kind) => { if kind.is_none() && node_id != DUMMY_NODE_ID { - // FIXME: Report this as a hard error eventually and remove equivalent errors from - // `parse_tt_inner` and `nameize`. Until then the error may be reported twice, once - // as a hard error and then once as a buffered lint. - if span.edition() >= Edition::Edition2024 { - psess.dcx().emit_err(errors::MissingFragmentSpecifier { - span, - add_span: span.shrink_to_hi(), - valid: VALID_FRAGMENT_NAMES_MSG, - }); - } else { - psess.buffer_lint( - MISSING_FRAGMENT_SPECIFIER, - span, - node_id, - BuiltinLintDiag::MissingFragmentSpecifier, - ); - } + psess.dcx().emit_err(errors::MissingFragmentSpecifier { + span, + add_span: span.shrink_to_hi(), + valid: VALID_FRAGMENT_NAMES_MSG, + }); } if !macros.is_empty() { psess.dcx().span_bug(span, "unexpected MetaVarDecl in nested lhs"); diff --git a/compiler/rustc_expand/src/stats.rs b/compiler/rustc_expand/src/stats.rs new file mode 100644 index 00000000000..6b2ad30dffd --- /dev/null +++ b/compiler/rustc_expand/src/stats.rs @@ -0,0 +1,171 @@ +use std::iter; + +use rustc_ast::ptr::P; +use rustc_ast::{self as ast, DUMMY_NODE_ID, Expr, ExprKind}; +use rustc_ast_pretty::pprust; +use rustc_span::hygiene::{ExpnKind, MacroKind}; +use rustc_span::{Span, Symbol, kw, sym}; +use smallvec::SmallVec; + +use crate::base::{Annotatable, ExtCtxt}; +use crate::expand::{AstFragment, AstFragmentKind}; + +#[derive(Default)] +pub struct MacroStat { + /// Number of uses of the macro. + pub uses: usize, + + /// Net increase in number of lines of code (when pretty-printed), i.e. + /// `lines(output) - lines(invocation)`. Can be negative because a macro + /// output may be smaller than the invocation. + pub lines: isize, + + /// Net increase in number of lines of code (when pretty-printed), i.e. + /// `bytes(output) - bytes(invocation)`. Can be negative because a macro + /// output may be smaller than the invocation. + pub bytes: isize, +} + +pub(crate) fn elems_to_string<T>(elems: &SmallVec<[T; 1]>, f: impl Fn(&T) -> String) -> String { + let mut s = String::new(); + for (i, elem) in elems.iter().enumerate() { + if i > 0 { + s.push('\n'); + } + s.push_str(&f(elem)); + } + s +} + +pub(crate) fn unreachable_to_string<T>(_: &T) -> String { + unreachable!() +} + +pub(crate) fn update_bang_macro_stats( + ecx: &mut ExtCtxt<'_>, + fragment_kind: AstFragmentKind, + span: Span, + mac: P<ast::MacCall>, + fragment: &AstFragment, +) { + // Does this path match any of the include macros, e.g. `include!`? + // Ignore them. They would have large numbers but are entirely + // unsurprising and uninteresting. + let is_include_path = mac.path == sym::include + || mac.path == sym::include_bytes + || mac.path == sym::include_str + || mac.path == [sym::std, sym::include].as_slice() // std::include + || mac.path == [sym::std, sym::include_bytes].as_slice() // std::include_bytes + || mac.path == [sym::std, sym::include_str].as_slice(); // std::include_str + if is_include_path { + return; + } + + // The call itself (e.g. `println!("hi")`) is the input. Need to wrap + // `mac` in something printable; `ast::Expr` is as good as anything + // else. + let expr = Expr { + id: DUMMY_NODE_ID, + kind: ExprKind::MacCall(mac), + span: Default::default(), + attrs: Default::default(), + tokens: None, + }; + let input = pprust::expr_to_string(&expr); + + // Get `mac` back out of `expr`. + let ast::Expr { kind: ExprKind::MacCall(mac), .. } = expr else { unreachable!() }; + + update_macro_stats(ecx, MacroKind::Bang, fragment_kind, span, &mac.path, &input, fragment); +} + +pub(crate) fn update_attr_macro_stats( + ecx: &mut ExtCtxt<'_>, + fragment_kind: AstFragmentKind, + span: Span, + path: &ast::Path, + attr: &ast::Attribute, + item: Annotatable, + fragment: &AstFragment, +) { + // Does this path match `#[derive(...)]` in any of its forms? If so, + // ignore it because the individual derives will go through the + // `Invocation::Derive` handling separately. + let is_derive_path = *path == sym::derive + // ::core::prelude::v1::derive + || *path == [kw::PathRoot, sym::core, sym::prelude, sym::v1, sym::derive].as_slice(); + if is_derive_path { + return; + } + + // The attribute plus the item itself constitute the input, which we + // measure. + let input = format!( + "{}\n{}", + pprust::attribute_to_string(attr), + fragment_kind.expect_from_annotatables(iter::once(item)).to_string(), + ); + update_macro_stats(ecx, MacroKind::Attr, fragment_kind, span, path, &input, fragment); +} + +pub(crate) fn update_derive_macro_stats( + ecx: &mut ExtCtxt<'_>, + fragment_kind: AstFragmentKind, + span: Span, + path: &ast::Path, + fragment: &AstFragment, +) { + // Use something like `#[derive(Clone)]` for the measured input, even + // though it may have actually appeared in a multi-derive attribute + // like `#[derive(Clone, Copy, Debug)]`. + let input = format!("#[derive({})]", pprust::path_to_string(path)); + update_macro_stats(ecx, MacroKind::Derive, fragment_kind, span, path, &input, fragment); +} + +pub(crate) fn update_macro_stats( + ecx: &mut ExtCtxt<'_>, + macro_kind: MacroKind, + fragment_kind: AstFragmentKind, + span: Span, + path: &ast::Path, + input: &str, + fragment: &AstFragment, +) { + fn lines_and_bytes(s: &str) -> (usize, usize) { + (s.trim_end().split('\n').count(), s.len()) + } + + // Measure the size of the output by pretty-printing it and counting + // the lines and bytes. + let name = Symbol::intern(&pprust::path_to_string(path)); + let output = fragment.to_string(); + let (in_l, in_b) = lines_and_bytes(input); + let (out_l, out_b) = lines_and_bytes(&output); + + // This code is useful for debugging `-Zmacro-stats`. For every + // invocation it prints the full input and output. + if false { + let name = ExpnKind::Macro(macro_kind, name).descr(); + let crate_name = &ecx.ecfg.crate_name; + let span = ecx + .sess + .source_map() + .span_to_string(span, rustc_span::FileNameDisplayPreference::Local); + eprint!( + "\ + -------------------------------\n\ + {name}: [{crate_name}] ({fragment_kind:?}) {span}\n\ + -------------------------------\n\ + {input}\n\ + -- ({in_l} lines, {in_b} bytes) --> ({out_l} lines, {out_b} bytes) --\n\ + {output}\n\ + " + ); + } + + // The recorded size is the difference between the input and the output. + let entry = ecx.macro_stats.entry((name, macro_kind)).or_insert(MacroStat::default()); + entry.uses += 1; + entry.lines += out_l as isize - in_l as isize; + entry.bytes += out_b as isize - in_b as isize; +} diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index 10c5cb194f4..b1c185220f4 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -259,6 +259,8 @@ declare_features! ( /// Allows some increased flexibility in the name resolution rules, /// especially around globs and shadowing (RFC 1560). (accepted, item_like_imports, "1.15.0", Some(35120)), + // Allows using the `kl` and `widekl` target features and the associated intrinsics + (accepted, keylocker_x86, "CURRENT_RUSTC_VERSION", Some(134813)), /// Allows `'a: { break 'a; }`. (accepted, label_break_value, "1.65.0", Some(48594)), /// Allows `let...else` statements. diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index c117e0fcf7c..73a21789c5d 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -9,7 +9,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_span::edition::Edition; use rustc_span::{Symbol, sym}; -use crate::{Features, Stability}; +use crate::Features; type GateFn = fn(&Features) -> bool; @@ -94,34 +94,23 @@ pub enum AttributeSafety { Unsafe { unsafe_since: Option<Edition> }, } -#[derive(Clone, Copy)] +#[derive(Clone, Debug, Copy)] pub enum AttributeGate { - /// Is gated by a given feature gate, reason - /// and function to check if enabled - Gated(Stability, Symbol, &'static str, fn(&Features) -> bool), - + /// A gated attribute which requires a feature gate to be enabled. + Gated { + /// The feature gate, for example `#![feature(rustc_attrs)]` for rustc_* attributes. + feature: Symbol, + /// The error message displayed when an attempt is made to use the attribute without its feature gate. + message: &'static str, + /// Check function to be called during the `PostExpansionVisitor` pass. + check: fn(&Features) -> bool, + /// Notes to be displayed when an attempt is made to use the attribute without its feature gate. + notes: &'static [&'static str], + }, /// Ungated attribute, can be used on all release channels Ungated, } -// fn() is not Debug -impl std::fmt::Debug for AttributeGate { - fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match *self { - Self::Gated(ref stab, name, expl, _) => { - write!(fmt, "Gated({stab:?}, {name}, {expl})") - } - Self::Ungated => write!(fmt, "Ungated"), - } - } -} - -impl AttributeGate { - fn is_deprecated(&self) -> bool { - matches!(*self, Self::Gated(Stability::Deprecated(_, _), ..)) - } -} - /// A template that the attribute input must match. /// Only top-level shape (`#[attr]` vs `#[attr(...)]` vs `#[attr = ...]`) is considered now. #[derive(Clone, Copy, Default)] @@ -247,7 +236,7 @@ macro_rules! ungated { } macro_rules! gated { - (unsafe $attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $gate:ident, $msg:expr $(,)?) => { + (unsafe $attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $gate:ident, $message:expr $(,)?) => { BuiltinAttribute { name: sym::$attr, encode_cross_crate: $encode_cross_crate, @@ -255,10 +244,15 @@ macro_rules! gated { safety: AttributeSafety::Unsafe { unsafe_since: None }, template: $tpl, duplicates: $duplicates, - gate: Gated(Stability::Unstable, sym::$gate, $msg, Features::$gate), + gate: Gated { + feature: sym::$gate, + message: $message, + check: Features::$gate, + notes: &[], + }, } }; - (unsafe $attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $msg:expr $(,)?) => { + (unsafe $attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $message:expr $(,)?) => { BuiltinAttribute { name: sym::$attr, encode_cross_crate: $encode_cross_crate, @@ -266,10 +260,15 @@ macro_rules! gated { safety: AttributeSafety::Unsafe { unsafe_since: None }, template: $tpl, duplicates: $duplicates, - gate: Gated(Stability::Unstable, sym::$attr, $msg, Features::$attr), + gate: Gated { + feature: sym::$attr, + message: $message, + check: Features::$attr, + notes: &[], + }, } }; - ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $gate:ident, $msg:expr $(,)?) => { + ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $gate:ident, $message:expr $(,)?) => { BuiltinAttribute { name: sym::$attr, encode_cross_crate: $encode_cross_crate, @@ -277,10 +276,15 @@ macro_rules! gated { safety: AttributeSafety::Normal, template: $tpl, duplicates: $duplicates, - gate: Gated(Stability::Unstable, sym::$gate, $msg, Features::$gate), + gate: Gated { + feature: sym::$gate, + message: $message, + check: Features::$gate, + notes: &[], + }, } }; - ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $msg:expr $(,)?) => { + ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $message:expr $(,)?) => { BuiltinAttribute { name: sym::$attr, encode_cross_crate: $encode_cross_crate, @@ -288,7 +292,12 @@ macro_rules! gated { safety: AttributeSafety::Normal, template: $tpl, duplicates: $duplicates, - gate: Gated(Stability::Unstable, sym::$attr, $msg, Features::$attr), + gate: Gated { + feature: sym::$attr, + message: $message, + check: Features::$attr, + notes: &[], + }, } }; } @@ -304,12 +313,11 @@ macro_rules! rustc_attr { concat!( "the `#[", stringify!($attr), - "]` attribute is just used for rustc unit tests \ - and will never be stable", + "]` attribute is used for rustc unit tests" ), ) }; - ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $msg:expr $(,)?) => { + ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $($notes:expr),* $(,)?) => { BuiltinAttribute { name: sym::$attr, encode_cross_crate: $encode_cross_crate, @@ -317,7 +325,17 @@ macro_rules! rustc_attr { safety: AttributeSafety::Normal, template: $tpl, duplicates: $duplicates, - gate: Gated(Stability::Unstable, sym::rustc_attrs, $msg, Features::rustc_attrs), + gate: Gated { + feature: sym::rustc_attrs, + message: "use of an internal attribute", + check: Features::rustc_attrs, + notes: &[ + concat!("the `#[", + stringify!($attr), + "]` attribute is an internal implementation detail that will never be stable"), + $($notes),* + ] + }, } }; } @@ -328,9 +346,6 @@ macro_rules! experimental { }; } -const IMPL_DETAIL: &str = "internal implementation detail"; -const INTERNAL_UNSTABLE: &str = "this is an internal attribute that will never be stable"; - #[derive(PartialEq)] pub enum EncodeCrossCrate { Yes, @@ -668,7 +683,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ rustc_attr!( rustc_deprecated_safe_2024, Normal, template!(List: r#"audit_that = "...""#), ErrorFollowing, EncodeCrossCrate::Yes, - "rustc_deprecated_safe_2024 is supposed to be used in libstd only", + "`#[rustc_deprecated_safe_2024]` is used to declare functions unsafe across the edition 2024 boundary", ), rustc_attr!( rustc_pub_transparent, Normal, template!(Word), @@ -695,7 +710,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ ErrorFollowing, EncodeCrossCrate::No, "`rustc_never_type_options` is used to experiment with never type fallback and work on \ - never type stabilization, and will never be stable" + never type stabilization" ), // ========================================================================== @@ -704,23 +719,23 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ rustc_attr!( rustc_allocator, Normal, template!(Word), WarnFollowing, - EncodeCrossCrate::No, IMPL_DETAIL + EncodeCrossCrate::No, ), rustc_attr!( rustc_nounwind, Normal, template!(Word), WarnFollowing, - EncodeCrossCrate::No, IMPL_DETAIL + EncodeCrossCrate::No, ), rustc_attr!( rustc_reallocator, Normal, template!(Word), WarnFollowing, - EncodeCrossCrate::No, IMPL_DETAIL + EncodeCrossCrate::No, ), rustc_attr!( rustc_deallocator, Normal, template!(Word), WarnFollowing, - EncodeCrossCrate::No, IMPL_DETAIL + EncodeCrossCrate::No, ), rustc_attr!( rustc_allocator_zeroed, Normal, template!(Word), WarnFollowing, - EncodeCrossCrate::No, IMPL_DETAIL + EncodeCrossCrate::No, ), gated!( default_lib_allocator, Normal, template!(Word), WarnFollowing, @@ -762,7 +777,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ ), rustc_attr!( rustc_std_internal_symbol, Normal, template!(Word), WarnFollowing, - EncodeCrossCrate::No, INTERNAL_UNSTABLE + EncodeCrossCrate::No, ), // ========================================================================== @@ -772,11 +787,11 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ rustc_attr!( rustc_builtin_macro, Normal, template!(Word, List: "name, /*opt*/ attributes(name1, name2, ...)"), ErrorFollowing, - EncodeCrossCrate::Yes, IMPL_DETAIL + EncodeCrossCrate::Yes, ), rustc_attr!( rustc_proc_macro_decls, Normal, template!(Word), WarnFollowing, - EncodeCrossCrate::No, INTERNAL_UNSTABLE + EncodeCrossCrate::No, ), rustc_attr!( rustc_macro_transparency, Normal, @@ -786,7 +801,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ rustc_attr!( rustc_autodiff, Normal, template!(Word, List: r#""...""#), DuplicatesOk, - EncodeCrossCrate::Yes, INTERNAL_UNSTABLE + EncodeCrossCrate::Yes, ), // Traces that are left when `cfg` and `cfg_attr` attributes are expanded. // The attributes are not gated, to avoid stability errors, but they cannot be used in stable @@ -812,54 +827,53 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ NameValueStr: "message" ), ErrorFollowing, EncodeCrossCrate::Yes, - INTERNAL_UNSTABLE + "see `#[diagnostic::on_unimplemented]` for the stable equivalent of this attribute" ), rustc_attr!( rustc_confusables, Normal, template!(List: r#""name1", "name2", ..."#), ErrorFollowing, EncodeCrossCrate::Yes, - INTERNAL_UNSTABLE, ), // Enumerates "identity-like" conversion methods to suggest on type mismatch. rustc_attr!( rustc_conversion_suggestion, Normal, template!(Word), - WarnFollowing, EncodeCrossCrate::Yes, INTERNAL_UNSTABLE + WarnFollowing, EncodeCrossCrate::Yes, ), // Prevents field reads in the marked trait or method to be considered // during dead code analysis. rustc_attr!( rustc_trivial_field_reads, Normal, template!(Word), - WarnFollowing, EncodeCrossCrate::Yes, INTERNAL_UNSTABLE + WarnFollowing, EncodeCrossCrate::Yes, ), // Used by the `rustc::potential_query_instability` lint to warn methods which // might not be stable during incremental compilation. rustc_attr!( rustc_lint_query_instability, Normal, template!(Word), - WarnFollowing, EncodeCrossCrate::Yes, INTERNAL_UNSTABLE + WarnFollowing, EncodeCrossCrate::Yes, ), // Used by the `rustc::untracked_query_information` lint to warn methods which // might not be stable during incremental compilation. rustc_attr!( rustc_lint_untracked_query_information, Normal, template!(Word), - WarnFollowing, EncodeCrossCrate::Yes, INTERNAL_UNSTABLE + WarnFollowing, EncodeCrossCrate::Yes, ), // Used by the `rustc::diagnostic_outside_of_impl` lints to assist in changes to diagnostic // APIs. Any function with this attribute will be checked by that lint. rustc_attr!( rustc_lint_diagnostics, Normal, template!(Word), - WarnFollowing, EncodeCrossCrate::Yes, INTERNAL_UNSTABLE + WarnFollowing, EncodeCrossCrate::Yes, ), // Used by the `rustc::bad_opt_access` lint to identify `DebuggingOptions` and `CodegenOptions` // types (as well as any others in future). rustc_attr!( rustc_lint_opt_ty, Normal, template!(Word), - WarnFollowing, EncodeCrossCrate::Yes, INTERNAL_UNSTABLE + WarnFollowing, EncodeCrossCrate::Yes, ), // Used by the `rustc::bad_opt_access` lint on fields // types (as well as any others in future). rustc_attr!( rustc_lint_opt_deny_field_access, Normal, template!(List: "message"), - WarnFollowing, EncodeCrossCrate::Yes, INTERNAL_UNSTABLE + WarnFollowing, EncodeCrossCrate::Yes, ), // ========================================================================== @@ -868,28 +882,30 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ rustc_attr!( rustc_promotable, Normal, template!(Word), WarnFollowing, - EncodeCrossCrate::No, IMPL_DETAIL), + EncodeCrossCrate::No, ), rustc_attr!( rustc_legacy_const_generics, Normal, template!(List: "N"), ErrorFollowing, - EncodeCrossCrate::Yes, INTERNAL_UNSTABLE + EncodeCrossCrate::Yes, ), // Do not const-check this function's body. It will always get replaced during CTFE. rustc_attr!( rustc_do_not_const_check, Normal, template!(Word), WarnFollowing, - EncodeCrossCrate::Yes, INTERNAL_UNSTABLE + EncodeCrossCrate::Yes, "`#[rustc_do_not_const_check]` skips const-check for this function's body", ), - // Ensure the argument to this function is &&str during const-check. rustc_attr!( rustc_const_panic_str, Normal, template!(Word), WarnFollowing, - EncodeCrossCrate::Yes, INTERNAL_UNSTABLE + EncodeCrossCrate::Yes, "`#[rustc_const_panic_str]` ensures the argument to this function is &&str during const-check", ), rustc_attr!( rustc_const_stable_indirect, Normal, - template!(Word), WarnFollowing, EncodeCrossCrate::No, IMPL_DETAIL, + template!(Word), + WarnFollowing, + EncodeCrossCrate::No, + "this is an internal implementation detail", ), rustc_attr!( rustc_intrinsic_const_stable_indirect, Normal, - template!(Word), WarnFollowing, EncodeCrossCrate::No, IMPL_DETAIL, + template!(Word), WarnFollowing, EncodeCrossCrate::No, "this is an internal implementation detail", ), gated!( rustc_allow_const_fn_unstable, Normal, @@ -905,21 +921,21 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ rustc_layout_scalar_valid_range_start, Normal, template!(List: "value"), ErrorFollowing, EncodeCrossCrate::Yes, "the `#[rustc_layout_scalar_valid_range_start]` attribute is just used to enable \ - niche optimizations in libcore and libstd and will never be stable", + niche optimizations in the standard library", ), rustc_attr!( rustc_layout_scalar_valid_range_end, Normal, template!(List: "value"), ErrorFollowing, EncodeCrossCrate::Yes, "the `#[rustc_layout_scalar_valid_range_end]` attribute is just used to enable \ - niche optimizations in libcore and libstd and will never be stable", + niche optimizations in the standard library", ), rustc_attr!( rustc_nonnull_optimization_guaranteed, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::Yes, "the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to document \ - guaranteed niche optimizations in libcore and libstd and will never be stable\n\ - (note that the compiler does not even check whether the type indeed is being non-null-optimized; \ - it is your responsibility to ensure that the attribute is only used on types that are optimized)", + guaranteed niche optimizations in the standard library", + "the compiler does not even check whether the type indeed is being non-null-optimized; \ + it is your responsibility to ensure that the attribute is only used on types that are optimized", ), // ========================================================================== @@ -932,17 +948,17 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ rustc_attr!( rustc_as_ptr, Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::Yes, - "#[rustc_as_ptr] is used to mark functions returning pointers to their inner allocations." + "`#[rustc_as_ptr]` is used to mark functions returning pointers to their inner allocations." ), rustc_attr!( rustc_pass_by_value, Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::Yes, - "#[rustc_pass_by_value] is used to mark types that must be passed by value instead of reference." + "`#[rustc_pass_by_value]` is used to mark types that must be passed by value instead of reference." ), rustc_attr!( rustc_never_returns_null_ptr, Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::Yes, - "#[rustc_never_returns_null_ptr] is used to mark functions returning non-null pointers." + "`#[rustc_never_returns_null_ptr]` is used to mark functions returning non-null pointers." ), rustc_attr!( rustc_no_implicit_autorefs, AttributeType::Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::Yes, @@ -950,15 +966,15 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ ), rustc_attr!( rustc_coherence_is_core, AttributeType::CrateLevel, template!(Word), ErrorFollowing, EncodeCrossCrate::No, - "#![rustc_coherence_is_core] allows inherent methods on builtin types, only intended to be used in `core`." + "`#![rustc_coherence_is_core]` allows inherent methods on builtin types, only intended to be used in `core`." ), rustc_attr!( rustc_coinductive, AttributeType::Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No, - "#![rustc_coinductive] changes a trait to be coinductive, allowing cycles in the trait solver." + "`#[rustc_coinductive]` changes a trait to be coinductive, allowing cycles in the trait solver." ), rustc_attr!( rustc_allow_incoherent_impl, AttributeType::Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::No, - "#[rustc_allow_incoherent_impl] has to be added to all impl items of an incoherent inherent impl." + "`#[rustc_allow_incoherent_impl]` has to be added to all impl items of an incoherent inherent impl." ), rustc_attr!( rustc_preserve_ub_checks, AttributeType::CrateLevel, template!(Word), ErrorFollowing, EncodeCrossCrate::No, @@ -970,7 +986,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ template!(Word), ErrorFollowing, EncodeCrossCrate::No, - "#[rustc_deny_explicit_impl] enforces that a trait can have no user-provided impls" + "`#[rustc_deny_explicit_impl]` enforces that a trait can have no user-provided impls" ), rustc_attr!( rustc_do_not_implement_via_object, @@ -978,14 +994,14 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ template!(Word), ErrorFollowing, EncodeCrossCrate::No, - "#[rustc_do_not_implement_via_object] opts out of the automatic trait impl for trait objects \ + "`#[rustc_do_not_implement_via_object]` opts out of the automatic trait impl for trait objects \ (`impl Trait for dyn Trait`)" ), rustc_attr!( rustc_has_incoherent_inherent_impls, AttributeType::Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::Yes, - "#[rustc_has_incoherent_inherent_impls] allows the addition of incoherent inherent impls for \ - the given type by annotating all impl items with #[rustc_allow_incoherent_impl]." + "`#[rustc_has_incoherent_inherent_impls]` allows the addition of incoherent inherent impls for \ + the given type by annotating all impl items with `#[rustc_allow_incoherent_impl]`." ), BuiltinAttribute { @@ -996,12 +1012,13 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ safety: AttributeSafety::Normal, template: template!(NameValueStr: "name"), duplicates: ErrorFollowing, - gate: Gated( - Stability::Unstable, - sym::rustc_attrs, - "diagnostic items compiler internal support for linting", - Features::rustc_attrs, - ), + gate: Gated{ + feature: sym::rustc_attrs, + message: "use of an internal attribute", + check: Features::rustc_attrs, + notes: &["the `#[rustc_diagnostic_item]` attribute allows the compiler to reference types \ + from the standard library for diagnostic purposes"], + }, }, gated!( // Used in resolve: @@ -1015,14 +1032,14 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ rustc_attr!( rustc_inherit_overflow_checks, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No, "the `#[rustc_inherit_overflow_checks]` attribute is just used to control \ - overflow checking behavior of several libcore functions that are inlined \ - across crates and will never be stable", + overflow checking behavior of several functions in the standard library that are inlined \ + across crates", ), rustc_attr!( rustc_reservation_impl, Normal, template!(NameValueStr: "reservation message"), ErrorFollowing, EncodeCrossCrate::Yes, "the `#[rustc_reservation_impl]` attribute is internally used \ - for reserving for `for<T> From<!> for T` impl" + for reserving `impl<T> From<!> for T` as part of the effort to stabilize `!`" ), rustc_attr!( rustc_test_marker, Normal, template!(NameValueStr: "name"), WarnFollowing, @@ -1053,12 +1070,13 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ rustc_must_implement_one_of, Normal, template!(List: "function1, function2, ..."), ErrorFollowing, EncodeCrossCrate::No, "the `#[rustc_must_implement_one_of]` attribute is used to change minimal complete \ - definition of a trait, it's currently in experimental form and should be changed before \ - being exposed outside of the std" + definition of a trait. Its syntax and semantics are highly experimental and will be \ + subject to change before stabilization", ), rustc_attr!( rustc_doc_primitive, Normal, template!(NameValueStr: "primitive name"), ErrorFollowing, - EncodeCrossCrate::Yes, r#"`rustc_doc_primitive` is a rustc internal attribute"#, + EncodeCrossCrate::Yes, "the `#[rustc_doc_primitive]` attribute is used by the standard library \ + to provide a way to generate documentation for primitive types", ), gated!( rustc_intrinsic, Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::Yes, intrinsics, @@ -1066,11 +1084,11 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ ), rustc_attr!( rustc_no_mir_inline, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::Yes, - "#[rustc_no_mir_inline] prevents the MIR inliner from inlining a function while not affecting codegen" + "`#[rustc_no_mir_inline]` prevents the MIR inliner from inlining a function while not affecting codegen" ), rustc_attr!( rustc_force_inline, Normal, template!(Word, NameValueStr: "reason"), WarnFollowing, EncodeCrossCrate::Yes, - "#[rustc_force_inline] forces a free function to be inlined" + "`#[rustc_force_inline]` forces a free function to be inlined" ), // ========================================================================== @@ -1209,10 +1227,6 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ ), ]; -pub fn deprecated_attributes() -> Vec<&'static BuiltinAttribute> { - BUILTIN_ATTRIBUTES.iter().filter(|attr| attr.gate.is_deprecated()).collect() -} - pub fn is_builtin_attr_name(name: Symbol) -> bool { BUILTIN_ATTRIBUTE_MAP.get(&name).is_some() } diff --git a/compiler/rustc_feature/src/lib.rs b/compiler/rustc_feature/src/lib.rs index 25764755a8f..dbc0daa3d83 100644 --- a/compiler/rustc_feature/src/lib.rs +++ b/compiler/rustc_feature/src/lib.rs @@ -40,14 +40,6 @@ pub struct Feature { issue: Option<NonZero<u32>>, } -#[derive(Copy, Clone, Debug)] -pub enum Stability { - Unstable, - // First argument is tracking issue link; second argument is an optional - // help message, which defaults to "remove this attribute". - Deprecated(&'static str, Option<&'static str>), -} - #[derive(Clone, Copy, Debug, Hash)] pub enum UnstableFeatures { /// Disallow use of unstable features, as on beta/stable channels. @@ -144,9 +136,8 @@ pub fn find_feature_issue(feature: Symbol, issue: GateIssue) -> Option<NonZero<u pub use accepted::ACCEPTED_LANG_FEATURES; pub use builtin_attrs::{ AttributeDuplicates, AttributeGate, AttributeSafety, AttributeTemplate, AttributeType, - BUILTIN_ATTRIBUTE_MAP, BUILTIN_ATTRIBUTES, BuiltinAttribute, GatedCfg, deprecated_attributes, - encode_cross_crate, find_gated_cfg, is_builtin_attr_name, is_stable_diagnostic_attribute, - is_valid_for_get_attr, + BUILTIN_ATTRIBUTE_MAP, BUILTIN_ATTRIBUTES, BuiltinAttribute, GatedCfg, encode_cross_crate, + find_gated_cfg, is_builtin_attr_name, is_stable_diagnostic_attribute, is_valid_for_get_attr, }; pub use removed::REMOVED_LANG_FEATURES; pub use unstable::{ diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs index 013e1d5d0fa..9738f169595 100644 --- a/compiler/rustc_feature/src/removed.rs +++ b/compiler/rustc_feature/src/removed.rs @@ -1,5 +1,7 @@ //! List of the removed feature gates. +use std::num::{NonZero, NonZeroU32}; + use rustc_span::sym; use super::{Feature, to_nonzero}; @@ -7,11 +9,21 @@ use super::{Feature, to_nonzero}; pub struct RemovedFeature { pub feature: Feature, pub reason: Option<&'static str>, + pub pull: Option<NonZero<u32>>, +} + +macro_rules! opt_nonzero_u32 { + () => { + None + }; + ($val:expr) => { + Some(NonZeroU32::new($val).unwrap()) + }; } macro_rules! declare_features { ($( - $(#[doc = $doc:tt])* (removed, $feature:ident, $ver:expr, $issue:expr, $reason:expr), + $(#[doc = $doc:tt])* (removed, $feature:ident, $ver:expr, $issue:expr, $reason:expr $(, $pull:expr)?), )+) => { /// Formerly unstable features that have now been removed. pub static REMOVED_LANG_FEATURES: &[RemovedFeature] = &[ @@ -21,7 +33,8 @@ macro_rules! declare_features { since: $ver, issue: to_nonzero($issue), }, - reason: $reason + reason: $reason, + pull: opt_nonzero_u32!($($pull)?), }),+ ]; }; @@ -40,64 +53,64 @@ declare_features! ( // version they got originally added in.) /// Allows using the `amdgpu-kernel` ABI. - (removed, abi_amdgpu_kernel, "1.77.0", Some(51575), None), - (removed, advanced_slice_patterns, "1.0.0", Some(62254), - Some("merged into `#![feature(slice_patterns)]`")), + (removed, abi_amdgpu_kernel, "1.77.0", Some(51575), None, 120495), + (removed, advanced_slice_patterns, "1.42.0", Some(62254), + Some("merged into `#![feature(slice_patterns)]`"), 67712), (removed, allocator, "1.0.0", None, None), /// Allows a test to fail without failing the whole suite. - (removed, allow_fail, "1.19.0", Some(46488), Some("removed due to no clear use cases")), + (removed, allow_fail, "1.60.0", Some(46488), Some("removed due to no clear use cases"), 93416), (removed, await_macro, "1.38.0", Some(50547), - Some("subsumed by `.await` syntax")), + Some("subsumed by `.await` syntax"), 62293), /// Allows using the `box $expr` syntax. - (removed, box_syntax, "1.70.0", Some(49733), Some("replaced with `#[rustc_box]`")), + (removed, box_syntax, "1.70.0", Some(49733), Some("replaced with `#[rustc_box]`"), 108471), /// Allows capturing disjoint fields in a closure/coroutine (RFC 2229). - (removed, capture_disjoint_fields, "1.49.0", Some(53488), Some("stabilized in Rust 2021")), + (removed, capture_disjoint_fields, "1.69.0", Some(53488), Some("stabilized in Rust 2021"), 108550), /// Allows comparing raw pointers during const eval. (removed, const_compare_raw_pointers, "1.46.0", Some(53020), - Some("cannot be allowed in const eval in any meaningful way")), + Some("cannot be allowed in const eval in any meaningful way"), 73398), /// Allows limiting the evaluation steps of const expressions - (removed, const_eval_limit, "1.43.0", Some(67217), Some("removed the limit entirely")), + (removed, const_eval_limit, "1.72.0", Some(67217), Some("removed the limit entirely"), 103877), /// Allows non-trivial generic constants which have to be manually propagated upwards. - (removed, const_evaluatable_checked, "1.48.0", Some(76560), Some("renamed to `generic_const_exprs`")), + (removed, const_evaluatable_checked, "1.56.0", Some(76560), Some("renamed to `generic_const_exprs`"), 88369), /// Allows the definition of `const` functions with some advanced features. (removed, const_fn, "1.54.0", Some(57563), - Some("split into finer-grained feature gates")), + Some("split into finer-grained feature gates"), 85109), /// Allows const generic types (e.g. `struct Foo<const N: usize>(...);`). - (removed, const_generics, "1.34.0", Some(44580), - Some("removed in favor of `#![feature(adt_const_params)]` and `#![feature(generic_const_exprs)]`")), + (removed, const_generics, "1.56.0", Some(44580), + Some("removed in favor of `#![feature(adt_const_params)]` and `#![feature(generic_const_exprs)]`"), 88369), /// Allows `[x; N]` where `x` is a constant (RFC 2203). - (removed, const_in_array_repeat_expressions, "1.37.0", Some(49147), - Some("removed due to causing promotable bugs")), + (removed, const_in_array_repeat_expressions, "1.51.0", Some(49147), + Some("removed due to causing promotable bugs"), 80404), /// Allows casting raw pointers to `usize` during const eval. (removed, const_raw_ptr_to_usize_cast, "1.55.0", Some(51910), - Some("at compile-time, pointers do not have an integer value, so these casts cannot be properly supported")), + Some("at compile-time, pointers do not have an integer value, so these casts cannot be properly supported"), 87020), /// Allows `T: ?const Trait` syntax in bounds. - (removed, const_trait_bound_opt_out, "1.42.0", Some(67794), - Some("Removed in favor of `~const` bound in #![feature(const_trait_impl)]")), + (removed, const_trait_bound_opt_out, "1.56.0", Some(67794), + Some("Removed in favor of `~const` bound in #![feature(const_trait_impl)]"), 88328), /// Allows using `crate` as visibility modifier, synonymous with `pub(crate)`. - (removed, crate_visibility_modifier, "1.63.0", Some(53120), Some("removed in favor of `pub(crate)`")), + (removed, crate_visibility_modifier, "1.63.0", Some(53120), Some("removed in favor of `pub(crate)`"), 97254), /// Allows using custom attributes (RFC 572). (removed, custom_attribute, "1.0.0", Some(29642), - Some("removed in favor of `#![register_tool]` and `#![register_attr]`")), + Some("removed in favor of `#![register_tool]` and `#![register_attr]`"), 66070), /// Allows the use of `#[derive(Anything)]` as sugar for `#[derive_Anything]`. (removed, custom_derive, "1.32.0", Some(29644), Some("subsumed by `#[proc_macro_derive]`")), /// Allows default type parameters to influence type inference. (removed, default_type_parameter_fallback, "1.82.0", Some(27336), - Some("never properly implemented; requires significant design work")), + Some("never properly implemented; requires significant design work"), 127655), /// Allows deriving traits as per `SmartPointer` specification - (removed, derive_smart_pointer, "1.79.0", Some(123430), Some("replaced by `CoercePointee`")), + (removed, derive_smart_pointer, "1.84.0", Some(123430), Some("replaced by `CoercePointee`"), 131284), /// Allows using `#[doc(keyword = "...")]`. - (removed, doc_keyword, "1.28.0", Some(51315), - Some("merged into `#![feature(rustdoc_internals)]`")), + (removed, doc_keyword, "1.58.0", Some(51315), + Some("merged into `#![feature(rustdoc_internals)]`"), 90420), /// Allows using `doc(primitive)` without a future-incompat warning. - (removed, doc_primitive, "1.56.0", Some(88070), - Some("merged into `#![feature(rustdoc_internals)]`")), + (removed, doc_primitive, "1.58.0", Some(88070), + Some("merged into `#![feature(rustdoc_internals)]`"), 90420), /// Allows `#[doc(spotlight)]`. /// The attribute was renamed to `#[doc(notable_trait)]` /// and the feature to `doc_notable_trait`. - (removed, doc_spotlight, "1.22.0", Some(45040), - Some("renamed to `doc_notable_trait`")), + (removed, doc_spotlight, "1.53.0", Some(45040), + Some("renamed to `doc_notable_trait`"), 80965), /// Allows using `#[unsafe_destructor_blind_to_params]` (RFC 1238). (removed, dropck_parametricity, "1.38.0", Some(28498), None), /// Allows making `dyn Trait` well-formed even if `Trait` is not dyn compatible[^1]. @@ -107,161 +120,162 @@ declare_features! ( /// Renamed from `object_safe_for_dispatch`. /// /// [^1]: Formerly known as "object safe". - (removed, dyn_compatible_for_dispatch, "1.83.0", Some(43561), - Some("removed, not used heavily and represented additional complexity in dyn compatibility")), + (removed, dyn_compatible_for_dispatch, "1.87.0", Some(43561), + Some("removed, not used heavily and represented additional complexity in dyn compatibility"), 136522), /// Uses generic effect parameters for ~const bounds (removed, effects, "1.84.0", Some(102090), - Some("removed, redundant with `#![feature(const_trait_impl)]`")), + Some("removed, redundant with `#![feature(const_trait_impl)]`"), 132479), /// Allows defining `existential type`s. (removed, existential_type, "1.38.0", Some(63063), Some("removed in favor of `#![feature(type_alias_impl_trait)]`")), /// Paths of the form: `extern::foo::bar` (removed, extern_in_paths, "1.33.0", Some(55600), - Some("subsumed by `::foo::bar` paths")), + Some("subsumed by `::foo::bar` paths"), 57572), /// Allows `#[doc(include = "some-file")]`. (removed, external_doc, "1.54.0", Some(44732), - Some("use #[doc = include_str!(\"filename\")] instead, which handles macro invocations")), + Some("use #[doc = include_str!(\"filename\")] instead, which handles macro invocations"), 85457), /// Allows using `#[ffi_returns_twice]` on foreign functions. (removed, ffi_returns_twice, "1.78.0", Some(58314), - Some("being investigated by the ffi-unwind project group")), + Some("being investigated by the ffi-unwind project group"), 120502), /// Allows generators to be cloned. - (removed, generator_clone, "1.65.0", Some(95360), Some("renamed to `coroutine_clone`")), + (removed, generator_clone, "1.75.0", Some(95360), Some("renamed to `coroutine_clone`"), 116958), /// Allows defining generators. - (removed, generators, "1.21.0", Some(43122), Some("renamed to `coroutines`")), + (removed, generators, "1.75.0", Some(43122), Some("renamed to `coroutines`"), 116958), /// An extension to the `generic_associated_types` feature, allowing incomplete features. (removed, generic_associated_types_extended, "1.85.0", Some(95451), Some( "feature needs overhaul and reimplementation pending \ better implied higher-ranked implied bounds support" - ) + ), + 133768 ), (removed, import_shadowing, "1.0.0", None, None), /// Allows in-band quantification of lifetime bindings (e.g., `fn foo(x: &'a u8) -> &'a u8`). - (removed, in_band_lifetimes, "1.23.0", Some(44524), - Some("removed due to unsolved ergonomic questions and added lifetime resolution complexity")), + (removed, in_band_lifetimes, "1.61.0", Some(44524), + Some("removed due to unsolved ergonomic questions and added lifetime resolution complexity"), 93845), /// Allows inferring `'static` outlives requirements (RFC 2093). (removed, infer_static_outlives_requirements, "1.63.0", Some(54185), - Some("removed as it caused some confusion and discussion was inactive for years")), + Some("removed as it caused some confusion and discussion was inactive for years"), 97875), /// Allow anonymous constants from an inline `const` block in pattern position (removed, inline_const_pat, "1.88.0", Some(76001), - Some("removed due to implementation concerns as it requires significant refactorings")), + Some("removed due to implementation concerns as it requires significant refactorings"), 138492), /// Lazily evaluate constants. This allows constants to depend on type parameters. - (removed, lazy_normalization_consts, "1.46.0", Some(72219), Some("superseded by `generic_const_exprs`")), + (removed, lazy_normalization_consts, "1.56.0", Some(72219), Some("superseded by `generic_const_exprs`"), 88369), /// Changes `impl Trait` to capture all lifetimes in scope. - (removed, lifetime_capture_rules_2024, "1.76.0", None, Some("unnecessary -- use edition 2024 instead")), + (removed, lifetime_capture_rules_2024, "1.87.0", None, Some("unnecessary -- use edition 2024 instead"), 136787), /// Allows using the `#[link_args]` attribute. (removed, link_args, "1.53.0", Some(29596), Some("removed in favor of using `-C link-arg=ARG` on command line, \ - which is available from cargo build scripts with `cargo:rustc-link-arg` now")), + which is available from cargo build scripts with `cargo:rustc-link-arg` now"), 83820), (removed, macro_reexport, "1.0.0", Some(29638), - Some("subsumed by `pub use`")), + Some("subsumed by `pub use`"), 49982), /// Allows using `#[main]` to replace the entrypoint `#[lang = "start"]` calls. - (removed, main, "1.53.0", Some(29634), None), + (removed, main, "1.53.0", Some(29634), None, 84217), (removed, managed_boxes, "1.0.0", None, None), /// Allows the use of type alias impl trait in function return positions (removed, min_type_alias_impl_trait, "1.56.0", Some(63063), - Some("removed in favor of full type_alias_impl_trait")), + Some("removed in favor of full type_alias_impl_trait"), 87564), /// Make `mut` not reset the binding mode on edition >= 2024. - (removed, mut_preserve_binding_mode_2024, "1.79.0", Some(123076), Some("superseded by `ref_pat_eat_one_layer_2024`")), + (removed, mut_preserve_binding_mode_2024, "1.80.0", Some(123076), Some("superseded by `ref_pat_eat_one_layer_2024`"), 125168), (removed, needs_allocator, "1.4.0", Some(27389), Some("subsumed by `#![feature(allocator_internals)]`")), /// Allows use of unary negate on unsigned integers, e.g., -e for e: u8 (removed, negate_unsigned, "1.0.0", Some(29645), None), /// Allows `#[no_coverage]` on functions. /// The feature was renamed to `coverage_attribute` and the attribute to `#[coverage(on|off)]` - (removed, no_coverage, "1.74.0", Some(84605), Some("renamed to `coverage_attribute`")), + (removed, no_coverage, "1.74.0", Some(84605), Some("renamed to `coverage_attribute`"), 114656), /// Allows `#[no_debug]`. - (removed, no_debug, "1.43.0", Some(29721), Some("removed due to lack of demand")), + (removed, no_debug, "1.43.0", Some(29721), Some("removed due to lack of demand"), 69667), /// Note: this feature was previously recorded in a separate /// `STABLE_REMOVED` list because it, uniquely, was once stable but was /// then removed. But there was no utility storing it separately, so now /// it's in this list. - (removed, no_stack_check, "1.0.0", None, None), + (removed, no_stack_check, "1.0.0", None, None, 40110), /// Allows making `dyn Trait` well-formed even if `Trait` is not dyn compatible (object safe). /// Renamed to `dyn_compatible_for_dispatch`. (removed, object_safe_for_dispatch, "1.83.0", Some(43561), - Some("renamed to `dyn_compatible_for_dispatch`")), + Some("renamed to `dyn_compatible_for_dispatch`"), 131511), /// Allows using `#[on_unimplemented(..)]` on traits. /// (Moved to `rustc_attrs`.) - (removed, on_unimplemented, "1.40.0", None, None), + (removed, on_unimplemented, "1.40.0", None, None, 65794), /// A way to temporarily opt out of opt-in copy. This will *never* be accepted. - (removed, opt_out_copy, "1.0.0", None, None), + (removed, opt_out_copy, "1.0.0", None, None, 20740), /// Allows features specific to OIBIT (now called auto traits). /// Renamed to `auto_traits`. - (removed, optin_builtin_traits, "1.0.0", Some(13231), - Some("renamed to `auto_traits`")), + (removed, optin_builtin_traits, "1.50.0", Some(13231), + Some("renamed to `auto_traits`"), 79336), /// Allows overlapping impls of marker traits. (removed, overlapping_marker_traits, "1.42.0", Some(29864), - Some("removed in favor of `#![feature(marker_trait_attr)]`")), + Some("removed in favor of `#![feature(marker_trait_attr)]`"), 68544), (removed, panic_implementation, "1.28.0", Some(44489), - Some("subsumed by `#[panic_handler]`")), + Some("subsumed by `#[panic_handler]`"), 53619), /// Allows `extern "platform-intrinsic" { ... }`. - (removed, platform_intrinsics, "1.4.0", Some(27731), - Some("SIMD intrinsics use the regular intrinsics ABI now")), + (removed, platform_intrinsics, "1.78.0", Some(27731), + Some("SIMD intrinsics use the regular intrinsics ABI now"), 121516), /// Allows using `#![plugin(myplugin)]`. (removed, plugin, "1.75.0", Some(29597), - Some("plugins are no longer supported")), + Some("plugins are no longer supported"), 116412), /// Allows using `#[plugin_registrar]` on functions. - (removed, plugin_registrar, "1.54.0", Some(29597), - Some("plugins are no longer supported")), + (removed, plugin_registrar, "1.75.0", Some(29597), + Some("plugins are no longer supported"), 116412), /// Allows exhaustive integer pattern matching with `usize::MAX`/`isize::MIN`/`isize::MAX`. - (removed, precise_pointer_size_matching, "1.32.0", Some(56354), - Some("removed in favor of half-open ranges")), + (removed, precise_pointer_size_matching, "1.76.0", Some(56354), + Some("removed in favor of half-open ranges"), 118598), (removed, pref_align_of, "CURRENT_RUSTC_VERSION", Some(91971), Some("removed due to marginal use and inducing compiler complications")), (removed, proc_macro_expr, "1.27.0", Some(54727), - Some("subsumed by `#![feature(proc_macro_hygiene)]`")), + Some("subsumed by `#![feature(proc_macro_hygiene)]`"), 52121), (removed, proc_macro_gen, "1.27.0", Some(54727), - Some("subsumed by `#![feature(proc_macro_hygiene)]`")), + Some("subsumed by `#![feature(proc_macro_hygiene)]`"), 52121), (removed, proc_macro_mod, "1.27.0", Some(54727), - Some("subsumed by `#![feature(proc_macro_hygiene)]`")), + Some("subsumed by `#![feature(proc_macro_hygiene)]`"), 52121), (removed, proc_macro_non_items, "1.27.0", Some(54727), - Some("subsumed by `#![feature(proc_macro_hygiene)]`")), + Some("subsumed by `#![feature(proc_macro_hygiene)]`"), 52121), (removed, pub_macro_rules, "1.53.0", Some(78855), Some("removed due to being incomplete, in particular it does not work across crates")), (removed, pushpop_unsafe, "1.2.0", None, None), (removed, quad_precision_float, "1.0.0", None, None), (removed, quote, "1.33.0", Some(29601), None), - (removed, ref_pat_everywhere, "1.79.0", Some(123076), Some("superseded by `ref_pat_eat_one_layer_2024")), + (removed, ref_pat_everywhere, "1.80.0", Some(123076), Some("superseded by `ref_pat_eat_one_layer_2024"), 125168), (removed, reflect, "1.0.0", Some(27749), None), /// Allows using the `#[register_attr]` attribute. (removed, register_attr, "1.65.0", Some(66080), - Some("removed in favor of `#![register_tool]`")), + Some("removed in favor of `#![register_tool]`"), 66070), (removed, rust_2018_preview, "1.76.0", None, Some("2018 Edition preview is no longer relevant")), /// Allows using the macros: /// + `__diagnostic_used` /// + `__register_diagnostic` /// +`__build_diagnostic_array` - (removed, rustc_diagnostic_macros, "1.38.0", None, None), + (removed, rustc_diagnostic_macros, "1.38.0", None, None, 64139), /// Allows identifying crates that contain sanitizer runtimes. - (removed, sanitizer_runtime, "1.17.0", None, None), + (removed, sanitizer_runtime, "1.17.0", None, None, 65241), (removed, simd, "1.0.0", Some(27731), Some("removed in favor of `#[repr(simd)]`")), /// Allows using `#[start]` on a function indicating that it is the program entrypoint. - (removed, start, "1.0.0", Some(29633), Some("not portable enough and never RFC'd")), + (removed, start, "1.86.0", Some(29633), Some("not portable enough and never RFC'd"), 134299), /// Allows `#[link(kind = "static-nobundle", ...)]`. - (removed, static_nobundle, "1.16.0", Some(37403), - Some(r#"subsumed by `#[link(kind = "static", modifiers = "-bundle", ...)]`"#)), + (removed, static_nobundle, "1.63.0", Some(37403), + Some(r#"subsumed by `#[link(kind = "static", modifiers = "-bundle", ...)]`"#), 95818), (removed, struct_inherit, "1.0.0", None, None), (removed, test_removed_feature, "1.0.0", None, None), /// Allows using items which are missing stability attributes (removed, unmarked_api, "1.0.0", None, None), /// Allows unnamed fields of struct and union type - (removed, unnamed_fields, "1.83.0", Some(49804), Some("feature needs redesign")), + (removed, unnamed_fields, "1.83.0", Some(49804), Some("feature needs redesign"), 131045), (removed, unsafe_no_drop_flag, "1.0.0", None, None), (removed, unsized_tuple_coercion, "1.87.0", Some(42877), - Some("The feature restricts possible layouts for tuples, and this restriction is not worth it.")), + Some("The feature restricts possible layouts for tuples, and this restriction is not worth it."), 137728), /// Allows `union` fields that don't implement `Copy` as long as they don't have any drop glue. - (removed, untagged_unions, "1.13.0", Some(55149), - Some("unions with `Copy` and `ManuallyDrop` fields are stable; there is no intent to stabilize more")), + (removed, untagged_unions, "1.64.0", Some(55149), + Some("unions with `Copy` and `ManuallyDrop` fields are stable; there is no intent to stabilize more"), 97995), /// Allows `#[unwind(..)]`. /// /// Permits specifying whether a function should permit unwinding or abort on unwind. - (removed, unwind_attributes, "1.56.0", Some(58760), Some("use the C-unwind ABI instead")), + (removed, unwind_attributes, "1.56.0", Some(58760), Some("use the C-unwind ABI instead"), 86155), (removed, visible_private_types, "1.0.0", None, None), /// Allows `extern "wasm" fn` (removed, wasm_abi, "1.81.0", Some(83788), - Some("non-standard wasm ABI is no longer supported")), + Some("non-standard wasm ABI is no longer supported"), 127605), // !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! // Features are listed in alphabetical order. Tidy will fail if you don't keep it this way. // !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 9447deeecbb..cfdca8c48b0 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -353,6 +353,8 @@ declare_features! ( (unstable, abi_avr_interrupt, "1.45.0", Some(69664)), /// Allows `extern "C-cmse-nonsecure-call" fn()`. (unstable, abi_c_cmse_nonsecure_call, "1.51.0", Some(81391)), + /// Allows `extern "custom" fn()`. + (unstable, abi_custom, "CURRENT_RUSTC_VERSION", Some(140829)), /// Allows `extern "gpu-kernel" fn()`. (unstable, abi_gpu_kernel, "1.86.0", Some(135467)), /// Allows `extern "msp430-interrupt" fn()`. @@ -546,8 +548,6 @@ declare_features! ( (incomplete, inherent_associated_types, "1.52.0", Some(8995)), /// Allows using `pointer` and `reference` in intra-doc links (unstable, intra_doc_pointers, "1.51.0", Some(80896)), - // Allows using the `kl` and `widekl` target features and the associated intrinsics - (unstable, keylocker_x86, "1.86.0", Some(134813)), // Allows setting the threshold for the `large_assignments` lint. (unstable, large_assignments, "1.52.0", Some(83518)), /// Allow to have type alias types for inter-crate use. diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 6f288bb39b9..336bf0d93fd 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -34,6 +34,7 @@ use crate::def::{CtorKind, DefKind, PerNS, Res}; use crate::def_id::{DefId, LocalDefIdMap}; pub(crate) use crate::hir_id::{HirId, ItemLocalId, ItemLocalMap, OwnerId}; use crate::intravisit::{FnKind, VisitorExt}; +use crate::lints::DelayedLints; #[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable_Generic)] pub enum AngleBrackets { @@ -1526,6 +1527,10 @@ pub struct OwnerInfo<'hir> { /// Map indicating what traits are in scope for places where this /// is relevant; generated by resolve. pub trait_map: ItemLocalMap<Box<[TraitCandidate]>>, + + /// Lints delayed during ast lowering to be emitted + /// after hir has completely built + pub delayed_lints: DelayedLints, } impl<'tcx> OwnerInfo<'tcx> { diff --git a/compiler/rustc_hir/src/lib.rs b/compiler/rustc_hir/src/lib.rs index c6fe475b460..dafd31336fb 100644 --- a/compiler/rustc_hir/src/lib.rs +++ b/compiler/rustc_hir/src/lib.rs @@ -27,6 +27,7 @@ mod hir; pub mod hir_id; pub mod intravisit; pub mod lang_items; +pub mod lints; pub mod pat_util; mod stable_hash_impls; mod target; diff --git a/compiler/rustc_hir/src/lints.rs b/compiler/rustc_hir/src/lints.rs new file mode 100644 index 00000000000..7be6c32e57e --- /dev/null +++ b/compiler/rustc_hir/src/lints.rs @@ -0,0 +1,23 @@ +use rustc_attr_data_structures::lints::AttributeLint; +use rustc_data_structures::fingerprint::Fingerprint; +use rustc_macros::HashStable_Generic; + +use crate::HirId; + +/// During ast lowering, no lints can be emitted. +/// That is because lints attach to nodes either in the AST, or on the built HIR. +/// When attached to AST nodes, they're emitted just before building HIR, +/// and then there's a gap where no lints can be emitted until HIR is done. +/// The variants in this enum represent lints that are temporarily stashed during +/// AST lowering to be emitted once HIR is built. +#[derive(Clone, Debug, HashStable_Generic)] +pub enum DelayedLint { + AttributeParsing(AttributeLint<HirId>), +} + +#[derive(Debug)] +pub struct DelayedLints { + pub lints: Box<[DelayedLint]>, + // Only present when the crate hash is needed. + pub opt_hash: Option<Fingerprint>, +} diff --git a/compiler/rustc_hir/src/stable_hash_impls.rs b/compiler/rustc_hir/src/stable_hash_impls.rs index 91ea88cae47..6acf1524b60 100644 --- a/compiler/rustc_hir/src/stable_hash_impls.rs +++ b/compiler/rustc_hir/src/stable_hash_impls.rs @@ -6,6 +6,7 @@ use crate::hir::{ AttributeMap, BodyId, Crate, ForeignItemId, ImplItemId, ItemId, OwnerNodes, TraitItemId, }; use crate::hir_id::{HirId, ItemLocalId}; +use crate::lints::DelayedLints; /// Requirements for a `StableHashingContext` to be used in this crate. /// This is a hack to allow using the `HashStable_Generic` derive macro @@ -102,6 +103,13 @@ impl<'tcx, HirCtx: crate::HashStableContext> HashStable<HirCtx> for OwnerNodes<' } } +impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for DelayedLints { + fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) { + let DelayedLints { opt_hash, .. } = *self; + opt_hash.unwrap().hash_stable(hcx, hasher); + } +} + impl<'tcx, HirCtx: crate::HashStableContext> HashStable<HirCtx> for AttributeMap<'tcx> { fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) { // We ignore the `map` since it refers to information included in `opt_hash` which is diff --git a/compiler/rustc_hir_analysis/Cargo.toml b/compiler/rustc_hir_analysis/Cargo.toml index 899370b34e4..5d6c49ee862 100644 --- a/compiler/rustc_hir_analysis/Cargo.toml +++ b/compiler/rustc_hir_analysis/Cargo.toml @@ -14,6 +14,7 @@ rustc_abi = { path = "../rustc_abi" } rustc_arena = { path = "../rustc_arena" } rustc_ast = { path = "../rustc_ast" } rustc_attr_data_structures = { path = "../rustc_attr_data_structures" } +rustc_attr_parsing = { path = "../rustc_attr_parsing" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_feature = { path = "../rustc_feature" } diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 4fcd9f8a646..3e98bd213d3 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -1,3 +1,7 @@ +hir_analysis_abi_custom_clothed_function = + items with the `"custom"` ABI can only be declared externally or defined via naked functions + .suggestion = convert this to an `#[unsafe(naked)]` function + hir_analysis_ambiguous_assoc_item = ambiguous associated {$assoc_kind} `{$assoc_ident}` in bounds of `{$qself}` .label = ambiguous associated {$assoc_kind} `{$assoc_ident}` diff --git a/compiler/rustc_hir_analysis/src/autoderef.rs b/compiler/rustc_hir_analysis/src/autoderef.rs index 99e495d9266..c88c534e135 100644 --- a/compiler/rustc_hir_analysis/src/autoderef.rs +++ b/compiler/rustc_hir_analysis/src/autoderef.rs @@ -160,7 +160,7 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> { self.param_env, ty::Binder::dummy(trait_ref), ); - if !self.infcx.predicate_may_hold(&obligation) { + if !self.infcx.next_trait_solver() && !self.infcx.predicate_may_hold(&obligation) { debug!("overloaded_deref_ty: cannot match obligation"); return None; } @@ -184,17 +184,17 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> { self.param_env, ty, ) else { - // We shouldn't have errors here, except for evaluate/fulfill mismatches, - // but that's not a reason for an ICE (`predicate_may_hold` is conservative - // by design). - // FIXME(-Znext-solver): This *actually* shouldn't happen then. + // We shouldn't have errors here in the old solver, except for + // evaluate/fulfill mismatches, but that's not a reason for an ICE. return None; }; let errors = ocx.select_where_possible(); if !errors.is_empty() { - // This shouldn't happen, except for evaluate/fulfill mismatches, - // but that's not a reason for an ICE (`predicate_may_hold` is conservative - // by design). + if self.infcx.next_trait_solver() { + unreachable!(); + } + // We shouldn't have errors here in the old solver, except for + // evaluate/fulfill mismatches, but that's not a reason for an ICE. debug!(?errors, "encountered errors while fulfilling"); return None; } diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 064b42413f0..32fec0604c0 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -21,7 +21,7 @@ use rustc_middle::ty::error::TypeErrorToStringExt; use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES}; use rustc_middle::ty::util::Discr; use rustc_middle::ty::{ - AdtDef, BottomUpFolder, GenericArgKind, RegionKind, TypeFoldable, TypeSuperVisitable, + AdtDef, BottomUpFolder, FnSig, GenericArgKind, RegionKind, TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, fold_regions, }; use rustc_session::lint::builtin::UNINHABITED_STATIC; @@ -37,22 +37,23 @@ use {rustc_attr_data_structures as attrs, rustc_hir as hir}; use super::compare_impl_item::check_type_bounds; use super::*; +fn add_abi_diag_help<T: EmissionGuarantee>(abi: ExternAbi, diag: &mut Diag<'_, T>) { + if let ExternAbi::Cdecl { unwind } = abi { + let c_abi = ExternAbi::C { unwind }; + diag.help(format!("use `extern {c_abi}` instead",)); + } else if let ExternAbi::Stdcall { unwind } = abi { + let c_abi = ExternAbi::C { unwind }; + let system_abi = ExternAbi::System { unwind }; + diag.help(format!( + "if you need `extern {abi}` on win32 and `extern {c_abi}` everywhere else, \ + use `extern {system_abi}`" + )); + } +} + pub fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: ExternAbi) { // FIXME: this should be checked earlier, e.g. in `rustc_ast_lowering`, to fix // things like #86232. - fn add_help<T: EmissionGuarantee>(abi: ExternAbi, diag: &mut Diag<'_, T>) { - if let ExternAbi::Cdecl { unwind } = abi { - let c_abi = ExternAbi::C { unwind }; - diag.help(format!("use `extern {c_abi}` instead",)); - } else if let ExternAbi::Stdcall { unwind } = abi { - let c_abi = ExternAbi::C { unwind }; - let system_abi = ExternAbi::System { unwind }; - diag.help(format!( - "if you need `extern {abi}` on win32 and `extern {c_abi}` everywhere else, \ - use `extern {system_abi}`" - )); - } - } match AbiMap::from_target(&tcx.sess.target).canonize_abi(abi, false) { AbiMapping::Direct(..) => (), @@ -63,13 +64,13 @@ pub fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: ExternAbi E0570, "`{abi}` is not a supported ABI for the current target", ); - add_help(abi, &mut err); + add_abi_diag_help(abi, &mut err); err.emit(); } AbiMapping::Deprecated(..) => { tcx.node_span_lint(UNSUPPORTED_CALLING_CONVENTIONS, hir_id, span, |lint| { lint.primary_message("use of calling convention not supported on this target"); - add_help(abi, lint); + add_abi_diag_help(abi, lint); }); } } @@ -80,7 +81,16 @@ pub fn check_abi_fn_ptr(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Ex // in `check_abi` above. match AbiMap::from_target(&tcx.sess.target).canonize_abi(abi, false) { AbiMapping::Direct(..) => (), - AbiMapping::Deprecated(..) | AbiMapping::Invalid => { + // This is not a redundant match arm: these ABIs started linting after introducing + // UNSUPPORTED_FN_PTR_CALLING_CONVENTIONS already existed and we want to + // avoid expanding the scope of that lint so it can move to a hard error sooner. + AbiMapping::Deprecated(..) => { + tcx.node_span_lint(UNSUPPORTED_CALLING_CONVENTIONS, hir_id, span, |lint| { + lint.primary_message("use of calling convention not supported on this target"); + add_abi_diag_help(abi, lint); + }); + } + AbiMapping::Invalid => { tcx.node_span_lint(UNSUPPORTED_FN_PTR_CALLING_CONVENTIONS, hir_id, span, |lint| { lint.primary_message(format!( "the calling convention {abi} is not supported on this target" @@ -90,6 +100,18 @@ pub fn check_abi_fn_ptr(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Ex } } +pub fn check_custom_abi(tcx: TyCtxt<'_>, def_id: LocalDefId, fn_sig: FnSig<'_>, fn_sig_span: Span) { + if fn_sig.abi == ExternAbi::Custom { + // Function definitions that use `extern "custom"` must be naked functions. + if !tcx.has_attr(def_id, sym::naked) { + tcx.dcx().emit_err(crate::errors::AbiCustomClothedFunction { + span: fn_sig_span, + naked_span: tcx.def_span(def_id).shrink_to_lo(), + }); + } + } +} + fn check_struct(tcx: TyCtxt<'_>, def_id: LocalDefId) { let def = tcx.adt_def(def_id); let span = tcx.def_span(def_id); diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 481cdaa4c6c..060fc51b7bd 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -71,7 +71,7 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi | sym::box_new | sym::breakpoint | sym::size_of - | sym::min_align_of + | sym::align_of | sym::needs_drop | sym::caller_location | sym::add_with_overflow @@ -200,10 +200,8 @@ pub(crate) fn check_intrinsic_type( sym::abort => (0, 0, vec![], tcx.types.never), sym::unreachable => (0, 0, vec![], tcx.types.never), sym::breakpoint => (0, 0, vec![], tcx.types.unit), - sym::size_of | sym::pref_align_of | sym::min_align_of | sym::variant_count => { - (1, 0, vec![], tcx.types.usize) - } - sym::size_of_val | sym::min_align_of_val => { + sym::size_of | sym::align_of | sym::variant_count => (1, 0, vec![], tcx.types.usize), + sym::size_of_val | sym::align_of_val => { (1, 0, vec![Ty::new_imm_ptr(tcx, param(0))], tcx.types.usize) } sym::rustc_peek => (1, 0, vec![param(0)], param(0)), diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index fad8abf5fae..c5c7e6b2aa7 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -72,7 +72,7 @@ pub mod wfcheck; use std::num::NonZero; -pub use check::{check_abi, check_abi_fn_ptr}; +pub use check::{check_abi, check_abi_fn_ptr, check_custom_abi}; use rustc_abi::{ExternAbi, VariantIdx}; use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_errors::{Diag, ErrorGuaranteed, pluralize, struct_span_code_err}; diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index e1df0d60452..6e22ac5a28a 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -494,7 +494,7 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> { // Only visit the type looking for `_` if we didn't fix the type above visitor.visit_ty_unambig(a); - self.lowerer().lower_arg_ty(a, None) + self.lowerer().lower_ty(a) }) .collect(); diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index a27d1ed6c53..809cb311c1f 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -1698,3 +1698,17 @@ pub(crate) struct SelfInTypeAlias { #[label] pub span: Span, } + +#[derive(Diagnostic)] +#[diag(hir_analysis_abi_custom_clothed_function)] +pub(crate) struct AbiCustomClothedFunction { + #[primary_span] + pub span: Span, + #[suggestion( + hir_analysis_suggestion, + applicability = "maybe-incorrect", + code = "#[unsafe(naked)]\n", + style = "short" + )] + pub naked_span: Span, +} diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 4c65d0d0510..bf407cbaccb 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -805,7 +805,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref, polarity }) }); let bound = (bound.upcast(tcx), span); - // FIXME(-Znext-solver): We can likely remove this hack once the new trait solver lands. + // FIXME(-Znext-solver): We can likely remove this hack once the + // new trait solver lands. This fixed an overflow in the old solver. + // This may have performance implications, so please check perf when + // removing it. + // This was added in <https://github.com/rust-lang/rust/pull/123302>. if tcx.is_lang_item(trait_def_id, rustc_hir::LangItem::Sized) { bounds.insert(0, bound); } else { @@ -2704,16 +2708,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } } - pub fn lower_arg_ty(&self, ty: &hir::Ty<'tcx>, expected_ty: Option<Ty<'tcx>>) -> Ty<'tcx> { - match ty.kind { - hir::TyKind::Infer(()) if let Some(expected_ty) = expected_ty => { - self.record_ty(ty.hir_id, expected_ty, ty.span); - expected_ty - } - _ => self.lower_ty(ty), - } - } - /// Lower a function type from the HIR to our internal notion of a function signature. #[instrument(level = "debug", skip(self, hir_id, safety, abi, decl, generics, hir_ty), ret)] pub fn lower_fn_ty( diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index a92ee89186c..007f3a6abf6 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -92,8 +92,9 @@ mod variance; pub use errors::NoVariantNamed; use rustc_abi::ExternAbi; -use rustc_hir as hir; use rustc_hir::def::DefKind; +use rustc_hir::lints::DelayedLint; +use rustc_hir::{self as hir}; use rustc_middle::middle; use rustc_middle::mir::interpret::GlobalId; use rustc_middle::query::Providers; @@ -174,6 +175,14 @@ pub fn provide(providers: &mut Providers) { }; } +fn emit_delayed_lint(lint: &DelayedLint, tcx: TyCtxt<'_>) { + match lint { + DelayedLint::AttributeParsing(attribute_lint) => { + rustc_attr_parsing::emit_attribute_lint(attribute_lint, tcx) + } + } +} + pub fn check_crate(tcx: TyCtxt<'_>) { let _prof_timer = tcx.sess.timer("type_check_crate"); @@ -192,6 +201,14 @@ pub fn check_crate(tcx: TyCtxt<'_>) { let _: R = tcx.ensure_ok().crate_inherent_impls_overlap_check(()); }); + for owner_id in tcx.hir_crate_items(()).owners() { + if let Some(delayed_lints) = tcx.opt_ast_lowering_delayed_lints(owner_id) { + for lint in &delayed_lints.lints { + emit_delayed_lint(lint, tcx); + } + } + } + tcx.par_hir_body_owners(|item_def_id| { let def_kind = tcx.def_kind(item_def_id); // Make sure we evaluate all static and (non-associated) const items, even if unused. diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl index 6c33dfb4ec0..ac7ff65528d 100644 --- a/compiler/rustc_hir_typeck/messages.ftl +++ b/compiler/rustc_hir_typeck/messages.ftl @@ -1,3 +1,7 @@ +hir_typeck_abi_custom_call = + functions with the `"custom"` ABI cannot be called + .note = an `extern "custom"` function can only be called from within inline assembly + hir_typeck_add_missing_parentheses_in_range = you must surround the range in parentheses to call its `{$func_name}` function hir_typeck_add_return_type_add = try adding a return type @@ -17,6 +21,24 @@ hir_typeck_base_expression_double_dot_enable_default_field_values = add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields hir_typeck_base_expression_double_dot_remove = remove the `..` as all the fields are already present +hir_typeck_break_inside_closure = + `{$name}` inside of a closure + .label = cannot `{$name}` inside of a closure + .closure_label = enclosing closure + +hir_typeck_break_inside_coroutine = + `{$name}` inside `{$kind}` {$source} + .label = cannot `{$name}` inside `{$kind}` {$source} + .coroutine_label = enclosing `{$kind}` {$source} + +hir_typeck_break_non_loop = + `break` with value from a `{$kind}` loop + .label = can only break with a value inside `loop` or breakable block + .label2 = you can't `break` with a value in a `{$kind}` loop + .suggestion = use `break` on its own without a value inside this `{$kind}` loop + .break_expr_suggestion = alternatively, you might have meant to use the available loop label + + hir_typeck_candidate_trait_note = `{$trait_name}` defines an item `{$item_name}`{$action_or_ty -> [NONE] {""} [implement] , perhaps you need to implement it @@ -64,6 +86,12 @@ hir_typeck_const_select_must_be_fn = this argument must be a function item .note = expected a function item, found {$ty} .help = consult the documentation on `const_eval_select` for more information +hir_typeck_continue_labeled_block = + `continue` pointing to a labeled block + .label = labeled blocks cannot be `continue`'d + .block_label = labeled block the `continue` points to + + hir_typeck_convert_to_str = try converting the passed type into a `&str` hir_typeck_convert_using_method = try using `{$sugg}` to convert `{$found}` to `{$expected}` @@ -182,6 +210,19 @@ hir_typeck_option_result_asref = use `{$def_path}::as_ref` to convert `{$expecte hir_typeck_option_result_cloned = use `{$def_path}::cloned` to clone the value inside the `{$def_path}` hir_typeck_option_result_copied = use `{$def_path}::copied` to copy the value inside the `{$def_path}` +hir_typeck_outside_loop = + `{$name}` outside of a loop{$is_break -> + [true] {" or labeled block"} + *[false] {""} + } + .label = cannot `{$name}` outside of a loop{$is_break -> + [true] {" or labeled block"} + *[false] {""} + } + +hir_typeck_outside_loop_suggestion = consider labeling this block to be able to break within it + + hir_typeck_params_not_allowed = referencing function parameters is not allowed in naked functions .help = follow the calling convention in asm block to use parameters @@ -254,6 +295,13 @@ hir_typeck_union_pat_dotdot = `..` cannot be used in union patterns hir_typeck_union_pat_multiple_fields = union patterns should have exactly one field +hir_typeck_unlabeled_cf_in_while_condition = + `break` or `continue` with no label in the condition of a `while` loop + .label = unlabeled `{$cf_type}` in the condition of a `while` loop + +hir_typeck_unlabeled_in_labeled_block = + unlabeled `{$cf_type}` inside of a labeled block + .label = `{$cf_type}` statements that would diverge to or through a labeled block need to bear a label hir_typeck_use_is_empty = consider using the `is_empty` method on `{$expr_ty}` to determine if it contains anything diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs index 61dd8c57307..4ac260cb15f 100644 --- a/compiler/rustc_hir_typeck/src/_match.rs +++ b/compiler/rustc_hir_typeck/src/_match.rs @@ -600,7 +600,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let (def_id, args) = match *expected_ty.kind() { // FIXME: Could also check that the RPIT is not defined ty::Alias(ty::Opaque, alias_ty) => (alias_ty.def_id.as_local()?, alias_ty.args), - // FIXME(-Znext-solver): Remove this branch once `replace_opaque_types_with_infer` is gone. + // FIXME(-Znext-solver=no): Remove this branch once `replace_opaque_types_with_infer` is gone. ty::Infer(ty::TyVar(_)) => self .inner .borrow_mut() diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index d173fe7c2c2..e915b4fc626 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -1,5 +1,6 @@ use std::iter; +use rustc_abi::ExternAbi; use rustc_ast::util::parser::ExprPrecedence; use rustc_errors::{Applicability, Diag, ErrorGuaranteed, StashKey}; use rustc_hir::def::{self, CtorKind, Namespace, Res}; @@ -83,6 +84,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { while result.is_none() && autoderef.next().is_some() { result = self.try_overloaded_call_step(call_expr, callee_expr, arg_exprs, &autoderef); } + self.check_call_custom_abi(autoderef.final_ty(false), call_expr.span); self.register_predicates(autoderef.into_obligations()); let output = match result { @@ -135,6 +137,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { output } + /// Functions of type `extern "custom" fn(/* ... */)` cannot be called using `ExprKind::Call`. + /// + /// These functions have a calling convention that is unknown to rust, hence it cannot generate + /// code for the call. The only way to execute such a function is via inline assembly. + fn check_call_custom_abi(&self, callee_ty: Ty<'tcx>, span: Span) { + let abi = match callee_ty.kind() { + ty::FnDef(def_id, _) => self.tcx.fn_sig(def_id).skip_binder().skip_binder().abi, + ty::FnPtr(_, header) => header.abi, + _ => return, + }; + + if let ExternAbi::Custom = abi { + self.tcx.dcx().emit_err(errors::AbiCustomCall { span }); + } + } + #[instrument(level = "debug", skip(self, call_expr, callee_expr, arg_exprs, autoderef), ret)] fn try_overloaded_call_step( &self, diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index 152c88ad92a..5b55fbe9150 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -260,7 +260,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { mut expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>, allow_two_phase: AllowTwoPhase, ) -> Result<Ty<'tcx>, Diag<'a>> { - let expected = self.resolve_vars_with_obligations(expected); + let expected = if self.next_trait_solver() { + expected + } else { + self.resolve_vars_with_obligations(expected) + }; let e = match self.coerce(expr, checked_ty, expected, allow_two_phase, None) { Ok(ty) => return Ok(ty), diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index 97a90548fc5..abb8cdc1cdf 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -2,11 +2,14 @@ use std::borrow::Cow; +use rustc_ast::Label; use rustc_errors::codes::*; use rustc_errors::{ Applicability, Diag, DiagArgValue, DiagCtxtHandle, DiagSymbolList, Diagnostic, EmissionGuarantee, IntoDiagArg, Level, MultiSpan, Subdiagnostic, }; +use rustc_hir as hir; +use rustc_hir::ExprKind; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_middle::ty::{self, Ty}; use rustc_span::edition::{Edition, LATEST_STABLE_EDITION}; @@ -721,6 +724,131 @@ pub(crate) struct TrivialCast<'tcx> { pub cast_ty: Ty<'tcx>, } +pub(crate) struct BreakNonLoop<'a> { + pub span: Span, + pub head: Option<Span>, + pub kind: &'a str, + pub suggestion: String, + pub loop_label: Option<Label>, + pub break_label: Option<Label>, + pub break_expr_kind: &'a ExprKind<'a>, + pub break_expr_span: Span, +} + +impl<'a, G: EmissionGuarantee> Diagnostic<'_, G> for BreakNonLoop<'a> { + #[track_caller] + fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { + let mut diag = Diag::new(dcx, level, fluent::hir_typeck_break_non_loop); + diag.span(self.span); + diag.code(E0571); + diag.arg("kind", self.kind); + diag.span_label(self.span, fluent::hir_typeck_label); + if let Some(head) = self.head { + diag.span_label(head, fluent::hir_typeck_label2); + } + diag.span_suggestion( + self.span, + fluent::hir_typeck_suggestion, + self.suggestion, + Applicability::MaybeIncorrect, + ); + if let (Some(label), None) = (self.loop_label, self.break_label) { + match self.break_expr_kind { + ExprKind::Path(hir::QPath::Resolved( + None, + hir::Path { segments: [segment], res: hir::def::Res::Err, .. }, + )) if label.ident.to_string() == format!("'{}", segment.ident) => { + // This error is redundant, we will have already emitted a + // suggestion to use the label when `segment` wasn't found + // (hence the `Res::Err` check). + diag.downgrade_to_delayed_bug(); + } + _ => { + diag.span_suggestion( + self.break_expr_span, + fluent::hir_typeck_break_expr_suggestion, + label.ident, + Applicability::MaybeIncorrect, + ); + } + } + } + diag + } +} + +#[derive(Diagnostic)] +#[diag(hir_typeck_continue_labeled_block, code = E0696)] +pub(crate) struct ContinueLabeledBlock { + #[primary_span] + #[label] + pub span: Span, + #[label(hir_typeck_block_label)] + pub block_span: Span, +} + +#[derive(Diagnostic)] +#[diag(hir_typeck_break_inside_closure, code = E0267)] +pub(crate) struct BreakInsideClosure<'a> { + #[primary_span] + #[label] + pub span: Span, + #[label(hir_typeck_closure_label)] + pub closure_span: Span, + pub name: &'a str, +} + +#[derive(Diagnostic)] +#[diag(hir_typeck_break_inside_coroutine, code = E0267)] +pub(crate) struct BreakInsideCoroutine<'a> { + #[primary_span] + #[label] + pub span: Span, + #[label(hir_typeck_coroutine_label)] + pub coroutine_span: Span, + pub name: &'a str, + pub kind: &'a str, + pub source: &'a str, +} + +#[derive(Diagnostic)] +#[diag(hir_typeck_outside_loop, code = E0268)] +pub(crate) struct OutsideLoop<'a> { + #[primary_span] + #[label] + pub spans: Vec<Span>, + pub name: &'a str, + pub is_break: bool, + #[subdiagnostic] + pub suggestion: Option<OutsideLoopSuggestion>, +} +#[derive(Subdiagnostic)] +#[multipart_suggestion(hir_typeck_outside_loop_suggestion, applicability = "maybe-incorrect")] +pub(crate) struct OutsideLoopSuggestion { + #[suggestion_part(code = "'block: ")] + pub block_span: Span, + #[suggestion_part(code = " 'block")] + pub break_spans: Vec<Span>, +} + +#[derive(Diagnostic)] +#[diag(hir_typeck_unlabeled_in_labeled_block, code = E0695)] +pub(crate) struct UnlabeledInLabeledBlock<'a> { + #[primary_span] + #[label] + pub span: Span, + pub cf_type: &'a str, +} + +#[derive(Diagnostic)] +#[diag(hir_typeck_unlabeled_cf_in_while_condition, code = E0590)] +pub(crate) struct UnlabeledCfInWhileCondition<'a> { + #[primary_span] + #[label] + pub span: Span, + pub cf_type: &'a str, +} + #[derive(Diagnostic)] #[diag(hir_typeck_no_associated_item, code = E0599)] pub(crate) struct NoAssociatedItem { @@ -1035,3 +1163,10 @@ pub(crate) struct NakedFunctionsMustNakedAsm { #[label] pub span: Span, } + +#[derive(Diagnostic)] +#[diag(hir_typeck_abi_custom_call)] +pub(crate) struct AbiCustomCall { + #[primary_span] + pub span: Span, +} diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index dfc7935d02b..87682d52dbf 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -5,7 +5,7 @@ //! //! See [`rustc_hir_analysis::check`] for more context on type checking in general. -use rustc_abi::{FIRST_VARIANT, FieldIdx}; +use rustc_abi::{ExternAbi, FIRST_VARIANT, FieldIdx}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::unord::UnordMap; @@ -1627,6 +1627,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Some(method.def_id), ); + // Functions of type `extern "custom" fn(/* ... */)` cannot be called using + // `ExprKind::MethodCall`. These functions have a calling convention that is + // unknown to rust, hence it cannot generate code for the call. The only way + // to execute such a function is via inline assembly. + if let ExternAbi::Custom = method.sig.abi { + self.tcx.dcx().emit_err(crate::errors::AbiCustomCall { span: expr.span }); + } + method.sig.output() } Err(error) => { diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 8a90e768d70..a43449a8f99 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -1436,8 +1436,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// in this case. #[instrument(level = "debug", skip(self, sp), ret)] pub(crate) fn try_structurally_resolve_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> { - let ty = self.resolve_vars_with_obligations(ty); - if self.next_trait_solver() && let ty::Alias(..) = ty.kind() { @@ -1455,7 +1453,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } } else { - ty + self.resolve_vars_with_obligations(ty) } } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs index 7f1f3c3c802..e4c62bf027b 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs @@ -120,15 +120,7 @@ impl<'a, 'tcx> ProofTreeVisitor<'tcx> for NestedObligationsForSelfTy<'a, 'tcx> { fn visit_goal(&mut self, inspect_goal: &InspectGoal<'_, 'tcx>) { // No need to walk into goal subtrees that certainly hold, since they // wouldn't then be stalled on an infer var. - // FIXME: We also walk into normalizes-to goals since their certainty - // is forced to `Certainty::Yes` since they pass down ambiguous subgoals - // to their parent. - if inspect_goal.result() == Ok(Certainty::Yes) - && !matches!( - inspect_goal.goal().predicate.kind().skip_binder(), - ty::PredicateKind::NormalizesTo(_) - ) - { + if inspect_goal.result() == Ok(Certainty::Yes) { return; } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index a5c0829b8d9..e979798a402 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -382,7 +382,7 @@ impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> { _hir_id: rustc_hir::HirId, _hir_ty: Option<&hir::Ty<'_>>, ) -> (Vec<Ty<'tcx>>, Ty<'tcx>) { - let input_tys = decl.inputs.iter().map(|a| self.lowerer().lower_arg_ty(a, None)).collect(); + let input_tys = decl.inputs.iter().map(|a| self.lowerer().lower_ty(a)).collect(); let output_ty = match decl.output { hir::FnRetTy::Return(output) => self.lowerer().lower_ty(output), @@ -412,9 +412,10 @@ pub(crate) struct LoweredTy<'tcx> { impl<'tcx> LoweredTy<'tcx> { fn from_raw(fcx: &FnCtxt<'_, 'tcx>, span: Span, raw: Ty<'tcx>) -> LoweredTy<'tcx> { - // FIXME(-Znext-solver): We're still figuring out how to best handle - // normalization and this doesn't feel too great. We should look at this - // code again before stabilizing it. + // FIXME(-Znext-solver=no): This is easier than requiring all uses of `LoweredTy` + // to call `try_structurally_resolve_type` instead. This seems like a lot of + // effort, especially as we're still supporting the old solver. We may revisit + // this in the future. let normalized = if fcx.next_trait_solver() { fcx.try_structurally_resolve_type(span, raw) } else { diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 741a616631a..043a687914b 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -28,6 +28,7 @@ mod fallback; mod fn_ctxt; mod gather_locals; mod intrinsicck; +mod loops; mod method; mod naked_functions; mod op; @@ -47,7 +48,7 @@ use rustc_errors::{Applicability, ErrorGuaranteed, pluralize, struct_span_code_e use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{HirId, HirIdMap, Node}; -use rustc_hir_analysis::check::check_abi; +use rustc_hir_analysis::check::{check_abi, check_custom_abi}; use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer; use rustc_infer::traits::{ObligationCauseCode, ObligationInspector, WellFormedLoc}; use rustc_middle::query::Providers; @@ -137,7 +138,7 @@ fn typeck_with_inspect<'tcx>( // for visit the asm expr of the body. let ty = fcx.check_expr(body.value); fcx.write_ty(id, ty); - } else if let Some(hir::FnSig { header, decl, .. }) = node.fn_sig() { + } else if let Some(hir::FnSig { header, decl, span: fn_sig_span }) = node.fn_sig() { let fn_sig = if decl.output.is_suggestable_infer_ty().is_some() { // In the case that we're recovering `fn() -> W<_>` or some other return // type that has an infer in it, lower the type directly so that it'll @@ -149,6 +150,9 @@ fn typeck_with_inspect<'tcx>( }; check_abi(tcx, id, span, fn_sig.abi()); + check_custom_abi(tcx, def_id, fn_sig.skip_binder(), *fn_sig_span); + + loops::check(tcx, def_id, body); // Compute the function signature from point of view of inside the fn. let mut fn_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), fn_sig); @@ -189,6 +193,8 @@ fn typeck_with_inspect<'tcx>( tcx.type_of(def_id).instantiate_identity() }; + loops::check(tcx, def_id, body); + let expected_type = fcx.normalize(body.value.span, expected_type); let wf_code = ObligationCauseCode::WellFormed(Some(WellFormedLoc::Ty(def_id))); diff --git a/compiler/rustc_passes/src/loops.rs b/compiler/rustc_hir_typeck/src/loops.rs index b06f16cc7bd..b06e0704b6f 100644 --- a/compiler/rustc_passes/src/loops.rs +++ b/compiler/rustc_hir_typeck/src/loops.rs @@ -3,11 +3,11 @@ use std::fmt; use Context::*; use rustc_hir as hir; -use rustc_hir::def_id::{LocalDefId, LocalModDefId}; +use rustc_hir::def::DefKind; +use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{Destination, Node}; use rustc_middle::hir::nested_filter; -use rustc_middle::query::Providers; use rustc_middle::span_bug; use rustc_middle::ty::TyCtxt; use rustc_span::hygiene::DesugaringKind; @@ -73,17 +73,17 @@ struct CheckLoopVisitor<'tcx> { block_breaks: BTreeMap<Span, BlockInfo>, } -fn check_mod_loops(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) { +pub(crate) fn check<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &'tcx hir::Body<'tcx>) { let mut check = CheckLoopVisitor { tcx, cx_stack: vec![Normal], block_breaks: Default::default() }; - tcx.hir_visit_item_likes_in_module(module_def_id, &mut check); + let cx = match tcx.def_kind(def_id) { + DefKind::AnonConst => AnonConst, + _ => Fn, + }; + check.with_context(cx, |v| v.visit_body(body)); check.report_outside_loop_error(); } -pub(crate) fn provide(providers: &mut Providers) { - *providers = Providers { check_mod_loops, ..*providers }; -} - impl<'hir> Visitor<'hir> for CheckLoopVisitor<'hir> { type NestedFilter = nested_filter::OnlyBodies; @@ -91,33 +91,14 @@ impl<'hir> Visitor<'hir> for CheckLoopVisitor<'hir> { self.tcx } - fn visit_anon_const(&mut self, c: &'hir hir::AnonConst) { - self.with_context(AnonConst, |v| intravisit::walk_anon_const(v, c)); + fn visit_anon_const(&mut self, _: &'hir hir::AnonConst) { + // Typecked on its own. } fn visit_inline_const(&mut self, c: &'hir hir::ConstBlock) { self.with_context(ConstBlock, |v| intravisit::walk_inline_const(v, c)); } - fn visit_fn( - &mut self, - fk: hir::intravisit::FnKind<'hir>, - fd: &'hir hir::FnDecl<'hir>, - b: hir::BodyId, - _: Span, - id: LocalDefId, - ) { - self.with_context(Fn, |v| intravisit::walk_fn(v, fk, fd, b, id)); - } - - fn visit_trait_item(&mut self, trait_item: &'hir hir::TraitItem<'hir>) { - self.with_context(Fn, |v| intravisit::walk_trait_item(v, trait_item)); - } - - fn visit_impl_item(&mut self, impl_item: &'hir hir::ImplItem<'hir>) { - self.with_context(Fn, |v| intravisit::walk_impl_item(v, impl_item)); - } - fn visit_expr(&mut self, e: &'hir hir::Expr<'hir>) { match e.kind { hir::ExprKind::If(cond, then, else_opt) => { diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 725240b480b..a3fdf200c8e 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -1913,8 +1913,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { ty::Binder::dummy(trait_ref), ); - // FIXME(-Znext-solver): We only need this hack to deal with fatal - // overflow in the old solver. + // We only need this hack to deal with fatal overflow in the old solver. if self.infcx.next_trait_solver() || self.infcx.predicate_may_hold(&obligation) { ocx.register_obligation(obligation); @@ -1955,17 +1954,17 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } } - // FIXME(-Znext-solver): See the linked issue below. - // <https://github.com/rust-lang/trait-system-refactor-initiative/issues/134> + // See <https://github.com/rust-lang/trait-system-refactor-initiative/issues/134>. // // In the new solver, check the well-formedness of the return type. // This emulates, in a way, the predicates that fall out of // normalizing the return type in the old solver. // - // We alternatively could check the predicates of the method itself hold, - // but we intentionally do not do this in the old solver b/c of cycles, - // and doing it in the new solver would be stronger. This should be fixed - // in the future, since it likely leads to much better method winnowing. + // FIXME(-Znext-solver): We alternatively could check the predicates of + // the method itself hold, but we intentionally do not do this in the old + // solver b/c of cycles, and doing it in the new solver would be stronger. + // This should be fixed in the future, since it likely leads to much better + // method winnowing. if let Some(xform_ret_ty) = xform_ret_ty && self.infcx.next_trait_solver() { diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 2fac13b7201..6cb53bbd745 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -14,7 +14,9 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::sorted_map::SortedMap; use rustc_data_structures::unord::UnordSet; use rustc_errors::codes::*; -use rustc_errors::{Applicability, Diag, MultiSpan, StashKey, pluralize, struct_span_code_err}; +use rustc_errors::{ + Applicability, Diag, DiagStyledString, MultiSpan, StashKey, pluralize, struct_span_code_err, +}; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{self, Visitor}; @@ -1569,7 +1571,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } - if rcvr_ty.is_numeric() && rcvr_ty.is_fresh() || restrict_type_params || suggested_derive { + if rcvr_ty.is_numeric() && rcvr_ty.is_fresh() + || restrict_type_params + || suggested_derive + || self.lookup_alternative_tuple_impls(&mut err, &unsatisfied_predicates) + { } else { self.suggest_traits_to_import( &mut err, @@ -1744,6 +1750,119 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.emit() } + /// If the predicate failure is caused by an unmet bound on a tuple, recheck if the bound would + /// succeed if all the types on the tuple had no borrows. This is a common problem for libraries + /// like Bevy and ORMs, which rely heavily on traits being implemented on tuples. + fn lookup_alternative_tuple_impls( + &self, + err: &mut Diag<'_>, + unsatisfied_predicates: &[( + ty::Predicate<'tcx>, + Option<ty::Predicate<'tcx>>, + Option<ObligationCause<'tcx>>, + )], + ) -> bool { + let mut found_tuple = false; + for (pred, root, _ob) in unsatisfied_predicates { + let mut preds = vec![pred]; + if let Some(root) = root { + // We will look at both the current predicate and the root predicate that caused it + // to be needed. If calling something like `<(A, &B)>::default()`, then `pred` is + // `&B: Default` and `root` is `(A, &B): Default`, which is the one we are checking + // for further down, so we check both. + preds.push(root); + } + for pred in preds { + if let Some(clause) = pred.as_clause() + && let Some(clause) = clause.as_trait_clause() + && let ty = clause.self_ty().skip_binder() + && let ty::Tuple(types) = ty.kind() + { + let path = clause.skip_binder().trait_ref.print_only_trait_path(); + let def_id = clause.def_id(); + let ty = Ty::new_tup( + self.tcx, + self.tcx.mk_type_list_from_iter(types.iter().map(|ty| ty.peel_refs())), + ); + let args = ty::GenericArgs::for_item(self.tcx, def_id, |param, _| { + if param.index == 0 { + ty.into() + } else { + self.infcx.var_for_def(DUMMY_SP, param) + } + }); + if self + .infcx + .type_implements_trait(def_id, args, self.param_env) + .must_apply_modulo_regions() + { + // "`Trait` is implemented for `(A, B)` but not for `(A, &B)`" + let mut msg = DiagStyledString::normal(format!("`{path}` ")); + msg.push_highlighted("is"); + msg.push_normal(" implemented for `("); + let len = types.len(); + for (i, t) in types.iter().enumerate() { + msg.push( + format!("{}", with_forced_trimmed_paths!(t.peel_refs())), + t.peel_refs() != t, + ); + if i < len - 1 { + msg.push_normal(", "); + } + } + msg.push_normal(")` but "); + msg.push_highlighted("not"); + msg.push_normal(" for `("); + for (i, t) in types.iter().enumerate() { + msg.push( + format!("{}", with_forced_trimmed_paths!(t)), + t.peel_refs() != t, + ); + if i < len - 1 { + msg.push_normal(", "); + } + } + msg.push_normal(")`"); + + // Find the span corresponding to the impl that was found to point at it. + if let Some(impl_span) = self + .tcx + .all_impls(def_id) + .filter(|&impl_def_id| { + let header = self.tcx.impl_trait_header(impl_def_id).unwrap(); + let trait_ref = header.trait_ref.instantiate( + self.tcx, + self.infcx.fresh_args_for_item(DUMMY_SP, impl_def_id), + ); + + let value = ty::fold_regions(self.tcx, ty, |_, _| { + self.tcx.lifetimes.re_erased + }); + // FIXME: Don't bother dealing with non-lifetime binders here... + if value.has_escaping_bound_vars() { + return false; + } + self.infcx.can_eq(ty::ParamEnv::empty(), trait_ref.self_ty(), value) + && header.polarity == ty::ImplPolarity::Positive + }) + .map(|impl_def_id| self.tcx.def_span(impl_def_id)) + .next() + { + err.highlighted_span_note(impl_span, msg.0); + } else { + err.highlighted_note(msg.0); + } + found_tuple = true; + } + // If `pred` was already on the tuple, we don't need to look at the root + // obligation too. + break; + } + } + } + found_tuple + } + /// If an appropriate error source is not found, check method chain for possible candidates fn lookup_segments_chain_for_no_match_method( &self, diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index 10827c9fd03..db937b3e83e 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -198,8 +198,11 @@ impl<'tcx> InferCtxt<'tcx> { } if !self.tcx.recursion_limit().value_within_limit(iteration) { + // This may actually be reachable. If so, we should convert + // this to a proper error/consider whether we should detect + // this somewhere else. bug!( - "FIXME(-Znext-solver): Overflowed when processing region obligations: {my_region_obligations:#?}" + "unexpected overflowed when processing region obligations: {my_region_obligations:#?}" ); } diff --git a/compiler/rustc_infer/src/infer/type_variable.rs b/compiler/rustc_infer/src/infer/type_variable.rs index 2086483b94a..6f6791804d3 100644 --- a/compiler/rustc_infer/src/infer/type_variable.rs +++ b/compiler/rustc_infer/src/infer/type_variable.rs @@ -238,6 +238,9 @@ impl<'tcx> ut::UnifyKey for TyVidEqKey<'tcx> { fn tag() -> &'static str { "TyVidEqKey" } + fn order_roots(a: Self, _: &Self::Value, b: Self, _: &Self::Value) -> Option<(Self, Self)> { + if a.vid.as_u32() < b.vid.as_u32() { Some((a, b)) } else { Some((b, a)) } + } } impl<'tcx> ut::UnifyValue for TypeVariableValue<'tcx> { diff --git a/compiler/rustc_infer/src/infer/unify_key.rs b/compiler/rustc_infer/src/infer/unify_key.rs index 3ba8aea1d3a..5e5d0e063a0 100644 --- a/compiler/rustc_infer/src/infer/unify_key.rs +++ b/compiler/rustc_infer/src/infer/unify_key.rs @@ -137,6 +137,9 @@ impl<'tcx> UnifyKey for ConstVidKey<'tcx> { fn tag() -> &'static str { "ConstVidKey" } + fn order_roots(a: Self, _: &Self::Value, b: Self, _: &Self::Value) -> Option<(Self, Self)> { + if a.vid.as_u32() < b.vid.as_u32() { Some((a, b)) } else { Some((b, a)) } + } } impl<'tcx> UnifyValue for ConstVariableValue<'tcx> { diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 2643e5c1926..0238d6a3947 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -8,9 +8,9 @@ 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}; +use rustc_data_structures::{parallel, thousands}; use rustc_expand::base::{ExtCtxt, LintStoreExpand}; use rustc_feature::Features; use rustc_fs_util::try_canonicalize; @@ -35,7 +35,8 @@ use rustc_session::parse::feature_err; use rustc_session::search_paths::PathKind; use rustc_session::{Limit, Session}; use rustc_span::{ - DUMMY_SP, ErrorGuaranteed, FileName, SourceFileHash, SourceFileHashAlgorithm, Span, Symbol, sym, + DUMMY_SP, ErrorGuaranteed, ExpnKind, FileName, SourceFileHash, SourceFileHashAlgorithm, Span, + Symbol, sym, }; use rustc_target::spec::PanicStrategy; use rustc_trait_selection::traits; @@ -205,7 +206,7 @@ fn configure_and_expand( // Expand macros now! let krate = sess.time("expand_crate", || ecx.monotonic_expander().expand_crate(krate)); - // The rest is error reporting + // The rest is error reporting and stats sess.psess.buffered_lints.with_lock(|buffered_lints: &mut Vec<BufferedEarlyLint>| { buffered_lints.append(&mut ecx.buffered_early_lint); @@ -228,6 +229,10 @@ fn configure_and_expand( } } + if ecx.sess.opts.unstable_opts.macro_stats { + print_macro_stats(&ecx); + } + krate }); @@ -288,6 +293,76 @@ fn configure_and_expand( krate } +fn print_macro_stats(ecx: &ExtCtxt<'_>) { + use std::fmt::Write; + + // No instability because we immediately sort the produced vector. + #[allow(rustc::potential_query_instability)] + let mut macro_stats: Vec<_> = ecx + .macro_stats + .iter() + .map(|((name, kind), stat)| { + // This gives the desired sort order: sort by bytes, then lines, etc. + (stat.bytes, stat.lines, stat.uses, name, *kind) + }) + .collect(); + macro_stats.sort_unstable(); + macro_stats.reverse(); // bigger items first + + let prefix = "macro-stats"; + let name_w = 32; + let uses_w = 7; + let lines_w = 11; + let avg_lines_w = 11; + let bytes_w = 11; + let avg_bytes_w = 11; + let banner_w = name_w + uses_w + lines_w + avg_lines_w + bytes_w + avg_bytes_w; + + // We write all the text into a string and print it with a single + // `eprint!`. This is an attempt to minimize interleaved text if multiple + // rustc processes are printing macro-stats at the same time (e.g. with + // `RUSTFLAGS='-Zmacro-stats' cargo build`). It still doesn't guarantee + // non-interleaving, though. + let mut s = String::new(); + _ = writeln!(s, "{prefix} {}", "=".repeat(banner_w)); + _ = writeln!(s, "{prefix} MACRO EXPANSION STATS: {}", ecx.ecfg.crate_name); + _ = writeln!( + s, + "{prefix} {:<name_w$}{:>uses_w$}{:>lines_w$}{:>avg_lines_w$}{:>bytes_w$}{:>avg_bytes_w$}", + "Macro Name", "Uses", "Lines", "Avg Lines", "Bytes", "Avg Bytes", + ); + _ = writeln!(s, "{prefix} {}", "-".repeat(banner_w)); + // It's helpful to print something when there are no entries, otherwise it + // might look like something went wrong. + if macro_stats.is_empty() { + _ = writeln!(s, "{prefix} (none)"); + } + for (bytes, lines, uses, name, kind) in macro_stats { + let mut name = ExpnKind::Macro(kind, *name).descr(); + let avg_lines = lines as f64 / uses as f64; + let avg_bytes = bytes as f64 / uses as f64; + if name.len() >= name_w { + // If the name is long, print it on a line by itself, then + // set the name to empty and print things normally, to show the + // stats on the next line. + _ = writeln!(s, "{prefix} {:<name_w$}", name); + name = String::new(); + } + _ = writeln!( + s, + "{prefix} {:<name_w$}{:>uses_w$}{:>lines_w$}{:>avg_lines_w$}{:>bytes_w$}{:>avg_bytes_w$}", + name, + thousands::usize_with_underscores(uses), + thousands::isize_with_underscores(lines), + thousands::f64p1_with_underscores(avg_lines), + thousands::isize_with_underscores(bytes), + thousands::f64p1_with_underscores(avg_bytes), + ); + } + _ = writeln!(s, "{prefix} {}", "=".repeat(banner_w)); + eprint!("{s}"); +} + fn early_lint_checks(tcx: TyCtxt<'_>, (): ()) { let sess = tcx.sess; let (resolver, krate) = &*tcx.resolver_for_lowering().borrow(); @@ -954,7 +1029,6 @@ fn run_required_analyses(tcx: TyCtxt<'_>) { 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); tcx.ensure_ok().check_mod_unstable_api_usage(module); }); diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 558f13a832c..5419d688caa 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -709,6 +709,7 @@ fn test_unstable_options_tracking_hash() { untracked!(llvm_time_trace, true); untracked!(ls, vec!["all".to_owned()]); untracked!(macro_backtrace, true); + untracked!(macro_stats, true); untracked!(meta_stats, true); untracked!(mir_include_spans, MirIncludeSpans::On); untracked!(nll_facts, true); diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index fd2e2ba39ac..46ae4146528 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -72,9 +72,6 @@ lint_builtin_const_no_mangle = const items should never be `#[no_mangle]` lint_builtin_decl_unsafe_fn = declaration of an `unsafe` function lint_builtin_decl_unsafe_method = declaration of an `unsafe` method -lint_builtin_deprecated_attr_link = use of deprecated attribute `{$name}`: {$reason}. See {$link} - .msg_suggestion = {$msg} - .default_suggestion = remove this attribute lint_builtin_deref_nullptr = dereferencing a null pointer .label = this code causes undefined behavior when executed @@ -533,8 +530,6 @@ lint_mismatched_lifetime_syntaxes_suggestion_implicit = lint_mismatched_lifetime_syntaxes_suggestion_mixed = one option is to remove the lifetime for references and use the anonymous lifetime for paths -lint_missing_fragment_specifier = missing fragment specifier - lint_missing_unsafe_on_extern = extern blocks should be unsafe .suggestion = needs `unsafe` before the extern keyword diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 69e9f8e1b2c..dedea54f8e0 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -22,7 +22,7 @@ use rustc_ast::visit::{FnCtxt, FnKind}; use rustc_ast::{self as ast, *}; use rustc_ast_pretty::pprust::expr_to_string; use rustc_errors::{Applicability, LintDiagnostic}; -use rustc_feature::{AttributeGate, BuiltinAttribute, GateIssue, Stability, deprecated_attributes}; +use rustc_feature::GateIssue; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId}; @@ -48,8 +48,7 @@ use rustc_trait_selection::traits::{self}; use crate::errors::BuiltinEllipsisInclusiveRangePatterns; use crate::lints::{ - BuiltinAnonymousParams, BuiltinConstNoMangle, BuiltinDeprecatedAttrLink, - BuiltinDeprecatedAttrLinkSuggestion, BuiltinDerefNullptr, BuiltinDoubleNegations, + BuiltinAnonymousParams, BuiltinConstNoMangle, BuiltinDerefNullptr, BuiltinDoubleNegations, BuiltinDoubleNegationsAddParens, BuiltinEllipsisInclusiveRangePatternsLint, BuiltinExplicitOutlives, BuiltinExplicitOutlivesSuggestion, BuiltinFeatureIssueNote, BuiltinIncompleteFeatures, BuiltinIncompleteFeaturesHelp, BuiltinInternalFeatures, @@ -799,53 +798,6 @@ impl EarlyLintPass for AnonymousParameters { } } -/// Check for use of attributes which have been deprecated. -#[derive(Clone)] -pub struct DeprecatedAttr { - // This is not free to compute, so we want to keep it around, rather than - // compute it for every attribute. - depr_attrs: Vec<&'static BuiltinAttribute>, -} - -impl_lint_pass!(DeprecatedAttr => []); - -impl Default for DeprecatedAttr { - fn default() -> Self { - DeprecatedAttr { depr_attrs: deprecated_attributes() } - } -} - -impl EarlyLintPass for DeprecatedAttr { - fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) { - for BuiltinAttribute { name, gate, .. } in &self.depr_attrs { - if attr.ident().map(|ident| ident.name) == Some(*name) { - if let &AttributeGate::Gated( - Stability::Deprecated(link, suggestion), - name, - reason, - _, - ) = gate - { - let suggestion = match suggestion { - Some(msg) => { - BuiltinDeprecatedAttrLinkSuggestion::Msg { suggestion: attr.span, msg } - } - None => { - BuiltinDeprecatedAttrLinkSuggestion::Default { suggestion: attr.span } - } - }; - cx.emit_span_lint( - DEPRECATED, - attr.span, - BuiltinDeprecatedAttrLink { name, reason, link, suggestion }, - ); - } - return; - } - } - } -} - fn warn_if_doc(cx: &EarlyContext<'_>, node_span: Span, node_kind: &str, attrs: &[ast::Attribute]) { use rustc_ast::token::CommentKind; diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs index 4978f293ab7..12666d383f9 100644 --- a/compiler/rustc_lint/src/early.rs +++ b/compiler/rustc_lint/src/early.rs @@ -136,7 +136,6 @@ impl<'ast, 'ecx, 'tcx, T: EarlyLintPass> ast_visit::Visitor<'ast> // the AST struct that they wrap (e.g. an item) self.with_lint_attrs(s.id, s.attrs(), |cx| { lint_callback!(cx, check_stmt, s); - cx.check_id(s.id); }); // The visitor for the AST struct wrapped // by the statement (e.g. `Item`) will call @@ -147,7 +146,6 @@ impl<'ast, 'ecx, 'tcx, T: EarlyLintPass> ast_visit::Visitor<'ast> fn visit_fn(&mut self, fk: ast_visit::FnKind<'ast>, span: Span, id: ast::NodeId) { lint_callback!(self, check_fn, fk, span, id); - self.check_id(id); ast_visit::walk_fn(self, fk); } diff --git a/compiler/rustc_lint/src/early/diagnostics.rs b/compiler/rustc_lint/src/early/diagnostics.rs index 60c477dd6c7..3b0a36186b6 100644 --- a/compiler/rustc_lint/src/early/diagnostics.rs +++ b/compiler/rustc_lint/src/early/diagnostics.rs @@ -432,9 +432,6 @@ pub fn decorate_builtin_lint( BuiltinLintDiag::CfgAttrNoAttributes => { lints::CfgAttrNoAttributes.decorate_lint(diag); } - BuiltinLintDiag::MissingFragmentSpecifier => { - lints::MissingFragmentSpecifier.decorate_lint(diag); - } BuiltinLintDiag::MetaVariableStillRepeating(name) => { lints::MetaVariableStillRepeating { name }.decorate_lint(diag); } diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 72bfeaddbf1..e84cdb581b5 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -174,7 +174,6 @@ early_lint_methods!( AnonymousParameters: AnonymousParameters, EllipsisInclusiveRangePatterns: EllipsisInclusiveRangePatterns::default(), NonCamelCaseTypes: NonCamelCaseTypes, - DeprecatedAttr: DeprecatedAttr::default(), WhileTrue: WhileTrue, NonAsciiIdents: NonAsciiIdents, IncompleteInternalFeatures: IncompleteInternalFeatures, @@ -619,6 +618,11 @@ fn register_builtins(store: &mut LintStore) { "converted into hard error, \ see <https://github.com/rust-lang/rust/issues/116558> for more information", ); + store.register_removed( + "missing_fragment_specifier", + "converted into hard error, \ + see <https://github.com/rust-lang/rust/issues/40107> for more information", + ); } fn register_internals(store: &mut LintStore) { diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 9d3c74a9a2b..3d17dfbc451 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -199,32 +199,6 @@ pub(crate) struct BuiltinAnonymousParams<'a> { pub ty_snip: &'a str, } -// FIXME(davidtwco) translatable deprecated attr -#[derive(LintDiagnostic)] -#[diag(lint_builtin_deprecated_attr_link)] -pub(crate) struct BuiltinDeprecatedAttrLink<'a> { - pub name: Symbol, - pub reason: &'a str, - pub link: &'a str, - #[subdiagnostic] - pub suggestion: BuiltinDeprecatedAttrLinkSuggestion<'a>, -} - -#[derive(Subdiagnostic)] -pub(crate) enum BuiltinDeprecatedAttrLinkSuggestion<'a> { - #[suggestion(lint_msg_suggestion, code = "", applicability = "machine-applicable")] - Msg { - #[primary_span] - suggestion: Span, - msg: &'a str, - }, - #[suggestion(lint_default_suggestion, code = "", applicability = "machine-applicable")] - Default { - #[primary_span] - suggestion: Span, - }, -} - #[derive(LintDiagnostic)] #[diag(lint_builtin_unused_doc_comment)] pub(crate) struct BuiltinUnusedDocComment<'a> { @@ -2617,10 +2591,6 @@ pub(crate) struct DuplicateMacroAttribute; pub(crate) struct CfgAttrNoAttributes; #[derive(LintDiagnostic)] -#[diag(lint_missing_fragment_specifier)] -pub(crate) struct MissingFragmentSpecifier; - -#[derive(LintDiagnostic)] #[diag(lint_metavariable_still_repeating)] pub(crate) struct MetaVariableStillRepeating { pub name: MacroRulesNormalizedIdent, diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index 31c18074466..1b60466a589 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -164,7 +164,7 @@ impl NonCamelCaseTypes { impl EarlyLintPass for NonCamelCaseTypes { fn check_item(&mut self, cx: &EarlyContext<'_>, it: &ast::Item) { let has_repr_c = matches!( - AttributeParser::parse_limited(cx.sess(), &it.attrs, sym::repr, it.span, true), + AttributeParser::parse_limited(cx.sess(), &it.attrs, sym::repr, it.span, it.id), Some(Attribute::Parsed(AttributeKind::Repr(r))) if r.iter().any(|(r, _)| r == &ReprAttr::ReprC) ); diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index fec23354c91..aaba0c14b1c 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -196,7 +196,8 @@ declare_lint! { /// same address after being merged together. UNPREDICTABLE_FUNCTION_POINTER_COMPARISONS, Warn, - "detects unpredictable function pointer comparisons" + "detects unpredictable function pointer comparisons", + report_in_external_macro } #[derive(Copy, Clone, Default)] diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 777118e69fb..295dd82fead 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -65,7 +65,6 @@ declare_lint_pass! { MACRO_USE_EXTERN_CRATE, META_VARIABLE_MISUSE, MISSING_ABI, - MISSING_FRAGMENT_SPECIFIER, MISSING_UNSAFE_ON_EXTERN, MUST_NOT_SUSPEND, NAMED_ARGUMENTS_USED_POSITIONALLY, @@ -1418,51 +1417,6 @@ declare_lint! { } declare_lint! { - /// The `missing_fragment_specifier` lint is issued when an unused pattern in a - /// `macro_rules!` macro definition has a meta-variable (e.g. `$e`) that is not - /// followed by a fragment specifier (e.g. `:expr`). - /// - /// This warning can always be fixed by removing the unused pattern in the - /// `macro_rules!` macro definition. - /// - /// ### Example - /// - /// ```rust,compile_fail,edition2021 - /// macro_rules! foo { - /// () => {}; - /// ($name) => { }; - /// } - /// - /// fn main() { - /// foo!(); - /// } - /// ``` - /// - /// {{produces}} - /// - /// ### Explanation - /// - /// To fix this, remove the unused pattern from the `macro_rules!` macro definition: - /// - /// ```rust - /// macro_rules! foo { - /// () => {}; - /// } - /// fn main() { - /// foo!(); - /// } - /// ``` - pub MISSING_FRAGMENT_SPECIFIER, - Deny, - "detects missing fragment specifiers in unused `macro_rules!` patterns", - @future_incompatible = FutureIncompatibleInfo { - reason: FutureIncompatibilityReason::FutureReleaseError, - reference: "issue #40107 <https://github.com/rust-lang/rust/issues/40107>", - report_in_deps: true, - }; -} - -declare_lint! { /// The `late_bound_lifetime_arguments` lint detects generic lifetime /// arguments in path segments with late bound lifetime parameters. /// @@ -3664,7 +3618,7 @@ declare_lint! { "use of unsupported calling convention", @future_incompatible = FutureIncompatibleInfo { reason: FutureIncompatibilityReason::FutureReleaseError, - report_in_deps: true, + report_in_deps: false, reference: "issue #137018 <https://github.com/rust-lang/rust/issues/137018>", }; } diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 1d9b7a7fcb9..cd402c9234f 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -778,7 +778,6 @@ pub enum BuiltinLintDiag { UnnameableTestItems, DuplicateMacroAttribute, CfgAttrNoAttributes, - MissingFragmentSpecifier, MetaVariableStillRepeating(MacroRulesNormalizedIdent), MetaVariableWrongOperator, DuplicateMatcherBinding, diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 1dae858b7ef..1953eef8170 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -1649,34 +1649,7 @@ impl<'a> CrateMetadataRef<'a> { old_name && let Ok(rest) = virtual_name.strip_prefix(virtual_dir) { - // The std library crates are in - // `$sysroot/lib/rustlib/src/rust/library`, whereas other crates - // may be in `$sysroot/lib/rustlib/src/rust/` directly. So we - // detect crates from the std libs and handle them specially. - const STD_LIBS: &[&str] = &[ - "core", - "alloc", - "std", - "test", - "term", - "unwind", - "proc_macro", - "panic_abort", - "panic_unwind", - "profiler_builtins", - "rtstartup", - "rustc-std-workspace-core", - "rustc-std-workspace-alloc", - "rustc-std-workspace-std", - "backtrace", - ]; - let is_std_lib = STD_LIBS.iter().any(|l| rest.starts_with(l)); - - let new_path = if is_std_lib { - real_dir.join("library").join(rest) - } else { - real_dir.join(rest) - }; + let new_path = real_dir.join(rest); debug!( "try_to_translate_virtual_to_real: `{}` -> `{}`", diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 3ab989d2d3b..00bd32eb0eb 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -10,7 +10,7 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::memmap::{Mmap, MmapMut}; use rustc_data_structures::sync::{join, par_for_each_in}; use rustc_data_structures::temp_dir::MaybeTempDir; -use rustc_data_structures::thousands::format_with_underscores; +use rustc_data_structures::thousands::usize_with_underscores; use rustc_feature::Features; use rustc_hir as hir; use rustc_hir::def_id::{CRATE_DEF_ID, CRATE_DEF_INDEX, LOCAL_CRATE, LocalDefId, LocalDefIdSet}; @@ -789,7 +789,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { "{} {:<23}{:>10} ({:4.1}%)", prefix, label, - format_with_underscores(size), + usize_with_underscores(size), perc(size) ); } @@ -798,7 +798,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { "{} {:<23}{:>10} (of which {:.1}% are zero bytes)", prefix, "Total", - format_with_underscores(total_bytes), + usize_with_underscores(total_bytes), perc(zero_bytes) ); eprintln!("{prefix}"); diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index d1f5caaafb2..cb4760c18de 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -12,6 +12,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::{DynSend, DynSync, try_par_for_each_in}; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId}; +use rustc_hir::lints::DelayedLint; use rustc_hir::*; use rustc_macros::{Decodable, Encodable, HashStable}; use rustc_span::{ErrorGuaranteed, ExpnId, Span}; @@ -161,8 +162,9 @@ impl<'tcx> TyCtxt<'tcx> { node: OwnerNode<'_>, bodies: &SortedMap<ItemLocalId, &Body<'_>>, attrs: &SortedMap<ItemLocalId, &[Attribute]>, + delayed_lints: &[DelayedLint], define_opaque: Option<&[(Span, LocalDefId)]>, - ) -> (Option<Fingerprint>, Option<Fingerprint>) { + ) -> (Option<Fingerprint>, Option<Fingerprint>, Option<Fingerprint>) { if self.needs_crate_hash() { self.with_stable_hashing_context(|mut hcx| { let mut stable_hasher = StableHasher::new(); @@ -178,10 +180,16 @@ impl<'tcx> TyCtxt<'tcx> { define_opaque.hash_stable(&mut hcx, &mut stable_hasher); let h2 = stable_hasher.finish(); - (Some(h1), Some(h2)) + + // hash lints emitted during ast lowering + let mut stable_hasher = StableHasher::new(); + delayed_lints.hash_stable(&mut hcx, &mut stable_hasher); + let h3 = stable_hasher.finish(); + + (Some(h1), Some(h2), Some(h3)) }) } else { - (None, None) + (None, None, None) } } } @@ -214,6 +222,8 @@ pub fn provide(providers: &mut Providers) { providers.hir_attr_map = |tcx, id| { tcx.hir_crate(()).owners[id.def_id].as_owner().map_or(AttributeMap::EMPTY, |o| &o.attrs) }; + providers.opt_ast_lowering_delayed_lints = + |tcx, id| tcx.hir_crate(()).owners[id.def_id].as_owner().map(|o| &o.delayed_lints); providers.def_span = |tcx, def_id| tcx.hir_span(tcx.local_def_id_to_hir_id(def_id)); providers.def_ident_span = |tcx, def_id| { let hir_id = tcx.local_def_id_to_hir_id(def_id); diff --git a/compiler/rustc_middle/src/middle/mod.rs b/compiler/rustc_middle/src/middle/mod.rs index 4587dcaddc4..6ca1e620704 100644 --- a/compiler/rustc_middle/src/middle/mod.rs +++ b/compiler/rustc_middle/src/middle/mod.rs @@ -12,7 +12,7 @@ pub mod lib_features { #[derive(HashStable, TyEncodable, TyDecodable)] pub enum FeatureStability { AcceptedSince(Symbol), - Unstable, + Unstable { old_name: Option<Symbol> }, } #[derive(HashStable, Debug, Default)] diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index 454ab8c107f..ab6a65ed526 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -411,7 +411,7 @@ impl<'tcx> TyCtxt<'tcx> { match stability { Some(Stability { - level: attrs::StabilityLevel::Unstable { reason, issue, is_soft, implied_by }, + level: attrs::StabilityLevel::Unstable { reason, issue, is_soft, implied_by, .. }, feature, .. }) => { diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index bb068f3821d..f2f975a6968 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -1531,8 +1531,6 @@ pub enum CastKind { /// /// MIR is well-formed if the input and output types have different sizes, /// but running a transmute between differently-sized types is UB. - /// - /// Allowed only in [`MirPhase::Runtime`]; Earlier it's a [`TerminatorKind::Call`]. Transmute, } diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index 6035056baaf..7c998761a9d 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -389,6 +389,7 @@ tcx_lifetime! { rustc_middle::ty::layout::FnAbiError, rustc_middle::ty::layout::LayoutError, rustc_middle::ty::ParamEnv, + rustc_middle::ty::TypingEnv, rustc_middle::ty::Predicate, rustc_middle::ty::SymbolName, rustc_middle::ty::TraitRef, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index d03f01bf863..15e8c1ef3cc 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -221,6 +221,14 @@ rustc_queries! { feedable } + /// Gives access to lints emitted during ast lowering. + /// + /// This can be conveniently accessed by `tcx.hir_*` methods. + /// Avoid calling this query directly. + query opt_ast_lowering_delayed_lints(key: hir::OwnerId) -> Option<&'tcx hir::lints::DelayedLints> { + desc { |tcx| "getting AST lowering delayed lints in `{}`", tcx.def_path_str(key) } + } + /// Returns the *default* of the const pararameter given by `DefId`. /// /// E.g., given `struct Ty<const N: usize = 3>;` this returns `3` for `N`. @@ -1115,11 +1123,6 @@ rustc_queries! { desc { |tcx| "checking for unstable API usage in {}", describe_as_module(key, tcx) } } - /// Checks the loops in the module. - query check_mod_loops(key: LocalModDefId) { - desc { |tcx| "checking loops in {}", describe_as_module(key, tcx) } - } - query check_mod_privacy(key: LocalModDefId) { desc { |tcx| "checking privacy in {}", describe_as_module(key.to_local_def_id(), tcx) } } @@ -1571,7 +1574,7 @@ rustc_queries! { /// Like `param_env`, but returns the `ParamEnv` after all opaque types have been /// replaced with their hidden type. This is used in the old trait solver /// when in `PostAnalysis` mode and should not be called directly. - query param_env_normalized_for_post_analysis(def_id: DefId) -> ty::ParamEnv<'tcx> { + query typing_env_normalized_for_post_analysis(def_id: DefId) -> ty::TypingEnv<'tcx> { desc { |tcx| "computing revealed normalized predicates of `{}`", tcx.def_path_str(def_id) } } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 0b1e9852d2a..6a47000fc85 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -30,7 +30,7 @@ use rustc_data_structures::sync::{ self, DynSend, DynSync, FreezeReadGuard, Lock, RwLock, WorkerLocal, }; use rustc_errors::{ - Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, LintDiagnostic, MultiSpan, + Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, LintDiagnostic, LintEmitter, MultiSpan, }; use rustc_hir::def::{CtorKind, DefKind}; use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId}; @@ -86,6 +86,10 @@ use crate::ty::{ #[allow(rustc::usage_of_ty_tykind)] impl<'tcx> Interner for TyCtxt<'tcx> { + fn next_trait_solver_globally(self) -> bool { + self.next_trait_solver_globally() + } + type DefId = DefId; type LocalDefId = LocalDefId; type Span = Span; @@ -179,6 +183,17 @@ impl<'tcx> Interner for TyCtxt<'tcx> { f(&mut *self.new_solver_evaluation_cache.lock()) } + fn canonical_param_env_cache_get_or_insert<R>( + self, + param_env: ty::ParamEnv<'tcx>, + f: impl FnOnce() -> ty::CanonicalParamEnvCacheEntry<Self>, + from_entry: impl FnOnce(&ty::CanonicalParamEnvCacheEntry<Self>) -> R, + ) -> R { + let mut cache = self.new_solver_canonical_param_env_cache.lock(); + let entry = cache.entry(param_env).or_insert_with(f); + from_entry(entry) + } + fn evaluation_is_concurrent(&self) -> bool { self.sess.threads() > 1 } @@ -1335,8 +1350,8 @@ impl<'tcx> TyCtxtFeed<'tcx, LocalDefId> { let bodies = Default::default(); let attrs = hir::AttributeMap::EMPTY; - let (opt_hash_including_bodies, _) = - self.tcx.hash_owner_nodes(node, &bodies, &attrs.map, attrs.define_opaque); + let (opt_hash_including_bodies, _, _) = + self.tcx.hash_owner_nodes(node, &bodies, &attrs.map, &[], attrs.define_opaque); let node = node.into(); self.opt_hir_owner_nodes(Some(self.tcx.arena.alloc(hir::OwnerNodes { opt_hash_including_bodies, @@ -1374,6 +1389,18 @@ pub struct TyCtxt<'tcx> { gcx: &'tcx GlobalCtxt<'tcx>, } +impl<'tcx> LintEmitter for TyCtxt<'tcx> { + fn emit_node_span_lint( + self, + lint: &'static Lint, + hir_id: HirId, + span: impl Into<MultiSpan>, + decorator: impl for<'a> LintDiagnostic<'a, ()>, + ) { + self.emit_node_span_lint(lint, hir_id, span, decorator); + } +} + // Explicitly implement `DynSync` and `DynSend` for `TyCtxt` to short circuit trait resolution. Its // field are asserted to implement these traits below, so this is trivially safe, and it greatly // speeds-up compilation of this crate and its dependents. @@ -1444,6 +1471,8 @@ pub struct GlobalCtxt<'tcx> { /// Caches the results of goal evaluation in the new solver. pub new_solver_evaluation_cache: Lock<search_graph::GlobalCache<TyCtxt<'tcx>>>, + pub new_solver_canonical_param_env_cache: + Lock<FxHashMap<ty::ParamEnv<'tcx>, ty::CanonicalParamEnvCacheEntry<TyCtxt<'tcx>>>>, pub canonical_param_env_cache: CanonicalParamEnvCache<'tcx>, @@ -1692,6 +1721,7 @@ impl<'tcx> TyCtxt<'tcx> { selection_cache: Default::default(), evaluation_cache: Default::default(), new_solver_evaluation_cache: Default::default(), + new_solver_canonical_param_env_cache: Default::default(), canonical_param_env_cache: Default::default(), data_layout, alloc_map: interpret::AllocMap::new(), diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index c2ae6b06192..9bce2845680 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -1266,6 +1266,7 @@ pub fn fn_can_unwind(tcx: TyCtxt<'_>, fn_def_id: Option<DefId>, abi: ExternAbi) | RiscvInterruptS | CCmseNonSecureCall | CCmseNonSecureEntry + | Custom | Unadjusted => false, Rust | RustCall | RustCold => tcx.sess.panic_strategy() == PanicStrategy::Unwind, } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index af31f7ed33b..dc3f2844e5a 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1116,10 +1116,7 @@ impl<'tcx> TypingEnv<'tcx> { } pub fn post_analysis(tcx: TyCtxt<'tcx>, def_id: impl IntoQueryParam<DefId>) -> TypingEnv<'tcx> { - TypingEnv { - typing_mode: TypingMode::PostAnalysis, - param_env: tcx.param_env_normalized_for_post_analysis(def_id), - } + tcx.typing_env_normalized_for_post_analysis(def_id) } /// Modify the `typing_mode` to `PostAnalysis` and eagerly reveal all @@ -1133,7 +1130,7 @@ impl<'tcx> TypingEnv<'tcx> { // No need to reveal opaques with the new solver enabled, // since we have lazy norm. let param_env = if tcx.next_trait_solver_globally() { - ParamEnv::new(param_env.caller_bounds()) + param_env } else { ParamEnv::new(tcx.reveal_opaque_types_in_bounds(param_env.caller_bounds())) }; diff --git a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs index c7feb9e949b..da88e5c698b 100644 --- a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs +++ b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs @@ -128,28 +128,20 @@ impl<'tcx> crate::MirPass<'tcx> for EarlyOtherwiseBranch { let mut patch = MirPatch::new(body); - let (second_discriminant_temp, second_operand) = if opt_data.need_hoist_discriminant { + let second_operand = if opt_data.need_hoist_discriminant { // create temp to store second discriminant in, `_s` in example above let second_discriminant_temp = patch.new_temp(opt_data.child_ty, opt_data.child_source.span); - patch.add_statement( - parent_end, - StatementKind::StorageLive(second_discriminant_temp), - ); - // create assignment of discriminant patch.add_assign( parent_end, Place::from(second_discriminant_temp), Rvalue::Discriminant(opt_data.child_place), ); - ( - Some(second_discriminant_temp), - Operand::Move(Place::from(second_discriminant_temp)), - ) + Operand::Move(Place::from(second_discriminant_temp)) } else { - (None, Operand::Copy(opt_data.child_place)) + Operand::Copy(opt_data.child_place) }; // create temp to store inequality comparison between the two discriminants, `_t` in @@ -157,7 +149,6 @@ impl<'tcx> crate::MirPass<'tcx> for EarlyOtherwiseBranch { let nequal = BinOp::Ne; let comp_res_type = nequal.ty(tcx, parent_ty, opt_data.child_ty); let comp_temp = patch.new_temp(comp_res_type, opt_data.child_source.span); - patch.add_statement(parent_end, StatementKind::StorageLive(comp_temp)); // create inequality comparison let comp_rvalue = @@ -200,23 +191,6 @@ impl<'tcx> crate::MirPass<'tcx> for EarlyOtherwiseBranch { TerminatorKind::if_(Operand::Move(Place::from(comp_temp)), true_case, false_case), ); - if let Some(second_discriminant_temp) = second_discriminant_temp { - // generate StorageDead for the second_discriminant_temp not in use anymore - patch.add_statement( - parent_end, - StatementKind::StorageDead(second_discriminant_temp), - ); - } - - // Generate a StorageDead for comp_temp in each of the targets, since we moved it into - // the switch - for bb in [false_case, true_case].iter() { - patch.add_statement( - Location { block: *bb, statement_index: 0 }, - StatementKind::StorageDead(comp_temp), - ); - } - patch.apply(body); } diff --git a/compiler/rustc_mir_transform/src/inline/cycle.rs b/compiler/rustc_mir_transform/src/inline/cycle.rs index 292278800f8..a944960ce4a 100644 --- a/compiler/rustc_mir_transform/src/inline/cycle.rs +++ b/compiler/rustc_mir_transform/src/inline/cycle.rs @@ -138,7 +138,7 @@ pub(crate) fn mir_callgraph_reachable<'tcx>( } false } - // FIXME(-Znext-solver): Remove this hack when trait solver overflow can return an error. + // FIXME(-Znext-solver=no): Remove this hack when trait solver overflow can return an error. // In code like that pointed out in #128887, the type complexity we ask the solver to deal with // grows as we recurse into the call graph. If we use the same recursion limit here and in the // solver, the solver hits the limit first and emits a fatal error. But if we use a reduced diff --git a/compiler/rustc_mir_transform/src/lower_intrinsics.rs b/compiler/rustc_mir_transform/src/lower_intrinsics.rs index 52f4c39c09b..fa29ab985b7 100644 --- a/compiler/rustc_mir_transform/src/lower_intrinsics.rs +++ b/compiler/rustc_mir_transform/src/lower_intrinsics.rs @@ -150,12 +150,12 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics { }); terminator.kind = TerminatorKind::Goto { target }; } - sym::size_of | sym::min_align_of => { + sym::size_of | sym::align_of => { let target = target.unwrap(); let tp_ty = generic_args.type_at(0); let null_op = match intrinsic.name { sym::size_of => NullOp::SizeOf, - sym::min_align_of => NullOp::AlignOf, + sym::align_of => NullOp::AlignOf, _ => bug!("unexpected intrinsic"), }; block.statements.push(Statement { diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs index fd91508cc11..7dcdd7999f2 100644 --- a/compiler/rustc_mir_transform/src/validate.rs +++ b/compiler/rustc_mir_transform/src/validate.rs @@ -1308,37 +1308,27 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } } CastKind::Transmute => { - if let MirPhase::Runtime(..) = self.body.phase { - // Unlike `mem::transmute`, a MIR `Transmute` is well-formed - // for any two `Sized` types, just potentially UB to run. - - if !self - .tcx - .normalize_erasing_regions(self.typing_env, op_ty) - .is_sized(self.tcx, self.typing_env) - { - self.fail( - location, - format!("Cannot transmute from non-`Sized` type {op_ty}"), - ); - } - if !self - .tcx - .normalize_erasing_regions(self.typing_env, *target_type) - .is_sized(self.tcx, self.typing_env) - { - self.fail( - location, - format!("Cannot transmute to non-`Sized` type {target_type:?}"), - ); - } - } else { + // Unlike `mem::transmute`, a MIR `Transmute` is well-formed + // for any two `Sized` types, just potentially UB to run. + + if !self + .tcx + .normalize_erasing_regions(self.typing_env, op_ty) + .is_sized(self.tcx, self.typing_env) + { self.fail( location, - format!( - "Transmute is not supported in non-runtime phase {:?}.", - self.body.phase - ), + format!("Cannot transmute from non-`Sized` type {op_ty}"), + ); + } + if !self + .tcx + .normalize_erasing_regions(self.typing_env, *target_type) + .is_sized(self.tcx, self.typing_env) + { + self.fail( + location, + format!("Cannot transmute to non-`Sized` type {target_type:?}"), ); } } diff --git a/compiler/rustc_next_trait_solver/src/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonicalizer.rs index a87ae5284b1..cea77533178 100644 --- a/compiler/rustc_next_trait_solver/src/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonicalizer.rs @@ -4,8 +4,9 @@ use rustc_type_ir::data_structures::{HashMap, ensure_sufficient_stack}; use rustc_type_ir::inherent::*; use rustc_type_ir::solve::{Goal, QueryInput}; use rustc_type_ir::{ - self as ty, Canonical, CanonicalTyVarKind, CanonicalVarKind, Flags, InferCtxtLike, Interner, - TypeFlags, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, + self as ty, Canonical, CanonicalParamEnvCacheEntry, CanonicalTyVarKind, CanonicalVarKind, + Flags, InferCtxtLike, Interner, TypeFlags, TypeFoldable, TypeFolder, TypeSuperFoldable, + TypeVisitableExt, }; use crate::delegate::SolverDelegate; @@ -100,6 +101,76 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> { Canonical { max_universe, variables, value } } + fn canonicalize_param_env( + delegate: &'a D, + variables: &'a mut Vec<I::GenericArg>, + param_env: I::ParamEnv, + ) -> (I::ParamEnv, HashMap<I::GenericArg, usize>, Vec<CanonicalVarKind<I>>) { + if !param_env.has_type_flags(NEEDS_CANONICAL) { + return (param_env, Default::default(), Vec::new()); + } + + // Check whether we can use the global cache for this param_env. As we only use + // the `param_env` itself as the cache key, considering any additional information + // durnig its canonicalization would be incorrect. We always canonicalize region + // inference variables in a separate universe, so these are fine. However, we do + // track the universe of type and const inference variables so these must not be + // globally cached. We don't rely on any additional information when canonicalizing + // placeholders. + if !param_env.has_non_region_infer() { + delegate.cx().canonical_param_env_cache_get_or_insert( + param_env, + || { + let mut variables = Vec::new(); + let mut env_canonicalizer = Canonicalizer { + delegate, + canonicalize_mode: CanonicalizeMode::Input { keep_static: true }, + + variables: &mut variables, + variable_lookup_table: Default::default(), + var_kinds: Vec::new(), + binder_index: ty::INNERMOST, + + cache: Default::default(), + }; + let param_env = param_env.fold_with(&mut env_canonicalizer); + debug_assert_eq!(env_canonicalizer.binder_index, ty::INNERMOST); + CanonicalParamEnvCacheEntry { + param_env, + variable_lookup_table: env_canonicalizer.variable_lookup_table, + var_kinds: env_canonicalizer.var_kinds, + variables, + } + }, + |&CanonicalParamEnvCacheEntry { + param_env, + variables: ref cache_variables, + ref variable_lookup_table, + ref var_kinds, + }| { + debug_assert!(variables.is_empty()); + variables.extend(cache_variables.iter().copied()); + (param_env, variable_lookup_table.clone(), var_kinds.clone()) + }, + ) + } else { + let mut env_canonicalizer = Canonicalizer { + delegate, + canonicalize_mode: CanonicalizeMode::Input { keep_static: true }, + + variables, + variable_lookup_table: Default::default(), + var_kinds: Vec::new(), + binder_index: ty::INNERMOST, + + cache: Default::default(), + }; + let param_env = param_env.fold_with(&mut env_canonicalizer); + debug_assert_eq!(env_canonicalizer.binder_index, ty::INNERMOST); + (param_env, env_canonicalizer.variable_lookup_table, env_canonicalizer.var_kinds) + } + } + /// When canonicalizing query inputs, we keep `'static` in the `param_env` /// but erase it everywhere else. We generally don't want to depend on region /// identity, so while it should not matter whether `'static` is kept in the @@ -114,37 +185,17 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> { input: QueryInput<I, P>, ) -> ty::Canonical<I, QueryInput<I, P>> { // First canonicalize the `param_env` while keeping `'static` - let mut env_canonicalizer = Canonicalizer { - delegate, - canonicalize_mode: CanonicalizeMode::Input { keep_static: true }, - - variables, - variable_lookup_table: Default::default(), - var_kinds: Vec::new(), - binder_index: ty::INNERMOST, - - cache: Default::default(), - }; - - let param_env = input.goal.param_env; - let param_env = if param_env.has_type_flags(NEEDS_CANONICAL) { - param_env.fold_with(&mut env_canonicalizer) - } else { - param_env - }; - - debug_assert_eq!(env_canonicalizer.binder_index, ty::INNERMOST); + let (param_env, variable_lookup_table, var_kinds) = + Canonicalizer::canonicalize_param_env(delegate, variables, input.goal.param_env); // Then canonicalize the rest of the input without keeping `'static` // while *mostly* reusing the canonicalizer from above. let mut rest_canonicalizer = Canonicalizer { delegate, canonicalize_mode: CanonicalizeMode::Input { keep_static: false }, - variables: env_canonicalizer.variables, - // We're able to reuse the `variable_lookup_table` as whether or not - // it already contains an entry for `'static` does not matter. - variable_lookup_table: env_canonicalizer.variable_lookup_table, - var_kinds: env_canonicalizer.var_kinds, + variables, + variable_lookup_table, + var_kinds, binder_index: ty::INNERMOST, // We do not reuse the cache as it may contain entries whose canonicalized diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs index a7a984181d7..e4e0aba7b50 100644 --- a/compiler/rustc_next_trait_solver/src/solve/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs @@ -237,8 +237,8 @@ where return None; } - // FIXME(-Znext-solver): We should instead try to find a `Certainty::Yes` response with - // a subset of the constraints that all the other responses have. + // FIXME(-Znext-solver): Add support to merge region constraints in + // responses to deal with trait-system-refactor-initiative#27. let one = responses[0]; if responses[1..].iter().all(|&resp| resp == one) { return Some(one); 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 2640238f5a9..26443c54e18 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 @@ -41,6 +41,9 @@ where // and we tag the impl bounds with `GoalSource::ImplWhereBound`? // Right now this includes both the impl and the assoc item where bounds, // and I don't think the assoc item where-bounds are allowed to be coinductive. + // + // Projecting to the IAT also "steps out the impl contructor", so we would have + // to be very careful when changing the impl where-clauses to be productive. self.add_goals( GoalSource::Misc, cx.predicates_of(inherent.def_id) diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index 7c4e1dc2c12..110c67a8e21 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -235,7 +235,11 @@ where .predicates_of(goal.predicate.def_id()) .iter_instantiated(cx, goal.predicate.trait_ref.args) .map(|p| goal.with(cx, p)); - // FIXME(-Znext-solver=coinductive): Should this be `GoalSource::ImplWhereBound`? + // While you could think of trait aliases to have a single builtin impl + // which uses its implied trait bounds as where-clauses, using + // `GoalSource::ImplWhereClause` here would be incorrect, as we also + // impl them, which means we're "stepping out of the impl constructor" + // again. To handle this, we treat these cycles as ambiguous for now. ecx.add_goals(GoalSource::Misc, nested_obligations); ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) }) diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index a298c4d4dec..93489aa8ee9 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1520,22 +1520,20 @@ impl<'a> Parser<'a> { Ok(this.mk_expr(this.prev_token.span, ExprKind::Underscore)) } else if this.token_uninterpolated_span().at_least_rust_2018() { // `Span::at_least_rust_2018()` is somewhat expensive; don't get it repeatedly. + let at_async = this.check_keyword(exp!(Async)); + // check for `gen {}` and `gen move {}` + // or `async gen {}` and `async gen move {}` + // FIXME: (async) gen closures aren't yet parsed. + // FIXME(gen_blocks): Parse `gen async` and suggest swap if this.token_uninterpolated_span().at_least_rust_2024() - // check for `gen {}` and `gen move {}` - // or `async gen {}` and `async gen move {}` - && (this.is_gen_block(kw::Gen, 0) - || (this.check_keyword(exp!(Async)) && this.is_gen_block(kw::Gen, 1))) + && this.is_gen_block(kw::Gen, at_async as usize) { - // FIXME: (async) gen closures aren't yet parsed. this.parse_gen_block() - } else if this.check_keyword(exp!(Async)) { - // FIXME(gen_blocks): Parse `gen async` and suggest swap - if this.is_gen_block(kw::Async, 0) { - // Check for `async {` and `async move {`, - this.parse_gen_block() - } else { - this.parse_expr_closure() - } + // Check for `async {` and `async move {`, + } else if this.is_gen_block(kw::Async, 0) { + this.parse_gen_block() + } else if at_async { + this.parse_expr_closure() } else if this.eat_keyword_noexpect(kw::Await) { this.recover_incorrect_await_syntax(lo) } else { @@ -2407,6 +2405,14 @@ impl<'a> Parser<'a> { None }; + if let ClosureBinder::NotPresent = binder + && coroutine_kind.is_some() + { + // coroutine closures and generators can have the same qualifiers, so we might end up + // in here if there is a missing `|` but also no `{`. Adjust the expectations in that case. + self.expected_token_types.insert(TokenType::OpenBrace); + } + let capture_clause = self.parse_capture_clause()?; let (fn_decl, fn_arg_span) = self.parse_fn_block_decl()?; let decl_hi = self.prev_token.span; diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index 378cbb84637..555ab3cdb2b 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -180,9 +180,14 @@ pub fn check_attribute_safety( let diag_span = attr_item.span(); // Attributes can be safe in earlier editions, and become unsafe in later ones. + // + // Use the span of the attribute's name to determine the edition: the span of the + // attribute as a whole may be inaccurate if it was emitted by a macro. + // + // See https://github.com/rust-lang/rust/issues/142182. let emit_error = match unsafe_since { None => true, - Some(unsafe_since) => attr.span.edition() >= unsafe_since, + Some(unsafe_since) => path_span.edition() >= unsafe_since, }; if emit_error { diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs index 9dd064aca66..42bd0f5d847 100644 --- a/compiler/rustc_parse_format/src/lib.rs +++ b/compiler/rustc_parse_format/src/lib.rs @@ -29,58 +29,45 @@ pub enum ParseMode { Format, /// An inline assembly template string for `asm!`. InlineAsm, + /// A format string for use in diagnostic attributes. + /// + /// Similar to `format_args!`, however only named ("captured") arguments + /// are allowed, and no format modifiers are permitted. + Diagnostic, } /// 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)] -pub enum Piece<'a> { +pub enum Piece<'input> { /// A literal string which should directly be emitted - Lit(&'a str), + Lit(&'input str), /// This describes that formatting should process the next argument (as /// specified inside) for emission. - NextArgument(Box<Argument<'a>>), + NextArgument(Box<Argument<'input>>), } /// Representation of an argument specification. #[derive(Clone, Debug, PartialEq)] -pub struct Argument<'a> { +pub struct Argument<'input> { /// Where to find this argument - pub position: Position<'a>, + pub position: Position<'input>, /// The span of the position indicator. Includes any whitespace in implicit /// positions (`{ }`). pub position_span: Range<usize>, /// How to format the argument - pub format: FormatSpec<'a>, + pub format: FormatSpec<'input>, } -impl<'a> Argument<'a> { +impl<'input> Argument<'input> { 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, - }, - ) + matches!(self.position, Position::ArgumentNamed(_)) && self.format == FormatSpec::default() } } /// Specification for the formatting of an argument in the format string. -#[derive(Clone, Debug, PartialEq)] -pub struct FormatSpec<'a> { +#[derive(Clone, Debug, PartialEq, Default)] +pub struct FormatSpec<'input> { /// Optionally specified character to fill alignment with. pub fill: Option<char>, /// Span of the optionally specified fill character. @@ -96,30 +83,30 @@ pub struct FormatSpec<'a> { /// The `x` or `X` flag. (Only for `Debug`.) pub debug_hex: Option<DebugHex>, /// The integer precision to use. - pub precision: Count<'a>, + pub precision: Count<'input>, /// The span of the precision formatting flag (for diagnostics). pub precision_span: Option<Range<usize>>, /// The string width requested for the resulting format. - pub width: Count<'a>, + pub width: Count<'input>, /// The span of the width formatting flag (for diagnostics). pub width_span: Option<Range<usize>>, /// 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, + pub ty: &'input str, /// The span of the descriptor string (for diagnostics). pub ty_span: Option<Range<usize>>, } /// Enum describing where an argument for a format can be located. #[derive(Clone, Debug, PartialEq)] -pub enum Position<'a> { +pub enum Position<'input> { /// The argument is implied to be located at an index ArgumentImplicitlyIs(usize), /// The argument is located at a specific index given in the format, ArgumentIs(usize), /// The argument has a name. - ArgumentNamed(&'a str), + ArgumentNamed(&'input str), } impl Position<'_> { @@ -132,7 +119,7 @@ impl Position<'_> { } /// Enum of alignments which are supported. -#[derive(Copy, Clone, Debug, PartialEq)] +#[derive(Copy, Clone, Debug, PartialEq, Default)] pub enum Alignment { /// The value will be aligned to the left. AlignLeft, @@ -141,6 +128,7 @@ pub enum Alignment { /// The value will be aligned in the center. AlignCenter, /// The value will take on a default alignment. + #[default] AlignUnknown, } @@ -164,17 +152,18 @@ 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(Clone, Debug, PartialEq)] -pub enum Count<'a> { +#[derive(Clone, Debug, PartialEq, Default)] +pub enum Count<'input> { /// The count is specified explicitly. CountIs(u16), /// The count is specified by the argument with the given name. - CountIsName(&'a str, Range<usize>), + CountIsName(&'input str, Range<usize>), /// 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. CountIsStar(usize), /// The count is implied and cannot be explicitly specified. + #[default] CountImplied, } @@ -208,10 +197,10 @@ pub enum Suggestion { /// /// This is a recursive-descent parser for the sake of simplicity, and if /// necessary there's probably lots of room for improvement performance-wise. -pub struct Parser<'a> { +pub struct Parser<'input> { mode: ParseMode, /// Input to be parsed - input: &'a str, + input: &'input str, /// 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>, usize, char)>, /// Index into input_vec @@ -237,15 +226,15 @@ pub struct Parser<'a> { pub line_spans: Vec<Range<usize>>, } -impl<'a> Iterator for Parser<'a> { - type Item = Piece<'a>; +impl<'input> Iterator for Parser<'input> { + type Item = Piece<'input>; - fn next(&mut self) -> Option<Piece<'a>> { - if let Some(&(Range { start, end }, idx, ch)) = self.input_vec.get(self.input_vec_index) { + fn next(&mut self) -> Option<Piece<'input>> { + if let Some((Range { start, end }, idx, ch)) = self.peek() { match ch { '{' => { self.input_vec_index += 1; - if let Some(&(_, i, '{')) = self.input_vec.get(self.input_vec_index) { + if let Some((_, i, '{')) = self.peek() { self.input_vec_index += 1; // double open brace escape: "{{" // next state after this is either end-of-input or seen-a-brace @@ -254,25 +243,21 @@ impl<'a> Iterator for Parser<'a> { // 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) { + self.ws(); + if let Some((close_brace_range, _)) = self.consume_pos('}') { if self.is_source_literal { self.arg_places.push(start..close_brace_range.end); } - } else if let Some(&(_, _, c)) = self.input_vec.get(self.input_vec_index) { - match c { - '?' => self.suggest_format_debug(), - '<' | '^' | '>' => self.suggest_format_align(c), - _ => { - self.suggest_positional_arg_instead_of_captured_arg(arg.clone()) - } - } + } else { + self.missing_closing_brace(&arg); } + Some(Piece::NextArgument(Box::new(arg))) } } '}' => { self.input_vec_index += 1; - if let Some(&(_, i, '}')) = self.input_vec.get(self.input_vec_index) { + if let Some((_, i, '}')) = self.peek() { self.input_vec_index += 1; // double close brace escape: "}}" // next state after this is either end-of-input or start @@ -307,14 +292,14 @@ impl<'a> Iterator for Parser<'a> { } } -impl<'a> Parser<'a> { +impl<'input> Parser<'input> { /// 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( - input: &'a str, + input: &'input str, style: Option<usize>, snippet: Option<String>, appended_newline: bool, @@ -406,6 +391,16 @@ impl<'a> Parser<'a> { } } + /// Peeks at the current position, without incrementing the pointer. + pub fn peek(&self) -> Option<(Range<usize>, usize, char)> { + self.input_vec.get(self.input_vec_index).cloned() + } + + /// Peeks at the current position + 1, without incrementing the pointer. + pub fn peek_ahead(&self) -> Option<(Range<usize>, usize, char)> { + self.input_vec.get(self.input_vec_index + 1).cloned() + } + /// 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. @@ -418,27 +413,19 @@ impl<'a> Parser<'a> { /// returned, otherwise the character is consumed and the current position is /// returned. fn consume_pos(&mut self, ch: char) -> Option<(Range<usize>, 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)); - } + if let Some((r, i, c)) = self.peek() + && ch == c + { + self.input_vec_index += 1; + return Some((r, i)); } + None } - /// 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<Range<usize>> { - self.ws(); - - 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()); - } - // or r.clone()? + /// Called if a closing brace was not found. + fn missing_closing_brace(&mut self, arg: &Argument<'_>) { + let (range, description) = if let Some((r, _, c)) = self.peek() { (r.start..r.start, format!("expected `}}`, found `{}`", c.escape_debug())) } else { ( @@ -471,7 +458,13 @@ impl<'a> Parser<'a> { suggestion: Suggestion::None, }); - None + if let Some((_, _, c)) = self.peek() { + match c { + '?' => self.suggest_format_debug(), + '<' | '^' | '>' => self.suggest_format_align(c), + _ => self.suggest_positional_arg_instead_of_captured_arg(arg), + } + } } /// Consumes all whitespace characters until the first non-whitespace character @@ -483,11 +476,11 @@ impl<'a> Parser<'a> { /// 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 { - while let Some((r, i, c)) = self.input_vec.get(self.input_vec_index) { + fn string(&mut self, start: usize) -> &'input str { + while let Some((r, i, c)) = self.peek() { match c { '{' | '}' => { - return &self.input[start..*i]; + return &self.input[start..i]; } '\n' if self.is_source_literal => { self.input_vec_index += 1; @@ -507,7 +500,7 @@ impl<'a> Parser<'a> { } /// Parses an `Argument` structure, or what's contained within braces inside the format string. - fn argument(&mut self) -> Argument<'a> { + fn argument(&mut self) -> Argument<'input> { let start_idx = self.input_vec_index; let position = self.position(); @@ -518,6 +511,7 @@ impl<'a> Parser<'a> { let format = match self.mode { ParseMode::Format => self.format(), ParseMode::InlineAsm => self.inline_asm(), + ParseMode::Diagnostic => self.diagnostic(), }; // Resolve position after parsing format spec. @@ -536,31 +530,27 @@ impl<'a> Parser<'a> { /// integer index of an argument, a named argument, or a blank string. /// Returns `Some(parsed_position)` if the position is not implicitly /// consuming a macro argument, `None` if it's the case. - fn position(&mut self) -> Option<Position<'a>> { + fn position(&mut self) -> Option<Position<'input>> { if let Some(i) = self.integer() { Some(ArgumentIs(i.into())) } else { - match self.input_vec.get(self.input_vec_index) { - Some((range, _, c)) if rustc_lexer::is_id_start(*c) => { + match self.peek() { + 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((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.input_vec_index += 1; - let prefix_end = r.end; - let word = self.word(); - let prefix_span = start..prefix_end; - let full_span = - start..self.input_vec_index2range(self.input_vec_index).start; - self.errors.insert(0, ParseError { + if word == "r" + && let Some((r, _, '#')) = self.peek() + && self.peek_ahead().is_some_and(|(_, _, c)| rustc_lexer::is_id_start(c)) + { + self.input_vec_index += 1; + let prefix_end = r.end; + let word = self.word(); + 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()), label: "raw identifier used here".to_owned(), @@ -568,9 +558,7 @@ impl<'a> Parser<'a> { secondary_label: None, suggestion: Suggestion::RemoveRawIdent(prefix_span), }); - return Some(ArgumentNamed(word)); - } - } + return Some(ArgumentNamed(word)); } Some(ArgumentNamed(word)) @@ -584,7 +572,7 @@ impl<'a> Parser<'a> { } fn input_vec_index2pos(&self, index: usize) -> usize { - if let Some(&(_, pos, _)) = self.input_vec.get(index) { pos } else { self.input.len() } + if let Some((_, pos, _)) = self.input_vec.get(index) { *pos } else { self.input.len() } } fn input_vec_index2range(&self, index: usize) -> Range<usize> { @@ -597,33 +585,18 @@ impl<'a> Parser<'a> { /// Parses a format specifier at the current position, returning all of the /// relevant information in the `FormatSpec` struct. - fn format(&mut self) -> FormatSpec<'a> { - let mut spec = 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: &self.input[..0], - ty_span: None, - }; + fn format(&mut self) -> FormatSpec<'input> { + let mut spec = FormatSpec::default(); + if !self.consume(':') { return spec; } // fill character - 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(r.clone()); - } + if let (Some((r, _, c)), Some((_, _, '>' | '<' | '^'))) = (self.peek(), self.peek_ahead()) { + self.input_vec_index += 1; + spec.fill = Some(c); + spec.fill_span = Some(r); } // Alignment if self.consume('<') { @@ -701,24 +674,21 @@ impl<'a> Parser<'a> { } } else if let Some((range, _)) = self.consume_pos('?') { spec.ty = "?"; - 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}?"), - ), - }, - ), - _ => (), - } + if let Some((r, _, c @ ('#' | 'x' | 'X'))) = self.peek() { + 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(); @@ -733,22 +703,9 @@ impl<'a> Parser<'a> { /// Parses an inline assembly template modifier at the current position, returning the modifier /// in the `ty` field of the `FormatSpec` struct. - fn inline_asm(&mut self) -> FormatSpec<'a> { - let mut spec = 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: &self.input[..0], - ty_span: None, - }; + fn inline_asm(&mut self) -> FormatSpec<'input> { + let mut spec = FormatSpec::default(); + if !self.consume(':') { return spec; } @@ -764,10 +721,26 @@ impl<'a> Parser<'a> { spec } + /// Always returns an empty `FormatSpec` + fn diagnostic(&mut self) -> FormatSpec<'input> { + let mut spec = FormatSpec::default(); + + let Some((Range { start, .. }, start_idx)) = self.consume_pos(':') else { + return spec; + }; + + spec.ty = self.string(start_idx); + spec.ty_span = { + let end = self.input_vec_index2range(self.input_vec_index).start; + Some(start..end) + }; + spec + } + /// 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) -> Count<'a> { + fn count(&mut self) -> Count<'input> { if let Some(i) = self.integer() { if self.consume('$') { CountIsParam(i.into()) } else { CountIs(i) } } else { @@ -786,10 +759,10 @@ impl<'a> Parser<'a> { /// 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 { + fn word(&mut self) -> &'input str { 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) => { + match self.peek() { + Some((ref r, i, c)) if rustc_lexer::is_id_start(c) => { self.input_vec_index += 1; (r.start, i) } @@ -798,7 +771,7 @@ impl<'a> Parser<'a> { } }; let (err_end, end): (usize, usize) = loop { - if let Some(&(ref r, i, c)) = self.input_vec.get(self.input_vec_index) { + if let Some((ref r, i, c)) = self.peek() { if rustc_lexer::is_id_continue(c) { self.input_vec_index += 1; } else { @@ -828,7 +801,7 @@ impl<'a> Parser<'a> { let mut found = false; let mut overflow = false; let start_index = self.input_vec_index; - while let Some(&(_, _, c)) = self.input_vec.get(self.input_vec_index) { + while let Some((_, _, c)) = self.peek() { if let Some(i) = c.to_digit(10) { self.input_vec_index += 1; let (tmp, mul_overflow) = cur.overflowing_mul(10); @@ -897,7 +870,7 @@ impl<'a> Parser<'a> { } } - fn suggest_positional_arg_instead_of_captured_arg(&mut self, arg: Argument<'a>) { + fn suggest_positional_arg_instead_of_captured_arg(&mut self, arg: &Argument<'_>) { // If the argument is not an identifier, it is not a field access. if !arg.is_identifier() { return; diff --git a/compiler/rustc_parse_format/src/tests.rs b/compiler/rustc_parse_format/src/tests.rs index e6a7f24034a..a6c7e1890ab 100644 --- a/compiler/rustc_parse_format/src/tests.rs +++ b/compiler/rustc_parse_format/src/tests.rs @@ -553,3 +553,45 @@ fn asm_concat() { assert_eq!(parser.by_ref().collect::<Vec<Piece<'static>>>(), &[Lit(asm)]); assert_eq!(parser.line_spans, &[]); } + +#[test] +fn diagnostic_format_flags() { + let lit = "{thing:blah}"; + let mut parser = Parser::new(lit, None, None, false, ParseMode::Diagnostic); + assert!(!parser.is_source_literal); + + let [NextArgument(arg)] = &*parser.by_ref().collect::<Vec<Piece<'static>>>() else { panic!() }; + + assert_eq!( + **arg, + Argument { + position: ArgumentNamed("thing"), + position_span: 2..7, + format: FormatSpec { ty: ":blah", ty_span: Some(7..12), ..Default::default() }, + } + ); + + assert_eq!(parser.line_spans, &[]); + assert!(parser.errors.is_empty()); +} + +#[test] +fn diagnostic_format_mod() { + let lit = "{thing:+}"; + let mut parser = Parser::new(lit, None, None, false, ParseMode::Diagnostic); + assert!(!parser.is_source_literal); + + let [NextArgument(arg)] = &*parser.by_ref().collect::<Vec<Piece<'static>>>() else { panic!() }; + + assert_eq!( + **arg, + Argument { + position: ArgumentNamed("thing"), + position_span: 2..7, + format: FormatSpec { ty: ":+", ty_span: Some(7..9), ..Default::default() }, + } + ); + + assert_eq!(parser.line_spans, &[]); + assert!(parser.errors.is_empty()); +} diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 983e562cdf3..7c237d708c0 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -56,23 +56,6 @@ passes_autodiff_attr = passes_both_ffi_const_and_pure = `#[ffi_const]` function cannot be `#[ffi_pure]` -passes_break_inside_closure = - `{$name}` inside of a closure - .label = cannot `{$name}` inside of a closure - .closure_label = enclosing closure - -passes_break_inside_coroutine = - `{$name}` inside `{$kind}` {$source} - .label = cannot `{$name}` inside `{$kind}` {$source} - .coroutine_label = enclosing `{$kind}` {$source} - -passes_break_non_loop = - `break` with value from a `{$kind}` loop - .label = can only break with a value inside `loop` or breakable block - .label2 = you can't `break` with a value in a `{$kind}` loop - .suggestion = use `break` on its own without a value inside this `{$kind}` loop - .break_expr_suggestion = alternatively, you might have meant to use the available loop label - passes_cannot_stabilize_deprecated = an API can't be stabilized after it is deprecated .label = invalid version @@ -103,10 +86,6 @@ passes_const_stable_not_stable = attribute `#[rustc_const_stable]` can only be applied to functions that are declared `#[stable]` .label = attribute specified here -passes_continue_labeled_block = - `continue` pointing to a labeled block - .label = labeled blocks cannot be `continue`'d - .block_label = labeled block the `continue` points to passes_coroutine_on_non_closure = attribute should be applied to closures @@ -311,6 +290,9 @@ passes_duplicate_lang_item_crate_depends = .first_definition_path = first definition in `{$orig_crate_name}` loaded from {$orig_path} .second_definition_path = second definition in `{$crate_name}` loaded from {$path} +passes_enum_variant_same_name = + it is impossible to refer to the {$descr} `{$dead_name}` because it is shadowed by this enum variant with the same name + passes_export_name = attribute should be applied to a free function, impl method or static .label = not a free function, impl method or static @@ -574,17 +556,6 @@ passes_optimize_invalid_target = passes_outer_crate_level_attr = crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` -passes_outside_loop = - `{$name}` outside of a loop{$is_break -> - [true] {" or labeled block"} - *[false] {""} - } - .label = cannot `{$name}` outside of a loop{$is_break -> - [true] {" or labeled block"} - *[false] {""} - } - -passes_outside_loop_suggestion = consider labeling this block to be able to break within it passes_panic_unwind_without_std = unwinding panics are not supported without std @@ -748,18 +719,13 @@ passes_unknown_external_lang_item = passes_unknown_feature = unknown feature `{$feature}` +passes_unknown_feature_alias = + feature `{$alias}` has been renamed to `{$feature}` + passes_unknown_lang_item = definition of an unknown lang item: `{$name}` .label = definition of unknown lang item `{$name}` -passes_unlabeled_cf_in_while_condition = - `break` or `continue` with no label in the condition of a `while` loop - .label = unlabeled `{$cf_type}` in the condition of a `while` loop - -passes_unlabeled_in_labeled_block = - unlabeled `{$cf_type}` inside of a labeled block - .label = `{$cf_type}` statements that would diverge to or through a labeled block need to bear a label - passes_unnecessary_partial_stable_feature = the feature `{$feature}` has been partially stabilized since {$since} and is succeeded by the feature `{$implies}` .suggestion = if you are using features which are still unstable, change to using `{$implies}` .suggestion_remove = if you are using features which are now stable, remove this line diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index dc29b03083f..4e2be8ff0b8 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -132,7 +132,22 @@ impl<'tcx> CheckAttrVisitor<'tcx> { target, attrs, ), - _ => { + Attribute::Parsed(AttributeKind::AllowConstFnUnstable { .. }) => { + self.check_rustc_allow_const_fn_unstable(hir_id, attr, span, target) + } + Attribute::Parsed(AttributeKind::Deprecation { .. }) => { + self.check_deprecated(hir_id, attr, span, target) + } + Attribute::Parsed(AttributeKind::DocComment { .. }) => { /* `#[doc]` is actually a lot more than just doc comments, so is checked below*/ + } + Attribute::Parsed(AttributeKind::Repr(_)) => { /* handled below this loop and elsewhere */ + } + Attribute::Parsed( + AttributeKind::BodyStability { .. } + | AttributeKind::ConstStabilityIndirect + | AttributeKind::MacroTransparency(_), + ) => { /* do nothing */ } + Attribute::Unparsed(_) => { match attr.path().as_slice() { [sym::diagnostic, sym::do_not_recommend, ..] => { self.check_do_not_recommend(attr.span(), hir_id, target, attr, item) @@ -169,9 +184,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.check_rustc_layout_scalar_valid_range(attr, span, target) } [sym::debugger_visualizer, ..] => self.check_debugger_visualizer(attr, target), - [sym::rustc_allow_const_fn_unstable, ..] => { - self.check_rustc_allow_const_fn_unstable(hir_id, attr, span, target) - } [sym::rustc_std_internal_symbol, ..] => { self.check_rustc_std_internal_symbol(attr, span, target) } @@ -229,7 +241,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { [sym::link_name, ..] => self.check_link_name(hir_id, attr, span, target), [sym::link_section, ..] => self.check_link_section(hir_id, attr, span, target), [sym::no_mangle, ..] => self.check_no_mangle(hir_id, attr, span, target), - [sym::deprecated, ..] => self.check_deprecated(hir_id, attr, span, target), [sym::macro_use, ..] | [sym::macro_escape, ..] => { self.check_macro_use(hir_id, attr, target) } @@ -283,7 +294,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | sym::pointee // FIXME(derive_coerce_pointee) | sym::omit_gdb_pretty_printer_section // FIXME(omit_gdb_pretty_printer_section) | sym::used // handled elsewhere to restrict to static items - | sym::repr // handled elsewhere to restrict to type decls items | sym::instruction_set // broken on stable!!! | sym::windows_subsystem // broken on stable!!! | sym::patchable_function_entry // FIXME(patchable_function_entry) diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index e597c819a3a..4257d8e8d16 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -14,7 +14,7 @@ use rustc_errors::MultiSpan; use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId}; use rustc_hir::intravisit::{self, Visitor}; -use rustc_hir::{self as hir, Node, PatKind, QPath, TyKind}; +use rustc_hir::{self as hir, ImplItem, ImplItemKind, Node, PatKind, QPath, TyKind}; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::middle::privacy::Level; use rustc_middle::query::Providers; @@ -936,7 +936,9 @@ enum ShouldWarnAboutField { #[derive(Debug, Copy, Clone, PartialEq, Eq)] enum ReportOn { + /// Report on something that hasn't got a proper name to refer to TupleField, + /// Report on something that has got a name, which could be a field but also a method NamedField, } @@ -1061,6 +1063,31 @@ impl<'tcx> DeadVisitor<'tcx> { None }; + let enum_variants_with_same_name = dead_codes + .iter() + .filter_map(|dead_item| { + if let Node::ImplItem(ImplItem { + kind: ImplItemKind::Fn(..) | ImplItemKind::Const(..), + .. + }) = tcx.hir_node_by_def_id(dead_item.def_id) + && let Some(impl_did) = tcx.opt_parent(dead_item.def_id.to_def_id()) + && let DefKind::Impl { of_trait: false } = tcx.def_kind(impl_did) + && let ty::Adt(maybe_enum, _) = tcx.type_of(impl_did).skip_binder().kind() + && maybe_enum.is_enum() + && let Some(variant) = + maybe_enum.variants().iter().find(|i| i.name == dead_item.name) + { + Some(crate::errors::EnumVariantSameName { + descr: tcx.def_descr(dead_item.def_id.to_def_id()), + dead_name: dead_item.name, + variant_span: tcx.def_span(variant.def_id), + }) + } else { + None + } + }) + .collect(); + let diag = match report_on { ReportOn::TupleField => { let tuple_fields = if let Some(parent_id) = parent_item @@ -1114,6 +1141,7 @@ impl<'tcx> DeadVisitor<'tcx> { name_list, parent_info, ignored_derived_impls, + enum_variants_with_same_name, }, }; diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index b995781719b..f0d4b610f63 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -1,13 +1,12 @@ use std::io::Error; use std::path::{Path, PathBuf}; -use rustc_ast::Label; use rustc_errors::codes::*; use rustc_errors::{ Applicability, Diag, DiagCtxtHandle, DiagSymbolList, Diagnostic, EmissionGuarantee, Level, MultiSpan, Subdiagnostic, }; -use rustc_hir::{self as hir, ExprKind, Target}; +use rustc_hir::Target; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_middle::ty::{MainDefinition, Ty}; use rustc_span::{DUMMY_SP, Span, Symbol}; @@ -1071,131 +1070,6 @@ pub(crate) struct FeaturePreviouslyDeclared<'a> { pub prev_declared: &'a str, } -pub(crate) struct BreakNonLoop<'a> { - pub span: Span, - pub head: Option<Span>, - pub kind: &'a str, - pub suggestion: String, - pub loop_label: Option<Label>, - pub break_label: Option<Label>, - pub break_expr_kind: &'a ExprKind<'a>, - pub break_expr_span: Span, -} - -impl<'a, G: EmissionGuarantee> Diagnostic<'_, G> for BreakNonLoop<'a> { - #[track_caller] - fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { - let mut diag = Diag::new(dcx, level, fluent::passes_break_non_loop); - diag.span(self.span); - diag.code(E0571); - diag.arg("kind", self.kind); - diag.span_label(self.span, fluent::passes_label); - if let Some(head) = self.head { - diag.span_label(head, fluent::passes_label2); - } - diag.span_suggestion( - self.span, - fluent::passes_suggestion, - self.suggestion, - Applicability::MaybeIncorrect, - ); - if let (Some(label), None) = (self.loop_label, self.break_label) { - match self.break_expr_kind { - ExprKind::Path(hir::QPath::Resolved( - None, - hir::Path { segments: [segment], res: hir::def::Res::Err, .. }, - )) if label.ident.to_string() == format!("'{}", segment.ident) => { - // This error is redundant, we will have already emitted a - // suggestion to use the label when `segment` wasn't found - // (hence the `Res::Err` check). - diag.downgrade_to_delayed_bug(); - } - _ => { - diag.span_suggestion( - self.break_expr_span, - fluent::passes_break_expr_suggestion, - label.ident, - Applicability::MaybeIncorrect, - ); - } - } - } - diag - } -} - -#[derive(Diagnostic)] -#[diag(passes_continue_labeled_block, code = E0696)] -pub(crate) struct ContinueLabeledBlock { - #[primary_span] - #[label] - pub span: Span, - #[label(passes_block_label)] - pub block_span: Span, -} - -#[derive(Diagnostic)] -#[diag(passes_break_inside_closure, code = E0267)] -pub(crate) struct BreakInsideClosure<'a> { - #[primary_span] - #[label] - pub span: Span, - #[label(passes_closure_label)] - pub closure_span: Span, - pub name: &'a str, -} - -#[derive(Diagnostic)] -#[diag(passes_break_inside_coroutine, code = E0267)] -pub(crate) struct BreakInsideCoroutine<'a> { - #[primary_span] - #[label] - pub span: Span, - #[label(passes_coroutine_label)] - pub coroutine_span: Span, - pub name: &'a str, - pub kind: &'a str, - pub source: &'a str, -} - -#[derive(Diagnostic)] -#[diag(passes_outside_loop, code = E0268)] -pub(crate) struct OutsideLoop<'a> { - #[primary_span] - #[label] - pub spans: Vec<Span>, - pub name: &'a str, - pub is_break: bool, - #[subdiagnostic] - pub suggestion: Option<OutsideLoopSuggestion>, -} -#[derive(Subdiagnostic)] -#[multipart_suggestion(passes_outside_loop_suggestion, applicability = "maybe-incorrect")] -pub(crate) struct OutsideLoopSuggestion { - #[suggestion_part(code = "'block: ")] - pub block_span: Span, - #[suggestion_part(code = " 'block")] - pub break_spans: Vec<Span>, -} - -#[derive(Diagnostic)] -#[diag(passes_unlabeled_in_labeled_block, code = E0695)] -pub(crate) struct UnlabeledInLabeledBlock<'a> { - #[primary_span] - #[label] - pub span: Span, - pub cf_type: &'a str, -} - -#[derive(Diagnostic)] -#[diag(passes_unlabeled_cf_in_while_condition, code = E0590)] -pub(crate) struct UnlabeledCfInWhileCondition<'a> { - #[primary_span] - #[label] - pub span: Span, - pub cf_type: &'a str, -} - #[derive(Diagnostic)] #[diag(passes_naked_functions_incompatible_attribute, code = E0736)] pub(crate) struct NakedFunctionIncompatibleAttribute { @@ -1561,6 +1435,15 @@ pub(crate) struct UnknownFeature { } #[derive(Diagnostic)] +#[diag(passes_unknown_feature_alias, code = E0635)] +pub(crate) struct RenamedFeature { + #[primary_span] + pub span: Span, + pub feature: Symbol, + pub alias: Symbol, +} + +#[derive(Diagnostic)] #[diag(passes_implied_feature_not_exist)] pub(crate) struct ImpliedFeatureNotExist { #[primary_span] @@ -1604,6 +1487,9 @@ pub(crate) enum MultipleDeadCodes<'tcx> { participle: &'tcx str, name_list: DiagSymbolList, #[subdiagnostic] + // only on DeadCodes since it's never a problem for tuple struct fields + enum_variants_with_same_name: Vec<EnumVariantSameName<'tcx>>, + #[subdiagnostic] parent_info: Option<ParentInfo<'tcx>>, #[subdiagnostic] ignored_derived_impls: Option<IgnoredDerivedImpls>, @@ -1625,6 +1511,15 @@ pub(crate) enum MultipleDeadCodes<'tcx> { } #[derive(Subdiagnostic)] +#[note(passes_enum_variant_same_name)] +pub(crate) struct EnumVariantSameName<'tcx> { + #[primary_span] + pub variant_span: Span, + pub dead_name: Symbol, + pub descr: &'tcx str, +} + +#[derive(Subdiagnostic)] #[label(passes_parent_info)] pub(crate) struct ParentInfo<'tcx> { pub num: usize, diff --git a/compiler/rustc_passes/src/input_stats.rs b/compiler/rustc_passes/src/input_stats.rs index 6852153a2e7..46e6c0bf7da 100644 --- a/compiler/rustc_passes/src/input_stats.rs +++ b/compiler/rustc_passes/src/input_stats.rs @@ -5,7 +5,7 @@ use rustc_ast::visit::BoundKind; use rustc_ast::{self as ast, NodeId, visit as ast_visit}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_data_structures::thousands::format_with_underscores; +use rustc_data_structures::thousands::usize_with_underscores; use rustc_hir::{self as hir, AmbigArg, HirId, intravisit as hir_visit}; use rustc_middle::ty::TyCtxt; use rustc_span::Span; @@ -140,10 +140,10 @@ impl<'k> StatCollector<'k> { "{} {:<18}{:>10} ({:4.1}%){:>14}{:>14}", prefix, label, - format_with_underscores(size), + usize_with_underscores(size), percent(size, total_size), - format_with_underscores(node.stats.count), - format_with_underscores(node.stats.size) + usize_with_underscores(node.stats.count), + usize_with_underscores(node.stats.size) ); if !node.subnodes.is_empty() { // We will soon sort, so the initial order does not matter. @@ -159,9 +159,9 @@ impl<'k> StatCollector<'k> { "{} - {:<18}{:>10} ({:4.1}%){:>14}", prefix, label, - format_with_underscores(size), + usize_with_underscores(size), percent(size, total_size), - format_with_underscores(subnode.count), + usize_with_underscores(subnode.count), ); } } @@ -171,8 +171,8 @@ impl<'k> StatCollector<'k> { "{} {:<18}{:>10} {:>14}", prefix, "Total", - format_with_underscores(total_size), - format_with_underscores(total_count), + usize_with_underscores(total_size), + usize_with_underscores(total_count), ); eprintln!("{prefix}"); } diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs index 1831f45a9ec..af7ecf0830c 100644 --- a/compiler/rustc_passes/src/lib.rs +++ b/compiler/rustc_passes/src/lib.rs @@ -29,7 +29,6 @@ mod lang_items; pub mod layout_test; mod lib_features; mod liveness; -pub mod loops; mod reachable; pub mod stability; mod upvars; @@ -45,7 +44,6 @@ pub fn provide(providers: &mut Providers) { entry::provide(providers); lang_items::provide(providers); lib_features::provide(providers); - loops::provide(providers); liveness::provide(providers); reachable::provide(providers); stability::provide(providers); diff --git a/compiler/rustc_passes/src/lib_features.rs b/compiler/rustc_passes/src/lib_features.rs index b3e6ee9512c..127e0df1332 100644 --- a/compiler/rustc_passes/src/lib_features.rs +++ b/compiler/rustc_passes/src/lib_features.rs @@ -40,7 +40,7 @@ impl<'tcx> LibFeatureCollector<'tcx> { }; let feature_stability = match level { - StabilityLevel::Unstable { .. } => FeatureStability::Unstable, + StabilityLevel::Unstable { old_name, .. } => FeatureStability::Unstable { old_name }, StabilityLevel::Stable { since, .. } => FeatureStability::AcceptedSince(match since { StableSince::Version(v) => Symbol::intern(&v.to_string()), StableSince::Current => sym::env_CFG_RELEASE, @@ -71,7 +71,7 @@ impl<'tcx> LibFeatureCollector<'tcx> { }); } } - (FeatureStability::AcceptedSince(_), Some((FeatureStability::Unstable, _))) => { + (FeatureStability::AcceptedSince(_), Some((FeatureStability::Unstable { .. }, _))) => { self.tcx.dcx().emit_err(FeaturePreviouslyDeclared { span, feature, @@ -79,7 +79,7 @@ impl<'tcx> LibFeatureCollector<'tcx> { prev_declared: "unstable", }); } - (FeatureStability::Unstable, Some((FeatureStability::AcceptedSince(_), _))) => { + (FeatureStability::Unstable { .. }, Some((FeatureStability::AcceptedSince(_), _))) => { self.tcx.dcx().emit_err(FeaturePreviouslyDeclared { span, feature, @@ -88,7 +88,7 @@ impl<'tcx> LibFeatureCollector<'tcx> { }); } // duplicate `unstable` feature is ok. - (FeatureStability::Unstable, Some((FeatureStability::Unstable, _))) => {} + (FeatureStability::Unstable { .. }, Some((FeatureStability::Unstable { .. }, _))) => {} } } } diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 45e26c8999a..56d9f5bf785 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -718,6 +718,7 @@ fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index { issue: NonZero::new(27812), is_soft: false, implied_by: None, + old_name: None, }, feature: sym::rustc_private, }; @@ -1161,8 +1162,8 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) { defined_features: &LibFeatures, all_implications: &UnordMap<Symbol, Symbol>, ) { - for (feature, since) in defined_features.to_sorted_vec() { - if let FeatureStability::AcceptedSince(since) = since + for (feature, stability) in defined_features.to_sorted_vec() { + if let FeatureStability::AcceptedSince(since) = stability && let Some(span) = remaining_lib_features.get(&feature) { // Warn if the user has enabled an already-stable lib feature. @@ -1181,6 +1182,12 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) { // implications from this crate. remaining_implications.remove(&feature); + if let FeatureStability::Unstable { old_name: Some(alias) } = stability { + if let Some(span) = remaining_lib_features.swap_remove(&alias) { + tcx.dcx().emit_err(errors::RenamedFeature { span, feature, alias }); + } + } + if remaining_lib_features.is_empty() && remaining_implications.is_empty() { break; } diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl index 38cdfa72a14..58942474e32 100644 --- a/compiler/rustc_resolve/messages.ftl +++ b/compiler/rustc_resolve/messages.ftl @@ -119,7 +119,7 @@ resolve_const_param_in_enum_discriminant = const parameters may not be used in enum discriminant values resolve_const_param_in_non_trivial_anon_const = - const parameters may only be used as standalone arguments, i.e. `{$name}` + const parameters may only be used as standalone arguments here, i.e. `{$name}` resolve_constructor_private_if_any_field_private = a constructor is private if any of the fields is private diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index c30ed781f35..650a827ba56 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -1098,22 +1098,20 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { self.r.potentially_unused_imports.push(import); module.for_each_child(self, |this, ident, ns, binding| { if ns == MacroNS { - let imported_binding = - if this.r.is_accessible_from(binding.vis, this.parent_scope.module) { - this.r.import(binding, import) - } else if !this.r.is_builtin_macro(binding.res()) - && !this.r.macro_use_prelude.contains_key(&ident.name) - { - // - `!r.is_builtin_macro(res)` excluding the built-in macros such as `Debug` or `Hash`. - // - `!r.macro_use_prelude.contains_key(name)` excluding macros defined in other extern - // crates such as `std`. - // FIXME: This branch should eventually be removed. - let import = macro_use_import(this, span, true); - this.r.import(binding, import) - } else { + let import = if this.r.is_accessible_from(binding.vis, this.parent_scope.module) + { + import + } else { + // FIXME: This branch is used for reporting the `private_macro_use` lint + // and should eventually be removed. + if this.r.macro_use_prelude.contains_key(&ident.name) { + // Do not override already existing entries with compatibility entries. return; - }; - this.add_macro_use_binding(ident.name, imported_binding, span, allow_shadowing); + } + macro_use_import(this, span, true) + }; + let import_binding = this.r.import(binding, import); + this.add_macro_use_binding(ident.name, import_binding, span, allow_shadowing); } }); } else { diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index dc16fe212b1..f8e0a6936a0 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -128,7 +128,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { // FIXME(jdonszelmann) make one of these in the resolver? // FIXME(jdonszelmann) don't care about tools here maybe? Just parse what we can. // Does that prevents errors from happening? maybe - let parser = AttributeParser::new( + let mut parser = AttributeParser::new_early( &self.resolver.tcx.sess, self.resolver.tcx.features(), Vec::new(), @@ -136,8 +136,14 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { let attrs = parser.parse_attribute_list( &i.attrs, i.span, + i.id, OmitDoc::Skip, std::convert::identity, + |_l| { + // FIXME(jdonszelmann): emit lints here properly + // NOTE that before new attribute parsing, they didn't happen either + // but it would be nice if we could change that. + }, ); let macro_data = diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 201b1c0a493..9149974a617 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -7,7 +7,7 @@ use rustc_ast::{ use rustc_ast_pretty::pprust; use rustc_attr_data_structures::{self as attr, Stability}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_data_structures::unord::UnordSet; +use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_errors::codes::*; use rustc_errors::{ Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, MultiSpan, SuggestionStyle, @@ -1054,6 +1054,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { false, false, None, + None, ) else { continue; }; @@ -1482,7 +1483,35 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { parent_scope: &ParentScope<'ra>, ident: Ident, krate: &Crate, + sugg_span: Option<Span>, ) { + // Bring imported but unused `derive` macros into `macro_map` so we ensure they can be used + // for suggestions. + self.visit_scopes( + ScopeSet::Macro(MacroKind::Derive), + &parent_scope, + ident.span.ctxt(), + |this, scope, _use_prelude, _ctxt| { + let Scope::Module(m, _) = scope else { + return None; + }; + for (_, resolution) in this.resolutions(m).borrow().iter() { + let Some(binding) = resolution.borrow().binding else { + continue; + }; + let Res::Def(DefKind::Macro(MacroKind::Derive | MacroKind::Attr), def_id) = + binding.res() + else { + continue; + }; + // By doing this all *imported* macros get added to the `macro_map` even if they + // are *unused*, which makes the later suggestions find them and work. + let _ = this.get_macro_by_def_id(def_id); + } + None::<()> + }, + ); + let is_expected = &|res: Res| res.macro_kind() == Some(macro_kind); let suggestion = self.early_lookup_typo_candidate( ScopeSet::Macro(macro_kind), @@ -1490,7 +1519,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ident, is_expected, ); - self.add_typo_suggestion(err, suggestion, ident.span); + if !self.add_typo_suggestion(err, suggestion, ident.span) { + self.detect_derive_attribute(err, ident, parent_scope, sugg_span); + } let import_suggestions = self.lookup_import_candidates(ident, Namespace::MacroNS, parent_scope, is_expected); @@ -1623,6 +1654,105 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } + /// Given an attribute macro that failed to be resolved, look for `derive` macros that could + /// provide it, either as-is or with small typos. + fn detect_derive_attribute( + &self, + err: &mut Diag<'_>, + ident: Ident, + parent_scope: &ParentScope<'ra>, + sugg_span: Option<Span>, + ) { + // Find all of the `derive`s in scope and collect their corresponding declared + // attributes. + // FIXME: this only works if the crate that owns the macro that has the helper_attr + // has already been imported. + let mut derives = vec![]; + let mut all_attrs: UnordMap<Symbol, Vec<_>> = UnordMap::default(); + // We're collecting these in a hashmap, and handle ordering the output further down. + #[allow(rustc::potential_query_instability)] + for (def_id, data) in &self.macro_map { + for helper_attr in &data.ext.helper_attrs { + let item_name = self.tcx.item_name(*def_id); + all_attrs.entry(*helper_attr).or_default().push(item_name); + if helper_attr == &ident.name { + derives.push(item_name); + } + } + } + let kind = MacroKind::Derive.descr(); + if !derives.is_empty() { + // We found an exact match for the missing attribute in a `derive` macro. Suggest it. + let mut derives: Vec<String> = derives.into_iter().map(|d| d.to_string()).collect(); + derives.sort(); + derives.dedup(); + let msg = match &derives[..] { + [derive] => format!(" `{derive}`"), + [start @ .., last] => format!( + "s {} and `{last}`", + start.iter().map(|d| format!("`{d}`")).collect::<Vec<_>>().join(", ") + ), + [] => unreachable!("we checked for this to be non-empty 10 lines above!?"), + }; + let msg = format!( + "`{}` is an attribute that can be used by the {kind}{msg}, you might be \ + missing a `derive` attribute", + ident.name, + ); + let sugg_span = if let ModuleKind::Def(DefKind::Enum, id, _) = parent_scope.module.kind + { + let span = self.def_span(id); + if span.from_expansion() { + None + } else { + // For enum variants sugg_span is empty but we can get the enum's Span. + Some(span.shrink_to_lo()) + } + } else { + // For items this `Span` will be populated, everything else it'll be None. + sugg_span + }; + match sugg_span { + Some(span) => { + err.span_suggestion_verbose( + span, + msg, + format!("#[derive({})]\n", derives.join(", ")), + Applicability::MaybeIncorrect, + ); + } + None => { + err.note(msg); + } + } + } else { + // We didn't find an exact match. Look for close matches. If any, suggest fixing typo. + let all_attr_names = all_attrs.keys().map(|s| *s).into_sorted_stable_ord(); + if let Some(best_match) = find_best_match_for_name(&all_attr_names, ident.name, None) + && let Some(macros) = all_attrs.get(&best_match) + { + let mut macros: Vec<String> = macros.into_iter().map(|d| d.to_string()).collect(); + macros.sort(); + macros.dedup(); + let msg = match ¯os[..] { + [] => return, + [name] => format!(" `{name}` accepts"), + [start @ .., end] => format!( + "s {} and `{end}` accept", + start.iter().map(|m| format!("`{m}`")).collect::<Vec<_>>().join(", "), + ), + }; + let msg = format!("the {kind}{msg} the similarly named `{best_match}` attribute"); + err.span_suggestion_verbose( + ident.span, + msg, + best_match, + Applicability::MaybeIncorrect, + ); + } + } + } + pub(crate) fn add_typo_suggestion( &self, err: &mut Diag<'_>, diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 180d6af219d..68fbe48ebcb 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -460,6 +460,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { true, force, ignore_import, + None, ) { Ok((Some(ext), _)) => { if ext.helper_attrs.contains(&ident.name) { diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 816efd0d5fa..e989209e177 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -133,7 +133,9 @@ impl<'ra> std::fmt::Debug for ImportKind<'ra> { .field("target", target) .field("id", id) .finish(), - MacroUse { .. } => f.debug_struct("MacroUse").finish(), + MacroUse { warn_private } => { + f.debug_struct("MacroUse").field("warn_private", warn_private).finish() + } MacroExport => f.debug_struct("MacroExport").finish(), } } diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 3dc285fdab6..fa4b024c422 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -4509,7 +4509,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { let path_seg = |seg: &Segment| PathSegment::from_ident(seg.ident); let path = Path { segments: path.iter().map(path_seg).collect(), span, tokens: None }; if let Ok((_, res)) = - self.r.resolve_macro_path(&path, None, &self.parent_scope, false, false, None) + self.r.resolve_macro_path(&path, None, &self.parent_scope, false, false, None, None) { return Ok(Some(PartialRes::new(res))); } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 9ba70abd4d9..f0540725416 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1139,7 +1139,7 @@ pub struct Resolver<'ra, 'tcx> { proc_macro_stubs: FxHashSet<LocalDefId>, /// Traces collected during macro resolution and validated when it's complete. single_segment_macro_resolutions: - Vec<(Ident, MacroKind, ParentScope<'ra>, Option<NameBinding<'ra>>)>, + Vec<(Ident, MacroKind, ParentScope<'ra>, Option<NameBinding<'ra>>, Option<Span>)>, multi_segment_macro_resolutions: Vec<(Vec<Segment>, Span, MacroKind, ParentScope<'ra>, Option<Res>, Namespace)>, builtin_attrs: Vec<(Ident, ParentScope<'ra>)>, @@ -1934,12 +1934,26 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } if let NameBindingKind::Import { import, binding } = used_binding.kind { if let ImportKind::MacroUse { warn_private: true } = import.kind { - self.lint_buffer().buffer_lint( - PRIVATE_MACRO_USE, - import.root_id, - ident.span, - BuiltinLintDiag::MacroIsPrivate(ident), - ); + // Do not report the lint if the macro name resolves in stdlib prelude + // even without the problematic `macro_use` import. + let found_in_stdlib_prelude = self.prelude.is_some_and(|prelude| { + self.maybe_resolve_ident_in_module( + ModuleOrUniformRoot::Module(prelude), + ident, + MacroNS, + &ParentScope::module(self.empty_module, self), + None, + ) + .is_ok() + }); + if !found_in_stdlib_prelude { + self.lint_buffer().buffer_lint( + PRIVATE_MACRO_USE, + import.root_id, + ident.span, + BuiltinLintDiag::MacroIsPrivate(ident), + ); + } } // Avoid marking `extern crate` items that refer to a name from extern prelude, // but not introduce it, as used if they are accessed from lexical scope. diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index ee905065b96..1b82e9c9799 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -12,7 +12,8 @@ use rustc_attr_data_structures::StabilityLevel; use rustc_data_structures::intern::Interned; use rustc_errors::{Applicability, DiagCtxtHandle, StashKey}; use rustc_expand::base::{ - DeriveResolution, Indeterminate, ResolverExpand, SyntaxExtension, SyntaxExtensionKind, + Annotatable, DeriveResolution, Indeterminate, ResolverExpand, SyntaxExtension, + SyntaxExtensionKind, }; use rustc_expand::compile_declarative_macro; use rustc_expand::expand::{ @@ -294,6 +295,14 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { && self.tcx.def_kind(mod_def_id) == DefKind::Mod }) .map(|&InvocationParent { parent_def: mod_def_id, .. }| mod_def_id); + let sugg_span = match &invoc.kind { + InvocationKind::Attr { item: Annotatable::Item(item), .. } + if !item.span.from_expansion() => + { + Some(item.span.shrink_to_lo()) + } + _ => None, + }; let (ext, res) = self.smart_resolve_macro_path( path, kind, @@ -304,6 +313,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { force, deleg_impl, looks_like_invoc_in_mod_inert_attr, + sugg_span, )?; let span = invoc.span(); @@ -386,6 +396,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { true, force, None, + None, ) { Ok((Some(ext), _)) => { if !ext.helper_attrs.is_empty() { @@ -528,6 +539,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { force: bool, deleg_impl: Option<LocalDefId>, invoc_in_mod_inert_attr: Option<LocalDefId>, + suggestion_span: Option<Span>, ) -> Result<(Arc<SyntaxExtension>, Res), Indeterminate> { let (ext, res) = match self.resolve_macro_or_delegation_path( path, @@ -538,6 +550,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { deleg_impl, invoc_in_mod_inert_attr.map(|def_id| (def_id, node_id)), None, + suggestion_span, ) { Ok((Some(ext), res)) => (ext, res), Ok((None, res)) => (self.dummy_ext(kind), res), @@ -681,6 +694,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { trace: bool, force: bool, ignore_import: Option<Import<'ra>>, + suggestion_span: Option<Span>, ) -> Result<(Option<Arc<SyntaxExtension>>, Res), Determinacy> { self.resolve_macro_or_delegation_path( path, @@ -691,6 +705,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { None, None, ignore_import, + suggestion_span, ) } @@ -704,6 +719,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { deleg_impl: Option<LocalDefId>, invoc_in_mod_inert_attr: Option<(LocalDefId, NodeId)>, ignore_import: Option<Import<'ra>>, + suggestion_span: Option<Span>, ) -> Result<(Option<Arc<SyntaxExtension>>, Res), Determinacy> { let path_span = ast_path.span; let mut path = Segment::from_path(ast_path); @@ -768,6 +784,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { kind, *parent_scope, binding.ok(), + suggestion_span, )); } @@ -905,7 +922,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } let macro_resolutions = mem::take(&mut self.single_segment_macro_resolutions); - for (ident, kind, parent_scope, initial_binding) in macro_resolutions { + for (ident, kind, parent_scope, initial_binding, sugg_span) in macro_resolutions { match self.early_resolve_ident_in_lexical_scope( ident, ScopeSet::Macro(kind), @@ -946,7 +963,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { expected, ident, }); - self.unresolved_macro_suggestions(&mut err, kind, &parent_scope, ident, krate); + self.unresolved_macro_suggestions( + &mut err, + kind, + &parent_scope, + ident, + krate, + sugg_span, + ); err.emit(); } } @@ -974,7 +998,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ) { let span = path.span; if let Some(stability) = &ext.stability { - if let StabilityLevel::Unstable { reason, issue, is_soft, implied_by } = stability.level + if let StabilityLevel::Unstable { reason, issue, is_soft, implied_by, .. } = + stability.level { let feature = stability.feature; diff --git a/compiler/rustc_session/messages.ftl b/compiler/rustc_session/messages.ftl index 528c52eace7..61953614c77 100644 --- a/compiler/rustc_session/messages.ftl +++ b/compiler/rustc_session/messages.ftl @@ -40,6 +40,11 @@ session_file_is_not_writeable = output file {$file} is not writeable -- check it session_file_write_fail = failed to write `{$path}` due to error `{$err}` +session_forbidden_ctarget_feature = + target feature `{$feature}` cannot be {$enabled} with `-Ctarget-feature`: {$reason} + .note = this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +session_forbidden_ctarget_feature_issue = for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344> + session_function_return_requires_x86_or_x86_64 = `-Zfunction-return` (except `keep`) is only supported on x86 and x86_64 session_function_return_thunk_extern_requires_non_large_code_model = `-Zfunction-return=thunk-extern` is only supported on non-large code models @@ -132,6 +137,9 @@ session_target_stack_protector_not_supported = `-Z stack-protector={$stack_prote session_unleashed_feature_help_named = skipping check for `{$gate}` feature session_unleashed_feature_help_unnamed = skipping check that does not even have a feature gate +session_unstable_ctarget_feature = + unstable feature specified for `-Ctarget-feature`: `{$feature}` + .note = this feature is not stably supported; its behavior can change in the future session_unstable_virtual_function_elimination = `-Zvirtual-function-elimination` requires `-Clto` session_unsupported_crate_type_for_target = diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 60e1b465ba9..8984634e5ec 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -2649,6 +2649,15 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M let prints = collect_print_requests(early_dcx, &mut cg, &unstable_opts, matches); + // -Zretpoline-external-thunk also requires -Zretpoline + if unstable_opts.retpoline_external_thunk { + unstable_opts.retpoline = true; + target_modifiers.insert( + OptionsTargetModifiers::UnstableOptions(UnstableOptionsTargetModifiers::retpoline), + "true".to_string(), + ); + } + let cg = cg; let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m)); diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs index bf95014843d..9c591dcf619 100644 --- a/compiler/rustc_session/src/errors.rs +++ b/compiler/rustc_session/src/errors.rs @@ -501,3 +501,20 @@ pub(crate) struct SoftFloatIgnored; #[note] #[note(session_soft_float_deprecated_issue)] pub(crate) struct SoftFloatDeprecated; + +#[derive(Diagnostic)] +#[diag(session_forbidden_ctarget_feature)] +#[note] +#[note(session_forbidden_ctarget_feature_issue)] +pub(crate) struct ForbiddenCTargetFeature<'a> { + pub feature: &'a str, + pub enabled: &'a str, + pub reason: &'a str, +} + +#[derive(Diagnostic)] +#[diag(session_unstable_ctarget_feature)] +#[note] +pub(crate) struct UnstableCTargetFeature<'a> { + pub feature: &'a str, +} diff --git a/compiler/rustc_session/src/features.rs b/compiler/rustc_session/src/features.rs new file mode 100644 index 00000000000..70a088a236f --- /dev/null +++ b/compiler/rustc_session/src/features.rs @@ -0,0 +1,59 @@ +use rustc_target::target_features::Stability; + +use crate::Session; +use crate::errors::{ForbiddenCTargetFeature, UnstableCTargetFeature}; + +pub trait StabilityExt { + /// Returns whether the feature may be toggled via `#[target_feature]` or `-Ctarget-feature`. + /// Otherwise, some features also may only be enabled by flag (target modifier). + /// (It might still be nightly-only even if this returns `true`, so make sure to also check + /// `requires_nightly`.) + fn is_toggle_permitted(&self, sess: &Session) -> Result<(), &'static str>; + + /// Check that feature is correctly enabled/disabled by command line flag (emits warnings) + fn verify_feature_enabled_by_flag(&self, sess: &Session, enable: bool, feature: &str); +} + +impl StabilityExt for Stability { + fn is_toggle_permitted(&self, sess: &Session) -> Result<(), &'static str> { + match self { + Stability::Forbidden { reason } => Err(reason), + Stability::TargetModifierOnly { reason, flag } => { + if !sess.opts.target_feature_flag_enabled(*flag) { Err(reason) } else { Ok(()) } + } + _ => Ok(()), + } + } + fn verify_feature_enabled_by_flag(&self, sess: &Session, enable: bool, feature: &str) { + if let Err(reason) = self.is_toggle_permitted(sess) { + sess.dcx().emit_warn(ForbiddenCTargetFeature { + feature, + enabled: if enable { "enabled" } else { "disabled" }, + reason, + }); + } else if self.requires_nightly().is_some() { + // An unstable feature. Warn about using it. It makes little sense + // to hard-error here since we just warn about fully unknown + // features above. + sess.dcx().emit_warn(UnstableCTargetFeature { feature }); + } + } +} + +pub fn retpoline_features_by_flags(sess: &Session, features: &mut Vec<&str>) { + // -Zretpoline without -Zretpoline-external-thunk enables + // retpoline-indirect-branches and retpoline-indirect-calls target features + let unstable_opts = &sess.opts.unstable_opts; + if unstable_opts.retpoline && !unstable_opts.retpoline_external_thunk { + features.push("+retpoline-indirect-branches"); + features.push("+retpoline-indirect-calls"); + } + // -Zretpoline-external-thunk (maybe, with -Zretpoline too) enables + // retpoline-external-thunk, retpoline-indirect-branches and + // retpoline-indirect-calls target features + if unstable_opts.retpoline_external_thunk { + features.push("+retpoline-external-thunk"); + features.push("+retpoline-indirect-branches"); + features.push("+retpoline-indirect-calls"); + } +} diff --git a/compiler/rustc_session/src/lib.rs b/compiler/rustc_session/src/lib.rs index 5e5872ee068..4added19e56 100644 --- a/compiler/rustc_session/src/lib.rs +++ b/compiler/rustc_session/src/lib.rs @@ -29,6 +29,7 @@ pub use session::*; pub mod output; pub use getopts; +pub mod features; rustc_fluent_macro::fluent_messages! { "../messages.ftl" } diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 12fa05118ca..6218521d4f0 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -290,6 +290,14 @@ macro_rules! top_level_options { mods.sort_by(|a, b| a.opt.cmp(&b.opt)); mods } + + pub fn target_feature_flag_enabled(&self, flag: &str) -> bool { + match flag { + "retpoline" => self.unstable_opts.retpoline, + "retpoline-external-thunk" => self.unstable_opts.retpoline_external_thunk, + _ => false, + } + } } ); } @@ -2305,6 +2313,8 @@ options! { (space separated)"), macro_backtrace: bool = (false, parse_bool, [UNTRACKED], "show macro backtraces (default: no)"), + macro_stats: bool = (false, parse_bool, [UNTRACKED], + "print some statistics about macro expansions (default: no)"), maximal_hir_to_mir_coverage: bool = (false, parse_bool, [TRACKED], "save as much information as possible about the correspondence between MIR and HIR \ as source scopes (default: no)"), @@ -2446,6 +2456,11 @@ options! { remark_dir: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED], "directory into which to write optimization remarks (if not specified, they will be \ written to standard error output)"), + retpoline: bool = (false, parse_bool, [TRACKED TARGET_MODIFIER], + "enables retpoline-indirect-branches and retpoline-indirect-calls target features (default: no)"), + retpoline_external_thunk: bool = (false, parse_bool, [TRACKED TARGET_MODIFIER], + "enables retpoline-external-thunk, retpoline-indirect-branches and retpoline-indirect-calls \ + target features (default: no)"), sanitizer: SanitizerSet = (SanitizerSet::empty(), parse_sanitizers, [TRACKED], "use a sanitizer"), sanitizer_cfi_canonical_jump_tables: Option<bool> = (Some(true), parse_opt_bool, [TRACKED], diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index 1fe521bd32d..87c848cf857 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -17,7 +17,7 @@ use rustc_feature::{GateIssue, UnstableFeatures, find_feature_issue}; use rustc_span::edition::Edition; use rustc_span::hygiene::ExpnId; use rustc_span::source_map::{FilePathMapping, SourceMap}; -use rustc_span::{Span, Symbol}; +use rustc_span::{Span, Symbol, sym}; use crate::Session; use crate::config::{Cfg, CheckCfg}; @@ -192,8 +192,11 @@ pub fn add_feature_diagnostics_for_issue<G: EmissionGuarantee>( } else { err.subdiagnostic(FeatureDiagnosticHelp { feature }); } - - if sess.opts.unstable_opts.ui_testing { + if feature == sym::rustc_attrs { + // We're unlikely to stabilize something out of `rustc_attrs` + // without at least renaming it, so pointing out how old + // the compiler is will do little good. + } else if sess.opts.unstable_opts.ui_testing { err.subdiagnostic(SuggestUpgradeCompiler::ui_testing()); } else if let Some(suggestion) = SuggestUpgradeCompiler::new() { err.subdiagnostic(suggestion); diff --git a/compiler/rustc_smir/src/rustc_internal/internal.rs b/compiler/rustc_smir/src/rustc_internal/internal.rs index 6e13b87c41d..a4c6f186222 100644 --- a/compiler/rustc_smir/src/rustc_internal/internal.rs +++ b/compiler/rustc_smir/src/rustc_internal/internal.rs @@ -496,6 +496,7 @@ impl RustcInternal for Abi { Abi::RustCold => rustc_abi::ExternAbi::RustCold, Abi::RiscvInterruptM => rustc_abi::ExternAbi::RiscvInterruptM, Abi::RiscvInterruptS => rustc_abi::ExternAbi::RiscvInterruptS, + Abi::Custom => rustc_abi::ExternAbi::Custom, } } } diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs index bac5c9066f1..ef8c88355f6 100644 --- a/compiler/rustc_smir/src/rustc_smir/context.rs +++ b/compiler/rustc_smir/src/rustc_smir/context.rs @@ -16,7 +16,7 @@ use rustc_middle::ty::{ }; use rustc_middle::{mir, ty}; use rustc_span::def_id::LOCAL_CRATE; -use stable_mir::abi::{FnAbi, Layout, LayoutShape}; +use stable_mir::abi::{FnAbi, Layout, LayoutShape, ReprOptions}; use stable_mir::mir::alloc::GlobalAlloc; use stable_mir::mir::mono::{InstanceDef, StaticDef}; use stable_mir::mir::{BinOp, Body, Place, UnOp}; @@ -397,6 +397,13 @@ impl<'tcx> SmirCtxt<'tcx> { tables.tcx.is_lang_item(def_id, LangItem::CStr) } + /// Returns the representation options for this ADT + pub fn adt_repr(&self, def: AdtDef) -> ReprOptions { + let mut tables = self.0.borrow_mut(); + let tcx = tables.tcx; + def.internal(&mut *tables, tcx).repr().stable(&mut *tables) + } + /// Retrieve the function signature for the given generic arguments. pub fn fn_sig(&self, def: FnDef, args: &GenericArgs) -> PolyFnSig { let mut tables = self.0.borrow_mut(); diff --git a/compiler/rustc_smir/src/rustc_smir/convert/abi.rs b/compiler/rustc_smir/src/rustc_smir/convert/abi.rs index 64901ee0502..35d5b7fb89a 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/abi.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/abi.rs @@ -6,9 +6,9 @@ use rustc_abi::{ArmCall, CanonAbi, InterruptKind, X86Call}; use rustc_middle::ty; use rustc_target::callconv; use stable_mir::abi::{ - AddressSpace, ArgAbi, CallConvention, FieldsShape, FloatLength, FnAbi, IntegerLength, Layout, - LayoutShape, PassMode, Primitive, Scalar, TagEncoding, TyAndLayout, ValueAbi, VariantsShape, - WrappingRange, + AddressSpace, ArgAbi, CallConvention, FieldsShape, FloatLength, FnAbi, IntegerLength, + IntegerType, Layout, LayoutShape, PassMode, Primitive, ReprFlags, ReprOptions, Scalar, + TagEncoding, TyAndLayout, ValueAbi, VariantsShape, WrappingRange, }; use stable_mir::opaque; use stable_mir::target::MachineSize as Size; @@ -101,6 +101,7 @@ impl<'tcx> Stable<'tcx> for CanonAbi { CanonAbi::C => CallConvention::C, CanonAbi::Rust => CallConvention::Rust, CanonAbi::RustCold => CallConvention::Cold, + CanonAbi::Custom => CallConvention::Custom, CanonAbi::Arm(arm_call) => match arm_call { ArmCall::Aapcs => CallConvention::ArmAapcs, ArmCall::CCmseNonSecureCall => CallConvention::CCmseNonSecureCall, @@ -310,3 +311,42 @@ impl<'tcx> Stable<'tcx> for rustc_abi::WrappingRange { WrappingRange { start: self.start, end: self.end } } } + +impl<'tcx> Stable<'tcx> for rustc_abi::ReprFlags { + type T = ReprFlags; + + fn stable(&self, _tables: &mut Tables<'_>) -> Self::T { + ReprFlags { + is_simd: self.intersects(Self::IS_SIMD), + is_c: self.intersects(Self::IS_C), + is_transparent: self.intersects(Self::IS_TRANSPARENT), + is_linear: self.intersects(Self::IS_LINEAR), + } + } +} + +impl<'tcx> Stable<'tcx> for rustc_abi::IntegerType { + type T = IntegerType; + + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { + match self { + rustc_abi::IntegerType::Pointer(signed) => IntegerType::Pointer { is_signed: *signed }, + rustc_abi::IntegerType::Fixed(integer, signed) => { + IntegerType::Fixed { length: integer.stable(tables), is_signed: *signed } + } + } + } +} + +impl<'tcx> Stable<'tcx> for rustc_abi::ReprOptions { + type T = ReprOptions; + + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { + ReprOptions { + int: self.int.map(|int| int.stable(tables)), + align: self.align.map(|align| align.stable(tables)), + pack: self.pack.map(|pack| pack.stable(tables)), + flags: self.flags.stable(tables), + } + } +} diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs index b0c9dba78a6..6a26f5f7997 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs @@ -879,6 +879,7 @@ impl<'tcx> Stable<'tcx> for rustc_abi::ExternAbi { ExternAbi::RustCold => Abi::RustCold, ExternAbi::RiscvInterruptM => Abi::RiscvInterruptM, ExternAbi::RiscvInterruptS => Abi::RiscvInterruptS, + ExternAbi::Custom => Abi::Custom, } } } diff --git a/compiler/rustc_smir/src/stable_mir/abi.rs b/compiler/rustc_smir/src/stable_mir/abi.rs index 3842cb7e653..d8a2b97662c 100644 --- a/compiler/rustc_smir/src/stable_mir/abi.rs +++ b/compiler/rustc_smir/src/stable_mir/abi.rs @@ -430,6 +430,8 @@ pub enum CallConvention { PreserveMost, PreserveAll, + Custom, + // Target-specific calling conventions. ArmAapcs, CCmseNonSecureCall, @@ -455,3 +457,38 @@ pub enum CallConvention { RiscvInterrupt, } + +#[non_exhaustive] +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Serialize)] +pub struct ReprFlags { + pub is_simd: bool, + pub is_c: bool, + pub is_transparent: bool, + pub is_linear: bool, +} + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Serialize)] +pub enum IntegerType { + /// Pointer-sized integer type, i.e. `isize` and `usize`. + Pointer { + /// Signedness. e.g. `true` for `isize` + is_signed: bool, + }, + /// Fixed-sized integer type, e.g. `i8`, `u32`, `i128`. + Fixed { + /// Length of this integer type. e.g. `IntegerLength::I8` for `u8`. + length: IntegerLength, + /// Signedness. e.g. `false` for `u8` + is_signed: bool, + }, +} + +/// Representation options provided by the user +#[non_exhaustive] +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Serialize)] +pub struct ReprOptions { + pub int: Option<IntegerType>, + pub align: Option<Align>, + pub pack: Option<Align>, + pub flags: ReprFlags, +} diff --git a/compiler/rustc_smir/src/stable_mir/compiler_interface.rs b/compiler/rustc_smir/src/stable_mir/compiler_interface.rs index bb35e23a728..3967ad13eeb 100644 --- a/compiler/rustc_smir/src/stable_mir/compiler_interface.rs +++ b/compiler/rustc_smir/src/stable_mir/compiler_interface.rs @@ -6,7 +6,7 @@ use std::cell::Cell; use rustc_smir::context::SmirCtxt; -use stable_mir::abi::{FnAbi, Layout, LayoutShape}; +use stable_mir::abi::{FnAbi, Layout, LayoutShape, ReprOptions}; use stable_mir::crate_def::Attribute; use stable_mir::mir::alloc::{AllocId, GlobalAlloc}; use stable_mir::mir::mono::{Instance, InstanceDef, StaticDef}; @@ -200,6 +200,11 @@ impl<'tcx> SmirInterface<'tcx> { self.cx.adt_is_cstr(def) } + /// Returns the representation options for this ADT + pub(crate) fn adt_repr(&self, def: AdtDef) -> ReprOptions { + self.cx.adt_repr(def) + } + /// Retrieve the function signature for the given generic arguments. pub(crate) fn fn_sig(&self, def: FnDef, args: &GenericArgs) -> PolyFnSig { self.cx.fn_sig(def, args) diff --git a/compiler/rustc_smir/src/stable_mir/ty.rs b/compiler/rustc_smir/src/stable_mir/ty.rs index e331e593471..2934af31cd5 100644 --- a/compiler/rustc_smir/src/stable_mir/ty.rs +++ b/compiler/rustc_smir/src/stable_mir/ty.rs @@ -9,6 +9,7 @@ use stable_mir::mir::mono::StaticDef; use stable_mir::target::MachineInfo; use stable_mir::{Filename, Opaque}; +use super::abi::ReprOptions; use super::mir::{Body, Mutability, Safety}; use super::{DefId, Error, Symbol, with}; use crate::stable_mir; @@ -742,6 +743,14 @@ crate_def! { pub ClosureDef; } +impl ClosureDef { + /// Retrieves the body of the closure definition. Returns None if the body + /// isn't available. + pub fn body(&self) -> Option<Body> { + with(|ctx| ctx.has_body(self.0).then(|| ctx.mir_body(self.0))) + } +} + crate_def! { #[derive(Serialize)] pub CoroutineDef; @@ -818,6 +827,10 @@ impl AdtDef { pub fn variant(&self, idx: VariantIdx) -> Option<VariantDef> { (idx.to_index() < self.num_variants()).then_some(VariantDef { idx, adt_def: *self }) } + + pub fn repr(&self) -> ReprOptions { + with(|cx| cx.adt_repr(*self)) + } } /// Definition of a variant, which can be either a struct / union field or an enum variant. @@ -1098,6 +1111,7 @@ pub enum Abi { RustCold, RiscvInterruptM, RiscvInterruptS, + Custom, } /// A binder represents a possibly generic type and its bound vars. diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index b621920d62b..315dedec107 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -1135,7 +1135,7 @@ impl ExpnKind { } /// The kind of macro invocation or definition. -#[derive(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash, Debug)] +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Encodable, Decodable, Hash, Debug)] #[derive(HashStable_Generic)] pub enum MacroKind { /// A bang macro `foo!()`. diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index d66f98871b9..cb9ccf4cc3f 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -407,6 +407,7 @@ symbols! { abi_amdgpu_kernel, abi_avr_interrupt, abi_c_cmse_nonsecure_call, + abi_custom, abi_efiapi, abi_gpu_kernel, abi_msp430_interrupt, @@ -429,6 +430,8 @@ symbols! { aggregate_raw_ptr, alias, align, + align_of, + align_of_val, alignment, all, alloc, @@ -1353,8 +1356,6 @@ symbols! { message, meta, metadata_type, - min_align_of, - min_align_of_val, min_const_fn, min_const_generics, min_const_unsafe_fn, @@ -1512,6 +1513,7 @@ symbols! { offset_of_nested, offset_of_slice, ok_or_else, + old_name, omit_gdb_pretty_printer_section, on, on_unimplemented, @@ -2288,6 +2290,7 @@ symbols! { usize_legacy_fn_max_value, usize_legacy_fn_min_value, usize_legacy_mod, + v1, v8plus, va_arg, va_copy, @@ -2675,7 +2678,7 @@ impl Interner { assert_eq!( strings.len(), init.len() + extra.len(), - "`init` or `extra` contain duplicate symbols", + "there are duplicate symbols in the rustc symbol list and the extra symbols added by the driver", ); Interner(Lock::new(InternerInner { arena: Default::default(), strings })) } diff --git a/compiler/rustc_target/src/asm/loongarch.rs b/compiler/rustc_target/src/asm/loongarch.rs index b4ea6fc592a..8783d3953b1 100644 --- a/compiler/rustc_target/src/asm/loongarch.rs +++ b/compiler/rustc_target/src/asm/loongarch.rs @@ -34,11 +34,13 @@ impl LoongArchInlineAsmRegClass { pub fn supported_types( self, - _arch: InlineAsmArch, + arch: InlineAsmArch, ) -> &'static [(InlineAsmType, Option<Symbol>)] { - match self { - Self::reg => types! { _: I8, I16, I32, I64, F32, F64; }, - Self::freg => types! { f: F32; d: F64; }, + match (self, arch) { + (Self::reg, InlineAsmArch::LoongArch64) => types! { _: I8, I16, I32, I64, F32, F64; }, + (Self::reg, InlineAsmArch::LoongArch32) => types! { _: I8, I16, I32, F32; }, + (Self::freg, _) => types! { f: F32; d: F64; }, + _ => unreachable!("unsupported register class"), } } } diff --git a/compiler/rustc_target/src/spec/abi_map.rs b/compiler/rustc_target/src/spec/abi_map.rs index c4978a8e52a..4659bbdb890 100644 --- a/compiler/rustc_target/src/spec/abi_map.rs +++ b/compiler/rustc_target/src/spec/abi_map.rs @@ -71,6 +71,8 @@ impl AbiMap { (ExternAbi::RustCold, _) if self.os == OsKind::Windows => CanonAbi::Rust, (ExternAbi::RustCold, _) => CanonAbi::RustCold, + (ExternAbi::Custom, _) => CanonAbi::Custom, + (ExternAbi::System { .. }, Arch::X86) if os == OsKind::Windows && !has_c_varargs => { CanonAbi::X86(X86Call::Stdcall) } diff --git a/compiler/rustc_target/src/spec/base/xtensa.rs b/compiler/rustc_target/src/spec/base/xtensa.rs index 47a532dfdd4..a7cc748973c 100644 --- a/compiler/rustc_target/src/spec/base/xtensa.rs +++ b/compiler/rustc_target/src/spec/base/xtensa.rs @@ -6,7 +6,7 @@ pub(crate) fn opts() -> TargetOptions { TargetOptions { os: "none".into(), endian: Endian::Little, - c_int_width: "32".into(), + c_int_width: 32, linker_flavor: LinkerFlavor::Gnu(Cc::Yes, Lld::No), executables: true, panic_strategy: PanicStrategy::Abort, diff --git a/compiler/rustc_target/src/spec/json.rs b/compiler/rustc_target/src/spec/json.rs index 039056a5a25..6c716f87125 100644 --- a/compiler/rustc_target/src/spec/json.rs +++ b/compiler/rustc_target/src/spec/json.rs @@ -80,6 +80,12 @@ impl Target { base.$key_name = s; } } ); + ($key_name:ident = $json_name:expr, u64 as $int_ty:ty) => ( { + let name = $json_name; + if let Some(s) = obj.remove(name).and_then(|b| b.as_u64()) { + base.$key_name = s as $int_ty; + } + } ); ($key_name:ident, bool) => ( { let name = (stringify!($key_name)).replace("_", "-"); if let Some(s) = obj.remove(&name).and_then(|b| b.as_bool()) { @@ -554,7 +560,7 @@ impl Target { } } - key!(c_int_width = "target-c-int-width"); + key!(c_int_width = "target-c-int-width", u64 as u16); key!(c_enum_min_bits, Option<u64>); // if None, matches c_int_width key!(os); key!(env); diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 6ceb5e80f21..c360fe63a00 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -2213,18 +2213,10 @@ impl Target { }); } - dl.c_enum_min_size = self - .c_enum_min_bits - .map_or_else( - || { - self.c_int_width - .parse() - .map_err(|_| String::from("failed to parse c_int_width")) - }, - Ok, - ) - .and_then(|i| Integer::from_size(Size::from_bits(i))) - .map_err(|err| TargetDataLayoutErrors::InvalidBitsSize { err })?; + dl.c_enum_min_size = Integer::from_size(Size::from_bits( + self.c_enum_min_bits.unwrap_or(self.c_int_width as _), + )) + .map_err(|err| TargetDataLayoutErrors::InvalidBitsSize { err })?; Ok(dl) } @@ -2286,7 +2278,7 @@ pub struct TargetOptions { /// Used as the `target_endian` `cfg` variable. Defaults to little endian. pub endian: Endian, /// Width of c_int type. Defaults to "32". - pub c_int_width: StaticCow<str>, + pub c_int_width: u16, /// OS name to use for conditional compilation (`target_os`). Defaults to "none". /// "none" implies a bare metal target without `std` library. /// A couple of targets having `std` also use "unknown" as an `os` value, @@ -2783,7 +2775,7 @@ impl Default for TargetOptions { fn default() -> TargetOptions { TargetOptions { endian: Endian::Little, - c_int_width: "32".into(), + c_int_width: 32, os: "none".into(), env: "".into(), abi: "".into(), diff --git a/compiler/rustc_target/src/spec/targets/armv7_sony_vita_newlibeabihf.rs b/compiler/rustc_target/src/spec/targets/armv7_sony_vita_newlibeabihf.rs index 6a83835059e..4902dc37d13 100644 --- a/compiler/rustc_target/src/spec/targets/armv7_sony_vita_newlibeabihf.rs +++ b/compiler/rustc_target/src/spec/targets/armv7_sony_vita_newlibeabihf.rs @@ -31,7 +31,7 @@ pub(crate) fn target() -> Target { options: TargetOptions { os: "vita".into(), endian: Endian::Little, - c_int_width: "32".into(), + c_int_width: 32, env: "newlib".into(), vendor: "sony".into(), abi: "eabihf".into(), diff --git a/compiler/rustc_target/src/spec/targets/avr_none.rs b/compiler/rustc_target/src/spec/targets/avr_none.rs index 91d3197d099..07ed2a37803 100644 --- a/compiler/rustc_target/src/spec/targets/avr_none.rs +++ b/compiler/rustc_target/src/spec/targets/avr_none.rs @@ -13,7 +13,7 @@ pub(crate) fn target() -> Target { llvm_target: "avr-unknown-unknown".into(), pointer_width: 16, options: TargetOptions { - c_int_width: "16".into(), + c_int_width: 16, exe_suffix: ".elf".into(), linker: Some("avr-gcc".into()), eh_frame_header: false, diff --git a/compiler/rustc_target/src/spec/targets/msp430_none_elf.rs b/compiler/rustc_target/src/spec/targets/msp430_none_elf.rs index b067ac1e54a..caf77bb8669 100644 --- a/compiler/rustc_target/src/spec/targets/msp430_none_elf.rs +++ b/compiler/rustc_target/src/spec/targets/msp430_none_elf.rs @@ -16,7 +16,7 @@ pub(crate) fn target() -> Target { arch: "msp430".into(), options: TargetOptions { - c_int_width: "16".into(), + c_int_width: 16, // The LLVM backend currently can't generate object files. To // workaround this LLVM generates assembly files which then we feed diff --git a/compiler/rustc_target/src/spec/targets/xtensa_esp32_espidf.rs b/compiler/rustc_target/src/spec/targets/xtensa_esp32_espidf.rs index c5b4d472fad..8a6773811e8 100644 --- a/compiler/rustc_target/src/spec/targets/xtensa_esp32_espidf.rs +++ b/compiler/rustc_target/src/spec/targets/xtensa_esp32_espidf.rs @@ -13,7 +13,7 @@ pub(crate) fn target() -> Target { options: TargetOptions { endian: Endian::Little, - c_int_width: "32".into(), + c_int_width: 32, families: cvs!["unix"], os: "espidf".into(), env: "newlib".into(), diff --git a/compiler/rustc_target/src/spec/targets/xtensa_esp32s2_espidf.rs b/compiler/rustc_target/src/spec/targets/xtensa_esp32s2_espidf.rs index cffdaa90727..f38d771f257 100644 --- a/compiler/rustc_target/src/spec/targets/xtensa_esp32s2_espidf.rs +++ b/compiler/rustc_target/src/spec/targets/xtensa_esp32s2_espidf.rs @@ -13,7 +13,7 @@ pub(crate) fn target() -> Target { options: TargetOptions { endian: Endian::Little, - c_int_width: "32".into(), + c_int_width: 32, families: cvs!["unix"], os: "espidf".into(), env: "newlib".into(), diff --git a/compiler/rustc_target/src/spec/targets/xtensa_esp32s3_espidf.rs b/compiler/rustc_target/src/spec/targets/xtensa_esp32s3_espidf.rs index 2e4afc00541..4ec6e319fd4 100644 --- a/compiler/rustc_target/src/spec/targets/xtensa_esp32s3_espidf.rs +++ b/compiler/rustc_target/src/spec/targets/xtensa_esp32s3_espidf.rs @@ -13,7 +13,7 @@ pub(crate) fn target() -> Target { options: TargetOptions { endian: Endian::Little, - c_int_width: "32".into(), + c_int_width: 32, families: cvs!["unix"], os: "espidf".into(), env: "newlib".into(), diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index d48a599f544..a1eac1fba25 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -34,6 +34,9 @@ pub enum Stability { /// particular for features are actually ABI configuration flags (not all targets are as nice as /// RISC-V and have an explicit way to set the ABI separate from target features). Forbidden { reason: &'static str }, + /// This feature can not be set via `-Ctarget-feature` or `#[target_feature]`, it can only be set + /// by target modifier flag. Target modifier flags are tracked to be consistent in linked modules. + TargetModifierOnly { reason: &'static str, flag: &'static str }, } use Stability::*; @@ -49,6 +52,7 @@ impl<CTX> HashStable<CTX> for Stability { Stability::Forbidden { reason } => { reason.hash_stable(hcx, hasher); } + Stability::TargetModifierOnly { .. } => {} } } } @@ -74,16 +78,7 @@ impl Stability { Stability::Unstable(nightly_feature) => Some(nightly_feature), Stability::Stable { .. } => None, Stability::Forbidden { .. } => panic!("forbidden features should not reach this far"), - } - } - - /// Returns whether the feature may be toggled via `#[target_feature]` or `-Ctarget-feature`. - /// (It might still be nightly-only even if this returns `true`, so make sure to also check - /// `requires_nightly`.) - pub fn toggle_allowed(&self) -> Result<(), &'static str> { - match self { - Stability::Forbidden { reason } => Err(reason), - _ => Ok(()), + Stability::TargetModifierOnly { .. } => None, } } } @@ -443,7 +438,7 @@ static X86_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("fma", Stable, &["avx"]), ("fxsr", Stable, &[]), ("gfni", Stable, &["sse2"]), - ("kl", Unstable(sym::keylocker_x86), &["sse2"]), + ("kl", Stable, &["sse2"]), ("lahfsahf", Unstable(sym::lahfsahf_target_feature), &[]), ("lzcnt", Stable, &[]), ("movbe", Stable, &[]), @@ -453,6 +448,30 @@ static X86_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("prfchw", Unstable(sym::prfchw_target_feature), &[]), ("rdrand", Stable, &[]), ("rdseed", Stable, &[]), + ( + "retpoline-external-thunk", + Stability::TargetModifierOnly { + reason: "use `retpoline-external-thunk` target modifier flag instead", + flag: "retpoline-external-thunk", + }, + &[], + ), + ( + "retpoline-indirect-branches", + Stability::TargetModifierOnly { + reason: "use `retpoline` target modifier flag instead", + flag: "retpoline", + }, + &[], + ), + ( + "retpoline-indirect-calls", + Stability::TargetModifierOnly { + reason: "use `retpoline` target modifier flag instead", + flag: "retpoline", + }, + &[], + ), ("rtm", Unstable(sym::rtm_target_feature), &[]), ("sha", Stable, &["sse2"]), ("sha512", Stable, &["avx2"]), @@ -471,7 +490,7 @@ static X86_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("tbm", Unstable(sym::tbm_target_feature), &[]), ("vaes", Stable, &["avx2", "aes"]), ("vpclmulqdq", Stable, &["avx", "pclmulqdq"]), - ("widekl", Unstable(sym::keylocker_x86), &["kl"]), + ("widekl", Stable, &["kl"]), ("x87", Unstable(sym::x87_target_feature), &[]), ("xop", Unstable(sym::xop_target_feature), &[/*"fma4", */ "avx", "sse4a"]), ("xsave", Stable, &[]), 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 fc5be111144..0c88bd3dcbc 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 @@ -2558,32 +2558,31 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { rustc_transmute::Reason::SrcIsNotYetSupported => { format!("analyzing the transmutability of `{src}` is not yet supported") } - rustc_transmute::Reason::DstIsNotYetSupported => { format!("analyzing the transmutability of `{dst}` is not yet supported") } - rustc_transmute::Reason::DstIsBitIncompatible => { format!( "at least one value of `{src}` isn't a bit-valid value of `{dst}`" ) } - rustc_transmute::Reason::DstUninhabited => { format!("`{dst}` is uninhabited") } - rustc_transmute::Reason::DstMayHaveSafetyInvariants => { format!("`{dst}` may carry safety invariants") } rustc_transmute::Reason::DstIsTooBig => { format!("the size of `{src}` is smaller than the size of `{dst}`") } - rustc_transmute::Reason::DstRefIsTooBig { src, dst } => { - let src_size = src.size; - let dst_size = dst.size; + rustc_transmute::Reason::DstRefIsTooBig { + src, + src_size, + dst, + dst_size, + } => { format!( - "the referent size of `{src}` ({src_size} bytes) \ + "the size of `{src}` ({src_size} bytes) \ is smaller than that of `{dst}` ({dst_size} bytes)" ) } 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 37968386e9a..89dab90dc68 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 @@ -810,7 +810,8 @@ impl<'tcx> OnUnimplementedFormatString { let mut result = Ok(()); - match FormatString::parse(self.symbol, self.span, &ctx) { + let snippet = tcx.sess.source_map().span_to_snippet(self.span).ok(); + match FormatString::parse(self.symbol, snippet, self.span, &ctx) { // Warnings about format specifiers, deprecated parameters, wrong parameters etc. // In other words we'd like to let the author know, but we can still try to format the string later Ok(FormatString { warnings, .. }) => { @@ -848,34 +849,27 @@ impl<'tcx> OnUnimplementedFormatString { } } } - // Errors from the underlying `rustc_parse_format::Parser` - Err(errors) => { + // Error from the underlying `rustc_parse_format::Parser` + Err(e) => { // we cannot return errors from processing the format string as hard error here // as the diagnostic namespace guarantees that malformed input cannot cause an error // // if we encounter any error while processing we nevertheless want to show it as warning // so that users are aware that something is not correct - for e in errors { - if self.is_diagnostic_namespace_variant { - if let Some(trait_def_id) = trait_def_id.as_local() { - tcx.emit_node_span_lint( - UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, - tcx.local_def_id_to_hir_id(trait_def_id), - self.span, - WrappedParserError { description: e.description, label: e.label }, - ); - } - } else { - let reported = struct_span_code_err!( - tcx.dcx(), + if self.is_diagnostic_namespace_variant { + if let Some(trait_def_id) = trait_def_id.as_local() { + tcx.emit_node_span_lint( + UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, + tcx.local_def_id_to_hir_id(trait_def_id), self.span, - E0231, - "{}", - e.description, - ) - .emit(); - result = Err(reported); + WrappedParserError { description: e.description, label: e.label }, + ); } + } else { + let reported = + struct_span_code_err!(tcx.dcx(), self.span, E0231, "{}", e.description,) + .emit(); + result = Err(reported); } } } @@ -896,7 +890,8 @@ impl<'tcx> OnUnimplementedFormatString { Ctx::RustcOnUnimplemented { tcx, trait_def_id } }; - if let Ok(s) = FormatString::parse(self.symbol, self.span, &ctx) { + // No point passing a snippet here, we already did that in `verify` + if let Ok(s) = FormatString::parse(self.symbol, None, self.span, &ctx) { s.format(args) } else { // we cannot return errors from processing the format string as hard error here 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 e8ea9f2d23e..171d05230d4 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 @@ -198,7 +198,7 @@ enum LitOrArg { impl FilterFormatString { fn parse(input: Symbol) -> Self { - let pieces = Parser::new(input.as_str(), None, None, false, ParseMode::Format) + let pieces = Parser::new(input.as_str(), None, None, false, ParseMode::Diagnostic) .map(|p| match p { Piece::Lit(s) => LitOrArg::Lit(s.to_owned()), // We just ignore formatspecs here 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 7c1dfc1728f..3e8b906fa93 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 @@ -5,12 +5,11 @@ use errors::*; use rustc_middle::ty::print::TraitRefPrintSugared; use rustc_middle::ty::{GenericParamDefKind, TyCtxt}; use rustc_parse_format::{ - Alignment, Argument, Count, FormatSpec, ParseError, ParseMode, Parser, Piece as RpfPiece, - Position, + Argument, FormatSpec, ParseError, ParseMode, Parser, Piece as RpfPiece, Position, }; use rustc_session::lint::builtin::UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES; use rustc_span::def_id::DefId; -use rustc_span::{BytePos, Pos, Span, Symbol, kw, sym}; +use rustc_span::{InnerSpan, Span, Symbol, kw, sym}; /// Like [std::fmt::Arguments] this is a string that has been parsed into "pieces", /// either as string pieces or dynamic arguments. @@ -160,32 +159,32 @@ impl FormatString { pub fn parse<'tcx>( input: Symbol, + snippet: Option<String>, span: Span, ctx: &Ctx<'tcx>, - ) -> Result<Self, Vec<ParseError>> { + ) -> Result<Self, ParseError> { let s = input.as_str(); - let mut parser = Parser::new(s, None, None, false, ParseMode::Format); - let mut pieces = Vec::new(); + let mut parser = Parser::new(s, None, snippet, false, ParseMode::Diagnostic); + let pieces: Vec<_> = parser.by_ref().collect(); + + if let Some(err) = parser.errors.into_iter().next() { + return Err(err); + } let mut warnings = Vec::new(); - for piece in &mut parser { - match piece { - RpfPiece::Lit(lit) => { - pieces.push(Piece::Lit(lit.into())); - } + let pieces = pieces + .into_iter() + .map(|piece| match piece { + RpfPiece::Lit(lit) => Piece::Lit(lit.into()), RpfPiece::NextArgument(arg) => { - warn_on_format_spec(arg.format.clone(), &mut warnings, span); - let arg = parse_arg(&arg, ctx, &mut warnings, span); - pieces.push(Piece::Arg(arg)); + warn_on_format_spec(&arg.format, &mut warnings, span, parser.is_source_literal); + let arg = parse_arg(&arg, ctx, &mut warnings, span, parser.is_source_literal); + Piece::Arg(arg) } - } - } + }) + .collect(); - if parser.errors.is_empty() { - Ok(FormatString { input, pieces, span, warnings }) - } else { - Err(parser.errors) - } + Ok(FormatString { input, pieces, span, warnings }) } pub fn format(&self, args: &FormatArgs<'_>) -> String { @@ -229,11 +228,12 @@ fn parse_arg<'tcx>( ctx: &Ctx<'tcx>, warnings: &mut Vec<FormatWarning>, input_span: Span, + is_source_literal: bool, ) -> FormatArg { let (Ctx::RustcOnUnimplemented { tcx, trait_def_id } | Ctx::DiagnosticOnUnimplemented { tcx, trait_def_id }) = ctx; - let span = slice_span(input_span, arg.position_span.clone()); + let span = slice_span(input_span, arg.position_span.clone(), is_source_literal); match arg.position { // Something like "hello {name}" @@ -283,39 +283,24 @@ fn parse_arg<'tcx>( /// `#[rustc_on_unimplemented]` and `#[diagnostic::...]` don't actually do anything /// with specifiers, so emit a warning if they are used. -fn warn_on_format_spec(spec: FormatSpec<'_>, warnings: &mut Vec<FormatWarning>, input_span: Span) { - if !matches!( - spec, - FormatSpec { - fill: None, - fill_span: None, - align: Alignment::AlignUnknown, - sign: None, - alternate: false, - zero_pad: false, - debug_hex: None, - precision: Count::CountImplied, - precision_span: None, - width: Count::CountImplied, - width_span: None, - ty: _, - ty_span: _, - }, - ) { - let span = spec.ty_span.map(|inner| slice_span(input_span, inner)).unwrap_or(input_span); +fn warn_on_format_spec( + spec: &FormatSpec<'_>, + warnings: &mut Vec<FormatWarning>, + input_span: Span, + is_source_literal: bool, +) { + if spec.ty != "" { + let span = spec + .ty_span + .as_ref() + .map(|inner| slice_span(input_span, inner.clone(), is_source_literal)) + .unwrap_or(input_span); warnings.push(FormatWarning::InvalidSpecifier { span, name: spec.ty.into() }) } } -fn slice_span(input: Span, range: Range<usize>) -> Span { - let span = input.data(); - - Span::new( - span.lo + BytePos::from_usize(range.start), - span.lo + BytePos::from_usize(range.end), - span.ctxt, - span.parent, - ) +fn slice_span(input: Span, Range { start, end }: Range<usize>, is_source_literal: bool) -> Span { + if is_source_literal { input.from_inner(InnerSpan { start, end }) } else { input } } pub mod errors { diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs index 06f81ac554e..7bf49056e29 100644 --- a/compiler/rustc_trait_selection/src/errors.rs +++ b/compiler/rustc_trait_selection/src/errors.rs @@ -759,7 +759,8 @@ pub enum ExplicitLifetimeRequired<'a> { #[suggestion( trait_selection_explicit_lifetime_required_sugg_with_ident, code = "{new_ty}", - applicability = "unspecified" + applicability = "unspecified", + style = "verbose" )] new_ty_span: Span, #[skip_arg] @@ -774,7 +775,8 @@ pub enum ExplicitLifetimeRequired<'a> { #[suggestion( trait_selection_explicit_lifetime_required_sugg_with_param_type, code = "{new_ty}", - applicability = "unspecified" + applicability = "unspecified", + style = "verbose" )] new_ty_span: Span, #[skip_arg] @@ -1462,7 +1464,8 @@ pub enum SuggestAccessingField<'a> { #[suggestion( trait_selection_suggest_accessing_field, code = "{snippet}.{name}", - applicability = "maybe-incorrect" + applicability = "maybe-incorrect", + style = "verbose" )] Safe { #[primary_span] @@ -1474,7 +1477,8 @@ pub enum SuggestAccessingField<'a> { #[suggestion( trait_selection_suggest_accessing_field, code = "unsafe {{ {snippet}.{name} }}", - applicability = "maybe-incorrect" + applicability = "maybe-incorrect", + style = "verbose" )] Unsafe { #[primary_span] diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs index d5d318ee490..b0c8fa1f217 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs @@ -11,7 +11,8 @@ use std::assert_matches::assert_matches; -use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk}; +use rustc_infer::infer::InferCtxt; +use rustc_infer::traits::Obligation; use rustc_macros::extension; use rustc_middle::traits::ObligationCause; use rustc_middle::traits::solve::{Certainty, Goal, GoalSource, NoSolution, QueryResult}; @@ -20,7 +21,7 @@ use rustc_middle::{bug, ty}; use rustc_next_trait_solver::resolve::eager_resolve_vars; use rustc_next_trait_solver::solve::inspect::{self, instantiate_canonical_state}; use rustc_next_trait_solver::solve::{GenerateProofTree, MaybeCause, SolverDelegateEvalExt as _}; -use rustc_span::{DUMMY_SP, Span}; +use rustc_span::Span; use tracing::instrument; use crate::solve::delegate::SolverDelegate; @@ -60,28 +61,29 @@ impl<'tcx> NormalizesToTermHack<'tcx> { /// Relate the `term` with the new `unconstrained_term` created /// when computing the proof tree for this `NormalizesTo` goals. /// This handles nested obligations. - fn constrain( - self, + fn constrain_and( + &self, infcx: &InferCtxt<'tcx>, span: Span, param_env: ty::ParamEnv<'tcx>, + f: impl FnOnce(&ObligationCtxt<'_, 'tcx>), ) -> Result<Certainty, NoSolution> { - infcx - .at(&ObligationCause::dummy_with_span(span), param_env) - .eq(DefineOpaqueTypes::Yes, self.term, self.unconstrained_term) - .map_err(|_| NoSolution) - .and_then(|InferOk { value: (), obligations }| { - let ocx = ObligationCtxt::new(infcx); - ocx.register_obligations(obligations); - let errors = ocx.select_all_or_error(); - if errors.is_empty() { - Ok(Certainty::Yes) - } else if errors.iter().all(|e| !e.is_true_error()) { - Ok(Certainty::AMBIGUOUS) - } else { - Err(NoSolution) - } - }) + let ocx = ObligationCtxt::new(infcx); + ocx.eq( + &ObligationCause::dummy_with_span(span), + param_env, + self.term, + self.unconstrained_term, + )?; + f(&ocx); + let errors = ocx.select_all_or_error(); + if errors.is_empty() { + Ok(Certainty::Yes) + } else if errors.iter().all(|e| !e.is_true_error()) { + Ok(Certainty::AMBIGUOUS) + } else { + Err(NoSolution) + } } } @@ -160,11 +162,11 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> { let () = instantiate_canonical_state(infcx, span, param_env, &mut orig_values, self.final_state); - if let Some(term_hack) = self.goal.normalizes_to_term_hack { + if let Some(term_hack) = &self.goal.normalizes_to_term_hack { // FIXME: We ignore the expected term of `NormalizesTo` goals // when computing the result of its candidates. This is // scuffed. - let _ = term_hack.constrain(infcx, span, param_env); + let _ = term_hack.constrain_and(infcx, span, param_env, |_| {}); } instantiated_goals @@ -240,13 +242,39 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> { // building their proof tree, the expected term was unconstrained, but when // instantiating the candidate it is already constrained to the result of another // candidate. - let proof_tree = infcx - .probe(|_| infcx.evaluate_root_goal_raw(goal, GenerateProofTree::Yes, None).1); + let normalizes_to_term_hack = NormalizesToTermHack { term, unconstrained_term }; + let (proof_tree, nested_goals_result) = infcx.probe(|_| { + // Here, if we have any nested goals, then we make sure to apply them + // considering the constrained RHS, and pass the resulting certainty to + // `InspectGoal::new` so that the goal has the right result (and maintains + // the impression that we don't do this normalizes-to infer hack at all). + let (nested, proof_tree) = + infcx.evaluate_root_goal_raw(goal, GenerateProofTree::Yes, None); + let proof_tree = proof_tree.unwrap(); + let nested_goals_result = nested.and_then(|(nested, _)| { + normalizes_to_term_hack.constrain_and( + infcx, + span, + proof_tree.uncanonicalized_goal.param_env, + |ocx| { + ocx.register_obligations(nested.0.into_iter().map(|(_, goal)| { + Obligation::new( + infcx.tcx, + ObligationCause::dummy_with_span(span), + goal.param_env, + goal.predicate, + ) + })); + }, + ) + }); + (proof_tree, nested_goals_result) + }); InspectGoal::new( infcx, self.goal.depth + 1, - proof_tree.unwrap(), - Some(NormalizesToTermHack { term, unconstrained_term }), + proof_tree, + Some((normalizes_to_term_hack, nested_goals_result)), source, ) } @@ -393,20 +421,21 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> { infcx: &'a InferCtxt<'tcx>, depth: usize, root: inspect::GoalEvaluation<TyCtxt<'tcx>>, - normalizes_to_term_hack: Option<NormalizesToTermHack<'tcx>>, + term_hack_and_nested_certainty: Option<( + NormalizesToTermHack<'tcx>, + Result<Certainty, NoSolution>, + )>, source: GoalSource, ) -> Self { let infcx = <&SolverDelegate<'tcx>>::from(infcx); let inspect::GoalEvaluation { uncanonicalized_goal, orig_values, evaluation } = root; + // If there's a normalizes-to goal, AND the evaluation result with the result of + // constraining the normalizes-to RHS and computing the nested goals. let result = evaluation.result.and_then(|ok| { - if let Some(term_hack) = normalizes_to_term_hack { - infcx - .probe(|_| term_hack.constrain(infcx, DUMMY_SP, uncanonicalized_goal.param_env)) - .map(|certainty| ok.value.certainty.and(certainty)) - } else { - Ok(ok.value.certainty) - } + let nested_goals_certainty = + term_hack_and_nested_certainty.map_or(Ok(Certainty::Yes), |(_, c)| c)?; + Ok(ok.value.certainty.and(nested_goals_certainty)) }); InspectGoal { @@ -416,7 +445,7 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> { goal: eager_resolve_vars(infcx, uncanonicalized_goal), result, evaluation_kind: evaluation.kind, - normalizes_to_term_hack, + normalizes_to_term_hack: term_hack_and_nested_certainty.map(|(n, _)| n), source, } } diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs index eb6d5c8a60a..35a43b294ee 100644 --- a/compiler/rustc_trait_selection/src/traits/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/normalize.rs @@ -47,7 +47,7 @@ impl<'tcx> At<'_, 'tcx> { /// same goals in both a temporary and the shared context which negatively impacts /// performance as these don't share caching. /// - /// FIXME(-Znext-solver): For performance reasons, we currently reuse an existing + /// FIXME(-Znext-solver=no): For performance reasons, we currently reuse an existing /// fulfillment context in the old solver. Once we have removed the old solver, we /// can remove the `fulfill_cx` parameter on this function. fn deeply_normalize<T, E>( diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 7acf0f990d1..786afd7cf48 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -9,13 +9,12 @@ use std::ops::ControlFlow; -use rustc_ast::Mutability; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir::lang_items::LangItem; use rustc_infer::infer::{DefineOpaqueTypes, HigherRankedType, InferOk}; use rustc_infer::traits::ObligationCauseCode; use rustc_middle::traits::{BuiltinImplSource, SignatureMismatchData}; -use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, Upcast, elaborate}; +use rustc_middle::ty::{self, GenericArgsRef, Region, Ty, TyCtxt, Upcast, elaborate}; use rustc_middle::{bug, span_bug}; use rustc_span::def_id::DefId; use thin_vec::thin_vec; @@ -286,99 +285,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ) -> Result<PredicateObligations<'tcx>, SelectionError<'tcx>> { use rustc_transmute::{Answer, Assume, Condition}; - /// Generate sub-obligations for reference-to-reference transmutations. - fn reference_obligations<'tcx>( - tcx: TyCtxt<'tcx>, - obligation: &PolyTraitObligation<'tcx>, - (src_lifetime, src_ty, src_mut): (ty::Region<'tcx>, Ty<'tcx>, Mutability), - (dst_lifetime, dst_ty, dst_mut): (ty::Region<'tcx>, Ty<'tcx>, Mutability), - assume: Assume, - ) -> PredicateObligations<'tcx> { - let make_transmute_obl = |src, dst| { - let transmute_trait = obligation.predicate.def_id(); - let assume = obligation.predicate.skip_binder().trait_ref.args.const_at(2); - let trait_ref = ty::TraitRef::new( - tcx, - transmute_trait, - [ - ty::GenericArg::from(dst), - ty::GenericArg::from(src), - ty::GenericArg::from(assume), - ], - ); - Obligation::with_depth( - tcx, - obligation.cause.clone(), - obligation.recursion_depth + 1, - obligation.param_env, - trait_ref, - ) - }; - - let make_freeze_obl = |ty| { - let trait_ref = ty::TraitRef::new( - tcx, - tcx.require_lang_item(LangItem::Freeze, obligation.cause.span), - [ty::GenericArg::from(ty)], - ); - Obligation::with_depth( - tcx, - obligation.cause.clone(), - obligation.recursion_depth + 1, - obligation.param_env, - trait_ref, - ) - }; - - let make_outlives_obl = |target, region| { - let outlives = ty::OutlivesPredicate(target, region); - Obligation::with_depth( - tcx, - obligation.cause.clone(), - obligation.recursion_depth + 1, - obligation.param_env, - outlives, - ) - }; - - // Given a transmutation from `&'a (mut) Src` and `&'dst (mut) Dst`, - // it is always the case that `Src` must be transmutable into `Dst`, - // and that that `'src` must outlive `'dst`. - let mut obls = PredicateObligations::with_capacity(1); - obls.push(make_transmute_obl(src_ty, dst_ty)); - if !assume.lifetimes { - obls.push(make_outlives_obl(src_lifetime, dst_lifetime)); - } - - // Given a transmutation from `&Src`, both `Src` and `Dst` must be - // `Freeze`, otherwise, using the transmuted value could lead to - // data races. - if src_mut == Mutability::Not { - obls.extend([make_freeze_obl(src_ty), make_freeze_obl(dst_ty)]) - } - - // Given a transmutation into `&'dst mut Dst`, it also must be the - // case that `Dst` is transmutable into `Src`. For example, - // transmuting bool -> u8 is OK as long as you can't update that u8 - // to be > 1, because you could later transmute the u8 back to a - // bool and get undefined behavior. It also must be the case that - // `'dst` lives exactly as long as `'src`. - if dst_mut == Mutability::Mut { - obls.push(make_transmute_obl(dst_ty, src_ty)); - if !assume.lifetimes { - obls.push(make_outlives_obl(dst_lifetime, src_lifetime)); - } - } - - obls - } - /// Flatten the `Condition` tree into a conjunction of obligations. #[instrument(level = "debug", skip(tcx, obligation))] fn flatten_answer_tree<'tcx>( tcx: TyCtxt<'tcx>, obligation: &PolyTraitObligation<'tcx>, - cond: Condition<rustc_transmute::layout::rustc::Ref<'tcx>>, + cond: Condition<Region<'tcx>, Ty<'tcx>>, assume: Assume, ) -> PredicateObligations<'tcx> { match cond { @@ -388,13 +300,50 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .into_iter() .flat_map(|cond| flatten_answer_tree(tcx, obligation, cond, assume)) .collect(), - Condition::IfTransmutable { src, dst } => reference_obligations( - tcx, - obligation, - (src.lifetime, src.ty, src.mutability), - (dst.lifetime, dst.ty, dst.mutability), - assume, - ), + Condition::Immutable { ty } => { + let trait_ref = ty::TraitRef::new( + tcx, + tcx.require_lang_item(LangItem::Freeze, obligation.cause.span), + [ty::GenericArg::from(ty)], + ); + thin_vec![Obligation::with_depth( + tcx, + obligation.cause.clone(), + obligation.recursion_depth + 1, + obligation.param_env, + trait_ref, + )] + } + Condition::Outlives { long, short } => { + let outlives = ty::OutlivesPredicate(long, short); + thin_vec![Obligation::with_depth( + tcx, + obligation.cause.clone(), + obligation.recursion_depth + 1, + obligation.param_env, + outlives, + )] + } + Condition::Transmutable { src, dst } => { + let transmute_trait = obligation.predicate.def_id(); + let assume = obligation.predicate.skip_binder().trait_ref.args.const_at(2); + let trait_ref = ty::TraitRef::new( + tcx, + transmute_trait, + [ + ty::GenericArg::from(dst), + ty::GenericArg::from(src), + ty::GenericArg::from(assume), + ], + ); + thin_vec![Obligation::with_depth( + tcx, + obligation.cause.clone(), + obligation.recursion_depth + 1, + obligation.param_env, + trait_ref, + )] + } } } diff --git a/compiler/rustc_traits/src/codegen.rs b/compiler/rustc_traits/src/codegen.rs index 88f02d16c7d..a0a1d454556 100644 --- a/compiler/rustc_traits/src/codegen.rs +++ b/compiler/rustc_traits/src/codegen.rs @@ -58,7 +58,6 @@ pub(crate) fn codegen_select_candidate<'tcx>( // Currently, we use a fulfillment context to completely resolve // all nested obligations. This is because they can inform the // inference of the impl's type parameters. - // FIXME(-Znext-solver): Doesn't need diagnostics if new solver. let ocx = ObligationCtxt::new(&infcx); let impl_source = selection.map(|obligation| { ocx.register_obligation(obligation); diff --git a/compiler/rustc_transmute/src/layout/dfa.rs b/compiler/rustc_transmute/src/layout/dfa.rs index 6d072c336af..6fc40ce42d8 100644 --- a/compiler/rustc_transmute/src/layout/dfa.rs +++ b/compiler/rustc_transmute/src/layout/dfa.rs @@ -2,32 +2,35 @@ use std::fmt; use std::iter::Peekable; use std::sync::atomic::{AtomicU32, Ordering}; -use super::{Byte, Ref, Tree, Uninhabited}; +use super::{Byte, Reference, Region, Tree, Type, Uninhabited}; use crate::{Map, Set}; #[derive(PartialEq)] #[cfg_attr(test, derive(Clone))] -pub(crate) struct Dfa<R> +pub(crate) struct Dfa<R, T> where - R: Ref, + R: Region, + T: Type, { - pub(crate) transitions: Map<State, Transitions<R>>, + pub(crate) transitions: Map<State, Transitions<R, T>>, pub(crate) start: State, pub(crate) accept: State, } #[derive(PartialEq, Clone, Debug)] -pub(crate) struct Transitions<R> +pub(crate) struct Transitions<R, T> where - R: Ref, + R: Region, + T: Type, { byte_transitions: EdgeSet<State>, - ref_transitions: Map<R, State>, + ref_transitions: Map<Reference<R, T>, State>, } -impl<R> Default for Transitions<R> +impl<R, T> Default for Transitions<R, T> where - R: Ref, + R: Region, + T: Type, { fn default() -> Self { Self { byte_transitions: EdgeSet::empty(), ref_transitions: Map::default() } @@ -51,9 +54,10 @@ impl fmt::Debug for State { } } -impl<R> Dfa<R> +impl<R, T> Dfa<R, T> where - R: Ref, + R: Region, + T: Type, { #[cfg(test)] pub(crate) fn bool() -> Self { @@ -64,7 +68,7 @@ where } pub(crate) fn unit() -> Self { - let transitions: Map<State, Transitions<R>> = Map::default(); + let transitions: Map<State, Transitions<R, T>> = Map::default(); let start = State::new(); let accept = start; @@ -78,21 +82,21 @@ where }) } - pub(crate) fn from_ref(r: R) -> Self { + pub(crate) fn from_ref(r: Reference<R, T>) -> Self { Self::from_transitions(|accept| Transitions { byte_transitions: EdgeSet::empty(), ref_transitions: [(r, accept)].into_iter().collect(), }) } - fn from_transitions(f: impl FnOnce(State) -> Transitions<R>) -> Self { + fn from_transitions(f: impl FnOnce(State) -> Transitions<R, T>) -> Self { let start = State::new(); let accept = State::new(); Self { transitions: [(start, f(accept))].into_iter().collect(), start, accept } } - pub(crate) fn from_tree(tree: Tree<!, R>) -> Result<Self, Uninhabited> { + pub(crate) fn from_tree(tree: Tree<!, R, T>) -> Result<Self, Uninhabited> { Ok(match tree { Tree::Byte(b) => Self::from_byte(b), Tree::Ref(r) => Self::from_ref(r), @@ -125,7 +129,7 @@ where let start = self.start; let accept = other.accept; - let mut transitions: Map<State, Transitions<R>> = self.transitions; + let mut transitions: Map<State, Transitions<R, T>> = self.transitions; for (source, transition) in other.transitions { let fix_state = |state| if state == other.start { self.accept } else { state }; @@ -169,7 +173,7 @@ where }; let start = mapped((Some(a.start), Some(b.start))); - let mut transitions: Map<State, Transitions<R>> = Map::default(); + let mut transitions: Map<State, Transitions<R, T>> = Map::default(); let empty_transitions = Transitions::default(); struct WorkQueue { @@ -257,7 +261,7 @@ where .flat_map(|transitions| transitions.byte_transitions.iter()) } - pub(crate) fn refs_from(&self, start: State) -> impl Iterator<Item = (R, State)> { + pub(crate) fn refs_from(&self, start: State) -> impl Iterator<Item = (Reference<R, T>, State)> { self.transitions .get(&start) .into_iter() @@ -297,9 +301,10 @@ where } /// Serialize the DFA using the Graphviz DOT format. -impl<R> fmt::Debug for Dfa<R> +impl<R, T> fmt::Debug for Dfa<R, T> where - R: Ref, + R: Region, + T: Type, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { writeln!(f, "digraph {{")?; diff --git a/compiler/rustc_transmute/src/layout/mod.rs b/compiler/rustc_transmute/src/layout/mod.rs index c08bf440734..acbce258f39 100644 --- a/compiler/rustc_transmute/src/layout/mod.rs +++ b/compiler/rustc_transmute/src/layout/mod.rs @@ -78,16 +78,41 @@ impl From<u8> for Byte { } } +/// A reference, i.e., `&'region T` or `&'region mut T`. +#[derive(Debug, Hash, Eq, PartialEq, Ord, PartialOrd, Clone, Copy)] +pub(crate) struct Reference<R, T> +where + R: Region, + T: Type, +{ + pub(crate) region: R, + pub(crate) is_mut: bool, + pub(crate) referent: T, + pub(crate) referent_size: usize, + pub(crate) referent_align: usize, +} + +impl<R, T> fmt::Display for Reference<R, T> +where + R: Region, + T: Type, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("&")?; + if self.is_mut { + f.write_str("mut ")?; + } + self.referent.fmt(f) + } +} + pub(crate) trait Def: Debug + Hash + Eq + PartialEq + Copy + Clone { fn has_safety_invariants(&self) -> bool; } -pub trait Ref: Debug + Hash + Eq + PartialEq + Copy + Clone { - fn min_align(&self) -> usize; - fn size(&self) -> usize; +pub(crate) trait Region: Debug + Hash + Eq + PartialEq + Copy + Clone {} - fn is_mutable(&self) -> bool; -} +pub(crate) trait Type: Debug + Hash + Eq + PartialEq + Copy + Clone {} impl Def for ! { fn has_safety_invariants(&self) -> bool { @@ -95,79 +120,21 @@ impl Def for ! { } } -impl Ref for ! { - fn min_align(&self) -> usize { - unreachable!() - } - fn size(&self) -> usize { - unreachable!() - } - fn is_mutable(&self) -> bool { - unreachable!() - } -} +impl Region for ! {} -#[cfg(test)] -impl<const N: usize> Ref for [(); N] { - fn min_align(&self) -> usize { - N - } +impl Type for ! {} - fn size(&self) -> usize { - N - } +#[cfg(test)] +impl Region for usize {} - fn is_mutable(&self) -> bool { - false - } -} +#[cfg(test)] +impl Type for () {} #[cfg(feature = "rustc")] pub mod rustc { - use std::fmt::{self, Write}; - use rustc_abi::Layout; - use rustc_middle::mir::Mutability; use rustc_middle::ty::layout::{HasTyCtxt, LayoutCx, LayoutError}; - use rustc_middle::ty::{self, Ty}; - - /// A reference in the layout. - #[derive(Debug, Hash, Eq, PartialEq, Clone, Copy)] - pub struct Ref<'tcx> { - pub lifetime: ty::Region<'tcx>, - pub ty: Ty<'tcx>, - pub mutability: Mutability, - pub align: usize, - pub size: usize, - } - - impl<'tcx> super::Ref for Ref<'tcx> { - fn min_align(&self) -> usize { - self.align - } - - fn size(&self) -> usize { - self.size - } - - fn is_mutable(&self) -> bool { - match self.mutability { - Mutability::Mut => true, - Mutability::Not => false, - } - } - } - impl<'tcx> Ref<'tcx> {} - - impl<'tcx> fmt::Display for Ref<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_char('&')?; - if self.mutability == Mutability::Mut { - f.write_str("mut ")?; - } - self.ty.fmt(f) - } - } + use rustc_middle::ty::{self, Region, Ty}; /// A visibility node in the layout. #[derive(Debug, Hash, Eq, PartialEq, Clone, Copy)] @@ -187,6 +154,10 @@ pub mod rustc { } } + impl<'tcx> super::Region for Region<'tcx> {} + + impl<'tcx> super::Type for Ty<'tcx> {} + pub(crate) fn layout_of<'tcx>( cx: LayoutCx<'tcx>, ty: Ty<'tcx>, diff --git a/compiler/rustc_transmute/src/layout/tree.rs b/compiler/rustc_transmute/src/layout/tree.rs index ff665695b5a..372b4f5353a 100644 --- a/compiler/rustc_transmute/src/layout/tree.rs +++ b/compiler/rustc_transmute/src/layout/tree.rs @@ -1,6 +1,6 @@ use std::ops::{ControlFlow, RangeInclusive}; -use super::{Byte, Def, Ref}; +use super::{Byte, Def, Reference, Region, Type}; #[cfg(test)] mod tests; @@ -15,10 +15,11 @@ mod tests; /// 2. A `Seq` is never directly nested beneath another `Seq`. /// 3. `Seq`s and `Alt`s with a single member do not exist. #[derive(Clone, Debug, Hash, PartialEq, Eq)] -pub(crate) enum Tree<D, R> +pub(crate) enum Tree<D, R, T> where D: Def, - R: Ref, + R: Region, + T: Type, { /// A sequence of successive layouts. Seq(Vec<Self>), @@ -27,7 +28,7 @@ where /// A definition node. Def(D), /// A reference node. - Ref(R), + Ref(Reference<R, T>), /// A byte node. Byte(Byte), } @@ -48,10 +49,11 @@ impl From<rustc_abi::Endian> for Endian { } } -impl<D, R> Tree<D, R> +impl<D, R, T> Tree<D, R, T> where D: Def, - R: Ref, + R: Region, + T: Type, { /// A `Tree` consisting only of a definition node. pub(crate) fn def(def: D) -> Self { @@ -138,7 +140,7 @@ where /// Remove all `Def` nodes, and all branches of the layout for which `f` /// produces `true`. - pub(crate) fn prune<F>(self, f: &F) -> Tree<!, R> + pub(crate) fn prune<F>(self, f: &F) -> Tree<!, R, T> where F: Fn(D) -> bool, { @@ -198,13 +200,13 @@ where /// Produces a `Tree` where each of the trees in `trees` are sequenced one /// after another. - pub(crate) fn seq<const N: usize>(trees: [Tree<D, R>; N]) -> Self { + pub(crate) fn seq<const N: usize>(trees: [Tree<D, R, T>; N]) -> Self { trees.into_iter().fold(Tree::unit(), Self::then) } /// Produces a `Tree` where each of the trees in `trees` are accepted as /// alternative layouts. - pub(crate) fn alt<const N: usize>(trees: [Tree<D, R>; N]) -> Self { + pub(crate) fn alt<const N: usize>(trees: [Tree<D, R, T>; N]) -> Self { trees.into_iter().fold(Tree::uninhabited(), Self::or) } @@ -251,11 +253,14 @@ pub(crate) mod rustc { FieldIdx, FieldsShape, Layout, Size, TagEncoding, TyAndLayout, VariantIdx, Variants, }; use rustc_middle::ty::layout::{HasTyCtxt, LayoutCx, LayoutError}; - use rustc_middle::ty::{self, AdtDef, AdtKind, List, ScalarInt, Ty, TyCtxt, TypeVisitableExt}; + use rustc_middle::ty::{ + self, AdtDef, AdtKind, List, Region, ScalarInt, Ty, TyCtxt, TypeVisitableExt, + }; use rustc_span::ErrorGuaranteed; use super::Tree; - use crate::layout::rustc::{Def, Ref, layout_of}; + use crate::layout::Reference; + use crate::layout::rustc::{Def, layout_of}; #[derive(Debug, Copy, Clone)] pub(crate) enum Err { @@ -281,7 +286,7 @@ pub(crate) mod rustc { } } - impl<'tcx> Tree<Def<'tcx>, Ref<'tcx>> { + impl<'tcx> Tree<Def<'tcx>, Region<'tcx>, Ty<'tcx>> { pub(crate) fn from_ty(ty: Ty<'tcx>, cx: LayoutCx<'tcx>) -> Result<Self, Err> { use rustc_abi::HasDataLayout; let layout = layout_of(cx, ty)?; @@ -353,16 +358,17 @@ pub(crate) mod rustc { } } - ty::Ref(lifetime, ty, mutability) => { + ty::Ref(region, ty, mutability) => { let layout = layout_of(cx, *ty)?; - let align = layout.align.abi.bytes_usize(); - let size = layout.size.bytes_usize(); - Ok(Tree::Ref(Ref { - lifetime: *lifetime, - ty: *ty, - mutability: *mutability, - align, - size, + let referent_align = layout.align.abi.bytes_usize(); + let referent_size = layout.size.bytes_usize(); + + Ok(Tree::Ref(Reference { + region: *region, + is_mut: mutability.is_mut(), + referent: *ty, + referent_align, + referent_size, })) } diff --git a/compiler/rustc_transmute/src/layout/tree/tests.rs b/compiler/rustc_transmute/src/layout/tree/tests.rs index 8c3dbbe37ab..bc47b19c681 100644 --- a/compiler/rustc_transmute/src/layout/tree/tests.rs +++ b/compiler/rustc_transmute/src/layout/tree/tests.rs @@ -20,13 +20,13 @@ mod prune { #[test] fn seq_1() { - let layout: Tree<Def, !> = Tree::def(Def::NoSafetyInvariants).then(Tree::byte(0x00)); + let layout: Tree<Def, !, !> = Tree::def(Def::NoSafetyInvariants).then(Tree::byte(0x00)); assert_eq!(layout.prune(&|d| matches!(d, Def::HasSafetyInvariants)), Tree::byte(0x00)); } #[test] fn seq_2() { - let layout: Tree<Def, !> = + let layout: Tree<Def, !, !> = Tree::byte(0x00).then(Tree::def(Def::NoSafetyInvariants)).then(Tree::byte(0x01)); assert_eq!( @@ -41,7 +41,7 @@ mod prune { #[test] fn invisible_def() { - let layout: Tree<Def, !> = Tree::def(Def::HasSafetyInvariants); + let layout: Tree<Def, !, !> = Tree::def(Def::HasSafetyInvariants); assert_eq!( layout.prune(&|d| matches!(d, Def::HasSafetyInvariants)), Tree::uninhabited() @@ -50,7 +50,7 @@ mod prune { #[test] fn invisible_def_in_seq_len_2() { - let layout: Tree<Def, !> = + let layout: Tree<Def, !, !> = Tree::def(Def::NoSafetyInvariants).then(Tree::def(Def::HasSafetyInvariants)); assert_eq!( layout.prune(&|d| matches!(d, Def::HasSafetyInvariants)), @@ -60,7 +60,7 @@ mod prune { #[test] fn invisible_def_in_seq_len_3() { - let layout: Tree<Def, !> = Tree::def(Def::NoSafetyInvariants) + let layout: Tree<Def, !, !> = Tree::def(Def::NoSafetyInvariants) .then(Tree::byte(0x00)) .then(Tree::def(Def::HasSafetyInvariants)); assert_eq!( @@ -75,20 +75,20 @@ mod prune { #[test] fn visible_def() { - let layout: Tree<Def, !> = Tree::def(Def::NoSafetyInvariants); + let layout: Tree<Def, !, !> = Tree::def(Def::NoSafetyInvariants); assert_eq!(layout.prune(&|d| matches!(d, Def::HasSafetyInvariants)), Tree::unit()); } #[test] fn visible_def_in_seq_len_2() { - let layout: Tree<Def, !> = + let layout: Tree<Def, !, !> = Tree::def(Def::NoSafetyInvariants).then(Tree::def(Def::NoSafetyInvariants)); assert_eq!(layout.prune(&|d| matches!(d, Def::HasSafetyInvariants)), Tree::unit()); } #[test] fn visible_def_in_seq_len_3() { - let layout: Tree<Def, !> = Tree::def(Def::NoSafetyInvariants) + let layout: Tree<Def, !, !> = Tree::def(Def::NoSafetyInvariants) .then(Tree::byte(0x00)) .then(Tree::def(Def::NoSafetyInvariants)); assert_eq!(layout.prune(&|d| matches!(d, Def::HasSafetyInvariants)), Tree::byte(0x00)); diff --git a/compiler/rustc_transmute/src/lib.rs b/compiler/rustc_transmute/src/lib.rs index ce18dad5517..36281ff16bc 100644 --- a/compiler/rustc_transmute/src/lib.rs +++ b/compiler/rustc_transmute/src/lib.rs @@ -19,23 +19,29 @@ pub struct Assume { /// Either transmutation is allowed, we have an error, or we have an optional /// Condition that must hold. #[derive(Debug, Hash, Eq, PartialEq, Clone)] -pub enum Answer<R> { +pub enum Answer<R, T> { Yes, - No(Reason<R>), - If(Condition<R>), + No(Reason<T>), + If(Condition<R, T>), } /// A condition which must hold for safe transmutation to be possible. #[derive(Debug, Hash, Eq, PartialEq, Clone)] -pub enum Condition<R> { +pub enum Condition<R, T> { /// `Src` is transmutable into `Dst`, if `src` is transmutable into `dst`. - IfTransmutable { src: R, dst: R }, + Transmutable { src: T, dst: T }, + + /// The region `long` must outlive `short`. + Outlives { long: R, short: R }, + + /// The `ty` is immutable. + Immutable { ty: T }, /// `Src` is transmutable into `Dst`, if all of the enclosed requirements are met. - IfAll(Vec<Condition<R>>), + IfAll(Vec<Condition<R, T>>), /// `Src` is transmutable into `Dst` if any of the enclosed requirements are met. - IfAny(Vec<Condition<R>>), + IfAny(Vec<Condition<R, T>>), } /// Answers "why wasn't the source type transmutable into the destination type?" @@ -53,12 +59,16 @@ pub enum Reason<T> { DstMayHaveSafetyInvariants, /// `Dst` is larger than `Src`, and the excess bytes were not exclusively uninitialized. DstIsTooBig, - /// A referent of `Dst` is larger than a referent in `Src`. + /// `Dst` is larger `Src`. DstRefIsTooBig { /// The referent of the source type. src: T, + /// The size of the source type's referent. + src_size: usize, /// The too-large referent of the destination type. dst: T, + /// The size of the destination type's referent. + dst_size: usize, }, /// Src should have a stricter alignment than Dst, but it does not. DstHasStricterAlignment { src_min_align: usize, dst_min_align: usize }, @@ -79,7 +89,7 @@ pub enum Reason<T> { #[cfg(feature = "rustc")] mod rustc { use rustc_hir::lang_items::LangItem; - use rustc_middle::ty::{Const, Ty, TyCtxt}; + use rustc_middle::ty::{Const, Region, Ty, TyCtxt}; use super::*; @@ -105,7 +115,7 @@ mod rustc { &mut self, types: Types<'tcx>, assume: crate::Assume, - ) -> crate::Answer<crate::layout::rustc::Ref<'tcx>> { + ) -> crate::Answer<Region<'tcx>, Ty<'tcx>> { crate::maybe_transmutable::MaybeTransmutableQuery::new( types.src, types.dst, assume, self.tcx, ) diff --git a/compiler/rustc_transmute/src/maybe_transmutable/mod.rs b/compiler/rustc_transmute/src/maybe_transmutable/mod.rs index f76abe50ed3..062de4b5d08 100644 --- a/compiler/rustc_transmute/src/maybe_transmutable/mod.rs +++ b/compiler/rustc_transmute/src/maybe_transmutable/mod.rs @@ -5,7 +5,7 @@ pub(crate) mod query_context; #[cfg(test)] mod tests; -use crate::layout::{self, Def, Dfa, Ref, Tree, dfa, union}; +use crate::layout::{self, Def, Dfa, Reference, Tree, dfa, union}; use crate::maybe_transmutable::query_context::QueryContext; use crate::{Answer, Condition, Map, Reason}; @@ -41,7 +41,10 @@ mod rustc { /// This method begins by converting `src` and `dst` from `Ty`s to `Tree`s, /// then computes an answer using those trees. #[instrument(level = "debug", skip(self), fields(src = ?self.src, dst = ?self.dst))] - pub(crate) fn answer(self) -> Answer<<TyCtxt<'tcx> as QueryContext>::Ref> { + pub(crate) fn answer( + self, + ) -> Answer<<TyCtxt<'tcx> as QueryContext>::Region, <TyCtxt<'tcx> as QueryContext>::Type> + { let Self { src, dst, assume, context } = self; let layout_cx = LayoutCx::new(context, TypingEnv::fully_monomorphized()); @@ -67,7 +70,11 @@ mod rustc { } } -impl<C> MaybeTransmutableQuery<Tree<<C as QueryContext>::Def, <C as QueryContext>::Ref>, C> +impl<C> + MaybeTransmutableQuery< + Tree<<C as QueryContext>::Def, <C as QueryContext>::Region, <C as QueryContext>::Type>, + C, + > where C: QueryContext, { @@ -77,7 +84,7 @@ where /// then converts `src` and `dst` to `Dfa`s, and computes an answer using those DFAs. #[inline(always)] #[instrument(level = "debug", skip(self), fields(src = ?self.src, dst = ?self.dst))] - pub(crate) fn answer(self) -> Answer<<C as QueryContext>::Ref> { + pub(crate) fn answer(self) -> Answer<<C as QueryContext>::Region, <C as QueryContext>::Type> { let Self { src, dst, assume, context } = self; // Unconditionally remove all `Def` nodes from `src`, without pruning away the @@ -130,12 +137,12 @@ where } } -impl<C> MaybeTransmutableQuery<Dfa<<C as QueryContext>::Ref>, C> +impl<C> MaybeTransmutableQuery<Dfa<<C as QueryContext>::Region, <C as QueryContext>::Type>, C> where C: QueryContext, { /// Answers whether a `Dfa` is transmutable into another `Dfa`. - pub(crate) fn answer(self) -> Answer<<C as QueryContext>::Ref> { + pub(crate) fn answer(self) -> Answer<<C as QueryContext>::Region, <C as QueryContext>::Type> { self.answer_memo(&mut Map::default(), self.src.start, self.dst.start) } @@ -143,10 +150,13 @@ where #[instrument(level = "debug", skip(self))] fn answer_memo( &self, - cache: &mut Map<(dfa::State, dfa::State), Answer<<C as QueryContext>::Ref>>, + cache: &mut Map< + (dfa::State, dfa::State), + Answer<<C as QueryContext>::Region, <C as QueryContext>::Type>, + >, src_state: dfa::State, dst_state: dfa::State, - ) -> Answer<<C as QueryContext>::Ref> { + ) -> Answer<<C as QueryContext>::Region, <C as QueryContext>::Type> { if let Some(answer) = cache.get(&(src_state, dst_state)) { answer.clone() } else { @@ -160,10 +170,13 @@ where fn answer_impl( &self, - cache: &mut Map<(dfa::State, dfa::State), Answer<<C as QueryContext>::Ref>>, + cache: &mut Map< + (dfa::State, dfa::State), + Answer<<C as QueryContext>::Region, <C as QueryContext>::Type>, + >, src_state: dfa::State, dst_state: dfa::State, - ) -> Answer<<C as QueryContext>::Ref> { + ) -> Answer<<C as QueryContext>::Region, <C as QueryContext>::Type> { debug!(?src_state, ?dst_state); debug!(src = ?self.src); debug!(dst = ?self.dst); @@ -247,27 +260,51 @@ where // ...there exists a reference transition out of `dst_state`... Quantifier::ThereExists.apply(self.dst.refs_from(dst_state).map( |(dst_ref, dst_state_prime)| { - if !src_ref.is_mutable() && dst_ref.is_mutable() { + if !src_ref.is_mut && dst_ref.is_mut { Answer::No(Reason::DstIsMoreUnique) } else if !self.assume.alignment - && src_ref.min_align() < dst_ref.min_align() + && src_ref.referent_align < dst_ref.referent_align { Answer::No(Reason::DstHasStricterAlignment { - src_min_align: src_ref.min_align(), - dst_min_align: dst_ref.min_align(), + src_min_align: src_ref.referent_align, + dst_min_align: dst_ref.referent_align, + }) + } else if dst_ref.referent_size > src_ref.referent_size { + Answer::No(Reason::DstRefIsTooBig { + src: src_ref.referent, + src_size: src_ref.referent_size, + dst: dst_ref.referent, + dst_size: dst_ref.referent_size, }) - } else if dst_ref.size() > src_ref.size() { - Answer::No(Reason::DstRefIsTooBig { src: src_ref, dst: dst_ref }) } else { - // ...such that `src` is transmutable into `dst`, if - // `src_ref` is transmutability into `dst_ref`. - and( - Answer::If(Condition::IfTransmutable { - src: src_ref, - dst: dst_ref, - }), - self.answer_memo(cache, src_state_prime, dst_state_prime), - ) + let mut conditions = Vec::with_capacity(4); + let mut is_transmutable = + |src: Reference<_, _>, dst: Reference<_, _>| { + conditions.push(Condition::Transmutable { + src: src.referent, + dst: dst.referent, + }); + if !self.assume.lifetimes { + conditions.push(Condition::Outlives { + long: src.region, + short: dst.region, + }); + } + }; + + is_transmutable(src_ref, dst_ref); + + if dst_ref.is_mut { + is_transmutable(dst_ref, src_ref); + } else { + conditions.push(Condition::Immutable { ty: dst_ref.referent }); + } + + Answer::If(Condition::IfAll(conditions)).and(self.answer_memo( + cache, + src_state_prime, + dst_state_prime, + )) } }, )) @@ -275,67 +312,65 @@ where ); if self.assume.validity { - or(bytes_answer, refs_answer) + bytes_answer.or(refs_answer) } else { - and(bytes_answer, refs_answer) + bytes_answer.and(refs_answer) } } } } -fn and<R>(lhs: Answer<R>, rhs: Answer<R>) -> Answer<R> -where - R: PartialEq, -{ - match (lhs, rhs) { - // If both are errors, then we should return the more specific one - (Answer::No(Reason::DstIsBitIncompatible), Answer::No(reason)) - | (Answer::No(reason), Answer::No(_)) - // If either is an error, return it - | (Answer::No(reason), _) | (_, Answer::No(reason)) => Answer::No(reason), - // If only one side has a condition, pass it along - | (Answer::Yes, other) | (other, Answer::Yes) => other, - // If both sides have IfAll conditions, merge them - (Answer::If(Condition::IfAll(mut lhs)), Answer::If(Condition::IfAll(ref mut rhs))) => { - lhs.append(rhs); - Answer::If(Condition::IfAll(lhs)) - } - // If only one side is an IfAll, add the other Condition to it - (Answer::If(cond), Answer::If(Condition::IfAll(mut conds))) - | (Answer::If(Condition::IfAll(mut conds)), Answer::If(cond)) => { - conds.push(cond); - Answer::If(Condition::IfAll(conds)) +impl<R, T> Answer<R, T> { + fn and(self, rhs: Answer<R, T>) -> Answer<R, T> { + let lhs = self; + match (lhs, rhs) { + // If both are errors, then we should return the more specific one + (Answer::No(Reason::DstIsBitIncompatible), Answer::No(reason)) + | (Answer::No(reason), Answer::No(_)) + // If either is an error, return it + | (Answer::No(reason), _) | (_, Answer::No(reason)) => Answer::No(reason), + // If only one side has a condition, pass it along + | (Answer::Yes, other) | (other, Answer::Yes) => other, + // If both sides have IfAll conditions, merge them + (Answer::If(Condition::IfAll(mut lhs)), Answer::If(Condition::IfAll(ref mut rhs))) => { + lhs.append(rhs); + Answer::If(Condition::IfAll(lhs)) + } + // If only one side is an IfAll, add the other Condition to it + (Answer::If(cond), Answer::If(Condition::IfAll(mut conds))) + | (Answer::If(Condition::IfAll(mut conds)), Answer::If(cond)) => { + conds.push(cond); + Answer::If(Condition::IfAll(conds)) + } + // Otherwise, both lhs and rhs conditions can be combined in a parent IfAll + (Answer::If(lhs), Answer::If(rhs)) => Answer::If(Condition::IfAll(vec![lhs, rhs])), } - // Otherwise, both lhs and rhs conditions can be combined in a parent IfAll - (Answer::If(lhs), Answer::If(rhs)) => Answer::If(Condition::IfAll(vec![lhs, rhs])), } -} -fn or<R>(lhs: Answer<R>, rhs: Answer<R>) -> Answer<R> -where - R: PartialEq, -{ - match (lhs, rhs) { - // If both are errors, then we should return the more specific one - (Answer::No(Reason::DstIsBitIncompatible), Answer::No(reason)) - | (Answer::No(reason), Answer::No(_)) => Answer::No(reason), - // Otherwise, errors can be ignored for the rest of the pattern matching - (Answer::No(_), other) | (other, Answer::No(_)) => or(other, Answer::Yes), - // If only one side has a condition, pass it along - (Answer::Yes, other) | (other, Answer::Yes) => other, - // If both sides have IfAny conditions, merge them - (Answer::If(Condition::IfAny(mut lhs)), Answer::If(Condition::IfAny(ref mut rhs))) => { - lhs.append(rhs); - Answer::If(Condition::IfAny(lhs)) - } - // If only one side is an IfAny, add the other Condition to it - (Answer::If(cond), Answer::If(Condition::IfAny(mut conds))) - | (Answer::If(Condition::IfAny(mut conds)), Answer::If(cond)) => { - conds.push(cond); - Answer::If(Condition::IfAny(conds)) + fn or(self, rhs: Answer<R, T>) -> Answer<R, T> { + let lhs = self; + match (lhs, rhs) { + // If both are errors, then we should return the more specific one + (Answer::No(Reason::DstIsBitIncompatible), Answer::No(reason)) + | (Answer::No(reason), Answer::No(_)) => Answer::No(reason), + // Otherwise, errors can be ignored for the rest of the pattern matching + (Answer::No(_), other) | (other, Answer::No(_)) => other.or(Answer::Yes), + // If only one side has a condition, pass it along + (Answer::Yes, other) | (other, Answer::Yes) => other, + // If both sides have IfAny conditions, merge them + (Answer::If(Condition::IfAny(mut lhs)), Answer::If(Condition::IfAny(ref mut rhs))) => { + lhs.append(rhs); + Answer::If(Condition::IfAny(lhs)) + } + // If only one side is an IfAny, add the other Condition to it + (Answer::If(cond), Answer::If(Condition::IfAny(mut conds))) + | (Answer::If(Condition::IfAny(mut conds)), Answer::If(cond)) => { + conds.push(cond); + Answer::If(Condition::IfAny(conds)) + } + // Otherwise, both lhs and rhs conditions can be combined in a parent IfAny + (Answer::If(lhs), Answer::If(rhs)) => Answer::If(Condition::IfAny(vec![lhs, rhs])), } - // Otherwise, both lhs and rhs conditions can be combined in a parent IfAny - (Answer::If(lhs), Answer::If(rhs)) => Answer::If(Condition::IfAny(vec![lhs, rhs])), } } @@ -345,24 +380,25 @@ enum Quantifier { } impl Quantifier { - fn apply<R, I>(&self, iter: I) -> Answer<R> + fn apply<R, T, I>(&self, iter: I) -> Answer<R, T> where - R: layout::Ref, - I: IntoIterator<Item = Answer<R>>, + R: layout::Region, + T: layout::Type, + I: IntoIterator<Item = Answer<R, T>>, { use std::ops::ControlFlow::{Break, Continue}; let (init, try_fold_f): (_, fn(_, _) -> _) = match self { Self::ThereExists => { - (Answer::No(Reason::DstIsBitIncompatible), |accum: Answer<R>, next| { - match or(accum, next) { - Answer::Yes => Break(Answer::Yes), - maybe => Continue(maybe), - } + (Answer::No(Reason::DstIsBitIncompatible), |accum: Answer<R, T>, next| match accum + .or(next) + { + Answer::Yes => Break(Answer::Yes), + maybe => Continue(maybe), }) } - Self::ForAll => (Answer::Yes, |accum: Answer<R>, next| { - let answer = and(accum, next); + Self::ForAll => (Answer::Yes, |accum: Answer<R, T>, next| { + let answer = accum.and(next); match answer { Answer::No(_) => Break(answer), maybe => Continue(maybe), diff --git a/compiler/rustc_transmute/src/maybe_transmutable/query_context.rs b/compiler/rustc_transmute/src/maybe_transmutable/query_context.rs index 214da101be3..6be0cb11904 100644 --- a/compiler/rustc_transmute/src/maybe_transmutable/query_context.rs +++ b/compiler/rustc_transmute/src/maybe_transmutable/query_context.rs @@ -3,7 +3,8 @@ use crate::layout; /// Context necessary to answer the question "Are these types transmutable?". pub(crate) trait QueryContext { type Def: layout::Def; - type Ref: layout::Ref; + type Region: layout::Region; + type Type: layout::Type; } #[cfg(test)] @@ -12,9 +13,9 @@ pub(crate) mod test { use super::QueryContext; - pub(crate) struct UltraMinimal<R = !>(PhantomData<R>); + pub(crate) struct UltraMinimal<R = !, T = !>(PhantomData<(R, T)>); - impl<R> Default for UltraMinimal<R> { + impl<R, T> Default for UltraMinimal<R, T> { fn default() -> Self { Self(PhantomData) } @@ -32,20 +33,26 @@ pub(crate) mod test { } } - impl<R: crate::layout::Ref> QueryContext for UltraMinimal<R> { + impl<R, T> QueryContext for UltraMinimal<R, T> + where + R: crate::layout::Region, + T: crate::layout::Type, + { type Def = Def; - type Ref = R; + type Region = R; + type Type = T; } } #[cfg(feature = "rustc")] mod rustc { - use rustc_middle::ty::TyCtxt; + use rustc_middle::ty::{Region, Ty, TyCtxt}; use super::*; impl<'tcx> super::QueryContext for TyCtxt<'tcx> { type Def = layout::rustc::Def<'tcx>; - type Ref = layout::rustc::Ref<'tcx>; + type Region = Region<'tcx>; + type Type = Ty<'tcx>; } } diff --git a/compiler/rustc_transmute/src/maybe_transmutable/tests.rs b/compiler/rustc_transmute/src/maybe_transmutable/tests.rs index 0227ad71ae6..8440ace2608 100644 --- a/compiler/rustc_transmute/src/maybe_transmutable/tests.rs +++ b/compiler/rustc_transmute/src/maybe_transmutable/tests.rs @@ -3,17 +3,17 @@ extern crate test; use itertools::Itertools; use super::query_context::test::{Def, UltraMinimal}; -use crate::{Answer, Assume, Reason, layout}; +use crate::{Answer, Assume, Condition, Reason, layout}; -type Tree = layout::Tree<Def, !>; -type Dfa = layout::Dfa<!>; +type Tree = layout::Tree<Def, !, !>; +type Dfa = layout::Dfa<!, !>; trait Representation { - fn is_transmutable(src: Self, dst: Self, assume: Assume) -> Answer<!>; + fn is_transmutable(src: Self, dst: Self, assume: Assume) -> Answer<!, !>; } impl Representation for Tree { - fn is_transmutable(src: Self, dst: Self, assume: Assume) -> Answer<!> { + fn is_transmutable(src: Self, dst: Self, assume: Assume) -> Answer<!, !> { crate::maybe_transmutable::MaybeTransmutableQuery::new( src, dst, @@ -25,7 +25,7 @@ impl Representation for Tree { } impl Representation for Dfa { - fn is_transmutable(src: Self, dst: Self, assume: Assume) -> Answer<!> { + fn is_transmutable(src: Self, dst: Self, assume: Assume) -> Answer<!, !> { crate::maybe_transmutable::MaybeTransmutableQuery::new( src, dst, @@ -40,7 +40,7 @@ fn is_transmutable<R: Representation + Clone>( src: &R, dst: &R, assume: Assume, -) -> crate::Answer<!> { +) -> crate::Answer<!, !> { let src = src.clone(); let dst = dst.clone(); // The only dimension of the transmutability analysis we want to test @@ -53,7 +53,7 @@ mod safety { use super::*; use crate::Answer; - const DST_HAS_SAFETY_INVARIANTS: Answer<!> = + const DST_HAS_SAFETY_INVARIANTS: Answer<!, !> = Answer::No(crate::Reason::DstMayHaveSafetyInvariants); #[test] @@ -177,14 +177,15 @@ mod bool { #[test] fn should_permit_validity_expansion_and_reject_contraction() { - let b0 = layout::Tree::<Def, !>::byte(0); - let b1 = layout::Tree::<Def, !>::byte(1); - let b2 = layout::Tree::<Def, !>::byte(2); + let b0 = layout::Tree::<Def, !, !>::byte(0); + let b1 = layout::Tree::<Def, !, !>::byte(1); + let b2 = layout::Tree::<Def, !, !>::byte(2); let alts = [b0, b1, b2]; let into_layout = |alts: Vec<_>| { - alts.into_iter().fold(layout::Tree::<Def, !>::uninhabited(), layout::Tree::<Def, !>::or) + alts.into_iter() + .fold(layout::Tree::<Def, !, !>::uninhabited(), layout::Tree::<Def, !, !>::or) }; let into_set = |alts: Vec<_>| { @@ -277,7 +278,7 @@ mod alt { #[test] fn should_permit_identity_transmutation() { - type Tree = layout::Tree<Def, !>; + type Tree = layout::Tree<Def, !, !>; let x = Tree::Seq(vec![Tree::byte(0), Tree::byte(0)]); let y = Tree::Seq(vec![Tree::bool(), Tree::byte(1)]); @@ -331,7 +332,7 @@ mod char { fn should_permit_valid_transmutation() { for order in [Endian::Big, Endian::Little] { use Answer::*; - let char_layout = layout::Tree::<Def, !>::char(order); + let char_layout = layout::Tree::<Def, !, !>::char(order); // `char`s can be in the following ranges: // - [0, 0xD7FF] @@ -353,7 +354,7 @@ mod char { (0xFFFFFFFF, no), ] { let src_layout = - layout::tree::Tree::<Def, !>::from_big_endian(order, src.to_be_bytes()); + layout::tree::Tree::<Def, !, !>::from_big_endian(order, src.to_be_bytes()); let a = is_transmutable(&src_layout, &char_layout, Assume::default()); assert_eq!(a, answer, "endian:{order:?},\nsrc:{src:x}"); @@ -371,7 +372,7 @@ mod nonzero { #[test] fn should_permit_identity_transmutation() { for width in NONZERO_BYTE_WIDTHS { - let layout = layout::Tree::<Def, !>::nonzero(width); + let layout = layout::Tree::<Def, !, !>::nonzero(width); assert_eq!(is_transmutable(&layout, &layout, Assume::default()), Answer::Yes); } } @@ -381,8 +382,8 @@ mod nonzero { for width in NONZERO_BYTE_WIDTHS { use Answer::*; - let num = layout::Tree::<Def, !>::number(width); - let nz = layout::Tree::<Def, !>::nonzero(width); + let num = layout::Tree::<Def, !, !>::number(width); + let nz = layout::Tree::<Def, !, !>::nonzero(width); let a = is_transmutable(&num, &nz, Assume::default()); assert_eq!(a, No(Reason::DstIsBitIncompatible), "width:{width}"); @@ -395,13 +396,23 @@ mod nonzero { mod r#ref { use super::*; + use crate::layout::Reference; #[test] fn should_permit_identity_transmutation() { - type Tree = crate::layout::Tree<Def, [(); 1]>; + type Tree = crate::layout::Tree<Def, usize, ()>; for validity in [false, true] { - let layout = Tree::Seq(vec![Tree::byte(0x00), Tree::Ref([()])]); + let layout = Tree::Seq(vec![ + Tree::byte(0x00), + Tree::Ref(Reference { + region: 42, + is_mut: false, + referent: (), + referent_size: 0, + referent_align: 1, + }), + ]); let assume = Assume { validity, ..Assume::default() }; @@ -414,7 +425,11 @@ mod r#ref { .answer(); assert_eq!( answer, - Answer::If(crate::Condition::IfTransmutable { src: [()], dst: [()] }) + Answer::If(Condition::IfAll(vec![ + Condition::Transmutable { src: (), dst: () }, + Condition::Outlives { long: 42, short: 42 }, + Condition::Immutable { ty: () }, + ])) ); } } diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index 4dc27622d23..79ac622df32 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -255,10 +255,8 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ImplTraitInTraitFinder<'_, 'tcx> { } } -fn param_env_normalized_for_post_analysis(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> { - // This is a bit ugly but the easiest way to avoid code duplication. - let typing_env = ty::TypingEnv::non_body_analysis(tcx, def_id); - typing_env.with_post_analysis_normalized(tcx).param_env +fn typing_env_normalized_for_post_analysis(tcx: TyCtxt<'_>, def_id: DefId) -> ty::TypingEnv<'_> { + ty::TypingEnv::non_body_analysis(tcx, def_id).with_post_analysis_normalized(tcx) } /// Check if a function is async. @@ -374,7 +372,7 @@ pub(crate) fn provide(providers: &mut Providers) { asyncness, adt_sized_constraint, param_env, - param_env_normalized_for_post_analysis, + typing_env_normalized_for_post_analysis, defaultness, unsizing_params_for_adt, impl_self_is_guaranteed_unsized, diff --git a/compiler/rustc_type_ir/src/canonical.rs b/compiler/rustc_type_ir/src/canonical.rs index 2b1b0617cef..c66a83662d7 100644 --- a/compiler/rustc_type_ir/src/canonical.rs +++ b/compiler/rustc_type_ir/src/canonical.rs @@ -7,6 +7,7 @@ use derive_where::derive_where; use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext}; use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic}; +use crate::data_structures::HashMap; use crate::inherent::*; use crate::{self as ty, Interner, TypingMode, UniverseIndex}; @@ -333,3 +334,11 @@ impl<I: Interner> Index<ty::BoundVar> for CanonicalVarValues<I> { &self.var_values.as_slice()[value.as_usize()] } } + +#[derive_where(Clone, Debug; I: Interner)] +pub struct CanonicalParamEnvCacheEntry<I: Interner> { + pub param_env: I::ParamEnv, + pub variables: Vec<I::GenericArg>, + pub variable_lookup_table: HashMap<I::GenericArg, usize>, + pub var_kinds: Vec<CanonicalVarKind<I>>, +} diff --git a/compiler/rustc_type_ir/src/fast_reject.rs b/compiler/rustc_type_ir/src/fast_reject.rs index 34502f49550..615d07707b9 100644 --- a/compiler/rustc_type_ir/src/fast_reject.rs +++ b/compiler/rustc_type_ir/src/fast_reject.rs @@ -84,6 +84,9 @@ pub enum TreatParams { /// /// This also treats projections with inference variables as infer vars /// since they could be further normalized. + // FIXME(@lcnr): This treats aliases as rigid. This is only correct if the + // type has been structurally normalized. We should reflect this requirement + // in the variant name. It is currently incorrectly used in diagnostics. AsRigid, } @@ -151,9 +154,11 @@ pub fn simplify_type<I: Interner>( ty::Alias(..) => match treat_params { // When treating `ty::Param` as a placeholder, projections also // don't unify with anything else as long as they are fully normalized. - // FIXME(-Znext-solver): Can remove this `if` and always simplify to `Placeholder` - // when the new solver is enabled by default. - TreatParams::AsRigid if !ty.has_non_region_infer() => Some(SimplifiedType::Placeholder), + TreatParams::AsRigid + if !ty.has_non_region_infer() || cx.next_trait_solver_globally() => + { + Some(SimplifiedType::Placeholder) + } TreatParams::AsRigid | TreatParams::InstantiateWithInfer => None, }, ty::Foreign(def_id) => Some(SimplifiedType::Foreign(def_id)), diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 05ca6f10323..cc0925b2c32 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -12,7 +12,7 @@ use crate::lang_items::TraitSolverLangItem; use crate::relate::Relate; use crate::solve::{CanonicalInput, ExternalConstraintsData, PredefinedOpaquesData, QueryResult}; use crate::visit::{Flags, TypeVisitable}; -use crate::{self as ty, search_graph}; +use crate::{self as ty, CanonicalParamEnvCacheEntry, search_graph}; #[cfg_attr(feature = "nightly", rustc_diagnostic_item = "type_ir_interner")] pub trait Interner: @@ -32,6 +32,10 @@ pub trait Interner: + IrPrint<ty::FnSig<Self>> + IrPrint<ty::PatternKind<Self>> { + fn next_trait_solver_globally(self) -> bool { + true + } + type DefId: DefId<Self>; type LocalDefId: Copy + Debug + Hash + Eq + Into<Self::DefId> + TypeFoldable<Self>; type Span: Span<Self>; @@ -149,6 +153,13 @@ pub trait Interner: fn with_global_cache<R>(self, f: impl FnOnce(&mut search_graph::GlobalCache<Self>) -> R) -> R; + fn canonical_param_env_cache_get_or_insert<R>( + self, + param_env: Self::ParamEnv, + f: impl FnOnce() -> CanonicalParamEnvCacheEntry<Self>, + from_entry: impl FnOnce(&CanonicalParamEnvCacheEntry<Self>) -> R, + ) -> R; + fn evaluation_is_concurrent(&self) -> bool; fn expand_abstract_consts<T: TypeFoldable<Self>>(self, t: T) -> T; diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs index 0cd98b5aa53..9669772d1a6 100644 --- a/compiler/rustc_type_ir/src/ty_kind.rs +++ b/compiler/rustc_type_ir/src/ty_kind.rs @@ -771,23 +771,6 @@ pub enum InferTy { FreshFloatTy(u32), } -/// Raw `TyVid` are used as the unification key for `sub_relations`; -/// they carry no values. -impl UnifyKey for TyVid { - type Value = (); - #[inline] - fn index(&self) -> u32 { - self.as_u32() - } - #[inline] - fn from_index(i: u32) -> TyVid { - TyVid::from_u32(i) - } - fn tag() -> &'static str { - "TyVid" - } -} - impl UnifyValue for IntVarValue { type Error = NoError; diff --git a/library/Cargo.lock b/library/Cargo.lock index 966ae72dc2a..1bd97e7b527 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -4,11 +4,10 @@ version = 4 [[package]] name = "addr2line" -version = "0.24.2" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" +checksum = "9acbfca36652500c911ddb767ed433e3ed99b032b5d935be73c6923662db1d43" dependencies = [ - "compiler_builtins", "gimli", "rustc-std-workspace-alloc", "rustc-std-workspace-core", @@ -16,11 +15,10 @@ dependencies = [ [[package]] name = "adler2" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" dependencies = [ - "compiler_builtins", "rustc-std-workspace-core", ] @@ -51,11 +49,10 @@ dependencies = [ [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" dependencies = [ - "compiler_builtins", "rustc-std-workspace-core", ] @@ -81,12 +78,11 @@ dependencies = [ [[package]] name = "dlmalloc" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cff88b751e7a276c4ab0e222c3f355190adc6dde9ce39c851db39da34990df7" +checksum = "d01597dde41c0b9da50d5f8c219023d63d8f27f39a27095070fd191fddc83891" dependencies = [ "cfg-if", - "compiler_builtins", "libc", "rustc-std-workspace-core", "windows-sys", @@ -104,9 +100,9 @@ dependencies = [ [[package]] name = "getopts" -version = "0.2.21" +version = "0.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" +checksum = "cba6ae63eb948698e300f645f87c70f76630d505f23b8907cf1e193ee85048c1" dependencies = [ "rustc-std-workspace-core", "rustc-std-workspace-std", @@ -115,33 +111,30 @@ dependencies = [ [[package]] name = "gimli" -version = "0.31.1" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" +checksum = "93563d740bc9ef04104f9ed6f86f1e3275c2cdafb95664e26584b9ca807a8ffe" dependencies = [ - "compiler_builtins", "rustc-std-workspace-alloc", "rustc-std-workspace-core", ] [[package]] name = "hashbrown" -version = "0.15.3" +version = "0.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3" +checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" dependencies = [ - "compiler_builtins", "rustc-std-workspace-alloc", "rustc-std-workspace-core", ] [[package]] name = "hermit-abi" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f154ce46856750ed433c8649605bf7ed2de3bc35fd9d2a9f30cddd873c80cb08" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" dependencies = [ - "compiler_builtins", "rustc-std-workspace-alloc", "rustc-std-workspace-core", ] @@ -157,33 +150,30 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.4" +version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" dependencies = [ - "compiler_builtins", "rustc-std-workspace-core", ] [[package]] name = "miniz_oxide" -version = "0.8.8" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" dependencies = [ "adler2", - "compiler_builtins", "rustc-std-workspace-alloc", "rustc-std-workspace-core", ] [[package]] name = "object" -version = "0.36.7" +version = "0.37.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" +checksum = "03fd943161069e1768b4b3d050890ba48730e590f57e56d4aa04e7e090e61b4a" dependencies = [ - "compiler_builtins", "memchr", "rustc-std-workspace-alloc", "rustc-std-workspace-core", @@ -274,11 +264,10 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.24" +version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f" dependencies = [ - "compiler_builtins", "rustc-std-workspace-core", ] @@ -353,7 +342,6 @@ name = "std_detect" version = "0.1.5" dependencies = [ "cfg-if", - "compiler_builtins", "libc", "rustc-std-workspace-alloc", "rustc-std-workspace-core", @@ -381,11 +369,10 @@ dependencies = [ [[package]] name = "unicode-width" -version = "0.1.14" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" +checksum = "4a1a07cc7db3810833284e8d372ccdc6da29741639ecc70c9ec107df0fa6154c" dependencies = [ - "compiler_builtins", "rustc-std-workspace-core", "rustc-std-workspace-std", ] @@ -403,9 +390,9 @@ dependencies = [ [[package]] name = "unwinding" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8393f2782b6060a807337ff353780c1ca15206f9ba2424df18cb6e733bd7b345" +checksum = "7d80f6c2bfede213d9a90b4a14f3eb99b84e33c52df6c1a15de0a100f5a88751" dependencies = [ "compiler_builtins", "gimli", @@ -414,11 +401,10 @@ dependencies = [ [[package]] name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" +version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" dependencies = [ - "compiler_builtins", "rustc-std-workspace-alloc", "rustc-std-workspace-core", ] diff --git a/library/alloc/src/ffi/c_str.rs b/library/alloc/src/ffi/c_str.rs index 8b448a18402..48849bf7536 100644 --- a/library/alloc/src/ffi/c_str.rs +++ b/library/alloc/src/ffi/c_str.rs @@ -714,6 +714,8 @@ impl ops::Deref for CString { } } +/// Delegates to the [`CStr`] implementation of [`fmt::Debug`], +/// showing invalid UTF-8 as hex escapes. #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for CString { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { diff --git a/library/alloctests/tests/slice.rs b/library/alloctests/tests/slice.rs index 2516563187f..1e15d54d979 100644 --- a/library/alloctests/tests/slice.rs +++ b/library/alloctests/tests/slice.rs @@ -1636,6 +1636,19 @@ fn test_chunk_by() { assert_eq!(iter.next_back(), Some(&[1][..])); assert_eq!(iter.next(), Some(&[2, 2, 2][..])); assert_eq!(iter.next_back(), None); + + let mut iter = slice.chunk_by(|a, b| a == b); + assert_eq!(iter.next(), Some(&[1, 1, 1][..])); + assert_eq!(iter.next(), Some(&[3, 3][..])); + let mut iter_clone = iter.clone(); + assert_eq!(iter.next(), Some(&[2, 2, 2][..])); + assert_eq!(iter.next(), Some(&[1][..])); + assert_eq!(iter.next(), Some(&[0][..])); + assert_eq!(iter.next(), None); + assert_eq!(iter_clone.next(), Some(&[2, 2, 2][..])); + assert_eq!(iter_clone.next(), Some(&[1][..])); + assert_eq!(iter_clone.next(), Some(&[0][..])); + assert_eq!(iter_clone.next(), None); } #[test] diff --git a/library/compiler-builtins/compiler-builtins/src/lib.rs b/library/compiler-builtins/compiler-builtins/src/lib.rs index 6a6b28067e8..6549d4cef9e 100644 --- a/library/compiler-builtins/compiler-builtins/src/lib.rs +++ b/library/compiler-builtins/compiler-builtins/src/lib.rs @@ -8,6 +8,7 @@ #![feature(linkage)] #![feature(naked_functions)] #![feature(repr_simd)] +#![feature(rustc_attrs)] #![cfg_attr(f16_enabled, feature(f16))] #![cfg_attr(f128_enabled, feature(f128))] #![no_builtins] diff --git a/library/compiler-builtins/compiler-builtins/src/probestack.rs b/library/compiler-builtins/compiler-builtins/src/probestack.rs index c9070cf55c6..1441fd73b8d 100644 --- a/library/compiler-builtins/compiler-builtins/src/probestack.rs +++ b/library/compiler-builtins/compiler-builtins/src/probestack.rs @@ -49,304 +49,198 @@ // We only define stack probing for these architectures today. #![cfg(any(target_arch = "x86_64", target_arch = "x86"))] -// SAFETY: defined in this module. -// FIXME(extern_custom): the ABI is not correct. -unsafe extern "C" { - pub fn __rust_probestack(); -} - -// A wrapper for our implementation of __rust_probestack, which allows us to -// keep the assembly inline while controlling all CFI directives in the assembly -// emitted for the function. -// -// This is the ELF version. -#[cfg(not(any(target_vendor = "apple", target_os = "uefi")))] -macro_rules! define_rust_probestack { - ($body: expr) => { - concat!( - " - .pushsection .text.__rust_probestack - .globl __rust_probestack - .type __rust_probestack, @function - .hidden __rust_probestack - __rust_probestack: - ", - $body, - " - .size __rust_probestack, . - __rust_probestack - .popsection - " - ) - }; -} - -#[cfg(all(target_os = "uefi", target_arch = "x86_64"))] -macro_rules! define_rust_probestack { - ($body: expr) => { - concat!( - " - .globl __rust_probestack - __rust_probestack: - ", - $body - ) - }; -} - -// Same as above, but for Mach-O. Note that the triple underscore -// is deliberate -#[cfg(target_vendor = "apple")] -macro_rules! define_rust_probestack { - ($body: expr) => { - concat!( - " - .globl ___rust_probestack - ___rust_probestack: - ", - $body - ) - }; -} - -// In UEFI x86 arch, triple underscore is deliberate. -#[cfg(all(target_os = "uefi", target_arch = "x86"))] -macro_rules! define_rust_probestack { - ($body: expr) => { - concat!( - " - .globl ___rust_probestack - ___rust_probestack: - ", - $body - ) - }; -} - // Our goal here is to touch each page between %rsp+8 and %rsp+8-%rax, // ensuring that if any pages are unmapped we'll make a page fault. // +// FIXME(abi_custom): This function is unsafe because it uses a custom ABI, +// it does not actually match `extern "C"`. +// // The ABI here is that the stack frame size is located in `%rax`. Upon // return we're not supposed to modify `%rsp` or `%rax`. -// -// Any changes to this function should be replicated to the SGX version below. -#[cfg(all( - target_arch = "x86_64", - not(all(target_env = "sgx", target_vendor = "fortanix")) -))] -core::arch::global_asm!( - define_rust_probestack!( - " - .cfi_startproc - pushq %rbp - .cfi_adjust_cfa_offset 8 - .cfi_offset %rbp, -16 - movq %rsp, %rbp - .cfi_def_cfa_register %rbp - - mov %rax,%r11 // duplicate %rax as we're clobbering %r11 - - // Main loop, taken in one page increments. We're decrementing rsp by - // a page each time until there's less than a page remaining. We're - // guaranteed that this function isn't called unless there's more than a - // page needed. - // - // Note that we're also testing against `8(%rsp)` to account for the 8 - // bytes pushed on the stack orginally with our return address. Using - // `8(%rsp)` simulates us testing the stack pointer in the caller's - // context. - - // It's usually called when %rax >= 0x1000, but that's not always true. - // Dynamic stack allocation, which is needed to implement unsized - // rvalues, triggers stackprobe even if %rax < 0x1000. - // Thus we have to check %r11 first to avoid segfault. - cmp $0x1000,%r11 - jna 3f -2: - sub $0x1000,%rsp - test %rsp,8(%rsp) - sub $0x1000,%r11 - cmp $0x1000,%r11 - ja 2b - -3: - // Finish up the last remaining stack space requested, getting the last - // bits out of r11 - sub %r11,%rsp - test %rsp,8(%rsp) - - // Restore the stack pointer to what it previously was when entering - // this function. The caller will readjust the stack pointer after we - // return. - add %rax,%rsp - - leave - .cfi_def_cfa_register %rsp - .cfi_adjust_cfa_offset -8 - ret - .cfi_endproc - " - ), - options(att_syntax) -); +#[cfg(target_arch = "x86_64")] +#[unsafe(naked)] +#[rustc_std_internal_symbol] +pub unsafe extern "C" fn __rust_probestack() { + #[cfg(not(all(target_env = "sgx", target_vendor = "fortanix")))] + macro_rules! ret { + () => { + "ret" + }; + } + + #[cfg(all(target_env = "sgx", target_vendor = "fortanix"))] + macro_rules! ret { + // for this target, [manually patch for LVI]. + // + // [manually patch for LVI]: https://software.intel.com/security-software-guidance/insights/deep-dive-load-value-injection#specialinstructions + () => { + " + pop %r11 + lfence + jmp *%r11 + " + }; + } -// This function is the same as above, except that some instructions are -// [manually patched for LVI]. -// -// [manually patched for LVI]: https://software.intel.com/security-software-guidance/insights/deep-dive-load-value-injection#specialinstructions -#[cfg(all( - target_arch = "x86_64", - all(target_env = "sgx", target_vendor = "fortanix") -))] -core::arch::global_asm!( - define_rust_probestack!( + core::arch::naked_asm!( " - .cfi_startproc - pushq %rbp - .cfi_adjust_cfa_offset 8 - .cfi_offset %rbp, -16 - movq %rsp, %rbp - .cfi_def_cfa_register %rbp - - mov %rax,%r11 // duplicate %rax as we're clobbering %r11 - - // Main loop, taken in one page increments. We're decrementing rsp by - // a page each time until there's less than a page remaining. We're - // guaranteed that this function isn't called unless there's more than a - // page needed. - // - // Note that we're also testing against `8(%rsp)` to account for the 8 - // bytes pushed on the stack orginally with our return address. Using - // `8(%rsp)` simulates us testing the stack pointer in the caller's - // context. - - // It's usually called when %rax >= 0x1000, but that's not always true. - // Dynamic stack allocation, which is needed to implement unsized - // rvalues, triggers stackprobe even if %rax < 0x1000. - // Thus we have to check %r11 first to avoid segfault. - cmp $0x1000,%r11 - jna 3f -2: - sub $0x1000,%rsp - test %rsp,8(%rsp) - sub $0x1000,%r11 - cmp $0x1000,%r11 - ja 2b - -3: - // Finish up the last remaining stack space requested, getting the last - // bits out of r11 - sub %r11,%rsp - test %rsp,8(%rsp) - - // Restore the stack pointer to what it previously was when entering - // this function. The caller will readjust the stack pointer after we - // return. - add %rax,%rsp - - leave - .cfi_def_cfa_register %rsp - .cfi_adjust_cfa_offset -8 - pop %r11 - lfence - jmp *%r11 - .cfi_endproc - " - ), - options(att_syntax) -); + .cfi_startproc + pushq %rbp + .cfi_adjust_cfa_offset 8 + .cfi_offset %rbp, -16 + movq %rsp, %rbp + .cfi_def_cfa_register %rbp + + mov %rax,%r11 // duplicate %rax as we're clobbering %r11 + + // Main loop, taken in one page increments. We're decrementing rsp by + // a page each time until there's less than a page remaining. We're + // guaranteed that this function isn't called unless there's more than a + // page needed. + // + // Note that we're also testing against `8(%rsp)` to account for the 8 + // bytes pushed on the stack orginally with our return address. Using + // `8(%rsp)` simulates us testing the stack pointer in the caller's + // context. + + // It's usually called when %rax >= 0x1000, but that's not always true. + // Dynamic stack allocation, which is needed to implement unsized + // rvalues, triggers stackprobe even if %rax < 0x1000. + // Thus we have to check %r11 first to avoid segfault. + cmp $0x1000,%r11 + jna 3f + 2: + sub $0x1000,%rsp + test %rsp,8(%rsp) + sub $0x1000,%r11 + cmp $0x1000,%r11 + ja 2b + + 3: + // Finish up the last remaining stack space requested, getting the last + // bits out of r11 + sub %r11,%rsp + test %rsp,8(%rsp) + + // Restore the stack pointer to what it previously was when entering + // this function. The caller will readjust the stack pointer after we + // return. + add %rax,%rsp + + leave + .cfi_def_cfa_register %rsp + .cfi_adjust_cfa_offset -8 + ", + ret!(), + " + .cfi_endproc + ", + options(att_syntax) + ) +} #[cfg(all(target_arch = "x86", not(target_os = "uefi")))] // This is the same as x86_64 above, only translated for 32-bit sizes. Note // that on Unix we're expected to restore everything as it was, this // function basically can't tamper with anything. // +// FIXME(abi_custom): This function is unsafe because it uses a custom ABI, +// it does not actually match `extern "C"`. +// // The ABI here is the same as x86_64, except everything is 32-bits large. -core::arch::global_asm!( - define_rust_probestack!( +#[unsafe(naked)] +#[rustc_std_internal_symbol] +pub unsafe extern "C" fn __rust_probestack() { + core::arch::naked_asm!( " - .cfi_startproc - push %ebp - .cfi_adjust_cfa_offset 4 - .cfi_offset %ebp, -8 - mov %esp, %ebp - .cfi_def_cfa_register %ebp - push %ecx - mov %eax,%ecx - - cmp $0x1000,%ecx - jna 3f -2: - sub $0x1000,%esp - test %esp,8(%esp) - sub $0x1000,%ecx - cmp $0x1000,%ecx - ja 2b - -3: - sub %ecx,%esp - test %esp,8(%esp) - - add %eax,%esp - pop %ecx - leave - .cfi_def_cfa_register %esp - .cfi_adjust_cfa_offset -4 - ret - .cfi_endproc - " - ), - options(att_syntax) -); + .cfi_startproc + push %ebp + .cfi_adjust_cfa_offset 4 + .cfi_offset %ebp, -8 + mov %esp, %ebp + .cfi_def_cfa_register %ebp + push %ecx + mov %eax,%ecx + + cmp $0x1000,%ecx + jna 3f + 2: + sub $0x1000,%esp + test %esp,8(%esp) + sub $0x1000,%ecx + cmp $0x1000,%ecx + ja 2b + + 3: + sub %ecx,%esp + test %esp,8(%esp) + + add %eax,%esp + pop %ecx + leave + .cfi_def_cfa_register %esp + .cfi_adjust_cfa_offset -4 + ret + .cfi_endproc + ", + options(att_syntax) + ) +} #[cfg(all(target_arch = "x86", target_os = "uefi"))] // UEFI target is windows like target. LLVM will do _chkstk things like windows. // probestack function will also do things like _chkstk in MSVC. // So we need to sub %ax %sp in probestack when arch is x86. // +// FIXME(abi_custom): This function is unsafe because it uses a custom ABI, +// it does not actually match `extern "C"`. +// // REF: Rust commit(74e80468347) // rust\src\llvm-project\llvm\lib\Target\X86\X86FrameLowering.cpp: 805 // Comments in LLVM: // MSVC x32's _chkstk and cygwin/mingw's _alloca adjust %esp themselves. // MSVC x64's __chkstk and cygwin/mingw's ___chkstk_ms do not adjust %rsp // themselves. -core::arch::global_asm!( - define_rust_probestack!( +#[unsafe(naked)] +#[rustc_std_internal_symbol] +pub unsafe extern "C" fn __rust_probestack() { + core::arch::naked_asm!( " - .cfi_startproc - push %ebp - .cfi_adjust_cfa_offset 4 - .cfi_offset %ebp, -8 - mov %esp, %ebp - .cfi_def_cfa_register %ebp - push %ecx - push %edx - mov %eax,%ecx - - cmp $0x1000,%ecx - jna 3f -2: - sub $0x1000,%esp - test %esp,8(%esp) - sub $0x1000,%ecx - cmp $0x1000,%ecx - ja 2b - -3: - sub %ecx,%esp - test %esp,8(%esp) - mov 4(%ebp),%edx - mov %edx, 12(%esp) - add %eax,%esp - pop %edx - pop %ecx - leave - - sub %eax, %esp - .cfi_def_cfa_register %esp - .cfi_adjust_cfa_offset -4 - ret - .cfi_endproc - " - ), - options(att_syntax) -); + .cfi_startproc + push %ebp + .cfi_adjust_cfa_offset 4 + .cfi_offset %ebp, -8 + mov %esp, %ebp + .cfi_def_cfa_register %ebp + push %ecx + push %edx + mov %eax,%ecx + + cmp $0x1000,%ecx + jna 3f + 2: + sub $0x1000,%esp + test %esp,8(%esp) + sub $0x1000,%ecx + cmp $0x1000,%ecx + ja 2b + + 3: + sub %ecx,%esp + test %esp,8(%esp) + mov 4(%ebp),%edx + mov %edx, 12(%esp) + add %eax,%esp + pop %edx + pop %ecx + leave + + sub %eax, %esp + .cfi_def_cfa_register %esp + .cfi_adjust_cfa_offset -4 + ret + .cfi_endproc + ", + options(att_syntax) + ) +} diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index 595cc1fe025..f7a21072f53 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs @@ -162,10 +162,12 @@ impl fmt::Display for FromBytesUntilNulError { } } +/// Shows the underlying bytes as a normal string, with invalid UTF-8 +/// presented as hex escape sequences. #[stable(feature = "cstr_debug", since = "1.3.0")] impl fmt::Debug for CStr { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "\"{}\"", self.to_bytes().escape_ascii()) + fmt::Debug::fmt(crate::bstr::ByteStr::from_bytes(self.to_bytes()), f) } } diff --git a/library/core/src/fmt/num.rs b/library/core/src/fmt/num.rs index dd9c379b666..ce878f2da4b 100644 --- a/library/core/src/fmt/num.rs +++ b/library/core/src/fmt/num.rs @@ -279,7 +279,7 @@ macro_rules! impl_Display { // Format per two digits from the lookup table. if remain > 9 { // SAFETY: All of the decimals fit in buf due to MAX_DEC_N - // and the while condition ensures at least 2 more decimals. + // and the if condition ensures at least 2 more decimals. unsafe { core::hint::assert_unchecked(offset >= 2) } // SAFETY: The offset counts down from its initial buf.len() // without underflow due to the previous precondition. @@ -565,93 +565,6 @@ mod imp { } impl_Exp!(i128, u128 as u128 via to_u128 named exp_u128); -/// Helper function for writing a u64 into `buf` going from last to first, with `curr`. -fn parse_u64_into<const N: usize>(mut n: u64, buf: &mut [MaybeUninit<u8>; N], curr: &mut usize) { - let buf_ptr = MaybeUninit::slice_as_mut_ptr(buf); - let lut_ptr = DEC_DIGITS_LUT.as_ptr(); - assert!(*curr > 19); - - // SAFETY: - // Writes at most 19 characters into the buffer. Guaranteed that any ptr into LUT is at most - // 198, so will never OOB. There is a check above that there are at least 19 characters - // remaining. - unsafe { - if n >= 1e16 as u64 { - let to_parse = n % 1e16 as u64; - n /= 1e16 as u64; - - // Some of these are nops but it looks more elegant this way. - let d1 = ((to_parse / 1e14 as u64) % 100) << 1; - let d2 = ((to_parse / 1e12 as u64) % 100) << 1; - let d3 = ((to_parse / 1e10 as u64) % 100) << 1; - let d4 = ((to_parse / 1e8 as u64) % 100) << 1; - let d5 = ((to_parse / 1e6 as u64) % 100) << 1; - let d6 = ((to_parse / 1e4 as u64) % 100) << 1; - let d7 = ((to_parse / 1e2 as u64) % 100) << 1; - let d8 = ((to_parse / 1e0 as u64) % 100) << 1; - - *curr -= 16; - - ptr::copy_nonoverlapping(lut_ptr.add(d1 as usize), buf_ptr.add(*curr + 0), 2); - ptr::copy_nonoverlapping(lut_ptr.add(d2 as usize), buf_ptr.add(*curr + 2), 2); - ptr::copy_nonoverlapping(lut_ptr.add(d3 as usize), buf_ptr.add(*curr + 4), 2); - ptr::copy_nonoverlapping(lut_ptr.add(d4 as usize), buf_ptr.add(*curr + 6), 2); - ptr::copy_nonoverlapping(lut_ptr.add(d5 as usize), buf_ptr.add(*curr + 8), 2); - ptr::copy_nonoverlapping(lut_ptr.add(d6 as usize), buf_ptr.add(*curr + 10), 2); - ptr::copy_nonoverlapping(lut_ptr.add(d7 as usize), buf_ptr.add(*curr + 12), 2); - ptr::copy_nonoverlapping(lut_ptr.add(d8 as usize), buf_ptr.add(*curr + 14), 2); - } - if n >= 1e8 as u64 { - let to_parse = n % 1e8 as u64; - n /= 1e8 as u64; - - // Some of these are nops but it looks more elegant this way. - let d1 = ((to_parse / 1e6 as u64) % 100) << 1; - let d2 = ((to_parse / 1e4 as u64) % 100) << 1; - let d3 = ((to_parse / 1e2 as u64) % 100) << 1; - let d4 = ((to_parse / 1e0 as u64) % 100) << 1; - *curr -= 8; - - ptr::copy_nonoverlapping(lut_ptr.add(d1 as usize), buf_ptr.add(*curr + 0), 2); - ptr::copy_nonoverlapping(lut_ptr.add(d2 as usize), buf_ptr.add(*curr + 2), 2); - ptr::copy_nonoverlapping(lut_ptr.add(d3 as usize), buf_ptr.add(*curr + 4), 2); - ptr::copy_nonoverlapping(lut_ptr.add(d4 as usize), buf_ptr.add(*curr + 6), 2); - } - // `n` < 1e8 < (1 << 32) - let mut n = n as u32; - if n >= 1e4 as u32 { - let to_parse = n % 1e4 as u32; - n /= 1e4 as u32; - - let d1 = (to_parse / 100) << 1; - let d2 = (to_parse % 100) << 1; - *curr -= 4; - - ptr::copy_nonoverlapping(lut_ptr.add(d1 as usize), buf_ptr.add(*curr + 0), 2); - ptr::copy_nonoverlapping(lut_ptr.add(d2 as usize), buf_ptr.add(*curr + 2), 2); - } - - // `n` < 1e4 < (1 << 16) - let mut n = n as u16; - if n >= 100 { - let d1 = (n % 100) << 1; - n /= 100; - *curr -= 2; - ptr::copy_nonoverlapping(lut_ptr.add(d1 as usize), buf_ptr.add(*curr), 2); - } - - // decode last 1 or 2 chars - if n < 10 { - *curr -= 1; - *buf_ptr.add(*curr) = (n as u8) + b'0'; - } else { - let d1 = n << 1; - *curr -= 2; - ptr::copy_nonoverlapping(lut_ptr.add(d1 as usize), buf_ptr.add(*curr), 2); - } - } -} - #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Display for u128 { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -662,90 +575,153 @@ impl fmt::Display for u128 { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Display for i128 { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let is_nonnegative = *self >= 0; - let n = if is_nonnegative { - self.to_u128() - } else { - // convert the negative num to positive by summing 1 to its 2s complement - (!self.to_u128()).wrapping_add(1) - }; - fmt_u128(n, is_nonnegative, f) + fmt_u128(self.unsigned_abs(), *self >= 0, f) } } -/// Specialized optimization for u128. Instead of taking two items at a time, it splits -/// into at most 2 u64s, and then chunks by 10e16, 10e8, 10e4, 10e2, and then 10e1. -/// It also has to handle 1 last item, as 10^40 > 2^128 > 10^39, whereas -/// 10^20 > 2^64 > 10^19. +/// Format optimized for u128. Computation of 128 bits is limited by proccessing +/// in batches of 16 decimals at a time. fn fmt_u128(n: u128, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // Optimize common-case zero, which would also need special treatment due to + // its "leading" zero. + if n == 0 { + return f.pad_integral(true, "", "0"); + } + + // U128::MAX has 39 significant-decimals. const MAX_DEC_N: usize = u128::MAX.ilog(10) as usize + 1; + // Buffer decimals with right alignment. let mut buf = [MaybeUninit::<u8>::uninit(); MAX_DEC_N]; - let mut curr = buf.len(); - - let (n, rem) = udiv_1e19(n); - parse_u64_into(rem, &mut buf, &mut curr); - - if n != 0 { - // 0 pad up to point - let target = buf.len() - 19; - // SAFETY: Guaranteed that we wrote at most 19 bytes, and there must be space - // remaining since it has length 39 - unsafe { - ptr::write_bytes( - MaybeUninit::slice_as_mut_ptr(&mut buf).add(target), - b'0', - curr - target, - ); - } - curr = target; - - let (n, rem) = udiv_1e19(n); - parse_u64_into(rem, &mut buf, &mut curr); - // Should this following branch be annotated with unlikely? - if n != 0 { - let target = buf.len() - 38; - // The raw `buf_ptr` pointer is only valid until `buf` is used the next time, - // buf `buf` is not used in this scope so we are good. - let buf_ptr = MaybeUninit::slice_as_mut_ptr(&mut buf); - // SAFETY: At this point we wrote at most 38 bytes, pad up to that point, - // There can only be at most 1 digit remaining. - unsafe { - ptr::write_bytes(buf_ptr.add(target), b'0', curr - target); - curr = target - 1; - *buf_ptr.add(curr) = (n as u8) + b'0'; - } + + // Take the 16 least-significant decimals. + let (quot_1e16, mod_1e16) = div_rem_1e16(n); + let (mut remain, mut offset) = if quot_1e16 == 0 { + (mod_1e16, MAX_DEC_N) + } else { + // Write digits at buf[23..39]. + enc_16lsd::<{ MAX_DEC_N - 16 }>(&mut buf, mod_1e16); + + // Take another 16 decimals. + let (quot2, mod2) = div_rem_1e16(quot_1e16); + if quot2 == 0 { + (mod2, MAX_DEC_N - 16) + } else { + // Write digits at buf[7..23]. + enc_16lsd::<{ MAX_DEC_N - 32 }>(&mut buf, mod2); + // Quot2 has at most 7 decimals remaining after two 1e16 divisions. + (quot2 as u64, MAX_DEC_N - 32) } + }; + + // Format per four digits from the lookup table. + while remain > 999 { + // SAFETY: All of the decimals fit in buf due to MAX_DEC_N + // and the while condition ensures at least 4 more decimals. + unsafe { core::hint::assert_unchecked(offset >= 4) } + // SAFETY: The offset counts down from its initial buf.len() + // without underflow due to the previous precondition. + unsafe { core::hint::assert_unchecked(offset <= buf.len()) } + offset -= 4; + + // pull two pairs + let quad = remain % 1_00_00; + remain /= 1_00_00; + let pair1 = (quad / 100) as usize; + let pair2 = (quad % 100) as usize; + buf[offset + 0].write(DEC_DIGITS_LUT[pair1 * 2 + 0]); + buf[offset + 1].write(DEC_DIGITS_LUT[pair1 * 2 + 1]); + buf[offset + 2].write(DEC_DIGITS_LUT[pair2 * 2 + 0]); + buf[offset + 3].write(DEC_DIGITS_LUT[pair2 * 2 + 1]); + } + + // Format per two digits from the lookup table. + if remain > 9 { + // SAFETY: All of the decimals fit in buf due to MAX_DEC_N + // and the if condition ensures at least 2 more decimals. + unsafe { core::hint::assert_unchecked(offset >= 2) } + // SAFETY: The offset counts down from its initial buf.len() + // without underflow due to the previous precondition. + unsafe { core::hint::assert_unchecked(offset <= buf.len()) } + offset -= 2; + + let pair = (remain % 100) as usize; + remain /= 100; + buf[offset + 0].write(DEC_DIGITS_LUT[pair * 2 + 0]); + buf[offset + 1].write(DEC_DIGITS_LUT[pair * 2 + 1]); + } + + // Format the last remaining digit, if any. + if remain != 0 { + // SAFETY: All of the decimals fit in buf due to MAX_DEC_N + // and the if condition ensures (at least) 1 more decimals. + unsafe { core::hint::assert_unchecked(offset >= 1) } + // SAFETY: The offset counts down from its initial buf.len() + // without underflow due to the previous precondition. + unsafe { core::hint::assert_unchecked(offset <= buf.len()) } + offset -= 1; + + // Either the compiler sees that remain < 10, or it prevents + // a boundary check up next. + let last = (remain & 15) as usize; + buf[offset].write(DEC_DIGITS_LUT[last * 2 + 1]); + // not used: remain = 0; } - // SAFETY: `curr` > 0 (since we made `buf` large enough), and all the chars are valid - // UTF-8 since `DEC_DIGITS_LUT` is - let buf_slice = unsafe { + // SAFETY: All buf content since offset is set. + let written = unsafe { buf.get_unchecked(offset..) }; + // SAFETY: Writes use ASCII from the lookup table exclusively. + let as_str = unsafe { str::from_utf8_unchecked(slice::from_raw_parts( - MaybeUninit::slice_as_mut_ptr(&mut buf).add(curr), - buf.len() - curr, + MaybeUninit::slice_as_ptr(written), + written.len(), )) }; - f.pad_integral(is_nonnegative, "", buf_slice) + f.pad_integral(is_nonnegative, "", as_str) } -/// Partition of `n` into n > 1e19 and rem <= 1e19 +/// Encodes the 16 least-significant decimals of n into `buf[OFFSET .. OFFSET + +/// 16 ]`. +fn enc_16lsd<const OFFSET: usize>(buf: &mut [MaybeUninit<u8>; 39], n: u64) { + // Consume the least-significant decimals from a working copy. + let mut remain = n; + + // Format per four digits from the lookup table. + for quad_index in (0..4).rev() { + // pull two pairs + let quad = remain % 1_00_00; + remain /= 1_00_00; + let pair1 = (quad / 100) as usize; + let pair2 = (quad % 100) as usize; + buf[quad_index * 4 + OFFSET + 0].write(DEC_DIGITS_LUT[pair1 * 2 + 0]); + buf[quad_index * 4 + OFFSET + 1].write(DEC_DIGITS_LUT[pair1 * 2 + 1]); + buf[quad_index * 4 + OFFSET + 2].write(DEC_DIGITS_LUT[pair2 * 2 + 0]); + buf[quad_index * 4 + OFFSET + 3].write(DEC_DIGITS_LUT[pair2 * 2 + 1]); + } +} + +/// Euclidean division plus remainder with constant 1E16 basically consumes 16 +/// decimals from n. /// -/// Integer division algorithm is based on the following paper: +/// The integer division algorithm is based on the following paper: /// /// T. Granlund and P. Montgomery, “Division by Invariant Integers Using Multiplication” /// in Proc. of the SIGPLAN94 Conference on Programming Language Design and /// Implementation, 1994, pp. 61–72 /// -fn udiv_1e19(n: u128) -> (u128, u64) { - const DIV: u64 = 1e19 as u64; - const FACTOR: u128 = 156927543384667019095894735580191660403; +#[inline] +fn div_rem_1e16(n: u128) -> (u128, u64) { + const D: u128 = 1_0000_0000_0000_0000; + // The check inlines well with the caller flow. + if n < D { + return (0, n as u64); + } - let quot = if n < 1 << 83 { - ((n >> 19) as u64 / (DIV >> 19)) as u128 - } else { - n.widening_mul(FACTOR).1 >> 62 - }; + // These constant values are computed with the CHOOSE_MULTIPLIER procedure + // from the Granlund & Montgomery paper, using N=128, prec=128 and d=1E16. + const M_HIGH: u128 = 76624777043294442917917351357515459181; + const SH_POST: u8 = 51; - let rem = (n - quot * DIV as u128) as u64; - (quot, rem) + let quot = n.widening_mul(M_HIGH).1 >> SH_POST; + let rem = n - quot * D; + (quot, rem as u64) } diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index 4434ceb49bc..7ba48cc7268 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -926,8 +926,7 @@ pub const unsafe fn slice_get_unchecked< pub fn ptr_mask<T>(ptr: *const T, mask: usize) -> *const T; /// Equivalent to the appropriate `llvm.memcpy.p0i8.0i8.*` intrinsic, with -/// a size of `count` * `size_of::<T>()` and an alignment of -/// `min_align_of::<T>()` +/// a size of `count` * `size_of::<T>()` and an alignment of `align_of::<T>()`. /// /// This intrinsic does not have a stable counterpart. /// # Safety @@ -941,8 +940,7 @@ pub fn ptr_mask<T>(ptr: *const T, mask: usize) -> *const T; #[rustc_nounwind] pub unsafe fn volatile_copy_nonoverlapping_memory<T>(dst: *mut T, src: *const T, count: usize); /// Equivalent to the appropriate `llvm.memmove.p0i8.0i8.*` intrinsic, with -/// a size of `count * size_of::<T>()` and an alignment of -/// `min_align_of::<T>()` +/// a size of `count * size_of::<T>()` and an alignment of `align_of::<T>()`. /// /// The volatile parameter is set to `true`, so it will not be optimized out /// unless size is equal to zero. @@ -952,8 +950,7 @@ pub unsafe fn volatile_copy_nonoverlapping_memory<T>(dst: *mut T, src: *const T, #[rustc_nounwind] pub unsafe fn volatile_copy_memory<T>(dst: *mut T, src: *const T, count: usize); /// Equivalent to the appropriate `llvm.memset.p0i8.*` intrinsic, with a -/// size of `count * size_of::<T>()` and an alignment of -/// `min_align_of::<T>()`. +/// size of `count * size_of::<T>()` and an alignment of `align_of::<T>()`. /// /// This intrinsic does not have a stable counterpart. /// # Safety @@ -2649,7 +2646,7 @@ pub const fn size_of<T>() -> usize; #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_intrinsic_const_stable_indirect] #[rustc_intrinsic] -pub const fn min_align_of<T>() -> usize; +pub const fn align_of<T>() -> usize; /// Returns the number of variants of the type `T` cast to a `usize`; /// if `T` has no variants, returns `0`. Uninhabited variants will be counted. @@ -2689,7 +2686,7 @@ pub const unsafe fn size_of_val<T: ?Sized>(ptr: *const T) -> usize; #[unstable(feature = "core_intrinsics", issue = "none")] #[rustc_intrinsic] #[rustc_intrinsic_const_stable_indirect] -pub const unsafe fn min_align_of_val<T: ?Sized>(ptr: *const T) -> usize; +pub const unsafe fn align_of_val<T: ?Sized>(ptr: *const T) -> usize; /// Gets a static string slice containing the name of a type. /// diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index fc98ae9ff3f..88855831788 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -190,7 +190,6 @@ #![feature(aarch64_unstable_target_feature)] #![feature(arm_target_feature)] #![feature(hexagon_target_feature)] -#![feature(keylocker_x86)] #![feature(loongarch_target_feature)] #![feature(mips_target_feature)] #![feature(powerpc_target_feature)] diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index d5efb03cfbc..b21845a1c16 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -1273,6 +1273,19 @@ pub(crate) mod builtin { /// first macro invocation leading up to the invocation of the `file!` /// macro. /// + /// The file name is derived from the crate root's source path passed to the Rust compiler + /// and the sequence the compiler takes to get from the crate root to the + /// module containing `file!`, modified by any flags passed to the Rust compiler (e.g. + /// `--remap-path-prefix`). If the crate's source path is relative, the initial base + /// directory will be the working directory of the Rust compiler. For example, if the source + /// path passed to the compiler is `./src/lib.rs` which has a `mod foo;` with a source path of + /// `src/foo/mod.rs`, then calling `file!` inside `mod foo;` will return `./src/foo/mod.rs`. + /// + /// Future compiler options might make further changes to the behavior of `file!`, + /// including potentially making it entirely empty. Code (e.g. test libraries) + /// relying on `file!` producing an openable file path would be incompatible + /// with such options, and might wish to recommend not using those options. + /// /// # Examples /// /// ``` diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index 0a5f3ee35b1..6819face4c2 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -412,7 +412,7 @@ pub const unsafe fn size_of_val_raw<T: ?Sized>(val: *const T) -> usize { #[stable(feature = "rust1", since = "1.0.0")] #[deprecated(note = "use `align_of` instead", since = "1.2.0", suggestion = "align_of")] pub fn min_align_of<T>() -> usize { - intrinsics::min_align_of::<T>() + intrinsics::align_of::<T>() } /// Returns the [ABI]-required minimum alignment of the type of the value that `val` points to in @@ -436,7 +436,7 @@ pub fn min_align_of<T>() -> usize { #[deprecated(note = "use `align_of_val` instead", since = "1.2.0", suggestion = "align_of_val")] pub fn min_align_of_val<T: ?Sized>(val: &T) -> usize { // SAFETY: val is a reference, so it's a valid raw pointer - unsafe { intrinsics::min_align_of_val(val) } + unsafe { intrinsics::align_of_val(val) } } /// Returns the [ABI]-required minimum alignment of a type in bytes. @@ -458,7 +458,7 @@ pub fn min_align_of_val<T: ?Sized>(val: &T) -> usize { #[rustc_promotable] #[rustc_const_stable(feature = "const_align_of", since = "1.24.0")] pub const fn align_of<T>() -> usize { - intrinsics::min_align_of::<T>() + intrinsics::align_of::<T>() } /// Returns the [ABI]-required minimum alignment of the type of the value that `val` points to in @@ -477,10 +477,9 @@ pub const fn align_of<T>() -> usize { #[must_use] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_align_of_val", since = "1.85.0")] -#[allow(deprecated)] pub const fn align_of_val<T: ?Sized>(val: &T) -> usize { // SAFETY: val is a reference, so it's a valid raw pointer - unsafe { intrinsics::min_align_of_val(val) } + unsafe { intrinsics::align_of_val(val) } } /// Returns the [ABI]-required minimum alignment of the type of the value that `val` points to in @@ -527,7 +526,7 @@ pub const fn align_of_val<T: ?Sized>(val: &T) -> usize { #[unstable(feature = "layout_for_ptr", issue = "69835")] pub const unsafe fn align_of_val_raw<T: ?Sized>(val: *const T) -> usize { // SAFETY: the caller must provide a valid raw pointer - unsafe { intrinsics::min_align_of_val(val) } + unsafe { intrinsics::align_of_val(val) } } /// Returns `true` if dropping values of type `T` matters. @@ -637,8 +636,6 @@ pub const fn needs_drop<T: ?Sized>() -> bool { #[inline(always)] #[must_use] #[stable(feature = "rust1", since = "1.0.0")] -#[allow(deprecated_in_future)] -#[allow(deprecated)] #[rustc_diagnostic_item = "mem_zeroed"] #[track_caller] #[rustc_const_stable(feature = "const_mem_zeroed", since = "1.75.0")] @@ -677,8 +674,6 @@ pub const unsafe fn zeroed<T>() -> T { #[must_use] #[deprecated(since = "1.39.0", note = "use `mem::MaybeUninit` instead")] #[stable(feature = "rust1", since = "1.0.0")] -#[allow(deprecated_in_future)] -#[allow(deprecated)] #[rustc_diagnostic_item = "mem_uninitialized"] #[track_caller] pub unsafe fn uninitialized<T>() -> T { diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index 65560f63c18..3a7bc902f93 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -239,7 +239,6 @@ macro_rules! int_impl { /// Basic usage: /// /// ``` - /// #[doc = concat!("let n = -1", stringify!($SelfT), ";")] /// #[doc = concat!("assert_eq!(n.cast_unsigned(), ", stringify!($UnsignedT), "::MAX);")] diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index 5c73bddbef2..ab2fcff61cd 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -1053,7 +1053,6 @@ impl u8 { /// # Examples /// /// ``` - /// /// assert_eq!("0", b'0'.escape_ascii().to_string()); /// assert_eq!("\\t", b'\t'.escape_ascii().to_string()); /// assert_eq!("\\r", b'\r'.escape_ascii().to_string()); diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index 5f82e6af86b..4ee0e7326b3 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -213,6 +213,30 @@ macro_rules! uint_impl { (!self).trailing_zeros() } + /// Returns the minimum number of bits required to represent `self`. + /// + /// This method returns zero if `self` is zero. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(uint_bit_width)] + /// + #[doc = concat!("assert_eq!(0_", stringify!($SelfT), ".bit_width(), 0);")] + #[doc = concat!("assert_eq!(0b111_", stringify!($SelfT), ".bit_width(), 3);")] + #[doc = concat!("assert_eq!(0b1110_", stringify!($SelfT), ".bit_width(), 4);")] + #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.bit_width(), ", stringify!($BITS), ");")] + /// ``` + #[unstable(feature = "uint_bit_width", issue = "142326")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline(always)] + pub const fn bit_width(self) -> u32 { + Self::BITS - self.leading_zeros() + } + /// Returns `self` with only the most significant bit set, or `0` if /// the input is `0`. /// diff --git a/library/core/src/ops/control_flow.rs b/library/core/src/ops/control_flow.rs index ef7e6f9c2f4..26661b20c12 100644 --- a/library/core/src/ops/control_flow.rs +++ b/library/core/src/ops/control_flow.rs @@ -98,7 +98,7 @@ pub enum ControlFlow<B, C = ()> { // is a no-op conversion in the `Try` implementation. } -#[unstable(feature = "try_trait_v2", issue = "84277")] +#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] impl<B, C> ops::Try for ControlFlow<B, C> { type Output = C; type Residual = ControlFlow<B, convert::Infallible>; @@ -117,7 +117,7 @@ impl<B, C> ops::Try for ControlFlow<B, C> { } } -#[unstable(feature = "try_trait_v2", issue = "84277")] +#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] // Note: manually specifying the residual type instead of using the default to work around // https://github.com/rust-lang/rust/issues/99940 impl<B, C> ops::FromResidual<ControlFlow<B, convert::Infallible>> for ControlFlow<B, C> { diff --git a/library/core/src/ops/mod.rs b/library/core/src/ops/mod.rs index 1658f0e5a36..87dd873fdb5 100644 --- a/library/core/src/ops/mod.rs +++ b/library/core/src/ops/mod.rs @@ -194,7 +194,7 @@ pub use self::try_trait::Residual; #[unstable(feature = "try_trait_v2_yeet", issue = "96374")] pub use self::try_trait::Yeet; pub(crate) use self::try_trait::{ChangeOutputType, NeverShortCircuit}; -#[unstable(feature = "try_trait_v2", issue = "84277")] +#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] pub use self::try_trait::{FromResidual, Try}; #[unstable(feature = "coerce_unsized", issue = "18598")] pub use self::unsize::CoerceUnsized; diff --git a/library/core/src/ops/try_trait.rs b/library/core/src/ops/try_trait.rs index bac8ffb074b..aebbddb4f1c 100644 --- a/library/core/src/ops/try_trait.rs +++ b/library/core/src/ops/try_trait.rs @@ -112,7 +112,7 @@ use crate::ops::ControlFlow; /// R::from_output(accum) /// } /// ``` -#[unstable(feature = "try_trait_v2", issue = "84277")] +#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] #[rustc_on_unimplemented( on( all(from_desugaring = "TryBlock"), @@ -130,7 +130,7 @@ use crate::ops::ControlFlow; #[lang = "Try"] pub trait Try: FromResidual { /// The type of the value produced by `?` when *not* short-circuiting. - #[unstable(feature = "try_trait_v2", issue = "84277")] + #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] type Output; /// The type of the value passed to [`FromResidual::from_residual`] @@ -154,7 +154,7 @@ pub trait Try: FromResidual { /// then typically you can use `Foo<std::convert::Infallible>` as its `Residual` /// type: that type will have a "hole" in the correct place, and will maintain the /// "foo-ness" of the residual so other types need to opt-in to interconversion. - #[unstable(feature = "try_trait_v2", issue = "84277")] + #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] type Residual; /// Constructs the type from its `Output` type. @@ -186,7 +186,7 @@ pub trait Try: FromResidual { /// assert_eq!(r, Some(4)); /// ``` #[lang = "from_output"] - #[unstable(feature = "try_trait_v2", issue = "84277")] + #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] fn from_output(output: Self::Output) -> Self; /// Used in `?` to decide whether the operator should produce a value @@ -213,7 +213,7 @@ pub trait Try: FromResidual { /// ); /// ``` #[lang = "branch"] - #[unstable(feature = "try_trait_v2", issue = "84277")] + #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] fn branch(self) -> ControlFlow<Self::Residual, Self::Output>; } @@ -303,7 +303,7 @@ pub trait Try: FromResidual { ), )] #[rustc_diagnostic_item = "FromResidual"] -#[unstable(feature = "try_trait_v2", issue = "84277")] +#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] pub trait FromResidual<R = <Self as Try>::Residual> { /// Constructs the type from a compatible `Residual` type. /// @@ -326,7 +326,7 @@ pub trait FromResidual<R = <Self as Try>::Residual> { /// ); /// ``` #[lang = "from_residual"] - #[unstable(feature = "try_trait_v2", issue = "84277")] + #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] fn from_residual(residual: R) -> Self; } diff --git a/library/core/src/option.rs b/library/core/src/option.rs index c04754848b4..f2a1e901188 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -2532,7 +2532,7 @@ impl<A, V: FromIterator<A>> FromIterator<Option<A>> for Option<V> { } } -#[unstable(feature = "try_trait_v2", issue = "84277")] +#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] impl<T> ops::Try for Option<T> { type Output = T; type Residual = Option<convert::Infallible>; @@ -2551,7 +2551,7 @@ impl<T> ops::Try for Option<T> { } } -#[unstable(feature = "try_trait_v2", issue = "84277")] +#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] // Note: manually specifying the residual type instead of using the default to work around // https://github.com/rust-lang/rust/issues/99940 impl<T> ops::FromResidual<Option<convert::Infallible>> for Option<T> { diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index cb1cf818bf0..0ac887f99dc 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -1847,6 +1847,8 @@ mod prim_ref {} /// - If `T` is guaranteed to be subject to the [null pointer /// optimization](option/index.html#representation), and `E` is an enum satisfying the following /// requirements, then `T` and `E` are ABI-compatible. Such an enum `E` is called "option-like". +/// - The enum `E` uses the [`Rust` representation], and is not modified by the `align` or +/// `packed` representation modifiers. /// - The enum `E` has exactly two variants. /// - One variant has exactly one field, of type `T`. /// - All fields of the other variant are zero-sized with 1-byte alignment. @@ -1920,6 +1922,7 @@ mod prim_ref {} /// [`Pointer`]: fmt::Pointer /// [`UnwindSafe`]: panic::UnwindSafe /// [`RefUnwindSafe`]: panic::RefUnwindSafe +/// [`Rust` representation]: <https://doc.rust-lang.org/reference/type-layout.html#the-rust-representation> /// /// In addition, all *safe* function pointers implement [`Fn`], [`FnMut`], and [`FnOnce`], because /// these traits are specially known to the compiler. diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index a1dab23ea7b..9366cb36c6e 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -5,24 +5,7 @@ use crate::mem::{self, SizedTypeProperties}; use crate::slice::{self, SliceIndex}; impl<T: ?Sized> *const T { - /// Returns `true` if the pointer is null. - /// - /// Note that unsized types have many possible null pointers, as only the - /// raw data pointer is considered, not their length, vtable, etc. - /// Therefore, two pointers that are null may still not compare equal to - /// each other. - /// - /// # Panics during const evaluation - /// - /// If this method is used during const evaluation, and `self` is a pointer - /// that is offset beyond the bounds of the memory it initially pointed to, - /// then there might not be enough information to determine whether the - /// pointer is null. This is because the absolute address in memory is not - /// known at compile time. If the nullness of the pointer cannot be - /// determined, this method will panic. - /// - /// In-bounds pointers are never null, so the method will never panic for - /// such pointers. + #[doc = include_str!("docs/is_null.md")] /// /// # Examples /// @@ -1550,50 +1533,7 @@ impl<T> *const [T] { unsafe { index.get_unchecked(self) } } - /// Returns `None` if the pointer is null, or else returns a shared slice to - /// the value wrapped in `Some`. In contrast to [`as_ref`], this does not require - /// that the value has to be initialized. - /// - /// [`as_ref`]: #method.as_ref - /// - /// # Safety - /// - /// When calling this method, you have to ensure that *either* the pointer is null *or* - /// all of the following is true: - /// - /// * The pointer must be [valid] for reads for `ptr.len() * size_of::<T>()` many bytes, - /// and it must be properly aligned. This means in particular: - /// - /// * The entire memory range of this slice must be contained within a single [allocation]! - /// Slices can never span across multiple allocations. - /// - /// * The pointer must be aligned even for zero-length slices. One - /// reason for this is that enum layout optimizations may rely on references - /// (including slices of any length) being aligned and non-null to distinguish - /// them from other data. You can obtain a pointer that is usable as `data` - /// for zero-length slices using [`NonNull::dangling()`]. - /// - /// * The total size `ptr.len() * size_of::<T>()` of the slice must be no larger than `isize::MAX`. - /// See the safety documentation of [`pointer::offset`]. - /// - /// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is - /// arbitrarily chosen and does not necessarily reflect the actual lifetime of the data. - /// In particular, while this reference exists, the memory the pointer points to must - /// not get mutated (except inside `UnsafeCell`). - /// - /// This applies even if the result of this method is unused! - /// - /// See also [`slice::from_raw_parts`][]. - /// - /// [valid]: crate::ptr#safety - /// [allocation]: crate::ptr#allocation - /// - /// # Panics during const evaluation - /// - /// This method will panic during const evaluation if the pointer cannot be - /// determined to be null or not. See [`is_null`] for more information. - /// - /// [`is_null`]: #method.is_null + #[doc = include_str!("docs/as_uninit_slice.md")] #[inline] #[unstable(feature = "ptr_as_uninit", issue = "75402")] pub const unsafe fn as_uninit_slice<'a>(self) -> Option<&'a [MaybeUninit<T>]> { diff --git a/library/core/src/ptr/docs/as_uninit_slice.md b/library/core/src/ptr/docs/as_uninit_slice.md new file mode 100644 index 00000000000..c80c0405883 --- /dev/null +++ b/library/core/src/ptr/docs/as_uninit_slice.md @@ -0,0 +1,44 @@ +Returns `None` if the pointer is null, or else returns a shared slice to +the value wrapped in `Some`. In contrast to [`as_ref`], this does not require +that the value has to be initialized. + +[`as_ref`]: #method.as_ref + +# Safety + +When calling this method, you have to ensure that *either* the pointer is null *or* +all of the following is true: + +* The pointer must be [valid] for reads for `ptr.len() * size_of::<T>()` many bytes, +and it must be properly aligned. This means in particular: + +* The entire memory range of this slice must be contained within a single [allocation]! +Slices can never span across multiple allocations. + +* The pointer must be aligned even for zero-length slices. One +reason for this is that enum layout optimizations may rely on references +(including slices of any length) being aligned and non-null to distinguish +them from other data. You can obtain a pointer that is usable as `data` +for zero-length slices using [`NonNull::dangling()`]. + +* The total size `ptr.len() * size_of::<T>()` of the slice must be no larger than `isize::MAX`. +See the safety documentation of [`pointer::offset`]. + +* You must enforce Rust's aliasing rules, since the returned lifetime `'a` is +arbitrarily chosen and does not necessarily reflect the actual lifetime of the data. +In particular, while this reference exists, the memory the pointer points to must +not get mutated (except inside `UnsafeCell`). + +This applies even if the result of this method is unused! + +See also [`slice::from_raw_parts`][]. + +[valid]: crate::ptr#safety +[allocation]: crate::ptr#allocation + +# Panics during const evaluation + +This method will panic during const evaluation if the pointer cannot be +determined to be null or not. See [`is_null`] for more information. + +[`is_null`]: #method.is_null diff --git a/library/core/src/ptr/docs/is_null.md b/library/core/src/ptr/docs/is_null.md new file mode 100644 index 00000000000..7368ab9b576 --- /dev/null +++ b/library/core/src/ptr/docs/is_null.md @@ -0,0 +1,18 @@ +Returns `true` if the pointer is null. + +Note that unsized types have many possible null pointers, as only the +raw data pointer is considered, not their length, vtable, etc. +Therefore, two pointers that are null may still not compare equal to +each other. + +# Panics during const evaluation + +If this method is used during const evaluation, and `self` is a pointer +that is offset beyond the bounds of the memory it initially pointed to, +then there might not be enough information to determine whether the +pointer is null. This is because the absolute address in memory is not +known at compile time. If the nullness of the pointer cannot be +determined, this method will panic. + +In-bounds pointers are never null, so the method will never panic for +such pointers. diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 968f033bf59..efe1031b79c 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -5,24 +5,7 @@ use crate::mem::{self, SizedTypeProperties}; use crate::slice::{self, SliceIndex}; impl<T: ?Sized> *mut T { - /// Returns `true` if the pointer is null. - /// - /// Note that unsized types have many possible null pointers, as only the - /// raw data pointer is considered, not their length, vtable, etc. - /// Therefore, two pointers that are null may still not compare equal to - /// each other. - /// - /// # Panics during const evaluation - /// - /// If this method is used during const evaluation, and `self` is a pointer - /// that is offset beyond the bounds of the memory it initially pointed to, - /// then there might not be enough information to determine whether the - /// pointer is null. This is because the absolute address in memory is not - /// known at compile time. If the nullness of the pointer cannot be - /// determined, this method will panic. - /// - /// In-bounds pointers are never null, so the method will never panic for - /// such pointers. + #[doc = include_str!("docs/is_null.md")] /// /// # Examples /// @@ -1906,53 +1889,10 @@ impl<T> *mut [T] { unsafe { index.get_unchecked_mut(self) } } - /// Returns `None` if the pointer is null, or else returns a shared slice to - /// the value wrapped in `Some`. In contrast to [`as_ref`], this does not require - /// that the value has to be initialized. - /// - /// For the mutable counterpart see [`as_uninit_slice_mut`]. - /// - /// [`as_ref`]: pointer#method.as_ref-1 - /// [`as_uninit_slice_mut`]: #method.as_uninit_slice_mut - /// - /// # Safety - /// - /// When calling this method, you have to ensure that *either* the pointer is null *or* - /// all of the following is true: - /// - /// * The pointer must be [valid] for reads for `ptr.len() * size_of::<T>()` many bytes, - /// and it must be properly aligned. This means in particular: - /// - /// * The entire memory range of this slice must be contained within a single [allocation]! - /// Slices can never span across multiple allocations. - /// - /// * The pointer must be aligned even for zero-length slices. One - /// reason for this is that enum layout optimizations may rely on references - /// (including slices of any length) being aligned and non-null to distinguish - /// them from other data. You can obtain a pointer that is usable as `data` - /// for zero-length slices using [`NonNull::dangling()`]. - /// - /// * The total size `ptr.len() * size_of::<T>()` of the slice must be no larger than `isize::MAX`. - /// See the safety documentation of [`pointer::offset`]. - /// - /// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is - /// arbitrarily chosen and does not necessarily reflect the actual lifetime of the data. - /// In particular, while this reference exists, the memory the pointer points to must - /// not get mutated (except inside `UnsafeCell`). - /// - /// This applies even if the result of this method is unused! - /// - /// See also [`slice::from_raw_parts`][]. - /// - /// [valid]: crate::ptr#safety - /// [allocation]: crate::ptr#allocation + #[doc = include_str!("docs/as_uninit_slice.md")] /// - /// # Panics during const evaluation - /// - /// This method will panic during const evaluation if the pointer cannot be - /// determined to be null or not. See [`is_null`] for more information. - /// - /// [`is_null`]: #method.is_null-1 + /// # See Also + /// For the mutable counterpart see [`as_uninit_slice_mut`](pointer::as_uninit_slice_mut). #[inline] #[unstable(feature = "ptr_as_uninit", issue = "75402")] pub const unsafe fn as_uninit_slice<'a>(self) -> Option<&'a [MaybeUninit<T>]> { diff --git a/library/core/src/result.rs b/library/core/src/result.rs index 23e32c2e0f0..3a84ea66ad4 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -2051,7 +2051,7 @@ impl<A, E, V: FromIterator<A>> FromIterator<Result<A, E>> for Result<V, E> { } } -#[unstable(feature = "try_trait_v2", issue = "84277")] +#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] impl<T, E> ops::Try for Result<T, E> { type Output = T; type Residual = Result<convert::Infallible, E>; @@ -2070,7 +2070,7 @@ impl<T, E> ops::Try for Result<T, E> { } } -#[unstable(feature = "try_trait_v2", issue = "84277")] +#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] impl<T, E, F: From<E>> ops::FromResidual<Result<convert::Infallible, E>> for Result<T, F> { #[inline] #[track_caller] diff --git a/library/core/src/slice/ascii.rs b/library/core/src/slice/ascii.rs index d91f8bba548..b4d9a1b1ca4 100644 --- a/library/core/src/slice/ascii.rs +++ b/library/core/src/slice/ascii.rs @@ -128,7 +128,6 @@ impl [u8] { /// # Examples /// /// ``` - /// /// let s = b"0\t\r\n'\"\\\x9d"; /// let escaped = s.escape_ascii().to_string(); /// assert_eq!(escaped, "0\\t\\r\\n\\'\\\"\\\\\\x9d"); diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index 85a5e89a49e..6def6ae8530 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -3376,6 +3376,13 @@ where #[stable(feature = "slice_group_by", since = "1.77.0")] impl<'a, T: 'a, P> FusedIterator for ChunkBy<'a, T, P> where P: FnMut(&T, &T) -> bool {} +#[stable(feature = "slice_group_by_clone", since = "CURRENT_RUSTC_VERSION")] +impl<'a, T: 'a, P: Clone> Clone for ChunkBy<'a, T, P> { + fn clone(&self) -> Self { + Self { slice: self.slice, predicate: self.predicate.clone() } + } +} + #[stable(feature = "slice_group_by", since = "1.77.0")] impl<'a, T: 'a + fmt::Debug, P> fmt::Debug for ChunkBy<'a, T, P> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 4f7e1440880..c26bbad087a 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -21,6 +21,7 @@ use crate::{fmt, hint, ptr, range, slice}; issue = "none", reason = "exposed from core to be reused in std; use the memchr crate" )] +#[doc(hidden)] /// Pure Rust memchr implementation, taken from rust-memchr pub mod memchr; diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index 4f9f2936564..04c8d1473b0 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -891,6 +891,19 @@ impl AtomicBool { /// Err(false)); /// assert_eq!(some_bool.load(Ordering::Relaxed), false); /// ``` + /// + /// # Considerations + /// + /// `compare_exchange` is a [compare-and-swap operation] and thus exhibits the usual downsides + /// of CAS operations. In particular, a load of the value followed by a successful + /// `compare_exchange` with the previous load *does not ensure* that other threads have not + /// changed the value in the interim. This is usually important when the *equality* check in + /// the `compare_exchange` is being used to check the *identity* of a value, but equality + /// does not necessarily imply identity. In this case, `compare_exchange` can lead to the + /// [ABA problem]. + /// + /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem + /// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap #[inline] #[stable(feature = "extended_compare_and_swap", since = "1.10.0")] #[doc(alias = "compare_and_swap")] @@ -973,6 +986,19 @@ impl AtomicBool { /// } /// } /// ``` + /// + /// # Considerations + /// + /// `compare_exchange` is a [compare-and-swap operation] and thus exhibits the usual downsides + /// of CAS operations. In particular, a load of the value followed by a successful + /// `compare_exchange` with the previous load *does not ensure* that other threads have not + /// changed the value in the interim. This is usually important when the *equality* check in + /// the `compare_exchange` is being used to check the *identity* of a value, but equality + /// does not necessarily imply identity. In this case, `compare_exchange` can lead to the + /// [ABA problem]. + /// + /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem + /// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap #[inline] #[stable(feature = "extended_compare_and_swap", since = "1.10.0")] #[doc(alias = "compare_and_swap")] @@ -1271,11 +1297,14 @@ impl AtomicBool { /// /// # Considerations /// - /// This method is not magic; it is not provided by the hardware. - /// It is implemented in terms of [`AtomicBool::compare_exchange_weak`], and suffers from the same drawbacks. - /// In particular, this method will not circumvent the [ABA Problem]. + /// This method is not magic; it is not provided by the hardware, and does not act like a + /// critical section or mutex. + /// + /// It is implemented on top of an atomic [compare-and-swap operation], and thus is subject to + /// the usual drawbacks of CAS operations. In particular, be careful of the [ABA problem]. /// /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem + /// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap /// /// # Examples /// @@ -1338,11 +1367,14 @@ impl AtomicBool { /// /// # Considerations /// - /// This method is not magic; it is not provided by the hardware. - /// It is implemented in terms of [`AtomicBool::compare_exchange_weak`], and suffers from the same drawbacks. - /// In particular, this method will not circumvent the [ABA Problem]. + /// This method is not magic; it is not provided by the hardware, and does not act like a + /// critical section or mutex. + /// + /// It is implemented on top of an atomic [compare-and-swap operation], and thus is subject to + /// the usual drawbacks of CAS operations. In particular, be careful of the [ABA problem]. /// /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem + /// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap /// /// # Examples /// @@ -1393,11 +1425,14 @@ impl AtomicBool { /// /// # Considerations /// - /// This method is not magic; it is not provided by the hardware. - /// It is implemented in terms of [`AtomicBool::compare_exchange_weak`], and suffers from the same drawbacks. - /// In particular, this method will not circumvent the [ABA Problem]. + /// This method is not magic; it is not provided by the hardware, and does not act like a + /// critical section or mutex. + /// + /// It is implemented on top of an atomic [compare-and-swap operation], and thus is subject to + /// the usual drawbacks of CAS operations. In particular, be careful of the [ABA problem]. /// /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem + /// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap /// /// # Examples /// @@ -1825,6 +1860,20 @@ impl<T> AtomicPtr<T> { /// let value = some_ptr.compare_exchange(ptr, other_ptr, /// Ordering::SeqCst, Ordering::Relaxed); /// ``` + /// + /// # Considerations + /// + /// `compare_exchange` is a [compare-and-swap operation] and thus exhibits the usual downsides + /// of CAS operations. In particular, a load of the value followed by a successful + /// `compare_exchange` with the previous load *does not ensure* that other threads have not + /// changed the value in the interim. This is usually important when the *equality* check in + /// the `compare_exchange` is being used to check the *identity* of a value, but equality + /// does not necessarily imply identity. This is a particularly common case for pointers, as + /// a pointer holding the same address does not imply that the same object exists at that + /// address! In this case, `compare_exchange` can lead to the [ABA problem]. + /// + /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem + /// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap #[inline] #[stable(feature = "extended_compare_and_swap", since = "1.10.0")] #[cfg(target_has_atomic = "ptr")] @@ -1874,6 +1923,20 @@ impl<T> AtomicPtr<T> { /// } /// } /// ``` + /// + /// # Considerations + /// + /// `compare_exchange` is a [compare-and-swap operation] and thus exhibits the usual downsides + /// of CAS operations. In particular, a load of the value followed by a successful + /// `compare_exchange` with the previous load *does not ensure* that other threads have not + /// changed the value in the interim. This is usually important when the *equality* check in + /// the `compare_exchange` is being used to check the *identity* of a value, but equality + /// does not necessarily imply identity. This is a particularly common case for pointers, as + /// a pointer holding the same address does not imply that the same object exists at that + /// address! In this case, `compare_exchange` can lead to the [ABA problem]. + /// + /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem + /// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap #[inline] #[stable(feature = "extended_compare_and_swap", since = "1.10.0")] #[cfg(target_has_atomic = "ptr")] @@ -1917,11 +1980,15 @@ impl<T> AtomicPtr<T> { /// /// # Considerations /// - /// This method is not magic; it is not provided by the hardware. - /// It is implemented in terms of [`AtomicPtr::compare_exchange_weak`], and suffers from the same drawbacks. - /// In particular, this method will not circumvent the [ABA Problem]. + /// This method is not magic; it is not provided by the hardware, and does not act like a + /// critical section or mutex. + /// + /// It is implemented on top of an atomic [compare-and-swap operation], and thus is subject to + /// the usual drawbacks of CAS operations. In particular, be careful of the [ABA problem], + /// which is a particularly common pitfall for pointers! /// /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem + /// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap /// /// # Examples /// @@ -1992,11 +2059,15 @@ impl<T> AtomicPtr<T> { /// /// # Considerations /// - /// This method is not magic; it is not provided by the hardware. - /// It is implemented in terms of [`AtomicPtr::compare_exchange_weak`], and suffers from the same drawbacks. - /// In particular, this method will not circumvent the [ABA Problem]. + /// This method is not magic; it is not provided by the hardware, and does not act like a + /// critical section or mutex. + /// + /// It is implemented on top of an atomic [compare-and-swap operation], and thus is subject to + /// the usual drawbacks of CAS operations. In particular, be careful of the [ABA problem], + /// which is a particularly common pitfall for pointers! /// /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem + /// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap /// /// # Examples /// @@ -2057,11 +2128,15 @@ impl<T> AtomicPtr<T> { /// /// # Considerations /// - /// This method is not magic; it is not provided by the hardware. - /// It is implemented in terms of [`AtomicPtr::compare_exchange_weak`], and suffers from the same drawbacks. - /// In particular, this method will not circumvent the [ABA Problem]. + /// This method is not magic; it is not provided by the hardware, and does not act like a + /// critical section or mutex. + /// + /// It is implemented on top of an atomic [compare-and-swap operation], and thus is subject to + /// the usual drawbacks of CAS operations. In particular, be careful of the [ABA problem], + /// which is a particularly common pitfall for pointers! /// /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem + /// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap /// /// # Examples /// @@ -2967,6 +3042,20 @@ macro_rules! atomic_int { /// Err(10)); /// assert_eq!(some_var.load(Ordering::Relaxed), 10); /// ``` + /// + /// # Considerations + /// + /// `compare_exchange` is a [compare-and-swap operation] and thus exhibits the usual downsides + /// of CAS operations. In particular, a load of the value followed by a successful + /// `compare_exchange` with the previous load *does not ensure* that other threads have not + /// changed the value in the interim! This is usually important when the *equality* check in + /// the `compare_exchange` is being used to check the *identity* of a value, but equality + /// does not necessarily imply identity. This is a particularly common case for pointers, as + /// a pointer holding the same address does not imply that the same object exists at that + /// address! In this case, `compare_exchange` can lead to the [ABA problem]. + /// + /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem + /// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap #[inline] #[$stable_cxchg] #[$cfg_cas] @@ -3016,6 +3105,20 @@ macro_rules! atomic_int { /// } /// } /// ``` + /// + /// # Considerations + /// + /// `compare_exchange` is a [compare-and-swap operation] and thus exhibits the usual downsides + /// of CAS operations. In particular, a load of the value followed by a successful + /// `compare_exchange` with the previous load *does not ensure* that other threads have not + /// changed the value in the interim. This is usually important when the *equality* check in + /// the `compare_exchange` is being used to check the *identity* of a value, but equality + /// does not necessarily imply identity. This is a particularly common case for pointers, as + /// a pointer holding the same address does not imply that the same object exists at that + /// address! In this case, `compare_exchange` can lead to the [ABA problem]. + /// + /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem + /// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap #[inline] #[$stable_cxchg] #[$cfg_cas] @@ -3246,13 +3349,16 @@ macro_rules! atomic_int { /// /// # Considerations /// - /// This method is not magic; it is not provided by the hardware. - /// It is implemented in terms of - #[doc = concat!("[`", stringify!($atomic_type), "::compare_exchange_weak`],")] - /// and suffers from the same drawbacks. - /// In particular, this method will not circumvent the [ABA Problem]. + /// This method is not magic; it is not provided by the hardware, and does not act like a + /// critical section or mutex. + /// + /// It is implemented on top of an atomic [compare-and-swap operation], and thus is subject to + /// the usual drawbacks of CAS operations. In particular, be careful of the [ABA problem] + /// if this atomic integer is an index or more generally if knowledge of only the *bitwise value* + /// of the atomic is not in and of itself sufficient to ensure any required preconditions. /// /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem + /// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap /// /// # Examples /// @@ -3309,13 +3415,16 @@ macro_rules! atomic_int { /// /// # Considerations /// - /// This method is not magic; it is not provided by the hardware. - /// It is implemented in terms of - #[doc = concat!("[`", stringify!($atomic_type), "::compare_exchange_weak`],")] - /// and suffers from the same drawbacks. - /// In particular, this method will not circumvent the [ABA Problem]. + /// This method is not magic; it is not provided by the hardware, and does not act like a + /// critical section or mutex. + /// + /// It is implemented on top of an atomic [compare-and-swap operation], and thus is subject to + /// the usual drawbacks of CAS operations. In particular, be careful of the [ABA problem] + /// if this atomic integer is an index or more generally if knowledge of only the *bitwise value* + /// of the atomic is not in and of itself sufficient to ensure any required preconditions. /// /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem + /// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap /// /// # Examples /// @@ -3367,13 +3476,17 @@ macro_rules! atomic_int { /// /// # Considerations /// - /// This method is not magic; it is not provided by the hardware. - /// It is implemented in terms of - #[doc = concat!("[`", stringify!($atomic_type), "::compare_exchange_weak`],")] - /// and suffers from the same drawbacks. - /// In particular, this method will not circumvent the [ABA Problem]. + /// [CAS operation]: https://en.wikipedia.org/wiki/Compare-and-swap + /// This method is not magic; it is not provided by the hardware, and does not act like a + /// critical section or mutex. + /// + /// It is implemented on top of an atomic [compare-and-swap operation], and thus is subject to + /// the usual drawbacks of CAS operations. In particular, be careful of the [ABA problem] + /// if this atomic integer is an index or more generally if knowledge of only the *bitwise value* + /// of the atomic is not in and of itself sufficient to ensure any required preconditions. /// /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem + /// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap /// /// # Examples /// diff --git a/library/core/src/task/poll.rs b/library/core/src/task/poll.rs index 6aab22177ab..ca668361ef6 100644 --- a/library/core/src/task/poll.rs +++ b/library/core/src/task/poll.rs @@ -229,7 +229,7 @@ impl<T> From<T> for Poll<T> { } } -#[unstable(feature = "try_trait_v2", issue = "84277")] +#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] impl<T, E> ops::Try for Poll<Result<T, E>> { type Output = Poll<T>; type Residual = Result<convert::Infallible, E>; @@ -249,7 +249,7 @@ impl<T, E> ops::Try for Poll<Result<T, E>> { } } -#[unstable(feature = "try_trait_v2", issue = "84277")] +#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] impl<T, E, F: From<E>> ops::FromResidual<Result<convert::Infallible, E>> for Poll<Result<T, F>> { #[inline] fn from_residual(x: Result<convert::Infallible, E>) -> Self { @@ -259,7 +259,7 @@ impl<T, E, F: From<E>> ops::FromResidual<Result<convert::Infallible, E>> for Pol } } -#[unstable(feature = "try_trait_v2", issue = "84277")] +#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] impl<T, E> ops::Try for Poll<Option<Result<T, E>>> { type Output = Poll<Option<T>>; type Residual = Result<convert::Infallible, E>; @@ -280,7 +280,7 @@ impl<T, E> ops::Try for Poll<Option<Result<T, E>>> { } } -#[unstable(feature = "try_trait_v2", issue = "84277")] +#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")] impl<T, E, F: From<E>> ops::FromResidual<Result<convert::Infallible, E>> for Poll<Option<Result<T, F>>> { diff --git a/library/core/src/task/wake.rs b/library/core/src/task/wake.rs index 9b8fefe42af..bb7efe582f7 100644 --- a/library/core/src/task/wake.rs +++ b/library/core/src/task/wake.rs @@ -104,6 +104,7 @@ impl RawWaker { /// synchronization. This is because [`LocalWaker`] is not thread safe itself, so it cannot /// be sent across threads. #[stable(feature = "futures_api", since = "1.36.0")] +#[allow(unpredictable_function_pointer_comparisons)] #[derive(PartialEq, Copy, Clone, Debug)] pub struct RawWakerVTable { /// This function will be called when the [`RawWaker`] gets cloned, e.g. when diff --git a/library/coretests/tests/ffi/cstr.rs b/library/coretests/tests/ffi/cstr.rs index dc34240cd99..7d669cc1c3f 100644 --- a/library/coretests/tests/ffi/cstr.rs +++ b/library/coretests/tests/ffi/cstr.rs @@ -17,7 +17,7 @@ fn compares_as_u8s() { #[test] fn debug() { let s = c"abc\x01\x02\n\xE2\x80\xA6\xFF"; - assert_eq!(format!("{s:?}"), r#""abc\x01\x02\n\xe2\x80\xa6\xff""#); + assert_eq!(format!("{s:?}"), r#""abc\x01\x02\n…\xff""#); } #[test] diff --git a/library/coretests/tests/fmt/num.rs b/library/coretests/tests/fmt/num.rs index bc387a46ea7..4c145b484dd 100644 --- a/library/coretests/tests/fmt/num.rs +++ b/library/coretests/tests/fmt/num.rs @@ -1,5 +1,29 @@ +use std::mem::size_of; + +#[test] +fn test_format_int_zero() { + assert_eq!(format!("{}", 0), "0"); + assert_eq!(format!("{:?}", 0), "0"); + assert_eq!(format!("{:b}", 0), "0"); + assert_eq!(format!("{:o}", 0), "0"); + assert_eq!(format!("{:x}", 0), "0"); + assert_eq!(format!("{:X}", 0), "0"); + assert_eq!(format!("{:e}", 0), "0e0"); + assert_eq!(format!("{:E}", 0), "0E0"); + + // again, with unsigned + assert_eq!(format!("{}", 0u32), "0"); + assert_eq!(format!("{:?}", 0u32), "0"); + assert_eq!(format!("{:b}", 0u32), "0"); + assert_eq!(format!("{:o}", 0u32), "0"); + assert_eq!(format!("{:x}", 0u32), "0"); + assert_eq!(format!("{:X}", 0u32), "0"); + assert_eq!(format!("{:e}", 0u32), "0e0"); + assert_eq!(format!("{:E}", 0u32), "0E0"); +} + #[test] -fn test_format_int() { +fn test_format_int_one() { // Formatting integers should select the right implementation based off // the type of the argument. Also, hex/octal/binary should be defined // for integers, but they shouldn't emit the negative sign. @@ -8,87 +32,157 @@ fn test_format_int() { assert_eq!(format!("{}", 1i16), "1"); assert_eq!(format!("{}", 1i32), "1"); assert_eq!(format!("{}", 1i64), "1"); - assert_eq!(format!("{}", -1isize), "-1"); - assert_eq!(format!("{}", -1i8), "-1"); - assert_eq!(format!("{}", -1i16), "-1"); - assert_eq!(format!("{}", -1i32), "-1"); - assert_eq!(format!("{}", -1i64), "-1"); + assert_eq!(format!("{}", 1i128), "1"); assert_eq!(format!("{:?}", 1isize), "1"); assert_eq!(format!("{:?}", 1i8), "1"); assert_eq!(format!("{:?}", 1i16), "1"); assert_eq!(format!("{:?}", 1i32), "1"); assert_eq!(format!("{:?}", 1i64), "1"); + assert_eq!(format!("{:?}", 1i128), "1"); assert_eq!(format!("{:b}", 1isize), "1"); assert_eq!(format!("{:b}", 1i8), "1"); assert_eq!(format!("{:b}", 1i16), "1"); assert_eq!(format!("{:b}", 1i32), "1"); assert_eq!(format!("{:b}", 1i64), "1"); + assert_eq!(format!("{:b}", 1i128), "1"); assert_eq!(format!("{:x}", 1isize), "1"); assert_eq!(format!("{:x}", 1i8), "1"); assert_eq!(format!("{:x}", 1i16), "1"); assert_eq!(format!("{:x}", 1i32), "1"); assert_eq!(format!("{:x}", 1i64), "1"); + assert_eq!(format!("{:x}", 1i128), "1"); assert_eq!(format!("{:X}", 1isize), "1"); assert_eq!(format!("{:X}", 1i8), "1"); assert_eq!(format!("{:X}", 1i16), "1"); assert_eq!(format!("{:X}", 1i32), "1"); assert_eq!(format!("{:X}", 1i64), "1"); + assert_eq!(format!("{:X}", 1i128), "1"); assert_eq!(format!("{:o}", 1isize), "1"); assert_eq!(format!("{:o}", 1i8), "1"); assert_eq!(format!("{:o}", 1i16), "1"); assert_eq!(format!("{:o}", 1i32), "1"); assert_eq!(format!("{:o}", 1i64), "1"); + assert_eq!(format!("{:o}", 1i128), "1"); assert_eq!(format!("{:e}", 1isize), "1e0"); assert_eq!(format!("{:e}", 1i8), "1e0"); assert_eq!(format!("{:e}", 1i16), "1e0"); assert_eq!(format!("{:e}", 1i32), "1e0"); assert_eq!(format!("{:e}", 1i64), "1e0"); + assert_eq!(format!("{:e}", 1i128), "1e0"); assert_eq!(format!("{:E}", 1isize), "1E0"); assert_eq!(format!("{:E}", 1i8), "1E0"); assert_eq!(format!("{:E}", 1i16), "1E0"); assert_eq!(format!("{:E}", 1i32), "1E0"); assert_eq!(format!("{:E}", 1i64), "1E0"); + assert_eq!(format!("{:E}", 1i128), "1E0"); + // again, with unsigned assert_eq!(format!("{}", 1usize), "1"); assert_eq!(format!("{}", 1u8), "1"); assert_eq!(format!("{}", 1u16), "1"); assert_eq!(format!("{}", 1u32), "1"); assert_eq!(format!("{}", 1u64), "1"); + assert_eq!(format!("{}", 1u128), "1"); assert_eq!(format!("{:?}", 1usize), "1"); assert_eq!(format!("{:?}", 1u8), "1"); assert_eq!(format!("{:?}", 1u16), "1"); assert_eq!(format!("{:?}", 1u32), "1"); assert_eq!(format!("{:?}", 1u64), "1"); + assert_eq!(format!("{:?}", 1u128), "1"); assert_eq!(format!("{:b}", 1usize), "1"); assert_eq!(format!("{:b}", 1u8), "1"); assert_eq!(format!("{:b}", 1u16), "1"); assert_eq!(format!("{:b}", 1u32), "1"); assert_eq!(format!("{:b}", 1u64), "1"); + assert_eq!(format!("{:b}", 1u128), "1"); assert_eq!(format!("{:x}", 1usize), "1"); assert_eq!(format!("{:x}", 1u8), "1"); assert_eq!(format!("{:x}", 1u16), "1"); assert_eq!(format!("{:x}", 1u32), "1"); assert_eq!(format!("{:x}", 1u64), "1"); + assert_eq!(format!("{:x}", 1u128), "1"); assert_eq!(format!("{:X}", 1usize), "1"); assert_eq!(format!("{:X}", 1u8), "1"); assert_eq!(format!("{:X}", 1u16), "1"); assert_eq!(format!("{:X}", 1u32), "1"); assert_eq!(format!("{:X}", 1u64), "1"); + assert_eq!(format!("{:X}", 1u128), "1"); assert_eq!(format!("{:o}", 1usize), "1"); assert_eq!(format!("{:o}", 1u8), "1"); assert_eq!(format!("{:o}", 1u16), "1"); assert_eq!(format!("{:o}", 1u32), "1"); assert_eq!(format!("{:o}", 1u64), "1"); + assert_eq!(format!("{:o}", 1u128), "1"); assert_eq!(format!("{:e}", 1u8), "1e0"); assert_eq!(format!("{:e}", 1u16), "1e0"); assert_eq!(format!("{:e}", 1u32), "1e0"); assert_eq!(format!("{:e}", 1u64), "1e0"); + assert_eq!(format!("{:e}", 1u128), "1e0"); assert_eq!(format!("{:E}", 1u8), "1E0"); assert_eq!(format!("{:E}", 1u16), "1E0"); assert_eq!(format!("{:E}", 1u32), "1E0"); assert_eq!(format!("{:E}", 1u64), "1E0"); + assert_eq!(format!("{:E}", 1u128), "1E0"); - // Test a larger number + // again, with negative + assert_eq!(format!("{}", -1isize), "-1"); + assert_eq!(format!("{}", -1i8), "-1"); + assert_eq!(format!("{}", -1i16), "-1"); + assert_eq!(format!("{}", -1i32), "-1"); + assert_eq!(format!("{}", -1i64), "-1"); + assert_eq!(format!("{}", -1i128), "-1"); + assert_eq!(format!("{:?}", -1isize), "-1"); + assert_eq!(format!("{:?}", -1i8), "-1"); + assert_eq!(format!("{:?}", -1i16), "-1"); + assert_eq!(format!("{:?}", -1i32), "-1"); + assert_eq!(format!("{:?}", -1i64), "-1"); + assert_eq!(format!("{:?}", -1i128), "-1"); + assert_eq!(format!("{:b}", -1isize), "1".repeat(size_of::<isize>() * 8)); + assert_eq!(format!("{:b}", -1i8), "11111111"); + assert_eq!(format!("{:b}", -1i16), "1111111111111111"); + assert_eq!(format!("{:b}", -1i32), "11111111111111111111111111111111"); + assert_eq!( + format!("{:b}", -1i64), + "1111111111111111111111111111111111111111111111111111111111111111" + ); + assert_eq!( + format!("{:b}", -1i128), + "11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111" + ); + assert_eq!(format!("{:x}", -1isize), "ff".repeat(size_of::<isize>())); + assert_eq!(format!("{:x}", -1i8), "ff"); + assert_eq!(format!("{:x}", -1i16), "ffff"); + assert_eq!(format!("{:x}", -1i32), "ffffffff"); + assert_eq!(format!("{:x}", -1i64), "ffffffffffffffff"); + assert_eq!(format!("{:x}", -1i128), "ffffffffffffffffffffffffffffffff"); + assert_eq!(format!("{:X}", -1isize), "FF".repeat(size_of::<isize>())); + assert_eq!(format!("{:X}", -1i8), "FF"); + assert_eq!(format!("{:X}", -1i16), "FFFF"); + assert_eq!(format!("{:X}", -1i32), "FFFFFFFF"); + assert_eq!(format!("{:X}", -1i64), "FFFFFFFFFFFFFFFF"); + assert_eq!(format!("{:X}", -1i128), "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"); + // octal test for isize omitted + assert_eq!(format!("{:o}", -1i8), "377"); + assert_eq!(format!("{:o}", -1i16), "177777"); + assert_eq!(format!("{:o}", -1i32), "37777777777"); + assert_eq!(format!("{:o}", -1i64), "1777777777777777777777"); + assert_eq!(format!("{:o}", -1i128), "3777777777777777777777777777777777777777777"); + assert_eq!(format!("{:e}", -1isize), "-1e0"); + assert_eq!(format!("{:e}", -1i8), "-1e0"); + assert_eq!(format!("{:e}", -1i16), "-1e0"); + assert_eq!(format!("{:e}", -1i32), "-1e0"); + assert_eq!(format!("{:e}", -1i64), "-1e0"); + assert_eq!(format!("{:e}", -1i128), "-1e0"); + assert_eq!(format!("{:E}", -1isize), "-1E0"); + assert_eq!(format!("{:E}", -1i8), "-1E0"); + assert_eq!(format!("{:E}", -1i16), "-1E0"); + assert_eq!(format!("{:E}", -1i32), "-1E0"); + assert_eq!(format!("{:E}", -1i64), "-1E0"); + assert_eq!(format!("{:E}", -1i128), "-1E0"); +} + +#[test] +fn test_format_int_misc() { assert_eq!(format!("{:b}", 55), "110111"); assert_eq!(format!("{:o}", 55), "67"); assert_eq!(format!("{}", 55), "55"); @@ -103,6 +197,26 @@ fn test_format_int() { } #[test] +fn test_format_int_limits() { + assert_eq!(format!("{}", i8::MIN), "-128"); + assert_eq!(format!("{}", i8::MAX), "127"); + assert_eq!(format!("{}", i16::MIN), "-32768"); + assert_eq!(format!("{}", i16::MAX), "32767"); + assert_eq!(format!("{}", i32::MIN), "-2147483648"); + assert_eq!(format!("{}", i32::MAX), "2147483647"); + assert_eq!(format!("{}", i64::MIN), "-9223372036854775808"); + assert_eq!(format!("{}", i64::MAX), "9223372036854775807"); + assert_eq!(format!("{}", i128::MIN), "-170141183460469231731687303715884105728"); + assert_eq!(format!("{}", i128::MAX), "170141183460469231731687303715884105727"); + + assert_eq!(format!("{}", u8::MAX), "255"); + assert_eq!(format!("{}", u16::MAX), "65535"); + assert_eq!(format!("{}", u32::MAX), "4294967295"); + assert_eq!(format!("{}", u64::MAX), "18446744073709551615"); + assert_eq!(format!("{}", u128::MAX), "340282366920938463463374607431768211455"); +} + +#[test] fn test_format_int_exp_limits() { assert_eq!(format!("{:e}", i8::MIN), "-1.28e2"); assert_eq!(format!("{:e}", i8::MAX), "1.27e2"); @@ -168,27 +282,6 @@ fn test_format_int_exp_precision() { } #[test] -fn test_format_int_zero() { - assert_eq!(format!("{}", 0), "0"); - assert_eq!(format!("{:?}", 0), "0"); - assert_eq!(format!("{:b}", 0), "0"); - assert_eq!(format!("{:o}", 0), "0"); - assert_eq!(format!("{:x}", 0), "0"); - assert_eq!(format!("{:X}", 0), "0"); - assert_eq!(format!("{:e}", 0), "0e0"); - assert_eq!(format!("{:E}", 0), "0E0"); - - assert_eq!(format!("{}", 0u32), "0"); - assert_eq!(format!("{:?}", 0u32), "0"); - assert_eq!(format!("{:b}", 0u32), "0"); - assert_eq!(format!("{:o}", 0u32), "0"); - assert_eq!(format!("{:x}", 0u32), "0"); - assert_eq!(format!("{:X}", 0u32), "0"); - assert_eq!(format!("{:e}", 0u32), "0e0"); - assert_eq!(format!("{:E}", 0u32), "0E0"); -} - -#[test] fn test_format_int_flags() { assert_eq!(format!("{:3}", 1), " 1"); assert_eq!(format!("{:>3}", 1), " 1"); @@ -226,14 +319,6 @@ fn test_format_int_sign_padding() { } #[test] -fn test_format_int_twos_complement() { - assert_eq!(format!("{}", i8::MIN), "-128"); - assert_eq!(format!("{}", i16::MIN), "-32768"); - assert_eq!(format!("{}", i32::MIN), "-2147483648"); - assert_eq!(format!("{}", i64::MIN), "-9223372036854775808"); -} - -#[test] fn test_format_debug_hex() { assert_eq!(format!("{:02x?}", b"Foo\0"), "[46, 6f, 6f, 00]"); assert_eq!(format!("{:02X?}", b"Foo\0"), "[46, 6F, 6F, 00]"); diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index 92b920dd775..5449132413b 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -94,6 +94,7 @@ #![feature(try_blocks)] #![feature(try_find)] #![feature(try_trait_v2)] +#![feature(uint_bit_width)] #![feature(unsize)] #![feature(unwrap_infallible)] // tidy-alphabetical-end diff --git a/library/coretests/tests/num/uint_macros.rs b/library/coretests/tests/num/uint_macros.rs index 6f3d160964f..7e02027bdd6 100644 --- a/library/coretests/tests/num/uint_macros.rs +++ b/library/coretests/tests/num/uint_macros.rs @@ -72,6 +72,14 @@ macro_rules! uint_module { assert_eq_const_safe!(u32: X.trailing_ones(), 0); } + fn test_bit_width() { + assert_eq_const_safe!(u32: A.bit_width(), 6); + assert_eq_const_safe!(u32: B.bit_width(), 6); + assert_eq_const_safe!(u32: C.bit_width(), 7); + assert_eq_const_safe!(u32: _0.bit_width(), 0); + assert_eq_const_safe!(u32: _1.bit_width(), $T::BITS); + } + fn test_rotate() { assert_eq_const_safe!($T: A.rotate_left(6).rotate_right(2).rotate_right(4), A); assert_eq_const_safe!($T: B.rotate_left(3).rotate_left(2).rotate_right(5), B); diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 53d78dcc488..ae7107938f3 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -32,7 +32,7 @@ rustc-demangle = { version = "0.1.24", features = ['rustc-dep-of-std'] } [target.'cfg(not(all(windows, target_env = "msvc", not(target_vendor = "uwp"))))'.dependencies] miniz_oxide = { version = "0.8.0", optional = true, default-features = false } -addr2line = { version = "0.24.0", optional = true, default-features = false } +addr2line = { version = "0.25.0", optional = true, default-features = false } [target.'cfg(not(all(windows, target_env = "msvc")))'.dependencies] libc = { version = "0.2.172", default-features = false, features = [ @@ -40,7 +40,7 @@ libc = { version = "0.2.172", default-features = false, features = [ ], public = true } [target.'cfg(all(not(target_os = "aix"), not(all(windows, target_env = "msvc", not(target_vendor = "uwp")))))'.dependencies] -object = { version = "0.36.0", default-features = false, optional = true, features = [ +object = { version = "0.37.1", default-features = false, optional = true, features = [ 'read_core', 'elf', 'macho', @@ -50,7 +50,7 @@ object = { version = "0.36.0", default-features = false, optional = true, featur ] } [target.'cfg(target_os = "aix")'.dependencies] -object = { version = "0.36.0", default-features = false, optional = true, features = [ +object = { version = "0.37.1", default-features = false, optional = true, features = [ 'read_core', 'xcoff', 'unaligned', diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 20c82b64bcc..a9a24681e7c 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -917,6 +917,19 @@ pub trait Read { /// # } /// ``` /// + /// # Usage Notes + /// + /// `read_to_end` attempts to read a source until EOF, but many sources are continuous streams + /// that do not send EOF. In these cases, `read_to_end` will block indefinitely. Standard input + /// is one such stream which may be finite if piped, but is typically continuous. For example, + /// `cat file | my-rust-program` will correctly terminate with an `EOF` upon closure of cat. + /// Reading user input or running programs that remain open indefinitely will never terminate + /// the stream with `EOF` (e.g. `yes | my-rust-program`). + /// + /// Using `.lines()` with a [`BufReader`] or using [`read`] can provide a better solution + /// + ///[`read`]: Read::read + /// /// [`Vec::try_reserve`]: crate::vec::Vec::try_reserve #[stable(feature = "rust1", since = "1.0.0")] fn read_to_end(&mut self, buf: &mut Vec<u8>) -> Result<usize> { @@ -960,6 +973,19 @@ pub trait Read { /// (See also the [`std::fs::read_to_string`] convenience function for /// reading from a file.) /// + /// # Usage Notes + /// + /// `read_to_string` attempts to read a source until EOF, but many sources are continuous streams + /// that do not send EOF. In these cases, `read_to_string` will block indefinitely. Standard input + /// is one such stream which may be finite if piped, but is typically continuous. For example, + /// `cat file | my-rust-program` will correctly terminate with an `EOF` upon closure of cat. + /// Reading user input or running programs that remain open indefinitely will never terminate + /// the stream with `EOF` (e.g. `yes | my-rust-program`). + /// + /// Using `.lines()` with a [`BufReader`] or using [`read`] can provide a better solution + /// + ///[`read`]: Read::read + /// /// [`std::fs::read_to_string`]: crate::fs::read_to_string #[stable(feature = "rust1", since = "1.0.0")] fn read_to_string(&mut self, buf: &mut String) -> Result<usize> { @@ -1262,6 +1288,20 @@ pub trait Read { /// Ok(()) /// } /// ``` +/// +/// # Usage Notes +/// +/// `read_to_string` attempts to read a source until EOF, but many sources are continuous streams +/// that do not send EOF. In these cases, `read_to_string` will block indefinitely. Standard input +/// is one such stream which may be finite if piped, but is typically continuous. For example, +/// `cat file | my-rust-program` will correctly terminate with an `EOF` upon closure of cat. +/// Reading user input or running programs that remain open indefinitely will never terminate +/// the stream with `EOF` (e.g. `yes | my-rust-program`). +/// +/// Using `.lines()` with a [`BufReader`] or using [`read`] can provide a better solution +/// +///[`read`]: Read::read +/// #[stable(feature = "io_read_to_string", since = "1.65.0")] pub fn read_to_string<R: Read>(mut reader: R) -> Result<String> { let mut buf = String::new(); diff --git a/library/stdarch b/library/stdarch -Subproject 5c1c436524c0bbc8db83577f42f8bea9006a7b7 +Subproject 1b4d15df12079504942d0a3f1030b2039b8a776 diff --git a/library/unwind/Cargo.toml b/library/unwind/Cargo.toml index ad373420a96..f8da09f7193 100644 --- a/library/unwind/Cargo.toml +++ b/library/unwind/Cargo.toml @@ -22,7 +22,7 @@ cfg-if = "1.0" libc = { version = "0.2.140", features = ['rustc-dep-of-std'], default-features = false } [target.'cfg(target_os = "xous")'.dependencies] -unwinding = { version = "0.2.6", features = ['rustc-dep-of-std', 'unwinder', 'fde-custom'], default-features = false } +unwinding = { version = "0.2.7", features = ['rustc-dep-of-std', 'unwinder', 'fde-custom'], default-features = false } [features] diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs index 911a51b0e16..f47873590a1 100644 --- a/src/bootstrap/src/core/build_steps/check.rs +++ b/src/bootstrap/src/core/build_steps/check.rs @@ -89,7 +89,7 @@ impl Step for Std { let stage = self.custom_stage.unwrap_or(builder.top_stage); let target = self.target; - let compiler = builder.compiler(stage, builder.config.build); + let compiler = builder.compiler(stage, builder.config.host_target); if stage == 0 { let mut is_explicitly_called = @@ -244,7 +244,7 @@ impl Step for Rustc { /// the `compiler` targeting the `target` architecture. The artifacts /// created will also be linked into the sysroot directory. fn run(self, builder: &Builder<'_>) { - let compiler = builder.compiler(builder.top_stage, builder.config.build); + let compiler = builder.compiler(builder.top_stage, builder.config.host_target); let target = self.target; if compiler.stage != 0 { @@ -327,7 +327,7 @@ impl Step for CodegenBackend { return; } - let compiler = builder.compiler(builder.top_stage, builder.config.build); + let compiler = builder.compiler(builder.top_stage, builder.config.host_target); let target = self.target; let backend = self.backend; @@ -382,7 +382,7 @@ impl Step for RustAnalyzer { } fn run(self, builder: &Builder<'_>) { - let compiler = builder.compiler(builder.top_stage, builder.config.build); + let compiler = builder.compiler(builder.top_stage, builder.config.host_target); let target = self.target; builder.ensure(Rustc::new(target, builder)); @@ -448,7 +448,7 @@ impl Step for Compiletest { let compiler = builder.compiler( if mode == Mode::ToolBootstrap { 0 } else { builder.top_stage }, - builder.config.build, + builder.config.host_target, ); if mode != Mode::ToolBootstrap { @@ -527,7 +527,7 @@ fn run_tool_check_step( path: &str, ) { let display_name = path.rsplit('/').next().unwrap(); - let compiler = builder.compiler(builder.top_stage, builder.config.build); + let compiler = builder.compiler(builder.top_stage, builder.config.host_target); builder.ensure(Rustc::new(target, builder)); @@ -614,7 +614,7 @@ impl Step for CoverageDump { // 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 host = builder.config.host_target; let target = host; let mode = Mode::ToolBootstrap; diff --git a/src/bootstrap/src/core/build_steps/clippy.rs b/src/bootstrap/src/core/build_steps/clippy.rs index 0652c08ff49..788a3b9601d 100644 --- a/src/bootstrap/src/core/build_steps/clippy.rs +++ b/src/bootstrap/src/core/build_steps/clippy.rs @@ -144,7 +144,7 @@ impl Step for Std { builder.require_submodule("library/stdarch", None); let target = self.target; - let compiler = builder.compiler(builder.top_stage, builder.config.build); + let compiler = builder.compiler(builder.top_stage, builder.config.host_target); let mut cargo = builder::Cargo::new( builder, @@ -204,7 +204,7 @@ impl Step for Rustc { /// This will lint the compiler for a particular stage of the build using /// the `compiler` targeting the `target` architecture. fn run(self, builder: &Builder<'_>) { - let compiler = builder.compiler(builder.top_stage, builder.config.build); + let compiler = builder.compiler(builder.top_stage, builder.config.host_target); let target = self.target; if !builder.download_rustc() { @@ -285,7 +285,7 @@ macro_rules! lint_any { } fn run(self, builder: &Builder<'_>) -> Self::Output { - let compiler = builder.compiler(builder.top_stage, builder.config.build); + let compiler = builder.compiler(builder.top_stage, builder.config.host_target); let target = self.target; if !builder.download_rustc() { diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 5ecce31fe15..560925abba6 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -35,6 +35,7 @@ use crate::utils::helpers::{ }; use crate::{CLang, Compiler, DependencyType, FileType, GitRepo, LLVM_TOOLS, Mode, debug, trace}; +/// Build a standard library for the given `target` using the given `compiler`. #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Std { pub target: TargetSelection, @@ -159,7 +160,7 @@ impl Step for Std { let compiler = if builder.download_rustc() && self.force_recompile { // When there are changes in the library tree with CI-rustc, we want to build // the stageN library and that requires using stageN-1 compiler. - builder.compiler(self.compiler.stage.saturating_sub(1), builder.config.build) + builder.compiler(self.compiler.stage.saturating_sub(1), builder.config.host_target) } else { self.compiler }; @@ -301,7 +302,7 @@ impl Step for Std { builder.ensure(StdLink::from_std( self, - builder.compiler(compiler.stage, builder.config.build), + builder.compiler(compiler.stage, builder.config.host_target), )); } } @@ -960,11 +961,18 @@ fn cp_rustc_component_to_ci_sysroot(builder: &Builder<'_>, sysroot: &Path, conte } } +/// Build rustc using the passed `build_compiler`. +/// +/// - Makes sure that `build_compiler` has a standard library prepared for its host target, +/// so that it can compile build scripts and proc macros when building this `rustc`. +/// - Makes sure that `build_compiler` has a standard library prepared for `target`, +/// so that the built `rustc` can *link to it* and use it at runtime. #[derive(Debug, PartialOrd, Ord, Clone, PartialEq, Eq, Hash)] pub struct Rustc { + /// The target on which rustc will run (its host). pub target: TargetSelection, - /// The **previous** compiler used to compile this compiler. - pub compiler: Compiler, + /// The **previous** compiler used to compile this rustc. + pub build_compiler: Compiler, /// Whether to build a subset of crates, rather than the whole compiler. /// /// This should only be requested by the user, not used within bootstrap itself. @@ -974,8 +982,8 @@ pub struct Rustc { } impl Rustc { - pub fn new(compiler: Compiler, target: TargetSelection) -> Self { - Self { target, compiler, crates: Default::default() } + pub fn new(build_compiler: Compiler, target: TargetSelection) -> Self { + Self { target, build_compiler, crates: Default::default() } } } @@ -1007,7 +1015,7 @@ impl Step for Rustc { fn make_run(run: RunConfig<'_>) { let crates = run.cargo_crates_in_set(); run.builder.ensure(Rustc { - compiler: run + build_compiler: run .builder .compiler(run.builder.top_stage.saturating_sub(1), run.build_triple()), target: run.target, @@ -1018,7 +1026,7 @@ impl Step for Rustc { /// Builds the compiler. /// /// This will build the compiler for a particular stage of the build using - /// the `compiler` targeting the `target` architecture. The artifacts + /// the `build_compiler` targeting the `target` architecture. The artifacts /// created will also be linked into the sysroot directory. #[cfg_attr( feature = "tracing", @@ -1026,54 +1034,58 @@ impl Step for Rustc { level = "debug", name = "Rustc::run", skip_all, - fields(previous_compiler = ?self.compiler, target = ?self.target), + fields(previous_compiler = ?self.build_compiler, target = ?self.target), ), )] fn run(self, builder: &Builder<'_>) -> u32 { - let compiler = self.compiler; + let build_compiler = self.build_compiler; let target = self.target; // NOTE: the ABI of the stage0 compiler is different from the ABI of the downloaded compiler, // so its artifacts can't be reused. - if builder.download_rustc() && compiler.stage != 0 { - trace!(stage = compiler.stage, "`download_rustc` requested"); + if builder.download_rustc() && build_compiler.stage != 0 { + trace!(stage = build_compiler.stage, "`download_rustc` requested"); - let sysroot = builder.ensure(Sysroot { compiler, force_recompile: false }); + let sysroot = + builder.ensure(Sysroot { compiler: build_compiler, force_recompile: false }); cp_rustc_component_to_ci_sysroot( builder, &sysroot, builder.config.ci_rustc_dev_contents(), ); - return compiler.stage; + return build_compiler.stage; } - builder.ensure(Std::new(compiler, target)); + // Build a standard library for `target` using the `build_compiler`. + // This will be the standard library that the rustc which we build *links to*. + builder.ensure(Std::new(build_compiler, target)); - if builder.config.keep_stage.contains(&compiler.stage) { - trace!(stage = compiler.stage, "`keep-stage` requested"); + if builder.config.keep_stage.contains(&build_compiler.stage) { + trace!(stage = build_compiler.stage, "`keep-stage` requested"); builder.info("WARNING: Using a potentially old librustc. This may not behave well."); builder.info("WARNING: Use `--keep-stage-std` if you want to rebuild the compiler when it changes"); - builder.ensure(RustcLink::from_rustc(self, compiler)); + builder.ensure(RustcLink::from_rustc(self, build_compiler)); - return compiler.stage; + return build_compiler.stage; } - let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target); - if compiler_to_use != compiler { + let compiler_to_use = + builder.compiler_for(build_compiler.stage, build_compiler.host, target); + if compiler_to_use != build_compiler { builder.ensure(Rustc::new(compiler_to_use, target)); let msg = if compiler_to_use.host == target { format!( "Uplifting rustc (stage{} -> stage{})", compiler_to_use.stage, - compiler.stage + 1 + build_compiler.stage + 1 ) } else { format!( "Uplifting rustc (stage{}:{} -> stage{}:{})", compiler_to_use.stage, compiler_to_use.host, - compiler.stage + 1, + build_compiler.stage + 1, target ) }; @@ -1082,22 +1094,26 @@ impl Step for Rustc { return compiler_to_use.stage; } - // Ensure that build scripts and proc macros have a std / libproc_macro to link against. + // Build a standard library for the current host target using the `build_compiler`. + // This standard library will be used when building `rustc` for compiling + // build scripts and proc macros. + // If we are not cross-compiling, the Std build above will be the same one as the one we + // prepare here. builder.ensure(Std::new( - builder.compiler(self.compiler.stage, builder.config.build), - builder.config.build, + builder.compiler(self.build_compiler.stage, builder.config.host_target), + builder.config.host_target, )); let mut cargo = builder::Cargo::new( builder, - compiler, + build_compiler, Mode::Rustc, SourceType::InTree, target, Kind::Build, ); - rustc_cargo(builder, &mut cargo, target, &compiler, &self.crates); + rustc_cargo(builder, &mut cargo, target, &build_compiler, &self.crates); // NB: all RUSTFLAGS should be added to `rustc_cargo()` so they will be // consistently applied by check/doc/test modes too. @@ -1106,19 +1122,19 @@ impl Step for Rustc { cargo.arg("-p").arg(krate); } - if builder.build.config.enable_bolt_settings && compiler.stage == 1 { + if builder.build.config.enable_bolt_settings && build_compiler.stage == 1 { // Relocations are required for BOLT to work. cargo.env("RUSTC_BOLT_LINK_FLAGS", "1"); } let _guard = builder.msg_sysroot_tool( Kind::Build, - compiler.stage, + build_compiler.stage, format_args!("compiler artifacts{}", crate_description(&self.crates)), - compiler.host, + build_compiler.host, target, ); - let stamp = build_stamp::librustc_stamp(builder, compiler, target); + let stamp = build_stamp::librustc_stamp(builder, build_compiler, target); run_cargo( builder, cargo, @@ -1150,10 +1166,10 @@ impl Step for Rustc { builder.ensure(RustcLink::from_rustc( self, - builder.compiler(compiler.stage, builder.config.build), + builder.compiler(build_compiler.stage, builder.config.host_target), )); - compiler.stage + build_compiler.stage } } @@ -1161,7 +1177,7 @@ pub fn rustc_cargo( builder: &Builder<'_>, cargo: &mut Cargo, target: TargetSelection, - compiler: &Compiler, + build_compiler: &Compiler, crates: &[String], ) { cargo @@ -1190,11 +1206,11 @@ pub fn rustc_cargo( // We want to link against registerEnzyme and in the future we want to use additional // functionality from Enzyme core. For that we need to link against Enzyme. if builder.config.llvm_enzyme { - let arch = builder.build.build; + let arch = builder.build.host_target; let enzyme_dir = builder.build.out.join(arch).join("enzyme").join("lib"); cargo.rustflag("-L").rustflag(enzyme_dir.to_str().expect("Invalid path")); - if let Some(llvm_config) = builder.llvm_config(builder.config.build) { + if let Some(llvm_config) = builder.llvm_config(builder.config.host_target) { let llvm_version_major = llvm::get_llvm_version_major(builder, &llvm_config); cargo.rustflag("-l").rustflag(&format!("Enzyme-{llvm_version_major}")); } @@ -1208,7 +1224,7 @@ pub fn rustc_cargo( cargo.rustflag("-Zdefault-visibility=protected"); } - if is_lto_stage(compiler) { + if is_lto_stage(build_compiler) { match builder.config.rust_lto { RustcLto::Thin | RustcLto::Fat => { // Since using LTO for optimizing dylibs is currently experimental, @@ -1241,7 +1257,7 @@ pub fn rustc_cargo( // is already on by default in MSVC optimized builds, which is interpreted as --icf=all: // https://github.com/llvm/llvm-project/blob/3329cec2f79185bafd678f310fafadba2a8c76d2/lld/COFF/Driver.cpp#L1746 // https://github.com/rust-lang/rust/blob/f22819bcce4abaff7d1246a56eec493418f9f4ee/compiler/rustc_codegen_ssa/src/back/linker.rs#L827 - if builder.config.lld_mode.is_used() && !compiler.host.is_msvc() { + if builder.config.lld_mode.is_used() && !build_compiler.host.is_msvc() { cargo.rustflag("-Clink-args=-Wl,--icf=all"); } @@ -1249,7 +1265,7 @@ pub fn rustc_cargo( panic!("Cannot use and generate PGO profiles at the same time"); } let is_collecting = if let Some(path) = &builder.config.rust_profile_generate { - if compiler.stage == 1 { + if build_compiler.stage == 1 { cargo.rustflag(&format!("-Cprofile-generate={path}")); // Apparently necessary to avoid overflowing the counters during // a Cargo build profile @@ -1259,7 +1275,7 @@ pub fn rustc_cargo( false } } else if let Some(path) = &builder.config.rust_profile_use { - if compiler.stage == 1 { + if build_compiler.stage == 1 { cargo.rustflag(&format!("-Cprofile-use={path}")); if builder.is_verbose() { cargo.rustflag("-Cllvm-args=-pgo-warn-missing-function"); @@ -1284,20 +1300,20 @@ pub fn rustc_cargo( // useful. // This is only performed for non-incremental builds, as ccache cannot deal with these. if let Some(ref ccache) = builder.config.ccache - && compiler.stage == 0 + && build_compiler.stage == 0 && !builder.config.incremental { cargo.env("RUSTC_WRAPPER", ccache); } - rustc_cargo_env(builder, cargo, target, compiler.stage); + rustc_cargo_env(builder, cargo, target, build_compiler.stage); } pub fn rustc_cargo_env( builder: &Builder<'_>, cargo: &mut Cargo, target: TargetSelection, - stage: u32, + build_stage: u32, ) { // Set some configuration variables picked up by build scripts and // the compiler alike @@ -1364,7 +1380,7 @@ pub fn rustc_cargo_env( crate::core::build_steps::llvm::prebuilt_llvm_config(builder, target, false) .should_build(); // `top_stage == stage` might be false for `check --stage 1`, if we are building the stage 1 compiler - let can_skip_build = builder.kind == Kind::Check && builder.top_stage == stage; + let can_skip_build = builder.kind == Kind::Check && builder.top_stage == build_stage; let should_skip_build = building_is_expensive && can_skip_build; if !should_skip_build { rustc_llvm_env(builder, cargo, target) @@ -1475,7 +1491,7 @@ impl RustcLink { fn from_rustc(rustc: Rustc, host_compiler: Compiler) -> Self { Self { compiler: host_compiler, - previous_stage_compiler: rustc.compiler, + previous_stage_compiler: rustc.build_compiler, target: rustc.target, crates: rustc.crates, } @@ -1813,7 +1829,7 @@ impl Step for Sysroot { // If we're downloading a compiler from CI, we can use the same compiler for all stages other than 0. if builder.download_rustc() && compiler.stage != 0 { assert_eq!( - builder.config.build, compiler.host, + builder.config.host_target, compiler.host, "Cross-compiling is not yet supported with `download-rustc`", ); @@ -1967,7 +1983,7 @@ impl Step for Assemble { if target_compiler.stage == 0 { trace!("stage 0 build compiler is always available, simply returning"); assert_eq!( - builder.config.build, target_compiler.host, + builder.config.host_target, target_compiler.host, "Cannot obtain compiler for non-native build triple at stage 0" ); // The stage 0 compiler for the build triple is always pre-built. @@ -2080,15 +2096,16 @@ impl Step for Assemble { debug!( "ensuring build compiler is available: compiler(stage = {}, host = {:?})", target_compiler.stage - 1, - builder.config.build, + builder.config.host_target, ); - let mut build_compiler = builder.compiler(target_compiler.stage - 1, builder.config.build); + let mut build_compiler = + builder.compiler(target_compiler.stage - 1, builder.config.host_target); // Build enzyme if builder.config.llvm_enzyme && !builder.config.dry_run() { debug!("`llvm_enzyme` requested"); let enzyme_install = builder.ensure(llvm::Enzyme { target: build_compiler.host }); - let llvm_config = builder.llvm_config(builder.config.build).unwrap(); + let llvm_config = builder.llvm_config(builder.config.host_target).unwrap(); let llvm_version_major = llvm::get_llvm_version_major(builder, &llvm_config); let lib_ext = std::env::consts::DLL_EXTENSION; let libenzyme = format!("libEnzyme-{llvm_version_major}"); diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index 587fca80374..e0f632eda0e 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -422,7 +422,7 @@ impl Step for Rustc { } let ra_proc_macro_srv_compiler = - builder.compiler_for(compiler.stage, builder.config.build, compiler.host); + builder.compiler_for(compiler.stage, builder.config.host_target, compiler.host); builder.ensure(compile::Rustc::new(ra_proc_macro_srv_compiler, compiler.host)); if let Some(ra_proc_macro_srv) = builder.ensure_if_default( @@ -696,7 +696,7 @@ impl Step for Std { run.builder.ensure(Std { compiler: run.builder.compiler_for( run.builder.top_stage, - run.builder.config.build, + run.builder.config.host_target, run.target, ), target: run.target, @@ -748,7 +748,7 @@ impl Step for RustcDev { run.builder.ensure(RustcDev { compiler: run.builder.compiler_for( run.builder.top_stage, - run.builder.config.build, + run.builder.config.host_target, run.target, ), target: run.target, @@ -815,7 +815,7 @@ impl Step for Analysis { // through the sysroot uplifting. compiler: run.builder.compiler_for( run.builder.top_stage, - run.builder.config.build, + run.builder.config.host_target, run.target, ), target: run.target, @@ -1168,7 +1168,7 @@ impl Step for Cargo { run.builder.ensure(Cargo { compiler: run.builder.compiler_for( run.builder.top_stage, - run.builder.config.build, + run.builder.config.host_target, run.target, ), target: run.target, @@ -1224,7 +1224,7 @@ impl Step for RustAnalyzer { run.builder.ensure(RustAnalyzer { compiler: run.builder.compiler_for( run.builder.top_stage, - run.builder.config.build, + run.builder.config.host_target, run.target, ), target: run.target, @@ -1268,7 +1268,7 @@ impl Step for Clippy { run.builder.ensure(Clippy { compiler: run.builder.compiler_for( run.builder.top_stage, - run.builder.config.build, + run.builder.config.host_target, run.target, ), target: run.target, @@ -1317,7 +1317,7 @@ impl Step for Miri { run.builder.ensure(Miri { compiler: run.builder.compiler_for( run.builder.top_stage, - run.builder.config.build, + run.builder.config.host_target, run.target, ), target: run.target, @@ -1462,7 +1462,7 @@ impl Step for Rustfmt { run.builder.ensure(Rustfmt { compiler: run.builder.compiler_for( run.builder.top_stage, - run.builder.config.build, + run.builder.config.host_target, run.target, ), target: run.target, @@ -1507,7 +1507,7 @@ impl Step for Extended { fn make_run(run: RunConfig<'_>) { run.builder.ensure(Extended { stage: run.builder.top_stage, - host: run.builder.config.build, + host: run.builder.config.host_target, target: run.target, }); } @@ -1681,7 +1681,8 @@ impl Step for Extended { cmd.run(builder); } - if target.is_windows() { + // FIXME(mati865): `gnullvm` here is temporary, remove it once it can host itself + if target.is_windows() && !target.contains("gnullvm") { let exe = tmp.join("exe"); let _ = fs::remove_dir_all(&exe); @@ -2156,7 +2157,7 @@ fn maybe_install_llvm( cmd.arg("--libfiles"); builder.verbose(|| println!("running {cmd:?}")); let files = cmd.run_capture_stdout(builder).stdout(); - let build_llvm_out = &builder.llvm_out(builder.config.build); + let build_llvm_out = &builder.llvm_out(builder.config.host_target); let target_llvm_out = &builder.llvm_out(target); for file in files.trim_end().split(' ') { // If we're not using a custom LLVM, make sure we package for the target. @@ -2340,7 +2341,7 @@ impl Step for LlvmBitcodeLinker { run.builder.ensure(LlvmBitcodeLinker { compiler: run.builder.compiler_for( run.builder.top_stage, - run.builder.config.build, + run.builder.config.host_target, run.target, ), target: run.target, diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs index 7fccf85a0ea..215c155651a 100644 --- a/src/bootstrap/src/core/build_steps/doc.rs +++ b/src/bootstrap/src/core/build_steps/doc.rs @@ -209,7 +209,7 @@ impl Step for TheBook { fn make_run(run: RunConfig<'_>) { run.builder.ensure(TheBook { - compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build), + compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.host_target), target: run.target, }); } @@ -329,7 +329,7 @@ impl Step for Standalone { fn make_run(run: RunConfig<'_>) { run.builder.ensure(Standalone { - compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build), + compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.host_target), target: run.target, }); } @@ -431,7 +431,7 @@ impl Step for Releases { fn make_run(run: RunConfig<'_>) { run.builder.ensure(Releases { - compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build), + compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.host_target), target: run.target, }); } @@ -449,7 +449,7 @@ impl Step for Releases { t!(fs::create_dir_all(&out)); builder.ensure(Standalone { - compiler: builder.compiler(builder.top_stage, builder.config.build), + compiler: builder.compiler(builder.top_stage, builder.config.host_target), target, }); @@ -700,7 +700,7 @@ fn doc_std( extra_args: &[&str], requested_crates: &[String], ) { - let compiler = builder.compiler(stage, builder.config.build); + let compiler = builder.compiler(stage, builder.config.host_target); let target_doc_dir_name = if format == DocumentationFormat::Json { "json-doc" } else { "doc" }; let target_dir = builder.stage_out(compiler, Mode::Std).join(target).join(target_doc_dir_name); @@ -803,8 +803,8 @@ impl Step for Rustc { // Build the standard library, so that proc-macros can use it. // (Normally, only the metadata would be necessary, but proc-macros are special since they run at compile-time.) - let compiler = builder.compiler(stage, builder.config.build); - builder.ensure(compile::Std::new(compiler, builder.config.build)); + let compiler = builder.compiler(stage, builder.config.host_target); + builder.ensure(compile::Std::new(compiler, builder.config.host_target)); let _guard = builder.msg_sysroot_tool( Kind::Doc, @@ -946,7 +946,7 @@ macro_rules! tool_doc { let out = builder.compiler_doc_out(target); t!(fs::create_dir_all(&out)); - let compiler = builder.compiler(stage, builder.config.build); + let compiler = builder.compiler(stage, builder.config.host_target); builder.ensure(compile::Std::new(compiler, target)); if true $(&& $rustc_tool)? { @@ -1174,7 +1174,7 @@ impl Step for RustcBook { fn make_run(run: RunConfig<'_>) { run.builder.ensure(RustcBook { - compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build), + compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.host_target), target: run.target, validate: false, }); @@ -1261,7 +1261,7 @@ impl Step for Reference { fn make_run(run: RunConfig<'_>) { run.builder.ensure(Reference { - compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build), + compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.host_target), target: run.target, }); } @@ -1272,7 +1272,7 @@ impl Step for Reference { // This is needed for generating links to the standard library using // the mdbook-spec plugin. - builder.ensure(compile::Std::new(self.compiler, builder.config.build)); + builder.ensure(compile::Std::new(self.compiler, builder.config.host_target)); // Run rustbook/mdbook to generate the HTML pages. builder.ensure(RustbookSrc { diff --git a/src/bootstrap/src/core/build_steps/gcc.rs b/src/bootstrap/src/core/build_steps/gcc.rs index ee8bd8286da..899e3fd9a45 100644 --- a/src/bootstrap/src/core/build_steps/gcc.rs +++ b/src/bootstrap/src/core/build_steps/gcc.rs @@ -285,7 +285,7 @@ pub fn add_cg_gcc_cargo_flags(cargo: &mut Cargo, gcc: &GccOutput) { /// The absolute path to the downloaded GCC artifacts. #[cfg(not(test))] fn ci_gcc_root(config: &crate::Config) -> PathBuf { - config.out.join(config.build).join("ci-gcc") + config.out.join(config.host_target).join("ci-gcc") } /// Detect whether GCC sources have been modified locally or not. diff --git a/src/bootstrap/src/core/build_steps/install.rs b/src/bootstrap/src/core/build_steps/install.rs index 5419540aa2e..4434d6658eb 100644 --- a/src/bootstrap/src/core/build_steps/install.rs +++ b/src/bootstrap/src/core/build_steps/install.rs @@ -73,7 +73,7 @@ fn install_sh( let prefix = default_path(&builder.config.prefix, "/usr/local"); let sysconfdir = prefix.join(default_path(&builder.config.sysconfdir, "/etc")); let destdir_env = env::var_os("DESTDIR").map(PathBuf::from); - let is_cygwin = builder.config.build.is_cygwin(); + let is_cygwin = builder.config.host_target.is_cygwin(); // Sanity checks on the write access of user. // @@ -187,7 +187,7 @@ macro_rules! install { fn make_run(run: RunConfig<'_>) { run.builder.ensure($name { - compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build), + compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.host_target), target: run.target, }); } @@ -246,7 +246,7 @@ install!((self, builder, _config), ); } }; - LlvmTools, alias = "llvm-tools", _config.llvm_tools_enabled && _config.llvm_enabled(_config.build), only_hosts: true, { + LlvmTools, alias = "llvm-tools", _config.llvm_tools_enabled && _config.llvm_enabled(_config.host_target), only_hosts: true, { if let Some(tarball) = builder.ensure(dist::LlvmTools { target: self.target }) { install_sh(builder, "llvm-tools", self.compiler.stage, Some(self.target), &tarball); } else { diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index 2b7703000cb..8f2f143c352 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -132,14 +132,14 @@ pub fn prebuilt_llvm_config( let build_llvm_config = if let Some(build_llvm_config) = builder .config .target_config - .get(&builder.config.build) + .get(&builder.config.host_target) .and_then(|config| config.llvm_config.clone()) { build_llvm_config } else { - let mut llvm_config_ret_dir = builder.llvm_out(builder.config.build); + let mut llvm_config_ret_dir = builder.llvm_out(builder.config.host_target); llvm_config_ret_dir.push("bin"); - llvm_config_ret_dir.join(exe("llvm-config", builder.config.build)) + llvm_config_ret_dir.join(exe("llvm-config", builder.config.host_target)) }; let llvm_cmake_dir = out_dir.join("lib/cmake/llvm"); @@ -235,8 +235,8 @@ pub(crate) fn is_ci_llvm_available_for_target(config: &Config, asserts: bool) -> ("x86_64-unknown-netbsd", false), ]; - if !supported_platforms.contains(&(&*config.build.triple, asserts)) - && (asserts || !supported_platforms.contains(&(&*config.build.triple, true))) + if !supported_platforms.contains(&(&*config.host_target.triple, asserts)) + && (asserts || !supported_platforms.contains(&(&*config.host_target.triple, true))) { return false; } @@ -480,7 +480,7 @@ impl Step for Llvm { // https://llvm.org/docs/HowToCrossCompileLLVM.html if !builder.config.is_host_target(target) { let LlvmResult { llvm_config, .. } = - builder.ensure(Llvm { target: builder.config.build }); + builder.ensure(Llvm { target: builder.config.host_target }); if !builder.config.dry_run() { let llvm_bindir = command(&llvm_config).arg("--bindir").run_capture_stdout(builder).stdout(); @@ -494,7 +494,8 @@ impl Step for Llvm { } cfg.define("LLVM_CONFIG_PATH", llvm_config); if builder.config.llvm_clang { - let build_bin = builder.llvm_out(builder.config.build).join("build").join("bin"); + let build_bin = + builder.llvm_out(builder.config.host_target).join("build").join("bin"); let clang_tblgen = build_bin.join("clang-tblgen").with_extension(EXE_EXTENSION); if !builder.config.dry_run() && !clang_tblgen.exists() { panic!("unable to find {}", clang_tblgen.display()); @@ -628,7 +629,7 @@ fn configure_cmake( if builder.ninja() { cfg.generator("Ninja"); } - cfg.target(&target.triple).host(&builder.config.build.triple); + cfg.target(&target.triple).host(&builder.config.host_target.triple); if !builder.config.is_host_target(target) { cfg.define("CMAKE_CROSSCOMPILING", "True"); @@ -813,7 +814,7 @@ fn configure_cmake( ldflags.push_all(flags); } - if let Some(flags) = get_var("LDFLAGS", &builder.config.build.triple, &target.triple) { + if let Some(flags) = get_var("LDFLAGS", &builder.config.host_target.triple, &target.triple) { ldflags.push_all(&flags); } @@ -1135,7 +1136,8 @@ impl Step for Sanitizers { return runtimes; } - let LlvmResult { llvm_config, .. } = builder.ensure(Llvm { target: builder.config.build }); + let LlvmResult { llvm_config, .. } = + builder.ensure(Llvm { target: builder.config.host_target }); static STAMP_HASH_MEMO: OnceLock<String> = OnceLock::new(); let smart_stamp_hash = STAMP_HASH_MEMO.get_or_init(|| { @@ -1345,7 +1347,7 @@ impl Step for CrtBeginEnd { cfg.cargo_metadata(false) .out_dir(&out_dir) .target(&self.target.triple) - .host(&builder.config.build.triple) + .host(&builder.config.host_target.triple) .warnings(false) .debug(false) .opt_level(3) @@ -1424,7 +1426,7 @@ impl Step for Libunwind { cfg.archiver(ar); } cfg.target(&self.target.triple); - cfg.host(&builder.config.build.triple); + cfg.host(&builder.config.host_target.triple); cfg.warnings(false); cfg.debug(false); // get_compiler() need set opt_level first. diff --git a/src/bootstrap/src/core/build_steps/perf.rs b/src/bootstrap/src/core/build_steps/perf.rs index 14c7b7cf5e9..c43043b48f4 100644 --- a/src/bootstrap/src/core/build_steps/perf.rs +++ b/src/bootstrap/src/core/build_steps/perf.rs @@ -136,8 +136,8 @@ impl Display for Scenario { /// Performs profiling using `rustc-perf` on a built version of the compiler. pub fn perf(builder: &Builder<'_>, args: &PerfArgs) { let collector = builder.ensure(RustcPerf { - compiler: builder.compiler(0, builder.config.build), - target: builder.config.build, + compiler: builder.compiler(0, builder.config.host_target), + target: builder.config.host_target, }); let is_profiling = match &args.cmd { @@ -151,8 +151,8 @@ pub fn perf(builder: &Builder<'_>, args: &PerfArgs) { Consider setting `rust.debuginfo-level = 1` in `bootstrap.toml`."#); } - let compiler = builder.compiler(builder.top_stage, builder.config.build); - builder.ensure(Std::new(compiler, builder.config.build)); + let compiler = builder.compiler(builder.top_stage, builder.config.host_target); + builder.ensure(Std::new(compiler, builder.config.host_target)); if let Some(opts) = args.cmd.shared_opts() && opts.profiles.contains(&Profile::Doc) diff --git a/src/bootstrap/src/core/build_steps/run.rs b/src/bootstrap/src/core/build_steps/run.rs index 6ef1b13abcd..b3104ae05e8 100644 --- a/src/bootstrap/src/core/build_steps/run.rs +++ b/src/bootstrap/src/core/build_steps/run.rs @@ -116,7 +116,7 @@ impl Step for Miri { } fn run(self, builder: &Builder<'_>) { - let host = builder.build.build; + let host = builder.build.host_target; let target = self.target; // `x run` uses stage 0 by default but miri does not work well with stage 0. @@ -448,7 +448,7 @@ impl Step for Rustfmt { } fn run(self, builder: &Builder<'_>) { - let host = builder.build.build; + let host = builder.build.host_target; // `x run` uses stage 0 by default but rustfmt does not work well with stage 0. // Change the stage to 1 if it's not set explicitly. diff --git a/src/bootstrap/src/core/build_steps/setup.rs b/src/bootstrap/src/core/build_steps/setup.rs index 25adfdf1601..86b7456d7b4 100644 --- a/src/bootstrap/src/core/build_steps/setup.rs +++ b/src/bootstrap/src/core/build_steps/setup.rs @@ -260,7 +260,7 @@ impl Step for Link { } let stage_path = - ["build", config.build.rustc_target_arg(), "stage1"].join(MAIN_SEPARATOR_STR); + ["build", config.host_target.rustc_target_arg(), "stage1"].join(MAIN_SEPARATOR_STR); if stage_dir_exists(&stage_path[..]) && !config.dry_run() { attempt_toolchain_link(builder, &stage_path[..]); diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index dddce8fe05d..ebb926d81ce 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -70,7 +70,7 @@ impl Step for CrateBootstrap { } fn run(self, builder: &Builder<'_>) { - let bootstrap_host = builder.config.build; + let bootstrap_host = builder.config.host_target; let compiler = builder.compiler(0, bootstrap_host); let mut path = self.path.to_str().unwrap(); @@ -128,7 +128,7 @@ You can skip linkcheck with --skip src/tools/linkchecker" builder.info(&format!("Linkcheck ({host})")); // Test the linkchecker itself. - let bootstrap_host = builder.config.build; + let bootstrap_host = builder.config.host_target; let compiler = builder.compiler(0, bootstrap_host); let cargo = tool::prepare_tool_cargo( @@ -525,7 +525,7 @@ impl Step for Miri { /// Runs `cargo test` for miri. fn run(self, builder: &Builder<'_>) { - let host = builder.build.build; + let host = builder.build.host_target; let target = self.target; let stage = builder.top_stage; if stage == 0 { @@ -637,7 +637,7 @@ impl Step for CargoMiri { /// Tests `cargo miri test`. fn run(self, builder: &Builder<'_>) { - let host = builder.build.build; + let host = builder.build.host_target; let target = self.target; let stage = builder.top_stage; if stage == 0 { @@ -915,7 +915,7 @@ impl Step for RustdocJSStd { Kind::Test, builder.top_stage, "rustdoc-js-std", - builder.config.build, + builder.config.host_target, self.target, ); command.run(builder); @@ -1607,7 +1607,7 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the // At stage 0 (stage - 1) we are using the stage0 compiler. Using `self.target` can lead // finding an incorrect compiler path on cross-targets, as the stage 0 is always equal to // `build.build` in the configuration. - let build = builder.build.build; + let build = builder.build.host_target; compiler = builder.compiler(compiler.stage - 1, build); let test_stage = compiler.stage + 1; (test_stage, format!("stage{test_stage}-{build}")) @@ -1729,7 +1729,7 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the cmd.arg("--mode").arg(mode); cmd.arg("--target").arg(target.rustc_target_arg()); cmd.arg("--host").arg(&*compiler.host.triple); - cmd.arg("--llvm-filecheck").arg(builder.llvm_filecheck(builder.config.build)); + cmd.arg("--llvm-filecheck").arg(builder.llvm_filecheck(builder.config.host_target)); if builder.build.config.llvm_enzyme { cmd.arg("--has-enzyme"); @@ -1900,7 +1900,7 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the let mut copts_passed = false; if builder.config.llvm_enabled(compiler.host) { let llvm::LlvmResult { llvm_config, .. } = - builder.ensure(llvm::Llvm { target: builder.config.build }); + builder.ensure(llvm::Llvm { target: builder.config.host_target }); if !builder.config.dry_run() { let llvm_version = get_llvm_version(builder, &llvm_config); let llvm_components = @@ -1947,7 +1947,7 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the // If LLD is available, add it to the PATH if builder.config.lld_enabled { let lld_install_root = - builder.ensure(llvm::Lld { target: builder.config.build }); + builder.ensure(llvm::Lld { target: builder.config.host_target }); let lld_bin_path = lld_install_root.join("bin"); @@ -2202,7 +2202,7 @@ impl BookTest { let mut lib_paths = vec![]; for dep in self.dependencies { let mode = Mode::ToolRustc; - let target = builder.config.build; + let target = builder.config.host_target; let cargo = tool::prepare_tool_cargo( builder, compiler, @@ -2384,7 +2384,7 @@ impl Step for ErrorIndex { // error_index_generator depends on librustdoc. Use the compiler that // is normally used to build rustdoc for other tests (like compiletest // tests in tests/rustdoc) so that it shares the same artifacts. - let compiler = run.builder.compiler(run.builder.top_stage, run.builder.config.build); + let compiler = run.builder.compiler(run.builder.top_stage, run.builder.config.host_target); run.builder.ensure(ErrorIndex { compiler }); } @@ -2983,7 +2983,7 @@ impl Step for Distcheck { .arg("--enable-vendor") .current_dir(&dir) .run(builder); - command(helpers::make(&builder.config.build.triple)) + command(helpers::make(&builder.config.host_target.triple)) .arg("check") .current_dir(&dir) .run(builder); @@ -3024,7 +3024,7 @@ impl Step for Bootstrap { /// Tests the build system itself. fn run(self, builder: &Builder<'_>) { - let host = builder.config.build; + let host = builder.config.host_target; let compiler = builder.compiler(0, host); let _guard = builder.msg(Kind::Test, 0, "bootstrap", host, host); @@ -3035,7 +3035,7 @@ impl Step for Bootstrap { check_bootstrap .args(["-m", "unittest", "bootstrap_test.py"]) .env("BUILD_DIR", &builder.out) - .env("BUILD_PLATFORM", builder.build.build.triple) + .env("BUILD_PLATFORM", builder.build.host_target.triple) .env("BOOTSTRAP_TEST_RUSTC_BIN", &builder.initial_rustc) .env("BOOTSTRAP_TEST_CARGO_BIN", &builder.initial_cargo) .current_dir(builder.src.join("src/bootstrap/")); @@ -3090,8 +3090,11 @@ impl Step for TierCheck { } fn make_run(run: RunConfig<'_>) { - let compiler = - run.builder.compiler_for(run.builder.top_stage, run.builder.build.build, run.target); + let compiler = run.builder.compiler_for( + run.builder.top_stage, + run.builder.build.host_target, + run.target, + ); run.builder.ensure(TierCheck { compiler }); } @@ -3142,7 +3145,7 @@ impl Step for LintDocs { fn make_run(run: RunConfig<'_>) { run.builder.ensure(LintDocs { - compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build), + compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.host_target), target: run.target, }); } @@ -3168,7 +3171,7 @@ impl Step for RustInstaller { /// Ensure the version placeholder replacement tool builds fn run(self, builder: &Builder<'_>) { - let bootstrap_host = builder.config.build; + let bootstrap_host = builder.config.host_target; let compiler = builder.compiler(0, bootstrap_host); let cargo = tool::prepare_tool_cargo( builder, @@ -3270,7 +3273,7 @@ impl Step for TestHelpers { cfg.cargo_metadata(false) .out_dir(&dst) .target(&target.triple) - .host(&builder.config.build.triple) + .host(&builder.config.host_target.triple) .opt_level(0) .warnings(false) .debug(false) @@ -3560,7 +3563,7 @@ impl Step for TestFloatParse { } fn run(self, builder: &Builder<'_>) { - let bootstrap_host = builder.config.build; + let bootstrap_host = builder.config.host_target; let compiler = builder.compiler(builder.top_stage, bootstrap_host); let path = self.path.to_str().unwrap(); let crate_name = self.path.iter().next_back().unwrap().to_str().unwrap(); diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index 9861637d8c8..f64d67341cf 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -23,7 +23,6 @@ use crate::core::builder::{ Builder, Cargo as CargoCommand, RunConfig, ShouldRun, Step, cargo_profile_var, }; use crate::core::config::{DebuginfoLevel, RustcLto, TargetSelection}; -use crate::utils::channel::GitInfo; use crate::utils::exec::{BootstrapCommand, command}; use crate::utils::helpers::{add_dylib_path, exe, t}; use crate::{Compiler, FileType, Kind, Mode, gha}; @@ -137,6 +136,19 @@ impl Step for ToolBuild { _ => panic!("unexpected Mode for tool build"), } + // build.tool.TOOL_NAME.features in bootstrap.toml allows specifying which features to + // enable for a specific tool. `extra_features` instead is not controlled by the toml and + // provides features that are always enabled for a specific tool (e.g. "in-rust-tree" for + // rust-analyzer). Finally, `prepare_tool_cargo` might add more features to adapt the build + // to the chosen flags (e.g. "all-static" for cargo if `cargo_native_static` is true). + let mut features = builder + .config + .tool + .get(self.tool) + .and_then(|tool| tool.features.clone()) + .unwrap_or_default(); + features.extend(self.extra_features.clone()); + let mut cargo = prepare_tool_cargo( builder, self.compiler, @@ -145,7 +157,7 @@ impl Step for ToolBuild { Kind::Build, path, self.source_type, - &self.extra_features, + &features, ); // The stage0 compiler changes infrequently and does not directly depend on code @@ -278,7 +290,7 @@ pub fn prepare_tool_cargo( cargo.env("CFG_VER_DESCRIPTION", description); } - let info = GitInfo::new(builder.config.omit_git_hash, &dir); + let info = builder.config.git_info(builder.config.omit_git_hash, &dir); if let Some(sha) = info.sha() { cargo.env("CFG_COMMIT_HASH", sha); } @@ -342,14 +354,14 @@ pub(crate) fn get_tool_rustc_compiler( if builder.download_rustc() && target_compiler.stage == 1 { // We shouldn't drop to stage0 compiler when using CI rustc. - return builder.compiler(1, builder.config.build); + return builder.compiler(1, builder.config.host_target); } // Similar to `compile::Assemble`, build with the previous stage's compiler. Otherwise // we'd have stageN/bin/rustc and stageN/bin/$rustc_tool be effectively different stage // compilers, which isn't what we want. Rustc tools should be linked in the same way as the // compiler it's paired with, so it must be built with the previous stage compiler. - builder.compiler(target_compiler.stage.saturating_sub(1), builder.config.build) + builder.compiler(target_compiler.stage.saturating_sub(1), builder.config.host_target) } /// Links a built tool binary with the given `name` from the build directory to the @@ -390,8 +402,8 @@ macro_rules! bootstrap_tool { match tool { $(Tool::$name => self.ensure($name { - compiler: self.compiler(0, self.config.build), - target: self.config.build, + compiler: self.compiler(0, self.config.host_target), + target: self.config.host_target, }).tool_path, )+ } @@ -415,7 +427,7 @@ macro_rules! bootstrap_tool { fn make_run(run: RunConfig<'_>) { run.builder.ensure($name { // snapshot compiler - compiler: run.builder.compiler(0, run.builder.config.build), + compiler: run.builder.compiler(0, run.builder.config.host_target), target: run.target, }); } @@ -532,7 +544,7 @@ impl Step for RustcPerf { fn make_run(run: RunConfig<'_>) { run.builder.ensure(RustcPerf { - compiler: run.builder.compiler(0, run.builder.config.build), + compiler: run.builder.compiler(0, run.builder.config.host_target), target: run.target, }); } @@ -573,7 +585,7 @@ impl ErrorIndex { pub fn command(builder: &Builder<'_>) -> BootstrapCommand { // Error-index-generator links with the rustdoc library, so we need to add `rustc_lib_paths` // for rustc_private and libLLVM.so, and `sysroot_lib` for libstd, etc. - let host = builder.config.build; + let host = builder.config.host_target; let compiler = builder.compiler_for(builder.top_stage, host, host); let mut cmd = command(builder.ensure(ErrorIndex { compiler }).tool_path); let mut dylib_paths = builder.rustc_lib_paths(compiler); @@ -596,7 +608,7 @@ impl Step for ErrorIndex { // src/tools/error-index-generator` which almost nobody does. // Normally, `x.py test` or `x.py doc` will use the // `ErrorIndex::command` function instead. - let compiler = run.builder.compiler(run.builder.top_stage, run.builder.config.build); + let compiler = run.builder.compiler(run.builder.top_stage, run.builder.config.host_target); run.builder.ensure(ErrorIndex { compiler }); } @@ -631,7 +643,7 @@ impl Step for RemoteTestServer { fn make_run(run: RunConfig<'_>) { run.builder.ensure(RemoteTestServer { - compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build), + compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.host_target), target: run.target, }); } @@ -788,7 +800,7 @@ impl Step for Cargo { fn make_run(run: RunConfig<'_>) { run.builder.ensure(Cargo { - compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build), + compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.host_target), target: run.target, }); } @@ -906,7 +918,7 @@ impl Step for RustAnalyzer { fn make_run(run: RunConfig<'_>) { run.builder.ensure(RustAnalyzer { - compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build), + compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.host_target), target: run.target, }); } @@ -951,7 +963,7 @@ impl Step for RustAnalyzerProcMacroSrv { fn make_run(run: RunConfig<'_>) { run.builder.ensure(RustAnalyzerProcMacroSrv { - compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build), + compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.host_target), target: run.target, }); } @@ -1004,7 +1016,7 @@ impl Step for LlvmBitcodeLinker { fn make_run(run: RunConfig<'_>) { run.builder.ensure(LlvmBitcodeLinker { - compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build), + compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.host_target), extra_features: Vec::new(), target: run.target, }); @@ -1142,7 +1154,7 @@ macro_rules! tool_extended { fn make_run(run: RunConfig<'_>) { run.builder.ensure($name { - compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build), + compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.host_target), target: run.target, }); } @@ -1284,7 +1296,7 @@ impl Step for TestFloatParse { } fn run(self, builder: &Builder<'_>) -> ToolBuildResult { - let bootstrap_host = builder.config.build; + let bootstrap_host = builder.config.host_target; let compiler = builder.compiler(builder.top_stage, bootstrap_host); builder.ensure(ToolBuild { @@ -1307,7 +1319,7 @@ impl Builder<'_> { /// `host`. pub fn tool_cmd(&self, tool: Tool) -> BootstrapCommand { let mut cmd = command(self.tool_exe(tool)); - let compiler = self.compiler(0, self.config.build); + let compiler = self.compiler(0, self.config.host_target); let host = &compiler.host; // Prepares the `cmd` provided to be able to run the `compiler` provided. // diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs index cf7f962d026..c6cfdb69356 100644 --- a/src/bootstrap/src/core/builder/cargo.rs +++ b/src/bootstrap/src/core/builder/cargo.rs @@ -551,7 +551,7 @@ impl Builder<'_> { let libdir = self.rustc_libdir(compiler); let sysroot_str = sysroot.as_os_str().to_str().expect("sysroot should be UTF-8"); - if self.is_verbose() && !matches!(self.config.dry_run, DryRun::SelfCheck) { + if self.is_verbose() && !matches!(self.config.get_dry_run(), DryRun::SelfCheck) { println!("using sysroot {sysroot_str}"); } diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index 19b79bfe818..887db683f78 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -22,6 +22,7 @@ use crate::core::config::flags::Subcommand; use crate::core::config::{DryRun, TargetSelection}; use crate::utils::cache::Cache; use crate::utils::exec::{BootstrapCommand, command}; +use crate::utils::execution_context::ExecutionContext; use crate::utils::helpers::{self, LldThreads, add_dylib_path, exe, libdir, linker_args, t}; use crate::{Build, Crate, trace}; @@ -136,7 +137,7 @@ pub struct RunConfig<'a> { impl RunConfig<'_> { pub fn build_triple(&self) -> TargetSelection { - self.builder.build.build + self.builder.build.host_target } /// Return a list of crate names selected by `run.paths`. @@ -442,13 +443,15 @@ impl StepDescription { fn is_excluded(&self, builder: &Builder<'_>, pathset: &PathSet) -> bool { if builder.config.skip.iter().any(|e| pathset.has(e, builder.kind)) { - if !matches!(builder.config.dry_run, DryRun::SelfCheck) { + if !matches!(builder.config.get_dry_run(), DryRun::SelfCheck) { println!("Skipping {pathset:?} because it is excluded"); } return true; } - if !builder.config.skip.is_empty() && !matches!(builder.config.dry_run, DryRun::SelfCheck) { + if !builder.config.skip.is_empty() + && !matches!(builder.config.get_dry_run(), DryRun::SelfCheck) + { builder.verbose(|| { println!( "{:?} not skipped for {:?} -- not in {:?}", @@ -1294,10 +1297,10 @@ impl<'a> Builder<'a> { ) -> Compiler { let mut resolved_compiler = if self.build.force_use_stage2(stage) { trace!(target: "COMPILER_FOR", ?stage, "force_use_stage2"); - self.compiler(2, self.config.build) + self.compiler(2, self.config.host_target) } else if self.build.force_use_stage1(stage, target) { trace!(target: "COMPILER_FOR", ?stage, "force_use_stage1"); - self.compiler(1, self.config.build) + self.compiler(1, self.config.host_target) } else { trace!(target: "COMPILER_FOR", ?stage, ?host, "no force, fallback to `compiler()`"); self.compiler(stage, host) @@ -1355,7 +1358,7 @@ impl<'a> Builder<'a> { /// Windows. pub fn libdir_relative(&self, compiler: Compiler) -> &Path { if compiler.is_snapshot(self) { - libdir(self.config.build).as_ref() + libdir(self.config.host_target).as_ref() } else { match self.config.libdir_relative() { Some(relative_libdir) if compiler.stage >= 1 => relative_libdir, @@ -1436,9 +1439,10 @@ impl<'a> Builder<'a> { return cmd; } - let _ = self.ensure(tool::Clippy { compiler: run_compiler, target: self.build.build }); - let cargo_clippy = - self.ensure(tool::CargoClippy { compiler: run_compiler, target: self.build.build }); + let _ = + self.ensure(tool::Clippy { compiler: run_compiler, target: self.build.host_target }); + let cargo_clippy = self + .ensure(tool::CargoClippy { compiler: run_compiler, target: self.build.host_target }); let mut dylib_path = helpers::dylib_path(); dylib_path.insert(0, self.sysroot(run_compiler).join("lib")); @@ -1451,9 +1455,10 @@ impl<'a> Builder<'a> { pub fn cargo_miri_cmd(&self, run_compiler: Compiler) -> BootstrapCommand { assert!(run_compiler.stage > 0, "miri can not be invoked at stage 0"); // Prepare the tools - let miri = self.ensure(tool::Miri { compiler: run_compiler, target: self.build.build }); + let miri = + self.ensure(tool::Miri { compiler: run_compiler, target: self.build.host_target }); let cargo_miri = - self.ensure(tool::CargoMiri { compiler: run_compiler, target: self.build.build }); + self.ensure(tool::CargoMiri { compiler: run_compiler, target: self.build.host_target }); // Invoke cargo-miri, make sure it can find miri and cargo. let mut cmd = command(cargo_miri.tool_path); cmd.env("MIRI", &miri.tool_path); @@ -1633,4 +1638,14 @@ impl<'a> Builder<'a> { self.info(&format!("{err}\n")); } } + + pub fn exec_ctx(&self) -> &ExecutionContext { + &self.config.exec_ctx + } +} + +impl<'a> AsRef<ExecutionContext> for Builder<'a> { + fn as_ref(&self) -> &ExecutionContext { + self.exec_ctx() + } } diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index baa22fc7f72..a26a96f2815 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -22,7 +22,7 @@ fn configure_with_args(cmd: &[String], host: &[&str], target: &[&str]) -> Config let mut config = Config::parse(Flags::parse(cmd)); // don't save toolstates config.save_toolstates = None; - config.dry_run = DryRun::SelfCheck; + config.set_dry_run(DryRun::SelfCheck); // Ignore most submodules, since we don't need them for a dry run, and the // tests run much faster without them. @@ -46,7 +46,7 @@ fn configure_with_args(cmd: &[String], host: &[&str], target: &[&str]) -> Config .join(&thread::current().name().unwrap_or("unknown").replace(":", "-")); t!(fs::create_dir_all(&dir)); config.out = dir; - config.build = TargetSelection::from_user(TEST_TRIPLE_1); + config.host_target = TargetSelection::from_user(TEST_TRIPLE_1); config.hosts = host.iter().map(|s| TargetSelection::from_user(s)).collect(); config.targets = target.iter().map(|s| TargetSelection::from_user(s)).collect(); config @@ -1102,7 +1102,7 @@ fn test_prebuilt_llvm_config_path_resolution() { let actual = drop_win_disk_prefix_if_present(actual); assert_eq!(expected, actual); - let actual = prebuilt_llvm_config(&builder, builder.config.build, false) + let actual = prebuilt_llvm_config(&builder, builder.config.host_target, false) .llvm_result() .llvm_config .clone(); @@ -1120,15 +1120,15 @@ fn test_prebuilt_llvm_config_path_resolution() { let build = Build::new(config.clone()); let builder = Builder::new(&build); - let actual = prebuilt_llvm_config(&builder, builder.config.build, false) + let actual = prebuilt_llvm_config(&builder, builder.config.host_target, false) .llvm_result() .llvm_config .clone(); let expected = builder .out - .join(builder.config.build) + .join(builder.config.host_target) .join("llvm/bin") - .join(exe("llvm-config", builder.config.build)); + .join(exe("llvm-config", builder.config.host_target)); assert_eq!(expected, actual); let config = configure( @@ -1143,15 +1143,15 @@ fn test_prebuilt_llvm_config_path_resolution() { let build = Build::new(config.clone()); let builder = Builder::new(&build); - let actual = prebuilt_llvm_config(&builder, builder.config.build, false) + let actual = prebuilt_llvm_config(&builder, builder.config.host_target, false) .llvm_result() .llvm_config .clone(); let expected = builder .out - .join(builder.config.build) + .join(builder.config.host_target) .join("ci-llvm/bin") - .join(exe("llvm-config", builder.config.build)); + .join(exe("llvm-config", builder.config.host_target)); assert_eq!(expected, actual); } } @@ -1163,7 +1163,7 @@ fn test_is_builder_target() { for (target1, target2) in [(target1, target2), (target2, target1)] { let mut config = configure("build", &[], &[]); - config.build = target1; + config.host_target = target1; let build = Build::new(config); let builder = Builder::new(&build); diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 824b159c326..970a982dae4 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -24,7 +24,7 @@ use std::{cmp, env, fs}; use build_helper::ci::CiEnv; use build_helper::exit; -use build_helper::git::{GitConfig, PathFreshness, check_path_modifications, output_result}; +use build_helper::git::{GitConfig, PathFreshness, check_path_modifications}; use serde::Deserialize; #[cfg(feature = "tracing")] use tracing::{instrument, span}; @@ -35,7 +35,7 @@ pub use crate::core::config::flags::Subcommand; use crate::core::config::flags::{Color, Flags}; use crate::core::config::target_selection::TargetSelectionList; use crate::core::config::toml::TomlConfig; -use crate::core::config::toml::build::Build; +use crate::core::config::toml::build::{Build, Tool}; use crate::core::config::toml::change_id::ChangeId; use crate::core::config::toml::rust::{ LldMode, RustOptimize, check_incompatible_options_for_ci_rustc, @@ -47,42 +47,31 @@ use crate::core::config::{ }; use crate::core::download::is_download_ci_available; use crate::utils::channel; +use crate::utils::exec::command; +use crate::utils::execution_context::ExecutionContext; use crate::utils::helpers::exe; -use crate::{Command, GitInfo, OnceLock, TargetSelection, check_ci_llvm, helpers, output, t}; +use crate::{GitInfo, OnceLock, TargetSelection, check_ci_llvm, helpers, t}; -/// Each path from this function is considered "allowed" in the `download-rustc="if-unchanged"` logic. +/// Each path in this list is considered "allowed" in the `download-rustc="if-unchanged"` logic. /// This means they can be modified and changes to these paths should never trigger a compiler build /// when "if-unchanged" is set. -pub fn rustc_if_unchanged_allowed_paths() -> Vec<&'static str> { - // NOTE: Paths must have the ":!" prefix to tell git to ignore changes in those paths during - // the diff check. - // - // WARNING: Be cautious when adding paths to this list. If a path that influences the compiler build - // is added here, it will cause bootstrap to skip necessary rebuilds, which may lead to risky results. - // For example, "src/bootstrap" should never be included in this list as it plays a crucial role in the - // final output/compiler, which can be significantly affected by changes made to the bootstrap sources. - let mut paths = vec![ - ":!library", - ":!src/tools", - ":!src/librustdoc", - ":!src/rustdoc-json-types", - ":!tests", - ":!triagebot.toml", - ]; - - if !CiEnv::is_ci() { - // When a dependency is added/updated/removed in the library tree (or in some tools), - // `Cargo.lock` will be updated by `cargo`. This update will incorrectly invalidate the - // `download-rustc=if-unchanged` cache. - // - // To prevent this, add `Cargo.lock` to the list of allowed paths when not running on CI. - // This is generally safe because changes to dependencies typically involve modifying - // `Cargo.toml`, which would already invalidate the CI-rustc cache on non-allowed paths. - paths.push(":!Cargo.lock"); - } - - paths -} +/// +/// NOTE: Paths must have the ":!" prefix to tell git to ignore changes in those paths during +/// the diff check. +/// +/// WARNING: Be cautious when adding paths to this list. If a path that influences the compiler build +/// is added here, it will cause bootstrap to skip necessary rebuilds, which may lead to risky results. +/// For example, "src/bootstrap" should never be included in this list as it plays a crucial role in the +/// final output/compiler, which can be significantly affected by changes made to the bootstrap sources. +#[rustfmt::skip] // We don't want rustfmt to oneline this list +pub const RUSTC_IF_UNCHANGED_ALLOWED_PATHS: &[&str] = &[ + ":!library", + ":!src/tools", + ":!src/librustdoc", + ":!src/rustdoc-json-types", + ":!tests", + ":!triagebot.toml", +]; /// Global configuration for the entire build and/or bootstrap. /// @@ -112,6 +101,9 @@ pub struct Config { pub bootstrap_cache_path: Option<PathBuf>, pub extended: bool, pub tools: Option<HashSet<String>>, + /// Specify build configuration specific for some tool, such as enabled features, see [Tool]. + /// The key in the map is the name of the tool, and the value is tool-specific configuration. + pub tool: HashMap<String, Tool>, pub sanitizers: bool, pub profiler: bool, pub omit_git_hash: bool, @@ -142,7 +134,6 @@ pub struct Config { pub jobs: Option<u32>, pub cmd: Subcommand, pub incremental: bool, - pub dry_run: DryRun, pub dump_bootstrap_shims: bool, /// Arguments appearing after `--` to be forwarded to tools, /// e.g. `--fix-broken` or test arguments. @@ -233,7 +224,7 @@ pub struct Config { pub reproducible_artifacts: Vec<String>, - pub build: TargetSelection, + pub host_target: TargetSelection, pub hosts: Vec<TargetSelection>, pub targets: Vec<TargetSelection>, pub local_rebuild: bool, @@ -317,6 +308,8 @@ pub struct Config { /// This is mostly for RA as building the stage1 compiler to check the library tree /// on each code change might be too much for some computers. pub skip_std_check_if_no_download_rustc: bool, + + pub exec_ctx: ExecutionContext, } impl Config { @@ -356,7 +349,7 @@ impl Config { stderr_is_tty: std::io::stderr().is_terminal(), // set by build.rs - build: TargetSelection::from_user(env!("BUILD_TRIPLE")), + host_target: TargetSelection::from_user(env!("BUILD_TRIPLE")), src: { let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")); @@ -373,6 +366,14 @@ impl Config { } } + pub fn set_dry_run(&mut self, dry_run: DryRun) { + self.exec_ctx.set_dry_run(dry_run); + } + + pub fn get_dry_run(&self) -> &DryRun { + self.exec_ctx.get_dry_run() + } + #[cfg_attr( feature = "tracing", instrument(target = "CONFIG_HANDLING", level = "trace", name = "Config::parse", skip_all) @@ -395,6 +396,11 @@ impl Config { get_toml: impl Fn(&Path) -> Result<TomlConfig, toml::de::Error>, ) -> Config { let mut config = Config::default_opts(); + let mut exec_ctx = ExecutionContext::new(); + exec_ctx.set_verbose(flags.verbose); + exec_ctx.set_fail_fast(flags.cmd.fail_fast()); + + config.exec_ctx = exec_ctx; // Set flags. config.paths = std::mem::take(&mut flags.paths); @@ -423,7 +429,7 @@ impl Config { config.on_fail = flags.on_fail; config.cmd = flags.cmd; config.incremental = flags.incremental; - config.dry_run = if flags.dry_run { DryRun::UserSelected } else { DryRun::Disabled }; + config.set_dry_run(if flags.dry_run { DryRun::UserSelected } else { DryRun::Disabled }); config.dump_bootstrap_shims = flags.dump_bootstrap_shims; config.keep_stage = flags.keep_stage; config.keep_stage_std = flags.keep_stage_std; @@ -453,14 +459,9 @@ impl Config { // has already been (kinda-cross-)compiled to Windows land, we require a normal Windows path. cmd.arg("rev-parse").arg("--show-cdup"); // Discard stderr because we expect this to fail when building from a tarball. - let output = cmd - .as_command_mut() - .stderr(std::process::Stdio::null()) - .output() - .ok() - .and_then(|output| if output.status.success() { Some(output) } else { None }); - if let Some(output) = output { - let git_root_relative = String::from_utf8(output.stdout).unwrap(); + let output = cmd.allow_failure().run_capture_stdout(&config); + if output.is_success() { + let git_root_relative = output.stdout(); // We need to canonicalize this path to make sure it uses backslashes instead of forward slashes, // and to resolve any relative components. let git_root = env::current_dir() @@ -555,7 +556,7 @@ impl Config { build.cargo = build.cargo.take().or(std::env::var_os("CARGO").map(|p| p.into())); } - if GitInfo::new(false, &config.src).is_from_tarball() && toml.profile.is_none() { + if config.git_info(false, &config.src).is_from_tarball() && toml.profile.is_none() { toml.profile = Some("dist".into()); } @@ -678,6 +679,7 @@ impl Config { bootstrap_cache_path, extended, tools, + tool, verbose, sanitizers, profiler, @@ -729,7 +731,7 @@ impl Config { config.jobs = Some(threads_from_config(flags.jobs.unwrap_or(jobs.unwrap_or(0)))); if let Some(file_build) = build { - config.build = TargetSelection::from_user(&file_build); + config.host_target = TargetSelection::from_user(&file_build); }; set(&mut config.out, flags.build_dir.or_else(|| build_dir.map(PathBuf::from))); @@ -755,14 +757,19 @@ impl Config { config.download_beta_toolchain(); config .out - .join(config.build) + .join(config.host_target) .join("stage0") .join("bin") - .join(exe("rustc", config.build)) + .join(exe("rustc", config.host_target)) }; config.initial_sysroot = t!(PathBuf::from_str( - output(Command::new(&config.initial_rustc).args(["--print", "sysroot"])).trim() + command(&config.initial_rustc) + .args(["--print", "sysroot"]) + .run_always() + .run_capture_stdout(&config) + .stdout() + .trim() )); config.initial_cargo_clippy = cargo_clippy; @@ -774,7 +781,7 @@ impl Config { cargo } else { config.download_beta_toolchain(); - config.initial_sysroot.join("bin").join(exe("cargo", config.build)) + config.initial_sysroot.join("bin").join(exe("cargo", config.host_target)) }; // NOTE: it's important this comes *after* we set `initial_rustc` just above. @@ -789,7 +796,7 @@ impl Config { } else if let Some(file_host) = host { file_host.iter().map(|h| TargetSelection::from_user(h)).collect() } else { - vec![config.build] + vec![config.host_target] }; config.targets = if let Some(TargetSelectionList(arg_target)) = flags.target { arg_target @@ -819,6 +826,7 @@ impl Config { set(&mut config.full_bootstrap, full_bootstrap); set(&mut config.extended, extended); config.tools = tools; + set(&mut config.tool, tool); set(&mut config.verbose, verbose); set(&mut config.sanitizers, sanitizers); set(&mut config.profiler, profiler); @@ -858,19 +866,21 @@ impl Config { let default = config.channel == "dev"; config.omit_git_hash = toml.rust.as_ref().and_then(|r| r.omit_git_hash).unwrap_or(default); - config.rust_info = GitInfo::new(config.omit_git_hash, &config.src); - config.cargo_info = GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/cargo")); + config.rust_info = config.git_info(config.omit_git_hash, &config.src); + config.cargo_info = + config.git_info(config.omit_git_hash, &config.src.join("src/tools/cargo")); config.rust_analyzer_info = - GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/rust-analyzer")); + config.git_info(config.omit_git_hash, &config.src.join("src/tools/rust-analyzer")); config.clippy_info = - GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/clippy")); - config.miri_info = GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/miri")); + config.git_info(config.omit_git_hash, &config.src.join("src/tools/clippy")); + config.miri_info = + config.git_info(config.omit_git_hash, &config.src.join("src/tools/miri")); config.rustfmt_info = - GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/rustfmt")); + config.git_info(config.omit_git_hash, &config.src.join("src/tools/rustfmt")); config.enzyme_info = - GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/enzyme")); - config.in_tree_llvm_info = GitInfo::new(false, &config.src.join("src/llvm-project")); - config.in_tree_gcc_info = GitInfo::new(false, &config.src.join("src/gcc")); + config.git_info(config.omit_git_hash, &config.src.join("src/tools/enzyme")); + config.in_tree_llvm_info = config.git_info(false, &config.src.join("src/llvm-project")); + config.in_tree_gcc_info = config.git_info(false, &config.src.join("src/gcc")); config.vendor = vendor.unwrap_or( config.rust_info.is_from_tarball() @@ -921,17 +931,19 @@ impl Config { } if config.llvm_from_ci { - let triple = &config.build.triple; + let triple = &config.host_target.triple; let ci_llvm_bin = config.ci_llvm_root().join("bin"); let build_target = config .target_config - .entry(config.build) + .entry(config.host_target) .or_insert_with(|| Target::from_triple(triple)); check_ci_llvm!(build_target.llvm_config); check_ci_llvm!(build_target.llvm_filecheck); - build_target.llvm_config = Some(ci_llvm_bin.join(exe("llvm-config", config.build))); - build_target.llvm_filecheck = Some(ci_llvm_bin.join(exe("FileCheck", config.build))); + build_target.llvm_config = + Some(ci_llvm_bin.join(exe("llvm-config", config.host_target))); + build_target.llvm_filecheck = + Some(ci_llvm_bin.join(exe("FileCheck", config.host_target))); } config.apply_dist_config(toml.dist); @@ -948,7 +960,7 @@ impl Config { ); } - if config.lld_enabled && config.is_system_llvm(config.build) { + if config.lld_enabled && config.is_system_llvm(config.host_target) { eprintln!( "Warning: LLD is enabled when using external llvm-config. LLD will not be built and copied to the sysroot." ); @@ -1030,28 +1042,13 @@ impl Config { } pub fn dry_run(&self) -> bool { - match self.dry_run { - DryRun::Disabled => false, - DryRun::SelfCheck | DryRun::UserSelected => true, - } + self.exec_ctx.dry_run() } pub fn is_explicit_stage(&self) -> bool { self.explicit_stage_from_cli || self.explicit_stage_from_config } - /// Runs a command, printing out nice contextual information if it fails. - /// Exits if the command failed to execute at all, otherwise returns its - /// `status.success()`. - #[deprecated = "use `Builder::try_run` instead where possible"] - pub(crate) fn try_run(&self, cmd: &mut Command) -> Result<(), ()> { - if self.dry_run() { - return Ok(()); - } - self.verbose(|| println!("running: {cmd:?}")); - build_helper::util::try_run(cmd, self.is_verbose()) - } - pub(crate) fn test_args(&self) -> Vec<&str> { let mut test_args = match self.cmd { Subcommand::Test { ref test_args, .. } @@ -1085,7 +1082,7 @@ impl Config { let mut git = helpers::git(Some(&self.src)); git.arg("show").arg(format!("{commit}:{}", file.to_str().unwrap())); - output(git.as_command_mut()) + git.run_capture_stdout(self).stdout() } /// Bootstrap embeds a version number into the name of shared libraries it uploads in CI. @@ -1157,13 +1154,13 @@ impl Config { /// The absolute path to the downloaded LLVM artifacts. pub(crate) fn ci_llvm_root(&self) -> PathBuf { assert!(self.llvm_from_ci); - self.out.join(self.build).join("ci-llvm") + self.out.join(self.host_target).join("ci-llvm") } /// Directory where the extracted `rustc-dev` component is stored. pub(crate) fn ci_rustc_dir(&self) -> PathBuf { assert!(self.download_rustc()); - self.out.join(self.build).join("ci-rustc") + self.out.join(self.host_target).join("ci-rustc") } /// Determine whether llvm should be linked dynamically. @@ -1247,7 +1244,7 @@ impl Config { // Check the config compatibility // FIXME: this doesn't cover `--set` flags yet. let res = check_incompatible_options_for_ci_rustc( - self.build, + self.host_target, current_config_toml, ci_config_toml, ); @@ -1273,9 +1270,7 @@ impl Config { /// Runs a function if verbosity is greater than 0 pub fn verbose(&self, f: impl Fn()) { - if self.is_verbose() { - f() - } + self.exec_ctx.verbose(f); } pub fn any_sanitizers_to_build(&self) -> bool { @@ -1337,7 +1332,7 @@ impl Config { // NOTE: The check for the empty directory is here because when running x.py the first time, // the submodule won't be checked out. Check it out now so we can build it. - if !GitInfo::new(false, &absolute_path).is_managed_git_subrepository() + if !self.git_info(false, &absolute_path).is_managed_git_subrepository() && !helpers::dir_is_empty(&absolute_path) { return; @@ -1356,16 +1351,16 @@ impl Config { }; // Determine commit checked out in submodule. - let checked_out_hash = output(submodule_git().args(["rev-parse", "HEAD"]).as_command_mut()); + let checked_out_hash = + submodule_git().args(["rev-parse", "HEAD"]).run_capture_stdout(self).stdout(); let checked_out_hash = checked_out_hash.trim_end(); // Determine commit that the submodule *should* have. - let recorded = output( - helpers::git(Some(&self.src)) - .run_always() - .args(["ls-tree", "HEAD"]) - .arg(relative_path) - .as_command_mut(), - ); + let recorded = helpers::git(Some(&self.src)) + .run_always() + .args(["ls-tree", "HEAD"]) + .arg(relative_path) + .run_capture_stdout(self) + .stdout(); let actual_hash = recorded .split_whitespace() @@ -1389,21 +1384,20 @@ impl Config { let update = |progress: bool| { // Git is buggy and will try to fetch submodules from the tracking branch for *this* repository, // even though that has no relation to the upstream for the submodule. - let current_branch = output_result( - helpers::git(Some(&self.src)) - .allow_failure() - .run_always() - .args(["symbolic-ref", "--short", "HEAD"]) - .as_command_mut(), - ) - .map(|b| b.trim().to_owned()); + let current_branch = helpers::git(Some(&self.src)) + .allow_failure() + .run_always() + .args(["symbolic-ref", "--short", "HEAD"]) + .run_capture(self); let mut git = helpers::git(Some(&self.src)).allow_failure(); git.run_always(); - if let Ok(branch) = current_branch { + if current_branch.is_success() { // If there is a tag named after the current branch, git will try to disambiguate by prepending `heads/` to the branch name. // This syntax isn't accepted by `branch.{branch}`. Strip it. - let branch = branch.strip_prefix("heads/").unwrap_or(&branch); + let branch = current_branch.stdout(); + let branch = branch.trim(); + let branch = branch.strip_prefix("heads/").unwrap_or(branch); git.arg("-c").arg(format!("branch.{branch}.remote=origin")); } git.args(["submodule", "update", "--init", "--recursive", "--depth=1"]); @@ -1448,7 +1442,8 @@ impl Config { return; } - let stage0_output = output(Command::new(program_path).arg("--version")); + let stage0_output = + command(program_path).arg("--version").run_capture_stdout(self).stdout(); let mut stage0_output = stage0_output.lines().next().unwrap().split(' '); let stage0_name = stage0_output.next().unwrap(); @@ -1485,7 +1480,7 @@ impl Config { debug_assertions_requested: bool, llvm_assertions: bool, ) -> Option<String> { - if !is_download_ci_available(&self.build.triple, llvm_assertions) { + if !is_download_ci_available(&self.host_target.triple, llvm_assertions) { return None; } @@ -1516,7 +1511,7 @@ impl Config { let commit = if self.rust_info.is_managed_git_subrepository() { // Look for a version to compare to based on the current commit. // Only commits merged by bors will have CI artifacts. - let freshness = self.check_path_modifications(&rustc_if_unchanged_allowed_paths()); + let freshness = self.check_path_modifications(RUSTC_IF_UNCHANGED_ALLOWED_PATHS); self.verbose(|| { eprintln!("rustc freshness: {freshness:?}"); }); @@ -1721,7 +1716,7 @@ impl Config { /// Checks if the given target is the same as the host target. pub fn is_host_target(&self, target: TargetSelection) -> bool { - self.build == target + self.host_target == target } /// Returns `true` if this is an external version of LLVM not managed by bootstrap. @@ -1754,4 +1749,18 @@ impl Config { _ => !self.is_system_llvm(target), } } + + pub fn exec_ctx(&self) -> &ExecutionContext { + &self.exec_ctx + } + + pub fn git_info(&self, omit_git_hash: bool, dir: &Path) -> GitInfo { + GitInfo::new(omit_git_hash, dir, self) + } +} + +impl AsRef<ExecutionContext> for Config { + fn as_ref(&self) -> &ExecutionContext { + &self.exec_ctx + } } diff --git a/src/bootstrap/src/core/config/flags.rs b/src/bootstrap/src/core/config/flags.rs index 30617f58d43..ea0251e209a 100644 --- a/src/bootstrap/src/core/config/flags.rs +++ b/src/bootstrap/src/core/config/flags.rs @@ -59,7 +59,7 @@ pub struct Flags { pub build_dir: Option<PathBuf>, #[arg(global = true, long, value_hint = clap::ValueHint::Other, value_name = "BUILD")] - /// build target of the stage0 compiler + /// host target of the stage0 compiler pub build: Option<String>, #[arg(global = true, long, value_hint = clap::ValueHint::Other, value_name = "HOST", value_parser = target_selection_list)] @@ -209,7 +209,8 @@ impl Flags { HelpVerboseOnly::try_parse_from(normalize_args(args)) { println!("NOTE: updating submodules before printing available paths"); - let config = Config::parse(Self::parse(&[String::from("build")])); + let flags = Self::parse(&[String::from("build")]); + let config = Config::parse(flags); let build = Build::new(config); let paths = Builder::get_help(&build, subcommand); if let Some(s) = paths { diff --git a/src/bootstrap/src/core/config/tests.rs b/src/bootstrap/src/core/config/tests.rs index e660addfb2c..50eba12aba7 100644 --- a/src/bootstrap/src/core/config/tests.rs +++ b/src/bootstrap/src/core/config/tests.rs @@ -11,7 +11,7 @@ use serde::Deserialize; use super::flags::Flags; use super::toml::change_id::ChangeIdWrapper; -use super::{Config, rustc_if_unchanged_allowed_paths}; +use super::{Config, RUSTC_IF_UNCHANGED_ALLOWED_PATHS}; use crate::ChangeId; use crate::core::build_steps::clippy::{LintConfig, get_clippy_rules_in_order}; use crate::core::build_steps::llvm; @@ -459,7 +459,7 @@ fn jobs_precedence() { #[test] fn check_rustc_if_unchanged_paths() { let config = parse(""); - let normalised_allowed_paths: Vec<_> = rustc_if_unchanged_allowed_paths() + let normalised_allowed_paths: Vec<_> = RUSTC_IF_UNCHANGED_ALLOWED_PATHS .iter() .map(|t| { t.strip_prefix(":!").expect(&format!("{t} doesn't have ':!' prefix, but it should.")) diff --git a/src/bootstrap/src/core/config/toml/build.rs b/src/bootstrap/src/core/config/toml/build.rs index 85ded3c87d9..98e1194de72 100644 --- a/src/bootstrap/src/core/config/toml/build.rs +++ b/src/bootstrap/src/core/config/toml/build.rs @@ -6,6 +6,8 @@ //! various feature flags. These options apply across different stages and components //! unless specifically overridden by other configuration sections or command-line flags. +use std::collections::HashMap; + use serde::{Deserialize, Deserializer}; use crate::core::config::toml::ReplaceOpt; @@ -42,6 +44,7 @@ define_config! { bootstrap_cache_path: Option<PathBuf> = "bootstrap-cache-path", extended: Option<bool> = "extended", tools: Option<HashSet<String>> = "tools", + tool: Option<HashMap<String, Tool>> = "tool", verbose: Option<usize> = "verbose", sanitizers: Option<bool> = "sanitizers", profiler: Option<bool> = "profiler", @@ -70,3 +73,11 @@ define_config! { exclude: Option<Vec<PathBuf>> = "exclude", } } + +define_config! { + /// Configuration specific for some tool, e.g. which features to enable during build. + #[derive(Default, Clone)] + struct Tool { + features: Option<Vec<String>> = "features", + } +} diff --git a/src/bootstrap/src/core/config/toml/mod.rs b/src/bootstrap/src/core/config/toml/mod.rs index ac4e249e580..01eb243159c 100644 --- a/src/bootstrap/src/core/config/toml/mod.rs +++ b/src/bootstrap/src/core/config/toml/mod.rs @@ -147,7 +147,7 @@ impl Config { } let builder_config_path = - self.out.join(self.build.triple).join(build_name).join(BUILDER_CONFIG_FILENAME); + self.out.join(self.host_target.triple).join(build_name).join(BUILDER_CONFIG_FILENAME); Self::get_toml(&builder_config_path) } diff --git a/src/bootstrap/src/core/config/toml/rust.rs b/src/bootstrap/src/core/config/toml/rust.rs index 81f95f356a5..642f2f2271d 100644 --- a/src/bootstrap/src/core/config/toml/rust.rs +++ b/src/bootstrap/src/core/config/toml/rust.rs @@ -321,11 +321,11 @@ pub fn check_incompatible_options_for_ci_rustc( rpath, channel, description, - incremental, default_linker, std_features, // Rest of the options can simply be ignored. + incremental: _, debug: _, codegen_units: _, codegen_units_std: _, @@ -389,7 +389,6 @@ pub fn check_incompatible_options_for_ci_rustc( warn!(current_rust_config.channel, channel, "rust"); warn!(current_rust_config.description, description, "rust"); - warn!(current_rust_config.incremental, incremental, "rust"); Ok(()) } @@ -622,13 +621,13 @@ impl Config { // thus, disabled // - similarly, lld will not be built nor used by default when explicitly asked not to, e.g. // when the config sets `rust.lld = false` - if self.build.triple == "x86_64-unknown-linux-gnu" - && self.hosts == [self.build] + if self.host_target.triple == "x86_64-unknown-linux-gnu" + && self.hosts == [self.host_target] && (self.channel == "dev" || self.channel == "nightly") { let no_llvm_config = self .target_config - .get(&self.build) + .get(&self.host_target) .is_some_and(|target_config| target_config.llvm_config.is_none()); let enable_lld = self.llvm_from_ci || no_llvm_config; // Prefer the config setting in case an explicit opt-out is needed. diff --git a/src/bootstrap/src/core/config/toml/target.rs b/src/bootstrap/src/core/config/toml/target.rs index 7f074d1b25e..b9f6780ca3f 100644 --- a/src/bootstrap/src/core/config/toml/target.rs +++ b/src/bootstrap/src/core/config/toml/target.rs @@ -84,7 +84,7 @@ pub struct Target { impl Target { pub fn from_triple(triple: &str) -> Self { let mut target: Self = Default::default(); - if triple.contains("-none") || triple.contains("nvptx") || triple.contains("switch") { + if !build_helper::targets::target_supports_std(triple) { target.no_std = true; } if triple.contains("emscripten") { @@ -101,7 +101,7 @@ impl Config { let mut target = Target::from_triple(&triple); if let Some(ref s) = cfg.llvm_config { - if self.download_rustc_commit.is_some() && triple == *self.build.triple { + if self.download_rustc_commit.is_some() && triple == *self.host_target.triple { panic!( "setting llvm_config for the host is incompatible with download-rustc" ); diff --git a/src/bootstrap/src/core/download.rs b/src/bootstrap/src/core/download.rs index ba00b405c61..88a58e580e6 100644 --- a/src/bootstrap/src/core/download.rs +++ b/src/bootstrap/src/core/download.rs @@ -3,7 +3,6 @@ use std::ffi::OsString; use std::fs::{self, File}; use std::io::{BufRead, BufReader, BufWriter, ErrorKind, Write}; use std::path::{Path, PathBuf}; -use std::process::{Command, Stdio}; use std::sync::OnceLock; use xz2::bufread::XzDecoder; @@ -16,14 +15,7 @@ use crate::{Config, t}; static SHOULD_FIX_BINS_AND_DYLIBS: OnceLock<bool> = OnceLock::new(); -/// `Config::try_run` wrapper for this module to avoid warnings on `try_run`, since we don't have access to a `builder` yet. -fn try_run(config: &Config, cmd: &mut Command) -> Result<(), ()> { - #[expect(deprecated)] - config.try_run(cmd) -} - -fn extract_curl_version(out: &[u8]) -> semver::Version { - let out = String::from_utf8_lossy(out); +fn extract_curl_version(out: String) -> semver::Version { // The output should look like this: "curl <major>.<minor>.<patch> ..." out.lines() .next() @@ -32,18 +24,21 @@ fn extract_curl_version(out: &[u8]) -> semver::Version { .unwrap_or(semver::Version::new(1, 0, 0)) } -fn curl_version() -> semver::Version { - let mut curl = Command::new("curl"); +fn curl_version(config: &Config) -> semver::Version { + let mut curl = command("curl"); curl.arg("-V"); - let Ok(out) = curl.output() else { return semver::Version::new(1, 0, 0) }; - let out = out.stdout; - extract_curl_version(&out) + let curl = curl.run_capture_stdout(config); + if curl.is_failure() { + return semver::Version::new(1, 0, 0); + } + let output = curl.stdout(); + extract_curl_version(output) } /// Generic helpers that are useful anywhere in bootstrap. impl Config { pub fn is_verbose(&self) -> bool { - self.verbose > 0 + self.exec_ctx.is_verbose() } pub(crate) fn create<P: AsRef<Path>>(&self, path: P, s: &str) { @@ -85,20 +80,14 @@ impl Config { /// on NixOS fn should_fix_bins_and_dylibs(&self) -> bool { let val = *SHOULD_FIX_BINS_AND_DYLIBS.get_or_init(|| { - match Command::new("uname").arg("-s").stderr(Stdio::inherit()).output() { - Err(_) => return false, - Ok(output) if !output.status.success() => return false, - Ok(output) => { - let mut os_name = output.stdout; - if os_name.last() == Some(&b'\n') { - os_name.pop(); - } - if os_name != b"Linux" { - return false; - } - } + let uname = command("uname").allow_failure().arg("-s").run_capture_stdout(self); + if uname.is_failure() { + return false; + } + let output = uname.stdout(); + if !output.starts_with("Linux") { + return false; } - // If the user has asked binaries to be patched for Nix, then // don't check for NixOS or `/lib`. // NOTE: this intentionally comes after the Linux check: @@ -173,23 +162,18 @@ impl Config { ]; } "; - nix_build_succeeded = try_run( - self, - Command::new("nix-build").args([ - Path::new("-E"), - Path::new(NIX_EXPR), - Path::new("-o"), - &nix_deps_dir, - ]), - ) - .is_ok(); + nix_build_succeeded = command("nix-build") + .allow_failure() + .args([Path::new("-E"), Path::new(NIX_EXPR), Path::new("-o"), &nix_deps_dir]) + .run_capture_stdout(self) + .is_success(); nix_deps_dir }); if !nix_build_succeeded { return; } - let mut patchelf = Command::new(nix_deps_dir.join("bin/patchelf")); + let mut patchelf = command(nix_deps_dir.join("bin/patchelf")); patchelf.args(&[ OsString::from("--add-rpath"), OsString::from(t!(fs::canonicalize(nix_deps_dir)).join("lib")), @@ -200,8 +184,8 @@ impl Config { let dynamic_linker = t!(fs::read_to_string(dynamic_linker_path)); patchelf.args(["--set-interpreter", dynamic_linker.trim_end()]); } - - let _ = try_run(self, patchelf.arg(fname)); + patchelf.arg(fname); + let _ = patchelf.allow_failure().run_capture_stdout(self); } fn download_file(&self, url: &str, dest_path: &Path, help_on_error: &str) { @@ -267,15 +251,15 @@ impl Config { curl.arg("--progress-bar"); } // --retry-all-errors was added in 7.71.0, don't use it if curl is old. - if curl_version() >= semver::Version::new(7, 71, 0) { + if curl_version(self) >= semver::Version::new(7, 71, 0) { curl.arg("--retry-all-errors"); } curl.arg(url); if !self.check_run(&mut curl) { - if self.build.contains("windows-msvc") { + if self.host_target.contains("windows-msvc") { eprintln!("Fallback to PowerShell"); for _ in 0..3 { - if try_run(self, Command::new("PowerShell.exe").args([ + let powershell = command("PowerShell.exe").allow_failure().args([ "/nologo", "-Command", "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12;", @@ -283,9 +267,12 @@ impl Config { "(New-Object System.Net.WebClient).DownloadFile('{}', '{}')", url, tempfile.to_str().expect("invalid UTF-8 not supported with powershell downloads"), ), - ])).is_err() { + ]).run_capture_stdout(self); + + if powershell.is_failure() { return; } + eprintln!("\nspurious failure, trying again"); } } @@ -424,7 +411,7 @@ impl Config { let date = &self.stage0_metadata.compiler.date; let version = &self.stage0_metadata.compiler.version; - let host = self.build; + let host = self.host_target; let clippy_stamp = BuildStamp::new(&self.initial_sysroot).with_prefix("clippy").add_stamp(date); @@ -462,7 +449,7 @@ impl Config { let VersionMetadata { date, version } = self.stage0_metadata.rustfmt.as_ref()?; let channel = format!("{version}-{date}"); - let host = self.build; + let host = self.host_target; let bin_root = self.out.join(host).join("rustfmt"); let rustfmt_path = bin_root.join("bin").join(exe("rustfmt", host)); let rustfmt_stamp = BuildStamp::new(&bin_root).with_prefix("rustfmt").add_stamp(channel); @@ -570,11 +557,11 @@ impl Config { extra_components: &[&str], download_component: fn(&Config, String, &str, &str), ) { - let host = self.build.triple; + let host = self.host_target.triple; let bin_root = self.out.join(host).join(sysroot); let rustc_stamp = BuildStamp::new(&bin_root).with_prefix("rustc").add_stamp(stamp_key); - if !bin_root.join("bin").join(exe("rustc", self.build)).exists() + if !bin_root.join("bin").join(exe("rustc", self.host_target)).exists() || !rustc_stamp.is_up_to_date() { if bin_root.exists() { @@ -643,7 +630,7 @@ impl Config { t!(fs::create_dir_all(&cache_dir)); } - let bin_root = self.out.join(self.build).join(destination); + let bin_root = self.out.join(self.host_target).join(destination); let tarball = cache_dir.join(&filename); let (base_url, url, should_verify) = match mode { DownloadSource::CI => { @@ -772,7 +759,7 @@ download-rustc = false let now = std::time::SystemTime::now(); let file_times = fs::FileTimes::new().set_accessed(now).set_modified(now); - let llvm_config = llvm_root.join("bin").join(exe("llvm-config", self.build)); + let llvm_config = llvm_root.join("bin").join(exe("llvm-config", self.host_target)); t!(crate::utils::helpers::set_file_times(llvm_config, file_times)); if self.should_fix_bins_and_dylibs() { @@ -827,7 +814,7 @@ download-rustc = false &self.stage0_metadata.config.artifacts_server }; let version = self.artifact_version_part(llvm_sha); - let filename = format!("rust-dev-{}-{}.tar.xz", version, self.build.triple); + let filename = format!("rust-dev-{}-{}.tar.xz", version, self.host_target.triple); let tarball = rustc_cache.join(&filename); if !tarball.exists() { let help_on_error = "ERROR: failed to download llvm from ci @@ -857,7 +844,7 @@ download-rustc = false } let base = &self.stage0_metadata.config.artifacts_server; let version = self.artifact_version_part(gcc_sha); - let filename = format!("gcc-{version}-{}.tar.xz", self.build.triple); + let filename = format!("gcc-{version}-{}.tar.xz", self.host_target.triple); let tarball = gcc_cache.join(&filename); if !tarball.exists() { let help_on_error = "ERROR: failed to download gcc from ci diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs index 59ae303e21e..ef776e21943 100644 --- a/src/bootstrap/src/core/sanity.rs +++ b/src/bootstrap/src/core/sanity.rs @@ -109,9 +109,9 @@ pub fn check(build: &mut Build) { // Ensure that a compatible version of libstdc++ is available on the system when using `llvm.download-ci-llvm`. #[cfg(not(test))] - if !build.config.dry_run() && !build.build.is_msvc() && build.config.llvm_from_ci { + if !build.config.dry_run() && !build.host_target.is_msvc() && build.config.llvm_from_ci { let builder = Builder::new(build); - let libcxx_version = builder.ensure(tool::LibcxxVersionTool { target: build.build }); + let libcxx_version = builder.ensure(tool::LibcxxVersionTool { target: build.host_target }); match libcxx_version { tool::LibcxxVersion::Gnu(version) => { @@ -237,7 +237,7 @@ than building it. } // skip check for cross-targets - if skip_target_sanity && target != &build.build { + if skip_target_sanity && target != &build.host_target { continue; } @@ -308,7 +308,7 @@ than building it. if build.config.llvm_enabled(*host) { // Externally configured LLVM requires FileCheck to exist - let filecheck = build.llvm_filecheck(build.build); + let filecheck = build.llvm_filecheck(build.host_target); if !filecheck.starts_with(&build.out) && !filecheck.exists() && build.config.codegen_tests @@ -333,7 +333,7 @@ than building it. } // skip check for cross-targets - if skip_target_sanity && target != &build.build { + if skip_target_sanity && target != &build.host_target { continue; } @@ -364,7 +364,7 @@ than building it. // Cygwin. The Cygwin build does not have generators for Visual // Studio, so detect that here and error. let out = - command("cmake").arg("--help").run_always().run_capture_stdout(build).stdout(); + command("cmake").arg("--help").run_always().run_capture_stdout(&build).stdout(); if !out.contains("Visual Studio") { panic!( " diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index 7db57889009..25e59bfe3a8 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -32,6 +32,7 @@ use cc::Tool; use termcolor::{ColorChoice, StandardStream, WriteColor}; use utils::build_stamp::BuildStamp; use utils::channel::GitInfo; +use utils::execution_context::ExecutionContext; use crate::core::builder; use crate::core::builder::Kind; @@ -174,7 +175,7 @@ pub struct Build { verbosity: usize, /// Build triple for the pre-compiled snapshot compiler. - build: TargetSelection, + host_target: TargetSelection, /// Which triples to produce a compiler toolchain for. hosts: Vec<TargetSelection>, /// Which triples to build libraries (core/alloc/std/test/proc_macro) for. @@ -198,7 +199,6 @@ pub struct Build { crates: HashMap<String, Crate>, crate_paths: HashMap<PathBuf, String>, is_sudo: bool, - delayed_failures: RefCell<Vec<String>>, prerelease_version: Cell<Option<u32>>, #[cfg(feature = "build-metrics")] @@ -420,7 +420,7 @@ impl Build { if bootstrap_out.ends_with("deps") { bootstrap_out.pop(); } - if !bootstrap_out.join(exe("rustc", config.build)).exists() && !cfg!(test) { + if !bootstrap_out.join(exe("rustc", config.host_target)).exists() && !cfg!(test) { // this restriction can be lifted whenever https://github.com/rust-lang/rfcs/pull/3028 is implemented panic!( "`rustc` not found in {}, run `cargo build --bins` before `cargo run`", @@ -436,7 +436,9 @@ impl Build { initial_lld, initial_relative_libdir, initial_rustc: config.initial_rustc.clone(), - initial_rustdoc: config.initial_rustc.with_file_name(exe("rustdoc", config.build)), + initial_rustdoc: config + .initial_rustc + .with_file_name(exe("rustdoc", config.host_target)), initial_cargo: config.initial_cargo.clone(), initial_sysroot: config.initial_sysroot.clone(), local_rebuild: config.local_rebuild, @@ -444,7 +446,7 @@ impl Build { doc_tests: config.cmd.doc_tests(), verbosity: config.verbose, - build: config.build, + host_target: config.host_target, hosts: config.hosts.clone(), targets: config.targets.clone(), @@ -469,7 +471,6 @@ impl Build { crates: HashMap::new(), crate_paths: HashMap::new(), is_sudo, - delayed_failures: RefCell::new(Vec::new()), prerelease_version: Cell::new(None), #[cfg(feature = "build-metrics")] @@ -522,7 +523,7 @@ impl Build { } // Create symbolic link to use host sysroot from a consistent path (e.g., in the rust-analyzer config file). - let build_triple = build.out.join(build.build); + let build_triple = build.out.join(build.host_target); t!(fs::create_dir_all(&build_triple)); let host = build.out.join("host"); if host.is_symlink() { @@ -629,7 +630,7 @@ impl Build { return; } - if GitInfo::new(false, Path::new(submodule)).is_managed_git_subrepository() { + if config.git_info(false, Path::new(submodule)).is_managed_git_subrepository() { config.update_submodule(submodule); } } @@ -684,7 +685,7 @@ impl Build { #[cfg(feature = "tracing")] let _sanity_check_span = span!(tracing::Level::DEBUG, "(1) executing dry-run sanity-check").entered(); - self.config.dry_run = DryRun::SelfCheck; + self.config.set_dry_run(DryRun::SelfCheck); let builder = builder::Builder::new(self); builder.execute_cli(); } @@ -694,7 +695,7 @@ impl Build { #[cfg(feature = "tracing")] let _actual_run_span = span!(tracing::Level::DEBUG, "(2) executing actual run").entered(); - self.config.dry_run = DryRun::Disabled; + self.config.set_dry_run(DryRun::Disabled); let builder = builder::Builder::new(self); builder.execute_cli(); } @@ -710,14 +711,7 @@ impl Build { debug!("checking for postponed test failures from `test --no-fail-fast`"); // Check for postponed failures from `test --no-fail-fast`. - let failures = self.delayed_failures.borrow(); - if !failures.is_empty() { - eprintln!("\n{} command(s) did not execute successfully:\n", failures.len()); - for failure in failures.iter() { - eprintln!(" - {failure}\n"); - } - exit!(1); - } + self.config.exec_ctx().report_failures_and_exit(); #[cfg(feature = "build-metrics")] self.metrics.persist(self); @@ -940,7 +934,7 @@ impl Build { /// Returns the libdir of the snapshot compiler. fn rustc_snapshot_libdir(&self) -> PathBuf { - self.rustc_snapshot_sysroot().join(libdir(self.config.build)) + self.rustc_snapshot_sysroot().join(libdir(self.config.host_target)) } /// Returns the sysroot of the snapshot compiler. @@ -953,133 +947,6 @@ impl Build { }) } - /// Execute a command and return its output. - /// Note: Ideally, you should use one of the BootstrapCommand::run* functions to - /// execute commands. They internally call this method. - #[track_caller] - fn run( - &self, - command: &mut BootstrapCommand, - stdout: OutputMode, - stderr: OutputMode, - ) -> CommandOutput { - command.mark_as_executed(); - if self.config.dry_run() && !command.run_always { - return CommandOutput::default(); - } - - #[cfg(feature = "tracing")] - let _run_span = trace_cmd!(command); - - let created_at = command.get_created_location(); - let executed_at = std::panic::Location::caller(); - - self.verbose(|| { - println!("running: {command:?} (created at {created_at}, executed at {executed_at})") - }); - - let cmd = command.as_command_mut(); - cmd.stdout(stdout.stdio()); - cmd.stderr(stderr.stdio()); - - let output = cmd.output(); - - use std::fmt::Write; - - let mut message = String::new(); - let output: CommandOutput = match output { - // Command has succeeded - Ok(output) if output.status.success() => { - CommandOutput::from_output(output, stdout, stderr) - } - // Command has started, but then it failed - Ok(output) => { - writeln!( - message, - r#" -Command {command:?} did not execute successfully. -Expected success, got {} -Created at: {created_at} -Executed at: {executed_at}"#, - output.status, - ) - .unwrap(); - - let output: CommandOutput = CommandOutput::from_output(output, stdout, stderr); - - // If the output mode is OutputMode::Capture, we can now print the output. - // If it is OutputMode::Print, then the output has already been printed to - // stdout/stderr, and we thus don't have anything captured to print anyway. - if stdout.captures() { - writeln!(message, "\nSTDOUT ----\n{}", output.stdout().trim()).unwrap(); - } - if stderr.captures() { - writeln!(message, "\nSTDERR ----\n{}", output.stderr().trim()).unwrap(); - } - output - } - // The command did not even start - Err(e) => { - writeln!( - message, - "\n\nCommand {command:?} did not execute successfully.\ - \nIt was not possible to execute the command: {e:?}" - ) - .unwrap(); - CommandOutput::did_not_start(stdout, stderr) - } - }; - - let fail = |message: &str, output: CommandOutput| -> ! { - if self.is_verbose() { - println!("{message}"); - } else { - let (stdout, stderr) = (output.stdout_if_present(), output.stderr_if_present()); - // If the command captures output, the user would not see any indication that - // it has failed. In this case, print a more verbose error, since to provide more - // context. - if stdout.is_some() || stderr.is_some() { - if let Some(stdout) = - output.stdout_if_present().take_if(|s| !s.trim().is_empty()) - { - println!("STDOUT:\n{stdout}\n"); - } - if let Some(stderr) = - output.stderr_if_present().take_if(|s| !s.trim().is_empty()) - { - println!("STDERR:\n{stderr}\n"); - } - println!("Command {command:?} has failed. Rerun with -v to see more details."); - } else { - println!("Command has failed. Rerun with -v to see more details."); - } - } - exit!(1); - }; - - if !output.is_success() { - match command.failure_behavior { - BehaviorOnFailure::DelayFail => { - if self.fail_fast { - fail(&message, output); - } - - let mut failures = self.delayed_failures.borrow_mut(); - failures.push(message); - } - BehaviorOnFailure::Exit => { - fail(&message, output); - } - BehaviorOnFailure::Ignore => { - // If failures are allowed, either the error has been printed already - // (OutputMode::Print) or the user used a capture output mode and wants to - // handle the error output on their own. - } - } - } - output - } - /// Check if verbosity is greater than the `level` pub fn is_verbose_than(&self, level: usize) -> bool { self.verbosity > level @@ -1093,7 +960,7 @@ Executed at: {executed_at}"#, } fn info(&self, msg: &str) { - match self.config.dry_run { + match self.config.get_dry_run() { DryRun::SelfCheck => (), DryRun::Disabled | DryRun::UserSelected => { println!("{msg}"); @@ -1108,7 +975,7 @@ Executed at: {executed_at}"#, what: impl Display, target: impl Into<Option<TargetSelection>>, ) -> Option<gha::Group> { - self.msg(Kind::Clippy, self.config.stage, what, self.config.build, target) + self.msg(Kind::Clippy, self.config.stage, what, self.config.host_target, target) } #[must_use = "Groups should not be dropped until the Step finishes running"] @@ -1123,7 +990,7 @@ Executed at: {executed_at}"#, Kind::Check, custom_stage.unwrap_or(self.config.stage), what, - self.config.build, + self.config.host_target, target, ) } @@ -1216,7 +1083,7 @@ Executed at: {executed_at}"#, #[track_caller] fn group(&self, msg: &str) -> Option<gha::Group> { - match self.config.dry_run { + match self.config.get_dry_run() { DryRun::SelfCheck => None, DryRun::Disabled | DryRun::UserSelected => Some(gha::group(msg)), } @@ -1381,7 +1248,7 @@ Executed at: {executed_at}"#, Some(self.cc(target)) } else if self.config.lld_mode.is_used() && self.is_lld_direct_linker(target) - && self.build == target + && self.host_target == target { match self.config.lld_mode { LldMode::SelfContained => Some(self.initial_lld.clone()), @@ -1535,7 +1402,7 @@ Executed at: {executed_at}"#, /// Path to the python interpreter to use fn python(&self) -> &Path { - if self.config.build.ends_with("apple-darwin") { + if self.config.host_target.ends_with("apple-darwin") { // Force /usr/bin/python3 on macOS for LLDB tests because we're loading the // LLDB plugin's compiled module which only works with the system python // (namely not Homebrew-installed python) @@ -1575,7 +1442,7 @@ Executed at: {executed_at}"#, !self.config.full_bootstrap && !self.config.download_rustc() && stage >= 2 - && (self.hosts.contains(&target) || target == self.build) + && (self.hosts.contains(&target) || target == self.host_target) } /// Checks whether the `compiler` compiling for `target` should be forced to @@ -2012,7 +1879,7 @@ to download LLVM rather than building it. // In these cases we automatically enable Ninja if we find it in the // environment. if !self.config.ninja_in_file - && self.config.build.is_msvc() + && self.config.host_target.is_msvc() && cmd_finder.maybe_have("ninja").is_some() { return true; @@ -2045,6 +1912,16 @@ to download LLVM rather than building it. stream.reset().unwrap(); result } + + pub fn exec_ctx(&self) -> &ExecutionContext { + &self.config.exec_ctx + } +} + +impl AsRef<ExecutionContext> for Build { + fn as_ref(&self) -> &ExecutionContext { + &self.config.exec_ctx + } } #[cfg(unix)] @@ -2071,7 +1948,7 @@ impl Compiler { /// Returns `true` if this is a snapshot compiler for `build`'s configuration pub fn is_snapshot(&self, build: &Build) -> bool { - self.stage == 0 && self.host == build.build + self.stage == 0 && self.host == build.host_target } /// Indicates whether the compiler was forced to use a specific stage. diff --git a/src/bootstrap/src/utils/cc_detect.rs b/src/bootstrap/src/utils/cc_detect.rs index 5c9e30706ee..851bb38074e 100644 --- a/src/bootstrap/src/utils/cc_detect.rs +++ b/src/bootstrap/src/utils/cc_detect.rs @@ -39,7 +39,7 @@ fn new_cc_build(build: &Build, target: TargetSelection) -> cc::Build { // Compress debuginfo .flag_if_supported("-gz") .target(&target.triple) - .host(&build.build.triple); + .host(&build.host_target.triple); match build.crt_static(target) { Some(a) => { cfg.static_crt(a); @@ -70,7 +70,7 @@ pub fn find(build: &Build) { | crate::Subcommand::Suggest { .. } | crate::Subcommand::Format { .. } | crate::Subcommand::Setup { .. } => { - build.hosts.iter().cloned().chain(iter::once(build.build)).collect() + build.hosts.iter().cloned().chain(iter::once(build.host_target)).collect() } _ => { @@ -81,7 +81,7 @@ pub fn find(build: &Build) { .iter() .chain(&build.hosts) .cloned() - .chain(iter::once(build.build)) + .chain(iter::once(build.host_target)) .collect() } }; diff --git a/src/bootstrap/src/utils/cc_detect/tests.rs b/src/bootstrap/src/utils/cc_detect/tests.rs index 225fb7619b5..1f50738959f 100644 --- a/src/bootstrap/src/utils/cc_detect/tests.rs +++ b/src/bootstrap/src/utils/cc_detect/tests.rs @@ -155,7 +155,7 @@ fn test_find() { build.targets.push(target1.clone()); build.hosts.push(target2.clone()); find(&build); - for t in build.hosts.iter().chain(build.targets.iter()).chain(iter::once(&build.build)) { + for t in build.hosts.iter().chain(build.targets.iter()).chain(iter::once(&build.host_target)) { assert!(build.cc.borrow().contains_key(t), "CC not set for target {}", t.triple); } } diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs index e939a8362ad..93e01a58077 100644 --- a/src/bootstrap/src/utils/change_tracker.rs +++ b/src/bootstrap/src/utils/change_tracker.rs @@ -421,4 +421,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[ severity: ChangeSeverity::Info, summary: "Added new bootstrap flag `--skip-std-check-if-no-download-rustc` that skips std checks when download-rustc is unavailable. Mainly intended for developers to reduce RA overhead.", }, + ChangeInfo { + change_id: 142379, + severity: ChangeSeverity::Info, + summary: "Added new option `tool.TOOL_NAME.features` to specify the features to compile a tool with", + }, ]; diff --git a/src/bootstrap/src/utils/channel.rs b/src/bootstrap/src/utils/channel.rs index 4a9ecc7a4f8..38f250af42f 100644 --- a/src/bootstrap/src/utils/channel.rs +++ b/src/bootstrap/src/utils/channel.rs @@ -8,6 +8,7 @@ use std::fs; use std::path::Path; +use super::execution_context::ExecutionContext; use super::helpers; use crate::Build; use crate::utils::helpers::{start_process, t}; @@ -34,7 +35,7 @@ pub struct Info { } impl GitInfo { - pub fn new(omit_git_hash: bool, dir: &Path) -> GitInfo { + pub fn new(omit_git_hash: bool, dir: &Path, exec_ctx: impl AsRef<ExecutionContext>) -> GitInfo { // See if this even begins to look like a git dir if !dir.join(".git").exists() { match read_commit_info_file(dir) { @@ -43,10 +44,12 @@ impl GitInfo { } } - // Make sure git commands work - match helpers::git(Some(dir)).arg("rev-parse").as_command_mut().output() { - Ok(ref out) if out.status.success() => {} - _ => return GitInfo::Absent, + let mut git_command = helpers::git(Some(dir)); + git_command.arg("rev-parse"); + let output = git_command.allow_failure().run_capture(exec_ctx); + + if output.is_failure() { + return GitInfo::Absent; } // If we're ignoring the git info, we don't actually need to collect it, just make sure this diff --git a/src/bootstrap/src/utils/exec.rs b/src/bootstrap/src/utils/exec.rs index 64e46f10563..f297300e34a 100644 --- a/src/bootstrap/src/utils/exec.rs +++ b/src/bootstrap/src/utils/exec.rs @@ -11,7 +11,7 @@ use std::process::{Command, CommandArgs, CommandEnvs, ExitStatus, Output, Stdio} use build_helper::ci::CiEnv; use build_helper::drop_bomb::DropBomb; -use crate::Build; +use super::execution_context::ExecutionContext; /// What should be done when the command fails. #[derive(Debug, Copy, Clone)] @@ -125,7 +125,6 @@ impl BootstrapCommand { Self { failure_behavior: BehaviorOnFailure::DelayFail, ..self } } - #[expect(dead_code)] pub fn fail_fast(self) -> Self { Self { failure_behavior: BehaviorOnFailure::Exit, ..self } } @@ -143,20 +142,20 @@ impl BootstrapCommand { /// Run the command, while printing stdout and stderr. /// Returns true if the command has succeeded. #[track_caller] - pub fn run(&mut self, builder: &Build) -> bool { - builder.run(self, OutputMode::Print, OutputMode::Print).is_success() + pub fn run(&mut self, exec_ctx: impl AsRef<ExecutionContext>) -> bool { + exec_ctx.as_ref().run(self, OutputMode::Print, OutputMode::Print).is_success() } /// Run the command, while capturing and returning all its output. #[track_caller] - pub fn run_capture(&mut self, builder: &Build) -> CommandOutput { - builder.run(self, OutputMode::Capture, OutputMode::Capture) + pub fn run_capture(&mut self, exec_ctx: impl AsRef<ExecutionContext>) -> CommandOutput { + exec_ctx.as_ref().run(self, OutputMode::Capture, OutputMode::Capture) } /// Run the command, while capturing and returning stdout, and printing stderr. #[track_caller] - pub fn run_capture_stdout(&mut self, builder: &Build) -> CommandOutput { - builder.run(self, OutputMode::Capture, OutputMode::Print) + pub fn run_capture_stdout(&mut self, exec_ctx: impl AsRef<ExecutionContext>) -> CommandOutput { + exec_ctx.as_ref().run(self, OutputMode::Capture, OutputMode::Print) } /// Provides access to the stdlib Command inside. @@ -280,7 +279,6 @@ impl CommandOutput { !self.is_success() } - #[expect(dead_code)] pub fn status(&self) -> Option<ExitStatus> { match self.status { CommandStatus::Finished(status) => Some(status), diff --git a/src/bootstrap/src/utils/execution_context.rs b/src/bootstrap/src/utils/execution_context.rs new file mode 100644 index 00000000000..a5e1e9bcc07 --- /dev/null +++ b/src/bootstrap/src/utils/execution_context.rs @@ -0,0 +1,204 @@ +//! Shared execution context for running bootstrap commands. +//! +//! This module provides the [`ExecutionContext`] type, which holds global configuration +//! relevant during the execution of commands in bootstrap. This includes dry-run +//! mode, verbosity level, and behavior on failure. +use std::sync::{Arc, Mutex}; + +use crate::core::config::DryRun; +#[cfg(feature = "tracing")] +use crate::trace_cmd; +use crate::{BehaviorOnFailure, BootstrapCommand, CommandOutput, OutputMode, exit}; + +#[derive(Clone, Default)] +pub struct ExecutionContext { + dry_run: DryRun, + verbose: u8, + pub fail_fast: bool, + delayed_failures: Arc<Mutex<Vec<String>>>, +} + +impl ExecutionContext { + pub fn new() -> Self { + ExecutionContext::default() + } + + pub fn dry_run(&self) -> bool { + match self.dry_run { + DryRun::Disabled => false, + DryRun::SelfCheck | DryRun::UserSelected => true, + } + } + + pub fn get_dry_run(&self) -> &DryRun { + &self.dry_run + } + + pub fn verbose(&self, f: impl Fn()) { + if self.is_verbose() { + f() + } + } + + pub fn is_verbose(&self) -> bool { + self.verbose > 0 + } + + pub fn fail_fast(&self) -> bool { + self.fail_fast + } + + pub fn set_dry_run(&mut self, value: DryRun) { + self.dry_run = value; + } + + pub fn set_verbose(&mut self, value: u8) { + self.verbose = value; + } + + pub fn set_fail_fast(&mut self, value: bool) { + self.fail_fast = value; + } + + pub fn add_to_delay_failure(&self, message: String) { + self.delayed_failures.lock().unwrap().push(message); + } + + pub fn report_failures_and_exit(&self) { + let failures = self.delayed_failures.lock().unwrap(); + if failures.is_empty() { + return; + } + eprintln!("\n{} command(s) did not execute successfully:\n", failures.len()); + for failure in &*failures { + eprintln!(" - {failure}"); + } + exit!(1); + } + + /// Execute a command and return its output. + /// Note: Ideally, you should use one of the BootstrapCommand::run* functions to + /// execute commands. They internally call this method. + #[track_caller] + pub fn run( + &self, + command: &mut BootstrapCommand, + stdout: OutputMode, + stderr: OutputMode, + ) -> CommandOutput { + command.mark_as_executed(); + if self.dry_run() && !command.run_always { + return CommandOutput::default(); + } + + #[cfg(feature = "tracing")] + let _run_span = trace_cmd!(command); + + let created_at = command.get_created_location(); + let executed_at = std::panic::Location::caller(); + + self.verbose(|| { + println!("running: {command:?} (created at {created_at}, executed at {executed_at})") + }); + + let cmd = command.as_command_mut(); + cmd.stdout(stdout.stdio()); + cmd.stderr(stderr.stdio()); + + let output = cmd.output(); + + use std::fmt::Write; + + let mut message = String::new(); + let output: CommandOutput = match output { + // Command has succeeded + Ok(output) if output.status.success() => { + CommandOutput::from_output(output, stdout, stderr) + } + // Command has started, but then it failed + Ok(output) => { + writeln!( + message, + r#" +Command {command:?} did not execute successfully. +Expected success, got {} +Created at: {created_at} +Executed at: {executed_at}"#, + output.status, + ) + .unwrap(); + + let output: CommandOutput = CommandOutput::from_output(output, stdout, stderr); + + // If the output mode is OutputMode::Capture, we can now print the output. + // If it is OutputMode::Print, then the output has already been printed to + // stdout/stderr, and we thus don't have anything captured to print anyway. + if stdout.captures() { + writeln!(message, "\nSTDOUT ----\n{}", output.stdout().trim()).unwrap(); + } + if stderr.captures() { + writeln!(message, "\nSTDERR ----\n{}", output.stderr().trim()).unwrap(); + } + output + } + // The command did not even start + Err(e) => { + writeln!( + message, + "\n\nCommand {command:?} did not execute successfully.\ + \nIt was not possible to execute the command: {e:?}" + ) + .unwrap(); + CommandOutput::did_not_start(stdout, stderr) + } + }; + + let fail = |message: &str, output: CommandOutput| -> ! { + if self.is_verbose() { + println!("{message}"); + } else { + let (stdout, stderr) = (output.stdout_if_present(), output.stderr_if_present()); + // If the command captures output, the user would not see any indication that + // it has failed. In this case, print a more verbose error, since to provide more + // context. + if stdout.is_some() || stderr.is_some() { + if let Some(stdout) = + output.stdout_if_present().take_if(|s| !s.trim().is_empty()) + { + println!("STDOUT:\n{stdout}\n"); + } + if let Some(stderr) = + output.stderr_if_present().take_if(|s| !s.trim().is_empty()) + { + println!("STDERR:\n{stderr}\n"); + } + println!("Command {command:?} has failed. Rerun with -v to see more details."); + } else { + println!("Command has failed. Rerun with -v to see more details."); + } + } + exit!(1); + }; + + if !output.is_success() { + match command.failure_behavior { + BehaviorOnFailure::DelayFail => { + if self.fail_fast { + fail(&message, output); + } + + self.add_to_delay_failure(message); + } + BehaviorOnFailure::Exit => { + fail(&message, output); + } + BehaviorOnFailure::Ignore => { + // If failures are allowed, either the error has been printed already + // (OutputMode::Print) or the user used a capture output mode and wants to + // handle the error output on their own. + } + } + } + output + } +} diff --git a/src/bootstrap/src/utils/mod.rs b/src/bootstrap/src/utils/mod.rs index 169fcec303e..5a0b90801e7 100644 --- a/src/bootstrap/src/utils/mod.rs +++ b/src/bootstrap/src/utils/mod.rs @@ -8,6 +8,7 @@ pub(crate) mod cc_detect; pub(crate) mod change_tracker; pub(crate) mod channel; pub(crate) mod exec; +pub(crate) mod execution_context; pub(crate) mod helpers; pub(crate) mod job; pub(crate) mod render_tests; diff --git a/src/bootstrap/src/utils/render_tests.rs b/src/bootstrap/src/utils/render_tests.rs index 418f3ff975d..77e645a9e3c 100644 --- a/src/bootstrap/src/utils/render_tests.rs +++ b/src/bootstrap/src/utils/render_tests.rs @@ -43,8 +43,7 @@ pub(crate) fn try_run_tests( if builder.fail_fast { crate::exit!(1); } else { - let mut failures = builder.delayed_failures.borrow_mut(); - failures.push(format!("{cmd:?}")); + builder.config.exec_ctx().add_to_delay_failure(format!("{cmd:?}")); false } } else { diff --git a/src/build_helper/src/lib.rs b/src/build_helper/src/lib.rs index 1f5cf723641..05de8fd2d42 100644 --- a/src/build_helper/src/lib.rs +++ b/src/build_helper/src/lib.rs @@ -6,6 +6,7 @@ pub mod fs; pub mod git; pub mod metrics; pub mod stage0_parser; +pub mod targets; pub mod util; /// The default set of crates for opt-dist to collect LLVM profiles. diff --git a/src/build_helper/src/targets.rs b/src/build_helper/src/targets.rs new file mode 100644 index 00000000000..cccc413368b --- /dev/null +++ b/src/build_helper/src/targets.rs @@ -0,0 +1,11 @@ +// FIXME(#142296): this hack is because there is no reliable way (yet) to determine whether a given +// target supports std. In the long-term, we should try to implement a way to *reliably* determine +// target (std) metadata. +// +// NOTE: this is pulled out to `build_helpers` to share this hack between `bootstrap` and +// `compiletest`. +pub fn target_supports_std(target_tuple: &str) -> bool { + !(target_tuple.contains("-none") + || target_tuple.contains("nvptx") + || target_tuple.contains("switch")) +} diff --git a/src/ci/docker/host-x86_64/mingw-check-2/Dockerfile b/src/ci/docker/host-x86_64/mingw-check-2/Dockerfile index a1d04bd984c..ce18a181d31 100644 --- a/src/ci/docker/host-x86_64/mingw-check-2/Dockerfile +++ b/src/ci/docker/host-x86_64/mingw-check-2/Dockerfile @@ -36,4 +36,7 @@ ENV SCRIPT \ RUSTDOCFLAGS=\"--document-private-items --document-hidden-items\" python3 ../x.py doc --stage 1 library && \ mkdir -p /checkout/obj/staging/doc && \ cp -r build/x86_64-unknown-linux-gnu/doc /checkout/obj/staging && \ - RUSTDOCFLAGS=\"--document-private-items --document-hidden-items\" python3 ../x.py doc --stage 1 library/test + RUSTDOCFLAGS=\"--document-private-items --document-hidden-items\" python3 ../x.py doc --stage 1 library/test && \ + # The BOOTSTRAP_TRACING flag is added to verify whether the + # bootstrap process compiles successfully with this flag enabled. + BOOTSTRAP_TRACING=1 python3 ../x.py --help diff --git a/src/doc/rustc-dev-guide/rust-version b/src/doc/rustc-dev-guide/rust-version index c8721bb3600..86d35b31498 100644 --- a/src/doc/rustc-dev-guide/rust-version +++ b/src/doc/rustc-dev-guide/rust-version @@ -1 +1 @@ -c31cccb7b5cc098b1a8c1794ed38d7fdbec0ccb0 +14346303d760027e53214e705109a62c0f00b214 diff --git a/src/doc/rustc-dev-guide/src/git.md b/src/doc/rustc-dev-guide/src/git.md index 8118ddff10c..8726ddfce20 100644 --- a/src/doc/rustc-dev-guide/src/git.md +++ b/src/doc/rustc-dev-guide/src/git.md @@ -142,7 +142,8 @@ The most common cause is that you rebased after a change and ran `git add .` wit `x` to update the submodules. Alternatively, you might have run `cargo fmt` instead of `x fmt` and modified files in a submodule, then committed the changes. -To fix it, do the following things: +To fix it, do the following things (if you changed a submodule other than cargo, +replace `src/tools/cargo` with the path to that submodule): 1. See which commit has the accidental changes: `git log --stat -n1 src/tools/cargo` 2. Revert the changes to that commit: `git checkout <my-commit>~ src/tools/cargo`. Type `~` diff --git a/src/doc/rustc-dev-guide/src/tests/compiletest.md b/src/doc/rustc-dev-guide/src/tests/compiletest.md index 20dd16c81df..ded30234e70 100644 --- a/src/doc/rustc-dev-guide/src/tests/compiletest.md +++ b/src/doc/rustc-dev-guide/src/tests/compiletest.md @@ -115,7 +115,7 @@ default behavior without any commands is to: 2. Run `rustc -Zunpretty=normal` on the output of the previous step. 3. The output of the previous two steps should be the same. 4. Run `rustc -Zno-codegen` on the output to make sure that it can type check - (this is similar to running `cargo check`). + (similar to `cargo check`). If any of the commands above fail, then the test fails. diff --git a/src/doc/rustc-dev-guide/src/tests/directives.md b/src/doc/rustc-dev-guide/src/tests/directives.md index f73a2811d5a..839076b809d 100644 --- a/src/doc/rustc-dev-guide/src/tests/directives.md +++ b/src/doc/rustc-dev-guide/src/tests/directives.md @@ -202,6 +202,7 @@ settings: `//@ needs-crate-type: cdylib, proc-macro` will cause the test to be ignored on `wasm32-unknown-unknown` target because the target does not support the `proc-macro` crate type. +- `needs-target-std` — ignores if target platform does not have std support. The following directives will check LLVM support: diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index e2e2ad9ac3b..559e4867bbb 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -33,7 +33,7 @@ All tier 1 targets with host tools support the full standard library. target | notes -------|------- [`aarch64-apple-darwin`](platform-support/apple-darwin.md) | ARM64 macOS (11.0+, Big Sur+) -`aarch64-unknown-linux-gnu` | ARM64 Linux (kernel 4.1, glibc 2.17+) +`aarch64-unknown-linux-gnu` | ARM64 Linux (kernel 4.1+, glibc 2.17+) `i686-pc-windows-msvc` | 32-bit MSVC (Windows 10+, Windows Server 2016+, Pentium 4) [^x86_32-floats-return-ABI] [^win32-msvc-alignment] `i686-unknown-linux-gnu` | 32-bit Linux (kernel 3.2+, glibc 2.17+, Pentium 4) [^x86_32-floats-return-ABI] [`x86_64-apple-darwin`](platform-support/apple-darwin.md) | 64-bit macOS (10.12+, Sierra+) @@ -91,20 +91,20 @@ target | notes `aarch64-pc-windows-msvc` | ARM64 Windows MSVC `aarch64-unknown-linux-musl` | ARM64 Linux with musl 1.2.3 [`aarch64-unknown-linux-ohos`](platform-support/openharmony.md) | ARM64 OpenHarmony -`arm-unknown-linux-gnueabi` | Armv6 Linux (kernel 3.2, glibc 2.17) -`arm-unknown-linux-gnueabihf` | Armv6 Linux, hardfloat (kernel 3.2, glibc 2.17) -`armv7-unknown-linux-gnueabihf` | Armv7-A Linux, hardfloat (kernel 3.2, glibc 2.17) +`arm-unknown-linux-gnueabi` | Armv6 Linux (kernel 3.2+, glibc 2.17) +`arm-unknown-linux-gnueabihf` | Armv6 Linux, hardfloat (kernel 3.2+, glibc 2.17) +`armv7-unknown-linux-gnueabihf` | Armv7-A Linux, hardfloat (kernel 3.2+, glibc 2.17) [`armv7-unknown-linux-ohos`](platform-support/openharmony.md) | Armv7-A OpenHarmony -[`loongarch64-unknown-linux-gnu`](platform-support/loongarch-linux.md) | LoongArch64 Linux, LP64D ABI (kernel 5.19, glibc 2.36) -[`loongarch64-unknown-linux-musl`](platform-support/loongarch-linux.md) | LoongArch64 Linux, LP64D ABI (kernel 5.19, musl 1.2.5) +[`loongarch64-unknown-linux-gnu`](platform-support/loongarch-linux.md) | LoongArch64 Linux, LP64D ABI (kernel 5.19+, glibc 2.36) +[`loongarch64-unknown-linux-musl`](platform-support/loongarch-linux.md) | LoongArch64 Linux, LP64D ABI (kernel 5.19+, musl 1.2.5) [`i686-pc-windows-gnu`](platform-support/windows-gnu.md) | 32-bit MinGW (Windows 10+, Windows Server 2016+, Pentium 4) [^x86_32-floats-return-ABI] [^win32-msvc-alignment] -`powerpc-unknown-linux-gnu` | PowerPC Linux (kernel 3.2, glibc 2.17) -`powerpc64-unknown-linux-gnu` | PPC64 Linux (kernel 3.2, glibc 2.17) -[`powerpc64le-unknown-linux-gnu`](platform-support/powerpc64le-unknown-linux-gnu.md) | PPC64LE Linux (kernel 3.10, glibc 2.17) -[`powerpc64le-unknown-linux-musl`](platform-support/powerpc64le-unknown-linux-musl.md) | PPC64LE Linux (kernel 4.19, musl 1.2.3) -[`riscv64gc-unknown-linux-gnu`](platform-support/riscv64gc-unknown-linux-gnu.md) | RISC-V Linux (kernel 4.20, glibc 2.29) -[`riscv64gc-unknown-linux-musl`](platform-support/riscv64gc-unknown-linux-musl.md) | RISC-V Linux (kernel 4.20, musl 1.2.3) -[`s390x-unknown-linux-gnu`](platform-support/s390x-unknown-linux-gnu.md) | S390x Linux (kernel 3.2, glibc 2.17) +`powerpc-unknown-linux-gnu` | PowerPC Linux (kernel 3.2+, glibc 2.17) +`powerpc64-unknown-linux-gnu` | PPC64 Linux (kernel 3.2+, glibc 2.17) +[`powerpc64le-unknown-linux-gnu`](platform-support/powerpc64le-unknown-linux-gnu.md) | PPC64LE Linux (kernel 3.10+, glibc 2.17) +[`powerpc64le-unknown-linux-musl`](platform-support/powerpc64le-unknown-linux-musl.md) | PPC64LE Linux (kernel 4.19+, musl 1.2.3) +[`riscv64gc-unknown-linux-gnu`](platform-support/riscv64gc-unknown-linux-gnu.md) | RISC-V Linux (kernel 4.20+, glibc 2.29) +[`riscv64gc-unknown-linux-musl`](platform-support/riscv64gc-unknown-linux-musl.md) | RISC-V Linux (kernel 4.20+, musl 1.2.3) +[`s390x-unknown-linux-gnu`](platform-support/s390x-unknown-linux-gnu.md) | S390x Linux (kernel 3.2+, glibc 2.17) [`x86_64-unknown-freebsd`](platform-support/freebsd.md) | 64-bit x86 FreeBSD [`x86_64-unknown-illumos`](platform-support/illumos.md) | illumos `x86_64-unknown-linux-musl` | 64-bit Linux with musl 1.2.3 @@ -158,16 +158,16 @@ 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`](platform-support/armv5te-unknown-linux-gnueabi.md) | ✓ | 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) +`armv7-unknown-linux-gnueabi` | ✓ | Armv7-A Linux (kernel 4.15+, glibc 2.27) `armv7-unknown-linux-musleabi` | ✓ | Armv7-A Linux with musl 1.2.3 `armv7-unknown-linux-musleabihf` | ✓ | Armv7-A Linux with musl 1.2.3, hardfloat [`armv7a-none-eabi`](platform-support/arm-none-eabi.md) | * | Bare Armv7-A [`armv7r-none-eabi`](platform-support/armv7r-none-eabi.md) | * | Bare Armv7-R [`armv7r-none-eabihf`](platform-support/armv7r-none-eabi.md) | * | Bare Armv7-R, hardfloat -`i586-unknown-linux-gnu` | ✓ | 32-bit Linux (kernel 3.2, glibc 2.17, original Pentium) [^x86_32-floats-x87] +`i586-unknown-linux-gnu` | ✓ | 32-bit Linux (kernel 3.2+, glibc 2.17, original Pentium) [^x86_32-floats-x87] `i586-unknown-linux-musl` | ✓ | 32-bit Linux (musl 1.2.3, original Pentium) [^x86_32-floats-x87] [`i686-linux-android`](platform-support/android.md) | ✓ | 32-bit x86 Android ([Pentium 4 plus various extensions](https://developer.android.com/ndk/guides/abis.html#x86)) [^x86_32-floats-return-ABI] [`i686-pc-windows-gnullvm`](platform-support/windows-gnullvm.md) | ✓ | 32-bit x86 MinGW (Windows 10+, Pentium 4), LLVM ABI [^x86_32-floats-return-ABI] @@ -184,13 +184,13 @@ target | std | notes [`riscv32imc-unknown-none-elf`](platform-support/riscv32-unknown-none-elf.md) | * | Bare RISC-V (RV32IMC ISA) `riscv64gc-unknown-none-elf` | * | Bare RISC-V (RV64IMAFDC ISA) `riscv64imac-unknown-none-elf` | * | Bare RISC-V (RV64IMAC ISA) -`sparc64-unknown-linux-gnu` | ✓ | SPARC Linux (kernel 4.4, glibc 2.23) +`sparc64-unknown-linux-gnu` | ✓ | SPARC Linux (kernel 4.4+, glibc 2.23) [`thumbv6m-none-eabi`](platform-support/thumbv6m-none-eabi.md) | * | Bare Armv6-M [`thumbv7em-none-eabi`](platform-support/thumbv7em-none-eabi.md) | * | Bare Armv7E-M [`thumbv7em-none-eabihf`](platform-support/thumbv7em-none-eabi.md) | * | Bare Armv7E-M, hardfloat [`thumbv7m-none-eabi`](platform-support/thumbv7m-none-eabi.md) | * | Bare Armv7-M [`thumbv7neon-linux-androideabi`](platform-support/android.md) | ✓ | Thumb2-mode Armv7-A Android with NEON -`thumbv7neon-unknown-linux-gnueabihf` | ✓ | Thumb2-mode Armv7-A Linux with NEON (kernel 4.4, glibc 2.23) +`thumbv7neon-unknown-linux-gnueabihf` | ✓ | Thumb2-mode Armv7-A Linux with NEON (kernel 4.4+, glibc 2.23) [`thumbv8m.base-none-eabi`](platform-support/thumbv8m.base-none-eabi.md) | * | Bare Armv8-M Baseline [`thumbv8m.main-none-eabi`](platform-support/thumbv8m.main-none-eabi.md) | * | Bare Armv8-M Mainline [`thumbv8m.main-none-eabihf`](platform-support/thumbv8m.main-none-eabi.md) | * | Bare Armv8-M Mainline, hardfloat @@ -206,7 +206,7 @@ target | std | notes [`x86_64-linux-android`](platform-support/android.md) | ✓ | 64-bit x86 Android [`x86_64-pc-windows-gnullvm`](platform-support/windows-gnullvm.md) | ✓ | 64-bit x86 MinGW (Windows 10+), LLVM ABI [`x86_64-unknown-fuchsia`](platform-support/fuchsia.md) | ✓ | 64-bit x86 Fuchsia -`x86_64-unknown-linux-gnux32` | ✓ | 64-bit Linux (x32 ABI) (kernel 4.15, glibc 2.27) +`x86_64-unknown-linux-gnux32` | ✓ | 64-bit Linux (x32 ABI) (kernel 4.15+, glibc 2.27) [`x86_64-unknown-none`](platform-support/x86_64-unknown-none.md) | * | Freestanding/bare-metal x86_64, softfloat [`x86_64-unknown-redox`](platform-support/redox.md) | ✓ | Redox OS [`x86_64-unknown-uefi`](platform-support/unknown-uefi.md) | ? | 64-bit UEFI diff --git a/src/doc/rustc/src/platform-support/loongarch-none.md b/src/doc/rustc/src/platform-support/loongarch-none.md index fd90b0a2763..7c3a7e6c8bc 100644 --- a/src/doc/rustc/src/platform-support/loongarch-none.md +++ b/src/doc/rustc/src/platform-support/loongarch-none.md @@ -11,8 +11,8 @@ Freestanding/bare-metal LoongArch binaries in ELF format: firmware, kernels, etc ## Target maintainers -- [@heiher](https://github.com/heiher) -- [@xen0n](https://github.com/xen0n) +[@heiher](https://github.com/heiher) +[@xen0n](https://github.com/xen0n) ## Requirements diff --git a/src/doc/unstable-book/src/compiler-flags/macro-stats.md b/src/doc/unstable-book/src/compiler-flags/macro-stats.md new file mode 100644 index 00000000000..b2622cff057 --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/macro-stats.md @@ -0,0 +1,24 @@ +# `macro-stats` + +This feature is perma-unstable and has no tracking issue. + +---- + +Some macros, especially procedural macros, can generate a surprising amount of +code, which can slow down compile times. This is hard to detect because the +generated code is normally invisible to the programmer. + +This flag helps identify such cases. When enabled, the compiler measures the +effect on code size of all used macros and prints a table summarizing that +effect. For each distinct macro, it counts how many times it is used, and the +net effect on code size (in terms of lines of code, and bytes of code). The +code size evaluation uses the compiler's internal pretty-printing, and so will +be independent of the formatting in the original code. + +Note that the net effect of a macro may be negative. E.g. the `cfg!` and +`#[test]` macros often strip out code. + +If a macro is identified as causing a large increase in code size, it is worth +using `cargo expand` to inspect the post-expansion code, which includes the +code produced by all macros. It may be possible to optimize the macro to +produce smaller code, or it may be possible to avoid using it altogether. diff --git a/src/doc/unstable-book/src/language-features/asm-experimental-arch.md b/src/doc/unstable-book/src/language-features/asm-experimental-arch.md index d9566c9f55c..121f9493435 100644 --- a/src/doc/unstable-book/src/language-features/asm-experimental-arch.md +++ b/src/doc/unstable-book/src/language-features/asm-experimental-arch.md @@ -19,6 +19,7 @@ This feature tracks `asm!` and `global_asm!` support for the following architect - M68k - CSKY - SPARC +- LoongArch32 ## Register classes @@ -53,6 +54,8 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | CSKY | `freg` | `f[0-31]` | `f` | | SPARC | `reg` | `r[2-29]` | `r` | | SPARC | `yreg` | `y` | Only clobbers | +| LoongArch32 | `reg` | `$r1`, `$r[4-20]`, `$r[23,30]` | `r` | +| LoongArch32 | `freg` | `$f[0-31]` | `f` | > **Notes**: > - NVPTX doesn't have a fixed register set, so named registers are not supported. @@ -91,6 +94,8 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | CSKY | `freg` | None | `f32`, | | SPARC | `reg` | None | `i8`, `i16`, `i32`, `i64` (SPARC64 only) | | SPARC | `yreg` | N/A | Only clobbers | +| LoongArch32 | `reg` | None | `i8`, `i16`, `i32`, `f32` | +| LoongArch32 | `freg` | None | `f32`, `f64` | ## Register aliases diff --git a/src/etc/completions/x.fish b/src/etc/completions/x.fish index 10a4e684e33..a030f45830e 100644 --- a/src/etc/completions/x.fish +++ b/src/etc/completions/x.fish @@ -26,7 +26,7 @@ end complete -c x -n "__fish_x_needs_command" -l config -d 'TOML configuration file for build' -r -F complete -c x -n "__fish_x_needs_command" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" -complete -c x -n "__fish_x_needs_command" -l build -d 'build target of the stage0 compiler' -r -f +complete -c x -n "__fish_x_needs_command" -l build -d 'host target of the stage0 compiler' -r -f complete -c x -n "__fish_x_needs_command" -l host -d 'host targets to build' -r -f complete -c x -n "__fish_x_needs_command" -l target -d 'target targets to build' -r -f complete -c x -n "__fish_x_needs_command" -l exclude -d 'build paths to exclude' -r -F @@ -78,7 +78,7 @@ complete -c x -n "__fish_x_needs_command" -a "vendor" -d 'Vendor dependencies' complete -c x -n "__fish_x_needs_command" -a "perf" -d 'Perform profiling and benchmarking of the compiler using `rustc-perf`' complete -c x -n "__fish_x_using_subcommand build" -l config -d 'TOML configuration file for build' -r -F complete -c x -n "__fish_x_using_subcommand build" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" -complete -c x -n "__fish_x_using_subcommand build" -l build -d 'build target of the stage0 compiler' -r -f +complete -c x -n "__fish_x_using_subcommand build" -l build -d 'host target of the stage0 compiler' -r -f complete -c x -n "__fish_x_using_subcommand build" -l host -d 'host targets to build' -r -f complete -c x -n "__fish_x_using_subcommand build" -l target -d 'target targets to build' -r -f complete -c x -n "__fish_x_using_subcommand build" -l exclude -d 'build paths to exclude' -r -F @@ -113,7 +113,7 @@ complete -c x -n "__fish_x_using_subcommand build" -l skip-std-check-if-no-downl complete -c x -n "__fish_x_using_subcommand build" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x -n "__fish_x_using_subcommand check" -l config -d 'TOML configuration file for build' -r -F complete -c x -n "__fish_x_using_subcommand check" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" -complete -c x -n "__fish_x_using_subcommand check" -l build -d 'build target of the stage0 compiler' -r -f +complete -c x -n "__fish_x_using_subcommand check" -l build -d 'host target of the stage0 compiler' -r -f complete -c x -n "__fish_x_using_subcommand check" -l host -d 'host targets to build' -r -f complete -c x -n "__fish_x_using_subcommand check" -l target -d 'target targets to build' -r -f complete -c x -n "__fish_x_using_subcommand check" -l exclude -d 'build paths to exclude' -r -F @@ -153,7 +153,7 @@ complete -c x -n "__fish_x_using_subcommand clippy" -s W -d 'clippy lints to war complete -c x -n "__fish_x_using_subcommand clippy" -s F -d 'clippy lints to forbid' -r complete -c x -n "__fish_x_using_subcommand clippy" -l config -d 'TOML configuration file for build' -r -F complete -c x -n "__fish_x_using_subcommand clippy" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" -complete -c x -n "__fish_x_using_subcommand clippy" -l build -d 'build target of the stage0 compiler' -r -f +complete -c x -n "__fish_x_using_subcommand clippy" -l build -d 'host target of the stage0 compiler' -r -f complete -c x -n "__fish_x_using_subcommand clippy" -l host -d 'host targets to build' -r -f complete -c x -n "__fish_x_using_subcommand clippy" -l target -d 'target targets to build' -r -f complete -c x -n "__fish_x_using_subcommand clippy" -l exclude -d 'build paths to exclude' -r -F @@ -191,7 +191,7 @@ complete -c x -n "__fish_x_using_subcommand clippy" -l skip-std-check-if-no-down complete -c x -n "__fish_x_using_subcommand clippy" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x -n "__fish_x_using_subcommand fix" -l config -d 'TOML configuration file for build' -r -F complete -c x -n "__fish_x_using_subcommand fix" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" -complete -c x -n "__fish_x_using_subcommand fix" -l build -d 'build target of the stage0 compiler' -r -f +complete -c x -n "__fish_x_using_subcommand fix" -l build -d 'host target of the stage0 compiler' -r -f complete -c x -n "__fish_x_using_subcommand fix" -l host -d 'host targets to build' -r -f complete -c x -n "__fish_x_using_subcommand fix" -l target -d 'target targets to build' -r -f complete -c x -n "__fish_x_using_subcommand fix" -l exclude -d 'build paths to exclude' -r -F @@ -226,7 +226,7 @@ complete -c x -n "__fish_x_using_subcommand fix" -l skip-std-check-if-no-downloa complete -c x -n "__fish_x_using_subcommand fix" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x -n "__fish_x_using_subcommand fmt" -l config -d 'TOML configuration file for build' -r -F complete -c x -n "__fish_x_using_subcommand fmt" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" -complete -c x -n "__fish_x_using_subcommand fmt" -l build -d 'build target of the stage0 compiler' -r -f +complete -c x -n "__fish_x_using_subcommand fmt" -l build -d 'host target of the stage0 compiler' -r -f complete -c x -n "__fish_x_using_subcommand fmt" -l host -d 'host targets to build' -r -f complete -c x -n "__fish_x_using_subcommand fmt" -l target -d 'target targets to build' -r -f complete -c x -n "__fish_x_using_subcommand fmt" -l exclude -d 'build paths to exclude' -r -F @@ -263,7 +263,7 @@ complete -c x -n "__fish_x_using_subcommand fmt" -l skip-std-check-if-no-downloa complete -c x -n "__fish_x_using_subcommand fmt" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x -n "__fish_x_using_subcommand doc" -l config -d 'TOML configuration file for build' -r -F complete -c x -n "__fish_x_using_subcommand doc" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" -complete -c x -n "__fish_x_using_subcommand doc" -l build -d 'build target of the stage0 compiler' -r -f +complete -c x -n "__fish_x_using_subcommand doc" -l build -d 'host target of the stage0 compiler' -r -f complete -c x -n "__fish_x_using_subcommand doc" -l host -d 'host targets to build' -r -f complete -c x -n "__fish_x_using_subcommand doc" -l target -d 'target targets to build' -r -f complete -c x -n "__fish_x_using_subcommand doc" -l exclude -d 'build paths to exclude' -r -F @@ -306,7 +306,7 @@ complete -c x -n "__fish_x_using_subcommand test" -l pass -d 'force {check,build complete -c x -n "__fish_x_using_subcommand test" -l run -d 'whether to execute run-* tests' -r complete -c x -n "__fish_x_using_subcommand test" -l config -d 'TOML configuration file for build' -r -F complete -c x -n "__fish_x_using_subcommand test" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" -complete -c x -n "__fish_x_using_subcommand test" -l build -d 'build target of the stage0 compiler' -r -f +complete -c x -n "__fish_x_using_subcommand test" -l build -d 'host target of the stage0 compiler' -r -f complete -c x -n "__fish_x_using_subcommand test" -l host -d 'host targets to build' -r -f complete -c x -n "__fish_x_using_subcommand test" -l target -d 'target targets to build' -r -f complete -c x -n "__fish_x_using_subcommand test" -l exclude -d 'build paths to exclude' -r -F @@ -350,7 +350,7 @@ complete -c x -n "__fish_x_using_subcommand test" -s h -l help -d 'Print help (s complete -c x -n "__fish_x_using_subcommand miri" -l test-args -d 'extra arguments to be passed for the test tool being used (e.g. libtest, compiletest or rustdoc)' -r complete -c x -n "__fish_x_using_subcommand miri" -l config -d 'TOML configuration file for build' -r -F complete -c x -n "__fish_x_using_subcommand miri" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" -complete -c x -n "__fish_x_using_subcommand miri" -l build -d 'build target of the stage0 compiler' -r -f +complete -c x -n "__fish_x_using_subcommand miri" -l build -d 'host target of the stage0 compiler' -r -f complete -c x -n "__fish_x_using_subcommand miri" -l host -d 'host targets to build' -r -f complete -c x -n "__fish_x_using_subcommand miri" -l target -d 'target targets to build' -r -f complete -c x -n "__fish_x_using_subcommand miri" -l exclude -d 'build paths to exclude' -r -F @@ -389,7 +389,7 @@ complete -c x -n "__fish_x_using_subcommand miri" -s h -l help -d 'Print help (s complete -c x -n "__fish_x_using_subcommand bench" -l test-args -r complete -c x -n "__fish_x_using_subcommand bench" -l config -d 'TOML configuration file for build' -r -F complete -c x -n "__fish_x_using_subcommand bench" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" -complete -c x -n "__fish_x_using_subcommand bench" -l build -d 'build target of the stage0 compiler' -r -f +complete -c x -n "__fish_x_using_subcommand bench" -l build -d 'host target of the stage0 compiler' -r -f complete -c x -n "__fish_x_using_subcommand bench" -l host -d 'host targets to build' -r -f complete -c x -n "__fish_x_using_subcommand bench" -l target -d 'target targets to build' -r -f complete -c x -n "__fish_x_using_subcommand bench" -l exclude -d 'build paths to exclude' -r -F @@ -425,7 +425,7 @@ complete -c x -n "__fish_x_using_subcommand bench" -s h -l help -d 'Print help ( complete -c x -n "__fish_x_using_subcommand clean" -l stage -d 'Clean a specific stage without touching other artifacts. By default, every stage is cleaned if this option is not used' -r complete -c x -n "__fish_x_using_subcommand clean" -l config -d 'TOML configuration file for build' -r -F complete -c x -n "__fish_x_using_subcommand clean" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" -complete -c x -n "__fish_x_using_subcommand clean" -l build -d 'build target of the stage0 compiler' -r -f +complete -c x -n "__fish_x_using_subcommand clean" -l build -d 'host target of the stage0 compiler' -r -f complete -c x -n "__fish_x_using_subcommand clean" -l host -d 'host targets to build' -r -f complete -c x -n "__fish_x_using_subcommand clean" -l target -d 'target targets to build' -r -f complete -c x -n "__fish_x_using_subcommand clean" -l exclude -d 'build paths to exclude' -r -F @@ -460,7 +460,7 @@ complete -c x -n "__fish_x_using_subcommand clean" -l skip-std-check-if-no-downl complete -c x -n "__fish_x_using_subcommand clean" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x -n "__fish_x_using_subcommand dist" -l config -d 'TOML configuration file for build' -r -F complete -c x -n "__fish_x_using_subcommand dist" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" -complete -c x -n "__fish_x_using_subcommand dist" -l build -d 'build target of the stage0 compiler' -r -f +complete -c x -n "__fish_x_using_subcommand dist" -l build -d 'host target of the stage0 compiler' -r -f complete -c x -n "__fish_x_using_subcommand dist" -l host -d 'host targets to build' -r -f complete -c x -n "__fish_x_using_subcommand dist" -l target -d 'target targets to build' -r -f complete -c x -n "__fish_x_using_subcommand dist" -l exclude -d 'build paths to exclude' -r -F @@ -495,7 +495,7 @@ complete -c x -n "__fish_x_using_subcommand dist" -l skip-std-check-if-no-downlo complete -c x -n "__fish_x_using_subcommand dist" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x -n "__fish_x_using_subcommand install" -l config -d 'TOML configuration file for build' -r -F complete -c x -n "__fish_x_using_subcommand install" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" -complete -c x -n "__fish_x_using_subcommand install" -l build -d 'build target of the stage0 compiler' -r -f +complete -c x -n "__fish_x_using_subcommand install" -l build -d 'host target of the stage0 compiler' -r -f complete -c x -n "__fish_x_using_subcommand install" -l host -d 'host targets to build' -r -f complete -c x -n "__fish_x_using_subcommand install" -l target -d 'target targets to build' -r -f complete -c x -n "__fish_x_using_subcommand install" -l exclude -d 'build paths to exclude' -r -F @@ -531,7 +531,7 @@ complete -c x -n "__fish_x_using_subcommand install" -s h -l help -d 'Print help complete -c x -n "__fish_x_using_subcommand run" -l args -d 'arguments for the tool' -r complete -c x -n "__fish_x_using_subcommand run" -l config -d 'TOML configuration file for build' -r -F complete -c x -n "__fish_x_using_subcommand run" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" -complete -c x -n "__fish_x_using_subcommand run" -l build -d 'build target of the stage0 compiler' -r -f +complete -c x -n "__fish_x_using_subcommand run" -l build -d 'host target of the stage0 compiler' -r -f complete -c x -n "__fish_x_using_subcommand run" -l host -d 'host targets to build' -r -f complete -c x -n "__fish_x_using_subcommand run" -l target -d 'target targets to build' -r -f complete -c x -n "__fish_x_using_subcommand run" -l exclude -d 'build paths to exclude' -r -F @@ -566,7 +566,7 @@ complete -c x -n "__fish_x_using_subcommand run" -l skip-std-check-if-no-downloa complete -c x -n "__fish_x_using_subcommand run" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x -n "__fish_x_using_subcommand setup" -l config -d 'TOML configuration file for build' -r -F complete -c x -n "__fish_x_using_subcommand setup" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" -complete -c x -n "__fish_x_using_subcommand setup" -l build -d 'build target of the stage0 compiler' -r -f +complete -c x -n "__fish_x_using_subcommand setup" -l build -d 'host target of the stage0 compiler' -r -f complete -c x -n "__fish_x_using_subcommand setup" -l host -d 'host targets to build' -r -f complete -c x -n "__fish_x_using_subcommand setup" -l target -d 'target targets to build' -r -f complete -c x -n "__fish_x_using_subcommand setup" -l exclude -d 'build paths to exclude' -r -F @@ -601,7 +601,7 @@ complete -c x -n "__fish_x_using_subcommand setup" -l skip-std-check-if-no-downl complete -c x -n "__fish_x_using_subcommand setup" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x -n "__fish_x_using_subcommand suggest" -l config -d 'TOML configuration file for build' -r -F complete -c x -n "__fish_x_using_subcommand suggest" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" -complete -c x -n "__fish_x_using_subcommand suggest" -l build -d 'build target of the stage0 compiler' -r -f +complete -c x -n "__fish_x_using_subcommand suggest" -l build -d 'host target of the stage0 compiler' -r -f complete -c x -n "__fish_x_using_subcommand suggest" -l host -d 'host targets to build' -r -f complete -c x -n "__fish_x_using_subcommand suggest" -l target -d 'target targets to build' -r -f complete -c x -n "__fish_x_using_subcommand suggest" -l exclude -d 'build paths to exclude' -r -F @@ -638,7 +638,7 @@ complete -c x -n "__fish_x_using_subcommand suggest" -s h -l help -d 'Print help complete -c x -n "__fish_x_using_subcommand vendor" -l sync -d 'Additional `Cargo.toml` to sync and vendor' -r -F complete -c x -n "__fish_x_using_subcommand vendor" -l config -d 'TOML configuration file for build' -r -F complete -c x -n "__fish_x_using_subcommand vendor" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" -complete -c x -n "__fish_x_using_subcommand vendor" -l build -d 'build target of the stage0 compiler' -r -f +complete -c x -n "__fish_x_using_subcommand vendor" -l build -d 'host target of the stage0 compiler' -r -f complete -c x -n "__fish_x_using_subcommand vendor" -l host -d 'host targets to build' -r -f complete -c x -n "__fish_x_using_subcommand vendor" -l target -d 'target targets to build' -r -f complete -c x -n "__fish_x_using_subcommand vendor" -l exclude -d 'build paths to exclude' -r -F @@ -674,7 +674,7 @@ complete -c x -n "__fish_x_using_subcommand vendor" -l skip-std-check-if-no-down complete -c x -n "__fish_x_using_subcommand vendor" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x -n "__fish_x_using_subcommand perf; and not __fish_seen_subcommand_from eprintln samply cachegrind benchmark compare" -l config -d 'TOML configuration file for build' -r -F complete -c x -n "__fish_x_using_subcommand perf; and not __fish_seen_subcommand_from eprintln samply cachegrind benchmark compare" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" -complete -c x -n "__fish_x_using_subcommand perf; and not __fish_seen_subcommand_from eprintln samply cachegrind benchmark compare" -l build -d 'build target of the stage0 compiler' -r -f +complete -c x -n "__fish_x_using_subcommand perf; and not __fish_seen_subcommand_from eprintln samply cachegrind benchmark compare" -l build -d 'host target of the stage0 compiler' -r -f complete -c x -n "__fish_x_using_subcommand perf; and not __fish_seen_subcommand_from eprintln samply cachegrind benchmark compare" -l host -d 'host targets to build' -r -f complete -c x -n "__fish_x_using_subcommand perf; and not __fish_seen_subcommand_from eprintln samply cachegrind benchmark compare" -l target -d 'target targets to build' -r -f complete -c x -n "__fish_x_using_subcommand perf; and not __fish_seen_subcommand_from eprintln samply cachegrind benchmark compare" -l exclude -d 'build paths to exclude' -r -F @@ -718,7 +718,7 @@ complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_fro complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from eprintln" -l profiles -d 'Select the profiles that should be benchmarked' -r -f -a "{Check\t'',Debug\t'',Doc\t'',Opt\t'',Clippy\t''}" complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from eprintln" -l config -d 'TOML configuration file for build' -r -F complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from eprintln" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" -complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from eprintln" -l build -d 'build target of the stage0 compiler' -r -f +complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from eprintln" -l build -d 'host target of the stage0 compiler' -r -f complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from eprintln" -l host -d 'host targets to build' -r -f complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from eprintln" -l target -d 'target targets to build' -r -f complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from eprintln" -l skip -d 'build paths to skip' -r -F @@ -756,7 +756,7 @@ complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_fro complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from samply" -l profiles -d 'Select the profiles that should be benchmarked' -r -f -a "{Check\t'',Debug\t'',Doc\t'',Opt\t'',Clippy\t''}" complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from samply" -l config -d 'TOML configuration file for build' -r -F complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from samply" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" -complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from samply" -l build -d 'build target of the stage0 compiler' -r -f +complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from samply" -l build -d 'host target of the stage0 compiler' -r -f complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from samply" -l host -d 'host targets to build' -r -f complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from samply" -l target -d 'target targets to build' -r -f complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from samply" -l skip -d 'build paths to skip' -r -F @@ -794,7 +794,7 @@ complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_fro complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from cachegrind" -l profiles -d 'Select the profiles that should be benchmarked' -r -f -a "{Check\t'',Debug\t'',Doc\t'',Opt\t'',Clippy\t''}" complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from cachegrind" -l config -d 'TOML configuration file for build' -r -F complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from cachegrind" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" -complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from cachegrind" -l build -d 'build target of the stage0 compiler' -r -f +complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from cachegrind" -l build -d 'host target of the stage0 compiler' -r -f complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from cachegrind" -l host -d 'host targets to build' -r -f complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from cachegrind" -l target -d 'target targets to build' -r -f complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from cachegrind" -l skip -d 'build paths to skip' -r -F @@ -832,7 +832,7 @@ complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_fro complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -l profiles -d 'Select the profiles that should be benchmarked' -r -f -a "{Check\t'',Debug\t'',Doc\t'',Opt\t'',Clippy\t''}" complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -l config -d 'TOML configuration file for build' -r -F complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" -complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -l build -d 'build target of the stage0 compiler' -r -f +complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -l build -d 'host target of the stage0 compiler' -r -f complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -l host -d 'host targets to build' -r -f complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -l target -d 'target targets to build' -r -f complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -l skip -d 'build paths to skip' -r -F @@ -866,7 +866,7 @@ complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_fro complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from compare" -l config -d 'TOML configuration file for build' -r -F complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from compare" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" -complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from compare" -l build -d 'build target of the stage0 compiler' -r -f +complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from compare" -l build -d 'host target of the stage0 compiler' -r -f complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from compare" -l host -d 'host targets to build' -r -f complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from compare" -l target -d 'target targets to build' -r -f complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from compare" -l exclude -d 'build paths to exclude' -r -F diff --git a/src/etc/completions/x.ps1 b/src/etc/completions/x.ps1 index 23d8fe0cdd3..a891a9db332 100644 --- a/src/etc/completions/x.ps1 +++ b/src/etc/completions/x.ps1 @@ -23,7 +23,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { 'x' { [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`') - [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler') + [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler') [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build') [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build') [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude') @@ -82,7 +82,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { 'x;build' { [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`') - [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler') + [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler') [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build') [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build') [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude') @@ -124,7 +124,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { 'x;check' { [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`') - [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler') + [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler') [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build') [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build') [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude') @@ -171,7 +171,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { [CompletionResult]::new('-F', '-F ', [CompletionResultType]::ParameterName, 'clippy lints to forbid') [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`') - [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler') + [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler') [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build') [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build') [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude') @@ -216,7 +216,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { 'x;fix' { [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`') - [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler') + [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler') [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build') [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build') [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude') @@ -258,7 +258,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { 'x;fmt' { [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`') - [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler') + [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler') [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build') [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build') [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude') @@ -302,7 +302,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { 'x;doc' { [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`') - [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler') + [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler') [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build') [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build') [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude') @@ -352,7 +352,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { [CompletionResult]::new('--run', '--run', [CompletionResultType]::ParameterName, 'whether to execute run-* tests') [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`') - [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler') + [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler') [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build') [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build') [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude') @@ -403,7 +403,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { [CompletionResult]::new('--test-args', '--test-args', [CompletionResultType]::ParameterName, 'extra arguments to be passed for the test tool being used (e.g. libtest, compiletest or rustdoc)') [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`') - [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler') + [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler') [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build') [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build') [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude') @@ -449,7 +449,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { [CompletionResult]::new('--test-args', '--test-args', [CompletionResultType]::ParameterName, 'test-args') [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`') - [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler') + [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler') [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build') [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build') [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude') @@ -492,7 +492,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { [CompletionResult]::new('--stage', '--stage', [CompletionResultType]::ParameterName, 'Clean a specific stage without touching other artifacts. By default, every stage is cleaned if this option is not used') [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`') - [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler') + [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler') [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build') [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build') [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude') @@ -534,7 +534,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { 'x;dist' { [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`') - [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler') + [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler') [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build') [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build') [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude') @@ -576,7 +576,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { 'x;install' { [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`') - [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler') + [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler') [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build') [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build') [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude') @@ -619,7 +619,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { [CompletionResult]::new('--args', '--args', [CompletionResultType]::ParameterName, 'arguments for the tool') [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`') - [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler') + [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler') [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build') [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build') [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude') @@ -661,7 +661,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { 'x;setup' { [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`') - [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler') + [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler') [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build') [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build') [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude') @@ -703,7 +703,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { 'x;suggest' { [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`') - [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler') + [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler') [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build') [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build') [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude') @@ -747,7 +747,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { [CompletionResult]::new('--sync', '--sync', [CompletionResultType]::ParameterName, 'Additional `Cargo.toml` to sync and vendor') [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`') - [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler') + [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler') [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build') [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build') [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude') @@ -790,7 +790,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { 'x;perf' { [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`') - [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler') + [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler') [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build') [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build') [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude') @@ -841,7 +841,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { [CompletionResult]::new('--profiles', '--profiles', [CompletionResultType]::ParameterName, 'Select the profiles that should be benchmarked') [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`') - [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler') + [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler') [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build') [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build') [CompletionResult]::new('--skip', '--skip', [CompletionResultType]::ParameterName, 'build paths to skip') @@ -886,7 +886,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { [CompletionResult]::new('--profiles', '--profiles', [CompletionResultType]::ParameterName, 'Select the profiles that should be benchmarked') [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`') - [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler') + [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler') [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build') [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build') [CompletionResult]::new('--skip', '--skip', [CompletionResultType]::ParameterName, 'build paths to skip') @@ -931,7 +931,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { [CompletionResult]::new('--profiles', '--profiles', [CompletionResultType]::ParameterName, 'Select the profiles that should be benchmarked') [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`') - [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler') + [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler') [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build') [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build') [CompletionResult]::new('--skip', '--skip', [CompletionResultType]::ParameterName, 'build paths to skip') @@ -976,7 +976,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { [CompletionResult]::new('--profiles', '--profiles', [CompletionResultType]::ParameterName, 'Select the profiles that should be benchmarked') [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`') - [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler') + [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler') [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build') [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build') [CompletionResult]::new('--skip', '--skip', [CompletionResultType]::ParameterName, 'build paths to skip') @@ -1017,7 +1017,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock { 'x;perf;compare' { [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`') - [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler') + [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler') [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build') [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build') [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude') diff --git a/src/etc/completions/x.py.fish b/src/etc/completions/x.py.fish index 1fc5bb12cfb..e6326fcb0bb 100644 --- a/src/etc/completions/x.py.fish +++ b/src/etc/completions/x.py.fish @@ -26,7 +26,7 @@ end complete -c x.py -n "__fish_x.py_needs_command" -l config -d 'TOML configuration file for build' -r -F complete -c x.py -n "__fish_x.py_needs_command" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" -complete -c x.py -n "__fish_x.py_needs_command" -l build -d 'build target of the stage0 compiler' -r -f +complete -c x.py -n "__fish_x.py_needs_command" -l build -d 'host target of the stage0 compiler' -r -f complete -c x.py -n "__fish_x.py_needs_command" -l host -d 'host targets to build' -r -f complete -c x.py -n "__fish_x.py_needs_command" -l target -d 'target targets to build' -r -f complete -c x.py -n "__fish_x.py_needs_command" -l exclude -d 'build paths to exclude' -r -F @@ -78,7 +78,7 @@ complete -c x.py -n "__fish_x.py_needs_command" -a "vendor" -d 'Vendor dependenc complete -c x.py -n "__fish_x.py_needs_command" -a "perf" -d 'Perform profiling and benchmarking of the compiler using `rustc-perf`' complete -c x.py -n "__fish_x.py_using_subcommand build" -l config -d 'TOML configuration file for build' -r -F complete -c x.py -n "__fish_x.py_using_subcommand build" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" -complete -c x.py -n "__fish_x.py_using_subcommand build" -l build -d 'build target of the stage0 compiler' -r -f +complete -c x.py -n "__fish_x.py_using_subcommand build" -l build -d 'host target of the stage0 compiler' -r -f complete -c x.py -n "__fish_x.py_using_subcommand build" -l host -d 'host targets to build' -r -f complete -c x.py -n "__fish_x.py_using_subcommand build" -l target -d 'target targets to build' -r -f complete -c x.py -n "__fish_x.py_using_subcommand build" -l exclude -d 'build paths to exclude' -r -F @@ -113,7 +113,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand build" -l skip-std-check-if-no complete -c x.py -n "__fish_x.py_using_subcommand build" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x.py -n "__fish_x.py_using_subcommand check" -l config -d 'TOML configuration file for build' -r -F complete -c x.py -n "__fish_x.py_using_subcommand check" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" -complete -c x.py -n "__fish_x.py_using_subcommand check" -l build -d 'build target of the stage0 compiler' -r -f +complete -c x.py -n "__fish_x.py_using_subcommand check" -l build -d 'host target of the stage0 compiler' -r -f complete -c x.py -n "__fish_x.py_using_subcommand check" -l host -d 'host targets to build' -r -f complete -c x.py -n "__fish_x.py_using_subcommand check" -l target -d 'target targets to build' -r -f complete -c x.py -n "__fish_x.py_using_subcommand check" -l exclude -d 'build paths to exclude' -r -F @@ -153,7 +153,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand clippy" -s W -d 'clippy lints complete -c x.py -n "__fish_x.py_using_subcommand clippy" -s F -d 'clippy lints to forbid' -r complete -c x.py -n "__fish_x.py_using_subcommand clippy" -l config -d 'TOML configuration file for build' -r -F complete -c x.py -n "__fish_x.py_using_subcommand clippy" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" -complete -c x.py -n "__fish_x.py_using_subcommand clippy" -l build -d 'build target of the stage0 compiler' -r -f +complete -c x.py -n "__fish_x.py_using_subcommand clippy" -l build -d 'host target of the stage0 compiler' -r -f complete -c x.py -n "__fish_x.py_using_subcommand clippy" -l host -d 'host targets to build' -r -f complete -c x.py -n "__fish_x.py_using_subcommand clippy" -l target -d 'target targets to build' -r -f complete -c x.py -n "__fish_x.py_using_subcommand clippy" -l exclude -d 'build paths to exclude' -r -F @@ -191,7 +191,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand clippy" -l skip-std-check-if-n complete -c x.py -n "__fish_x.py_using_subcommand clippy" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x.py -n "__fish_x.py_using_subcommand fix" -l config -d 'TOML configuration file for build' -r -F complete -c x.py -n "__fish_x.py_using_subcommand fix" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" -complete -c x.py -n "__fish_x.py_using_subcommand fix" -l build -d 'build target of the stage0 compiler' -r -f +complete -c x.py -n "__fish_x.py_using_subcommand fix" -l build -d 'host target of the stage0 compiler' -r -f complete -c x.py -n "__fish_x.py_using_subcommand fix" -l host -d 'host targets to build' -r -f complete -c x.py -n "__fish_x.py_using_subcommand fix" -l target -d 'target targets to build' -r -f complete -c x.py -n "__fish_x.py_using_subcommand fix" -l exclude -d 'build paths to exclude' -r -F @@ -226,7 +226,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand fix" -l skip-std-check-if-no-d complete -c x.py -n "__fish_x.py_using_subcommand fix" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x.py -n "__fish_x.py_using_subcommand fmt" -l config -d 'TOML configuration file for build' -r -F complete -c x.py -n "__fish_x.py_using_subcommand fmt" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" -complete -c x.py -n "__fish_x.py_using_subcommand fmt" -l build -d 'build target of the stage0 compiler' -r -f +complete -c x.py -n "__fish_x.py_using_subcommand fmt" -l build -d 'host target of the stage0 compiler' -r -f complete -c x.py -n "__fish_x.py_using_subcommand fmt" -l host -d 'host targets to build' -r -f complete -c x.py -n "__fish_x.py_using_subcommand fmt" -l target -d 'target targets to build' -r -f complete -c x.py -n "__fish_x.py_using_subcommand fmt" -l exclude -d 'build paths to exclude' -r -F @@ -263,7 +263,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand fmt" -l skip-std-check-if-no-d complete -c x.py -n "__fish_x.py_using_subcommand fmt" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x.py -n "__fish_x.py_using_subcommand doc" -l config -d 'TOML configuration file for build' -r -F complete -c x.py -n "__fish_x.py_using_subcommand doc" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" -complete -c x.py -n "__fish_x.py_using_subcommand doc" -l build -d 'build target of the stage0 compiler' -r -f +complete -c x.py -n "__fish_x.py_using_subcommand doc" -l build -d 'host target of the stage0 compiler' -r -f complete -c x.py -n "__fish_x.py_using_subcommand doc" -l host -d 'host targets to build' -r -f complete -c x.py -n "__fish_x.py_using_subcommand doc" -l target -d 'target targets to build' -r -f complete -c x.py -n "__fish_x.py_using_subcommand doc" -l exclude -d 'build paths to exclude' -r -F @@ -306,7 +306,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand test" -l pass -d 'force {check complete -c x.py -n "__fish_x.py_using_subcommand test" -l run -d 'whether to execute run-* tests' -r complete -c x.py -n "__fish_x.py_using_subcommand test" -l config -d 'TOML configuration file for build' -r -F complete -c x.py -n "__fish_x.py_using_subcommand test" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" -complete -c x.py -n "__fish_x.py_using_subcommand test" -l build -d 'build target of the stage0 compiler' -r -f +complete -c x.py -n "__fish_x.py_using_subcommand test" -l build -d 'host target of the stage0 compiler' -r -f complete -c x.py -n "__fish_x.py_using_subcommand test" -l host -d 'host targets to build' -r -f complete -c x.py -n "__fish_x.py_using_subcommand test" -l target -d 'target targets to build' -r -f complete -c x.py -n "__fish_x.py_using_subcommand test" -l exclude -d 'build paths to exclude' -r -F @@ -350,7 +350,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand test" -s h -l help -d 'Print h complete -c x.py -n "__fish_x.py_using_subcommand miri" -l test-args -d 'extra arguments to be passed for the test tool being used (e.g. libtest, compiletest or rustdoc)' -r complete -c x.py -n "__fish_x.py_using_subcommand miri" -l config -d 'TOML configuration file for build' -r -F complete -c x.py -n "__fish_x.py_using_subcommand miri" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" -complete -c x.py -n "__fish_x.py_using_subcommand miri" -l build -d 'build target of the stage0 compiler' -r -f +complete -c x.py -n "__fish_x.py_using_subcommand miri" -l build -d 'host target of the stage0 compiler' -r -f complete -c x.py -n "__fish_x.py_using_subcommand miri" -l host -d 'host targets to build' -r -f complete -c x.py -n "__fish_x.py_using_subcommand miri" -l target -d 'target targets to build' -r -f complete -c x.py -n "__fish_x.py_using_subcommand miri" -l exclude -d 'build paths to exclude' -r -F @@ -389,7 +389,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand miri" -s h -l help -d 'Print h complete -c x.py -n "__fish_x.py_using_subcommand bench" -l test-args -r complete -c x.py -n "__fish_x.py_using_subcommand bench" -l config -d 'TOML configuration file for build' -r -F complete -c x.py -n "__fish_x.py_using_subcommand bench" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" -complete -c x.py -n "__fish_x.py_using_subcommand bench" -l build -d 'build target of the stage0 compiler' -r -f +complete -c x.py -n "__fish_x.py_using_subcommand bench" -l build -d 'host target of the stage0 compiler' -r -f complete -c x.py -n "__fish_x.py_using_subcommand bench" -l host -d 'host targets to build' -r -f complete -c x.py -n "__fish_x.py_using_subcommand bench" -l target -d 'target targets to build' -r -f complete -c x.py -n "__fish_x.py_using_subcommand bench" -l exclude -d 'build paths to exclude' -r -F @@ -425,7 +425,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand bench" -s h -l help -d 'Print complete -c x.py -n "__fish_x.py_using_subcommand clean" -l stage -d 'Clean a specific stage without touching other artifacts. By default, every stage is cleaned if this option is not used' -r complete -c x.py -n "__fish_x.py_using_subcommand clean" -l config -d 'TOML configuration file for build' -r -F complete -c x.py -n "__fish_x.py_using_subcommand clean" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" -complete -c x.py -n "__fish_x.py_using_subcommand clean" -l build -d 'build target of the stage0 compiler' -r -f +complete -c x.py -n "__fish_x.py_using_subcommand clean" -l build -d 'host target of the stage0 compiler' -r -f complete -c x.py -n "__fish_x.py_using_subcommand clean" -l host -d 'host targets to build' -r -f complete -c x.py -n "__fish_x.py_using_subcommand clean" -l target -d 'target targets to build' -r -f complete -c x.py -n "__fish_x.py_using_subcommand clean" -l exclude -d 'build paths to exclude' -r -F @@ -460,7 +460,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand clean" -l skip-std-check-if-no complete -c x.py -n "__fish_x.py_using_subcommand clean" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x.py -n "__fish_x.py_using_subcommand dist" -l config -d 'TOML configuration file for build' -r -F complete -c x.py -n "__fish_x.py_using_subcommand dist" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" -complete -c x.py -n "__fish_x.py_using_subcommand dist" -l build -d 'build target of the stage0 compiler' -r -f +complete -c x.py -n "__fish_x.py_using_subcommand dist" -l build -d 'host target of the stage0 compiler' -r -f complete -c x.py -n "__fish_x.py_using_subcommand dist" -l host -d 'host targets to build' -r -f complete -c x.py -n "__fish_x.py_using_subcommand dist" -l target -d 'target targets to build' -r -f complete -c x.py -n "__fish_x.py_using_subcommand dist" -l exclude -d 'build paths to exclude' -r -F @@ -495,7 +495,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand dist" -l skip-std-check-if-no- complete -c x.py -n "__fish_x.py_using_subcommand dist" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x.py -n "__fish_x.py_using_subcommand install" -l config -d 'TOML configuration file for build' -r -F complete -c x.py -n "__fish_x.py_using_subcommand install" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" -complete -c x.py -n "__fish_x.py_using_subcommand install" -l build -d 'build target of the stage0 compiler' -r -f +complete -c x.py -n "__fish_x.py_using_subcommand install" -l build -d 'host target of the stage0 compiler' -r -f complete -c x.py -n "__fish_x.py_using_subcommand install" -l host -d 'host targets to build' -r -f complete -c x.py -n "__fish_x.py_using_subcommand install" -l target -d 'target targets to build' -r -f complete -c x.py -n "__fish_x.py_using_subcommand install" -l exclude -d 'build paths to exclude' -r -F @@ -531,7 +531,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand install" -s h -l help -d 'Prin complete -c x.py -n "__fish_x.py_using_subcommand run" -l args -d 'arguments for the tool' -r complete -c x.py -n "__fish_x.py_using_subcommand run" -l config -d 'TOML configuration file for build' -r -F complete -c x.py -n "__fish_x.py_using_subcommand run" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" -complete -c x.py -n "__fish_x.py_using_subcommand run" -l build -d 'build target of the stage0 compiler' -r -f +complete -c x.py -n "__fish_x.py_using_subcommand run" -l build -d 'host target of the stage0 compiler' -r -f complete -c x.py -n "__fish_x.py_using_subcommand run" -l host -d 'host targets to build' -r -f complete -c x.py -n "__fish_x.py_using_subcommand run" -l target -d 'target targets to build' -r -f complete -c x.py -n "__fish_x.py_using_subcommand run" -l exclude -d 'build paths to exclude' -r -F @@ -566,7 +566,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand run" -l skip-std-check-if-no-d complete -c x.py -n "__fish_x.py_using_subcommand run" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x.py -n "__fish_x.py_using_subcommand setup" -l config -d 'TOML configuration file for build' -r -F complete -c x.py -n "__fish_x.py_using_subcommand setup" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" -complete -c x.py -n "__fish_x.py_using_subcommand setup" -l build -d 'build target of the stage0 compiler' -r -f +complete -c x.py -n "__fish_x.py_using_subcommand setup" -l build -d 'host target of the stage0 compiler' -r -f complete -c x.py -n "__fish_x.py_using_subcommand setup" -l host -d 'host targets to build' -r -f complete -c x.py -n "__fish_x.py_using_subcommand setup" -l target -d 'target targets to build' -r -f complete -c x.py -n "__fish_x.py_using_subcommand setup" -l exclude -d 'build paths to exclude' -r -F @@ -601,7 +601,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand setup" -l skip-std-check-if-no complete -c x.py -n "__fish_x.py_using_subcommand setup" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l config -d 'TOML configuration file for build' -r -F complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" -complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l build -d 'build target of the stage0 compiler' -r -f +complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l build -d 'host target of the stage0 compiler' -r -f complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l host -d 'host targets to build' -r -f complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l target -d 'target targets to build' -r -f complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l exclude -d 'build paths to exclude' -r -F @@ -638,7 +638,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand suggest" -s h -l help -d 'Prin complete -c x.py -n "__fish_x.py_using_subcommand vendor" -l sync -d 'Additional `Cargo.toml` to sync and vendor' -r -F complete -c x.py -n "__fish_x.py_using_subcommand vendor" -l config -d 'TOML configuration file for build' -r -F complete -c x.py -n "__fish_x.py_using_subcommand vendor" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" -complete -c x.py -n "__fish_x.py_using_subcommand vendor" -l build -d 'build target of the stage0 compiler' -r -f +complete -c x.py -n "__fish_x.py_using_subcommand vendor" -l build -d 'host target of the stage0 compiler' -r -f complete -c x.py -n "__fish_x.py_using_subcommand vendor" -l host -d 'host targets to build' -r -f complete -c x.py -n "__fish_x.py_using_subcommand vendor" -l target -d 'target targets to build' -r -f complete -c x.py -n "__fish_x.py_using_subcommand vendor" -l exclude -d 'build paths to exclude' -r -F @@ -674,7 +674,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand vendor" -l skip-std-check-if-n complete -c x.py -n "__fish_x.py_using_subcommand vendor" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x.py -n "__fish_x.py_using_subcommand perf; and not __fish_seen_subcommand_from eprintln samply cachegrind benchmark compare" -l config -d 'TOML configuration file for build' -r -F complete -c x.py -n "__fish_x.py_using_subcommand perf; and not __fish_seen_subcommand_from eprintln samply cachegrind benchmark compare" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" -complete -c x.py -n "__fish_x.py_using_subcommand perf; and not __fish_seen_subcommand_from eprintln samply cachegrind benchmark compare" -l build -d 'build target of the stage0 compiler' -r -f +complete -c x.py -n "__fish_x.py_using_subcommand perf; and not __fish_seen_subcommand_from eprintln samply cachegrind benchmark compare" -l build -d 'host target of the stage0 compiler' -r -f complete -c x.py -n "__fish_x.py_using_subcommand perf; and not __fish_seen_subcommand_from eprintln samply cachegrind benchmark compare" -l host -d 'host targets to build' -r -f complete -c x.py -n "__fish_x.py_using_subcommand perf; and not __fish_seen_subcommand_from eprintln samply cachegrind benchmark compare" -l target -d 'target targets to build' -r -f complete -c x.py -n "__fish_x.py_using_subcommand perf; and not __fish_seen_subcommand_from eprintln samply cachegrind benchmark compare" -l exclude -d 'build paths to exclude' -r -F @@ -718,7 +718,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcomma complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from eprintln" -l profiles -d 'Select the profiles that should be benchmarked' -r -f -a "{Check\t'',Debug\t'',Doc\t'',Opt\t'',Clippy\t''}" complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from eprintln" -l config -d 'TOML configuration file for build' -r -F complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from eprintln" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" -complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from eprintln" -l build -d 'build target of the stage0 compiler' -r -f +complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from eprintln" -l build -d 'host target of the stage0 compiler' -r -f complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from eprintln" -l host -d 'host targets to build' -r -f complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from eprintln" -l target -d 'target targets to build' -r -f complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from eprintln" -l skip -d 'build paths to skip' -r -F @@ -756,7 +756,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcomma complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from samply" -l profiles -d 'Select the profiles that should be benchmarked' -r -f -a "{Check\t'',Debug\t'',Doc\t'',Opt\t'',Clippy\t''}" complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from samply" -l config -d 'TOML configuration file for build' -r -F complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from samply" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" -complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from samply" -l build -d 'build target of the stage0 compiler' -r -f +complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from samply" -l build -d 'host target of the stage0 compiler' -r -f complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from samply" -l host -d 'host targets to build' -r -f complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from samply" -l target -d 'target targets to build' -r -f complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from samply" -l skip -d 'build paths to skip' -r -F @@ -794,7 +794,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcomma complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from cachegrind" -l profiles -d 'Select the profiles that should be benchmarked' -r -f -a "{Check\t'',Debug\t'',Doc\t'',Opt\t'',Clippy\t''}" complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from cachegrind" -l config -d 'TOML configuration file for build' -r -F complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from cachegrind" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" -complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from cachegrind" -l build -d 'build target of the stage0 compiler' -r -f +complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from cachegrind" -l build -d 'host target of the stage0 compiler' -r -f complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from cachegrind" -l host -d 'host targets to build' -r -f complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from cachegrind" -l target -d 'target targets to build' -r -f complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from cachegrind" -l skip -d 'build paths to skip' -r -F @@ -832,7 +832,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcomma complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -l profiles -d 'Select the profiles that should be benchmarked' -r -f -a "{Check\t'',Debug\t'',Doc\t'',Opt\t'',Clippy\t''}" complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -l config -d 'TOML configuration file for build' -r -F complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" -complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -l build -d 'build target of the stage0 compiler' -r -f +complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -l build -d 'host target of the stage0 compiler' -r -f complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -l host -d 'host targets to build' -r -f complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -l target -d 'target targets to build' -r -f complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -l skip -d 'build paths to skip' -r -F @@ -866,7 +866,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcomma complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -s h -l help -d 'Print help (see more with \'--help\')' complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from compare" -l config -d 'TOML configuration file for build' -r -F complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from compare" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)" -complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from compare" -l build -d 'build target of the stage0 compiler' -r -f +complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from compare" -l build -d 'host target of the stage0 compiler' -r -f complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from compare" -l host -d 'host targets to build' -r -f complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from compare" -l target -d 'target targets to build' -r -f complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from compare" -l exclude -d 'build paths to exclude' -r -F diff --git a/src/etc/completions/x.py.ps1 b/src/etc/completions/x.py.ps1 index 5d224ac6df4..ee3373b9e75 100644 --- a/src/etc/completions/x.py.ps1 +++ b/src/etc/completions/x.py.ps1 @@ -23,7 +23,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { 'x.py' { [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`') - [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler') + [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler') [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build') [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build') [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude') @@ -82,7 +82,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { 'x.py;build' { [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`') - [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler') + [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler') [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build') [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build') [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude') @@ -124,7 +124,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { 'x.py;check' { [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`') - [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler') + [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler') [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build') [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build') [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude') @@ -171,7 +171,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('-F', '-F ', [CompletionResultType]::ParameterName, 'clippy lints to forbid') [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`') - [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler') + [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler') [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build') [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build') [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude') @@ -216,7 +216,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { 'x.py;fix' { [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`') - [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler') + [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler') [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build') [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build') [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude') @@ -258,7 +258,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { 'x.py;fmt' { [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`') - [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler') + [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler') [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build') [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build') [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude') @@ -302,7 +302,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { 'x.py;doc' { [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`') - [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler') + [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler') [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build') [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build') [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude') @@ -352,7 +352,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--run', '--run', [CompletionResultType]::ParameterName, 'whether to execute run-* tests') [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`') - [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler') + [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler') [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build') [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build') [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude') @@ -403,7 +403,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--test-args', '--test-args', [CompletionResultType]::ParameterName, 'extra arguments to be passed for the test tool being used (e.g. libtest, compiletest or rustdoc)') [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`') - [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler') + [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler') [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build') [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build') [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude') @@ -449,7 +449,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--test-args', '--test-args', [CompletionResultType]::ParameterName, 'test-args') [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`') - [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler') + [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler') [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build') [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build') [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude') @@ -492,7 +492,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--stage', '--stage', [CompletionResultType]::ParameterName, 'Clean a specific stage without touching other artifacts. By default, every stage is cleaned if this option is not used') [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`') - [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler') + [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler') [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build') [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build') [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude') @@ -534,7 +534,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { 'x.py;dist' { [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`') - [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler') + [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler') [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build') [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build') [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude') @@ -576,7 +576,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { 'x.py;install' { [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`') - [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler') + [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler') [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build') [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build') [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude') @@ -619,7 +619,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--args', '--args', [CompletionResultType]::ParameterName, 'arguments for the tool') [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`') - [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler') + [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler') [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build') [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build') [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude') @@ -661,7 +661,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { 'x.py;setup' { [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`') - [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler') + [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler') [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build') [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build') [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude') @@ -703,7 +703,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { 'x.py;suggest' { [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`') - [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler') + [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler') [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build') [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build') [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude') @@ -747,7 +747,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--sync', '--sync', [CompletionResultType]::ParameterName, 'Additional `Cargo.toml` to sync and vendor') [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`') - [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler') + [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler') [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build') [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build') [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude') @@ -790,7 +790,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { 'x.py;perf' { [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`') - [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler') + [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler') [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build') [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build') [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude') @@ -841,7 +841,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--profiles', '--profiles', [CompletionResultType]::ParameterName, 'Select the profiles that should be benchmarked') [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`') - [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler') + [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler') [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build') [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build') [CompletionResult]::new('--skip', '--skip', [CompletionResultType]::ParameterName, 'build paths to skip') @@ -886,7 +886,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--profiles', '--profiles', [CompletionResultType]::ParameterName, 'Select the profiles that should be benchmarked') [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`') - [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler') + [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler') [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build') [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build') [CompletionResult]::new('--skip', '--skip', [CompletionResultType]::ParameterName, 'build paths to skip') @@ -931,7 +931,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--profiles', '--profiles', [CompletionResultType]::ParameterName, 'Select the profiles that should be benchmarked') [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`') - [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler') + [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler') [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build') [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build') [CompletionResult]::new('--skip', '--skip', [CompletionResultType]::ParameterName, 'build paths to skip') @@ -976,7 +976,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { [CompletionResult]::new('--profiles', '--profiles', [CompletionResultType]::ParameterName, 'Select the profiles that should be benchmarked') [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`') - [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler') + [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler') [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build') [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build') [CompletionResult]::new('--skip', '--skip', [CompletionResultType]::ParameterName, 'build paths to skip') @@ -1017,7 +1017,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { 'x.py;perf;compare' { [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`') - [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler') + [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler') [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build') [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build') [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude') diff --git a/src/etc/completions/x.py.zsh b/src/etc/completions/x.py.zsh index bc55280d038..6dc05708199 100644 --- a/src/etc/completions/x.py.zsh +++ b/src/etc/completions/x.py.zsh @@ -17,7 +17,7 @@ _x.py() { _arguments "${_arguments_options[@]}" : \ '--config=[TOML configuration file for build]:FILE:_files' \ '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \ -'--build=[build target of the stage0 compiler]:BUILD:' \ +'--build=[host target of the stage0 compiler]:BUILD:' \ '--host=[host targets to build]:HOST:' \ '--target=[target targets to build]:TARGET:' \ '*--exclude=[build paths to exclude]:PATH:_files' \ @@ -69,7 +69,7 @@ _x.py() { _arguments "${_arguments_options[@]}" : \ '--config=[TOML configuration file for build]:FILE:_files' \ '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \ -'--build=[build target of the stage0 compiler]:BUILD:' \ +'--build=[host target of the stage0 compiler]:BUILD:' \ '--host=[host targets to build]:HOST:' \ '--target=[target targets to build]:TARGET:' \ '*--exclude=[build paths to exclude]:PATH:_files' \ @@ -113,7 +113,7 @@ _arguments "${_arguments_options[@]}" : \ _arguments "${_arguments_options[@]}" : \ '--config=[TOML configuration file for build]:FILE:_files' \ '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \ -'--build=[build target of the stage0 compiler]:BUILD:' \ +'--build=[host target of the stage0 compiler]:BUILD:' \ '--host=[host targets to build]:HOST:' \ '--target=[target targets to build]:TARGET:' \ '*--exclude=[build paths to exclude]:PATH:_files' \ @@ -162,7 +162,7 @@ _arguments "${_arguments_options[@]}" : \ '*-F+[clippy lints to forbid]:LINT:_default' \ '--config=[TOML configuration file for build]:FILE:_files' \ '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \ -'--build=[build target of the stage0 compiler]:BUILD:' \ +'--build=[host target of the stage0 compiler]:BUILD:' \ '--host=[host targets to build]:HOST:' \ '--target=[target targets to build]:TARGET:' \ '*--exclude=[build paths to exclude]:PATH:_files' \ @@ -209,7 +209,7 @@ _arguments "${_arguments_options[@]}" : \ _arguments "${_arguments_options[@]}" : \ '--config=[TOML configuration file for build]:FILE:_files' \ '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \ -'--build=[build target of the stage0 compiler]:BUILD:' \ +'--build=[host target of the stage0 compiler]:BUILD:' \ '--host=[host targets to build]:HOST:' \ '--target=[target targets to build]:TARGET:' \ '*--exclude=[build paths to exclude]:PATH:_files' \ @@ -253,7 +253,7 @@ _arguments "${_arguments_options[@]}" : \ _arguments "${_arguments_options[@]}" : \ '--config=[TOML configuration file for build]:FILE:_files' \ '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \ -'--build=[build target of the stage0 compiler]:BUILD:' \ +'--build=[host target of the stage0 compiler]:BUILD:' \ '--host=[host targets to build]:HOST:' \ '--target=[target targets to build]:TARGET:' \ '*--exclude=[build paths to exclude]:PATH:_files' \ @@ -299,7 +299,7 @@ _arguments "${_arguments_options[@]}" : \ _arguments "${_arguments_options[@]}" : \ '--config=[TOML configuration file for build]:FILE:_files' \ '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \ -'--build=[build target of the stage0 compiler]:BUILD:' \ +'--build=[host target of the stage0 compiler]:BUILD:' \ '--host=[host targets to build]:HOST:' \ '--target=[target targets to build]:TARGET:' \ '*--exclude=[build paths to exclude]:PATH:_files' \ @@ -351,7 +351,7 @@ _arguments "${_arguments_options[@]}" : \ '--run=[whether to execute run-* tests]:auto | always | never:_default' \ '--config=[TOML configuration file for build]:FILE:_files' \ '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \ -'--build=[build target of the stage0 compiler]:BUILD:' \ +'--build=[host target of the stage0 compiler]:BUILD:' \ '--host=[host targets to build]:HOST:' \ '--target=[target targets to build]:TARGET:' \ '*--exclude=[build paths to exclude]:PATH:_files' \ @@ -404,7 +404,7 @@ _arguments "${_arguments_options[@]}" : \ '*--test-args=[extra arguments to be passed for the test tool being used (e.g. libtest, compiletest or rustdoc)]:ARGS:_default' \ '--config=[TOML configuration file for build]:FILE:_files' \ '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \ -'--build=[build target of the stage0 compiler]:BUILD:' \ +'--build=[host target of the stage0 compiler]:BUILD:' \ '--host=[host targets to build]:HOST:' \ '--target=[target targets to build]:TARGET:' \ '*--exclude=[build paths to exclude]:PATH:_files' \ @@ -452,7 +452,7 @@ _arguments "${_arguments_options[@]}" : \ '*--test-args=[]:TEST_ARGS:_default' \ '--config=[TOML configuration file for build]:FILE:_files' \ '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \ -'--build=[build target of the stage0 compiler]:BUILD:' \ +'--build=[host target of the stage0 compiler]:BUILD:' \ '--host=[host targets to build]:HOST:' \ '--target=[target targets to build]:TARGET:' \ '*--exclude=[build paths to exclude]:PATH:_files' \ @@ -497,7 +497,7 @@ _arguments "${_arguments_options[@]}" : \ '--stage=[Clean a specific stage without touching other artifacts. By default, every stage is cleaned if this option is not used]:N:_default' \ '--config=[TOML configuration file for build]:FILE:_files' \ '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \ -'--build=[build target of the stage0 compiler]:BUILD:' \ +'--build=[host target of the stage0 compiler]:BUILD:' \ '--host=[host targets to build]:HOST:' \ '--target=[target targets to build]:TARGET:' \ '*--exclude=[build paths to exclude]:PATH:_files' \ @@ -541,7 +541,7 @@ _arguments "${_arguments_options[@]}" : \ _arguments "${_arguments_options[@]}" : \ '--config=[TOML configuration file for build]:FILE:_files' \ '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \ -'--build=[build target of the stage0 compiler]:BUILD:' \ +'--build=[host target of the stage0 compiler]:BUILD:' \ '--host=[host targets to build]:HOST:' \ '--target=[target targets to build]:TARGET:' \ '*--exclude=[build paths to exclude]:PATH:_files' \ @@ -585,7 +585,7 @@ _arguments "${_arguments_options[@]}" : \ _arguments "${_arguments_options[@]}" : \ '--config=[TOML configuration file for build]:FILE:_files' \ '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \ -'--build=[build target of the stage0 compiler]:BUILD:' \ +'--build=[host target of the stage0 compiler]:BUILD:' \ '--host=[host targets to build]:HOST:' \ '--target=[target targets to build]:TARGET:' \ '*--exclude=[build paths to exclude]:PATH:_files' \ @@ -630,7 +630,7 @@ _arguments "${_arguments_options[@]}" : \ '*--args=[arguments for the tool]:ARGS:_default' \ '--config=[TOML configuration file for build]:FILE:_files' \ '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \ -'--build=[build target of the stage0 compiler]:BUILD:' \ +'--build=[host target of the stage0 compiler]:BUILD:' \ '--host=[host targets to build]:HOST:' \ '--target=[target targets to build]:TARGET:' \ '*--exclude=[build paths to exclude]:PATH:_files' \ @@ -674,7 +674,7 @@ _arguments "${_arguments_options[@]}" : \ _arguments "${_arguments_options[@]}" : \ '--config=[TOML configuration file for build]:FILE:_files' \ '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \ -'--build=[build target of the stage0 compiler]:BUILD:' \ +'--build=[host target of the stage0 compiler]:BUILD:' \ '--host=[host targets to build]:HOST:' \ '--target=[target targets to build]:TARGET:' \ '*--exclude=[build paths to exclude]:PATH:_files' \ @@ -719,7 +719,7 @@ _arguments "${_arguments_options[@]}" : \ _arguments "${_arguments_options[@]}" : \ '--config=[TOML configuration file for build]:FILE:_files' \ '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \ -'--build=[build target of the stage0 compiler]:BUILD:' \ +'--build=[host target of the stage0 compiler]:BUILD:' \ '--host=[host targets to build]:HOST:' \ '--target=[target targets to build]:TARGET:' \ '*--exclude=[build paths to exclude]:PATH:_files' \ @@ -765,7 +765,7 @@ _arguments "${_arguments_options[@]}" : \ '*--sync=[Additional \`Cargo.toml\` to sync and vendor]:SYNC:_files' \ '--config=[TOML configuration file for build]:FILE:_files' \ '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \ -'--build=[build target of the stage0 compiler]:BUILD:' \ +'--build=[host target of the stage0 compiler]:BUILD:' \ '--host=[host targets to build]:HOST:' \ '--target=[target targets to build]:TARGET:' \ '*--exclude=[build paths to exclude]:PATH:_files' \ @@ -810,7 +810,7 @@ _arguments "${_arguments_options[@]}" : \ _arguments "${_arguments_options[@]}" : \ '--config=[TOML configuration file for build]:FILE:_files' \ '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \ -'--build=[build target of the stage0 compiler]:BUILD:' \ +'--build=[host target of the stage0 compiler]:BUILD:' \ '--host=[host targets to build]:HOST:' \ '--target=[target targets to build]:TARGET:' \ '*--exclude=[build paths to exclude]:PATH:_files' \ @@ -867,7 +867,7 @@ _arguments "${_arguments_options[@]}" : \ '*--profiles=[Select the profiles that should be benchmarked]:PROFILES:(Check Debug Doc Opt Clippy)' \ '--config=[TOML configuration file for build]:FILE:_files' \ '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \ -'--build=[build target of the stage0 compiler]:BUILD:' \ +'--build=[host target of the stage0 compiler]:BUILD:' \ '--host=[host targets to build]:HOST:' \ '--target=[target targets to build]:TARGET:' \ '*--skip=[build paths to skip]:PATH:_files' \ @@ -914,7 +914,7 @@ _arguments "${_arguments_options[@]}" : \ '*--profiles=[Select the profiles that should be benchmarked]:PROFILES:(Check Debug Doc Opt Clippy)' \ '--config=[TOML configuration file for build]:FILE:_files' \ '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \ -'--build=[build target of the stage0 compiler]:BUILD:' \ +'--build=[host target of the stage0 compiler]:BUILD:' \ '--host=[host targets to build]:HOST:' \ '--target=[target targets to build]:TARGET:' \ '*--skip=[build paths to skip]:PATH:_files' \ @@ -961,7 +961,7 @@ _arguments "${_arguments_options[@]}" : \ '*--profiles=[Select the profiles that should be benchmarked]:PROFILES:(Check Debug Doc Opt Clippy)' \ '--config=[TOML configuration file for build]:FILE:_files' \ '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \ -'--build=[build target of the stage0 compiler]:BUILD:' \ +'--build=[host target of the stage0 compiler]:BUILD:' \ '--host=[host targets to build]:HOST:' \ '--target=[target targets to build]:TARGET:' \ '*--skip=[build paths to skip]:PATH:_files' \ @@ -1008,7 +1008,7 @@ _arguments "${_arguments_options[@]}" : \ '*--profiles=[Select the profiles that should be benchmarked]:PROFILES:(Check Debug Doc Opt Clippy)' \ '--config=[TOML configuration file for build]:FILE:_files' \ '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \ -'--build=[build target of the stage0 compiler]:BUILD:' \ +'--build=[host target of the stage0 compiler]:BUILD:' \ '--host=[host targets to build]:HOST:' \ '--target=[target targets to build]:TARGET:' \ '*--skip=[build paths to skip]:PATH:_files' \ @@ -1052,7 +1052,7 @@ _arguments "${_arguments_options[@]}" : \ _arguments "${_arguments_options[@]}" : \ '--config=[TOML configuration file for build]:FILE:_files' \ '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \ -'--build=[build target of the stage0 compiler]:BUILD:' \ +'--build=[host target of the stage0 compiler]:BUILD:' \ '--host=[host targets to build]:HOST:' \ '--target=[target targets to build]:TARGET:' \ '*--exclude=[build paths to exclude]:PATH:_files' \ diff --git a/src/etc/completions/x.zsh b/src/etc/completions/x.zsh index 2e3094fc379..869884bf1dc 100644 --- a/src/etc/completions/x.zsh +++ b/src/etc/completions/x.zsh @@ -17,7 +17,7 @@ _x() { _arguments "${_arguments_options[@]}" : \ '--config=[TOML configuration file for build]:FILE:_files' \ '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \ -'--build=[build target of the stage0 compiler]:BUILD:' \ +'--build=[host target of the stage0 compiler]:BUILD:' \ '--host=[host targets to build]:HOST:' \ '--target=[target targets to build]:TARGET:' \ '*--exclude=[build paths to exclude]:PATH:_files' \ @@ -69,7 +69,7 @@ _x() { _arguments "${_arguments_options[@]}" : \ '--config=[TOML configuration file for build]:FILE:_files' \ '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \ -'--build=[build target of the stage0 compiler]:BUILD:' \ +'--build=[host target of the stage0 compiler]:BUILD:' \ '--host=[host targets to build]:HOST:' \ '--target=[target targets to build]:TARGET:' \ '*--exclude=[build paths to exclude]:PATH:_files' \ @@ -113,7 +113,7 @@ _arguments "${_arguments_options[@]}" : \ _arguments "${_arguments_options[@]}" : \ '--config=[TOML configuration file for build]:FILE:_files' \ '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \ -'--build=[build target of the stage0 compiler]:BUILD:' \ +'--build=[host target of the stage0 compiler]:BUILD:' \ '--host=[host targets to build]:HOST:' \ '--target=[target targets to build]:TARGET:' \ '*--exclude=[build paths to exclude]:PATH:_files' \ @@ -162,7 +162,7 @@ _arguments "${_arguments_options[@]}" : \ '*-F+[clippy lints to forbid]:LINT:_default' \ '--config=[TOML configuration file for build]:FILE:_files' \ '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \ -'--build=[build target of the stage0 compiler]:BUILD:' \ +'--build=[host target of the stage0 compiler]:BUILD:' \ '--host=[host targets to build]:HOST:' \ '--target=[target targets to build]:TARGET:' \ '*--exclude=[build paths to exclude]:PATH:_files' \ @@ -209,7 +209,7 @@ _arguments "${_arguments_options[@]}" : \ _arguments "${_arguments_options[@]}" : \ '--config=[TOML configuration file for build]:FILE:_files' \ '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \ -'--build=[build target of the stage0 compiler]:BUILD:' \ +'--build=[host target of the stage0 compiler]:BUILD:' \ '--host=[host targets to build]:HOST:' \ '--target=[target targets to build]:TARGET:' \ '*--exclude=[build paths to exclude]:PATH:_files' \ @@ -253,7 +253,7 @@ _arguments "${_arguments_options[@]}" : \ _arguments "${_arguments_options[@]}" : \ '--config=[TOML configuration file for build]:FILE:_files' \ '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \ -'--build=[build target of the stage0 compiler]:BUILD:' \ +'--build=[host target of the stage0 compiler]:BUILD:' \ '--host=[host targets to build]:HOST:' \ '--target=[target targets to build]:TARGET:' \ '*--exclude=[build paths to exclude]:PATH:_files' \ @@ -299,7 +299,7 @@ _arguments "${_arguments_options[@]}" : \ _arguments "${_arguments_options[@]}" : \ '--config=[TOML configuration file for build]:FILE:_files' \ '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \ -'--build=[build target of the stage0 compiler]:BUILD:' \ +'--build=[host target of the stage0 compiler]:BUILD:' \ '--host=[host targets to build]:HOST:' \ '--target=[target targets to build]:TARGET:' \ '*--exclude=[build paths to exclude]:PATH:_files' \ @@ -351,7 +351,7 @@ _arguments "${_arguments_options[@]}" : \ '--run=[whether to execute run-* tests]:auto | always | never:_default' \ '--config=[TOML configuration file for build]:FILE:_files' \ '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \ -'--build=[build target of the stage0 compiler]:BUILD:' \ +'--build=[host target of the stage0 compiler]:BUILD:' \ '--host=[host targets to build]:HOST:' \ '--target=[target targets to build]:TARGET:' \ '*--exclude=[build paths to exclude]:PATH:_files' \ @@ -404,7 +404,7 @@ _arguments "${_arguments_options[@]}" : \ '*--test-args=[extra arguments to be passed for the test tool being used (e.g. libtest, compiletest or rustdoc)]:ARGS:_default' \ '--config=[TOML configuration file for build]:FILE:_files' \ '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \ -'--build=[build target of the stage0 compiler]:BUILD:' \ +'--build=[host target of the stage0 compiler]:BUILD:' \ '--host=[host targets to build]:HOST:' \ '--target=[target targets to build]:TARGET:' \ '*--exclude=[build paths to exclude]:PATH:_files' \ @@ -452,7 +452,7 @@ _arguments "${_arguments_options[@]}" : \ '*--test-args=[]:TEST_ARGS:_default' \ '--config=[TOML configuration file for build]:FILE:_files' \ '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \ -'--build=[build target of the stage0 compiler]:BUILD:' \ +'--build=[host target of the stage0 compiler]:BUILD:' \ '--host=[host targets to build]:HOST:' \ '--target=[target targets to build]:TARGET:' \ '*--exclude=[build paths to exclude]:PATH:_files' \ @@ -497,7 +497,7 @@ _arguments "${_arguments_options[@]}" : \ '--stage=[Clean a specific stage without touching other artifacts. By default, every stage is cleaned if this option is not used]:N:_default' \ '--config=[TOML configuration file for build]:FILE:_files' \ '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \ -'--build=[build target of the stage0 compiler]:BUILD:' \ +'--build=[host target of the stage0 compiler]:BUILD:' \ '--host=[host targets to build]:HOST:' \ '--target=[target targets to build]:TARGET:' \ '*--exclude=[build paths to exclude]:PATH:_files' \ @@ -541,7 +541,7 @@ _arguments "${_arguments_options[@]}" : \ _arguments "${_arguments_options[@]}" : \ '--config=[TOML configuration file for build]:FILE:_files' \ '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \ -'--build=[build target of the stage0 compiler]:BUILD:' \ +'--build=[host target of the stage0 compiler]:BUILD:' \ '--host=[host targets to build]:HOST:' \ '--target=[target targets to build]:TARGET:' \ '*--exclude=[build paths to exclude]:PATH:_files' \ @@ -585,7 +585,7 @@ _arguments "${_arguments_options[@]}" : \ _arguments "${_arguments_options[@]}" : \ '--config=[TOML configuration file for build]:FILE:_files' \ '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \ -'--build=[build target of the stage0 compiler]:BUILD:' \ +'--build=[host target of the stage0 compiler]:BUILD:' \ '--host=[host targets to build]:HOST:' \ '--target=[target targets to build]:TARGET:' \ '*--exclude=[build paths to exclude]:PATH:_files' \ @@ -630,7 +630,7 @@ _arguments "${_arguments_options[@]}" : \ '*--args=[arguments for the tool]:ARGS:_default' \ '--config=[TOML configuration file for build]:FILE:_files' \ '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \ -'--build=[build target of the stage0 compiler]:BUILD:' \ +'--build=[host target of the stage0 compiler]:BUILD:' \ '--host=[host targets to build]:HOST:' \ '--target=[target targets to build]:TARGET:' \ '*--exclude=[build paths to exclude]:PATH:_files' \ @@ -674,7 +674,7 @@ _arguments "${_arguments_options[@]}" : \ _arguments "${_arguments_options[@]}" : \ '--config=[TOML configuration file for build]:FILE:_files' \ '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \ -'--build=[build target of the stage0 compiler]:BUILD:' \ +'--build=[host target of the stage0 compiler]:BUILD:' \ '--host=[host targets to build]:HOST:' \ '--target=[target targets to build]:TARGET:' \ '*--exclude=[build paths to exclude]:PATH:_files' \ @@ -719,7 +719,7 @@ _arguments "${_arguments_options[@]}" : \ _arguments "${_arguments_options[@]}" : \ '--config=[TOML configuration file for build]:FILE:_files' \ '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \ -'--build=[build target of the stage0 compiler]:BUILD:' \ +'--build=[host target of the stage0 compiler]:BUILD:' \ '--host=[host targets to build]:HOST:' \ '--target=[target targets to build]:TARGET:' \ '*--exclude=[build paths to exclude]:PATH:_files' \ @@ -765,7 +765,7 @@ _arguments "${_arguments_options[@]}" : \ '*--sync=[Additional \`Cargo.toml\` to sync and vendor]:SYNC:_files' \ '--config=[TOML configuration file for build]:FILE:_files' \ '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \ -'--build=[build target of the stage0 compiler]:BUILD:' \ +'--build=[host target of the stage0 compiler]:BUILD:' \ '--host=[host targets to build]:HOST:' \ '--target=[target targets to build]:TARGET:' \ '*--exclude=[build paths to exclude]:PATH:_files' \ @@ -810,7 +810,7 @@ _arguments "${_arguments_options[@]}" : \ _arguments "${_arguments_options[@]}" : \ '--config=[TOML configuration file for build]:FILE:_files' \ '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \ -'--build=[build target of the stage0 compiler]:BUILD:' \ +'--build=[host target of the stage0 compiler]:BUILD:' \ '--host=[host targets to build]:HOST:' \ '--target=[target targets to build]:TARGET:' \ '*--exclude=[build paths to exclude]:PATH:_files' \ @@ -867,7 +867,7 @@ _arguments "${_arguments_options[@]}" : \ '*--profiles=[Select the profiles that should be benchmarked]:PROFILES:(Check Debug Doc Opt Clippy)' \ '--config=[TOML configuration file for build]:FILE:_files' \ '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \ -'--build=[build target of the stage0 compiler]:BUILD:' \ +'--build=[host target of the stage0 compiler]:BUILD:' \ '--host=[host targets to build]:HOST:' \ '--target=[target targets to build]:TARGET:' \ '*--skip=[build paths to skip]:PATH:_files' \ @@ -914,7 +914,7 @@ _arguments "${_arguments_options[@]}" : \ '*--profiles=[Select the profiles that should be benchmarked]:PROFILES:(Check Debug Doc Opt Clippy)' \ '--config=[TOML configuration file for build]:FILE:_files' \ '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \ -'--build=[build target of the stage0 compiler]:BUILD:' \ +'--build=[host target of the stage0 compiler]:BUILD:' \ '--host=[host targets to build]:HOST:' \ '--target=[target targets to build]:TARGET:' \ '*--skip=[build paths to skip]:PATH:_files' \ @@ -961,7 +961,7 @@ _arguments "${_arguments_options[@]}" : \ '*--profiles=[Select the profiles that should be benchmarked]:PROFILES:(Check Debug Doc Opt Clippy)' \ '--config=[TOML configuration file for build]:FILE:_files' \ '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \ -'--build=[build target of the stage0 compiler]:BUILD:' \ +'--build=[host target of the stage0 compiler]:BUILD:' \ '--host=[host targets to build]:HOST:' \ '--target=[target targets to build]:TARGET:' \ '*--skip=[build paths to skip]:PATH:_files' \ @@ -1008,7 +1008,7 @@ _arguments "${_arguments_options[@]}" : \ '*--profiles=[Select the profiles that should be benchmarked]:PROFILES:(Check Debug Doc Opt Clippy)' \ '--config=[TOML configuration file for build]:FILE:_files' \ '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \ -'--build=[build target of the stage0 compiler]:BUILD:' \ +'--build=[host target of the stage0 compiler]:BUILD:' \ '--host=[host targets to build]:HOST:' \ '--target=[target targets to build]:TARGET:' \ '*--skip=[build paths to skip]:PATH:_files' \ @@ -1052,7 +1052,7 @@ _arguments "${_arguments_options[@]}" : \ _arguments "${_arguments_options[@]}" : \ '--config=[TOML configuration file for build]:FILE:_files' \ '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \ -'--build=[build target of the stage0 compiler]:BUILD:' \ +'--build=[host target of the stage0 compiler]:BUILD:' \ '--host=[host targets to build]:HOST:' \ '--target=[target targets to build]:TARGET:' \ '*--exclude=[build paths to exclude]:PATH:_files' \ diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index 138ac3c97f7..a91ea55bcae 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -11,7 +11,7 @@ use tracing::{debug, instrument}; use crate::clean::{ self, Lifetime, clean_generic_param_def, clean_middle_ty, clean_predicate, - clean_trait_ref_with_constraints, clean_ty_generics, simplify, + clean_trait_ref_with_constraints, clean_ty_generics_inner, simplify, }; use crate::core::DocContext; @@ -101,7 +101,7 @@ fn synthesize_auto_trait_impl<'tcx>( // Instead, we generate `impl !Send for Foo<T>`, which better // expresses the fact that `Foo<T>` never implements `Send`, // regardless of the choice of `T`. - let mut generics = clean_ty_generics( + let mut generics = clean_ty_generics_inner( cx, tcx.generics_of(item_def_id), ty::GenericPredicates::default(), diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs index 89245fee515..c889f52b789 100644 --- a/src/librustdoc/clean/blanket_impl.rs +++ b/src/librustdoc/clean/blanket_impl.rs @@ -90,11 +90,7 @@ pub(crate) fn synthesize_blanket_impls( stability: None, kind: clean::ImplItem(Box::new(clean::Impl { safety: hir::Safety::Safe, - generics: clean_ty_generics( - cx, - tcx.generics_of(impl_def_id), - tcx.explicit_predicates_of(impl_def_id), - ), + generics: clean_ty_generics(cx, impl_def_id), // FIXME(eddyb) compute both `trait_` and `for_` from // the post-inference `trait_ref`, as it's more accurate. trait_: Some(clean_trait_ref_with_constraints( diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index a3762e4117d..b6ce8551060 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -169,33 +169,36 @@ impl Cfg { msg } - /// Renders the configuration for long display, as a long HTML description. - pub(crate) fn render_long_html(&self) -> String { + fn render_long_inner(&self, format: Format) -> String { let on = if self.omit_preposition() { - "" + " " } else if self.should_use_with_in_description() { - "with " + " with " } else { - "on " + " on " }; - let mut msg = format!("Available {on}<strong>{}</strong>", Display(self, Format::LongHtml)); + let mut msg = if matches!(format, Format::LongHtml) { + format!("Available{on}<strong>{}</strong>", Display(self, format)) + } else { + format!("Available{on}{}", Display(self, format)) + }; if self.should_append_only_to_description() { msg.push_str(" only"); } + msg + } + + /// Renders the configuration for long display, as a long HTML description. + pub(crate) fn render_long_html(&self) -> String { + let mut msg = self.render_long_inner(Format::LongHtml); msg.push('.'); msg } /// Renders the configuration for long display, as a long plain text description. pub(crate) fn render_long_plain(&self) -> String { - let on = if self.should_use_with_in_description() { "with" } else { "on" }; - - let mut msg = format!("Available {on} {}", Display(self, Format::LongPlain)); - if self.should_append_only_to_description() { - msg.push_str(" only"); - } - msg + self.render_long_inner(Format::LongPlain) } fn should_capitalize_first_letter(&self) -> bool { diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 55a116a018a..9b5491310b4 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -264,16 +264,13 @@ pub(crate) fn build_trait(cx: &mut DocContext<'_>, did: DefId) -> clean::Trait { .map(|item| clean_middle_assoc_item(item, cx)) .collect(); - let predicates = cx.tcx.predicates_of(did); - let generics = clean_ty_generics(cx, cx.tcx.generics_of(did), predicates); - let generics = filter_non_trait_generics(did, generics); + let generics = clean_ty_generics(cx, did); let (generics, supertrait_bounds) = separate_self_bounds(generics); clean::Trait { def_id: did, generics, items: trait_items, bounds: supertrait_bounds } } fn build_trait_alias(cx: &mut DocContext<'_>, did: DefId) -> clean::TraitAlias { - let predicates = cx.tcx.predicates_of(did); - let generics = clean_ty_generics(cx, cx.tcx.generics_of(did), predicates); + let generics = clean_ty_generics(cx, did); let (generics, bounds) = separate_self_bounds(generics); clean::TraitAlias { generics, bounds } } @@ -281,8 +278,7 @@ fn build_trait_alias(cx: &mut DocContext<'_>, did: DefId) -> clean::TraitAlias { pub(super) fn build_function(cx: &mut DocContext<'_>, def_id: DefId) -> Box<clean::Function> { let sig = cx.tcx.fn_sig(def_id).instantiate_identity(); // The generics need to be cleaned before the signature. - let mut generics = - clean_ty_generics(cx, cx.tcx.generics_of(def_id), cx.tcx.explicit_predicates_of(def_id)); + let mut generics = clean_ty_generics(cx, def_id); let bound_vars = clean_bound_vars(sig.bound_vars()); // At the time of writing early & late-bound params are stored separately in rustc, @@ -311,30 +307,26 @@ pub(super) fn build_function(cx: &mut DocContext<'_>, def_id: DefId) -> Box<clea } fn build_enum(cx: &mut DocContext<'_>, did: DefId) -> clean::Enum { - let predicates = cx.tcx.explicit_predicates_of(did); - clean::Enum { - generics: clean_ty_generics(cx, cx.tcx.generics_of(did), predicates), + generics: clean_ty_generics(cx, did), variants: cx.tcx.adt_def(did).variants().iter().map(|v| clean_variant_def(v, cx)).collect(), } } fn build_struct(cx: &mut DocContext<'_>, did: DefId) -> clean::Struct { - let predicates = cx.tcx.explicit_predicates_of(did); let variant = cx.tcx.adt_def(did).non_enum_variant(); clean::Struct { ctor_kind: variant.ctor_kind(), - generics: clean_ty_generics(cx, cx.tcx.generics_of(did), predicates), + generics: clean_ty_generics(cx, did), fields: variant.fields.iter().map(|x| clean_middle_field(x, cx)).collect(), } } fn build_union(cx: &mut DocContext<'_>, did: DefId) -> clean::Union { - let predicates = cx.tcx.explicit_predicates_of(did); let variant = cx.tcx.adt_def(did).non_enum_variant(); - let generics = clean_ty_generics(cx, cx.tcx.generics_of(did), predicates); + let generics = clean_ty_generics(cx, did); let fields = variant.fields.iter().map(|x| clean_middle_field(x, cx)).collect(); clean::Union { generics, fields } } @@ -344,14 +336,13 @@ fn build_type_alias( did: DefId, ret: &mut Vec<Item>, ) -> Box<clean::TypeAlias> { - let predicates = cx.tcx.explicit_predicates_of(did); let ty = cx.tcx.type_of(did).instantiate_identity(); let type_ = clean_middle_ty(ty::Binder::dummy(ty), cx, Some(did), None); let inner_type = clean_ty_alias_inner_type(ty, cx, ret); Box::new(clean::TypeAlias { type_, - generics: clean_ty_generics(cx, cx.tcx.generics_of(did), predicates), + generics: clean_ty_generics(cx, did), inner_type, item_type: None, }) @@ -483,7 +474,6 @@ pub(crate) fn build_impl( } let document_hidden = cx.render_options.document_hidden; - let predicates = tcx.explicit_predicates_of(did); let (trait_items, generics) = match impl_item { Some(impl_) => ( impl_ @@ -549,9 +539,7 @@ pub(crate) fn build_impl( }) .map(|item| clean_middle_assoc_item(item, cx)) .collect::<Vec<_>>(), - clean::enter_impl_trait(cx, |cx| { - clean_ty_generics(cx, tcx.generics_of(did), predicates) - }), + clean::enter_impl_trait(cx, |cx| clean_ty_generics(cx, did)), ), }; let polarity = tcx.impl_polarity(did); @@ -713,8 +701,7 @@ pub(crate) fn print_inlined_const(tcx: TyCtxt<'_>, did: DefId) -> String { } fn build_const_item(cx: &mut DocContext<'_>, def_id: DefId) -> clean::Constant { - let mut generics = - clean_ty_generics(cx, cx.tcx.generics_of(def_id), cx.tcx.explicit_predicates_of(def_id)); + let mut generics = clean_ty_generics(cx, def_id); clean::simplify::move_bounds_to_generic_parameters(&mut generics); let ty = clean_middle_ty( ty::Binder::dummy(cx.tcx.type_of(def_id).instantiate_identity()), @@ -761,44 +748,6 @@ fn build_macro( } } -/// A trait's generics clause actually contains all of the predicates for all of -/// its associated types as well. We specifically move these clauses to the -/// associated types instead when displaying, so when we're generating the -/// generics for the trait itself we need to be sure to remove them. -/// We also need to remove the implied "recursive" Self: Trait bound. -/// -/// The inverse of this filtering logic can be found in the `Clean` -/// implementation for `AssociatedType` -fn filter_non_trait_generics(trait_did: DefId, mut g: clean::Generics) -> clean::Generics { - for pred in &mut g.where_predicates { - if let clean::WherePredicate::BoundPredicate { ty: clean::SelfTy, ref mut bounds, .. } = - *pred - { - bounds.retain(|bound| match bound { - clean::GenericBound::TraitBound(clean::PolyTrait { trait_, .. }, _) => { - trait_.def_id() != trait_did - } - _ => true, - }); - } - } - - g.where_predicates.retain(|pred| match pred { - clean::WherePredicate::BoundPredicate { - ty: - clean::QPath(box clean::QPathData { - self_type: clean::Generic(_), - trait_: Some(trait_), - .. - }), - bounds, - .. - } => !bounds.is_empty() && trait_.def_id() != trait_did, - _ => true, - }); - g -} - fn separate_self_bounds(mut g: clean::Generics) -> (clean::Generics, Vec<clean::GenericBound>) { let mut ty_bounds = Vec::new(); g.where_predicates.retain(|pred| match *pred { diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 7658e7ad35f..db4bcdaeb6c 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -793,7 +793,11 @@ pub(crate) fn clean_generics<'tcx>( } } -fn clean_ty_generics<'tcx>( +fn clean_ty_generics<'tcx>(cx: &mut DocContext<'tcx>, def_id: DefId) -> Generics { + clean_ty_generics_inner(cx, cx.tcx.generics_of(def_id), cx.tcx.explicit_predicates_of(def_id)) +} + +fn clean_ty_generics_inner<'tcx>( cx: &mut DocContext<'tcx>, gens: &ty::Generics, preds: ty::GenericPredicates<'tcx>, @@ -1297,11 +1301,7 @@ pub(crate) fn clean_middle_assoc_item(assoc_item: &ty::AssocItem, cx: &mut DocCo None, ); - let mut generics = clean_ty_generics( - cx, - tcx.generics_of(assoc_item.def_id), - tcx.explicit_predicates_of(assoc_item.def_id), - ); + let mut generics = clean_ty_generics(cx, assoc_item.def_id); simplify::move_bounds_to_generic_parameters(&mut generics); match assoc_item.container { @@ -1389,7 +1389,7 @@ pub(crate) fn clean_middle_assoc_item(assoc_item: &ty::AssocItem, cx: &mut DocCo let bounds = tcx.explicit_item_bounds(assoc_item.def_id).iter_identity_copied(); predicates = tcx.arena.alloc_from_iter(bounds.chain(predicates.iter().copied())); } - let mut generics = clean_ty_generics( + let mut generics = clean_ty_generics_inner( cx, tcx.generics_of(assoc_item.def_id), ty::GenericPredicates { parent: None, predicates }, diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index bde1a2e5e66..58e05bd1e85 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -2638,7 +2638,7 @@ mod size_asserts { static_assert_size!(GenericParamDef, 40); static_assert_size!(Generics, 16); static_assert_size!(Item, 8); - static_assert_size!(ItemInner, 136); + static_assert_size!(ItemInner, 144); static_assert_size!(ItemKind, 48); static_assert_size!(PathSegment, 32); static_assert_size!(Type, 32); diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs index 131a12ce228..0ceeea2b9b1 100644 --- a/src/librustdoc/json/mod.rs +++ b/src/librustdoc/json/mod.rs @@ -18,6 +18,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_hir::def_id::{DefId, DefIdSet}; use rustc_middle::ty::TyCtxt; use rustc_session::Session; +use rustc_session::features::StabilityExt; use rustc_span::def_id::LOCAL_CRATE; use rustdoc_json_types as types; // It's important to use the FxHashMap from rustdoc_json_types here, instead of @@ -148,7 +149,7 @@ fn target(sess: &rustc_session::Session) -> types::Target { .copied() .filter(|(_, stability, _)| { // Describe only target features which the user can toggle - stability.toggle_allowed().is_ok() + stability.is_toggle_permitted(sess).is_ok() }) .map(|(name, stability, implied_features)| { types::TargetFeature { @@ -164,7 +165,7 @@ fn target(sess: &rustc_session::Session) -> types::Target { // Imply only target features which the user can toggle feature_stability .get(name) - .map(|stability| stability.toggle_allowed().is_ok()) + .map(|stability| stability.is_toggle_permitted(sess).is_ok()) .unwrap_or(false) }) .map(String::from) diff --git a/src/tools/cargo b/src/tools/cargo -Subproject 64a12460708cf146e16cc61f28aba5dc2463bbb +Subproject fc1518ef02b77327d70d4026b95ea719dd9b8c5 diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md index 3a98217f625..0cfe89ad378 100644 --- a/src/tools/clippy/CHANGELOG.md +++ b/src/tools/clippy/CHANGELOG.md @@ -5685,6 +5685,7 @@ Released 2018-09-13 [`cmp_nan`]: https://rust-lang.github.io/rust-clippy/master/index.html#cmp_nan [`cmp_null`]: https://rust-lang.github.io/rust-clippy/master/index.html#cmp_null [`cmp_owned`]: https://rust-lang.github.io/rust-clippy/master/index.html#cmp_owned +[`coerce_container_to_any`]: https://rust-lang.github.io/rust-clippy/master/index.html#coerce_container_to_any [`cognitive_complexity`]: https://rust-lang.github.io/rust-clippy/master/index.html#cognitive_complexity [`collapsible_else_if`]: https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_else_if [`collapsible_if`]: https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_if @@ -5736,6 +5737,7 @@ Released 2018-09-13 [`doc_markdown`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_markdown [`doc_nested_refdefs`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_nested_refdefs [`doc_overindented_list_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_overindented_list_items +[`doc_suspicious_footnotes`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_suspicious_footnotes [`double_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_comparisons [`double_ended_iterator_last`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_ended_iterator_last [`double_must_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_must_use @@ -5862,6 +5864,7 @@ Released 2018-09-13 [`ineffective_open_options`]: https://rust-lang.github.io/rust-clippy/master/index.html#ineffective_open_options [`inefficient_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#inefficient_to_string [`infallible_destructuring_match`]: https://rust-lang.github.io/rust-clippy/master/index.html#infallible_destructuring_match +[`infallible_try_from`]: https://rust-lang.github.io/rust-clippy/master/index.html#infallible_try_from [`infinite_iter`]: https://rust-lang.github.io/rust-clippy/master/index.html#infinite_iter [`infinite_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#infinite_loop [`inherent_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#inherent_to_string @@ -5888,6 +5891,7 @@ Released 2018-09-13 [`inverted_saturating_sub`]: https://rust-lang.github.io/rust-clippy/master/index.html#inverted_saturating_sub [`invisible_characters`]: https://rust-lang.github.io/rust-clippy/master/index.html#invisible_characters [`io_other_error`]: https://rust-lang.github.io/rust-clippy/master/index.html#io_other_error +[`ip_constant`]: https://rust-lang.github.io/rust-clippy/master/index.html#ip_constant [`is_digit_ascii_radix`]: https://rust-lang.github.io/rust-clippy/master/index.html#is_digit_ascii_radix [`items_after_statements`]: https://rust-lang.github.io/rust-clippy/master/index.html#items_after_statements [`items_after_test_module`]: https://rust-lang.github.io/rust-clippy/master/index.html#items_after_test_module @@ -6163,6 +6167,7 @@ Released 2018-09-13 [`pathbuf_init_then_push`]: https://rust-lang.github.io/rust-clippy/master/index.html#pathbuf_init_then_push [`pattern_type_mismatch`]: https://rust-lang.github.io/rust-clippy/master/index.html#pattern_type_mismatch [`permissions_set_readonly_false`]: https://rust-lang.github.io/rust-clippy/master/index.html#permissions_set_readonly_false +[`pointer_format`]: https://rust-lang.github.io/rust-clippy/master/index.html#pointer_format [`pointers_in_nomem_asm_block`]: https://rust-lang.github.io/rust-clippy/master/index.html#pointers_in_nomem_asm_block [`positional_named_format_parameters`]: https://rust-lang.github.io/rust-clippy/master/index.html#positional_named_format_parameters [`possible_missing_comma`]: https://rust-lang.github.io/rust-clippy/master/index.html#possible_missing_comma diff --git a/src/tools/clippy/clippy_dev/src/update_lints.rs b/src/tools/clippy/clippy_dev/src/update_lints.rs index 320462a2c96..08592f2521f 100644 --- a/src/tools/clippy/clippy_dev/src/update_lints.rs +++ b/src/tools/clippy/clippy_dev/src/update_lints.rs @@ -73,8 +73,8 @@ pub fn generate_lint_files( ( "clippy_lints/src/lib.rs", &mut update_text_region_fn( - "// begin lints modules, do not remove this comment, it’s used in `update_lints`\n", - "// end lints modules, do not remove this comment, it’s used in `update_lints`", + "// begin lints modules, do not remove this comment, it's used in `update_lints`\n", + "// end lints modules, do not remove this comment, it's used in `update_lints`", |dst| { for lint_mod in lints.iter().map(|l| &l.module).sorted().dedup() { writeln!(dst, "mod {lint_mod};").unwrap(); diff --git a/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs b/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs index 59a0c7c8868..b9ae9afe851 100644 --- a/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs +++ b/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs @@ -204,7 +204,7 @@ impl ArbitrarySourceItemOrdering { self.assoc_types_order ), Some(before_item.span), - format!("should be placed before `{}`", before_item.ident.as_str(),), + format!("should be placed before `{}`", before_item.ident.name), ); } @@ -216,7 +216,7 @@ impl ArbitrarySourceItemOrdering { ident.span, "incorrect ordering of items (must be alphabetically ordered)", Some(before_ident.span), - format!("should be placed before `{}`", before_ident.as_str(),), + format!("should be placed before `{}`", before_ident.name), ); } @@ -228,7 +228,7 @@ impl ArbitrarySourceItemOrdering { }; let (before_span, note) = if let Some(ident) = before_item.kind.ident() { - (ident.span, format!("should be placed before `{}`", ident.as_str(),)) + (ident.span, format!("should be placed before `{}`", ident.name)) } else { ( before_item.span, @@ -255,7 +255,7 @@ impl ArbitrarySourceItemOrdering { self.assoc_types_order ), Some(before_item.span), - format!("should be placed before `{}`", before_item.ident.as_str(),), + format!("should be placed before `{}`", before_item.ident.name), ); } } 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 0edb50be8c7..d67a194b020 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 @@ -61,7 +61,7 @@ pub(super) fn check_clippy(cx: &EarlyContext<'_>, attr: &Attribute) { fn check_deprecated_cfg_recursively(cx: &EarlyContext<'_>, attr: &rustc_ast::MetaItem) { if let Some(ident) = attr.ident() { - if ["any", "all", "not"].contains(&ident.name.as_str()) { + if matches!(ident.name, sym::any | sym::all | sym::not) { let Some(list) = attr.meta_item_list() else { return }; for item in list.iter().filter_map(|item| item.meta_item()) { check_deprecated_cfg_recursively(cx, item); diff --git a/src/tools/clippy/clippy_lints/src/attrs/duplicated_attributes.rs b/src/tools/clippy/clippy_lints/src/attrs/duplicated_attributes.rs index a851daaede7..c2406bcfb64 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/duplicated_attributes.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/duplicated_attributes.rs @@ -1,9 +1,10 @@ use super::DUPLICATED_ATTRIBUTES; use clippy_utils::diagnostics::span_lint_and_then; +use itertools::Itertools; use rustc_ast::{Attribute, MetaItem}; use rustc_data_structures::fx::FxHashMap; use rustc_lint::EarlyContext; -use rustc_span::{Span, sym}; +use rustc_span::{Span, Symbol, sym}; use std::collections::hash_map::Entry; fn emit_if_duplicated( @@ -29,7 +30,7 @@ fn check_duplicated_attr( cx: &EarlyContext<'_>, attr: &MetaItem, attr_paths: &mut FxHashMap<String, Span>, - parent: &mut Vec<String>, + parent: &mut Vec<Symbol>, ) { if attr.span.from_expansion() { return; @@ -43,7 +44,7 @@ fn check_duplicated_attr( return; } if let Some(direct_parent) = parent.last() - && direct_parent == sym::cfg_trace.as_str() + && *direct_parent == sym::cfg_trace && [sym::all, sym::not, sym::any].contains(&name) { // FIXME: We don't correctly check `cfg`s for now, so if it's more complex than just a one @@ -51,9 +52,14 @@ fn check_duplicated_attr( return; } if let Some(value) = attr.value_str() { - emit_if_duplicated(cx, attr, attr_paths, format!("{}:{name}={value}", parent.join(":"))); + emit_if_duplicated( + cx, + attr, + attr_paths, + format!("{}:{name}={value}", parent.iter().join(":")), + ); } else if let Some(sub_attrs) = attr.meta_item_list() { - parent.push(name.as_str().to_string()); + parent.push(name); for sub_attr in sub_attrs { if let Some(meta) = sub_attr.meta_item() { check_duplicated_attr(cx, meta, attr_paths, parent); @@ -61,7 +67,7 @@ fn check_duplicated_attr( } parent.pop(); } else { - emit_if_duplicated(cx, attr, attr_paths, format!("{}:{name}", parent.join(":"))); + emit_if_duplicated(cx, attr, attr_paths, format!("{}:{name}", parent.iter().join(":"))); } } diff --git a/src/tools/clippy/clippy_lints/src/booleans.rs b/src/tools/clippy/clippy_lints/src/booleans.rs index 7c6fd91ca67..bf43234ff50 100644 --- a/src/tools/clippy/clippy_lints/src/booleans.rs +++ b/src/tools/clippy/clippy_lints/src/booleans.rs @@ -1,10 +1,10 @@ use clippy_config::Conf; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then}; -use clippy_utils::eq_expr_value; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::SpanRangeExt; use clippy_utils::sugg::Sugg; use clippy_utils::ty::{implements_trait, is_type_diagnostic_item}; +use clippy_utils::{eq_expr_value, sym}; use rustc_ast::ast::LitKind; use rustc_attr_data_structures::RustcVersion; use rustc_errors::Applicability; @@ -13,7 +13,7 @@ use rustc_hir::{BinOpKind, Body, Expr, ExprKind, FnDecl, UnOp}; use rustc_lint::{LateContext, LateLintPass, Level}; use rustc_session::impl_lint_pass; use rustc_span::def_id::LocalDefId; -use rustc_span::{Span, SyntaxContext, sym}; +use rustc_span::{Span, Symbol, SyntaxContext}; declare_clippy_lint! { /// ### What it does @@ -73,10 +73,10 @@ declare_clippy_lint! { } // For each pairs, both orders are considered. -const METHODS_WITH_NEGATION: [(Option<RustcVersion>, &str, &str); 3] = [ - (None, "is_some", "is_none"), - (None, "is_err", "is_ok"), - (Some(msrvs::IS_NONE_OR), "is_some_and", "is_none_or"), +const METHODS_WITH_NEGATION: [(Option<RustcVersion>, Symbol, Symbol); 3] = [ + (None, sym::is_some, sym::is_none), + (None, sym::is_err, sym::is_ok), + (Some(msrvs::IS_NONE_OR), sym::is_some_and, sym::is_none_or), ]; pub struct NonminimalBool { @@ -440,9 +440,7 @@ fn simplify_not(cx: &LateContext<'_>, curr_msrv: Msrv, expr: &Expr<'_>) -> Optio .iter() .copied() .flat_map(|(msrv, a, b)| vec![(msrv, a, b), (msrv, b, a)]) - .find(|&(msrv, a, _)| { - a == path.ident.name.as_str() && msrv.is_none_or(|msrv| curr_msrv.meets(cx, msrv)) - }) + .find(|&(msrv, a, _)| a == path.ident.name && msrv.is_none_or(|msrv| curr_msrv.meets(cx, msrv))) .and_then(|(_, _, neg_method)| { let negated_args = args .iter() diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs b/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs index 0f066fae118..c1d6cec1b62 100644 --- a/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs +++ b/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs @@ -76,19 +76,20 @@ fn should_lint(cx: &LateContext<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>, msrv: M return false; } - match (cast_from.is_integral(), cast_to.is_integral()) { - (true, true) => { + match ( + utils::int_ty_to_nbits(cx.tcx, cast_from), + utils::int_ty_to_nbits(cx.tcx, cast_to), + ) { + (Some(from_nbits), Some(to_nbits)) => { let cast_signed_to_unsigned = cast_from.is_signed() && !cast_to.is_signed(); - let from_nbits = utils::int_ty_to_nbits(cast_from, cx.tcx); - let to_nbits = utils::int_ty_to_nbits(cast_to, cx.tcx); !is_isize_or_usize(cast_from) && !is_isize_or_usize(cast_to) && from_nbits < to_nbits && !cast_signed_to_unsigned }, - (true, false) => { - let from_nbits = utils::int_ty_to_nbits(cast_from, cx.tcx); + (Some(from_nbits), None) => { + // FIXME: handle `f16` and `f128` let to_nbits = if let ty::Float(FloatTy::F32) = cast_to.kind() { 32 } else { @@ -96,9 +97,7 @@ fn should_lint(cx: &LateContext<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>, msrv: M }; !is_isize_or_usize(cast_from) && from_nbits < to_nbits }, - (false, true) if matches!(cast_from.kind(), ty::Bool) && msrv.meets(cx, msrvs::FROM_BOOL) => true, - (_, _) => { - matches!(cast_from.kind(), ty::Float(FloatTy::F32)) && matches!(cast_to.kind(), ty::Float(FloatTy::F64)) - }, + (None, Some(_)) if cast_from.is_bool() && msrv.meets(cx, msrvs::FROM_BOOL) => true, + _ => matches!(cast_from.kind(), ty::Float(FloatTy::F32)) && matches!(cast_to.kind(), ty::Float(FloatTy::F64)), } } 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 4120e5c8cb7..a2ecb5fb44a 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 @@ -91,15 +91,14 @@ pub(super) fn check( cast_to: Ty<'_>, cast_to_span: Span, ) { - let msg = match (cast_from.kind(), cast_to.is_integral()) { - (ty::Int(_) | ty::Uint(_), true) => { + let msg = match (cast_from.kind(), utils::int_ty_to_nbits(cx.tcx, cast_to)) { + (ty::Int(_) | ty::Uint(_), Some(to_nbits)) => { let from_nbits = apply_reductions( cx, - utils::int_ty_to_nbits(cast_from, cx.tcx), + utils::int_ty_to_nbits(cx.tcx, cast_from).unwrap(), cast_expr, cast_from.is_signed(), ); - let to_nbits = utils::int_ty_to_nbits(cast_to, cx.tcx); let (should_lint, suffix) = match (is_isize_or_usize(cast_from), is_isize_or_usize(cast_to)) { (true, true) | (false, false) => (to_nbits < from_nbits, ""), @@ -121,7 +120,7 @@ pub(super) fn check( format!("casting `{cast_from}` to `{cast_to}` may truncate the value{suffix}",) }, - (ty::Adt(def, _), true) if def.is_enum() => { + (ty::Adt(def, _), Some(to_nbits)) if def.is_enum() => { let (from_nbits, variant) = if let ExprKind::Path(p) = &cast_expr.kind && let Res::Def(DefKind::Ctor(..), id) = cx.qpath_res(p, cast_expr.hir_id) { @@ -132,7 +131,6 @@ pub(super) fn check( } else { (utils::enum_ty_to_nbits(*def, cx.tcx), None) }; - let to_nbits = utils::int_ty_to_nbits(cast_to, cx.tcx); let cast_from_ptr_size = def.repr().int.is_none_or(|ty| matches!(ty, IntegerType::Pointer(_),)); let suffix = match (cast_from_ptr_size, is_isize_or_usize(cast_to)) { @@ -157,11 +155,11 @@ pub(super) fn check( format!("casting `{cast_from}` to `{cast_to}` may truncate the value{suffix}") }, - (ty::Float(_), true) => { + (ty::Float(_), Some(_)) => { format!("casting `{cast_from}` to `{cast_to}` may truncate the value") }, - (ty::Float(FloatTy::F64), false) if matches!(cast_to.kind(), &ty::Float(FloatTy::F32)) => { + (ty::Float(FloatTy::F64), None) if matches!(cast_to.kind(), &ty::Float(FloatTy::F32)) => { "casting `f64` to `f32` may truncate the value".to_string() }, diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_possible_wrap.rs b/src/tools/clippy/clippy_lints/src/casts/cast_possible_wrap.rs index 504d0a267e4..e26c03ccda9 100644 --- a/src/tools/clippy/clippy_lints/src/casts/cast_possible_wrap.rs +++ b/src/tools/clippy/clippy_lints/src/casts/cast_possible_wrap.rs @@ -17,9 +17,12 @@ enum EmitState { } pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) { - if !(cast_from.is_integral() && cast_to.is_integral()) { + let (Some(from_nbits), Some(to_nbits)) = ( + utils::int_ty_to_nbits(cx.tcx, cast_from), + utils::int_ty_to_nbits(cx.tcx, cast_to), + ) else { return; - } + }; // emit a lint if a cast is: // 1. unsigned to signed @@ -35,9 +38,6 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, ca return; } - let from_nbits = utils::int_ty_to_nbits(cast_from, cx.tcx); - let to_nbits = utils::int_ty_to_nbits(cast_to, cx.tcx); - let should_lint = match (cast_from.is_ptr_sized_integral(), cast_to.is_ptr_sized_integral()) { (true, true) => { // casts between two ptr sized integers are trivially always the same size diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_precision_loss.rs b/src/tools/clippy/clippy_lints/src/casts/cast_precision_loss.rs index 1eb115ce6bd..712e38db499 100644 --- a/src/tools/clippy/clippy_lints/src/casts/cast_precision_loss.rs +++ b/src/tools/clippy/clippy_lints/src/casts/cast_precision_loss.rs @@ -7,15 +7,14 @@ use rustc_middle::ty::{self, FloatTy, Ty}; use super::{CAST_PRECISION_LOSS, utils}; pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) { - if !cast_from.is_integral() || cast_to.is_integral() { + let Some(from_nbits) = utils::int_ty_to_nbits(cx.tcx, cast_from) else { return; - } + }; - let from_nbits = utils::int_ty_to_nbits(cast_from, cx.tcx); - let to_nbits = if cast_to.kind() == &ty::Float(FloatTy::F32) { - 32 - } else { - 64 + // FIXME: handle `f16` and `f128` + let to_nbits = match cast_to.kind() { + ty::Float(f @ (FloatTy::F32 | FloatTy::F64)) => f.bit_width(), + _ => return, }; if !(is_isize_or_usize(cast_from) || from_nbits >= to_nbits) { @@ -29,9 +28,10 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, ca let from_nbits_str = if arch_dependent { "64".to_owned() } else if is_isize_or_usize(cast_from) { + // FIXME: handle 16 bits `usize` type "32 or 64".to_owned() } else { - utils::int_ty_to_nbits(cast_from, cx.tcx).to_string() + from_nbits.to_string() }; span_lint( 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 01020f3eee2..e4dafde0f9d 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 @@ -61,7 +61,7 @@ fn is_used_as_unaligned(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { }; match parent.kind { ExprKind::MethodCall(name, self_arg, ..) if self_arg.hir_id == e.hir_id => { - if matches!(name.ident.as_str(), "read_unaligned" | "write_unaligned") + if matches!(name.ident.name, sym::read_unaligned | sym::write_unaligned) && let Some(def_id) = cx.typeck_results().type_dependent_def_id(parent.hir_id) && let Some(def_id) = cx.tcx.impl_of_method(def_id) && cx.tcx.type_of(def_id).instantiate_identity().is_raw_ptr() diff --git a/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast.rs b/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast.rs index ac1a355c8d9..105477093b5 100644 --- a/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast.rs +++ b/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast.rs @@ -3,24 +3,22 @@ use clippy_utils::source::snippet_with_applicability; use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; -use rustc_middle::ty::{self, Ty, UintTy}; +use rustc_middle::ty::{self, Ty}; use super::{FN_TO_NUMERIC_CAST, utils}; pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) { // We only want to check casts to `ty::Uint` or `ty::Int` - match cast_to.kind() { - ty::Uint(_) | ty::Int(..) => { /* continue on */ }, - _ => return, - } + let Some(to_nbits) = utils::int_ty_to_nbits(cx.tcx, cast_to) else { + return; + }; match cast_from.kind() { ty::FnDef(..) | ty::FnPtr(..) => { let mut applicability = Applicability::MaybeIncorrect; - let from_snippet = snippet_with_applicability(cx, cast_expr.span, "x", &mut applicability); - let to_nbits = utils::int_ty_to_nbits(cast_to, cx.tcx); - if (to_nbits >= cx.tcx.data_layout.pointer_size.bits()) && (*cast_to.kind() != ty::Uint(UintTy::Usize)) { + if to_nbits >= cx.tcx.data_layout.pointer_size.bits() && !cast_to.is_usize() { + let from_snippet = snippet_with_applicability(cx, cast_expr.span, "x", &mut applicability); span_lint_and_sugg( cx, FN_TO_NUMERIC_CAST, diff --git a/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs b/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs index 18e7798452e..700b7d0d426 100644 --- a/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs +++ b/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs @@ -9,16 +9,14 @@ use super::{FN_TO_NUMERIC_CAST_WITH_TRUNCATION, utils}; pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) { // We only want to check casts to `ty::Uint` or `ty::Int` - match cast_to.kind() { - ty::Uint(_) | ty::Int(..) => { /* continue on */ }, - _ => return, - } + let Some(to_nbits) = utils::int_ty_to_nbits(cx.tcx, cast_to) else { + return; + }; match cast_from.kind() { ty::FnDef(..) | ty::FnPtr(..) => { let mut applicability = Applicability::MaybeIncorrect; let from_snippet = snippet_with_applicability(cx, cast_expr.span, "x", &mut applicability); - let to_nbits = utils::int_ty_to_nbits(cast_to, cx.tcx); if to_nbits < cx.tcx.data_layout.pointer_size.bits() { span_lint_and_sugg( cx, diff --git a/src/tools/clippy/clippy_lints/src/casts/utils.rs b/src/tools/clippy/clippy_lints/src/casts/utils.rs index 5ccba92a0af..318a1646477 100644 --- a/src/tools/clippy/clippy_lints/src/casts/utils.rs +++ b/src/tools/clippy/clippy_lints/src/casts/utils.rs @@ -1,27 +1,14 @@ use clippy_utils::ty::{EnumValue, read_explicit_enum_value}; use rustc_middle::ty::{self, AdtDef, IntTy, Ty, TyCtxt, UintTy, VariantDiscr}; -/// Returns the size in bits of an integral type. -/// Will return 0 if the type is not an int or uint variant -pub(super) fn int_ty_to_nbits(typ: Ty<'_>, tcx: TyCtxt<'_>) -> u64 { - match typ.kind() { - ty::Int(i) => match i { - IntTy::Isize => tcx.data_layout.pointer_size.bits(), - IntTy::I8 => 8, - IntTy::I16 => 16, - IntTy::I32 => 32, - IntTy::I64 => 64, - IntTy::I128 => 128, - }, - ty::Uint(i) => match i { - UintTy::Usize => tcx.data_layout.pointer_size.bits(), - UintTy::U8 => 8, - UintTy::U16 => 16, - UintTy::U32 => 32, - UintTy::U64 => 64, - UintTy::U128 => 128, - }, - _ => 0, +/// Returns the size in bits of an integral type, or `None` if `ty` is not an +/// integral type. +pub(super) fn int_ty_to_nbits(tcx: TyCtxt<'_>, ty: Ty<'_>) -> Option<u64> { + match ty.kind() { + ty::Int(IntTy::Isize) | ty::Uint(UintTy::Usize) => Some(tcx.data_layout.pointer_size.bits()), + ty::Int(i) => i.bit_width(), + ty::Uint(i) => i.bit_width(), + _ => None, } } diff --git a/src/tools/clippy/clippy_lints/src/checked_conversions.rs b/src/tools/clippy/clippy_lints/src/checked_conversions.rs index 8ada608049c..9b3822f9d8f 100644 --- a/src/tools/clippy/clippy_lints/src/checked_conversions.rs +++ b/src/tools/clippy/clippy_lints/src/checked_conversions.rs @@ -2,11 +2,12 @@ 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::{SpanlessEq, is_in_const_context, is_integer_literal}; +use clippy_utils::{SpanlessEq, is_in_const_context, is_integer_literal, sym}; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, QPath, TyKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::impl_lint_pass; +use rustc_span::Symbol; declare_clippy_lint! { /// ### What it does @@ -98,7 +99,7 @@ impl LateLintPass<'_> for CheckedConversions { struct Conversion<'a> { cvt: ConversionType, expr_to_cast: &'a Expr<'a>, - to_type: Option<&'a str>, + to_type: Option<Symbol>, } /// The kind of conversion that is checked @@ -150,7 +151,7 @@ impl<'a> Conversion<'a> { } /// Try to construct a new conversion if the conversion type is valid - fn try_new(expr_to_cast: &'a Expr<'_>, from_type: &str, to_type: &'a str) -> Option<Conversion<'a>> { + fn try_new(expr_to_cast: &'a Expr<'_>, from_type: Symbol, to_type: Symbol) -> Option<Conversion<'a>> { ConversionType::try_new(from_type, to_type).map(|cvt| Conversion { cvt, expr_to_cast, @@ -171,7 +172,7 @@ impl<'a> Conversion<'a> { impl ConversionType { /// Creates a conversion type if the type is allowed & conversion is valid #[must_use] - fn try_new(from: &str, to: &str) -> Option<Self> { + fn try_new(from: Symbol, to: Symbol) -> Option<Self> { if UINTS.contains(&from) { Some(Self::FromUnsigned) } else if SINTS.contains(&from) { @@ -190,7 +191,7 @@ impl ConversionType { /// Check for `expr <= (to_type::MAX as from_type)` fn check_upper_bound<'tcx>(lt: &'tcx Expr<'tcx>, gt: &'tcx Expr<'tcx>) -> Option<Conversion<'tcx>> { - if let Some((from, to)) = get_types_from_cast(gt, INTS, "max_value", "MAX") { + if let Some((from, to)) = get_types_from_cast(gt, INTS, sym::max_value, sym::MAX) { Conversion::try_new(lt, from, to) } else { None @@ -209,7 +210,7 @@ fn check_lower_bound_zero<'a>(candidate: &'a Expr<'_>, check: &'a Expr<'_>) -> O /// Check for `expr >= (to_type::MIN as from_type)` fn check_lower_bound_min<'a>(candidate: &'a Expr<'_>, check: &'a Expr<'_>) -> Option<Conversion<'a>> { - if let Some((from, to)) = get_types_from_cast(check, SINTS, "min_value", "MIN") { + if let Some((from, to)) = get_types_from_cast(check, SINTS, sym::min_value, sym::MIN) { Conversion::try_new(candidate, from, to) } else { None @@ -217,15 +218,15 @@ fn check_lower_bound_min<'a>(candidate: &'a Expr<'_>, check: &'a Expr<'_>) -> Op } /// Tries to extract the from- and to-type from a cast expression -fn get_types_from_cast<'a>( - expr: &'a Expr<'_>, - types: &'a [&str], - func: &'a str, - assoc_const: &'a str, -) -> Option<(&'a str, &'a str)> { +fn get_types_from_cast( + expr: &Expr<'_>, + types: &[Symbol], + func: Symbol, + assoc_const: Symbol, +) -> Option<(Symbol, Symbol)> { // `to_type::max_value() as from_type` // or `to_type::MAX as from_type` - let call_from_cast: Option<(&Expr<'_>, &str)> = if let ExprKind::Cast(limit, from_type) = &expr.kind + let call_from_cast: Option<(&Expr<'_>, Symbol)> = if let ExprKind::Cast(limit, from_type) = &expr.kind // to_type::max_value(), from_type && let TyKind::Path(from_type_path) = &from_type.kind && let Some(from_sym) = int_ty_to_sym(from_type_path) @@ -236,12 +237,12 @@ fn get_types_from_cast<'a>( }; // `from_type::from(to_type::max_value())` - let limit_from: Option<(&Expr<'_>, &str)> = call_from_cast.or_else(|| { + let limit_from: Option<(&Expr<'_>, Symbol)> = call_from_cast.or_else(|| { if let ExprKind::Call(from_func, [limit]) = &expr.kind // `from_type::from, to_type::max_value()` // `from_type::from` && let ExprKind::Path(path) = &from_func.kind - && let Some(from_sym) = get_implementing_type(path, INTS, "from") + && let Some(from_sym) = get_implementing_type(path, INTS, sym::from) { Some((limit, from_sym)) } else { @@ -273,32 +274,41 @@ fn get_types_from_cast<'a>( } /// Gets the type which implements the called function -fn get_implementing_type<'a>(path: &QPath<'_>, candidates: &'a [&str], function: &str) -> Option<&'a str> { +fn get_implementing_type(path: &QPath<'_>, candidates: &[Symbol], function: Symbol) -> Option<Symbol> { if let QPath::TypeRelative(ty, path) = &path - && path.ident.name.as_str() == function + && path.ident.name == function && let TyKind::Path(QPath::Resolved(None, tp)) = &ty.kind && let [int] = tp.segments { - let name = int.ident.name.as_str(); - candidates.iter().find(|c| &name == *c).copied() + candidates.iter().find(|c| int.ident.name == **c).copied() } else { None } } /// Gets the type as a string, if it is a supported integer -fn int_ty_to_sym<'tcx>(path: &QPath<'_>) -> Option<&'tcx str> { +fn int_ty_to_sym(path: &QPath<'_>) -> Option<Symbol> { if let QPath::Resolved(_, path) = *path && let [ty] = path.segments { - let name = ty.ident.name.as_str(); - INTS.iter().find(|c| &name == *c).copied() + INTS.iter().find(|c| ty.ident.name == **c).copied() } else { None } } // Constants -const UINTS: &[&str] = &["u8", "u16", "u32", "u64", "usize"]; -const SINTS: &[&str] = &["i8", "i16", "i32", "i64", "isize"]; -const INTS: &[&str] = &["u8", "u16", "u32", "u64", "usize", "i8", "i16", "i32", "i64", "isize"]; +const UINTS: &[Symbol] = &[sym::u8, sym::u16, sym::u32, sym::u64, sym::usize]; +const SINTS: &[Symbol] = &[sym::i8, sym::i16, sym::i32, sym::i64, sym::isize]; +const INTS: &[Symbol] = &[ + sym::u8, + sym::u16, + sym::u32, + sym::u64, + sym::usize, + sym::i8, + sym::i16, + sym::i32, + sym::i64, + sym::isize, +]; diff --git a/src/tools/clippy/clippy_lints/src/cloned_ref_to_slice_refs.rs b/src/tools/clippy/clippy_lints/src/cloned_ref_to_slice_refs.rs index 6b239a1541b..e33a8e0fb74 100644 --- a/src/tools/clippy/clippy_lints/src/cloned_ref_to_slice_refs.rs +++ b/src/tools/clippy/clippy_lints/src/cloned_ref_to_slice_refs.rs @@ -17,7 +17,7 @@ declare_clippy_lint! { /// /// ### Why is this bad /// - /// A reference does not need to be owned in order to used as a slice. + /// A reference does not need to be owned in order to be used as a slice. /// /// ### Known problems /// diff --git a/src/tools/clippy/clippy_lints/src/coerce_container_to_any.rs b/src/tools/clippy/clippy_lints/src/coerce_container_to_any.rs new file mode 100644 index 00000000000..2b659253763 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/coerce_container_to_any.rs @@ -0,0 +1,108 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet; +use clippy_utils::sym; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::{self, ExistentialPredicate, Ty, TyCtxt}; +use rustc_session::declare_lint_pass; + +declare_clippy_lint! { + /// ### What it does + /// + /// Protects against unintended coercion of references to container types to `&dyn Any` when the + /// container type dereferences to a `dyn Any` which could be directly referenced instead. + /// + /// ### Why is this bad? + /// + /// The intention is usually to get a reference to the `dyn Any` the value dereferences to, + /// rather than coercing a reference to the container itself to `&dyn Any`. + /// + /// ### Example + /// + /// Because `Box<dyn Any>` itself implements `Any`, `&Box<dyn Any>` + /// can be coerced to an `&dyn Any` which refers to *the `Box` itself*, rather than the + /// inner `dyn Any`. + /// ```no_run + /// # use std::any::Any; + /// let x: Box<dyn Any> = Box::new(0u32); + /// let dyn_any_of_box: &dyn Any = &x; + /// + /// // Fails as we have a &dyn Any to the Box, not the u32 + /// assert_eq!(dyn_any_of_box.downcast_ref::<u32>(), None); + /// ``` + /// Use instead: + /// ```no_run + /// # use std::any::Any; + /// let x: Box<dyn Any> = Box::new(0u32); + /// let dyn_any_of_u32: &dyn Any = &*x; + /// + /// // Succeeds since we have a &dyn Any to the inner u32! + /// assert_eq!(dyn_any_of_u32.downcast_ref::<u32>(), Some(&0u32)); + /// ``` + #[clippy::version = "1.88.0"] + pub COERCE_CONTAINER_TO_ANY, + nursery, + "coercing to `&dyn Any` when dereferencing could produce a `dyn Any` without coercion is usually not intended" +} +declare_lint_pass!(CoerceContainerToAny => [COERCE_CONTAINER_TO_ANY]); + +impl<'tcx> LateLintPass<'tcx> for CoerceContainerToAny { + fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { + // If this expression has an effective type of `&dyn Any` ... + { + let coerced_ty = cx.typeck_results().expr_ty_adjusted(e); + + let ty::Ref(_, coerced_ref_ty, _) = *coerced_ty.kind() else { + return; + }; + if !is_dyn_any(cx.tcx, coerced_ref_ty) { + return; + } + } + + let expr_ty = cx.typeck_results().expr_ty(e); + let ty::Ref(_, expr_ref_ty, _) = *expr_ty.kind() else { + return; + }; + // ... but only due to coercion ... + if is_dyn_any(cx.tcx, expr_ref_ty) { + return; + } + // ... and it also *derefs* to `dyn Any` ... + let Some((depth, target)) = clippy_utils::ty::deref_chain(cx, expr_ref_ty).enumerate().last() else { + return; + }; + if !is_dyn_any(cx.tcx, target) { + return; + } + + // ... that's probably not intended. + let (span, deref_count) = match e.kind { + // If `e` was already an `&` expression, skip `*&` in the suggestion + ExprKind::AddrOf(_, _, referent) => (referent.span, depth), + _ => (e.span, depth + 1), + }; + span_lint_and_sugg( + cx, + COERCE_CONTAINER_TO_ANY, + e.span, + format!("coercing `{expr_ty}` to `&dyn Any`"), + "consider dereferencing", + format!("&{}{}", str::repeat("*", deref_count), snippet(cx, span, "x")), + Applicability::MaybeIncorrect, + ); + } +} + +fn is_dyn_any(tcx: TyCtxt<'_>, ty: Ty<'_>) -> bool { + let ty::Dynamic(traits, ..) = ty.kind() else { + return false; + }; + traits.iter().any(|binder| { + let ExistentialPredicate::Trait(t) = binder.skip_binder() else { + return false; + }; + tcx.is_diagnostic_item(sym::Any, t.def_id) + }) +} diff --git a/src/tools/clippy/clippy_lints/src/copies.rs b/src/tools/clippy/clippy_lints/src/copies.rs index 2467fc95fd0..5ef726638a5 100644 --- a/src/tools/clippy/clippy_lints/src/copies.rs +++ b/src/tools/clippy/clippy_lints/src/copies.rs @@ -425,7 +425,9 @@ fn scan_block_for_eq<'tcx>( modifies_any_local(cx, stmt, &cond_locals) || !eq_stmts(stmt, blocks, |b| b.stmts.get(i), &mut eq, &mut moved_locals) }) - .map_or(block.stmts.len(), |(i, _)| i); + .map_or(block.stmts.len(), |(i, stmt)| { + adjust_by_closest_callsite(i, stmt, block.stmts[..i].iter().enumerate().rev()) + }); if local_needs_ordered_drop { return BlockEq { @@ -467,7 +469,9 @@ fn scan_block_for_eq<'tcx>( .is_none_or(|s| hash != hash_stmt(cx, s)) }) }) - .map_or(block.stmts.len() - start_end_eq, |(i, _)| i); + .map_or(block.stmts.len() - start_end_eq, |(i, stmt)| { + adjust_by_closest_callsite(i, stmt, (0..i).rev().zip(block.stmts[(block.stmts.len() - i)..].iter())) + }); let moved_locals_at_start = moved_locals.len(); let mut i = end_search_start; @@ -522,6 +526,49 @@ fn scan_block_for_eq<'tcx>( } } +/// Adjusts the index for which the statements begin to differ to the closest macro callsite. This +/// avoids giving suggestions that requires splitting a macro call in half, when only a part of the +/// macro expansion is equal. +/// +/// For example, for the following macro: +/// ```rust,ignore +/// macro_rules! foo { +/// ($x:expr) => { +/// let y = 42; +/// $x; +/// }; +/// } +/// ``` +/// If the macro is called like this: +/// ```rust,ignore +/// if false { +/// let z = 42; +/// foo!(println!("Hello")); +/// } else { +/// let z = 42; +/// foo!(println!("World")); +/// } +/// ``` +/// Although the expanded `let y = 42;` is equal, the macro call should not be included in the +/// suggestion. +fn adjust_by_closest_callsite<'tcx>( + i: usize, + stmt: &'tcx Stmt<'tcx>, + mut iter: impl Iterator<Item = (usize, &'tcx Stmt<'tcx>)>, +) -> usize { + let Some((_, first)) = iter.next() else { + return 0; + }; + + // If it is already at the boundary of a macro call, then just return. + if first.span.source_callsite() != stmt.span.source_callsite() { + return i; + } + + iter.find(|(_, stmt)| stmt.span.source_callsite() != first.span.source_callsite()) + .map_or(0, |(i, _)| i + 1) +} + fn check_for_warn_of_moved_symbol(cx: &LateContext<'_>, symbols: &[(HirId, Symbol)], if_expr: &Expr<'_>) -> bool { get_enclosing_block(cx, if_expr.hir_id).is_some_and(|block| { let ignore_span = block.span.shrink_to_lo().to(if_expr.span); diff --git a/src/tools/clippy/clippy_lints/src/create_dir.rs b/src/tools/clippy/clippy_lints/src/create_dir.rs index b43906903a0..695b25aeb0b 100644 --- a/src/tools/clippy/clippy_lints/src/create_dir.rs +++ b/src/tools/clippy/clippy_lints/src/create_dir.rs @@ -1,7 +1,6 @@ use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::source::snippet_with_applicability; use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind}; +use rustc_hir::{Expr, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; use rustc_span::sym; @@ -34,10 +33,12 @@ declare_lint_pass!(CreateDir => [CREATE_DIR]); impl LateLintPass<'_> for CreateDir { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { - if let ExprKind::Call(func, [arg]) = expr.kind + if let ExprKind::Call(func, [_]) = expr.kind && let ExprKind::Path(ref path) = func.kind && let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id() && cx.tcx.is_diagnostic_item(sym::fs_create_dir, def_id) + && let QPath::Resolved(_, path) = path + && let Some(last) = path.segments.last() { span_lint_and_then( cx, @@ -45,15 +46,15 @@ impl LateLintPass<'_> for CreateDir { expr.span, "calling `std::fs::create_dir` where there may be a better way", |diag| { - let mut app = Applicability::MaybeIncorrect; - diag.span_suggestion_verbose( - expr.span, + let mut suggestions = vec![(last.ident.span.shrink_to_hi(), "_all".to_owned())]; + if path.segments.len() == 1 { + suggestions.push((path.span.shrink_to_lo(), "std::fs::".to_owned())); + } + + diag.multipart_suggestion_verbose( "consider calling `std::fs::create_dir_all` instead", - format!( - "create_dir_all({})", - snippet_with_applicability(cx, arg.span, "..", &mut app) - ), - app, + suggestions, + Applicability::MaybeIncorrect, ); }, ); diff --git a/src/tools/clippy/clippy_lints/src/ctfe.rs b/src/tools/clippy/clippy_lints/src/ctfe.rs deleted file mode 100644 index 7bae04a10f1..00000000000 --- a/src/tools/clippy/clippy_lints/src/ctfe.rs +++ /dev/null @@ -1,26 +0,0 @@ -use rustc_hir::def_id::LocalDefId; -use rustc_hir::intravisit::FnKind; -use rustc_hir::{Body, FnDecl}; -use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::declare_lint_pass; -use rustc_span::Span; - -declare_lint_pass! { - /// Ensures that Constant-time Function Evaluation is being done (specifically, MIR lint passes). - /// As Clippy deactivates codegen, this lint ensures that CTFE (used in hard errors) is still ran. - ClippyCtfe => [] -} - -impl<'tcx> LateLintPass<'tcx> for ClippyCtfe { - fn check_fn( - &mut self, - cx: &LateContext<'_>, - _: FnKind<'tcx>, - _: &'tcx FnDecl<'tcx>, - _: &'tcx Body<'tcx>, - _: Span, - defid: LocalDefId, - ) { - cx.tcx.ensure_ok().mir_drops_elaborated_and_const_checked(defid); // Lint - } -} diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs index 5fcb851dfeb..1e3907d9ede 100644 --- a/src/tools/clippy/clippy_lints/src/declared_lints.rs +++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs @@ -77,6 +77,7 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::cfg_not_test::CFG_NOT_TEST_INFO, crate::checked_conversions::CHECKED_CONVERSIONS_INFO, crate::cloned_ref_to_slice_refs::CLONED_REF_TO_SLICE_REFS_INFO, + crate::coerce_container_to_any::COERCE_CONTAINER_TO_ANY_INFO, crate::cognitive_complexity::COGNITIVE_COMPLEXITY_INFO, crate::collapsible_if::COLLAPSIBLE_ELSE_IF_INFO, crate::collapsible_if::COLLAPSIBLE_IF_INFO, @@ -119,6 +120,7 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::doc::DOC_MARKDOWN_INFO, crate::doc::DOC_NESTED_REFDEFS_INFO, crate::doc::DOC_OVERINDENTED_LIST_ITEMS_INFO, + crate::doc::DOC_SUSPICIOUS_FOOTNOTES_INFO, crate::doc::EMPTY_DOCS_INFO, crate::doc::MISSING_ERRORS_DOC_INFO, crate::doc::MISSING_PANICS_DOC_INFO, @@ -166,6 +168,7 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::floating_point_arithmetic::SUBOPTIMAL_FLOPS_INFO, crate::format::USELESS_FORMAT_INFO, crate::format_args::FORMAT_IN_FORMAT_ARGS_INFO, + crate::format_args::POINTER_FORMAT_INFO, crate::format_args::TO_STRING_IN_FORMAT_ARGS_INFO, crate::format_args::UNINLINED_FORMAT_ARGS_INFO, crate::format_args::UNNECESSARY_DEBUG_FORMATTING_INFO, @@ -211,6 +214,7 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::indexing_slicing::INDEXING_SLICING_INFO, crate::indexing_slicing::OUT_OF_BOUNDS_INDEXING_INFO, crate::ineffective_open_options::INEFFECTIVE_OPEN_OPTIONS_INFO, + crate::infallible_try_from::INFALLIBLE_TRY_FROM_INFO, crate::infinite_iter::INFINITE_ITER_INFO, crate::infinite_iter::MAYBE_INFINITE_ITER_INFO, crate::inherent_impl::MULTIPLE_INHERENT_IMPL_INFO, @@ -379,6 +383,7 @@ pub static LINTS: &[&crate::LintInfo] = &[ crate::methods::INSPECT_FOR_EACH_INFO, crate::methods::INTO_ITER_ON_REF_INFO, crate::methods::IO_OTHER_ERROR_INFO, + crate::methods::IP_CONSTANT_INFO, crate::methods::IS_DIGIT_ASCII_RADIX_INFO, crate::methods::ITERATOR_STEP_BY_ZERO_INFO, crate::methods::ITER_CLONED_COLLECT_INFO, diff --git a/src/tools/clippy/clippy_lints/src/default.rs b/src/tools/clippy/clippy_lints/src/default.rs index 886c325b355..a48e4d2fbd5 100644 --- a/src/tools/clippy/clippy_lints/src/default.rs +++ b/src/tools/clippy/clippy_lints/src/default.rs @@ -1,10 +1,9 @@ use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_sugg}; use clippy_utils::source::snippet_with_context; use clippy_utils::ty::{has_drop, is_copy}; -use clippy_utils::{contains_name, get_parent_expr, in_automatically_derived, is_from_proc_macro}; +use clippy_utils::{contains_name, get_parent_expr, in_automatically_derived, is_expr_default, is_from_proc_macro}; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; -use rustc_hir::def::Res; use rustc_hir::{Block, Expr, ExprKind, PatKind, QPath, Stmt, StmtKind, StructTailExpr}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; @@ -129,7 +128,7 @@ impl<'tcx> LateLintPass<'tcx> for Default { // only take bindings to identifiers && let PatKind::Binding(_, binding_id, ident, _) = local.pat.kind // only when assigning `... = Default::default()` - && is_expr_default(expr, cx) + && is_expr_default(cx, expr) && let binding_type = cx.typeck_results().node_type(binding_id) && let ty::Adt(adt, args) = *binding_type.kind() && adt.is_struct() @@ -251,19 +250,6 @@ impl<'tcx> LateLintPass<'tcx> for Default { } } -/// Checks if the given expression is the `default` method belonging to the `Default` trait. -fn is_expr_default<'tcx>(expr: &'tcx Expr<'tcx>, cx: &LateContext<'tcx>) -> bool { - if let ExprKind::Call(fn_expr, []) = &expr.kind - && let ExprKind::Path(qpath) = &fn_expr.kind - && let Res::Def(_, def_id) = cx.qpath_res(qpath, fn_expr.hir_id) - { - // right hand side of assignment is `Default::default` - cx.tcx.is_diagnostic_item(sym::default_fn, def_id) - } else { - false - } -} - /// Returns the reassigned field and the assigning expression (right-hand side of assign). fn field_reassigned_by_stmt<'tcx>(this: &Stmt<'tcx>, binding_name: Symbol) -> Option<(Ident, &'tcx Expr<'tcx>)> { if let StmtKind::Semi(later_expr) = this.kind diff --git a/src/tools/clippy/clippy_lints/src/disallowed_names.rs b/src/tools/clippy/clippy_lints/src/disallowed_names.rs index f55b0cf1c50..566aa12b08f 100644 --- a/src/tools/clippy/clippy_lints/src/disallowed_names.rs +++ b/src/tools/clippy/clippy_lints/src/disallowed_names.rs @@ -1,6 +1,6 @@ use clippy_config::Conf; use clippy_utils::diagnostics::span_lint; -use clippy_utils::is_in_test; +use clippy_utils::{is_from_proc_macro, is_in_test}; use rustc_data_structures::fx::FxHashSet; use rustc_hir::{Pat, PatKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -43,8 +43,10 @@ impl_lint_pass!(DisallowedNames => [DISALLOWED_NAMES]); impl<'tcx> LateLintPass<'tcx> for DisallowedNames { fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) { if let PatKind::Binding(.., ident, _) = pat.kind + && !ident.span.from_expansion() && self.disallow.contains(&ident.name) && !is_in_test(cx.tcx, pat.hir_id) + && !is_from_proc_macro(cx, &ident) { span_lint( cx, diff --git a/src/tools/clippy/clippy_lints/src/disallowed_types.rs b/src/tools/clippy/clippy_lints/src/disallowed_types.rs index 821bb25d2ce..7875cdd77e8 100644 --- a/src/tools/clippy/clippy_lints/src/disallowed_types.rs +++ b/src/tools/clippy/clippy_lints/src/disallowed_types.rs @@ -105,10 +105,10 @@ impl_lint_pass!(DisallowedTypes => [DISALLOWED_TYPES]); impl<'tcx> LateLintPass<'tcx> for DisallowedTypes { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { - if let ItemKind::Use(path, UseKind::Single(_)) = &item.kind { - if let Some(res) = path.res.type_ns { - self.check_res_emit(cx, &res, item.span); - } + if let ItemKind::Use(path, UseKind::Single(_)) = &item.kind + && let Some(res) = path.res.type_ns + { + self.check_res_emit(cx, &res, item.span); } } diff --git a/src/tools/clippy/clippy_lints/src/doc/doc_suspicious_footnotes.rs b/src/tools/clippy/clippy_lints/src/doc/doc_suspicious_footnotes.rs new file mode 100644 index 00000000000..289b6b915d4 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/doc/doc_suspicious_footnotes.rs @@ -0,0 +1,113 @@ +use clippy_utils::diagnostics::span_lint_and_then; +use rustc_ast::token::CommentKind; +use rustc_errors::Applicability; +use rustc_hir::{AttrStyle, Attribute}; +use rustc_lint::{LateContext, LintContext}; +use rustc_resolve::rustdoc::DocFragmentKind; + +use std::ops::Range; + +use super::{DOC_SUSPICIOUS_FOOTNOTES, Fragments}; + +pub fn check(cx: &LateContext<'_>, doc: &str, range: Range<usize>, fragments: &Fragments<'_>, attrs: &[Attribute]) { + for i in doc[range.clone()] + .bytes() + .enumerate() + .filter_map(|(i, c)| if c == b'[' { Some(i) } else { None }) + { + let start = i + range.start; + if doc.as_bytes().get(start + 1) == Some(&b'^') + && let Some(end) = all_numbers_upto_brace(doc, start + 2) + && doc.as_bytes().get(end) != Some(&b':') + && doc.as_bytes().get(start - 1) != Some(&b'\\') + && let Some(this_fragment) = { + // the `doc` string contains all fragments concatenated together + // figure out which one this suspicious footnote comes from + let mut starting_position = 0; + let mut found_fragment = fragments.fragments.last(); + for fragment in fragments.fragments { + if start >= starting_position && start < starting_position + fragment.doc.as_str().len() { + found_fragment = Some(fragment); + break; + } + starting_position += fragment.doc.as_str().len(); + } + found_fragment + } + { + let span = fragments.span(cx, start..end).unwrap_or(this_fragment.span); + span_lint_and_then( + cx, + DOC_SUSPICIOUS_FOOTNOTES, + span, + "looks like a footnote ref, but has no matching footnote", + |diag| { + if this_fragment.kind == DocFragmentKind::SugaredDoc { + let (doc_attr, (_, doc_attr_comment_kind)) = attrs + .iter() + .filter(|attr| attr.span().overlaps(this_fragment.span)) + .rev() + .find_map(|attr| Some((attr, attr.doc_str_and_comment_kind()?))) + .unwrap(); + let (to_add, terminator) = match (doc_attr_comment_kind, doc_attr.style()) { + (CommentKind::Line, AttrStyle::Outer) => ("\n///\n/// ", ""), + (CommentKind::Line, AttrStyle::Inner) => ("\n//!\n//! ", ""), + (CommentKind::Block, AttrStyle::Outer) => ("\n/** ", " */"), + (CommentKind::Block, AttrStyle::Inner) => ("\n/*! ", " */"), + }; + diag.span_suggestion_verbose( + doc_attr.span().shrink_to_hi(), + "add footnote definition", + format!( + "{to_add}{label}: <!-- description -->{terminator}", + label = &doc[start..end] + ), + Applicability::HasPlaceholders, + ); + } else { + let is_file_include = cx + .sess() + .source_map() + .span_to_snippet(this_fragment.span) + .as_ref() + .map(|vdoc| vdoc.trim()) + == Ok(doc); + if is_file_include { + // if this is a file include, then there's no quote marks + diag.span_suggestion_verbose( + this_fragment.span.shrink_to_hi(), + "add footnote definition", + format!("\n\n{label}: <!-- description -->", label = &doc[start..end],), + Applicability::HasPlaceholders, + ); + } else { + // otherwise, we wrap in a string + diag.span_suggestion_verbose( + this_fragment.span, + "add footnote definition", + format!( + "r#\"{doc}\n\n{label}: <!-- description -->\"#", + doc = this_fragment.doc, + label = &doc[start..end], + ), + Applicability::HasPlaceholders, + ); + } + } + }, + ); + } + } +} + +fn all_numbers_upto_brace(text: &str, i: usize) -> Option<usize> { + for (j, c) in text.as_bytes()[i..].iter().copied().enumerate().take(64) { + if c == b']' && j != 0 { + return Some(i + j + 1); + } + if !c.is_ascii_digit() || j >= 64 { + break; + } + } + None +} diff --git a/src/tools/clippy/clippy_lints/src/doc/mod.rs b/src/tools/clippy/clippy_lints/src/doc/mod.rs index c46dd09d60c..e0fc2fd9347 100644 --- a/src/tools/clippy/clippy_lints/src/doc/mod.rs +++ b/src/tools/clippy/clippy_lints/src/doc/mod.rs @@ -25,6 +25,7 @@ use std::ops::Range; use url::Url; mod doc_comment_double_space_linebreaks; +mod doc_suspicious_footnotes; mod include_in_doc_without_cfg; mod lazy_continuation; mod link_with_quotes; @@ -607,6 +608,37 @@ declare_clippy_lint! { "double-space used for doc comment linebreak instead of `\\`" } +declare_clippy_lint! { + /// ### What it does + /// Detects syntax that looks like a footnote reference. + /// + /// Rustdoc footnotes are compatible with GitHub-Flavored Markdown (GFM). + /// GFM does not parse a footnote reference unless its definition also + /// exists. This lint checks for footnote references with missing + /// definitions, unless it thinks you're writing a regex. + /// + /// ### Why is this bad? + /// This probably means that a footnote was meant to exist, + /// but was not written. + /// + /// ### Example + /// ```no_run + /// /// This is not a footnote[^1], because no definition exists. + /// fn my_fn() {} + /// ``` + /// Use instead: + /// ```no_run + /// /// This is a footnote[^1]. + /// /// + /// /// [^1]: defined here + /// fn my_fn() {} + /// ``` + #[clippy::version = "1.88.0"] + pub DOC_SUSPICIOUS_FOOTNOTES, + suspicious, + "looks like a link or footnote ref, but with no definition" +} + pub struct Documentation { valid_idents: FxHashSet<String>, check_private_items: bool, @@ -638,7 +670,8 @@ impl_lint_pass!(Documentation => [ DOC_OVERINDENTED_LIST_ITEMS, TOO_LONG_FIRST_DOC_PARAGRAPH, DOC_INCLUDE_WITHOUT_CFG, - DOC_COMMENT_DOUBLE_SPACE_LINEBREAKS + DOC_COMMENT_DOUBLE_SPACE_LINEBREAKS, + DOC_SUSPICIOUS_FOOTNOTES, ]); impl EarlyLintPass for Documentation { @@ -825,6 +858,7 @@ fn check_attrs(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs: &[ doc: &doc, fragments: &fragments, }, + attrs, )) } @@ -905,6 +939,7 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize events: Events, doc: &str, fragments: Fragments<'_>, + attrs: &[Attribute], ) -> DocHeaders { // true if a safety header was found let mut headers = DocHeaders::default(); @@ -1148,7 +1183,8 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize // Don't check the text associated with external URLs continue; } - text_to_check.push((text, range, code_level)); + text_to_check.push((text, range.clone(), code_level)); + doc_suspicious_footnotes::check(cx, doc, range, &fragments, attrs); } } FootnoteReference(_) => {} diff --git a/src/tools/clippy/clippy_lints/src/endian_bytes.rs b/src/tools/clippy/clippy_lints/src/endian_bytes.rs index a7670ffce88..75db923b1c3 100644 --- a/src/tools/clippy/clippy_lints/src/endian_bytes.rs +++ b/src/tools/clippy/clippy_lints/src/endian_bytes.rs @@ -1,6 +1,6 @@ use crate::Lint; use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::is_lint_allowed; +use clippy_utils::{is_lint_allowed, sym}; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::ty::Ty; @@ -65,9 +65,9 @@ declare_clippy_lint! { declare_lint_pass!(EndianBytes => [HOST_ENDIAN_BYTES, LITTLE_ENDIAN_BYTES, BIG_ENDIAN_BYTES]); -const HOST_NAMES: [&str; 2] = ["from_ne_bytes", "to_ne_bytes"]; -const LITTLE_NAMES: [&str; 2] = ["from_le_bytes", "to_le_bytes"]; -const BIG_NAMES: [&str; 2] = ["from_be_bytes", "to_be_bytes"]; +const HOST_NAMES: [Symbol; 2] = [sym::from_ne_bytes, sym::to_ne_bytes]; +const LITTLE_NAMES: [Symbol; 2] = [sym::from_le_bytes, sym::to_le_bytes]; +const BIG_NAMES: [Symbol; 2] = [sym::from_be_bytes, sym::to_be_bytes]; #[derive(Clone, Debug)] enum LintKind { @@ -95,7 +95,7 @@ impl LintKind { } } - fn as_name(&self, prefix: Prefix) -> &str { + fn as_name(&self, prefix: Prefix) -> Symbol { let index = usize::from(prefix == Prefix::To); match self { @@ -133,7 +133,7 @@ fn maybe_lint_endian_bytes(cx: &LateContext<'_>, expr: &Expr<'_>, prefix: Prefix let le = LintKind::Little.as_name(prefix); let be = LintKind::Big.as_name(prefix); - let (lint, other_lints) = match name.as_str() { + let (lint, other_lints) = match name { name if name == ne => ((&LintKind::Host), [(&LintKind::Little), (&LintKind::Big)]), name if name == le => ((&LintKind::Little), [(&LintKind::Host), (&LintKind::Big)]), name if name == be => ((&LintKind::Big), [(&LintKind::Host), (&LintKind::Little)]), diff --git a/src/tools/clippy/clippy_lints/src/format_args.rs b/src/tools/clippy/clippy_lints/src/format_args.rs index a26e736c7ae..0c39aae9ca9 100644 --- a/src/tools/clippy/clippy_lints/src/format_args.rs +++ b/src/tools/clippy/clippy_lints/src/format_args.rs @@ -1,6 +1,8 @@ +use std::collections::hash_map::Entry; + use arrayvec::ArrayVec; use clippy_config::Conf; -use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::macros::{ FormatArgsStorage, FormatParamUsage, MacroCall, find_format_arg_expr, format_arg_removal_span, format_placeholder_format_span, is_assert_macro, is_format_macro, is_panic, matching_root_macro_call, @@ -9,7 +11,7 @@ use clippy_utils::macros::{ use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::{SpanRangeExt, snippet}; use clippy_utils::ty::{implements_trait, is_type_lang_item}; -use clippy_utils::{is_diag_trait_item, is_from_proc_macro, is_in_test}; +use clippy_utils::{is_diag_trait_item, is_from_proc_macro, is_in_test, trait_ref_of_method}; use itertools::Itertools; use rustc_ast::{ FormatArgPosition, FormatArgPositionKind, FormatArgsPiece, FormatArgumentKind, FormatCount, FormatOptions, @@ -22,10 +24,12 @@ use rustc_errors::SuggestionStyle::{CompletelyHidden, ShowCode}; use rustc_hir::{Expr, ExprKind, LangItem}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::ty::adjustment::{Adjust, Adjustment}; -use rustc_middle::ty::{List, Ty, TyCtxt}; +use rustc_middle::ty::{self, GenericArg, List, TraitRef, Ty, TyCtxt, Upcast}; use rustc_session::impl_lint_pass; use rustc_span::edition::Edition::Edition2021; use rustc_span::{Span, Symbol, sym}; +use rustc_trait_selection::infer::TyCtxtInferExt; +use rustc_trait_selection::traits::{Obligation, ObligationCause, Selection, SelectionContext}; declare_clippy_lint! { /// ### What it does @@ -194,12 +198,41 @@ declare_clippy_lint! { "use of a format specifier that has no effect" } +declare_clippy_lint! { + /// ### What it does + /// Detects [pointer format] as well as `Debug` formatting of raw pointers or function pointers + /// or any types that have a derived `Debug` impl that recursively contains them. + /// + /// ### Why restrict this? + /// The addresses are only useful in very specific contexts, and certain projects may want to keep addresses of + /// certain data structures or functions from prying hacker eyes as an additional line of security. + /// + /// ### Known problems + /// The lint currently only looks through derived `Debug` implementations. Checking whether a manual + /// implementation prints an address is left as an exercise to the next lint implementer. + /// + /// ### Example + /// ```no_run + /// let foo = &0_u32; + /// fn bar() {} + /// println!("{:p}", foo); + /// let _ = format!("{:?}", &(bar as fn())); + /// ``` + /// + /// [pointer format]: https://doc.rust-lang.org/std/fmt/index.html#formatting-traits + #[clippy::version = "1.88.0"] + pub POINTER_FORMAT, + restriction, + "formatting a pointer" +} + impl_lint_pass!(FormatArgs<'_> => [ FORMAT_IN_FORMAT_ARGS, TO_STRING_IN_FORMAT_ARGS, UNINLINED_FORMAT_ARGS, UNNECESSARY_DEBUG_FORMATTING, UNUSED_FORMAT_SPECS, + POINTER_FORMAT, ]); #[allow(clippy::struct_field_names)] @@ -208,6 +241,8 @@ pub struct FormatArgs<'tcx> { msrv: Msrv, ignore_mixed: bool, ty_msrv_map: FxHashMap<Ty<'tcx>, Option<RustcVersion>>, + has_derived_debug: FxHashMap<Ty<'tcx>, bool>, + has_pointer_format: FxHashMap<Ty<'tcx>, bool>, } impl<'tcx> FormatArgs<'tcx> { @@ -218,6 +253,8 @@ impl<'tcx> FormatArgs<'tcx> { msrv: conf.msrv, ignore_mixed: conf.allow_mixed_uninlined_format_args, ty_msrv_map, + has_derived_debug: FxHashMap::default(), + has_pointer_format: FxHashMap::default(), } } } @@ -228,7 +265,7 @@ impl<'tcx> LateLintPass<'tcx> for FormatArgs<'tcx> { && is_format_macro(cx, macro_call.def_id) && let Some(format_args) = self.format_args.get(cx, expr, macro_call.expn) { - let linter = FormatArgsExpr { + let mut linter = FormatArgsExpr { cx, expr, macro_call: ¯o_call, @@ -236,6 +273,8 @@ impl<'tcx> LateLintPass<'tcx> for FormatArgs<'tcx> { ignore_mixed: self.ignore_mixed, msrv: &self.msrv, ty_msrv_map: &self.ty_msrv_map, + has_derived_debug: &mut self.has_derived_debug, + has_pointer_format: &mut self.has_pointer_format, }; linter.check_templates(); @@ -255,10 +294,12 @@ struct FormatArgsExpr<'a, 'tcx> { ignore_mixed: bool, msrv: &'a Msrv, ty_msrv_map: &'a FxHashMap<Ty<'tcx>, Option<RustcVersion>>, + has_derived_debug: &'a mut FxHashMap<Ty<'tcx>, bool>, + has_pointer_format: &'a mut FxHashMap<Ty<'tcx>, bool>, } impl<'tcx> FormatArgsExpr<'_, 'tcx> { - fn check_templates(&self) { + fn check_templates(&mut self) { for piece in &self.format_args.template { if let FormatArgsPiece::Placeholder(placeholder) = piece && let Ok(index) = placeholder.argument.index @@ -279,6 +320,17 @@ impl<'tcx> FormatArgsExpr<'_, 'tcx> { if placeholder.format_trait == FormatTrait::Debug { let name = self.cx.tcx.item_name(self.macro_call.def_id); self.check_unnecessary_debug_formatting(name, arg_expr); + if let Some(span) = placeholder.span + && self.has_pointer_debug(self.cx.typeck_results().expr_ty(arg_expr), 0) + { + span_lint(self.cx, POINTER_FORMAT, span, "pointer formatting detected"); + } + } + + if placeholder.format_trait == FormatTrait::Pointer + && let Some(span) = placeholder.span + { + span_lint(self.cx, POINTER_FORMAT, span, "pointer formatting detected"); } } } @@ -490,6 +542,16 @@ impl<'tcx> FormatArgsExpr<'_, 'tcx> { && let ty = cx.typeck_results().expr_ty(value) && self.can_display_format(ty) { + // If the parent function is a method of `Debug`, we don't want to lint + // because it is likely that the user wants to use `Debug` formatting. + let parent_fn = cx.tcx.hir_get_parent_item(value.hir_id); + if let Some(trait_ref) = trait_ref_of_method(cx, parent_fn) + && let Some(trait_def_id) = trait_ref.trait_def_id() + && cx.tcx.is_diagnostic_item(sym::Debug, trait_def_id) + { + return; + } + let snippet = snippet(cx.sess(), value.span, ".."); span_lint_and_then( cx, @@ -559,6 +621,58 @@ impl<'tcx> FormatArgsExpr<'_, 'tcx> { false } + + fn has_pointer_debug(&mut self, ty: Ty<'tcx>, depth: usize) -> bool { + let cx = self.cx; + let tcx = cx.tcx; + if !tcx.recursion_limit().value_within_limit(depth) { + return false; + } + let depth = depth + 1; + let typing_env = cx.typing_env(); + let ty = tcx.normalize_erasing_regions(typing_env, ty); + match ty.kind() { + ty::RawPtr(..) | ty::FnPtr(..) | ty::FnDef(..) => true, + ty::Ref(_, t, _) | ty::Slice(t) | ty::Array(t, _) => self.has_pointer_debug(*t, depth), + ty::Tuple(ts) => ts.iter().any(|t| self.has_pointer_debug(t, depth)), + ty::Adt(adt, args) => { + match self.has_pointer_format.entry(ty) { + Entry::Occupied(o) => return *o.get(), + Entry::Vacant(v) => v.insert(false), + }; + let derived_debug = if let Some(&known) = self.has_derived_debug.get(&ty) { + known + } else { + let Some(trait_id) = tcx.get_diagnostic_item(sym::Debug) else { + return false; + }; + let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env); + let trait_ref = TraitRef::new(tcx, trait_id, [GenericArg::from(ty)]); + let obligation = Obligation { + cause: ObligationCause::dummy(), + param_env, + recursion_depth: 0, + predicate: trait_ref.upcast(tcx), + }; + let selection = SelectionContext::new(&infcx).select(&obligation); + let derived = if let Ok(Some(Selection::UserDefined(data))) = selection { + tcx.has_attr(data.impl_def_id, sym::automatically_derived) + } else { + false + }; + self.has_derived_debug.insert(ty, derived); + derived + }; + let pointer_debug = derived_debug + && adt.all_fields().any(|f| { + self.has_pointer_debug(tcx.normalize_erasing_regions(typing_env, f.ty(tcx, args)), depth) + }); + self.has_pointer_format.insert(ty, pointer_debug); + pointer_debug + }, + _ => false, + } + } } fn make_ty_msrv_map(tcx: TyCtxt<'_>) -> FxHashMap<Ty<'_>, Option<RustcVersion>> { diff --git a/src/tools/clippy/clippy_lints/src/functions/mod.rs b/src/tools/clippy/clippy_lints/src/functions/mod.rs index d0d02a382d1..6051dc9479b 100644 --- a/src/tools/clippy/clippy_lints/src/functions/mod.rs +++ b/src/tools/clippy/clippy_lints/src/functions/mod.rs @@ -303,7 +303,7 @@ declare_clippy_lint! { /// to the name of the method, when there is a field's whose name matches that of the method. /// /// ### Why is this bad? - /// It is most likely that such a method is a bug caused by a typo or by copy-pasting. + /// It is most likely that such a method is a bug caused by a typo or by copy-pasting. /// /// ### Example diff --git a/src/tools/clippy/clippy_lints/src/if_let_mutex.rs b/src/tools/clippy/clippy_lints/src/if_let_mutex.rs index 6444e99ae9c..a99118f90f8 100644 --- a/src/tools/clippy/clippy_lints/src/if_let_mutex.rs +++ b/src/tools/clippy/clippy_lints/src/if_let_mutex.rs @@ -1,14 +1,13 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::visitors::for_each_expr_without_closures; -use clippy_utils::{eq_expr_value, higher}; +use clippy_utils::{eq_expr_value, higher, sym}; use core::ops::ControlFlow; use rustc_errors::Diag; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; use rustc_span::edition::Edition::Edition2024; -use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -94,7 +93,7 @@ fn mutex_lock_call<'tcx>( op_mutex: Option<&'tcx Expr<'_>>, ) -> ControlFlow<&'tcx Expr<'tcx>> { if let ExprKind::MethodCall(path, self_arg, [], _) = &expr.kind - && path.ident.as_str() == "lock" + && path.ident.name == sym::lock && let ty = cx.typeck_results().expr_ty(self_arg).peel_refs() && is_type_diagnostic_item(cx, ty, sym::Mutex) && op_mutex.is_none_or(|op| eq_expr_value(cx, self_arg, op)) diff --git a/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs b/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs index 0823ef53ef9..c743501da25 100644 --- a/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs +++ b/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs @@ -3,7 +3,7 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::sugg::{Sugg, make_binop}; use clippy_utils::{ - SpanlessEq, eq_expr_value, higher, is_in_const_context, is_integer_literal, peel_blocks, peel_blocks_with_stmt, + SpanlessEq, eq_expr_value, higher, is_in_const_context, is_integer_literal, peel_blocks, peel_blocks_with_stmt, sym, }; use rustc_ast::ast::LitKind; use rustc_data_structures::packed::Pu128; @@ -11,7 +11,7 @@ use rustc_errors::Applicability; use rustc_hir::{AssignOpKind, BinOp, BinOpKind, Expr, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::impl_lint_pass; -use rustc_span::Span; +use rustc_span::{Span, Symbol}; declare_clippy_lint! { /// ### What it does @@ -325,7 +325,7 @@ fn check_with_condition<'tcx>( } // Get the variable name - let var_name = ares_path.segments[0].ident.name.as_str(); + let var_name = ares_path.segments[0].ident.name; match cond_num_val.kind { ExprKind::Lit(cond_lit) => { // Check if the constant is zero @@ -337,7 +337,7 @@ fn check_with_condition<'tcx>( } }, ExprKind::Path(QPath::TypeRelative(_, name)) => { - if name.ident.as_str() == "MIN" + if name.ident.name == sym::MIN && let Some(const_id) = cx.typeck_results().type_dependent_def_id(cond_num_val.hir_id) && let Some(impl_id) = cx.tcx.impl_of_method(const_id) && let None = cx.tcx.impl_trait_ref(impl_id) // An inherent impl @@ -348,7 +348,7 @@ fn check_with_condition<'tcx>( }, ExprKind::Call(func, []) => { if let ExprKind::Path(QPath::TypeRelative(_, name)) = func.kind - && name.ident.as_str() == "min_value" + && name.ident.name == sym::min_value && let Some(func_id) = cx.typeck_results().type_dependent_def_id(func.hir_id) && let Some(impl_id) = cx.tcx.impl_of_method(func_id) && let None = cx.tcx.impl_trait_ref(impl_id) // An inherent impl @@ -383,7 +383,7 @@ fn subtracts_one<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<&'a Exp } } -fn print_lint_and_sugg(cx: &LateContext<'_>, var_name: &str, expr: &Expr<'_>) { +fn print_lint_and_sugg(cx: &LateContext<'_>, var_name: Symbol, expr: &Expr<'_>) { span_lint_and_sugg( cx, IMPLICIT_SATURATING_SUB, diff --git a/src/tools/clippy/clippy_lints/src/infallible_try_from.rs b/src/tools/clippy/clippy_lints/src/infallible_try_from.rs new file mode 100644 index 00000000000..b54c289fa7e --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/infallible_try_from.rs @@ -0,0 +1,76 @@ +use clippy_utils::diagnostics::span_lint; +use clippy_utils::sym; +use rustc_errors::MultiSpan; +use rustc_hir::{AssocItemKind, Item, ItemKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::declare_lint_pass; + +declare_clippy_lint! { + /// ### What it does + /// + /// Finds manual impls of `TryFrom` with infallible error types. + /// + /// ### Why is this bad? + /// + /// Infalliable conversions should be implemented via `From` with the blanket conversion. + /// + /// ### Example + /// ```no_run + /// use std::convert::Infallible; + /// struct MyStruct(i16); + /// impl TryFrom<i16> for MyStruct { + /// type Error = Infallible; + /// fn try_from(other: i16) -> Result<Self, Infallible> { + /// Ok(Self(other.into())) + /// } + /// } + /// ``` + /// Use instead: + /// ```no_run + /// struct MyStruct(i16); + /// impl From<i16> for MyStruct { + /// fn from(other: i16) -> Self { + /// Self(other) + /// } + /// } + /// ``` + #[clippy::version = "1.88.0"] + pub INFALLIBLE_TRY_FROM, + suspicious, + "TryFrom with infallible Error type" +} +declare_lint_pass!(InfallibleTryFrom => [INFALLIBLE_TRY_FROM]); + +impl<'tcx> LateLintPass<'tcx> for InfallibleTryFrom { + fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { + let ItemKind::Impl(imp) = item.kind else { return }; + let Some(r#trait) = imp.of_trait else { return }; + let Some(trait_def_id) = r#trait.trait_def_id() else { + return; + }; + if !cx.tcx.is_diagnostic_item(sym::TryFrom, trait_def_id) { + return; + } + for ii in imp.items { + if ii.kind == AssocItemKind::Type { + let ii = cx.tcx.hir_impl_item(ii.id); + if ii.ident.name != sym::Error { + continue; + } + let ii_ty = ii.expect_type(); + let ii_ty_span = ii_ty.span; + let ii_ty = clippy_utils::ty::ty_from_hir_ty(cx, ii_ty); + if !ii_ty.is_inhabited_from(cx.tcx, ii.owner_id.to_def_id(), cx.typing_env()) { + let mut span = MultiSpan::from_span(cx.tcx.def_span(item.owner_id.to_def_id())); + span.push_span_label(ii_ty_span, "infallible error type"); + span_lint( + cx, + INFALLIBLE_TRY_FROM, + span, + "infallible TryFrom impl; consider implementing From, instead", + ); + } + } + } + } +} diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index 92eb3d7a7c5..be9142b17fe 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs @@ -55,6 +55,7 @@ extern crate rustc_session; extern crate rustc_span; extern crate rustc_target; extern crate rustc_trait_selection; +extern crate smallvec; extern crate thin_vec; #[macro_use] @@ -65,11 +66,10 @@ extern crate clippy_utils; mod utils; -pub mod ctfe; // Very important lint, do not remove (rust#125116) pub mod declared_lints; pub mod deprecated_lints; -// begin lints modules, do not remove this comment, it’s used in `update_lints` +// begin lints modules, do not remove this comment, it's used in `update_lints` mod absolute_paths; mod almost_complete_range; mod approx_const; @@ -95,6 +95,7 @@ mod casts; mod cfg_not_test; mod checked_conversions; mod cloned_ref_to_slice_refs; +mod coerce_container_to_any; mod cognitive_complexity; mod collapsible_if; mod collection_is_never_read; @@ -169,6 +170,7 @@ mod inconsistent_struct_constructor; mod index_refutable_slice; mod indexing_slicing; mod ineffective_open_options; +mod infallible_try_from; mod infinite_iter; mod inherent_impl; mod inherent_to_string; @@ -404,7 +406,7 @@ mod zero_div_zero; mod zero_repeat_side_effects; mod zero_sized_map_values; mod zombie_processes; -// end lints modules, do not remove this comment, it’s used in `update_lints` +// end lints modules, do not remove this comment, it's used in `update_lints` use clippy_config::{Conf, get_configuration_metadata, sanitize_explanation}; use clippy_utils::macros::FormatArgsStorage; @@ -583,8 +585,6 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { let attrs = attr_storage.clone(); store.register_early_pass(move || Box::new(AttrCollector::new(attrs.clone()))); - store.register_late_pass(|_| Box::new(ctfe::ClippyCtfe)); - store.register_late_pass(move |_| Box::new(operators::arithmetic_side_effects::ArithmeticSideEffects::new(conf))); store.register_late_pass(|_| Box::new(utils::dump_hir::DumpHir)); store.register_late_pass(|_| Box::new(utils::author::Author)); @@ -946,5 +946,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) { store.register_late_pass(|_| Box::new(single_option_map::SingleOptionMap)); store.register_late_pass(move |_| Box::new(redundant_test_prefix::RedundantTestPrefix)); store.register_late_pass(|_| Box::new(cloned_ref_to_slice_refs::ClonedRefToSliceRefs::new(conf))); + store.register_late_pass(|_| Box::new(infallible_try_from::InfallibleTryFrom)); + store.register_late_pass(|_| Box::new(coerce_container_to_any::CoerceContainerToAny)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs b/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs index 81f14b7b2b0..ddb8bb536c0 100644 --- a/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs +++ b/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs @@ -2,8 +2,9 @@ use super::MANUAL_FLATTEN; use super::utils::make_iterator_snippet; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::msrvs::{self, Msrv}; +use clippy_utils::source::{HasSession, indent_of, reindent_multiline, snippet_with_applicability}; use clippy_utils::visitors::is_local_used; -use clippy_utils::{higher, is_refutable, path_to_local_id, peel_blocks_with_stmt}; +use clippy_utils::{higher, is_refutable, path_to_local_id, peel_blocks_with_stmt, span_contains_comment}; use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Expr, Pat, PatKind}; @@ -39,13 +40,20 @@ pub(super) fn check<'tcx>( && msrv.meets(cx, msrvs::ITER_FLATTEN) && !is_refutable(cx, inner_pat) { + if arg.span.from_expansion() || if_then.span.from_expansion() { + return; + } let if_let_type = if some_ctor { "Some" } else { "Ok" }; // Prepare the error message let msg = format!("unnecessary `if let` since only the `{if_let_type}` variant of the iterator element is used"); // Prepare the help message - let mut applicability = Applicability::MaybeIncorrect; + let mut applicability = if span_contains_comment(cx.sess().source_map(), body.span) { + Applicability::MaybeIncorrect + } else { + Applicability::MachineApplicable + }; let arg_snippet = make_iterator_snippet(cx, arg, &mut applicability); let copied = match cx.typeck_results().expr_ty(let_expr).kind() { ty::Ref(_, inner, _) => match inner.kind() { @@ -55,20 +63,26 @@ pub(super) fn check<'tcx>( _ => "", }; - let sugg = format!("{arg_snippet}{copied}.flatten()"); + let help_msg = "try `.flatten()` and remove the `if let` statement in the for loop"; - // If suggestion is not a one-liner, it won't be shown inline within the error message. In that - // case, it will be shown in the extra `help` message at the end, which is why the first - // `help_msg` needs to refer to the correct relative position of the suggestion. - let help_msg = if sugg.contains('\n') { - "remove the `if let` statement in the for loop and then..." - } else { - "...and remove the `if let` statement in the for loop" - }; + let pat_snippet = + snippet_with_applicability(cx, inner_pat.span.source_callsite(), "_", &mut applicability).to_string(); + let body_snippet = + snippet_with_applicability(cx, if_then.span.source_callsite(), "[body]", &mut applicability).to_string(); + let suggestions = vec![ + // flatten the iterator + (arg.span, format!("{arg_snippet}{copied}.flatten()")), + (pat.span, pat_snippet), + // remove the `if let` statement + ( + body.span, + reindent_multiline(&body_snippet, true, indent_of(cx, body.span)), + ), + ]; span_lint_and_then(cx, MANUAL_FLATTEN, span, msg, |diag| { - diag.span_suggestion(arg.span, "try", sugg, applicability); diag.span_help(inner_expr.span, help_msg); + diag.multipart_suggestion("try", suggestions, applicability); }); } } diff --git a/src/tools/clippy/clippy_lints/src/manual_clamp.rs b/src/tools/clippy/clippy_lints/src/manual_clamp.rs index 02afe9f0997..42fe386d2c3 100644 --- a/src/tools/clippy/clippy_lints/src/manual_clamp.rs +++ b/src/tools/clippy/clippy_lints/src/manual_clamp.rs @@ -8,7 +8,7 @@ use clippy_utils::ty::implements_trait; use clippy_utils::visitors::is_const_evaluatable; use clippy_utils::{ MaybePath, eq_expr_value, is_diag_trait_item, is_in_const_context, is_trait_method, path_res, path_to_local_id, - peel_blocks, peel_blocks_with_stmt, + peel_blocks, peel_blocks_with_stmt, sym, }; use itertools::Itertools; use rustc_errors::{Applicability, Diag}; @@ -18,7 +18,6 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::Ty; use rustc_session::impl_lint_pass; use rustc_span::Span; -use rustc_span::symbol::sym; use std::cmp::Ordering; use std::ops::Deref; @@ -299,9 +298,9 @@ fn is_max_min_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> O && (cx.typeck_results().expr_ty_adjusted(input).is_floating_point() || is_trait_method(cx, receiver, sym::Ord)) { let is_float = cx.typeck_results().expr_ty_adjusted(input).is_floating_point(); - let (min, max) = match (seg_first.ident.as_str(), seg_second.ident.as_str()) { - ("min", "max") => (arg_second, arg_first), - ("max", "min") => (arg_first, arg_second), + let (min, max) = match (seg_first.ident.name, seg_second.ident.name) { + (sym::min, sym::max) => (arg_second, arg_first), + (sym::max, sym::min) => (arg_first, arg_second), _ => return None, }; Some(ClampSuggestion { diff --git a/src/tools/clippy/clippy_lints/src/manual_string_new.rs b/src/tools/clippy/clippy_lints/src/manual_string_new.rs index 73ee1c3c78a..9b590e092d0 100644 --- a/src/tools/clippy/clippy_lints/src/manual_string_new.rs +++ b/src/tools/clippy/clippy_lints/src/manual_string_new.rs @@ -1,11 +1,12 @@ use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::sym; use rustc_ast::LitKind; use rustc_errors::Applicability::MachineApplicable; use rustc_hir::{Expr, ExprKind, PathSegment, QPath, TyKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::declare_lint_pass; -use rustc_span::{Span, sym}; +use rustc_span::Span; declare_clippy_lint! { /// ### What it does @@ -89,9 +90,10 @@ fn warn_then_suggest(cx: &LateContext<'_>, span: Span) { /// Tries to parse an expression as a method call, emitting the warning if necessary. fn parse_method_call(cx: &LateContext<'_>, span: Span, path_segment: &PathSegment<'_>, receiver: &Expr<'_>) { - let ident = path_segment.ident.as_str(); let method_arg_kind = &receiver.kind; - if ["to_string", "to_owned", "into"].contains(&ident) && is_expr_kind_empty_str(method_arg_kind) { + if matches!(path_segment.ident.name, sym::to_string | sym::to_owned | sym::into) + && is_expr_kind_empty_str(method_arg_kind) + { warn_then_suggest(cx, span); } else if let ExprKind::Call(func, [arg]) = method_arg_kind { // If our first argument is a function call itself, it could be an `unwrap`-like function. diff --git a/src/tools/clippy/clippy_lints/src/match_result_ok.rs b/src/tools/clippy/clippy_lints/src/match_result_ok.rs index 2a5fc8b6609..e0cb5d14d3c 100644 --- a/src/tools/clippy/clippy_lints/src/match_result_ok.rs +++ b/src/tools/clippy/clippy_lints/src/match_result_ok.rs @@ -1,12 +1,11 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_context; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{higher, is_res_lang_ctor}; +use clippy_utils::{higher, is_res_lang_ctor, sym}; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, LangItem, PatKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -57,7 +56,7 @@ impl<'tcx> LateLintPass<'tcx> for MatchResultOk { if let ExprKind::MethodCall(ok_path, recv, [], ..) = let_expr.kind //check is expr.ok() has type Result<T,E>.ok(, _) && let PatKind::TupleStruct(ref pat_path, [ok_pat], _) = let_pat.kind //get operation - && ok_path.ident.as_str() == "ok" + && ok_path.ident.name == sym::ok && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result) && is_res_lang_ctor(cx, cx.qpath_res(pat_path, let_pat.hir_id), LangItem::OptionSome) && let ctxt = expr.span.ctxt() diff --git a/src/tools/clippy/clippy_lints/src/matches/match_single_binding.rs b/src/tools/clippy/clippy_lints/src/matches/match_single_binding.rs index adda3586990..6a76c6cedd0 100644 --- a/src/tools/clippy/clippy_lints/src/matches/match_single_binding.rs +++ b/src/tools/clippy/clippy_lints/src/matches/match_single_binding.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::macros::HirNode; use clippy_utils::source::{indent_of, snippet, snippet_block_with_context, snippet_with_context}; -use clippy_utils::{get_parent_expr, is_refutable, peel_blocks}; +use clippy_utils::{is_refutable, peel_blocks}; use rustc_errors::Applicability; use rustc_hir::{Arm, Expr, ExprKind, Node, PatKind, StmtKind}; use rustc_lint::LateContext; @@ -9,6 +9,7 @@ use rustc_span::Span; use super::MATCH_SINGLE_BINDING; +#[derive(Debug)] enum AssignmentExpr { Assign { span: Span, match_span: Span }, Local { span: Span, pat_span: Span }, @@ -160,6 +161,17 @@ fn opt_parent_assign_span<'a>(cx: &LateContext<'a>, ex: &Expr<'a>) -> Option<Ass None } +fn expr_parent_requires_curlies<'a>(cx: &LateContext<'a>, match_expr: &Expr<'a>) -> bool { + let parent = cx.tcx.parent_hir_node(match_expr.hir_id); + matches!( + parent, + Node::Expr(Expr { + kind: ExprKind::Closure { .. }, + .. + }) | Node::AnonConst(..) + ) +} + fn sugg_with_curlies<'a>( cx: &LateContext<'a>, (ex, match_expr): (&Expr<'a>, &Expr<'a>), @@ -172,9 +184,7 @@ fn sugg_with_curlies<'a>( let mut indent = " ".repeat(indent_of(cx, ex.span).unwrap_or(0)); let (mut cbrace_start, mut cbrace_end) = (String::new(), String::new()); - if let Some(parent_expr) = get_parent_expr(cx, match_expr) - && let ExprKind::Closure { .. } = parent_expr.kind - { + if expr_parent_requires_curlies(cx, match_expr) { cbrace_end = format!("\n{indent}}}"); // Fix body indent due to the closure indent = " ".repeat(indent_of(cx, bind_names).unwrap_or(0)); diff --git a/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs b/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs index 65b93a095b9..8b4c1700051 100644 --- a/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs +++ b/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs @@ -1,6 +1,7 @@ use std::ops::ControlFlow; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::sym; use clippy_utils::ty::is_type_lang_item; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; @@ -42,7 +43,7 @@ impl<'tcx> Visitor<'tcx> for MatchExprVisitor<'_, 'tcx> { type Result = ControlFlow<CaseMethod>; fn visit_expr(&mut self, ex: &'tcx Expr<'_>) -> Self::Result { if let ExprKind::MethodCall(segment, receiver, [], _) = ex.kind { - let result = self.case_altered(segment.ident.as_str(), receiver); + let result = self.case_altered(segment.ident.name, receiver); if result.is_break() { return result; } @@ -53,7 +54,7 @@ impl<'tcx> Visitor<'tcx> for MatchExprVisitor<'_, 'tcx> { } impl MatchExprVisitor<'_, '_> { - fn case_altered(&mut self, segment_ident: &str, receiver: &Expr<'_>) -> ControlFlow<CaseMethod> { + fn case_altered(&mut self, segment_ident: Symbol, receiver: &Expr<'_>) -> ControlFlow<CaseMethod> { if let Some(case_method) = get_case_method(segment_ident) { let ty = self.cx.typeck_results().expr_ty(receiver).peel_refs(); @@ -66,12 +67,12 @@ impl MatchExprVisitor<'_, '_> { } } -fn get_case_method(segment_ident_str: &str) -> Option<CaseMethod> { - match segment_ident_str { - "to_lowercase" => Some(CaseMethod::LowerCase), - "to_ascii_lowercase" => Some(CaseMethod::AsciiLowerCase), - "to_uppercase" => Some(CaseMethod::UpperCase), - "to_ascii_uppercase" => Some(CaseMethod::AsciiUppercase), +fn get_case_method(segment_ident: Symbol) -> Option<CaseMethod> { + match segment_ident { + sym::to_lowercase => Some(CaseMethod::LowerCase), + sym::to_ascii_lowercase => Some(CaseMethod::AsciiLowerCase), + sym::to_uppercase => Some(CaseMethod::UpperCase), + sym::to_ascii_uppercase => Some(CaseMethod::AsciiUppercase), _ => None, } } diff --git a/src/tools/clippy/clippy_lints/src/methods/ip_constant.rs b/src/tools/clippy/clippy_lints/src/methods/ip_constant.rs new file mode 100644 index 00000000000..83803fba6a1 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/methods/ip_constant.rs @@ -0,0 +1,52 @@ +use clippy_utils::consts::{ConstEvalCtxt, Constant}; +use clippy_utils::diagnostics::span_lint_and_then; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind, QPath, Ty, TyKind}; +use rustc_lint::LateContext; +use rustc_span::sym; +use smallvec::SmallVec; + +use super::IP_CONSTANT; + +pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, func: &Expr<'_>, args: &[Expr<'_>]) { + if let ExprKind::Path(QPath::TypeRelative( + Ty { + kind: TyKind::Path(QPath::Resolved(_, func_path)), + .. + }, + p, + )) = func.kind + && p.ident.name == sym::new + && let Some(func_def_id) = func_path.res.opt_def_id() + && matches!( + cx.tcx.get_diagnostic_name(func_def_id), + Some(sym::Ipv4Addr | sym::Ipv6Addr) + ) + && let Some(args) = args + .iter() + .map(|arg| { + if let Some(Constant::Int(constant @ (0 | 1 | 127 | 255))) = ConstEvalCtxt::new(cx).eval(arg) { + u8::try_from(constant).ok() + } else { + None + } + }) + .collect::<Option<SmallVec<[u8; 8]>>>() + { + let constant_name = match args.as_slice() { + [0, 0, 0, 0] | [0, 0, 0, 0, 0, 0, 0, 0] => "UNSPECIFIED", + [127, 0, 0, 1] | [0, 0, 0, 0, 0, 0, 0, 1] => "LOCALHOST", + [255, 255, 255, 255] => "BROADCAST", + _ => return, + }; + + span_lint_and_then(cx, IP_CONSTANT, expr.span, "hand-coded well-known IP address", |diag| { + diag.span_suggestion_verbose( + expr.span.with_lo(p.ident.span.lo()), + "use", + constant_name, + Applicability::MachineApplicable, + ); + }); + } +} diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs b/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs index c88462129af..cbb1b450e60 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs @@ -46,7 +46,7 @@ pub(super) fn check<'tcx>( if let ExprKind::Path(rustc_hir::QPath::Resolved(_, path)) = body_expr.kind && let [local_ident] = path.segments - && local_ident.ident.as_str() == bound_ident.as_str() + && local_ident.ident.name == bound_ident.name { span_lint_and_sugg( cx, diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs b/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs index e2df8ce1513..c785b23bc9c 100644 --- a/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs +++ b/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs @@ -72,9 +72,9 @@ fn is_min_or_max(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<MinMax> { if let hir::ExprKind::Call(func, []) = &expr.kind && let hir::ExprKind::Path(hir::QPath::TypeRelative(_, segment)) = &func.kind { - match segment.ident.as_str() { - "max_value" => return Some(MinMax::Max), - "min_value" => return Some(MinMax::Min), + match segment.ident.name { + sym::max_value => return Some(MinMax::Max), + sym::min_value => return Some(MinMax::Min), _ => {}, } } diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs index bc159206985..347960e0003 100644 --- a/src/tools/clippy/clippy_lints/src/methods/mod.rs +++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs @@ -37,6 +37,7 @@ mod inefficient_to_string; mod inspect_for_each; mod into_iter_on_ref; mod io_other_error; +mod ip_constant; mod is_digit_ascii_radix; mod is_empty; mod iter_cloned_collect; @@ -4528,6 +4529,42 @@ declare_clippy_lint! { "detect swap with a temporary value" } +declare_clippy_lint! { + /// ### What it does + /// Checks for IP addresses that could be replaced with predefined constants such as + /// `Ipv4Addr::new(127, 0, 0, 1)` instead of using the appropriate constants. + /// + /// ### Why is this bad? + /// Using specific IP addresses like `127.0.0.1` or `::1` is less clear and less maintainable than using the + /// predefined constants `Ipv4Addr::LOCALHOST` or `Ipv6Addr::LOCALHOST`. These constants improve code + /// readability, make the intent explicit, and are less error-prone. + /// + /// ### Example + /// ```no_run + /// use std::net::{Ipv4Addr, Ipv6Addr}; + /// + /// // IPv4 loopback + /// let addr_v4 = Ipv4Addr::new(127, 0, 0, 1); + /// + /// // IPv6 loopback + /// let addr_v6 = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1); + /// ``` + /// Use instead: + /// ```no_run + /// use std::net::{Ipv4Addr, Ipv6Addr}; + /// + /// // IPv4 loopback + /// let addr_v4 = Ipv4Addr::LOCALHOST; + /// + /// // IPv6 loopback + /// let addr_v6 = Ipv6Addr::LOCALHOST; + /// ``` + #[clippy::version = "1.89.0"] + pub IP_CONSTANT, + pedantic, + "hardcoded localhost IP address" +} + #[expect(clippy::struct_excessive_bools)] pub struct Methods { avoid_breaking_exported_api: bool, @@ -4706,6 +4743,7 @@ impl_lint_pass!(Methods => [ MANUAL_CONTAINS, IO_OTHER_ERROR, SWAP_WITH_TEMPORARY, + IP_CONSTANT, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -4738,6 +4776,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { useless_nonzero_new_unchecked::check(cx, expr, func, args, self.msrv); io_other_error::check(cx, expr, func, args, self.msrv); swap_with_temporary::check(cx, expr, func, args); + ip_constant::check(cx, expr, func, args); }, ExprKind::MethodCall(method_call, receiver, args, _) => { let method_span = method_call.ident.span; 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 2b75d6a8248..0075bf166cc 100644 --- a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs +++ b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs @@ -44,11 +44,10 @@ pub(super) fn check<'tcx>( if let ExprKind::MethodCall(name, _, args @ ([] | [_]), _) = parent.kind { let mut app = Applicability::MachineApplicable; - let name = name.ident.as_str(); let collect_ty = cx.typeck_results().expr_ty(collect_expr); - let sugg: String = match name { - "len" => { + let sugg: String = match name.ident.name { + sym::len => { if let Some(adt) = collect_ty.ty_adt_def() && matches!( cx.tcx.get_diagnostic_name(adt.did()), @@ -60,13 +59,13 @@ pub(super) fn check<'tcx>( return; } }, - "is_empty" + sym::is_empty if is_is_empty_sig(cx, parent.hir_id) && iterates_same_ty(cx, cx.typeck_results().expr_ty(iter_expr), collect_ty) => { "next().is_none()".into() }, - "contains" => { + sym::contains => { if is_contains_sig(cx, parent.hir_id, iter_expr) && let Some(arg) = args.first() { diff --git a/src/tools/clippy/clippy_lints/src/methods/open_options.rs b/src/tools/clippy/clippy_lints/src/methods/open_options.rs index bce314e64f0..fd368024177 100644 --- a/src/tools/clippy/clippy_lints/src/methods/open_options.rs +++ b/src/tools/clippy/clippy_lints/src/methods/open_options.rs @@ -1,14 +1,14 @@ use rustc_data_structures::fx::FxHashMap; use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; -use clippy_utils::paths; use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{paths, sym}; use rustc_ast::ast::LitKind; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; use rustc_middle::ty::Ty; +use rustc_span::Span; use rustc_span::source_map::Spanned; -use rustc_span::{Span, sym}; use super::{NONSENSICAL_OPEN_OPTIONS, SUSPICIOUS_OPEN_OPTIONS}; @@ -87,23 +87,23 @@ fn get_open_options( _ => Argument::Unknown, }; - match path.ident.as_str() { - "create" => { + match path.ident.name { + sym::create => { options.push((OpenOption::Create, argument_option, span)); }, - "create_new" => { + sym::create_new => { options.push((OpenOption::CreateNew, argument_option, span)); }, - "append" => { + sym::append => { options.push((OpenOption::Append, argument_option, span)); }, - "truncate" => { + sym::truncate => { options.push((OpenOption::Truncate, argument_option, span)); }, - "read" => { + sym::read => { options.push((OpenOption::Read, argument_option, span)); }, - "write" => { + sym::write => { options.push((OpenOption::Write, argument_option, span)); }, _ => { diff --git a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs index 6935ae1f391..6f78d6c6128 100644 --- a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs +++ b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs @@ -285,9 +285,9 @@ fn parse_iter_usage<'tcx>( let did = cx.typeck_results().type_dependent_def_id(e.hir_id)?; let iter_id = cx.tcx.get_diagnostic_item(sym::Iterator)?; - match (name.ident.as_str(), args) { - ("next", []) if cx.tcx.trait_of_item(did) == Some(iter_id) => (IterUsageKind::Nth(0), e.span), - ("next_tuple", []) => { + match (name.ident.name, args) { + (sym::next, []) if cx.tcx.trait_of_item(did) == Some(iter_id) => (IterUsageKind::Nth(0), e.span), + (sym::next_tuple, []) => { return if paths::ITERTOOLS_NEXT_TUPLE.matches(cx, did) && let ty::Adt(adt_def, subs) = cx.typeck_results().expr_ty(e).kind() && cx.tcx.is_diagnostic_item(sym::Option, adt_def.did()) @@ -303,7 +303,7 @@ fn parse_iter_usage<'tcx>( None }; }, - ("nth" | "skip", [idx_expr]) if cx.tcx.trait_of_item(did) == Some(iter_id) => { + (sym::nth | sym::skip, [idx_expr]) if cx.tcx.trait_of_item(did) == Some(iter_id) => { if let Some(Constant::Int(idx)) = ConstEvalCtxt::new(cx).eval(idx_expr) { let span = if name.ident.as_str() == "nth" { e.span diff --git a/src/tools/clippy/clippy_lints/src/multiple_bound_locations.rs b/src/tools/clippy/clippy_lints/src/multiple_bound_locations.rs index 4b32ba83b32..741f38f9756 100644 --- a/src/tools/clippy/clippy_lints/src/multiple_bound_locations.rs +++ b/src/tools/clippy/clippy_lints/src/multiple_bound_locations.rs @@ -47,7 +47,7 @@ impl EarlyLintPass for MultipleBoundLocations { for param in &generics.params { if !param.bounds.is_empty() { - generic_params_with_bounds.insert(param.ident.name.as_str(), param.ident.span); + generic_params_with_bounds.insert(param.ident.as_str(), param.ident.span); } } for clause in &generics.where_clause.predicates { @@ -64,7 +64,7 @@ impl EarlyLintPass for MultipleBoundLocations { }, WherePredicateKind::RegionPredicate(pred) => { if !pred.bounds.is_empty() - && let Some(bound_span) = generic_params_with_bounds.get(&pred.lifetime.ident.name.as_str()) + && let Some(bound_span) = generic_params_with_bounds.get(&pred.lifetime.ident.as_str()) { emit_lint(cx, *bound_span, pred.lifetime.ident.span); } diff --git a/src/tools/clippy/clippy_lints/src/non_canonical_impls.rs b/src/tools/clippy/clippy_lints/src/non_canonical_impls.rs index 93865197ec9..04b09276966 100644 --- a/src/tools/clippy/clippy_lints/src/non_canonical_impls.rs +++ b/src/tools/clippy/clippy_lints/src/non_canonical_impls.rs @@ -293,7 +293,14 @@ fn self_cmp_call<'tcx>( ExprKind::Call(path, [_, _]) => path_res(cx, path) .opt_def_id() .is_some_and(|def_id| cx.tcx.is_diagnostic_item(sym::ord_cmp_method, def_id)), - ExprKind::MethodCall(_, _, [_other], ..) => { + ExprKind::MethodCall(_, recv, [_], ..) => { + let ExprKind::Path(path) = recv.kind else { + return false; + }; + if last_path_segment(&path).ident.name != kw::SelfLower { + return false; + } + // We can set this to true here no matter what as if it's a `MethodCall` and goes to the // `else` branch, it must be a method named `cmp` that isn't `Ord::cmp` *needs_fully_qualified = true; diff --git a/src/tools/clippy/clippy_lints/src/pathbuf_init_then_push.rs b/src/tools/clippy/clippy_lints/src/pathbuf_init_then_push.rs index 35caac855cf..4ce6827cac9 100644 --- a/src/tools/clippy/clippy_lints/src/pathbuf_init_then_push.rs +++ b/src/tools/clippy/clippy_lints/src/pathbuf_init_then_push.rs @@ -1,14 +1,14 @@ use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::path_to_local_id; use clippy_utils::source::{SpanRangeExt, snippet}; use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{path_to_local_id, sym}; use rustc_ast::{LitKind, StrStyle}; use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::{BindingMode, Block, Expr, ExprKind, HirId, LetStmt, PatKind, QPath, Stmt, StmtKind, TyKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::impl_lint_pass; -use rustc_span::{Span, Symbol, sym}; +use rustc_span::{Span, Symbol}; declare_clippy_lint! { /// ### What it does @@ -177,7 +177,7 @@ impl<'tcx> LateLintPass<'tcx> for PathbufThenPush<'tcx> { && let StmtKind::Expr(expr) | StmtKind::Semi(expr) = stmt.kind && let ExprKind::MethodCall(name, self_arg, [arg_expr], _) = expr.kind && path_to_local_id(self_arg, searcher.local_id) - && name.ident.as_str() == "push" + && name.ident.name == sym::push { searcher.err_span = searcher.err_span.to(stmt.span); searcher.arg = Some(*arg_expr); diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs index 9149406642d..94cdcf00054 100644 --- a/src/tools/clippy/clippy_lints/src/ptr.rs +++ b/src/tools/clippy/clippy_lints/src/ptr.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then, span_lin use clippy_utils::source::SpanRangeExt; use clippy_utils::sugg::Sugg; use clippy_utils::visitors::contains_unsafe_block; -use clippy_utils::{get_expr_use_or_unification_node, is_lint_allowed, path_def_id, path_to_local, std_or_core}; +use clippy_utils::{get_expr_use_or_unification_node, is_lint_allowed, path_def_id, path_to_local, std_or_core, sym}; use hir::LifetimeKind; use rustc_abi::ExternAbi; use rustc_errors::{Applicability, MultiSpan}; @@ -18,8 +18,8 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; use rustc_middle::ty::{self, Binder, ClauseKind, ExistentialPredicate, List, PredicateKind, Ty}; use rustc_session::declare_lint_pass; +use rustc_span::Span; use rustc_span::symbol::Symbol; -use rustc_span::{Span, sym}; use rustc_trait_selection::infer::InferCtxtExt as _; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; use std::{fmt, iter}; @@ -268,6 +268,7 @@ impl<'tcx> LateLintPass<'tcx> for Ptr { (false, false, true) if let Some(sugg) = Sugg::hir_opt(cx, l) => sugg.maybe_paren(), _ => return check_ptr_eq(cx, expr, op.node, l, r), }; + let invert = if op.node == BinOpKind::Eq { "" } else { "!" }; span_lint_and_sugg( cx, @@ -275,7 +276,7 @@ impl<'tcx> LateLintPass<'tcx> for Ptr { expr.span, "comparing with null is better expressed by the `.is_null()` method", "try", - format!("{non_null_path_snippet}.is_null()"), + format!("{invert}{non_null_path_snippet}.is_null()",), Applicability::MachineApplicable, ); } @@ -299,7 +300,7 @@ struct PtrArg<'tcx> { emission_id: HirId, span: Span, ty_name: Symbol, - method_renames: &'static [(&'static str, &'static str)], + method_renames: &'static [(Symbol, &'static str)], ref_prefix: RefPrefix, deref_ty: DerefTy<'tcx>, } @@ -385,6 +386,7 @@ impl<'tcx> DerefTy<'tcx> { } } +#[expect(clippy::too_many_lines)] fn check_fn_args<'cx, 'tcx: 'cx>( cx: &'cx LateContext<'tcx>, fn_sig: ty::FnSig<'tcx>, @@ -409,7 +411,7 @@ fn check_fn_args<'cx, 'tcx: 'cx>( let emission_id = params.get(i).map_or(hir_ty.hir_id, |param| param.hir_id); let (method_renames, deref_ty) = match cx.tcx.get_diagnostic_name(adt.did()) { Some(sym::Vec) => ( - [("clone", ".to_owned()")].as_slice(), + [(sym::clone, ".to_owned()")].as_slice(), DerefTy::Slice( name.args.and_then(|args| args.args.first()).and_then(|arg| { if let GenericArg::Type(ty) = arg { @@ -421,10 +423,14 @@ fn check_fn_args<'cx, 'tcx: 'cx>( args.type_at(0), ), ), - _ if Some(adt.did()) == cx.tcx.lang_items().string() => { - ([("clone", ".to_owned()"), ("as_str", "")].as_slice(), DerefTy::Str) - }, - Some(sym::PathBuf) => ([("clone", ".to_path_buf()"), ("as_path", "")].as_slice(), DerefTy::Path), + _ if Some(adt.did()) == cx.tcx.lang_items().string() => ( + [(sym::clone, ".to_owned()"), (sym::as_str, "")].as_slice(), + DerefTy::Str, + ), + Some(sym::PathBuf) => ( + [(sym::clone, ".to_path_buf()"), (sym::as_path, "")].as_slice(), + DerefTy::Path, + ), Some(sym::Cow) if mutability == Mutability::Not => { if let Some((lifetime, ty)) = name.args.and_then(|args| { if let [GenericArg::Lifetime(lifetime), ty] = args.args { @@ -595,7 +601,7 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &Body<'tcx>, args: &[ if let ExprKind::MethodCall(name, receiver, ..) = use_expr.kind && receiver.hir_id == child_id { - let name = name.ident.as_str(); + let name = name.ident.name; // Check if the method can be renamed. if let Some((_, replacement)) = args.method_renames.iter().find(|&&(x, _)| x == name) { diff --git a/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs b/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs index 49b522994fb..6b1dc864fb7 100644 --- a/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs +++ b/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then}; -use clippy_utils::get_enclosing_block; use clippy_utils::higher::{VecInitKind, get_vec_init_kind}; use clippy_utils::source::snippet; +use clippy_utils::{get_enclosing_block, sym}; use hir::{Expr, ExprKind, HirId, LetStmt, PatKind, PathSegment, QPath, StmtKind}; use rustc_errors::Applicability; @@ -87,7 +87,7 @@ impl<'tcx> LateLintPass<'tcx> for ReadZeroByteVec { diag.span_suggestion( expr.span, "try", - format!("{}.resize({len}, 0); {}", ident.as_str(), snippet(cx, expr.span, "..")), + format!("{}.resize({len}, 0); {}", ident, snippet(cx, expr.span, "..")), applicability, ); }, @@ -106,7 +106,7 @@ impl<'tcx> LateLintPass<'tcx> for ReadZeroByteVec { "try", format!( "{}.resize({}, 0); {}", - ident.as_str(), + ident, snippet(cx, e.span, ".."), snippet(cx, expr.span, "..") ), @@ -142,8 +142,8 @@ impl<'tcx> Visitor<'tcx> for ReadVecVisitor<'tcx> { if let ExprKind::MethodCall(path, receiver, args, _) = e.kind { let PathSegment { ident, .. } = *path; - match ident.as_str() { - "read" | "read_exact" => { + match ident.name { + sym::read | sym::read_exact => { let [arg] = args else { return }; if let ExprKind::AddrOf(_, hir::Mutability::Mut, inner) = arg.kind && let ExprKind::Path(QPath::Resolved(None, inner_path)) = inner.kind @@ -155,7 +155,7 @@ impl<'tcx> Visitor<'tcx> for ReadVecVisitor<'tcx> { return; } }, - "resize" => { + sym::resize => { // If the Vec is resized, then it's a valid read if let ExprKind::Path(QPath::Resolved(_, inner_path)) = receiver.kind && let Res::Local(res_id) = inner_path.res diff --git a/src/tools/clippy/clippy_lints/src/reserve_after_initialization.rs b/src/tools/clippy/clippy_lints/src/reserve_after_initialization.rs index 152d7450f5f..51adbbcd58b 100644 --- a/src/tools/clippy/clippy_lints/src/reserve_after_initialization.rs +++ b/src/tools/clippy/clippy_lints/src/reserve_after_initialization.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::higher::{VecInitKind, get_vec_init_kind}; use clippy_utils::source::snippet; -use clippy_utils::{is_from_proc_macro, path_to_local_id}; +use clippy_utils::{is_from_proc_macro, path_to_local_id, sym}; use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::{BindingMode, Block, Expr, ExprKind, HirId, LetStmt, PatKind, QPath, Stmt, StmtKind}; @@ -126,7 +126,7 @@ impl<'tcx> LateLintPass<'tcx> for ReserveAfterInitialization { if let StmtKind::Expr(expr) | StmtKind::Semi(expr) = stmt.kind && let ExprKind::MethodCall(name, self_arg, [space_hint], _) = expr.kind && path_to_local_id(self_arg, searcher.local_id) - && name.ident.as_str() == "reserve" + && name.ident.name == sym::reserve && !is_from_proc_macro(cx, expr) { self.searcher = Some(VecReserveSearcher { diff --git a/src/tools/clippy/clippy_lints/src/semicolon_block.rs b/src/tools/clippy/clippy_lints/src/semicolon_block.rs index d85f4a8fa01..f6c128d4c52 100644 --- a/src/tools/clippy/clippy_lints/src/semicolon_block.rs +++ b/src/tools/clippy/clippy_lints/src/semicolon_block.rs @@ -143,7 +143,7 @@ impl LateLintPass<'_> for SemicolonBlock { StmtKind::Expr(Expr { kind: ExprKind::Block(block, _), .. - }) if !block.span.from_expansion() => { + }) if !block.span.from_expansion() && stmt.span.contains(block.span) => { let Block { expr: None, stmts: [.., stmt], diff --git a/src/tools/clippy/clippy_lints/src/serde_api.rs b/src/tools/clippy/clippy_lints/src/serde_api.rs index a64b9b22378..b36a5d6d502 100644 --- a/src/tools/clippy/clippy_lints/src/serde_api.rs +++ b/src/tools/clippy/clippy_lints/src/serde_api.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::span_lint; -use clippy_utils::paths; +use clippy_utils::{paths, sym}; use rustc_hir::{Impl, Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; @@ -36,9 +36,9 @@ impl<'tcx> LateLintPass<'tcx> for SerdeApi { let mut seen_str = None; let mut seen_string = None; for item in *items { - match item.ident.as_str() { - "visit_str" => seen_str = Some(item.span), - "visit_string" => seen_string = Some(item.span), + match item.ident.name { + sym::visit_str => seen_str = Some(item.span), + sym::visit_string => seen_string = Some(item.span), _ => {}, } } diff --git a/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs b/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs index 3d39386ecf9..442b3250d86 100644 --- a/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs +++ b/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs @@ -1,13 +1,13 @@ use clippy_config::Conf; -use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::is_from_proc_macro; use clippy_utils::msrvs::Msrv; use rustc_attr_data_structures::{StabilityLevel, StableSince}; use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::def_id::DefId; -use rustc_hir::{HirId, Path, PathSegment}; -use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_hir::{Block, Body, HirId, Path, PathSegment}; +use rustc_lint::{LateContext, LateLintPass, Lint, LintContext}; use rustc_session::impl_lint_pass; use rustc_span::symbol::kw; use rustc_span::{Span, sym}; @@ -88,24 +88,35 @@ declare_clippy_lint! { } pub struct StdReexports { - // Paths which can be either a module or a macro (e.g. `std::env`) will cause this check to happen - // twice. First for the mod, second for the macro. This is used to avoid the lint reporting for the macro - // when the path could be also be used to access the module. - prev_span: Span, + lint_point: (Span, Option<LintPoint>), msrv: Msrv, } impl StdReexports { pub fn new(conf: &'static Conf) -> Self { Self { - prev_span: Span::default(), + lint_point: Default::default(), msrv: conf.msrv, } } + + fn lint_if_finish(&mut self, cx: &LateContext<'_>, (span, item): (Span, Option<LintPoint>)) { + if span.source_equal(self.lint_point.0) { + return; + } + + if !self.lint_point.0.is_dummy() { + emit_lints(cx, &self.lint_point); + } + + self.lint_point = (span, item); + } } impl_lint_pass!(StdReexports => [STD_INSTEAD_OF_CORE, STD_INSTEAD_OF_ALLOC, ALLOC_INSTEAD_OF_CORE]); +type LintPoint = (&'static Lint, &'static str, &'static str); + impl<'tcx> LateLintPass<'tcx> for StdReexports { fn check_path(&mut self, cx: &LateContext<'tcx>, path: &Path<'tcx>, _: HirId) { if let Res::Def(_, def_id) = path.res @@ -119,7 +130,7 @@ impl<'tcx> LateLintPass<'tcx> for StdReexports { sym::core => (STD_INSTEAD_OF_CORE, "std", "core"), sym::alloc => (STD_INSTEAD_OF_ALLOC, "std", "alloc"), _ => { - self.prev_span = first_segment.ident.span; + self.lint_if_finish(cx, (first_segment.ident.span, None)); return; }, }, @@ -127,32 +138,44 @@ impl<'tcx> LateLintPass<'tcx> for StdReexports { if cx.tcx.crate_name(def_id.krate) == sym::core { (ALLOC_INSTEAD_OF_CORE, "alloc", "core") } else { - self.prev_span = first_segment.ident.span; + self.lint_if_finish(cx, (first_segment.ident.span, None)); return; } }, _ => return, }; - if first_segment.ident.span != self.prev_span { - #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")] - span_lint_and_then( - cx, - lint, - first_segment.ident.span, - format!("used import from `{used_mod}` instead of `{replace_with}`"), - |diag| { - diag.span_suggestion( - first_segment.ident.span, - format!("consider importing the item from `{replace_with}`"), - replace_with.to_string(), - Applicability::MachineApplicable, - ); - }, - ); - self.prev_span = first_segment.ident.span; - } + + self.lint_if_finish(cx, (first_segment.ident.span, Some((lint, used_mod, replace_with)))); } } + + fn check_block_post(&mut self, cx: &LateContext<'tcx>, _: &Block<'tcx>) { + self.lint_if_finish(cx, Default::default()); + } + + fn check_body_post(&mut self, cx: &LateContext<'tcx>, _: &Body<'tcx>) { + self.lint_if_finish(cx, Default::default()); + } + + fn check_crate_post(&mut self, cx: &LateContext<'tcx>) { + self.lint_if_finish(cx, Default::default()); + } +} + +fn emit_lints(cx: &LateContext<'_>, (span, item): &(Span, Option<LintPoint>)) { + let Some((lint, used_mod, replace_with)) = item else { + return; + }; + + span_lint_and_sugg( + cx, + lint, + *span, + format!("used import from `{used_mod}` instead of `{replace_with}`"), + format!("consider importing the item from `{replace_with}`"), + (*replace_with).to_string(), + Applicability::MachineApplicable, + ); } /// Returns the first named segment of a [`Path`]. diff --git a/src/tools/clippy/clippy_lints/src/strings.rs b/src/tools/clippy/clippy_lints/src/strings.rs index 73a9fe71e00..1cda6f596f4 100644 --- a/src/tools/clippy/clippy_lints/src/strings.rs +++ b/src/tools/clippy/clippy_lints/src/strings.rs @@ -560,7 +560,7 @@ impl<'tcx> LateLintPass<'tcx> for TrimSplitWhitespace { && 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 - && let trim_fn_name @ ("trim" | "trim_start" | "trim_end") = path.ident.name.as_str() + && let trim_fn_name @ (sym::trim | sym::trim_start | sym::trim_end) = path.ident.name && let Some(trim_def_id) = tyckres.type_dependent_def_id(split_recv.hir_id) && is_one_of_trim_diagnostic_items(cx, trim_def_id) { diff --git a/src/tools/clippy/clippy_lints/src/swap.rs b/src/tools/clippy/clippy_lints/src/swap.rs index e3ecd6508bf..5ecbb56925e 100644 --- a/src/tools/clippy/clippy_lints/src/swap.rs +++ b/src/tools/clippy/clippy_lints/src/swap.rs @@ -3,7 +3,7 @@ use clippy_utils::source::{snippet_indent, snippet_with_context}; use clippy_utils::sugg::Sugg; use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{can_mut_borrow_both, eq_expr_value, is_in_const_context, std_or_core}; +use clippy_utils::{can_mut_borrow_both, eq_expr_value, is_in_const_context, path_to_local, std_or_core}; use itertools::Itertools; use rustc_data_structures::fx::FxIndexSet; @@ -350,12 +350,21 @@ impl<'tcx> IndexBinding<'_, 'tcx> { format!("{lhs_snippet}{rhs_snippet}") }, ExprKind::Path(QPath::Resolved(_, path)) => { - let init = self.cx.expr_or_init(expr); - let Some(first_segment) = path.segments.first() else { return String::new(); }; - if !self.suggest_span.contains(init.span) || !self.is_used_other_than_swapping(first_segment.ident) { + + let init = self.cx.expr_or_init(expr); + + // We skip suggesting a variable binding in any of these cases: + // - Variable initialization is outside the suggestion span + // - Variable declaration is outside the suggestion span + // - Variable is not used as an index or elsewhere later + if !self.suggest_span.contains(init.span) + || path_to_local(expr) + .is_some_and(|hir_id| !self.suggest_span.contains(self.cx.tcx.hir_span(hir_id))) + || !self.is_used_other_than_swapping(first_segment.ident) + { return String::new(); } diff --git a/src/tools/clippy/clippy_lints/src/transmute/missing_transmute_annotations.rs b/src/tools/clippy/clippy_lints/src/transmute/missing_transmute_annotations.rs index 96286fcf73d..08f36a2ed5d 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/missing_transmute_annotations.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/missing_transmute_annotations.rs @@ -74,7 +74,7 @@ pub(super) fn check<'tcx>( last.ident.span.with_hi(path.span.hi()), "transmute used without annotations", "consider adding missing annotations", - format!("{}::<{from_ty}, {to_ty}>", last.ident.as_str()), + format!("{}::<{from_ty}, {to_ty}>", last.ident), Applicability::MaybeIncorrect, ); true diff --git a/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs b/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs index 004ad03e708..4b23367645e 100644 --- a/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs +++ b/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs @@ -33,7 +33,7 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, lt: &Lifetime, m let ltopt = if lt.is_anonymous() { String::new() } else { - format!("{} ", lt.ident.as_str()) + format!("{} ", lt.ident) }; if mut_ty.mutbl == Mutability::Mut { diff --git a/src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs b/src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs index 019ae16ca85..ae6d8a1c1aa 100644 --- a/src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs +++ b/src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs @@ -1,9 +1,14 @@ +use std::iter; + use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::is_from_proc_macro; -use clippy_utils::source::{SourceText, SpanRangeExt, indent_of, reindent_multiline}; +use clippy_utils::source::{SpanRangeExt, indent_of, reindent_multiline}; +use clippy_utils::sugg::Sugg; +use clippy_utils::ty::expr_type_is_certain; +use clippy_utils::{is_expr_default, is_from_proc_macro}; use rustc_errors::Applicability; use rustc_hir::{Block, Expr, ExprKind, MatchSource, Node, StmtKind}; use rustc_lint::LateContext; +use rustc_span::SyntaxContext; use super::{UNIT_ARG, utils}; @@ -59,7 +64,7 @@ fn is_questionmark_desugar_marked_call(expr: &Expr<'_>) -> bool { } } -fn lint_unit_args(cx: &LateContext<'_>, expr: &Expr<'_>, args_to_recover: &[&Expr<'_>]) { +fn lint_unit_args<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, args_to_recover: &[&'tcx Expr<'tcx>]) { let mut applicability = Applicability::MachineApplicable; let (singular, plural) = if args_to_recover.len() > 1 { ("", "s") @@ -100,34 +105,41 @@ fn lint_unit_args(cx: &LateContext<'_>, expr: &Expr<'_>, args_to_recover: &[&Exp let arg_snippets: Vec<_> = args_to_recover .iter() - .filter_map(|arg| arg.span.get_source_text(cx)) + // If the argument is from an expansion and is a `Default::default()`, we skip it + .filter(|arg| !arg.span.from_expansion() || !is_expr_default_nested(cx, arg)) + .filter_map(|arg| get_expr_snippet(cx, arg)) .collect(); - let arg_snippets_without_empty_blocks: Vec<_> = args_to_recover + + // If the argument is an empty block or `Default::default()`, we can replace it with `()`. + let arg_snippets_without_redundant_exprs: Vec<_> = args_to_recover .iter() - .filter(|arg| !is_empty_block(arg)) - .filter_map(|arg| arg.span.get_source_text(cx)) + .filter(|arg| !is_expr_default_nested(cx, arg) && (arg.span.from_expansion() || !is_empty_block(arg))) + .filter_map(|arg| get_expr_snippet_with_type_certainty(cx, arg)) .collect(); if let Some(call_snippet) = expr.span.get_source_text(cx) { - let sugg = fmt_stmts_and_call( - cx, - expr, - &call_snippet, - &arg_snippets, - &arg_snippets_without_empty_blocks, - ); - - if arg_snippets_without_empty_blocks.is_empty() { + if arg_snippets_without_redundant_exprs.is_empty() + && let suggestions = args_to_recover + .iter() + .filter(|arg| !arg.span.from_expansion() || !is_expr_default_nested(cx, arg)) + .map(|arg| (arg.span.parent_callsite().unwrap_or(arg.span), "()".to_string())) + .collect::<Vec<_>>() + && !suggestions.is_empty() + { db.multipart_suggestion( format!("use {singular}unit literal{plural} instead"), - args_to_recover - .iter() - .map(|arg| (arg.span, "()".to_string())) - .collect::<Vec<_>>(), + suggestions, applicability, ); } else { - let plural = arg_snippets_without_empty_blocks.len() > 1; + let plural = arg_snippets_without_redundant_exprs.len() > 1; + let sugg = fmt_stmts_and_call( + cx, + expr, + &call_snippet, + arg_snippets, + arg_snippets_without_redundant_exprs, + ); let empty_or_s = if plural { "s" } else { "" }; let it_or_them = if plural { "them" } else { "it" }; db.span_suggestion( @@ -144,6 +156,55 @@ fn lint_unit_args(cx: &LateContext<'_>, expr: &Expr<'_>, args_to_recover: &[&Exp ); } +fn is_expr_default_nested<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool { + is_expr_default(cx, expr) + || matches!(expr.kind, ExprKind::Block(block, _) + if block.expr.is_some() && is_expr_default_nested(cx, block.expr.unwrap())) +} + +enum MaybeTypeUncertain<'tcx> { + Certain(Sugg<'tcx>), + Uncertain(Sugg<'tcx>), +} + +impl From<MaybeTypeUncertain<'_>> for String { + fn from(value: MaybeTypeUncertain<'_>) -> Self { + match value { + MaybeTypeUncertain::Certain(sugg) => sugg.to_string(), + MaybeTypeUncertain::Uncertain(sugg) => format!("let _: () = {sugg}"), + } + } +} + +fn get_expr_snippet<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option<Sugg<'tcx>> { + let mut app = Applicability::MachineApplicable; + let snip = Sugg::hir_with_context(cx, expr, SyntaxContext::root(), "..", &mut app); + if app != Applicability::MachineApplicable { + return None; + } + + Some(snip) +} + +fn get_expr_snippet_with_type_certainty<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'tcx>, +) -> Option<MaybeTypeUncertain<'tcx>> { + get_expr_snippet(cx, expr).map(|snip| { + // If the type of the expression is certain, we can use it directly. + // Otherwise, we wrap it in a `let _: () = ...` to ensure the type is correct. + if !expr_type_is_certain(cx, expr) && !is_block_with_no_expr(expr) { + MaybeTypeUncertain::Uncertain(snip) + } else { + MaybeTypeUncertain::Certain(snip) + } + }) +} + +fn is_block_with_no_expr(expr: &Expr<'_>) -> bool { + matches!(expr.kind, ExprKind::Block(Block { expr: None, .. }, _)) +} + fn is_empty_block(expr: &Expr<'_>) -> bool { matches!( expr.kind, @@ -162,23 +223,20 @@ fn fmt_stmts_and_call( cx: &LateContext<'_>, call_expr: &Expr<'_>, call_snippet: &str, - args_snippets: &[SourceText], - non_empty_block_args_snippets: &[SourceText], + args_snippets: Vec<Sugg<'_>>, + non_empty_block_args_snippets: Vec<MaybeTypeUncertain<'_>>, ) -> String { let call_expr_indent = indent_of(cx, call_expr.span).unwrap_or(0); - let call_snippet_with_replacements = args_snippets - .iter() - .fold(call_snippet.to_owned(), |acc, arg| acc.replacen(arg.as_ref(), "()", 1)); + let call_snippet_with_replacements = args_snippets.into_iter().fold(call_snippet.to_owned(), |acc, arg| { + acc.replacen(&arg.to_string(), "()", 1) + }); - let mut stmts_and_call = non_empty_block_args_snippets - .iter() - .map(|it| it.as_ref().to_owned()) - .collect::<Vec<_>>(); - stmts_and_call.push(call_snippet_with_replacements); - stmts_and_call = stmts_and_call + let stmts_and_call = non_empty_block_args_snippets .into_iter() + .map(Into::into) + .chain(iter::once(call_snippet_with_replacements)) .map(|v| reindent_multiline(&v, true, Some(call_expr_indent))) - .collect(); + .collect::<Vec<_>>(); let mut stmts_and_call_snippet = stmts_and_call.join(&format!("{}{}", ";\n", " ".repeat(call_expr_indent))); // expr is not in a block statement or result expression position, wrap in a block diff --git a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs index 5e1cb9e54f5..12cc1093899 100644 --- a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs +++ b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs @@ -1,11 +1,11 @@ use clippy_utils::diagnostics::span_lint_hir_and_then; use clippy_utils::macros::{is_panic, root_macro_call_first_node}; -use clippy_utils::{is_res_lang_ctor, paths, peel_blocks}; +use clippy_utils::{is_res_lang_ctor, paths, peel_blocks, sym}; use hir::{ExprKind, HirId, PatKind}; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::{Span, sym}; +use rustc_span::Span; declare_clippy_lint! { /// ### What it does @@ -232,8 +232,16 @@ fn is_unreachable_or_panic(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { fn unpack_call_chain<'a>(mut expr: &'a hir::Expr<'a>) -> &'a hir::Expr<'a> { while let ExprKind::MethodCall(path, receiver, ..) = expr.kind { if matches!( - path.ident.as_str(), - "unwrap" | "expect" | "unwrap_or" | "unwrap_or_else" | "ok" | "is_ok" | "is_err" | "or_else" | "or" + path.ident.name, + sym::unwrap + | sym::expect + | sym::unwrap_or + | sym::unwrap_or_else + | sym::ok + | sym::is_ok + | sym::is_err + | sym::or_else + | sym::or ) { expr = receiver; } else { diff --git a/src/tools/clippy/clippy_lints/src/unused_result_ok.rs b/src/tools/clippy/clippy_lints/src/unused_result_ok.rs index 958f19d1833..f5ed10fb760 100644 --- a/src/tools/clippy/clippy_lints/src/unused_result_ok.rs +++ b/src/tools/clippy/clippy_lints/src/unused_result_ok.rs @@ -1,11 +1,11 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_context; +use clippy_utils::sym; use clippy_utils::ty::is_type_diagnostic_item; use rustc_errors::Applicability; use rustc_hir::{ExprKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::declare_lint_pass; -use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -36,7 +36,7 @@ impl LateLintPass<'_> for UnusedResultOk { fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &Stmt<'_>) { if let StmtKind::Semi(expr) = stmt.kind && let ExprKind::MethodCall(ok_path, recv, [], ..) = expr.kind //check is expr.ok() has type Result<T,E>.ok(, _) - && ok_path.ident.as_str() == "ok" + && ok_path.ident.name == sym::ok && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result) && !stmt.span.in_external_macro(cx.sess().source_map()) { diff --git a/src/tools/clippy/clippy_lints/src/unused_unit.rs b/src/tools/clippy/clippy_lints/src/unused_unit.rs index 9859ddfdf7b..3811f0fe6b5 100644 --- a/src/tools/clippy/clippy_lints/src/unused_unit.rs +++ b/src/tools/clippy/clippy_lints/src/unused_unit.rs @@ -100,7 +100,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedUnit { let segments = &poly.trait_ref.path.segments; if segments.len() == 1 - && ["Fn", "FnMut", "FnOnce"].contains(&segments[0].ident.name.as_str()) + && matches!(segments[0].ident.name, sym::Fn | sym::FnMut | sym::FnOnce) && let Some(args) = segments[0].args && args.parenthesized == GenericArgsParentheses::ParenSugar && let constraints = &args.constraints @@ -109,6 +109,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedUnit { && let AssocItemConstraintKind::Equality { term: Term::Ty(hir_ty) } = constraints[0].kind && args.span_ext.hi() != poly.span.hi() && !hir_ty.span.from_expansion() + && args.span_ext.hi() != hir_ty.span.hi() && is_unit_ty(hir_ty) { lint_unneeded_unit_return(cx, hir_ty.span, poly.span); diff --git a/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs b/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs index 3c23662e9d1..8d873536295 100644 --- a/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs +++ b/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::higher::{VecInitKind, get_vec_init_kind}; use clippy_utils::source::snippet; use clippy_utils::visitors::for_each_local_use_after_expr; -use clippy_utils::{get_parent_expr, path_to_local_id}; +use clippy_utils::{get_parent_expr, path_to_local_id, sym}; use core::ops::ControlFlow; use rustc_errors::Applicability; use rustc_hir::def::Res; @@ -202,7 +202,7 @@ impl<'tcx> LateLintPass<'tcx> for VecInitThenPush { if let StmtKind::Expr(expr) | StmtKind::Semi(expr) = stmt.kind && let ExprKind::MethodCall(name, self_arg, [_], _) = expr.kind && path_to_local_id(self_arg, searcher.local_id) - && name.ident.as_str() == "push" + && name.ident.name == sym::push { self.searcher = Some(VecPushSearcher { err_span: searcher.err_span.to(stmt.span), diff --git a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs index 467811c586b..d9dda6eadb2 100644 --- a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs +++ b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs @@ -9,8 +9,8 @@ use rustc_hir::{Item, ItemKind, PathSegment, UseKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::ty; use rustc_session::impl_lint_pass; +use rustc_span::BytePos; use rustc_span::symbol::kw; -use rustc_span::{BytePos, sym}; declare_clippy_lint! { /// ### What it does @@ -193,9 +193,7 @@ impl WildcardImports { // Allow "...prelude::..::*" imports. // Many crates have a prelude, and it is imported as a glob by design. fn is_prelude_import(segments: &[PathSegment<'_>]) -> bool { - segments - .iter() - .any(|ps| ps.ident.as_str().contains(sym::prelude.as_str())) + segments.iter().any(|ps| ps.ident.as_str().contains("prelude")) } // Allow "super::*" imports in tests. diff --git a/src/tools/clippy/clippy_lints/src/write.rs b/src/tools/clippy/clippy_lints/src/write.rs index a8758b65c91..d9a007635ca 100644 --- a/src/tools/clippy/clippy_lints/src/write.rs +++ b/src/tools/clippy/clippy_lints/src/write.rs @@ -5,8 +5,8 @@ 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, - FormatTrait, + FormatArgPosition, FormatArgPositionKind, FormatArgs, FormatArgsPiece, FormatCount, FormatOptions, + FormatPlaceholder, FormatTrait, }; use rustc_errors::Applicability; use rustc_hir::{Expr, Impl, Item, ItemKind}; @@ -556,12 +556,7 @@ fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgs, name: &str) { // Decrement the index of the remaining by the number of replaced positional arguments if !suggestion.is_empty() { for piece in &format_args.template { - if let Some((span, index)) = positional_arg_piece_span(piece) - && suggestion.iter().all(|(s, _)| *s != span) - { - let decrement = replaced_position.iter().filter(|i| **i < index).count(); - suggestion.push((span, format!("{{{}}}", index.saturating_sub(decrement)))); - } + relocalize_format_args_indexes(piece, &mut suggestion, &replaced_position); } } @@ -574,7 +569,7 @@ fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgs, name: &str) { } } -/// Extract Span and its index from the given `piece`, iff it's positional argument. +/// Extract Span and its index from the given `piece`, if it's positional argument. fn positional_arg_piece_span(piece: &FormatArgsPiece) -> Option<(Span, usize)> { match piece { FormatArgsPiece::Placeholder(FormatPlaceholder { @@ -591,6 +586,57 @@ fn positional_arg_piece_span(piece: &FormatArgsPiece) -> Option<(Span, usize)> { } } +/// Relocalizes the indexes of positional arguments in the format string +fn relocalize_format_args_indexes( + piece: &FormatArgsPiece, + suggestion: &mut Vec<(Span, String)>, + replaced_position: &[usize], +) { + if let FormatArgsPiece::Placeholder(FormatPlaceholder { + argument: + FormatArgPosition { + index: Ok(index), + // Only consider positional arguments + kind: FormatArgPositionKind::Number, + span: Some(span), + }, + format_options, + .. + }) = piece + { + if suggestion.iter().any(|(s, _)| s.overlaps(*span)) { + // If the span is already in the suggestion, we don't need to process it again + return; + } + + // lambda to get the decremented index based on the replaced positions + let decremented_index = |index: usize| -> usize { + let decrement = replaced_position.iter().filter(|&&i| i < index).count(); + index - decrement + }; + + suggestion.push((*span, decremented_index(*index).to_string())); + + // If there are format options, we need to handle them as well + if *format_options != FormatOptions::default() { + // lambda to process width and precision format counts and add them to the suggestion + let mut process_format_count = |count: &Option<FormatCount>, formatter: &dyn Fn(usize) -> String| { + if let Some(FormatCount::Argument(FormatArgPosition { + index: Ok(format_arg_index), + kind: FormatArgPositionKind::Number, + span: Some(format_arg_span), + })) = count + { + suggestion.push((*format_arg_span, formatter(decremented_index(*format_arg_index)))); + } + }; + + process_format_count(&format_options.width, &|index: usize| format!("{index}$")); + process_format_count(&format_options.precision, &|index: usize| format!(".{index}$")); + } + } +} + /// Removes the raw marker, `#`s and quotes from a str, and returns if the literal is raw /// /// `r#"a"#` -> (`a`, true) diff --git a/src/tools/clippy/clippy_lints/src/zombie_processes.rs b/src/tools/clippy/clippy_lints/src/zombie_processes.rs index 09f1084fe70..6ab94a52210 100644 --- a/src/tools/clippy/clippy_lints/src/zombie_processes.rs +++ b/src/tools/clippy/clippy_lints/src/zombie_processes.rs @@ -5,7 +5,7 @@ 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::intravisit::{Visitor, walk_block, walk_expr}; use rustc_hir::{Expr, ExprKind, HirId, LetStmt, Node, PatKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; @@ -69,8 +69,9 @@ impl<'tcx> LateLintPass<'tcx> for ZombieProcesses { let mut vis = WaitFinder { cx, local_id, + create_id: expr.hir_id, body_id: cx.tcx.hir_enclosing_body_owner(expr.hir_id), - state: VisitorState::WalkUpToLocal, + state: VisitorState::WalkUpToCreate, early_return: None, missing_wait_branch: None, }; @@ -131,6 +132,7 @@ struct MaybeWait(Span); struct WaitFinder<'a, 'tcx> { cx: &'a LateContext<'tcx>, local_id: HirId, + create_id: HirId, body_id: LocalDefId, state: VisitorState, early_return: Option<Span>, @@ -141,8 +143,8 @@ struct WaitFinder<'a, 'tcx> { #[derive(PartialEq)] enum VisitorState { - WalkUpToLocal, - LocalFound, + WalkUpToCreate, + CreateFound, } #[derive(Copy, Clone)] @@ -155,19 +157,13 @@ impl<'tcx> Visitor<'tcx> for WaitFinder<'_, 'tcx> { type NestedFilter = nested_filter::OnlyBodies; type Result = ControlFlow<MaybeWait>; - fn visit_local(&mut self, l: &'tcx LetStmt<'tcx>) -> Self::Result { - if self.state == VisitorState::WalkUpToLocal - && let PatKind::Binding(_, pat_id, ..) = l.pat.kind - && self.local_id == pat_id - { - self.state = VisitorState::LocalFound; + fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) -> Self::Result { + if ex.hir_id == self.create_id { + self.state = VisitorState::CreateFound; + return Continue(()); } - walk_local(self, l) - } - - fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) -> Self::Result { - if self.state != VisitorState::LocalFound { + if self.state != VisitorState::CreateFound { return walk_expr(self, ex); } diff --git a/src/tools/clippy/clippy_lints_internal/src/almost_standard_lint_formulation.rs b/src/tools/clippy/clippy_lints_internal/src/almost_standard_lint_formulation.rs index 311f76fee6b..7eeec84720f 100644 --- a/src/tools/clippy/clippy_lints_internal/src/almost_standard_lint_formulation.rs +++ b/src/tools/clippy/clippy_lints_internal/src/almost_standard_lint_formulation.rs @@ -45,7 +45,7 @@ impl AlmostStandardFormulation { impl<'tcx> LateLintPass<'tcx> for AlmostStandardFormulation { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { let mut check_next = false; - if let ItemKind::Static(_, ty, Mutability::Not, _) = item.kind { + if let ItemKind::Static(Mutability::Not, _, ty, _) = item.kind { let lines = cx .tcx .hir_attrs(item.hir_id()) diff --git a/src/tools/clippy/clippy_lints_internal/src/lint_without_lint_pass.rs b/src/tools/clippy/clippy_lints_internal/src/lint_without_lint_pass.rs index 0edeef3ab85..45a866030b2 100644 --- a/src/tools/clippy/clippy_lints_internal/src/lint_without_lint_pass.rs +++ b/src/tools/clippy/clippy_lints_internal/src/lint_without_lint_pass.rs @@ -105,7 +105,7 @@ impl_lint_pass!(LintWithoutLintPass => [ impl<'tcx> LateLintPass<'tcx> for LintWithoutLintPass { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { - if let hir::ItemKind::Static(ident, ty, Mutability::Not, body_id) = item.kind { + if let hir::ItemKind::Static(Mutability::Not, ident, ty, body_id) = item.kind { if is_lint_ref_type(cx, ty) { check_invalid_clippy_version_attribute(cx, item); diff --git a/src/tools/clippy/clippy_utils/README.md b/src/tools/clippy/clippy_utils/README.md index efbacbd72db..1aa16e3943c 100644 --- a/src/tools/clippy/clippy_utils/README.md +++ b/src/tools/clippy/clippy_utils/README.md @@ -8,7 +8,7 @@ This crate is only guaranteed to build with this `nightly` toolchain: <!-- begin autogenerated nightly --> ``` -nightly-2025-05-31 +nightly-2025-06-12 ``` <!-- end autogenerated nightly --> diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index f6ef638e618..c7a2375c8df 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -1793,10 +1793,9 @@ pub fn in_automatically_derived(tcx: TyCtxt<'_>, id: HirId) -> bool { /// Checks if the given `DefId` matches the `libc` item. pub fn match_libc_symbol(cx: &LateContext<'_>, did: DefId, name: Symbol) -> 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 == sym::libc) && path.last().copied() == Some(name) + cx.tcx.crate_name(did.krate) == sym::libc && cx.tcx.def_path_str(did).ends_with(name.as_str()) } /// Returns the list of condition expressions and the list of blocks in a @@ -3473,3 +3472,15 @@ pub fn desugar_await<'tcx>(expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> { None } } + +/// Checks if the given expression is a call to `Default::default()`. +pub fn is_expr_default<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool { + if let ExprKind::Call(fn_expr, []) = &expr.kind + && let ExprKind::Path(qpath) = &fn_expr.kind + && let Res::Def(_, def_id) = cx.qpath_res(qpath, fn_expr.hir_id) + { + cx.tcx.is_diagnostic_item(sym::default_fn, def_id) + } else { + false + } +} diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs index 8e16f943e9f..e629012b187 100644 --- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs +++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs @@ -18,7 +18,7 @@ use rustc_middle::mir::{ }; use rustc_middle::traits::{BuiltinImplSource, ImplSource, ObligationCause}; use rustc_middle::ty::adjustment::PointerCoercion; -use rustc_middle::ty::{self, GenericArgKind, TraitRef, Ty, TyCtxt}; +use rustc_middle::ty::{self, GenericArgKind, Instance, TraitRef, Ty, TyCtxt}; use rustc_span::Span; use rustc_span::symbol::sym; use rustc_trait_selection::traits::{ObligationCtxt, SelectionContext}; @@ -349,7 +349,15 @@ fn check_terminator<'tcx>( } | TerminatorKind::TailCall { func, args, fn_span: _ } => { let fn_ty = func.ty(body, cx.tcx); - if let ty::FnDef(fn_def_id, _) = *fn_ty.kind() { + if let ty::FnDef(fn_def_id, fn_substs) = fn_ty.kind() { + // FIXME: when analyzing a function with generic parameters, we may not have enough information to + // resolve to an instance. However, we could check if a host effect predicate can guarantee that + // this can be made a `const` call. + let fn_def_id = match Instance::try_resolve(cx.tcx, cx.typing_env(), *fn_def_id, fn_substs) { + Ok(Some(fn_inst)) => fn_inst.def_id(), + Ok(None) => return Err((span, format!("cannot resolve instance for {func:?}").into())), + Err(_) => return Err((span, format!("error during instance resolution of {func:?}").into())), + }; if !is_stable_const_fn(cx, fn_def_id, msrv) { return Err(( span, diff --git a/src/tools/clippy/clippy_utils/src/sym.rs b/src/tools/clippy/clippy_utils/src/sym.rs index f417530be36..3b58dba5628 100644 --- a/src/tools/clippy/clippy_utils/src/sym.rs +++ b/src/tools/clippy/clippy_utils/src/sym.rs @@ -76,7 +76,6 @@ generate! { Visitor, Weak, abs, - align_of, ambiguous_glob_reexports, append, arg, @@ -84,6 +83,7 @@ generate! { as_deref, as_deref_mut, as_mut, + as_path, assert_failed, author, borrow, @@ -121,6 +121,8 @@ generate! { copy_to, copy_to_nonoverlapping, count_ones, + create, + create_new, cycle, cyclomatic_complexity, de, @@ -132,7 +134,6 @@ generate! { enum_glob_use, enumerate, err, - error, exp, expect_err, expn_data, @@ -150,8 +151,11 @@ generate! { floor_char_boundary, fold, for_each, + from_be_bytes, from_bytes_with_nul, from_bytes_with_nul_unchecked, + from_le_bytes, + from_ne_bytes, from_ptr, from_raw, from_ref, @@ -184,8 +188,10 @@ generate! { is_err, is_file, is_none, + is_none_or, is_ok, is_some, + is_some_and, isqrt, itertools, join, @@ -252,9 +258,12 @@ generate! { powi, product, push, + read, + read_exact, read_line, read_to_end, read_to_string, + read_unaligned, redundant_pub_crate, regex, rem_euclid, @@ -323,16 +332,22 @@ generate! { then_some, to_ascii_lowercase, to_ascii_uppercase, + to_be_bytes, to_digit, + to_le_bytes, to_lowercase, + to_ne_bytes, to_os_string, to_owned, to_path_buf, to_uppercase, tokio, trim, + trim_end, trim_end_matches, + trim_start, trim_start_matches, + truncate, unreachable_pub, unsafe_removed_from_name, unused, @@ -347,12 +362,15 @@ generate! { unwrap_unchecked, unzip, utils, + visit_str, + visit_string, wake, warnings, wildcard_imports, with_capacity, wrapping_offset, write, + write_unaligned, writeln, zip, } diff --git a/src/tools/clippy/clippy_utils/src/ty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/mod.rs index 61e70b3fa0b..1f0a0f2b02a 100644 --- a/src/tools/clippy/clippy_utils/src/ty/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ty/mod.rs @@ -1137,21 +1137,38 @@ impl<'tcx> InteriorMut<'tcx> { /// Check if given type has interior mutability such as [`std::cell::Cell`] or /// [`std::cell::RefCell`] etc. and if it does, returns a chain of types that causes - /// this type to be interior mutable + /// this type to be interior mutable. False negatives may be expected for infinitely recursive + /// types, and `None` will be returned there. pub fn interior_mut_ty_chain(&mut self, cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<&'tcx ty::List<Ty<'tcx>>> { + self.interior_mut_ty_chain_inner(cx, ty, 0) + } + + fn interior_mut_ty_chain_inner( + &mut self, + cx: &LateContext<'tcx>, + ty: Ty<'tcx>, + depth: usize, + ) -> Option<&'tcx ty::List<Ty<'tcx>>> { + if !cx.tcx.recursion_limit().value_within_limit(depth) { + return None; + } + match self.tys.entry(ty) { Entry::Occupied(o) => return *o.get(), // Temporarily insert a `None` to break cycles Entry::Vacant(v) => v.insert(None), }; + let depth = depth + 1; let chain = match *ty.kind() { - ty::RawPtr(inner_ty, _) if !self.ignore_pointers => self.interior_mut_ty_chain(cx, inner_ty), - ty::Ref(_, inner_ty, _) | ty::Slice(inner_ty) => self.interior_mut_ty_chain(cx, inner_ty), + ty::RawPtr(inner_ty, _) if !self.ignore_pointers => self.interior_mut_ty_chain_inner(cx, inner_ty, depth), + ty::Ref(_, inner_ty, _) | ty::Slice(inner_ty) => self.interior_mut_ty_chain_inner(cx, inner_ty, depth), ty::Array(inner_ty, size) if size.try_to_target_usize(cx.tcx) != Some(0) => { - self.interior_mut_ty_chain(cx, inner_ty) + self.interior_mut_ty_chain_inner(cx, inner_ty, depth) }, - ty::Tuple(fields) => fields.iter().find_map(|ty| self.interior_mut_ty_chain(cx, ty)), + ty::Tuple(fields) => fields + .iter() + .find_map(|ty| self.interior_mut_ty_chain_inner(cx, ty, depth)), ty::Adt(def, _) if def.is_unsafe_cell() => Some(ty::List::empty()), ty::Adt(def, args) => { let is_std_collection = matches!( @@ -1171,16 +1188,17 @@ impl<'tcx> InteriorMut<'tcx> { if is_std_collection || def.is_box() { // Include the types from std collections that are behind pointers internally - args.types().find_map(|ty| self.interior_mut_ty_chain(cx, ty)) + args.types() + .find_map(|ty| self.interior_mut_ty_chain_inner(cx, ty, depth)) } else if self.ignored_def_ids.contains(&def.did()) || def.is_phantom_data() { None } else { def.all_fields() - .find_map(|f| self.interior_mut_ty_chain(cx, f.ty(cx.tcx, args))) + .find_map(|f| self.interior_mut_ty_chain_inner(cx, f.ty(cx.tcx, args), depth)) } }, ty::Alias(ty::Projection, _) => match cx.tcx.try_normalize_erasing_regions(cx.typing_env(), ty) { - Ok(normalized_ty) if ty != normalized_ty => self.interior_mut_ty_chain(cx, normalized_ty), + Ok(normalized_ty) if ty != normalized_ty => self.interior_mut_ty_chain_inner(cx, normalized_ty, depth), _ => None, }, _ => None, @@ -1342,7 +1360,8 @@ pub fn has_non_owning_mutable_access<'tcx>(cx: &LateContext<'tcx>, iter_ty: Ty<' mutability.is_mut() || !pointee_ty.is_freeze(cx.tcx, cx.typing_env()) }, ty::Closure(_, closure_args) => { - matches!(closure_args.types().next_back(), Some(captures) if has_non_owning_mutable_access_inner(cx, phantoms, captures)) + matches!(closure_args.types().next_back(), + Some(captures) if has_non_owning_mutable_access_inner(cx, phantoms, captures)) }, ty::Tuple(tuple_args) => tuple_args .iter() diff --git a/src/tools/clippy/rust-toolchain.toml b/src/tools/clippy/rust-toolchain.toml index b6817d9a146..3fc5a1224a8 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-05-31" +channel = "nightly-2025-06-12" # end autogenerated nightly components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] profile = "minimal" diff --git a/src/tools/clippy/tests/compile-test.rs b/src/tools/clippy/tests/compile-test.rs index 78b27e2f613..99a01257a7b 100644 --- a/src/tools/clippy/tests/compile-test.rs +++ b/src/tools/clippy/tests/compile-test.rs @@ -273,10 +273,10 @@ fn run_ui_cargo(cx: &TestContext) { config.program.input_file_flag = CommandBuilder::cargo().input_file_flag; config.program.out_dir_flag = CommandBuilder::cargo().out_dir_flag; config.program.args = vec!["clippy".into(), "--color".into(), "never".into(), "--quiet".into()]; - config - .program - .envs - .push(("RUSTFLAGS".into(), Some("-Dwarnings".into()))); + config.program.envs.extend([ + ("RUSTFLAGS".into(), Some("-Dwarnings".into())), + ("CARGO_INCREMENTAL".into(), Some("0".into())), + ]); // We need to do this while we still have a rustc in the `program` field. config.fill_host_and_target().unwrap(); config.program.program.set_file_name(if cfg!(windows) { diff --git a/src/tools/clippy/tests/symbols-used.rs b/src/tools/clippy/tests/symbols-used.rs new file mode 100644 index 00000000000..bc0456711fb --- /dev/null +++ b/src/tools/clippy/tests/symbols-used.rs @@ -0,0 +1,81 @@ +// This test checks that all symbols defined in Clippy's `sym.rs` file +// are used in Clippy. Otherwise, it will fail with a list of symbols +// which are unused. +// +// This test is a no-op if run as part of the compiler test suite +// and will always succeed. + +use std::collections::HashSet; +use std::ffi::OsStr; +use std::fs; + +use regex::Regex; +use walkdir::{DirEntry, WalkDir}; + +const SYM_FILE: &str = "clippy_utils/src/sym.rs"; + +type Result<T, E = AnyError> = std::result::Result<T, E>; +type AnyError = Box<dyn std::error::Error>; + +#[test] +#[allow(clippy::case_sensitive_file_extension_comparisons)] +fn all_symbols_are_used() -> Result<()> { + if option_env!("RUSTC_TEST_SUITE").is_some() { + return Ok(()); + } + + // Load all symbols defined in `SYM_FILE`. + let content = fs::read_to_string(SYM_FILE)?; + let content = content + .split_once("generate! {") + .ok_or("cannot find symbols start")? + .1 + .split_once("\n}\n") + .ok_or("cannot find symbols end")? + .0; + let mut interned: HashSet<String> = Regex::new(r"(?m)^ (\w+)") + .unwrap() + .captures_iter(content) + .map(|m| m[1].to_owned()) + .collect(); + + // Remove symbols used as `sym::*`. + let used_re = Regex::new(r"\bsym::(\w+)\b").unwrap(); + let rs_ext = OsStr::new("rs"); + for dir in ["clippy_lints", "clippy_lints_internal", "clippy_utils", "src"] { + for file in WalkDir::new(dir) + .into_iter() + .flatten() + .map(DirEntry::into_path) + .filter(|p| p.extension() == Some(rs_ext)) + { + for cap in used_re.captures_iter(&fs::read_to_string(file)?) { + interned.remove(&cap[1]); + } + } + } + + // Remove symbols used as part of paths. + let paths_re = Regex::new(r"path!\(([\w:]+)\)").unwrap(); + for path in [ + "clippy_utils/src/paths.rs", + "clippy_lints_internal/src/internal_paths.rs", + ] { + for cap in paths_re.captures_iter(&fs::read_to_string(path)?) { + for sym in cap[1].split("::") { + interned.remove(sym); + } + } + } + + let mut extra = interned.iter().collect::<Vec<_>>(); + if !extra.is_empty() { + extra.sort_unstable(); + eprintln!("Unused symbols defined in {SYM_FILE}:"); + for sym in extra { + eprintln!(" - {sym}"); + } + Err(format!("extra symbols found — remove them {SYM_FILE}"))?; + } + Ok(()) +} diff --git a/src/tools/clippy/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.rs b/src/tools/clippy/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.rs index 6a9a49324db..4a179cd929f 100644 --- a/src/tools/clippy/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.rs +++ b/src/tools/clippy/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.rs @@ -1,4 +1,5 @@ #![warn(clippy::await_holding_invalid_type)] +#![allow(clippy::ip_constant)] use std::net::Ipv4Addr; async fn bad() -> u32 { diff --git a/src/tools/clippy/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.stderr b/src/tools/clippy/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.stderr index deb7f49db9e..c3c88698032 100644 --- a/src/tools/clippy/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.stderr +++ b/src/tools/clippy/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.stderr @@ -1,5 +1,5 @@ error: holding a disallowed type across an await point `std::string::String` - --> tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.rs:5:9 + --> tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.rs:6:9 | LL | let _x = String::from("hello"); | ^^ @@ -9,13 +9,13 @@ LL | let _x = String::from("hello"); = help: to override `-D warnings` add `#[allow(clippy::await_holding_invalid_type)]` error: holding a disallowed type across an await point `std::net::Ipv4Addr` - --> tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.rs:11:9 + --> tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.rs:12:9 | LL | let x = Ipv4Addr::new(127, 0, 0, 1); | ^ error: holding a disallowed type across an await point `std::string::String` - --> tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.rs:35:13 + --> tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.rs:36:13 | LL | let _x = String::from("hi!"); | ^^ diff --git a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.rs b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.rs index 06472a4f5d5..922d30443fc 100644 --- a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.rs +++ b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.rs @@ -239,3 +239,40 @@ fn fp_if_let_issue7054() { } fn main() {} + +mod issue14873 { + fn foo() -> i32 { + todo!() + } + + macro_rules! qux { + ($a:ident, $b:ident, $condition:expr) => { + if $condition { + "." + } else { + "" + }; + $a = foo(); + $b = foo(); + }; + } + + fn share_on_bottom() { + let mut a = 0; + let mut b = 0; + if false { + qux!(a, b, a == b); + } else { + qux!(a, b, a != b); + }; + + if false { + qux!(a, b, a == b); + let y = 1; + } else { + qux!(a, b, a != b); + let y = 1; + //~^ branches_sharing_code + } + } +} diff --git a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.stderr b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.stderr index 648a99c65ed..f437db8b733 100644 --- a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.stderr +++ b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.stderr @@ -157,5 +157,20 @@ LL ~ if x == 17 { b = 1; a = 0x99; } else { } LL + a = 0x99; | -error: aborting due to 9 previous errors +error: all if blocks contain the same code at the end + --> tests/ui/branches_sharing_code/shared_at_bottom.rs:274:9 + | +LL | / let y = 1; +LL | | +LL | | } + | |_________^ + | + = warning: some moved values might need to be renamed to avoid wrong references +help: consider moving these statements after the if + | +LL ~ } +LL + let y = 1; + | + +error: aborting due to 10 previous errors diff --git a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top.rs b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top.rs index 694c67d4c85..dcd77679fc6 100644 --- a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top.rs +++ b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top.rs @@ -124,3 +124,34 @@ fn pf_local_with_inferred_type_issue7053() { } fn main() {} + +mod issue14873 { + fn foo() -> i32 { + todo!() + } + + macro_rules! qux { + ($a:ident, $b:ident, $condition:expr) => { + let $a: i32 = foo(); + let $b: i32 = foo(); + if $condition { "." } else { "" } + }; + } + + fn share_on_top() { + if false { + qux!(a, b, a == b); + } else { + qux!(a, b, a != b); + }; + + if false { + //~^ branches_sharing_code + let x = 1; + qux!(a, b, a == b); + } else { + let x = 1; + qux!(a, b, a != b); + } + } +} diff --git a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top.stderr b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top.stderr index d28e9c7af29..30efb98b3f5 100644 --- a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top.stderr +++ b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top.stderr @@ -125,5 +125,20 @@ note: the lint level is defined here LL | #![deny(clippy::branches_sharing_code, clippy::if_same_then_else)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 7 previous errors +error: all if blocks contain the same code at the start + --> tests/ui/branches_sharing_code/shared_at_top.rs:148:9 + | +LL | / if false { +LL | | +LL | | let x = 1; + | |______________________^ + | + = warning: some moved values might need to be renamed to avoid wrong references +help: consider moving these statements before the if + | +LL ~ let x = 1; +LL + if false { + | + +error: aborting due to 8 previous errors diff --git a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs index 75334f70f1f..e848f0601e3 100644 --- a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs +++ b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs @@ -128,3 +128,42 @@ fn added_note_for_expression_use() -> u32 { } fn main() {} + +mod issue14873 { + fn foo() -> i32 { + todo!() + } + + macro_rules! qux { + ($a:ident, $b:ident, $condition:expr) => { + let mut $a: i32 = foo(); + let mut $b: i32 = foo(); + if $condition { + "." + } else { + "" + }; + $a = foo(); + $b = foo(); + }; + } + + fn share_on_top_and_bottom() { + if false { + qux!(a, b, a == b); + } else { + qux!(a, b, a != b); + }; + + if false { + //~^ branches_sharing_code + let x = 1; + qux!(a, b, a == b); + let y = 1; + } else { + let x = 1; + qux!(a, b, a != b); + let y = 1; + } + } +} diff --git a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top_and_bottom.stderr b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top_and_bottom.stderr index 2200ab45089..40f3453edb9 100644 --- a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top_and_bottom.stderr +++ b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top_and_bottom.stderr @@ -159,5 +159,31 @@ LL ~ } LL + x * 4 | -error: aborting due to 5 previous errors +error: all if blocks contain the same code at both the start and the end + --> tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs:158:9 + | +LL | / if false { +LL | | +LL | | let x = 1; + | |______________________^ + | +note: this code is shared at the end + --> tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs:166:9 + | +LL | / let y = 1; +LL | | } + | |_________^ + = warning: some moved values might need to be renamed to avoid wrong references +help: consider moving these statements before the if + | +LL ~ let x = 1; +LL + if false { + | +help: consider moving these statements after the if + | +LL ~ } +LL + let y = 1; + | + +error: aborting due to 6 previous errors diff --git a/src/tools/clippy/tests/ui/cmp_null.fixed b/src/tools/clippy/tests/ui/cmp_null.fixed index 140ddb10aeb..04b8ec50160 100644 --- a/src/tools/clippy/tests/ui/cmp_null.fixed +++ b/src/tools/clippy/tests/ui/cmp_null.fixed @@ -33,3 +33,9 @@ fn main() { let _ = (x as *const ()).is_null(); //~^ cmp_null } + +fn issue15010() { + let f: *mut i32 = std::ptr::null_mut(); + debug_assert!(!f.is_null()); + //~^ cmp_null +} diff --git a/src/tools/clippy/tests/ui/cmp_null.rs b/src/tools/clippy/tests/ui/cmp_null.rs index 16ed17765da..6f7762e6ae8 100644 --- a/src/tools/clippy/tests/ui/cmp_null.rs +++ b/src/tools/clippy/tests/ui/cmp_null.rs @@ -33,3 +33,9 @@ fn main() { let _ = x as *const () == ptr::null(); //~^ cmp_null } + +fn issue15010() { + let f: *mut i32 = std::ptr::null_mut(); + debug_assert!(f != std::ptr::null_mut()); + //~^ cmp_null +} diff --git a/src/tools/clippy/tests/ui/cmp_null.stderr b/src/tools/clippy/tests/ui/cmp_null.stderr index 6821846d046..8a75b050111 100644 --- a/src/tools/clippy/tests/ui/cmp_null.stderr +++ b/src/tools/clippy/tests/ui/cmp_null.stderr @@ -31,5 +31,11 @@ error: comparing with null is better expressed by the `.is_null()` method LL | let _ = x as *const () == ptr::null(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(x as *const ()).is_null()` -error: aborting due to 5 previous errors +error: comparing with null is better expressed by the `.is_null()` method + --> tests/ui/cmp_null.rs:39:19 + | +LL | debug_assert!(f != std::ptr::null_mut()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `!f.is_null()` + +error: aborting due to 6 previous errors diff --git a/src/tools/clippy/tests/ui/coerce_container_to_any.fixed b/src/tools/clippy/tests/ui/coerce_container_to_any.fixed new file mode 100644 index 00000000000..ae9d3ef9656 --- /dev/null +++ b/src/tools/clippy/tests/ui/coerce_container_to_any.fixed @@ -0,0 +1,26 @@ +#![warn(clippy::coerce_container_to_any)] + +use std::any::Any; + +fn main() { + let x: Box<dyn Any> = Box::new(()); + let ref_x = &x; + + f(&*x); + //~^ coerce_container_to_any + + f(&**ref_x); + //~^ coerce_container_to_any + + let _: &dyn Any = &*x; + //~^ coerce_container_to_any + + f(&42); + f(&Box::new(())); + f(&Box::new(Box::new(()))); + f(&**ref_x); + f(&*x); + let _: &dyn Any = &*x; +} + +fn f(_: &dyn Any) {} diff --git a/src/tools/clippy/tests/ui/coerce_container_to_any.rs b/src/tools/clippy/tests/ui/coerce_container_to_any.rs new file mode 100644 index 00000000000..9948bd48e0d --- /dev/null +++ b/src/tools/clippy/tests/ui/coerce_container_to_any.rs @@ -0,0 +1,26 @@ +#![warn(clippy::coerce_container_to_any)] + +use std::any::Any; + +fn main() { + let x: Box<dyn Any> = Box::new(()); + let ref_x = &x; + + f(&x); + //~^ coerce_container_to_any + + f(ref_x); + //~^ coerce_container_to_any + + let _: &dyn Any = &x; + //~^ coerce_container_to_any + + f(&42); + f(&Box::new(())); + f(&Box::new(Box::new(()))); + f(&**ref_x); + f(&*x); + let _: &dyn Any = &*x; +} + +fn f(_: &dyn Any) {} diff --git a/src/tools/clippy/tests/ui/coerce_container_to_any.stderr b/src/tools/clippy/tests/ui/coerce_container_to_any.stderr new file mode 100644 index 00000000000..00ab77e0ce0 --- /dev/null +++ b/src/tools/clippy/tests/ui/coerce_container_to_any.stderr @@ -0,0 +1,23 @@ +error: coercing `&std::boxed::Box<dyn std::any::Any>` to `&dyn Any` + --> tests/ui/coerce_container_to_any.rs:9:7 + | +LL | f(&x); + | ^^ help: consider dereferencing: `&*x` + | + = note: `-D clippy::coerce-container-to-any` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::coerce_container_to_any)]` + +error: coercing `&std::boxed::Box<dyn std::any::Any>` to `&dyn Any` + --> tests/ui/coerce_container_to_any.rs:12:7 + | +LL | f(ref_x); + | ^^^^^ help: consider dereferencing: `&**ref_x` + +error: coercing `&std::boxed::Box<dyn std::any::Any>` to `&dyn Any` + --> tests/ui/coerce_container_to_any.rs:15:23 + | +LL | let _: &dyn Any = &x; + | ^^ help: consider dereferencing: `&*x` + +error: aborting due to 3 previous errors + diff --git a/src/tools/clippy/tests/ui/crashes/ice-14935.rs b/src/tools/clippy/tests/ui/crashes/ice-14935.rs new file mode 100644 index 00000000000..74cda9aae53 --- /dev/null +++ b/src/tools/clippy/tests/ui/crashes/ice-14935.rs @@ -0,0 +1,27 @@ +//@check-pass +#![warn(clippy::mutable_key_type)] + +use std::marker::PhantomData; + +trait Group { + type ExposantSet: Group; +} + +struct Pow<T: Group> { + exposant: Box<Pow<T::ExposantSet>>, + _p: PhantomData<T>, +} + +impl<T: Group> Pow<T> { + fn is_zero(&self) -> bool { + false + } + fn normalize(&self) { + #[expect(clippy::if_same_then_else)] + if self.is_zero() { + } else if false { + } + } +} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/crashes/ice-9463.rs b/src/tools/clippy/tests/ui/crashes/ice-9463.rs index 93808e0f892..cfa6cdac6fa 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-9463.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-9463.rs @@ -1,8 +1,7 @@ -#![deny(arithmetic_overflow)] +//@check-pass + fn main() { let _x = -1_i32 >> -1; - //~^ ERROR: this arithmetic operation will overflow + #[expect(overflowing_literals)] let _y = 1u32 >> 10000000000000u32; - //~^ ERROR: this arithmetic operation will overflow - //~| ERROR: literal out of range } diff --git a/src/tools/clippy/tests/ui/crashes/ice-9463.stderr b/src/tools/clippy/tests/ui/crashes/ice-9463.stderr deleted file mode 100644 index 9a3a5e444ad..00000000000 --- a/src/tools/clippy/tests/ui/crashes/ice-9463.stderr +++ /dev/null @@ -1,29 +0,0 @@ -error: this arithmetic operation will overflow - --> tests/ui/crashes/ice-9463.rs:3:14 - | -LL | let _x = -1_i32 >> -1; - | ^^^^^^^^^^^^ attempt to shift right by `-1_i32`, which would overflow - | -note: the lint level is defined here - --> tests/ui/crashes/ice-9463.rs:1:9 - | -LL | #![deny(arithmetic_overflow)] - | ^^^^^^^^^^^^^^^^^^^ - -error: this arithmetic operation will overflow - --> tests/ui/crashes/ice-9463.rs:5:14 - | -LL | let _y = 1u32 >> 10000000000000u32; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to shift right by `1316134912_u32`, which would overflow - -error: literal out of range for `u32` - --> tests/ui/crashes/ice-9463.rs:5:22 - | -LL | let _y = 1u32 >> 10000000000000u32; - | ^^^^^^^^^^^^^^^^^ - | - = note: the literal `10000000000000u32` does not fit into the type `u32` whose range is `0..=4294967295` - = note: `#[deny(overflowing_literals)]` on by default - -error: aborting due to 3 previous errors - diff --git a/src/tools/clippy/tests/ui/crashes/ice-rust-107877.rs b/src/tools/clippy/tests/ui/crashes/ice-rust-107877.rs index 55fe418bed1..dccb0cf8ac1 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-rust-107877.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-rust-107877.rs @@ -4,6 +4,7 @@ struct Foo; +#[allow(clippy::infallible_try_from)] impl<'a> std::convert::TryFrom<&'a String> for Foo { type Error = std::convert::Infallible; diff --git a/src/tools/clippy/tests/ui/create_dir.fixed b/src/tools/clippy/tests/ui/create_dir.fixed index 4a5b1b77be6..d4b8f8b4d07 100644 --- a/src/tools/clippy/tests/ui/create_dir.fixed +++ b/src/tools/clippy/tests/ui/create_dir.fixed @@ -7,12 +7,31 @@ fn create_dir() {} fn main() { // Should be warned - create_dir_all("foo"); + std::fs::create_dir_all("foo"); //~^ create_dir - create_dir_all("bar").unwrap(); + std::fs::create_dir_all("bar").unwrap(); //~^ create_dir // Shouldn't be warned create_dir(); std::fs::create_dir_all("foobar"); } + +mod issue14994 { + fn with_no_prefix() { + use std::fs::create_dir; + std::fs::create_dir_all("some/dir").unwrap(); + //~^ create_dir + } + + fn with_fs_prefix() { + use std::fs; + fs::create_dir_all("/some/dir").unwrap(); + //~^ create_dir + } + + fn with_full_prefix() { + std::fs::create_dir_all("/some/dir").unwrap(); + //~^ create_dir + } +} diff --git a/src/tools/clippy/tests/ui/create_dir.rs b/src/tools/clippy/tests/ui/create_dir.rs index bf185ba3a7c..21e0bdba03b 100644 --- a/src/tools/clippy/tests/ui/create_dir.rs +++ b/src/tools/clippy/tests/ui/create_dir.rs @@ -16,3 +16,22 @@ fn main() { create_dir(); std::fs::create_dir_all("foobar"); } + +mod issue14994 { + fn with_no_prefix() { + use std::fs::create_dir; + create_dir("some/dir").unwrap(); + //~^ create_dir + } + + fn with_fs_prefix() { + use std::fs; + fs::create_dir("/some/dir").unwrap(); + //~^ create_dir + } + + fn with_full_prefix() { + std::fs::create_dir("/some/dir").unwrap(); + //~^ create_dir + } +} diff --git a/src/tools/clippy/tests/ui/create_dir.stderr b/src/tools/clippy/tests/ui/create_dir.stderr index 51d6ac686e0..e3ca0e7255c 100644 --- a/src/tools/clippy/tests/ui/create_dir.stderr +++ b/src/tools/clippy/tests/ui/create_dir.stderr @@ -8,9 +8,8 @@ LL | std::fs::create_dir("foo"); = help: to override `-D warnings` add `#[allow(clippy::create_dir)]` help: consider calling `std::fs::create_dir_all` instead | -LL - std::fs::create_dir("foo"); -LL + create_dir_all("foo"); - | +LL | std::fs::create_dir_all("foo"); + | ++++ error: calling `std::fs::create_dir` where there may be a better way --> tests/ui/create_dir.rs:12:5 @@ -20,9 +19,41 @@ LL | std::fs::create_dir("bar").unwrap(); | help: consider calling `std::fs::create_dir_all` instead | -LL - std::fs::create_dir("bar").unwrap(); -LL + create_dir_all("bar").unwrap(); +LL | std::fs::create_dir_all("bar").unwrap(); + | ++++ + +error: calling `std::fs::create_dir` where there may be a better way + --> tests/ui/create_dir.rs:23:9 + | +LL | create_dir("some/dir").unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider calling `std::fs::create_dir_all` instead + | +LL | std::fs::create_dir_all("some/dir").unwrap(); + | +++++++++ ++++ + +error: calling `std::fs::create_dir` where there may be a better way + --> tests/ui/create_dir.rs:29:9 + | +LL | fs::create_dir("/some/dir").unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider calling `std::fs::create_dir_all` instead + | +LL | fs::create_dir_all("/some/dir").unwrap(); + | ++++ + +error: calling `std::fs::create_dir` where there may be a better way + --> tests/ui/create_dir.rs:34:9 + | +LL | std::fs::create_dir("/some/dir").unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider calling `std::fs::create_dir_all` instead | +LL | std::fs::create_dir_all("/some/dir").unwrap(); + | ++++ -error: aborting due to 2 previous errors +error: aborting due to 5 previous errors diff --git a/src/tools/clippy/tests/ui/disallowed_names.rs b/src/tools/clippy/tests/ui/disallowed_names.rs index 30fbdbc1fdc..15bb6734997 100644 --- a/src/tools/clippy/tests/ui/disallowed_names.rs +++ b/src/tools/clippy/tests/ui/disallowed_names.rs @@ -1,3 +1,4 @@ +//@aux-build:proc_macros.rs #![allow( dead_code, clippy::needless_if, @@ -9,6 +10,9 @@ )] #![warn(clippy::disallowed_names)] +extern crate proc_macros; +use proc_macros::{external, with_span}; + fn test(foo: ()) {} //~^ disallowed_names @@ -66,6 +70,17 @@ fn issue_1647_ref_mut() { //~^ disallowed_names } +pub fn issue_14958_proc_macro() { + // does not lint macro-generated code + external! { + let foo = 0; + } + with_span! { + span + let foo = 0; + } +} + #[cfg(test)] mod tests { fn issue_7305() { diff --git a/src/tools/clippy/tests/ui/disallowed_names.stderr b/src/tools/clippy/tests/ui/disallowed_names.stderr index 09398ebbab7..b43d1b3ebfa 100644 --- a/src/tools/clippy/tests/ui/disallowed_names.stderr +++ b/src/tools/clippy/tests/ui/disallowed_names.stderr @@ -1,5 +1,5 @@ error: use of a disallowed/placeholder name `foo` - --> tests/ui/disallowed_names.rs:12:9 + --> tests/ui/disallowed_names.rs:16:9 | LL | fn test(foo: ()) {} | ^^^ @@ -8,79 +8,79 @@ LL | fn test(foo: ()) {} = help: to override `-D warnings` add `#[allow(clippy::disallowed_names)]` error: use of a disallowed/placeholder name `foo` - --> tests/ui/disallowed_names.rs:16:9 + --> tests/ui/disallowed_names.rs:20:9 | LL | let foo = 42; | ^^^ error: use of a disallowed/placeholder name `baz` - --> tests/ui/disallowed_names.rs:19:9 + --> tests/ui/disallowed_names.rs:23:9 | LL | let baz = 42; | ^^^ error: use of a disallowed/placeholder name `quux` - --> tests/ui/disallowed_names.rs:22:9 + --> tests/ui/disallowed_names.rs:26:9 | LL | let quux = 42; | ^^^^ error: use of a disallowed/placeholder name `foo` - --> tests/ui/disallowed_names.rs:35:10 + --> tests/ui/disallowed_names.rs:39:10 | LL | (foo, Some(baz), quux @ Some(_)) => (), | ^^^ error: use of a disallowed/placeholder name `baz` - --> tests/ui/disallowed_names.rs:35:20 + --> tests/ui/disallowed_names.rs:39:20 | LL | (foo, Some(baz), quux @ Some(_)) => (), | ^^^ error: use of a disallowed/placeholder name `quux` - --> tests/ui/disallowed_names.rs:35:26 + --> tests/ui/disallowed_names.rs:39:26 | LL | (foo, Some(baz), quux @ Some(_)) => (), | ^^^^ error: use of a disallowed/placeholder name `foo` - --> tests/ui/disallowed_names.rs:43:19 + --> tests/ui/disallowed_names.rs:47:19 | LL | fn issue_1647(mut foo: u8) { | ^^^ error: use of a disallowed/placeholder name `baz` - --> tests/ui/disallowed_names.rs:46:13 + --> tests/ui/disallowed_names.rs:50:13 | LL | let mut baz = 0; | ^^^ error: use of a disallowed/placeholder name `quux` - --> tests/ui/disallowed_names.rs:49:21 + --> tests/ui/disallowed_names.rs:53:21 | LL | if let Some(mut quux) = Some(42) {} | ^^^^ error: use of a disallowed/placeholder name `baz` - --> tests/ui/disallowed_names.rs:54:13 + --> tests/ui/disallowed_names.rs:58:13 | LL | let ref baz = 0; | ^^^ error: use of a disallowed/placeholder name `quux` - --> tests/ui/disallowed_names.rs:57:21 + --> tests/ui/disallowed_names.rs:61:21 | LL | if let Some(ref quux) = Some(42) {} | ^^^^ error: use of a disallowed/placeholder name `baz` - --> tests/ui/disallowed_names.rs:62:17 + --> tests/ui/disallowed_names.rs:66:17 | LL | let ref mut baz = 0; | ^^^ error: use of a disallowed/placeholder name `quux` - --> tests/ui/disallowed_names.rs:65:25 + --> tests/ui/disallowed_names.rs:69:25 | LL | if let Some(ref mut quux) = Some(42) {} | ^^^^ diff --git a/src/tools/clippy/tests/ui/doc_suspicious_footnotes.fixed b/src/tools/clippy/tests/ui/doc_suspicious_footnotes.fixed new file mode 100644 index 00000000000..9ed3fd4ef31 --- /dev/null +++ b/src/tools/clippy/tests/ui/doc_suspicious_footnotes.fixed @@ -0,0 +1,186 @@ +#![warn(clippy::doc_suspicious_footnotes)] +#![allow(clippy::needless_raw_string_hashes)] +//! This is not a footnote[^1]. +//! +//! [^1]: <!-- description --> +//~^ doc_suspicious_footnotes +//! +//! This is not a footnote[^either], but it doesn't warn. +//! +//! This is not a footnote\[^1], but it also doesn't warn. +//! +//! This is not a footnote[^1\], but it also doesn't warn. +//! +//! This is not a `footnote[^1]`, but it also doesn't warn. +//! +//! This is a footnote[^2]. +//! +//! [^2]: hello world + +/// This is not a footnote[^1]. +/// +/// [^1]: <!-- description --> +//~^ doc_suspicious_footnotes +/// +/// This is not a footnote[^either], but it doesn't warn. +/// +/// This is not a footnote\[^1], but it also doesn't warn. +/// +/// This is not a footnote[^1\], but it also doesn't warn. +/// +/// This is not a `footnote[^1]`, but it also doesn't warn. +/// +/// This is a footnote[^2]. +/// +/// [^2]: hello world +pub fn footnotes() { + // test code goes here +} + +pub struct Foo; +#[rustfmt::skip] +impl Foo { + #[doc = r#"This is not a footnote[^1]. + +[^1]: <!-- description -->"#] + //~^ doc_suspicious_footnotes + #[doc = r#""#] + #[doc = r#"This is not a footnote[^either], but it doesn't warn."#] + #[doc = r#""#] + #[doc = r#"This is not a footnote\[^1], but it also doesn't warn."#] + #[doc = r#""#] + #[doc = r#"This is not a footnote[^1\], but it also doesn't warn."#] + #[doc = r#""#] + #[doc = r#"This is not a `footnote[^1]`, but it also doesn't warn."#] + #[doc = r#""#] + #[doc = r#"This is a footnote[^2]."#] + #[doc = r#""#] + #[doc = r#"[^2]: hello world"#] + pub fn footnotes() { + // test code goes here + } + #[doc = r#"This is not a footnote[^1]. + + This is not a footnote[^either], but it doesn't warn. + + This is not a footnote\[^1], but it also doesn't warn. + + This is not a footnote[^1\], but it also doesn't warn. + + This is not a `footnote[^1]`, but it also doesn't warn. + + This is a footnote[^2]. + + [^2]: hello world + + +[^1]: <!-- description -->"#] + //~^^^^^^^^^^^^^^ doc_suspicious_footnotes + pub fn footnotes2() { + // test code goes here + } + #[cfg_attr( + not(FALSE), + doc = r#"This is not a footnote[^1]. + +This is not a footnote[^either], but it doesn't warn. + +[^1]: <!-- description -->"# + //~^ doc_suspicious_footnotes + )] + pub fn footnotes3() { + // test code goes here + } + #[doc = "My footnote [^foot\note]"] + pub fn footnote4() { + // test code goes here + } + #[doc = "Hihi"]pub fn footnote5() { + // test code goes here + } +} + +#[doc = r#"This is not a footnote[^1]. + +[^1]: <!-- description -->"#] +//~^ doc_suspicious_footnotes +#[doc = r""] +#[doc = r"This is not a footnote[^either], but it doesn't warn."] +#[doc = r""] +#[doc = r"This is not a footnote\[^1], but it also doesn't warn."] +#[doc = r""] +#[doc = r"This is not a footnote[^1\], but it also doesn't warn."] +#[doc = r""] +#[doc = r"This is not a `footnote[^1]`, but it also doesn't warn."] +#[doc = r""] +#[doc = r"This is a footnote[^2]."] +#[doc = r""] +#[doc = r"[^2]: hello world"] +pub fn footnotes_attrs() { + // test code goes here +} + +pub mod multiline { + /*! + * This is not a footnote[^1]. //~ doc_suspicious_footnotes + * + * This is not a footnote\[^1], but it doesn't warn. + * + * This is a footnote[^2]. + * + * These give weird results, but correct ones, so it works. + * + * [^2]: hello world + */ +/*! [^1]: <!-- description --> */ + /** + * This is not a footnote[^1]. //~ doc_suspicious_footnotes + * + * This is not a footnote\[^1], but it doesn't warn. + * + * This is a footnote[^2]. + * + * These give weird results, but correct ones, so it works. + * + * [^2]: hello world + */ +/** [^1]: <!-- description --> */ + pub fn foo() {} +} + +/// This is not a footnote [^1] +/// +/// [^1]: <!-- description --> +//~^ doc_suspicious_footnotes +/// +/// This one is [^2] +/// +/// [^2]: contents +#[doc = r#"This is not a footnote [^3] + +[^3]: <!-- description -->"#] +//~^ doc_suspicious_footnotes +#[doc = ""] +#[doc = "This one is [^4]"] +#[doc = ""] +#[doc = "[^4]: contents"] +pub struct MultiFragmentFootnote; + +#[doc(inline)] +/// This is not a footnote [^5] +/// +/// [^5]: <!-- description --> +//~^ doc_suspicious_footnotes +/// +/// This one is [^6] +/// +/// [^6]: contents +#[doc = r#"This is not a footnote [^7] + +[^7]: <!-- description -->"#] +//~^ doc_suspicious_footnotes +#[doc = ""] +#[doc = "This one is [^8]"] +#[doc = ""] +#[doc = "[^8]: contents"] +pub use MultiFragmentFootnote as OtherInlinedFootnote; diff --git a/src/tools/clippy/tests/ui/doc_suspicious_footnotes.rs b/src/tools/clippy/tests/ui/doc_suspicious_footnotes.rs new file mode 100644 index 00000000000..9a8d0dcf475 --- /dev/null +++ b/src/tools/clippy/tests/ui/doc_suspicious_footnotes.rs @@ -0,0 +1,162 @@ +#![warn(clippy::doc_suspicious_footnotes)] +#![allow(clippy::needless_raw_string_hashes)] +//! This is not a footnote[^1]. +//~^ doc_suspicious_footnotes +//! +//! This is not a footnote[^either], but it doesn't warn. +//! +//! This is not a footnote\[^1], but it also doesn't warn. +//! +//! This is not a footnote[^1\], but it also doesn't warn. +//! +//! This is not a `footnote[^1]`, but it also doesn't warn. +//! +//! This is a footnote[^2]. +//! +//! [^2]: hello world + +/// This is not a footnote[^1]. +//~^ doc_suspicious_footnotes +/// +/// This is not a footnote[^either], but it doesn't warn. +/// +/// This is not a footnote\[^1], but it also doesn't warn. +/// +/// This is not a footnote[^1\], but it also doesn't warn. +/// +/// This is not a `footnote[^1]`, but it also doesn't warn. +/// +/// This is a footnote[^2]. +/// +/// [^2]: hello world +pub fn footnotes() { + // test code goes here +} + +pub struct Foo; +#[rustfmt::skip] +impl Foo { + #[doc = r#"This is not a footnote[^1]."#] + //~^ doc_suspicious_footnotes + #[doc = r#""#] + #[doc = r#"This is not a footnote[^either], but it doesn't warn."#] + #[doc = r#""#] + #[doc = r#"This is not a footnote\[^1], but it also doesn't warn."#] + #[doc = r#""#] + #[doc = r#"This is not a footnote[^1\], but it also doesn't warn."#] + #[doc = r#""#] + #[doc = r#"This is not a `footnote[^1]`, but it also doesn't warn."#] + #[doc = r#""#] + #[doc = r#"This is a footnote[^2]."#] + #[doc = r#""#] + #[doc = r#"[^2]: hello world"#] + pub fn footnotes() { + // test code goes here + } + #[doc = "This is not a footnote[^1]. + + This is not a footnote[^either], but it doesn't warn. + + This is not a footnote\\[^1], but it also doesn't warn. + + This is not a footnote[^1\\], but it also doesn't warn. + + This is not a `footnote[^1]`, but it also doesn't warn. + + This is a footnote[^2]. + + [^2]: hello world + "] + //~^^^^^^^^^^^^^^ doc_suspicious_footnotes + pub fn footnotes2() { + // test code goes here + } + #[cfg_attr( + not(FALSE), + doc = "This is not a footnote[^1].\n\nThis is not a footnote[^either], but it doesn't warn." + //~^ doc_suspicious_footnotes + )] + pub fn footnotes3() { + // test code goes here + } + #[doc = "My footnote [^foot\note]"] + pub fn footnote4() { + // test code goes here + } + #[doc = "Hihi"]pub fn footnote5() { + // test code goes here + } +} + +#[doc = r"This is not a footnote[^1]."] +//~^ doc_suspicious_footnotes +#[doc = r""] +#[doc = r"This is not a footnote[^either], but it doesn't warn."] +#[doc = r""] +#[doc = r"This is not a footnote\[^1], but it also doesn't warn."] +#[doc = r""] +#[doc = r"This is not a footnote[^1\], but it also doesn't warn."] +#[doc = r""] +#[doc = r"This is not a `footnote[^1]`, but it also doesn't warn."] +#[doc = r""] +#[doc = r"This is a footnote[^2]."] +#[doc = r""] +#[doc = r"[^2]: hello world"] +pub fn footnotes_attrs() { + // test code goes here +} + +pub mod multiline { + /*! + * This is not a footnote[^1]. //~ doc_suspicious_footnotes + * + * This is not a footnote\[^1], but it doesn't warn. + * + * This is a footnote[^2]. + * + * These give weird results, but correct ones, so it works. + * + * [^2]: hello world + */ + /** + * This is not a footnote[^1]. //~ doc_suspicious_footnotes + * + * This is not a footnote\[^1], but it doesn't warn. + * + * This is a footnote[^2]. + * + * These give weird results, but correct ones, so it works. + * + * [^2]: hello world + */ + pub fn foo() {} +} + +/// This is not a footnote [^1] +//~^ doc_suspicious_footnotes +/// +/// This one is [^2] +/// +/// [^2]: contents +#[doc = "This is not a footnote [^3]"] +//~^ doc_suspicious_footnotes +#[doc = ""] +#[doc = "This one is [^4]"] +#[doc = ""] +#[doc = "[^4]: contents"] +pub struct MultiFragmentFootnote; + +#[doc(inline)] +/// This is not a footnote [^5] +//~^ doc_suspicious_footnotes +/// +/// This one is [^6] +/// +/// [^6]: contents +#[doc = "This is not a footnote [^7]"] +//~^ doc_suspicious_footnotes +#[doc = ""] +#[doc = "This one is [^8]"] +#[doc = ""] +#[doc = "[^8]: contents"] +pub use MultiFragmentFootnote as OtherInlinedFootnote; diff --git a/src/tools/clippy/tests/ui/doc_suspicious_footnotes.stderr b/src/tools/clippy/tests/ui/doc_suspicious_footnotes.stderr new file mode 100644 index 00000000000..4f920f37a62 --- /dev/null +++ b/src/tools/clippy/tests/ui/doc_suspicious_footnotes.stderr @@ -0,0 +1,179 @@ +error: looks like a footnote ref, but has no matching footnote + --> tests/ui/doc_suspicious_footnotes.rs:3:27 + | +LL | //! This is not a footnote[^1]. + | ^^^^ + | + = note: `-D clippy::doc-suspicious-footnotes` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::doc_suspicious_footnotes)]` +help: add footnote definition + | +LL ~ //! This is not a footnote[^1]. +LL + //! +LL + //! [^1]: <!-- description --> + | + +error: looks like a footnote ref, but has no matching footnote + --> tests/ui/doc_suspicious_footnotes.rs:18:27 + | +LL | /// This is not a footnote[^1]. + | ^^^^ + | +help: add footnote definition + | +LL ~ /// This is not a footnote[^1]. +LL + /// +LL + /// [^1]: <!-- description --> + | + +error: looks like a footnote ref, but has no matching footnote + --> tests/ui/doc_suspicious_footnotes.rs:39:13 + | +LL | #[doc = r#"This is not a footnote[^1]."#] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: add footnote definition + | +LL ~ #[doc = r#"This is not a footnote[^1]. +LL + +LL ~ [^1]: <!-- description -->"#] + | + +error: looks like a footnote ref, but has no matching footnote + --> tests/ui/doc_suspicious_footnotes.rs:56:13 + | +LL | #[doc = "This is not a footnote[^1]. + | _____________^ +LL | | +LL | | This is not a footnote[^either], but it doesn't warn. +... | +LL | | [^2]: hello world +LL | | "] + | |_____^ + | +help: add footnote definition + | +LL ~ #[doc = r#"This is not a footnote[^1]. +LL + +LL + This is not a footnote[^either], but it doesn't warn. +LL + +LL + This is not a footnote\[^1], but it also doesn't warn. +LL + +LL + This is not a footnote[^1\], but it also doesn't warn. +LL + +LL + This is not a `footnote[^1]`, but it also doesn't warn. +LL + +LL + This is a footnote[^2]. +LL + +LL + [^2]: hello world +LL + +LL + +LL ~ [^1]: <!-- description -->"#] + | + +error: looks like a footnote ref, but has no matching footnote + --> tests/ui/doc_suspicious_footnotes.rs:76:38 + | +LL | doc = "This is not a footnote[^1].\n\nThis is not a footnote[^either], but it doesn't warn." + | ^^^^ + | +help: add footnote definition + | +LL ~ doc = r#"This is not a footnote[^1]. +LL + +LL + This is not a footnote[^either], but it doesn't warn. +LL + +LL + [^1]: <!-- description -->"# + | + +error: looks like a footnote ref, but has no matching footnote + --> tests/ui/doc_suspicious_footnotes.rs:91:9 + | +LL | #[doc = r"This is not a footnote[^1]."] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: add footnote definition + | +LL ~ #[doc = r#"This is not a footnote[^1]. +LL + +LL ~ [^1]: <!-- description -->"#] + | + +error: looks like a footnote ref, but has no matching footnote + --> tests/ui/doc_suspicious_footnotes.rs:111:30 + | +LL | * This is not a footnote[^1]. + | ^^^^ + | +help: add footnote definition + | +LL ~ */ +LL + /*! [^1]: <!-- description --> */ + | + +error: looks like a footnote ref, but has no matching footnote + --> tests/ui/doc_suspicious_footnotes.rs:122:30 + | +LL | * This is not a footnote[^1]. + | ^^^^ + | +help: add footnote definition + | +LL ~ */ +LL + /** [^1]: <!-- description --> */ + | + +error: looks like a footnote ref, but has no matching footnote + --> tests/ui/doc_suspicious_footnotes.rs:135:28 + | +LL | /// This is not a footnote [^1] + | ^^^^ + | +help: add footnote definition + | +LL ~ /// This is not a footnote [^1] +LL + /// +LL + /// [^1]: <!-- description --> + | + +error: looks like a footnote ref, but has no matching footnote + --> tests/ui/doc_suspicious_footnotes.rs:141:33 + | +LL | #[doc = "This is not a footnote [^3]"] + | ^^^^ + | +help: add footnote definition + | +LL ~ #[doc = r#"This is not a footnote [^3] +LL + +LL ~ [^3]: <!-- description -->"#] + | + +error: looks like a footnote ref, but has no matching footnote + --> tests/ui/doc_suspicious_footnotes.rs:150:28 + | +LL | /// This is not a footnote [^5] + | ^^^^ + | +help: add footnote definition + | +LL ~ /// This is not a footnote [^5] +LL + /// +LL + /// [^5]: <!-- description --> + | + +error: looks like a footnote ref, but has no matching footnote + --> tests/ui/doc_suspicious_footnotes.rs:156:33 + | +LL | #[doc = "This is not a footnote [^7]"] + | ^^^^ + | +help: add footnote definition + | +LL ~ #[doc = r#"This is not a footnote [^7] +LL + +LL ~ [^7]: <!-- description -->"#] + | + +error: aborting due to 12 previous errors + diff --git a/src/tools/clippy/tests/ui/doc_suspicious_footnotes_include.rs b/src/tools/clippy/tests/ui/doc_suspicious_footnotes_include.rs new file mode 100644 index 00000000000..4f75ad94eaf --- /dev/null +++ b/src/tools/clippy/tests/ui/doc_suspicious_footnotes_include.rs @@ -0,0 +1,4 @@ +//@ error-in-other-file: footnote +//@ no-rustfix +#![warn(clippy::doc_suspicious_footnotes)] +#![doc=include_str!("doc_suspicious_footnotes_include.txt")] diff --git a/src/tools/clippy/tests/ui/doc_suspicious_footnotes_include.stderr b/src/tools/clippy/tests/ui/doc_suspicious_footnotes_include.stderr new file mode 100644 index 00000000000..74154e3f4ef --- /dev/null +++ b/src/tools/clippy/tests/ui/doc_suspicious_footnotes_include.stderr @@ -0,0 +1,17 @@ +error: looks like a footnote ref, but has no matching footnote + --> tests/ui/doc_suspicious_footnotes_include.txt:1:23 + | +LL | This is not a footnote[^1]. + | ^^^^ + | + = note: `-D clippy::doc-suspicious-footnotes` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::doc_suspicious_footnotes)]` +help: add footnote definition + | +LL ~ [^2]: hello world +LL + +LL + [^1]: <!-- description --> + | + +error: aborting due to 1 previous error + diff --git a/src/tools/clippy/tests/ui/doc_suspicious_footnotes_include.txt b/src/tools/clippy/tests/ui/doc_suspicious_footnotes_include.txt new file mode 100644 index 00000000000..2a533e32c4a --- /dev/null +++ b/src/tools/clippy/tests/ui/doc_suspicious_footnotes_include.txt @@ -0,0 +1,13 @@ +This is not a footnote[^1]. //~ doc_suspicious_footnotes + +This is not a footnote[^either], but it doesn't warn. + +This is not a footnote\[^1], but it also doesn't warn. + +This is not a footnote[^1\], but it also doesn't warn. + +This is not a `footnote[^1]`, but it also doesn't warn. + +This is a footnote[^2]. + +[^2]: hello world diff --git a/src/tools/clippy/tests/ui/format_args.fixed b/src/tools/clippy/tests/ui/format_args.fixed index edfdaa23ca1..3cb6c0b4d97 100644 --- a/src/tools/clippy/tests/ui/format_args.fixed +++ b/src/tools/clippy/tests/ui/format_args.fixed @@ -192,3 +192,13 @@ mod issue_9256 { print_substring("Hello, world!"); } } + +mod issue14952 { + use std::path::Path; + struct Foo(Path); + impl std::fmt::Debug for Foo { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", &self.0) + } + } +} diff --git a/src/tools/clippy/tests/ui/format_args.rs b/src/tools/clippy/tests/ui/format_args.rs index 367560d577d..8a9c369fff3 100644 --- a/src/tools/clippy/tests/ui/format_args.rs +++ b/src/tools/clippy/tests/ui/format_args.rs @@ -192,3 +192,13 @@ mod issue_9256 { print_substring("Hello, world!"); } } + +mod issue14952 { + use std::path::Path; + struct Foo(Path); + impl std::fmt::Debug for Foo { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", &self.0) + } + } +} diff --git a/src/tools/clippy/tests/ui/indexing_slicing_index.rs b/src/tools/clippy/tests/ui/indexing_slicing_index.rs index ab6a8235008..2510a023acd 100644 --- a/src/tools/clippy/tests/ui/indexing_slicing_index.rs +++ b/src/tools/clippy/tests/ui/indexing_slicing_index.rs @@ -68,7 +68,6 @@ fn main() { // This should be linted, since `suppress-restriction-lint-in-const` default is false. const { &ARR[idx4()] }; //~^ ERROR: indexing may panic - //~| ERROR: index out of bounds let y = &x; // Ok, referencing shouldn't affect this lint. See the issue 6021 diff --git a/src/tools/clippy/tests/ui/indexing_slicing_index.stderr b/src/tools/clippy/tests/ui/indexing_slicing_index.stderr index 8e24b898ed5..c68e1d53a93 100644 --- a/src/tools/clippy/tests/ui/indexing_slicing_index.stderr +++ b/src/tools/clippy/tests/ui/indexing_slicing_index.stderr @@ -9,18 +9,6 @@ LL | const REF: &i32 = &ARR[idx()]; // This should be linted, since `suppress-re = note: `-D clippy::indexing-slicing` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::indexing_slicing)]` -error[E0080]: index out of bounds: the length is 2 but the index is 4 - --> tests/ui/indexing_slicing_index.rs:69:14 - | -LL | const { &ARR[idx4()] }; - | ^^^^^^^^^^^ evaluation of `main::{constant#3}` failed here - -note: erroneous constant encountered - --> tests/ui/indexing_slicing_index.rs:69:5 - | -LL | const { &ARR[idx4()] }; - | ^^^^^^^^^^^^^^^^^^^^^^ - error: indexing may panic --> tests/ui/indexing_slicing_index.rs:48:5 | @@ -63,13 +51,13 @@ LL | const { &ARR[idx4()] }; = note: the suggestion might not be applicable in constant blocks error: index is out of bounds - --> tests/ui/indexing_slicing_index.rs:77:5 + --> tests/ui/indexing_slicing_index.rs:76:5 | LL | y[4]; | ^^^^ error: indexing may panic - --> tests/ui/indexing_slicing_index.rs:81:5 + --> tests/ui/indexing_slicing_index.rs:80:5 | LL | v[0]; | ^^^^ @@ -77,7 +65,7 @@ LL | v[0]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic - --> tests/ui/indexing_slicing_index.rs:83:5 + --> tests/ui/indexing_slicing_index.rs:82:5 | LL | v[10]; | ^^^^^ @@ -85,7 +73,7 @@ LL | v[10]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic - --> tests/ui/indexing_slicing_index.rs:85:5 + --> tests/ui/indexing_slicing_index.rs:84:5 | LL | v[1 << 3]; | ^^^^^^^^^ @@ -93,13 +81,13 @@ LL | v[1 << 3]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: index is out of bounds - --> tests/ui/indexing_slicing_index.rs:93:5 + --> tests/ui/indexing_slicing_index.rs:92:5 | LL | x[N]; | ^^^^ error: indexing may panic - --> tests/ui/indexing_slicing_index.rs:97:5 + --> tests/ui/indexing_slicing_index.rs:96:5 | LL | v[N]; | ^^^^ @@ -107,7 +95,7 @@ LL | v[N]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: indexing may panic - --> tests/ui/indexing_slicing_index.rs:99:5 + --> tests/ui/indexing_slicing_index.rs:98:5 | LL | v[M]; | ^^^^ @@ -115,11 +103,10 @@ LL | v[M]; = help: consider using `.get(n)` or `.get_mut(n)` instead error: index is out of bounds - --> tests/ui/indexing_slicing_index.rs:103:13 + --> tests/ui/indexing_slicing_index.rs:102:13 | LL | let _ = x[4]; | ^^^^ -error: aborting due to 15 previous errors +error: aborting due to 14 previous errors -For more information about this error, try `rustc --explain E0080`. diff --git a/src/tools/clippy/tests/ui/infallible_try_from.rs b/src/tools/clippy/tests/ui/infallible_try_from.rs new file mode 100644 index 00000000000..6a1f12f824f --- /dev/null +++ b/src/tools/clippy/tests/ui/infallible_try_from.rs @@ -0,0 +1,33 @@ +#![feature(never_type)] +#![warn(clippy::infallible_try_from)] + +use std::convert::Infallible; + +struct MyStruct(i32); + +impl TryFrom<i8> for MyStruct { + //~^ infallible_try_from + type Error = !; + fn try_from(other: i8) -> Result<Self, !> { + Ok(Self(other.into())) + } +} + +impl TryFrom<i16> for MyStruct { + //~^ infallible_try_from + type Error = Infallible; + fn try_from(other: i16) -> Result<Self, Infallible> { + Ok(Self(other.into())) + } +} + +impl TryFrom<i64> for MyStruct { + type Error = i64; + fn try_from(other: i64) -> Result<Self, i64> { + Ok(Self(i32::try_from(other).map_err(|_| other)?)) + } +} + +fn main() { + // test code goes here +} diff --git a/src/tools/clippy/tests/ui/infallible_try_from.stderr b/src/tools/clippy/tests/ui/infallible_try_from.stderr new file mode 100644 index 00000000000..705b1188489 --- /dev/null +++ b/src/tools/clippy/tests/ui/infallible_try_from.stderr @@ -0,0 +1,23 @@ +error: infallible TryFrom impl; consider implementing From, instead + --> tests/ui/infallible_try_from.rs:8:1 + | +LL | impl TryFrom<i8> for MyStruct { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | type Error = !; + | - infallible error type + | + = note: `-D clippy::infallible-try-from` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::infallible_try_from)]` + +error: infallible TryFrom impl; consider implementing From, instead + --> tests/ui/infallible_try_from.rs:16:1 + | +LL | impl TryFrom<i16> for MyStruct { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | type Error = Infallible; + | ---------- infallible error type + +error: aborting due to 2 previous errors + diff --git a/src/tools/clippy/tests/ui/ip_constant.fixed b/src/tools/clippy/tests/ui/ip_constant.fixed new file mode 100644 index 00000000000..2e3389c1193 --- /dev/null +++ b/src/tools/clippy/tests/ui/ip_constant.fixed @@ -0,0 +1,107 @@ +#![warn(clippy::ip_constant)] +#![allow(dead_code)] +#![allow(clippy::identity_op)] +#![allow(clippy::eq_op)] + +fn literal_test1() { + use std::net::Ipv4Addr; + let _ = Ipv4Addr::LOCALHOST; + //~^ ip_constant + let _ = Ipv4Addr::BROADCAST; + //~^ ip_constant + let _ = Ipv4Addr::UNSPECIFIED; + //~^ ip_constant + + use std::net::Ipv6Addr; + let _ = Ipv6Addr::LOCALHOST; + //~^ ip_constant + let _ = Ipv6Addr::UNSPECIFIED; + //~^ ip_constant +} + +fn literal_test2() { + use std::net; + let _ = net::Ipv4Addr::LOCALHOST; + //~^ ip_constant + let _ = net::Ipv4Addr::BROADCAST; + //~^ ip_constant + let _ = net::Ipv4Addr::UNSPECIFIED; + //~^ ip_constant + + let _ = net::Ipv6Addr::LOCALHOST; + //~^ ip_constant + let _ = net::Ipv6Addr::UNSPECIFIED; + //~^ ip_constant +} + +fn literal_test3() { + let _ = std::net::Ipv4Addr::LOCALHOST; + //~^ ip_constant + let _ = std::net::Ipv4Addr::BROADCAST; + //~^ ip_constant + let _ = std::net::Ipv4Addr::UNSPECIFIED; + //~^ ip_constant + + let _ = std::net::Ipv6Addr::LOCALHOST; + //~^ ip_constant + let _ = std::net::Ipv6Addr::UNSPECIFIED; + //~^ ip_constant +} + +const CONST_U8_0: u8 = 0; +const CONST_U8_1: u8 = 1; +const CONST_U8_127: u8 = 127; +const CONST_U8_255: u8 = 255; + +const CONST_U16_0: u16 = 0; +const CONST_U16_1: u16 = 1; + +fn const_test1() { + use std::net::Ipv4Addr; + let _ = Ipv4Addr::LOCALHOST; + //~^ ip_constant + let _ = Ipv4Addr::BROADCAST; + //~^ ip_constant + let _ = Ipv4Addr::UNSPECIFIED; + //~^ ip_constant + + use std::net::Ipv6Addr; + let _ = Ipv6Addr::LOCALHOST; + + let _ = Ipv6Addr::UNSPECIFIED; +} + +fn const_test2() { + use std::net::Ipv4Addr; + let _ = Ipv4Addr::LOCALHOST; + //~^ ip_constant + let _ = Ipv4Addr::BROADCAST; + //~^ ip_constant + let _ = Ipv4Addr::UNSPECIFIED; + //~^ ip_constant + + use std::net::Ipv6Addr; + let _ = Ipv6Addr::LOCALHOST; + //~^ ip_constant + let _ = Ipv6Addr::LOCALHOST; + //~^ ip_constant +} + +macro_rules! ipv4_new { + ($a:expr, $b:expr, $c:expr, $d:expr) => { + std::net::Ipv4Addr::new($a, $b, $c, $d) + }; +} + +fn macro_test() { + let _ = ipv4_new!(127, 0, 0, 1); + // no lint + let _ = ipv4_new!(255, 255, 255, 255); + // no lint + let _ = ipv4_new!(0, 0, 0, 0); + // no lint +} + +fn main() { + // UI Test +} diff --git a/src/tools/clippy/tests/ui/ip_constant.rs b/src/tools/clippy/tests/ui/ip_constant.rs new file mode 100644 index 00000000000..15e0b0551ba --- /dev/null +++ b/src/tools/clippy/tests/ui/ip_constant.rs @@ -0,0 +1,127 @@ +#![warn(clippy::ip_constant)] +#![allow(dead_code)] +#![allow(clippy::identity_op)] +#![allow(clippy::eq_op)] + +fn literal_test1() { + use std::net::Ipv4Addr; + let _ = Ipv4Addr::new(127, 0, 0, 1); + //~^ ip_constant + let _ = Ipv4Addr::new(255, 255, 255, 255); + //~^ ip_constant + let _ = Ipv4Addr::new(0, 0, 0, 0); + //~^ ip_constant + + use std::net::Ipv6Addr; + let _ = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1); + //~^ ip_constant + let _ = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0); + //~^ ip_constant +} + +fn literal_test2() { + use std::net; + let _ = net::Ipv4Addr::new(127, 0, 0, 1); + //~^ ip_constant + let _ = net::Ipv4Addr::new(255, 255, 255, 255); + //~^ ip_constant + let _ = net::Ipv4Addr::new(0, 0, 0, 0); + //~^ ip_constant + + let _ = net::Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1); + //~^ ip_constant + let _ = net::Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0); + //~^ ip_constant +} + +fn literal_test3() { + let _ = std::net::Ipv4Addr::new(127, 0, 0, 1); + //~^ ip_constant + let _ = std::net::Ipv4Addr::new(255, 255, 255, 255); + //~^ ip_constant + let _ = std::net::Ipv4Addr::new(0, 0, 0, 0); + //~^ ip_constant + + let _ = std::net::Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1); + //~^ ip_constant + let _ = std::net::Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0); + //~^ ip_constant +} + +const CONST_U8_0: u8 = 0; +const CONST_U8_1: u8 = 1; +const CONST_U8_127: u8 = 127; +const CONST_U8_255: u8 = 255; + +const CONST_U16_0: u16 = 0; +const CONST_U16_1: u16 = 1; + +fn const_test1() { + use std::net::Ipv4Addr; + let _ = Ipv4Addr::new(CONST_U8_127, CONST_U8_0, CONST_U8_0, CONST_U8_1); + //~^ ip_constant + let _ = Ipv4Addr::new(CONST_U8_255, CONST_U8_255, CONST_U8_255, CONST_U8_255); + //~^ ip_constant + let _ = Ipv4Addr::new(CONST_U8_0, CONST_U8_0, CONST_U8_0, CONST_U8_0); + //~^ ip_constant + + use std::net::Ipv6Addr; + let _ = Ipv6Addr::new( + //~^ ip_constant + CONST_U16_0, + CONST_U16_0, + CONST_U16_0, + CONST_U16_0, + CONST_U16_0, + CONST_U16_0, + CONST_U16_0, + CONST_U16_1, + ); + + let _ = Ipv6Addr::new( + //~^ ip_constant + CONST_U16_0, + CONST_U16_0, + CONST_U16_0, + CONST_U16_0, + CONST_U16_0, + CONST_U16_0, + CONST_U16_0, + CONST_U16_0, + ); +} + +fn const_test2() { + use std::net::Ipv4Addr; + let _ = Ipv4Addr::new(126 + 1, 0, 0, 1); + //~^ ip_constant + let _ = Ipv4Addr::new(254 + CONST_U8_1, 255, { 255 - CONST_U8_0 }, CONST_U8_255); + //~^ ip_constant + let _ = Ipv4Addr::new(0, CONST_U8_255 - 255, 0, { 1 + 0 - 1 }); + //~^ ip_constant + + use std::net::Ipv6Addr; + let _ = Ipv6Addr::new(0 + CONST_U16_0, 0, 0, 0, 0, 0, 0, 1); + //~^ ip_constant + let _ = Ipv6Addr::new(0 + 0, 0, 0, 0, 0, { 2 - 1 - CONST_U16_1 }, 0, 1); + //~^ ip_constant +} + +macro_rules! ipv4_new { + ($a:expr, $b:expr, $c:expr, $d:expr) => { + std::net::Ipv4Addr::new($a, $b, $c, $d) + }; +} + +fn macro_test() { + let _ = ipv4_new!(127, 0, 0, 1); + // no lint + let _ = ipv4_new!(255, 255, 255, 255); + // no lint + let _ = ipv4_new!(0, 0, 0, 0); + // no lint +} + +fn main() { + // UI Test +} diff --git a/src/tools/clippy/tests/ui/ip_constant.stderr b/src/tools/clippy/tests/ui/ip_constant.stderr new file mode 100644 index 00000000000..3e984c6cb3b --- /dev/null +++ b/src/tools/clippy/tests/ui/ip_constant.stderr @@ -0,0 +1,338 @@ +error: hand-coded well-known IP address + --> tests/ui/ip_constant.rs:8:13 + | +LL | let _ = Ipv4Addr::new(127, 0, 0, 1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::ip-constant` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::ip_constant)]` +help: use + | +LL - let _ = Ipv4Addr::new(127, 0, 0, 1); +LL + let _ = Ipv4Addr::LOCALHOST; + | + +error: hand-coded well-known IP address + --> tests/ui/ip_constant.rs:10:13 + | +LL | let _ = Ipv4Addr::new(255, 255, 255, 255); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use + | +LL - let _ = Ipv4Addr::new(255, 255, 255, 255); +LL + let _ = Ipv4Addr::BROADCAST; + | + +error: hand-coded well-known IP address + --> tests/ui/ip_constant.rs:12:13 + | +LL | let _ = Ipv4Addr::new(0, 0, 0, 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use + | +LL - let _ = Ipv4Addr::new(0, 0, 0, 0); +LL + let _ = Ipv4Addr::UNSPECIFIED; + | + +error: hand-coded well-known IP address + --> tests/ui/ip_constant.rs:16:13 + | +LL | let _ = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use + | +LL - let _ = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1); +LL + let _ = Ipv6Addr::LOCALHOST; + | + +error: hand-coded well-known IP address + --> tests/ui/ip_constant.rs:18:13 + | +LL | let _ = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use + | +LL - let _ = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0); +LL + let _ = Ipv6Addr::UNSPECIFIED; + | + +error: hand-coded well-known IP address + --> tests/ui/ip_constant.rs:24:13 + | +LL | let _ = net::Ipv4Addr::new(127, 0, 0, 1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use + | +LL - let _ = net::Ipv4Addr::new(127, 0, 0, 1); +LL + let _ = net::Ipv4Addr::LOCALHOST; + | + +error: hand-coded well-known IP address + --> tests/ui/ip_constant.rs:26:13 + | +LL | let _ = net::Ipv4Addr::new(255, 255, 255, 255); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use + | +LL - let _ = net::Ipv4Addr::new(255, 255, 255, 255); +LL + let _ = net::Ipv4Addr::BROADCAST; + | + +error: hand-coded well-known IP address + --> tests/ui/ip_constant.rs:28:13 + | +LL | let _ = net::Ipv4Addr::new(0, 0, 0, 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use + | +LL - let _ = net::Ipv4Addr::new(0, 0, 0, 0); +LL + let _ = net::Ipv4Addr::UNSPECIFIED; + | + +error: hand-coded well-known IP address + --> tests/ui/ip_constant.rs:31:13 + | +LL | let _ = net::Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use + | +LL - let _ = net::Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1); +LL + let _ = net::Ipv6Addr::LOCALHOST; + | + +error: hand-coded well-known IP address + --> tests/ui/ip_constant.rs:33:13 + | +LL | let _ = net::Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use + | +LL - let _ = net::Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0); +LL + let _ = net::Ipv6Addr::UNSPECIFIED; + | + +error: hand-coded well-known IP address + --> tests/ui/ip_constant.rs:38:13 + | +LL | let _ = std::net::Ipv4Addr::new(127, 0, 0, 1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use + | +LL - let _ = std::net::Ipv4Addr::new(127, 0, 0, 1); +LL + let _ = std::net::Ipv4Addr::LOCALHOST; + | + +error: hand-coded well-known IP address + --> tests/ui/ip_constant.rs:40:13 + | +LL | let _ = std::net::Ipv4Addr::new(255, 255, 255, 255); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use + | +LL - let _ = std::net::Ipv4Addr::new(255, 255, 255, 255); +LL + let _ = std::net::Ipv4Addr::BROADCAST; + | + +error: hand-coded well-known IP address + --> tests/ui/ip_constant.rs:42:13 + | +LL | let _ = std::net::Ipv4Addr::new(0, 0, 0, 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use + | +LL - let _ = std::net::Ipv4Addr::new(0, 0, 0, 0); +LL + let _ = std::net::Ipv4Addr::UNSPECIFIED; + | + +error: hand-coded well-known IP address + --> tests/ui/ip_constant.rs:45:13 + | +LL | let _ = std::net::Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use + | +LL - let _ = std::net::Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1); +LL + let _ = std::net::Ipv6Addr::LOCALHOST; + | + +error: hand-coded well-known IP address + --> tests/ui/ip_constant.rs:47:13 + | +LL | let _ = std::net::Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use + | +LL - let _ = std::net::Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0); +LL + let _ = std::net::Ipv6Addr::UNSPECIFIED; + | + +error: hand-coded well-known IP address + --> tests/ui/ip_constant.rs:61:13 + | +LL | let _ = Ipv4Addr::new(CONST_U8_127, CONST_U8_0, CONST_U8_0, CONST_U8_1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use + | +LL - let _ = Ipv4Addr::new(CONST_U8_127, CONST_U8_0, CONST_U8_0, CONST_U8_1); +LL + let _ = Ipv4Addr::LOCALHOST; + | + +error: hand-coded well-known IP address + --> tests/ui/ip_constant.rs:63:13 + | +LL | let _ = Ipv4Addr::new(CONST_U8_255, CONST_U8_255, CONST_U8_255, CONST_U8_255); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use + | +LL - let _ = Ipv4Addr::new(CONST_U8_255, CONST_U8_255, CONST_U8_255, CONST_U8_255); +LL + let _ = Ipv4Addr::BROADCAST; + | + +error: hand-coded well-known IP address + --> tests/ui/ip_constant.rs:65:13 + | +LL | let _ = Ipv4Addr::new(CONST_U8_0, CONST_U8_0, CONST_U8_0, CONST_U8_0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use + | +LL - let _ = Ipv4Addr::new(CONST_U8_0, CONST_U8_0, CONST_U8_0, CONST_U8_0); +LL + let _ = Ipv4Addr::UNSPECIFIED; + | + +error: hand-coded well-known IP address + --> tests/ui/ip_constant.rs:69:13 + | +LL | let _ = Ipv6Addr::new( + | _____________^ +LL | | +LL | | CONST_U16_0, +LL | | CONST_U16_0, +... | +LL | | CONST_U16_1, +LL | | ); + | |_____^ + | +help: use + | +LL - let _ = Ipv6Addr::new( +LL - +LL - CONST_U16_0, +LL - CONST_U16_0, +LL - CONST_U16_0, +LL - CONST_U16_0, +LL - CONST_U16_0, +LL - CONST_U16_0, +LL - CONST_U16_0, +LL - CONST_U16_1, +LL - ); +LL + let _ = Ipv6Addr::LOCALHOST; + | + +error: hand-coded well-known IP address + --> tests/ui/ip_constant.rs:81:13 + | +LL | let _ = Ipv6Addr::new( + | _____________^ +LL | | +LL | | CONST_U16_0, +LL | | CONST_U16_0, +... | +LL | | CONST_U16_0, +LL | | ); + | |_____^ + | +help: use + | +LL - let _ = Ipv6Addr::new( +LL - +LL - CONST_U16_0, +LL - CONST_U16_0, +LL - CONST_U16_0, +LL - CONST_U16_0, +LL - CONST_U16_0, +LL - CONST_U16_0, +LL - CONST_U16_0, +LL - CONST_U16_0, +LL - ); +LL + let _ = Ipv6Addr::UNSPECIFIED; + | + +error: hand-coded well-known IP address + --> tests/ui/ip_constant.rs:96:13 + | +LL | let _ = Ipv4Addr::new(126 + 1, 0, 0, 1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use + | +LL - let _ = Ipv4Addr::new(126 + 1, 0, 0, 1); +LL + let _ = Ipv4Addr::LOCALHOST; + | + +error: hand-coded well-known IP address + --> tests/ui/ip_constant.rs:98:13 + | +LL | let _ = Ipv4Addr::new(254 + CONST_U8_1, 255, { 255 - CONST_U8_0 }, CONST_U8_255); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use + | +LL - let _ = Ipv4Addr::new(254 + CONST_U8_1, 255, { 255 - CONST_U8_0 }, CONST_U8_255); +LL + let _ = Ipv4Addr::BROADCAST; + | + +error: hand-coded well-known IP address + --> tests/ui/ip_constant.rs:100:13 + | +LL | let _ = Ipv4Addr::new(0, CONST_U8_255 - 255, 0, { 1 + 0 - 1 }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use + | +LL - let _ = Ipv4Addr::new(0, CONST_U8_255 - 255, 0, { 1 + 0 - 1 }); +LL + let _ = Ipv4Addr::UNSPECIFIED; + | + +error: hand-coded well-known IP address + --> tests/ui/ip_constant.rs:104:13 + | +LL | let _ = Ipv6Addr::new(0 + CONST_U16_0, 0, 0, 0, 0, 0, 0, 1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use + | +LL - let _ = Ipv6Addr::new(0 + CONST_U16_0, 0, 0, 0, 0, 0, 0, 1); +LL + let _ = Ipv6Addr::LOCALHOST; + | + +error: hand-coded well-known IP address + --> tests/ui/ip_constant.rs:106:13 + | +LL | let _ = Ipv6Addr::new(0 + 0, 0, 0, 0, 0, { 2 - 1 - CONST_U16_1 }, 0, 1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: use + | +LL - let _ = Ipv6Addr::new(0 + 0, 0, 0, 0, 0, { 2 - 1 - CONST_U16_1 }, 0, 1); +LL + let _ = Ipv6Addr::LOCALHOST; + | + +error: aborting due to 25 previous errors + diff --git a/src/tools/clippy/tests/ui/ip_constant_from_external.rs b/src/tools/clippy/tests/ui/ip_constant_from_external.rs new file mode 100644 index 00000000000..7fd27022f12 --- /dev/null +++ b/src/tools/clippy/tests/ui/ip_constant_from_external.rs @@ -0,0 +1,12 @@ +//@error-in-other-file: hand-coded well-known IP address +//@no-rustfix +#![warn(clippy::ip_constant)] + +fn external_constant_test() { + let _ = include!("localhost.txt"); + // lint in external file `localhost.txt` +} + +fn main() { + external_constant_test(); +} diff --git a/src/tools/clippy/tests/ui/ip_constant_from_external.stderr b/src/tools/clippy/tests/ui/ip_constant_from_external.stderr new file mode 100644 index 00000000000..99dd827d41f --- /dev/null +++ b/src/tools/clippy/tests/ui/ip_constant_from_external.stderr @@ -0,0 +1,16 @@ +error: hand-coded well-known IP address + --> tests/ui/localhost.txt:1:1 + | +LL | std::net::Ipv4Addr::new(127, 0, 0, 1) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::ip-constant` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::ip_constant)]` +help: use + | +LL - std::net::Ipv4Addr::new(127, 0, 0, 1) +LL + std::net::Ipv4Addr::LOCALHOST + | + +error: aborting due to 1 previous error + diff --git a/src/tools/clippy/tests/ui/localhost.txt b/src/tools/clippy/tests/ui/localhost.txt new file mode 100644 index 00000000000..4502ec2b234 --- /dev/null +++ b/src/tools/clippy/tests/ui/localhost.txt @@ -0,0 +1 @@ +std::net::Ipv4Addr::new(127, 0, 0, 1) \ No newline at end of file diff --git a/src/tools/clippy/tests/ui/manual_flatten.fixed b/src/tools/clippy/tests/ui/manual_flatten.fixed new file mode 100644 index 00000000000..cc1fbd25765 --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_flatten.fixed @@ -0,0 +1,148 @@ +#![warn(clippy::manual_flatten)] +#![allow(clippy::useless_vec, clippy::uninlined_format_args)] + +fn main() { + // Test for loop over implicitly adjusted `Iterator` with `if let` expression + let x = vec![Some(1), Some(2), Some(3)]; + for y in x.into_iter().flatten() { + println!("{}", y); + } + + // Test for loop over implicitly adjusted `Iterator` with `if let` statement + let y: Vec<Result<i32, i32>> = vec![]; + for n in y.clone().into_iter().flatten() { + println!("{}", n); + } + + // Test for loop over by reference + for n in y.iter().flatten() { + println!("{}", n); + } + + // Test for loop over an implicit reference + let z = &y; + for n in z.iter().flatten() { + println!("{}", n); + } + + // Test for loop over `Iterator` with `if let` expression + let z = vec![Some(1), Some(2), Some(3)]; + let z = z.iter(); + for m in z.flatten() { + println!("{}", m); + } + + // Using the `None` variant should not trigger the lint + // Note: for an autofixable suggestion, the binding in the for loop has to take the + // name of the binding in the `if let` + let z = vec![Some(1), Some(2), Some(3)]; + for n in z { + if n.is_none() { + println!("Nada."); + } + } + + // Using the `Err` variant should not trigger the lint + for n in y.clone() { + if let Err(e) = n { + println!("Oops: {}!", e); + } + } + + // Having an else clause should not trigger the lint + for n in y.clone() { + if let Ok(n) = n { + println!("{}", n); + } else { + println!("Oops!"); + } + } + + let vec_of_ref = vec![&Some(1)]; + for n in vec_of_ref.iter().copied().flatten() { + println!("{:?}", n); + } + + let vec_of_ref = &vec_of_ref; + for n in vec_of_ref.iter().copied().flatten() { + println!("{:?}", n); + } + + let slice_of_ref = &[&Some(1)]; + for n in slice_of_ref.iter().copied().flatten() { + println!("{:?}", n); + } + + struct Test { + a: usize, + } + + let mut vec_of_struct = [Some(Test { a: 1 }), None]; + + // Usage of `if let` expression should not trigger lint + for n in vec_of_struct.iter_mut() { + if let Some(z) = n { + *n = None; + } + } + + // Using manual flatten should not trigger the lint + for n in vec![Some(1), Some(2), Some(3)].iter().flatten() { + println!("{}", n); + } + + // Using nested `Some` pattern should not trigger the lint + for n in vec![Some((1, Some(2)))] { + if let Some((_, Some(n))) = n { + println!("{}", n); + } + } + + macro_rules! inner { + ($id:ident / $new:pat => $action:expr) => { + if let Some($new) = $id { + $action; + } + }; + } + + // Usage of `if let` expression with macro should not trigger lint + for ab in [Some((1, 2)), Some((3, 4))] { + inner!(ab / (c, d) => println!("{c}-{d}")); + } + + macro_rules! args { + ($($arg:expr),*) => { + vec![$(Some($arg)),*] + }; + } + + // Usage of `if let` expression with macro should not trigger lint + for n in args!(1, 2, 3) { + if let Some(n) = n { + println!("{:?}", n); + } + } + + // This should trigger the lint, but the applicability is `MaybeIncorrect` + let z = vec![Some(1), Some(2), Some(3)]; + for n in z.into_iter().flatten() { + println!("{:?}", n); + } + + run_unformatted_tests(); +} + +#[rustfmt::skip] +fn run_unformatted_tests() { + // Skip rustfmt here on purpose so the suggestion does not fit in one line + for n in vec![ + //~^ manual_flatten + + Some(1), + Some(2), + Some(3) + ].iter().flatten() { + println!("{:?}", n); + } +} diff --git a/src/tools/clippy/tests/ui/manual_flatten.rs b/src/tools/clippy/tests/ui/manual_flatten.rs index f1a0053ef38..53b4ac7d3b6 100644 --- a/src/tools/clippy/tests/ui/manual_flatten.rs +++ b/src/tools/clippy/tests/ui/manual_flatten.rs @@ -1,6 +1,6 @@ #![warn(clippy::manual_flatten)] #![allow(clippy::useless_vec, clippy::uninlined_format_args)] -//@no-rustfix + fn main() { // Test for loop over implicitly adjusted `Iterator` with `if let` expression let x = vec![Some(1), Some(2), Some(3)]; @@ -130,6 +130,43 @@ fn main() { } } + macro_rules! inner { + ($id:ident / $new:pat => $action:expr) => { + if let Some($new) = $id { + $action; + } + }; + } + + // Usage of `if let` expression with macro should not trigger lint + for ab in [Some((1, 2)), Some((3, 4))] { + inner!(ab / (c, d) => println!("{c}-{d}")); + } + + macro_rules! args { + ($($arg:expr),*) => { + vec![$(Some($arg)),*] + }; + } + + // Usage of `if let` expression with macro should not trigger lint + for n in args!(1, 2, 3) { + if let Some(n) = n { + println!("{:?}", n); + } + } + + // This should trigger the lint, but the applicability is `MaybeIncorrect` + let z = vec![Some(1), Some(2), Some(3)]; + for n in z { + //~^ manual_flatten + + if let Some(n) = n { + println!("{:?}", n); + } + // foo + } + run_unformatted_tests(); } diff --git a/src/tools/clippy/tests/ui/manual_flatten.stderr b/src/tools/clippy/tests/ui/manual_flatten.stderr index 9a846fe17f3..eb39ee42071 100644 --- a/src/tools/clippy/tests/ui/manual_flatten.stderr +++ b/src/tools/clippy/tests/ui/manual_flatten.stderr @@ -1,10 +1,7 @@ error: unnecessary `if let` since only the `Some` variant of the iterator element is used --> tests/ui/manual_flatten.rs:7:5 | -LL | for n in x { - | ^ - help: try: `x.into_iter().flatten()` - | _____| - | | +LL | / for n in x { LL | | LL | | LL | | if let Some(y) = n { @@ -12,7 +9,7 @@ LL | | if let Some(y) = n { LL | | } | |_____^ | -help: ...and remove the `if let` statement in the for loop +help: try `.flatten()` and remove the `if let` statement in the for loop --> tests/ui/manual_flatten.rs:10:9 | LL | / if let Some(y) = n { @@ -21,14 +18,17 @@ LL | | } | |_________^ = note: `-D clippy::manual-flatten` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::manual_flatten)]` +help: try + | +LL ~ for y in x.into_iter().flatten() { +LL + println!("{}", y); +LL + } + | error: unnecessary `if let` since only the `Ok` variant of the iterator element is used --> tests/ui/manual_flatten.rs:17:5 | -LL | for n in y.clone() { - | ^ --------- help: try: `y.clone().into_iter().flatten()` - | _____| - | | +LL | / for n in y.clone() { LL | | LL | | LL | | if let Ok(n) = n { @@ -37,21 +37,24 @@ LL | | }; LL | | } | |_____^ | -help: ...and remove the `if let` statement in the for loop +help: try `.flatten()` and remove the `if let` statement in the for loop --> tests/ui/manual_flatten.rs:20:9 | LL | / if let Ok(n) = n { LL | | println!("{}", n); LL | | }; | |_________^ +help: try + | +LL ~ for n in y.clone().into_iter().flatten() { +LL + println!("{}", n); +LL + } + | error: unnecessary `if let` since only the `Ok` variant of the iterator element is used --> tests/ui/manual_flatten.rs:26:5 | -LL | for n in &y { - | ^ -- help: try: `y.iter().flatten()` - | _____| - | | +LL | / for n in &y { LL | | LL | | LL | | if let Ok(n) = n { @@ -59,21 +62,24 @@ LL | | if let Ok(n) = n { LL | | } | |_____^ | -help: ...and remove the `if let` statement in the for loop +help: try `.flatten()` and remove the `if let` statement in the for loop --> tests/ui/manual_flatten.rs:29:9 | LL | / if let Ok(n) = n { LL | | println!("{}", n); LL | | } | |_________^ +help: try + | +LL ~ for n in y.iter().flatten() { +LL + println!("{}", n); +LL + } + | error: unnecessary `if let` since only the `Ok` variant of the iterator element is used --> tests/ui/manual_flatten.rs:36:5 | -LL | for n in z { - | ^ - help: try: `z.iter().flatten()` - | _____| - | | +LL | / for n in z { LL | | LL | | LL | | if let Ok(n) = n { @@ -81,21 +87,24 @@ LL | | if let Ok(n) = n { LL | | } | |_____^ | -help: ...and remove the `if let` statement in the for loop +help: try `.flatten()` and remove the `if let` statement in the for loop --> tests/ui/manual_flatten.rs:39:9 | LL | / if let Ok(n) = n { LL | | println!("{}", n); LL | | } | |_________^ +help: try + | +LL ~ for n in z.iter().flatten() { +LL + println!("{}", n); +LL + } + | error: unnecessary `if let` since only the `Some` variant of the iterator element is used --> tests/ui/manual_flatten.rs:47:5 | -LL | for n in z { - | ^ - help: try: `z.flatten()` - | _____| - | | +LL | / for n in z { LL | | LL | | LL | | if let Some(m) = n { @@ -103,21 +112,24 @@ LL | | if let Some(m) = n { LL | | } | |_____^ | -help: ...and remove the `if let` statement in the for loop +help: try `.flatten()` and remove the `if let` statement in the for loop --> tests/ui/manual_flatten.rs:50:9 | LL | / if let Some(m) = n { LL | | println!("{}", m); LL | | } | |_________^ +help: try + | +LL ~ for m in z.flatten() { +LL + println!("{}", m); +LL + } + | error: unnecessary `if let` since only the `Some` variant of the iterator element is used --> tests/ui/manual_flatten.rs:82:5 | -LL | for n in &vec_of_ref { - | ^ ----------- help: try: `vec_of_ref.iter().copied().flatten()` - | _____| - | | +LL | / for n in &vec_of_ref { LL | | LL | | LL | | if let Some(n) = n { @@ -125,21 +137,24 @@ LL | | if let Some(n) = n { LL | | } | |_____^ | -help: ...and remove the `if let` statement in the for loop +help: try `.flatten()` and remove the `if let` statement in the for loop --> tests/ui/manual_flatten.rs:85:9 | LL | / if let Some(n) = n { LL | | println!("{:?}", n); LL | | } | |_________^ +help: try + | +LL ~ for n in vec_of_ref.iter().copied().flatten() { +LL + println!("{:?}", n); +LL + } + | error: unnecessary `if let` since only the `Some` variant of the iterator element is used --> tests/ui/manual_flatten.rs:91:5 | -LL | for n in vec_of_ref { - | ^ ---------- help: try: `vec_of_ref.iter().copied().flatten()` - | _____| - | | +LL | / for n in vec_of_ref { LL | | LL | | LL | | if let Some(n) = n { @@ -147,21 +162,24 @@ LL | | if let Some(n) = n { LL | | } | |_____^ | -help: ...and remove the `if let` statement in the for loop +help: try `.flatten()` and remove the `if let` statement in the for loop --> tests/ui/manual_flatten.rs:94:9 | LL | / if let Some(n) = n { LL | | println!("{:?}", n); LL | | } | |_________^ +help: try + | +LL ~ for n in vec_of_ref.iter().copied().flatten() { +LL + println!("{:?}", n); +LL + } + | error: unnecessary `if let` since only the `Some` variant of the iterator element is used --> tests/ui/manual_flatten.rs:100:5 | -LL | for n in slice_of_ref { - | ^ ------------ help: try: `slice_of_ref.iter().copied().flatten()` - | _____| - | | +LL | / for n in slice_of_ref { LL | | LL | | LL | | if let Some(n) = n { @@ -169,16 +187,47 @@ LL | | if let Some(n) = n { LL | | } | |_____^ | -help: ...and remove the `if let` statement in the for loop +help: try `.flatten()` and remove the `if let` statement in the for loop --> tests/ui/manual_flatten.rs:103:9 | LL | / if let Some(n) = n { LL | | println!("{:?}", n); LL | | } | |_________^ +help: try + | +LL ~ for n in slice_of_ref.iter().copied().flatten() { +LL + println!("{:?}", n); +LL + } + | + +error: unnecessary `if let` since only the `Some` variant of the iterator element is used + --> tests/ui/manual_flatten.rs:161:5 + | +LL | / for n in z { +LL | | +LL | | +LL | | if let Some(n) = n { +... | +LL | | } + | |_____^ + | +help: try `.flatten()` and remove the `if let` statement in the for loop + --> tests/ui/manual_flatten.rs:164:9 + | +LL | / if let Some(n) = n { +LL | | println!("{:?}", n); +LL | | } + | |_________^ +help: try + | +LL ~ for n in z.into_iter().flatten() { +LL + println!("{:?}", n); +LL + } + | error: unnecessary `if let` since only the `Some` variant of the iterator element is used - --> tests/ui/manual_flatten.rs:139:5 + --> tests/ui/manual_flatten.rs:176:5 | LL | / for n in vec![ LL | | @@ -188,8 +237,8 @@ LL | | Some(1), LL | | } | |_____^ | -help: remove the `if let` statement in the for loop and then... - --> tests/ui/manual_flatten.rs:146:9 +help: try `.flatten()` and remove the `if let` statement in the for loop + --> tests/ui/manual_flatten.rs:183:9 | LL | / if let Some(n) = n { LL | | println!("{:?}", n); @@ -201,7 +250,9 @@ LL | for n in vec![ ... LL | Some(3) LL ~ ].iter().flatten() { +LL + println!("{:?}", n); +LL + } | -error: aborting due to 9 previous errors +error: aborting due to 10 previous errors diff --git a/src/tools/clippy/tests/ui/manual_swap_auto_fix.fixed b/src/tools/clippy/tests/ui/manual_swap_auto_fix.fixed index 28466ff3f9b..6cd81bafce8 100644 --- a/src/tools/clippy/tests/ui/manual_swap_auto_fix.fixed +++ b/src/tools/clippy/tests/ui/manual_swap_auto_fix.fixed @@ -55,3 +55,14 @@ fn swap8() { let i2 = 1; v.swap(i1 + i2, i2); } + +fn issue_14931() { + let mut v = [1, 2, 3, 4]; + + let mut i1 = 0; + for i2 in 0..4 { + v.swap(i1, i2); + + i1 += 2; + } +} diff --git a/src/tools/clippy/tests/ui/manual_swap_auto_fix.rs b/src/tools/clippy/tests/ui/manual_swap_auto_fix.rs index c9880e651cd..19dabfd833f 100644 --- a/src/tools/clippy/tests/ui/manual_swap_auto_fix.rs +++ b/src/tools/clippy/tests/ui/manual_swap_auto_fix.rs @@ -78,3 +78,17 @@ fn swap8() { v[i1 + i2] = v[i2]; v[i2] = tmp; } + +fn issue_14931() { + let mut v = [1, 2, 3, 4]; + + let mut i1 = 0; + for i2 in 0..4 { + let tmp = v[i1]; + //~^ manual_swap + v[i1] = v[i2]; + v[i2] = tmp; + + i1 += 2; + } +} diff --git a/src/tools/clippy/tests/ui/manual_swap_auto_fix.stderr b/src/tools/clippy/tests/ui/manual_swap_auto_fix.stderr index 7ab898fcc72..a0bb32233e2 100644 --- a/src/tools/clippy/tests/ui/manual_swap_auto_fix.stderr +++ b/src/tools/clippy/tests/ui/manual_swap_auto_fix.stderr @@ -92,5 +92,14 @@ LL | | v[i1 + i2] = v[i2]; LL | | v[i2] = tmp; | |________________^ help: try: `v.swap(i1 + i2, i2);` -error: aborting due to 8 previous errors +error: this looks like you are swapping elements of `v` manually + --> tests/ui/manual_swap_auto_fix.rs:87:9 + | +LL | / let tmp = v[i1]; +LL | | +LL | | v[i1] = v[i2]; +LL | | v[i2] = tmp; + | |____________________^ help: try: `v.swap(i1, i2);` + +error: aborting due to 9 previous errors diff --git a/src/tools/clippy/tests/ui/match_single_binding.fixed b/src/tools/clippy/tests/ui/match_single_binding.fixed index bdf39796ebf..e11dea35204 100644 --- a/src/tools/clippy/tests/ui/match_single_binding.fixed +++ b/src/tools/clippy/tests/ui/match_single_binding.fixed @@ -188,3 +188,19 @@ fn issue14634() { let id!(_a) = dbg!(b + 1); //~^^^ match_single_binding } + +mod issue14991 { + struct AnnoConstWOBlock { + inner: [(); { + let _n = 1; + 42 + }], + } + + struct AnnoConstWBlock { + inner: [(); { + let _n = 1; + 42 + }], + } +} diff --git a/src/tools/clippy/tests/ui/match_single_binding.rs b/src/tools/clippy/tests/ui/match_single_binding.rs index 419ff95d873..d498da30fc8 100644 --- a/src/tools/clippy/tests/ui/match_single_binding.rs +++ b/src/tools/clippy/tests/ui/match_single_binding.rs @@ -249,3 +249,21 @@ fn issue14634() { }; //~^^^ match_single_binding } + +mod issue14991 { + struct AnnoConstWOBlock { + inner: [(); match 1 { + //~^ match_single_binding + _n => 42, + }], + } + + struct AnnoConstWBlock { + inner: [(); { + match 1 { + //~^ match_single_binding + _n => 42, + } + }], + } +} diff --git a/src/tools/clippy/tests/ui/match_single_binding.stderr b/src/tools/clippy/tests/ui/match_single_binding.stderr index bdd0134a5f1..f274f80c81d 100644 --- a/src/tools/clippy/tests/ui/match_single_binding.stderr +++ b/src/tools/clippy/tests/ui/match_single_binding.stderr @@ -378,5 +378,38 @@ LL ~ let id!(b) = dbg!(3); LL + let id!(_a) = dbg!(b + 1); | -error: aborting due to 27 previous errors +error: this match could be written as a `let` statement + --> tests/ui/match_single_binding.rs:255:21 + | +LL | inner: [(); match 1 { + | _____________________^ +LL | | +LL | | _n => 42, +LL | | }], + | |_________^ + | +help: consider using a `let` statement + | +LL ~ inner: [(); { +LL + let _n = 1; +LL + 42 +LL ~ }], + | + +error: this match could be written as a `let` statement + --> tests/ui/match_single_binding.rs:263:13 + | +LL | / match 1 { +LL | | +LL | | _n => 42, +LL | | } + | |_____________^ + | +help: consider using a `let` statement + | +LL ~ let _n = 1; +LL + 42 + | + +error: aborting due to 29 previous errors diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.fixed b/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.fixed new file mode 100644 index 00000000000..7e0d4fccaae --- /dev/null +++ b/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.fixed @@ -0,0 +1,36 @@ +#![feature(const_trait_impl)] +#![warn(clippy::missing_const_for_fn)] + +// Reduced test case from https://github.com/rust-lang/rust-clippy/issues/14658 + +#[const_trait] +trait ConstTrait { + fn method(self); +} + +impl ConstTrait for u32 { + fn method(self) {} +} + +impl const ConstTrait for u64 { + fn method(self) {} +} + +fn cannot_be_const() { + 0u32.method(); +} + +//~v missing_const_for_fn +const fn can_be_const() { + 0u64.method(); +} + +// False negative, see FIXME comment in `clipy_utils::qualify_min_const` +fn could_be_const_but_does_not_trigger<T>(t: T) +where + T: const ConstTrait, +{ + t.method(); +} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.rs b/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.rs new file mode 100644 index 00000000000..439da4622d7 --- /dev/null +++ b/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.rs @@ -0,0 +1,36 @@ +#![feature(const_trait_impl)] +#![warn(clippy::missing_const_for_fn)] + +// Reduced test case from https://github.com/rust-lang/rust-clippy/issues/14658 + +#[const_trait] +trait ConstTrait { + fn method(self); +} + +impl ConstTrait for u32 { + fn method(self) {} +} + +impl const ConstTrait for u64 { + fn method(self) {} +} + +fn cannot_be_const() { + 0u32.method(); +} + +//~v missing_const_for_fn +fn can_be_const() { + 0u64.method(); +} + +// False negative, see FIXME comment in `clipy_utils::qualify_min_const` +fn could_be_const_but_does_not_trigger<T>(t: T) +where + T: const ConstTrait, +{ + t.method(); +} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.stderr b/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.stderr new file mode 100644 index 00000000000..b994b88fac6 --- /dev/null +++ b/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.stderr @@ -0,0 +1,17 @@ +error: this could be a `const fn` + --> tests/ui/missing_const_for_fn/const_trait.rs:24:1 + | +LL | / fn can_be_const() { +LL | | 0u64.method(); +LL | | } + | |_^ + | + = note: `-D clippy::missing-const-for-fn` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::missing_const_for_fn)]` +help: make the function `const` + | +LL | const fn can_be_const() { + | +++++ + +error: aborting due to 1 previous error + diff --git a/src/tools/clippy/tests/ui/needless_lifetimes.fixed b/src/tools/clippy/tests/ui/needless_lifetimes.fixed index ceea4480d0d..15ca409c95b 100644 --- a/src/tools/clippy/tests/ui/needless_lifetimes.fixed +++ b/src/tools/clippy/tests/ui/needless_lifetimes.fixed @@ -10,7 +10,7 @@ clippy::unnecessary_wraps, dyn_drop, clippy::get_first, - mismatched_lifetime_syntaxes, + mismatched_lifetime_syntaxes )] extern crate proc_macros; diff --git a/src/tools/clippy/tests/ui/needless_lifetimes.rs b/src/tools/clippy/tests/ui/needless_lifetimes.rs index 8432f9e6d2f..af9649d7298 100644 --- a/src/tools/clippy/tests/ui/needless_lifetimes.rs +++ b/src/tools/clippy/tests/ui/needless_lifetimes.rs @@ -10,7 +10,7 @@ clippy::unnecessary_wraps, dyn_drop, clippy::get_first, - mismatched_lifetime_syntaxes, + mismatched_lifetime_syntaxes )] extern crate proc_macros; diff --git a/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.fixed b/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.fixed index 23dbee5a084..6915e1984fb 100644 --- a/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.fixed +++ b/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.fixed @@ -195,3 +195,19 @@ impl PartialOrd for K { //~^ non_canonical_partial_ord_impl fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(self.cmp(other)) } } + +// #14574, check that partial_cmp invokes other.cmp + +#[derive(Eq, PartialEq)] +struct L(u32); + +impl Ord for L { + fn cmp(&self, other: &Self) -> Ordering { + todo!(); + } +} + +impl PartialOrd for L { + //~^ non_canonical_partial_ord_impl + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(self.cmp(other)) } +} diff --git a/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.rs b/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.rs index 12f055a542b..7ce4cdc9aec 100644 --- a/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.rs +++ b/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.rs @@ -201,3 +201,21 @@ impl PartialOrd for K { Ordering::Greater.into() } } + +// #14574, check that partial_cmp invokes other.cmp + +#[derive(Eq, PartialEq)] +struct L(u32); + +impl Ord for L { + fn cmp(&self, other: &Self) -> Ordering { + todo!(); + } +} + +impl PartialOrd for L { + //~^ non_canonical_partial_ord_impl + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { + Some(other.cmp(self)) + } +} diff --git a/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.stderr b/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.stderr index c7de968588f..9bd6b1f726d 100644 --- a/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.stderr +++ b/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.stderr @@ -44,5 +44,18 @@ LL | || } LL | | } | |__^ -error: aborting due to 3 previous errors +error: non-canonical implementation of `partial_cmp` on an `Ord` type + --> tests/ui/non_canonical_partial_ord_impl.rs:216:1 + | +LL | / impl PartialOrd for L { +LL | | +LL | | fn partial_cmp(&self, other: &Self) -> Option<Ordering> { + | | _____________________________________________________________- +LL | || Some(other.cmp(self)) +LL | || } + | ||_____- help: change this to: `{ Some(self.cmp(other)) }` +LL | | } + | |__^ + +error: aborting due to 4 previous errors diff --git a/src/tools/clippy/tests/ui/pointer_format.rs b/src/tools/clippy/tests/ui/pointer_format.rs new file mode 100644 index 00000000000..0621f966ad1 --- /dev/null +++ b/src/tools/clippy/tests/ui/pointer_format.rs @@ -0,0 +1,66 @@ +#![warn(clippy::pointer_format)] + +use core::fmt::Debug; +use core::marker::PhantomData; + +#[derive(Debug)] +struct ContainsPointerDeep { + w: WithPointer, +} + +struct ManualDebug { + ptr: *const u8, +} + +#[derive(Debug)] +struct WithPointer { + len: usize, + ptr: *const u8, +} + +impl std::fmt::Debug for ManualDebug { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + f.write_str("ManualDebug") + } +} + +trait Foo { + type Assoc: Foo + Debug; +} + +#[derive(Debug)] +struct S<T: Foo + 'static>(&'static S<T::Assoc>, PhantomData<T>); + +#[allow(unused)] +fn unbounded<T: Foo + Debug + 'static>(s: &S<T>) { + format!("{s:?}"); +} + +fn main() { + let m = &(main as fn()); + let g = &0; + let o = &format!("{m:p}"); + //~^ pointer_format + let _ = format!("{m:?}"); + //~^ pointer_format + println!("{g:p}"); + //~^ pointer_format + panic!("{o:p}"); + //~^ pointer_format + let answer = 42; + let x = &raw const answer; + let arr = [0u8; 8]; + let with_ptr = WithPointer { len: 8, ptr: &arr as _ }; + let _ = format!("{x:?}"); + //~^ pointer_format + print!("{with_ptr:?}"); + //~^ pointer_format + let container = ContainsPointerDeep { w: with_ptr }; + print!("{container:?}"); + //~^ pointer_format + + let no_pointer = "foo"; + println!("{no_pointer:?}"); + let manual_debug = ManualDebug { ptr: &arr as _ }; + println!("{manual_debug:?}"); +} diff --git a/src/tools/clippy/tests/ui/pointer_format.stderr b/src/tools/clippy/tests/ui/pointer_format.stderr new file mode 100644 index 00000000000..21ba39b8f8c --- /dev/null +++ b/src/tools/clippy/tests/ui/pointer_format.stderr @@ -0,0 +1,47 @@ +error: pointer formatting detected + --> tests/ui/pointer_format.rs:42:23 + | +LL | let o = &format!("{m:p}"); + | ^^^^^ + | + = note: `-D clippy::pointer-format` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::pointer_format)]` + +error: pointer formatting detected + --> tests/ui/pointer_format.rs:44:22 + | +LL | let _ = format!("{m:?}"); + | ^^^^^ + +error: pointer formatting detected + --> tests/ui/pointer_format.rs:46:15 + | +LL | println!("{g:p}"); + | ^^^^^ + +error: pointer formatting detected + --> tests/ui/pointer_format.rs:48:13 + | +LL | panic!("{o:p}"); + | ^^^^^ + +error: pointer formatting detected + --> tests/ui/pointer_format.rs:54:22 + | +LL | let _ = format!("{x:?}"); + | ^^^^^ + +error: pointer formatting detected + --> tests/ui/pointer_format.rs:56:13 + | +LL | print!("{with_ptr:?}"); + | ^^^^^^^^^^^^ + +error: pointer formatting detected + --> tests/ui/pointer_format.rs:59:13 + | +LL | print!("{container:?}"); + | ^^^^^^^^^^^^^ + +error: aborting due to 7 previous errors + diff --git a/src/tools/clippy/tests/ui/print_literal.fixed b/src/tools/clippy/tests/ui/print_literal.fixed index 24c45a4a61b..ebfe19c700e 100644 --- a/src/tools/clippy/tests/ui/print_literal.fixed +++ b/src/tools/clippy/tests/ui/print_literal.fixed @@ -94,3 +94,14 @@ fn issue_13959() { " ); } + +fn issue_14930() { + println!("Hello x is {0:2$.1$}", 0.01, 2, 3); + //~^ print_literal + println!("Hello x is {0:2$.1$}", 0.01, 2, 3); + //~^ print_literal + println!("Hello x is {0:2$.1$}", 0.01, 2, 3); + //~^ print_literal + println!("Hello x is {0:2$.1$}", 0.01, 2, 3); + //~^ print_literal +} diff --git a/src/tools/clippy/tests/ui/print_literal.rs b/src/tools/clippy/tests/ui/print_literal.rs index 42ae589ca63..8f3d9be0698 100644 --- a/src/tools/clippy/tests/ui/print_literal.rs +++ b/src/tools/clippy/tests/ui/print_literal.rs @@ -95,3 +95,14 @@ fn issue_13959() { "# ); } + +fn issue_14930() { + println!("Hello {3} is {0:2$.1$}", 0.01, 2, 3, "x"); + //~^ print_literal + println!("Hello {2} is {0:3$.1$}", 0.01, 2, "x", 3); + //~^ print_literal + println!("Hello {1} is {0:3$.2$}", 0.01, "x", 2, 3); + //~^ print_literal + println!("Hello {0} is {1:3$.2$}", "x", 0.01, 2, 3); + //~^ print_literal +} diff --git a/src/tools/clippy/tests/ui/print_literal.stderr b/src/tools/clippy/tests/ui/print_literal.stderr index da663000686..1c378017d15 100644 --- a/src/tools/clippy/tests/ui/print_literal.stderr +++ b/src/tools/clippy/tests/ui/print_literal.stderr @@ -229,5 +229,53 @@ LL + bar LL ~ " | -error: aborting due to 18 previous errors +error: literal with an empty format string + --> tests/ui/print_literal.rs:100:52 + | +LL | println!("Hello {3} is {0:2$.1$}", 0.01, 2, 3, "x"); + | ^^^ + | +help: try + | +LL - println!("Hello {3} is {0:2$.1$}", 0.01, 2, 3, "x"); +LL + println!("Hello x is {0:2$.1$}", 0.01, 2, 3); + | + +error: literal with an empty format string + --> tests/ui/print_literal.rs:102:49 + | +LL | println!("Hello {2} is {0:3$.1$}", 0.01, 2, "x", 3); + | ^^^ + | +help: try + | +LL - println!("Hello {2} is {0:3$.1$}", 0.01, 2, "x", 3); +LL + println!("Hello x is {0:2$.1$}", 0.01, 2, 3); + | + +error: literal with an empty format string + --> tests/ui/print_literal.rs:104:46 + | +LL | println!("Hello {1} is {0:3$.2$}", 0.01, "x", 2, 3); + | ^^^ + | +help: try + | +LL - println!("Hello {1} is {0:3$.2$}", 0.01, "x", 2, 3); +LL + println!("Hello x is {0:2$.1$}", 0.01, 2, 3); + | + +error: literal with an empty format string + --> tests/ui/print_literal.rs:106:40 + | +LL | println!("Hello {0} is {1:3$.2$}", "x", 0.01, 2, 3); + | ^^^ + | +help: try + | +LL - println!("Hello {0} is {1:3$.2$}", "x", 0.01, 2, 3); +LL + println!("Hello x is {0:2$.1$}", 0.01, 2, 3); + | + +error: aborting due to 22 previous errors diff --git a/src/tools/clippy/tests/ui/semicolon_outside_block.fixed b/src/tools/clippy/tests/ui/semicolon_outside_block.fixed index 52fae9a3aff..a3be80b4928 100644 --- a/src/tools/clippy/tests/ui/semicolon_outside_block.fixed +++ b/src/tools/clippy/tests/ui/semicolon_outside_block.fixed @@ -96,3 +96,28 @@ fn main() { unit_fn_block() } + +fn issue14926() { + macro_rules! gen_code { + [$l:lifetime: $b:block, $b2: block $(,)?] => { + $l: loop { + $b + break $l; + } + $l: loop { + $b2 + break $l; + } + }; + } + + gen_code! { + 'root: + { + println!("Block1"); + }, + { + println!("Block2"); + }, + } +} diff --git a/src/tools/clippy/tests/ui/semicolon_outside_block.rs b/src/tools/clippy/tests/ui/semicolon_outside_block.rs index 5975e66fbb8..3b7bf68029f 100644 --- a/src/tools/clippy/tests/ui/semicolon_outside_block.rs +++ b/src/tools/clippy/tests/ui/semicolon_outside_block.rs @@ -96,3 +96,28 @@ fn main() { unit_fn_block() } + +fn issue14926() { + macro_rules! gen_code { + [$l:lifetime: $b:block, $b2: block $(,)?] => { + $l: loop { + $b + break $l; + } + $l: loop { + $b2 + break $l; + } + }; + } + + gen_code! { + 'root: + { + println!("Block1"); + }, + { + println!("Block2"); + }, + } +} diff --git a/src/tools/clippy/tests/ui/std_instead_of_core.fixed b/src/tools/clippy/tests/ui/std_instead_of_core.fixed index ab2e801eee2..1820ade422f 100644 --- a/src/tools/clippy/tests/ui/std_instead_of_core.fixed +++ b/src/tools/clippy/tests/ui/std_instead_of_core.fixed @@ -90,3 +90,9 @@ fn msrv_1_76(_: std::net::IpAddr) {} #[clippy::msrv = "1.77"] fn msrv_1_77(_: core::net::IpAddr) {} //~^ std_instead_of_core + +#[warn(clippy::std_instead_of_core)] +#[rustfmt::skip] +fn issue14982() { + use std::{collections::HashMap, hash::Hash}; +} diff --git a/src/tools/clippy/tests/ui/std_instead_of_core.rs b/src/tools/clippy/tests/ui/std_instead_of_core.rs index f760b3561ae..32c49330981 100644 --- a/src/tools/clippy/tests/ui/std_instead_of_core.rs +++ b/src/tools/clippy/tests/ui/std_instead_of_core.rs @@ -90,3 +90,9 @@ fn msrv_1_76(_: std::net::IpAddr) {} #[clippy::msrv = "1.77"] fn msrv_1_77(_: std::net::IpAddr) {} //~^ std_instead_of_core + +#[warn(clippy::std_instead_of_core)] +#[rustfmt::skip] +fn issue14982() { + use std::{collections::HashMap, hash::Hash}; +} diff --git a/src/tools/clippy/tests/ui/unit_arg.rs b/src/tools/clippy/tests/ui/unit_arg.rs index 22a6a26dab6..4208efad677 100644 --- a/src/tools/clippy/tests/ui/unit_arg.rs +++ b/src/tools/clippy/tests/ui/unit_arg.rs @@ -151,3 +151,27 @@ fn main() { bad(); ok(); } + +fn issue14857() { + let fn_take_unit = |_: ()| {}; + fn some_other_fn(_: &i32) {} + + macro_rules! mac { + (def) => { + Default::default() + }; + (func $f:expr) => { + $f() + }; + (nonempty_block $e:expr) => {{ + some_other_fn(&$e); + $e + }}; + } + fn_take_unit(mac!(def)); + //~^ unit_arg + fn_take_unit(mac!(func Default::default)); + //~^ unit_arg + fn_take_unit(mac!(nonempty_block Default::default())); + //~^ unit_arg +} diff --git a/src/tools/clippy/tests/ui/unit_arg.stderr b/src/tools/clippy/tests/ui/unit_arg.stderr index 6c333d9792d..0dcfb02b9fa 100644 --- a/src/tools/clippy/tests/ui/unit_arg.stderr +++ b/src/tools/clippy/tests/ui/unit_arg.stderr @@ -199,5 +199,26 @@ LL ~ foo(1); LL + Some(()) | -error: aborting due to 10 previous errors +error: passing a unit value to a function + --> tests/ui/unit_arg.rs:171:5 + | +LL | fn_take_unit(mac!(def)); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + +error: passing a unit value to a function + --> tests/ui/unit_arg.rs:173:5 + | +LL | fn_take_unit(mac!(func Default::default)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + +error: passing a unit value to a function + --> tests/ui/unit_arg.rs:175:5 + | +LL | fn_take_unit(mac!(nonempty_block Default::default())); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + +error: aborting due to 13 previous errors diff --git a/src/tools/clippy/tests/ui/unit_arg_empty_blocks.fixed b/src/tools/clippy/tests/ui/unit_arg_empty_blocks.fixed deleted file mode 100644 index b045a33608d..00000000000 --- a/src/tools/clippy/tests/ui/unit_arg_empty_blocks.fixed +++ /dev/null @@ -1,34 +0,0 @@ -#![warn(clippy::unit_arg)] -#![allow(unused_must_use, unused_variables)] -#![allow(clippy::no_effect, clippy::uninlined_format_args)] - -use std::fmt::Debug; - -fn foo<T: Debug>(t: T) { - println!("{:?}", t); -} - -fn foo3<T1: Debug, T2: Debug, T3: Debug>(t1: T1, t2: T2, t3: T3) { - println!("{:?}, {:?}, {:?}", t1, t2, t3); -} - -fn bad() { - foo(()); - //~^ unit_arg - foo3((), 2, 2); - //~^ unit_arg - foo(0); - taking_two_units((), ()); - //~^ unit_arg - foo(0); - foo(1); - taking_three_units((), (), ()); - //~^ unit_arg -} - -fn taking_two_units(a: (), b: ()) {} -fn taking_three_units(a: (), b: (), c: ()) {} - -fn main() { - bad(); -} diff --git a/src/tools/clippy/tests/ui/unit_arg_empty_blocks.rs b/src/tools/clippy/tests/ui/unit_arg_empty_blocks.rs deleted file mode 100644 index ab305913f3f..00000000000 --- a/src/tools/clippy/tests/ui/unit_arg_empty_blocks.rs +++ /dev/null @@ -1,31 +0,0 @@ -#![warn(clippy::unit_arg)] -#![allow(unused_must_use, unused_variables)] -#![allow(clippy::no_effect, clippy::uninlined_format_args)] - -use std::fmt::Debug; - -fn foo<T: Debug>(t: T) { - println!("{:?}", t); -} - -fn foo3<T1: Debug, T2: Debug, T3: Debug>(t1: T1, t2: T2, t3: T3) { - println!("{:?}, {:?}, {:?}", t1, t2, t3); -} - -fn bad() { - foo({}); - //~^ unit_arg - foo3({}, 2, 2); - //~^ unit_arg - taking_two_units({}, foo(0)); - //~^ unit_arg - taking_three_units({}, foo(0), foo(1)); - //~^ unit_arg -} - -fn taking_two_units(a: (), b: ()) {} -fn taking_three_units(a: (), b: (), c: ()) {} - -fn main() { - bad(); -} diff --git a/src/tools/clippy/tests/ui/unit_arg_empty_blocks.stderr b/src/tools/clippy/tests/ui/unit_arg_empty_blocks.stderr deleted file mode 100644 index 2c686d58ecc..00000000000 --- a/src/tools/clippy/tests/ui/unit_arg_empty_blocks.stderr +++ /dev/null @@ -1,46 +0,0 @@ -error: passing a unit value to a function - --> tests/ui/unit_arg_empty_blocks.rs:16:5 - | -LL | foo({}); - | ^^^^--^ - | | - | help: use a unit literal instead: `()` - | - = note: `-D clippy::unit-arg` implied by `-D warnings` - = help: to override `-D warnings` add `#[allow(clippy::unit_arg)]` - -error: passing a unit value to a function - --> tests/ui/unit_arg_empty_blocks.rs:18:5 - | -LL | foo3({}, 2, 2); - | ^^^^^--^^^^^^^ - | | - | help: use a unit literal instead: `()` - -error: passing unit values to a function - --> tests/ui/unit_arg_empty_blocks.rs:20:5 - | -LL | taking_two_units({}, foo(0)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: move the expression in front of the call and replace it with the unit literal `()` - | -LL ~ foo(0); -LL ~ taking_two_units((), ()); - | - -error: passing unit values to a function - --> tests/ui/unit_arg_empty_blocks.rs:22:5 - | -LL | taking_three_units({}, foo(0), foo(1)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: move the expressions in front of the call and replace them with the unit literal `()` - | -LL ~ foo(0); -LL + foo(1); -LL ~ taking_three_units((), (), ()); - | - -error: aborting due to 4 previous errors - diff --git a/src/tools/clippy/tests/ui/unit_arg_fixable.fixed b/src/tools/clippy/tests/ui/unit_arg_fixable.fixed new file mode 100644 index 00000000000..03353a14081 --- /dev/null +++ b/src/tools/clippy/tests/ui/unit_arg_fixable.fixed @@ -0,0 +1,78 @@ +#![warn(clippy::unit_arg)] +#![allow(unused_must_use, unused_variables)] +#![allow(clippy::no_effect, clippy::uninlined_format_args)] + +use std::fmt::Debug; + +fn foo<T: Debug>(t: T) { + println!("{:?}", t); +} + +fn foo3<T1: Debug, T2: Debug, T3: Debug>(t1: T1, t2: T2, t3: T3) { + println!("{:?}, {:?}, {:?}", t1, t2, t3); +} + +fn bad() { + foo(()); + //~^ unit_arg + foo3((), 2, 2); + //~^ unit_arg + foo(0); + taking_two_units((), ()); + //~^ unit_arg + foo(0); + foo(1); + taking_three_units((), (), ()); + //~^ unit_arg +} + +fn taking_two_units(a: (), b: ()) {} +fn taking_three_units(a: (), b: (), c: ()) {} + +fn main() { + bad(); +} + +fn issue14857() { + let fn_take_unit = |_: ()| {}; + fn_take_unit(()); + //~^ unit_arg + + fn some_other_fn(_: &i32) {} + + macro_rules! another_mac { + () => { + some_other_fn(&Default::default()) + }; + ($e:expr) => { + some_other_fn(&$e) + }; + } + + another_mac!(); + fn_take_unit(()); + //~^ unit_arg + another_mac!(1); + fn_take_unit(()); + //~^ unit_arg + + macro_rules! mac { + (nondef $e:expr) => { + $e + }; + (empty_block) => {{}}; + } + fn_take_unit(mac!(nondef ())); + //~^ unit_arg + mac!(empty_block); + fn_take_unit(()); + //~^ unit_arg + + fn def<T: Default>() -> T { + Default::default() + } + + let _: () = def(); + fn_take_unit(()); + //~^ unit_arg +} diff --git a/src/tools/clippy/tests/ui/unit_arg_fixable.rs b/src/tools/clippy/tests/ui/unit_arg_fixable.rs new file mode 100644 index 00000000000..03fd96efdf9 --- /dev/null +++ b/src/tools/clippy/tests/ui/unit_arg_fixable.rs @@ -0,0 +1,71 @@ +#![warn(clippy::unit_arg)] +#![allow(unused_must_use, unused_variables)] +#![allow(clippy::no_effect, clippy::uninlined_format_args)] + +use std::fmt::Debug; + +fn foo<T: Debug>(t: T) { + println!("{:?}", t); +} + +fn foo3<T1: Debug, T2: Debug, T3: Debug>(t1: T1, t2: T2, t3: T3) { + println!("{:?}, {:?}, {:?}", t1, t2, t3); +} + +fn bad() { + foo({}); + //~^ unit_arg + foo3({}, 2, 2); + //~^ unit_arg + taking_two_units({}, foo(0)); + //~^ unit_arg + taking_three_units({}, foo(0), foo(1)); + //~^ unit_arg +} + +fn taking_two_units(a: (), b: ()) {} +fn taking_three_units(a: (), b: (), c: ()) {} + +fn main() { + bad(); +} + +fn issue14857() { + let fn_take_unit = |_: ()| {}; + fn_take_unit(Default::default()); + //~^ unit_arg + + fn some_other_fn(_: &i32) {} + + macro_rules! another_mac { + () => { + some_other_fn(&Default::default()) + }; + ($e:expr) => { + some_other_fn(&$e) + }; + } + + fn_take_unit(another_mac!()); + //~^ unit_arg + fn_take_unit(another_mac!(1)); + //~^ unit_arg + + macro_rules! mac { + (nondef $e:expr) => { + $e + }; + (empty_block) => {{}}; + } + fn_take_unit(mac!(nondef Default::default())); + //~^ unit_arg + fn_take_unit(mac!(empty_block)); + //~^ unit_arg + + fn def<T: Default>() -> T { + Default::default() + } + + fn_take_unit(def()); + //~^ unit_arg +} diff --git a/src/tools/clippy/tests/ui/unit_arg_fixable.stderr b/src/tools/clippy/tests/ui/unit_arg_fixable.stderr new file mode 100644 index 00000000000..ccd5aa8322f --- /dev/null +++ b/src/tools/clippy/tests/ui/unit_arg_fixable.stderr @@ -0,0 +1,110 @@ +error: passing a unit value to a function + --> tests/ui/unit_arg_fixable.rs:16:5 + | +LL | foo({}); + | ^^^^--^ + | | + | help: use a unit literal instead: `()` + | + = note: `-D clippy::unit-arg` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(clippy::unit_arg)]` + +error: passing a unit value to a function + --> tests/ui/unit_arg_fixable.rs:18:5 + | +LL | foo3({}, 2, 2); + | ^^^^^--^^^^^^^ + | | + | help: use a unit literal instead: `()` + +error: passing unit values to a function + --> tests/ui/unit_arg_fixable.rs:20:5 + | +LL | taking_two_units({}, foo(0)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: move the expression in front of the call and replace it with the unit literal `()` + | +LL ~ foo(0); +LL ~ taking_two_units((), ()); + | + +error: passing unit values to a function + --> tests/ui/unit_arg_fixable.rs:22:5 + | +LL | taking_three_units({}, foo(0), foo(1)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: move the expressions in front of the call and replace them with the unit literal `()` + | +LL ~ foo(0); +LL + foo(1); +LL ~ taking_three_units((), (), ()); + | + +error: passing a unit value to a function + --> tests/ui/unit_arg_fixable.rs:35:5 + | +LL | fn_take_unit(Default::default()); + | ^^^^^^^^^^^^^------------------^ + | | + | help: use a unit literal instead: `()` + +error: passing a unit value to a function + --> tests/ui/unit_arg_fixable.rs:49:5 + | +LL | fn_take_unit(another_mac!()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: move the expression in front of the call and replace it with the unit literal `()` + | +LL ~ another_mac!(); +LL ~ fn_take_unit(()); + | + +error: passing a unit value to a function + --> tests/ui/unit_arg_fixable.rs:51:5 + | +LL | fn_take_unit(another_mac!(1)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: move the expression in front of the call and replace it with the unit literal `()` + | +LL ~ another_mac!(1); +LL ~ fn_take_unit(()); + | + +error: passing a unit value to a function + --> tests/ui/unit_arg_fixable.rs:60:5 + | +LL | fn_take_unit(mac!(nondef Default::default())); + | ^^^^^^^^^^^^^^^^^^^^^^^^^------------------^^ + | | + | help: use a unit literal instead: `()` + +error: passing a unit value to a function + --> tests/ui/unit_arg_fixable.rs:62:5 + | +LL | fn_take_unit(mac!(empty_block)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: move the expression in front of the call and replace it with the unit literal `()` + | +LL ~ mac!(empty_block); +LL ~ fn_take_unit(()); + | + +error: passing a unit value to a function + --> tests/ui/unit_arg_fixable.rs:69:5 + | +LL | fn_take_unit(def()); + | ^^^^^^^^^^^^^^^^^^^ + | +help: move the expression in front of the call and replace it with the unit literal `()` + | +LL ~ let _: () = def(); +LL ~ fn_take_unit(()); + | + +error: aborting due to 10 previous errors + diff --git a/src/tools/clippy/tests/ui/unused_unit.edition2021.fixed b/src/tools/clippy/tests/ui/unused_unit.edition2021.fixed index 93dd58b8e9d..def8ef86e3c 100644 --- a/src/tools/clippy/tests/ui/unused_unit.edition2021.fixed +++ b/src/tools/clippy/tests/ui/unused_unit.edition2021.fixed @@ -143,4 +143,10 @@ mod issue14577 { todo!() } } -} \ No newline at end of file +} + +mod pr14962 { + #[allow(unused_parens)] + type UnusedParensButNoUnit = Box<dyn (Fn())>; +} + diff --git a/src/tools/clippy/tests/ui/unused_unit.edition2024.fixed b/src/tools/clippy/tests/ui/unused_unit.edition2024.fixed index 987d901b97d..f908b958b19 100644 --- a/src/tools/clippy/tests/ui/unused_unit.edition2024.fixed +++ b/src/tools/clippy/tests/ui/unused_unit.edition2024.fixed @@ -143,4 +143,10 @@ mod issue14577 { todo!() } } -} \ No newline at end of file +} + +mod pr14962 { + #[allow(unused_parens)] + type UnusedParensButNoUnit = Box<dyn (Fn())>; +} + diff --git a/src/tools/clippy/tests/ui/unused_unit.rs b/src/tools/clippy/tests/ui/unused_unit.rs index b7645f7b6a2..7298ec40cc2 100644 --- a/src/tools/clippy/tests/ui/unused_unit.rs +++ b/src/tools/clippy/tests/ui/unused_unit.rs @@ -143,4 +143,10 @@ mod issue14577 { todo!() } } -} \ No newline at end of file +} + +mod pr14962 { + #[allow(unused_parens)] + type UnusedParensButNoUnit = Box<dyn (Fn())>; +} + diff --git a/src/tools/clippy/tests/ui/write_literal.fixed b/src/tools/clippy/tests/ui/write_literal.fixed index e84f768e33d..29352fd468e 100644 --- a/src/tools/clippy/tests/ui/write_literal.fixed +++ b/src/tools/clippy/tests/ui/write_literal.fixed @@ -87,3 +87,15 @@ fn issue_13959() { " ); } + +fn issue_14930() { + let mut v = Vec::new(); + writeln!(v, "Hello x is {0:2$.1$}", 0.01, 2, 3); + //~^ write_literal + writeln!(v, "Hello x is {0:2$.1$}", 0.01, 2, 3); + //~^ write_literal + writeln!(v, "Hello x is {0:2$.1$}", 0.01, 2, 3); + //~^ write_literal + writeln!(v, "Hello x is {0:2$.1$}", 0.01, 2, 3); + //~^ write_literal +} diff --git a/src/tools/clippy/tests/ui/write_literal.rs b/src/tools/clippy/tests/ui/write_literal.rs index fc29fcbede7..92872752759 100644 --- a/src/tools/clippy/tests/ui/write_literal.rs +++ b/src/tools/clippy/tests/ui/write_literal.rs @@ -88,3 +88,15 @@ fn issue_13959() { "# ); } + +fn issue_14930() { + let mut v = Vec::new(); + writeln!(v, "Hello {3} is {0:2$.1$}", 0.01, 2, 3, "x"); + //~^ write_literal + writeln!(v, "Hello {2} is {0:3$.1$}", 0.01, 2, "x", 3); + //~^ write_literal + writeln!(v, "Hello {1} is {0:3$.2$}", 0.01, "x", 2, 3); + //~^ write_literal + writeln!(v, "Hello {0} is {1:3$.2$}", "x", 0.01, 2, 3); + //~^ write_literal +} diff --git a/src/tools/clippy/tests/ui/write_literal.stderr b/src/tools/clippy/tests/ui/write_literal.stderr index d53c2a7de2e..ca37406c811 100644 --- a/src/tools/clippy/tests/ui/write_literal.stderr +++ b/src/tools/clippy/tests/ui/write_literal.stderr @@ -181,5 +181,53 @@ LL + bar LL ~ " | -error: aborting due to 14 previous errors +error: literal with an empty format string + --> tests/ui/write_literal.rs:94:55 + | +LL | writeln!(v, "Hello {3} is {0:2$.1$}", 0.01, 2, 3, "x"); + | ^^^ + | +help: try + | +LL - writeln!(v, "Hello {3} is {0:2$.1$}", 0.01, 2, 3, "x"); +LL + writeln!(v, "Hello x is {0:2$.1$}", 0.01, 2, 3); + | + +error: literal with an empty format string + --> tests/ui/write_literal.rs:96:52 + | +LL | writeln!(v, "Hello {2} is {0:3$.1$}", 0.01, 2, "x", 3); + | ^^^ + | +help: try + | +LL - writeln!(v, "Hello {2} is {0:3$.1$}", 0.01, 2, "x", 3); +LL + writeln!(v, "Hello x is {0:2$.1$}", 0.01, 2, 3); + | + +error: literal with an empty format string + --> tests/ui/write_literal.rs:98:49 + | +LL | writeln!(v, "Hello {1} is {0:3$.2$}", 0.01, "x", 2, 3); + | ^^^ + | +help: try + | +LL - writeln!(v, "Hello {1} is {0:3$.2$}", 0.01, "x", 2, 3); +LL + writeln!(v, "Hello x is {0:2$.1$}", 0.01, 2, 3); + | + +error: literal with an empty format string + --> tests/ui/write_literal.rs:100:43 + | +LL | writeln!(v, "Hello {0} is {1:3$.2$}", "x", 0.01, 2, 3); + | ^^^ + | +help: try + | +LL - writeln!(v, "Hello {0} is {1:3$.2$}", "x", 0.01, 2, 3); +LL + writeln!(v, "Hello x is {0:2$.1$}", 0.01, 2, 3); + | + +error: aborting due to 18 previous errors diff --git a/src/tools/clippy/tests/ui/zombie_processes.rs b/src/tools/clippy/tests/ui/zombie_processes.rs index 395f9dd2def..e81b5fd4f3e 100644 --- a/src/tools/clippy/tests/ui/zombie_processes.rs +++ b/src/tools/clippy/tests/ui/zombie_processes.rs @@ -198,3 +198,13 @@ mod issue14677 { child.wait().unwrap(); } } + +fn issue14911() -> std::io::Result<String> { + let (mut recv, send) = std::io::pipe()?; + let mut command = Command::new("ls") + .stdout(send.try_clone()?) + .spawn() + .expect("Could not spawn new process..."); + command.wait()?; + Ok("".into()) +} diff --git a/src/tools/clippy/util/gh-pages/script.js b/src/tools/clippy/util/gh-pages/script.js index fec883938d6..285aa34e701 100644 --- a/src/tools/clippy/util/gh-pages/script.js +++ b/src/tools/clippy/util/gh-pages/script.js @@ -602,7 +602,7 @@ filters.filterLints(); updateLintCount(); function updateLintCount() { - const allLints = filters.getAllLints(); + const allLints = filters.getAllLints().filter(lint => lint.group != "deprecated"); const totalLints = allLints.length; const countElement = document.getElementById("lint-count"); diff --git a/src/tools/compiletest/src/directive-list.rs b/src/tools/compiletest/src/directive-list.rs index 1406553c9ea..2ecb4fc8652 100644 --- a/src/tools/compiletest/src/directive-list.rs +++ b/src/tools/compiletest/src/directive-list.rs @@ -166,6 +166,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "needs-subprocess", "needs-symlink", "needs-target-has-atomic", + "needs-target-std", "needs-threads", "needs-unwind", "needs-wasmtime", diff --git a/src/tools/compiletest/src/header/needs.rs b/src/tools/compiletest/src/header/needs.rs index 2ace40c490b..b1165f4bb18 100644 --- a/src/tools/compiletest/src/header/needs.rs +++ b/src/tools/compiletest/src/header/needs.rs @@ -174,6 +174,11 @@ pub(super) fn handle_needs( condition: config.with_std_debug_assertions, ignore_reason: "ignored if std wasn't built with debug assertions", }, + Need { + name: "needs-target-std", + condition: build_helper::targets::target_supports_std(&config.target), + ignore_reason: "ignored if target does not support std", + }, ]; let (name, rest) = match ln.split_once([':', ' ']) { diff --git a/src/tools/compiletest/src/header/tests.rs b/src/tools/compiletest/src/header/tests.rs index e7e5ff0ab00..31b49b09bcd 100644 --- a/src/tools/compiletest/src/header/tests.rs +++ b/src/tools/compiletest/src/header/tests.rs @@ -945,3 +945,14 @@ fn test_ignore_auxiliary() { let config = cfg().build(); assert!(check_ignore(&config, "//@ ignore-auxiliary")); } + +#[test] +fn test_needs_target_std() { + // Cherry-picks two targets: + // 1. `x86_64-unknown-none`: Tier 2, intentionally never supports std. + // 2. `x86_64-unknown-linux-gnu`: Tier 1, always supports std. + let config = cfg().target("x86_64-unknown-none").build(); + assert!(check_ignore(&config, "//@ needs-target-std")); + let config = cfg().target("x86_64-unknown-linux-gnu").build(); + assert!(!check_ignore(&config, "//@ needs-target-std")); +} diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md index fc7942a49c0..5554c7975ff 100644 --- a/src/tools/miri/README.md +++ b/src/tools/miri/README.md @@ -286,6 +286,11 @@ environment variable. We first document the most relevant and most commonly used 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-deterministic-floats` makes Miri's floating-point behavior fully deterministic. This means + that operations will always return the preferred NaN, imprecise operations will not have any + random error applied to them, and `min`/`max` as "maybe fused" multiply-add all behave + deterministically. Note that Miri still uses host floats for some operations, so behavior can + still differ depending on the host target and setup. * `-Zmiri-disable-isolation` disables host isolation. As a consequence, the program has access to host resources such as environment variables, file systems, and randomness. diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs index 2faaec5a174..d4ba7fbd6a4 100644 --- a/src/tools/miri/src/bin/miri.rs +++ b/src/tools/miri/src/bin/miri.rs @@ -601,6 +601,8 @@ fn main() { miri_config.collect_leak_backtraces = false; } else if arg == "-Zmiri-force-intrinsic-fallback" { miri_config.force_intrinsic_fallback = true; + } else if arg == "-Zmiri-deterministic-floats" { + miri_config.float_nondet = false; } else if arg == "-Zmiri-strict-provenance" { miri_config.provenance_mode = ProvenanceMode::Strict; } else if arg == "-Zmiri-permissive-provenance" { diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs index 6f5f756e144..7a5f96ec177 100644 --- a/src/tools/miri/src/eval.rs +++ b/src/tools/miri/src/eval.rs @@ -166,6 +166,8 @@ pub struct MiriConfig { pub fixed_scheduling: bool, /// Always prefer the intrinsic fallback body over the native Miri implementation. pub force_intrinsic_fallback: bool, + /// Whether floating-point operations can behave non-deterministically. + pub float_nondet: bool, } impl Default for MiriConfig { @@ -205,6 +207,7 @@ impl Default for MiriConfig { address_reuse_cross_thread_rate: 0.1, fixed_scheduling: false, force_intrinsic_fallback: false, + float_nondet: true, } } } diff --git a/src/tools/miri/src/intrinsics/mod.rs b/src/tools/miri/src/intrinsics/mod.rs index 9957e351ff1..458b7723299 100644 --- a/src/tools/miri/src/intrinsics/mod.rs +++ b/src/tools/miri/src/intrinsics/mod.rs @@ -272,8 +272,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let a = this.read_scalar(a)?.to_f32()?; let b = this.read_scalar(b)?.to_f32()?; let c = this.read_scalar(c)?.to_f32()?; - // FIXME: Using host floats, to work around https://github.com/rust-lang/rustc_apfloat/issues/11 - let res = a.to_host().mul_add(b.to_host(), c.to_host()).to_soft(); + let res = a.mul_add(b, c).value; let res = this.adjust_nan(res, &[a, b, c]); this.write_scalar(res, dest)?; } @@ -282,8 +281,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let a = this.read_scalar(a)?.to_f64()?; let b = this.read_scalar(b)?.to_f64()?; let c = this.read_scalar(c)?.to_f64()?; - // FIXME: Using host floats, to work around https://github.com/rust-lang/rustc_apfloat/issues/11 - let res = a.to_host().mul_add(b.to_host(), c.to_host()).to_soft(); + let res = a.mul_add(b, c).value; let res = this.adjust_nan(res, &[a, b, c]); this.write_scalar(res, dest)?; } @@ -293,10 +291,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let a = this.read_scalar(a)?.to_f32()?; let b = this.read_scalar(b)?.to_f32()?; let c = this.read_scalar(c)?.to_f32()?; - let fuse: bool = this.machine.rng.get_mut().random(); + let fuse: bool = this.machine.float_nondet && this.machine.rng.get_mut().random(); let res = if fuse { - // FIXME: Using host floats, to work around https://github.com/rust-lang/rustc_apfloat/issues/11 - a.to_host().mul_add(b.to_host(), c.to_host()).to_soft() + a.mul_add(b, c).value } else { ((a * b).value + c).value }; @@ -308,10 +305,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let a = this.read_scalar(a)?.to_f64()?; let b = this.read_scalar(b)?.to_f64()?; let c = this.read_scalar(c)?.to_f64()?; - let fuse: bool = this.machine.rng.get_mut().random(); + let fuse: bool = this.machine.float_nondet && this.machine.rng.get_mut().random(); let res = if fuse { - // FIXME: Using host floats, to work around https://github.com/rust-lang/rustc_apfloat/issues/11 - a.to_host().mul_add(b.to_host(), c.to_host()).to_soft() + a.mul_add(b, c).value } else { ((a * b).value + c).value }; diff --git a/src/tools/miri/src/intrinsics/simd.rs b/src/tools/miri/src/intrinsics/simd.rs index b17fd4fb7f9..dbe193bdbda 100644 --- a/src/tools/miri/src/intrinsics/simd.rs +++ b/src/tools/miri/src/intrinsics/simd.rs @@ -306,7 +306,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let c = this.read_scalar(&this.project_index(&c, i)?)?; let dest = this.project_index(&dest, i)?; - let fuse: bool = intrinsic_name == "fma" || this.machine.rng.get_mut().random(); + let fuse: bool = intrinsic_name == "fma" + || (this.machine.float_nondet && this.machine.rng.get_mut().random()); // Works for f32 and f64. // FIXME: using host floats to work around https://github.com/rust-lang/miri/issues/2468. @@ -320,7 +321,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let b = b.to_f32()?; let c = c.to_f32()?; let res = if fuse { - a.to_host().mul_add(b.to_host(), c.to_host()).to_soft() + a.mul_add(b, c).value } else { ((a * b).value + c).value }; @@ -332,7 +333,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let b = b.to_f64()?; let c = c.to_f64()?; let res = if fuse { - a.to_host().mul_add(b.to_host(), c.to_host()).to_soft() + a.mul_add(b, c).value } else { ((a * b).value + c).value }; diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index b221dd85092..b4d7db34efa 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -618,6 +618,9 @@ pub struct MiriMachine<'tcx> { /// Always prefer the intrinsic fallback body over the native Miri implementation. pub force_intrinsic_fallback: bool, + + /// Whether floating-point operations can behave non-deterministically. + pub float_nondet: bool, } impl<'tcx> MiriMachine<'tcx> { @@ -778,6 +781,7 @@ impl<'tcx> MiriMachine<'tcx> { int2ptr_warned: Default::default(), mangle_internal_symbol_cache: Default::default(), force_intrinsic_fallback: config.force_intrinsic_fallback, + float_nondet: config.float_nondet, } } @@ -956,6 +960,7 @@ impl VisitProvenance for MiriMachine<'_> { int2ptr_warned: _, mangle_internal_symbol_cache: _, force_intrinsic_fallback: _, + float_nondet: _, } = self; threads.visit_provenance(visit); diff --git a/src/tools/miri/src/math.rs b/src/tools/miri/src/math.rs index d1355a21684..cf16a5676d6 100644 --- a/src/tools/miri/src/math.rs +++ b/src/tools/miri/src/math.rs @@ -15,6 +15,10 @@ pub(crate) fn apply_random_float_error<F: rustc_apfloat::Float>( val: F, err_scale: i32, ) -> F { + if !ecx.machine.float_nondet { + return val; + } + let rng = ecx.machine.rng.get_mut(); // Generate a random integer in the range [0, 2^PREC). // (When read as binary, the position of the first `1` determines the exponent, diff --git a/src/tools/miri/src/operator.rs b/src/tools/miri/src/operator.rs index 81f22b2d0b2..73d671121f6 100644 --- a/src/tools/miri/src/operator.rs +++ b/src/tools/miri/src/operator.rs @@ -76,6 +76,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } fn generate_nan<F1: Float + FloatConvert<F2>, F2: Float>(&self, inputs: &[F1]) -> F2 { + let this = self.eval_context_ref(); + if !this.machine.float_nondet { + return F2::NAN; + } + /// Make the given NaN a signaling NaN. /// Returns `None` if this would not result in a NaN. fn make_signaling<F: Float>(f: F) -> Option<F> { @@ -89,7 +94,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { if f.is_nan() { Some(f) } else { None } } - let this = self.eval_context_ref(); let mut rand = this.machine.rng.borrow_mut(); // Assemble an iterator of possible NaNs: preferred, quieting propagation, unchanged propagation. // On some targets there are more possibilities; for now we just generate those options that @@ -118,6 +122,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn equal_float_min_max<F: Float>(&self, a: F, b: F) -> F { let this = self.eval_context_ref(); + if !this.machine.float_nondet { + return a; + } // Return one side non-deterministically. let mut rand = this.machine.rng.borrow_mut(); if rand.random() { a } else { b } diff --git a/src/tools/rust-analyzer/.github/workflows/autopublish.yaml b/src/tools/rust-analyzer/.github/workflows/autopublish.yaml index d3f0499e434..6e2be7fd3da 100644 --- a/src/tools/rust-analyzer/.github/workflows/autopublish.yaml +++ b/src/tools/rust-analyzer/.github/workflows/autopublish.yaml @@ -28,7 +28,7 @@ jobs: run: rustup update --no-self-update stable - name: Install cargo-workspaces - run: cargo install cargo-workspaces + run: cargo install cargo-workspaces --version "0.3.6" - name: Publish Crates env: @@ -54,8 +54,8 @@ jobs: cargo workspaces rename --from project-model project_model cargo workspaces rename --from test-fixture test_fixture cargo workspaces rename --from test-utils test_utils - # Remove library crates from the workspaces so we don't auto-publish them as well - sed -i 's/ "lib\/\*",//' ./Cargo.toml + # Remove library crates and xtask from the workspaces so we don't auto-publish them as well + sed -i 's|^members = .*$|members = ["crates/*"]|' Cargo.toml cargo workspaces rename ra_ap_%n find crates/rust-analyzer -type f -name '*.rs' -exec sed -i 's/rust_analyzer/ra_ap_rust_analyzer/g' {} + cargo workspaces publish --yes --force '*' --exact --no-git-commit --allow-dirty --skip-published custom 0.0.$(($RUN_NUMBER + 133)) diff --git a/src/tools/rust-analyzer/.github/workflows/publish-libs.yaml b/src/tools/rust-analyzer/.github/workflows/publish-libs.yaml index 93ae5675a71..f2c8b6365b6 100644 --- a/src/tools/rust-analyzer/.github/workflows/publish-libs.yaml +++ b/src/tools/rust-analyzer/.github/workflows/publish-libs.yaml @@ -22,7 +22,7 @@ jobs: run: rustup update --no-self-update stable - name: Install cargo-workspaces - run: cargo install cargo-workspaces + run: cargo install cargo-workspaces --version "0.3.6" - name: Publish Crates env: diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml index 8c507189846..975fe277b22 100644 --- a/src/tools/rust-analyzer/Cargo.toml +++ b/src/tools/rust-analyzer/Cargo.toml @@ -21,6 +21,8 @@ smol_str.opt-level = 3 text-size.opt-level = 3 serde.opt-level = 3 salsa.opt-level = 3 +dissimilar.opt-level = 3 + # This speeds up `cargo xtask dist`. miniz_oxide.opt-level = 3 diff --git a/src/tools/rust-analyzer/crates/hir-def/src/dyn_map.rs b/src/tools/rust-analyzer/crates/hir-def/src/dyn_map.rs index eed1490a7af..20018b61e5c 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/dyn_map.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/dyn_map.rs @@ -67,8 +67,14 @@ pub mod keys { pub const PROC_MACRO: Key<ast::Fn, ProcMacroId> = Key::new(); pub const MACRO_CALL: Key<ast::MacroCall, MacroCallId> = Key::new(); pub const ATTR_MACRO_CALL: Key<ast::Item, MacroCallId> = Key::new(); - pub const DERIVE_MACRO_CALL: Key<ast::Attr, (AttrId, MacroCallId, Box<[Option<MacroCallId>]>)> = - Key::new(); + pub const DERIVE_MACRO_CALL: Key< + ast::Attr, + ( + AttrId, + /* derive() */ MacroCallId, + /* actual derive macros */ Box<[Option<MacroCallId>]>, + ), + > = Key::new(); /// XXX: AST Nodes and SyntaxNodes have identity equality semantics: nodes are /// equal if they point to exactly the same object. diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs index cb4fcd887d8..2cc3ca8c752 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs @@ -931,11 +931,12 @@ pub fn new() { // PATH_TYPE@23..26 // PATH@23..26 // PATH_SEGMENT@23..26 -// L_ANGLE@23..24 "<" -// PAREN_TYPE@24..26 -// L_PAREN@24..25 "(" -// ERROR@25..26 -// INT_NUMBER@25..26 "8" +// TYPE_ANCHOR@23..26 +// L_ANGLE@23..24 "<" +// PAREN_TYPE@24..26 +// L_PAREN@24..25 "(" +// ERROR@25..26 +// INT_NUMBER@25..26 "8" // PLUS@26..27 "+" // CONST_ARG@27..28 // LITERAL@27..28 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 980ee264b02..1e985dc604e 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs @@ -31,6 +31,7 @@ use crate::{ #[query_group::query_group] pub trait HirDatabase: DefDatabase + std::fmt::Debug { #[salsa::invoke(crate::infer::infer_query)] + #[salsa::cycle(cycle_result = crate::infer::infer_cycle_result)] fn infer(&self, def: DefWithBodyId) -> Arc<InferenceResult>; // region:mir @@ -132,6 +133,7 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { // FIXME: Make this a non-interned query. #[salsa::invoke_interned(crate::lower::const_param_ty_with_diagnostics_query)] + #[salsa::cycle(cycle_result = crate::lower::const_param_ty_with_diagnostics_cycle_result)] fn const_param_ty_with_diagnostics(&self, def: ConstParamId) -> (Ty, Diagnostics); #[salsa::invoke(crate::lower::const_param_ty_query)] 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 e698fb201cb..14eb7160753 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs @@ -35,7 +35,8 @@ use chalk_ir::{ use either::Either; use hir_def::{ AdtId, AssocItemId, ConstId, DefWithBodyId, FieldId, FunctionId, GenericDefId, GenericParamId, - ImplId, ItemContainerId, Lookup, TraitId, TupleFieldId, TupleId, TypeAliasId, VariantId, + ImplId, ItemContainerId, LocalFieldId, Lookup, TraitId, TupleFieldId, TupleId, TypeAliasId, + VariantId, builtin_type::{BuiltinInt, BuiltinType, BuiltinUint}, expr_store::{Body, ExpressionStore, HygieneId, path::Path}, hir::{BindingAnnotation, BindingId, ExprId, ExprOrPatId, LabelId, PatId}, @@ -135,6 +136,10 @@ pub(crate) fn infer_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc<Infer Arc::new(ctx.resolve_all()) } +pub(crate) fn infer_cycle_result(_: &dyn HirDatabase, _: DefWithBodyId) -> Arc<InferenceResult> { + Arc::new(InferenceResult { has_errors: true, ..Default::default() }) +} + /// Fully normalize all the types found within `ty` in context of `owner` body definition. /// /// This is appropriate to use only after type-check: it assumes @@ -203,7 +208,7 @@ pub(crate) type InferResult<T> = Result<InferOk<T>, TypeError>; pub enum InferenceDiagnostic { NoSuchField { field: ExprOrPatId, - private: bool, + private: Option<LocalFieldId>, variant: VariantId, }, PrivateField { @@ -558,6 +563,9 @@ impl InferenceResult { ExprOrPatId::PatId(id) => self.type_of_pat.get(id), } } + pub fn is_erroneous(&self) -> bool { + self.has_errors && self.type_of_expr.iter().count() == 0 + } } impl Index<ExprId> for InferenceResult { 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 87b7f3406ff..64031279296 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 @@ -554,7 +554,7 @@ impl InferenceContext<'_> { self.push_diagnostic( InferenceDiagnostic::NoSuchField { field: field.expr.into(), - private: true, + private: Some(local_id), variant: def, }, ); @@ -564,7 +564,7 @@ impl InferenceContext<'_> { None => { self.push_diagnostic(InferenceDiagnostic::NoSuchField { field: field.expr.into(), - private: false, + private: None, variant: def, }); None 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 a9a3265858e..4bc3e167ebf 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 @@ -143,7 +143,7 @@ impl InferenceContext<'_> { { self.push_diagnostic(InferenceDiagnostic::NoSuchField { field: inner.into(), - private: true, + private: Some(local_id), variant: def, }); } @@ -157,7 +157,7 @@ impl InferenceContext<'_> { None => { self.push_diagnostic(InferenceDiagnostic::NoSuchField { field: inner.into(), - private: false, + private: None, variant: def, }); self.err_ty() 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 ea8e7cc2be9..0a546768dab 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs @@ -1604,6 +1604,14 @@ pub(crate) fn impl_self_ty_with_diagnostics_query( ) } +pub(crate) fn impl_self_ty_with_diagnostics_cycle_result( + db: &dyn HirDatabase, + impl_id: ImplId, +) -> (Binders<Ty>, Diagnostics) { + let generics = generics(db, impl_id.into()); + (make_binders(db, &generics, TyKind::Error.intern(Interner)), None) +} + pub(crate) fn const_param_ty_query(db: &dyn HirDatabase, def: ConstParamId) -> Ty { db.const_param_ty_with_diagnostics(def).0 } @@ -1633,12 +1641,12 @@ pub(crate) fn const_param_ty_with_diagnostics_query( (ty, create_diagnostics(ctx.diagnostics)) } -pub(crate) fn impl_self_ty_with_diagnostics_cycle_result( - db: &dyn HirDatabase, - impl_id: ImplId, -) -> (Binders<Ty>, Diagnostics) { - let generics = generics(db, impl_id.into()); - (make_binders(db, &generics, TyKind::Error.intern(Interner)), None) +pub(crate) fn const_param_ty_with_diagnostics_cycle_result( + _: &dyn HirDatabase, + _: crate::db::HirDatabaseData, + _: ConstParamId, +) -> (Ty, Diagnostics) { + (TyKind::Error.intern(Interner), None) } pub(crate) fn impl_trait_query(db: &dyn HirDatabase, impl_id: ImplId) -> Option<Binders<TraitRef>> { 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 e6caf2d8d97..99d93515303 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 @@ -2182,7 +2182,7 @@ pub fn lower_to_mir( // need to take this input explicitly. root_expr: ExprId, ) -> Result<MirBody> { - if infer.type_mismatches().next().is_some() { + if infer.type_mismatches().next().is_some() || infer.is_erroneous() { return Err(MirLowerError::HasErrors); } let mut ctx = MirLowerCtx::new(db, owner, body, infer); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs index 48474d2d26d..e8e3812c69d 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs @@ -106,3 +106,256 @@ fn baz() -> i32 { assert_eq!(format!("{events:?}").matches("infer_shim").count(), 1, "{events:#?}") } } + +#[test] +fn adding_struct_invalidates_infer() { + let (mut db, pos) = TestDB::with_position( + " +//- /lib.rs +fn foo() -> i32 { + 1 + 1 +} + +fn bar() -> f32 { + 2.0 * 3.0 +} +$0", + ); + { + let events = db.log_executed(|| { + let module = db.module_for_file(pos.file_id.file_id(&db)); + let _crate_def_map = module.def_map(&db); + db.trait_impls_in_crate(module.krate()); + }); + assert!(format!("{events:?}").contains("trait_impls_in_crate_shim")) + } + + let new_text = " +fn foo() -> i32 { + 1 + 1 +} + +fn bar() -> f32 { + 2.0 * 3.0 +} + +pub struct NewStruct { + field: i32, +} +"; + + db.set_file_text(pos.file_id.file_id(&db), new_text); + + { + let actual = db.log_executed(|| { + let module = db.module_for_file(pos.file_id.file_id(&db)); + let _crate_def_map = module.def_map(&db); + db.trait_impls_in_crate(module.krate()); + }); + + let expected = vec![ + "parse_shim".to_owned(), + "ast_id_map_shim".to_owned(), + "file_item_tree_shim".to_owned(), + "real_span_map_shim".to_owned(), + "crate_local_def_map".to_owned(), + "trait_impls_in_crate_shim".to_owned(), + ]; + + assert_eq!(expected, actual); + } +} + +#[test] +fn adding_enum_query_log() { + let (mut db, pos) = TestDB::with_position( + " +//- /lib.rs +fn foo() -> i32 { + 1 + 1 +} + +fn bar() -> f32 { + 2.0 * 3.0 +} +$0", + ); + { + let events = db.log_executed(|| { + let module = db.module_for_file(pos.file_id.file_id(&db)); + let _crate_def_map = module.def_map(&db); + db.trait_impls_in_crate(module.krate()); + }); + assert!(format!("{events:?}").contains("trait_impls_in_crate_shim")) + } + + let new_text = " +fn foo() -> i32 { + 1 + 1 +} + +fn bar() -> f32 { + 2.0 * 3.0 +} + +pub enum SomeEnum { + A, + B +} +"; + + db.set_file_text(pos.file_id.file_id(&db), new_text); + + { + let actual = db.log_executed(|| { + let module = db.module_for_file(pos.file_id.file_id(&db)); + let _crate_def_map = module.def_map(&db); + db.trait_impls_in_crate(module.krate()); + }); + + let expected = vec![ + "parse_shim".to_owned(), + "ast_id_map_shim".to_owned(), + "file_item_tree_shim".to_owned(), + "real_span_map_shim".to_owned(), + "crate_local_def_map".to_owned(), + "trait_impls_in_crate_shim".to_owned(), + ]; + + assert_eq!(expected, actual); + } +} + +#[test] +fn adding_use_query_log() { + let (mut db, pos) = TestDB::with_position( + " +//- /lib.rs +fn foo() -> i32 { + 1 + 1 +} + +fn bar() -> f32 { + 2.0 * 3.0 +} +$0", + ); + { + let events = db.log_executed(|| { + let module = db.module_for_file(pos.file_id.file_id(&db)); + let _crate_def_map = module.def_map(&db); + db.trait_impls_in_crate(module.krate()); + }); + assert!(format!("{events:?}").contains("trait_impls_in_crate_shim")) + } + + let new_text = " +use std::collections::HashMap; + +fn foo() -> i32 { + 1 + 1 +} + +fn bar() -> f32 { + 2.0 * 3.0 +} +"; + + db.set_file_text(pos.file_id.file_id(&db), new_text); + + { + let actual = db.log_executed(|| { + let module = db.module_for_file(pos.file_id.file_id(&db)); + let _crate_def_map = module.def_map(&db); + db.trait_impls_in_crate(module.krate()); + }); + + let expected = vec![ + "parse_shim".to_owned(), + "ast_id_map_shim".to_owned(), + "file_item_tree_shim".to_owned(), + "real_span_map_shim".to_owned(), + "crate_local_def_map".to_owned(), + "trait_impls_in_crate_shim".to_owned(), + ]; + + assert_eq!(expected, actual); + } +} + +#[test] +fn adding_impl_query_log() { + let (mut db, pos) = TestDB::with_position( + " +//- /lib.rs +fn foo() -> i32 { + 1 + 1 +} + +fn bar() -> f32 { + 2.0 * 3.0 +} + +pub struct SomeStruct { + field: i32, +} +$0", + ); + { + let events = db.log_executed(|| { + let module = db.module_for_file(pos.file_id.file_id(&db)); + let _crate_def_map = module.def_map(&db); + db.trait_impls_in_crate(module.krate()); + }); + assert!(format!("{events:?}").contains("trait_impls_in_crate_shim")) + } + + let new_text = " +fn foo() -> i32 { + 1 + 1 +} + +fn bar() -> f32 { + 2.0 * 3.0 +} + +pub struct SomeStruct { + field: i32, +} + +impl SomeStruct { + pub fn new(value: i32) -> Self { + Self { field: value } + } +} +"; + + db.set_file_text(pos.file_id.file_id(&db), new_text); + + { + let actual = db.log_executed(|| { + let module = db.module_for_file(pos.file_id.file_id(&db)); + let _crate_def_map = module.def_map(&db); + db.trait_impls_in_crate(module.krate()); + }); + + let expected = vec![ + "parse_shim".to_owned(), + "ast_id_map_shim".to_owned(), + "file_item_tree_shim".to_owned(), + "real_span_map_shim".to_owned(), + "crate_local_def_map".to_owned(), + "trait_impls_in_crate_shim".to_owned(), + "attrs_shim".to_owned(), + "impl_trait_with_diagnostics_shim".to_owned(), + "impl_signature_shim".to_owned(), + "impl_signature_with_source_map_shim".to_owned(), + "impl_self_ty_with_diagnostics_shim".to_owned(), + "struct_signature_shim".to_owned(), + "struct_signature_with_source_map_shim".to_owned(), + "type_for_adt_tracked".to_owned(), + ]; + + assert_eq!(expected, actual); + } +} 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 47c695c6974..ff8adeef1db 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 @@ -2301,3 +2301,51 @@ trait Foo { "#]], ); } + +#[test] +fn no_panic_on_recursive_const() { + check_infer( + r#" +struct Foo<const N: usize> {} +impl<const N: Foo<N>> Foo<N> { + fn foo(self) {} +} + +fn test() { + let _ = N; +} +"#, + expect![[r#" + 72..76 'self': Foo<N> + 78..80 '{}': () + 94..112 '{ ...= N; }': () + 104..105 '_': {unknown} + 108..109 'N': {unknown} + "#]], + ); + + check_infer( + r#" +struct Foo<const N: usize>; +const N: Foo<N> = Foo; + +impl<const N: usize> Foo<N> { + fn foo(self) -> usize { + N + } +} + +fn test() { + let _ = N; +} +"#, + expect![[r#" + 93..97 'self': Foo<N> + 108..125 '{ ... }': usize + 118..119 'N': usize + 139..157 '{ ...= N; }': () + 149..150 '_': Foo<_> + 153..154 'N': Foo<_> + "#]], + ); +} diff --git a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs index b6e3002ed5d..f7b140e03d4 100644 --- a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs @@ -224,7 +224,7 @@ pub struct MalformedDerive { #[derive(Debug)] pub struct NoSuchField { pub field: InFile<AstPtr<Either<ast::RecordExprField, ast::RecordPatField>>>, - pub private: bool, + pub private: Option<Field>, pub variant: VariantId, } @@ -648,6 +648,7 @@ impl AnyDiagnostic { } ExprOrPatId::PatId(pat) => source_map.pat_field_syntax(pat), }; + let private = private.map(|id| Field { id, parent: variant.into() }); NoSuchField { field: expr_or_pat, private, variant }.into() } &InferenceDiagnostic::MismatchedArgCount { call_expr, expected, found } => { diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs index e01774650b1..4a2e8e379fb 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs @@ -222,6 +222,21 @@ impl<DB: HirDatabase> Semantics<'_, DB> { self.imp.descend_node_at_offset(node, offset).filter_map(|mut it| it.find_map(N::cast)) } + // FIXME: Rethink this API + pub fn find_namelike_at_offset_with_descend<'slf>( + &'slf self, + node: &SyntaxNode, + offset: TextSize, + ) -> impl Iterator<Item = ast::NameLike> + 'slf { + node.token_at_offset(offset) + .map(move |token| self.descend_into_macros_no_opaque(token)) + .map(|descendants| descendants.into_iter().filter_map(move |it| it.value.parent())) + // re-order the tokens from token_at_offset by returning the ancestors with the smaller first nodes first + // See algo::ancestors_at_offset, which uses the same approach + .kmerge_by(|left, right| left.text_range().len().lt(&right.text_range().len())) + .filter_map(ast::NameLike::cast) + } + pub fn resolve_range_pat(&self, range_pat: &ast::RangePat) -> Option<Struct> { self.imp.resolve_range_pat(range_pat).map(Struct::from) } @@ -535,7 +550,7 @@ impl<'db> SemanticsImpl<'db> { } pub fn is_derive_annotated(&self, adt: InFile<&ast::Adt>) -> bool { - self.with_ctx(|ctx| ctx.has_derives(adt)) + self.with_ctx(|ctx| ctx.file_of_adt_has_derives(adt)) } pub fn derive_helpers_in_scope(&self, adt: &ast::Adt) -> Option<Vec<(Symbol, Symbol)>> { @@ -644,7 +659,7 @@ impl<'db> SemanticsImpl<'db> { /// Checks if renaming `renamed` to `new_name` may introduce conflicts with other locals, /// and returns the conflicting locals. - pub fn rename_conflicts(&self, to_be_renamed: &Local, new_name: &str) -> Vec<Local> { + pub fn rename_conflicts(&self, to_be_renamed: &Local, new_name: &Name) -> Vec<Local> { let body = self.db.body(to_be_renamed.parent); let resolver = to_be_renamed.parent.resolver(self.db); let starting_expr = @@ -653,7 +668,7 @@ impl<'db> SemanticsImpl<'db> { body: &body, conflicts: FxHashSet::default(), db: self.db, - new_name: Symbol::intern(new_name), + new_name: new_name.symbol().clone(), old_name: to_be_renamed.name(self.db).symbol().clone(), owner: to_be_renamed.parent, to_be_renamed: to_be_renamed.binding_id, @@ -877,8 +892,9 @@ impl<'db> SemanticsImpl<'db> { if first == last { // node is just the token, so descend the token - self.descend_into_macros_impl( + self.descend_into_macros_all( InFile::new(file.file_id, first), + false, &mut |InFile { value, .. }, _ctx| { if let Some(node) = value .parent_ancestors() @@ -887,20 +903,21 @@ impl<'db> SemanticsImpl<'db> { { res.push(node) } - CONTINUE_NO_BREAKS }, ); } else { // Descend first and last token, then zip them to look for the node they belong to let mut scratch: SmallVec<[_; 1]> = smallvec![]; - self.descend_into_macros_impl(InFile::new(file.file_id, first), &mut |token, _ctx| { - scratch.push(token); - CONTINUE_NO_BREAKS - }); + self.descend_into_macros_all( + InFile::new(file.file_id, first), + false, + &mut |token, _ctx| scratch.push(token), + ); let mut scratch = scratch.into_iter(); - self.descend_into_macros_impl( + self.descend_into_macros_all( InFile::new(file.file_id, last), + false, &mut |InFile { value: last, file_id: last_fid }, _ctx| { if let Some(InFile { value: first, file_id: first_fid }) = scratch.next() { if first_fid == last_fid { @@ -917,17 +934,18 @@ impl<'db> SemanticsImpl<'db> { } } } - CONTINUE_NO_BREAKS }, ); } res } - pub fn is_inside_macro_call(&self, token: InFile<&SyntaxToken>) -> bool { - // FIXME: Maybe `ancestors_with_macros()` is more suitable here? Currently - // this is only used on real (not macro) files so this is not a problem. - token.value.parent_ancestors().any(|ancestor| { + /// Returns true if the given input is within a macro call. + /// + /// Note that if this token itself is within the context of a macro expansion does not matter. + /// That is, we strictly check if it lies inside the input of a macro call. + pub fn is_inside_macro_call(&self, token @ InFile { value, .. }: InFile<&SyntaxToken>) -> bool { + value.parent_ancestors().any(|ancestor| { if ast::MacroCall::can_cast(ancestor.kind()) { return true; } @@ -952,7 +970,7 @@ impl<'db> SemanticsImpl<'db> { ast::Item::Union(it) => it.into(), _ => return false, }; - ctx.has_derives(token.with_value(&adt)) + ctx.file_of_adt_has_derives(token.with_value(&adt)) }) }) } @@ -962,18 +980,18 @@ impl<'db> SemanticsImpl<'db> { token: SyntaxToken, mut cb: impl FnMut(InFile<SyntaxToken>, SyntaxContext), ) { - self.descend_into_macros_impl(self.wrap_token_infile(token), &mut |t, ctx| { - cb(t, ctx); - CONTINUE_NO_BREAKS + self.descend_into_macros_all(self.wrap_token_infile(token), false, &mut |t, ctx| { + cb(t, ctx) }); } pub fn descend_into_macros(&self, token: SyntaxToken) -> SmallVec<[SyntaxToken; 1]> { let mut res = smallvec![]; - self.descend_into_macros_impl(self.wrap_token_infile(token.clone()), &mut |t, _ctx| { - res.push(t.value); - CONTINUE_NO_BREAKS - }); + self.descend_into_macros_all( + self.wrap_token_infile(token.clone()), + false, + &mut |t, _ctx| res.push(t.value), + ); if res.is_empty() { res.push(token); } @@ -986,12 +1004,11 @@ impl<'db> SemanticsImpl<'db> { ) -> SmallVec<[InFile<SyntaxToken>; 1]> { let mut res = smallvec![]; let token = self.wrap_token_infile(token); - self.descend_into_macros_impl(token.clone(), &mut |t, ctx| { + self.descend_into_macros_all(token.clone(), true, &mut |t, ctx| { if !ctx.is_opaque(self.db) { // Don't descend into opaque contexts res.push(t); } - CONTINUE_NO_BREAKS }); if res.is_empty() { res.push(token); @@ -1004,7 +1021,7 @@ impl<'db> SemanticsImpl<'db> { token: InFile<SyntaxToken>, mut cb: impl FnMut(InFile<SyntaxToken>, SyntaxContext) -> ControlFlow<T>, ) -> Option<T> { - self.descend_into_macros_impl(token, &mut cb) + self.descend_into_macros_impl(token, false, &mut cb) } /// Descends the token into expansions, returning the tokens that matches the input @@ -1074,44 +1091,56 @@ impl<'db> SemanticsImpl<'db> { .unwrap_or(token) } + fn descend_into_macros_all( + &self, + token: InFile<SyntaxToken>, + always_descend_into_derives: bool, + f: &mut dyn FnMut(InFile<SyntaxToken>, SyntaxContext), + ) { + self.descend_into_macros_impl(token, always_descend_into_derives, &mut |tok, ctx| { + f(tok, ctx); + CONTINUE_NO_BREAKS + }); + } + fn descend_into_macros_impl<T>( &self, InFile { value: token, file_id }: InFile<SyntaxToken>, + always_descend_into_derives: bool, f: &mut dyn FnMut(InFile<SyntaxToken>, SyntaxContext) -> ControlFlow<T>, ) -> Option<T> { let _p = tracing::info_span!("descend_into_macros_impl").entered(); - let span = self.db.span_map(file_id).span_for_range(token.text_range()); + let db = self.db; + let span = db.span_map(file_id).span_for_range(token.text_range()); // Process the expansion of a call, pushing all tokens with our span in the expansion back onto our stack - let process_expansion_for_token = |stack: &mut Vec<_>, macro_file| { - let InMacroFile { file_id, value: mapped_tokens } = self.with_ctx(|ctx| { - Some( - ctx.cache - .get_or_insert_expansion(ctx.db, macro_file) - .map_range_down(span)? - .map(SmallVec::<[_; 2]>::from_iter), - ) - })?; - // we have found a mapping for the token if the vec is non-empty - let res = mapped_tokens.is_empty().not().then_some(()); - // requeue the tokens we got from mapping our current token down - stack.push((HirFileId::from(file_id), mapped_tokens)); - res - }; + let process_expansion_for_token = + |ctx: &mut SourceToDefCtx<'_, '_>, stack: &mut Vec<_>, macro_file| { + let InMacroFile { file_id, value: mapped_tokens } = ctx + .cache + .get_or_insert_expansion(ctx.db, macro_file) + .map_range_down(span)? + .map(SmallVec::<[_; 2]>::from_iter); + // we have found a mapping for the token if the vec is non-empty + let res = mapped_tokens.is_empty().not().then_some(()); + // requeue the tokens we got from mapping our current token down + stack.push((HirFileId::from(file_id), mapped_tokens)); + res + }; // A stack of tokens to process, along with the file they came from // These are tracked to know which macro calls we still have to look into // the tokens themselves aren't that interesting as the span that is being used to map // things down never changes. let mut stack: Vec<(_, SmallVec<[_; 2]>)> = vec![]; - let include = file_id.file_id().and_then(|file_id| { - self.s2d_cache.borrow_mut().get_or_insert_include_for(self.db, file_id) - }); + let include = file_id + .file_id() + .and_then(|file_id| self.s2d_cache.borrow_mut().get_or_insert_include_for(db, file_id)); match include { Some(include) => { // include! inputs are always from real files, so they only need to be handled once upfront - process_expansion_for_token(&mut stack, include)?; + self.with_ctx(|ctx| process_expansion_for_token(ctx, &mut stack, include))?; } None => { stack.push((file_id, smallvec![(token, span.ctx)])); @@ -1133,62 +1162,120 @@ impl<'db> SemanticsImpl<'db> { tokens.reverse(); while let Some((token, ctx)) = tokens.pop() { let was_not_remapped = (|| { - // First expand into attribute invocations - let containing_attribute_macro_call = self.with_ctx(|ctx| { - token.parent_ancestors().filter_map(ast::Item::cast).find_map(|item| { - // Don't force populate the dyn cache for items that don't have an attribute anyways - item.attrs().next()?; - Some((ctx.item_to_macro_call(InFile::new(expansion, &item))?, item)) - }) - }); - if let Some((call_id, item)) = containing_attribute_macro_call { - let attr_id = match self.db.lookup_intern_macro_call(call_id).kind { - hir_expand::MacroCallKind::Attr { invoc_attr_index, .. } => { - invoc_attr_index.ast_index() - } - _ => 0, - }; - // FIXME: here, the attribute's text range is used to strip away all - // entries from the start of the attribute "list" up the invoking - // attribute. But in - // ``` - // mod foo { - // #![inner] - // } - // ``` - // we don't wanna strip away stuff in the `mod foo {` range, that is - // here if the id corresponds to an inner attribute we got strip all - // text ranges of the outer ones, and then all of the inner ones up - // to the invoking attribute so that the inbetween is ignored. - let text_range = item.syntax().text_range(); - let start = collect_attrs(&item) - .nth(attr_id) - .map(|attr| match attr.1 { - Either::Left(it) => it.syntax().text_range().start(), - Either::Right(it) => it.syntax().text_range().start(), + // First expand into attribute invocations, this is required to be handled + // upfront as any other macro call within will not semantically resolve unless + // also descended. + let res = self.with_ctx(|ctx| { + token + .parent_ancestors() + .filter_map(ast::Item::cast) + // FIXME: This might work incorrectly when we have a derive, followed by + // an attribute on an item, like: + // ``` + // #[derive(Debug$0)] + // #[my_attr] + // struct MyStruct; + // ``` + // here we should not consider the attribute at all, as our cursor + // technically lies outside of its expansion + .find_map(|item| { + // Don't force populate the dyn cache for items that don't have an attribute anyways + item.attrs().next()?; + ctx.item_to_macro_call(InFile::new(expansion, &item)) + .zip(Some(item)) }) - .unwrap_or_else(|| text_range.start()); - let text_range = TextRange::new(start, text_range.end()); - filter_duplicates(tokens, text_range); - return process_expansion_for_token(&mut stack, call_id); + .map(|(call_id, item)| { + let attr_id = match db.lookup_intern_macro_call(call_id).kind { + hir_expand::MacroCallKind::Attr { + invoc_attr_index, .. + } => invoc_attr_index.ast_index(), + _ => 0, + }; + // FIXME: here, the attribute's text range is used to strip away all + // entries from the start of the attribute "list" up the invoking + // attribute. But in + // ``` + // mod foo { + // #![inner] + // } + // ``` + // we don't wanna strip away stuff in the `mod foo {` range, that is + // here if the id corresponds to an inner attribute we got strip all + // text ranges of the outer ones, and then all of the inner ones up + // to the invoking attribute so that the inbetween is ignored. + let text_range = item.syntax().text_range(); + let start = collect_attrs(&item) + .nth(attr_id) + .map(|attr| match attr.1 { + Either::Left(it) => it.syntax().text_range().start(), + Either::Right(it) => it.syntax().text_range().start(), + }) + .unwrap_or_else(|| text_range.start()); + let text_range = TextRange::new(start, text_range.end()); + filter_duplicates(tokens, text_range); + process_expansion_for_token(ctx, &mut stack, call_id) + }) + }); + + if let Some(res) = res { + return res; } + if always_descend_into_derives { + let res = self.with_ctx(|ctx| { + let (derives, adt) = token + .parent_ancestors() + .filter_map(ast::Adt::cast) + .find_map(|adt| { + Some(( + ctx.derive_macro_calls(InFile::new(expansion, &adt))? + .map(|(a, b, c)| (a, b, c.to_owned())) + .collect::<SmallVec<[_; 2]>>(), + adt, + )) + })?; + let mut res = None; + for (_, derive_attr, derives) in derives { + // as there may be multiple derives registering the same helper + // name, we gotta make sure to call this for all of them! + // FIXME: We need to call `f` for all of them as well though! + res = res.or(process_expansion_for_token( + ctx, + &mut stack, + derive_attr, + )); + for derive in derives.into_iter().flatten() { + res = res + .or(process_expansion_for_token(ctx, &mut stack, derive)); + } + } + // remove all tokens that are within the derives expansion + filter_duplicates(tokens, adt.syntax().text_range()); + Some(res) + }); + // if we found derives, we can early exit. There is no way we can be in any + // macro call at this point given we are not in a token tree + if let Some(res) = res { + return res; + } + } // Then check for token trees, that means we are either in a function-like macro or // secondary attribute inputs let tt = token .parent_ancestors() .map_while(Either::<ast::TokenTree, ast::Meta>::cast) .last()?; + match tt { // function-like macro call Either::Left(tt) => { + let macro_call = tt.syntax().parent().and_then(ast::MacroCall::cast)?; if tt.left_delimiter_token().map_or(false, |it| it == token) { return None; } if tt.right_delimiter_token().map_or(false, |it| it == token) { return None; } - let macro_call = tt.syntax().parent().and_then(ast::MacroCall::cast)?; let mcall = InFile::new(expansion, macro_call); let file_id = match m_cache.get(&mcall) { Some(&it) => it, @@ -1201,13 +1288,16 @@ impl<'db> SemanticsImpl<'db> { let text_range = tt.syntax().text_range(); filter_duplicates(tokens, text_range); - process_expansion_for_token(&mut stack, file_id).or(file_id - .eager_arg(self.db) - .and_then(|arg| { - // also descend into eager expansions - process_expansion_for_token(&mut stack, arg) - })) + self.with_ctx(|ctx| { + process_expansion_for_token(ctx, &mut stack, file_id).or(file_id + .eager_arg(db) + .and_then(|arg| { + // also descend into eager expansions + process_expansion_for_token(ctx, &mut stack, arg) + })) + }) } + Either::Right(_) if always_descend_into_derives => None, // derive or derive helper Either::Right(meta) => { // attribute we failed expansion for earlier, this might be a derive invocation @@ -1216,31 +1306,33 @@ impl<'db> SemanticsImpl<'db> { let adt = match attr.syntax().parent().and_then(ast::Adt::cast) { Some(adt) => { // this might be a derive on an ADT - let derive_call = self.with_ctx(|ctx| { + let res = self.with_ctx(|ctx| { // so try downmapping the token into the pseudo derive expansion // see [hir_expand::builtin_attr_macro] for how the pseudo derive expansion works - ctx.attr_to_derive_macro_call( - InFile::new(expansion, &adt), - InFile::new(expansion, attr.clone()), - ) - .map(|(_, call_id, _)| call_id) + let derive_call = ctx + .attr_to_derive_macro_call( + InFile::new(expansion, &adt), + InFile::new(expansion, attr.clone()), + )? + .1; + + // resolved to a derive + let text_range = attr.syntax().text_range(); + // remove any other token in this macro input, all their mappings are the + // same as this + tokens.retain(|(t, _)| { + !text_range.contains_range(t.text_range()) + }); + Some(process_expansion_for_token( + ctx, + &mut stack, + derive_call, + )) }); - - match derive_call { - Some(call_id) => { - // resolved to a derive - let text_range = attr.syntax().text_range(); - // remove any other token in this macro input, all their mappings are the - // same as this - tokens.retain(|(t, _)| { - !text_range.contains_range(t.text_range()) - }); - return process_expansion_for_token( - &mut stack, call_id, - ); - } - None => Some(adt), + if let Some(res) = res { + return res; } + Some(adt) } None => { // Otherwise this could be a derive helper on a variant or field @@ -1254,12 +1346,9 @@ impl<'db> SemanticsImpl<'db> { ) } }?; - if !self.with_ctx(|ctx| ctx.has_derives(InFile::new(expansion, &adt))) { - return None; - } let attr_name = attr.path().and_then(|it| it.as_single_name_ref())?.as_name(); - // Not an attribute, nor a derive, so it's either an intert attribute or a derive helper + // Not an attribute, nor a derive, so it's either an inert attribute or a derive helper // Try to resolve to a derive helper and downmap let resolver = &token .parent() @@ -1267,7 +1356,7 @@ impl<'db> SemanticsImpl<'db> { self.analyze_impl(InFile::new(expansion, &parent), None, false) })? .resolver; - let id = self.db.ast_id_map(expansion).ast_id(&adt); + let id = db.ast_id_map(expansion).ast_id(&adt); let helpers = resolver .def_map() .derive_helpers_in_scope(InFile::new(expansion, id))?; @@ -1278,20 +1367,22 @@ impl<'db> SemanticsImpl<'db> { } let mut res = None; - for (.., derive) in - helpers.iter().filter(|(helper, ..)| *helper == attr_name) - { - // as there may be multiple derives registering the same helper - // name, we gotta make sure to call this for all of them! - // FIXME: We need to call `f` for all of them as well though! - res = res.or(process_expansion_for_token(&mut stack, *derive)); - } - res + self.with_ctx(|ctx| { + for (.., derive) in + helpers.iter().filter(|(helper, ..)| *helper == attr_name) + { + // as there may be multiple derives registering the same helper + // name, we gotta make sure to call this for all of them! + // FIXME: We need to call `f` for all of them as well though! + res = res + .or(process_expansion_for_token(ctx, &mut stack, *derive)); + } + res + }) } } })() .is_none(); - if was_not_remapped { if let ControlFlow::Break(b) = f(InFile::new(expansion, token), ctx) { return Some(b); @@ -1380,25 +1471,31 @@ impl<'db> SemanticsImpl<'db> { } /// Iterates the ancestors of the given node, climbing up macro expansions while doing so. + // FIXME: Replace with `ancestors_with_macros_file` when all usages are updated. pub fn ancestors_with_macros( &self, node: SyntaxNode, ) -> impl Iterator<Item = SyntaxNode> + Clone + '_ { let node = self.find_file(&node); - iter::successors(Some(node.cloned()), move |&InFile { file_id, ref value }| { - match value.parent() { - Some(parent) => Some(InFile::new(file_id, parent)), - None => { - let macro_file = file_id.macro_file()?; - - self.with_ctx(|ctx| { - let expansion_info = ctx.cache.get_or_insert_expansion(ctx.db, macro_file); - expansion_info.arg().map(|node| node?.parent()).transpose() - }) - } + self.ancestors_with_macros_file(node.cloned()).map(|it| it.value) + } + + /// Iterates the ancestors of the given node, climbing up macro expansions while doing so. + pub fn ancestors_with_macros_file( + &self, + node: InFile<SyntaxNode>, + ) -> impl Iterator<Item = InFile<SyntaxNode>> + Clone + '_ { + iter::successors(Some(node), move |&InFile { file_id, ref value }| match value.parent() { + Some(parent) => Some(InFile::new(file_id, parent)), + None => { + let macro_file = file_id.macro_file()?; + + self.with_ctx(|ctx| { + let expansion_info = ctx.cache.get_or_insert_expansion(ctx.db, macro_file); + expansion_info.arg().map(|node| node?.parent()).transpose() + }) } }) - .map(|it| it.value) } pub fn ancestors_at_offset_with_macros( @@ -1851,18 +1948,12 @@ impl<'db> SemanticsImpl<'db> { ChildContainer::TraitId(it) => { return Some(SourceAnalyzer::new_generic_def(self.db, it.into(), node, offset)); } - ChildContainer::TraitAliasId(it) => { - return Some(SourceAnalyzer::new_generic_def(self.db, it.into(), node, offset)); - } ChildContainer::ImplId(it) => { return Some(SourceAnalyzer::new_generic_def(self.db, it.into(), node, offset)); } ChildContainer::EnumId(it) => { return Some(SourceAnalyzer::new_generic_def(self.db, it.into(), node, offset)); } - ChildContainer::TypeAliasId(it) => { - return Some(SourceAnalyzer::new_generic_def(self.db, it.into(), node, offset)); - } ChildContainer::GenericDefId(it) => { return Some(SourceAnalyzer::new_generic_def(self.db, it, node, offset)); } diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics/child_by_source.rs b/src/tools/rust-analyzer/crates/hir/src/semantics/child_by_source.rs index 6accf9b2e9c..1a6d63c88c6 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics/child_by_source.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics/child_by_source.rs @@ -17,6 +17,7 @@ use hir_def::{ DynMap, keys::{self, Key}, }, + hir::generics::GenericParams, item_scope::ItemScope, item_tree::ItemTreeNode, nameres::DefMap, @@ -49,6 +50,12 @@ impl ChildBySource for TraitId { data.items.iter().for_each(|&(_, item)| { add_assoc_item(db, res, file_id, item); }); + let (_, source_map) = db.trait_signature_with_source_map(*self); + source_map.expansions().filter(|(ast, _)| ast.file_id == file_id).for_each( + |(ast, &exp_id)| { + res[keys::MACRO_CALL].insert(ast.value, exp_id); + }, + ); } } @@ -68,6 +75,12 @@ impl ChildBySource for ImplId { data.items.iter().for_each(|&(_, item)| { add_assoc_item(db, res, file_id, item); }); + let (_, source_map) = db.impl_signature_with_source_map(*self); + source_map.expansions().filter(|(ast, _)| ast.file_id == file_id).for_each( + |(ast, &exp_id)| { + res[keys::MACRO_CALL].insert(ast.value, exp_id); + }, + ); } } @@ -178,6 +191,8 @@ impl ChildBySource for VariantId { Either::Right(source) => res[keys::RECORD_FIELD].insert(AstPtr::new(&source), id), } } + let (_, sm) = db.variant_fields_with_source_map(*self); + sm.expansions().for_each(|(ast, &exp_id)| res[keys::MACRO_CALL].insert(ast.value, exp_id)); } } @@ -195,6 +210,11 @@ impl ChildBySource for EnumId { res[keys::ENUM_VARIANT] .insert(ast_id_map.get(tree[variant.lookup(db).id.value].ast_id), variant); }); + let (_, source_map) = db.enum_signature_with_source_map(*self); + source_map + .expansions() + .filter(|(ast, _)| ast.file_id == file_id) + .for_each(|(ast, &exp_id)| res[keys::MACRO_CALL].insert(ast.value, exp_id)); } } @@ -225,7 +245,8 @@ impl ChildBySource for GenericDefId { return; } - let generic_params = db.generic_params(*self); + let (generic_params, _, source_map) = + GenericParams::generic_params_and_store_and_source_map(db, *self); let mut toc_idx_iter = generic_params.iter_type_or_consts().map(|(idx, _)| idx); let lts_idx_iter = generic_params.iter_lt().map(|(idx, _)| idx); @@ -253,6 +274,11 @@ impl ChildBySource for GenericDefId { res[keys::LIFETIME_PARAM].insert(AstPtr::new(&ast_param), id); } } + + source_map + .expansions() + .filter(|(ast, _)| ast.file_id == file_id) + .for_each(|(ast, &exp_id)| res[keys::MACRO_CALL].insert(ast.value, exp_id)); } } 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 7f6c9af4740..71ee0f69389 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 @@ -108,7 +108,7 @@ use span::FileId; use stdx::impl_from; use syntax::{ AstNode, AstPtr, SyntaxNode, - ast::{self, HasName}, + ast::{self, HasAttrs, HasName}, }; use tt::TextRange; @@ -411,10 +411,25 @@ impl SourceToDefCtx<'_, '_> { .map(|&(attr_id, call_id, ref ids)| (attr_id, call_id, &**ids)) } - pub(super) fn has_derives(&mut self, adt: InFile<&ast::Adt>) -> bool { + // FIXME: Make this more fine grained! This should be a `adt_has_derives`! + pub(super) fn file_of_adt_has_derives(&mut self, adt: InFile<&ast::Adt>) -> bool { self.dyn_map(adt).as_ref().is_some_and(|map| !map[keys::DERIVE_MACRO_CALL].is_empty()) } + pub(super) fn derive_macro_calls<'slf>( + &'slf mut self, + adt: InFile<&ast::Adt>, + ) -> Option<impl Iterator<Item = (AttrId, MacroCallId, &'slf [Option<MacroCallId>])> + use<'slf>> + { + self.dyn_map(adt).as_ref().map(|&map| { + let dyn_map = &map[keys::DERIVE_MACRO_CALL]; + adt.value + .attrs() + .filter_map(move |attr| dyn_map.get(&AstPtr::new(&attr))) + .map(|&(attr_id, call_id, ref ids)| (attr_id, call_id, &**ids)) + }) + } + fn to_def<Ast: AstNode + 'static, ID: Copy + 'static>( &mut self, src: InFile<&Ast>, @@ -616,14 +631,14 @@ impl SourceToDefCtx<'_, '_> { match &item { ast::Item::Module(it) => self.module_to_def(container.with_value(it))?.into(), ast::Item::Trait(it) => self.trait_to_def(container.with_value(it))?.into(), - ast::Item::TraitAlias(it) => { - self.trait_alias_to_def(container.with_value(it))?.into() - } ast::Item::Impl(it) => self.impl_to_def(container.with_value(it))?.into(), ast::Item::Enum(it) => self.enum_to_def(container.with_value(it))?.into(), - ast::Item::TypeAlias(it) => { - self.type_alias_to_def(container.with_value(it))?.into() - } + ast::Item::TypeAlias(it) => ChildContainer::GenericDefId( + self.type_alias_to_def(container.with_value(it))?.into(), + ), + ast::Item::TraitAlias(it) => ChildContainer::GenericDefId( + self.trait_alias_to_def(container.with_value(it))?.into(), + ), ast::Item::Struct(it) => { let def = self.struct_to_def(container.with_value(it))?; let is_in_body = it.field_list().is_some_and(|it| { @@ -723,11 +738,9 @@ pub(crate) enum ChildContainer { DefWithBodyId(DefWithBodyId), ModuleId(ModuleId), TraitId(TraitId), - TraitAliasId(TraitAliasId), ImplId(ImplId), EnumId(EnumId), VariantId(VariantId), - TypeAliasId(TypeAliasId), /// XXX: this might be the same def as, for example an `EnumId`. However, /// here the children are generic parameters, and not, eg enum variants. GenericDefId(GenericDefId), @@ -736,11 +749,9 @@ impl_from! { DefWithBodyId, ModuleId, TraitId, - TraitAliasId, ImplId, EnumId, VariantId, - TypeAliasId, GenericDefId for ChildContainer } @@ -752,11 +763,9 @@ impl ChildContainer { ChildContainer::DefWithBodyId(it) => it.child_by_source(db, file_id), ChildContainer::ModuleId(it) => it.child_by_source(db, file_id), ChildContainer::TraitId(it) => it.child_by_source(db, file_id), - ChildContainer::TraitAliasId(_) => DynMap::default(), ChildContainer::ImplId(it) => it.child_by_source(db, file_id), ChildContainer::EnumId(it) => it.child_by_source(db, file_id), ChildContainer::VariantId(it) => it.child_by_source(db, file_id), - ChildContainer::TypeAliasId(_) => DynMap::default(), ChildContainer::GenericDefId(it) => it.child_by_source(db, file_id), } } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs index 5d75e445861..32c4ae2e869 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs @@ -56,14 +56,22 @@ pub(crate) fn convert_named_struct_to_tuple_struct( // XXX: We don't currently provide this assist for struct definitions inside macros, but if we // are to lift this limitation, don't forget to make `edit_struct_def()` consider macro files // too. - let name = ctx.find_node_at_offset::<ast::Name>()?; - let strukt = name.syntax().parent().and_then(<Either<ast::Struct, ast::Variant>>::cast)?; - let field_list = strukt.as_ref().either(|s| s.field_list(), |v| v.field_list())?; + let strukt_or_variant = ctx + .find_node_at_offset::<ast::Struct>() + .map(Either::Left) + .or_else(|| ctx.find_node_at_offset::<ast::Variant>().map(Either::Right))?; + let field_list = strukt_or_variant.as_ref().either(|s| s.field_list(), |v| v.field_list())?; + + if ctx.offset() > field_list.syntax().text_range().start() { + // Assist could be distracting after the braces + return None; + } + let record_fields = match field_list { ast::FieldList::RecordFieldList(it) => it, ast::FieldList::TupleFieldList(_) => return None, }; - let strukt_def = match &strukt { + let strukt_def = match &strukt_or_variant { Either::Left(s) => Either::Left(ctx.sema.to_def(s)?), Either::Right(v) => Either::Right(ctx.sema.to_def(v)?), }; @@ -71,11 +79,11 @@ pub(crate) fn convert_named_struct_to_tuple_struct( acc.add( AssistId::refactor_rewrite("convert_named_struct_to_tuple_struct"), "Convert to tuple struct", - strukt.syntax().text_range(), + strukt_or_variant.syntax().text_range(), |edit| { edit_field_references(ctx, edit, record_fields.fields()); edit_struct_references(ctx, edit, strukt_def); - edit_struct_def(ctx, edit, &strukt, record_fields); + edit_struct_def(ctx, edit, &strukt_or_variant, record_fields); }, ) } @@ -294,6 +302,88 @@ impl A { } #[test] + fn convert_simple_struct_cursor_on_struct_keyword() { + check_assist( + convert_named_struct_to_tuple_struct, + r#" +struct Inner; +struct$0 A { inner: Inner } + +impl A { + fn new(inner: Inner) -> A { + A { inner } + } + + fn new_with_default() -> A { + A::new(Inner) + } + + fn into_inner(self) -> Inner { + self.inner + } +}"#, + r#" +struct Inner; +struct A(Inner); + +impl A { + fn new(inner: Inner) -> A { + A(inner) + } + + fn new_with_default() -> A { + A::new(Inner) + } + + fn into_inner(self) -> Inner { + self.0 + } +}"#, + ); + } + + #[test] + fn convert_simple_struct_cursor_on_visibility_keyword() { + check_assist( + convert_named_struct_to_tuple_struct, + r#" +struct Inner; +pub$0 struct A { inner: Inner } + +impl A { + fn new(inner: Inner) -> A { + A { inner } + } + + fn new_with_default() -> A { + A::new(Inner) + } + + fn into_inner(self) -> Inner { + self.inner + } +}"#, + r#" +struct Inner; +pub struct A(Inner); + +impl A { + fn new(inner: Inner) -> A { + A(inner) + } + + fn new_with_default() -> A { + A::new(Inner) + } + + fn into_inner(self) -> Inner { + self.0 + } +}"#, + ); + } + + #[test] fn convert_struct_referenced_via_self_kw() { check_assist( convert_named_struct_to_tuple_struct, diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs index 0c0b93bcfbc..80756197fb7 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs @@ -51,18 +51,26 @@ pub(crate) fn convert_tuple_struct_to_named_struct( acc: &mut Assists, ctx: &AssistContext<'_>, ) -> Option<()> { - let name = ctx.find_node_at_offset::<ast::Name>()?; - let strukt = name.syntax().parent().and_then(<Either<ast::Struct, ast::Variant>>::cast)?; - let field_list = strukt.as_ref().either(|s| s.field_list(), |v| v.field_list())?; + let strukt_or_variant = ctx + .find_node_at_offset::<ast::Struct>() + .map(Either::Left) + .or_else(|| ctx.find_node_at_offset::<ast::Variant>().map(Either::Right))?; + let field_list = strukt_or_variant.as_ref().either(|s| s.field_list(), |v| v.field_list())?; + + if ctx.offset() > field_list.syntax().text_range().start() { + // Assist could be distracting after the braces + return None; + } + let tuple_fields = match field_list { ast::FieldList::TupleFieldList(it) => it, ast::FieldList::RecordFieldList(_) => return None, }; - let strukt_def = match &strukt { + let strukt_def = match &strukt_or_variant { Either::Left(s) => Either::Left(ctx.sema.to_def(s)?), Either::Right(v) => Either::Right(ctx.sema.to_def(v)?), }; - let target = strukt.as_ref().either(|s| s.syntax(), |v| v.syntax()).text_range(); + let target = strukt_or_variant.as_ref().either(|s| s.syntax(), |v| v.syntax()).text_range(); acc.add( AssistId::refactor_rewrite("convert_tuple_struct_to_named_struct"), @@ -72,7 +80,7 @@ pub(crate) fn convert_tuple_struct_to_named_struct( let names = generate_names(tuple_fields.fields()); edit_field_references(ctx, edit, tuple_fields.fields(), &names); edit_struct_references(ctx, edit, strukt_def, &names); - edit_struct_def(ctx, edit, &strukt, tuple_fields, names); + edit_struct_def(ctx, edit, &strukt_or_variant, tuple_fields, names); }, ) } @@ -317,6 +325,88 @@ impl A { } #[test] + fn convert_simple_struct_cursor_on_struct_keyword() { + check_assist( + convert_tuple_struct_to_named_struct, + r#" +struct Inner; +struct$0 A(Inner); + +impl A { + fn new(inner: Inner) -> A { + A(inner) + } + + fn new_with_default() -> A { + A::new(Inner) + } + + fn into_inner(self) -> Inner { + self.0 + } +}"#, + r#" +struct Inner; +struct A { field1: Inner } + +impl A { + fn new(inner: Inner) -> A { + A { field1: inner } + } + + fn new_with_default() -> A { + A::new(Inner) + } + + fn into_inner(self) -> Inner { + self.field1 + } +}"#, + ); + } + + #[test] + fn convert_simple_struct_cursor_on_visibility_keyword() { + check_assist( + convert_tuple_struct_to_named_struct, + r#" +struct Inner; +pub$0 struct A(Inner); + +impl A { + fn new(inner: Inner) -> A { + A(inner) + } + + fn new_with_default() -> A { + A::new(Inner) + } + + fn into_inner(self) -> Inner { + self.0 + } +}"#, + r#" +struct Inner; +pub struct A { field1: Inner } + +impl A { + fn new(inner: Inner) -> A { + A { field1: inner } + } + + fn new_with_default() -> A { + A::new(Inner) + } + + fn into_inner(self) -> Inner { + self.field1 + } +}"#, + ); + } + + #[test] fn convert_struct_referenced_via_self_kw() { check_assist( convert_tuple_struct_to_named_struct, diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/fix_visibility.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/fix_visibility.rs index 19e0a73f333..3badc17d01a 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/fix_visibility.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/fix_visibility.rs @@ -7,10 +7,10 @@ use syntax::{ use crate::{AssistContext, AssistId, Assists}; -// FIXME: this really should be a fix for diagnostic, rather than an assist. - // Assist: fix_visibility // +// Note that there is some duplication between this and the no_such_field diagnostic. +// // Makes inaccessible item public. // // ``` @@ -32,7 +32,6 @@ use crate::{AssistContext, AssistId, Assists}; // ``` pub(crate) fn fix_visibility(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { add_vis_to_referenced_module_def(acc, ctx) - .or_else(|| add_vis_to_referenced_record_field(acc, ctx)) } fn add_vis_to_referenced_module_def(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { @@ -88,59 +87,6 @@ fn add_vis_to_referenced_module_def(acc: &mut Assists, ctx: &AssistContext<'_>) }) } -fn add_vis_to_referenced_record_field(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { - let record_field: ast::RecordExprField = ctx.find_node_at_offset()?; - let (record_field_def, _, _) = ctx.sema.resolve_record_field(&record_field)?; - - let current_module = ctx.sema.scope(record_field.syntax())?.module(); - let current_edition = current_module.krate().edition(ctx.db()); - let visibility = record_field_def.visibility(ctx.db()); - if visibility.is_visible_from(ctx.db(), current_module.into()) { - return None; - } - - let parent = record_field_def.parent_def(ctx.db()); - let parent_name = parent.name(ctx.db()); - let target_module = parent.module(ctx.db()); - - let in_file_source = record_field_def.source(ctx.db())?; - let (vis_owner, target) = match in_file_source.value { - hir::FieldSource::Named(it) => { - let range = it.syntax().text_range(); - (ast::AnyHasVisibility::new(it), range) - } - hir::FieldSource::Pos(it) => { - let range = it.syntax().text_range(); - (ast::AnyHasVisibility::new(it), range) - } - }; - - let missing_visibility = if current_module.krate() == target_module.krate() { - make::visibility_pub_crate() - } else { - make::visibility_pub() - }; - let target_file = in_file_source.file_id.original_file(ctx.db()); - - let target_name = record_field_def.name(ctx.db()); - let assist_label = format!( - "Change visibility of {}.{} to {missing_visibility}", - parent_name.display(ctx.db(), current_edition), - target_name.display(ctx.db(), current_edition) - ); - - acc.add(AssistId::quick_fix("fix_visibility"), assist_label, target, |edit| { - edit.edit_file(target_file.file_id(ctx.db())); - - let vis_owner = edit.make_mut(vis_owner); - vis_owner.set_visibility(Some(missing_visibility.clone_for_update())); - - if let Some((cap, vis)) = ctx.config.snippet_cap.zip(vis_owner.visibility()) { - edit.add_tabstop_before(cap, vis); - } - }) -} - fn target_data_for_def( db: &dyn HirDatabase, def: hir::ModuleDef, @@ -294,44 +240,6 @@ struct Foo; } #[test] - fn fix_visibility_of_struct_field() { - check_assist( - fix_visibility, - r"mod foo { pub struct Foo { bar: (), } } - fn main() { foo::Foo { $0bar: () }; } ", - r"mod foo { pub struct Foo { $0pub(crate) bar: (), } } - fn main() { foo::Foo { bar: () }; } ", - ); - check_assist( - fix_visibility, - r" -//- /lib.rs -mod foo; -fn main() { foo::Foo { $0bar: () }; } -//- /foo.rs -pub struct Foo { bar: () } -", - r"pub struct Foo { $0pub(crate) bar: () } -", - ); - check_assist_not_applicable( - fix_visibility, - r"mod foo { pub struct Foo { pub bar: (), } } - fn main() { foo::Foo { $0bar: () }; } ", - ); - check_assist_not_applicable( - fix_visibility, - r" -//- /lib.rs -mod foo; -fn main() { foo::Foo { $0bar: () }; } -//- /foo.rs -pub struct Foo { pub bar: () } -", - ); - } - - #[test] fn fix_visibility_of_enum_variant_field() { // Enum variants, as well as their fields, always get the enum's visibility. In fact, rustc // rejects any visibility specifiers on them, so this assist should never fire on them. @@ -368,44 +276,6 @@ pub struct Foo { pub bar: () } } #[test] - fn fix_visibility_of_union_field() { - check_assist( - fix_visibility, - r"mod foo { pub union Foo { bar: (), } } - fn main() { foo::Foo { $0bar: () }; } ", - r"mod foo { pub union Foo { $0pub(crate) bar: (), } } - fn main() { foo::Foo { bar: () }; } ", - ); - check_assist( - fix_visibility, - r" -//- /lib.rs -mod foo; -fn main() { foo::Foo { $0bar: () }; } -//- /foo.rs -pub union Foo { bar: () } -", - r"pub union Foo { $0pub(crate) bar: () } -", - ); - check_assist_not_applicable( - fix_visibility, - r"mod foo { pub union Foo { pub bar: (), } } - fn main() { foo::Foo { $0bar: () }; } ", - ); - check_assist_not_applicable( - fix_visibility, - r" -//- /lib.rs -mod foo; -fn main() { foo::Foo { $0bar: () }; } -//- /foo.rs -pub union Foo { pub bar: () } -", - ); - } - - #[test] fn fix_visibility_of_const() { check_assist( fix_visibility, @@ -572,19 +442,6 @@ pub(crate) struct Bar; r"$0pub struct Bar; ", ); - check_assist( - fix_visibility, - r" -//- /main.rs crate:a deps:foo -fn main() { - foo::Foo { $0bar: () }; -} -//- /lib.rs crate:foo -pub struct Foo { pub(crate) bar: () } -", - r"pub struct Foo { $0pub bar: () } -", - ); } #[test] diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_underscore.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_underscore.rs index 912e1936b59..a8e27416d5c 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_underscore.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_underscore.rs @@ -1,6 +1,7 @@ use ide_db::{ assists::AssistId, defs::{Definition, NameClass, NameRefClass}, + rename::RenameDefinition, }; use syntax::{AstNode, ast}; @@ -61,7 +62,7 @@ pub(crate) fn remove_underscore(acc: &mut Assists, ctx: &AssistContext<'_>) -> O "Remove underscore from a used variable", text_range, |builder| { - let changes = def.rename(&ctx.sema, new_name).unwrap(); + let changes = def.rename(&ctx.sema, new_name, RenameDefinition::Yes).unwrap(); builder.source_change = changes; }, ) diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs index 3c195f80fea..705402c785a 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs @@ -25,6 +25,7 @@ use crate::{ mod cfg; mod derive; +mod diagnostic; mod lint; mod macro_use; mod repr; @@ -40,23 +41,22 @@ pub(crate) fn complete_known_attribute_input( extern_crate: Option<&ast::ExternCrate>, ) -> Option<()> { let attribute = fake_attribute_under_caret; - let name_ref = match attribute.path() { - Some(p) => Some(p.as_single_name_ref()?), - None => None, - }; - let (path, tt) = name_ref.zip(attribute.token_tree())?; - tt.l_paren_token()?; + let path = attribute.path()?; + let segments = path.segments().map(|s| s.name_ref()).collect::<Option<Vec<_>>>()?; + let segments = segments.iter().map(|n| n.text()).collect::<Vec<_>>(); + let segments = segments.iter().map(|t| t.as_str()).collect::<Vec<_>>(); + let tt = attribute.token_tree()?; - match path.text().as_str() { - "repr" => repr::complete_repr(acc, ctx, tt), - "feature" => lint::complete_lint( + match segments.as_slice() { + ["repr"] => repr::complete_repr(acc, ctx, tt), + ["feature"] => lint::complete_lint( acc, ctx, colon_prefix, &parse_tt_as_comma_sep_paths(tt, ctx.edition)?, FEATURES, ), - "allow" | "expect" | "deny" | "forbid" | "warn" => { + ["allow"] | ["expect"] | ["deny"] | ["forbid"] | ["warn"] => { let existing_lints = parse_tt_as_comma_sep_paths(tt, ctx.edition)?; let lints: Vec<Lint> = CLIPPY_LINT_GROUPS @@ -70,13 +70,14 @@ pub(crate) fn complete_known_attribute_input( lint::complete_lint(acc, ctx, colon_prefix, &existing_lints, &lints); } - "cfg" => cfg::complete_cfg(acc, ctx), - "macro_use" => macro_use::complete_macro_use( + ["cfg"] => cfg::complete_cfg(acc, ctx), + ["macro_use"] => macro_use::complete_macro_use( acc, ctx, extern_crate, &parse_tt_as_comma_sep_paths(tt, ctx.edition)?, ), + ["diagnostic", "on_unimplemented"] => diagnostic::complete_on_unimplemented(acc, ctx, tt), _ => (), } Some(()) @@ -139,6 +140,8 @@ pub(crate) fn complete_attribute_path( } Qualified::TypeAnchor { .. } | Qualified::With { .. } => {} } + let qualifier_path = + if let Qualified::With { path, .. } = qualified { Some(path) } else { None }; let attributes = annotated_item_kind.and_then(|kind| { if ast::Expr::can_cast(kind) { @@ -149,18 +152,33 @@ pub(crate) fn complete_attribute_path( }); let add_completion = |attr_completion: &AttrCompletion| { - let mut item = CompletionItem::new( - SymbolKind::Attribute, - ctx.source_range(), - attr_completion.label, - ctx.edition, - ); + // if we don't already have the qualifiers of the completion, then + // add the missing parts to the label and snippet + let mut label = attr_completion.label.to_owned(); + let mut snippet = attr_completion.snippet.map(|s| s.to_owned()); + let segments = qualifier_path.iter().flat_map(|q| q.segments()).collect::<Vec<_>>(); + let qualifiers = attr_completion.qualifiers; + let matching_qualifiers = segments + .iter() + .zip(qualifiers) + .take_while(|(s, q)| s.name_ref().is_some_and(|t| t.text() == **q)) + .count(); + if matching_qualifiers != qualifiers.len() { + let prefix = qualifiers[matching_qualifiers..].join("::"); + label = format!("{prefix}::{label}"); + if let Some(s) = snippet.as_mut() { + *s = format!("{prefix}::{s}"); + } + } + + let mut item = + CompletionItem::new(SymbolKind::Attribute, ctx.source_range(), label, ctx.edition); if let Some(lookup) = attr_completion.lookup { item.lookup_by(lookup); } - if let Some((snippet, cap)) = attr_completion.snippet.zip(ctx.config.snippet_cap) { + if let Some((snippet, cap)) = snippet.zip(ctx.config.snippet_cap) { item.insert_snippet(cap, snippet); } @@ -184,6 +202,7 @@ struct AttrCompletion { label: &'static str, lookup: Option<&'static str>, snippet: Option<&'static str>, + qualifiers: &'static [&'static str], prefer_inner: bool, } @@ -192,6 +211,10 @@ impl AttrCompletion { self.lookup.unwrap_or(self.label) } + const fn qualifiers(self, qualifiers: &'static [&'static str]) -> AttrCompletion { + AttrCompletion { qualifiers, ..self } + } + const fn prefer_inner(self) -> AttrCompletion { AttrCompletion { prefer_inner: true, ..self } } @@ -202,7 +225,7 @@ const fn attr( lookup: Option<&'static str>, snippet: Option<&'static str>, ) -> AttrCompletion { - AttrCompletion { label, lookup, snippet, prefer_inner: false } + AttrCompletion { label, lookup, snippet, qualifiers: &[], prefer_inner: false } } macro_rules! attrs { @@ -264,14 +287,14 @@ static KIND_TO_ATTRIBUTES: LazyLock<FxHashMap<SyntaxKind, &[&str]>> = LazyLock:: FN, attrs!( item, linkable, - "cold", "ignore", "inline", "must_use", "panic_handler", "proc_macro", + "cold", "ignore", "inline", "panic_handler", "proc_macro", "proc_macro_derive", "proc_macro_attribute", "should_panic", "target_feature", "test", "track_caller" ), ), (STATIC, attrs!(item, linkable, "global_allocator", "used")), - (TRAIT, attrs!(item, "must_use")), - (IMPL, attrs!(item, "automatically_derived")), + (TRAIT, attrs!(item, "diagnostic::on_unimplemented")), + (IMPL, attrs!(item, "automatically_derived", "diagnostic::do_not_recommend")), (ASSOC_ITEM_LIST, attrs!(item)), (EXTERN_BLOCK, attrs!(item, "link")), (EXTERN_ITEM_LIST, attrs!(item, "link")), @@ -311,6 +334,14 @@ const ATTRIBUTES: &[AttrCompletion] = &[ attr("deny(…)", Some("deny"), Some("deny(${0:lint})")), attr(r#"deprecated"#, Some("deprecated"), Some(r#"deprecated"#)), attr("derive(…)", Some("derive"), Some(r#"derive(${0:Debug})"#)), + attr("do_not_recommend", Some("diagnostic::do_not_recommend"), None) + .qualifiers(&["diagnostic"]), + attr( + "on_unimplemented", + Some("diagnostic::on_unimplemented"), + Some(r#"on_unimplemented(${0:keys})"#), + ) + .qualifiers(&["diagnostic"]), attr(r#"doc = "…""#, Some("doc"), Some(r#"doc = "${0:docs}""#)), attr(r#"doc(alias = "…")"#, Some("docalias"), Some(r#"doc(alias = "${0:docs}")"#)), attr(r#"doc(hidden)"#, Some("dochidden"), Some(r#"doc(hidden)"#)), diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/diagnostic.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/diagnostic.rs new file mode 100644 index 00000000000..8adc9742390 --- /dev/null +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/diagnostic.rs @@ -0,0 +1,60 @@ +//! Completion for diagnostic attributes. + +use ide_db::SymbolKind; +use syntax::ast; + +use crate::{CompletionItem, Completions, context::CompletionContext}; + +use super::AttrCompletion; + +pub(super) fn complete_on_unimplemented( + acc: &mut Completions, + ctx: &CompletionContext<'_>, + input: ast::TokenTree, +) { + if let Some(existing_keys) = super::parse_comma_sep_expr(input) { + for attr in ATTRIBUTE_ARGS { + let already_annotated = existing_keys + .iter() + .filter_map(|expr| match expr { + ast::Expr::PathExpr(path) => path.path()?.as_single_name_ref(), + ast::Expr::BinExpr(bin) + if bin.op_kind() == Some(ast::BinaryOp::Assignment { op: None }) => + { + match bin.lhs()? { + ast::Expr::PathExpr(path) => path.path()?.as_single_name_ref(), + _ => None, + } + } + _ => None, + }) + .any(|it| { + let text = it.text(); + attr.key() == text && text != "note" + }); + if already_annotated { + continue; + } + + let mut item = CompletionItem::new( + SymbolKind::BuiltinAttr, + ctx.source_range(), + attr.label, + ctx.edition, + ); + if let Some(lookup) = attr.lookup { + item.lookup_by(lookup); + } + if let Some((snippet, cap)) = attr.snippet.zip(ctx.config.snippet_cap) { + item.insert_snippet(cap, snippet); + } + item.add_to(acc, ctx.db); + } + } +} + +const ATTRIBUTE_ARGS: &[AttrCompletion] = &[ + super::attr(r#"label = "…""#, Some("label"), Some(r#"label = "${0:label}""#)), + super::attr(r#"message = "…""#, Some("message"), Some(r#"message = "${0:message}""#)), + super::attr(r#"note = "…""#, Some("note"), Some(r#"note = "${0:note}""#)), +]; diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs index 32d3b50f237..411902f1117 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs @@ -30,6 +30,8 @@ pub struct Foo(#[m$0] i32); at deprecated at derive macro derive at derive(…) + at diagnostic::do_not_recommend + at diagnostic::on_unimplemented at doc = "…" at doc(alias = "…") at doc(hidden) @@ -472,13 +474,13 @@ fn attr_on_trait() { at cfg_attr(…) at deny(…) at deprecated + at diagnostic::on_unimplemented at doc = "…" at doc(alias = "…") at doc(hidden) at expect(…) at forbid(…) at must_use - at must_use at no_mangle at warn(…) kw crate:: @@ -498,6 +500,7 @@ fn attr_on_impl() { at cfg_attr(…) at deny(…) at deprecated + at diagnostic::do_not_recommend at doc = "…" at doc(alias = "…") at doc(hidden) @@ -533,6 +536,76 @@ fn attr_on_impl() { } #[test] +fn attr_with_qualifier() { + check( + r#"#[diagnostic::$0] impl () {}"#, + expect![[r#" + at allow(…) + at automatically_derived + at cfg(…) + at cfg_attr(…) + at deny(…) + at deprecated + at do_not_recommend + at doc = "…" + at doc(alias = "…") + at doc(hidden) + at expect(…) + at forbid(…) + at must_use + at no_mangle + at warn(…) + "#]], + ); + check( + r#"#[diagnostic::$0] trait Foo {}"#, + expect![[r#" + at allow(…) + at cfg(…) + at cfg_attr(…) + at deny(…) + at deprecated + at doc = "…" + at doc(alias = "…") + at doc(hidden) + at expect(…) + at forbid(…) + at must_use + at no_mangle + at on_unimplemented + at warn(…) + "#]], + ); +} + +#[test] +fn attr_diagnostic_on_unimplemented() { + check( + r#"#[diagnostic::on_unimplemented($0)] trait Foo {}"#, + expect![[r#" + ba label = "…" + ba message = "…" + ba note = "…" + "#]], + ); + check( + r#"#[diagnostic::on_unimplemented(message = "foo", $0)] trait Foo {}"#, + expect![[r#" + ba label = "…" + ba note = "…" + "#]], + ); + check( + r#"#[diagnostic::on_unimplemented(note = "foo", $0)] trait Foo {}"#, + expect![[r#" + ba label = "…" + ba message = "…" + ba note = "…" + "#]], + ); +} + +#[test] fn attr_on_extern_block() { check( r#"#[$0] extern {}"#, @@ -619,7 +692,6 @@ fn attr_on_fn() { at link_name = "…" at link_section = "…" at must_use - at must_use at no_mangle at panic_handler at proc_macro @@ -649,6 +721,8 @@ fn attr_in_source_file_end() { at deny(…) at deprecated at derive(…) + at diagnostic::do_not_recommend + at diagnostic::on_unimplemented at doc = "…" at doc(alias = "…") at doc(hidden) diff --git a/src/tools/rust-analyzer/crates/ide-db/src/rename.rs b/src/tools/rust-analyzer/crates/ide-db/src/rename.rs index fa2a46a0f7c..4e737e27f05 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/rename.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/rename.rs @@ -20,7 +20,7 @@ //! //! The correct behavior in such cases is probably to show a dialog to the user. //! Our current behavior is ¯\_(ツ)_/¯. -use std::fmt; +use std::fmt::{self, Display}; use crate::{ source_change::ChangeAnnotation, @@ -28,13 +28,12 @@ use crate::{ }; use base_db::AnchoredPathBuf; use either::Either; -use hir::{EditionedFileId, FieldSource, FileRange, InFile, ModuleSource, Semantics}; +use hir::{FieldSource, FileRange, InFile, ModuleSource, Name, Semantics, sym}; use span::{Edition, FileId, SyntaxContext}; use stdx::{TupleExt, never}; use syntax::{ AstNode, SyntaxKind, T, TextRange, ast::{self, HasName}, - utils::is_raw_identifier, }; use crate::{ @@ -70,26 +69,33 @@ macro_rules! _bail { } pub use _bail as bail; +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum RenameDefinition { + Yes, + No, +} + impl Definition { pub fn rename( &self, sema: &Semantics<'_, RootDatabase>, new_name: &str, + rename_definition: RenameDefinition, ) -> Result<SourceChange> { - // We append `r#` if needed. - let new_name = new_name.trim_start_matches("r#"); - // self.krate() returns None if // self is a built-in attr, built-in type or tool module. // it is not allowed for these defs to be renamed. // cases where self.krate() is None is handled below. - if let Some(krate) = self.krate(sema.db) { + let edition = if let Some(krate) = self.krate(sema.db) { // Can we not rename non-local items? // Then bail if non-local if !krate.origin(sema.db).is_local() { bail!("Cannot rename a non-local definition") } - } + krate.edition(sema.db) + } else { + Edition::LATEST + }; match *self { Definition::Module(module) => rename_mod(sema, module, new_name), @@ -103,8 +109,10 @@ impl Definition { bail!("Cannot rename a builtin attr.") } Definition::SelfType(_) => bail!("Cannot rename `Self`"), - Definition::Macro(mac) => rename_reference(sema, Definition::Macro(mac), new_name), - def => rename_reference(sema, def, new_name), + Definition::Macro(mac) => { + rename_reference(sema, Definition::Macro(mac), new_name, rename_definition, edition) + } + def => rename_reference(sema, def, new_name, rename_definition, edition), } } @@ -237,10 +245,6 @@ fn rename_mod( module: hir::Module, new_name: &str, ) -> Result<SourceChange> { - if IdentifierKind::classify(new_name)? != IdentifierKind::Ident { - bail!("Invalid name `{0}`: cannot rename module to {0}", new_name); - } - let mut source_change = SourceChange::default(); if module.is_crate_root() { @@ -248,6 +252,14 @@ fn rename_mod( } let InFile { file_id, value: def_source } = module.definition_source(sema.db); + let edition = file_id.edition(sema.db); + let (new_name, kind) = IdentifierKind::classify(edition, new_name)?; + if kind != IdentifierKind::Ident { + bail!( + "Invalid name `{0}`: cannot rename module to {0}", + new_name.display(sema.db, edition) + ); + } if let ModuleSource::SourceFile(..) = def_source { let anchor = file_id.original_file(sema.db).file_id(sema.db); @@ -256,7 +268,7 @@ fn rename_mod( // Module exists in a named file if !is_mod_rs { - let path = format!("{new_name}.rs"); + let path = format!("{}.rs", new_name.as_str()); let dst = AnchoredPathBuf { anchor, path }; source_change.push_file_system_edit(FileSystemEdit::MoveFile { src: anchor, dst }) } @@ -267,11 +279,11 @@ fn rename_mod( let dir_paths = match (is_mod_rs, has_detached_child, module.name(sema.db)) { // Go up one level since the anchor is inside the dir we're trying to rename (true, _, Some(mod_name)) => { - Some((format!("../{}", mod_name.as_str()), format!("../{new_name}"))) + Some((format!("../{}", mod_name.as_str()), format!("../{}", new_name.as_str()))) } // The anchor is on the same level as target dir (false, true, Some(mod_name)) => { - Some((mod_name.as_str().to_owned(), new_name.to_owned())) + Some((mod_name.as_str().to_owned(), new_name.as_str().to_owned())) } _ => None, }; @@ -296,11 +308,7 @@ fn rename_mod( .original_file_range_opt(sema.db) .map(TupleExt::head) { - let new_name = if is_raw_identifier(new_name, file_id.edition(sema.db)) { - format!("r#{new_name}") - } else { - new_name.to_owned() - }; + let new_name = new_name.display(sema.db, edition).to_string(); source_change.insert_source_edit( file_id.file_id(sema.db), TextEdit::replace(file_range.range, new_name), @@ -314,9 +322,10 @@ fn rename_mod( let def = Definition::Module(module); let usages = def.usages(sema).all(); let ref_edits = usages.iter().map(|(file_id, references)| { + let edition = file_id.edition(sema.db); ( file_id.file_id(sema.db), - source_edit_from_references(references, def, new_name, file_id.edition(sema.db)), + source_edit_from_references(sema.db, references, def, &new_name, edition), ) }); source_change.extend(ref_edits); @@ -328,8 +337,10 @@ fn rename_reference( sema: &Semantics<'_, RootDatabase>, def: Definition, new_name: &str, + rename_definition: RenameDefinition, + edition: Edition, ) -> Result<SourceChange> { - let ident_kind = IdentifierKind::classify(new_name)?; + let (mut new_name, ident_kind) = IdentifierKind::classify(edition, new_name)?; if matches!( def, @@ -337,18 +348,34 @@ fn rename_reference( ) { match ident_kind { IdentifierKind::Underscore => { - bail!("Invalid name `{}`: not a lifetime identifier", new_name); + bail!( + "Invalid name `{}`: not a lifetime identifier", + new_name.display(sema.db, edition) + ); + } + IdentifierKind::Ident => { + new_name = Name::new_lifetime(&format!("'{}", new_name.as_str())) } - _ => cov_mark::hit!(rename_lifetime), + IdentifierKind::Lifetime => (), + IdentifierKind::LowercaseSelf => bail!( + "Invalid name `{}`: not a lifetime identifier", + new_name.display(sema.db, edition) + ), } } else { match ident_kind { IdentifierKind::Lifetime => { cov_mark::hit!(rename_not_an_ident_ref); - bail!("Invalid name `{}`: not an identifier", new_name); + bail!("Invalid name `{}`: not an identifier", new_name.display(sema.db, edition)); } IdentifierKind::Ident => cov_mark::hit!(rename_non_local), IdentifierKind::Underscore => (), + IdentifierKind::LowercaseSelf => { + bail!( + "Invalid name `{}`: cannot rename to `self`", + new_name.display(sema.db, edition) + ); + } } } @@ -361,30 +388,29 @@ fn rename_reference( } let mut source_change = SourceChange::default(); source_change.extend(usages.iter().map(|(file_id, references)| { + let edition = file_id.edition(sema.db); ( file_id.file_id(sema.db), - source_edit_from_references(references, def, new_name, file_id.edition(sema.db)), + source_edit_from_references(sema.db, references, def, &new_name, edition), ) })); - - // This needs to come after the references edits, because we change the annotation of existing edits - // if a conflict is detected. - let (file_id, edit) = source_edit_from_def(sema, def, new_name, &mut source_change)?; - source_change.insert_source_edit(file_id, edit); + if rename_definition == RenameDefinition::Yes { + // This needs to come after the references edits, because we change the annotation of existing edits + // if a conflict is detected. + let (file_id, edit) = source_edit_from_def(sema, def, &new_name, &mut source_change)?; + source_change.insert_source_edit(file_id, edit); + } Ok(source_change) } pub fn source_edit_from_references( + db: &RootDatabase, references: &[FileReference], def: Definition, - new_name: &str, + new_name: &Name, edition: Edition, ) -> TextEdit { - let new_name = if is_raw_identifier(new_name, edition) { - format!("r#{new_name}") - } else { - new_name.to_owned() - }; + let name_display = new_name.display(db, edition); let mut edit = TextEdit::builder(); // macros can cause multiple refs to occur for the same text range, so keep track of what we have edited so far let mut edited_ranges = Vec::new(); @@ -395,23 +421,15 @@ pub fn source_edit_from_references( // to make special rewrites like shorthand syntax and such, so just rename the node in // the macro input FileReferenceNode::NameRef(name_ref) if name_range == range => { - source_edit_from_name_ref(&mut edit, name_ref, &new_name, def) + source_edit_from_name_ref(&mut edit, name_ref, &name_display, def) } FileReferenceNode::Name(name) if name_range == range => { - source_edit_from_name(&mut edit, name, &new_name) + source_edit_from_name(&mut edit, name, &name_display) } _ => false, }; if !has_emitted_edit && !edited_ranges.contains(&range.start()) { - let (range, new_name) = match name { - FileReferenceNode::Lifetime(_) => ( - TextRange::new(range.start() + syntax::TextSize::from(1), range.end()), - new_name.strip_prefix('\'').unwrap_or(&new_name).to_owned(), - ), - _ => (range, new_name.to_owned()), - }; - - edit.replace(range, new_name); + edit.replace(range, name_display.to_string()); edited_ranges.push(range.start()); } } @@ -419,7 +437,11 @@ pub fn source_edit_from_references( edit.finish() } -fn source_edit_from_name(edit: &mut TextEditBuilder, name: &ast::Name, new_name: &str) -> bool { +fn source_edit_from_name( + edit: &mut TextEditBuilder, + name: &ast::Name, + new_name: &dyn Display, +) -> bool { if ast::RecordPatField::for_field_name(name).is_some() { if let Some(ident_pat) = name.syntax().parent().and_then(ast::IdentPat::cast) { cov_mark::hit!(rename_record_pat_field_name_split); @@ -439,7 +461,7 @@ fn source_edit_from_name(edit: &mut TextEditBuilder, name: &ast::Name, new_name: fn source_edit_from_name_ref( edit: &mut TextEditBuilder, name_ref: &ast::NameRef, - new_name: &str, + new_name: &dyn Display, def: Definition, ) -> bool { if name_ref.super_token().is_some() { @@ -452,6 +474,7 @@ fn source_edit_from_name_ref( match &(rcf_name_ref, rcf_expr.and_then(|it| expr_as_name_ref(&it))) { // field: init-expr, check if we can use a field init shorthand (Some(field_name), Some(init)) => { + let new_name = new_name.to_string(); if field_name == name_ref { if init.text() == new_name { cov_mark::hit!(test_rename_field_put_init_shorthand); @@ -507,6 +530,7 @@ fn source_edit_from_name_ref( { // field name is being renamed if let Some(name) = pat.name() { + let new_name = new_name.to_string(); if name.text() == new_name { cov_mark::hit!(test_rename_field_put_init_shorthand_pat); // Foo { field: ref mut local } -> Foo { ref mut field } @@ -518,7 +542,7 @@ fn source_edit_from_name_ref( let s = field_name.syntax().text_range().start(); let e = pat.syntax().text_range().start(); edit.delete(TextRange::new(s, e)); - edit.replace(name.syntax().text_range(), new_name.to_owned()); + edit.replace(name.syntax().text_range(), new_name); return true; } } @@ -532,16 +556,9 @@ fn source_edit_from_name_ref( fn source_edit_from_def( sema: &Semantics<'_, RootDatabase>, def: Definition, - new_name: &str, + new_name: &Name, source_change: &mut SourceChange, ) -> Result<(FileId, TextEdit)> { - let new_name_edition_aware = |new_name: &str, file_id: EditionedFileId| { - if is_raw_identifier(new_name, file_id.edition(sema.db)) { - format!("r#{new_name}") - } else { - new_name.to_owned() - } - }; let mut edit = TextEdit::builder(); if let Definition::Local(local) = def { let mut file_id = None; @@ -573,7 +590,10 @@ fn source_edit_from_def( { Some(FileRange { file_id: file_id2, range }) => { file_id = Some(file_id2); - edit.replace(range, new_name_edition_aware(new_name, file_id2)); + edit.replace( + range, + new_name.display(sema.db, file_id2.edition(sema.db)).to_string(), + ); continue; } None => { @@ -587,7 +607,7 @@ fn source_edit_from_def( // special cases required for renaming fields/locals in Record patterns if let Some(pat_field) = pat.syntax().parent().and_then(ast::RecordPatField::cast) { if let Some(name_ref) = pat_field.name_ref() { - if new_name == name_ref.text().as_str().trim_start_matches("r#") + if new_name.as_str() == name_ref.text().as_str().trim_start_matches("r#") && pat.at_token().is_none() { // Foo { field: ref mut local } -> Foo { ref mut field } @@ -607,7 +627,9 @@ fn source_edit_from_def( // ^^^^^ replace this with `new_name` edit.replace( name_range, - new_name_edition_aware(new_name, source.file_id), + new_name + .display(sema.db, source.file_id.edition(sema.db)) + .to_string(), ); } } else { @@ -618,10 +640,16 @@ fn source_edit_from_def( pat.syntax().text_range().start(), format!("{}: ", pat_field.field_name().unwrap()), ); - edit.replace(name_range, new_name_edition_aware(new_name, source.file_id)); + edit.replace( + name_range, + new_name.display(sema.db, source.file_id.edition(sema.db)).to_string(), + ); } } else { - edit.replace(name_range, new_name_edition_aware(new_name, source.file_id)); + edit.replace( + name_range, + new_name.display(sema.db, source.file_id.edition(sema.db)).to_string(), + ); } } } @@ -639,16 +667,13 @@ fn source_edit_from_def( .range_for_rename(sema) .ok_or_else(|| format_err!("No identifier available to rename"))?; let (range, new_name) = match def { - Definition::GenericParam(hir::GenericParam::LifetimeParam(_)) | Definition::Label(_) => ( - TextRange::new(range.start() + syntax::TextSize::from(1), range.end()), - new_name.strip_prefix('\'').unwrap_or(new_name).to_owned(), + Definition::ExternCrateDecl(decl) if decl.alias(sema.db).is_none() => ( + TextRange::empty(range.end()), + format!(" as {}", new_name.display(sema.db, file_id.edition(sema.db)),), ), - Definition::ExternCrateDecl(decl) if decl.alias(sema.db).is_none() => { - (TextRange::empty(range.end()), format!(" as {new_name}")) - } - _ => (range, new_name.to_owned()), + _ => (range, new_name.display(sema.db, file_id.edition(sema.db)).to_string()), }; - edit.replace(range, new_name_edition_aware(&new_name, file_id)); + edit.replace(range, new_name); Ok((file_id.file_id(sema.db), edit.finish())) } @@ -657,26 +682,27 @@ pub enum IdentifierKind { Ident, Lifetime, Underscore, + LowercaseSelf, } impl IdentifierKind { - pub fn classify(new_name: &str) -> Result<IdentifierKind> { - let new_name = new_name.trim_start_matches("r#"); - match parser::LexedStr::single_token(Edition::LATEST, new_name) { + pub fn classify(edition: Edition, new_name: &str) -> Result<(Name, IdentifierKind)> { + match parser::LexedStr::single_token(edition, new_name) { Some(res) => match res { - (SyntaxKind::IDENT, _) => { - if let Some(inner) = new_name.strip_prefix("r#") { - if matches!(inner, "self" | "crate" | "super" | "Self") { - bail!("Invalid name: `{}` cannot be a raw identifier", inner); - } - } - Ok(IdentifierKind::Ident) + (SyntaxKind::IDENT, _) => Ok((Name::new_root(new_name), IdentifierKind::Ident)), + (T![_], _) => { + Ok((Name::new_symbol_root(sym::underscore), IdentifierKind::Underscore)) } - (T![_], _) => Ok(IdentifierKind::Underscore), (SyntaxKind::LIFETIME_IDENT, _) if new_name != "'static" && new_name != "'_" => { - Ok(IdentifierKind::Lifetime) + Ok((Name::new_lifetime(new_name), IdentifierKind::Lifetime)) } - _ if is_raw_identifier(new_name, Edition::LATEST) => Ok(IdentifierKind::Ident), + _ if SyntaxKind::from_keyword(new_name, edition).is_some() => match new_name { + "self" => Ok((Name::new_root(new_name), IdentifierKind::LowercaseSelf)), + "crate" | "super" | "Self" => { + bail!("Invalid name `{}`: cannot rename to a keyword", new_name) + } + _ => Ok((Name::new_root(new_name), IdentifierKind::Ident)), + }, (_, Some(syntax_error)) => bail!("Invalid name `{}`: {}", new_name, syntax_error), (_, None) => bail!("Invalid name `{}`: not an identifier", new_name), }, diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs index 38f10c778d6..519ff192799 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs @@ -1,5 +1,5 @@ use hir::{CaseType, InFile, db::ExpandDatabase}; -use ide_db::{assists::Assist, defs::NameClass}; +use ide_db::{assists::Assist, defs::NameClass, rename::RenameDefinition}; use syntax::AstNode; use crate::{ @@ -44,7 +44,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::IncorrectCase) -> Option<Vec<Ass let label = format!("Rename to {}", d.suggested_text); let mut res = unresolved_fix("change_case", &label, frange.range); if ctx.resolve.should_resolve(&res.id) { - let source_change = def.rename(&ctx.sema, &d.suggested_text); + let source_change = def.rename(&ctx.sema, &d.suggested_text, RenameDefinition::Yes); res.source_change = Some(source_change.ok().unwrap_or_default()); } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs index 87c9397fb77..bf7dddacd8c 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs @@ -135,6 +135,7 @@ pub(crate) fn json_in_items( "JSON syntax is not valid as a Rust item", FileRange { file_id: vfs_file_id, range }, ) + .stable() .with_fixes(Some(vec![{ let mut scb = SourceChangeBuilder::new(vfs_file_id); let scope = scb.make_import_scope_mut(import_scope); diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs index 84fb467a5ce..ef42f2dc744 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs @@ -1,4 +1,5 @@ use either::Either; +use hir::{Field, HasCrate}; use hir::{HasSource, HirDisplay, Semantics, VariantId, db::ExpandDatabase}; use ide_db::text_edit::TextEdit; use ide_db::{EditionedFileId, RootDatabase, source_change::SourceChange}; @@ -13,44 +14,69 @@ use crate::{Assist, Diagnostic, DiagnosticCode, DiagnosticsContext, fix}; // // This diagnostic is triggered if created structure does not have field provided in record. pub(crate) fn no_such_field(ctx: &DiagnosticsContext<'_>, d: &hir::NoSuchField) -> Diagnostic { - let node = d.field.map(Into::into); - if d.private { - // FIXME: quickfix to add required visibility - Diagnostic::new_with_syntax_node_ptr( - ctx, - DiagnosticCode::RustcHardError("E0451"), - "field is private", - node, - ) - .stable() + let (code, message) = if d.private.is_some() { + ("E0451", "field is private") + } else if let VariantId::EnumVariantId(_) = d.variant { + ("E0559", "no such field") } else { - Diagnostic::new_with_syntax_node_ptr( - ctx, - match d.variant { - VariantId::EnumVariantId(_) => DiagnosticCode::RustcHardError("E0559"), - _ => DiagnosticCode::RustcHardError("E0560"), - }, - "no such field", - node, - ) + ("E0560", "no such field") + }; + + let node = d.field.map(Into::into); + Diagnostic::new_with_syntax_node_ptr(ctx, DiagnosticCode::RustcHardError(code), message, node) .stable() .with_fixes(fixes(ctx, d)) - } } fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::NoSuchField) -> Option<Vec<Assist>> { // FIXME: quickfix for pattern let root = ctx.sema.db.parse_or_expand(d.field.file_id); match &d.field.value.to_node(&root) { - Either::Left(node) => missing_record_expr_field_fixes( - &ctx.sema, - d.field.file_id.original_file(ctx.sema.db), - node, - ), + Either::Left(node) => { + if let Some(private_field) = d.private { + field_is_private_fixes( + &ctx.sema, + d.field.file_id.original_file(ctx.sema.db), + node, + private_field, + ) + } else { + missing_record_expr_field_fixes( + &ctx.sema, + d.field.file_id.original_file(ctx.sema.db), + node, + ) + } + } _ => None, } } +fn field_is_private_fixes( + sema: &Semantics<'_, RootDatabase>, + usage_file_id: EditionedFileId, + record_expr_field: &ast::RecordExprField, + private_field: Field, +) -> Option<Vec<Assist>> { + let def_crate = private_field.krate(sema.db); + let usage_crate = sema.file_to_module_def(usage_file_id.file_id(sema.db))?.krate(); + let visibility = if usage_crate == def_crate { "pub(crate) " } else { "pub " }; + + let source = private_field.source(sema.db)?; + let (range, _) = source.syntax().original_file_range_opt(sema.db)?; + let source_change = SourceChange::from_text_edit( + range.file_id.file_id(sema.db), + TextEdit::insert(range.range.start(), visibility.into()), + ); + + Some(vec![fix( + "increase_field_visibility", + "Increase field visibility", + source_change, + sema.original_range(record_expr_field.syntax()).range, + )]) +} + fn missing_record_expr_field_fixes( sema: &Semantics<'_, RootDatabase>, usage_file_id: EditionedFileId, @@ -118,7 +144,7 @@ fn missing_record_expr_field_fixes( "create_field", "Create field", source_change, - record_expr_field.syntax().text_range(), + sema.original_range(record_expr_field.syntax()).range, )]); fn record_field_list(field_def_list: ast::FieldList) -> Option<ast::RecordFieldList> { @@ -387,15 +413,15 @@ fn f(s@m::Struct { // assignee expression m::Struct { field: 0, - //^^^^^^^^ error: field is private + //^^^^^^^^ 💡 error: field is private field2 - //^^^^^^ error: field is private + //^^^^^^ 💡 error: field is private } = s; m::Struct { field: 0, - //^^^^^^^^ error: field is private + //^^^^^^^^ 💡 error: field is private field2 - //^^^^^^ error: field is private + //^^^^^^ 💡 error: field is private }; } "#, @@ -403,6 +429,77 @@ fn f(s@m::Struct { } #[test] + fn test_struct_field_private_same_crate_fix() { + check_diagnostics( + r#" +mod m { + pub struct Struct { + field: u32, + } +} +fn f() { + let _ = m::Struct { + field: 0, + //^^^^^^^^ 💡 error: field is private + }; +} +"#, + ); + + check_fix( + r#" +mod m { + pub struct Struct { + field: u32, + } +} +fn f() { + let _ = m::Struct { + field$0: 0, + }; +} +"#, + r#" +mod m { + pub struct Struct { + pub(crate) field: u32, + } +} +fn f() { + let _ = m::Struct { + field: 0, + }; +} +"#, + ); + } + + #[test] + fn test_struct_field_private_other_crate_fix() { + check_fix( + r#" +//- /lib.rs crate:another_crate +pub struct Struct { + field: u32, +} +//- /lib.rs crate:this_crate deps:another_crate +use another_crate; + +fn f() { + let _ = another_crate::Struct { + field$0: 0, + }; +} +"#, + r#" +pub struct Struct { + pub field: u32, +} +"#, + ); + } + + #[test] fn editions_between_macros() { check_diagnostics( r#" diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs index af9126c8933..d96c658d7b0 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs @@ -69,6 +69,7 @@ pub(crate) fn unlinked_file( FileRange { file_id, range }, ) .with_unused(unused) + .stable() .with_fixes(fixes), ); } diff --git a/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs b/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs index 7c396339c14..f31886b9697 100644 --- a/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs +++ b/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs @@ -800,4 +800,65 @@ foo(); foo();"#]], ); } + + #[test] + fn works_in_sig() { + check( + r#" +macro_rules! foo { + () => { u32 }; +} +fn foo() -> foo$0!() { + 42 +} +"#, + expect![[r#" + foo! + u32"#]], + ); + check( + r#" +macro_rules! foo { + () => { u32 }; +} +fn foo(_: foo$0!() ) {} +"#, + expect![[r#" + foo! + u32"#]], + ); + } + + #[test] + fn works_in_generics() { + check( + r#" +trait Trait {} +macro_rules! foo { + () => { Trait }; +} +impl<const C: foo$0!()> Trait for () {} +"#, + expect![[r#" + foo! + Trait"#]], + ); + } + + #[test] + fn works_in_fields() { + check( + r#" +macro_rules! foo { + () => { u32 }; +} +struct S { + field: foo$0!(), +} +"#, + expect![[r#" + foo! + u32"#]], + ); + } } diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs index 82704af647d..b094b098462 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs @@ -6,7 +6,7 @@ use std::{ use either::Either; use hir::{ ClosureStyle, DisplayTarget, EditionedFileId, HasVisibility, HirDisplay, HirDisplayError, - HirWrite, ModuleDef, ModuleDefId, Semantics, sym, + HirWrite, InRealFile, ModuleDef, ModuleDefId, Semantics, sym, }; use ide_db::{FileRange, RootDatabase, famous_defs::FamousDefs, text_edit::TextEditBuilder}; use ide_db::{FxHashSet, text_edit::TextEdit}; @@ -34,6 +34,7 @@ mod extern_block; mod generic_param; mod implicit_drop; mod implicit_static; +mod implied_dyn_trait; mod lifetime; mod param_name; mod range_exclusive; @@ -95,16 +96,16 @@ pub(crate) fn inlay_hints( return acc; }; let famous_defs = FamousDefs(&sema, scope.krate()); + let display_target = famous_defs.1.to_display_target(sema.db); let ctx = &mut InlayHintCtx::default(); let mut hints = |event| { if let Some(node) = handle_event(ctx, event) { - hints(&mut acc, ctx, &famous_defs, config, file_id, node); + hints(&mut acc, ctx, &famous_defs, config, file_id, display_target, node); } }; let mut preorder = file.preorder(); while let Some(event) = preorder.next() { - // FIXME: This can miss some hints that require the parent of the range to calculate if matches!((&event, range_limit), (WalkEvent::Enter(node), Some(range)) if range.intersect(node.text_range()).is_none()) { preorder.skip_subtree(); @@ -144,10 +145,12 @@ pub(crate) fn inlay_hints_resolve( let famous_defs = FamousDefs(&sema, scope.krate()); let mut acc = Vec::new(); + let display_target = famous_defs.1.to_display_target(sema.db); + let ctx = &mut InlayHintCtx::default(); let mut hints = |event| { if let Some(node) = handle_event(ctx, event) { - hints(&mut acc, ctx, &famous_defs, config, file_id, node); + hints(&mut acc, ctx, &famous_defs, config, file_id, display_target, node); } }; @@ -202,17 +205,19 @@ fn handle_event(ctx: &mut InlayHintCtx, node: WalkEvent<SyntaxNode>) -> Option<S fn hints( hints: &mut Vec<InlayHint>, ctx: &mut InlayHintCtx, - famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>, + famous_defs @ FamousDefs(sema, _krate): &FamousDefs<'_, '_>, config: &InlayHintsConfig, file_id: EditionedFileId, + display_target: DisplayTarget, node: SyntaxNode, ) { - let file_id = file_id.editioned_file_id(sema.db); - let Some(krate) = sema.first_crate(file_id.file_id()) else { - return; - }; - let display_target = krate.to_display_target(sema.db); - closing_brace::hints(hints, sema, config, file_id, display_target, node.clone()); + closing_brace::hints( + hints, + sema, + config, + display_target, + InRealFile { file_id, value: node.clone() }, + ); if let Some(any_has_generic_args) = ast::AnyHasGenericArgs::cast(node.clone()) { generic_param::hints(hints, famous_defs, config, any_has_generic_args); } @@ -231,18 +236,18 @@ fn hints( closure_captures::hints(hints, famous_defs, config, it.clone()); closure_ret::hints(hints, famous_defs, config, display_target, it) }, - ast::Expr::RangeExpr(it) => range_exclusive::hints(hints, famous_defs, config, file_id, it), + ast::Expr::RangeExpr(it) => range_exclusive::hints(hints, famous_defs, config, it), _ => Some(()), } }, ast::Pat(it) => { - binding_mode::hints(hints, famous_defs, config, file_id, &it); + binding_mode::hints(hints, famous_defs, config, &it); match it { ast::Pat::IdentPat(it) => { bind_pat::hints(hints, famous_defs, config, display_target, &it); } ast::Pat::RangePat(it) => { - range_exclusive::hints(hints, famous_defs, config, file_id, it); + range_exclusive::hints(hints, famous_defs, config, it); } _ => {} } @@ -250,30 +255,38 @@ fn hints( }, ast::Item(it) => match it { ast::Item::Fn(it) => { - implicit_drop::hints(hints, famous_defs, config, file_id, &it); + implicit_drop::hints(hints, famous_defs, config, display_target, &it); if let Some(extern_block) = &ctx.extern_block_parent { - extern_block::fn_hints(hints, famous_defs, config, file_id, &it, extern_block); + extern_block::fn_hints(hints, famous_defs, config, &it, extern_block); } - lifetime::fn_hints(hints, ctx, famous_defs, config, file_id, it) + lifetime::fn_hints(hints, ctx, famous_defs, config, it) }, ast::Item::Static(it) => { if let Some(extern_block) = &ctx.extern_block_parent { - extern_block::static_hints(hints, famous_defs, config, file_id, &it, extern_block); + extern_block::static_hints(hints, famous_defs, config, &it, extern_block); } - implicit_static::hints(hints, famous_defs, config, file_id, Either::Left(it)) + implicit_static::hints(hints, famous_defs, config, Either::Left(it)) }, - ast::Item::Const(it) => implicit_static::hints(hints, famous_defs, config, file_id, Either::Right(it)), - ast::Item::Enum(it) => discriminant::enum_hints(hints, famous_defs, config, file_id, it), - ast::Item::ExternBlock(it) => extern_block::extern_block_hints(hints, famous_defs, config, file_id, it), + ast::Item::Const(it) => implicit_static::hints(hints, famous_defs, config, Either::Right(it)), + ast::Item::Enum(it) => discriminant::enum_hints(hints, famous_defs, config, it), + ast::Item::ExternBlock(it) => extern_block::extern_block_hints(hints, famous_defs, config, it), _ => None, }, // FIXME: trait object type elisions ast::Type(ty) => match ty { - ast::Type::FnPtrType(ptr) => lifetime::fn_ptr_hints(hints, ctx, famous_defs, config, file_id, ptr), - ast::Type::PathType(path) => lifetime::fn_path_hints(hints, ctx, famous_defs, config, file_id, path), + ast::Type::FnPtrType(ptr) => lifetime::fn_ptr_hints(hints, ctx, famous_defs, config, ptr), + ast::Type::PathType(path) => { + lifetime::fn_path_hints(hints, ctx, famous_defs, config, &path); + implied_dyn_trait::hints(hints, famous_defs, config, Either::Left(path)); + Some(()) + }, + ast::Type::DynTraitType(dyn_) => { + implied_dyn_trait::hints(hints, famous_defs, config, Either::Right(dyn_)); + Some(()) + }, _ => Some(()), }, - ast::GenericParamList(it) => bounds::hints(hints, famous_defs, config, file_id, it), + ast::GenericParamList(it) => bounds::hints(hints, famous_defs, config, it), _ => Some(()), } }; @@ -438,6 +451,7 @@ pub enum InlayKind { Parameter, GenericParameter, Type, + Dyn, Drop, RangeExclusive, ExternUnsafety, diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/binding_mode.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/binding_mode.rs index d2917320688..169ab92342b 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/binding_mode.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/binding_mode.rs @@ -8,7 +8,6 @@ use hir::Mutability; use ide_db::famous_defs::FamousDefs; use ide_db::text_edit::TextEditBuilder; -use span::EditionedFileId; use syntax::ast::{self, AstNode}; use crate::{InlayHint, InlayHintLabel, InlayHintPosition, InlayHintsConfig, InlayKind}; @@ -17,7 +16,6 @@ pub(super) fn hints( acc: &mut Vec<InlayHint>, FamousDefs(sema, _): &FamousDefs<'_, '_>, config: &InlayHintsConfig, - _file_id: EditionedFileId, pat: &ast::Pat, ) -> Option<()> { if !config.binding_mode_hints { diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bounds.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bounds.rs index 8ddbfaeffe8..b9a98f88be7 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bounds.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bounds.rs @@ -3,7 +3,6 @@ //! Currently this renders the implied `Sized` bound. use ide_db::{FileRange, famous_defs::FamousDefs}; -use span::EditionedFileId; use syntax::ast::{self, AstNode, HasTypeBounds}; use crate::{ @@ -15,7 +14,6 @@ pub(super) fn hints( acc: &mut Vec<InlayHint>, famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>, config: &InlayHintsConfig, - _file_id: EditionedFileId, params: ast::GenericParamList, ) -> Option<()> { if !config.sized_bound { 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 2ec85da4a42..ca3a982760f 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 @@ -3,9 +3,8 @@ //! fn g() { //! } /* fn g */ //! ``` -use hir::{DisplayTarget, HirDisplay, Semantics}; +use hir::{DisplayTarget, HirDisplay, InRealFile, Semantics}; use ide_db::{FileRange, RootDatabase}; -use span::EditionedFileId; use syntax::{ SyntaxKind, SyntaxNode, T, ast::{self, AstNode, HasLoopBody, HasName}, @@ -21,15 +20,14 @@ pub(super) fn hints( acc: &mut Vec<InlayHint>, sema: &Semantics<'_, RootDatabase>, config: &InlayHintsConfig, - file_id: EditionedFileId, display_target: DisplayTarget, - original_node: SyntaxNode, + InRealFile { file_id, value: node }: InRealFile<SyntaxNode>, ) -> Option<()> { let min_lines = config.closing_brace_hints_min_lines?; let name = |it: ast::Name| it.syntax().text_range(); - let mut node = original_node.clone(); + let mut node = node.clone(); let mut closing_token; let (label, name_range) = if let Some(item_list) = ast::AssocItemList::cast(node.clone()) { closing_token = item_list.r_curly_token()?; @@ -44,7 +42,7 @@ pub(super) fn hints( let hint_text = match trait_ { Some(tr) => format!( "impl {} for {}", - tr.name(sema.db).display(sema.db, file_id.edition()), + tr.name(sema.db).display(sema.db, display_target.edition), ty.display_truncated(sema.db, config.max_length, display_target, )), None => format!("impl {}", ty.display_truncated(sema.db, config.max_length, display_target)), @@ -142,7 +140,8 @@ pub(super) fn hints( return None; } - let linked_location = name_range.map(|range| FileRange { file_id: file_id.into(), range }); + let linked_location = + name_range.map(|range| FileRange { file_id: file_id.file_id(sema.db), range }); acc.push(InlayHint { range: closing_token.text_range(), kind: InlayKind::ClosingBrace, @@ -151,7 +150,7 @@ pub(super) fn hints( position: InlayHintPosition::After, pad_left: true, pad_right: false, - resolve_parent: Some(original_node.text_range()), + resolve_parent: Some(node.text_range()), }); None diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/discriminant.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/discriminant.rs index 827a0438dd0..a2a702835a7 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/discriminant.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/discriminant.rs @@ -7,7 +7,6 @@ use hir::Semantics; use ide_db::text_edit::TextEdit; use ide_db::{RootDatabase, famous_defs::FamousDefs}; -use span::EditionedFileId; use syntax::ast::{self, AstNode, HasName}; use crate::{ @@ -19,7 +18,6 @@ pub(super) fn enum_hints( acc: &mut Vec<InlayHint>, FamousDefs(sema, _): &FamousDefs<'_, '_>, config: &InlayHintsConfig, - _: EditionedFileId, enum_: ast::Enum, ) -> Option<()> { if let DiscriminantHints::Never = config.discriminant_hints { diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/extern_block.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/extern_block.rs index 20f54b2cd19..88152bf3e38 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/extern_block.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/extern_block.rs @@ -1,6 +1,5 @@ //! Extern block hints use ide_db::{famous_defs::FamousDefs, text_edit::TextEdit}; -use span::EditionedFileId; use syntax::{AstNode, SyntaxToken, ast}; use crate::{InlayHint, InlayHintsConfig}; @@ -9,7 +8,6 @@ pub(super) fn extern_block_hints( acc: &mut Vec<InlayHint>, FamousDefs(sema, _): &FamousDefs<'_, '_>, config: &InlayHintsConfig, - _file_id: EditionedFileId, extern_block: ast::ExternBlock, ) -> Option<()> { if extern_block.unsafe_token().is_some() { @@ -36,7 +34,6 @@ pub(super) fn fn_hints( acc: &mut Vec<InlayHint>, FamousDefs(sema, _): &FamousDefs<'_, '_>, config: &InlayHintsConfig, - _file_id: EditionedFileId, fn_: &ast::Fn, extern_block: &ast::ExternBlock, ) -> Option<()> { @@ -55,7 +52,6 @@ pub(super) fn static_hints( acc: &mut Vec<InlayHint>, FamousDefs(sema, _): &FamousDefs<'_, '_>, config: &InlayHintsConfig, - _file_id: EditionedFileId, static_: &ast::Static, extern_block: &ast::ExternBlock, ) -> Option<()> { diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs index f52e27946ff..bf4688e9d82 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs @@ -12,7 +12,6 @@ use hir::{ }; use ide_db::{FileRange, famous_defs::FamousDefs}; -use span::EditionedFileId; use syntax::{ ToSmolStr, ast::{self, AstNode}, @@ -25,7 +24,7 @@ pub(super) fn hints( acc: &mut Vec<InlayHint>, FamousDefs(sema, _): &FamousDefs<'_, '_>, config: &InlayHintsConfig, - file_id: EditionedFileId, + display_target: hir::DisplayTarget, node: &ast::Fn, ) -> Option<()> { if !config.implicit_drop_hints { @@ -94,7 +93,7 @@ pub(super) fn hints( MirSpan::Unknown => continue, }; let binding = &hir.bindings[binding_idx]; - let name = binding.name.display_no_db(file_id.edition()).to_smolstr(); + let name = binding.name.display_no_db(display_target.edition).to_smolstr(); if name.starts_with("<ra@") { continue; // Ignore desugared variables } diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_static.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_static.rs index f3be09f30a1..7212efd954e 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_static.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_static.rs @@ -5,7 +5,6 @@ use either::Either; use ide_db::famous_defs::FamousDefs; use ide_db::text_edit::TextEdit; -use span::EditionedFileId; use syntax::{ SyntaxKind, ast::{self, AstNode}, @@ -17,7 +16,6 @@ pub(super) fn hints( acc: &mut Vec<InlayHint>, FamousDefs(_sema, _): &FamousDefs<'_, '_>, config: &InlayHintsConfig, - _file_id: EditionedFileId, statik_or_const: Either<ast::Static, ast::Const>, ) -> Option<()> { if config.lifetime_elision_hints != LifetimeElisionHints::Always { diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implied_dyn_trait.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implied_dyn_trait.rs new file mode 100644 index 00000000000..32d130503a4 --- /dev/null +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implied_dyn_trait.rs @@ -0,0 +1,133 @@ +//! Implementation of trait bound hints. +//! +//! Currently this renders the implied `Sized` bound. +use either::Either; +use ide_db::{famous_defs::FamousDefs, text_edit::TextEdit}; + +use syntax::ast::{self, AstNode}; + +use crate::{InlayHint, InlayHintLabel, InlayHintPosition, InlayHintsConfig, InlayKind}; + +pub(super) fn hints( + acc: &mut Vec<InlayHint>, + FamousDefs(sema, _): &FamousDefs<'_, '_>, + config: &InlayHintsConfig, + path: Either<ast::PathType, ast::DynTraitType>, +) -> Option<()> { + let parent = path.syntax().parent()?; + let range = match path { + Either::Left(path) => { + let paren = + parent.ancestors().take_while(|it| ast::ParenType::can_cast(it.kind())).last(); + let parent = paren.as_ref().and_then(|it| it.parent()).unwrap_or(parent); + if ast::TypeBound::can_cast(parent.kind()) + || ast::TypeAnchor::can_cast(parent.kind()) + || ast::Impl::cast(parent) + .and_then(|it| it.trait_()) + .is_some_and(|it| it.syntax() == path.syntax()) + { + return None; + } + sema.resolve_trait(&path.path()?)?; + paren.map_or_else(|| path.syntax().text_range(), |it| it.text_range()) + } + Either::Right(dyn_) => { + if dyn_.dyn_token().is_some() { + return None; + } + + dyn_.syntax().text_range() + } + }; + + acc.push(InlayHint { + range, + kind: InlayKind::Dyn, + label: InlayHintLabel::simple("dyn", None, None), + text_edit: Some( + config.lazy_text_edit(|| TextEdit::insert(range.start(), "dyn ".to_owned())), + ), + position: InlayHintPosition::Before, + pad_left: false, + pad_right: true, + resolve_parent: Some(range), + }); + + Some(()) +} + +#[cfg(test)] +mod tests { + + use expect_test::expect; + + use crate::inlay_hints::InlayHintsConfig; + + use crate::inlay_hints::tests::{DISABLED_CONFIG, check_edit, check_with_config}; + + #[track_caller] + fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str) { + check_with_config(InlayHintsConfig { sized_bound: true, ..DISABLED_CONFIG }, ra_fixture); + } + + #[test] + fn path_works() { + check( + r#" +struct S {} +trait T {} +fn foo(_: T, _: dyn T, _: S) {} + // ^ dyn +fn foo(_: &T, _: for<'a> T) {} + // ^ dyn + // ^ dyn +impl T {} + // ^ dyn +impl T for (T) {} + // ^^^ dyn +"#, + ); + } + + #[test] + fn missing_dyn_bounds() { + check( + r#" +trait T {} +fn foo( + _: T + T, + // ^^^^^ dyn + _: T + 'a, + // ^^^^^^ dyn + _: 'a + T, + // ^^^^^^ dyn + _: &(T + T) + // ^^^^^ dyn + _: &mut (T + T) + // ^^^^^ dyn + _: *mut (T), + // ^^^ dyn +) {} +"#, + ); + } + + #[test] + fn edit() { + check_edit( + DISABLED_CONFIG, + r#" +trait T {} +fn foo( + _: &mut T +) {} +"#, + expect![[r#" + trait T {} + fn foo( + _: &mut dyn T + ) {} + "#]], + ); + } +} diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/lifetime.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/lifetime.rs index baba49a427d..0069452e7b9 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/lifetime.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/lifetime.rs @@ -6,7 +6,6 @@ use std::iter; use ide_db::{FxHashMap, famous_defs::FamousDefs, syntax_helpers::node_ext::walk_ty}; use itertools::Itertools; -use span::EditionedFileId; use syntax::{SmolStr, format_smolstr}; use syntax::{ SyntaxKind, SyntaxToken, @@ -23,7 +22,6 @@ pub(super) fn fn_hints( ctx: &mut InlayHintCtx, fd: &FamousDefs<'_, '_>, config: &InlayHintsConfig, - file_id: EditionedFileId, func: ast::Fn, ) -> Option<()> { if config.lifetime_elision_hints == LifetimeElisionHints::Never { @@ -40,7 +38,6 @@ pub(super) fn fn_hints( ctx, fd, config, - file_id, param_list.params().filter_map(|it| { Some(( it.pat().and_then(|it| match it { @@ -74,7 +71,6 @@ pub(super) fn fn_ptr_hints( ctx: &mut InlayHintCtx, fd: &FamousDefs<'_, '_>, config: &InlayHintsConfig, - file_id: EditionedFileId, func: ast::FnPtrType, ) -> Option<()> { if config.lifetime_elision_hints == LifetimeElisionHints::Never { @@ -97,7 +93,6 @@ pub(super) fn fn_ptr_hints( ctx, fd, config, - file_id, param_list.params().filter_map(|it| { Some(( it.pat().and_then(|it| match it { @@ -140,8 +135,7 @@ pub(super) fn fn_path_hints( ctx: &mut InlayHintCtx, fd: &FamousDefs<'_, '_>, config: &InlayHintsConfig, - file_id: EditionedFileId, - func: ast::PathType, + func: &ast::PathType, ) -> Option<()> { if config.lifetime_elision_hints == LifetimeElisionHints::Never { return None; @@ -163,7 +157,6 @@ pub(super) fn fn_path_hints( ctx, fd, config, - file_id, param_list.type_args().filter_map(|it| Some((None, it.ty()?))), generic_param_list, ret_type, @@ -202,7 +195,6 @@ fn hints_( ctx: &mut InlayHintCtx, FamousDefs(_, _): &FamousDefs<'_, '_>, config: &InlayHintsConfig, - _file_id: EditionedFileId, params: impl Iterator<Item = (Option<ast::Name>, ast::Type)>, generic_param_list: Option<ast::GenericParamList>, ret_type: Option<ast::RetType>, diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/range_exclusive.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/range_exclusive.rs index d67d8458840..47bd6d737f8 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/range_exclusive.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/range_exclusive.rs @@ -4,7 +4,6 @@ //! if let ../* < */100 = 50 {} //! ``` use ide_db::famous_defs::FamousDefs; -use span::EditionedFileId; use syntax::{SyntaxToken, T, ast}; use crate::{InlayHint, InlayHintsConfig}; @@ -13,7 +12,6 @@ pub(super) fn hints( acc: &mut Vec<InlayHint>, FamousDefs(_sema, _): &FamousDefs<'_, '_>, config: &InlayHintsConfig, - _file_id: EditionedFileId, range: impl ast::RangeItem, ) -> Option<()> { (config.range_exclusive_hints && range.end().is_some()) diff --git a/src/tools/rust-analyzer/crates/ide/src/rename.rs b/src/tools/rust-analyzer/crates/ide/src/rename.rs index 0423e3da2c8..fb84e8e6b47 100644 --- a/src/tools/rust-analyzer/crates/ide/src/rename.rs +++ b/src/tools/rust-analyzer/crates/ide/src/rename.rs @@ -4,11 +4,11 @@ //! tests. This module also implements a couple of magic tricks, like renaming //! `self` and to `self` (to switch between associated function and method). -use hir::{AsAssocItem, InFile, Semantics}; +use hir::{AsAssocItem, InFile, Name, Semantics, sym}; use ide_db::{ FileId, FileRange, RootDatabase, defs::{Definition, NameClass, NameRefClass}, - rename::{IdentifierKind, bail, format_err, source_edit_from_references}, + rename::{IdentifierKind, RenameDefinition, bail, format_err, source_edit_from_references}, source_change::SourceChangeBuilder, }; use itertools::Itertools; @@ -33,8 +33,8 @@ pub(crate) fn prepare_rename( let source_file = sema.parse_guess_edition(position.file_id); let syntax = source_file.syntax(); - let res = find_definitions(&sema, syntax, position)? - .map(|(frange, kind, def)| { + let res = find_definitions(&sema, syntax, position, &Name::new_symbol_root(sym::underscore))? + .map(|(frange, kind, def, _, _)| { // ensure all ranges are valid if def.range_for_rename(&sema).is_none() { @@ -88,22 +88,28 @@ pub(crate) fn rename( let source_file = sema.parse(file_id); let syntax = source_file.syntax(); - let defs = find_definitions(&sema, syntax, position)?; - let alias_fallback = alias_fallback(syntax, position, new_name); + let edition = file_id.edition(db); + let (new_name, kind) = IdentifierKind::classify(edition, new_name)?; + + let defs = find_definitions(&sema, syntax, position, &new_name)?; + let alias_fallback = + alias_fallback(syntax, position, &new_name.display(db, edition).to_string()); let ops: RenameResult<Vec<SourceChange>> = match alias_fallback { Some(_) => defs // FIXME: This can use the `ide_db::rename_reference` (or def.rename) method once we can // properly find "direct" usages/references. - .map(|(.., def)| { - match IdentifierKind::classify(new_name)? { + .map(|(.., def, new_name, _)| { + match kind { IdentifierKind::Ident => (), IdentifierKind::Lifetime => { bail!("Cannot alias reference to a lifetime identifier") } IdentifierKind::Underscore => bail!("Cannot alias reference to `_`"), + IdentifierKind::LowercaseSelf => { + bail!("Cannot rename alias reference to `self`") + } }; - let mut usages = def.usages(&sema).all(); // FIXME: hack - removes the usage that triggered this rename operation. @@ -120,7 +126,7 @@ pub(crate) fn rename( source_change.extend(usages.references.get_mut(&file_id).iter().map(|refs| { ( position.file_id, - source_edit_from_references(refs, def, new_name, file_id.edition(db)), + source_edit_from_references(db, refs, def, &new_name, edition), ) })); @@ -128,18 +134,18 @@ pub(crate) fn rename( }) .collect(), None => defs - .map(|(.., def)| { + .map(|(.., def, new_name, rename_def)| { if let Definition::Local(local) = def { if let Some(self_param) = local.as_self_param(sema.db) { cov_mark::hit!(rename_self_to_param); - return rename_self_to_param(&sema, local, self_param, new_name); + return rename_self_to_param(&sema, local, self_param, &new_name, kind); } - if new_name == "self" { + if kind == IdentifierKind::LowercaseSelf { cov_mark::hit!(rename_to_self); return rename_to_self(&sema, local); } } - def.rename(&sema, new_name) + def.rename(&sema, new_name.as_str(), rename_def) }) .collect(), }; @@ -159,7 +165,7 @@ pub(crate) fn will_rename_file( let sema = Semantics::new(db); let module = sema.file_to_module_def(file_id)?; let def = Definition::Module(module); - let mut change = def.rename(&sema, new_name_stem).ok()?; + let mut change = def.rename(&sema, new_name_stem, RenameDefinition::Yes).ok()?; change.file_system_edits.clear(); Some(change) } @@ -200,22 +206,40 @@ fn find_definitions( sema: &Semantics<'_, RootDatabase>, syntax: &SyntaxNode, FilePosition { file_id, offset }: FilePosition, -) -> RenameResult<impl Iterator<Item = (FileRange, SyntaxKind, Definition)>> { - let token = syntax.token_at_offset(offset).find(|t| matches!(t.kind(), SyntaxKind::STRING)); + new_name: &Name, +) -> RenameResult<impl Iterator<Item = (FileRange, SyntaxKind, Definition, Name, RenameDefinition)>> +{ + let maybe_format_args = + syntax.token_at_offset(offset).find(|t| matches!(t.kind(), SyntaxKind::STRING)); if let Some((range, _, _, Some(resolution))) = - token.and_then(|token| sema.check_for_format_args_template(token, offset)) + maybe_format_args.and_then(|token| sema.check_for_format_args_template(token, offset)) { return Ok(vec![( FileRange { file_id, range }, SyntaxKind::STRING, Definition::from(resolution), + new_name.clone(), + RenameDefinition::Yes, )] .into_iter()); } + let original_ident = syntax + .token_at_offset(offset) + .max_by_key(|t| { + t.kind().is_any_identifier() || matches!(t.kind(), SyntaxKind::LIFETIME_IDENT) + }) + .map(|t| { + if t.kind() == SyntaxKind::LIFETIME_IDENT { + Name::new_lifetime(t.text()) + } else { + Name::new_root(t.text()) + } + }) + .ok_or_else(|| format_err!("No references found at position"))?; let symbols = - sema.find_nodes_at_offset_with_descend::<ast::NameLike>(syntax, offset).map(|name_like| { + sema.find_namelike_at_offset_with_descend(syntax, offset).map(|name_like| { let kind = name_like.syntax().kind(); let range = sema .original_range_opt(name_like.syntax()) @@ -284,23 +308,28 @@ fn find_definitions( .ok_or_else(|| format_err!("No references found at position")) } }; - res.map(|def| (range, kind, def)) + res.map(|def| { + let n = def.name(sema.db)?; + if n == original_ident { + Some((range, kind, def, new_name.clone(), RenameDefinition::Yes)) + } else if let Some(suffix) = n.as_str().strip_prefix(original_ident.as_str()) { + Some((range, kind, def, Name::new_root(&format!("{}{suffix}", new_name.as_str())), RenameDefinition::No)) + } else { + n.as_str().strip_suffix(original_ident.as_str().trim_start_matches('\'')) + .map(|prefix| (range, kind, def, Name::new_root(&format!("{prefix}{}", new_name.as_str())), RenameDefinition::No)) + } + }) }); - let res: RenameResult<Vec<_>> = symbols.collect(); + let res: RenameResult<Vec<_>> = symbols.filter_map(Result::transpose).collect(); match res { Ok(v) => { - if v.is_empty() { - // FIXME: some semantic duplication between "empty vec" and "Err()" - Err(format_err!("No references found at position")) - } else { - // remove duplicates, comparing `Definition`s - Ok(v.into_iter() - .unique_by(|&(.., def)| def) - .map(|(a, b, c)| (a.into_file_id(sema.db), b, c)) - .collect::<Vec<_>>() - .into_iter()) - } + // remove duplicates, comparing `Definition`s + Ok(v.into_iter() + .unique_by(|&(.., def, _, _)| def) + .map(|(a, b, c, d, e)| (a.into_file_id(sema.db), b, c, d, e)) + .collect::<Vec<_>>() + .into_iter()) } Err(e) => Err(e), } @@ -370,7 +399,13 @@ fn rename_to_self( source_change.extend(usages.iter().map(|(file_id, references)| { ( file_id.file_id(sema.db), - source_edit_from_references(references, def, "self", file_id.edition(sema.db)), + source_edit_from_references( + sema.db, + references, + def, + &Name::new_symbol_root(sym::self_), + file_id.edition(sema.db), + ), ) })); source_change.insert_source_edit( @@ -384,23 +419,25 @@ fn rename_self_to_param( sema: &Semantics<'_, RootDatabase>, local: hir::Local, self_param: hir::SelfParam, - new_name: &str, + new_name: &Name, + identifier_kind: IdentifierKind, ) -> RenameResult<SourceChange> { - if new_name == "self" { + if identifier_kind == IdentifierKind::LowercaseSelf { // Let's do nothing rather than complain. cov_mark::hit!(rename_self_to_self); return Ok(SourceChange::default()); } - let identifier_kind = IdentifierKind::classify(new_name)?; - let InFile { file_id, value: self_param } = sema.source(self_param).ok_or_else(|| format_err!("cannot find function source"))?; let def = Definition::Local(local); let usages = def.usages(sema).all(); - let edit = text_edit_from_self_param(&self_param, new_name) - .ok_or_else(|| format_err!("No target type found"))?; + let edit = text_edit_from_self_param( + &self_param, + new_name.display(sema.db, file_id.edition(sema.db)).to_string(), + ) + .ok_or_else(|| format_err!("No target type found"))?; if usages.len() > 1 && identifier_kind == IdentifierKind::Underscore { bail!("Cannot rename reference to `_` as it is being referenced multiple times"); } @@ -409,13 +446,19 @@ fn rename_self_to_param( source_change.extend(usages.iter().map(|(file_id, references)| { ( file_id.file_id(sema.db), - source_edit_from_references(references, def, new_name, file_id.edition(sema.db)), + source_edit_from_references( + sema.db, + references, + def, + new_name, + file_id.edition(sema.db), + ), ) })); Ok(source_change) } -fn text_edit_from_self_param(self_param: &ast::SelfParam, new_name: &str) -> Option<TextEdit> { +fn text_edit_from_self_param(self_param: &ast::SelfParam, new_name: String) -> Option<TextEdit> { fn target_type_name(impl_def: &ast::Impl) -> Option<String> { if let Some(ast::Type::PathType(p)) = impl_def.self_ty() { return Some(p.path()?.segment()?.name_ref()?.text().to_string()); @@ -427,7 +470,7 @@ fn text_edit_from_self_param(self_param: &ast::SelfParam, new_name: &str) -> Opt Some(impl_def) => { let type_name = target_type_name(&impl_def)?; - let mut replacement_text = String::from(new_name); + let mut replacement_text = new_name; replacement_text.push_str(": "); match (self_param.amp_token(), self_param.mut_token()) { (Some(_), None) => replacement_text.push('&'), @@ -440,7 +483,7 @@ fn text_edit_from_self_param(self_param: &ast::SelfParam, new_name: &str) -> Opt } None => { cov_mark::hit!(rename_self_outside_of_methods); - let mut replacement_text = String::from(new_name); + let mut replacement_text = new_name; replacement_text.push_str(": _"); Some(TextEdit::replace(self_param.syntax().text_range(), replacement_text)) } @@ -710,7 +753,7 @@ impl Foo { check( "super", r#"fn main() { let i$0 = 1; }"#, - "error: Invalid name `super`: not an identifier", + "error: Invalid name `super`: cannot rename to a keyword", ); } @@ -759,7 +802,11 @@ impl Foo { #[test] fn test_rename_mod_invalid_raw_ident() { - check("r#self", r#"mod foo$0 {}"#, "error: Invalid name `self`: not an identifier"); + check( + "r#self", + r#"mod foo$0 {}"#, + "error: Invalid name `self`: cannot rename module to self", + ); } #[test] @@ -2359,7 +2406,6 @@ fn foo(foo: Foo) { #[test] fn test_rename_lifetimes() { - cov_mark::check!(rename_lifetime); check( "'yeeee", r#" @@ -2536,7 +2582,7 @@ fn baz() { x.0$0 = 5; } "#, - "error: No identifier available to rename", + "error: No references found at position", ); } @@ -2566,7 +2612,7 @@ impl Foo { } } "#, - "error: Cannot rename `Self`", + "error: No references found at position", ); } @@ -3262,4 +3308,100 @@ trait Trait<U> { "#, ); } + + #[test] + fn rename_macro_generated_type_from_type_with_a_suffix() { + check( + "Bar", + r#" +//- proc_macros: generate_suffixed_type +#[proc_macros::generate_suffixed_type] +struct Foo$0; +fn usage(_: FooSuffix) {} +usage(FooSuffix); +"#, + r#" +#[proc_macros::generate_suffixed_type] +struct Bar; +fn usage(_: BarSuffix) {} +usage(BarSuffix); +"#, + ); + } + + #[test] + // FIXME + #[should_panic] + fn rename_macro_generated_type_from_type_usage_with_a_suffix() { + check( + "Bar", + r#" +//- proc_macros: generate_suffixed_type +#[proc_macros::generate_suffixed_type] +struct Foo; +fn usage(_: FooSuffix) {} +usage(FooSuffix); +fn other_place() { Foo$0; } +"#, + r#" +#[proc_macros::generate_suffixed_type] +struct Bar; +fn usage(_: BarSuffix) {} +usage(BarSuffix); +fn other_place() { Bar; } +"#, + ); + } + + #[test] + fn rename_macro_generated_type_from_variant_with_a_suffix() { + check( + "Bar", + r#" +//- proc_macros: generate_suffixed_type +#[proc_macros::generate_suffixed_type] +enum Quux { + Foo$0, +} +fn usage(_: FooSuffix) {} +usage(FooSuffix); +"#, + r#" +#[proc_macros::generate_suffixed_type] +enum Quux { + Bar, +} +fn usage(_: BarSuffix) {} +usage(BarSuffix); +"#, + ); + } + + #[test] + // FIXME + #[should_panic] + fn rename_macro_generated_type_from_variant_usage_with_a_suffix() { + check( + "Bar", + r#" +//- proc_macros: generate_suffixed_type +#[proc_macros::generate_suffixed_type] +enum Quux { + Foo, +} +fn usage(_: FooSuffix) {} +usage(FooSuffix); +fn other_place() { Quux::Foo$0; } +"#, + r#" +#[proc_macros::generate_suffixed_type] +enum Quux { + Bar, +} +fn usage(_: BarSuffix) {} +usage(BartSuffix); +fn other_place() { Quux::Bar$0; } +"#, + ); + } } 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 8cc332d4633..8ed0fc6729f 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 @@ -562,8 +562,12 @@ fn closure_expr(p: &mut Parser<'_>) -> CompletedMarker { let m = p.start(); + // test closure_binder + // fn main() { for<'a> || (); } if p.at(T![for]) { + let b = p.start(); types::for_binder(p); + b.complete(p, CLOSURE_BINDER); } // test const_closure // fn main() { let cl = const || _ = 0; } diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs index 9d4fdbfaf2e..ea5a3bc8593 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs @@ -201,6 +201,17 @@ fn type_bound(p: &mut Parser<'_>) -> bool { } if paths::is_use_path_start(p) { types::path_type_bounds(p, false); + // test_err type_bounds_macro_call_recovery + // fn foo<T: T![], T: T!, T: T!{}>() -> Box<T! + T!{}> {} + if p.at(T![!]) { + let m = p.start(); + p.bump(T![!]); + p.error("unexpected `!` in type path, macro calls are not allowed here"); + if p.at_ts(TokenSet::new(&[T!['{'], T!['['], T!['(']])) { + items::token_tree(p); + } + m.complete(p, ERROR); + } } else { m.abandon(p); return false; 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 770827c6b0d..dfe7cb57d24 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/paths.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/paths.rs @@ -89,19 +89,22 @@ fn path_segment(p: &mut Parser<'_>, mode: Mode, first: bool) -> Option<Completed // test qual_paths // type X = <A as B>::Output; // fn foo() { <usize as Default>::default(); } - if first && p.eat(T![<]) { + if first && p.at(T![<]) { + let m = p.start(); + p.bump(T![<]); // test_err angled_path_without_qual // type X = <()>; // type Y = <A as B>; types::type_(p); if p.eat(T![as]) { if is_use_path_start(p) { - types::path_type(p); + types::path_type_bounds(p, true); } else { p.error("expected a trait"); } } p.expect(T![>]); + m.complete(p, TYPE_ANCHOR); if !p.at(T![::]) { p.error("expected `::`"); } 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 9d31e435cf9..908440b5d05 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/types.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/types.rs @@ -330,15 +330,6 @@ fn bare_dyn_trait_type(p: &mut Parser<'_>) { m.complete(p, DYN_TRAIT_TYPE); } -// test path_type -// type A = Foo; -// type B = ::Foo; -// type C = self::Foo; -// type D = super::Foo; -pub(super) fn path_type(p: &mut Parser<'_>) { - path_type_bounds(p, true); -} - // test macro_call_type // type A = foo!(); // type B = crate::foo!(); @@ -365,6 +356,11 @@ fn path_or_macro_type(p: &mut Parser<'_>, allow_bounds: bool) { } } +// test path_type +// type A = Foo; +// type B = ::Foo; +// type C = self::Foo; +// type D = super::Foo; pub(super) fn path_type_bounds(p: &mut Parser<'_>, allow_bounds: bool) { assert!(paths::is_path_start(p)); let m = p.start(); 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 b1727509b13..f534546ea07 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 @@ -291,6 +291,7 @@ pub enum SyntaxKind { TUPLE_STRUCT_PAT, TUPLE_TYPE, TYPE_ALIAS, + TYPE_ANCHOR, TYPE_ARG, TYPE_BOUND, TYPE_BOUND_LIST, @@ -463,6 +464,7 @@ impl SyntaxKind { | TUPLE_STRUCT_PAT | TUPLE_TYPE | TYPE_ALIAS + | TYPE_ANCHOR | TYPE_ARG | TYPE_BOUND | TYPE_BOUND_LIST 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 030d8e0f04d..6ec4192830b 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 @@ -83,6 +83,10 @@ mod ok { #[test] fn cast_expr() { run_and_expect_no_errors("test_data/parser/inline/ok/cast_expr.rs"); } #[test] + fn closure_binder() { + run_and_expect_no_errors("test_data/parser/inline/ok/closure_binder.rs"); + } + #[test] fn closure_body_underscore_assignment() { run_and_expect_no_errors( "test_data/parser/inline/ok/closure_body_underscore_assignment.rs", @@ -872,6 +876,10 @@ mod err { run_and_expect_errors("test_data/parser/inline/err/tuple_pat_leading_comma.rs"); } #[test] + fn type_bounds_macro_call_recovery() { + run_and_expect_errors("test_data/parser/inline/err/type_bounds_macro_call_recovery.rs"); + } + #[test] fn type_in_array_recover() { run_and_expect_errors("test_data/parser/inline/err/type_in_array_recover.rs"); } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0024_many_type_parens.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0024_many_type_parens.rast index f0dbc9b1027..025c12e4c2a 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0024_many_type_parens.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0024_many_type_parens.rast @@ -186,13 +186,14 @@ SOURCE_FILE TUPLE_EXPR L_PAREN "(" CLOSURE_EXPR - FOR_KW "for" - GENERIC_PARAM_LIST - L_ANGLE "<" - LIFETIME_PARAM - LIFETIME - LIFETIME_IDENT "'a" - R_ANGLE ">" + CLOSURE_BINDER + FOR_KW "for" + GENERIC_PARAM_LIST + L_ANGLE "<" + LIFETIME_PARAM + LIFETIME + LIFETIME_IDENT "'a" + R_ANGLE ">" WHITESPACE " " BIN_EXPR BIN_EXPR diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/angled_path_without_qual.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/angled_path_without_qual.rast index 0529e9750e7..53fbe0b615e 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/angled_path_without_qual.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/angled_path_without_qual.rast @@ -10,11 +10,12 @@ SOURCE_FILE PATH_TYPE PATH PATH_SEGMENT - L_ANGLE "<" - TUPLE_TYPE - L_PAREN "(" - R_PAREN ")" - R_ANGLE ">" + TYPE_ANCHOR + L_ANGLE "<" + TUPLE_TYPE + L_PAREN "(" + R_PAREN ")" + R_ANGLE ">" SEMICOLON ";" WHITESPACE "\n" TYPE_ALIAS @@ -28,21 +29,22 @@ SOURCE_FILE PATH_TYPE PATH PATH_SEGMENT - L_ANGLE "<" - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "A" - WHITESPACE " " - AS_KW "as" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "B" - R_ANGLE ">" + TYPE_ANCHOR + L_ANGLE "<" + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "A" + WHITESPACE " " + AS_KW "as" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "B" + R_ANGLE ">" SEMICOLON ";" WHITESPACE "\n" error 13: expected `::` diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/type_bounds_macro_call_recovery.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/type_bounds_macro_call_recovery.rast new file mode 100644 index 00000000000..4722beb6192 --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/type_bounds_macro_call_recovery.rast @@ -0,0 +1,112 @@ +SOURCE_FILE + FN + FN_KW "fn" + WHITESPACE " " + NAME + IDENT "foo" + GENERIC_PARAM_LIST + L_ANGLE "<" + TYPE_PARAM + NAME + IDENT "T" + COLON ":" + WHITESPACE " " + TYPE_BOUND_LIST + TYPE_BOUND + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "T" + ERROR + BANG "!" + TOKEN_TREE + L_BRACK "[" + R_BRACK "]" + COMMA "," + WHITESPACE " " + TYPE_PARAM + NAME + IDENT "T" + COLON ":" + WHITESPACE " " + TYPE_BOUND_LIST + TYPE_BOUND + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "T" + ERROR + BANG "!" + COMMA "," + WHITESPACE " " + TYPE_PARAM + NAME + IDENT "T" + COLON ":" + WHITESPACE " " + TYPE_BOUND_LIST + TYPE_BOUND + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "T" + ERROR + BANG "!" + TOKEN_TREE + L_CURLY "{" + R_CURLY "}" + R_ANGLE ">" + PARAM_LIST + L_PAREN "(" + R_PAREN ")" + WHITESPACE " " + RET_TYPE + THIN_ARROW "->" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Box" + GENERIC_ARG_LIST + L_ANGLE "<" + TYPE_ARG + DYN_TRAIT_TYPE + TYPE_BOUND_LIST + TYPE_BOUND + MACRO_TYPE + MACRO_CALL + PATH + PATH_SEGMENT + NAME_REF + IDENT "T" + BANG "!" + WHITESPACE " " + PLUS "+" + WHITESPACE " " + TYPE_BOUND + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "T" + ERROR + BANG "!" + TOKEN_TREE + L_CURLY "{" + R_CURLY "}" + R_ANGLE ">" + WHITESPACE " " + BLOCK_EXPR + STMT_LIST + L_CURLY "{" + R_CURLY "}" + WHITESPACE "\n" +error 12: unexpected `!` in type path, macro calls are not allowed here +error 21: unexpected `!` in type path, macro calls are not allowed here +error 28: unexpected `!` in type path, macro calls are not allowed here +error 43: expected `{`, `[`, `(` +error 48: unexpected `!` in type path, macro calls are not allowed here diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/type_bounds_macro_call_recovery.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/type_bounds_macro_call_recovery.rs new file mode 100644 index 00000000000..517404fdb0e --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/type_bounds_macro_call_recovery.rs @@ -0,0 +1 @@ +fn foo<T: T![], T: T!, T: T!{}>() -> Box<T! + T!{}> {} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/call_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/call_expr.rast index 19cc8d5ac7c..7c1d894f7e4 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/call_expr.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/call_expr.rast @@ -88,13 +88,14 @@ SOURCE_FILE PATH PATH PATH_SEGMENT - L_ANGLE "<" - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Foo" - R_ANGLE ">" + TYPE_ANCHOR + L_ANGLE "<" + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Foo" + R_ANGLE ">" COLON2 "::" PATH_SEGMENT NAME_REF @@ -119,21 +120,22 @@ SOURCE_FILE PATH PATH PATH_SEGMENT - L_ANGLE "<" - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Foo" - WHITESPACE " " - AS_KW "as" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Trait" - R_ANGLE ">" + TYPE_ANCHOR + L_ANGLE "<" + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Foo" + WHITESPACE " " + AS_KW "as" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Trait" + R_ANGLE ">" COLON2 "::" PATH_SEGMENT NAME_REF diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/closure_binder.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/closure_binder.rast new file mode 100644 index 00000000000..c04dbe1ea0a --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/closure_binder.rast @@ -0,0 +1,36 @@ +SOURCE_FILE + FN + FN_KW "fn" + WHITESPACE " " + NAME + IDENT "main" + PARAM_LIST + L_PAREN "(" + R_PAREN ")" + WHITESPACE " " + BLOCK_EXPR + STMT_LIST + L_CURLY "{" + WHITESPACE " " + EXPR_STMT + CLOSURE_EXPR + CLOSURE_BINDER + FOR_KW "for" + GENERIC_PARAM_LIST + L_ANGLE "<" + LIFETIME_PARAM + LIFETIME + LIFETIME_IDENT "'a" + R_ANGLE ">" + WHITESPACE " " + PARAM_LIST + PIPE "|" + PIPE "|" + WHITESPACE " " + TUPLE_EXPR + L_PAREN "(" + R_PAREN ")" + SEMICOLON ";" + WHITESPACE " " + R_CURLY "}" + WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/closure_binder.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/closure_binder.rs new file mode 100644 index 00000000000..a6d8aafb08a --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/closure_binder.rs @@ -0,0 +1 @@ +fn main() { for<'a> || (); } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/lambda_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/lambda_expr.rast index c25ad8430d0..ea401d224e6 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/lambda_expr.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/lambda_expr.rast @@ -202,13 +202,14 @@ SOURCE_FILE WHITESPACE "\n " EXPR_STMT CLOSURE_EXPR - FOR_KW "for" - GENERIC_PARAM_LIST - L_ANGLE "<" - LIFETIME_PARAM - LIFETIME - LIFETIME_IDENT "'a" - R_ANGLE ">" + CLOSURE_BINDER + FOR_KW "for" + GENERIC_PARAM_LIST + L_ANGLE "<" + LIFETIME_PARAM + LIFETIME + LIFETIME_IDENT "'a" + R_ANGLE ">" WHITESPACE " " PARAM_LIST PIPE "|" @@ -222,13 +223,14 @@ SOURCE_FILE WHITESPACE "\n " EXPR_STMT CLOSURE_EXPR - FOR_KW "for" - GENERIC_PARAM_LIST - L_ANGLE "<" - LIFETIME_PARAM - LIFETIME - LIFETIME_IDENT "'a" - R_ANGLE ">" + CLOSURE_BINDER + FOR_KW "for" + GENERIC_PARAM_LIST + L_ANGLE "<" + LIFETIME_PARAM + LIFETIME + LIFETIME_IDENT "'a" + R_ANGLE ">" WHITESPACE " " MOVE_KW "move" WHITESPACE " " diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/qual_paths.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/qual_paths.rast index 8c66cfe599f..10f8a6a7516 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/qual_paths.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/qual_paths.rast @@ -11,21 +11,22 @@ SOURCE_FILE PATH PATH PATH_SEGMENT - L_ANGLE "<" - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "A" - WHITESPACE " " - AS_KW "as" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "B" - R_ANGLE ">" + TYPE_ANCHOR + L_ANGLE "<" + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "A" + WHITESPACE " " + AS_KW "as" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "B" + R_ANGLE ">" COLON2 "::" PATH_SEGMENT NAME_REF @@ -51,21 +52,22 @@ SOURCE_FILE PATH PATH PATH_SEGMENT - L_ANGLE "<" - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "usize" - WHITESPACE " " - AS_KW "as" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Default" - R_ANGLE ">" + TYPE_ANCHOR + L_ANGLE "<" + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "usize" + WHITESPACE " " + AS_KW "as" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Default" + R_ANGLE ">" COLON2 "::" PATH_SEGMENT NAME_REF diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/type_path_in_pattern.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/type_path_in_pattern.rast index 297f7575ca6..3d27afa5ecd 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/type_path_in_pattern.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/type_path_in_pattern.rast @@ -19,10 +19,11 @@ SOURCE_FILE PATH PATH PATH_SEGMENT - L_ANGLE "<" - INFER_TYPE - UNDERSCORE "_" - R_ANGLE ">" + TYPE_ANCHOR + L_ANGLE "<" + INFER_TYPE + UNDERSCORE "_" + R_ANGLE ">" COLON2 "::" PATH_SEGMENT NAME_REF diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/where_clause.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/where_clause.rast index a3cbe457e1a..9adfe2caa73 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/where_clause.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/where_clause.rast @@ -84,21 +84,22 @@ SOURCE_FILE PATH PATH PATH_SEGMENT - L_ANGLE "<" - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "T" - WHITESPACE " " - AS_KW "as" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Iterator" - R_ANGLE ">" + TYPE_ANCHOR + L_ANGLE "<" + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "T" + WHITESPACE " " + AS_KW "as" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Iterator" + R_ANGLE ">" COLON2 "::" PATH_SEGMENT NAME_REF diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0036_fully_qualified.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0036_fully_qualified.rast index 9382020e2f6..2fecb1cc47d 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0036_fully_qualified.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0036_fully_qualified.rast @@ -45,21 +45,22 @@ SOURCE_FILE PATH PATH PATH_SEGMENT - L_ANGLE "<" - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "S" - WHITESPACE " " - AS_KW "as" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Iterator" - R_ANGLE ">" + TYPE_ANCHOR + L_ANGLE "<" + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "S" + WHITESPACE " " + AS_KW "as" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Iterator" + R_ANGLE ">" COLON2 "::" PATH_SEGMENT NAME_REF diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0042_ufcs_call_list.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0042_ufcs_call_list.rast index a536b0e881f..d1d1ffacf0d 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0042_ufcs_call_list.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0042_ufcs_call_list.rast @@ -107,13 +107,14 @@ SOURCE_FILE PATH PATH PATH_SEGMENT - L_ANGLE "<" - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Foo" - R_ANGLE ">" + TYPE_ANCHOR + L_ANGLE "<" + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Foo" + R_ANGLE ">" COLON2 "::" PATH_SEGMENT NAME_REF diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0067_where_for_pred.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0067_where_for_pred.rast index cd3b21ae94f..8bf1090f9cf 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0067_where_for_pred.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0067_where_for_pred.rast @@ -288,26 +288,27 @@ SOURCE_FILE PATH PATH PATH_SEGMENT - L_ANGLE "<" - REF_TYPE - AMP "&" - LIFETIME - LIFETIME_IDENT "'a" + TYPE_ANCHOR + L_ANGLE "<" + REF_TYPE + AMP "&" + LIFETIME + LIFETIME_IDENT "'a" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "T" + WHITESPACE " " + AS_KW "as" WHITESPACE " " PATH_TYPE PATH PATH_SEGMENT NAME_REF - IDENT "T" - WHITESPACE " " - AS_KW "as" - WHITESPACE " " - PATH_TYPE - PATH - PATH_SEGMENT - NAME_REF - IDENT "Baz" - R_ANGLE ">" + IDENT "Baz" + R_ANGLE ">" COLON2 "::" PATH_SEGMENT NAME_REF diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl.rs index 11dbd920091..ad285990334 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl.rs @@ -10,6 +10,7 @@ use std::fmt; +use intern::Symbol; use proc_macro::bridge; mod token_stream; @@ -112,3 +113,135 @@ fn literal_kind_to_internal(kind: bridge::LitKind) -> tt::LitKind { bridge::LitKind::ErrWithGuar => tt::LitKind::Err(()), } } + +pub(super) fn literal_from_str<Span: Copy>( + s: &str, + span: Span, +) -> Result<bridge::Literal<Span, Symbol>, ()> { + use proc_macro::bridge::LitKind; + use rustc_lexer::{LiteralKind, Token, TokenKind}; + + let mut tokens = rustc_lexer::tokenize(s); + let minus_or_lit = tokens.next().unwrap_or(Token { kind: TokenKind::Eof, len: 0 }); + + let lit = if minus_or_lit.kind == TokenKind::Minus { + let lit = tokens.next().ok_or(())?; + if !matches!( + lit.kind, + TokenKind::Literal { kind: LiteralKind::Int { .. } | LiteralKind::Float { .. }, .. } + ) { + return Err(()); + } + lit + } else { + minus_or_lit + }; + + if tokens.next().is_some() { + return Err(()); + } + + let TokenKind::Literal { kind, suffix_start } = lit.kind else { return Err(()) }; + let (kind, start_offset, end_offset) = match kind { + LiteralKind::Int { .. } => (LitKind::Integer, 0, 0), + LiteralKind::Float { .. } => (LitKind::Float, 0, 0), + LiteralKind::Char { terminated } => (LitKind::Char, 1, terminated as usize), + LiteralKind::Byte { terminated } => (LitKind::Byte, 2, terminated as usize), + LiteralKind::Str { terminated } => (LitKind::Str, 1, terminated as usize), + LiteralKind::ByteStr { terminated } => (LitKind::ByteStr, 2, terminated as usize), + LiteralKind::CStr { terminated } => (LitKind::CStr, 2, terminated as usize), + LiteralKind::RawStr { n_hashes } => ( + LitKind::StrRaw(n_hashes.unwrap_or_default()), + 2 + n_hashes.unwrap_or_default() as usize, + 1 + n_hashes.unwrap_or_default() as usize, + ), + LiteralKind::RawByteStr { n_hashes } => ( + LitKind::ByteStrRaw(n_hashes.unwrap_or_default()), + 3 + n_hashes.unwrap_or_default() as usize, + 1 + n_hashes.unwrap_or_default() as usize, + ), + LiteralKind::RawCStr { n_hashes } => ( + LitKind::CStrRaw(n_hashes.unwrap_or_default()), + 3 + n_hashes.unwrap_or_default() as usize, + 1 + n_hashes.unwrap_or_default() as usize, + ), + }; + + let (lit, suffix) = s.split_at(suffix_start as usize); + let lit = &lit[start_offset..lit.len() - end_offset]; + let suffix = match suffix { + "" | "_" => None, + suffix => Some(Symbol::intern(suffix)), + }; + + Ok(bridge::Literal { kind, symbol: Symbol::intern(lit), suffix, span }) +} + +pub(super) fn from_token_tree<Span: Copy>( + tree: bridge::TokenTree<TokenStream<Span>, Span, Symbol>, +) -> TokenStream<Span> { + match tree { + bridge::TokenTree::Group(group) => { + let group = TopSubtree::from_bridge(group); + TokenStream { token_trees: group.0 } + } + + bridge::TokenTree::Ident(ident) => { + let text = ident.sym; + let ident: tt::Ident<Span> = tt::Ident { + sym: text, + span: ident.span, + is_raw: if ident.is_raw { tt::IdentIsRaw::Yes } else { tt::IdentIsRaw::No }, + }; + let leaf = tt::Leaf::from(ident); + let tree = tt::TokenTree::from(leaf); + TokenStream { token_trees: vec![tree] } + } + + bridge::TokenTree::Literal(literal) => { + let token_trees = + if let Some((_minus, symbol)) = literal.symbol.as_str().split_once('-') { + let punct = tt::Punct { + spacing: tt::Spacing::Alone, + span: literal.span, + char: '-' as char, + }; + let leaf: tt::Leaf<Span> = tt::Leaf::from(punct); + let minus_tree = tt::TokenTree::from(leaf); + + let literal = tt::Literal { + symbol: Symbol::intern(symbol), + suffix: literal.suffix, + span: literal.span, + kind: literal_kind_to_internal(literal.kind), + }; + let leaf: tt::Leaf<Span> = tt::Leaf::from(literal); + let tree = tt::TokenTree::from(leaf); + vec![minus_tree, tree] + } else { + let literal = tt::Literal { + symbol: literal.symbol, + suffix: literal.suffix, + span: literal.span, + kind: literal_kind_to_internal(literal.kind), + }; + + let leaf: tt::Leaf<Span> = tt::Leaf::from(literal); + let tree = tt::TokenTree::from(leaf); + vec![tree] + }; + TokenStream { token_trees } + } + + bridge::TokenTree::Punct(p) => { + let punct = tt::Punct { + char: p.ch as char, + spacing: if p.joint { tt::Spacing::Joint } else { tt::Spacing::Alone }, + span: p.span, + }; + let leaf = tt::Leaf::from(punct); + let tree = tt::TokenTree::from(leaf); + TokenStream { token_trees: vec![tree] } + } + } +} diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs index e0c6e68f803..5d1271ba81e 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs @@ -14,16 +14,7 @@ use proc_macro::bridge::{self, server}; use span::{FIXUP_ERASED_FILE_AST_ID_MARKER, Span}; use tt::{TextRange, TextSize}; -use crate::server_impl::{TopSubtree, literal_kind_to_internal, token_stream::TokenStreamBuilder}; -mod tt { - pub use tt::*; - - pub type TokenTree = ::tt::TokenTree<super::Span>; - pub type Leaf = ::tt::Leaf<super::Span>; - pub type Literal = ::tt::Literal<super::Span>; - pub type Punct = ::tt::Punct<super::Span>; - pub type Ident = ::tt::Ident<super::Span>; -} +use crate::server_impl::{from_token_tree, literal_from_str, token_stream::TokenStreamBuilder}; type TokenStream = crate::server_impl::TokenStream<Span>; @@ -62,66 +53,7 @@ impl server::FreeFunctions for RaSpanServer { &mut self, s: &str, ) -> Result<bridge::Literal<Self::Span, Self::Symbol>, ()> { - use proc_macro::bridge::LitKind; - use rustc_lexer::{LiteralKind, Token, TokenKind}; - - let mut tokens = rustc_lexer::tokenize(s); - let minus_or_lit = tokens.next().unwrap_or(Token { kind: TokenKind::Eof, len: 0 }); - - let lit = if minus_or_lit.kind == TokenKind::Minus { - let lit = tokens.next().ok_or(())?; - if !matches!( - lit.kind, - TokenKind::Literal { - kind: LiteralKind::Int { .. } | LiteralKind::Float { .. }, - .. - } - ) { - return Err(()); - } - lit - } else { - minus_or_lit - }; - - if tokens.next().is_some() { - return Err(()); - } - - let TokenKind::Literal { kind, suffix_start } = lit.kind else { return Err(()) }; - let (kind, start_offset, end_offset) = match kind { - LiteralKind::Int { .. } => (LitKind::Integer, 0, 0), - LiteralKind::Float { .. } => (LitKind::Float, 0, 0), - LiteralKind::Char { terminated } => (LitKind::Char, 1, terminated as usize), - LiteralKind::Byte { terminated } => (LitKind::Byte, 2, terminated as usize), - LiteralKind::Str { terminated } => (LitKind::Str, 1, terminated as usize), - LiteralKind::ByteStr { terminated } => (LitKind::ByteStr, 2, terminated as usize), - LiteralKind::CStr { terminated } => (LitKind::CStr, 2, terminated as usize), - LiteralKind::RawStr { n_hashes } => ( - LitKind::StrRaw(n_hashes.unwrap_or_default()), - 2 + n_hashes.unwrap_or_default() as usize, - 1 + n_hashes.unwrap_or_default() as usize, - ), - LiteralKind::RawByteStr { n_hashes } => ( - LitKind::ByteStrRaw(n_hashes.unwrap_or_default()), - 3 + n_hashes.unwrap_or_default() as usize, - 1 + n_hashes.unwrap_or_default() as usize, - ), - LiteralKind::RawCStr { n_hashes } => ( - LitKind::CStrRaw(n_hashes.unwrap_or_default()), - 3 + n_hashes.unwrap_or_default() as usize, - 1 + n_hashes.unwrap_or_default() as usize, - ), - }; - - let (lit, suffix) = s.split_at(suffix_start as usize); - let lit = &lit[start_offset..lit.len() - end_offset]; - let suffix = match suffix { - "" | "_" => None, - suffix => Some(Symbol::intern(suffix)), - }; - - Ok(bridge::Literal { kind, symbol: Symbol::intern(lit), suffix, span: self.call_site }) + literal_from_str(s, self.call_site) } fn emit_diagnostic(&mut self, _: bridge::Diagnostic<Self::Span>) { @@ -149,70 +81,7 @@ impl server::TokenStream for RaSpanServer { &mut self, tree: bridge::TokenTree<Self::TokenStream, Self::Span, Self::Symbol>, ) -> Self::TokenStream { - match tree { - bridge::TokenTree::Group(group) => { - let group = TopSubtree::from_bridge(group); - TokenStream { token_trees: group.0 } - } - - bridge::TokenTree::Ident(ident) => { - let text = ident.sym; - let ident: tt::Ident = tt::Ident { - sym: text, - span: ident.span, - is_raw: if ident.is_raw { tt::IdentIsRaw::Yes } else { tt::IdentIsRaw::No }, - }; - let leaf = tt::Leaf::from(ident); - let tree = tt::TokenTree::from(leaf); - TokenStream { token_trees: vec![tree] } - } - - bridge::TokenTree::Literal(literal) => { - let token_trees = - if let Some((_minus, symbol)) = literal.symbol.as_str().split_once('-') { - let punct = tt::Punct { - spacing: tt::Spacing::Alone, - span: literal.span, - char: '-' as char, - }; - let leaf: tt::Leaf = tt::Leaf::from(punct); - let minus_tree = tt::TokenTree::from(leaf); - - let literal = tt::Literal { - symbol: Symbol::intern(symbol), - suffix: literal.suffix, - span: literal.span, - kind: literal_kind_to_internal(literal.kind), - }; - let leaf: tt::Leaf = tt::Leaf::from(literal); - let tree = tt::TokenTree::from(leaf); - vec![minus_tree, tree] - } else { - let literal = tt::Literal { - symbol: literal.symbol, - suffix: literal.suffix, - span: literal.span, - kind: literal_kind_to_internal(literal.kind), - }; - - let leaf: tt::Leaf = tt::Leaf::from(literal); - let tree = tt::TokenTree::from(leaf); - vec![tree] - }; - TokenStream { token_trees } - } - - bridge::TokenTree::Punct(p) => { - let punct = tt::Punct { - char: p.ch as char, - spacing: if p.joint { tt::Spacing::Joint } else { tt::Spacing::Alone }, - span: p.span, - }; - let leaf = tt::Leaf::from(punct); - let tree = tt::TokenTree::from(leaf); - TokenStream { token_trees: vec![tree] } - } - } + from_token_tree(tree) } fn expand_expr(&mut self, self_: &Self::TokenStream) -> Result<Self::TokenStream, ()> { diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs index d55b269f868..b493b325e83 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs @@ -5,23 +5,9 @@ use std::ops::{Bound, Range}; use intern::Symbol; use proc_macro::bridge::{self, server}; -use crate::server_impl::{TopSubtree, literal_kind_to_internal, token_stream::TokenStreamBuilder}; -mod tt { - pub use span::TokenId; +use crate::server_impl::{from_token_tree, literal_from_str, token_stream::TokenStreamBuilder}; - pub use tt::*; - - pub type TokenTree = ::tt::TokenTree<TokenId>; - pub type Leaf = ::tt::Leaf<TokenId>; - pub type Literal = ::tt::Literal<TokenId>; - pub type Punct = ::tt::Punct<TokenId>; - pub type Ident = ::tt::Ident<TokenId>; -} -type TokenTree = tt::TokenTree; -type Punct = tt::Punct; -type Spacing = tt::Spacing; -type Literal = tt::Literal; -type Span = tt::TokenId; +type Span = span::TokenId; type TokenStream = crate::server_impl::TokenStream<Span>; pub struct FreeFunctions; @@ -49,67 +35,7 @@ impl server::FreeFunctions for TokenIdServer { &mut self, s: &str, ) -> Result<bridge::Literal<Self::Span, Self::Symbol>, ()> { - use proc_macro::bridge::LitKind; - use rustc_lexer::{LiteralKind, Token, TokenKind}; - - let mut tokens = rustc_lexer::tokenize(s); - let minus_or_lit = tokens.next().unwrap_or(Token { kind: TokenKind::Eof, len: 0 }); - - let lit = if minus_or_lit.kind == TokenKind::Minus { - let lit = tokens.next().ok_or(())?; - if !matches!( - lit.kind, - TokenKind::Literal { - kind: LiteralKind::Int { .. } | LiteralKind::Float { .. }, - .. - } - ) { - return Err(()); - } - lit - } else { - minus_or_lit - }; - - if tokens.next().is_some() { - return Err(()); - } - - let TokenKind::Literal { kind, suffix_start } = lit.kind else { return Err(()) }; - - let (kind, start_offset, end_offset) = match kind { - LiteralKind::Int { .. } => (LitKind::Integer, 0, 0), - LiteralKind::Float { .. } => (LitKind::Float, 0, 0), - LiteralKind::Char { terminated } => (LitKind::Char, 1, terminated as usize), - LiteralKind::Byte { terminated } => (LitKind::Byte, 2, terminated as usize), - LiteralKind::Str { terminated } => (LitKind::Str, 1, terminated as usize), - LiteralKind::ByteStr { terminated } => (LitKind::ByteStr, 2, terminated as usize), - LiteralKind::CStr { terminated } => (LitKind::CStr, 2, terminated as usize), - LiteralKind::RawStr { n_hashes } => ( - LitKind::StrRaw(n_hashes.unwrap_or_default()), - 2 + n_hashes.unwrap_or_default() as usize, - 1 + n_hashes.unwrap_or_default() as usize, - ), - LiteralKind::RawByteStr { n_hashes } => ( - LitKind::ByteStrRaw(n_hashes.unwrap_or_default()), - 3 + n_hashes.unwrap_or_default() as usize, - 1 + n_hashes.unwrap_or_default() as usize, - ), - LiteralKind::RawCStr { n_hashes } => ( - LitKind::CStrRaw(n_hashes.unwrap_or_default()), - 3 + n_hashes.unwrap_or_default() as usize, - 1 + n_hashes.unwrap_or_default() as usize, - ), - }; - - let (lit, suffix) = s.split_at(suffix_start as usize); - let lit = &lit[start_offset..lit.len() - end_offset]; - let suffix = match suffix { - "" | "_" => None, - suffix => Some(Symbol::intern(suffix)), - }; - - Ok(bridge::Literal { kind, symbol: Symbol::intern(lit), suffix, span: self.call_site }) + literal_from_str(s, self.call_site) } fn emit_diagnostic(&mut self, _: bridge::Diagnostic<Self::Span>) {} @@ -135,69 +61,7 @@ impl server::TokenStream for TokenIdServer { &mut self, tree: bridge::TokenTree<Self::TokenStream, Self::Span, Self::Symbol>, ) -> Self::TokenStream { - match tree { - bridge::TokenTree::Group(group) => { - let group = TopSubtree::from_bridge(group); - TokenStream { token_trees: group.0 } - } - - bridge::TokenTree::Ident(ident) => { - let ident: tt::Ident = tt::Ident { - sym: ident.sym, - span: ident.span, - is_raw: if ident.is_raw { tt::IdentIsRaw::Yes } else { tt::IdentIsRaw::No }, - }; - let leaf = tt::Leaf::from(ident); - let tree = TokenTree::from(leaf); - TokenStream { token_trees: vec![tree] } - } - - bridge::TokenTree::Literal(literal) => { - let token_trees = - if let Some((_minus, symbol)) = literal.symbol.as_str().split_once('-') { - let punct = tt::Punct { - spacing: tt::Spacing::Alone, - span: literal.span, - char: '-' as char, - }; - let leaf: tt::Leaf = tt::Leaf::from(punct); - let minus_tree = tt::TokenTree::from(leaf); - - let literal = Literal { - symbol: Symbol::intern(symbol), - suffix: literal.suffix, - span: literal.span, - kind: literal_kind_to_internal(literal.kind), - }; - let leaf: tt::Leaf = tt::Leaf::from(literal); - let tree = tt::TokenTree::from(leaf); - vec![minus_tree, tree] - } else { - let literal = Literal { - symbol: literal.symbol, - suffix: literal.suffix, - span: literal.span, - kind: literal_kind_to_internal(literal.kind), - }; - - let leaf: tt::Leaf = tt::Leaf::from(literal); - let tree = tt::TokenTree::from(leaf); - vec![tree] - }; - TokenStream { token_trees } - } - - bridge::TokenTree::Punct(p) => { - let punct = Punct { - char: p.ch as char, - spacing: if p.joint { Spacing::Joint } else { Spacing::Alone }, - span: p.span, - }; - let leaf = tt::Leaf::from(punct); - let tree = TokenTree::from(leaf); - TokenStream { token_trees: vec![tree] } - } - } + from_token_tree(tree) } fn expand_expr(&mut self, self_: &Self::TokenStream) -> Result<Self::TokenStream, ()> { @@ -337,6 +201,8 @@ impl server::Server for TokenIdServer { #[cfg(test)] mod tests { + use span::TokenId; + use super::*; #[test] @@ -345,18 +211,18 @@ mod tests { token_trees: vec![ tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { sym: Symbol::intern("struct"), - span: tt::TokenId(0), + span: TokenId(0), is_raw: tt::IdentIsRaw::No, })), tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { sym: Symbol::intern("T"), - span: tt::TokenId(0), + span: TokenId(0), is_raw: tt::IdentIsRaw::No, })), tt::TokenTree::Subtree(tt::Subtree { delimiter: tt::Delimiter { - open: tt::TokenId(0), - close: tt::TokenId(0), + open: TokenId(0), + close: TokenId(0), kind: tt::DelimiterKind::Brace, }, len: 0, @@ -372,8 +238,8 @@ mod tests { let subtree_paren_a = vec![ tt::TokenTree::Subtree(tt::Subtree { delimiter: tt::Delimiter { - open: tt::TokenId(0), - close: tt::TokenId(0), + open: TokenId(0), + close: TokenId(0), kind: tt::DelimiterKind::Parenthesis, }, len: 1, @@ -381,24 +247,24 @@ mod tests { tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { is_raw: tt::IdentIsRaw::No, sym: Symbol::intern("a"), - span: tt::TokenId(0), + span: TokenId(0), })), ]; - let t1 = TokenStream::from_str("(a)", tt::TokenId(0)).unwrap(); + let t1 = TokenStream::from_str("(a)", TokenId(0)).unwrap(); assert_eq!(t1.token_trees.len(), 2); assert!(t1.token_trees[0..2] == subtree_paren_a); - let t2 = TokenStream::from_str("(a);", tt::TokenId(0)).unwrap(); + let t2 = TokenStream::from_str("(a);", TokenId(0)).unwrap(); assert_eq!(t2.token_trees.len(), 3); assert!(t2.token_trees[0..2] == subtree_paren_a); - let underscore = TokenStream::from_str("_", tt::TokenId(0)).unwrap(); + let underscore = TokenStream::from_str("_", TokenId(0)).unwrap(); assert!( underscore.token_trees[0] == tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { sym: Symbol::intern("_"), - span: tt::TokenId(0), + span: TokenId(0), is_raw: tt::IdentIsRaw::No, })) ); diff --git a/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs index 6e730b1aea2..bb02284a513 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs @@ -431,12 +431,6 @@ impl CargoWorkspace { .ok_or(cargo_metadata::Error::NoJson)?; Ok((cargo_metadata::MetadataCommand::parse(stdout)?, None)) })() - .map(|(metadata, error)| { - ( - metadata, - error.map(|e| e.context(format!("Failed to run `{:?}`", meta.cargo_command()))), - ) - }) .with_context(|| format!("Failed to run `{:?}`", meta.cargo_command())) } 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 d1ca8c1a91a..5cbea9c2b3d 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs @@ -1192,7 +1192,7 @@ impl ConfigChange { #[derive(Debug, Clone, Eq, PartialEq)] pub enum LinkedProject { ProjectManifest(ProjectManifest), - InlineJsonProject(ProjectJson), + InlineProjectJson(ProjectJson), } impl From<ProjectManifest> for LinkedProject { @@ -1203,7 +1203,7 @@ impl From<ProjectManifest> for LinkedProject { impl From<ProjectJson> for LinkedProject { fn from(v: ProjectJson) -> Self { - LinkedProject::InlineJsonProject(v) + LinkedProject::InlineProjectJson(v) } } @@ -1597,6 +1597,16 @@ impl Config { term_search_borrowck: self.assist_termSearch_borrowcheck(source_root).to_owned(), } } + + pub fn diagnostic_fixes(&self, source_root: Option<SourceRootId>) -> DiagnosticsConfig { + // We always want to show quickfixes for diagnostics, even when diagnostics/experimental diagnostics are disabled. + DiagnosticsConfig { + enabled: true, + disable_experimental: false, + ..self.diagnostics(source_root) + } + } + pub fn expand_proc_attr_macros(&self) -> bool { self.procMacro_enable().to_owned() && self.procMacro_attributes_enable().to_owned() } 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 69983a67626..6d46ce68ed4 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 @@ -1439,7 +1439,7 @@ pub(crate) fn handle_code_action( }; let assists = snap.analysis.assists_with_fixes( &assists_config, - &snap.config.diagnostics(Some(source_root)), + &snap.config.diagnostic_fixes(Some(source_root)), resolve, frange, )?; @@ -1530,7 +1530,7 @@ pub(crate) fn handle_code_action_resolve( let assists = snap.analysis.assists_with_fixes( &assists_config, - &snap.config.diagnostics(Some(source_root)), + &snap.config.diagnostic_fixes(Some(source_root)), AssistResolveStrategy::Single(assist_resolve), frange, )?; diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/utils.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/utils.rs index 673eaa5952f..5bea7084fdb 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/utils.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/utils.rs @@ -108,8 +108,7 @@ impl GlobalState { /// edge users from being upset! pub(crate) fn poke_rust_analyzer_developer(&mut self, message: String) { let from_source_build = option_env!("POKE_RA_DEVS").is_some(); - let profiling_enabled = std::env::var("RA_PROFILE").is_ok(); - if from_source_build || profiling_enabled { + if from_source_build { self.show_and_log_error(message, None); } } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs index ae9e3e99874..4677880daaf 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs @@ -292,7 +292,7 @@ impl GlobalState { if let (Some(_command), Some(path)) = (&discover_command, &path) { let build = linked_projects.iter().find_map(|project| match project { - LinkedProject::InlineJsonProject(it) => it.crate_by_buildfile(path), + LinkedProject::InlineProjectJson(it) => it.crate_by_buildfile(path), _ => None, }); @@ -318,7 +318,7 @@ impl GlobalState { &progress, ) } - LinkedProject::InlineJsonProject(it) => { + LinkedProject::InlineProjectJson(it) => { let workspace = project_model::ProjectWorkspace::load_inline( it.clone(), &cargo_config, 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 f6bcb5642c3..59073af983b 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 @@ -975,10 +975,6 @@ version = \"0.0.0\" } fn out_dirs_check_impl(root_contains_symlink: bool) { - if skip_slow_tests() { - return; - } - let mut server = Project::with_fixture( r###" //- /Cargo.toml @@ -1130,12 +1126,18 @@ fn main() { #[test] fn out_dirs_check() { + if skip_slow_tests() { + return; + } out_dirs_check_impl(false); } #[test] #[cfg(not(windows))] // windows requires elevated permissions to create symlinks fn root_contains_symlink_out_dirs_check() { + if skip_slow_tests() { + return; + } out_dirs_check_impl(true); } 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 485f32281dd..cac7efd84aa 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 @@ -439,6 +439,7 @@ assist.emitMustUse = true"#, } #[test] +#[ignore = "flaky test that tends to hang"] fn ratoml_inherit_config_from_ws_root() { if skip_slow_tests() { return; diff --git a/src/tools/rust-analyzer/crates/syntax/rust.ungram b/src/tools/rust-analyzer/crates/syntax/rust.ungram index 10abca7d35d..c81da06682e 100644 --- a/src/tools/rust-analyzer/crates/syntax/rust.ungram +++ b/src/tools/rust-analyzer/crates/syntax/rust.ungram @@ -39,7 +39,10 @@ PathSegment = | NameRef GenericArgList? | NameRef ParenthesizedArgList RetType? | NameRef ReturnTypeSyntax -| '<' Type ('as' PathType)? '>' +| TypeAnchor + +TypeAnchor = + '<' Type ('as' PathType)? '>' ReturnTypeSyntax = '(' '..' ')' @@ -98,7 +101,7 @@ WhereClause = 'where' predicates:(WherePred (',' WherePred)* ','?) WherePred = - ('for' GenericParamList)? (Lifetime | Type) ':' TypeBoundList? + ('for' GenericParamList)? (Lifetime | Type) ':' TypeBoundList? //*************************// 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 cd9f4dba890..04c7e8a578c 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 @@ -1232,21 +1232,13 @@ impl PathSegment { support::child(&self.syntax) } #[inline] - pub fn path_type(&self) -> Option<PathType> { support::child(&self.syntax) } - #[inline] pub fn ret_type(&self) -> Option<RetType> { support::child(&self.syntax) } #[inline] pub fn return_type_syntax(&self) -> Option<ReturnTypeSyntax> { support::child(&self.syntax) } #[inline] - pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) } + pub fn type_anchor(&self) -> Option<TypeAnchor> { support::child(&self.syntax) } #[inline] pub fn coloncolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![::]) } - #[inline] - pub fn l_angle_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![<]) } - #[inline] - pub fn r_angle_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![>]) } - #[inline] - pub fn as_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![as]) } } pub struct PathType { pub(crate) syntax: SyntaxNode, @@ -1739,6 +1731,21 @@ impl TypeAlias { #[inline] pub fn type_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![type]) } } +pub struct TypeAnchor { + pub(crate) syntax: SyntaxNode, +} +impl TypeAnchor { + #[inline] + pub fn path_type(&self) -> Option<PathType> { support::child(&self.syntax) } + #[inline] + pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) } + #[inline] + pub fn l_angle_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![<]) } + #[inline] + pub fn r_angle_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![>]) } + #[inline] + pub fn as_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![as]) } +} pub struct TypeArg { pub(crate) syntax: SyntaxNode, } @@ -7108,6 +7115,42 @@ impl fmt::Debug for TypeAlias { f.debug_struct("TypeAlias").field("syntax", &self.syntax).finish() } } +impl AstNode for TypeAnchor { + #[inline] + fn kind() -> SyntaxKind + where + Self: Sized, + { + TYPE_ANCHOR + } + #[inline] + fn can_cast(kind: SyntaxKind) -> bool { kind == TYPE_ANCHOR } + #[inline] + fn cast(syntax: SyntaxNode) -> Option<Self> { + if Self::can_cast(syntax.kind()) { + Some(Self { syntax }) + } else { + None + } + } + #[inline] + fn syntax(&self) -> &SyntaxNode { &self.syntax } +} +impl hash::Hash for TypeAnchor { + fn hash<H: hash::Hasher>(&self, state: &mut H) { self.syntax.hash(state); } +} +impl Eq for TypeAnchor {} +impl PartialEq for TypeAnchor { + fn eq(&self, other: &Self) -> bool { self.syntax == other.syntax } +} +impl Clone for TypeAnchor { + fn clone(&self) -> Self { Self { syntax: self.syntax.clone() } } +} +impl fmt::Debug for TypeAnchor { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("TypeAnchor").field("syntax", &self.syntax).finish() + } +} impl AstNode for TypeArg { #[inline] fn kind() -> SyntaxKind @@ -10624,6 +10667,11 @@ impl std::fmt::Display for TypeAlias { std::fmt::Display::fmt(self.syntax(), f) } } +impl std::fmt::Display for TypeAnchor { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} impl std::fmt::Display for TypeArg { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs index b9ccd34cff0..dcf853427e5 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs @@ -276,18 +276,15 @@ impl ast::PathSegment { _ => PathSegmentKind::Name(name_ref), } } else { - match self.syntax().first_child_or_token()?.kind() { - T![<] => { - // <T> or <T as Trait> - // T is any TypeRef, Trait has to be a PathType - let mut type_refs = - self.syntax().children().filter(|node| ast::Type::can_cast(node.kind())); - let type_ref = type_refs.next().and_then(ast::Type::cast); - let trait_ref = type_refs.next().and_then(ast::PathType::cast); - PathSegmentKind::Type { type_ref, trait_ref } - } - _ => return None, - } + let anchor = self.type_anchor()?; + // FIXME: Move this over to `ast::TypeAnchor` + // <T> or <T as Trait> + // T is any TypeRef, Trait has to be a PathType + let mut type_refs = + anchor.syntax().children().filter(|node| ast::Type::can_cast(node.kind())); + let type_ref = type_refs.next().and_then(ast::Type::cast); + let trait_ref = type_refs.next().and_then(ast::PathType::cast); + PathSegmentKind::Type { type_ref, trait_ref } }; Some(res) } @@ -473,7 +470,7 @@ impl ast::Impl { // [#15778](https://github.com/rust-lang/rust-analyzer/issues/15778) impl ast::PathSegment { pub fn qualifying_trait(&self) -> Option<ast::PathType> { - let mut path_types = support::children(self.syntax()); + let mut path_types = support::children(self.type_anchor()?.syntax()); let first = path_types.next()?; path_types.next().or(Some(first)) } 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 96e1301f227..8eb48f8d93e 100644 --- a/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs +++ b/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs @@ -538,6 +538,21 @@ pub fn disallow_cfg(_attr: TokenStream, input: TokenStream) -> TokenStream { disabled: false, }, ), + ( + r#" +#[proc_macro_attribute] +pub fn generate_suffixed_type(_attr: TokenStream, input: TokenStream) -> TokenStream { + input +} +"# + .into(), + ProcMacro { + name: Symbol::intern("generate_suffixed_type"), + kind: ProcMacroKind::Attr, + expander: sync::Arc::new(GenerateSuffixedTypeProcMacroExpander), + disabled: false, + }, + ), ]) } @@ -919,3 +934,57 @@ impl ProcMacroExpander for DisallowCfgProcMacroExpander { Ok(subtree.clone()) } } + +// Generates a new type by adding a suffix to the original name +#[derive(Debug)] +struct GenerateSuffixedTypeProcMacroExpander; +impl ProcMacroExpander for GenerateSuffixedTypeProcMacroExpander { + fn expand( + &self, + subtree: &TopSubtree, + _attrs: Option<&TopSubtree>, + _env: &Env, + _def_site: Span, + call_site: Span, + _mixed_site: Span, + _current_dir: String, + ) -> Result<TopSubtree, ProcMacroExpansionError> { + let TokenTree::Leaf(Leaf::Ident(ident)) = &subtree.0[1] else { + return Err(ProcMacroExpansionError::Panic("incorrect Input".into())); + }; + + let ident = match ident.sym.as_str() { + "struct" => { + let TokenTree::Leaf(Leaf::Ident(ident)) = &subtree.0[2] else { + return Err(ProcMacroExpansionError::Panic("incorrect Input".into())); + }; + ident + } + + "enum" => { + let TokenTree::Leaf(Leaf::Ident(ident)) = &subtree.0[4] else { + return Err(ProcMacroExpansionError::Panic("incorrect Input".into())); + }; + ident + } + + _ => { + return Err(ProcMacroExpansionError::Panic("incorrect Input".into())); + } + }; + + let generated_ident = tt::Ident { + sym: Symbol::intern(&format!("{}Suffix", ident.sym)), + span: ident.span, + is_raw: tt::IdentIsRaw::No, + }; + + let ret = quote! { call_site => + #subtree + + struct #generated_ident; + }; + + Ok(ret) + } +} diff --git a/src/tools/rust-analyzer/docs/book/src/non_cargo_based_projects.md b/src/tools/rust-analyzer/docs/book/src/non_cargo_based_projects.md index 151f8758a17..bbdb48bbbc9 100644 --- a/src/tools/rust-analyzer/docs/book/src/non_cargo_based_projects.md +++ b/src/tools/rust-analyzer/docs/book/src/non_cargo_based_projects.md @@ -5,7 +5,7 @@ build system, you’ll have to describe the structure of your project for rust-analyzer in the `rust-project.json` format: ```typescript -interface JsonProject { +interface ProjectJson { /// Path to the sysroot directory. /// /// The sysroot is where rustc looks for the diff --git a/src/tools/rust-analyzer/editors/code/package-lock.json b/src/tools/rust-analyzer/editors/code/package-lock.json index 18fb097aad7..ab431140c10 100644 --- a/src/tools/rust-analyzer/editors/code/package-lock.json +++ b/src/tools/rust-analyzer/editors/code/package-lock.json @@ -5500,9 +5500,9 @@ } }, "node_modules/tar-fs": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.2.tgz", - "integrity": "sha512-EsaAXwxmx8UB7FRKqeozqEPop69DXcmYwTQwXvyAPF352HJsPdkVhvTaDPYqfNgruveJIJy3TA2l+2zj8LJIJA==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.3.tgz", + "integrity": "sha512-090nwYJDmlhwFwEW3QQl+vaNnxsO2yVsd45eTKRBzSzu+hlb1w2K9inVq5b0ngXuLVqQ4ApvsUHHnu/zQNkWAg==", "dev": true, "license": "MIT", "optional": true, diff --git a/src/tools/rust-analyzer/rust-version b/src/tools/rust-analyzer/rust-version index 5b47d1bbaed..af0dd5c9acd 100644 --- a/src/tools/rust-analyzer/rust-version +++ b/src/tools/rust-analyzer/rust-version @@ -1 +1 @@ -a8e4c68dcb4dc1e48a0db294c5323cab0227fcb9 +7c10378e1fee5ddc6573b916aeb884ab10e0de17 diff --git a/src/tools/rustbook/Cargo.lock b/src/tools/rustbook/Cargo.lock index 8893846b5fa..ed67fa7d1a9 100644 --- a/src/tools/rustbook/Cargo.lock +++ b/src/tools/rustbook/Cargo.lock @@ -47,9 +47,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.18" +version = "0.6.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" +checksum = "301af1932e46185686725e0fad2f8f2aa7da69dd70bf6ecc44d6b703844a3933" dependencies = [ "anstyle", "anstyle-parse", @@ -62,36 +62,36 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" +checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" [[package]] name = "anstyle-parse" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" +checksum = "6c8bdeb6047d8983be085bab0ba1472e6dc604e7041dbf6fcd5e71523014fae9" dependencies = [ "windows-sys", ] [[package]] name = "anstyle-wincon" -version = "3.0.7" +version = "3.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" +checksum = "403f75924867bb1033c59fbf0797484329750cfbe3c4325cd33127941fabc882" dependencies = [ "anstyle", - "once_cell", + "once_cell_polyfill", "windows-sys", ] @@ -124,9 +124,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.9.0" +version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" +checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" [[package]] name = "block-buffer" @@ -150,15 +150,15 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.17.0" +version = "3.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" +checksum = "793db76d6187cd04dff33004d8e6c9cc4e05cd330500379d2394209271b4aeee" [[package]] name = "cc" -version = "1.2.22" +version = "1.2.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32db95edf998450acc7881c932f94cd9b05c87b4b2599e8bab064753da4acfd1" +checksum = "956a5e21988b87f372569b66183b78babf23ebc2e744b733e4350a752c4dafac" dependencies = [ "shlex", ] @@ -185,9 +185,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.38" +version = "4.5.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed93b9805f8ba930df42c2590f05453d5ec36cbb85d018868a5b24d31f6ac000" +checksum = "fd60e63e9be68e5fb56422e397cf9baddded06dae1d2e523401542383bc72a9f" dependencies = [ "clap_builder", "clap_derive", @@ -195,9 +195,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.38" +version = "4.5.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "379026ff283facf611b0ea629334361c4211d1b12ee01024eec1591133b04120" +checksum = "89cc6392a1f72bbeb820d71f32108f61fdaf18bc526e1d23954168a67759ef51" dependencies = [ "anstream", "anstyle", @@ -208,9 +208,9 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.5.50" +version = "4.5.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c91d3baa3bcd889d60e6ef28874126a0b384fd225ab83aa6d8a801c519194ce1" +checksum = "1a554639e42d0c838336fc4fbedb9e2df3ad1fa4acda149f9126b4ccfcd7900f" dependencies = [ "clap", ] @@ -235,9 +235,9 @@ checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" [[package]] name = "colorchoice" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" [[package]] name = "core-foundation-sys" @@ -459,9 +459,9 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" -version = "0.3.11" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e" +checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18" dependencies = [ "libc", "windows-sys", @@ -482,9 +482,9 @@ checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "flate2" -version = "1.1.1" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece" +checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d" dependencies = [ "crc32fast", "miniz_oxide", @@ -531,7 +531,7 @@ version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" dependencies = [ - "unicode-width", + "unicode-width 0.1.14", ] [[package]] @@ -564,9 +564,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.3" +version = "0.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3" +checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" [[package]] name = "heck" @@ -680,9 +680,9 @@ checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" [[package]] name = "icu_properties" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2549ca8c7241c82f59c80ba2a6f415d931c5b58d24fb8412caa1a1f02c49139a" +checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" dependencies = [ "displaydoc", "icu_collections", @@ -696,9 +696,9 @@ dependencies = [ [[package]] name = "icu_properties_data" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8197e866e47b68f8f7d95249e172903bec06004b18b2937f1095d40a0c57de04" +checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" [[package]] name = "icu_provider" @@ -768,9 +768,9 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "jiff" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f02000660d30638906021176af16b17498bd0d12813dbfe7b276d8bc7f3c0806" +checksum = "a194df1107f33c79f4f93d02c80798520551949d59dfad22b6157048a88cca93" dependencies = [ "jiff-static", "log", @@ -781,9 +781,9 @@ dependencies = [ [[package]] name = "jiff-static" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3c30758ddd7188629c6713fc45d1188af4f44c90582311d0c8d8c9907f60c48" +checksum = "6c6e1db7ed32c6c71b759497fae34bf7933636f75a251b9e736555da426f6442" dependencies = [ "proc-macro2", "quote", @@ -835,9 +835,9 @@ checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" [[package]] name = "lock_api" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" dependencies = [ "autocfg", "scopeguard", @@ -961,7 +961,7 @@ dependencies = [ "pulldown-cmark-to-cmark 19.0.1", "serde_json", "thiserror 1.0.69", - "toml 0.8.22", + "toml 0.8.23", ] [[package]] @@ -1025,12 +1025,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] +name = "once_cell_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" + +[[package]] name = "onig" version = "6.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "336b9c63443aceef14bea841b899035ae3abe89b7c486aaf4c5bd8aafedac3f0" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "libc", "once_cell", "onig_sys", @@ -1048,9 +1054,9 @@ dependencies = [ [[package]] name = "opener" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de96cad6ee771be7f68df884d3767460b4684012308d8342ed5623fe62b2628c" +checksum = "771b9704f8cd8b424ec747a320b30b47517a6966ba2c7da90047c16f4a962223" dependencies = [ "bstr", "normpath", @@ -1059,9 +1065,9 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.12.3" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" dependencies = [ "lock_api", "parking_lot_core", @@ -1069,9 +1075,9 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.10" +version = "0.9.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" dependencies = [ "cfg-if", "libc", @@ -1206,9 +1212,9 @@ dependencies = [ [[package]] name = "portable-atomic" -version = "1.11.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e" +checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" [[package]] name = "portable-atomic-util" @@ -1249,7 +1255,7 @@ version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76979bea66e7875e7509c4ec5300112b316af87fa7a252ca91c448b32dfe3993" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "memchr", "pulldown-cmark-escape 0.10.1", "unicase", @@ -1261,7 +1267,7 @@ version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f86ba2052aebccc42cbbb3ed234b8b13ce76f75c3551a303cb2bcffcff12bb14" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "getopts", "memchr", "pulldown-cmark-escape 0.11.0", @@ -1315,11 +1321,11 @@ checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" [[package]] name = "railroad" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ecedffc46c1b2cb04f4b80e094eae6b3f3f470a9635f1f396dd5206428f6b58" +checksum = "e6d5b8e8a7c20c600f9b98cbf46b64e63d5c9e69deb98cee1ff264de9f1dda5d" dependencies = [ - "unicode-width", + "unicode-width 0.2.0", ] [[package]] @@ -1343,7 +1349,7 @@ version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", ] [[package]] @@ -1393,7 +1399,7 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "errno", "libc", "linux-raw-sys", @@ -1402,9 +1408,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.20" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" +checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" [[package]] name = "ryu" @@ -1467,9 +1473,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.8" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" dependencies = [ "serde", ] @@ -1499,9 +1505,9 @@ checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" [[package]] name = "smallvec" -version = "1.15.0" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "stable_deref_trait" @@ -1584,9 +1590,9 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.19.1" +version = "3.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7437ac7763b9b123ccf33c338a5cc1bac6f69b45a136c19bdd8a65e3916435bf" +checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1" dependencies = [ "fastrand", "getrandom", @@ -1683,9 +1689,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.22" +version = "0.8.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05ae329d1f08c4d17a59bed7ff5b5a769d062e64a62d34a3261b219e62cd5aae" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" dependencies = [ "serde", "serde_spanned", @@ -1695,18 +1701,18 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.9" +version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3da5db5a963e24bc68be8b17b6fa82814bb22ee8660f192bb182771d498f09a3" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.22.26" +version = "0.22.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "310068873db2c5b3e7659d2cc35d21855dbafa50d1ce336397c666e3cb08137e" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ "indexmap", "serde", @@ -1718,9 +1724,9 @@ dependencies = [ [[package]] name = "toml_write" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfb942dfe1d8e29a7ee7fcbde5bd2b9a25fb89aa70caea2eba3bee836ff41076" +checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" [[package]] name = "topological-sort" @@ -1759,6 +1765,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" [[package]] +name = "unicode-width" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" + +[[package]] name = "url" version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1872,9 +1884,9 @@ dependencies = [ [[package]] name = "web_atoms" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b9c5f0bc545ea3b20b423e33b9b457764de0b3730cd957f6c6aa6c301785f6e" +checksum = "57ffde1dc01240bdf9992e3205668b235e59421fd085e8a317ed98da0178d414" dependencies = [ "phf", "phf_codegen", @@ -1893,9 +1905,9 @@ dependencies = [ [[package]] name = "windows-core" -version = "0.61.0" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980" +checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" dependencies = [ "windows-implement", "windows-interface", @@ -1934,18 +1946,18 @@ checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" [[package]] name = "windows-result" -version = "0.3.2" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" dependencies = [ "windows-link", ] [[package]] name = "windows-strings" -version = "0.4.0" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" dependencies = [ "windows-link", ] @@ -2038,7 +2050,7 @@ version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", ] [[package]] diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index fdca7a7a40e..170dcd626a2 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -441,6 +441,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "windows-strings", "windows-sys", "windows-targets", + "windows-threading", "windows_aarch64_gnullvm", "windows_aarch64_msvc", "windows_i686_gnu", diff --git a/tests/codegen/autovec/dont-shuffle-bswaps-opt2.rs b/tests/codegen/autovec/dont-shuffle-bswaps-opt2.rs new file mode 100644 index 00000000000..c354228acc5 --- /dev/null +++ b/tests/codegen/autovec/dont-shuffle-bswaps-opt2.rs @@ -0,0 +1,31 @@ +//@ compile-flags: -Copt-level=2 + +#![crate_type = "lib"] +#![no_std] + +// This test is paired with the arch-specific -opt3.rs test. + +// The code is from https://github.com/rust-lang/rust/issues/122805. +// Ensure we do not generate the shufflevector instruction +// to avoid complicating the code. + +// CHECK-LABEL: define{{.*}}void @convert( +// CHECK-NOT: shufflevector +#[no_mangle] +pub fn convert(value: [u16; 8]) -> [u8; 16] { + #[cfg(target_endian = "little")] + let bswap = u16::to_be; + #[cfg(target_endian = "big")] + let bswap = u16::to_le; + let addr16 = [ + bswap(value[0]), + bswap(value[1]), + bswap(value[2]), + bswap(value[3]), + bswap(value[4]), + bswap(value[5]), + bswap(value[6]), + bswap(value[7]), + ]; + unsafe { core::mem::transmute::<_, [u8; 16]>(addr16) } +} diff --git a/tests/codegen/dont-shuffle-bswaps.rs b/tests/codegen/autovec/dont-shuffle-bswaps-opt3.rs index c1dab2bc295..203d12005de 100644 --- a/tests/codegen/dont-shuffle-bswaps.rs +++ b/tests/codegen/autovec/dont-shuffle-bswaps-opt3.rs @@ -1,29 +1,27 @@ -//@ revisions: OPT2 OPT3 OPT3_S390X -//@[OPT2] compile-flags: -Copt-level=2 -//@[OPT3] compile-flags: -C opt-level=3 -// some targets don't do the opt we are looking for -//@[OPT3] only-64bit -//@[OPT3] ignore-s390x -//@[OPT3_S390X] compile-flags: -C opt-level=3 -C target-cpu=z13 -//@[OPT3_S390X] only-s390x +//@ revisions: AARCH64 X86_64 Z13 +//@ compile-flags: -Copt-level=3 +//@[AARCH64] only-aarch64 +//@[X86_64] only-x86_64 +//@[Z13] only-s390x +//@[Z13] compile-flags: -Ctarget-cpu=z13 #![crate_type = "lib"] #![no_std] +// This test is paired with the arch-neutral -opt2.rs test + // The code is from https://github.com/rust-lang/rust/issues/122805. // Ensure we do not generate the shufflevector instruction // to avoid complicating the code. + // CHECK-LABEL: define{{.*}}void @convert( // CHECK-NOT: shufflevector + // On higher opt levels, this should just be a bswap: -// OPT3: load <8 x i16> -// OPT3-NEXT: call <8 x i16> @llvm.bswap -// OPT3-NEXT: store <8 x i16> -// OPT3-NEXT: ret void -// OPT3_S390X: load <8 x i16> -// OPT3_S390X-NEXT: call <8 x i16> @llvm.bswap -// OPT3_S390X-NEXT: store <8 x i16> -// OPT3_S390X-NEXT: ret void +// CHECK: load <8 x i16> +// CHECK-NEXT: call <8 x i16> @llvm.bswap +// CHECK-NEXT: store <8 x i16> +// CHECK-NEXT: ret void #[no_mangle] pub fn convert(value: [u16; 8]) -> [u8; 16] { #[cfg(target_endian = "little")] diff --git a/tests/codegen/retpoline.rs b/tests/codegen/retpoline.rs new file mode 100644 index 00000000000..30fdd9c2db2 --- /dev/null +++ b/tests/codegen/retpoline.rs @@ -0,0 +1,29 @@ +// ignore-tidy-linelength +// Test that the +// `retpoline-external-thunk`, `retpoline-indirect-branches`, `retpoline-indirect-calls` +// target features are (not) emitted when the `retpoline/retpoline-external-thunk` flag is (not) set. + +//@ revisions: disabled enabled_retpoline enabled_retpoline_external_thunk +//@ needs-llvm-components: x86 +//@ compile-flags: --target x86_64-unknown-linux-gnu +//@ [enabled_retpoline] compile-flags: -Zretpoline +//@ [enabled_retpoline_external_thunk] compile-flags: -Zretpoline-external-thunk + +#![crate_type = "lib"] +#![feature(no_core, lang_items)] +#![no_core] + +#[lang = "sized"] +trait Sized {} + +#[no_mangle] +pub fn foo() { + // CHECK: @foo() unnamed_addr #0 + + // disabled-NOT: attributes #0 = { {{.*}}"target-features"="{{[^"]*}}+retpoline-external-thunk{{.*}} } + // disabled-NOT: attributes #0 = { {{.*}}"target-features"="{{[^"]*}}+retpoline-indirect-branches{{.*}} } + // disabled-NOT: attributes #0 = { {{.*}}"target-features"="{{[^"]*}}+retpoline-indirect-calls{{.*}} } + + // enabled_retpoline: attributes #0 = { {{.*}}"target-features"="{{[^"]*}}+retpoline-indirect-branches,+retpoline-indirect-calls{{.*}} } + // enabled_retpoline_external_thunk: attributes #0 = { {{.*}}"target-features"="{{[^"]*}}+retpoline-external-thunk,+retpoline-indirect-branches,+retpoline-indirect-calls{{.*}} } +} diff --git a/tests/crashes/139825.rs b/tests/crashes/139825.rs deleted file mode 100644 index 8c5b6b80f0b..00000000000 --- a/tests/crashes/139825.rs +++ /dev/null @@ -1,5 +0,0 @@ -//@ 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/debuginfo/type-names.rs b/tests/debuginfo/type-names.rs index 3c7eab7e8d7..ac61fef48fe 100644 --- a/tests/debuginfo/type-names.rs +++ b/tests/debuginfo/type-names.rs @@ -19,7 +19,7 @@ // gdb-check:type = type_names::GenericStruct<type_names::mod1::Struct2, type_names::mod1::mod2::Struct3> // gdb-command:whatis generic_struct2 -// gdb-check:type = type_names::GenericStruct<type_names::Struct1, extern "fastcall" fn(isize) -> usize> +// gdb-check:type = type_names::GenericStruct<type_names::Struct1, extern "system" fn(isize) -> usize> // gdb-command:whatis mod_struct // gdb-check:type = type_names::mod1::Struct2 @@ -379,7 +379,7 @@ fn main() { let simple_struct = Struct1; let generic_struct1: GenericStruct<mod1::Struct2, mod1::mod2::Struct3> = GenericStruct(PhantomData); - let generic_struct2: GenericStruct<Struct1, extern "fastcall" fn(isize) -> usize> = + let generic_struct2: GenericStruct<Struct1, extern "system" fn(isize) -> usize> = GenericStruct(PhantomData); let mod_struct = mod1::Struct2; diff --git a/tests/incremental/hashes/trait_defs.rs b/tests/incremental/hashes/trait_defs.rs index cb8716d90b0..7141ddb0d7e 100644 --- a/tests/incremental/hashes/trait_defs.rs +++ b/tests/incremental/hashes/trait_defs.rs @@ -440,7 +440,7 @@ trait TraitAddExternModifier { // Change extern "C" to extern "stdcall" #[cfg(any(cfail1,cfail4))] -trait TraitChangeExternCToRustIntrinsic { +trait TraitChangeExternCToExternSystem { // -------------------------------------------------------------- // ------------------------- // -------------------------------------------------------------- @@ -458,7 +458,7 @@ trait TraitChangeExternCToRustIntrinsic { #[rustc_clean(cfg="cfail3")] #[rustc_clean(except="opt_hir_owner_nodes,fn_sig", cfg="cfail5")] #[rustc_clean(cfg="cfail6")] - extern "stdcall" fn method(); + extern "system" fn method(); } diff --git a/tests/mir-opt/early_otherwise_branch.opt3.EarlyOtherwiseBranch.diff b/tests/mir-opt/early_otherwise_branch.opt3.EarlyOtherwiseBranch.diff index 7b94a4c2bf7..22ebe2f3f29 100644 --- a/tests/mir-opt/early_otherwise_branch.opt3.EarlyOtherwiseBranch.diff +++ b/tests/mir-opt/early_otherwise_branch.opt3.EarlyOtherwiseBranch.diff @@ -32,16 +32,12 @@ StorageDead(_4); _9 = discriminant((_3.0: Option2<u32>)); - switchInt(move _9) -> [0: bb2, 1: bb3, 2: bb4, otherwise: bb9]; -+ StorageLive(_12); + _12 = discriminant((_3.1: Option2<bool>)); -+ StorageLive(_13); + _13 = Ne(copy _9, move _12); -+ StorageDead(_12); + switchInt(move _13) -> [0: bb7, otherwise: bb1]; } bb1: { -+ StorageDead(_13); _0 = const 1_u32; - goto -> bb8; + goto -> bb5; @@ -100,7 +96,6 @@ + } + + bb7: { -+ StorageDead(_13); + switchInt(copy _9) -> [0: bb4, 1: bb3, 2: bb2, otherwise: bb6]; } } diff --git a/tests/mir-opt/early_otherwise_branch.opt4.EarlyOtherwiseBranch.diff b/tests/mir-opt/early_otherwise_branch.opt4.EarlyOtherwiseBranch.diff index f52795baef8..0da0eb3c53c 100644 --- a/tests/mir-opt/early_otherwise_branch.opt4.EarlyOtherwiseBranch.diff +++ b/tests/mir-opt/early_otherwise_branch.opt4.EarlyOtherwiseBranch.diff @@ -32,16 +32,12 @@ StorageDead(_4); _9 = discriminant((_3.0: Option2<u32>)); - switchInt(move _9) -> [0: bb2, 1: bb3, 2: bb4, otherwise: bb9]; -+ StorageLive(_12); + _12 = discriminant((_3.1: Option2<u32>)); -+ StorageLive(_13); + _13 = Ne(copy _9, move _12); -+ StorageDead(_12); + switchInt(move _13) -> [0: bb7, otherwise: bb1]; } bb1: { -+ StorageDead(_13); _0 = const 1_u32; - goto -> bb8; + goto -> bb5; @@ -100,7 +96,6 @@ + } + + bb7: { -+ StorageDead(_13); + switchInt(copy _9) -> [0: bb4, 1: bb3, 2: bb2, otherwise: bb6]; } } diff --git a/tests/mir-opt/early_otherwise_branch.opt5.EarlyOtherwiseBranch.diff b/tests/mir-opt/early_otherwise_branch.opt5.EarlyOtherwiseBranch.diff index b7447ef0c46..b13d21e2d7a 100644 --- a/tests/mir-opt/early_otherwise_branch.opt5.EarlyOtherwiseBranch.diff +++ b/tests/mir-opt/early_otherwise_branch.opt5.EarlyOtherwiseBranch.diff @@ -20,13 +20,11 @@ StorageDead(_5); StorageDead(_4); - switchInt(copy (_3.0: u32)) -> [1: bb2, 2: bb3, 3: bb4, otherwise: bb1]; -+ StorageLive(_6); + _6 = Ne(copy (_3.0: u32), copy (_3.1: u32)); + switchInt(move _6) -> [0: bb6, otherwise: bb1]; } bb1: { -+ StorageDead(_6); _0 = const 0_u32; - goto -> bb8; + goto -> bb5; @@ -70,7 +68,6 @@ - bb8: { - StorageDead(_3); - return; -+ StorageDead(_6); + switchInt(copy (_3.0: u32)) -> [1: bb4, 2: bb3, 3: bb2, otherwise: bb1]; } } diff --git a/tests/mir-opt/early_otherwise_branch.rs b/tests/mir-opt/early_otherwise_branch.rs index 382c38ceb3a..19a5d25de2d 100644 --- a/tests/mir-opt/early_otherwise_branch.rs +++ b/tests/mir-opt/early_otherwise_branch.rs @@ -1,6 +1,10 @@ //@ test-mir-pass: EarlyOtherwiseBranch //@ compile-flags: -Zmir-enable-passes=+UnreachableEnumBranching +#![feature(custom_mir, core_intrinsics)] + +use std::intrinsics::mir::*; + enum Option2<T> { Some(T), None, @@ -124,6 +128,34 @@ fn opt5_failed_type(x: u32, y: u64) -> u32 { } } +// EMIT_MIR early_otherwise_branch.target_self.EarlyOtherwiseBranch.diff +#[custom_mir(dialect = "runtime")] +fn target_self(val: i32) { + // CHECK-LABEL: fn target_self( + // CHECK: Ne( + // CHECK-NEXT: switchInt + mir! { + { + Goto(bb1) + } + bb1 = { + match val { + 0 => bb2, + _ => bb1, + } + } + bb2 = { + match val { + 0 => bb3, + _ => bb1, + } + } + bb3 = { + Return() + } + } +} + fn main() { opt1(None, Some(0)); opt2(None, Some(0)); @@ -131,4 +163,5 @@ fn main() { opt4(Option2::None, Option2::Some(0)); opt5(0, 0); opt5_failed(0, 0); + target_self(1); } diff --git a/tests/mir-opt/early_otherwise_branch.target_self.EarlyOtherwiseBranch.diff b/tests/mir-opt/early_otherwise_branch.target_self.EarlyOtherwiseBranch.diff new file mode 100644 index 00000000000..4f70847bcdf --- /dev/null +++ b/tests/mir-opt/early_otherwise_branch.target_self.EarlyOtherwiseBranch.diff @@ -0,0 +1,28 @@ +- // MIR for `target_self` before EarlyOtherwiseBranch ++ // MIR for `target_self` after EarlyOtherwiseBranch + + fn target_self(_1: i32) -> () { + let mut _0: (); ++ let mut _2: bool; + + bb0: { + goto -> bb1; + } + + bb1: { +- switchInt(copy _1) -> [0: bb2, otherwise: bb1]; ++ _2 = Ne(copy _1, copy _1); ++ switchInt(move _2) -> [0: bb3, otherwise: bb1]; + } + + bb2: { +- switchInt(copy _1) -> [0: bb3, otherwise: bb1]; ++ return; + } + + bb3: { +- return; ++ switchInt(copy _1) -> [0: bb2, otherwise: bb1]; + } + } + diff --git a/tests/mir-opt/early_otherwise_branch_3_element_tuple.opt2.EarlyOtherwiseBranch.diff b/tests/mir-opt/early_otherwise_branch_3_element_tuple.opt2.EarlyOtherwiseBranch.diff index 831d8cbb4d6..e0878167e44 100644 --- a/tests/mir-opt/early_otherwise_branch_3_element_tuple.opt2.EarlyOtherwiseBranch.diff +++ b/tests/mir-opt/early_otherwise_branch_3_element_tuple.opt2.EarlyOtherwiseBranch.diff @@ -42,16 +42,12 @@ StorageDead(_5); _14 = discriminant((_4.0: Option2<u32>)); - switchInt(move _14) -> [0: bb2, 1: bb4, 2: bb6, otherwise: bb12]; -+ StorageLive(_18); + _18 = discriminant((_4.1: Option2<u32>)); -+ StorageLive(_19); + _19 = Ne(copy _14, move _18); -+ StorageDead(_18); + switchInt(move _19) -> [0: bb10, otherwise: bb1]; } bb1: { -+ StorageDead(_19); _0 = const 1_u32; - goto -> bb11; + goto -> bb8; @@ -134,7 +130,6 @@ + } + + bb10: { -+ StorageDead(_19); + switchInt(copy _14) -> [0: bb2, 1: bb3, 2: bb4, otherwise: bb9]; } } diff --git a/tests/mir-opt/lower_intrinsics.align_of.LowerIntrinsics.panic-abort.diff b/tests/mir-opt/lower_intrinsics.align_of.LowerIntrinsics.panic-abort.diff index 8ebd07b9c9c..e61a3e8d738 100644 --- a/tests/mir-opt/lower_intrinsics.align_of.LowerIntrinsics.panic-abort.diff +++ b/tests/mir-opt/lower_intrinsics.align_of.LowerIntrinsics.panic-abort.diff @@ -5,7 +5,7 @@ let mut _0: usize; bb0: { -- _0 = std::intrinsics::min_align_of::<T>() -> [return: bb1, unwind unreachable]; +- _0 = std::intrinsics::align_of::<T>() -> [return: bb1, unwind unreachable]; + _0 = AlignOf(T); + goto -> bb1; } diff --git a/tests/mir-opt/lower_intrinsics.align_of.LowerIntrinsics.panic-unwind.diff b/tests/mir-opt/lower_intrinsics.align_of.LowerIntrinsics.panic-unwind.diff index 8ebd07b9c9c..e61a3e8d738 100644 --- a/tests/mir-opt/lower_intrinsics.align_of.LowerIntrinsics.panic-unwind.diff +++ b/tests/mir-opt/lower_intrinsics.align_of.LowerIntrinsics.panic-unwind.diff @@ -5,7 +5,7 @@ let mut _0: usize; bb0: { -- _0 = std::intrinsics::min_align_of::<T>() -> [return: bb1, unwind unreachable]; +- _0 = std::intrinsics::align_of::<T>() -> [return: bb1, unwind unreachable]; + _0 = AlignOf(T); + goto -> bb1; } diff --git a/tests/mir-opt/lower_intrinsics.rs b/tests/mir-opt/lower_intrinsics.rs index 1e4f2024194..7729e502ad6 100644 --- a/tests/mir-opt/lower_intrinsics.rs +++ b/tests/mir-opt/lower_intrinsics.rs @@ -51,7 +51,7 @@ pub fn size_of<T>() -> usize { pub fn align_of<T>() -> usize { // CHECK-LABEL: fn align_of( // CHECK: {{_.*}} = AlignOf(T); - core::intrinsics::min_align_of::<T>() + core::intrinsics::align_of::<T>() } // EMIT_MIR lower_intrinsics.forget.LowerIntrinsics.diff diff --git a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir index 30eafe8594b..2eee8a97db0 100644 --- a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir @@ -39,7 +39,7 @@ fn vec_deref_to_slice(_1: &Vec<u8>) -> &[u8] { } scope 15 (inlined std::mem::size_of::<u8>) { } - scope 16 (inlined align_of::<u8>) { + scope 16 (inlined std::mem::align_of::<u8>) { } scope 17 (inlined slice_from_raw_parts::<u8>) { debug data => _3; diff --git a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir index 30eafe8594b..2eee8a97db0 100644 --- a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir @@ -39,7 +39,7 @@ fn vec_deref_to_slice(_1: &Vec<u8>) -> &[u8] { } scope 15 (inlined std::mem::size_of::<u8>) { } - scope 16 (inlined align_of::<u8>) { + scope 16 (inlined std::mem::align_of::<u8>) { } scope 17 (inlined slice_from_raw_parts::<u8>) { debug data => _3; diff --git a/tests/pretty/postfix-match/precedence.pp b/tests/pretty/postfix-match/precedence.pp index 967aa7bc39e..2052b445a2b 100644 --- a/tests/pretty/postfix-match/precedence.pp +++ b/tests/pretty/postfix-match/precedence.pp @@ -26,7 +26,7 @@ pub fn main() { _ => {} }; (4 as usize).match { _ => {} }; - (return).match { _ => {} }; + return.match { _ => {} }; (a = 42).match { _ => {} }; (|| {}).match { _ => {} }; (42..101).match { _ => {} }; diff --git a/tests/run-make/cpp-global-destructors/rmake.rs b/tests/run-make/cpp-global-destructors/rmake.rs index 9bc5c84e10d..92aeb67c278 100644 --- a/tests/run-make/cpp-global-destructors/rmake.rs +++ b/tests/run-make/cpp-global-destructors/rmake.rs @@ -6,15 +6,11 @@ //@ ignore-cross-compile // Reason: the compiled binary is executed -//@ ignore-none -// Reason: no-std is not supported. //@ ignore-wasm32 //@ ignore-wasm64 // Reason: compiling C++ to WASM may cause problems. -// Neither of these are tested in full CI. -//@ ignore-nvptx64-nvidia-cuda -// Reason: can't find crate "std" +// Not exercised in full CI, but sgx technically supports std. //@ ignore-sgx use run_make_support::{build_native_static_lib_cxx, run, rustc}; diff --git a/tests/run-make/export-executable-symbols/rmake.rs b/tests/run-make/export-executable-symbols/rmake.rs index 77f968189b6..dc8c59b9c74 100644 --- a/tests/run-make/export-executable-symbols/rmake.rs +++ b/tests/run-make/export-executable-symbols/rmake.rs @@ -10,8 +10,7 @@ // (See #85673) //@ ignore-wasm32 //@ ignore-wasm64 -//@ ignore-none -// Reason: no-std is not supported +//@ needs-target-std use run_make_support::{bin_name, llvm_readobj, rustc}; diff --git a/tests/run-make/incr-foreign-head-span/rmake.rs b/tests/run-make/incr-foreign-head-span/rmake.rs index 92e2ed5f879..d9841b31464 100644 --- a/tests/run-make/incr-foreign-head-span/rmake.rs +++ b/tests/run-make/incr-foreign-head-span/rmake.rs @@ -5,10 +5,7 @@ // source file from disk during compilation of a downstream crate. // See https://github.com/rust-lang/rust/issues/86480 -//@ ignore-none -// Reason: no-std is not supported -//@ ignore-nvptx64-nvidia-cuda -// Reason: can't find crate for 'std' +//@ needs-target-std use run_make_support::{rfs, rust_lib_name, rustc}; diff --git a/tests/run-make/incr-prev-body-beyond-eof/rmake.rs b/tests/run-make/incr-prev-body-beyond-eof/rmake.rs index 47dce85248a..cfa8d5b46cd 100644 --- a/tests/run-make/incr-prev-body-beyond-eof/rmake.rs +++ b/tests/run-make/incr-prev-body-beyond-eof/rmake.rs @@ -7,11 +7,7 @@ // was hashed by rustc in addition to the span length, and the fix still // works. -//@ ignore-none -// reason: no-std is not supported - -//@ ignore-nvptx64-nvidia-cuda -// FIXME: can't find crate for `std` +//@ needs-target-std use run_make_support::{rfs, rustc}; diff --git a/tests/run-make/incr-test-moved-file/rmake.rs b/tests/run-make/incr-test-moved-file/rmake.rs index 0ba1b0d58fe..dfba95d3fed 100644 --- a/tests/run-make/incr-test-moved-file/rmake.rs +++ b/tests/run-make/incr-test-moved-file/rmake.rs @@ -9,10 +9,7 @@ // for successful compilation. // See https://github.com/rust-lang/rust/issues/83112 -//@ ignore-none -// Reason: no-std is not supported -//@ ignore-nvptx64-nvidia-cuda -// FIXME: can't find crate for 'std' +//@ needs-target-std use run_make_support::{rfs, rustc}; diff --git a/tests/run-make/moved-src-dir-fingerprint-ice/rmake.rs b/tests/run-make/moved-src-dir-fingerprint-ice/rmake.rs index f63146e692a..0d96b40e8a4 100644 --- a/tests/run-make/moved-src-dir-fingerprint-ice/rmake.rs +++ b/tests/run-make/moved-src-dir-fingerprint-ice/rmake.rs @@ -12,10 +12,7 @@ // sessions. // See https://github.com/rust-lang/rust/issues/85019 -//@ ignore-none -// Reason: no-std is not supported -//@ ignore-nvptx64-nvidia-cuda -// FIXME: can't find crate for 'std' +//@ needs-target-std use run_make_support::{rfs, rust_lib_name, rustc}; diff --git a/tests/rustdoc-json/fn_pointer/abi.rs b/tests/rustdoc-json/fn_pointer/abi.rs index 34150c0fe89..ec76e0f6636 100644 --- a/tests/rustdoc-json/fn_pointer/abi.rs +++ b/tests/rustdoc-json/fn_pointer/abi.rs @@ -1,4 +1,4 @@ -#![feature(abi_vectorcall)] +#![feature(rust_cold_cc)] //@ is "$.index[?(@.name=='AbiRust')].inner.type_alias.type.function_pointer.header.abi" \"Rust\" pub type AbiRust = fn(); @@ -15,8 +15,5 @@ pub type AbiCUnwind = extern "C-unwind" fn(); //@ is "$.index[?(@.name=='AbiSystemUnwind')].inner.type_alias.type.function_pointer.header.abi" '{"System": {"unwind": true}}' pub type AbiSystemUnwind = extern "system-unwind" fn(); -//@ is "$.index[?(@.name=='AbiVecorcall')].inner.type_alias.type.function_pointer.header.abi.Other" '"\"vectorcall\""' -pub type AbiVecorcall = extern "vectorcall" fn(); - -//@ is "$.index[?(@.name=='AbiVecorcallUnwind')].inner.type_alias.type.function_pointer.header.abi.Other" '"\"vectorcall-unwind\""' -pub type AbiVecorcallUnwind = extern "vectorcall-unwind" fn(); +//@ is "$.index[?(@.name=='AbiRustCold')].inner.type_alias.type.function_pointer.header.abi.Other" '"\"rust-cold\""' +pub type AbiRustCold = extern "rust-cold" fn(); diff --git a/tests/rustdoc-json/fns/abi.rs b/tests/rustdoc-json/fns/abi.rs index 7277bb1f59a..3373d135c89 100644 --- a/tests/rustdoc-json/fns/abi.rs +++ b/tests/rustdoc-json/fns/abi.rs @@ -1,4 +1,4 @@ -#![feature(abi_vectorcall)] +#![feature(rust_cold_cc)] //@ is "$.index[?(@.name=='abi_rust')].inner.function.header.abi" \"Rust\" pub fn abi_rust() {} @@ -15,8 +15,5 @@ pub extern "C-unwind" fn abi_c_unwind() {} //@ is "$.index[?(@.name=='abi_system_unwind')].inner.function.header.abi" '{"System": {"unwind": true}}' pub extern "system-unwind" fn abi_system_unwind() {} -//@ is "$.index[?(@.name=='abi_vectorcall')].inner.function.header.abi.Other" '"\"vectorcall\""' -pub extern "vectorcall" fn abi_vectorcall() {} - -//@ is "$.index[?(@.name=='abi_vectorcall_unwind')].inner.function.header.abi.Other" '"\"vectorcall-unwind\""' -pub extern "vectorcall-unwind" fn abi_vectorcall_unwind() {} +//@ is "$.index[?(@.name=='abi_rust_cold')].inner.function.header.abi.Other" '"\"rust-cold\""' +pub extern "rust-cold" fn abi_rust_cold() {} diff --git a/tests/rustdoc-json/methods/abi.rs b/tests/rustdoc-json/methods/abi.rs index fa2387ddf67..be6a11784f5 100644 --- a/tests/rustdoc-json/methods/abi.rs +++ b/tests/rustdoc-json/methods/abi.rs @@ -1,5 +1,4 @@ -#![feature(abi_vectorcall)] - +#![feature(rust_cold_cc)] //@ has "$.index[?(@.name=='Foo')]" pub struct Foo; @@ -19,11 +18,8 @@ impl Foo { //@ is "$.index[?(@.name=='abi_system_unwind')].inner.function.header.abi" '{"System": {"unwind": true}}' pub extern "system-unwind" fn abi_system_unwind() {} - //@ is "$.index[?(@.name=='abi_vectorcall')].inner.function.header.abi.Other" '"\"vectorcall\""' - pub extern "vectorcall" fn abi_vectorcall() {} - - //@ is "$.index[?(@.name=='abi_vectorcall_unwind')].inner.function.header.abi.Other" '"\"vectorcall-unwind\""' - pub extern "vectorcall-unwind" fn abi_vectorcall_unwind() {} + //@ is "$.index[?(@.name=='abi_rust_cold')].inner.function.header.abi.Other" '"\"rust-cold\""' + pub extern "rust-cold" fn abi_rust_cold() {} } pub trait Bar { @@ -42,9 +38,6 @@ pub trait Bar { //@ is "$.index[?(@.name=='trait_abi_system_unwind')].inner.function.header.abi" '{"System": {"unwind": true}}' extern "system-unwind" fn trait_abi_system_unwind() {} - //@ is "$.index[?(@.name=='trait_abi_vectorcall')].inner.function.header.abi.Other" '"\"vectorcall\""' - extern "vectorcall" fn trait_abi_vectorcall() {} - - //@ is "$.index[?(@.name=='trait_abi_vectorcall_unwind')].inner.function.header.abi.Other" '"\"vectorcall-unwind\""' - extern "vectorcall-unwind" fn trait_abi_vectorcall_unwind() {} + //@ is "$.index[?(@.name=='trait_abi_rust_cold')].inner.function.header.abi.Other" '"\"rust-cold\""' + extern "rust-cold" fn trait_abi_rust_cold() {} } diff --git a/tests/rustdoc-json/vectorcall.rs b/tests/rustdoc-json/vectorcall.rs new file mode 100644 index 00000000000..19cac244f42 --- /dev/null +++ b/tests/rustdoc-json/vectorcall.rs @@ -0,0 +1,27 @@ +#![feature(abi_vectorcall)] +//@ only-x86_64 + +//@ is "$.index[?(@.name=='AbiVectorcall')].inner.type_alias.type.function_pointer.header.abi.Other" '"\"vectorcall\""' +pub type AbiVectorcall = extern "vectorcall" fn(); + +//@ is "$.index[?(@.name=='AbiVectorcallUnwind')].inner.type_alias.type.function_pointer.header.abi.Other" '"\"vectorcall-unwind\""' +pub type AbiVectorcallUnwind = extern "vectorcall-unwind" fn(); + +//@ has "$.index[?(@.name=='Foo')]" +pub struct Foo; + +impl Foo { + //@ is "$.index[?(@.name=='abi_vectorcall')].inner.function.header.abi.Other" '"\"vectorcall\""' + pub extern "vectorcall" fn abi_vectorcall() {} + + //@ is "$.index[?(@.name=='abi_vectorcall_unwind')].inner.function.header.abi.Other" '"\"vectorcall-unwind\""' + pub extern "vectorcall-unwind" fn abi_vectorcall_unwind() {} +} + +pub trait Bar { + //@ is "$.index[?(@.name=='trait_abi_vectorcall')].inner.function.header.abi.Other" '"\"vectorcall\""' + extern "vectorcall" fn trait_abi_vectorcall() {} + + //@ is "$.index[?(@.name=='trait_abi_vectorcall_unwind')].inner.function.header.abi.Other" '"\"vectorcall-unwind\""' + extern "vectorcall-unwind" fn trait_abi_vectorcall_unwind() {} +} diff --git a/tests/rustdoc/cfg-bool.rs b/tests/rustdoc/cfg-bool.rs index 34fdfbe930e..0aaa132e0b5 100644 --- a/tests/rustdoc/cfg-bool.rs +++ b/tests/rustdoc/cfg-bool.rs @@ -3,11 +3,15 @@ // regression test for https://github.com/rust-lang/rust/issues/138112 -//@ has 'foo/fn.foo.html' '//div[@class="stab portability"]' 'Available nowhere' +//@ has 'foo/index.html' +//@ has - '//*[@class="stab portability"]/@title' 'Available nowhere' + +//@ count 'foo/fn.foo.html' '//*[@class="stab portability"]' 1 +//@ has 'foo/fn.foo.html' '//*[@class="stab portability"]' 'Available nowhere' #[doc(cfg(false))] pub fn foo() {} -// a cfg(true) will simply be ommited, as it is the same as no cfg. -//@ !has 'foo/fn.bar.html' '//div[@class="stab portability"]' '' +// a cfg(true) will simply be omitted, as it is the same as no cfg. +//@ count 'foo/fn.bar.html' '//*[@class="stab portability"]' 0 #[doc(cfg(true))] pub fn bar() {} diff --git a/tests/rustdoc/macro/macro-generated-macro.macro_morestuff_pre.html b/tests/rustdoc/macro/macro-generated-macro.macro_morestuff_pre.html index 28f15522a82..4dcc8111c6f 100644 --- a/tests/rustdoc/macro/macro-generated-macro.macro_morestuff_pre.html +++ b/tests/rustdoc/macro/macro-generated-macro.macro_morestuff_pre.html @@ -1,7 +1,7 @@ macro_rules! morestuff { ( - <= "space between most kinds of tokens" : 1 $x + @ :: >>= 'static - "no space inside paren or bracket" : (2 a) [2 a] $(2 $a:tt)* + <= "space between most kinds of tokens" : 1 $x:ident + @ :: >>= + 'static "no space inside paren or bracket" : (2 a) [2 a] $(2 $a:tt)* "space inside curly brace" : { 2 a } "no space inside empty delimiters" : () [] {} "no space before comma or semicolon" : a, (a), { a }, a; [T; 0]; diff --git a/tests/rustdoc/macro/macro-generated-macro.rs b/tests/rustdoc/macro/macro-generated-macro.rs index e77d0cf89e7..dfb152bafb6 100644 --- a/tests/rustdoc/macro/macro-generated-macro.rs +++ b/tests/rustdoc/macro/macro-generated-macro.rs @@ -25,7 +25,7 @@ make_macro!(linebreak 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 //@ snapshot macro_morestuff_pre macro_generated_macro/macro.morestuff.html //pre/text() make_macro!(morestuff - "space between most kinds of tokens": 1 $x + @ :: >>= 'static + "space between most kinds of tokens": 1 $x:ident + @ :: >>= 'static "no space inside paren or bracket": (2 a) [2 a] $(2 $a:tt)* "space inside curly brace": { 2 a } "no space inside empty delimiters": () [] {} diff --git a/tests/ui-fulldeps/pprust-parenthesis-insertion.rs b/tests/ui-fulldeps/pprust-parenthesis-insertion.rs index c566ac459e0..36916e97856 100644 --- a/tests/ui-fulldeps/pprust-parenthesis-insertion.rs +++ b/tests/ui-fulldeps/pprust-parenthesis-insertion.rs @@ -63,8 +63,8 @@ static EXPRS: &[&str] = &[ "(2 += 2) += 2", // Return has lower precedence than a binary operator. "(return 2) + 2", - "2 + (return 2)", // FIXME: no parenthesis needed. - "(return) + 2", // FIXME: no parenthesis needed. + "2 + return 2", + "return + 2", // These mean different things. "return - 2", "(return) - 2", diff --git a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr index 03fca17aa55..001699b2bc7 100644 --- a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr +++ b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr @@ -583,18 +583,32 @@ error: cannot find attribute `multipart_suggestion` in this scope | LL | #[multipart_suggestion(no_crate_suggestion)] | ^^^^^^^^^^^^^^^^^^^^ + | +help: `multipart_suggestion` is an attribute that can be used by the derive macro `Subdiagnostic`, you might be missing a `derive` attribute + | +LL + #[derive(Subdiagnostic)] +LL | struct MultipartSuggestion { + | error: cannot find attribute `multipart_suggestion` in this scope --> $DIR/diagnostic-derive.rs:647:3 | LL | #[multipart_suggestion()] | ^^^^^^^^^^^^^^^^^^^^ + | +help: `multipart_suggestion` is an attribute that can be used by the derive macro `Subdiagnostic`, you might be missing a `derive` attribute + | +LL + #[derive(Subdiagnostic)] +LL | struct MultipartSuggestion { + | error: cannot find attribute `multipart_suggestion` in this scope --> $DIR/diagnostic-derive.rs:651:7 | LL | #[multipart_suggestion(no_crate_suggestion)] | ^^^^^^^^^^^^^^^^^^^^ + | + = note: `multipart_suggestion` is an attribute that can be used by the derive macro `Subdiagnostic`, you might be missing a `derive` attribute error[E0425]: cannot find value `nonsense` in module `crate::fluent_generated` --> $DIR/diagnostic-derive.rs:75:8 diff --git a/tests/ui-fulldeps/stable-mir/check_abi.rs b/tests/ui-fulldeps/stable-mir/check_abi.rs index 71edf813a7b..15ef583709b 100644 --- a/tests/ui-fulldeps/stable-mir/check_abi.rs +++ b/tests/ui-fulldeps/stable-mir/check_abi.rs @@ -21,10 +21,13 @@ use stable_mir::abi::{ ArgAbi, CallConvention, FieldsShape, IntegerLength, PassMode, Primitive, Scalar, ValueAbi, VariantsShape, }; +use stable_mir::mir::MirVisitor; use stable_mir::mir::mono::Instance; use stable_mir::target::MachineInfo; +use stable_mir::ty::{AdtDef, RigidTy, Ty, TyKind}; use stable_mir::{CrateDef, CrateItem, CrateItems, ItemKind}; use std::assert_matches::assert_matches; +use std::collections::HashSet; use std::convert::TryFrom; use std::io::Write; use std::ops::ControlFlow; @@ -67,6 +70,17 @@ fn test_stable_mir() -> ControlFlow<()> { assert!(ptr_variadic_fn_abi.c_variadic); assert_eq!(ptr_variadic_fn_abi.args.len(), 1); + let entry = stable_mir::entry_fn().unwrap(); + let main_fn = Instance::try_from(entry).unwrap(); + let mut visitor = AdtDefVisitor::default(); + visitor.visit_body(&main_fn.body().unwrap()); + let AdtDefVisitor { adt_defs } = visitor; + assert_eq!(adt_defs.len(), 1); + + // Test ADT representation options + let repr_c_struct = adt_defs.iter().find(|def| def.trimmed_name() == "ReprCStruct").unwrap(); + assert!(repr_c_struct.repr().flags.is_c); + ControlFlow::Continue(()) } @@ -138,6 +152,20 @@ fn get_item<'a>( items.iter().find(|crate_item| (item.0 == crate_item.kind()) && crate_item.name() == item.1) } +#[derive(Default)] +struct AdtDefVisitor { + adt_defs: HashSet<AdtDef>, +} + +impl MirVisitor for AdtDefVisitor { + fn visit_ty(&mut self, ty: &Ty, _location: stable_mir::mir::visit::Location) { + if let TyKind::RigidTy(RigidTy::Adt(adt, _)) = ty.kind() { + self.adt_defs.insert(adt); + } + self.super_ty(ty) + } +} + /// This test will generate and analyze a dummy crate using the stable mir. /// For that, it will first write the dummy crate into a file. /// Then it will create a `StableMir` using custom arguments and then @@ -147,7 +175,7 @@ fn main() { generate_input(&path).unwrap(); let args = &[ "rustc".to_string(), - "--crate-type=lib".to_string(), + "-Cpanic=abort".to_string(), "--crate-name".to_string(), CRATE_NAME.to_string(), path.to_string(), @@ -185,6 +213,13 @@ fn generate_input(path: &str) -> std::io::Result<()> { // We only care about the signature. todo!() }} + + fn main() {{ + #[repr(C)] + struct ReprCStruct; + + let _s = ReprCStruct; + }} "# )?; Ok(()) diff --git a/tests/ui-fulldeps/stable-mir/closure-generic-body.rs b/tests/ui-fulldeps/stable-mir/closure-generic-body.rs new file mode 100644 index 00000000000..2a23345a9d3 --- /dev/null +++ b/tests/ui-fulldeps/stable-mir/closure-generic-body.rs @@ -0,0 +1,90 @@ +//@ run-pass +//! Tests stable mir API for retrieving the body of a closure. + +//@ ignore-stage1 +//@ ignore-cross-compile +//@ ignore-remote +//@ edition: 2021 + +#![feature(rustc_private)] +#![feature(assert_matches)] + +extern crate rustc_middle; +#[macro_use] +extern crate rustc_smir; +extern crate rustc_driver; +extern crate rustc_interface; +extern crate stable_mir; + +use std::io::Write; +use std::ops::ControlFlow; + +use stable_mir::mir::{Body, ConstOperand, Operand, TerminatorKind}; +use stable_mir::ty::{FnDef, RigidTy, TyKind}; + +const CRATE_NAME: &str = "crate_closure_body"; + +fn test_closure_body() -> ControlFlow<()> { + let crate_items = stable_mir::all_local_items(); + for item in crate_items { + let item_ty = item.ty(); + match &item_ty.kind() { + TyKind::RigidTy(RigidTy::Closure(closure_def, _)) => { + let closure_body = closure_def.body().unwrap(); + check_incr_closure_body(closure_body); + } + _ => {} + } + } + + ControlFlow::Continue(()) +} + +fn check_incr_closure_body(body: Body) { + let first_block = &body.blocks[0]; + let TerminatorKind::Call { func: Operand::Constant(ConstOperand { const_, .. }), .. } = + &first_block.terminator.kind + else { + panic!("expected Call Terminator, got: "); + }; + + let TyKind::RigidTy(RigidTy::FnDef(FnDef(def_id), ..), ..) = const_.ty().kind() else { + panic!("expected FnDef"); + }; + + assert_eq!(def_id.name(), "id"); +} + +fn main() { + let path = "closure_body.rs"; + generate_input(&path).unwrap(); + let args = &[ + "rustc".to_string(), + "-Cpanic=abort".to_string(), + "--crate-name".to_string(), + CRATE_NAME.to_string(), + path.to_string(), + ]; + run!(args, test_closure_body).unwrap(); +} + +fn generate_input(path: &str) -> std::io::Result<()> { + let mut file = std::fs::File::create(path)?; + write!( + file, + r#" + fn id<T>(y: T) -> T {{ + y + }} + + fn main() {{ + let cl_id= |x| {{ + id(x) + }}; + + let _= cl_id(5); + }} + "# + )?; + Ok(()) +} diff --git a/tests/ui-fulldeps/stable-mir/closure_body.rs b/tests/ui-fulldeps/stable-mir/closure_body.rs new file mode 100644 index 00000000000..7ed0dabd2c3 --- /dev/null +++ b/tests/ui-fulldeps/stable-mir/closure_body.rs @@ -0,0 +1,90 @@ +//@ run-pass +//! Tests stable mir API for retrieving the body of a closure. + +//@ ignore-stage1 +//@ ignore-cross-compile +//@ ignore-remote +//@ edition: 2021 + +#![feature(rustc_private)] +#![feature(assert_matches)] + +extern crate rustc_middle; +#[macro_use] +extern crate rustc_smir; +extern crate rustc_driver; +extern crate rustc_interface; +extern crate stable_mir; + +use std::io::Write; +use std::ops::ControlFlow; + +use stable_mir::mir::{Body, ConstOperand, Operand, TerminatorKind}; +use stable_mir::ty::{FnDef, RigidTy, TyKind}; + +const CRATE_NAME: &str = "crate_closure_body"; + +fn test_closure_body() -> ControlFlow<()> { + let crate_items = stable_mir::all_local_items(); + for item in crate_items { + let item_ty = item.ty(); + match &item_ty.kind() { + TyKind::RigidTy(RigidTy::Closure(closure_def, _)) => { + let closure_body = closure_def.body().unwrap(); + check_incr_closure_body(closure_body); + } + _ => {} + } + } + + ControlFlow::Continue(()) +} + +fn check_incr_closure_body(body: Body) { + let first_block = &body.blocks[0]; + let TerminatorKind::Call { func: Operand::Constant(ConstOperand { const_, .. }), .. } = + &first_block.terminator.kind + else { + panic!("expected Call Terminator, got: "); + }; + + let TyKind::RigidTy(RigidTy::FnDef(FnDef(def_id), ..), ..) = const_.ty().kind() else { + panic!("expected FnDef"); + }; + + assert_eq!(def_id.name(), "incr"); +} + +fn main() { + let path = "closure_body.rs"; + generate_input(&path).unwrap(); + let args = &[ + "rustc".to_string(), + "-Cpanic=abort".to_string(), + "--crate-name".to_string(), + CRATE_NAME.to_string(), + path.to_string(), + ]; + run!(args, test_closure_body).unwrap(); +} + +fn generate_input(path: &str) -> std::io::Result<()> { + let mut file = std::fs::File::create(path)?; + write!( + file, + r#" + fn incr(y: i32) -> i32 {{ + y + 1 + }} + + fn main() {{ + let cl_incr = |x: i32| {{ + incr(x) + }}; + + let _= cl_incr(5); + }} + "# + )?; + Ok(()) +} diff --git a/tests/ui/abi/bad-custom.rs b/tests/ui/abi/bad-custom.rs new file mode 100644 index 00000000000..e792f0955b9 --- /dev/null +++ b/tests/ui/abi/bad-custom.rs @@ -0,0 +1,121 @@ +//@ edition: 2021 +//@ check-fail +//@ needs-asm-support +#![feature(abi_custom)] + +#[unsafe(naked)] +extern "custom" fn must_be_unsafe(a: i64) -> i64 { + //~^ ERROR functions with the `"custom"` ABI must be unsafe + //~| ERROR invalid signature for `extern "custom"` function + std::arch::naked_asm!("") +} + +#[unsafe(naked)] +unsafe extern "custom" fn no_parameters(a: i64) { + //~^ ERROR invalid signature for `extern "custom"` function + std::arch::naked_asm!("") +} + +#[unsafe(naked)] +unsafe extern "custom" fn no_return_type() -> i64 { + //~^ ERROR invalid signature for `extern "custom"` function + std::arch::naked_asm!("") +} + +unsafe extern "custom" fn double(a: i64) -> i64 { + //~^ ERROR items with the `"custom"` ABI can only be declared externally or defined via naked functions + //~| ERROR invalid signature for `extern "custom"` function + unimplemented!() +} + +struct Thing(i64); + +impl Thing { + unsafe extern "custom" fn is_even(self) -> bool { + //~^ ERROR items with the `"custom"` ABI can only be declared externally or defined via naked functions + //~| ERROR invalid signature for `extern "custom"` function + unimplemented!() + } +} + +trait BitwiseNot { + unsafe extern "custom" fn bitwise_not(a: i64) -> i64 { + //~^ ERROR items with the `"custom"` ABI can only be declared externally or defined via naked functions + //~| ERROR invalid signature for `extern "custom"` function + unimplemented!() + } +} + +impl BitwiseNot for Thing {} + +trait Negate { + extern "custom" fn negate(a: i64) -> i64; + //~^ ERROR functions with the `"custom"` ABI must be unsafe + //~| ERROR invalid signature for `extern "custom"` function +} + +impl Negate for Thing { + extern "custom" fn negate(a: i64) -> i64 { + //~^ ERROR items with the `"custom"` ABI can only be declared externally or defined via naked functions + //~| ERROR functions with the `"custom"` ABI must be unsafe + //~| ERROR invalid signature for `extern "custom"` function + -a + } +} + +unsafe extern "custom" { + fn increment(a: i64) -> i64; + //~^ ERROR invalid signature for `extern "custom"` function + + safe fn extern_cannot_be_safe(); + //~^ ERROR foreign functions with the `"custom"` ABI cannot be safe +} + +fn caller(f: unsafe extern "custom" fn(i64) -> i64, mut x: i64) -> i64 { + unsafe { f(x) } + //~^ ERROR functions with the `"custom"` ABI cannot be called +} + +fn caller_by_ref(f: &unsafe extern "custom" fn(i64) -> i64, mut x: i64) -> i64 { + unsafe { f(x) } + //~^ ERROR functions with the `"custom"` ABI cannot be called +} + +type Custom = unsafe extern "custom" fn(i64) -> i64; + +fn caller_alias(f: Custom, mut x: i64) -> i64 { + unsafe { f(x) } + //~^ ERROR functions with the `"custom"` ABI cannot be called +} + +#[unsafe(naked)] +const unsafe extern "custom" fn no_const_fn() { + std::arch::naked_asm!("") + //~^ ERROR inline assembly is not allowed in constant functions +} + +async unsafe extern "custom" fn no_async_fn() { + //~^ ERROR items with the `"custom"` ABI can only be declared externally or defined via naked functions + //~| ERROR functions with the `"custom"` ABI cannot be `async` +} + +fn no_promotion_to_fn_trait(f: unsafe extern "custom" fn()) -> impl Fn() { + //~^ ERROR expected a `Fn()` closure, found `unsafe extern "custom" fn()` + f +} + +pub fn main() { + unsafe { + assert_eq!(double(21), 42); + //~^ ERROR functions with the `"custom"` ABI cannot be called + + assert_eq!(unsafe { increment(41) }, 42); + //~^ ERROR functions with the `"custom"` ABI cannot be called + + assert!(Thing(41).is_even()); + //~^ ERROR functions with the `"custom"` ABI cannot be called + + assert_eq!(Thing::bitwise_not(42), !42); + //~^ ERROR functions with the `"custom"` ABI cannot be called + } +} diff --git a/tests/ui/abi/bad-custom.stderr b/tests/ui/abi/bad-custom.stderr new file mode 100644 index 00000000000..ec0f11af898 --- /dev/null +++ b/tests/ui/abi/bad-custom.stderr @@ -0,0 +1,299 @@ +error: functions with the `"custom"` ABI must be unsafe + --> $DIR/bad-custom.rs:7:1 + | +LL | extern "custom" fn must_be_unsafe(a: i64) -> i64 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: add the `unsafe` keyword to this definition + | +LL | unsafe extern "custom" fn must_be_unsafe(a: i64) -> i64 { + | ++++++ + +error: invalid signature for `extern "custom"` function + --> $DIR/bad-custom.rs:7:35 + | +LL | extern "custom" fn must_be_unsafe(a: i64) -> i64 { + | ^^^^^^ ^^^ + | + = note: functions with the `"custom"` ABI cannot have any parameters or return type +help: remove the parameters and return type + | +LL - extern "custom" fn must_be_unsafe(a: i64) -> i64 { +LL + extern "custom" fn must_be_unsafe() { + | + +error: invalid signature for `extern "custom"` function + --> $DIR/bad-custom.rs:14:41 + | +LL | unsafe extern "custom" fn no_parameters(a: i64) { + | ^^^^^^ + | + = note: functions with the `"custom"` ABI cannot have any parameters or return type +help: remove the parameters and return type + | +LL - unsafe extern "custom" fn no_parameters(a: i64) { +LL + unsafe extern "custom" fn no_parameters() { + | + +error: invalid signature for `extern "custom"` function + --> $DIR/bad-custom.rs:20:47 + | +LL | unsafe extern "custom" fn no_return_type() -> i64 { + | ^^^ + | + = note: functions with the `"custom"` ABI cannot have any parameters or return type +help: remove the parameters and return type + | +LL - unsafe extern "custom" fn no_return_type() -> i64 { +LL + unsafe extern "custom" fn no_return_type() { + | + +error: invalid signature for `extern "custom"` function + --> $DIR/bad-custom.rs:25:34 + | +LL | unsafe extern "custom" fn double(a: i64) -> i64 { + | ^^^^^^ ^^^ + | + = note: functions with the `"custom"` ABI cannot have any parameters or return type +help: remove the parameters and return type + | +LL - unsafe extern "custom" fn double(a: i64) -> i64 { +LL + unsafe extern "custom" fn double() { + | + +error: invalid signature for `extern "custom"` function + --> $DIR/bad-custom.rs:34:39 + | +LL | unsafe extern "custom" fn is_even(self) -> bool { + | ^^^^ ^^^^ + | + = note: functions with the `"custom"` ABI cannot have any parameters or return type +help: remove the parameters and return type + | +LL - unsafe extern "custom" fn is_even(self) -> bool { +LL + unsafe extern "custom" fn is_even() { + | + +error: invalid signature for `extern "custom"` function + --> $DIR/bad-custom.rs:42:43 + | +LL | unsafe extern "custom" fn bitwise_not(a: i64) -> i64 { + | ^^^^^^ ^^^ + | + = note: functions with the `"custom"` ABI cannot have any parameters or return type +help: remove the parameters and return type + | +LL - unsafe extern "custom" fn bitwise_not(a: i64) -> i64 { +LL + unsafe extern "custom" fn bitwise_not() { + | + +error: functions with the `"custom"` ABI must be unsafe + --> $DIR/bad-custom.rs:52:5 + | +LL | extern "custom" fn negate(a: i64) -> i64; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: add the `unsafe` keyword to this definition + | +LL | unsafe extern "custom" fn negate(a: i64) -> i64; + | ++++++ + +error: invalid signature for `extern "custom"` function + --> $DIR/bad-custom.rs:52:31 + | +LL | extern "custom" fn negate(a: i64) -> i64; + | ^^^^^^ ^^^ + | + = note: functions with the `"custom"` ABI cannot have any parameters or return type +help: remove the parameters and return type + | +LL - extern "custom" fn negate(a: i64) -> i64; +LL + extern "custom" fn negate(); + | + +error: functions with the `"custom"` ABI must be unsafe + --> $DIR/bad-custom.rs:58:5 + | +LL | extern "custom" fn negate(a: i64) -> i64 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: add the `unsafe` keyword to this definition + | +LL | unsafe extern "custom" fn negate(a: i64) -> i64 { + | ++++++ + +error: invalid signature for `extern "custom"` function + --> $DIR/bad-custom.rs:58:31 + | +LL | extern "custom" fn negate(a: i64) -> i64 { + | ^^^^^^ ^^^ + | + = note: functions with the `"custom"` ABI cannot have any parameters or return type +help: remove the parameters and return type + | +LL - extern "custom" fn negate(a: i64) -> i64 { +LL + extern "custom" fn negate() { + | + +error: invalid signature for `extern "custom"` function + --> $DIR/bad-custom.rs:67:18 + | +LL | fn increment(a: i64) -> i64; + | ^^^^^^ ^^^ + | + = note: functions with the `"custom"` ABI cannot have any parameters or return type +help: remove the parameters and return type + | +LL - fn increment(a: i64) -> i64; +LL + fn increment(); + | + +error: foreign functions with the `"custom"` ABI cannot be safe + --> $DIR/bad-custom.rs:70:5 + | +LL | safe fn extern_cannot_be_safe(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `safe` keyword from this definition + | +LL - safe fn extern_cannot_be_safe(); +LL + fn extern_cannot_be_safe(); + | + +error: functions with the `"custom"` ABI cannot be `async` + --> $DIR/bad-custom.rs:97:1 + | +LL | async unsafe extern "custom" fn no_async_fn() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: remove the `async` keyword from this definiton + | +LL - async unsafe extern "custom" fn no_async_fn() { +LL + unsafe extern "custom" fn no_async_fn() { + | + +error: items with the `"custom"` ABI can only be declared externally or defined via naked functions + --> $DIR/bad-custom.rs:97:1 + | +LL | async unsafe extern "custom" fn no_async_fn() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: convert this to an `#[unsafe(naked)]` function + | +LL + #[unsafe(naked)] +LL | async unsafe extern "custom" fn no_async_fn() { + | + +error[E0277]: expected a `Fn()` closure, found `unsafe extern "custom" fn()` + --> $DIR/bad-custom.rs:102:64 + | +LL | fn no_promotion_to_fn_trait(f: unsafe extern "custom" fn()) -> impl Fn() { + | ^^^^^^^^^ call the function in a closure: `|| unsafe { /* code */ }` +LL | +LL | f + | - return type was inferred to be `unsafe extern "custom" fn()` here + | + = help: the trait `Fn()` is not implemented for `unsafe extern "custom" fn()` + = note: unsafe function cannot be called generically without an unsafe block + = note: wrap the `unsafe extern "custom" fn()` in a closure with no arguments: `|| { /* code */ }` + +error: items with the `"custom"` ABI can only be declared externally or defined via naked functions + --> $DIR/bad-custom.rs:25:1 + | +LL | unsafe extern "custom" fn double(a: i64) -> i64 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: convert this to an `#[unsafe(naked)]` function + | +LL + #[unsafe(naked)] +LL | unsafe extern "custom" fn double(a: i64) -> i64 { + | + +error: items with the `"custom"` ABI can only be declared externally or defined via naked functions + --> $DIR/bad-custom.rs:34:5 + | +LL | unsafe extern "custom" fn is_even(self) -> bool { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: convert this to an `#[unsafe(naked)]` function + | +LL + #[unsafe(naked)] +LL | unsafe extern "custom" fn is_even(self) -> bool { + | + +error: items with the `"custom"` ABI can only be declared externally or defined via naked functions + --> $DIR/bad-custom.rs:42:5 + | +LL | unsafe extern "custom" fn bitwise_not(a: i64) -> i64 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: convert this to an `#[unsafe(naked)]` function + | +LL + #[unsafe(naked)] +LL | unsafe extern "custom" fn bitwise_not(a: i64) -> i64 { + | + +error: items with the `"custom"` ABI can only be declared externally or defined via naked functions + --> $DIR/bad-custom.rs:58:5 + | +LL | extern "custom" fn negate(a: i64) -> i64 { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: convert this to an `#[unsafe(naked)]` function + | +LL + #[unsafe(naked)] +LL | extern "custom" fn negate(a: i64) -> i64 { + | + +error: functions with the `"custom"` ABI cannot be called + --> $DIR/bad-custom.rs:75:14 + | +LL | unsafe { f(x) } + | ^^^^ + +error: functions with the `"custom"` ABI cannot be called + --> $DIR/bad-custom.rs:80:14 + | +LL | unsafe { f(x) } + | ^^^^ + +error: functions with the `"custom"` ABI cannot be called + --> $DIR/bad-custom.rs:87:14 + | +LL | unsafe { f(x) } + | ^^^^ + +error: functions with the `"custom"` ABI cannot be called + --> $DIR/bad-custom.rs:109:20 + | +LL | assert_eq!(double(21), 42); + | ^^^^^^^^^^ + +error: functions with the `"custom"` ABI cannot be called + --> $DIR/bad-custom.rs:112:29 + | +LL | assert_eq!(unsafe { increment(41) }, 42); + | ^^^^^^^^^^^^^ + +error: functions with the `"custom"` ABI cannot be called + --> $DIR/bad-custom.rs:115:17 + | +LL | assert!(Thing(41).is_even()); + | ^^^^^^^^^^^^^^^^^^^ + +error: functions with the `"custom"` ABI cannot be called + --> $DIR/bad-custom.rs:118:20 + | +LL | assert_eq!(Thing::bitwise_not(42), !42); + | ^^^^^^^^^^^^^^^^^^^^^^ + +error[E0015]: inline assembly is not allowed in constant functions + --> $DIR/bad-custom.rs:93:5 + | +LL | std::arch::naked_asm!("") + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 28 previous errors + +Some errors have detailed explanations: E0015, E0277. +For more information about an error, try `rustc --explain E0015`. diff --git a/tests/ui/abi/custom.rs b/tests/ui/abi/custom.rs new file mode 100644 index 00000000000..0f6ff77f580 --- /dev/null +++ b/tests/ui/abi/custom.rs @@ -0,0 +1,88 @@ +// Test that `extern "custom"` functions can be called from assembly, and defined using a naked +// function, and `global_asm!` with an `extern "custom"` block. +// +//@ run-pass +//@ only-x86_64 +#![feature(abi_custom)] + +use std::arch::{asm, global_asm, naked_asm}; + +#[unsafe(naked)] +unsafe extern "custom" fn double() { + naked_asm!("add rax, rax", "ret"); +} + +global_asm!( + // work around macOS prefixing symbols with _ + " .globl {0}", + "{0}:", + " add rax, 1", + " ret", + sym increment, +); + +unsafe extern "custom" { + fn increment(); +} + +#[repr(transparent)] +struct Thing(u64); + +impl Thing { + #[unsafe(naked)] + unsafe extern "custom" fn is_even() { + naked_asm!("test al, 1", "sete al", "ret"); + } +} + +trait BitwiseNot { + #[unsafe(naked)] + unsafe extern "custom" fn bitwise_not() { + naked_asm!("not rax", "ret"); + } +} + +impl BitwiseNot for Thing {} + +#[unsafe(naked)] +unsafe extern "C" fn const_generic<const N: u64>() { + naked_asm!( + "mov rax, {}", + "ret", + const N, + ); +} + +pub fn main() { + let mut x: u64 = 21; + unsafe { asm!("call {}", sym double, inout("rax") x) }; + assert_eq!(x, 42); + + let mut x: u64 = 41; + unsafe { asm!("call {}", sym increment, inout("rax") x) }; + assert_eq!(x, 42); + + let mut x: u8; + unsafe { asm!("call {}", sym Thing::is_even, inout("al") 42u8 => x) }; + assert!(x != 0); + + let mut x: u64 = 42; + unsafe { asm!("call {}", sym Thing::bitwise_not, inout("rax") x) }; + assert_eq!(x, !42); + + // Create and call in `asm!` an `extern "custom"` function pointer. + fn caller(f: unsafe extern "custom" fn(), mut x: u64) -> u64 { + unsafe { asm!("call {}", in(reg) f, inout("rax") x) }; + x + } + + assert_eq!(caller(double, 2), 4); + + let x: u64; + unsafe { asm!("call {}", sym const_generic::<42>, out("rax") x) }; + assert_eq!(x, 42); + + let x: u64; + unsafe { asm!("call {}", sym const_generic::<84>, out("rax") x) }; + assert_eq!(x, 84); +} diff --git a/tests/ui/abi/unsupported.aarch64.stderr b/tests/ui/abi/unsupported.aarch64.stderr index ea645780b0d..4721c26026d 100644 --- a/tests/ui/abi/unsupported.aarch64.stderr +++ b/tests/ui/abi/unsupported.aarch64.stderr @@ -114,7 +114,7 @@ LL | fn stdcall_ptr(f: extern "stdcall" fn()) { = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> error[E0570]: `"stdcall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:117:1 + --> $DIR/unsupported.rs:119:1 | LL | extern "stdcall" {} | ^^^^^^^^^^^^^^^^^^^ @@ -122,24 +122,26 @@ LL | extern "stdcall" {} = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` error[E0570]: `"stdcall-unwind"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:121:1 + --> $DIR/unsupported.rs:123:1 | LL | extern "stdcall-unwind" {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: if you need `extern "stdcall-unwind"` on win32 and `extern "C-unwind"` everywhere else, use `extern "system-unwind"` -warning: the calling convention "cdecl" is not supported on this target - --> $DIR/unsupported.rs:129:17 +warning: use of calling convention not supported on this target + --> $DIR/unsupported.rs:131:17 | LL | fn cdecl_ptr(f: extern "cdecl" fn()) { | ^^^^^^^^^^^^^^^^^^^ | = 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 #130260 <https://github.com/rust-lang/rust/issues/130260> + = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018> + = help: use `extern "C"` instead + = note: `#[warn(unsupported_calling_conventions)]` on by default warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:134:1 + --> $DIR/unsupported.rs:136:1 | LL | extern "cdecl" {} | ^^^^^^^^^^^^^^^^^ @@ -147,10 +149,9 @@ LL | extern "cdecl" {} = 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 #137018 <https://github.com/rust-lang/rust/issues/137018> = help: use `extern "C"` instead - = note: `#[warn(unsupported_calling_conventions)]` on by default warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:137:1 + --> $DIR/unsupported.rs:139:1 | LL | extern "cdecl-unwind" {} | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -160,7 +161,7 @@ LL | extern "cdecl-unwind" {} = help: use `extern "C-unwind"` instead warning: the calling convention "vectorcall" is not supported on this target - --> $DIR/unsupported.rs:143:22 + --> $DIR/unsupported.rs:145:22 | LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -169,13 +170,13 @@ LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) { = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> error[E0570]: `"vectorcall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:148:1 + --> $DIR/unsupported.rs:150:1 | LL | extern "vectorcall" {} | ^^^^^^^^^^^^^^^^^^^^^^ warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target - --> $DIR/unsupported.rs:151:21 + --> $DIR/unsupported.rs:153:21 | LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -184,7 +185,7 @@ LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> warning: the calling convention "C-cmse-nonsecure-entry" is not supported on this target - --> $DIR/unsupported.rs:159:22 + --> $DIR/unsupported.rs:161:22 | LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -193,7 +194,7 @@ LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:164:1 + --> $DIR/unsupported.rs:166:1 | LL | extern "C-cmse-nonsecure-entry" {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -255,7 +256,7 @@ LL | extern "stdcall" fn stdcall() {} = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:126:1 + --> $DIR/unsupported.rs:128:1 | LL | extern "cdecl" fn cdecl() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -265,13 +266,13 @@ LL | extern "cdecl" fn cdecl() {} = help: use `extern "C"` instead error[E0570]: `"vectorcall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:141:1 + --> $DIR/unsupported.rs:143:1 | LL | extern "vectorcall" fn vectorcall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:157:1 + --> $DIR/unsupported.rs:159:1 | LL | extern "C-cmse-nonsecure-entry" fn cmse_entry() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -368,43 +369,8 @@ LL | fn stdcall_ptr(f: extern "stdcall" fn()) { = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default Future breakage diagnostic: -warning: the calling convention "cdecl" is not supported on this target - --> $DIR/unsupported.rs:129:17 - | -LL | fn cdecl_ptr(f: extern "cdecl" fn()) { - | ^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 <https://github.com/rust-lang/rust/issues/130260> - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:134:1 - | -LL | extern "cdecl" {} - | ^^^^^^^^^^^^^^^^^ - | - = 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 #137018 <https://github.com/rust-lang/rust/issues/137018> - = help: use `extern "C"` instead - = note: `#[warn(unsupported_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:137:1 - | -LL | extern "cdecl-unwind" {} - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #137018 <https://github.com/rust-lang/rust/issues/137018> - = help: use `extern "C-unwind"` instead - = note: `#[warn(unsupported_calling_conventions)]` on by default - -Future breakage diagnostic: warning: the calling convention "vectorcall" is not supported on this target - --> $DIR/unsupported.rs:143:22 + --> $DIR/unsupported.rs:145:22 | LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -415,7 +381,7 @@ LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) { Future breakage diagnostic: warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target - --> $DIR/unsupported.rs:151:21 + --> $DIR/unsupported.rs:153:21 | LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -426,7 +392,7 @@ LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { Future breakage diagnostic: warning: the calling convention "C-cmse-nonsecure-entry" is not supported on this target - --> $DIR/unsupported.rs:159:22 + --> $DIR/unsupported.rs:161:22 | LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -435,15 +401,3 @@ LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default -Future breakage diagnostic: -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:126:1 - | -LL | extern "cdecl" fn cdecl() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #137018 <https://github.com/rust-lang/rust/issues/137018> - = help: use `extern "C"` instead - = note: `#[warn(unsupported_calling_conventions)]` on by default - diff --git a/tests/ui/abi/unsupported.arm.stderr b/tests/ui/abi/unsupported.arm.stderr index 2c82e2951e2..ed9cd2ab2c5 100644 --- a/tests/ui/abi/unsupported.arm.stderr +++ b/tests/ui/abi/unsupported.arm.stderr @@ -99,7 +99,7 @@ LL | fn stdcall_ptr(f: extern "stdcall" fn()) { = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> error[E0570]: `"stdcall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:117:1 + --> $DIR/unsupported.rs:119:1 | LL | extern "stdcall" {} | ^^^^^^^^^^^^^^^^^^^ @@ -107,24 +107,26 @@ LL | extern "stdcall" {} = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` error[E0570]: `"stdcall-unwind"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:121:1 + --> $DIR/unsupported.rs:123:1 | LL | extern "stdcall-unwind" {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: if you need `extern "stdcall-unwind"` on win32 and `extern "C-unwind"` everywhere else, use `extern "system-unwind"` -warning: the calling convention "cdecl" is not supported on this target - --> $DIR/unsupported.rs:129:17 +warning: use of calling convention not supported on this target + --> $DIR/unsupported.rs:131:17 | LL | fn cdecl_ptr(f: extern "cdecl" fn()) { | ^^^^^^^^^^^^^^^^^^^ | = 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 #130260 <https://github.com/rust-lang/rust/issues/130260> + = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018> + = help: use `extern "C"` instead + = note: `#[warn(unsupported_calling_conventions)]` on by default warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:134:1 + --> $DIR/unsupported.rs:136:1 | LL | extern "cdecl" {} | ^^^^^^^^^^^^^^^^^ @@ -132,10 +134,9 @@ LL | extern "cdecl" {} = 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 #137018 <https://github.com/rust-lang/rust/issues/137018> = help: use `extern "C"` instead - = note: `#[warn(unsupported_calling_conventions)]` on by default warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:137:1 + --> $DIR/unsupported.rs:139:1 | LL | extern "cdecl-unwind" {} | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -145,7 +146,7 @@ LL | extern "cdecl-unwind" {} = help: use `extern "C-unwind"` instead warning: the calling convention "vectorcall" is not supported on this target - --> $DIR/unsupported.rs:143:22 + --> $DIR/unsupported.rs:145:22 | LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -154,13 +155,13 @@ LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) { = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> error[E0570]: `"vectorcall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:148:1 + --> $DIR/unsupported.rs:150:1 | LL | extern "vectorcall" {} | ^^^^^^^^^^^^^^^^^^^^^^ warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target - --> $DIR/unsupported.rs:151:21 + --> $DIR/unsupported.rs:153:21 | LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -169,7 +170,7 @@ LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> warning: the calling convention "C-cmse-nonsecure-entry" is not supported on this target - --> $DIR/unsupported.rs:159:22 + --> $DIR/unsupported.rs:161:22 | LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -178,7 +179,7 @@ LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:164:1 + --> $DIR/unsupported.rs:166:1 | LL | extern "C-cmse-nonsecure-entry" {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -234,7 +235,7 @@ LL | extern "stdcall" fn stdcall() {} = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:126:1 + --> $DIR/unsupported.rs:128:1 | LL | extern "cdecl" fn cdecl() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -244,13 +245,13 @@ LL | extern "cdecl" fn cdecl() {} = help: use `extern "C"` instead error[E0570]: `"vectorcall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:141:1 + --> $DIR/unsupported.rs:143:1 | LL | extern "vectorcall" fn vectorcall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:157:1 + --> $DIR/unsupported.rs:159:1 | LL | extern "C-cmse-nonsecure-entry" fn cmse_entry() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -336,43 +337,8 @@ LL | fn stdcall_ptr(f: extern "stdcall" fn()) { = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default Future breakage diagnostic: -warning: the calling convention "cdecl" is not supported on this target - --> $DIR/unsupported.rs:129:17 - | -LL | fn cdecl_ptr(f: extern "cdecl" fn()) { - | ^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 <https://github.com/rust-lang/rust/issues/130260> - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:134:1 - | -LL | extern "cdecl" {} - | ^^^^^^^^^^^^^^^^^ - | - = 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 #137018 <https://github.com/rust-lang/rust/issues/137018> - = help: use `extern "C"` instead - = note: `#[warn(unsupported_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:137:1 - | -LL | extern "cdecl-unwind" {} - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #137018 <https://github.com/rust-lang/rust/issues/137018> - = help: use `extern "C-unwind"` instead - = note: `#[warn(unsupported_calling_conventions)]` on by default - -Future breakage diagnostic: warning: the calling convention "vectorcall" is not supported on this target - --> $DIR/unsupported.rs:143:22 + --> $DIR/unsupported.rs:145:22 | LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -383,7 +349,7 @@ LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) { Future breakage diagnostic: warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target - --> $DIR/unsupported.rs:151:21 + --> $DIR/unsupported.rs:153:21 | LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -394,7 +360,7 @@ LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { Future breakage diagnostic: warning: the calling convention "C-cmse-nonsecure-entry" is not supported on this target - --> $DIR/unsupported.rs:159:22 + --> $DIR/unsupported.rs:161:22 | LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -403,15 +369,3 @@ LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default -Future breakage diagnostic: -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:126:1 - | -LL | extern "cdecl" fn cdecl() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #137018 <https://github.com/rust-lang/rust/issues/137018> - = help: use `extern "C"` instead - = note: `#[warn(unsupported_calling_conventions)]` on by default - diff --git a/tests/ui/abi/unsupported.i686.stderr b/tests/ui/abi/unsupported.i686.stderr index d552f9a132c..4d903b435d8 100644 --- a/tests/ui/abi/unsupported.i686.stderr +++ b/tests/ui/abi/unsupported.i686.stderr @@ -75,7 +75,7 @@ LL | extern "riscv-interrupt-m" {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target - --> $DIR/unsupported.rs:151:21 + --> $DIR/unsupported.rs:153:21 | LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -84,7 +84,7 @@ LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> warning: the calling convention "C-cmse-nonsecure-entry" is not supported on this target - --> $DIR/unsupported.rs:159:22 + --> $DIR/unsupported.rs:161:22 | LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -93,7 +93,7 @@ LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:164:1 + --> $DIR/unsupported.rs:166:1 | LL | extern "C-cmse-nonsecure-entry" {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -135,7 +135,7 @@ LL | extern "riscv-interrupt-m" fn riscv() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:157:1 + --> $DIR/unsupported.rs:159:1 | LL | extern "C-cmse-nonsecure-entry" fn cmse_entry() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -200,7 +200,7 @@ LL | fn riscv_ptr(f: extern "riscv-interrupt-m" fn()) { Future breakage diagnostic: warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target - --> $DIR/unsupported.rs:151:21 + --> $DIR/unsupported.rs:153:21 | LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -211,7 +211,7 @@ LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { Future breakage diagnostic: warning: the calling convention "C-cmse-nonsecure-entry" is not supported on this target - --> $DIR/unsupported.rs:159:22 + --> $DIR/unsupported.rs:161:22 | LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/abi/unsupported.riscv32.stderr b/tests/ui/abi/unsupported.riscv32.stderr index a0e2901c759..9e75dfafca0 100644 --- a/tests/ui/abi/unsupported.riscv32.stderr +++ b/tests/ui/abi/unsupported.riscv32.stderr @@ -99,7 +99,7 @@ LL | fn stdcall_ptr(f: extern "stdcall" fn()) { = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> error[E0570]: `"stdcall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:117:1 + --> $DIR/unsupported.rs:119:1 | LL | extern "stdcall" {} | ^^^^^^^^^^^^^^^^^^^ @@ -107,24 +107,26 @@ LL | extern "stdcall" {} = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` error[E0570]: `"stdcall-unwind"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:121:1 + --> $DIR/unsupported.rs:123:1 | LL | extern "stdcall-unwind" {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: if you need `extern "stdcall-unwind"` on win32 and `extern "C-unwind"` everywhere else, use `extern "system-unwind"` -warning: the calling convention "cdecl" is not supported on this target - --> $DIR/unsupported.rs:129:17 +warning: use of calling convention not supported on this target + --> $DIR/unsupported.rs:131:17 | LL | fn cdecl_ptr(f: extern "cdecl" fn()) { | ^^^^^^^^^^^^^^^^^^^ | = 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 #130260 <https://github.com/rust-lang/rust/issues/130260> + = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018> + = help: use `extern "C"` instead + = note: `#[warn(unsupported_calling_conventions)]` on by default warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:134:1 + --> $DIR/unsupported.rs:136:1 | LL | extern "cdecl" {} | ^^^^^^^^^^^^^^^^^ @@ -132,10 +134,9 @@ LL | extern "cdecl" {} = 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 #137018 <https://github.com/rust-lang/rust/issues/137018> = help: use `extern "C"` instead - = note: `#[warn(unsupported_calling_conventions)]` on by default warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:137:1 + --> $DIR/unsupported.rs:139:1 | LL | extern "cdecl-unwind" {} | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -145,7 +146,7 @@ LL | extern "cdecl-unwind" {} = help: use `extern "C-unwind"` instead warning: the calling convention "vectorcall" is not supported on this target - --> $DIR/unsupported.rs:143:22 + --> $DIR/unsupported.rs:145:22 | LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -154,13 +155,13 @@ LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) { = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> error[E0570]: `"vectorcall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:148:1 + --> $DIR/unsupported.rs:150:1 | LL | extern "vectorcall" {} | ^^^^^^^^^^^^^^^^^^^^^^ warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target - --> $DIR/unsupported.rs:151:21 + --> $DIR/unsupported.rs:153:21 | LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -169,7 +170,7 @@ LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> warning: the calling convention "C-cmse-nonsecure-entry" is not supported on this target - --> $DIR/unsupported.rs:159:22 + --> $DIR/unsupported.rs:161:22 | LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -178,7 +179,7 @@ LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:164:1 + --> $DIR/unsupported.rs:166:1 | LL | extern "C-cmse-nonsecure-entry" {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -234,7 +235,7 @@ LL | extern "stdcall" fn stdcall() {} = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:126:1 + --> $DIR/unsupported.rs:128:1 | LL | extern "cdecl" fn cdecl() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -244,13 +245,13 @@ LL | extern "cdecl" fn cdecl() {} = help: use `extern "C"` instead error[E0570]: `"vectorcall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:141:1 + --> $DIR/unsupported.rs:143:1 | LL | extern "vectorcall" fn vectorcall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:157:1 + --> $DIR/unsupported.rs:159:1 | LL | extern "C-cmse-nonsecure-entry" fn cmse_entry() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -336,43 +337,8 @@ LL | fn stdcall_ptr(f: extern "stdcall" fn()) { = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default Future breakage diagnostic: -warning: the calling convention "cdecl" is not supported on this target - --> $DIR/unsupported.rs:129:17 - | -LL | fn cdecl_ptr(f: extern "cdecl" fn()) { - | ^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 <https://github.com/rust-lang/rust/issues/130260> - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:134:1 - | -LL | extern "cdecl" {} - | ^^^^^^^^^^^^^^^^^ - | - = 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 #137018 <https://github.com/rust-lang/rust/issues/137018> - = help: use `extern "C"` instead - = note: `#[warn(unsupported_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:137:1 - | -LL | extern "cdecl-unwind" {} - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #137018 <https://github.com/rust-lang/rust/issues/137018> - = help: use `extern "C-unwind"` instead - = note: `#[warn(unsupported_calling_conventions)]` on by default - -Future breakage diagnostic: warning: the calling convention "vectorcall" is not supported on this target - --> $DIR/unsupported.rs:143:22 + --> $DIR/unsupported.rs:145:22 | LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -383,7 +349,7 @@ LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) { Future breakage diagnostic: warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target - --> $DIR/unsupported.rs:151:21 + --> $DIR/unsupported.rs:153:21 | LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -394,7 +360,7 @@ LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { Future breakage diagnostic: warning: the calling convention "C-cmse-nonsecure-entry" is not supported on this target - --> $DIR/unsupported.rs:159:22 + --> $DIR/unsupported.rs:161:22 | LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -403,15 +369,3 @@ LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default -Future breakage diagnostic: -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:126:1 - | -LL | extern "cdecl" fn cdecl() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #137018 <https://github.com/rust-lang/rust/issues/137018> - = help: use `extern "C"` instead - = note: `#[warn(unsupported_calling_conventions)]` on by default - diff --git a/tests/ui/abi/unsupported.riscv64.stderr b/tests/ui/abi/unsupported.riscv64.stderr index a0e2901c759..9e75dfafca0 100644 --- a/tests/ui/abi/unsupported.riscv64.stderr +++ b/tests/ui/abi/unsupported.riscv64.stderr @@ -99,7 +99,7 @@ LL | fn stdcall_ptr(f: extern "stdcall" fn()) { = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> error[E0570]: `"stdcall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:117:1 + --> $DIR/unsupported.rs:119:1 | LL | extern "stdcall" {} | ^^^^^^^^^^^^^^^^^^^ @@ -107,24 +107,26 @@ LL | extern "stdcall" {} = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` error[E0570]: `"stdcall-unwind"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:121:1 + --> $DIR/unsupported.rs:123:1 | LL | extern "stdcall-unwind" {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: if you need `extern "stdcall-unwind"` on win32 and `extern "C-unwind"` everywhere else, use `extern "system-unwind"` -warning: the calling convention "cdecl" is not supported on this target - --> $DIR/unsupported.rs:129:17 +warning: use of calling convention not supported on this target + --> $DIR/unsupported.rs:131:17 | LL | fn cdecl_ptr(f: extern "cdecl" fn()) { | ^^^^^^^^^^^^^^^^^^^ | = 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 #130260 <https://github.com/rust-lang/rust/issues/130260> + = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018> + = help: use `extern "C"` instead + = note: `#[warn(unsupported_calling_conventions)]` on by default warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:134:1 + --> $DIR/unsupported.rs:136:1 | LL | extern "cdecl" {} | ^^^^^^^^^^^^^^^^^ @@ -132,10 +134,9 @@ LL | extern "cdecl" {} = 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 #137018 <https://github.com/rust-lang/rust/issues/137018> = help: use `extern "C"` instead - = note: `#[warn(unsupported_calling_conventions)]` on by default warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:137:1 + --> $DIR/unsupported.rs:139:1 | LL | extern "cdecl-unwind" {} | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -145,7 +146,7 @@ LL | extern "cdecl-unwind" {} = help: use `extern "C-unwind"` instead warning: the calling convention "vectorcall" is not supported on this target - --> $DIR/unsupported.rs:143:22 + --> $DIR/unsupported.rs:145:22 | LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -154,13 +155,13 @@ LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) { = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> error[E0570]: `"vectorcall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:148:1 + --> $DIR/unsupported.rs:150:1 | LL | extern "vectorcall" {} | ^^^^^^^^^^^^^^^^^^^^^^ warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target - --> $DIR/unsupported.rs:151:21 + --> $DIR/unsupported.rs:153:21 | LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -169,7 +170,7 @@ LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> warning: the calling convention "C-cmse-nonsecure-entry" is not supported on this target - --> $DIR/unsupported.rs:159:22 + --> $DIR/unsupported.rs:161:22 | LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -178,7 +179,7 @@ LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:164:1 + --> $DIR/unsupported.rs:166:1 | LL | extern "C-cmse-nonsecure-entry" {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -234,7 +235,7 @@ LL | extern "stdcall" fn stdcall() {} = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:126:1 + --> $DIR/unsupported.rs:128:1 | LL | extern "cdecl" fn cdecl() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -244,13 +245,13 @@ LL | extern "cdecl" fn cdecl() {} = help: use `extern "C"` instead error[E0570]: `"vectorcall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:141:1 + --> $DIR/unsupported.rs:143:1 | LL | extern "vectorcall" fn vectorcall() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:157:1 + --> $DIR/unsupported.rs:159:1 | LL | extern "C-cmse-nonsecure-entry" fn cmse_entry() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -336,43 +337,8 @@ LL | fn stdcall_ptr(f: extern "stdcall" fn()) { = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default Future breakage diagnostic: -warning: the calling convention "cdecl" is not supported on this target - --> $DIR/unsupported.rs:129:17 - | -LL | fn cdecl_ptr(f: extern "cdecl" fn()) { - | ^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 <https://github.com/rust-lang/rust/issues/130260> - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:134:1 - | -LL | extern "cdecl" {} - | ^^^^^^^^^^^^^^^^^ - | - = 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 #137018 <https://github.com/rust-lang/rust/issues/137018> - = help: use `extern "C"` instead - = note: `#[warn(unsupported_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:137:1 - | -LL | extern "cdecl-unwind" {} - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #137018 <https://github.com/rust-lang/rust/issues/137018> - = help: use `extern "C-unwind"` instead - = note: `#[warn(unsupported_calling_conventions)]` on by default - -Future breakage diagnostic: warning: the calling convention "vectorcall" is not supported on this target - --> $DIR/unsupported.rs:143:22 + --> $DIR/unsupported.rs:145:22 | LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -383,7 +349,7 @@ LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) { Future breakage diagnostic: warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target - --> $DIR/unsupported.rs:151:21 + --> $DIR/unsupported.rs:153:21 | LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -394,7 +360,7 @@ LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { Future breakage diagnostic: warning: the calling convention "C-cmse-nonsecure-entry" is not supported on this target - --> $DIR/unsupported.rs:159:22 + --> $DIR/unsupported.rs:161:22 | LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -403,15 +369,3 @@ LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default -Future breakage diagnostic: -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:126:1 - | -LL | extern "cdecl" fn cdecl() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #137018 <https://github.com/rust-lang/rust/issues/137018> - = help: use `extern "C"` instead - = note: `#[warn(unsupported_calling_conventions)]` on by default - diff --git a/tests/ui/abi/unsupported.rs b/tests/ui/abi/unsupported.rs index 9ea22ca516b..43bdfe3ea24 100644 --- a/tests/ui/abi/unsupported.rs +++ b/tests/ui/abi/unsupported.rs @@ -110,8 +110,10 @@ extern "stdcall" fn stdcall() {} //[x64_win]~^^ WARN unsupported_calling_conventions //[x64_win]~^^^ WARN this was previously accepted fn stdcall_ptr(f: extern "stdcall" fn()) { - //[x64,x64_win,arm,aarch64,riscv32,riscv64]~^ WARN unsupported_fn_ptr_calling_conventions - //[x64,x64_win,arm,aarch64,riscv32,riscv64]~^^ WARN this was previously accepted + //[x64_win]~^ WARN unsupported_calling_conventions + //[x64_win]~| WARN this was previously accepted + //[x64,arm,aarch64,riscv32,riscv64]~^^^ WARN unsupported_fn_ptr_calling_conventions + //[x64,arm,aarch64,riscv32,riscv64]~| WARN this was previously accepted f() } extern "stdcall" {} @@ -127,7 +129,7 @@ extern "cdecl" fn cdecl() {} //[x64,x64_win,arm,aarch64,riscv32,riscv64]~^ WARN unsupported_calling_conventions //[x64,x64_win,arm,aarch64,riscv32,riscv64]~^^ WARN this was previously accepted fn cdecl_ptr(f: extern "cdecl" fn()) { - //[x64,x64_win,arm,aarch64,riscv32,riscv64]~^ WARN unsupported_fn_ptr_calling_conventions + //[x64,x64_win,arm,aarch64,riscv32,riscv64]~^ WARN unsupported_calling_conventions //[x64,x64_win,arm,aarch64,riscv32,riscv64]~^^ WARN this was previously accepted f() } diff --git a/tests/ui/abi/unsupported.x64.stderr b/tests/ui/abi/unsupported.x64.stderr index 732a5f84f50..5b55e5707fa 100644 --- a/tests/ui/abi/unsupported.x64.stderr +++ b/tests/ui/abi/unsupported.x64.stderr @@ -99,7 +99,7 @@ LL | fn stdcall_ptr(f: extern "stdcall" fn()) { = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> error[E0570]: `"stdcall"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:117:1 + --> $DIR/unsupported.rs:119:1 | LL | extern "stdcall" {} | ^^^^^^^^^^^^^^^^^^^ @@ -107,24 +107,26 @@ LL | extern "stdcall" {} = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` error[E0570]: `"stdcall-unwind"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:121:1 + --> $DIR/unsupported.rs:123:1 | LL | extern "stdcall-unwind" {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: if you need `extern "stdcall-unwind"` on win32 and `extern "C-unwind"` everywhere else, use `extern "system-unwind"` -warning: the calling convention "cdecl" is not supported on this target - --> $DIR/unsupported.rs:129:17 +warning: use of calling convention not supported on this target + --> $DIR/unsupported.rs:131:17 | LL | fn cdecl_ptr(f: extern "cdecl" fn()) { | ^^^^^^^^^^^^^^^^^^^ | = 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 #130260 <https://github.com/rust-lang/rust/issues/130260> + = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018> + = help: use `extern "C"` instead + = note: `#[warn(unsupported_calling_conventions)]` on by default warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:134:1 + --> $DIR/unsupported.rs:136:1 | LL | extern "cdecl" {} | ^^^^^^^^^^^^^^^^^ @@ -132,10 +134,9 @@ LL | extern "cdecl" {} = 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 #137018 <https://github.com/rust-lang/rust/issues/137018> = help: use `extern "C"` instead - = note: `#[warn(unsupported_calling_conventions)]` on by default warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:137:1 + --> $DIR/unsupported.rs:139:1 | LL | extern "cdecl-unwind" {} | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -145,7 +146,7 @@ LL | extern "cdecl-unwind" {} = help: use `extern "C-unwind"` instead warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target - --> $DIR/unsupported.rs:151:21 + --> $DIR/unsupported.rs:153:21 | LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -154,7 +155,7 @@ LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> warning: the calling convention "C-cmse-nonsecure-entry" is not supported on this target - --> $DIR/unsupported.rs:159:22 + --> $DIR/unsupported.rs:161:22 | LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -163,7 +164,7 @@ LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:164:1 + --> $DIR/unsupported.rs:166:1 | LL | extern "C-cmse-nonsecure-entry" {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -219,7 +220,7 @@ LL | extern "stdcall" fn stdcall() {} = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:126:1 + --> $DIR/unsupported.rs:128:1 | LL | extern "cdecl" fn cdecl() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -229,7 +230,7 @@ LL | extern "cdecl" fn cdecl() {} = help: use `extern "C"` instead error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:157:1 + --> $DIR/unsupported.rs:159:1 | LL | extern "C-cmse-nonsecure-entry" fn cmse_entry() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -315,43 +316,8 @@ LL | fn stdcall_ptr(f: extern "stdcall" fn()) { = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default Future breakage diagnostic: -warning: the calling convention "cdecl" is not supported on this target - --> $DIR/unsupported.rs:129:17 - | -LL | fn cdecl_ptr(f: extern "cdecl" fn()) { - | ^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 <https://github.com/rust-lang/rust/issues/130260> - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:134:1 - | -LL | extern "cdecl" {} - | ^^^^^^^^^^^^^^^^^ - | - = 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 #137018 <https://github.com/rust-lang/rust/issues/137018> - = help: use `extern "C"` instead - = note: `#[warn(unsupported_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:137:1 - | -LL | extern "cdecl-unwind" {} - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #137018 <https://github.com/rust-lang/rust/issues/137018> - = help: use `extern "C-unwind"` instead - = note: `#[warn(unsupported_calling_conventions)]` on by default - -Future breakage diagnostic: warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target - --> $DIR/unsupported.rs:151:21 + --> $DIR/unsupported.rs:153:21 | LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -362,7 +328,7 @@ LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { Future breakage diagnostic: warning: the calling convention "C-cmse-nonsecure-entry" is not supported on this target - --> $DIR/unsupported.rs:159:22 + --> $DIR/unsupported.rs:161:22 | LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -371,15 +337,3 @@ LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default -Future breakage diagnostic: -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:126:1 - | -LL | extern "cdecl" fn cdecl() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #137018 <https://github.com/rust-lang/rust/issues/137018> - = help: use `extern "C"` instead - = note: `#[warn(unsupported_calling_conventions)]` on by default - diff --git a/tests/ui/abi/unsupported.x64_win.stderr b/tests/ui/abi/unsupported.x64_win.stderr index 5597440d5d9..93b5a272e92 100644 --- a/tests/ui/abi/unsupported.x64_win.stderr +++ b/tests/ui/abi/unsupported.x64_win.stderr @@ -89,17 +89,19 @@ error[E0570]: `"thiscall"` is not a supported ABI for the current target LL | extern "thiscall" {} | ^^^^^^^^^^^^^^^^^^^^ -warning: the calling convention "stdcall" is not supported on this target +warning: use of calling convention not supported on this target --> $DIR/unsupported.rs:112:19 | LL | fn stdcall_ptr(f: extern "stdcall" fn()) { | ^^^^^^^^^^^^^^^^^^^^^ | = 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 #130260 <https://github.com/rust-lang/rust/issues/130260> + = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018> + = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` + = note: `#[warn(unsupported_calling_conventions)]` on by default warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:117:1 + --> $DIR/unsupported.rs:119:1 | LL | extern "stdcall" {} | ^^^^^^^^^^^^^^^^^^^ @@ -107,10 +109,9 @@ LL | extern "stdcall" {} = 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 #137018 <https://github.com/rust-lang/rust/issues/137018> = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` - = note: `#[warn(unsupported_calling_conventions)]` on by default warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:121:1 + --> $DIR/unsupported.rs:123:1 | LL | extern "stdcall-unwind" {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -119,17 +120,18 @@ LL | extern "stdcall-unwind" {} = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018> = help: if you need `extern "stdcall-unwind"` on win32 and `extern "C-unwind"` everywhere else, use `extern "system-unwind"` -warning: the calling convention "cdecl" is not supported on this target - --> $DIR/unsupported.rs:129:17 +warning: use of calling convention not supported on this target + --> $DIR/unsupported.rs:131:17 | LL | fn cdecl_ptr(f: extern "cdecl" fn()) { | ^^^^^^^^^^^^^^^^^^^ | = 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 #130260 <https://github.com/rust-lang/rust/issues/130260> + = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018> + = help: use `extern "C"` instead warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:134:1 + --> $DIR/unsupported.rs:136:1 | LL | extern "cdecl" {} | ^^^^^^^^^^^^^^^^^ @@ -139,7 +141,7 @@ LL | extern "cdecl" {} = help: use `extern "C"` instead warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:137:1 + --> $DIR/unsupported.rs:139:1 | LL | extern "cdecl-unwind" {} | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -149,7 +151,7 @@ LL | extern "cdecl-unwind" {} = help: use `extern "C-unwind"` instead warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target - --> $DIR/unsupported.rs:151:21 + --> $DIR/unsupported.rs:153:21 | LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -158,7 +160,7 @@ LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> warning: the calling convention "C-cmse-nonsecure-entry" is not supported on this target - --> $DIR/unsupported.rs:159:22 + --> $DIR/unsupported.rs:161:22 | LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -167,13 +169,13 @@ LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:164:1 + --> $DIR/unsupported.rs:166:1 | LL | extern "C-cmse-nonsecure-entry" {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:169:1 + --> $DIR/unsupported.rs:171:1 | LL | extern "cdecl" {} | ^^^^^^^^^^^^^^^^^ @@ -235,7 +237,7 @@ LL | extern "stdcall" fn stdcall() {} = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:126:1 + --> $DIR/unsupported.rs:128:1 | LL | extern "cdecl" fn cdecl() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -245,7 +247,7 @@ LL | extern "cdecl" fn cdecl() {} = help: use `extern "C"` instead error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target - --> $DIR/unsupported.rs:157:1 + --> $DIR/unsupported.rs:159:1 | LL | extern "C-cmse-nonsecure-entry" fn cmse_entry() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -320,78 +322,8 @@ LL | fn thiscall_ptr(f: extern "thiscall" fn()) { = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default Future breakage diagnostic: -warning: the calling convention "stdcall" is not supported on this target - --> $DIR/unsupported.rs:112:19 - | -LL | fn stdcall_ptr(f: extern "stdcall" fn()) { - | ^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 <https://github.com/rust-lang/rust/issues/130260> - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:117:1 - | -LL | extern "stdcall" {} - | ^^^^^^^^^^^^^^^^^^^ - | - = 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 #137018 <https://github.com/rust-lang/rust/issues/137018> - = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` - = note: `#[warn(unsupported_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:121:1 - | -LL | extern "stdcall-unwind" {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #137018 <https://github.com/rust-lang/rust/issues/137018> - = help: if you need `extern "stdcall-unwind"` on win32 and `extern "C-unwind"` everywhere else, use `extern "system-unwind"` - = note: `#[warn(unsupported_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: the calling convention "cdecl" is not supported on this target - --> $DIR/unsupported.rs:129:17 - | -LL | fn cdecl_ptr(f: extern "cdecl" fn()) { - | ^^^^^^^^^^^^^^^^^^^ - | - = 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 #130260 <https://github.com/rust-lang/rust/issues/130260> - = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:134:1 - | -LL | extern "cdecl" {} - | ^^^^^^^^^^^^^^^^^ - | - = 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 #137018 <https://github.com/rust-lang/rust/issues/137018> - = help: use `extern "C"` instead - = note: `#[warn(unsupported_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:137:1 - | -LL | extern "cdecl-unwind" {} - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #137018 <https://github.com/rust-lang/rust/issues/137018> - = help: use `extern "C-unwind"` instead - = note: `#[warn(unsupported_calling_conventions)]` on by default - -Future breakage diagnostic: warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target - --> $DIR/unsupported.rs:151:21 + --> $DIR/unsupported.rs:153:21 | LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -402,7 +334,7 @@ LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) { Future breakage diagnostic: warning: the calling convention "C-cmse-nonsecure-entry" is not supported on this target - --> $DIR/unsupported.rs:159:22 + --> $DIR/unsupported.rs:161:22 | LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -411,39 +343,3 @@ LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) { = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260> = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default -Future breakage diagnostic: -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:169:1 - | -LL | extern "cdecl" {} - | ^^^^^^^^^^^^^^^^^ - | - = 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 #137018 <https://github.com/rust-lang/rust/issues/137018> - = help: use `extern "C"` instead - = note: `#[warn(unsupported_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:108:1 - | -LL | extern "stdcall" fn stdcall() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #137018 <https://github.com/rust-lang/rust/issues/137018> - = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` - = note: `#[warn(unsupported_calling_conventions)]` on by default - -Future breakage diagnostic: -warning: use of calling convention not supported on this target - --> $DIR/unsupported.rs:126:1 - | -LL | extern "cdecl" fn cdecl() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = 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 #137018 <https://github.com/rust-lang/rust/issues/137018> - = help: use `extern "C"` instead - = note: `#[warn(unsupported_calling_conventions)]` on by default - diff --git a/tests/ui/async-await/async-block-control-flow-static-semantics.stderr b/tests/ui/async-await/async-block-control-flow-static-semantics.stderr index 4ed15a942c6..b64690bae6c 100644 --- a/tests/ui/async-await/async-block-control-flow-static-semantics.stderr +++ b/tests/ui/async-await/async-block-control-flow-static-semantics.stderr @@ -1,19 +1,3 @@ -error[E0267]: `break` inside `async` block - --> $DIR/async-block-control-flow-static-semantics.rs:32:9 - | -LL | async { - | ----- enclosing `async` block -LL | break 0u8; - | ^^^^^^^^^ cannot `break` inside `async` block - -error[E0267]: `break` inside `async` block - --> $DIR/async-block-control-flow-static-semantics.rs:39:13 - | -LL | async { - | ----- enclosing `async` block -LL | break 0u8; - | ^^^^^^^^^ cannot `break` inside `async` block - error[E0308]: mismatched types --> $DIR/async-block-control-flow-static-semantics.rs:21:58 | @@ -50,6 +34,22 @@ LL | let _: &dyn Future<Output = ()> = █ | = note: required for the cast from `&{async block@$DIR/async-block-control-flow-static-semantics.rs:14:17: 14:22}` to `&dyn Future<Output = ()>` +error[E0267]: `break` inside `async` block + --> $DIR/async-block-control-flow-static-semantics.rs:32:9 + | +LL | async { + | ----- enclosing `async` block +LL | break 0u8; + | ^^^^^^^^^ cannot `break` inside `async` block + +error[E0267]: `break` inside `async` block + --> $DIR/async-block-control-flow-static-semantics.rs:39:13 + | +LL | async { + | ----- enclosing `async` block +LL | break 0u8; + | ^^^^^^^^^ cannot `break` inside `async` block + error[E0308]: mismatched types --> $DIR/async-block-control-flow-static-semantics.rs:49:44 | diff --git a/tests/ui/async-await/async-closures/without-precise-captures-we-are-powerless.stderr b/tests/ui/async-await/async-closures/without-precise-captures-we-are-powerless.stderr index 329cec6dad3..b7259074bf6 100644 --- a/tests/ui/async-await/async-closures/without-precise-captures-we-are-powerless.stderr +++ b/tests/ui/async-await/async-closures/without-precise-captures-we-are-powerless.stderr @@ -106,11 +106,13 @@ LL | } error[E0621]: explicit lifetime required in the type of `x` --> $DIR/without-precise-captures-we-are-powerless.rs:38:5 | -LL | fn through_field_and_ref<'a>(x: &S<'a>) { - | ------ help: add explicit lifetime `'a` to the type of `x`: `&'a S<'a>` -... LL | outlives::<'a>(call_once(c)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime `'a` required + | +help: add explicit lifetime `'a` to the type of `x` + | +LL | fn through_field_and_ref<'a>(x: &'a S<'a>) { + | ++ error[E0597]: `c` does not live long enough --> $DIR/without-precise-captures-we-are-powerless.rs:43:20 @@ -131,11 +133,13 @@ LL | } error[E0621]: explicit lifetime required in the type of `x` --> $DIR/without-precise-captures-we-are-powerless.rs:44:5 | -LL | fn through_field_and_ref_move<'a>(x: &S<'a>) { - | ------ help: add explicit lifetime `'a` to the type of `x`: `&'a S<'a>` -... LL | outlives::<'a>(call_once(c)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime `'a` required + | +help: add explicit lifetime `'a` to the type of `x` + | +LL | fn through_field_and_ref_move<'a>(x: &'a S<'a>) { + | ++ error: aborting due to 10 previous errors diff --git a/tests/ui/async-await/issues/issue-63388-1.stderr b/tests/ui/async-await/issues/issue-63388-1.stderr index 277f7fa6f63..a59fe7dbc20 100644 --- a/tests/ui/async-await/issues/issue-63388-1.stderr +++ b/tests/ui/async-await/issues/issue-63388-1.stderr @@ -1,11 +1,14 @@ error[E0621]: explicit lifetime required in the type of `foo` --> $DIR/issue-63388-1.rs:14:9 | -LL | &'a self, foo: &dyn Foo - | -------- help: add explicit lifetime `'a` to the type of `foo`: `&'a (dyn Foo + 'a)` -... LL | foo | ^^^ lifetime `'a` required + | +help: add explicit lifetime `'a` to the type of `foo` + | +LL - &'a self, foo: &dyn Foo +LL + &'a self, foo: &'a (dyn Foo + 'a) + | error: aborting due to 1 previous error diff --git a/tests/ui/auxiliary/typeid-intrinsic-aux1.rs b/tests/ui/auxiliary/typeid-intrinsic-aux1.rs index 281c079682f..a028008c6ae 100644 --- a/tests/ui/auxiliary/typeid-intrinsic-aux1.rs +++ b/tests/ui/auxiliary/typeid-intrinsic-aux1.rs @@ -9,9 +9,9 @@ pub struct E(Result<&'static str, isize>); pub type F = Option<isize>; pub type G = usize; pub type H = &'static str; -pub type I = Box<Fn()>; -pub type I32Iterator = Iterator<Item=i32>; -pub type U32Iterator = Iterator<Item=u32>; +pub type I = Box<dyn Fn()>; +pub type I32Iterator = dyn Iterator<Item=i32>; +pub type U32Iterator = dyn Iterator<Item=u32>; pub fn id_A() -> TypeId { TypeId::of::<A>() } pub fn id_B() -> TypeId { TypeId::of::<B>() } diff --git a/tests/ui/auxiliary/typeid-intrinsic-aux2.rs b/tests/ui/auxiliary/typeid-intrinsic-aux2.rs index 281c079682f..a028008c6ae 100644 --- a/tests/ui/auxiliary/typeid-intrinsic-aux2.rs +++ b/tests/ui/auxiliary/typeid-intrinsic-aux2.rs @@ -9,9 +9,9 @@ pub struct E(Result<&'static str, isize>); pub type F = Option<isize>; pub type G = usize; pub type H = &'static str; -pub type I = Box<Fn()>; -pub type I32Iterator = Iterator<Item=i32>; -pub type U32Iterator = Iterator<Item=u32>; +pub type I = Box<dyn Fn()>; +pub type I32Iterator = dyn Iterator<Item=i32>; +pub type U32Iterator = dyn Iterator<Item=u32>; pub fn id_A() -> TypeId { TypeId::of::<A>() } pub fn id_B() -> TypeId { TypeId::of::<B>() } diff --git a/tests/ui/box/empty-alloc-deref-rvalue.rs b/tests/ui/box/empty-alloc-deref-rvalue.rs new file mode 100644 index 00000000000..507a753467a --- /dev/null +++ b/tests/ui/box/empty-alloc-deref-rvalue.rs @@ -0,0 +1,10 @@ +//! Smoke test: dereferencing boxed zero-sized types (ZSTs) should not crash. +//! +//! Originally a regression test of github.com/rust-lang/rust/issues/13360 +//! but repurposed for a smoke test. + +//@ run-pass + +pub fn main() { + let _: () = *Box::new(()); +} diff --git a/tests/ui/filter-block-view-items.rs b/tests/ui/cfg/cfg-false-use-item.rs index cb599c27264..d37b48cdedb 100644 --- a/tests/ui/filter-block-view-items.rs +++ b/tests/ui/cfg/cfg-false-use-item.rs @@ -1,3 +1,5 @@ +//! Test that use items with cfg(false) are properly filtered out + //@ run-pass pub fn main() { diff --git a/tests/ui/check-cfg/hrtb-crash.rs b/tests/ui/check-cfg/hrtb-crash.rs new file mode 100644 index 00000000000..f2bce33f9f9 --- /dev/null +++ b/tests/ui/check-cfg/hrtb-crash.rs @@ -0,0 +1,7 @@ +// https://github.com/rust-lang/rust/issues/139825 +//@ compile-flags: --check-cfg=cfg(docsrs,test) --crate-type lib +//@ check-pass +struct A +where + for<#[cfg(b)] c> u8:; +//~^ WARN: unexpected `cfg` condition name diff --git a/tests/ui/check-cfg/hrtb-crash.stderr b/tests/ui/check-cfg/hrtb-crash.stderr new file mode 100644 index 00000000000..431cf9cf53e --- /dev/null +++ b/tests/ui/check-cfg/hrtb-crash.stderr @@ -0,0 +1,13 @@ +warning: unexpected `cfg` condition name: `b` + --> $DIR/hrtb-crash.rs:6:15 + | +LL | for<#[cfg(b)] c> u8:; + | ^ help: found config with similar value: `target_feature = "b"` + | + = help: expected names are: `FALSE`, `docsrs`, and `test` and 31 more + = help: to expect this configuration use `--check-cfg=cfg(b)` + = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration + = note: `#[warn(unexpected_cfgs)]` on by default + +warning: 1 warning emitted + diff --git a/tests/ui/check-cfg/target_feature.stderr b/tests/ui/check-cfg/target_feature.stderr index ec81ba2e3d8..f29a41d6a8e 100644 --- a/tests/ui/check-cfg/target_feature.stderr +++ b/tests/ui/check-cfg/target_feature.stderr @@ -212,6 +212,9 @@ LL | cfg!(target_feature = "_UNEXPECTED_VALUE"); `relax` `relaxed-simd` `reserve-x18` +`retpoline-external-thunk` +`retpoline-indirect-branches` +`retpoline-indirect-calls` `rtm` `sb` `scq` 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 16512cb69e2..ebb3e821e07 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 @@ -13,7 +13,7 @@ error: generic parameters may not be used in const operations LL | let _: [u8; bar::<N>()]; | ^ cannot perform const operation using `N` | - = help: const parameters may only be used as standalone arguments, i.e. `N` + = help: const parameters may only be used as standalone arguments here, i.e. `N` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations @@ -58,7 +58,7 @@ error: generic parameters may not be used in const operations LL | let _ = [0; bar::<N>()]; | ^ cannot perform const operation using `N` | - = help: const parameters may only be used as standalone arguments, i.e. `N` + = help: const parameters may only be used as standalone arguments here, i.e. `N` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations @@ -112,7 +112,7 @@ error: generic parameters may not be used in const operations LL | let _: Foo<{ bar::<N>() }>; | ^ cannot perform const operation using `N` | - = help: const parameters may only be used as standalone arguments, i.e. `N` + = help: const parameters may only be used as standalone arguments here, i.e. `N` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations @@ -166,7 +166,7 @@ error: generic parameters may not be used in const operations LL | let _ = Foo::<{ bar::<N>() }>; | ^ cannot perform const operation using `N` | - = help: const parameters may only be used as standalone arguments, i.e. `N` + = help: const parameters may only be used as standalone arguments here, i.e. `N` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations diff --git a/tests/ui/const-generics/defaults/complex-generic-default-expr.min.stderr b/tests/ui/const-generics/defaults/complex-generic-default-expr.min.stderr index 199546c0883..e41e488371a 100644 --- a/tests/ui/const-generics/defaults/complex-generic-default-expr.min.stderr +++ b/tests/ui/const-generics/defaults/complex-generic-default-expr.min.stderr @@ -4,7 +4,7 @@ error: generic parameters may not be used in const operations LL | struct Foo<const N: usize, const M: usize = { N + 1 }>; | ^ cannot perform const operation using `N` | - = help: const parameters may only be used as standalone arguments, i.e. `N` + = help: const parameters may only be used as standalone arguments here, i.e. `N` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations diff --git a/tests/ui/const-generics/early/const_arg_trivial_macro_expansion-4.stderr b/tests/ui/const-generics/early/const_arg_trivial_macro_expansion-4.stderr index 4722968b203..a1aee041b1f 100644 --- a/tests/ui/const-generics/early/const_arg_trivial_macro_expansion-4.stderr +++ b/tests/ui/const-generics/early/const_arg_trivial_macro_expansion-4.stderr @@ -7,7 +7,7 @@ LL | N LL | fn foo<const N: usize>() -> Foo<{ arg!{} arg!{} }> { loop {} } | ------ in this macro invocation | - = help: const parameters may only be used as standalone arguments, i.e. `N` + = help: const parameters may only be used as standalone arguments here, i.e. `N` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions = note: this error originates in the macro `arg` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -20,7 +20,7 @@ LL | N LL | fn foo<const N: usize>() -> Foo<{ arg!{} arg!{} }> { loop {} } | ------ in this macro invocation | - = help: const parameters may only be used as standalone arguments, i.e. `N` + = help: const parameters may only be used as standalone arguments here, i.e. `N` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions = note: this error originates in the macro `arg` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -30,7 +30,7 @@ error: generic parameters may not be used in const operations LL | fn bar<const N: usize>() -> [(); { empty!{}; N }] { loop {} } | ^ cannot perform const operation using `N` | - = help: const parameters may only be used as standalone arguments, i.e. `N` + = help: const parameters may only be used as standalone arguments here, i.e. `N` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: aborting due to 3 previous errors diff --git a/tests/ui/const-generics/early/macro_rules-braces.stderr b/tests/ui/const-generics/early/macro_rules-braces.stderr index 32695066801..30efa18982b 100644 --- a/tests/ui/const-generics/early/macro_rules-braces.stderr +++ b/tests/ui/const-generics/early/macro_rules-braces.stderr @@ -26,7 +26,7 @@ error: generic parameters may not be used in const operations LL | let _: foo!({{ N }}); | ^ cannot perform const operation using `N` | - = help: const parameters may only be used as standalone arguments, i.e. `N` + = help: const parameters may only be used as standalone arguments here, i.e. `N` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations @@ -35,7 +35,7 @@ error: generic parameters may not be used in const operations LL | let _: bar!({ N }); | ^ cannot perform const operation using `N` | - = help: const parameters may only be used as standalone arguments, i.e. `N` + = help: const parameters may only be used as standalone arguments here, i.e. `N` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations @@ -44,7 +44,7 @@ error: generic parameters may not be used in const operations LL | let _: baz!({{ N }}); | ^ cannot perform const operation using `N` | - = help: const parameters may only be used as standalone arguments, i.e. `N` + = help: const parameters may only be used as standalone arguments here, i.e. `N` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations @@ -53,7 +53,7 @@ error: generic parameters may not be used in const operations LL | let _: biz!({ N }); | ^ cannot perform const operation using `N` | - = help: const parameters may only be used as standalone arguments, i.e. `N` + = help: const parameters may only be used as standalone arguments here, i.e. `N` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: aborting due to 6 previous errors diff --git a/tests/ui/const-generics/early/trivial-const-arg-macro-nested-braces-2.stderr b/tests/ui/const-generics/early/trivial-const-arg-macro-nested-braces-2.stderr index e40d05924b1..d68715b4d8b 100644 --- a/tests/ui/const-generics/early/trivial-const-arg-macro-nested-braces-2.stderr +++ b/tests/ui/const-generics/early/trivial-const-arg-macro-nested-braces-2.stderr @@ -7,7 +7,7 @@ LL | N LL | fn foo<const N: usize>() -> A<{{ y!() }}> { | ---- in this macro invocation | - = help: const parameters may only be used as standalone arguments, i.e. `N` + = help: const parameters may only be used as standalone arguments here, i.e. `N` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions = note: this error originates in the macro `y` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/const-generics/early/trivial-const-arg-macro-nested-braces.stderr b/tests/ui/const-generics/early/trivial-const-arg-macro-nested-braces.stderr index b91d6c7a024..1171b359f17 100644 --- a/tests/ui/const-generics/early/trivial-const-arg-macro-nested-braces.stderr +++ b/tests/ui/const-generics/early/trivial-const-arg-macro-nested-braces.stderr @@ -7,7 +7,7 @@ LL | { N } LL | fn foo<const N: usize>() -> A<{ y!() }> { | ---- in this macro invocation | - = help: const parameters may only be used as standalone arguments, i.e. `N` + = help: const parameters may only be used as standalone arguments here, i.e. `N` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions = note: this error originates in the macro `y` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/const-generics/early/trivial-const-arg-nested-braces.stderr b/tests/ui/const-generics/early/trivial-const-arg-nested-braces.stderr index d60516ba4bc..b812e3333d9 100644 --- a/tests/ui/const-generics/early/trivial-const-arg-nested-braces.stderr +++ b/tests/ui/const-generics/early/trivial-const-arg-nested-braces.stderr @@ -4,7 +4,7 @@ error: generic parameters may not be used in const operations LL | fn foo<const N: usize>() -> A<{ { N } }> { | ^ cannot perform const operation using `N` | - = help: const parameters may only be used as standalone arguments, i.e. `N` + = help: const parameters may only be used as standalone arguments here, i.e. `N` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/generic_const_exprs/array-size-in-generic-struct-param.min.stderr b/tests/ui/const-generics/generic_const_exprs/array-size-in-generic-struct-param.min.stderr index a8b6f06ab1c..1f93c4f8909 100644 --- a/tests/ui/const-generics/generic_const_exprs/array-size-in-generic-struct-param.min.stderr +++ b/tests/ui/const-generics/generic_const_exprs/array-size-in-generic-struct-param.min.stderr @@ -4,7 +4,7 @@ error: generic parameters may not be used in const operations LL | struct ArithArrayLen<const N: usize>([u32; 0 + N]); | ^ cannot perform const operation using `N` | - = help: const parameters may only be used as standalone arguments, i.e. `N` + = help: const parameters may only be used as standalone arguments here, i.e. `N` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations @@ -13,7 +13,7 @@ error: generic parameters may not be used in const operations LL | arr: [u8; CFG.arr_size], | ^^^ cannot perform const operation using `CFG` | - = help: const parameters may only be used as standalone arguments, i.e. `CFG` + = help: const parameters may only be used as standalone arguments here, i.e. `CFG` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: `Config` is forbidden as the type of a const generic parameter diff --git a/tests/ui/const-generics/generic_const_exprs/bad-multiply.stderr b/tests/ui/const-generics/generic_const_exprs/bad-multiply.stderr index a8d6cebabe7..7719831e20c 100644 --- a/tests/ui/const-generics/generic_const_exprs/bad-multiply.stderr +++ b/tests/ui/const-generics/generic_const_exprs/bad-multiply.stderr @@ -4,7 +4,7 @@ error: generic parameters may not be used in const operations LL | SmallVec<{ D * 2 }>:, | ^ cannot perform const operation using `D` | - = help: const parameters may only be used as standalone arguments, i.e. `D` + = help: const parameters may only be used as standalone arguments here, i.e. `D` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error[E0747]: constant provided when a type was expected diff --git a/tests/ui/const-generics/generic_const_exprs/feature-gate-generic_const_exprs.stderr b/tests/ui/const-generics/generic_const_exprs/feature-gate-generic_const_exprs.stderr index 9c4e3d8583c..3208bbbd86b 100644 --- a/tests/ui/const-generics/generic_const_exprs/feature-gate-generic_const_exprs.stderr +++ b/tests/ui/const-generics/generic_const_exprs/feature-gate-generic_const_exprs.stderr @@ -4,7 +4,7 @@ error: generic parameters may not be used in const operations LL | type Arr<const N: usize> = [u8; N - 1]; | ^ cannot perform const operation using `N` | - = help: const parameters may only be used as standalone arguments, i.e. `N` + = help: const parameters may only be used as standalone arguments here, i.e. `N` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/generic_const_exprs/issue-72787.min.stderr b/tests/ui/const-generics/generic_const_exprs/issue-72787.min.stderr index 2454b311921..cccf6dc6ae0 100644 --- a/tests/ui/const-generics/generic_const_exprs/issue-72787.min.stderr +++ b/tests/ui/const-generics/generic_const_exprs/issue-72787.min.stderr @@ -4,7 +4,7 @@ error: generic parameters may not be used in const operations LL | Condition<{ LHS <= RHS }>: True | ^^^ cannot perform const operation using `LHS` | - = help: const parameters may only be used as standalone arguments, i.e. `LHS` + = help: const parameters may only be used as standalone arguments here, i.e. `LHS` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations @@ -13,7 +13,7 @@ error: generic parameters may not be used in const operations LL | Condition<{ LHS <= RHS }>: True | ^^^ cannot perform const operation using `RHS` | - = help: const parameters may only be used as standalone arguments, i.e. `RHS` + = help: const parameters may only be used as standalone arguments here, i.e. `RHS` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations @@ -22,7 +22,7 @@ error: generic parameters may not be used in const operations LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, | ^ cannot perform const operation using `I` | - = help: const parameters may only be used as standalone arguments, i.e. `I` + = help: const parameters may only be used as standalone arguments here, i.e. `I` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations @@ -31,7 +31,7 @@ error: generic parameters may not be used in const operations LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, | ^ cannot perform const operation using `J` | - = help: const parameters may only be used as standalone arguments, i.e. `J` + = help: const parameters may only be used as standalone arguments here, i.e. `J` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: aborting due to 4 previous errors diff --git a/tests/ui/const-generics/generic_const_exprs/issue-72819-generic-in-const-eval.min.stderr b/tests/ui/const-generics/generic_const_exprs/issue-72819-generic-in-const-eval.min.stderr index c504464127a..f91a2a30286 100644 --- a/tests/ui/const-generics/generic_const_exprs/issue-72819-generic-in-const-eval.min.stderr +++ b/tests/ui/const-generics/generic_const_exprs/issue-72819-generic-in-const-eval.min.stderr @@ -4,7 +4,7 @@ error: generic parameters may not be used in const operations LL | where Assert::<{N < usize::MAX / 2}>: IsTrue, | ^ cannot perform const operation using `N` | - = help: const parameters may only be used as standalone arguments, i.e. `N` + = help: const parameters may only be used as standalone arguments here, i.e. `N` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/generic_const_exprs/trivial-anon-const-use-cases.full.stderr b/tests/ui/const-generics/generic_const_exprs/trivial-anon-const-use-cases.full.stderr new file mode 100644 index 00000000000..586ac63016c --- /dev/null +++ b/tests/ui/const-generics/generic_const_exprs/trivial-anon-const-use-cases.full.stderr @@ -0,0 +1,13 @@ +error: unconstrained generic constant + --> $DIR/trivial-anon-const-use-cases.rs:14:12 + | +LL | stuff: [u8; { S + 1 }], // `S + 1` is NOT a valid const expression in this context. + | ^^^^^^^^^^^^^^^ + | +help: try adding a `where` bound + | +LL | struct Y<const S: usize> where [(); { S + 1 }]: { + | ++++++++++++++++++++++ + +error: aborting due to 1 previous error + diff --git a/tests/ui/const-generics/generic_const_exprs/trivial-anon-const-use-cases.min.stderr b/tests/ui/const-generics/generic_const_exprs/trivial-anon-const-use-cases.min.stderr new file mode 100644 index 00000000000..6a868e95c89 --- /dev/null +++ b/tests/ui/const-generics/generic_const_exprs/trivial-anon-const-use-cases.min.stderr @@ -0,0 +1,11 @@ +error: generic parameters may not be used in const operations + --> $DIR/trivial-anon-const-use-cases.rs:14:19 + | +LL | stuff: [u8; { S + 1 }], // `S + 1` is NOT a valid const expression in this context. + | ^ cannot perform const operation using `S` + | + = help: const parameters may only be used as standalone arguments here, i.e. `S` + = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions + +error: aborting due to 1 previous error + diff --git a/tests/ui/const-generics/generic_const_exprs/trivial-anon-const-use-cases.rs b/tests/ui/const-generics/generic_const_exprs/trivial-anon-const-use-cases.rs new file mode 100644 index 00000000000..b1fd4cbc661 --- /dev/null +++ b/tests/ui/const-generics/generic_const_exprs/trivial-anon-const-use-cases.rs @@ -0,0 +1,19 @@ +//! Regression test for <https://github.com/rust-lang/rust/issues/79429>. + +//@ revisions: full min +#![cfg_attr(full, feature(generic_const_exprs))] +#![cfg_attr(full, allow(incomplete_features))] + +struct X<const S: usize>; + +impl<const S: usize> X<S> { + const LEN: usize = S + 1; // `S + 1` is a valid const expression in this context. +} + +struct Y<const S: usize> { + stuff: [u8; { S + 1 }], // `S + 1` is NOT a valid const expression in this context. + //[min]~^ ERROR generic parameters may not be used in const operations + //[full]~^^ ERROR unconstrained generic constant +} + +fn main() {} diff --git a/tests/ui/const-generics/issues/issue-68366.min.stderr b/tests/ui/const-generics/issues/issue-68366.min.stderr index 10b5a06682f..4d721e958cb 100644 --- a/tests/ui/const-generics/issues/issue-68366.min.stderr +++ b/tests/ui/const-generics/issues/issue-68366.min.stderr @@ -4,7 +4,7 @@ error: generic parameters may not be used in const operations LL | impl <const N: usize> Collatz<{Some(N)}> {} | ^ cannot perform const operation using `N` | - = help: const parameters may only be used as standalone arguments, i.e. `N` + = help: const parameters may only be used as standalone arguments here, i.e. `N` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: `Option<usize>` is forbidden as the type of a const generic parameter diff --git a/tests/ui/const-generics/issues/issue-76701-ty-param-in-const.stderr b/tests/ui/const-generics/issues/issue-76701-ty-param-in-const.stderr index da2fbc52a6c..e58c894a270 100644 --- a/tests/ui/const-generics/issues/issue-76701-ty-param-in-const.stderr +++ b/tests/ui/const-generics/issues/issue-76701-ty-param-in-const.stderr @@ -13,7 +13,7 @@ error: generic parameters may not be used in const operations LL | fn const_param<const N: usize>() -> [u8; N + 1] { | ^ cannot perform const operation using `N` | - = help: const parameters may only be used as standalone arguments, i.e. `N` + = help: const parameters may only be used as standalone arguments here, i.e. `N` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: aborting due to 2 previous errors diff --git a/tests/ui/const-generics/issues/issue-80375.stderr b/tests/ui/const-generics/issues/issue-80375.stderr index 015196f8605..9a15e0380a1 100644 --- a/tests/ui/const-generics/issues/issue-80375.stderr +++ b/tests/ui/const-generics/issues/issue-80375.stderr @@ -4,7 +4,7 @@ error: generic parameters may not be used in const operations LL | struct MyArray<const COUNT: usize>([u8; COUNT + 1]); | ^^^^^ cannot perform const operation using `COUNT` | - = help: const parameters may only be used as standalone arguments, i.e. `COUNT` + = help: const parameters may only be used as standalone arguments here, i.e. `COUNT` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/legacy-const-generics-bad.stderr b/tests/ui/const-generics/legacy-const-generics-bad.stderr index 3a5fa417075..a8681d62053 100644 --- a/tests/ui/const-generics/legacy-const-generics-bad.stderr +++ b/tests/ui/const-generics/legacy-const-generics-bad.stderr @@ -16,7 +16,7 @@ error: generic parameters may not be used in const operations LL | legacy_const_generics::foo(0, N + 1, 2); | ^ cannot perform const operation using `N` | - = help: const parameters may only be used as standalone arguments, i.e. `N` + = help: const parameters may only be used as standalone arguments here, i.e. `N` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: aborting due to 2 previous errors diff --git a/tests/ui/const-generics/min_const_generics/complex-expression.stderr b/tests/ui/const-generics/min_const_generics/complex-expression.stderr index 3affdcf9b03..35039bb4109 100644 --- a/tests/ui/const-generics/min_const_generics/complex-expression.stderr +++ b/tests/ui/const-generics/min_const_generics/complex-expression.stderr @@ -4,7 +4,7 @@ error: generic parameters may not be used in const operations LL | struct Break0<const N: usize>([u8; { N + 1 }]); | ^ cannot perform const operation using `N` | - = help: const parameters may only be used as standalone arguments, i.e. `N` + = help: const parameters may only be used as standalone arguments here, i.e. `N` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations @@ -13,7 +13,7 @@ error: generic parameters may not be used in const operations LL | struct Break1<const N: usize>([u8; { { N } }]); | ^ cannot perform const operation using `N` | - = help: const parameters may only be used as standalone arguments, i.e. `N` + = help: const parameters may only be used as standalone arguments here, i.e. `N` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations @@ -22,7 +22,7 @@ error: generic parameters may not be used in const operations LL | let _: [u8; N + 1]; | ^ cannot perform const operation using `N` | - = help: const parameters may only be used as standalone arguments, i.e. `N` + = help: const parameters may only be used as standalone arguments here, i.e. `N` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations @@ -31,7 +31,7 @@ error: generic parameters may not be used in const operations LL | let _ = [0; N + 1]; | ^ cannot perform const operation using `N` | - = help: const parameters may only be used as standalone arguments, i.e. `N` + = help: const parameters may only be used as standalone arguments here, i.e. `N` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations diff --git a/tests/ui/const-generics/repeat_expr_hack_gives_right_generics.stderr b/tests/ui/const-generics/repeat_expr_hack_gives_right_generics.stderr index ead6c621d60..fe32fbcc87d 100644 --- a/tests/ui/const-generics/repeat_expr_hack_gives_right_generics.stderr +++ b/tests/ui/const-generics/repeat_expr_hack_gives_right_generics.stderr @@ -4,7 +4,7 @@ error: generic parameters may not be used in const operations LL | bar::<{ [1; N] }>(); | ^ cannot perform const operation using `N` | - = help: const parameters may only be used as standalone arguments, i.e. `N` + = help: const parameters may only be used as standalone arguments here, i.e. `N` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations @@ -13,7 +13,7 @@ error: generic parameters may not be used in const operations LL | bar::<{ [1; { N + 1 }] }>(); | ^ cannot perform const operation using `N` | - = help: const parameters may only be used as standalone arguments, i.e. `N` + = help: const parameters may only be used as standalone arguments here, i.e. `N` = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: aborting due to 2 previous errors diff --git a/tests/ui/consts/auxiliary/unstable_intrinsic.rs b/tests/ui/consts/auxiliary/unstable_intrinsic.rs index 45631df7859..c1c7571e0c9 100644 --- a/tests/ui/consts/auxiliary/unstable_intrinsic.rs +++ b/tests/ui/consts/auxiliary/unstable_intrinsic.rs @@ -8,4 +8,4 @@ pub const unsafe fn size_of_val<T>(x: *const T) -> usize; #[unstable(feature = "unstable", issue = "42")] #[rustc_const_unstable(feature = "unstable", issue = "42")] #[rustc_intrinsic] -pub const unsafe fn min_align_of_val<T>(x: *const T) -> usize; +pub const unsafe fn align_of_val<T>(x: *const T) -> usize; diff --git a/tests/ui/consts/const-adt-align-mismatch.rs b/tests/ui/consts/const-adt-align-mismatch.rs index 8faddbff30d..6ff74ad3a9c 100644 --- a/tests/ui/consts/const-adt-align-mismatch.rs +++ b/tests/ui/consts/const-adt-align-mismatch.rs @@ -18,5 +18,5 @@ static FOO: Foo = Foo::C; fn main() { assert_eq!(FOO, Foo::C); assert_eq!(mem::size_of::<Foo>(), 12); - assert_eq!(mem::min_align_of::<Foo>(), 4); + assert_eq!(mem::align_of::<Foo>(), 4); } diff --git a/tests/ui/consts/const-size_of_val-align_of_val-extern-type.rs b/tests/ui/consts/const-size_of_val-align_of_val-extern-type.rs index 14cdf6bb7c6..423ff37baef 100644 --- a/tests/ui/consts/const-size_of_val-align_of_val-extern-type.rs +++ b/tests/ui/consts/const-size_of_val-align_of_val-extern-type.rs @@ -1,13 +1,13 @@ #![feature(extern_types)] #![feature(core_intrinsics)] -use std::intrinsics::{min_align_of_val, size_of_val}; +use std::intrinsics::{align_of_val, size_of_val}; extern "C" { type Opaque; } const _SIZE: usize = unsafe { size_of_val(&4 as *const i32 as *const Opaque) }; //~ ERROR layout -const _ALIGN: usize = unsafe { min_align_of_val(&4 as *const i32 as *const Opaque) }; //~ ERROR layout +const _ALIGN: usize = unsafe { align_of_val(&4 as *const i32 as *const Opaque) }; //~ ERROR layout fn main() {} diff --git a/tests/ui/consts/const-size_of_val-align_of_val-extern-type.stderr b/tests/ui/consts/const-size_of_val-align_of_val-extern-type.stderr index 64b7a4129e0..c78626bdefc 100644 --- a/tests/ui/consts/const-size_of_val-align_of_val-extern-type.stderr +++ b/tests/ui/consts/const-size_of_val-align_of_val-extern-type.stderr @@ -7,8 +7,8 @@ LL | const _SIZE: usize = unsafe { size_of_val(&4 as *const i32 as *const Opaque error[E0080]: `extern type` does not have known layout --> $DIR/const-size_of_val-align_of_val-extern-type.rs:11:32 | -LL | const _ALIGN: usize = unsafe { min_align_of_val(&4 as *const i32 as *const Opaque) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `_ALIGN` failed here +LL | const _ALIGN: usize = unsafe { align_of_val(&4 as *const i32 as *const Opaque) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `_ALIGN` failed here error: aborting due to 2 previous errors diff --git a/tests/ui/consts/const-unstable-intrinsic.rs b/tests/ui/consts/const-unstable-intrinsic.rs index 890a30c73c8..d130eb6c707 100644 --- a/tests/ui/consts/const-unstable-intrinsic.rs +++ b/tests/ui/consts/const-unstable-intrinsic.rs @@ -17,13 +17,13 @@ const fn const_main() { unstable_intrinsic::size_of_val(&x); //~^ERROR: unstable library feature `unstable` //~|ERROR: not yet stable as a const intrinsic - unstable_intrinsic::min_align_of_val(&x); + unstable_intrinsic::align_of_val(&x); //~^ERROR: unstable library feature `unstable` //~|ERROR: not yet stable as a const intrinsic size_of_val(&x); //~^ERROR: cannot use `#[feature(local)]` - min_align_of_val(&x); + align_of_val(&x); //~^ERROR: cannot use `#[feature(local)]` } } @@ -35,7 +35,7 @@ pub const unsafe fn size_of_val<T>(x: *const T) -> usize; #[unstable(feature = "local", issue = "42")] #[rustc_const_unstable(feature = "local", issue = "42")] #[rustc_intrinsic] -pub const unsafe fn min_align_of_val<T>(x: *const T) -> usize; +pub const unsafe fn align_of_val<T>(x: *const T) -> usize; #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")] diff --git a/tests/ui/consts/const-unstable-intrinsic.stderr b/tests/ui/consts/const-unstable-intrinsic.stderr index 7e7ba966cee..973c7bae586 100644 --- a/tests/ui/consts/const-unstable-intrinsic.stderr +++ b/tests/ui/consts/const-unstable-intrinsic.stderr @@ -11,8 +11,8 @@ LL | unstable_intrinsic::size_of_val(&x); error[E0658]: use of unstable library feature `unstable` --> $DIR/const-unstable-intrinsic.rs:20:9 | -LL | unstable_intrinsic::min_align_of_val(&x); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | unstable_intrinsic::align_of_val(&x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #42 <https://github.com/rust-lang/rust/issues/42> for more information = help: add `#![feature(unstable)]` to the crate attributes to enable @@ -29,11 +29,11 @@ help: add `#![feature(unstable)]` to the crate attributes to enable LL + #![feature(unstable)] | -error: `min_align_of_val` is not yet stable as a const intrinsic +error: `align_of_val` is not yet stable as a const intrinsic --> $DIR/const-unstable-intrinsic.rs:20:9 | -LL | unstable_intrinsic::min_align_of_val(&x); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | unstable_intrinsic::align_of_val(&x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | help: add `#![feature(unstable)]` to the crate attributes to enable | @@ -55,8 +55,8 @@ LL | const fn const_main() { error: const function that might be (indirectly) exposed to stable cannot use `#[feature(local)]` --> $DIR/const-unstable-intrinsic.rs:26:9 | -LL | min_align_of_val(&x); - | ^^^^^^^^^^^^^^^^^^^^ +LL | align_of_val(&x); + | ^^^^^^^^^^^^^^^^ | help: if the function is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]` | diff --git a/tests/ui/consts/gate-do-not-const-check.rs b/tests/ui/consts/gate-do-not-const-check.rs index be7e70dfabb..0ebb1e7c82e 100644 --- a/tests/ui/consts/gate-do-not-const-check.rs +++ b/tests/ui/consts/gate-do-not-const-check.rs @@ -1,5 +1,7 @@ #[rustc_do_not_const_check] -//~^ ERROR this is an internal attribute that will never be stable +//~^ ERROR use of an internal attribute [E0658] +//~| NOTE the `#[rustc_do_not_const_check]` attribute is an internal implementation detail that will never be stable +//~| NOTE `#[rustc_do_not_const_check]` skips const-check for this function's body const fn foo() {} fn main() {} diff --git a/tests/ui/consts/gate-do-not-const-check.stderr b/tests/ui/consts/gate-do-not-const-check.stderr index 74ea71c4ed8..778ee50e71b 100644 --- a/tests/ui/consts/gate-do-not-const-check.stderr +++ b/tests/ui/consts/gate-do-not-const-check.stderr @@ -1,11 +1,12 @@ -error[E0658]: this is an internal attribute that will never be stable +error[E0658]: use of an internal attribute --> $DIR/gate-do-not-const-check.rs:1:1 | LL | #[rustc_do_not_const_check] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: the `#[rustc_do_not_const_check]` attribute is an internal implementation detail that will never be stable + = note: `#[rustc_do_not_const_check]` skips const-check for this function's body error: aborting due to 1 previous error diff --git a/tests/ui/coroutine/auto-trait-regions.stderr b/tests/ui/coroutine/auto-trait-regions.stderr index a9a0bde2ba0..a3b5a5f006e 100644 --- a/tests/ui/coroutine/auto-trait-regions.stderr +++ b/tests/ui/coroutine/auto-trait-regions.stderr @@ -11,7 +11,7 @@ LL | assert_foo(a); | help: consider using a `let` binding to create a longer lived value | -LL ~ let binding = true; +LL ~ let mut binding = true; LL ~ let a = A(&mut binding, &mut true, No); | @@ -28,7 +28,7 @@ LL | assert_foo(a); | help: consider using a `let` binding to create a longer lived value | -LL ~ let binding = true; +LL ~ let mut binding = true; LL ~ let a = A(&mut true, &mut binding, No); | diff --git a/tests/ui/deprecation/deprecated_no_stack_check.rs b/tests/ui/deprecation/deprecated_no_stack_check.rs index 8e1f5bbf045..ef482098634 100644 --- a/tests/ui/deprecation/deprecated_no_stack_check.rs +++ b/tests/ui/deprecation/deprecated_no_stack_check.rs @@ -1,3 +1,5 @@ +//@ normalize-stderr: "you are using [0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9]+)?( \([^)]*\))?" -> "you are using $$RUSTC_VERSION" + #![deny(warnings)] #![feature(no_stack_check)] //~^ ERROR: feature has been removed [E0557] diff --git a/tests/ui/deprecation/deprecated_no_stack_check.stderr b/tests/ui/deprecation/deprecated_no_stack_check.stderr index d78ca20f10b..2d08b1b8db5 100644 --- a/tests/ui/deprecation/deprecated_no_stack_check.stderr +++ b/tests/ui/deprecation/deprecated_no_stack_check.stderr @@ -1,8 +1,10 @@ error[E0557]: feature has been removed - --> $DIR/deprecated_no_stack_check.rs:2:12 + --> $DIR/deprecated_no_stack_check.rs:4:12 | LL | #![feature(no_stack_check)] | ^^^^^^^^^^^^^^ feature has been removed + | + = note: removed in 1.0.0 (you are using $RUSTC_VERSION); see <https://github.com/rust-lang/rust/pull/40110> for more information error: aborting due to 1 previous error diff --git a/tests/ui/exclusive-drop-and-copy.rs b/tests/ui/derives/copy-drop-mutually-exclusive.rs index 210ecaed756..5147605910d 100644 --- a/tests/ui/exclusive-drop-and-copy.rs +++ b/tests/ui/derives/copy-drop-mutually-exclusive.rs @@ -1,4 +1,4 @@ -// issue #20126 +//! Regression test for issue #20126: Copy and Drop traits are mutually exclusive #[derive(Copy, Clone)] //~ ERROR the trait `Copy` cannot be implemented struct Foo; diff --git a/tests/ui/exclusive-drop-and-copy.stderr b/tests/ui/derives/copy-drop-mutually-exclusive.stderr index 340ca89c396..771bbc92569 100644 --- a/tests/ui/exclusive-drop-and-copy.stderr +++ b/tests/ui/derives/copy-drop-mutually-exclusive.stderr @@ -1,11 +1,11 @@ error[E0184]: the trait `Copy` cannot be implemented for this type; the type has a destructor - --> $DIR/exclusive-drop-and-copy.rs:3:10 + --> $DIR/copy-drop-mutually-exclusive.rs:3:10 | LL | #[derive(Copy, Clone)] | ^^^^ `Copy` not allowed on types with destructors error[E0184]: the trait `Copy` cannot be implemented for this type; the type has a destructor - --> $DIR/exclusive-drop-and-copy.rs:10:10 + --> $DIR/copy-drop-mutually-exclusive.rs:10:10 | LL | #[derive(Copy, Clone)] | ^^^^ `Copy` not allowed on types with destructors diff --git a/tests/ui/diagnostic_namespace/multiline_spans.rs b/tests/ui/diagnostic_namespace/multiline_spans.rs new file mode 100644 index 00000000000..994dd9fd011 --- /dev/null +++ b/tests/ui/diagnostic_namespace/multiline_spans.rs @@ -0,0 +1,55 @@ +#![crate_type = "lib"] +#![deny(unknown_or_malformed_diagnostic_attributes)] + + +#[diagnostic::on_unimplemented(message = "here is a big \ + multiline string \ + {unknown}")] +//~^ ERROR there is no parameter `unknown` on trait `MultiLine` [unknown_or_malformed_diagnostic_attributes] +pub trait MultiLine {} + +#[diagnostic::on_unimplemented(message = "here is a big \ + multiline string {unknown}")] +//~^ ERROR there is no parameter `unknown` on trait `MultiLine2` [unknown_or_malformed_diagnostic_attributes] +pub trait MultiLine2 {} + +#[diagnostic::on_unimplemented(message = "here is a big \ + multiline string {unknown}")] +//~^ ERROR there is no parameter `unknown` on trait `MultiLine3` [unknown_or_malformed_diagnostic_attributes] +pub trait MultiLine3 {} + + +#[diagnostic::on_unimplemented(message = "here is a big \ +\ + \ + \ + \ + multiline string {unknown}")] +//~^ ERROR there is no parameter `unknown` on trait `MultiLine4` [unknown_or_malformed_diagnostic_attributes] +pub trait MultiLine4 {} + +#[diagnostic::on_unimplemented(message = "here is a big \ + multiline string \ + {Self:+}")] +//~^ ERROR invalid format specifier [unknown_or_malformed_diagnostic_attributes] +pub trait MultiLineFmt {} + +#[diagnostic::on_unimplemented(message = "here is a big \ + multiline string {Self:X}")] +//~^ ERROR invalid format specifier [unknown_or_malformed_diagnostic_attributes] +pub trait MultiLineFmt2 {} + +#[diagnostic::on_unimplemented(message = "here is a big \ + multiline string {Self:#}")] +//~^ ERROR invalid format specifier [unknown_or_malformed_diagnostic_attributes] +pub trait MultiLineFmt3 {} + + +#[diagnostic::on_unimplemented(message = "here is a big \ +\ + \ + \ + \ + multiline string {Self:?}")] +//~^ ERROR invalid format specifier [unknown_or_malformed_diagnostic_attributes] +pub trait MultiLineFmt4 {} diff --git a/tests/ui/diagnostic_namespace/multiline_spans.stderr b/tests/ui/diagnostic_namespace/multiline_spans.stderr new file mode 100644 index 00000000000..894bfe3d90a --- /dev/null +++ b/tests/ui/diagnostic_namespace/multiline_spans.stderr @@ -0,0 +1,71 @@ +error: there is no parameter `unknown` on trait `MultiLine` + --> $DIR/multiline_spans.rs:7:43 + | +LL | ... {unknown}")] + | ^^^^^^^ + | + = help: expect either a generic argument name or `{Self}` as format argument +note: the lint level is defined here + --> $DIR/multiline_spans.rs:2:9 + | +LL | #![deny(unknown_or_malformed_diagnostic_attributes)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: there is no parameter `unknown` on trait `MultiLine2` + --> $DIR/multiline_spans.rs:12:60 + | +LL | ... multiline string {unknown}")] + | ^^^^^^^ + | + = help: expect either a generic argument name or `{Self}` as format argument + +error: there is no parameter `unknown` on trait `MultiLine3` + --> $DIR/multiline_spans.rs:17:23 + | +LL | multiline string {unknown}")] + | ^^^^^^^ + | + = help: expect either a generic argument name or `{Self}` as format argument + +error: there is no parameter `unknown` on trait `MultiLine4` + --> $DIR/multiline_spans.rs:27:23 + | +LL | multiline string {unknown}")] + | ^^^^^^^ + | + = help: expect either a generic argument name or `{Self}` as format argument + +error: invalid format specifier + --> $DIR/multiline_spans.rs:33:47 + | +LL | ... {Self:+}")] + | ^^ + | + = help: no format specifier are supported in this position + +error: invalid format specifier + --> $DIR/multiline_spans.rs:38:64 + | +LL | ... multiline string {Self:X}")] + | ^^ + | + = help: no format specifier are supported in this position + +error: invalid format specifier + --> $DIR/multiline_spans.rs:43:27 + | +LL | multiline string {Self:#}")] + | ^^ + | + = help: no format specifier are supported in this position + +error: invalid format specifier + --> $DIR/multiline_spans.rs:53:27 + | +LL | multiline string {Self:?}")] + | ^^ + | + = help: no format specifier are supported in this position + +error: aborting due to 8 previous errors + diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.rs b/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.rs index 44f269eb967..4762d9e793f 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.rs +++ b/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.rs @@ -12,6 +12,8 @@ trait ImportantTrait2 {} #[diagnostic::on_unimplemented(message = "Test {1:}")] //~^WARN positional format arguments are not allowed here //~|WARN positional format arguments are not allowed here +//~|WARN invalid format specifier [unknown_or_malformed_diagnostic_attributes] +//~|WARN invalid format specifier [unknown_or_malformed_diagnostic_attributes] trait ImportantTrait3 {} #[diagnostic::on_unimplemented(message = "Test {Self:123}")] @@ -20,17 +22,22 @@ trait ImportantTrait3 {} trait ImportantTrait4 {} #[diagnostic::on_unimplemented(message = "Test {Self:!}")] -//~^WARN expected `}`, found `!` -//~|WARN expected `}`, found `!` -//~|WARN unmatched `}` found -//~|WARN unmatched `}` found +//~^WARN invalid format specifier [unknown_or_malformed_diagnostic_attributes] +//~|WARN invalid format specifier [unknown_or_malformed_diagnostic_attributes] trait ImportantTrait5 {} +#[diagnostic::on_unimplemented(message = "Test {Self:}")] +//~^WARN invalid format specifier [unknown_or_malformed_diagnostic_attributes] +//~|WARN invalid format specifier [unknown_or_malformed_diagnostic_attributes] +trait ImportantTrait6 {} + + fn check_1(_: impl ImportantTrait1) {} fn check_2(_: impl ImportantTrait2) {} fn check_3(_: impl ImportantTrait3) {} fn check_4(_: impl ImportantTrait4) {} fn check_5(_: impl ImportantTrait5) {} +fn check_6(_: impl ImportantTrait6) {} fn main() { check_1(()); @@ -42,5 +49,7 @@ fn main() { check_4(()); //~^ERROR Test () check_5(()); - //~^ERROR Test {Self:!} + //~^ERROR Test () + check_6(()); + //~^ERROR Test () } diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.stderr index a82a1e78da0..2670d0630f7 100644 --- a/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.stderr +++ b/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.stderr @@ -14,6 +14,14 @@ LL | #[diagnostic::on_unimplemented(message = "Test {}")] | = help: only named format arguments with the name of one of the generic types are allowed in this context +warning: invalid format specifier + --> $DIR/broken_format.rs:12:50 + | +LL | #[diagnostic::on_unimplemented(message = "Test {1:}")] + | ^ + | + = help: no format specifier are supported in this position + warning: positional format arguments are not allowed here --> $DIR/broken_format.rs:12:49 | @@ -23,24 +31,28 @@ LL | #[diagnostic::on_unimplemented(message = "Test {1:}")] = help: only named format arguments with the name of one of the generic types are allowed in this context warning: invalid format specifier - --> $DIR/broken_format.rs:17:42 + --> $DIR/broken_format.rs:19:53 | LL | #[diagnostic::on_unimplemented(message = "Test {Self:123}")] - | ^^^^^^^^^^^^^^^^^ + | ^^^^ | = help: no format specifier are supported in this position -warning: expected `}`, found `!` - --> $DIR/broken_format.rs:22:42 +warning: invalid format specifier + --> $DIR/broken_format.rs:24:53 | LL | #[diagnostic::on_unimplemented(message = "Test {Self:!}")] - | ^^^^^^^^^^^^^^^ + | ^^ + | + = help: no format specifier are supported in this position -warning: unmatched `}` found - --> $DIR/broken_format.rs:22:42 +warning: invalid format specifier + --> $DIR/broken_format.rs:29:53 | -LL | #[diagnostic::on_unimplemented(message = "Test {Self:!}")] - | ^^^^^^^^^^^^^^^ +LL | #[diagnostic::on_unimplemented(message = "Test {Self:}")] + | ^ + | + = help: no format specifier are supported in this position warning: unmatched `}` found --> $DIR/broken_format.rs:2:42 @@ -51,7 +63,7 @@ LL | #[diagnostic::on_unimplemented(message = "{{Test } thing")] = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: {{Test } thing - --> $DIR/broken_format.rs:36:13 + --> $DIR/broken_format.rs:43:13 | LL | check_1(()); | ------- ^^ the trait `ImportantTrait1` is not implemented for `()` @@ -64,7 +76,7 @@ help: this trait has no implementations, consider adding one LL | trait ImportantTrait1 {} | ^^^^^^^^^^^^^^^^^^^^^ note: required by a bound in `check_1` - --> $DIR/broken_format.rs:29:20 + --> $DIR/broken_format.rs:35:20 | LL | fn check_1(_: impl ImportantTrait1) {} | ^^^^^^^^^^^^^^^ required by this bound in `check_1` @@ -79,7 +91,7 @@ LL | #[diagnostic::on_unimplemented(message = "Test {}")] = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: Test {} - --> $DIR/broken_format.rs:38:13 + --> $DIR/broken_format.rs:45:13 | LL | check_2(()); | ------- ^^ the trait `ImportantTrait2` is not implemented for `()` @@ -92,11 +104,20 @@ help: this trait has no implementations, consider adding one LL | trait ImportantTrait2 {} | ^^^^^^^^^^^^^^^^^^^^^ note: required by a bound in `check_2` - --> $DIR/broken_format.rs:30:20 + --> $DIR/broken_format.rs:36:20 | LL | fn check_2(_: impl ImportantTrait2) {} | ^^^^^^^^^^^^^^^ required by this bound in `check_2` +warning: invalid format specifier + --> $DIR/broken_format.rs:12:50 + | +LL | #[diagnostic::on_unimplemented(message = "Test {1:}")] + | ^ + | + = help: no format specifier are supported in this position + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + warning: positional format arguments are not allowed here --> $DIR/broken_format.rs:12:49 | @@ -107,7 +128,7 @@ LL | #[diagnostic::on_unimplemented(message = "Test {1:}")] = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: Test {1} - --> $DIR/broken_format.rs:40:13 + --> $DIR/broken_format.rs:47:13 | LL | check_3(()); | ------- ^^ the trait `ImportantTrait3` is not implemented for `()` @@ -115,27 +136,27 @@ LL | check_3(()); | required by a bound introduced by this call | help: this trait has no implementations, consider adding one - --> $DIR/broken_format.rs:15:1 + --> $DIR/broken_format.rs:17:1 | LL | trait ImportantTrait3 {} | ^^^^^^^^^^^^^^^^^^^^^ note: required by a bound in `check_3` - --> $DIR/broken_format.rs:31:20 + --> $DIR/broken_format.rs:37:20 | LL | fn check_3(_: impl ImportantTrait3) {} | ^^^^^^^^^^^^^^^ required by this bound in `check_3` warning: invalid format specifier - --> $DIR/broken_format.rs:17:42 + --> $DIR/broken_format.rs:19:53 | LL | #[diagnostic::on_unimplemented(message = "Test {Self:123}")] - | ^^^^^^^^^^^^^^^^^ + | ^^^^ | = help: no format specifier are supported in this position = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error[E0277]: Test () - --> $DIR/broken_format.rs:42:13 + --> $DIR/broken_format.rs:49:13 | LL | check_4(()); | ------- ^^ the trait `ImportantTrait4` is not implemented for `()` @@ -143,34 +164,27 @@ LL | check_4(()); | required by a bound introduced by this call | help: this trait has no implementations, consider adding one - --> $DIR/broken_format.rs:20:1 + --> $DIR/broken_format.rs:22:1 | LL | trait ImportantTrait4 {} | ^^^^^^^^^^^^^^^^^^^^^ note: required by a bound in `check_4` - --> $DIR/broken_format.rs:32:20 + --> $DIR/broken_format.rs:38:20 | LL | fn check_4(_: impl ImportantTrait4) {} | ^^^^^^^^^^^^^^^ required by this bound in `check_4` -warning: expected `}`, found `!` - --> $DIR/broken_format.rs:22:42 - | -LL | #[diagnostic::on_unimplemented(message = "Test {Self:!}")] - | ^^^^^^^^^^^^^^^ - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -warning: unmatched `}` found - --> $DIR/broken_format.rs:22:42 +warning: invalid format specifier + --> $DIR/broken_format.rs:24:53 | LL | #[diagnostic::on_unimplemented(message = "Test {Self:!}")] - | ^^^^^^^^^^^^^^^ + | ^^ | + = help: no format specifier are supported in this position = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error[E0277]: Test {Self:!} - --> $DIR/broken_format.rs:44:13 +error[E0277]: Test () + --> $DIR/broken_format.rs:51:13 | LL | check_5(()); | ------- ^^ the trait `ImportantTrait5` is not implemented for `()` @@ -183,11 +197,39 @@ help: this trait has no implementations, consider adding one LL | trait ImportantTrait5 {} | ^^^^^^^^^^^^^^^^^^^^^ note: required by a bound in `check_5` - --> $DIR/broken_format.rs:33:20 + --> $DIR/broken_format.rs:39:20 | LL | fn check_5(_: impl ImportantTrait5) {} | ^^^^^^^^^^^^^^^ required by this bound in `check_5` -error: aborting due to 5 previous errors; 12 warnings emitted +warning: invalid format specifier + --> $DIR/broken_format.rs:29:53 + | +LL | #[diagnostic::on_unimplemented(message = "Test {Self:}")] + | ^ + | + = help: no format specifier are supported in this position + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0277]: Test () + --> $DIR/broken_format.rs:53:13 + | +LL | check_6(()); + | ------- ^^ the trait `ImportantTrait6` is not implemented for `()` + | | + | required by a bound introduced by this call + | +help: this trait has no implementations, consider adding one + --> $DIR/broken_format.rs:32:1 + | +LL | trait ImportantTrait6 {} + | ^^^^^^^^^^^^^^^^^^^^^ +note: required by a bound in `check_6` + --> $DIR/broken_format.rs:40:20 + | +LL | fn check_6(_: impl ImportantTrait6) {} + | ^^^^^^^^^^^^^^^ required by this bound in `check_6` + +error: aborting due to 6 previous errors; 14 warnings emitted For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/illegal-ufcs-drop.fixed b/tests/ui/drop/explicit-drop-call-error.fixed index 2b1c967ed1e..f2f0245df96 100644 --- a/tests/ui/illegal-ufcs-drop.fixed +++ b/tests/ui/drop/explicit-drop-call-error.fixed @@ -1,3 +1,5 @@ +//! Test error for explicit destructor method calls via UFCS + //@ run-rustfix #![allow(dropping_references)] diff --git a/tests/ui/illegal-ufcs-drop.rs b/tests/ui/drop/explicit-drop-call-error.rs index 99dda0dab34..e41c806bd1e 100644 --- a/tests/ui/illegal-ufcs-drop.rs +++ b/tests/ui/drop/explicit-drop-call-error.rs @@ -1,3 +1,5 @@ +//! Test error for explicit destructor method calls via UFCS + //@ run-rustfix #![allow(dropping_references)] diff --git a/tests/ui/illegal-ufcs-drop.stderr b/tests/ui/drop/explicit-drop-call-error.stderr index 4f214a12747..95d5c31ab6d 100644 --- a/tests/ui/illegal-ufcs-drop.stderr +++ b/tests/ui/drop/explicit-drop-call-error.stderr @@ -1,5 +1,5 @@ error[E0040]: explicit use of destructor method - --> $DIR/illegal-ufcs-drop.rs:12:5 + --> $DIR/explicit-drop-call-error.rs:14:5 | LL | Drop::drop(&mut Foo) | ^^^^^^^^^^ diff --git a/tests/ui/editions/edition-keywords-2018-2015-parsing.stderr b/tests/ui/editions/edition-keywords-2018-2015-parsing.stderr index 152a6f3a41e..34f5c7d3084 100644 --- a/tests/ui/editions/edition-keywords-2018-2015-parsing.stderr +++ b/tests/ui/editions/edition-keywords-2018-2015-parsing.stderr @@ -44,22 +44,22 @@ note: while trying to match `r#async` LL | (r#async) => (1) | ^^^^^^^ -error: macro expansion ends with an incomplete expression: expected one of `move`, `use`, `|`, or `||` +error: macro expansion ends with an incomplete expression: expected one of `move`, `use`, `{`, `|`, or `||` --> $DIR/auxiliary/edition-kw-macro-2015.rs:27:23 | LL | ($i: ident) => ($i) - | ^ expected one of `move`, `use`, `|`, or `||` + | ^ expected one of `move`, `use`, `{`, `|`, or `||` | ::: $DIR/edition-keywords-2018-2015-parsing.rs:22:8 | LL | if passes_ident!(async) == 1 {} // FIXME: Edition hygiene bug, async here is 2018 and reserved | -------------------- in this macro invocation -error: macro expansion ends with an incomplete expression: expected one of `move`, `use`, `|`, or `||` +error: macro expansion ends with an incomplete expression: expected one of `move`, `use`, `{`, `|`, or `||` --> $DIR/edition-keywords-2018-2015-parsing.rs:24:24 | LL | if passes_tt!(async) == 1 {} - | ^ expected one of `move`, `use`, `|`, or `||` + | ^ expected one of `move`, `use`, `{`, `|`, or `||` error[E0308]: mismatched types --> $DIR/edition-keywords-2018-2015-parsing.rs:29:33 diff --git a/tests/ui/editions/edition-keywords-2018-2018-parsing.stderr b/tests/ui/editions/edition-keywords-2018-2018-parsing.stderr index 53f1b827f9c..dd3f4938c74 100644 --- a/tests/ui/editions/edition-keywords-2018-2018-parsing.stderr +++ b/tests/ui/editions/edition-keywords-2018-2018-parsing.stderr @@ -44,34 +44,34 @@ note: while trying to match `r#async` LL | (r#async) => (1) | ^^^^^^^ -error: macro expansion ends with an incomplete expression: expected one of `move`, `use`, `|`, or `||` +error: macro expansion ends with an incomplete expression: expected one of `move`, `use`, `{`, `|`, or `||` --> $DIR/auxiliary/edition-kw-macro-2018.rs:27:23 | LL | ($i: ident) => ($i) - | ^ expected one of `move`, `use`, `|`, or `||` + | ^ expected one of `move`, `use`, `{`, `|`, or `||` | ::: $DIR/edition-keywords-2018-2018-parsing.rs:29:8 | LL | if passes_ident!(async) == 1 {} // FIXME: Edition hygiene bug, async here is 2018 and reserved | -------------------- in this macro invocation -error: macro expansion ends with an incomplete expression: expected one of `move`, `use`, `|`, or `||` +error: macro expansion ends with an incomplete expression: expected one of `move`, `use`, `{`, `|`, or `||` --> $DIR/edition-keywords-2018-2018-parsing.rs:31:24 | LL | if passes_tt!(async) == 1 {} - | ^ expected one of `move`, `use`, `|`, or `||` + | ^ expected one of `move`, `use`, `{`, `|`, or `||` -error: macro expansion ends with an incomplete expression: expected one of `move`, `use`, `|`, or `||` +error: macro expansion ends with an incomplete expression: expected one of `move`, `use`, `{`, `|`, or `||` --> $DIR/edition-keywords-2018-2018-parsing.rs:14:23 | LL | ($i: ident) => ($i) - | ^ expected one of `move`, `use`, `|`, or `||` + | ^ expected one of `move`, `use`, `{`, `|`, or `||` -error: macro expansion ends with an incomplete expression: expected one of `move`, `use`, `|`, or `||` +error: macro expansion ends with an incomplete expression: expected one of `move`, `use`, `{`, `|`, or `||` --> $DIR/edition-keywords-2018-2018-parsing.rs:35:30 | LL | if local_passes_tt!(async) == 1 {} - | ^ expected one of `move`, `use`, `|`, or `||` + | ^ expected one of `move`, `use`, `{`, `|`, or `||` error[E0308]: mismatched types --> $DIR/edition-keywords-2018-2018-parsing.rs:40:33 diff --git a/tests/ui/editions/unsafe-attr-edition-span.e2024.stderr b/tests/ui/editions/unsafe-attr-edition-span.e2024.stderr new file mode 100644 index 00000000000..28871a1cce4 --- /dev/null +++ b/tests/ui/editions/unsafe-attr-edition-span.e2024.stderr @@ -0,0 +1,24 @@ +error: unsafe attribute used without unsafe + --> $DIR/unsafe-attr-edition-span.rs:21:3 + | +LL | #[no_mangle] + | ^^^^^^^^^ usage of unsafe attribute + | +help: wrap the attribute in `unsafe(...)` + | +LL | #[unsafe(no_mangle)] + | +++++++ + + +error: unsafe attribute used without unsafe + --> $DIR/unsafe-attr-edition-span.rs:25:7 + | +LL | #[no_mangle] + | ^^^^^^^^^ usage of unsafe attribute + | +help: wrap the attribute in `unsafe(...)` + | +LL | #[unsafe(no_mangle)] + | +++++++ + + +error: aborting due to 2 previous errors + diff --git a/tests/ui/editions/unsafe-attr-edition-span.rs b/tests/ui/editions/unsafe-attr-edition-span.rs new file mode 100644 index 00000000000..bc44b34063c --- /dev/null +++ b/tests/ui/editions/unsafe-attr-edition-span.rs @@ -0,0 +1,27 @@ +// Tests that the correct span is used to determine the edition of an attribute that was safe to use +// in earlier editions, but has become `unsafe` in later editions. +// +// Determining the correct edition is non-trivial because of macro expansion. For instance, +// the `thread_local!` macro (defined in std and hence using the most recent edition) parses the +// attribute, and then re-emits it. Therefore, the span of the `#` token starting the +// `#[no_mangle]` attribute has std's edition, while the attribute name has the edition of this +// file, which may be different. + +//@ revisions: e2015 e2018 e2021 e2024 + +//@[e2018] edition:2018 +//@[e2021] edition:2021 +//@[e2024] edition:2024 +// +//@[e2015] check-pass +//@[e2018] check-pass +//@[e2021] check-pass +#![crate_type = "lib"] + +#[no_mangle] //[e2024]~ ERROR unsafe attribute used without unsafe +static TEST_OUTSIDE: usize = 0; + +thread_local! { + #[no_mangle]//[e2024]~ ERROR unsafe attribute used without unsafe + static TEST: usize = 0; +} diff --git a/tests/ui/empty-allocation-rvalue-non-null.rs b/tests/ui/empty-allocation-rvalue-non-null.rs deleted file mode 100644 index 0cd4fde73ed..00000000000 --- a/tests/ui/empty-allocation-rvalue-non-null.rs +++ /dev/null @@ -1,7 +0,0 @@ -//@ run-pass - -#![allow(unused_variables)] - -pub fn main() { - let x: () = *Box::new(()); -} diff --git a/tests/ui/empty-type-parameter-list.rs b/tests/ui/empty-type-parameter-list.rs deleted file mode 100644 index e8d6b2a9964..00000000000 --- a/tests/ui/empty-type-parameter-list.rs +++ /dev/null @@ -1,24 +0,0 @@ -//@ run-pass -// Test that empty type parameter list (<>) is synonymous with -// no type parameters at all - -struct S<>; -trait T<> {} //~ WARN trait `T` is never used -enum E<> { V } -impl<> T<> for S<> {} -impl T for E {} -fn foo<>() {} -fn bar() {} - -fn main() { - let _ = S; - let _ = S::<>; - let _ = E::V; - let _ = E::<>::V; - foo(); - foo::<>(); - - // Test that we can supply <> to non generic things - bar::<>(); - let _: i32<>; -} diff --git a/tests/ui/enum/dead-code-associated-function.rs b/tests/ui/enum/dead-code-associated-function.rs new file mode 100644 index 00000000000..d172ceb41dd --- /dev/null +++ b/tests/ui/enum/dead-code-associated-function.rs @@ -0,0 +1,20 @@ +//@ check-pass +#![warn(dead_code)] + +enum E { + F(), + C(), +} + +impl E { + #[expect(non_snake_case)] + fn F() {} + //~^ WARN: associated items `F` and `C` are never used + + const C: () = (); +} + +fn main() { + let _: E = E::F(); + let _: E = E::C(); +} diff --git a/tests/ui/enum/dead-code-associated-function.stderr b/tests/ui/enum/dead-code-associated-function.stderr new file mode 100644 index 00000000000..e3c1a4c81a4 --- /dev/null +++ b/tests/ui/enum/dead-code-associated-function.stderr @@ -0,0 +1,30 @@ +warning: associated items `F` and `C` are never used + --> $DIR/dead-code-associated-function.rs:11:8 + | +LL | impl E { + | ------ associated items in this implementation +LL | #[expect(non_snake_case)] +LL | fn F() {} + | ^ +... +LL | const C: () = (); + | ^ + | +note: it is impossible to refer to the associated function `F` because it is shadowed by this enum variant with the same name + --> $DIR/dead-code-associated-function.rs:5:5 + | +LL | F(), + | ^ +note: it is impossible to refer to the associated constant `C` because it is shadowed by this enum variant with the same name + --> $DIR/dead-code-associated-function.rs:6:5 + | +LL | C(), + | ^ +note: the lint level is defined here + --> $DIR/dead-code-associated-function.rs:2:9 + | +LL | #![warn(dead_code)] + | ^^^^^^^^^ + +warning: 1 warning emitted + diff --git a/tests/ui/error-should-say-copy-not-pod.rs b/tests/ui/error-should-say-copy-not-pod.rs deleted file mode 100644 index 40c4730ef69..00000000000 --- a/tests/ui/error-should-say-copy-not-pod.rs +++ /dev/null @@ -1,7 +0,0 @@ -// Tests that the error message uses the word Copy, not Pod. - -fn check_bound<T:Copy>(_: T) {} - -fn main() { - check_bound("nocopy".to_string()); //~ ERROR : Copy` is not satisfied -} diff --git a/tests/ui/error-should-say-copy-not-pod.stderr b/tests/ui/error-should-say-copy-not-pod.stderr deleted file mode 100644 index 6aa129fa29b..00000000000 --- a/tests/ui/error-should-say-copy-not-pod.stderr +++ /dev/null @@ -1,22 +0,0 @@ -error[E0277]: the trait bound `String: Copy` is not satisfied - --> $DIR/error-should-say-copy-not-pod.rs:6:17 - | -LL | check_bound("nocopy".to_string()); - | ----------- ^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `String` - | | - | required by a bound introduced by this call - | -note: required by a bound in `check_bound` - --> $DIR/error-should-say-copy-not-pod.rs:3:18 - | -LL | fn check_bound<T:Copy>(_: T) {} - | ^^^^ required by this bound in `check_bound` -help: consider removing this method call, as the receiver has type `&'static str` and `&'static str: Copy` trivially holds - | -LL - check_bound("nocopy".to_string()); -LL + check_bound("nocopy"); - | - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/explicit-i-suffix.rs b/tests/ui/explicit-i-suffix.rs deleted file mode 100644 index 0a6ed49ae27..00000000000 --- a/tests/ui/explicit-i-suffix.rs +++ /dev/null @@ -1,13 +0,0 @@ -//@ run-pass - -#![allow(unused_must_use)] - -pub fn main() { - let x: isize = 8; - let y = 9; - x + y; - - let q: isize = -8; - let r = -9; - q + r; -} diff --git a/tests/ui/ext-nonexistent.rs b/tests/ui/ext-nonexistent.rs deleted file mode 100644 index 1293324b67e..00000000000 --- a/tests/ui/ext-nonexistent.rs +++ /dev/null @@ -1,2 +0,0 @@ -fn main() { iamnotanextensionthatexists!(""); } -//~^ ERROR cannot find macro `iamnotanextensionthatexists` in this scope diff --git a/tests/ui/ext-nonexistent.stderr b/tests/ui/ext-nonexistent.stderr deleted file mode 100644 index edb59bba6e5..00000000000 --- a/tests/ui/ext-nonexistent.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: cannot find macro `iamnotanextensionthatexists` in this scope - --> $DIR/ext-nonexistent.rs:1:13 - | -LL | fn main() { iamnotanextensionthatexists!(""); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 1 previous error - diff --git a/tests/ui/fact.rs b/tests/ui/fact.rs deleted file mode 100644 index e94c12da013..00000000000 --- a/tests/ui/fact.rs +++ /dev/null @@ -1,26 +0,0 @@ -//@ run-pass - -fn f(x: isize) -> isize { - // println!("in f:"); - - println!("{}", x); - if x == 1 { - // println!("bottoming out"); - - return 1; - } else { - // println!("recurring"); - - let y: isize = x * f(x - 1); - // println!("returned"); - - println!("{}", y); - return y; - } -} - -pub fn main() { - assert_eq!(f(5), 120); - // println!("all done"); - -} diff --git a/tests/ui/feature-gates/feature-gate-abi-custom.rs b/tests/ui/feature-gates/feature-gate-abi-custom.rs new file mode 100644 index 00000000000..3ddce974dd7 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-abi-custom.rs @@ -0,0 +1,51 @@ +//@ add-core-stubs +//@ needs-asm-support +#![no_core] +#![feature(no_core, lang_items)] +#![crate_type = "rlib"] + +extern crate minicore; +use minicore::*; + +#[unsafe(naked)] +unsafe extern "custom" fn f7() { + //~^ ERROR "custom" ABI is experimental + naked_asm!("") +} +trait Tr { + extern "custom" fn m7(); + //~^ ERROR "custom" ABI is experimental + //~| ERROR functions with the `"custom"` ABI must be unsafe + #[unsafe(naked)] + extern "custom" fn dm7() { + //~^ ERROR "custom" ABI is experimental + //~| ERROR functions with the `"custom"` ABI must be unsafe + naked_asm!("") + } +} + +struct S; + +// Methods in trait impl +impl Tr for S { + #[unsafe(naked)] + extern "custom" fn m7() { + //~^ ERROR "custom" ABI is experimental + //~| ERROR functions with the `"custom"` ABI must be unsafe + naked_asm!("") + } +} + +// Methods in inherent impl +impl S { + #[unsafe(naked)] + extern "custom" fn im7() { + //~^ ERROR "custom" ABI is experimental + //~| ERROR functions with the `"custom"` ABI must be unsafe + naked_asm!("") + } +} + +type A7 = extern "custom" fn(); //~ ERROR "custom" ABI is experimental + +extern "custom" {} //~ ERROR "custom" ABI is experimental diff --git a/tests/ui/feature-gates/feature-gate-abi-custom.stderr b/tests/ui/feature-gates/feature-gate-abi-custom.stderr new file mode 100644 index 00000000000..e6dce0126d6 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-abi-custom.stderr @@ -0,0 +1,117 @@ +error: functions with the `"custom"` ABI must be unsafe + --> $DIR/feature-gate-abi-custom.rs:16:5 + | +LL | extern "custom" fn m7(); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: add the `unsafe` keyword to this definition + | +LL | unsafe extern "custom" fn m7(); + | ++++++ + +error: functions with the `"custom"` ABI must be unsafe + --> $DIR/feature-gate-abi-custom.rs:20:5 + | +LL | extern "custom" fn dm7() { + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: add the `unsafe` keyword to this definition + | +LL | unsafe extern "custom" fn dm7() { + | ++++++ + +error: functions with the `"custom"` ABI must be unsafe + --> $DIR/feature-gate-abi-custom.rs:32:5 + | +LL | extern "custom" fn m7() { + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +help: add the `unsafe` keyword to this definition + | +LL | unsafe extern "custom" fn m7() { + | ++++++ + +error: functions with the `"custom"` ABI must be unsafe + --> $DIR/feature-gate-abi-custom.rs:42:5 + | +LL | extern "custom" fn im7() { + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: add the `unsafe` keyword to this definition + | +LL | unsafe extern "custom" fn im7() { + | ++++++ + +error[E0658]: the extern "custom" ABI is experimental and subject to change + --> $DIR/feature-gate-abi-custom.rs:11:15 + | +LL | unsafe extern "custom" fn f7() { + | ^^^^^^^^ + | + = note: see issue #140829 <https://github.com/rust-lang/rust/issues/140829> for more information + = help: add `#![feature(abi_custom)]` 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]: the extern "custom" ABI is experimental and subject to change + --> $DIR/feature-gate-abi-custom.rs:16:12 + | +LL | extern "custom" fn m7(); + | ^^^^^^^^ + | + = note: see issue #140829 <https://github.com/rust-lang/rust/issues/140829> for more information + = help: add `#![feature(abi_custom)]` 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]: the extern "custom" ABI is experimental and subject to change + --> $DIR/feature-gate-abi-custom.rs:20:12 + | +LL | extern "custom" fn dm7() { + | ^^^^^^^^ + | + = note: see issue #140829 <https://github.com/rust-lang/rust/issues/140829> for more information + = help: add `#![feature(abi_custom)]` 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]: the extern "custom" ABI is experimental and subject to change + --> $DIR/feature-gate-abi-custom.rs:32:12 + | +LL | extern "custom" fn m7() { + | ^^^^^^^^ + | + = note: see issue #140829 <https://github.com/rust-lang/rust/issues/140829> for more information + = help: add `#![feature(abi_custom)]` 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]: the extern "custom" ABI is experimental and subject to change + --> $DIR/feature-gate-abi-custom.rs:42:12 + | +LL | extern "custom" fn im7() { + | ^^^^^^^^ + | + = note: see issue #140829 <https://github.com/rust-lang/rust/issues/140829> for more information + = help: add `#![feature(abi_custom)]` 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]: the extern "custom" ABI is experimental and subject to change + --> $DIR/feature-gate-abi-custom.rs:49:18 + | +LL | type A7 = extern "custom" fn(); + | ^^^^^^^^ + | + = note: see issue #140829 <https://github.com/rust-lang/rust/issues/140829> for more information + = help: add `#![feature(abi_custom)]` 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]: the extern "custom" ABI is experimental and subject to change + --> $DIR/feature-gate-abi-custom.rs:51:8 + | +LL | extern "custom" {} + | ^^^^^^^^ + | + = note: see issue #140829 <https://github.com/rust-lang/rust/issues/140829> for more information + = help: add `#![feature(abi_custom)]` 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 11 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-coverage-attribute.rs b/tests/ui/feature-gates/feature-gate-coverage-attribute.rs index 0a463755f13..2cf4b76180e 100644 --- a/tests/ui/feature-gates/feature-gate-coverage-attribute.rs +++ b/tests/ui/feature-gates/feature-gate-coverage-attribute.rs @@ -1,3 +1,5 @@ +//@ normalize-stderr: "you are using [0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9]+)?( \([^)]*\))?" -> "you are using $$RUSTC_VERSION" + #![crate_type = "lib"] #![feature(no_coverage)] //~ ERROR feature has been removed [E0557] diff --git a/tests/ui/feature-gates/feature-gate-coverage-attribute.stderr b/tests/ui/feature-gates/feature-gate-coverage-attribute.stderr index 00e0f0afbde..8c23544698d 100644 --- a/tests/ui/feature-gates/feature-gate-coverage-attribute.stderr +++ b/tests/ui/feature-gates/feature-gate-coverage-attribute.stderr @@ -1,13 +1,14 @@ error[E0557]: feature has been removed - --> $DIR/feature-gate-coverage-attribute.rs:2:12 + --> $DIR/feature-gate-coverage-attribute.rs:4:12 | LL | #![feature(no_coverage)] | ^^^^^^^^^^^ feature has been removed | + = note: removed in 1.74.0 (you are using $RUSTC_VERSION); see <https://github.com/rust-lang/rust/pull/114656> for more information = note: renamed to `coverage_attribute` error[E0658]: the `#[coverage]` attribute is an experimental feature - --> $DIR/feature-gate-coverage-attribute.rs:10:1 + --> $DIR/feature-gate-coverage-attribute.rs:12:1 | LL | #[coverage(off)] | ^^^^^^^^^^^^^^^^ diff --git a/tests/ui/feature-gates/feature-gate-keylocker_x86.rs b/tests/ui/feature-gates/feature-gate-keylocker_x86.rs deleted file mode 100644 index cef80ad41a8..00000000000 --- a/tests/ui/feature-gates/feature-gate-keylocker_x86.rs +++ /dev/null @@ -1,6 +0,0 @@ -//@ only-x86_64 -#[target_feature(enable = "kl")] -//~^ ERROR: currently unstable -unsafe fn foo() {} - -fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-keylocker_x86.stderr b/tests/ui/feature-gates/feature-gate-keylocker_x86.stderr deleted file mode 100644 index ed814d3a3ce..00000000000 --- a/tests/ui/feature-gates/feature-gate-keylocker_x86.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0658]: the target feature `kl` is currently unstable - --> $DIR/feature-gate-keylocker_x86.rs:2:18 - | -LL | #[target_feature(enable = "kl")] - | ^^^^^^^^^^^^^ - | - = note: see issue #134813 <https://github.com/rust-lang/rust/issues/134813> for more information - = help: add `#![feature(keylocker_x86)]` 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-pattern-complexity-limit.rs b/tests/ui/feature-gates/feature-gate-pattern-complexity-limit.rs index d1f6f4755f0..ffb444cd9aa 100644 --- a/tests/ui/feature-gates/feature-gate-pattern-complexity-limit.rs +++ b/tests/ui/feature-gates/feature-gate-pattern-complexity-limit.rs @@ -1,6 +1,8 @@ // check that `pattern_complexity_limit` is feature-gated #![pattern_complexity_limit = "42"] -//~^ ERROR: the `#[pattern_complexity_limit]` attribute is just used for rustc unit tests +//~^ ERROR: use of an internal attribute [E0658] +//~| NOTE the `#[pattern_complexity_limit]` attribute is an internal implementation detail that will never be stable +//~| NOTE: the `#[pattern_complexity_limit]` attribute is used for rustc unit tests fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-pattern-complexity-limit.stderr b/tests/ui/feature-gates/feature-gate-pattern-complexity-limit.stderr index e6f17710e09..9ddea866ea9 100644 --- a/tests/ui/feature-gates/feature-gate-pattern-complexity-limit.stderr +++ b/tests/ui/feature-gates/feature-gate-pattern-complexity-limit.stderr @@ -1,11 +1,12 @@ -error[E0658]: the `#[pattern_complexity_limit]` attribute is just used for rustc unit tests and will never be stable +error[E0658]: use of an internal attribute --> $DIR/feature-gate-pattern-complexity-limit.rs:3:1 | LL | #![pattern_complexity_limit = "42"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: the `#[pattern_complexity_limit]` attribute is an internal implementation detail that will never be stable + = note: the `#[pattern_complexity_limit]` attribute is used for rustc unit tests error: aborting due to 1 previous error diff --git a/tests/ui/feature-gates/feature-gate-rustc-attrs-1.rs b/tests/ui/feature-gates/feature-gate-rustc-attrs-1.rs index 025b4b52f12..17556723622 100644 --- a/tests/ui/feature-gates/feature-gate-rustc-attrs-1.rs +++ b/tests/ui/feature-gates/feature-gate-rustc-attrs-1.rs @@ -1,6 +1,12 @@ // Test that `#[rustc_*]` attributes are gated by `rustc_attrs` feature gate. -#[rustc_variance] //~ ERROR the `#[rustc_variance]` attribute is just used for rustc unit tests and will never be stable -#[rustc_nonnull_optimization_guaranteed] //~ ERROR the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to document guaranteed niche optimizations in libcore and libstd and will never be stable - +#[rustc_variance] +//~^ ERROR use of an internal attribute [E0658] +//~| NOTE the `#[rustc_variance]` attribute is an internal implementation detail that will never be stable +//~| NOTE the `#[rustc_variance]` attribute is used for rustc unit tests +#[rustc_nonnull_optimization_guaranteed] +//~^ ERROR use of an internal attribute [E0658] +//~| NOTE the `#[rustc_nonnull_optimization_guaranteed]` attribute is an internal implementation detail that will never be stable +//~| NOTE the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to document guaranteed niche optimizations in the standard library +//~| NOTE the compiler does not even check whether the type indeed is being non-null-optimized; it is your responsibility to ensure that the attribute is only used on types that are optimized fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-rustc-attrs-1.stderr b/tests/ui/feature-gates/feature-gate-rustc-attrs-1.stderr index 0f760e0602d..159d383e408 100644 --- a/tests/ui/feature-gates/feature-gate-rustc-attrs-1.stderr +++ b/tests/ui/feature-gates/feature-gate-rustc-attrs-1.stderr @@ -1,21 +1,23 @@ -error[E0658]: the `#[rustc_variance]` attribute is just used for rustc unit tests and will never be stable +error[E0658]: use of an internal attribute --> $DIR/feature-gate-rustc-attrs-1.rs:3:1 | LL | #[rustc_variance] | ^^^^^^^^^^^^^^^^^ | = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: the `#[rustc_variance]` attribute is an internal implementation detail that will never be stable + = note: the `#[rustc_variance]` attribute is used for rustc unit tests -error[E0658]: the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to document guaranteed niche optimizations in libcore and libstd and will never be stable - (note that the compiler does not even check whether the type indeed is being non-null-optimized; it is your responsibility to ensure that the attribute is only used on types that are optimized) - --> $DIR/feature-gate-rustc-attrs-1.rs:4:1 +error[E0658]: use of an internal attribute + --> $DIR/feature-gate-rustc-attrs-1.rs:7:1 | LL | #[rustc_nonnull_optimization_guaranteed] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: the `#[rustc_nonnull_optimization_guaranteed]` attribute is an internal implementation detail that will never be stable + = note: the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to document guaranteed niche optimizations in the standard library + = note: the compiler does not even check whether the type indeed is being non-null-optimized; it is your responsibility to ensure that the attribute is only used on types that are optimized error: aborting due to 2 previous errors diff --git a/tests/ui/feature-gates/feature-gate-rustc-attrs.rs b/tests/ui/feature-gates/feature-gate-rustc-attrs.rs index c985298a30a..e7b2eca6f85 100644 --- a/tests/ui/feature-gates/feature-gate-rustc-attrs.rs +++ b/tests/ui/feature-gates/feature-gate-rustc-attrs.rs @@ -8,15 +8,19 @@ mod unknown { pub macro rustc() {} } #[rustc::unknown] //~^ ERROR attributes starting with `rustc` are reserved for use by the `rustc` compiler //~| ERROR expected attribute, found macro `rustc::unknown` +//~| NOTE not an attribute fn f() {} #[unknown::rustc] //~^ ERROR attributes starting with `rustc` are reserved for use by the `rustc` compiler //~| ERROR expected attribute, found macro `unknown::rustc` +//~| NOTE not an attribute fn g() {} #[rustc_dummy] -//~^ ERROR the `#[rustc_dummy]` attribute is just used for rustc unit tests +//~^ ERROR use of an internal attribute [E0658] +//~| NOTE the `#[rustc_dummy]` attribute is an internal implementation detail that will never be stable +//~| NOTE the `#[rustc_dummy]` attribute is used for rustc unit tests #[rustc_unknown] //~^ ERROR attributes starting with `rustc` are reserved for use by the `rustc` compiler //~| ERROR cannot find attribute `rustc_unknown` in this scope diff --git a/tests/ui/feature-gates/feature-gate-rustc-attrs.stderr b/tests/ui/feature-gates/feature-gate-rustc-attrs.stderr index c7a5ef3e44b..d58603883f1 100644 --- a/tests/ui/feature-gates/feature-gate-rustc-attrs.stderr +++ b/tests/ui/feature-gates/feature-gate-rustc-attrs.stderr @@ -11,37 +11,38 @@ LL | #[rustc::unknown] | ^^^^^^^^^^^^^^ not an attribute error: attributes starting with `rustc` are reserved for use by the `rustc` compiler - --> $DIR/feature-gate-rustc-attrs.rs:13:12 + --> $DIR/feature-gate-rustc-attrs.rs:14:12 | LL | #[unknown::rustc] | ^^^^^ error: expected attribute, found macro `unknown::rustc` - --> $DIR/feature-gate-rustc-attrs.rs:13:3 + --> $DIR/feature-gate-rustc-attrs.rs:14:3 | LL | #[unknown::rustc] | ^^^^^^^^^^^^^^ not an attribute error: attributes starting with `rustc` are reserved for use by the `rustc` compiler - --> $DIR/feature-gate-rustc-attrs.rs:20:3 + --> $DIR/feature-gate-rustc-attrs.rs:24:3 | LL | #[rustc_unknown] | ^^^^^^^^^^^^^ error: cannot find attribute `rustc_unknown` in this scope - --> $DIR/feature-gate-rustc-attrs.rs:20:3 + --> $DIR/feature-gate-rustc-attrs.rs:24:3 | LL | #[rustc_unknown] | ^^^^^^^^^^^^^ -error[E0658]: the `#[rustc_dummy]` attribute is just used for rustc unit tests and will never be stable - --> $DIR/feature-gate-rustc-attrs.rs:18:1 +error[E0658]: use of an internal attribute + --> $DIR/feature-gate-rustc-attrs.rs:20:1 | LL | #[rustc_dummy] | ^^^^^^^^^^^^^^ | = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: the `#[rustc_dummy]` attribute is an internal implementation detail that will never be stable + = note: the `#[rustc_dummy]` attribute is used for rustc unit tests error: aborting due to 7 previous errors diff --git a/tests/ui/feature-gates/gated-bad-feature.rs b/tests/ui/feature-gates/gated-bad-feature.rs index 51f2db5556e..3114f661dc5 100644 --- a/tests/ui/feature-gates/gated-bad-feature.rs +++ b/tests/ui/feature-gates/gated-bad-feature.rs @@ -1,3 +1,4 @@ +//@ normalize-stderr: "you are using [0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9]+)?( \([^)]*\))?" -> "you are using $$RUSTC_VERSION" #![feature(foo_bar_baz, foo(bar), foo = "baz", foo)] //~^ ERROR malformed `feature` //~| ERROR malformed `feature` diff --git a/tests/ui/feature-gates/gated-bad-feature.stderr b/tests/ui/feature-gates/gated-bad-feature.stderr index 2d01bdf3c1d..0e75dff14f8 100644 --- a/tests/ui/feature-gates/gated-bad-feature.stderr +++ b/tests/ui/feature-gates/gated-bad-feature.stderr @@ -1,41 +1,43 @@ error[E0556]: malformed `feature` attribute input - --> $DIR/gated-bad-feature.rs:1:25 + --> $DIR/gated-bad-feature.rs:2:25 | LL | #![feature(foo_bar_baz, foo(bar), foo = "baz", foo)] | ^^^^^^^^ help: expected just one word: `foo` error[E0556]: malformed `feature` attribute input - --> $DIR/gated-bad-feature.rs:1:35 + --> $DIR/gated-bad-feature.rs:2:35 | LL | #![feature(foo_bar_baz, foo(bar), foo = "baz", foo)] | ^^^^^^^^^^^ help: expected just one word: `foo` error[E0557]: feature has been removed - --> $DIR/gated-bad-feature.rs:8:12 + --> $DIR/gated-bad-feature.rs:9:12 | LL | #![feature(test_removed_feature)] | ^^^^^^^^^^^^^^^^^^^^ feature has been removed + | + = note: removed in 1.0.0 (you are using $RUSTC_VERSION) error: malformed `feature` attribute input - --> $DIR/gated-bad-feature.rs:6:1 + --> $DIR/gated-bad-feature.rs:7:1 | LL | #![feature] | ^^^^^^^^^^^ help: must be of the form: `#![feature(name1, name2, ...)]` error: malformed `feature` attribute input - --> $DIR/gated-bad-feature.rs:7:1 + --> $DIR/gated-bad-feature.rs:8:1 | LL | #![feature = "foo"] | ^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#![feature(name1, name2, ...)]` error[E0635]: unknown feature `foo_bar_baz` - --> $DIR/gated-bad-feature.rs:1:12 + --> $DIR/gated-bad-feature.rs:2:12 | LL | #![feature(foo_bar_baz, foo(bar), foo = "baz", foo)] | ^^^^^^^^^^^ error[E0635]: unknown feature `foo` - --> $DIR/gated-bad-feature.rs:1:48 + --> $DIR/gated-bad-feature.rs:2:48 | LL | #![feature(foo_bar_baz, foo(bar), foo = "baz", foo)] | ^^^ diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.rs b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.rs index 02a56c7e6aa..7fb11b7bde7 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.rs +++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.rs @@ -11,9 +11,11 @@ #![macro_export] //~^ ERROR: `macro_export` attribute cannot be used at crate level -#![rustc_main] //~ ERROR: the `#[rustc_main]` attribute is used internally to specify +#![rustc_main] //~^ ERROR: `rustc_main` attribute cannot be used at crate level -//~| NOTE: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +//~| ERROR: use of an internal attribute [E0658] +//~| NOTE: the `#[rustc_main]` attribute is an internal implementation detail that will never be stable +//~| NOTE: the `#[rustc_main]` attribute is used internally to specify test entry point function #![repr()] //~^ ERROR: `repr` attribute cannot be used at crate level #![path = "3800"] diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr index 5c2a3ae699c..bdca6163473 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr +++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr @@ -1,14 +1,15 @@ -error[E0658]: the `#[rustc_main]` attribute is used internally to specify test entry point function +error[E0658]: use of an internal attribute --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:14:1 | LL | #![rustc_main] | ^^^^^^^^^^^^^^ | = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: the `#[rustc_main]` attribute is an internal implementation detail that will never be stable + = note: the `#[rustc_main]` attribute is used internally to specify test entry point function error: valid forms for the attribute are `#[inline]` and `#[inline(always|never)]` - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:44:5 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:46:5 | LL | #[inline = "2100"] fn f() { } | ^^^^^^^^^^^^^^^^^^ @@ -18,7 +19,7 @@ LL | #[inline = "2100"] fn f() { } = note: `#[deny(ill_formed_attribute_input)]` on by default error[E0518]: attribute should be applied to function or closure - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:30:1 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:32:1 | LL | #[inline] | ^^^^^^^^^ @@ -29,7 +30,7 @@ LL | | } | |_- not a function or closure error: attribute should be applied to an `extern crate` item - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:63:1 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:65:1 | LL | #[no_link] | ^^^^^^^^^^ @@ -43,7 +44,7 @@ LL | | } | |_- not an `extern crate` item error: attribute should be applied to a free function, impl method or static - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:89:1 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:91:1 | LL | #[export_name = "2200"] | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -57,7 +58,7 @@ LL | | } | |_- not a free function, impl method or static error[E0517]: attribute should be applied to a struct, enum, or union - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:123:8 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:125:8 | LL | #[repr(C)] | ^ @@ -70,7 +71,7 @@ LL | | } | |_- not a struct, enum, or union error[E0517]: attribute should be applied to a struct, enum, or union - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:147:8 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:149:8 | LL | #[repr(Rust)] | ^^^^ @@ -83,19 +84,19 @@ LL | | } | |_- not a struct, enum, or union error: attribute should be applied to an `extern crate` item - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:24:1 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:26:1 | LL | #![no_link] | ^^^^^^^^^^^ not an `extern crate` item error: attribute should be applied to a free function, impl method or static - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:26:1 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:28:1 | LL | #![export_name = "2200"] | ^^^^^^^^^^^^^^^^^^^^^^^^ not a free function, impl method or static error[E0518]: attribute should be applied to function or closure - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:28:1 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:30:1 | LL | #![inline] | ^^^^^^^^^^ not a function or closure @@ -131,7 +132,7 @@ LL + #[rustc_main] | error: `path` attribute cannot be used at crate level - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:19:1 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:21:1 | LL | #![path = "3800"] | ^^^^^^^^^^^^^^^^^ @@ -146,7 +147,7 @@ LL + #[path = "3800"] | error: `automatically_derived` attribute cannot be used at crate level - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:21:1 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:23:1 | LL | #![automatically_derived] | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -161,7 +162,7 @@ LL + #[automatically_derived] | error: `repr` attribute cannot be used at crate level - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:17:1 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:19:1 | LL | #![repr()] | ^^^^^^^^^^ @@ -176,139 +177,139 @@ LL + #[repr()] | error[E0518]: attribute should be applied to function or closure - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:40:17 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:42:17 | LL | mod inner { #![inline] } | ------------^^^^^^^^^^-- not a function or closure error[E0518]: attribute should be applied to function or closure - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:50:5 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:52:5 | LL | #[inline] struct S; | ^^^^^^^^^ --------- not a function or closure error[E0518]: attribute should be applied to function or closure - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:54:5 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:56:5 | LL | #[inline] type T = S; | ^^^^^^^^^ ----------- not a function or closure error[E0518]: attribute should be applied to function or closure - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:58:5 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:60:5 | LL | #[inline] impl S { } | ^^^^^^^^^ ---------- not a function or closure error: attribute should be applied to an `extern crate` item - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:68:17 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:70:17 | LL | mod inner { #![no_link] } | ------------^^^^^^^^^^^-- not an `extern crate` item error: attribute should be applied to an `extern crate` item - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:72:5 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:74:5 | LL | #[no_link] fn f() { } | ^^^^^^^^^^ ---------- not an `extern crate` item error: attribute should be applied to an `extern crate` item - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:76:5 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:78:5 | LL | #[no_link] struct S; | ^^^^^^^^^^ --------- not an `extern crate` item error: attribute should be applied to an `extern crate` item - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:80:5 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:82:5 | LL | #[no_link]type T = S; | ^^^^^^^^^^----------- not an `extern crate` item error: attribute should be applied to an `extern crate` item - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:84:5 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:86:5 | LL | #[no_link] impl S { } | ^^^^^^^^^^ ---------- not an `extern crate` item error: attribute should be applied to a free function, impl method or static - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:94:17 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:96:17 | LL | mod inner { #![export_name="2200"] } | ------------^^^^^^^^^^^^^^^^^^^^^^-- not a free function, impl method or static error: attribute should be applied to a free function, impl method or static - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:100:5 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:102:5 | LL | #[export_name = "2200"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^ --------- not a free function, impl method or static error: attribute should be applied to a free function, impl method or static - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:104:5 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:106:5 | LL | #[export_name = "2200"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^ ----------- not a free function, impl method or static error: attribute should be applied to a free function, impl method or static - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:108:5 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:110:5 | LL | #[export_name = "2200"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^ ---------- not a free function, impl method or static error: attribute should be applied to a free function, impl method or static - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:113:9 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:115:9 | LL | #[export_name = "2200"] fn foo(); | ^^^^^^^^^^^^^^^^^^^^^^^ --------- not a free function, impl method or static error: attribute should be applied to a free function, impl method or static - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:117:9 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:119:9 | LL | #[export_name = "2200"] fn bar() {} | ^^^^^^^^^^^^^^^^^^^^^^^ ----------- not a free function, impl method or static error[E0517]: attribute should be applied to a struct, enum, or union - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:127:25 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:129:25 | LL | mod inner { #![repr(C)] } | --------------------^---- not a struct, enum, or union error[E0517]: attribute should be applied to a struct, enum, or union - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:131:12 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:133:12 | LL | #[repr(C)] fn f() { } | ^ ---------- not a struct, enum, or union error[E0517]: attribute should be applied to a struct, enum, or union - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:137:12 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:139:12 | LL | #[repr(C)] type T = S; | ^ ----------- not a struct, enum, or union error[E0517]: attribute should be applied to a struct, enum, or union - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:141:12 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:143:12 | LL | #[repr(C)] impl S { } | ^ ---------- not a struct, enum, or union error[E0517]: attribute should be applied to a struct, enum, or union - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:151:25 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:153:25 | LL | mod inner { #![repr(Rust)] } | --------------------^^^^---- not a struct, enum, or union error[E0517]: attribute should be applied to a struct, enum, or union - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:155:12 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:157:12 | LL | #[repr(Rust)] fn f() { } | ^^^^ ---------- not a struct, enum, or union error[E0517]: attribute should be applied to a struct, enum, or union - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:161:12 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:163:12 | LL | #[repr(Rust)] type T = S; | ^^^^ ----------- not a struct, enum, or union error[E0517]: attribute should be applied to a struct, enum, or union - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:165:12 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:167:12 | LL | #[repr(Rust)] impl S { } | ^^^^ ---------- not a struct, enum, or union diff --git a/tests/ui/feature-gates/removed-features-note-version-and-pr-issue-141619.rs b/tests/ui/feature-gates/removed-features-note-version-and-pr-issue-141619.rs new file mode 100644 index 00000000000..ec6adb471ba --- /dev/null +++ b/tests/ui/feature-gates/removed-features-note-version-and-pr-issue-141619.rs @@ -0,0 +1,6 @@ +//@ normalize-stderr: "you are using [0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9]+)?( \([^)]*\))?" -> "you are using $$RUSTC_VERSION" + +#![feature(external_doc)] //~ ERROR feature has been removed +#![doc(include("README.md"))] //~ ERROR unknown `doc` attribute `include` + +fn main(){} diff --git a/tests/ui/feature-gates/removed-features-note-version-and-pr-issue-141619.stderr b/tests/ui/feature-gates/removed-features-note-version-and-pr-issue-141619.stderr new file mode 100644 index 00000000000..43205c7360b --- /dev/null +++ b/tests/ui/feature-gates/removed-features-note-version-and-pr-issue-141619.stderr @@ -0,0 +1,20 @@ +error[E0557]: feature has been removed + --> $DIR/removed-features-note-version-and-pr-issue-141619.rs:3:12 + | +LL | #![feature(external_doc)] + | ^^^^^^^^^^^^ feature has been removed + | + = note: removed in 1.54.0 (you are using $RUSTC_VERSION); see <https://github.com/rust-lang/rust/pull/85457> for more information + = note: use #[doc = include_str!("filename")] instead, which handles macro invocations + +error: unknown `doc` attribute `include` + --> $DIR/removed-features-note-version-and-pr-issue-141619.rs:4:8 + | +LL | #![doc(include("README.md"))] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[deny(invalid_doc_attributes)]` on by default + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0557`. diff --git a/tests/ui/format-no-std.rs b/tests/ui/fmt/format-macro-no-std.rs index 657b210a9a0..d096b4de013 100644 --- a/tests/ui/format-no-std.rs +++ b/tests/ui/fmt/format-macro-no-std.rs @@ -1,3 +1,5 @@ +//! Test format! macro functionality in no_std environment + //@ run-pass //@ ignore-emscripten no no_std executables //@ ignore-wasm different `main` convention @@ -9,7 +11,8 @@ // Import global allocator and panic handler. extern crate std as other; -#[macro_use] extern crate alloc; +#[macro_use] +extern crate alloc; use alloc::string::ToString; @@ -21,7 +24,7 @@ extern "C" fn main(_argc: core::ffi::c_int, _argv: *const *const u8) -> core::ff let s = format!("test"); assert_eq!(s, "test".to_string()); - let s = format!("{test}", test=3_isize); + let s = format!("{test}", test = 3_isize); assert_eq!(s, "3".to_string()); let s = format!("hello {}", "world"); diff --git a/tests/ui/force-inlining/gate.rs b/tests/ui/force-inlining/gate.rs index cea094c14f2..5918b0d4979 100644 --- a/tests/ui/force-inlining/gate.rs +++ b/tests/ui/force-inlining/gate.rs @@ -2,11 +2,15 @@ #![allow(internal_features)] #[rustc_force_inline] -//~^ ERROR #[rustc_force_inline] forces a free function to be inlined +//~^ ERROR use of an internal attribute [E0658] +//~| NOTE the `#[rustc_force_inline]` attribute is an internal implementation detail that will never be stable +//~| NOTE `#[rustc_force_inline]` forces a free function to be inlined pub fn bare() { } #[rustc_force_inline = "the test requires it"] -//~^ ERROR #[rustc_force_inline] forces a free function to be inlined +//~^ ERROR use of an internal attribute [E0658] +//~| NOTE the `#[rustc_force_inline]` attribute is an internal implementation detail that will never be stable +//~| NOTE `#[rustc_force_inline]` forces a free function to be inlined pub fn justified() { } diff --git a/tests/ui/force-inlining/gate.stderr b/tests/ui/force-inlining/gate.stderr index 964d43fa18f..6c2df08b1a3 100644 --- a/tests/ui/force-inlining/gate.stderr +++ b/tests/ui/force-inlining/gate.stderr @@ -1,20 +1,22 @@ -error[E0658]: #[rustc_force_inline] forces a free function to be inlined +error[E0658]: use of an internal attribute --> $DIR/gate.rs:4:1 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ | = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: the `#[rustc_force_inline]` attribute is an internal implementation detail that will never be stable + = note: `#[rustc_force_inline]` forces a free function to be inlined -error[E0658]: #[rustc_force_inline] forces a free function to be inlined - --> $DIR/gate.rs:9:1 +error[E0658]: use of an internal attribute + --> $DIR/gate.rs:11:1 | LL | #[rustc_force_inline = "the test requires it"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: the `#[rustc_force_inline]` attribute is an internal implementation detail that will never be stable + = note: `#[rustc_force_inline]` forces a free function to be inlined error: aborting due to 2 previous errors diff --git a/tests/ui/fun-indirect-call.rs b/tests/ui/fun-indirect-call.rs deleted file mode 100644 index 7919be07f7e..00000000000 --- a/tests/ui/fun-indirect-call.rs +++ /dev/null @@ -1,9 +0,0 @@ -//@ run-pass - -fn f() -> isize { return 42; } - -pub fn main() { - let g: fn() -> isize = f; - let i: isize = g(); - assert_eq!(i, 42); -} diff --git a/tests/ui/future-incompatible-lint-group.rs b/tests/ui/future-incompatible-lint-group.rs deleted file mode 100644 index ed2c47bb609..00000000000 --- a/tests/ui/future-incompatible-lint-group.rs +++ /dev/null @@ -1,15 +0,0 @@ -// Ensure that the future_incompatible lint group only includes -// lints for changes that are not tied to an edition -#![deny(future_incompatible)] - -// Error since this is a `future_incompatible` lint -macro_rules! m { ($i) => {} } //~ ERROR missing fragment specifier - //~| WARN this was previously accepted - -trait Tr { - // Warn only since this is not a `future_incompatible` lint - fn f(u8) {} //~ WARN anonymous parameters are deprecated - //~| WARN this is accepted in the current edition -} - -fn main() {} diff --git a/tests/ui/future-incompatible-lint-group.stderr b/tests/ui/future-incompatible-lint-group.stderr deleted file mode 100644 index 4c867e0aab3..00000000000 --- a/tests/ui/future-incompatible-lint-group.stderr +++ /dev/null @@ -1,43 +0,0 @@ -error: missing fragment specifier - --> $DIR/future-incompatible-lint-group.rs:6:19 - | -LL | macro_rules! m { ($i) => {} } - | ^^ - | - = 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 #40107 <https://github.com/rust-lang/rust/issues/40107> -note: the lint level is defined here - --> $DIR/future-incompatible-lint-group.rs:3:9 - | -LL | #![deny(future_incompatible)] - | ^^^^^^^^^^^^^^^^^^^ - = note: `#[deny(missing_fragment_specifier)]` implied by `#[deny(future_incompatible)]` - -warning: anonymous parameters are deprecated and will be removed in the next edition - --> $DIR/future-incompatible-lint-group.rs:11:10 - | -LL | fn f(u8) {} - | ^^ help: try naming the parameter or explicitly ignoring it: `_: u8` - | - = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! - = note: for more information, see issue #41686 <https://github.com/rust-lang/rust/issues/41686> - = note: `#[warn(anonymous_parameters)]` on by default - -error: aborting due to 1 previous error; 1 warning emitted - -Future incompatibility report: Future breakage diagnostic: -error: missing fragment specifier - --> $DIR/future-incompatible-lint-group.rs:6:19 - | -LL | macro_rules! m { ($i) => {} } - | ^^ - | - = 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 #40107 <https://github.com/rust-lang/rust/issues/40107> -note: the lint level is defined here - --> $DIR/future-incompatible-lint-group.rs:3:9 - | -LL | #![deny(future_incompatible)] - | ^^^^^^^^^^^^^^^^^^^ - = note: `#[deny(missing_fragment_specifier)]` implied by `#[deny(future_incompatible)]` - diff --git a/tests/ui/generics/empty-generic-brackets-equiv.rs b/tests/ui/generics/empty-generic-brackets-equiv.rs new file mode 100644 index 00000000000..d84498a60f8 --- /dev/null +++ b/tests/ui/generics/empty-generic-brackets-equiv.rs @@ -0,0 +1,27 @@ +//! Test that empty type parameter list <> is equivalent to no type parameters +//! +//! Checks` that empty angle brackets <> are syntactically valid and equivalent +//! to omitting type parameters entirely across various language constructs. + +//@ run-pass + +struct S<>; +trait T<> {} //~ WARN trait `T` is never used +enum E<> { + V +} +impl<> T<> for S<> {} +impl T for E {} +fn foo<>() {} +fn bar() {} +fn main() { + let _ = S; + let _ = S::<>; + let _ = E::V; + let _ = E::<>::V; + foo(); + foo::<>(); + // Test that we can supply <> to non-generic things + bar::<>(); + let _: i32<>; +} diff --git a/tests/ui/empty-type-parameter-list.stderr b/tests/ui/generics/empty-generic-brackets-equiv.stderr index 31a5015e993..151ee4697b4 100644 --- a/tests/ui/empty-type-parameter-list.stderr +++ b/tests/ui/generics/empty-generic-brackets-equiv.stderr @@ -1,5 +1,5 @@ warning: trait `T` is never used - --> $DIR/empty-type-parameter-list.rs:6:7 + --> $DIR/empty-generic-brackets-equiv.rs:9:7 | LL | trait T<> {} | ^ diff --git a/tests/ui/global-scope.rs b/tests/ui/global-scope.rs deleted file mode 100644 index 33b56bca940..00000000000 --- a/tests/ui/global-scope.rs +++ /dev/null @@ -1,13 +0,0 @@ -//@ run-pass - -pub fn f() -> isize { return 1; } - -pub mod foo { - pub fn f() -> isize { return 2; } - pub fn g() { - assert_eq!(f(), 2); - assert_eq!(::f(), 1); - } -} - -pub fn main() { return foo::g(); } diff --git a/tests/ui/hello.rs b/tests/ui/hello.rs deleted file mode 100644 index f329ee086f9..00000000000 --- a/tests/ui/hello.rs +++ /dev/null @@ -1,10 +0,0 @@ -//@ run-pass -//@ revisions: e2015 e2018 e2021 e2024 - -//@[e2018] edition:2018 -//@[e2021] edition:2021 -//@[e2024] edition:2024 - -fn main() { - println!("hello"); -} diff --git a/tests/ui/impl-trait/auto-trait-selection-freeze.next.stderr b/tests/ui/impl-trait/auto-trait-selection-freeze.next.stderr index 54ceec0aff5..5caf0eb2fd4 100644 --- a/tests/ui/impl-trait/auto-trait-selection-freeze.next.stderr +++ b/tests/ui/impl-trait/auto-trait-selection-freeze.next.stderr @@ -1,9 +1,22 @@ -error[E0284]: type annotations needed: cannot satisfy `impl Sized == _` - --> $DIR/auto-trait-selection-freeze.rs:19:5 +error[E0283]: type annotations needed + --> $DIR/auto-trait-selection-freeze.rs:19:16 | LL | if false { is_trait(foo()) } else { Default::default() } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot satisfy `impl Sized == _` + | ^^^^^^^^ ----- type must be known at this point + | | + | cannot infer type of the type parameter `T` declared on the function `is_trait` + | + = note: cannot satisfy `_: Trait<_>` +note: required by a bound in `is_trait` + --> $DIR/auto-trait-selection-freeze.rs:11:16 + | +LL | fn is_trait<T: Trait<U>, U: Default>(_: T) -> U { + | ^^^^^^^^ required by this bound in `is_trait` +help: consider specifying the generic arguments + | +LL | if false { is_trait::<T, U>(foo()) } else { Default::default() } + | ++++++++ error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0284`. +For more information about this error, try `rustc --explain E0283`. diff --git a/tests/ui/impl-trait/auto-trait-selection.next.stderr b/tests/ui/impl-trait/auto-trait-selection.next.stderr index 7acb9fd41b7..d34fdcc4496 100644 --- a/tests/ui/impl-trait/auto-trait-selection.next.stderr +++ b/tests/ui/impl-trait/auto-trait-selection.next.stderr @@ -1,9 +1,22 @@ -error[E0284]: type annotations needed: cannot satisfy `impl Sized == _` - --> $DIR/auto-trait-selection.rs:15:5 +error[E0283]: type annotations needed + --> $DIR/auto-trait-selection.rs:15:16 | LL | if false { is_trait(foo()) } else { Default::default() } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot satisfy `impl Sized == _` + | ^^^^^^^^ ----- type must be known at this point + | | + | cannot infer type of the type parameter `T` declared on the function `is_trait` + | + = note: cannot satisfy `_: Trait<_>` +note: required by a bound in `is_trait` + --> $DIR/auto-trait-selection.rs:7:16 + | +LL | fn is_trait<T: Trait<U>, U: Default>(_: T) -> U { + | ^^^^^^^^ required by this bound in `is_trait` +help: consider specifying the generic arguments + | +LL | if false { is_trait::<T, U>(foo()) } else { Default::default() } + | ++++++++ error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0284`. +For more information about this error, try `rustc --explain E0283`. diff --git a/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.next.stderr b/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.next.stderr index 9632d2ce624..f2e249f2cbf 100644 --- a/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.next.stderr +++ b/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.next.stderr @@ -25,7 +25,7 @@ LL | type LineStream<'c, 'd> = impl Stream; | = note: `LineStream` must be used in combination with a concrete type within the same impl -error[E0271]: type mismatch resolving `<Y as X>::LineStreamFut<'a, Repr> == ()` +error[E0271]: type mismatch resolving `<Y as X>::LineStreamFut<'a, Repr> normalizes-to ()` --> $DIR/ice-unexpected-param-type-whensubstituting-in-region-112823.rs:29:43 | LL | fn line_stream<'a, Repr>(&'a self) -> Self::LineStreamFut<'a, Repr> {} diff --git a/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.rs b/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.rs index 0b507ed948a..7cf155ce01e 100644 --- a/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.rs +++ b/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.rs @@ -29,7 +29,7 @@ impl X for Y { fn line_stream<'a, Repr>(&'a self) -> Self::LineStreamFut<'a, Repr> {} //~^ ERROR method `line_stream` is not a member of trait `X` //[current]~^^ ERROR `()` is not a future - //[next]~^^^ ERROR type mismatch resolving `<Y as X>::LineStreamFut<'a, Repr> == ()` + //[next]~^^^ ERROR type mismatch resolving `<Y as X>::LineStreamFut<'a, Repr> normalizes-to ()` //[next]~| ERROR type mismatch resolving `<Y as X>::LineStreamFut<'a, Repr> normalizes-to _` //[next]~| ERROR type mismatch resolving `<Y as X>::LineStreamFut<'a, Repr> normalizes-to _` } diff --git a/tests/ui/impl-trait/must_outlive_least_region_or_bound.stderr b/tests/ui/impl-trait/must_outlive_least_region_or_bound.stderr index ba7d7770e50..53c55686604 100644 --- a/tests/ui/impl-trait/must_outlive_least_region_or_bound.stderr +++ b/tests/ui/impl-trait/must_outlive_least_region_or_bound.stderr @@ -65,9 +65,12 @@ error[E0621]: explicit lifetime required in the type of `x` --> $DIR/must_outlive_least_region_or_bound.rs:15:41 | LL | fn foo<'a>(x: &i32) -> impl Copy + 'a { x } - | ---- ^ lifetime `'a` required - | | - | help: add explicit lifetime `'a` to the type of `x`: `&'a i32` + | ^ lifetime `'a` required + | +help: add explicit lifetime `'a` to the type of `x` + | +LL | fn foo<'a>(x: &'a i32) -> impl Copy + 'a { x } + | ++ error: lifetime may not live long enough --> $DIR/must_outlive_least_region_or_bound.rs:30:55 diff --git a/tests/ui/impl-trait/recursive-coroutine-boxed.next.stderr b/tests/ui/impl-trait/recursive-coroutine-boxed.next.stderr index 132f7de4ef2..5ce6eb0fc39 100644 --- a/tests/ui/impl-trait/recursive-coroutine-boxed.next.stderr +++ b/tests/ui/impl-trait/recursive-coroutine-boxed.next.stderr @@ -1,5 +1,5 @@ error[E0282]: type annotations needed - --> $DIR/recursive-coroutine-boxed.rs:14:23 + --> $DIR/recursive-coroutine-boxed.rs:11:23 | LL | let mut gen = Box::pin(foo()); | ^^^^^^^^ cannot infer type of the type parameter `T` declared on the struct `Box` diff --git a/tests/ui/impl-trait/recursive-coroutine-boxed.rs b/tests/ui/impl-trait/recursive-coroutine-boxed.rs index 8d38e6aed12..306edc3591e 100644 --- a/tests/ui/impl-trait/recursive-coroutine-boxed.rs +++ b/tests/ui/impl-trait/recursive-coroutine-boxed.rs @@ -7,9 +7,6 @@ use std::ops::{Coroutine, CoroutineState}; fn foo() -> impl Coroutine<Yield = (), Return = ()> { - // FIXME(-Znext-solver): this fails with a mismatched types as the - // hidden type of the opaque ends up as {type error}. We should not - // emit errors for such goals. #[coroutine] || { let mut gen = Box::pin(foo()); //[next]~^ ERROR type annotations needed diff --git a/tests/ui/impl-trait/recursive-in-exhaustiveness.next.stderr b/tests/ui/impl-trait/recursive-in-exhaustiveness.next.stderr index a3609b93cb3..db57be73acc 100644 --- a/tests/ui/impl-trait/recursive-in-exhaustiveness.next.stderr +++ b/tests/ui/impl-trait/recursive-in-exhaustiveness.next.stderr @@ -1,8 +1,8 @@ -error[E0284]: type annotations needed: cannot satisfy `impl Sized == _` - --> $DIR/recursive-in-exhaustiveness.rs:19:17 +error[E0284]: type annotations needed: cannot normalize `build<_>::{opaque#0}` + --> $DIR/recursive-in-exhaustiveness.rs:20:5 | -LL | let (x,) = (build(x),); - | ^^^^^^^^ cannot satisfy `impl Sized == _` +LL | build(x) + | ^^^^^^^^ cannot normalize `build<_>::{opaque#0}` error[E0271]: type mismatch resolving `build2<(_,)>::{opaque#0} normalizes-to _` --> $DIR/recursive-in-exhaustiveness.rs:30:6 diff --git a/tests/ui/impl-trait/recursive-in-exhaustiveness.rs b/tests/ui/impl-trait/recursive-in-exhaustiveness.rs index fa8fa0e8174..dabef22af86 100644 --- a/tests/ui/impl-trait/recursive-in-exhaustiveness.rs +++ b/tests/ui/impl-trait/recursive-in-exhaustiveness.rs @@ -17,8 +17,8 @@ fn build<T>(x: T) -> impl Sized { //[current]~^ ERROR cannot resolve opaque type let (x,) = (build(x),); - //[next]~^ ERROR type annotations needed build(x) + //[next]~^ ERROR type annotations needed: cannot normalize `build<_>::{opaque#0}` } // Opaque<T> = (Opaque<T>,) diff --git a/tests/ui/impl-trait/two_tait_defining_each_other2.next.stderr b/tests/ui/impl-trait/two_tait_defining_each_other2.next.stderr index 1a4c0f5f7ee..fac4776905d 100644 --- a/tests/ui/impl-trait/two_tait_defining_each_other2.next.stderr +++ b/tests/ui/impl-trait/two_tait_defining_each_other2.next.stderr @@ -1,9 +1,9 @@ -error[E0284]: type annotations needed: cannot satisfy `_ == A` - --> $DIR/two_tait_defining_each_other2.rs:12:8 +error[E0282]: type annotations needed + --> $DIR/two_tait_defining_each_other2.rs:12:11 | LL | fn muh(x: A) -> B { - | ^ cannot satisfy `_ == A` + | ^ cannot infer type error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0284`. +For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/impl-trait/two_tait_defining_each_other2.rs b/tests/ui/impl-trait/two_tait_defining_each_other2.rs index 6c454bba502..ec2963249f9 100644 --- a/tests/ui/impl-trait/two_tait_defining_each_other2.rs +++ b/tests/ui/impl-trait/two_tait_defining_each_other2.rs @@ -10,7 +10,7 @@ trait Foo {} #[define_opaque(A, B)] fn muh(x: A) -> B { - //[next]~^ ERROR: cannot satisfy `_ == A` + //[next]~^ ERROR: type annotations needed x // B's hidden type is A (opaquely) //[current]~^ ERROR opaque type's hidden type cannot be another opaque type } diff --git a/tests/ui/include-macros/parent_dir.rs b/tests/ui/include-macros/parent_dir.rs index 1dcf27324d1..9a81a6deeb1 100644 --- a/tests/ui/include-macros/parent_dir.rs +++ b/tests/ui/include-macros/parent_dir.rs @@ -3,8 +3,6 @@ fn main() { let _ = include_str!("include-macros/file.txt"); //~ ERROR couldn't read //~^HELP different directory - let _ = include_str!("hello.rs"); //~ ERROR couldn't read - //~^HELP different directory let _ = include_bytes!("../../data.bin"); //~ ERROR couldn't read //~^HELP different directory let _ = include_str!("tests/ui/include-macros/file.txt"); //~ ERROR couldn't read diff --git a/tests/ui/include-macros/parent_dir.stderr b/tests/ui/include-macros/parent_dir.stderr index 4ee6fe104b0..7a18b1de5d1 100644 --- a/tests/ui/include-macros/parent_dir.stderr +++ b/tests/ui/include-macros/parent_dir.stderr @@ -10,19 +10,8 @@ LL - let _ = include_str!("include-macros/file.txt"); LL + let _ = include_str!("file.txt"); | -error: couldn't read `$DIR/hello.rs`: $FILE_NOT_FOUND_MSG - --> $DIR/parent_dir.rs:6:13 - | -LL | let _ = include_str!("hello.rs"); - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: there is a file with the same name in a different directory - | -LL | let _ = include_str!("../hello.rs"); - | +++ - error: couldn't read `$DIR/../../data.bin`: $FILE_NOT_FOUND_MSG - --> $DIR/parent_dir.rs:8:13 + --> $DIR/parent_dir.rs:6:13 | LL | let _ = include_bytes!("../../data.bin"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -34,7 +23,7 @@ LL + let _ = include_bytes!("data.bin"); | error: couldn't read `$DIR/tests/ui/include-macros/file.txt`: $FILE_NOT_FOUND_MSG - --> $DIR/parent_dir.rs:10:13 + --> $DIR/parent_dir.rs:8:13 | LL | let _ = include_str!("tests/ui/include-macros/file.txt"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -45,5 +34,5 @@ LL - let _ = include_str!("tests/ui/include-macros/file.txt"); LL + let _ = include_str!("file.txt"); | -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors diff --git a/tests/ui/inline-const/break-inside-inline-const-issue-128604.rs b/tests/ui/inline-const/break-inside-inline-const-issue-128604.rs index a9795d1569c..cc0d757885d 100644 --- a/tests/ui/inline-const/break-inside-inline-const-issue-128604.rs +++ b/tests/ui/inline-const/break-inside-inline-const-issue-128604.rs @@ -23,3 +23,9 @@ fn main() { } } } + +const FOO: () = break; +//~^ ERROR: `break` outside of a loop or labeled block + +static BAR: () = break; +//~^ ERROR: `break` outside of a loop or labeled block diff --git a/tests/ui/inline-const/break-inside-inline-const-issue-128604.stderr b/tests/ui/inline-const/break-inside-inline-const-issue-128604.stderr index 300cd45ad69..6a967c59864 100644 --- a/tests/ui/inline-const/break-inside-inline-const-issue-128604.stderr +++ b/tests/ui/inline-const/break-inside-inline-const-issue-128604.stderr @@ -11,6 +11,19 @@ LL | break; | ^^^^^ cannot `break` outside of a loop or labeled block error[E0268]: `break` outside of a loop or labeled block + --> $DIR/break-inside-inline-const-issue-128604.rs:9:13 + | +LL | break; + | ^^^^^ cannot `break` outside of a loop or labeled block + | +help: consider labeling this block to be able to break within it + | +LL ~ 'block: { +LL | +LL ~ break 'block; + | + +error[E0268]: `break` outside of a loop or labeled block --> $DIR/break-inside-inline-const-issue-128604.rs:2:21 | LL | let _ = ['a'; { break 2; 1 }]; @@ -22,18 +35,17 @@ LL | let _ = ['a'; 'block: { break 'block 2; 1 }]; | +++++++ ++++++ error[E0268]: `break` outside of a loop or labeled block - --> $DIR/break-inside-inline-const-issue-128604.rs:9:13 - | -LL | break; - | ^^^^^ cannot `break` outside of a loop or labeled block - | -help: consider labeling this block to be able to break within it + --> $DIR/break-inside-inline-const-issue-128604.rs:27:17 | -LL ~ 'block: { -LL | -LL ~ break 'block; +LL | const FOO: () = break; + | ^^^^^ cannot `break` outside of a loop or labeled block + +error[E0268]: `break` outside of a loop or labeled block + --> $DIR/break-inside-inline-const-issue-128604.rs:30:18 | +LL | static BAR: () = break; + | ^^^^^ cannot `break` outside of a loop or labeled block -error: aborting due to 4 previous errors +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0268`. diff --git a/tests/ui/inline-const/cross-const-control-flow-125846.stderr b/tests/ui/inline-const/cross-const-control-flow-125846.stderr index 0a910e70d09..5ea571fe98a 100644 --- a/tests/ui/inline-const/cross-const-control-flow-125846.stderr +++ b/tests/ui/inline-const/cross-const-control-flow-125846.stderr @@ -39,6 +39,16 @@ LL | const { async {}.await } | | only allowed inside `async` functions and blocks | this is not `async` +error[E0572]: return statement outside of function body + --> $DIR/cross-const-control-flow-125846.rs:4:13 + | +LL | / fn foo() { +LL | | const { return } + | | --^^^^^^-- the return is part of this body... +LL | | +LL | | } + | |_- ...not the enclosing function body + error[E0268]: `break` outside of a loop or labeled block --> $DIR/cross-const-control-flow-125846.rs:9:19 | @@ -63,16 +73,6 @@ error[E0268]: `continue` outside of a loop LL | const { continue } | ^^^^^^^^ cannot `continue` outside of a loop -error[E0572]: return statement outside of function body - --> $DIR/cross-const-control-flow-125846.rs:4:13 - | -LL | / fn foo() { -LL | | const { return } - | | --^^^^^^-- the return is part of this body... -LL | | -LL | | } - | |_- ...not the enclosing function body - error: aborting due to 9 previous errors Some errors have detailed explanations: E0268, E0435, E0572, E0728, E0767. diff --git a/tests/ui/intrinsics/intrinsic-alignment.rs b/tests/ui/intrinsics/intrinsic-alignment.rs index 30a523f364c..904da71c306 100644 --- a/tests/ui/intrinsics/intrinsic-alignment.rs +++ b/tests/ui/intrinsics/intrinsic-alignment.rs @@ -23,12 +23,12 @@ use std::intrinsics as rusti; mod m { #[cfg(target_arch = "x86")] pub fn main() { - assert_eq!(crate::rusti::min_align_of::<u64>(), 4); + assert_eq!(crate::rusti::align_of::<u64>(), 4); } #[cfg(not(target_arch = "x86"))] pub fn main() { - assert_eq!(crate::rusti::min_align_of::<u64>(), 8); + assert_eq!(crate::rusti::align_of::<u64>(), 8); } } @@ -36,21 +36,21 @@ mod m { mod m { #[cfg(target_arch = "x86_64")] pub fn main() { - assert_eq!(crate::rusti::min_align_of::<u64>(), 8); + assert_eq!(crate::rusti::align_of::<u64>(), 8); } } #[cfg(target_os = "windows")] mod m { pub fn main() { - assert_eq!(crate::rusti::min_align_of::<u64>(), 8); + assert_eq!(crate::rusti::align_of::<u64>(), 8); } } #[cfg(target_family = "wasm")] mod m { pub fn main() { - assert_eq!(crate::rusti::min_align_of::<u64>(), 8); + assert_eq!(crate::rusti::align_of::<u64>(), 8); } } diff --git a/tests/ui/invalid/invalid-rustc_legacy_const_generics-issue-123077.stderr b/tests/ui/invalid/invalid-rustc_legacy_const_generics-issue-123077.stderr index d92836aa063..8d120ae98d9 100644 --- a/tests/ui/invalid/invalid-rustc_legacy_const_generics-issue-123077.stderr +++ b/tests/ui/invalid/invalid-rustc_legacy_const_generics-issue-123077.stderr @@ -19,7 +19,7 @@ LL | std::arch::x86_64::_mm_blend_ps(loop {}, loop {}, 5 + || ()); help: try using a const generic argument instead | LL - std::arch::x86_64::_mm_blend_ps(loop {}, loop {}, 5 + || ()); -LL + std::arch::x86_64::_mm_blend_ps::<{ 5 + (|| ()) }>(loop {}, loop {}); +LL + std::arch::x86_64::_mm_blend_ps::<{ 5 + || () }>(loop {}, loop {}); | error: invalid argument to a legacy const generic: cannot have const blocks, closures, async blocks or items @@ -81,7 +81,7 @@ LL | std::arch::x86_64::_mm_inserti_si64(loop {}, loop {}, || (), 1 + || ()) help: try using a const generic argument instead | LL - std::arch::x86_64::_mm_inserti_si64(loop {}, loop {}, || (), 1 + || ()); -LL + std::arch::x86_64::_mm_inserti_si64::<{ || () }, { 1 + (|| ()) }>(loop {}, loop {}); +LL + std::arch::x86_64::_mm_inserti_si64::<{ || () }, { 1 + || () }>(loop {}, loop {}); | error: aborting due to 7 previous errors diff --git a/tests/ui/issues/issue-13058.stderr b/tests/ui/issues/issue-13058.stderr index 7cc2860eb50..4f4108fa182 100644 --- a/tests/ui/issues/issue-13058.stderr +++ b/tests/ui/issues/issue-13058.stderr @@ -1,11 +1,13 @@ error[E0621]: explicit lifetime required in the type of `cont` --> $DIR/issue-13058.rs:14:21 | -LL | fn check<'r, I: Iterator<Item=usize>, T: Itble<'r, usize, I>>(cont: &T) -> bool - | -- help: add explicit lifetime `'r` to the type of `cont`: `&'r T` -LL | { LL | let cont_iter = cont.iter(); | ^^^^^^^^^^^ lifetime `'r` required + | +help: add explicit lifetime `'r` to the type of `cont` + | +LL | fn check<'r, I: Iterator<Item=usize>, T: Itble<'r, usize, I>>(cont: &'r T) -> bool + | ++ error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-14285.stderr b/tests/ui/issues/issue-14285.stderr index 4f89ae51157..edd139eecba 100644 --- a/tests/ui/issues/issue-14285.stderr +++ b/tests/ui/issues/issue-14285.stderr @@ -1,10 +1,14 @@ error[E0621]: explicit lifetime required in the type of `a` --> $DIR/issue-14285.rs:12:5 | -LL | fn foo<'a>(a: &dyn Foo) -> B<'a> { - | -------- help: add explicit lifetime `'a` to the type of `a`: `&'a (dyn Foo + 'a)` LL | B(a) | ^^^^ lifetime `'a` required + | +help: add explicit lifetime `'a` to the type of `a` + | +LL - fn foo<'a>(a: &dyn Foo) -> B<'a> { +LL + fn foo<'a>(a: &'a (dyn Foo + 'a)) -> B<'a> { + | error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-15034.stderr b/tests/ui/issues/issue-15034.stderr index 587a5c85e92..7db8ade2e48 100644 --- a/tests/ui/issues/issue-15034.stderr +++ b/tests/ui/issues/issue-15034.stderr @@ -1,10 +1,13 @@ error[E0621]: explicit lifetime required in the type of `lexer` --> $DIR/issue-15034.rs:17:9 | -LL | pub fn new(lexer: &'a mut Lexer) -> Parser<'a> { - | ------------- help: add explicit lifetime `'a` to the type of `lexer`: `&'a mut Lexer<'a>` LL | Parser { lexer: lexer } | ^^^^^^^^^^^^^^^^^^^^^^^ lifetime `'a` required + | +help: add explicit lifetime `'a` to the type of `lexer` + | +LL | pub fn new(lexer: &'a mut Lexer<'a>) -> Parser<'a> { + | ++++ error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-28561.rs b/tests/ui/issues/issue-28561.rs index f9b0ceb22fc..642b2193a4f 100644 --- a/tests/ui/issues/issue-28561.rs +++ b/tests/ui/issues/issue-28561.rs @@ -37,6 +37,7 @@ struct Array<T> { } #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] +#[allow(unpredictable_function_pointer_comparisons)] struct Fn<A, B, C, D, E, F, G, H, I, J, K, L> { f00: fn(), f01: fn(A), diff --git a/tests/ui/issues/issue-3154.stderr b/tests/ui/issues/issue-3154.stderr index 3106aaddc4a..c17e59f7fc3 100644 --- a/tests/ui/issues/issue-3154.stderr +++ b/tests/ui/issues/issue-3154.stderr @@ -1,10 +1,13 @@ error[E0621]: explicit lifetime required in the type of `x` --> $DIR/issue-3154.rs:6:5 | -LL | fn thing<'a,Q>(x: &Q) -> Thing<'a,Q> { - | -- help: add explicit lifetime `'a` to the type of `x`: `&'a Q` LL | Thing { x: x } | ^^^^^^^^^^^^^^ lifetime `'a` required + | +help: add explicit lifetime `'a` to the type of `x` + | +LL | fn thing<'a,Q>(x: &'a Q) -> Thing<'a,Q> { + | ++ error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-40288-2.stderr b/tests/ui/issues/issue-40288-2.stderr index 2c64856b08f..81cb7cdd51f 100644 --- a/tests/ui/issues/issue-40288-2.stderr +++ b/tests/ui/issues/issue-40288-2.stderr @@ -1,20 +1,24 @@ error[E0621]: explicit lifetime required in the type of `y` --> $DIR/issue-40288-2.rs:9:5 | -LL | fn lifetime_transmute_slice<'a, T: ?Sized>(x: &'a T, y: &T) -> &'a T { - | -- help: add explicit lifetime `'a` to the type of `y`: `&'a T` -... LL | out[0] | ^^^^^^ lifetime `'a` required + | +help: add explicit lifetime `'a` to the type of `y` + | +LL | fn lifetime_transmute_slice<'a, T: ?Sized>(x: &'a T, y: &'a T) -> &'a T { + | ++ error[E0621]: explicit lifetime required in the type of `y` --> $DIR/issue-40288-2.rs:24:5 | -LL | fn lifetime_transmute_struct<'a, T: ?Sized>(x: &'a T, y: &T) -> &'a T { - | -- help: add explicit lifetime `'a` to the type of `y`: `&'a T` -... LL | out.head | ^^^^^^^^ lifetime `'a` required + | +help: add explicit lifetime `'a` to the type of `y` + | +LL | fn lifetime_transmute_struct<'a, T: ?Sized>(x: &'a T, y: &'a T) -> &'a T { + | ++ error: aborting due to 2 previous errors diff --git a/tests/ui/layout/invalid-unsized-in-always-sized-tail.stderr b/tests/ui/layout/invalid-unsized-in-always-sized-tail.stderr index 1a43fd4ad18..5f6a6099ba2 100644 --- a/tests/ui/layout/invalid-unsized-in-always-sized-tail.stderr +++ b/tests/ui/layout/invalid-unsized-in-always-sized-tail.stderr @@ -24,7 +24,7 @@ error[E0080]: the type `MySlice<[bool]>` has an unknown layout LL | static CHECK: () = assert!(align_of::<P2>() == 1); | ^^^^^^^^^^^^^^^^ evaluation of `CHECK` failed inside this call | -note: inside `align_of::<P2>` +note: inside `std::mem::align_of::<P2>` --> $SRC_DIR/core/src/mem/mod.rs:LL:COL error: aborting due to 2 previous errors diff --git a/tests/ui/lifetimes/lifetime-errors/42701_one_named_and_one_anonymous.stderr b/tests/ui/lifetimes/lifetime-errors/42701_one_named_and_one_anonymous.stderr index af22078aff5..c524aabfacb 100644 --- a/tests/ui/lifetimes/lifetime-errors/42701_one_named_and_one_anonymous.stderr +++ b/tests/ui/lifetimes/lifetime-errors/42701_one_named_and_one_anonymous.stderr @@ -1,11 +1,13 @@ error[E0621]: explicit lifetime required in the type of `x` --> $DIR/42701_one_named_and_one_anonymous.rs:10:9 | -LL | fn foo2<'a>(a: &'a Foo, x: &i32) -> &'a i32 { - | ---- help: add explicit lifetime `'a` to the type of `x`: `&'a i32` -... LL | &*x | ^^^ lifetime `'a` required + | +help: add explicit lifetime `'a` to the type of `x` + | +LL | fn foo2<'a>(a: &'a Foo, x: &'a i32) -> &'a i32 { + | ++ error: aborting due to 1 previous error diff --git a/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-early-bound-in-struct.stderr b/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-early-bound-in-struct.stderr index e202c31214d..44a542eeeeb 100644 --- a/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-early-bound-in-struct.stderr +++ b/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-early-bound-in-struct.stderr @@ -1,11 +1,13 @@ error[E0621]: explicit lifetime required in the type of `other` --> $DIR/ex1-return-one-existing-name-early-bound-in-struct.rs:11:21 | -LL | fn bar(&self, other: Foo) -> Foo<'a> { - | --- help: add explicit lifetime `'a` to the type of `other`: `Foo<'a>` -... LL | other | ^^^^^ lifetime `'a` required + | +help: add explicit lifetime `'a` to the type of `other` + | +LL | fn bar(&self, other: Foo<'a>) -> Foo<'a> { + | ++++ error: aborting due to 1 previous error diff --git a/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-2.stderr b/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-2.stderr index 5518ded0106..52cf8595448 100644 --- a/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-2.stderr +++ b/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-2.stderr @@ -1,10 +1,13 @@ error[E0621]: explicit lifetime required in the type of `x` --> $DIR/ex1-return-one-existing-name-if-else-2.rs:2:16 | -LL | fn foo<'a>(x: &i32, y: &'a i32) -> &'a i32 { - | ---- help: add explicit lifetime `'a` to the type of `x`: `&'a i32` LL | if x > y { x } else { y } | ^ lifetime `'a` required + | +help: add explicit lifetime `'a` to the type of `x` + | +LL | fn foo<'a>(x: &'a i32, y: &'a i32) -> &'a i32 { + | ++ error: aborting due to 1 previous error diff --git a/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-3.stderr b/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-3.stderr index c689fa9884a..fbd9695e85f 100644 --- a/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-3.stderr +++ b/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-3.stderr @@ -1,10 +1,13 @@ error[E0621]: explicit lifetime required in parameter type --> $DIR/ex1-return-one-existing-name-if-else-3.rs:2:27 | -LL | fn foo<'a>((x, y): (&'a i32, &i32)) -> &'a i32 { - | --------------- help: add explicit lifetime `'a` to type: `(&'a i32, &'a i32)` LL | if x > y { x } else { y } | ^ lifetime `'a` required + | +help: add explicit lifetime `'a` to type + | +LL | fn foo<'a>((x, y): (&'a i32, &'a i32)) -> &'a i32 { + | ++ error: aborting due to 1 previous error diff --git a/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-2.stderr b/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-2.stderr index 3da50cfbb1d..c875381c615 100644 --- a/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-2.stderr +++ b/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-2.stderr @@ -1,10 +1,13 @@ error[E0621]: explicit lifetime required in the type of `x` --> $DIR/ex1-return-one-existing-name-if-else-using-impl-2.rs:4:15 | -LL | fn foo<'a>(x: &i32, y: &'a i32) -> &'a i32 { - | ---- help: add explicit lifetime `'a` to the type of `x`: `&'a i32` LL | if x > y { x } else { y } | ^ lifetime `'a` required + | +help: add explicit lifetime `'a` to the type of `x` + | +LL | fn foo<'a>(x: &'a i32, y: &'a i32) -> &'a i32 { + | ++ error: aborting due to 1 previous error diff --git a/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-3.stderr b/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-3.stderr index 071bda24ef8..83cd11baf39 100644 --- a/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-3.stderr +++ b/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-3.stderr @@ -1,10 +1,13 @@ error[E0621]: explicit lifetime required in the type of `x` --> $DIR/ex1-return-one-existing-name-if-else-using-impl-3.rs:7:36 | -LL | fn foo<'a>(&'a self, x: &i32) -> &i32 { - | ---- help: add explicit lifetime `'a` to the type of `x`: `&'a i32` LL | if true { &self.field } else { x } | ^ lifetime `'a` required + | +help: add explicit lifetime `'a` to the type of `x` + | +LL | fn foo<'a>(&'a self, x: &'a i32) -> &i32 { + | ++ error: aborting due to 1 previous error diff --git a/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else.stderr b/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else.stderr index 1df0776a51b..bf09bd26359 100644 --- a/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else.stderr +++ b/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else.stderr @@ -1,10 +1,13 @@ error[E0621]: explicit lifetime required in the type of `y` --> $DIR/ex1-return-one-existing-name-if-else.rs:2:27 | -LL | fn foo<'a>(x: &'a i32, y: &i32) -> &'a i32 { - | ---- help: add explicit lifetime `'a` to the type of `y`: `&'a i32` LL | if x > y { x } else { y } | ^ lifetime `'a` required + | +help: add explicit lifetime `'a` to the type of `y` + | +LL | fn foo<'a>(x: &'a i32, y: &'a i32) -> &'a i32 { + | ++ error: aborting due to 1 previous error diff --git a/tests/ui/lifetimes/lifetime-errors/ex2a-push-one-existing-name-2.stderr b/tests/ui/lifetimes/lifetime-errors/ex2a-push-one-existing-name-2.stderr index 25a2f4b96f4..f37e1ba00e7 100644 --- a/tests/ui/lifetimes/lifetime-errors/ex2a-push-one-existing-name-2.stderr +++ b/tests/ui/lifetimes/lifetime-errors/ex2a-push-one-existing-name-2.stderr @@ -1,10 +1,13 @@ error[E0621]: explicit lifetime required in the type of `x` --> $DIR/ex2a-push-one-existing-name-2.rs:6:5 | -LL | fn foo<'a>(x: Ref<i32>, y: &mut Vec<Ref<'a, i32>>) { - | -------- help: add explicit lifetime `'a` to the type of `x`: `Ref<'a, i32>` LL | y.push(x); | ^^^^^^^^^ lifetime `'a` required + | +help: add explicit lifetime `'a` to the type of `x` + | +LL | fn foo<'a>(x: Ref<'a, i32>, y: &mut Vec<Ref<'a, i32>>) { + | +++ error: aborting due to 1 previous error diff --git a/tests/ui/lifetimes/lifetime-errors/ex2a-push-one-existing-name-early-bound.stderr b/tests/ui/lifetimes/lifetime-errors/ex2a-push-one-existing-name-early-bound.stderr index e2725977d83..c25b4c9921f 100644 --- a/tests/ui/lifetimes/lifetime-errors/ex2a-push-one-existing-name-early-bound.stderr +++ b/tests/ui/lifetimes/lifetime-errors/ex2a-push-one-existing-name-early-bound.stderr @@ -1,11 +1,13 @@ error[E0621]: explicit lifetime required in the type of `y` --> $DIR/ex2a-push-one-existing-name-early-bound.rs:8:5 | -LL | fn baz<'a, 'b, T>(x: &mut Vec<&'a T>, y: &T) - | -- help: add explicit lifetime `'a` to the type of `y`: `&'a T` -... LL | x.push(y); | ^^^^^^^^^ lifetime `'a` required + | +help: add explicit lifetime `'a` to the type of `y` + | +LL | fn baz<'a, 'b, T>(x: &mut Vec<&'a T>, y: &'a T) + | ++ error: aborting due to 1 previous error diff --git a/tests/ui/lifetimes/lifetime-errors/ex2a-push-one-existing-name.stderr b/tests/ui/lifetimes/lifetime-errors/ex2a-push-one-existing-name.stderr index 1025581d5ac..8c7bee4bfc4 100644 --- a/tests/ui/lifetimes/lifetime-errors/ex2a-push-one-existing-name.stderr +++ b/tests/ui/lifetimes/lifetime-errors/ex2a-push-one-existing-name.stderr @@ -1,10 +1,13 @@ error[E0621]: explicit lifetime required in the type of `y` --> $DIR/ex2a-push-one-existing-name.rs:6:5 | -LL | fn foo<'a>(x: &mut Vec<Ref<'a, i32>>, y: Ref<i32>) { - | -------- help: add explicit lifetime `'a` to the type of `y`: `Ref<'a, i32>` LL | x.push(y); | ^^^^^^^^^ lifetime `'a` required + | +help: add explicit lifetime `'a` to the type of `y` + | +LL | fn foo<'a>(x: &mut Vec<Ref<'a, i32>>, y: Ref<'a, i32>) { + | +++ error: aborting due to 1 previous error diff --git a/tests/ui/lifetimes/noisy-follow-up-erro.stderr b/tests/ui/lifetimes/noisy-follow-up-erro.stderr index 04863badbd1..eb52147dba4 100644 --- a/tests/ui/lifetimes/noisy-follow-up-erro.stderr +++ b/tests/ui/lifetimes/noisy-follow-up-erro.stderr @@ -15,11 +15,14 @@ LL | struct Foo<'c, 'd>(&'c (), &'d ()); error[E0621]: explicit lifetime required in the type of `foo` --> $DIR/noisy-follow-up-erro.rs:14:9 | -LL | fn boom(&self, foo: &mut Foo<'_, '_, 'a>) -> Result<(), &'a ()> { - | -------------------- help: add explicit lifetime `'a` to the type of `foo`: `&mut Foo<'_, 'a>` -LL | LL | self.bar().map_err(|()| foo.acc(self))?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime `'a` required + | +help: add explicit lifetime `'a` to the type of `foo` + | +LL - fn boom(&self, foo: &mut Foo<'_, '_, 'a>) -> Result<(), &'a ()> { +LL + fn boom(&self, foo: &mut Foo<'_, 'a>) -> Result<(), &'a ()> { + | error: aborting due to 2 previous errors diff --git a/tests/ui/linkage-attr/raw-dylib/windows/unsupported-abi.rs b/tests/ui/linkage-attr/raw-dylib/windows/unsupported-abi.rs index df69782e154..9babc20d1a1 100644 --- a/tests/ui/linkage-attr/raw-dylib/windows/unsupported-abi.rs +++ b/tests/ui/linkage-attr/raw-dylib/windows/unsupported-abi.rs @@ -1,6 +1,14 @@ -//@ only-x86_64 -//@ only-windows +//@ add-core-stubs +//@ compile-flags: --target x86_64-pc-windows-msvc //@ compile-flags: --crate-type lib --emit link +//@ needs-llvm-components: x86 +#![no_core] +#![feature(no_core)] +extern crate minicore; + +// It may seem weird this is a cross-platform-testable thing, since doesn't it test linkage? +// However the main thing we are testing is an *error*, so it works fine! + #[link(name = "foo", kind = "raw-dylib")] extern "stdcall" { //~^ WARN: calling convention not supported on this target diff --git a/tests/ui/linkage-attr/raw-dylib/windows/unsupported-abi.stderr b/tests/ui/linkage-attr/raw-dylib/windows/unsupported-abi.stderr index e7a32f4c84b..95ea9080486 100644 --- a/tests/ui/linkage-attr/raw-dylib/windows/unsupported-abi.stderr +++ b/tests/ui/linkage-attr/raw-dylib/windows/unsupported-abi.stderr @@ -1,5 +1,5 @@ warning: use of calling convention not supported on this target - --> $DIR/unsupported-abi.rs:5:1 + --> $DIR/unsupported-abi.rs:13:1 | LL | / extern "stdcall" { LL | | @@ -15,27 +15,10 @@ LL | | } = note: `#[warn(unsupported_calling_conventions)]` on by default error: ABI not supported by `#[link(kind = "raw-dylib")]` on this architecture - --> $DIR/unsupported-abi.rs:8:5 + --> $DIR/unsupported-abi.rs:16:5 | LL | fn f(x: i32); | ^^^^^^^^^^^^^ error: aborting due to 1 previous error; 1 warning emitted -Future incompatibility report: Future breakage diagnostic: -warning: use of calling convention not supported on this target - --> $DIR/unsupported-abi.rs:5:1 - | -LL | / extern "stdcall" { -LL | | -LL | | -LL | | fn f(x: i32); -LL | | -LL | | } - | |_^ - | - = 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 #137018 <https://github.com/rust-lang/rust/issues/137018> - = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"` - = note: `#[warn(unsupported_calling_conventions)]` on by default - diff --git a/tests/ui/lint/expansion-time.rs b/tests/ui/lint/expansion-time.rs index 5ffb0c7881e..2c59bf00065 100644 --- a/tests/ui/lint/expansion-time.rs +++ b/tests/ui/lint/expansion-time.rs @@ -5,10 +5,6 @@ macro_rules! foo { ( $($i:ident)* ) => { $($i)+ }; //~ WARN meta-variable repeats with different Kleene operator } -#[warn(missing_fragment_specifier)] -macro_rules! m { ($i) => {} } //~ WARN missing fragment specifier - //~| WARN this was previously accepted - #[deprecated = "reason"] macro_rules! deprecated { () => {} diff --git a/tests/ui/lint/expansion-time.stderr b/tests/ui/lint/expansion-time.stderr index f24d1b68a8d..b1154d1a54c 100644 --- a/tests/ui/lint/expansion-time.stderr +++ b/tests/ui/lint/expansion-time.stderr @@ -12,20 +12,6 @@ note: the lint level is defined here LL | #[warn(meta_variable_misuse)] | ^^^^^^^^^^^^^^^^^^^^ -warning: missing fragment specifier - --> $DIR/expansion-time.rs:9:19 - | -LL | macro_rules! m { ($i) => {} } - | ^^ - | - = 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 #40107 <https://github.com/rust-lang/rust/issues/40107> -note: the lint level is defined here - --> $DIR/expansion-time.rs:8:8 - | -LL | #[warn(missing_fragment_specifier)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - warning: include macro expected single expression in source --> $DIR/expansion-time-include.rs:4:1 | @@ -33,25 +19,10 @@ LL | 2 | ^ | note: the lint level is defined here - --> $DIR/expansion-time.rs:22:8 + --> $DIR/expansion-time.rs:18:8 | LL | #[warn(incomplete_include)] | ^^^^^^^^^^^^^^^^^^ -warning: 3 warnings emitted - -Future incompatibility report: Future breakage diagnostic: -warning: missing fragment specifier - --> $DIR/expansion-time.rs:9:19 - | -LL | macro_rules! m { ($i) => {} } - | ^^ - | - = 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 #40107 <https://github.com/rust-lang/rust/issues/40107> -note: the lint level is defined here - --> $DIR/expansion-time.rs:8:8 - | -LL | #[warn(missing_fragment_specifier)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +warning: 2 warnings emitted diff --git a/tests/ui/lint/fn-ptr-comparisons-some.rs b/tests/ui/lint/fn-ptr-comparisons-some.rs index 152e16b9884..c6ddd759baa 100644 --- a/tests/ui/lint/fn-ptr-comparisons-some.rs +++ b/tests/ui/lint/fn-ptr-comparisons-some.rs @@ -12,6 +12,6 @@ fn main() { let _ = Some::<FnPtr>(func) == Some(func as unsafe extern "C" fn()); //~^ WARN function pointer comparisons - // Undecided as of https://github.com/rust-lang/rust/pull/134536 assert_eq!(Some::<FnPtr>(func), Some(func as unsafe extern "C" fn())); + //~^ WARN function pointer comparisons } diff --git a/tests/ui/lint/fn-ptr-comparisons-some.stderr b/tests/ui/lint/fn-ptr-comparisons-some.stderr index eefad05b676..522c4399bce 100644 --- a/tests/ui/lint/fn-ptr-comparisons-some.stderr +++ b/tests/ui/lint/fn-ptr-comparisons-some.stderr @@ -9,5 +9,16 @@ LL | let _ = Some::<FnPtr>(func) == Some(func as unsafe extern "C" fn()); = note: for more information visit <https://doc.rust-lang.org/nightly/core/ptr/fn.fn_addr_eq.html> = note: `#[warn(unpredictable_function_pointer_comparisons)]` on by default -warning: 1 warning emitted +warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique + --> $DIR/fn-ptr-comparisons-some.rs:15:5 + | +LL | assert_eq!(Some::<FnPtr>(func), Some(func as unsafe extern "C" fn())); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the address of the same function can vary between different codegen units + = note: furthermore, different functions could have the same address after being merged together + = note: for more information visit <https://doc.rust-lang.org/nightly/core/ptr/fn.fn_addr_eq.html> + = note: this warning originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + +warning: 2 warnings emitted diff --git a/tests/ui/lint/fn-ptr-comparisons-weird.rs b/tests/ui/lint/fn-ptr-comparisons-weird.rs index 171fbfb8727..4d756cb49df 100644 --- a/tests/ui/lint/fn-ptr-comparisons-weird.rs +++ b/tests/ui/lint/fn-ptr-comparisons-weird.rs @@ -1,5 +1,23 @@ //@ check-pass +#[derive(PartialEq, Eq)] +struct A { + f: fn(), + //~^ WARN function pointer comparisons +} + +#[allow(unpredictable_function_pointer_comparisons)] +#[derive(PartialEq, Eq)] +struct AllowedAbove { + f: fn(), +} + +#[derive(PartialEq, Eq)] +#[allow(unpredictable_function_pointer_comparisons)] +struct AllowedBelow { + f: fn(), +} + fn main() { let f: fn() = main; let g: fn() = main; @@ -12,4 +30,8 @@ fn main() { //~^ WARN function pointer comparisons let _ = f < g; //~^ WARN function pointer comparisons + let _ = assert_eq!(g, g); + //~^ WARN function pointer comparisons + let _ = assert_ne!(g, g); + //~^ WARN function pointer comparisons } diff --git a/tests/ui/lint/fn-ptr-comparisons-weird.stderr b/tests/ui/lint/fn-ptr-comparisons-weird.stderr index f2371663922..2014e519c25 100644 --- a/tests/ui/lint/fn-ptr-comparisons-weird.stderr +++ b/tests/ui/lint/fn-ptr-comparisons-weird.stderr @@ -1,5 +1,19 @@ warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique - --> $DIR/fn-ptr-comparisons-weird.rs:7:13 + --> $DIR/fn-ptr-comparisons-weird.rs:5:5 + | +LL | #[derive(PartialEq, Eq)] + | --------- in this derive macro expansion +LL | struct A { +LL | f: fn(), + | ^^^^^^^ + | + = note: the address of the same function can vary between different codegen units + = note: furthermore, different functions could have the same address after being merged together + = note: for more information visit <https://doc.rust-lang.org/nightly/core/ptr/fn.fn_addr_eq.html> + = note: `#[warn(unpredictable_function_pointer_comparisons)]` on by default + +warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique + --> $DIR/fn-ptr-comparisons-weird.rs:25:13 | LL | let _ = f > g; | ^^^^^ @@ -7,10 +21,9 @@ LL | let _ = f > g; = note: the address of the same function can vary between different codegen units = note: furthermore, different functions could have the same address after being merged together = note: for more information visit <https://doc.rust-lang.org/nightly/core/ptr/fn.fn_addr_eq.html> - = note: `#[warn(unpredictable_function_pointer_comparisons)]` on by default warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique - --> $DIR/fn-ptr-comparisons-weird.rs:9:13 + --> $DIR/fn-ptr-comparisons-weird.rs:27:13 | LL | let _ = f >= g; | ^^^^^^ @@ -20,7 +33,7 @@ LL | let _ = f >= g; = note: for more information visit <https://doc.rust-lang.org/nightly/core/ptr/fn.fn_addr_eq.html> warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique - --> $DIR/fn-ptr-comparisons-weird.rs:11:13 + --> $DIR/fn-ptr-comparisons-weird.rs:29:13 | LL | let _ = f <= g; | ^^^^^^ @@ -30,7 +43,7 @@ LL | let _ = f <= g; = note: for more information visit <https://doc.rust-lang.org/nightly/core/ptr/fn.fn_addr_eq.html> warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique - --> $DIR/fn-ptr-comparisons-weird.rs:13:13 + --> $DIR/fn-ptr-comparisons-weird.rs:31:13 | LL | let _ = f < g; | ^^^^^ @@ -39,5 +52,27 @@ LL | let _ = f < g; = note: furthermore, different functions could have the same address after being merged together = note: for more information visit <https://doc.rust-lang.org/nightly/core/ptr/fn.fn_addr_eq.html> -warning: 4 warnings emitted +warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique + --> $DIR/fn-ptr-comparisons-weird.rs:33:13 + | +LL | let _ = assert_eq!(g, g); + | ^^^^^^^^^^^^^^^^ + | + = note: the address of the same function can vary between different codegen units + = note: furthermore, different functions could have the same address after being merged together + = note: for more information visit <https://doc.rust-lang.org/nightly/core/ptr/fn.fn_addr_eq.html> + = note: this warning originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + +warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique + --> $DIR/fn-ptr-comparisons-weird.rs:35:13 + | +LL | let _ = assert_ne!(g, g); + | ^^^^^^^^^^^^^^^^ + | + = note: the address of the same function can vary between different codegen units + = note: furthermore, different functions could have the same address after being merged together + = note: for more information visit <https://doc.rust-lang.org/nightly/core/ptr/fn.fn_addr_eq.html> + = note: this warning originates in the macro `assert_ne` (in Nightly builds, run with -Z macro-backtrace for more info) + +warning: 7 warnings emitted diff --git a/tests/ui/lint/fn-ptr-comparisons.fixed b/tests/ui/lint/fn-ptr-comparisons.fixed index 22f16177a04..41cdb7bf6ae 100644 --- a/tests/ui/lint/fn-ptr-comparisons.fixed +++ b/tests/ui/lint/fn-ptr-comparisons.fixed @@ -11,7 +11,6 @@ extern "C" fn c() {} extern "C" fn args(_a: i32) -> i32 { 0 } -#[derive(PartialEq, Eq)] struct A { f: fn(), } @@ -52,7 +51,6 @@ fn main() { let _ = std::ptr::fn_addr_eq(t, test as unsafe extern "C" fn()); //~^ WARN function pointer comparisons - let _ = a1 == a2; // should not warn let _ = std::ptr::fn_addr_eq(a1.f, a2.f); //~^ WARN function pointer comparisons } diff --git a/tests/ui/lint/fn-ptr-comparisons.rs b/tests/ui/lint/fn-ptr-comparisons.rs index 90a8ab5c926..c2601d6adfb 100644 --- a/tests/ui/lint/fn-ptr-comparisons.rs +++ b/tests/ui/lint/fn-ptr-comparisons.rs @@ -11,7 +11,6 @@ extern "C" fn c() {} extern "C" fn args(_a: i32) -> i32 { 0 } -#[derive(PartialEq, Eq)] struct A { f: fn(), } @@ -52,7 +51,6 @@ fn main() { let _ = t == test; //~^ WARN function pointer comparisons - let _ = a1 == a2; // should not warn let _ = a1.f == a2.f; //~^ WARN function pointer comparisons } diff --git a/tests/ui/lint/fn-ptr-comparisons.stderr b/tests/ui/lint/fn-ptr-comparisons.stderr index e6993323898..5913acca16b 100644 --- a/tests/ui/lint/fn-ptr-comparisons.stderr +++ b/tests/ui/lint/fn-ptr-comparisons.stderr @@ -1,5 +1,5 @@ warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique - --> $DIR/fn-ptr-comparisons.rs:26:13 + --> $DIR/fn-ptr-comparisons.rs:25:13 | LL | let _ = f == a; | ^^^^^^ @@ -15,7 +15,7 @@ LL + let _ = std::ptr::fn_addr_eq(f, a as fn()); | warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique - --> $DIR/fn-ptr-comparisons.rs:28:13 + --> $DIR/fn-ptr-comparisons.rs:27:13 | LL | let _ = f != a; | ^^^^^^ @@ -30,7 +30,7 @@ LL + let _ = !std::ptr::fn_addr_eq(f, a as fn()); | warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique - --> $DIR/fn-ptr-comparisons.rs:30:13 + --> $DIR/fn-ptr-comparisons.rs:29:13 | LL | let _ = f == g; | ^^^^^^ @@ -45,7 +45,7 @@ LL + let _ = std::ptr::fn_addr_eq(f, g); | warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique - --> $DIR/fn-ptr-comparisons.rs:32:13 + --> $DIR/fn-ptr-comparisons.rs:31:13 | LL | let _ = f == f; | ^^^^^^ @@ -60,7 +60,7 @@ LL + let _ = std::ptr::fn_addr_eq(f, f); | warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique - --> $DIR/fn-ptr-comparisons.rs:34:13 + --> $DIR/fn-ptr-comparisons.rs:33:13 | LL | let _ = g == g; | ^^^^^^ @@ -75,7 +75,7 @@ LL + let _ = std::ptr::fn_addr_eq(g, g); | warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique - --> $DIR/fn-ptr-comparisons.rs:36:13 + --> $DIR/fn-ptr-comparisons.rs:35:13 | LL | let _ = g == g; | ^^^^^^ @@ -90,7 +90,7 @@ LL + let _ = std::ptr::fn_addr_eq(g, g); | warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique - --> $DIR/fn-ptr-comparisons.rs:38:13 + --> $DIR/fn-ptr-comparisons.rs:37:13 | LL | let _ = &g == &g; | ^^^^^^^^ @@ -105,7 +105,7 @@ LL + let _ = std::ptr::fn_addr_eq(g, g); | warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique - --> $DIR/fn-ptr-comparisons.rs:40:13 + --> $DIR/fn-ptr-comparisons.rs:39:13 | LL | let _ = a as fn() == g; | ^^^^^^^^^^^^^^ @@ -120,7 +120,7 @@ LL + let _ = std::ptr::fn_addr_eq(a as fn(), g); | warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique - --> $DIR/fn-ptr-comparisons.rs:44:13 + --> $DIR/fn-ptr-comparisons.rs:43:13 | LL | let _ = cfn == c; | ^^^^^^^^ @@ -135,7 +135,7 @@ LL + let _ = std::ptr::fn_addr_eq(cfn, c as extern "C" fn()); | warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique - --> $DIR/fn-ptr-comparisons.rs:48:13 + --> $DIR/fn-ptr-comparisons.rs:47:13 | LL | let _ = argsfn == args; | ^^^^^^^^^^^^^^ @@ -150,7 +150,7 @@ LL + let _ = std::ptr::fn_addr_eq(argsfn, args as extern "C" fn(i32) -> i32) | warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique - --> $DIR/fn-ptr-comparisons.rs:52:13 + --> $DIR/fn-ptr-comparisons.rs:51:13 | LL | let _ = t == test; | ^^^^^^^^^ @@ -165,7 +165,7 @@ LL + let _ = std::ptr::fn_addr_eq(t, test as unsafe extern "C" fn()); | warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique - --> $DIR/fn-ptr-comparisons.rs:56:13 + --> $DIR/fn-ptr-comparisons.rs:54:13 | LL | let _ = a1.f == a2.f; | ^^^^^^^^^^^^ diff --git a/tests/ui/lint/future-incompatible-lint-group.rs b/tests/ui/lint/future-incompatible-lint-group.rs new file mode 100644 index 00000000000..22a7ccb463b --- /dev/null +++ b/tests/ui/lint/future-incompatible-lint-group.rs @@ -0,0 +1,30 @@ +//! Test that future_incompatible lint group only includes edition-independent lints + +// Ensure that the future_incompatible lint group only includes +// lints for changes that are not tied to an edition +#![deny(future_incompatible)] + +enum E { V } + +trait Tr1 { + type V; + fn foo() -> Self::V; +} + +impl Tr1 for E { + type V = u8; + + // Error since this is a `future_incompatible` lint + fn foo() -> Self::V { 0 } + //~^ ERROR ambiguous associated item + //~| WARN this was previously accepted +} + +trait Tr2 { + // Warn only since this is not a `future_incompatible` lint + fn f(u8) {} + //~^ WARN anonymous parameters are deprecated + //~| WARN this is accepted in the current edition +} + +fn main() {} diff --git a/tests/ui/lint/future-incompatible-lint-group.stderr b/tests/ui/lint/future-incompatible-lint-group.stderr new file mode 100644 index 00000000000..87b9ebec08b --- /dev/null +++ b/tests/ui/lint/future-incompatible-lint-group.stderr @@ -0,0 +1,37 @@ +warning: anonymous parameters are deprecated and will be removed in the next edition + --> $DIR/future-incompatible-lint-group.rs:25:10 + | +LL | fn f(u8) {} + | ^^ help: try naming the parameter or explicitly ignoring it: `_: u8` + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! + = note: for more information, see issue #41686 <https://github.com/rust-lang/rust/issues/41686> + = note: `#[warn(anonymous_parameters)]` on by default + +error: ambiguous associated item + --> $DIR/future-incompatible-lint-group.rs:18:17 + | +LL | fn foo() -> Self::V { 0 } + | ^^^^^^^ help: use fully-qualified syntax: `<E as Tr1>::V` + | + = 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 #57644 <https://github.com/rust-lang/rust/issues/57644> +note: `V` could refer to the variant defined here + --> $DIR/future-incompatible-lint-group.rs:7:10 + | +LL | enum E { V } + | ^ +note: `V` could also refer to the associated type defined here + --> $DIR/future-incompatible-lint-group.rs:10:5 + | +LL | type V; + | ^^^^^^ +note: the lint level is defined here + --> $DIR/future-incompatible-lint-group.rs:5:9 + | +LL | #![deny(future_incompatible)] + | ^^^^^^^^^^^^^^^^^^^ + = note: `#[deny(ambiguous_associated_items)]` implied by `#[deny(future_incompatible)]` + +error: aborting due to 1 previous error; 1 warning emitted + diff --git a/tests/ui/loops/issue-43162.stderr b/tests/ui/loops/issue-43162.stderr index 40d9200058e..f6b6bf2621c 100644 --- a/tests/ui/loops/issue-43162.stderr +++ b/tests/ui/loops/issue-43162.stderr @@ -4,12 +4,6 @@ error[E0268]: `break` outside of a loop or labeled block LL | break true; | ^^^^^^^^^^ cannot `break` outside of a loop or labeled block -error[E0268]: `break` outside of a loop or labeled block - --> $DIR/issue-43162.rs:7:5 - | -LL | break {}; - | ^^^^^^^^ cannot `break` outside of a loop or labeled block - error[E0308]: mismatched types --> $DIR/issue-43162.rs:1:13 | @@ -18,6 +12,12 @@ LL | fn foo() -> bool { | | | implicitly returns `()` as its body has no tail or `return` expression +error[E0268]: `break` outside of a loop or labeled block + --> $DIR/issue-43162.rs:7:5 + | +LL | break {}; + | ^^^^^^^^ cannot `break` outside of a loop or labeled block + error: aborting due to 3 previous errors Some errors have detailed explanations: E0268, E0308. diff --git a/tests/ui/macros/auxiliary/serde.rs b/tests/ui/macros/auxiliary/serde.rs new file mode 100644 index 00000000000..355b650bcf3 --- /dev/null +++ b/tests/ui/macros/auxiliary/serde.rs @@ -0,0 +1,19 @@ +//@ force-host +//@ no-prefer-dynamic + +#![crate_type = "proc-macro"] +#![feature(proc_macro_quote)] + +extern crate proc_macro; + +use proc_macro::*; + +#[proc_macro_derive(Serialize, attributes(serde))] +pub fn serialize(ts: TokenStream) -> TokenStream { + quote!{} +} + +#[proc_macro_derive(Deserialize, attributes(serde))] +pub fn deserialize(ts: TokenStream) -> TokenStream { + quote!{} +} diff --git a/tests/ui/macros/issue-39404.rs b/tests/ui/macros/issue-39404.rs index 2229f2c3900..ceeb6231bc8 100644 --- a/tests/ui/macros/issue-39404.rs +++ b/tests/ui/macros/issue-39404.rs @@ -1,7 +1,7 @@ #![allow(unused)] -macro_rules! m { ($i) => {} } -//~^ ERROR missing fragment specifier -//~| WARN previously accepted +macro_rules! m { + ($i) => {}; //~ ERROR missing fragment specifier +} fn main() {} diff --git a/tests/ui/macros/issue-39404.stderr b/tests/ui/macros/issue-39404.stderr index 176c8e9f073..62d0bc1018c 100644 --- a/tests/ui/macros/issue-39404.stderr +++ b/tests/ui/macros/issue-39404.stderr @@ -1,23 +1,15 @@ error: missing fragment specifier - --> $DIR/issue-39404.rs:3:19 + --> $DIR/issue-39404.rs:4:6 | -LL | macro_rules! m { ($i) => {} } - | ^^ +LL | ($i) => {}; + | ^^ | - = 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 #40107 <https://github.com/rust-lang/rust/issues/40107> - = note: `#[deny(missing_fragment_specifier)]` on by default + = note: fragment specifiers must be provided + = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`, along with `expr_2021` and `pat_param` for edition compatibility +help: try adding a specifier here + | +LL | ($i:spec) => {}; + | +++++ error: aborting due to 1 previous error -Future incompatibility report: Future breakage diagnostic: -error: missing fragment specifier - --> $DIR/issue-39404.rs:3:19 - | -LL | macro_rules! m { ($i) => {} } - | ^^ - | - = 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 #40107 <https://github.com/rust-lang/rust/issues/40107> - = note: `#[deny(missing_fragment_specifier)]` on by default - diff --git a/tests/ui/macros/macro-match-nonterminal.rs b/tests/ui/macros/macro-match-nonterminal.rs index 5d9eb55fee0..fa2af945a1f 100644 --- a/tests/ui/macros/macro-match-nonterminal.rs +++ b/tests/ui/macros/macro-match-nonterminal.rs @@ -3,8 +3,6 @@ macro_rules! test { //~^ ERROR missing fragment //~| ERROR missing fragment //~| ERROR missing fragment - //~| WARN this was previously accepted - //~| WARN this was previously accepted () }; } diff --git a/tests/ui/macros/macro-match-nonterminal.stderr b/tests/ui/macros/macro-match-nonterminal.stderr index f221f92c3cd..8196d795c4c 100644 --- a/tests/ui/macros/macro-match-nonterminal.stderr +++ b/tests/ui/macros/macro-match-nonterminal.stderr @@ -3,16 +3,13 @@ error: missing fragment specifier | LL | ($a, $b) => { | ^^ - -error: missing fragment specifier - --> $DIR/macro-match-nonterminal.rs:2:6 | -LL | ($a, $b) => { - | ^^ + = note: fragment specifiers must be provided + = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`, along with `expr_2021` and `pat_param` for edition compatibility +help: try adding a specifier here | - = 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 #40107 <https://github.com/rust-lang/rust/issues/40107> - = note: `#[deny(missing_fragment_specifier)]` on by default +LL | ($a:spec, $b) => { + | +++++ error: missing fragment specifier --> $DIR/macro-match-nonterminal.rs:2:10 @@ -20,30 +17,18 @@ error: missing fragment specifier LL | ($a, $b) => { | ^^ | - = 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 #40107 <https://github.com/rust-lang/rust/issues/40107> - -error: aborting due to 3 previous errors + = note: fragment specifiers must be provided + = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`, along with `expr_2021` and `pat_param` for edition compatibility +help: try adding a specifier here + | +LL | ($a, $b:spec) => { + | +++++ -Future incompatibility report: Future breakage diagnostic: error: missing fragment specifier --> $DIR/macro-match-nonterminal.rs:2:6 | LL | ($a, $b) => { | ^^ - | - = 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 #40107 <https://github.com/rust-lang/rust/issues/40107> - = note: `#[deny(missing_fragment_specifier)]` on by default -Future breakage diagnostic: -error: missing fragment specifier - --> $DIR/macro-match-nonterminal.rs:2:10 - | -LL | ($a, $b) => { - | ^^ - | - = 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 #40107 <https://github.com/rust-lang/rust/issues/40107> - = note: `#[deny(missing_fragment_specifier)]` on by default +error: aborting due to 3 previous errors diff --git a/tests/ui/macros/macro-missing-fragment-deduplication.rs b/tests/ui/macros/macro-missing-fragment-deduplication.rs index b77c51e055b..481f08fa111 100644 --- a/tests/ui/macros/macro-missing-fragment-deduplication.rs +++ b/tests/ui/macros/macro-missing-fragment-deduplication.rs @@ -1,10 +1,8 @@ //@ compile-flags: -Zdeduplicate-diagnostics=yes macro_rules! m { - ($name) => {} - //~^ ERROR missing fragment - //~| ERROR missing fragment - //~| WARN this was previously accepted + ($name) => {}; //~ ERROR missing fragment + //~| ERROR missing fragment } fn main() { diff --git a/tests/ui/macros/macro-missing-fragment-deduplication.stderr b/tests/ui/macros/macro-missing-fragment-deduplication.stderr index c46712f70fd..820f7eb3cf7 100644 --- a/tests/ui/macros/macro-missing-fragment-deduplication.stderr +++ b/tests/ui/macros/macro-missing-fragment-deduplication.stderr @@ -1,29 +1,21 @@ error: missing fragment specifier --> $DIR/macro-missing-fragment-deduplication.rs:4:6 | -LL | ($name) => {} +LL | ($name) => {}; | ^^^^^ - -error: missing fragment specifier - --> $DIR/macro-missing-fragment-deduplication.rs:4:6 | -LL | ($name) => {} - | ^^^^^ + = note: fragment specifiers must be provided + = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`, along with `expr_2021` and `pat_param` for edition compatibility +help: try adding a specifier here | - = 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 #40107 <https://github.com/rust-lang/rust/issues/40107> - = note: `#[deny(missing_fragment_specifier)]` on by default +LL | ($name:spec) => {}; + | +++++ -error: aborting due to 2 previous errors - -Future incompatibility report: Future breakage diagnostic: error: missing fragment specifier --> $DIR/macro-missing-fragment-deduplication.rs:4:6 | -LL | ($name) => {} +LL | ($name) => {}; | ^^^^^ - | - = 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 #40107 <https://github.com/rust-lang/rust/issues/40107> - = note: `#[deny(missing_fragment_specifier)]` on by default + +error: aborting due to 2 previous errors diff --git a/tests/ui/macros/macro-missing-fragment.e2015.stderr b/tests/ui/macros/macro-missing-fragment.e2015.stderr deleted file mode 100644 index 3d32f203d4a..00000000000 --- a/tests/ui/macros/macro-missing-fragment.e2015.stderr +++ /dev/null @@ -1,85 +0,0 @@ -error: missing fragment specifier - --> $DIR/macro-missing-fragment.rs:8:20 - | -LL | ( $( any_token $field_rust_type )* ) => {}; - | ^^^^^^^^^^^^^^^^ - -warning: missing fragment specifier - --> $DIR/macro-missing-fragment.rs:8:20 - | -LL | ( $( any_token $field_rust_type )* ) => {}; - | ^^^^^^^^^^^^^^^^ - | - = 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 #40107 <https://github.com/rust-lang/rust/issues/40107> -note: the lint level is defined here - --> $DIR/macro-missing-fragment.rs:5:9 - | -LL | #![warn(missing_fragment_specifier)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - -warning: missing fragment specifier - --> $DIR/macro-missing-fragment.rs:18:7 - | -LL | ( $name ) => {}; - | ^^^^^ - | - = 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 #40107 <https://github.com/rust-lang/rust/issues/40107> - -warning: missing fragment specifier - --> $DIR/macro-missing-fragment.rs:25:7 - | -LL | ( $name ) => {}; - | ^^^^^ - | - = 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 #40107 <https://github.com/rust-lang/rust/issues/40107> - -error: aborting due to 1 previous error; 3 warnings emitted - -Future incompatibility report: Future breakage diagnostic: -warning: missing fragment specifier - --> $DIR/macro-missing-fragment.rs:8:20 - | -LL | ( $( any_token $field_rust_type )* ) => {}; - | ^^^^^^^^^^^^^^^^ - | - = 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 #40107 <https://github.com/rust-lang/rust/issues/40107> -note: the lint level is defined here - --> $DIR/macro-missing-fragment.rs:5:9 - | -LL | #![warn(missing_fragment_specifier)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Future breakage diagnostic: -warning: missing fragment specifier - --> $DIR/macro-missing-fragment.rs:18:7 - | -LL | ( $name ) => {}; - | ^^^^^ - | - = 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 #40107 <https://github.com/rust-lang/rust/issues/40107> -note: the lint level is defined here - --> $DIR/macro-missing-fragment.rs:5:9 - | -LL | #![warn(missing_fragment_specifier)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Future breakage diagnostic: -warning: missing fragment specifier - --> $DIR/macro-missing-fragment.rs:25:7 - | -LL | ( $name ) => {}; - | ^^^^^ - | - = 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 #40107 <https://github.com/rust-lang/rust/issues/40107> -note: the lint level is defined here - --> $DIR/macro-missing-fragment.rs:5:9 - | -LL | #![warn(missing_fragment_specifier)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - diff --git a/tests/ui/macros/macro-missing-fragment.rs b/tests/ui/macros/macro-missing-fragment.rs index 42387e8dbbf..533aa147bcb 100644 --- a/tests/ui/macros/macro-missing-fragment.rs +++ b/tests/ui/macros/macro-missing-fragment.rs @@ -1,31 +1,17 @@ -//@ revisions: e2015 e2024 -//@[e2015] edition:2015 -//@[e2024] edition:2024 - -#![warn(missing_fragment_specifier)] +//! Ensure that macros produce an error if fragment specifiers are missing. macro_rules! used_arm { - ( $( any_token $field_rust_type )* ) => {}; - //[e2015]~^ ERROR missing fragment - //[e2015]~| WARN missing fragment - //[e2015]~| WARN this was previously accepted - //[e2024]~^^^^ ERROR missing fragment - //[e2024]~| ERROR missing fragment + ( $( any_token $field_rust_type )* ) => {}; //~ ERROR missing fragment + //~| ERROR missing fragment } macro_rules! used_macro_unused_arm { () => {}; - ( $name ) => {}; - //[e2015]~^ WARN missing fragment - //[e2015]~| WARN this was previously accepted - //[e2024]~^^^ ERROR missing fragment + ( $name ) => {}; //~ ERROR missing fragment } macro_rules! unused_macro { - ( $name ) => {}; - //[e2015]~^ WARN missing fragment - //[e2015]~| WARN this was previously accepted - //[e2024]~^^^ ERROR missing fragment + ( $name ) => {}; //~ ERROR missing fragment } fn main() { diff --git a/tests/ui/macros/macro-missing-fragment.e2024.stderr b/tests/ui/macros/macro-missing-fragment.stderr index a9195063a5b..4a99d7d949c 100644 --- a/tests/ui/macros/macro-missing-fragment.e2024.stderr +++ b/tests/ui/macros/macro-missing-fragment.stderr @@ -1,10 +1,10 @@ error: missing fragment specifier - --> $DIR/macro-missing-fragment.rs:8:20 + --> $DIR/macro-missing-fragment.rs:4:20 | LL | ( $( any_token $field_rust_type )* ) => {}; | ^^^^^^^^^^^^^^^^ | - = note: fragment specifiers must be specified in the 2024 edition + = note: fragment specifiers must be provided = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`, along with `expr_2021` and `pat_param` for edition compatibility help: try adding a specifier here | @@ -12,12 +12,12 @@ LL | ( $( any_token $field_rust_type:spec )* ) => {}; | +++++ error: missing fragment specifier - --> $DIR/macro-missing-fragment.rs:18:7 + --> $DIR/macro-missing-fragment.rs:10:7 | LL | ( $name ) => {}; | ^^^^^ | - = note: fragment specifiers must be specified in the 2024 edition + = note: fragment specifiers must be provided = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`, along with `expr_2021` and `pat_param` for edition compatibility help: try adding a specifier here | @@ -25,12 +25,12 @@ LL | ( $name:spec ) => {}; | +++++ error: missing fragment specifier - --> $DIR/macro-missing-fragment.rs:25:7 + --> $DIR/macro-missing-fragment.rs:14:7 | LL | ( $name ) => {}; | ^^^^^ | - = note: fragment specifiers must be specified in the 2024 edition + = note: fragment specifiers must be provided = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`, along with `expr_2021` and `pat_param` for edition compatibility help: try adding a specifier here | @@ -38,7 +38,7 @@ LL | ( $name:spec ) => {}; | +++++ error: missing fragment specifier - --> $DIR/macro-missing-fragment.rs:8:20 + --> $DIR/macro-missing-fragment.rs:4:20 | LL | ( $( any_token $field_rust_type )* ) => {}; | ^^^^^^^^^^^^^^^^ diff --git a/tests/ui/macros/macro-reexport-removed.rs b/tests/ui/macros/macro-reexport-removed.rs index 4a054686d77..c1267f14cd8 100644 --- a/tests/ui/macros/macro-reexport-removed.rs +++ b/tests/ui/macros/macro-reexport-removed.rs @@ -1,4 +1,5 @@ //@ aux-build:two_macros.rs +//@ normalize-stderr: "you are using [0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9]+)?( \([^)]*\))?" -> "you are using $$RUSTC_VERSION" #![feature(macro_reexport)] //~ ERROR feature has been removed diff --git a/tests/ui/macros/macro-reexport-removed.stderr b/tests/ui/macros/macro-reexport-removed.stderr index 475a586ddc0..d4940eeb775 100644 --- a/tests/ui/macros/macro-reexport-removed.stderr +++ b/tests/ui/macros/macro-reexport-removed.stderr @@ -1,13 +1,14 @@ error[E0557]: feature has been removed - --> $DIR/macro-reexport-removed.rs:3:12 + --> $DIR/macro-reexport-removed.rs:4:12 | LL | #![feature(macro_reexport)] | ^^^^^^^^^^^^^^ feature has been removed | + = note: removed in 1.0.0 (you are using $RUSTC_VERSION); see <https://github.com/rust-lang/rust/pull/49982> for more information = note: subsumed by `pub use` error: cannot find attribute `macro_reexport` in this scope - --> $DIR/macro-reexport-removed.rs:5:3 + --> $DIR/macro-reexport-removed.rs:6:3 | LL | #[macro_reexport(macro_one)] | ^^^^^^^^^^^^^^ help: a built-in attribute with a similar name exists: `macro_export` diff --git a/tests/ui/macros/missing-derive-1.rs b/tests/ui/macros/missing-derive-1.rs new file mode 100644 index 00000000000..e23ef7bf07b --- /dev/null +++ b/tests/ui/macros/missing-derive-1.rs @@ -0,0 +1,33 @@ +//@aux-build:serde.rs + +// derive macros imported and used + +extern crate serde; +use serde::{Serialize, Deserialize}; + +#[serde(untagged)] //~ ERROR cannot find attribute `serde` +enum A { //~ HELP `serde` is an attribute that can be used by the derive macros `Deserialize` and `Serialize` + A, + B, +} + +enum B { //~ HELP `serde` is an attribute that can be used by the derive macros `Deserialize` and `Serialize` + A, + #[serde(untagged)] //~ ERROR cannot find attribute `serde` + B, +} + +enum C { + A, + #[sede(untagged)] //~ ERROR cannot find attribute `sede` + B, //~^ HELP the derive macros `Deserialize` and `Serialize` accept the similarly named `serde` attribute +} + +#[derive(Serialize, Deserialize)] +#[serde(untagged)] +enum D { + A, + B, +} + +fn main() {} diff --git a/tests/ui/macros/missing-derive-1.stderr b/tests/ui/macros/missing-derive-1.stderr new file mode 100644 index 00000000000..15584100ffa --- /dev/null +++ b/tests/ui/macros/missing-derive-1.stderr @@ -0,0 +1,47 @@ +error: cannot find attribute `serde` in this scope + --> $DIR/missing-derive-1.rs:8:3 + | +LL | #[serde(untagged)] + | ^^^^^ + | +note: `serde` is imported here, but it is a crate, not an attribute + --> $DIR/missing-derive-1.rs:5:1 + | +LL | extern crate serde; + | ^^^^^^^^^^^^^^^^^^^ +help: `serde` is an attribute that can be used by the derive macros `Deserialize` and `Serialize`, you might be missing a `derive` attribute + | +LL + #[derive(Deserialize, Serialize)] +LL | enum A { + | + +error: cannot find attribute `serde` in this scope + --> $DIR/missing-derive-1.rs:16:7 + | +LL | #[serde(untagged)] + | ^^^^^ + | +note: `serde` is imported here, but it is a crate, not an attribute + --> $DIR/missing-derive-1.rs:5:1 + | +LL | extern crate serde; + | ^^^^^^^^^^^^^^^^^^^ +help: `serde` is an attribute that can be used by the derive macros `Deserialize` and `Serialize`, you might be missing a `derive` attribute + | +LL + #[derive(Deserialize, Serialize)] +LL | enum B { + | + +error: cannot find attribute `sede` in this scope + --> $DIR/missing-derive-1.rs:22:7 + | +LL | #[sede(untagged)] + | ^^^^ + | +help: the derive macros `Deserialize` and `Serialize` accept the similarly named `serde` attribute + | +LL | #[serde(untagged)] + | + + +error: aborting due to 3 previous errors + diff --git a/tests/ui/macros/missing-derive-2.rs b/tests/ui/macros/missing-derive-2.rs new file mode 100644 index 00000000000..027d465d8b3 --- /dev/null +++ b/tests/ui/macros/missing-derive-2.rs @@ -0,0 +1,26 @@ +//@aux-build:serde.rs + +// derive macros imported but unused + +extern crate serde; +use serde::{Serialize, Deserialize}; + +#[serde(untagged)] //~ ERROR cannot find attribute `serde` +enum A { //~ HELP `serde` is an attribute that can be used by the derive macros `Deserialize` and `Serialize` + A, + B, +} + +enum B { //~ HELP `serde` is an attribute that can be used by the derive macros `Deserialize` and `Serialize` + A, + #[serde(untagged)] //~ ERROR cannot find attribute `serde` + B, +} + +enum C { + A, + #[sede(untagged)] //~ ERROR cannot find attribute `sede` + B, //~^ HELP the derive macros `Deserialize` and `Serialize` accept the similarly named `serde` attribute +} + +fn main() {} diff --git a/tests/ui/macros/missing-derive-2.stderr b/tests/ui/macros/missing-derive-2.stderr new file mode 100644 index 00000000000..6c8e9e12019 --- /dev/null +++ b/tests/ui/macros/missing-derive-2.stderr @@ -0,0 +1,47 @@ +error: cannot find attribute `sede` in this scope + --> $DIR/missing-derive-2.rs:22:7 + | +LL | #[sede(untagged)] + | ^^^^ + | +help: the derive macros `Deserialize` and `Serialize` accept the similarly named `serde` attribute + | +LL | #[serde(untagged)] + | + + +error: cannot find attribute `serde` in this scope + --> $DIR/missing-derive-2.rs:16:7 + | +LL | #[serde(untagged)] + | ^^^^^ + | +note: `serde` is imported here, but it is a crate, not an attribute + --> $DIR/missing-derive-2.rs:5:1 + | +LL | extern crate serde; + | ^^^^^^^^^^^^^^^^^^^ +help: `serde` is an attribute that can be used by the derive macros `Deserialize` and `Serialize`, you might be missing a `derive` attribute + | +LL + #[derive(Deserialize, Serialize)] +LL | enum B { + | + +error: cannot find attribute `serde` in this scope + --> $DIR/missing-derive-2.rs:8:3 + | +LL | #[serde(untagged)] + | ^^^^^ + | +note: `serde` is imported here, but it is a crate, not an attribute + --> $DIR/missing-derive-2.rs:5:1 + | +LL | extern crate serde; + | ^^^^^^^^^^^^^^^^^^^ +help: `serde` is an attribute that can be used by the derive macros `Deserialize` and `Serialize`, you might be missing a `derive` attribute + | +LL + #[derive(Deserialize, Serialize)] +LL | enum A { + | + +error: aborting due to 3 previous errors + diff --git a/tests/ui/macros/missing-derive-3.rs b/tests/ui/macros/missing-derive-3.rs new file mode 100644 index 00000000000..8add8198890 --- /dev/null +++ b/tests/ui/macros/missing-derive-3.rs @@ -0,0 +1,24 @@ +//@aux-build:serde.rs + +// derive macros not imported, but namespace imported. Not yet handled. +extern crate serde; + +#[serde(untagged)] //~ ERROR cannot find attribute `serde` +enum A { + A, + B, +} + +enum B { + A, + #[serde(untagged)] //~ ERROR cannot find attribute `serde` + B, +} + +enum C { + A, + #[sede(untagged)] //~ ERROR cannot find attribute `sede` + B, +} + +fn main() {} diff --git a/tests/ui/macros/missing-derive-3.stderr b/tests/ui/macros/missing-derive-3.stderr new file mode 100644 index 00000000000..0a7ed8d0876 --- /dev/null +++ b/tests/ui/macros/missing-derive-3.stderr @@ -0,0 +1,32 @@ +error: cannot find attribute `sede` in this scope + --> $DIR/missing-derive-3.rs:20:7 + | +LL | #[sede(untagged)] + | ^^^^ + +error: cannot find attribute `serde` in this scope + --> $DIR/missing-derive-3.rs:14:7 + | +LL | #[serde(untagged)] + | ^^^^^ + | +note: `serde` is imported here, but it is a crate, not an attribute + --> $DIR/missing-derive-3.rs:4:1 + | +LL | extern crate serde; + | ^^^^^^^^^^^^^^^^^^^ + +error: cannot find attribute `serde` in this scope + --> $DIR/missing-derive-3.rs:6:3 + | +LL | #[serde(untagged)] + | ^^^^^ + | +note: `serde` is imported here, but it is a crate, not an attribute + --> $DIR/missing-derive-3.rs:4:1 + | +LL | extern crate serde; + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + diff --git a/tests/ui/ext-expand-inner-exprs.rs b/tests/ui/macros/nested-macro-expansion.rs index 94610d0a328..3b94b1051c9 100644 --- a/tests/ui/ext-expand-inner-exprs.rs +++ b/tests/ui/macros/nested-macro-expansion.rs @@ -1,3 +1,5 @@ +//! Test nested macro expansion with concat! macros + //@ run-pass static FOO : &'static str = concat!(concat!("hel", "lo"), "world"); diff --git a/tests/ui/impl-inherent-non-conflict.rs b/tests/ui/methods/inherent-methods-same-name.rs index 41ab865892a..d7d19bc3325 100644 --- a/tests/ui/impl-inherent-non-conflict.rs +++ b/tests/ui/methods/inherent-methods-same-name.rs @@ -1,17 +1,22 @@ +//! Test multiple inherent methods with same name on different type parameters + //@ run-pass // Ensure that a user-defined type admits multiple inherent methods // with the same name, which can be called on values that have a // precise enough type to allow distinguishing between the methods. - struct Foo<T>(T); impl Foo<usize> { - fn bar(&self) -> i32 { self.0 as i32 } + fn bar(&self) -> i32 { + self.0 as i32 + } } impl Foo<isize> { - fn bar(&self) -> i32 { -(self.0 as i32) } + fn bar(&self) -> i32 { + -(self.0 as i32) + } } fn main() { diff --git a/tests/ui/methods/missing-bound-on-tuple.rs b/tests/ui/methods/missing-bound-on-tuple.rs new file mode 100644 index 00000000000..25deabf5926 --- /dev/null +++ b/tests/ui/methods/missing-bound-on-tuple.rs @@ -0,0 +1,39 @@ +trait WorksOnDefault { + fn do_something() {} +} + +impl<T: Default> WorksOnDefault for T {} +//~^ NOTE the following trait bounds were not satisfied +//~| NOTE unsatisfied trait bound introduced here + +trait Foo {} + +trait WorksOnFoo { + fn do_be_do() {} +} + +impl<T: Foo> WorksOnFoo for T {} +//~^ NOTE the following trait bounds were not satisfied +//~| NOTE unsatisfied trait bound introduced here + +impl<A: Foo, B: Foo, C: Foo> Foo for (A, B, C) {} +//~^ NOTE `Foo` is implemented for `(i32, u32, String)` +impl Foo for i32 {} +impl Foo for &i32 {} +impl Foo for u32 {} +impl Foo for String {} + +fn main() { + let _success = <(i32, u32, String)>::do_something(); + let _failure = <(i32, &u32, String)>::do_something(); //~ ERROR E0599 + //~^ NOTE `Default` is implemented for `(i32, u32, String)` + //~| NOTE function or associated item cannot be called on + let _success = <(i32, u32, String)>::do_be_do(); + let _failure = <(i32, &u32, String)>::do_be_do(); //~ ERROR E0599 + //~^ NOTE function or associated item cannot be called on + let _success = <(i32, u32, String)>::default(); + let _failure = <(i32, &u32, String)>::default(); //~ ERROR E0599 + //~^ NOTE `Default` is implemented for `(i32, u32, String)` + //~| NOTE function or associated item cannot be called on + //~| NOTE the following trait bounds were not satisfied +} diff --git a/tests/ui/methods/missing-bound-on-tuple.stderr b/tests/ui/methods/missing-bound-on-tuple.stderr new file mode 100644 index 00000000000..f3e0897e5e6 --- /dev/null +++ b/tests/ui/methods/missing-bound-on-tuple.stderr @@ -0,0 +1,58 @@ +error[E0599]: the function or associated item `do_something` exists for tuple `(i32, &u32, String)`, but its trait bounds were not satisfied + --> $DIR/missing-bound-on-tuple.rs:28:43 + | +LL | let _failure = <(i32, &u32, String)>::do_something(); + | ^^^^^^^^^^^^ function or associated item cannot be called on `(i32, &u32, String)` due to unsatisfied trait bounds + | +note: the following trait bounds were not satisfied: + `&(i32, &u32, String): Default` + `&mut (i32, &u32, String): Default` + `(i32, &u32, String): Default` + --> $DIR/missing-bound-on-tuple.rs:5:9 + | +LL | impl<T: Default> WorksOnDefault for T {} + | ^^^^^^^ -------------- - + | | + | unsatisfied trait bound introduced here +note: `Default` is implemented for `(i32, u32, String)` but not for `(i32, &u32, String)` + --> $SRC_DIR/core/src/tuple.rs:LL:COL + = note: this error originates in the macro `tuple_impls` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0599]: the function or associated item `do_be_do` exists for tuple `(i32, &u32, String)`, but its trait bounds were not satisfied + --> $DIR/missing-bound-on-tuple.rs:32:43 + | +LL | let _failure = <(i32, &u32, String)>::do_be_do(); + | ^^^^^^^^ function or associated item cannot be called on `(i32, &u32, String)` due to unsatisfied trait bounds + | +note: the following trait bounds were not satisfied: + `&(i32, &u32, String): Foo` + `&mut (i32, &u32, String): Foo` + `(i32, &u32, String): Foo` + --> $DIR/missing-bound-on-tuple.rs:15:9 + | +LL | impl<T: Foo> WorksOnFoo for T {} + | ^^^ ---------- - + | | + | unsatisfied trait bound introduced here +note: `Foo` is implemented for `(i32, u32, String)` but not for `(i32, &u32, String)` + --> $DIR/missing-bound-on-tuple.rs:19:1 + | +LL | impl<A: Foo, B: Foo, C: Foo> Foo for (A, B, C) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0599]: the function or associated item `default` exists for tuple `(i32, &u32, String)`, but its trait bounds were not satisfied + --> $DIR/missing-bound-on-tuple.rs:35:43 + | +LL | let _failure = <(i32, &u32, String)>::default(); + | ^^^^^^^ function or associated item cannot be called on `(i32, &u32, String)` due to unsatisfied trait bounds + | + = note: the following trait bounds were not satisfied: + `&u32: Default` + which is required by `(i32, &u32, String): Default` +note: `Default` is implemented for `(i32, u32, String)` but not for `(i32, &u32, String)` + --> $SRC_DIR/core/src/tuple.rs:LL:COL + = note: this error originates in the macro `tuple_impls` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/mir/mir_refs_correct.rs b/tests/ui/mir/mir_refs_correct.rs index fc23c8c3631..f1832d90a0f 100644 --- a/tests/ui/mir/mir_refs_correct.rs +++ b/tests/ui/mir/mir_refs_correct.rs @@ -1,6 +1,8 @@ //@ run-pass //@ aux-build:mir_external_refs.rs +#![allow(unpredictable_function_pointer_comparisons)] + extern crate mir_external_refs as ext; struct S(#[allow(dead_code)] u8); diff --git a/tests/ui/impl-not-adjacent-to-type.rs b/tests/ui/modules/impl-cross-module.rs index ccf59ed4393..3ed8c18ff3c 100644 --- a/tests/ui/impl-not-adjacent-to-type.rs +++ b/tests/ui/modules/impl-cross-module.rs @@ -1,3 +1,5 @@ +//! Test implementing methods for types defined in other modules + //@ run-pass mod foo { diff --git a/tests/ui/nll/sugg-mut-for-binding-issue-137486.fixed b/tests/ui/nll/sugg-mut-for-binding-issue-137486.fixed new file mode 100644 index 00000000000..ee9d9a373de --- /dev/null +++ b/tests/ui/nll/sugg-mut-for-binding-issue-137486.fixed @@ -0,0 +1,23 @@ +//@ run-rustfix +#![allow(unused_assignments)] + +use std::pin::Pin; +fn main() { + let mut s = String::from("hello"); + let mut ref_s = &mut s; + + let mut binding = String::from("world"); + ref_s = &mut binding; //~ ERROR temporary value dropped while borrowed [E0716] + + print!("r1 = {}", ref_s); + + let mut val: u8 = 5; + let mut s = Pin::new(&mut val); + let mut ref_s = &mut s; + + let mut val2: u8 = 10; + let mut binding = Pin::new(&mut val2); + ref_s = &mut binding; //~ ERROR temporary value dropped while borrowed [E0716] + + print!("r1 = {}", ref_s); +} diff --git a/tests/ui/nll/sugg-mut-for-binding-issue-137486.rs b/tests/ui/nll/sugg-mut-for-binding-issue-137486.rs new file mode 100644 index 00000000000..8f7ea756107 --- /dev/null +++ b/tests/ui/nll/sugg-mut-for-binding-issue-137486.rs @@ -0,0 +1,21 @@ +//@ run-rustfix +#![allow(unused_assignments)] + +use std::pin::Pin; +fn main() { + let mut s = String::from("hello"); + let mut ref_s = &mut s; + + ref_s = &mut String::from("world"); //~ ERROR temporary value dropped while borrowed [E0716] + + print!("r1 = {}", ref_s); + + let mut val: u8 = 5; + let mut s = Pin::new(&mut val); + let mut ref_s = &mut s; + + let mut val2: u8 = 10; + ref_s = &mut Pin::new(&mut val2); //~ ERROR temporary value dropped while borrowed [E0716] + + print!("r1 = {}", ref_s); +} diff --git a/tests/ui/nll/sugg-mut-for-binding-issue-137486.stderr b/tests/ui/nll/sugg-mut-for-binding-issue-137486.stderr new file mode 100644 index 00000000000..8432725f60a --- /dev/null +++ b/tests/ui/nll/sugg-mut-for-binding-issue-137486.stderr @@ -0,0 +1,37 @@ +error[E0716]: temporary value dropped while borrowed + --> $DIR/sugg-mut-for-binding-issue-137486.rs:9:18 + | +LL | ref_s = &mut String::from("world"); + | ^^^^^^^^^^^^^^^^^^^^^- temporary value is freed at the end of this statement + | | + | creates a temporary value which is freed while still in use +LL | +LL | print!("r1 = {}", ref_s); + | ----- borrow later used here + | +help: consider using a `let` binding to create a longer lived value + | +LL ~ let mut binding = String::from("world"); +LL ~ ref_s = &mut binding; + | + +error[E0716]: temporary value dropped while borrowed + --> $DIR/sugg-mut-for-binding-issue-137486.rs:18:18 + | +LL | ref_s = &mut Pin::new(&mut val2); + | ^^^^^^^^^^^^^^^^^^^- temporary value is freed at the end of this statement + | | + | creates a temporary value which is freed while still in use +LL | +LL | print!("r1 = {}", ref_s); + | ----- borrow later used here + | +help: consider using a `let` binding to create a longer lived value + | +LL ~ let mut binding = Pin::new(&mut val2); +LL ~ ref_s = &mut binding; + | + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0716`. diff --git a/tests/ui/nullable-pointer-iotareduction.rs b/tests/ui/nullable-pointer-iotareduction.rs index fa837dab51b..1b73164c9fc 100644 --- a/tests/ui/nullable-pointer-iotareduction.rs +++ b/tests/ui/nullable-pointer-iotareduction.rs @@ -8,6 +8,8 @@ // trying to get assert failure messages that at least identify which case // failed. +#![allow(unpredictable_function_pointer_comparisons)] + enum E<T> { Thing(isize, T), #[allow(dead_code)] Nothing((), ((), ()), [i8; 0]) } impl<T> E<T> { fn is_none(&self) -> bool { diff --git a/tests/ui/object-lifetime/object-lifetime-default-from-box-error.stderr b/tests/ui/object-lifetime/object-lifetime-default-from-box-error.stderr index 15b36925c47..05eb611081a 100644 --- a/tests/ui/object-lifetime/object-lifetime-default-from-box-error.stderr +++ b/tests/ui/object-lifetime/object-lifetime-default-from-box-error.stderr @@ -21,11 +21,13 @@ LL | ss.r error[E0621]: explicit lifetime required in the type of `ss` --> $DIR/object-lifetime-default-from-box-error.rs:33:5 | -LL | fn store1<'b>(ss: &mut SomeStruct, b: Box<dyn SomeTrait+'b>) { - | --------------- help: add explicit lifetime `'b` to the type of `ss`: `&mut SomeStruct<'b>` -... LL | ss.r = b; | ^^^^ lifetime `'b` required + | +help: add explicit lifetime `'b` to the type of `ss` + | +LL | fn store1<'b>(ss: &mut SomeStruct<'b>, b: Box<dyn SomeTrait+'b>) { + | ++++ error: aborting due to 3 previous errors diff --git a/tests/ui/on-unimplemented/feature-gate-on-unimplemented.rs b/tests/ui/on-unimplemented/feature-gate-on-unimplemented.rs index 3cc50e3499a..436caab5d64 100644 --- a/tests/ui/on-unimplemented/feature-gate-on-unimplemented.rs +++ b/tests/ui/on-unimplemented/feature-gate-on-unimplemented.rs @@ -1,8 +1,9 @@ // Test that `#[rustc_on_unimplemented]` is gated by `rustc_attrs` feature gate. #[rustc_on_unimplemented = "test error `{Self}` with `{Bar}`"] -//~^ ERROR this is an internal attribute that will never be stable -trait Foo<Bar> -{} +//~^ ERROR use of an internal attribute [E0658] +//~| NOTE the `#[rustc_on_unimplemented]` attribute is an internal implementation detail that will never be stable +//~| NOTE see `#[diagnostic::on_unimplemented]` for the stable equivalent of this attribute +trait Foo<Bar> {} fn main() {} diff --git a/tests/ui/on-unimplemented/feature-gate-on-unimplemented.stderr b/tests/ui/on-unimplemented/feature-gate-on-unimplemented.stderr index 2733f7478f0..d1983088af8 100644 --- a/tests/ui/on-unimplemented/feature-gate-on-unimplemented.stderr +++ b/tests/ui/on-unimplemented/feature-gate-on-unimplemented.stderr @@ -1,11 +1,12 @@ -error[E0658]: this is an internal attribute that will never be stable +error[E0658]: use of an internal attribute --> $DIR/feature-gate-on-unimplemented.rs:3:1 | LL | #[rustc_on_unimplemented = "test error `{Self}` with `{Bar}`"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: the `#[rustc_on_unimplemented]` attribute is an internal implementation detail that will never be stable + = note: see `#[diagnostic::on_unimplemented]` for the stable equivalent of this attribute error: aborting due to 1 previous error diff --git a/tests/ui/parser/block-no-opening-brace.rs b/tests/ui/parser/block-no-opening-brace.rs index b08c830bfc7..ea5a98ff6fc 100644 --- a/tests/ui/parser/block-no-opening-brace.rs +++ b/tests/ui/parser/block-no-opening-brace.rs @@ -27,10 +27,10 @@ fn in_try() { let x = 0; } -// FIXME(#80931) fn in_async() { async - let x = 0; //~ ERROR expected one of `move`, `use`, `|`, or `||`, found keyword `let` + let x = 0; + //~^ ERROR expected one of `move`, `use`, `{`, `|`, or `||`, found keyword `let` } // FIXME(#78168) diff --git a/tests/ui/parser/block-no-opening-brace.stderr b/tests/ui/parser/block-no-opening-brace.stderr index f51ee92626f..cf9eeba573d 100644 --- a/tests/ui/parser/block-no-opening-brace.stderr +++ b/tests/ui/parser/block-no-opening-brace.stderr @@ -43,11 +43,11 @@ error: expected expression, found reserved keyword `try` LL | try | ^^^ expected expression -error: expected one of `move`, `use`, `|`, or `||`, found keyword `let` - --> $DIR/block-no-opening-brace.rs:33:9 +error: expected one of `move`, `use`, `{`, `|`, or `||`, found keyword `let` + --> $DIR/block-no-opening-brace.rs:32:9 | LL | async - | - expected one of `move`, `use`, `|`, or `||` + | - expected one of `move`, `use`, `{`, `|`, or `||` LL | let x = 0; | ^^^ unexpected token diff --git a/tests/ui/parser/macro/issue-33569.rs b/tests/ui/parser/macro/issue-33569.rs index 069d181e962..e0a5352ab06 100644 --- a/tests/ui/parser/macro/issue-33569.rs +++ b/tests/ui/parser/macro/issue-33569.rs @@ -2,7 +2,6 @@ macro_rules! foo { { $+ } => { //~ ERROR expected identifier, found `+` //~^ ERROR missing fragment specifier //~| ERROR missing fragment specifier - //~| WARN this was previously accepted $(x)(y) //~ ERROR expected one of: `*`, `+`, or `?` } } diff --git a/tests/ui/parser/macro/issue-33569.stderr b/tests/ui/parser/macro/issue-33569.stderr index d1b6abfeeeb..0d53c04c1c9 100644 --- a/tests/ui/parser/macro/issue-33569.stderr +++ b/tests/ui/parser/macro/issue-33569.stderr @@ -5,7 +5,7 @@ LL | { $+ } => { | ^ error: expected one of: `*`, `+`, or `?` - --> $DIR/issue-33569.rs:6:13 + --> $DIR/issue-33569.rs:5:13 | LL | $(x)(y) | ^^^ @@ -15,27 +15,19 @@ error: missing fragment specifier | LL | { $+ } => { | ^ - -error: missing fragment specifier - --> $DIR/issue-33569.rs:2:8 | -LL | { $+ } => { - | ^ + = note: fragment specifiers must be provided + = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`, along with `expr_2021` and `pat_param` for edition compatibility +help: try adding a specifier here | - = 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 #40107 <https://github.com/rust-lang/rust/issues/40107> - = note: `#[deny(missing_fragment_specifier)]` on by default +LL | { $+:spec } => { + | +++++ -error: aborting due to 4 previous errors - -Future incompatibility report: Future breakage diagnostic: error: missing fragment specifier --> $DIR/issue-33569.rs:2:8 | LL | { $+ } => { | ^ - | - = 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 #40107 <https://github.com/rust-lang/rust/issues/40107> - = note: `#[deny(missing_fragment_specifier)]` on by default + +error: aborting due to 4 previous errors diff --git a/tests/ui/parser/misspelled-keywords/async-move.stderr b/tests/ui/parser/misspelled-keywords/async-move.stderr index 2507326fb28..26449a17f78 100644 --- a/tests/ui/parser/misspelled-keywords/async-move.stderr +++ b/tests/ui/parser/misspelled-keywords/async-move.stderr @@ -1,8 +1,8 @@ -error: expected one of `move`, `use`, `|`, or `||`, found `Move` +error: expected one of `move`, `use`, `{`, `|`, or `||`, found `Move` --> $DIR/async-move.rs:4:11 | LL | async Move {} - | ^^^^ expected one of `move`, `use`, `|`, or `||` + | ^^^^ expected one of `move`, `use`, `{`, `|`, or `||` | help: write keyword `move` in lowercase | diff --git a/tests/ui/print-calling-conventions.stdout b/tests/ui/print-calling-conventions.stdout index feee8cc3aa9..7b5ae495660 100644 --- a/tests/ui/print-calling-conventions.stdout +++ b/tests/ui/print-calling-conventions.stdout @@ -9,6 +9,7 @@ avr-interrupt avr-non-blocking-interrupt cdecl cdecl-unwind +custom efiapi fastcall fastcall-unwind diff --git a/tests/ui/proc-macro/derive-helper-legacy-limits.stderr b/tests/ui/proc-macro/derive-helper-legacy-limits.stderr index f5cd455435d..df3c5c47ddb 100644 --- a/tests/ui/proc-macro/derive-helper-legacy-limits.stderr +++ b/tests/ui/proc-macro/derive-helper-legacy-limits.stderr @@ -3,6 +3,12 @@ error: cannot find attribute `empty_helper` in this scope | LL | #[empty_helper] | ^^^^^^^^^^^^ + | +help: `empty_helper` is an attribute that can be used by the derive macro `Empty`, you might be missing a `derive` attribute + | +LL + #[derive(Empty)] +LL | struct S2; + | error: aborting due to 1 previous error diff --git a/tests/ui/proc-macro/derive-helper-shadowing.stderr b/tests/ui/proc-macro/derive-helper-shadowing.stderr index f284b1c54dd..1206778bb23 100644 --- a/tests/ui/proc-macro/derive-helper-shadowing.stderr +++ b/tests/ui/proc-macro/derive-helper-shadowing.stderr @@ -16,6 +16,7 @@ error: cannot find attribute `empty_helper` in this scope LL | #[derive(GenHelperUse)] | ^^^^^^^^^^^^ | + = note: `empty_helper` is an attribute that can be used by the derive macro `Empty`, you might be missing a `derive` attribute = note: this error originates in the derive macro `GenHelperUse` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider importing this attribute macro through its public re-export | @@ -31,6 +32,7 @@ LL | #[empty_helper] LL | gen_helper_use!(); | ----------------- in this macro invocation | + = note: `empty_helper` is an attribute that can be used by the derive macro `Empty`, you might be missing a `derive` attribute = note: this error originates in the macro `gen_helper_use` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider importing this attribute macro through its public re-export | diff --git a/tests/ui/proc-macro/disappearing-resolution.stderr b/tests/ui/proc-macro/disappearing-resolution.stderr index 734e0cd2ab6..6c0f1a52915 100644 --- a/tests/ui/proc-macro/disappearing-resolution.stderr +++ b/tests/ui/proc-macro/disappearing-resolution.stderr @@ -3,6 +3,12 @@ error: cannot find attribute `empty_helper` in this scope | LL | #[empty_helper] | ^^^^^^^^^^^^ + | +help: `empty_helper` is an attribute that can be used by the derive macro `Empty`, you might be missing a `derive` attribute + | +LL + #[derive(Empty)] +LL | struct S; + | error[E0603]: derive macro import `Empty` is private --> $DIR/disappearing-resolution.rs:11:8 diff --git a/tests/ui/regions/regions-glb-free-free.stderr b/tests/ui/regions/regions-glb-free-free.stderr index 727669f2683..6ea09e3e1d7 100644 --- a/tests/ui/regions/regions-glb-free-free.stderr +++ b/tests/ui/regions/regions-glb-free-free.stderr @@ -1,8 +1,6 @@ error[E0621]: explicit lifetime required in the type of `s` --> $DIR/regions-glb-free-free.rs:15:13 | -LL | pub fn set_desc(self, s: &str) -> Flag<'a> { - | ---- help: add explicit lifetime `'a` to the type of `s`: `&'a str` LL | / Flag { LL | | name: self.name, LL | | desc: s, @@ -10,6 +8,11 @@ LL | | max_count: self.max_count, LL | | value: self.value LL | | } | |_____________^ lifetime `'a` required + | +help: add explicit lifetime `'a` to the type of `s` + | +LL | pub fn set_desc(self, s: &'a str) -> Flag<'a> { + | ++ error: aborting due to 1 previous error diff --git a/tests/ui/regions/regions-infer-at-fn-not-param.stderr b/tests/ui/regions/regions-infer-at-fn-not-param.stderr index 4c7660276f2..58ff2586a82 100644 --- a/tests/ui/regions/regions-infer-at-fn-not-param.stderr +++ b/tests/ui/regions/regions-infer-at-fn-not-param.stderr @@ -2,9 +2,12 @@ error[E0621]: explicit lifetime required in the type of `p` --> $DIR/regions-infer-at-fn-not-param.rs:13:57 | LL | fn take1<'a>(p: Parameterized1) -> Parameterized1<'a> { p } - | -------------- ^ lifetime `'a` required - | | - | help: add explicit lifetime `'a` to the type of `p`: `Parameterized1<'a>` + | ^ lifetime `'a` required + | +help: add explicit lifetime `'a` to the type of `p` + | +LL | fn take1<'a>(p: Parameterized1<'a>) -> Parameterized1<'a> { p } + | ++++ error: aborting due to 1 previous error diff --git a/tests/ui/resolve/auxiliary/issue-80079.rs b/tests/ui/resolve/auxiliary/issue-80079.rs index 190ca75aba8..bfae5c5a24e 100644 --- a/tests/ui/resolve/auxiliary/issue-80079.rs +++ b/tests/ui/resolve/auxiliary/issue-80079.rs @@ -1,7 +1,7 @@ #![crate_type = "lib"] pub mod public { - use private_import; + use crate::private_import; // should not be suggested since it is private struct Foo; diff --git a/tests/ui/resolve/auxiliary/privacy-struct-ctor.rs b/tests/ui/resolve/auxiliary/privacy-struct-ctor.rs index 6d0bc728524..ac157a82e17 100644 --- a/tests/ui/resolve/auxiliary/privacy-struct-ctor.rs +++ b/tests/ui/resolve/auxiliary/privacy-struct-ctor.rs @@ -2,7 +2,7 @@ pub mod m { pub struct S(u8); pub mod n { - pub(in m) struct Z(pub(in m::n) u8); + pub(in crate::m) struct Z(pub(in crate::m::n) u8); } } diff --git a/tests/ui/resolve/extern-prelude-fail.rs b/tests/ui/resolve/extern-prelude-fail.rs index c0716f1ebf5..7d0df03e57b 100644 --- a/tests/ui/resolve/extern-prelude-fail.rs +++ b/tests/ui/resolve/extern-prelude-fail.rs @@ -1,3 +1,4 @@ +//@ edition: 2015 //@ compile-flags:--extern extern_prelude //@ aux-build:extern-prelude.rs diff --git a/tests/ui/resolve/extern-prelude-fail.stderr b/tests/ui/resolve/extern-prelude-fail.stderr index 199a31244c0..b9668154f44 100644 --- a/tests/ui/resolve/extern-prelude-fail.stderr +++ b/tests/ui/resolve/extern-prelude-fail.stderr @@ -1,5 +1,5 @@ error[E0432]: unresolved import `extern_prelude` - --> $DIR/extern-prelude-fail.rs:7:9 + --> $DIR/extern-prelude-fail.rs:8:9 | LL | use extern_prelude::S; | ^^^^^^^^^^^^^^ use of unresolved module or unlinked crate `extern_prelude` @@ -10,7 +10,7 @@ LL + extern crate extern_prelude; | error[E0433]: failed to resolve: use of unresolved module or unlinked crate `extern_prelude` - --> $DIR/extern-prelude-fail.rs:8:15 + --> $DIR/extern-prelude-fail.rs:9:15 | LL | let s = ::extern_prelude::S; | ^^^^^^^^^^^^^^ use of unresolved module or unlinked crate `extern_prelude` diff --git a/tests/ui/resolve/global-scope-resolution.rs b/tests/ui/resolve/global-scope-resolution.rs new file mode 100644 index 00000000000..176bab36da7 --- /dev/null +++ b/tests/ui/resolve/global-scope-resolution.rs @@ -0,0 +1,21 @@ +//! Test global scope resolution with :: operator + +//@ run-pass + +pub fn f() -> isize { + return 1; +} + +pub mod foo { + pub fn f() -> isize { + return 2; + } + pub fn g() { + assert_eq!(f(), 2); + assert_eq!(::f(), 1); + } +} + +pub fn main() { + return foo::g(); +} diff --git a/tests/ui/resolve/issue-42944.rs b/tests/ui/resolve/issue-42944.rs index 7e439c10b7b..24aa110329b 100644 --- a/tests/ui/resolve/issue-42944.rs +++ b/tests/ui/resolve/issue-42944.rs @@ -3,7 +3,7 @@ mod foo { } mod bar { - use foo::Bx; + use crate::foo::Bx; fn foo() { Bx(()); diff --git a/tests/ui/resolve/issue-5035.rs b/tests/ui/resolve/issue-5035.rs index 82c4bc0d5ef..a9e2509dde9 100644 --- a/tests/ui/resolve/issue-5035.rs +++ b/tests/ui/resolve/issue-5035.rs @@ -4,7 +4,7 @@ trait I {} type K = dyn I; impl K for isize {} //~ ERROR expected trait, found type alias `K` -use ImportError; //~ ERROR unresolved import `ImportError` [E0432] +use crate::ImportError; //~ ERROR unresolved import `crate::ImportError` [E0432] //~^ NOTE no `ImportError` in the root impl ImportError for () {} // check that this is not an additional error (cf. issue #35142) diff --git a/tests/ui/resolve/issue-5035.stderr b/tests/ui/resolve/issue-5035.stderr index f5717438fc8..b26c962c9bb 100644 --- a/tests/ui/resolve/issue-5035.stderr +++ b/tests/ui/resolve/issue-5035.stderr @@ -1,8 +1,8 @@ -error[E0432]: unresolved import `ImportError` +error[E0432]: unresolved import `crate::ImportError` --> $DIR/issue-5035.rs:7:5 | -LL | use ImportError; - | ^^^^^^^^^^^ no `ImportError` in the root +LL | use crate::ImportError; + | ^^^^^^^^^^^^^^^^^^ no `ImportError` in the root error[E0404]: expected trait, found type alias `K` --> $DIR/issue-5035.rs:5:6 diff --git a/tests/ui/resolve/nonexistent-macro.rs b/tests/ui/resolve/nonexistent-macro.rs new file mode 100644 index 00000000000..663075473a1 --- /dev/null +++ b/tests/ui/resolve/nonexistent-macro.rs @@ -0,0 +1,6 @@ +//! Test error handling for undefined macro calls + +fn main() { + iamnotanextensionthatexists!(""); + //~^ ERROR cannot find macro `iamnotanextensionthatexists` in this scope +} diff --git a/tests/ui/resolve/nonexistent-macro.stderr b/tests/ui/resolve/nonexistent-macro.stderr new file mode 100644 index 00000000000..7e89e07bf30 --- /dev/null +++ b/tests/ui/resolve/nonexistent-macro.stderr @@ -0,0 +1,8 @@ +error: cannot find macro `iamnotanextensionthatexists` in this scope + --> $DIR/nonexistent-macro.rs:4:5 + | +LL | iamnotanextensionthatexists!(""); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/resolve/privacy-enum-ctor.rs b/tests/ui/resolve/privacy-enum-ctor.rs index f0d2cf8c04e..3f79b12a267 100644 --- a/tests/ui/resolve/privacy-enum-ctor.rs +++ b/tests/ui/resolve/privacy-enum-ctor.rs @@ -8,7 +8,7 @@ mod m { } pub mod n { - pub(in m) enum Z { + pub(in crate::m) enum Z { Fn(u8), Struct { s: u8, @@ -17,7 +17,7 @@ mod m { } } - use m::n::Z; // OK, only the type is imported + use crate::m::n::Z; // OK, only the type is imported fn f() { n::Z; diff --git a/tests/ui/resolve/privacy-enum-ctor.stderr b/tests/ui/resolve/privacy-enum-ctor.stderr index f349b9391d1..4ec1b6b97bd 100644 --- a/tests/ui/resolve/privacy-enum-ctor.stderr +++ b/tests/ui/resolve/privacy-enum-ctor.stderr @@ -7,7 +7,7 @@ LL | n::Z; note: the enum is defined here --> $DIR/privacy-enum-ctor.rs:11:9 | -LL | / pub(in m) enum Z { +LL | / pub(in crate::m) enum Z { LL | | Fn(u8), LL | | Struct { LL | | s: u8, @@ -35,7 +35,7 @@ LL | Z; note: the enum is defined here --> $DIR/privacy-enum-ctor.rs:11:9 | -LL | / pub(in m) enum Z { +LL | / pub(in crate::m) enum Z { LL | | Fn(u8), LL | | Struct { LL | | s: u8, @@ -154,8 +154,8 @@ LL | let _: Z = m::n::Z; note: enum `m::Z` exists but is inaccessible --> $DIR/privacy-enum-ctor.rs:11:9 | -LL | pub(in m) enum Z { - | ^^^^^^^^^^^^^^^^ not accessible +LL | pub(in crate::m) enum Z { + | ^^^^^^^^^^^^^^^^^^^^^^^ not accessible error[E0423]: expected value, found enum `m::n::Z` --> $DIR/privacy-enum-ctor.rs:57:16 @@ -166,7 +166,7 @@ LL | let _: Z = m::n::Z; note: the enum is defined here --> $DIR/privacy-enum-ctor.rs:11:9 | -LL | / pub(in m) enum Z { +LL | / pub(in crate::m) enum Z { LL | | Fn(u8), LL | | Struct { LL | | s: u8, @@ -197,8 +197,8 @@ LL | let _: Z = m::n::Z::Fn; note: enum `m::Z` exists but is inaccessible --> $DIR/privacy-enum-ctor.rs:11:9 | -LL | pub(in m) enum Z { - | ^^^^^^^^^^^^^^^^ not accessible +LL | pub(in crate::m) enum Z { + | ^^^^^^^^^^^^^^^^^^^^^^^ not accessible error[E0412]: cannot find type `Z` in this scope --> $DIR/privacy-enum-ctor.rs:64:12 @@ -212,8 +212,8 @@ LL | let _: Z = m::n::Z::Struct; note: enum `m::Z` exists but is inaccessible --> $DIR/privacy-enum-ctor.rs:11:9 | -LL | pub(in m) enum Z { - | ^^^^^^^^^^^^^^^^ not accessible +LL | pub(in crate::m) enum Z { + | ^^^^^^^^^^^^^^^^^^^^^^^ not accessible error[E0412]: cannot find type `Z` in this scope --> $DIR/privacy-enum-ctor.rs:68:12 @@ -227,8 +227,8 @@ LL | let _: Z = m::n::Z::Unit {}; note: enum `m::Z` exists but is inaccessible --> $DIR/privacy-enum-ctor.rs:11:9 | -LL | pub(in m) enum Z { - | ^^^^^^^^^^^^^^^^ not accessible +LL | pub(in crate::m) enum Z { + | ^^^^^^^^^^^^^^^^^^^^^^^ not accessible error[E0603]: enum `Z` is private --> $DIR/privacy-enum-ctor.rs:57:22 @@ -239,8 +239,8 @@ LL | let _: Z = m::n::Z; note: the enum `Z` is defined here --> $DIR/privacy-enum-ctor.rs:11:9 | -LL | pub(in m) enum Z { - | ^^^^^^^^^^^^^^^^ +LL | pub(in crate::m) enum Z { + | ^^^^^^^^^^^^^^^^^^^^^^^ error[E0603]: enum `Z` is private --> $DIR/privacy-enum-ctor.rs:61:22 @@ -253,8 +253,8 @@ LL | let _: Z = m::n::Z::Fn; note: the enum `Z` is defined here --> $DIR/privacy-enum-ctor.rs:11:9 | -LL | pub(in m) enum Z { - | ^^^^^^^^^^^^^^^^ +LL | pub(in crate::m) enum Z { + | ^^^^^^^^^^^^^^^^^^^^^^^ error[E0603]: enum `Z` is private --> $DIR/privacy-enum-ctor.rs:64:22 @@ -265,8 +265,8 @@ LL | let _: Z = m::n::Z::Struct; note: the enum `Z` is defined here --> $DIR/privacy-enum-ctor.rs:11:9 | -LL | pub(in m) enum Z { - | ^^^^^^^^^^^^^^^^ +LL | pub(in crate::m) enum Z { + | ^^^^^^^^^^^^^^^^^^^^^^^ error[E0603]: enum `Z` is private --> $DIR/privacy-enum-ctor.rs:68:22 @@ -279,8 +279,8 @@ LL | let _: Z = m::n::Z::Unit {}; note: the enum `Z` is defined here --> $DIR/privacy-enum-ctor.rs:11:9 | -LL | pub(in m) enum Z { - | ^^^^^^^^^^^^^^^^ +LL | pub(in crate::m) enum Z { + | ^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types --> $DIR/privacy-enum-ctor.rs:27:20 diff --git a/tests/ui/resolve/privacy-struct-ctor.rs b/tests/ui/resolve/privacy-struct-ctor.rs index da0e9f2fc04..70c751999b7 100644 --- a/tests/ui/resolve/privacy-struct-ctor.rs +++ b/tests/ui/resolve/privacy-struct-ctor.rs @@ -9,10 +9,10 @@ mod m { } pub mod n { - pub(in m) struct Z(pub(in m::n) u8); + pub(in crate::m) struct Z(pub(in crate::m::n) u8); } - use m::n::Z; // OK, only the type is imported + use crate::m::n::Z; // OK, only the type is imported fn f() { n::Z; diff --git a/tests/ui/resolve/privacy-struct-ctor.stderr b/tests/ui/resolve/privacy-struct-ctor.stderr index 1d8c741c964..0a6b1b46afa 100644 --- a/tests/ui/resolve/privacy-struct-ctor.stderr +++ b/tests/ui/resolve/privacy-struct-ctor.stderr @@ -42,8 +42,8 @@ LL | pub struct S(u8); error[E0603]: tuple struct constructor `Z` is private --> $DIR/privacy-struct-ctor.rs:18:12 | -LL | pub(in m) struct Z(pub(in m::n) u8); - | --------------- a constructor is private if any of the fields is private +LL | pub(in crate::m) struct Z(pub(in crate::m::n) u8); + | ---------------------- a constructor is private if any of the fields is private ... LL | n::Z; | ^ private tuple struct constructor @@ -51,12 +51,12 @@ LL | n::Z; note: the tuple struct constructor `Z` is defined here --> $DIR/privacy-struct-ctor.rs:12:9 | -LL | pub(in m) struct Z(pub(in m::n) u8); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | pub(in crate::m) struct Z(pub(in crate::m::n) u8); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider making the field publicly accessible | -LL - pub(in m) struct Z(pub(in m::n) u8); -LL + pub(in m) struct Z(pub u8); +LL - pub(in crate::m) struct Z(pub(in crate::m::n) u8); +LL + pub(in crate::m) struct Z(pub u8); | error[E0603]: tuple struct constructor `S` is private @@ -100,8 +100,8 @@ LL | pub struct S(pub u8); error[E0603]: tuple struct constructor `Z` is private --> $DIR/privacy-struct-ctor.rs:35:11 | -LL | pub(in m) struct Z(pub(in m::n) u8); - | --------------- a constructor is private if any of the fields is private +LL | pub(in crate::m) struct Z(pub(in crate::m::n) u8); + | ---------------------- a constructor is private if any of the fields is private ... LL | m::n::Z; | ^ private tuple struct constructor @@ -109,12 +109,12 @@ LL | m::n::Z; note: the tuple struct constructor `Z` is defined here --> $DIR/privacy-struct-ctor.rs:12:9 | -LL | pub(in m) struct Z(pub(in m::n) u8); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | pub(in crate::m) struct Z(pub(in crate::m::n) u8); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider making the field publicly accessible | -LL - pub(in m) struct Z(pub(in m::n) u8); -LL + pub(in m) struct Z(pub u8); +LL - pub(in crate::m) struct Z(pub(in crate::m::n) u8); +LL + pub(in crate::m) struct Z(pub u8); | error[E0603]: tuple struct constructor `S` is private @@ -140,16 +140,16 @@ error[E0603]: tuple struct constructor `Z` is private LL | xcrate::m::n::Z; | ^ private tuple struct constructor | - ::: $DIR/auxiliary/privacy-struct-ctor.rs:5:28 + ::: $DIR/auxiliary/privacy-struct-ctor.rs:5:35 | -LL | pub(in m) struct Z(pub(in m::n) u8); - | --------------- a constructor is private if any of the fields is private +LL | pub(in crate::m) struct Z(pub(in crate::m::n) u8); + | ---------------------- a constructor is private if any of the fields is private | note: the tuple struct constructor `Z` is defined here --> $DIR/auxiliary/privacy-struct-ctor.rs:5:9 | -LL | pub(in m) struct Z(pub(in m::n) u8); - | ^^^^^^^^^^^^^^^^^^ +LL | pub(in crate::m) struct Z(pub(in crate::m::n) u8); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 10 previous errors diff --git a/tests/ui/resolve/resolve-bad-visibility.rs b/tests/ui/resolve/resolve-bad-visibility.rs index 7d48bb97b10..81635611fca 100644 --- a/tests/ui/resolve/resolve-bad-visibility.rs +++ b/tests/ui/resolve/resolve-bad-visibility.rs @@ -1,3 +1,4 @@ +//@ edition: 2015 enum E {} trait Tr {} diff --git a/tests/ui/resolve/resolve-bad-visibility.stderr b/tests/ui/resolve/resolve-bad-visibility.stderr index ac7e1c735b1..c7bbdfbd249 100644 --- a/tests/ui/resolve/resolve-bad-visibility.stderr +++ b/tests/ui/resolve/resolve-bad-visibility.stderr @@ -1,23 +1,23 @@ error[E0577]: expected module, found enum `E` - --> $DIR/resolve-bad-visibility.rs:4:8 + --> $DIR/resolve-bad-visibility.rs:5:8 | LL | pub(in E) struct S; | ^ not a module error[E0577]: expected module, found trait `Tr` - --> $DIR/resolve-bad-visibility.rs:5:8 + --> $DIR/resolve-bad-visibility.rs:6:8 | LL | pub(in Tr) struct Z; | ^^ not a module error[E0742]: visibilities can only be restricted to ancestor modules - --> $DIR/resolve-bad-visibility.rs:6:8 + --> $DIR/resolve-bad-visibility.rs:7:8 | LL | pub(in std::vec) struct F; | ^^^^^^^^ error[E0433]: failed to resolve: use of unresolved module or unlinked crate `nonexistent` - --> $DIR/resolve-bad-visibility.rs:7:8 + --> $DIR/resolve-bad-visibility.rs:8:8 | LL | pub(in nonexistent) struct G; | ^^^^^^^^^^^ use of unresolved module or unlinked crate `nonexistent` @@ -28,7 +28,7 @@ LL + extern crate nonexistent; | error[E0433]: failed to resolve: use of unresolved module or unlinked crate `too_soon` - --> $DIR/resolve-bad-visibility.rs:8:8 + --> $DIR/resolve-bad-visibility.rs:9:8 | LL | pub(in too_soon) struct H; | ^^^^^^^^ use of unresolved module or unlinked crate `too_soon` diff --git a/tests/ui/resolve/suggest-builder-fn.rs b/tests/ui/resolve/suggest-builder-fn.rs index 0d9b35549a4..959675ef2c9 100644 --- a/tests/ui/resolve/suggest-builder-fn.rs +++ b/tests/ui/resolve/suggest-builder-fn.rs @@ -32,7 +32,7 @@ impl Bar { } mod SomeMod { - use Bar; + use crate::Bar; impl Bar { // Public method. Should be suggested diff --git a/tests/ui/resolve/unresolved-segments-visibility.rs b/tests/ui/resolve/unresolved-segments-visibility.rs index c26171f75d2..fc86b31adfc 100644 --- a/tests/ui/resolve/unresolved-segments-visibility.rs +++ b/tests/ui/resolve/unresolved-segments-visibility.rs @@ -5,7 +5,7 @@ extern crate alloc as b; mod foo { mod bar { - pub(in b::string::String::newy) extern crate alloc as e; + pub(in crate::b::string::String::newy) extern crate alloc as e; //~^ ERROR failed to resolve: `String` is a struct, not a module [E0433] } } diff --git a/tests/ui/resolve/unresolved-segments-visibility.stderr b/tests/ui/resolve/unresolved-segments-visibility.stderr index 09f3c50258d..082579c9fa1 100644 --- a/tests/ui/resolve/unresolved-segments-visibility.stderr +++ b/tests/ui/resolve/unresolved-segments-visibility.stderr @@ -1,8 +1,8 @@ error[E0433]: failed to resolve: `String` is a struct, not a module - --> $DIR/unresolved-segments-visibility.rs:8:27 + --> $DIR/unresolved-segments-visibility.rs:8:34 | -LL | pub(in b::string::String::newy) extern crate alloc as e; - | ^^^^^^ `String` is a struct, not a module +LL | pub(in crate::b::string::String::newy) extern crate alloc as e; + | ^^^^^^ `String` is a struct, not a module error: aborting due to 1 previous error diff --git a/tests/ui/rust-2018/edition-lint-fully-qualified-paths.fixed b/tests/ui/rust-2018/edition-lint-fully-qualified-paths.fixed index fbe415e2e10..d685c4944ba 100644 --- a/tests/ui/rust-2018/edition-lint-fully-qualified-paths.fixed +++ b/tests/ui/rust-2018/edition-lint-fully-qualified-paths.fixed @@ -1,3 +1,4 @@ +//@ edition: 2015 //@ run-rustfix #![deny(absolute_paths_not_starting_with_crate)] diff --git a/tests/ui/rust-2018/edition-lint-fully-qualified-paths.rs b/tests/ui/rust-2018/edition-lint-fully-qualified-paths.rs index 72a212453cd..7a5ecf2720a 100644 --- a/tests/ui/rust-2018/edition-lint-fully-qualified-paths.rs +++ b/tests/ui/rust-2018/edition-lint-fully-qualified-paths.rs @@ -1,3 +1,4 @@ +//@ edition: 2015 //@ run-rustfix #![deny(absolute_paths_not_starting_with_crate)] diff --git a/tests/ui/rust-2018/edition-lint-fully-qualified-paths.stderr b/tests/ui/rust-2018/edition-lint-fully-qualified-paths.stderr index 036b9ccab4f..c0a322edcd6 100644 --- a/tests/ui/rust-2018/edition-lint-fully-qualified-paths.stderr +++ b/tests/ui/rust-2018/edition-lint-fully-qualified-paths.stderr @@ -1,5 +1,5 @@ error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition - --> $DIR/edition-lint-fully-qualified-paths.rs:18:25 + --> $DIR/edition-lint-fully-qualified-paths.rs:19:25 | LL | let _: <foo::Baz as ::foo::Foo>::Bar = (); | ^^^^^^^^^^ help: use `crate`: `crate::foo::Foo` @@ -7,13 +7,13 @@ LL | let _: <foo::Baz as ::foo::Foo>::Bar = (); = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130> note: the lint level is defined here - --> $DIR/edition-lint-fully-qualified-paths.rs:3:9 + --> $DIR/edition-lint-fully-qualified-paths.rs:4:9 | LL | #![deny(absolute_paths_not_starting_with_crate)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition - --> $DIR/edition-lint-fully-qualified-paths.rs:18:25 + --> $DIR/edition-lint-fully-qualified-paths.rs:19:25 | LL | let _: <foo::Baz as ::foo::Foo>::Bar = (); | ^^^^^^^^^^ help: use `crate`: `crate::foo::Foo` @@ -23,7 +23,7 @@ LL | let _: <foo::Baz as ::foo::Foo>::Bar = (); = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition - --> $DIR/edition-lint-fully-qualified-paths.rs:24:13 + --> $DIR/edition-lint-fully-qualified-paths.rs:25:13 | LL | let _: <::foo::Baz as foo::Foo>::Bar = (); | ^^^^^^^^^^ help: use `crate`: `crate::foo::Baz` diff --git a/tests/ui/rust-2018/edition-lint-nested-empty-paths.fixed b/tests/ui/rust-2018/edition-lint-nested-empty-paths.fixed index 7ec421099c7..4a584a55e64 100644 --- a/tests/ui/rust-2018/edition-lint-nested-empty-paths.fixed +++ b/tests/ui/rust-2018/edition-lint-nested-empty-paths.fixed @@ -1,3 +1,4 @@ +//@ edition: 2015 //@ run-rustfix #![deny(absolute_paths_not_starting_with_crate)] diff --git a/tests/ui/rust-2018/edition-lint-nested-empty-paths.rs b/tests/ui/rust-2018/edition-lint-nested-empty-paths.rs index 135908c8aef..2baafbd9704 100644 --- a/tests/ui/rust-2018/edition-lint-nested-empty-paths.rs +++ b/tests/ui/rust-2018/edition-lint-nested-empty-paths.rs @@ -1,3 +1,4 @@ +//@ edition: 2015 //@ run-rustfix #![deny(absolute_paths_not_starting_with_crate)] diff --git a/tests/ui/rust-2018/edition-lint-nested-empty-paths.stderr b/tests/ui/rust-2018/edition-lint-nested-empty-paths.stderr index 4174c2fa9ad..041572be844 100644 --- a/tests/ui/rust-2018/edition-lint-nested-empty-paths.stderr +++ b/tests/ui/rust-2018/edition-lint-nested-empty-paths.stderr @@ -1,5 +1,5 @@ error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition - --> $DIR/edition-lint-nested-empty-paths.rs:16:5 + --> $DIR/edition-lint-nested-empty-paths.rs:17:5 | LL | use foo::{bar::{baz::{}}}; | ^^^^^^^^^^^^^^^^^^^^^ help: use `crate`: `crate::foo::{bar::{baz::{}}}` @@ -7,13 +7,13 @@ LL | use foo::{bar::{baz::{}}}; = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130> note: the lint level is defined here - --> $DIR/edition-lint-nested-empty-paths.rs:3:9 + --> $DIR/edition-lint-nested-empty-paths.rs:4:9 | LL | #![deny(absolute_paths_not_starting_with_crate)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition - --> $DIR/edition-lint-nested-empty-paths.rs:20:5 + --> $DIR/edition-lint-nested-empty-paths.rs:21:5 | LL | use foo::{bar::{XX, baz::{}}}; | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `crate`: `crate::foo::{bar::{XX, baz::{}}}` @@ -22,7 +22,7 @@ LL | use foo::{bar::{XX, baz::{}}}; = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130> error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition - --> $DIR/edition-lint-nested-empty-paths.rs:20:5 + --> $DIR/edition-lint-nested-empty-paths.rs:21:5 | LL | use foo::{bar::{XX, baz::{}}}; | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `crate`: `crate::foo::{bar::{XX, baz::{}}}` @@ -32,7 +32,7 @@ LL | use foo::{bar::{XX, baz::{}}}; = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition - --> $DIR/edition-lint-nested-empty-paths.rs:26:5 + --> $DIR/edition-lint-nested-empty-paths.rs:27:5 | LL | use foo::{bar::{baz::{}, baz1::{}}}; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `crate`: `crate::foo::{bar::{baz::{}, baz1::{}}}` @@ -41,7 +41,7 @@ LL | use foo::{bar::{baz::{}, baz1::{}}}; = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130> error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition - --> $DIR/edition-lint-nested-empty-paths.rs:26:5 + --> $DIR/edition-lint-nested-empty-paths.rs:27:5 | LL | use foo::{bar::{baz::{}, baz1::{}}}; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `crate`: `crate::foo::{bar::{baz::{}, baz1::{}}}` diff --git a/tests/ui/rust-2018/edition-lint-nested-paths.fixed b/tests/ui/rust-2018/edition-lint-nested-paths.fixed index 93ccb2fe6af..bf0038c3be4 100644 --- a/tests/ui/rust-2018/edition-lint-nested-paths.fixed +++ b/tests/ui/rust-2018/edition-lint-nested-paths.fixed @@ -1,3 +1,4 @@ +//@ edition: 2015 //@ run-rustfix #![deny(absolute_paths_not_starting_with_crate)] diff --git a/tests/ui/rust-2018/edition-lint-nested-paths.rs b/tests/ui/rust-2018/edition-lint-nested-paths.rs index 1c1d21dbab9..87dc51a3745 100644 --- a/tests/ui/rust-2018/edition-lint-nested-paths.rs +++ b/tests/ui/rust-2018/edition-lint-nested-paths.rs @@ -1,3 +1,4 @@ +//@ edition: 2015 //@ run-rustfix #![deny(absolute_paths_not_starting_with_crate)] diff --git a/tests/ui/rust-2018/edition-lint-nested-paths.stderr b/tests/ui/rust-2018/edition-lint-nested-paths.stderr index d059a2533a9..4a70bb7e5c8 100644 --- a/tests/ui/rust-2018/edition-lint-nested-paths.stderr +++ b/tests/ui/rust-2018/edition-lint-nested-paths.stderr @@ -1,5 +1,5 @@ error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition - --> $DIR/edition-lint-nested-paths.rs:5:5 + --> $DIR/edition-lint-nested-paths.rs:6:5 | LL | use foo::{a, b}; | ^^^^^^^^^^^ help: use `crate`: `crate::foo::{a, b}` @@ -7,13 +7,13 @@ LL | use foo::{a, b}; = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130> note: the lint level is defined here - --> $DIR/edition-lint-nested-paths.rs:3:9 + --> $DIR/edition-lint-nested-paths.rs:4:9 | LL | #![deny(absolute_paths_not_starting_with_crate)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition - --> $DIR/edition-lint-nested-paths.rs:5:5 + --> $DIR/edition-lint-nested-paths.rs:6:5 | LL | use foo::{a, b}; | ^^^^^^^^^^^ help: use `crate`: `crate::foo::{a, b}` @@ -23,7 +23,7 @@ LL | use foo::{a, b}; = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition - --> $DIR/edition-lint-nested-paths.rs:22:13 + --> $DIR/edition-lint-nested-paths.rs:23:13 | LL | use foo::{self as x, c}; | ^^^^^^^^^^^^^^^^^^^ help: use `crate`: `crate::foo::{self as x, c}` @@ -32,7 +32,7 @@ LL | use foo::{self as x, c}; = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130> error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition - --> $DIR/edition-lint-nested-paths.rs:22:13 + --> $DIR/edition-lint-nested-paths.rs:23:13 | LL | use foo::{self as x, c}; | ^^^^^^^^^^^^^^^^^^^ help: use `crate`: `crate::foo::{self as x, c}` diff --git a/tests/ui/rust-2018/edition-lint-paths.fixed b/tests/ui/rust-2018/edition-lint-paths.fixed index 014bf91886f..9664b461161 100644 --- a/tests/ui/rust-2018/edition-lint-paths.fixed +++ b/tests/ui/rust-2018/edition-lint-paths.fixed @@ -1,3 +1,4 @@ +//@ edition: 2015 //@ aux-build:edition-lint-paths.rs //@ run-rustfix diff --git a/tests/ui/rust-2018/edition-lint-paths.rs b/tests/ui/rust-2018/edition-lint-paths.rs index 0ecd090c1df..39cdad3ab98 100644 --- a/tests/ui/rust-2018/edition-lint-paths.rs +++ b/tests/ui/rust-2018/edition-lint-paths.rs @@ -1,3 +1,4 @@ +//@ edition: 2015 //@ aux-build:edition-lint-paths.rs //@ run-rustfix diff --git a/tests/ui/rust-2018/edition-lint-paths.stderr b/tests/ui/rust-2018/edition-lint-paths.stderr index 553a3bfdaa8..fde17338d98 100644 --- a/tests/ui/rust-2018/edition-lint-paths.stderr +++ b/tests/ui/rust-2018/edition-lint-paths.stderr @@ -1,5 +1,5 @@ error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition - --> $DIR/edition-lint-paths.rs:11:9 + --> $DIR/edition-lint-paths.rs:12:9 | LL | use bar::Bar; | ^^^^^^^^ help: use `crate`: `crate::bar::Bar` @@ -7,13 +7,13 @@ LL | use bar::Bar; = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130> note: the lint level is defined here - --> $DIR/edition-lint-paths.rs:4:9 + --> $DIR/edition-lint-paths.rs:5:9 | LL | #![deny(absolute_paths_not_starting_with_crate)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition - --> $DIR/edition-lint-paths.rs:18:9 + --> $DIR/edition-lint-paths.rs:19:9 | LL | use bar; | ^^^ help: use `crate`: `crate::bar` @@ -22,7 +22,7 @@ LL | use bar; = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130> error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition - --> $DIR/edition-lint-paths.rs:24:9 + --> $DIR/edition-lint-paths.rs:25:9 | LL | use {main, Bar as SomethingElse}; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `crate`: `crate::{main, Bar as SomethingElse}` @@ -31,7 +31,7 @@ LL | use {main, Bar as SomethingElse}; = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130> error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition - --> $DIR/edition-lint-paths.rs:24:9 + --> $DIR/edition-lint-paths.rs:25:9 | LL | use {main, Bar as SomethingElse}; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `crate`: `crate::{main, Bar as SomethingElse}` @@ -41,7 +41,7 @@ LL | use {main, Bar as SomethingElse}; = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition - --> $DIR/edition-lint-paths.rs:24:9 + --> $DIR/edition-lint-paths.rs:25:9 | LL | use {main, Bar as SomethingElse}; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `crate`: `crate::{main, Bar as SomethingElse}` @@ -51,7 +51,7 @@ LL | use {main, Bar as SomethingElse}; = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition - --> $DIR/edition-lint-paths.rs:39:5 + --> $DIR/edition-lint-paths.rs:40:5 | LL | use bar::Bar; | ^^^^^^^^ help: use `crate`: `crate::bar::Bar` @@ -60,7 +60,7 @@ LL | use bar::Bar; = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130> error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition - --> $DIR/edition-lint-paths.rs:51:9 + --> $DIR/edition-lint-paths.rs:52:9 | LL | use *; | ^ help: use `crate`: `crate::*` @@ -69,7 +69,7 @@ LL | use *; = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130> error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition - --> $DIR/edition-lint-paths.rs:56:6 + --> $DIR/edition-lint-paths.rs:57:6 | LL | impl ::foo::SomeTrait for u32 {} | ^^^^^^^^^^^^^^^^ help: use `crate`: `crate::foo::SomeTrait` @@ -78,7 +78,7 @@ LL | impl ::foo::SomeTrait for u32 {} = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130> error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition - --> $DIR/edition-lint-paths.rs:61:13 + --> $DIR/edition-lint-paths.rs:62:13 | LL | let x = ::bar::Bar; | ^^^^^^^^^^ help: use `crate`: `crate::bar::Bar` diff --git a/tests/ui/rust-2018/extern-crate-rename.fixed b/tests/ui/rust-2018/extern-crate-rename.fixed index 36b52802990..b6b665f537e 100644 --- a/tests/ui/rust-2018/extern-crate-rename.fixed +++ b/tests/ui/rust-2018/extern-crate-rename.fixed @@ -1,3 +1,4 @@ +//@ edition: 2015 //@ aux-build:edition-lint-paths.rs //@ run-rustfix diff --git a/tests/ui/rust-2018/extern-crate-rename.rs b/tests/ui/rust-2018/extern-crate-rename.rs index 725e3aaa072..3257ab876e1 100644 --- a/tests/ui/rust-2018/extern-crate-rename.rs +++ b/tests/ui/rust-2018/extern-crate-rename.rs @@ -1,3 +1,4 @@ +//@ edition: 2015 //@ aux-build:edition-lint-paths.rs //@ run-rustfix diff --git a/tests/ui/rust-2018/extern-crate-rename.stderr b/tests/ui/rust-2018/extern-crate-rename.stderr index 6b251208030..36986c89c62 100644 --- a/tests/ui/rust-2018/extern-crate-rename.stderr +++ b/tests/ui/rust-2018/extern-crate-rename.stderr @@ -1,5 +1,5 @@ error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition - --> $DIR/extern-crate-rename.rs:11:5 + --> $DIR/extern-crate-rename.rs:12:5 | LL | use my_crate::foo; | ^^^^^^^^^^^^^ help: use `crate`: `crate::my_crate::foo` @@ -7,7 +7,7 @@ LL | use my_crate::foo; = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130> note: the lint level is defined here - --> $DIR/extern-crate-rename.rs:7:9 + --> $DIR/extern-crate-rename.rs:8:9 | LL | #![deny(absolute_paths_not_starting_with_crate)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/rust-2018/extern-crate-submod.fixed b/tests/ui/rust-2018/extern-crate-submod.fixed index dc864d87039..8657960e972 100644 --- a/tests/ui/rust-2018/extern-crate-submod.fixed +++ b/tests/ui/rust-2018/extern-crate-submod.fixed @@ -1,3 +1,4 @@ +//@ edition: 2015 //@ aux-build:edition-lint-paths.rs //@ run-rustfix diff --git a/tests/ui/rust-2018/extern-crate-submod.rs b/tests/ui/rust-2018/extern-crate-submod.rs index f15bc6bced8..bf0a38d2b34 100644 --- a/tests/ui/rust-2018/extern-crate-submod.rs +++ b/tests/ui/rust-2018/extern-crate-submod.rs @@ -1,3 +1,4 @@ +//@ edition: 2015 //@ aux-build:edition-lint-paths.rs //@ run-rustfix diff --git a/tests/ui/rust-2018/extern-crate-submod.stderr b/tests/ui/rust-2018/extern-crate-submod.stderr index 0d45d32d568..85e26d72a67 100644 --- a/tests/ui/rust-2018/extern-crate-submod.stderr +++ b/tests/ui/rust-2018/extern-crate-submod.stderr @@ -1,5 +1,5 @@ error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition - --> $DIR/extern-crate-submod.rs:18:5 + --> $DIR/extern-crate-submod.rs:19:5 | LL | use m::edition_lint_paths::foo; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `crate`: `crate::m::edition_lint_paths::foo` @@ -7,7 +7,7 @@ LL | use m::edition_lint_paths::foo; = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130> note: the lint level is defined here - --> $DIR/extern-crate-submod.rs:8:9 + --> $DIR/extern-crate-submod.rs:9:9 | LL | #![deny(absolute_paths_not_starting_with_crate)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/rust-2018/try-ident.fixed b/tests/ui/rust-2018/try-ident.fixed index b1c446e1022..b514c6d0756 100644 --- a/tests/ui/rust-2018/try-ident.fixed +++ b/tests/ui/rust-2018/try-ident.fixed @@ -1,3 +1,4 @@ +//@ edition: 2015 //@ run-rustfix //@ check-pass diff --git a/tests/ui/rust-2018/try-ident.rs b/tests/ui/rust-2018/try-ident.rs index 8e62f698e25..2b8bb9234e5 100644 --- a/tests/ui/rust-2018/try-ident.rs +++ b/tests/ui/rust-2018/try-ident.rs @@ -1,3 +1,4 @@ +//@ edition: 2015 //@ run-rustfix //@ check-pass diff --git a/tests/ui/rust-2018/try-ident.stderr b/tests/ui/rust-2018/try-ident.stderr index eaf4c235697..aca623d7d48 100644 --- a/tests/ui/rust-2018/try-ident.stderr +++ b/tests/ui/rust-2018/try-ident.stderr @@ -1,5 +1,5 @@ warning: `try` is a keyword in the 2018 edition - --> $DIR/try-ident.rs:7:5 + --> $DIR/try-ident.rs:8:5 | LL | try(); | ^^^ help: you can use a raw identifier to stay compatible: `r#try` @@ -7,14 +7,14 @@ LL | try(); = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716> note: the lint level is defined here - --> $DIR/try-ident.rs:4:9 + --> $DIR/try-ident.rs:5:9 | LL | #![warn(rust_2018_compatibility)] | ^^^^^^^^^^^^^^^^^^^^^^^ = note: `#[warn(keyword_idents_2018)]` implied by `#[warn(rust_2018_compatibility)]` warning: `try` is a keyword in the 2018 edition - --> $DIR/try-ident.rs:12:4 + --> $DIR/try-ident.rs:13:4 | LL | fn try() { | ^^^ help: you can use a raw identifier to stay compatible: `r#try` diff --git a/tests/ui/rust-2018/try-macro.fixed b/tests/ui/rust-2018/try-macro.fixed index 98c48d6b96f..f2d8cf2bd9a 100644 --- a/tests/ui/rust-2018/try-macro.fixed +++ b/tests/ui/rust-2018/try-macro.fixed @@ -1,5 +1,6 @@ // Test that `try!` macros are rewritten. +//@ edition: 2015 //@ run-rustfix //@ check-pass diff --git a/tests/ui/rust-2018/try-macro.rs b/tests/ui/rust-2018/try-macro.rs index 99480b2a3ec..fec8eaa1786 100644 --- a/tests/ui/rust-2018/try-macro.rs +++ b/tests/ui/rust-2018/try-macro.rs @@ -1,5 +1,6 @@ // Test that `try!` macros are rewritten. +//@ edition: 2015 //@ run-rustfix //@ check-pass diff --git a/tests/ui/rust-2018/try-macro.stderr b/tests/ui/rust-2018/try-macro.stderr index 095c755539d..20105e1868f 100644 --- a/tests/ui/rust-2018/try-macro.stderr +++ b/tests/ui/rust-2018/try-macro.stderr @@ -1,5 +1,5 @@ warning: `try` is a keyword in the 2018 edition - --> $DIR/try-macro.rs:12:5 + --> $DIR/try-macro.rs:13:5 | LL | try!(x); | ^^^ help: you can use a raw identifier to stay compatible: `r#try` @@ -7,7 +7,7 @@ LL | try!(x); = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018! = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716> note: the lint level is defined here - --> $DIR/try-macro.rs:6:9 + --> $DIR/try-macro.rs:7:9 | LL | #![warn(rust_2018_compatibility)] | ^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/rustdoc/feature-gate-doc_primitive.rs b/tests/ui/rustdoc/feature-gate-doc_primitive.rs index 78fcd90752e..dbf92f19378 100644 --- a/tests/ui/rustdoc/feature-gate-doc_primitive.rs +++ b/tests/ui/rustdoc/feature-gate-doc_primitive.rs @@ -1,5 +1,7 @@ #[rustc_doc_primitive = "usize"] -//~^ ERROR `rustc_doc_primitive` is a rustc internal attribute +//~^ ERROR use of an internal attribute [E0658] +//~| NOTE the `#[rustc_doc_primitive]` attribute is an internal implementation detail that will never be stable +//~| NOTE the `#[rustc_doc_primitive]` attribute is used by the standard library to provide a way to generate documentation for primitive types /// Some docs mod usize {} diff --git a/tests/ui/rustdoc/feature-gate-doc_primitive.stderr b/tests/ui/rustdoc/feature-gate-doc_primitive.stderr index e74b1322b25..0b1af78b504 100644 --- a/tests/ui/rustdoc/feature-gate-doc_primitive.stderr +++ b/tests/ui/rustdoc/feature-gate-doc_primitive.stderr @@ -1,11 +1,12 @@ -error[E0658]: `rustc_doc_primitive` is a rustc internal attribute +error[E0658]: use of an internal attribute --> $DIR/feature-gate-doc_primitive.rs:1:1 | LL | #[rustc_doc_primitive = "usize"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: the `#[rustc_doc_primitive]` attribute is an internal implementation detail that will never be stable + = note: the `#[rustc_doc_primitive]` attribute is used by the standard library to provide a way to generate documentation for primitive types error: aborting due to 1 previous error diff --git a/tests/ui/rustdoc/renamed-features-rustdoc_internals.rs b/tests/ui/rustdoc/renamed-features-rustdoc_internals.rs index 739c624d0c6..2257130280d 100644 --- a/tests/ui/rustdoc/renamed-features-rustdoc_internals.rs +++ b/tests/ui/rustdoc/renamed-features-rustdoc_internals.rs @@ -1,3 +1,5 @@ +//@ normalize-stderr: "you are using [0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9]+)?( \([^)]*\))?" -> "you are using $$RUSTC_VERSION" + #![feature(doc_keyword)] //~ ERROR #![feature(doc_primitive)] //~ ERROR #![crate_type = "lib"] diff --git a/tests/ui/rustdoc/renamed-features-rustdoc_internals.stderr b/tests/ui/rustdoc/renamed-features-rustdoc_internals.stderr index d0979ce97ac..9c664da8ee6 100644 --- a/tests/ui/rustdoc/renamed-features-rustdoc_internals.stderr +++ b/tests/ui/rustdoc/renamed-features-rustdoc_internals.stderr @@ -1,17 +1,19 @@ error[E0557]: feature has been removed - --> $DIR/renamed-features-rustdoc_internals.rs:1:12 + --> $DIR/renamed-features-rustdoc_internals.rs:3:12 | LL | #![feature(doc_keyword)] | ^^^^^^^^^^^ feature has been removed | + = note: removed in 1.58.0 (you are using $RUSTC_VERSION); see <https://github.com/rust-lang/rust/pull/90420> for more information = note: merged into `#![feature(rustdoc_internals)]` error[E0557]: feature has been removed - --> $DIR/renamed-features-rustdoc_internals.rs:2:12 + --> $DIR/renamed-features-rustdoc_internals.rs:4:12 | LL | #![feature(doc_primitive)] | ^^^^^^^^^^^^^ feature has been removed | + = note: removed in 1.58.0 (you are using $RUSTC_VERSION); see <https://github.com/rust-lang/rust/pull/90420> for more information = note: merged into `#![feature(rustdoc_internals)]` error: aborting due to 2 previous errors diff --git a/tests/ui/self/self-shadowing-import.rs b/tests/ui/self/self-shadowing-import.rs index 85574daad5f..78d04e0713a 100644 --- a/tests/ui/self/self-shadowing-import.rs +++ b/tests/ui/self/self-shadowing-import.rs @@ -9,7 +9,7 @@ mod a { } mod c { - use a::b::a; + use crate::a::b::a; pub fn bar() { assert_eq!(a::foo(), 1); } } diff --git a/tests/ui/sepcomp/auxiliary/sepcomp_lib.rs b/tests/ui/sepcomp/auxiliary/sepcomp_lib.rs index 59efb3f790b..a0d91c5dc87 100644 --- a/tests/ui/sepcomp/auxiliary/sepcomp_lib.rs +++ b/tests/ui/sepcomp/auxiliary/sepcomp_lib.rs @@ -13,8 +13,8 @@ pub mod b { } pub mod c { - use a::one; - use b::two; + use crate::a::one; + use crate::b::two; pub fn three() -> usize { one() + two() } diff --git a/tests/ui/sepcomp/sepcomp-extern.rs b/tests/ui/sepcomp/sepcomp-extern.rs index 6acd3a1eede..d0756c5f19a 100644 --- a/tests/ui/sepcomp/sepcomp-extern.rs +++ b/tests/ui/sepcomp/sepcomp-extern.rs @@ -16,13 +16,13 @@ fn call1() -> usize { mod a { pub fn call2() -> usize { - unsafe { ::foo() } + unsafe { crate::foo() } } } mod b { pub fn call3() -> usize { - unsafe { ::foo() } + unsafe { crate::foo() } } } diff --git a/tests/ui/sepcomp/sepcomp-fns-backwards.rs b/tests/ui/sepcomp/sepcomp-fns-backwards.rs index 35326d19d6e..c671771babb 100644 --- a/tests/ui/sepcomp/sepcomp-fns-backwards.rs +++ b/tests/ui/sepcomp/sepcomp-fns-backwards.rs @@ -12,13 +12,13 @@ fn pad() -> usize { 0 } mod b { pub fn three() -> usize { - ::one() + ::a::two() + crate::one() + crate::a::two() } } mod a { pub fn two() -> usize { - ::one() + ::one() + crate::one() + crate::one() } } diff --git a/tests/ui/sepcomp/sepcomp-fns.rs b/tests/ui/sepcomp/sepcomp-fns.rs index 399193e69b6..1486a2471b8 100644 --- a/tests/ui/sepcomp/sepcomp-fns.rs +++ b/tests/ui/sepcomp/sepcomp-fns.rs @@ -13,13 +13,13 @@ fn one() -> usize { 1 } mod a { pub fn two() -> usize { - ::one() + ::one() + crate::one() + crate::one() } } mod b { pub fn three() -> usize { - ::one() + ::a::two() + crate::one() + crate::a::two() } } diff --git a/tests/ui/sepcomp/sepcomp-statics.rs b/tests/ui/sepcomp/sepcomp-statics.rs index 580bb628da6..3fe897f3c30 100644 --- a/tests/ui/sepcomp/sepcomp-statics.rs +++ b/tests/ui/sepcomp/sepcomp-statics.rs @@ -15,13 +15,13 @@ mod b { // that `a` and `b` don't go into the same compilation unit. fn pad() -> usize { 0 } - pub static THREE: usize = ::ONE + ::a::TWO; + pub static THREE: usize = crate::ONE + crate::a::TWO; } mod a { fn pad() -> usize { 0 } - pub const TWO: usize = ::ONE + ::ONE; + pub const TWO: usize = crate::ONE + crate::ONE; } fn main() { diff --git a/tests/ui/sepcomp/sepcomp-unwind.rs b/tests/ui/sepcomp/sepcomp-unwind.rs index 8c25278bb7e..95591676b5e 100644 --- a/tests/ui/sepcomp/sepcomp-unwind.rs +++ b/tests/ui/sepcomp/sepcomp-unwind.rs @@ -26,10 +26,10 @@ mod a { mod b { pub fn g() { - ::a::f(); + crate::a::f(); } } fn main() { - thread::spawn(move|| { ::b::g() }).join().unwrap_err(); + thread::spawn(move|| { b::g() }).join().unwrap_err(); } diff --git a/tests/ui/shadowed-use-visibility.rs b/tests/ui/shadowed-use-visibility.rs index 66181267f98..5ce4103b559 100644 --- a/tests/ui/shadowed-use-visibility.rs +++ b/tests/ui/shadowed-use-visibility.rs @@ -5,7 +5,7 @@ mod foo { pub fn f() {} pub use self::f as bar; - use foo as bar; + use crate::foo as bar; } fn main() { diff --git a/tests/ui/shadowed/shadowed-trait-methods.rs b/tests/ui/shadowed/shadowed-trait-methods.rs index f9c25d97913..6cc5159fd08 100644 --- a/tests/ui/shadowed/shadowed-trait-methods.rs +++ b/tests/ui/shadowed/shadowed-trait-methods.rs @@ -5,7 +5,7 @@ mod foo { impl T for () {} } -mod bar { pub use foo::T; } +mod bar { pub use crate::foo::T; } fn main() { pub use bar::*; diff --git a/tests/ui/shadowed/shadowed-use-visibility.rs b/tests/ui/shadowed/shadowed-use-visibility.rs index 6b801972f41..070aeaf1467 100644 --- a/tests/ui/shadowed/shadowed-use-visibility.rs +++ b/tests/ui/shadowed/shadowed-use-visibility.rs @@ -1,15 +1,15 @@ mod foo { pub fn f() {} - use foo as bar; + use crate::foo as bar; pub use self::f as bar; } mod bar { - use foo::bar::f as g; //~ ERROR module import `bar` is private + use crate::foo::bar::f as g; //~ ERROR module import `bar` is private - use foo as f; - pub use foo::*; + use crate::foo as f; + pub use crate::foo::*; } use bar::f::f; //~ ERROR module import `f` is private diff --git a/tests/ui/shadowed/shadowed-use-visibility.stderr b/tests/ui/shadowed/shadowed-use-visibility.stderr index 1a642ae6e8e..b062341dc8b 100644 --- a/tests/ui/shadowed/shadowed-use-visibility.stderr +++ b/tests/ui/shadowed/shadowed-use-visibility.stderr @@ -1,14 +1,14 @@ error[E0603]: module import `bar` is private - --> $DIR/shadowed-use-visibility.rs:9:14 + --> $DIR/shadowed-use-visibility.rs:9:21 | -LL | use foo::bar::f as g; - | ^^^ private module import +LL | use crate::foo::bar::f as g; + | ^^^ private module import | note: the module import `bar` is defined here... --> $DIR/shadowed-use-visibility.rs:4:9 | -LL | use foo as bar; - | ^^^^^^^^^^ +LL | use crate::foo as bar; + | ^^^^^^^^^^^^^^^^^ note: ...and refers to the module `foo` which is defined here --> $DIR/shadowed-use-visibility.rs:1:1 | @@ -24,8 +24,8 @@ LL | use bar::f::f; note: the module import `f` is defined here... --> $DIR/shadowed-use-visibility.rs:11:9 | -LL | use foo as f; - | ^^^^^^^^ +LL | use crate::foo as f; + | ^^^^^^^^^^^^^^^ note: ...and refers to the module `foo` which is defined here --> $DIR/shadowed-use-visibility.rs:1:1 | diff --git a/tests/ui/simd/size-align.rs b/tests/ui/simd/size-align.rs index ff23ea5980b..53acb686fb8 100644 --- a/tests/ui/simd/size-align.rs +++ b/tests/ui/simd/size-align.rs @@ -7,12 +7,12 @@ use std::mem; -/// `T` should satisfy `size_of T (mod min_align_of T) === 0` to be stored at `Vec<T>` properly +/// `T` should satisfy `size_of T (mod align_of T) === 0` to be stored at `Vec<T>` properly /// Please consult the issue #20460 fn check<T>() { - assert_eq!(mem::size_of::<T>() % mem::min_align_of::<T>(), 0); - assert_eq!(mem::size_of::<T>() % mem::min_align_of::<T>(), 0); - assert_eq!(mem::size_of::<T>() % mem::min_align_of::<T>(), 0); + assert_eq!(mem::size_of::<T>() % mem::align_of::<T>(), 0); + assert_eq!(mem::size_of::<T>() % mem::align_of::<T>(), 0); + assert_eq!(mem::size_of::<T>() % mem::align_of::<T>(), 0); } #[repr(simd)] diff --git a/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.rs b/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.rs index 66a432be357..baa664d5933 100644 --- a/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.rs +++ b/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.rs @@ -1,3 +1,5 @@ +//@ edition: 2015 + #![warn(rust_2021_incompatible_closure_captures)] fn main() {} diff --git a/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.stderr b/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.stderr index 5ecbedf1867..00b9a81b27d 100644 --- a/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.stderr +++ b/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.stderr @@ -1,5 +1,5 @@ error[E0670]: `async fn` is not permitted in Rust 2015 - --> $DIR/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.rs:8:16 + --> $DIR/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.rs:10:16 | LL | pub(crate) async fn new( | ^^^^^ to use `async fn`, switch to Rust 2018 or later @@ -8,7 +8,7 @@ LL | pub(crate) async fn new( = note: for more on editions, read https://doc.rust-lang.org/edition-guide error[E0412]: cannot find type `Duration` in this scope - --> $DIR/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.rs:10:19 + --> $DIR/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.rs:12:19 | LL | interval: Duration, | ^^^^^^^^ not found in this scope diff --git a/tests/ui/span/dropck_arr_cycle_checked.rs b/tests/ui/span/dropck_arr_cycle_checked.rs index a14db5ff089..adecb3f5942 100644 --- a/tests/ui/span/dropck_arr_cycle_checked.rs +++ b/tests/ui/span/dropck_arr_cycle_checked.rs @@ -19,7 +19,7 @@ mod s { } mod id { - use s; + use crate::s; #[derive(Debug)] pub struct Id { orig_count: usize, diff --git a/tests/ui/span/dropck_vec_cycle_checked.rs b/tests/ui/span/dropck_vec_cycle_checked.rs index c5d21507d76..b015131caf1 100644 --- a/tests/ui/span/dropck_vec_cycle_checked.rs +++ b/tests/ui/span/dropck_vec_cycle_checked.rs @@ -16,7 +16,7 @@ mod s { } mod id { - use s; + use crate::s; #[derive(Debug)] pub struct Id { orig_count: usize, diff --git a/tests/ui/span/vec-must-not-hide-type-from-dropck.rs b/tests/ui/span/vec-must-not-hide-type-from-dropck.rs index 9bfbfab06a0..972ffef2e3c 100644 --- a/tests/ui/span/vec-must-not-hide-type-from-dropck.rs +++ b/tests/ui/span/vec-must-not-hide-type-from-dropck.rs @@ -31,7 +31,7 @@ mod s { } mod id { - use s; + use crate::s; /// Id represents a globally unique identifier (global across the /// current process, that is). When dropped, it automatically diff --git a/tests/ui/span/visibility-ty-params.rs b/tests/ui/span/visibility-ty-params.rs index 11c2cf44cb4..05d93e54636 100644 --- a/tests/ui/span/visibility-ty-params.rs +++ b/tests/ui/span/visibility-ty-params.rs @@ -3,11 +3,11 @@ macro_rules! m { } struct S<T>(T); -m!{ S<u8> } //~ ERROR unexpected generic arguments in path - //~| ERROR failed to resolve: `S` is a struct, not a module [E0433] +m!{ crate::S<u8> } //~ ERROR unexpected generic arguments in path + //~| ERROR failed to resolve: `S` is a struct, not a module [E0433] mod m { - m!{ m<> } //~ ERROR unexpected generic arguments in path + m!{ crate::m<> } //~ ERROR unexpected generic arguments in path } fn main() {} diff --git a/tests/ui/span/visibility-ty-params.stderr b/tests/ui/span/visibility-ty-params.stderr index 97d05c4644e..7b02d79a1bc 100644 --- a/tests/ui/span/visibility-ty-params.stderr +++ b/tests/ui/span/visibility-ty-params.stderr @@ -1,20 +1,20 @@ error: unexpected generic arguments in path - --> $DIR/visibility-ty-params.rs:6:6 + --> $DIR/visibility-ty-params.rs:6:13 | -LL | m!{ S<u8> } - | ^^^^ +LL | m!{ crate::S<u8> } + | ^^^^ error[E0433]: failed to resolve: `S` is a struct, not a module - --> $DIR/visibility-ty-params.rs:6:5 + --> $DIR/visibility-ty-params.rs:6:12 | -LL | m!{ S<u8> } - | ^ `S` is a struct, not a module +LL | m!{ crate::S<u8> } + | ^ `S` is a struct, not a module error: unexpected generic arguments in path - --> $DIR/visibility-ty-params.rs:10:10 + --> $DIR/visibility-ty-params.rs:10:17 | -LL | m!{ m<> } - | ^^ +LL | m!{ crate::m<> } + | ^^ error: aborting due to 3 previous errors diff --git a/tests/ui/auxiliary/pub-and-stability.rs b/tests/ui/stability-attribute/auxiliary/pub-and-stability.rs index 8866233b61e..8866233b61e 100644 --- a/tests/ui/auxiliary/pub-and-stability.rs +++ b/tests/ui/stability-attribute/auxiliary/pub-and-stability.rs diff --git a/tests/ui/stability-attribute/renamed_feature.rs b/tests/ui/stability-attribute/renamed_feature.rs new file mode 100644 index 00000000000..249c2abecff --- /dev/null +++ b/tests/ui/stability-attribute/renamed_feature.rs @@ -0,0 +1,3 @@ +#![feature(try_trait)] //~ ERROR feature `try_trait` has been renamed to `try_trait_v2` [E0635] + +fn main() {} diff --git a/tests/ui/stability-attribute/renamed_feature.stderr b/tests/ui/stability-attribute/renamed_feature.stderr new file mode 100644 index 00000000000..293a2feffb2 --- /dev/null +++ b/tests/ui/stability-attribute/renamed_feature.stderr @@ -0,0 +1,9 @@ +error[E0635]: feature `try_trait` has been renamed to `try_trait_v2` + --> $DIR/renamed_feature.rs:1:12 + | +LL | #![feature(try_trait)] + | ^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0635`. diff --git a/tests/ui/explore-issue-38412.rs b/tests/ui/stability-attribute/stability-privacy-interaction.rs index 2008b120faa..e02816ae1e7 100644 --- a/tests/ui/explore-issue-38412.rs +++ b/tests/ui/stability-attribute/stability-privacy-interaction.rs @@ -1,28 +1,39 @@ +//! Regression test for issue #38412: interaction between stability attributes and privacy +//! +//! Tests that the compiler correctly handles the interaction between feature gates +//! and privacy/visibility rules. Specifically verifies that enabled unstable features +//! are accessible while disabled ones are properly rejected. + //@ aux-build:pub-and-stability.rs -// A big point of this test is that we *enable* `unstable_declared`, -// but do *not* enable `unstable_undeclared`. This way we can check -// that the compiler is letting in uses of enabled feature-gated -// stuff but still rejecting uses of disabled feature-gated stuff. +// Enable `unstable_declared` but not `unstable_undeclared` to test +// that the compiler allows enabled features but rejects disabled ones #![feature(unstable_declared)] extern crate pub_and_stability; use pub_and_stability::{Record, Trait, Tuple}; fn main() { - // Okay + // Test struct field access patterns let Record { .. } = Record::new(); - // Okay - let Record { a_stable_pub: _, a_unstable_declared_pub: _, .. } = Record::new(); + let Record { + a_stable_pub: _, + a_unstable_declared_pub: _, + .. + } = Record::new(); - let Record { a_stable_pub: _, a_unstable_declared_pub: _, a_unstable_undeclared_pub: _, .. } = - Record::new(); - //~^^ ERROR use of unstable library feature `unstable_undeclared` + let Record { + a_stable_pub: _, + a_unstable_declared_pub: _, + a_unstable_undeclared_pub: _, //~ ERROR use of unstable library feature `unstable_undeclared` + .. + } = Record::new(); let r = Record::new(); let t = Tuple::new(); + // Test field access with different stability/privacy combinations r.a_stable_pub; r.a_unstable_declared_pub; r.a_unstable_undeclared_pub; //~ ERROR use of unstable library feature @@ -37,10 +48,12 @@ fn main() { t.4; //~ ERROR is private t.5; //~ ERROR is private + // Test trait method access r.stable_trait_method(); r.unstable_declared_trait_method(); r.unstable_undeclared_trait_method(); //~ ERROR use of unstable library feature + // Test inherent method access r.stable(); r.unstable_declared(); r.unstable_undeclared(); //~ ERROR use of unstable library feature @@ -49,6 +62,7 @@ fn main() { r.pub_mod(); //~ ERROR `pub_mod` is private r.private(); //~ ERROR `private` is private + // Repeat tests for tuple struct let t = Tuple::new(); t.stable_trait_method(); t.unstable_declared_trait_method(); diff --git a/tests/ui/explore-issue-38412.stderr b/tests/ui/stability-attribute/stability-privacy-interaction.stderr index fca5c738d27..991b3dbe019 100644 --- a/tests/ui/explore-issue-38412.stderr +++ b/tests/ui/stability-attribute/stability-privacy-interaction.stderr @@ -1,15 +1,15 @@ error[E0658]: use of unstable library feature `unstable_undeclared` - --> $DIR/explore-issue-38412.rs:19:63 + --> $DIR/stability-privacy-interaction.rs:29:9 | -LL | let Record { a_stable_pub: _, a_unstable_declared_pub: _, a_unstable_undeclared_pub: _, .. } = - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | a_unstable_undeclared_pub: _, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #38412 <https://github.com/rust-lang/rust/issues/38412> for more information = help: add `#![feature(unstable_undeclared)]` 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 `unstable_undeclared` - --> $DIR/explore-issue-38412.rs:28:5 + --> $DIR/stability-privacy-interaction.rs:39:5 | LL | r.a_unstable_undeclared_pub; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -19,25 +19,25 @@ LL | r.a_unstable_undeclared_pub; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0616]: field `b_crate` of struct `Record` is private - --> $DIR/explore-issue-38412.rs:29:7 + --> $DIR/stability-privacy-interaction.rs:40:7 | LL | r.b_crate; | ^^^^^^^ private field error[E0616]: field `c_mod` of struct `Record` is private - --> $DIR/explore-issue-38412.rs:30:7 + --> $DIR/stability-privacy-interaction.rs:41:7 | LL | r.c_mod; | ^^^^^ private field error[E0616]: field `d_priv` of struct `Record` is private - --> $DIR/explore-issue-38412.rs:31:7 + --> $DIR/stability-privacy-interaction.rs:42:7 | LL | r.d_priv; | ^^^^^^ private field error[E0658]: use of unstable library feature `unstable_undeclared` - --> $DIR/explore-issue-38412.rs:35:5 + --> $DIR/stability-privacy-interaction.rs:46:5 | LL | t.2; | ^^^ @@ -47,25 +47,25 @@ LL | t.2; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0616]: field `3` of struct `pub_and_stability::Tuple` is private - --> $DIR/explore-issue-38412.rs:36:7 + --> $DIR/stability-privacy-interaction.rs:47:7 | LL | t.3; | ^ private field error[E0616]: field `4` of struct `pub_and_stability::Tuple` is private - --> $DIR/explore-issue-38412.rs:37:7 + --> $DIR/stability-privacy-interaction.rs:48:7 | LL | t.4; | ^ private field error[E0616]: field `5` of struct `pub_and_stability::Tuple` is private - --> $DIR/explore-issue-38412.rs:38:7 + --> $DIR/stability-privacy-interaction.rs:49:7 | LL | t.5; | ^ private field error[E0658]: use of unstable library feature `unstable_undeclared` - --> $DIR/explore-issue-38412.rs:42:7 + --> $DIR/stability-privacy-interaction.rs:54:7 | LL | r.unstable_undeclared_trait_method(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -75,7 +75,7 @@ LL | r.unstable_undeclared_trait_method(); = 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 `unstable_undeclared` - --> $DIR/explore-issue-38412.rs:46:7 + --> $DIR/stability-privacy-interaction.rs:59:7 | LL | r.unstable_undeclared(); | ^^^^^^^^^^^^^^^^^^^ @@ -85,7 +85,7 @@ LL | r.unstable_undeclared(); = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0624]: method `pub_crate` is private - --> $DIR/explore-issue-38412.rs:48:7 + --> $DIR/stability-privacy-interaction.rs:61:7 | LL | r.pub_crate(); | ^^^^^^^^^ private method @@ -96,7 +96,7 @@ LL | pub(crate) fn pub_crate(&self) -> i32 { self.d_priv } | ------------------------------------- private method defined here error[E0624]: method `pub_mod` is private - --> $DIR/explore-issue-38412.rs:49:7 + --> $DIR/stability-privacy-interaction.rs:62:7 | LL | r.pub_mod(); | ^^^^^^^ private method @@ -107,7 +107,7 @@ LL | pub(in crate::m) fn pub_mod(&self) -> i32 { self.d_priv } | ----------------------------------------- private method defined here error[E0624]: method `private` is private - --> $DIR/explore-issue-38412.rs:50:7 + --> $DIR/stability-privacy-interaction.rs:63:7 | LL | r.private(); | ^^^^^^^ private method @@ -118,7 +118,7 @@ LL | fn private(&self) -> i32 { self.d_priv } | ------------------------ private method defined here error[E0658]: use of unstable library feature `unstable_undeclared` - --> $DIR/explore-issue-38412.rs:55:7 + --> $DIR/stability-privacy-interaction.rs:69:7 | LL | t.unstable_undeclared_trait_method(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -128,7 +128,7 @@ LL | t.unstable_undeclared_trait_method(); = 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 `unstable_undeclared` - --> $DIR/explore-issue-38412.rs:59:7 + --> $DIR/stability-privacy-interaction.rs:73:7 | LL | t.unstable_undeclared(); | ^^^^^^^^^^^^^^^^^^^ @@ -138,7 +138,7 @@ LL | t.unstable_undeclared(); = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0624]: method `pub_crate` is private - --> $DIR/explore-issue-38412.rs:61:7 + --> $DIR/stability-privacy-interaction.rs:75:7 | LL | t.pub_crate(); | ^^^^^^^^^ private method @@ -149,7 +149,7 @@ LL | pub(crate) fn pub_crate(&self) -> i32 { self.0 } | ------------------------------------- private method defined here error[E0624]: method `pub_mod` is private - --> $DIR/explore-issue-38412.rs:62:7 + --> $DIR/stability-privacy-interaction.rs:76:7 | LL | t.pub_mod(); | ^^^^^^^ private method @@ -160,7 +160,7 @@ LL | pub(in crate::m) fn pub_mod(&self) -> i32 { self.0 } | ----------------------------------------- private method defined here error[E0624]: method `private` is private - --> $DIR/explore-issue-38412.rs:63:7 + --> $DIR/stability-privacy-interaction.rs:77:7 | LL | t.private(); | ^^^^^^^ private method diff --git a/tests/ui/static/auxiliary/static_priv_by_default.rs b/tests/ui/static/auxiliary/static_priv_by_default.rs index 39f912066ec..fe9aef42feb 100644 --- a/tests/ui/static/auxiliary/static_priv_by_default.rs +++ b/tests/ui/static/auxiliary/static_priv_by_default.rs @@ -31,11 +31,11 @@ mod foo { } pub mod bar { - pub use foo::reexported_a as e; - pub use foo::reexported_b as f; - pub use foo::reexported_c as g; - pub use foo::reexported_d as h; - pub use foo::reexported_e as i; + pub use crate::foo::reexported_a as e; + pub use crate::foo::reexported_b as f; + pub use crate::foo::reexported_c as g; + pub use crate::foo::reexported_d as h; + pub use crate::foo::reexported_e as i; } pub static a: isize = 0; diff --git a/tests/ui/static/static-extern-type.rs b/tests/ui/static/static-extern-type.rs index 8b022a5c31c..2597c22ed7e 100644 --- a/tests/ui/static/static-extern-type.rs +++ b/tests/ui/static/static-extern-type.rs @@ -10,7 +10,7 @@ pub mod a { pub mod b { #[repr(transparent)] - pub struct TransparentType(::a::StartFn); + pub struct TransparentType(crate::a::StartFn); extern "C" { pub static start: TransparentType; } @@ -18,7 +18,7 @@ pub mod b { pub mod c { #[repr(C)] - pub struct CType(u32, ::b::TransparentType); + pub struct CType(u32, crate::b::TransparentType); extern "C" { pub static start: CType; } diff --git a/tests/ui/statics/auxiliary/static_fn_inline_xc_aux.rs b/tests/ui/statics/auxiliary/static_fn_inline_xc_aux.rs index 8d0f7f61ced..a739e8f2dbe 100644 --- a/tests/ui/statics/auxiliary/static_fn_inline_xc_aux.rs +++ b/tests/ui/statics/auxiliary/static_fn_inline_xc_aux.rs @@ -5,7 +5,7 @@ pub mod num { } pub mod f64 { - impl ::num::Num2 for f64 { + impl crate::num::Num2 for f64 { #[inline] fn from_int2(n: isize) -> f64 { return n as f64; } } diff --git a/tests/ui/statics/auxiliary/static_fn_trait_xc_aux.rs b/tests/ui/statics/auxiliary/static_fn_trait_xc_aux.rs index b8aed2c5f54..ab73bac3bf8 100644 --- a/tests/ui/statics/auxiliary/static_fn_trait_xc_aux.rs +++ b/tests/ui/statics/auxiliary/static_fn_trait_xc_aux.rs @@ -5,7 +5,7 @@ pub mod num { } pub mod f64 { - impl ::num::Num2 for f64 { + impl crate::num::Num2 for f64 { fn from_int2(n: isize) -> f64 { return n as f64; } } } diff --git a/tests/ui/statics/static-impl.rs b/tests/ui/statics/static-impl.rs index 37f3cd13133..5c8d20da0c6 100644 --- a/tests/ui/statics/static-impl.rs +++ b/tests/ui/statics/static-impl.rs @@ -9,12 +9,12 @@ pub trait plus { } mod a { - use plus; + use crate::plus; impl plus for usize { fn plus(&self) -> isize { *self as isize + 20 } } } mod b { - use plus; + use crate::plus; impl plus for String { fn plus(&self) -> isize { 200 } } } diff --git a/tests/ui/stats/auxiliary/include.rs b/tests/ui/stats/auxiliary/include.rs new file mode 100644 index 00000000000..7fb7c781137 --- /dev/null +++ b/tests/ui/stats/auxiliary/include.rs @@ -0,0 +1,3 @@ +fn zzz(x: u32) -> u32 { + x +} diff --git a/tests/ui/stats/input-stats.stderr b/tests/ui/stats/input-stats.stderr index f2598bd7eaf..88f91bef30b 100644 --- a/tests/ui/stats/input-stats.stderr +++ b/tests/ui/stats/input-stats.stderr @@ -82,10 +82,10 @@ hir-stats - Expr 32 (NN.N%) 1 hir-stats - Let 32 (NN.N%) 1 hir-stats - Semi 32 (NN.N%) 1 hir-stats FnDecl 120 (NN.N%) 3 40 -hir-stats Attribute 128 (NN.N%) 4 32 hir-stats FieldDef 128 (NN.N%) 2 64 hir-stats GenericArgs 144 (NN.N%) 3 48 hir-stats Variant 144 (NN.N%) 2 72 +hir-stats Attribute 160 (NN.N%) 4 40 hir-stats GenericBound 256 (NN.N%) 4 64 hir-stats - Trait 256 (NN.N%) 4 hir-stats Block 288 (NN.N%) 6 48 @@ -117,5 +117,5 @@ hir-stats - Use 352 (NN.N%) 4 hir-stats Path 1_040 (NN.N%) 26 40 hir-stats PathSegment 1_776 (NN.N%) 37 48 hir-stats ---------------------------------------------------------------- -hir-stats Total 8_644 172 +hir-stats Total 8_676 172 hir-stats diff --git a/tests/ui/stats/macro-stats.rs b/tests/ui/stats/macro-stats.rs new file mode 100644 index 00000000000..ee265d682fd --- /dev/null +++ b/tests/ui/stats/macro-stats.rs @@ -0,0 +1,130 @@ +//@ check-pass +//@ compile-flags: -Zmacro-stats + +#[test] +fn test_foo() { + let what = "this"; + let how = "completely"; + let when = "immediately"; + println!("{what} disappears {how} and {when}"); +} + +#[rustfmt::skip] // non-macro attr, ignored by `-Zmacro-stats` +fn rustfmt_skip() { + // Nothing to see here. +} + +#[derive(Default, Clone, Copy, Hash)] +enum E1 { + #[default] // non-macro attr, ignored by `-Zmacro-stats` + A, + B, +} + +#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] +struct E2 { + a: u32, + b: String, + c: Vec<bool>, +} + +#[derive(Clone)] struct S0; +#[derive(Clone)] struct S1(u32); +#[derive(Clone)] struct S2(u32, u32); +#[derive(Clone)] struct S3(u32, u32, u32); +#[derive(Clone)] struct S4(u32, u32, u32, u32); +#[derive(Clone)] struct S5(u32, u32, u32, u32, u32); + +macro_rules! u32 { + () => { u32 } +} + +macro_rules! none { + () => { None } +} +fn opt(x: Option<u32>) { + match x { + Some(_) => {} + none!() => {} // AstFragmentKind::Pat + } +} + +macro_rules! this_is_a_really_really_long_macro_name { + ($t:ty) => { + fn f(_: $t) {} + } +} +this_is_a_really_really_long_macro_name!(u32!()); // AstFragmentKind::{Items,Ty} + +macro_rules! trait_tys { + () => { + type A; + type B; + } +} +trait Tr { + trait_tys!(); // AstFragmentKind::TraitItems +} + +macro_rules! impl_const { () => { const X: u32 = 0; } } +struct U; +impl U { + impl_const!(); // AstFragmentKind::ImplItems +} + +macro_rules! trait_impl_tys { + () => { + type A = u32; + type B = bool; + } +} +struct Tr1; +impl Tr for Tr1 { + trait_impl_tys!(); // AstFragment::TraitImplItems +} + +macro_rules! foreign_item { + () => { fn fc(a: u32) -> u32; } +} +extern "C" { + foreign_item!(); // AstFragment::ForeignItems +} + +// Include macros are ignored by `-Zmacro-stats`. +mod includes { + mod z1 { + include!("auxiliary/include.rs"); + } + mod z2 { + std::include!("auxiliary/include.rs"); + } + + const B1: &[u8] = include_bytes!("auxiliary/include.rs"); + const B2: &[u8] = std::include_bytes!("auxiliary/include.rs"); + + const S1: &str = include_str!("auxiliary/include.rs"); + const S2: &str = std::include_str!("auxiliary/include.rs"); +} + +fn main() { + macro_rules! n99 { + () => { 99 } + } + let x = n99!() + n99!(); // AstFragmentKind::Expr + + macro_rules! p { + () => { + // blah + let x = 1; + let y = x; + let _ = y; + } + } + p!(); // AstFragmentKind::Stmts + + macro_rules! q { + () => {}; + ($($x:ident),*) => { $( let $x: u32 = 12345; )* }; + } + q!(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z); +} diff --git a/tests/ui/stats/macro-stats.stderr b/tests/ui/stats/macro-stats.stderr new file mode 100644 index 00000000000..f87e34622b9 --- /dev/null +++ b/tests/ui/stats/macro-stats.stderr @@ -0,0 +1,26 @@ +macro-stats =================================================================================== +macro-stats MACRO EXPANSION STATS: macro_stats +macro-stats Macro Name Uses Lines Avg Lines Bytes Avg Bytes +macro-stats ----------------------------------------------------------------------------------- +macro-stats #[derive(Clone)] 8 56 7.0 1_660 207.5 +macro-stats #[derive(PartialOrd)] 1 16 16.0 654 654.0 +macro-stats #[derive(Hash)] 2 15 7.5 547 273.5 +macro-stats #[derive(Ord)] 1 14 14.0 489 489.0 +macro-stats q! 1 24 24.0 435 435.0 +macro-stats #[derive(Default)] 2 14 7.0 367 183.5 +macro-stats #[derive(Eq)] 1 10 10.0 312 312.0 +macro-stats #[derive(Debug)] 1 7 7.0 261 261.0 +macro-stats #[derive(PartialEq)] 1 8 8.0 247 247.0 +macro-stats #[derive(Copy)] 1 1 1.0 46 46.0 +macro-stats p! 1 2 2.0 28 28.0 +macro-stats trait_impl_tys! 1 1 1.0 11 11.0 +macro-stats foreign_item! 1 0 0.0 6 6.0 +macro-stats impl_const! 1 0 0.0 4 4.0 +macro-stats trait_tys! 1 1 1.0 3 3.0 +macro-stats u32! 1 0 0.0 -3 -3.0 +macro-stats none! 1 0 0.0 -3 -3.0 +macro-stats n99! 2 0 0.0 -8 -4.0 +macro-stats this_is_a_really_really_long_macro_name! +macro-stats 1 0 0.0 -30 -30.0 +macro-stats #[test] 1 -6 -6.0 -158 -158.0 +macro-stats =================================================================================== diff --git a/tests/ui/structs-enums/enum-alignment.rs b/tests/ui/structs-enums/enum-alignment.rs index bb779b1e0cd..95f14e521b5 100644 --- a/tests/ui/structs-enums/enum-alignment.rs +++ b/tests/ui/structs-enums/enum-alignment.rs @@ -11,7 +11,7 @@ fn addr_of<T>(ptr: &T) -> usize { fn is_aligned<T>(ptr: &T) -> bool { unsafe { let addr: usize = mem::transmute(ptr); - (addr % mem::min_align_of::<T>()) == 0 + (addr % mem::align_of::<T>()) == 0 } } diff --git a/tests/ui/structs-enums/issue-2718-a.rs b/tests/ui/structs-enums/issue-2718-a.rs index 6c491584540..f799a82447f 100644 --- a/tests/ui/structs-enums/issue-2718-a.rs +++ b/tests/ui/structs-enums/issue-2718-a.rs @@ -3,7 +3,7 @@ pub struct SendPacket<T> { } mod pingpong { - use SendPacket; + use crate::SendPacket; pub type Ping = SendPacket<Pong>; pub struct Pong(SendPacket<Ping>); //~^ ERROR recursive type `Pong` has infinite size diff --git a/tests/ui/structs-enums/namespaced-enum-glob-import.rs b/tests/ui/structs-enums/namespaced-enum-glob-import.rs index e8a709d5bd0..82742a934c4 100644 --- a/tests/ui/structs-enums/namespaced-enum-glob-import.rs +++ b/tests/ui/structs-enums/namespaced-enum-glob-import.rs @@ -14,7 +14,7 @@ mod m2 { } mod m { - pub use m2::Foo::*; + pub use crate::m2::Foo::*; } fn _f(f: m2::Foo) { diff --git a/tests/ui/structs-enums/rec-align-u32.rs b/tests/ui/structs-enums/rec-align-u32.rs index 44879189739..b18cd11198e 100644 --- a/tests/ui/structs-enums/rec-align-u32.rs +++ b/tests/ui/structs-enums/rec-align-u32.rs @@ -34,12 +34,12 @@ pub fn main() { // Send it through the shape code let y = format!("{:?}", x); - println!("align inner = {:?}", intrinsics::min_align_of::<Inner>()); + println!("align inner = {:?}", intrinsics::align_of::<Inner>()); println!("size outer = {:?}", mem::size_of::<Outer>()); println!("y = {:?}", y); // per clang/gcc the alignment of `inner` is 4 on x86. - assert_eq!(intrinsics::min_align_of::<Inner>(), m::align()); + assert_eq!(intrinsics::align_of::<Inner>(), m::align()); // per clang/gcc the size of `outer` should be 12 // because `inner`s alignment was 4. diff --git a/tests/ui/structs-enums/rec-align-u64.rs b/tests/ui/structs-enums/rec-align-u64.rs index 0f7bb6b3505..df219892d73 100644 --- a/tests/ui/structs-enums/rec-align-u64.rs +++ b/tests/ui/structs-enums/rec-align-u64.rs @@ -84,12 +84,12 @@ pub fn main() { let y = format!("{:?}", x); - println!("align inner = {:?}", intrinsics::min_align_of::<Inner>()); + println!("align inner = {:?}", intrinsics::align_of::<Inner>()); println!("size outer = {:?}", mem::size_of::<Outer>()); println!("y = {:?}", y); // per clang/gcc the alignment of `Inner` is 4 on x86. - assert_eq!(intrinsics::min_align_of::<Inner>(), m::m::align()); + assert_eq!(intrinsics::align_of::<Inner>(), m::m::align()); // per clang/gcc the size of `Outer` should be 12 // because `Inner`s alignment was 4. diff --git a/tests/ui/structs-enums/tag-align-dyn-u64.rs b/tests/ui/structs-enums/tag-align-dyn-u64.rs index 5e7d918b4fb..5a4f0878c53 100644 --- a/tests/ui/structs-enums/tag-align-dyn-u64.rs +++ b/tests/ui/structs-enums/tag-align-dyn-u64.rs @@ -19,7 +19,7 @@ fn mk_rec() -> Rec { fn is_u64_aligned(u: &Tag<u64>) -> bool { let p: usize = unsafe { mem::transmute(u) }; - let u64_align = std::mem::min_align_of::<u64>(); + let u64_align = std::mem::align_of::<u64>(); return (p & (u64_align - 1)) == 0; } diff --git a/tests/ui/structs-enums/tag-align-dyn-variants.rs b/tests/ui/structs-enums/tag-align-dyn-variants.rs index c0574f3354e..019f1a82895 100644 --- a/tests/ui/structs-enums/tag-align-dyn-variants.rs +++ b/tests/ui/structs-enums/tag-align-dyn-variants.rs @@ -34,7 +34,7 @@ fn variant_data_is_aligned<A,B>(amnt: usize, u: &Tag<A,B>) -> bool { } pub fn main() { - let u64_align = std::mem::min_align_of::<u64>(); + let u64_align = std::mem::align_of::<u64>(); let x = mk_rec(22u64, 23u64); assert!(is_aligned(u64_align, &x.tA)); assert!(variant_data_is_aligned(u64_align, &x.tA)); diff --git a/tests/ui/structs-enums/tag-align-u64.rs b/tests/ui/structs-enums/tag-align-u64.rs index 8ab9f242822..e274cc0e157 100644 --- a/tests/ui/structs-enums/tag-align-u64.rs +++ b/tests/ui/structs-enums/tag-align-u64.rs @@ -19,7 +19,7 @@ fn mk_rec() -> Rec { fn is_u64_aligned(u: &Tag) -> bool { let p: usize = unsafe { mem::transmute(u) }; - let u64_align = std::mem::min_align_of::<u64>(); + let u64_align = std::mem::align_of::<u64>(); return (p & (u64_align - 1)) == 0; } diff --git a/tests/ui/suggestions/dyn-incompatible-trait-should-use-self.rs b/tests/ui/suggestions/dyn-incompatible-trait-should-use-self.rs index 2893bbc8b71..63fe5ebaea4 100644 --- a/tests/ui/suggestions/dyn-incompatible-trait-should-use-self.rs +++ b/tests/ui/suggestions/dyn-incompatible-trait-should-use-self.rs @@ -1,16 +1,15 @@ -#![allow(bare_trait_objects)] trait A: Sized { - fn f(a: A) -> A; + fn f(a: dyn A) -> dyn A; //~^ ERROR associated item referring to unboxed trait object for its own trait //~| ERROR the trait `A` is not dyn compatible } trait B { - fn f(a: B) -> B; + fn f(a: dyn B) -> dyn B; //~^ ERROR associated item referring to unboxed trait object for its own trait //~| ERROR the trait `B` is not dyn compatible } trait C { - fn f(&self, a: C) -> C; + fn f(&self, a: dyn C) -> dyn C; } fn main() {} diff --git a/tests/ui/suggestions/dyn-incompatible-trait-should-use-self.stderr b/tests/ui/suggestions/dyn-incompatible-trait-should-use-self.stderr index f4b669d7fcd..e8384afed7a 100644 --- a/tests/ui/suggestions/dyn-incompatible-trait-should-use-self.stderr +++ b/tests/ui/suggestions/dyn-incompatible-trait-should-use-self.stderr @@ -1,26 +1,26 @@ error: associated item referring to unboxed trait object for its own trait - --> $DIR/dyn-incompatible-trait-should-use-self.rs:3:13 + --> $DIR/dyn-incompatible-trait-should-use-self.rs:2:13 | LL | trait A: Sized { | - in this trait -LL | fn f(a: A) -> A; - | ^ ^ +LL | fn f(a: dyn A) -> dyn A; + | ^^^^^ ^^^^^ | help: you might have meant to use `Self` to refer to the implementing type | -LL - fn f(a: A) -> A; +LL - fn f(a: dyn A) -> dyn A; LL + fn f(a: Self) -> Self; | error[E0038]: the trait `A` is not dyn compatible - --> $DIR/dyn-incompatible-trait-should-use-self.rs:3:13 + --> $DIR/dyn-incompatible-trait-should-use-self.rs:2:13 | -LL | fn f(a: A) -> A; - | ^ `A` is not dyn compatible +LL | fn f(a: dyn A) -> dyn A; + | ^^^^^ `A` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> - --> $DIR/dyn-incompatible-trait-should-use-self.rs:2:10 + --> $DIR/dyn-incompatible-trait-should-use-self.rs:1:10 | LL | trait A: Sized { | - ^^^^^ ...because it requires `Self: Sized` @@ -28,41 +28,41 @@ LL | trait A: Sized { | this trait is not dyn compatible... error: associated item referring to unboxed trait object for its own trait - --> $DIR/dyn-incompatible-trait-should-use-self.rs:8:13 + --> $DIR/dyn-incompatible-trait-should-use-self.rs:7:13 | LL | trait B { | - in this trait -LL | fn f(a: B) -> B; - | ^ ^ +LL | fn f(a: dyn B) -> dyn B; + | ^^^^^ ^^^^^ | help: you might have meant to use `Self` to refer to the implementing type | -LL - fn f(a: B) -> B; +LL - fn f(a: dyn B) -> dyn B; LL + fn f(a: Self) -> Self; | error[E0038]: the trait `B` is not dyn compatible - --> $DIR/dyn-incompatible-trait-should-use-self.rs:8:13 + --> $DIR/dyn-incompatible-trait-should-use-self.rs:7:13 | -LL | fn f(a: B) -> B; - | ^ `B` is not dyn compatible +LL | fn f(a: dyn B) -> dyn B; + | ^^^^^ `B` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> - --> $DIR/dyn-incompatible-trait-should-use-self.rs:8:8 + --> $DIR/dyn-incompatible-trait-should-use-self.rs:7:8 | LL | trait B { | - this trait is not dyn compatible... -LL | fn f(a: B) -> B; +LL | fn f(a: dyn B) -> dyn B; | ^ ...because associated function `f` has no `self` parameter help: consider turning `f` into a method by giving it a `&self` argument | -LL | fn f(&self, a: B) -> B; +LL | fn f(&self, a: dyn B) -> dyn B; | ++++++ help: alternatively, consider constraining `f` so it does not apply to trait objects | -LL | fn f(a: B) -> B where Self: Sized; - | +++++++++++++++++ +LL | fn f(a: dyn B) -> dyn B where Self: Sized; + | +++++++++++++++++ error: aborting due to 4 previous errors diff --git a/tests/ui/suggestions/ice-unwrap-probe-many-result-125876.rs b/tests/ui/suggestions/ice-unwrap-probe-many-result-125876.rs index efa296db47c..d10b3bec543 100644 --- a/tests/ui/suggestions/ice-unwrap-probe-many-result-125876.rs +++ b/tests/ui/suggestions/ice-unwrap-probe-many-result-125876.rs @@ -1,4 +1,5 @@ // Regression test for ICE #125876 +//@ edition: 2015 fn main() { std::ptr::from_ref(num).cast_mut().as_deref(); diff --git a/tests/ui/suggestions/ice-unwrap-probe-many-result-125876.stderr b/tests/ui/suggestions/ice-unwrap-probe-many-result-125876.stderr index f943688e657..696151b6ee2 100644 --- a/tests/ui/suggestions/ice-unwrap-probe-many-result-125876.stderr +++ b/tests/ui/suggestions/ice-unwrap-probe-many-result-125876.stderr @@ -1,11 +1,11 @@ error[E0425]: cannot find value `num` in this scope - --> $DIR/ice-unwrap-probe-many-result-125876.rs:4:24 + --> $DIR/ice-unwrap-probe-many-result-125876.rs:5:24 | LL | std::ptr::from_ref(num).cast_mut().as_deref(); | ^^^ not found in this scope warning: type annotations needed - --> $DIR/ice-unwrap-probe-many-result-125876.rs:4:29 + --> $DIR/ice-unwrap-probe-many-result-125876.rs:5:29 | LL | std::ptr::from_ref(num).cast_mut().as_deref(); | ^^^^^^^^ @@ -15,7 +15,7 @@ LL | std::ptr::from_ref(num).cast_mut().as_deref(); = note: `#[warn(tyvar_behind_raw_pointer)]` on by default warning: type annotations needed - --> $DIR/ice-unwrap-probe-many-result-125876.rs:4:40 + --> $DIR/ice-unwrap-probe-many-result-125876.rs:5:40 | LL | std::ptr::from_ref(num).cast_mut().as_deref(); | ^^^^^^^^ @@ -24,7 +24,7 @@ LL | std::ptr::from_ref(num).cast_mut().as_deref(); = note: for more information, see issue #46906 <https://github.com/rust-lang/rust/issues/46906> error[E0599]: no method named `as_deref` found for raw pointer `*mut _` in the current scope - --> $DIR/ice-unwrap-probe-many-result-125876.rs:4:40 + --> $DIR/ice-unwrap-probe-many-result-125876.rs:5:40 | LL | std::ptr::from_ref(num).cast_mut().as_deref(); | ^^^^^^^^ diff --git a/tests/ui/suggestions/issue-116434-2015.rs b/tests/ui/suggestions/issue-116434-2015.rs index 1518765152f..bad9d02321c 100644 --- a/tests/ui/suggestions/issue-116434-2015.rs +++ b/tests/ui/suggestions/issue-116434-2015.rs @@ -1,3 +1,5 @@ +//@ edition: 2015 + trait Foo { type Clone; fn foo() -> Clone; diff --git a/tests/ui/suggestions/issue-116434-2015.stderr b/tests/ui/suggestions/issue-116434-2015.stderr index 07a254432a2..a0a99cc560d 100644 --- a/tests/ui/suggestions/issue-116434-2015.stderr +++ b/tests/ui/suggestions/issue-116434-2015.stderr @@ -1,5 +1,5 @@ warning: trait objects without an explicit `dyn` are deprecated - --> $DIR/issue-116434-2015.rs:3:17 + --> $DIR/issue-116434-2015.rs:5:17 | LL | fn foo() -> Clone; | ^^^^^ @@ -13,7 +13,7 @@ LL | fn foo() -> dyn Clone; | +++ warning: trait objects without an explicit `dyn` are deprecated - --> $DIR/issue-116434-2015.rs:3:17 + --> $DIR/issue-116434-2015.rs:5:17 | LL | fn foo() -> Clone; | ^^^^^ @@ -27,7 +27,7 @@ LL | fn foo() -> dyn Clone; | +++ error[E0038]: the trait `Clone` is not dyn compatible - --> $DIR/issue-116434-2015.rs:3:17 + --> $DIR/issue-116434-2015.rs:5:17 | LL | fn foo() -> Clone; | ^^^^^ `Clone` is not dyn compatible @@ -41,7 +41,7 @@ LL | fn foo() -> Self::Clone; | ++++++ warning: trait objects without an explicit `dyn` are deprecated - --> $DIR/issue-116434-2015.rs:18:20 + --> $DIR/issue-116434-2015.rs:20:20 | LL | fn handle() -> DbHandle; | ^^^^^^^^ @@ -54,7 +54,7 @@ LL | fn handle() -> dyn DbHandle; | +++ warning: trait objects without an explicit `dyn` are deprecated - --> $DIR/issue-116434-2015.rs:18:20 + --> $DIR/issue-116434-2015.rs:20:20 | LL | fn handle() -> DbHandle; | ^^^^^^^^ @@ -68,14 +68,14 @@ LL | fn handle() -> dyn DbHandle; | +++ error[E0038]: the trait `DbHandle` is not dyn compatible - --> $DIR/issue-116434-2015.rs:18:20 + --> $DIR/issue-116434-2015.rs:20:20 | LL | fn handle() -> DbHandle; | ^^^^^^^^ `DbHandle` is not dyn compatible | note: for a trait to be dyn compatible it needs to allow building a vtable for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> - --> $DIR/issue-116434-2015.rs:14:17 + --> $DIR/issue-116434-2015.rs:16:17 | LL | trait DbHandle: Sized {} | -------- ^^^^^ ...because it requires `Self: Sized` diff --git a/tests/ui/suggestions/issue-61963.rs b/tests/ui/suggestions/issue-61963.rs index 2fafe629db9..77e4b21f5db 100644 --- a/tests/ui/suggestions/issue-61963.rs +++ b/tests/ui/suggestions/issue-61963.rs @@ -1,3 +1,4 @@ +//@ edition: 2015 //@ proc-macro: issue-61963.rs //@ proc-macro: issue-61963-1.rs #![deny(bare_trait_objects)] diff --git a/tests/ui/suggestions/issue-61963.stderr b/tests/ui/suggestions/issue-61963.stderr index 734c88f3fd6..ef11efe5c74 100644 --- a/tests/ui/suggestions/issue-61963.stderr +++ b/tests/ui/suggestions/issue-61963.stderr @@ -1,5 +1,5 @@ error: trait objects without an explicit `dyn` are deprecated - --> $DIR/issue-61963.rs:22:14 + --> $DIR/issue-61963.rs:23:14 | LL | bar: Box<Bar>, | ^^^ @@ -7,7 +7,7 @@ LL | bar: Box<Bar>, = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html> note: the lint level is defined here - --> $DIR/issue-61963.rs:3:9 + --> $DIR/issue-61963.rs:4:9 | LL | #![deny(bare_trait_objects)] | ^^^^^^^^^^^^^^^^^^ @@ -17,7 +17,7 @@ LL | bar: Box<dyn Bar>, | +++ error: trait objects without an explicit `dyn` are deprecated - --> $DIR/issue-61963.rs:18:1 + --> $DIR/issue-61963.rs:19:1 | LL | pub struct Foo { | ^^^ diff --git a/tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr b/tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr index 41cb2ee46bb..0aa33d3b6fb 100644 --- a/tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr +++ b/tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr @@ -101,15 +101,17 @@ LL + fn bat<'b, 'a, G: 'a + 'b, T>(g: G, dest: &'b mut T) -> impl FnOnce() + 'b error[E0621]: explicit lifetime required in the type of `dest` --> $DIR/missing-lifetimes-in-signature.rs:73:5 | -LL | fn bat<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a - | ------ help: add explicit lifetime `'a` to the type of `dest`: `&'a mut T` -... LL | / move || { LL | | LL | | LL | | *dest = g.get(); LL | | } | |_____^ lifetime `'a` required + | +help: add explicit lifetime `'a` to the type of `dest` + | +LL | fn bat<'a, G: 'a, T>(g: G, dest: &'a mut T) -> impl FnOnce() + '_ + 'a + | ++ error[E0309]: the parameter type `G` may not live long enough --> $DIR/missing-lifetimes-in-signature.rs:85:5 diff --git a/tests/ui/suggestions/missing-lifetime-specifier.rs b/tests/ui/suggestions/missing-lifetime-specifier.rs index a957477897d..88d9736a071 100644 --- a/tests/ui/suggestions/missing-lifetime-specifier.rs +++ b/tests/ui/suggestions/missing-lifetime-specifier.rs @@ -7,7 +7,6 @@ // Different number of duplicated diagnostics on different targets //@ compile-flags: -Zdeduplicate-diagnostics=yes -#![allow(bare_trait_objects)] use std::cell::RefCell; use std::collections::HashMap; @@ -28,7 +27,7 @@ thread_local! { //~^ ERROR missing lifetime specifiers } thread_local! { - static b: RefCell<HashMap<i32, Vec<Vec<&Bar>>>> = RefCell::new(HashMap::new()); + static b: RefCell<HashMap<i32, Vec<Vec<&dyn Bar>>>> = RefCell::new(HashMap::new()); //~^ ERROR missing lifetime specifiers } thread_local! { @@ -36,7 +35,7 @@ thread_local! { //~^ ERROR missing lifetime specifiers } thread_local! { - static d: RefCell<HashMap<i32, Vec<Vec<&Tar<i32>>>>> = RefCell::new(HashMap::new()); + static d: RefCell<HashMap<i32, Vec<Vec<&dyn Tar<i32>>>>> = RefCell::new(HashMap::new()); //~^ ERROR missing lifetime specifiers } @@ -45,8 +44,9 @@ thread_local! { //~^ ERROR union takes 2 lifetime arguments but 1 lifetime argument } thread_local! { - static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new()); - //~^ ERROR trait takes 2 lifetime arguments but 1 lifetime argument was supplied + static f: RefCell<HashMap<i32, Vec<Vec<&dyn Tar<'static, i32>>>>> = + RefCell::new(HashMap::new()); + //~^^ ERROR trait takes 2 lifetime arguments but 1 lifetime argument was supplied //~| ERROR missing lifetime specifier } diff --git a/tests/ui/suggestions/missing-lifetime-specifier.stderr b/tests/ui/suggestions/missing-lifetime-specifier.stderr index 1fdbf3b0c79..b8c58155e63 100644 --- a/tests/ui/suggestions/missing-lifetime-specifier.stderr +++ b/tests/ui/suggestions/missing-lifetime-specifier.stderr @@ -1,5 +1,5 @@ error[E0106]: missing lifetime specifiers - --> $DIR/missing-lifetime-specifier.rs:27:44 + --> $DIR/missing-lifetime-specifier.rs:26:44 | LL | static a: RefCell<HashMap<i32, Vec<Vec<Foo>>>> = RefCell::new(HashMap::new()); | ^^^ expected 2 lifetime parameters @@ -11,21 +11,21 @@ LL | static a: RefCell<HashMap<i32, Vec<Vec<Foo<'static, 'static>>>>> = RefC | ++++++++++++++++++ error[E0106]: missing lifetime specifiers - --> $DIR/missing-lifetime-specifier.rs:31:44 + --> $DIR/missing-lifetime-specifier.rs:30:44 | -LL | static b: RefCell<HashMap<i32, Vec<Vec<&Bar>>>> = RefCell::new(HashMap::new()); - | ^^^^ expected 2 lifetime parameters +LL | static b: RefCell<HashMap<i32, Vec<Vec<&dyn Bar>>>> = RefCell::new(HashMap::new()); + | ^ ^^^ expected 2 lifetime parameters | | | 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 | static b: RefCell<HashMap<i32, Vec<Vec<&'static Bar<'static, 'static>>>>> = RefCell::new(HashMap::new()); - | +++++++ ++++++++++++++++++ +LL | static b: RefCell<HashMap<i32, Vec<Vec<&'static dyn Bar<'static, 'static>>>>> = RefCell::new(HashMap::new()); + | +++++++ ++++++++++++++++++ error[E0106]: missing lifetime specifiers - --> $DIR/missing-lifetime-specifier.rs:35:47 + --> $DIR/missing-lifetime-specifier.rs:34:47 | LL | static c: RefCell<HashMap<i32, Vec<Vec<Qux<i32>>>>> = RefCell::new(HashMap::new()); | ^ expected 2 lifetime parameters @@ -37,33 +37,38 @@ LL | static c: RefCell<HashMap<i32, Vec<Vec<Qux<'static, 'static, i32>>>>> = | +++++++++++++++++ error[E0106]: missing lifetime specifiers - --> $DIR/missing-lifetime-specifier.rs:39:44 + --> $DIR/missing-lifetime-specifier.rs:38:44 | -LL | static d: RefCell<HashMap<i32, Vec<Vec<&Tar<i32>>>>> = RefCell::new(HashMap::new()); - | ^ ^ expected 2 lifetime parameters +LL | static d: RefCell<HashMap<i32, Vec<Vec<&dyn Tar<i32>>>>> = RefCell::new(HashMap::new()); + | ^ ^ expected 2 lifetime parameters | | | 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 | static d: RefCell<HashMap<i32, Vec<Vec<&'static Tar<'static, 'static, i32>>>>> = RefCell::new(HashMap::new()); - | +++++++ +++++++++++++++++ +LL | static d: RefCell<HashMap<i32, Vec<Vec<&'static dyn Tar<'static, 'static, i32>>>>> = RefCell::new(HashMap::new()); + | +++++++ +++++++++++++++++ error[E0106]: missing lifetime specifier - --> $DIR/missing-lifetime-specifier.rs:48:44 + --> $DIR/missing-lifetime-specifier.rs:47:44 | -LL | static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new()); +LL | static f: RefCell<HashMap<i32, Vec<Vec<&dyn Tar<'static, i32>>>>> = | ^ 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 | static f: RefCell<HashMap<i32, Vec<Vec<&'static Tar<'static, i32>>>>> = RefCell::new(HashMap::new()); +LL | static f: RefCell<HashMap<i32, Vec<Vec<&'static dyn Tar<'static, i32>>>>> = | +++++++ +help: instead, you are more likely to want to return an owned value + | +LL - static f: RefCell<HashMap<i32, Vec<Vec<&dyn Tar<'static, i32>>>>> = +LL + static f: RefCell<HashMap<i32, Vec<Vec<dyn Tar<'static, i32>>>>> = + | error[E0107]: union takes 2 lifetime arguments but 1 lifetime argument was supplied - --> $DIR/missing-lifetime-specifier.rs:44:44 + --> $DIR/missing-lifetime-specifier.rs:43:44 | LL | static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, i32>>>>> = RefCell::new(HashMap::new()); | ^^^ ------- supplied 1 lifetime argument @@ -71,7 +76,7 @@ LL | static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, i32>>>>> = RefCell: | expected 2 lifetime arguments | note: union defined here, with 2 lifetime parameters: `'t`, `'k` - --> $DIR/missing-lifetime-specifier.rs:20:11 + --> $DIR/missing-lifetime-specifier.rs:19:11 | LL | pub union Qux<'t, 'k, I> { | ^^^ -- -- @@ -81,22 +86,22 @@ LL | static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, 'static, i32>>>>> = | +++++++++ error[E0107]: trait takes 2 lifetime arguments but 1 lifetime argument was supplied - --> $DIR/missing-lifetime-specifier.rs:48:45 + --> $DIR/missing-lifetime-specifier.rs:47:49 | -LL | static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new()); - | ^^^ ------- supplied 1 lifetime argument - | | - | expected 2 lifetime arguments +LL | static f: RefCell<HashMap<i32, Vec<Vec<&dyn Tar<'static, i32>>>>> = + | ^^^ ------- supplied 1 lifetime argument + | | + | expected 2 lifetime arguments | note: trait defined here, with 2 lifetime parameters: `'t`, `'k` - --> $DIR/missing-lifetime-specifier.rs:24:7 + --> $DIR/missing-lifetime-specifier.rs:23:7 | LL | trait Tar<'t, 'k, I> {} | ^^^ -- -- help: add missing lifetime argument | -LL | static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, 'static, i32>>>>> = RefCell::new(HashMap::new()); - | +++++++++ +LL | static f: RefCell<HashMap<i32, Vec<Vec<&dyn Tar<'static, 'static, i32>>>>> = + | +++++++++ error: aborting due to 7 previous errors diff --git a/tests/ui/symbol-names/impl1.rs b/tests/ui/symbol-names/impl1.rs index 694cd89bd80..0fdf5645479 100644 --- a/tests/ui/symbol-names/impl1.rs +++ b/tests/ui/symbol-names/impl1.rs @@ -26,7 +26,7 @@ mod foo { } mod bar { - use foo::Foo; + use crate::foo::Foo; impl Foo { #[rustc_symbol_name] diff --git a/tests/ui/symbol-names/issue-53912.rs b/tests/ui/symbol-names/issue-53912.rs index 194416cdb70..ba28316b0bf 100644 --- a/tests/ui/symbol-names/issue-53912.rs +++ b/tests/ui/symbol-names/issue-53912.rs @@ -12,13 +12,13 @@ mod llvm { mod foo { pub(crate) struct Foo<T>(T); - impl Foo<::llvm::Foo> { + impl Foo<crate::llvm::Foo> { pub(crate) fn foo() { for _ in 0..0 { - for _ in &[::dummy()] { - ::dummy(); - ::dummy(); - ::dummy(); + for _ in &[crate::dummy()] { + crate::dummy(); + crate::dummy(); + crate::dummy(); } } } diff --git a/tests/ui/symbol-names/issue-60925.rs b/tests/ui/symbol-names/issue-60925.rs index ca0f21b7a78..24969fc6641 100644 --- a/tests/ui/symbol-names/issue-60925.rs +++ b/tests/ui/symbol-names/issue-60925.rs @@ -17,7 +17,7 @@ mod llvm { mod foo { pub(crate) struct Foo<T>(T); - impl Foo<::llvm::Foo> { + impl Foo<crate::llvm::Foo> { #[rustc_symbol_name] //[legacy]~^ ERROR symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo //[legacy]~| ERROR demangling(issue_60925::foo::Foo<issue_60925::llvm::Foo>::foo @@ -27,10 +27,10 @@ mod foo { //[v0]~| ERROR demangling-alt(<issue_60925::foo::Foo<issue_60925::llvm::Foo>>::foo) pub(crate) fn foo() { for _ in 0..0 { - for _ in &[::dummy()] { - ::dummy(); - ::dummy(); - ::dummy(); + for _ in &[crate::dummy()] { + crate::dummy(); + crate::dummy(); + crate::dummy(); } } } diff --git a/tests/ui/target-feature/retpoline-target-feature-flag.by_feature.stderr b/tests/ui/target-feature/retpoline-target-feature-flag.by_feature.stderr new file mode 100644 index 00000000000..e2b6078b7a8 --- /dev/null +++ b/tests/ui/target-feature/retpoline-target-feature-flag.by_feature.stderr @@ -0,0 +1,7 @@ +warning: target feature `retpoline-external-thunk` cannot be enabled with `-Ctarget-feature`: use `x86-retpoline` target modifier flag instead + | + = 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 <https://github.com/rust-lang/rust/issues/116344> + +warning: 1 warning emitted + diff --git a/tests/ui/target-feature/retpoline-target-feature-flag.by_feature1.stderr b/tests/ui/target-feature/retpoline-target-feature-flag.by_feature1.stderr new file mode 100644 index 00000000000..2a0f5f01aef --- /dev/null +++ b/tests/ui/target-feature/retpoline-target-feature-flag.by_feature1.stderr @@ -0,0 +1,7 @@ +warning: target feature `retpoline-external-thunk` cannot be enabled with `-Ctarget-feature`: use `retpoline-external-thunk` target modifier flag instead + | + = 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 <https://github.com/rust-lang/rust/issues/116344> + +warning: 1 warning emitted + diff --git a/tests/ui/target-feature/retpoline-target-feature-flag.by_feature2.stderr b/tests/ui/target-feature/retpoline-target-feature-flag.by_feature2.stderr new file mode 100644 index 00000000000..f7b6cb16447 --- /dev/null +++ b/tests/ui/target-feature/retpoline-target-feature-flag.by_feature2.stderr @@ -0,0 +1,7 @@ +warning: target feature `retpoline-indirect-branches` cannot be enabled with `-Ctarget-feature`: use `retpoline` target modifier flag instead + | + = 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 <https://github.com/rust-lang/rust/issues/116344> + +warning: 1 warning emitted + diff --git a/tests/ui/target-feature/retpoline-target-feature-flag.by_feature3.stderr b/tests/ui/target-feature/retpoline-target-feature-flag.by_feature3.stderr new file mode 100644 index 00000000000..4f2cd1d1a52 --- /dev/null +++ b/tests/ui/target-feature/retpoline-target-feature-flag.by_feature3.stderr @@ -0,0 +1,7 @@ +warning: target feature `retpoline-indirect-calls` cannot be enabled with `-Ctarget-feature`: use `retpoline` target modifier flag instead + | + = 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 <https://github.com/rust-lang/rust/issues/116344> + +warning: 1 warning emitted + diff --git a/tests/ui/target-feature/retpoline-target-feature-flag.rs b/tests/ui/target-feature/retpoline-target-feature-flag.rs new file mode 100644 index 00000000000..3e614a4236c --- /dev/null +++ b/tests/ui/target-feature/retpoline-target-feature-flag.rs @@ -0,0 +1,23 @@ +//@ revisions: by_flag by_feature1 by_feature2 by_feature3 +//@ compile-flags: --target=x86_64-unknown-linux-gnu --crate-type=lib +//@ needs-llvm-components: x86 +//@ [by_flag]compile-flags: -Zretpoline + +//@ [by_feature1]compile-flags: -Ctarget-feature=+retpoline-external-thunk +//@ [by_feature2]compile-flags: -Ctarget-feature=+retpoline-indirect-branches +//@ [by_feature3]compile-flags: -Ctarget-feature=+retpoline-indirect-calls +//@ [by_flag]build-pass +// For now this is just a warning. +//@ [by_feature1]build-pass +//@ [by_feature2]build-pass +//@ [by_feature3]build-pass +#![feature(no_core, lang_items)] +#![no_std] +#![no_core] + +#[lang = "sized"] +pub trait Sized {} + +//[by_feature1]~? WARN target feature `retpoline-external-thunk` cannot be enabled with `-Ctarget-feature`: use `retpoline-external-thunk` target modifier flag instead +//[by_feature2]~? WARN target feature `retpoline-indirect-branches` cannot be enabled with `-Ctarget-feature`: use `retpoline` target modifier flag instead +//[by_feature3]~? WARN target feature `retpoline-indirect-calls` cannot be enabled with `-Ctarget-feature`: use `retpoline` target modifier flag instead diff --git a/tests/ui/threads-sendsync/thread-local-syntax.rs b/tests/ui/threads-sendsync/thread-local-syntax.rs index 2cf91f0c1f7..9492e1c93e2 100644 --- a/tests/ui/threads-sendsync/thread-local-syntax.rs +++ b/tests/ui/threads-sendsync/thread-local-syntax.rs @@ -13,7 +13,7 @@ mod foo { // look at these restrictions!! pub(crate) static BAZ: usize = 0; - pub(in foo) static QUUX: usize = 0; + pub(in crate::foo) static QUUX: usize = 0; } thread_local!(static SPLOK: u32 = 0); } diff --git a/tests/ui/tool-attributes/diagnostic_item.rs b/tests/ui/tool-attributes/diagnostic_item.rs index 26a52ce60cf..806b140feba 100644 --- a/tests/ui/tool-attributes/diagnostic_item.rs +++ b/tests/ui/tool-attributes/diagnostic_item.rs @@ -1,3 +1,5 @@ -#[rustc_diagnostic_item = "foomp"] //~ ERROR compiler internal support for linting +#[rustc_diagnostic_item = "foomp"] +//~^ ERROR use of an internal attribute [E0658] +//~| NOTE the `#[rustc_diagnostic_item]` attribute allows the compiler to reference types from the standard library for diagnostic purposes struct Foomp; fn main() {} diff --git a/tests/ui/tool-attributes/diagnostic_item.stderr b/tests/ui/tool-attributes/diagnostic_item.stderr index c6ae5a38594..d37044281a1 100644 --- a/tests/ui/tool-attributes/diagnostic_item.stderr +++ b/tests/ui/tool-attributes/diagnostic_item.stderr @@ -1,11 +1,11 @@ -error[E0658]: diagnostic items compiler internal support for linting +error[E0658]: use of an internal attribute --> $DIR/diagnostic_item.rs:1:1 | LL | #[rustc_diagnostic_item = "foomp"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: the `#[rustc_diagnostic_item]` attribute allows the compiler to reference types from the standard library for diagnostic purposes error: aborting due to 1 previous error diff --git a/tests/ui/track-diagnostics/track.stderr b/tests/ui/track-diagnostics/track.stderr index d2908bb9177..527c0d1b898 100644 --- a/tests/ui/track-diagnostics/track.stderr +++ b/tests/ui/track-diagnostics/track.stderr @@ -10,7 +10,7 @@ error[E0268]: `break` outside of a loop or labeled block | LL | break rust | ^^^^^^^^^^ cannot `break` outside of a loop or labeled block --Ztrack-diagnostics: created at compiler/rustc_passes/src/loops.rs:LL:CC +-Ztrack-diagnostics: created at compiler/rustc_hir_typeck/src/loops.rs:LL:CC error: internal compiler error: It looks like you're trying to break rust; would you like some ICE? --> $DIR/track.rs:LL:CC diff --git a/tests/ui/trait-bounds/shadowed-path-in-trait-bound-suggestion.fixed b/tests/ui/trait-bounds/shadowed-path-in-trait-bound-suggestion.fixed index e6aac1708ce..6354676bb25 100644 --- a/tests/ui/trait-bounds/shadowed-path-in-trait-bound-suggestion.fixed +++ b/tests/ui/trait-bounds/shadowed-path-in-trait-bound-suggestion.fixed @@ -1,3 +1,4 @@ +//@ edition: 2015 //@ run-rustfix #![allow(non_snake_case)] mod A { diff --git a/tests/ui/trait-bounds/shadowed-path-in-trait-bound-suggestion.rs b/tests/ui/trait-bounds/shadowed-path-in-trait-bound-suggestion.rs index d5c557dc9c7..c3b3a00aa6d 100644 --- a/tests/ui/trait-bounds/shadowed-path-in-trait-bound-suggestion.rs +++ b/tests/ui/trait-bounds/shadowed-path-in-trait-bound-suggestion.rs @@ -1,3 +1,4 @@ +//@ edition: 2015 //@ run-rustfix #![allow(non_snake_case)] mod A { diff --git a/tests/ui/trait-bounds/shadowed-path-in-trait-bound-suggestion.stderr b/tests/ui/trait-bounds/shadowed-path-in-trait-bound-suggestion.stderr index e2a72697501..4fb0dcc7901 100644 --- a/tests/ui/trait-bounds/shadowed-path-in-trait-bound-suggestion.stderr +++ b/tests/ui/trait-bounds/shadowed-path-in-trait-bound-suggestion.stderr @@ -1,5 +1,5 @@ error[E0405]: cannot find trait `Trait` in `A` - --> $DIR/shadowed-path-in-trait-bound-suggestion.rs:9:24 + --> $DIR/shadowed-path-in-trait-bound-suggestion.rs:10:24 | LL | pub struct A<H: A::Trait>(pub H); | ^^^^^ not found in `A` diff --git a/tests/ui/traits/auxiliary/traitimpl.rs b/tests/ui/traits/auxiliary/traitimpl.rs index fda5314cdbf..2544a96048b 100644 --- a/tests/ui/traits/auxiliary/traitimpl.rs +++ b/tests/ui/traits/auxiliary/traitimpl.rs @@ -2,6 +2,6 @@ pub trait Bar<'a> : 'a {} -impl<'a> Bar<'a> { +impl<'a> dyn Bar<'a> { pub fn bar(&self) {} } diff --git a/tests/ui/traits/const-traits/const-trait-impl-parameter-mismatch.rs b/tests/ui/traits/const-traits/const-trait-impl-parameter-mismatch.rs index f90ff91aff4..b563b78f78a 100644 --- a/tests/ui/traits/const-traits/const-trait-impl-parameter-mismatch.rs +++ b/tests/ui/traits/const-traits/const-trait-impl-parameter-mismatch.rs @@ -6,6 +6,7 @@ // Regression test for issue #125877. //@ compile-flags: -Znext-solver +//@ normalize-stderr: "you are using [0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9]+)?( \([^)]*\))?" -> "you are using $$RUSTC_VERSION" #![feature(const_trait_impl, effects)] //~^ ERROR feature has been removed diff --git a/tests/ui/traits/const-traits/const-trait-impl-parameter-mismatch.stderr b/tests/ui/traits/const-traits/const-trait-impl-parameter-mismatch.stderr index d45c4cba1f8..a04f98e68a6 100644 --- a/tests/ui/traits/const-traits/const-trait-impl-parameter-mismatch.stderr +++ b/tests/ui/traits/const-traits/const-trait-impl-parameter-mismatch.stderr @@ -1,13 +1,14 @@ error[E0557]: feature has been removed - --> $DIR/const-trait-impl-parameter-mismatch.rs:10:30 + --> $DIR/const-trait-impl-parameter-mismatch.rs:11:30 | LL | #![feature(const_trait_impl, effects)] | ^^^^^^^ feature has been removed | + = note: removed in 1.84.0 (you are using $RUSTC_VERSION); see <https://github.com/rust-lang/rust/pull/132479> for more information = note: removed, redundant with `#![feature(const_trait_impl)]` error[E0049]: associated function `compute` has 0 type parameters but its trait declaration has 1 type parameter - --> $DIR/const-trait-impl-parameter-mismatch.rs:19:16 + --> $DIR/const-trait-impl-parameter-mismatch.rs:20:16 | LL | fn compute<T: ~const Aux>() -> u32; | - expected 1 type parameter diff --git a/tests/ui/traits/const-traits/inherent-impl.rs b/tests/ui/traits/const-traits/inherent-impl.rs index afd0d137bb4..07b23adf9e1 100644 --- a/tests/ui/traits/const-traits/inherent-impl.rs +++ b/tests/ui/traits/const-traits/inherent-impl.rs @@ -7,7 +7,7 @@ trait T {} impl const S {} //~^ ERROR inherent impls cannot be `const` -impl const T {} +impl const dyn T {} //~^ ERROR inherent impls cannot be `const` fn main() {} diff --git a/tests/ui/traits/const-traits/inherent-impl.stderr b/tests/ui/traits/const-traits/inherent-impl.stderr index 8c55627031d..e4ec1e807b0 100644 --- a/tests/ui/traits/const-traits/inherent-impl.stderr +++ b/tests/ui/traits/const-traits/inherent-impl.stderr @@ -11,8 +11,8 @@ LL | impl const S {} error: inherent impls cannot be `const` --> $DIR/inherent-impl.rs:10:12 | -LL | impl const T {} - | ----- ^ inherent impl for this type +LL | impl const dyn T {} + | ----- ^^^^^ inherent impl for this type | | | `const` because of this | diff --git a/tests/ui/traits/const-traits/mbe-dyn-const-2015.rs b/tests/ui/traits/const-traits/mbe-dyn-const-2015.rs index 9d65a2ac302..fadfbe66788 100644 --- a/tests/ui/traits/const-traits/mbe-dyn-const-2015.rs +++ b/tests/ui/traits/const-traits/mbe-dyn-const-2015.rs @@ -1,6 +1,7 @@ // Ensure that the introduction of const trait bound didn't regress this code in Rust 2015. // See also `mbe-const-trait-bound-theoretical-regression.rs`. +//@ edition: 2015 //@ check-pass macro_rules! check { diff --git a/tests/ui/traits/default-method/rustc_must_implement_one_of_gated.rs b/tests/ui/traits/default-method/rustc_must_implement_one_of_gated.rs index 27e70556b7a..47cc9f5f960 100644 --- a/tests/ui/traits/default-method/rustc_must_implement_one_of_gated.rs +++ b/tests/ui/traits/default-method/rustc_must_implement_one_of_gated.rs @@ -1,5 +1,7 @@ #[rustc_must_implement_one_of(eq, neq)] -//~^ ERROR the `#[rustc_must_implement_one_of]` attribute is used to change minimal complete definition of a trait, it's currently in experimental form and should be changed before being exposed outside of the std +//~^ ERROR use of an internal attribute [E0658] +//~| NOTE the `#[rustc_must_implement_one_of]` attribute is an internal implementation detail that will never be stable +//~| NOTE the `#[rustc_must_implement_one_of]` attribute is used to change minimal complete definition of a trait. Its syntax and semantics are highly experimental and will be subject to change before stabilization trait Equal { fn eq(&self, other: &Self) -> bool { !self.neq(other) diff --git a/tests/ui/traits/default-method/rustc_must_implement_one_of_gated.stderr b/tests/ui/traits/default-method/rustc_must_implement_one_of_gated.stderr index 162c3d36cb1..4d44ceff98a 100644 --- a/tests/ui/traits/default-method/rustc_must_implement_one_of_gated.stderr +++ b/tests/ui/traits/default-method/rustc_must_implement_one_of_gated.stderr @@ -1,11 +1,12 @@ -error[E0658]: the `#[rustc_must_implement_one_of]` attribute is used to change minimal complete definition of a trait, it's currently in experimental form and should be changed before being exposed outside of the std +error[E0658]: use of an internal attribute --> $DIR/rustc_must_implement_one_of_gated.rs:1:1 | LL | #[rustc_must_implement_one_of(eq, neq)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: the `#[rustc_must_implement_one_of]` attribute is an internal implementation detail that will never be stable + = note: the `#[rustc_must_implement_one_of]` attribute is used to change minimal complete definition of a trait. Its syntax and semantics are highly experimental and will be subject to change before stabilization error: aborting due to 1 previous error diff --git a/tests/ui/traits/impl-2.rs b/tests/ui/traits/impl-2.rs index c6f60a9081c..41fa1cd334f 100644 --- a/tests/ui/traits/impl-2.rs +++ b/tests/ui/traits/impl-2.rs @@ -10,7 +10,7 @@ pub mod Foo { } mod Bar { - impl<'a> dyn (::Foo::Trait) + 'a { + impl<'a> dyn (crate::Foo::Trait) + 'a { fn bar(&self) { self.foo() } } } diff --git a/tests/ui/traits/item-privacy.rs b/tests/ui/traits/item-privacy.rs index 9f75e6e4c12..b8724399e32 100644 --- a/tests/ui/traits/item-privacy.rs +++ b/tests/ui/traits/item-privacy.rs @@ -15,9 +15,9 @@ mod method { fn c(&self) { } } - impl A for ::S {} - impl B for ::S {} - impl C for ::S {} + impl A for crate::S {} + impl B for crate::S {} + impl C for crate::S {} } mod assoc_const { @@ -33,9 +33,9 @@ mod assoc_const { const C: u8 = 0; } - impl A for ::S {} - impl B for ::S {} - impl C for ::S {} + impl A for crate::S {} + impl B for crate::S {} + impl C for crate::S {} } mod assoc_ty { @@ -51,9 +51,9 @@ mod assoc_ty { type C = u8; } - impl A for ::S {} - impl B for ::S {} - impl C for ::S {} + impl A for crate::S {} + impl B for crate::S {} + impl C for crate::S {} } fn check_method() { diff --git a/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-bound.rs b/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-bound.rs index ea6df938704..14f0cbcc8b7 100644 --- a/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-bound.rs +++ b/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-bound.rs @@ -13,9 +13,9 @@ fn main() { } fn weird0() -> impl Sized + !Sized {} -//~^ ERROR type mismatch resolving +//~^ ERROR the trait bound `(): !Sized` is not satisfied fn weird1() -> impl !Sized + Sized {} -//~^ ERROR type mismatch resolving +//~^ ERROR the trait bound `(): !Sized` is not satisfied fn weird2() -> impl !Sized {} -//~^ ERROR type mismatch resolving +//~^ ERROR the trait bound `(): !Sized` is not satisfied //~| ERROR the size for values of type diff --git a/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-bound.stderr b/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-bound.stderr index 41d9e74f807..3ba3d8d8bd5 100644 --- a/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-bound.stderr +++ b/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-bound.stderr @@ -7,23 +7,23 @@ LL | fn weird2() -> impl !Sized {} = help: the trait `Sized` is not implemented for `impl !Sized` = note: the return type of a function must have a statically known size -error[E0271]: type mismatch resolving `impl !Sized + Sized == ()` +error[E0277]: the trait bound `(): !Sized` is not satisfied --> $DIR/opaque-type-unsatisfied-bound.rs:15:16 | LL | fn weird0() -> impl Sized + !Sized {} - | ^^^^^^^^^^^^^^^^^^^ types differ + | ^^^^^^^^^^^^^^^^^^^ the trait bound `(): !Sized` is not satisfied -error[E0271]: type mismatch resolving `impl !Sized + Sized == ()` +error[E0277]: the trait bound `(): !Sized` is not satisfied --> $DIR/opaque-type-unsatisfied-bound.rs:17:16 | LL | fn weird1() -> impl !Sized + Sized {} - | ^^^^^^^^^^^^^^^^^^^ types differ + | ^^^^^^^^^^^^^^^^^^^ the trait bound `(): !Sized` is not satisfied -error[E0271]: type mismatch resolving `impl !Sized == ()` +error[E0277]: the trait bound `(): !Sized` is not satisfied --> $DIR/opaque-type-unsatisfied-bound.rs:19:16 | LL | fn weird2() -> impl !Sized {} - | ^^^^^^^^^^^ types differ + | ^^^^^^^^^^^ the trait bound `(): !Sized` is not satisfied error[E0277]: the trait bound `impl !Trait: Trait` is not satisfied --> $DIR/opaque-type-unsatisfied-bound.rs:12:13 @@ -41,5 +41,4 @@ LL | fn consume(_: impl Trait) {} error: aborting due to 5 previous errors -Some errors have detailed explanations: E0271, E0277. -For more information about an error, try `rustc --explain E0271`. +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-fn-bound.rs b/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-fn-bound.rs index ce42bce0ad4..39422914afc 100644 --- a/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-fn-bound.rs +++ b/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-fn-bound.rs @@ -3,6 +3,6 @@ #![feature(negative_bounds, unboxed_closures)] fn produce() -> impl !Fn<(u32,)> {} -//~^ ERROR type mismatch resolving +//~^ ERROR the trait bound `(): !Fn(u32)` is not satisfied fn main() {} diff --git a/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-fn-bound.stderr b/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-fn-bound.stderr index e1b84e0df7a..760e5aa62f2 100644 --- a/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-fn-bound.stderr +++ b/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-fn-bound.stderr @@ -1,9 +1,9 @@ -error[E0271]: type mismatch resolving `impl !Fn<(u32,)> == ()` +error[E0277]: the trait bound `(): !Fn(u32)` is not satisfied --> $DIR/opaque-type-unsatisfied-fn-bound.rs:5:17 | LL | fn produce() -> impl !Fn<(u32,)> {} - | ^^^^^^^^^^^^^^^^ types differ + | ^^^^^^^^^^^^^^^^ the trait bound `(): !Fn(u32)` is not satisfied error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0271`. +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/next-solver/opaques/dont-type_of-tait-in-defining-scope.is_send.stderr b/tests/ui/traits/next-solver/opaques/dont-type_of-tait-in-defining-scope.is_send.stderr index 736c8c10da9..6d2bbd8b08b 100644 --- a/tests/ui/traits/next-solver/opaques/dont-type_of-tait-in-defining-scope.is_send.stderr +++ b/tests/ui/traits/next-solver/opaques/dont-type_of-tait-in-defining-scope.is_send.stderr @@ -1,9 +1,16 @@ -error[E0284]: type annotations needed: cannot satisfy `Foo == _` +error[E0283]: type annotations needed: cannot satisfy `Foo: Send` --> $DIR/dont-type_of-tait-in-defining-scope.rs:16:18 | LL | needs_send::<Foo>(); - | ^^^ cannot satisfy `Foo == _` + | ^^^ + | + = note: cannot satisfy `Foo: Send` +note: required by a bound in `needs_send` + --> $DIR/dont-type_of-tait-in-defining-scope.rs:12:18 + | +LL | fn needs_send<T: Send>() {} + | ^^^^ required by this bound in `needs_send` error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0284`. +For more information about this error, try `rustc --explain E0283`. diff --git a/tests/ui/traits/next-solver/opaques/dont-type_of-tait-in-defining-scope.not_send.stderr b/tests/ui/traits/next-solver/opaques/dont-type_of-tait-in-defining-scope.not_send.stderr index 736c8c10da9..6d2bbd8b08b 100644 --- a/tests/ui/traits/next-solver/opaques/dont-type_of-tait-in-defining-scope.not_send.stderr +++ b/tests/ui/traits/next-solver/opaques/dont-type_of-tait-in-defining-scope.not_send.stderr @@ -1,9 +1,16 @@ -error[E0284]: type annotations needed: cannot satisfy `Foo == _` +error[E0283]: type annotations needed: cannot satisfy `Foo: Send` --> $DIR/dont-type_of-tait-in-defining-scope.rs:16:18 | LL | needs_send::<Foo>(); - | ^^^ cannot satisfy `Foo == _` + | ^^^ + | + = note: cannot satisfy `Foo: Send` +note: required by a bound in `needs_send` + --> $DIR/dont-type_of-tait-in-defining-scope.rs:12:18 + | +LL | fn needs_send<T: Send>() {} + | ^^^^ required by this bound in `needs_send` error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0284`. +For more information about this error, try `rustc --explain E0283`. diff --git a/tests/ui/traits/next-solver/opaques/dont-type_of-tait-in-defining-scope.rs b/tests/ui/traits/next-solver/opaques/dont-type_of-tait-in-defining-scope.rs index 2a08a3b2b94..fddf892e1ef 100644 --- a/tests/ui/traits/next-solver/opaques/dont-type_of-tait-in-defining-scope.rs +++ b/tests/ui/traits/next-solver/opaques/dont-type_of-tait-in-defining-scope.rs @@ -14,7 +14,7 @@ fn needs_send<T: Send>() {} #[define_opaque(Foo)] fn test(_: Foo) { needs_send::<Foo>(); - //~^ ERROR type annotations needed: cannot satisfy `Foo == _` + //~^ ERROR type annotations needed } #[define_opaque(Foo)] diff --git a/tests/ui/traits/static-method-overwriting.rs b/tests/ui/traits/static-method-overwriting.rs index 7a2a51a4b99..28edcde4c49 100644 --- a/tests/ui/traits/static-method-overwriting.rs +++ b/tests/ui/traits/static-method-overwriting.rs @@ -9,7 +9,7 @@ mod base { dummy: (), } - impl ::base::HasNew for Foo { + impl crate::base::HasNew for Foo { fn new() -> Foo { println!("Foo"); Foo { dummy: () } @@ -20,7 +20,7 @@ mod base { dummy: (), } - impl ::base::HasNew for Bar { + impl crate::base::HasNew for Bar { fn new() -> Bar { println!("Bar"); Bar { dummy: () } diff --git a/tests/ui/transmutability/references/reject_extension.stderr b/tests/ui/transmutability/references/reject_extension.stderr index 182106acf12..a5f67785094 100644 --- a/tests/ui/transmutability/references/reject_extension.stderr +++ b/tests/ui/transmutability/references/reject_extension.stderr @@ -2,7 +2,7 @@ error[E0277]: `&Packed<Two>` cannot be safely transmuted into `&Packed<Four>` --> $DIR/reject_extension.rs:48:37 | LL | assert::is_transmutable::<&Src, &Dst>(); - | ^^^^ the referent size of `&Packed<Two>` (2 bytes) is smaller than that of `&Packed<Four>` (4 bytes) + | ^^^^ the size of `Packed<Two>` (2 bytes) is smaller than that of `Packed<Four>` (4 bytes) | note: required by a bound in `is_transmutable` --> $DIR/reject_extension.rs:13:14 diff --git a/tests/ui/transmutability/references/unit-to-u8.stderr b/tests/ui/transmutability/references/unit-to-u8.stderr index bc9f286e097..35d1179f451 100644 --- a/tests/ui/transmutability/references/unit-to-u8.stderr +++ b/tests/ui/transmutability/references/unit-to-u8.stderr @@ -2,7 +2,7 @@ error[E0277]: `&Unit` cannot be safely transmuted into `&u8` --> $DIR/unit-to-u8.rs:22:52 | LL | assert::is_maybe_transmutable::<&'static Unit, &'static u8>(); - | ^^^^^^^^^^^ the referent size of `&Unit` (0 bytes) is smaller than that of `&u8` (1 bytes) + | ^^^^^^^^^^^ the size of `Unit` (0 bytes) is smaller than that of `u8` (1 bytes) | note: required by a bound in `is_maybe_transmutable` --> $DIR/unit-to-u8.rs:9:14 diff --git a/tests/ui/transmutability/references/unsafecell.rs b/tests/ui/transmutability/references/unsafecell.rs index 4001f139770..b0db4af45f5 100644 --- a/tests/ui/transmutability/references/unsafecell.rs +++ b/tests/ui/transmutability/references/unsafecell.rs @@ -38,10 +38,10 @@ fn mut_to_mut() { } fn mut_to_ref() { - // We don't care about `UnsafeCell` for transmutations in the form `&mut T - // -> &U`, because downgrading a `&mut T` to a `&U` deactivates `&mut T` for - // the lifetime of `&U`. - assert::is_maybe_transmutable::<&'static mut u8, &'static UnsafeCell<u8>>(); - assert::is_maybe_transmutable::<&'static mut UnsafeCell<u8>, &'static u8>(); - assert::is_maybe_transmutable::<&'static mut UnsafeCell<u8>, &'static UnsafeCell<u8>>(); + // `&mut UnsafeCell` is irrelevant in the source. + assert::is_maybe_transmutable::<&'static mut UnsafeCell<bool>, &'static u8>(); + // `&UnsafeCell` in forbidden in the destination, since the destination can be used to + // invalidate a shadowed source reference. + assert::is_maybe_transmutable::<&'static mut bool, &'static UnsafeCell<u8>>(); //~ ERROR: cannot be safely transmuted + assert::is_maybe_transmutable::<&'static mut UnsafeCell<bool>, &'static UnsafeCell<u8>>(); //~ ERROR: cannot be safely transmuted } diff --git a/tests/ui/transmutability/references/unsafecell.stderr b/tests/ui/transmutability/references/unsafecell.stderr index 6664d8a7d6f..02a0935e84e 100644 --- a/tests/ui/transmutability/references/unsafecell.stderr +++ b/tests/ui/transmutability/references/unsafecell.stderr @@ -28,6 +28,36 @@ LL | where LL | Dst: TransmuteFrom<Src, { Assume::SAFETY }> | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` -error: aborting due to 2 previous errors +error[E0277]: `&mut bool` cannot be safely transmuted into `&UnsafeCell<u8>` + --> $DIR/unsafecell.rs:45:56 + | +LL | assert::is_maybe_transmutable::<&'static mut bool, &'static UnsafeCell<u8>>(); + | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Freeze` is not implemented for `UnsafeCell<u8>` + | +note: required by a bound in `is_maybe_transmutable` + --> $DIR/unsafecell.rs:12:14 + | +LL | pub fn is_maybe_transmutable<Src, Dst>() + | --------------------- required by a bound in this function +LL | where +LL | Dst: TransmuteFrom<Src, { Assume::SAFETY }> + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` + +error[E0277]: `&mut UnsafeCell<bool>` cannot be safely transmuted into `&UnsafeCell<u8>` + --> $DIR/unsafecell.rs:46:68 + | +LL | assert::is_maybe_transmutable::<&'static mut UnsafeCell<bool>, &'static UnsafeCell<u8>>(); + | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Freeze` is not implemented for `UnsafeCell<u8>` + | +note: required by a bound in `is_maybe_transmutable` + --> $DIR/unsafecell.rs:12:14 + | +LL | pub fn is_maybe_transmutable<Src, Dst>() + | --------------------- required by a bound in this function +LL | where +LL | Dst: TransmuteFrom<Src, { Assume::SAFETY }> + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/tuple/tuple-struct-fields/test.rs b/tests/ui/tuple/tuple-struct-fields/test.rs index 00677090d78..29aabf4579b 100644 --- a/tests/ui/tuple/tuple-struct-fields/test.rs +++ b/tests/ui/tuple/tuple-struct-fields/test.rs @@ -1,6 +1,6 @@ mod foo { type T = (); - struct S1(pub(in foo) (), pub(T), pub(crate) (), pub(((), T))); + struct S1(pub(in crate::foo) (), pub(T), pub(crate) (), pub(((), T))); struct S2(pub((foo)) ()); //~^ ERROR expected one of `)` or `,`, found `(` //~| ERROR cannot find type `foo` in this scope diff --git a/tests/ui/tuple/tuple-struct-fields/test2.rs b/tests/ui/tuple/tuple-struct-fields/test2.rs index 2b2a2c127e9..544d486752c 100644 --- a/tests/ui/tuple/tuple-struct-fields/test2.rs +++ b/tests/ui/tuple/tuple-struct-fields/test2.rs @@ -1,7 +1,7 @@ macro_rules! define_struct { ($t:ty) => { struct S1(pub $t); - struct S2(pub (in foo) ()); + struct S2(pub (in crate::foo) ()); struct S3(pub $t ()); //~^ ERROR expected one of `)` or `,`, found `(` } diff --git a/tests/ui/tuple/tuple-struct-fields/test3.rs b/tests/ui/tuple/tuple-struct-fields/test3.rs index 98d19426e77..b5f98a65fa6 100644 --- a/tests/ui/tuple/tuple-struct-fields/test3.rs +++ b/tests/ui/tuple/tuple-struct-fields/test3.rs @@ -1,7 +1,7 @@ macro_rules! define_struct { ($t:ty) => { struct S1(pub($t)); - struct S2(pub (in foo) ()); + struct S2(pub (in crate::foo) ()); struct S3(pub($t) ()); //~^ ERROR expected one of `)` or `,`, found `(` } diff --git a/tests/ui/type-alias-impl-trait/issue-84660-unsoundness.next.stderr b/tests/ui/type-alias-impl-trait/issue-84660-unsoundness.next.stderr index 9e83de5375f..f7e0245bc83 100644 --- a/tests/ui/type-alias-impl-trait/issue-84660-unsoundness.next.stderr +++ b/tests/ui/type-alias-impl-trait/issue-84660-unsoundness.next.stderr @@ -7,7 +7,7 @@ LL | impl<In, Out> Trait<Bar, In> for Out { LL | impl<In, Out> Trait<(), In> for Out { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation -error[E0284]: type annotations needed: cannot satisfy `Bar == _` +error[E0282]: type annotations needed --> $DIR/issue-84660-unsoundness.rs:24:37 | LL | fn convert(_i: In) -> Self::Out { @@ -16,9 +16,9 @@ LL | | LL | | LL | | unreachable!(); LL | | } - | |_____^ cannot satisfy `Bar == _` + | |_____^ cannot infer type error: aborting due to 2 previous errors -Some errors have detailed explanations: E0119, E0284. +Some errors have detailed explanations: E0119, E0282. For more information about an error, try `rustc --explain E0119`. diff --git a/tests/ui/type-alias-impl-trait/issue-84660-unsoundness.rs b/tests/ui/type-alias-impl-trait/issue-84660-unsoundness.rs index 7a540d2a574..a385138b295 100644 --- a/tests/ui/type-alias-impl-trait/issue-84660-unsoundness.rs +++ b/tests/ui/type-alias-impl-trait/issue-84660-unsoundness.rs @@ -22,7 +22,7 @@ impl<In, Out> Trait<Bar, In> for Out { type Out = Out; #[define_opaque(Bar)] fn convert(_i: In) -> Self::Out { - //[next]~^ ERROR: type annotations needed: cannot satisfy `Bar == _` + //[next]~^ ERROR: type annotations needed //[current]~^^ ERROR: item does not constrain `Bar::{opaque#0}` unreachable!(); } diff --git a/tests/ui/type-alias-impl-trait/nested-tait-inference2.next.stderr b/tests/ui/type-alias-impl-trait/nested-tait-inference2.next.stderr index b733739e4c8..d2127976e7d 100644 --- a/tests/ui/type-alias-impl-trait/nested-tait-inference2.next.stderr +++ b/tests/ui/type-alias-impl-trait/nested-tait-inference2.next.stderr @@ -1,9 +1,9 @@ -error[E0284]: type annotations needed: cannot satisfy `impl Foo<FooX> == ()` +error[E0282]: type annotations needed --> $DIR/nested-tait-inference2.rs:20:5 | LL | () - | ^^ cannot satisfy `impl Foo<FooX> == ()` + | ^^ cannot infer type error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0284`. +For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/type-alias-impl-trait/nested-tait-inference2.rs b/tests/ui/type-alias-impl-trait/nested-tait-inference2.rs index 4aeecb9140c..606336178e5 100644 --- a/tests/ui/type-alias-impl-trait/nested-tait-inference2.rs +++ b/tests/ui/type-alias-impl-trait/nested-tait-inference2.rs @@ -18,7 +18,7 @@ impl Foo<u32> for () {} fn foo() -> impl Foo<FooX> { //[current]~^ ERROR: the trait bound `(): Foo<FooX>` is not satisfied () - //[next]~^ ERROR: cannot satisfy `impl Foo<FooX> == ()` + //[next]~^ ERROR: type annotations needed } fn main() {} diff --git a/tests/ui/type/auxiliary/crate_a1.rs b/tests/ui/type/auxiliary/crate_a1.rs index 616493193fd..f8ee9ae15c1 100644 --- a/tests/ui/type/auxiliary/crate_a1.rs +++ b/tests/ui/type/auxiliary/crate_a1.rs @@ -2,10 +2,10 @@ pub struct Foo; pub trait Bar {} -pub fn bar() -> Box<Bar> { +pub fn bar() -> Box<dyn Bar> { unimplemented!() } pub fn try_foo(x: Foo){} -pub fn try_bar(x: Box<Bar>){} +pub fn try_bar(x: Box<dyn Bar>){} diff --git a/tests/ui/type/auxiliary/crate_a2.rs b/tests/ui/type/auxiliary/crate_a2.rs index 57a7685b77c..fe22598e63e 100644 --- a/tests/ui/type/auxiliary/crate_a2.rs +++ b/tests/ui/type/auxiliary/crate_a2.rs @@ -2,6 +2,6 @@ pub struct Foo; pub trait Bar {} -pub fn bar() -> Box<Bar> { +pub fn bar() -> Box<dyn Bar> { unimplemented!() } diff --git a/tests/ui/type/issue-7607-2.rs b/tests/ui/type/issue-7607-2.rs index ebc4fe1c2d3..53fafdf9489 100644 --- a/tests/ui/type/issue-7607-2.rs +++ b/tests/ui/type/issue-7607-2.rs @@ -6,7 +6,7 @@ pub mod a { } pub mod b { - use a::Foo; + use crate::a::Foo; impl Foo { fn bar(&self) { } } diff --git a/tests/ui/type/pattern_types/matching.rs b/tests/ui/type/pattern_types/matching.rs index b8463a8e822..21f89b3b673 100644 --- a/tests/ui/type/pattern_types/matching.rs +++ b/tests/ui/type/pattern_types/matching.rs @@ -1,6 +1,7 @@ #![feature(pattern_types, pattern_type_macro, structural_match)] //@ check-pass +//@ compile-flags: -Zvalidate-mir use std::marker::StructuralPartialEq; use std::pat::pattern_type; diff --git a/tests/ui/type/type-mismatch-same-crate-name.stderr b/tests/ui/type/type-mismatch-same-crate-name.stderr index 7b791549f56..8fafbfaa934 100644 --- a/tests/ui/type/type-mismatch-same-crate-name.stderr +++ b/tests/ui/type/type-mismatch-same-crate-name.stderr @@ -59,7 +59,7 @@ LL | extern crate crate_a1 as a; note: function defined here --> $DIR/auxiliary/crate_a1.rs:11:8 | -LL | pub fn try_bar(x: Box<Bar>){} +LL | pub fn try_bar(x: Box<dyn Bar>){} | ^^^^^^^ error: aborting due to 2 previous errors diff --git a/tests/ui/typeck/issue-114529-illegal-break-with-value.stderr b/tests/ui/typeck/issue-114529-illegal-break-with-value.stderr index de993df722c..872c506c7f1 100644 --- a/tests/ui/typeck/issue-114529-illegal-break-with-value.stderr +++ b/tests/ui/typeck/issue-114529-illegal-break-with-value.stderr @@ -1,4 +1,22 @@ error[E0571]: `break` with value from a `while` loop + --> $DIR/issue-114529-illegal-break-with-value.rs:22:9 + | +LL | while true { + | ---------- you can't `break` with a value in a `while` loop +LL | / break (|| { +LL | | let local = 9; +LL | | }); + | |__________^ can only break with a value inside `loop` or breakable block + | +help: use `break` on its own without a value inside this `while` loop + | +LL - break (|| { +LL - let local = 9; +LL - }); +LL + break; + | + +error[E0571]: `break` with value from a `while` loop --> $DIR/issue-114529-illegal-break-with-value.rs:9:13 | LL | while true { @@ -26,24 +44,6 @@ LL - break v; LL + break; | -error[E0571]: `break` with value from a `while` loop - --> $DIR/issue-114529-illegal-break-with-value.rs:22:9 - | -LL | while true { - | ---------- you can't `break` with a value in a `while` loop -LL | / break (|| { -LL | | let local = 9; -LL | | }); - | |__________^ can only break with a value inside `loop` or breakable block - | -help: use `break` on its own without a value inside this `while` loop - | -LL - break (|| { -LL - let local = 9; -LL - }); -LL + break; - | - error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0571`. diff --git a/tests/ui/underscore-imports/basic.rs b/tests/ui/underscore-imports/basic.rs index 624ecb47ca6..8d8ff5c47bc 100644 --- a/tests/ui/underscore-imports/basic.rs +++ b/tests/ui/underscore-imports/basic.rs @@ -18,25 +18,25 @@ mod m { fn tr2_is_in_scope(&self) {} } - impl Tr1 for ::S {} - impl Tr2 for ::S {} + impl Tr1 for crate::S {} + impl Tr2 for crate::S {} } mod unused { - use m::Tr1 as _; //~ WARN unused import - use S as _; //~ WARN unused import + use crate::m::Tr1 as _; //~ WARN unused import + use crate::S as _; //~ WARN unused import extern crate core as _; // OK } mod outer { mod middle { - pub use m::Tr1 as _; - pub use m::Tr2 as _; // OK, no name conflict + pub use crate::m::Tr1 as _; + pub use crate::m::Tr2 as _; // OK, no name conflict struct Tr1; // OK, no name conflict fn check() { // Both traits are in scope - ::S.tr1_is_in_scope(); - ::S.tr2_is_in_scope(); + crate::S.tr1_is_in_scope(); + crate::S.tr2_is_in_scope(); } mod inner { @@ -44,8 +44,8 @@ mod outer { use super::*; fn check() { // Both traits are in scope - ::S.tr1_is_in_scope(); - ::S.tr2_is_in_scope(); + crate::S.tr1_is_in_scope(); + crate::S.tr2_is_in_scope(); } } } @@ -54,8 +54,8 @@ mod outer { use self::middle::*; fn check() { // Both traits are in scope - ::S.tr1_is_in_scope(); - ::S.tr2_is_in_scope(); + crate::S.tr1_is_in_scope(); + crate::S.tr2_is_in_scope(); } } diff --git a/tests/ui/underscore-imports/basic.stderr b/tests/ui/underscore-imports/basic.stderr index c51493562eb..666d07349df 100644 --- a/tests/ui/underscore-imports/basic.stderr +++ b/tests/ui/underscore-imports/basic.stderr @@ -1,8 +1,8 @@ -warning: unused import: `m::Tr1 as _` +warning: unused import: `crate::m::Tr1 as _` --> $DIR/basic.rs:26:9 | -LL | use m::Tr1 as _; - | ^^^^^^^^^^^ +LL | use crate::m::Tr1 as _; + | ^^^^^^^^^^^^^^^^^^ | note: the lint level is defined here --> $DIR/basic.rs:4:9 @@ -10,11 +10,11 @@ note: the lint level is defined here LL | #![warn(unused_imports, unused_extern_crates)] | ^^^^^^^^^^^^^^ -warning: unused import: `S as _` +warning: unused import: `crate::S as _` --> $DIR/basic.rs:27:9 | -LL | use S as _; - | ^^^^^^ +LL | use crate::S as _; + | ^^^^^^^^^^^^^ warning: 2 warnings emitted diff --git a/tests/ui/unpretty/exhaustive.expanded.stdout b/tests/ui/unpretty/exhaustive.expanded.stdout index 9712ba58e62..cd1a5d0af08 100644 --- a/tests/ui/unpretty/exhaustive.expanded.stdout +++ b/tests/ui/unpretty/exhaustive.expanded.stdout @@ -190,7 +190,7 @@ mod expressions { (static async || value); (static async move || value); || -> u8 { value }; - 1 + (|| {}); + 1 + || {}; } /// ExprKind::Block diff --git a/tests/ui/unresolved/unresolved-import-recovery.rs b/tests/ui/unresolved/unresolved-import-recovery.rs index 0b0653378cb..8657bb661a8 100644 --- a/tests/ui/unresolved/unresolved-import-recovery.rs +++ b/tests/ui/unresolved/unresolved-import-recovery.rs @@ -1,7 +1,7 @@ // Check that unresolved imports do not create additional errors and ICEs mod m { - pub use unresolved; //~ ERROR unresolved import `unresolved` + pub use crate::unresolved; //~ ERROR unresolved import `crate::unresolved` fn f() { let unresolved = 0; // OK diff --git a/tests/ui/unresolved/unresolved-import-recovery.stderr b/tests/ui/unresolved/unresolved-import-recovery.stderr index 1c006049756..ec41c9e79d7 100644 --- a/tests/ui/unresolved/unresolved-import-recovery.stderr +++ b/tests/ui/unresolved/unresolved-import-recovery.stderr @@ -1,8 +1,8 @@ -error[E0432]: unresolved import `unresolved` +error[E0432]: unresolved import `crate::unresolved` --> $DIR/unresolved-import-recovery.rs:4:13 | -LL | pub use unresolved; - | ^^^^^^^^^^ no `unresolved` in the root +LL | pub use crate::unresolved; + | ^^^^^^^^^^^^^^^^^ no `unresolved` in the root error: aborting due to 1 previous error diff --git a/tests/ui/unsafe/break-inside-unsafe-block-issue-128604.stderr b/tests/ui/unsafe/break-inside-unsafe-block-issue-128604.stderr index b7cbe1a5cf4..2f01331db9a 100644 --- a/tests/ui/unsafe/break-inside-unsafe-block-issue-128604.stderr +++ b/tests/ui/unsafe/break-inside-unsafe-block-issue-128604.stderr @@ -1,10 +1,4 @@ error[E0268]: `break` outside of a loop or labeled block - --> $DIR/break-inside-unsafe-block-issue-128604.rs:2:28 - | -LL | let a = ["_"; unsafe { break; 1 + 2 }]; - | ^^^^^ cannot `break` outside of a loop or labeled block - -error[E0268]: `break` outside of a loop or labeled block --> $DIR/break-inside-unsafe-block-issue-128604.rs:14:9 | LL | break; @@ -37,6 +31,12 @@ LL | unsafe { LL ~ break 'block; | +error[E0268]: `break` outside of a loop or labeled block + --> $DIR/break-inside-unsafe-block-issue-128604.rs:2:28 + | +LL | let a = ["_"; unsafe { break; 1 + 2 }]; + | ^^^^^ cannot `break` outside of a loop or labeled block + error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0268`. diff --git a/tests/ui/unsized/unsized3-rpass.rs b/tests/ui/unsized/unsized3-rpass.rs index ff35051774b..03aa1a538ea 100644 --- a/tests/ui/unsized/unsized3-rpass.rs +++ b/tests/ui/unsized/unsized3-rpass.rs @@ -37,7 +37,7 @@ impl Tr for St { } struct Qux<'a> { - f: Tr + 'a, + f: dyn Tr + 'a, } pub fn main() { @@ -85,7 +85,7 @@ pub fn main() { } let obj: Box<St> = Box::new(St { f: 42 }); - let obj: &Tr = &*obj; + let obj: &dyn Tr = &*obj; let data: Box<_> = Box::new(Qux_ { f: St { f: 234 } }); let x: &Qux = &*ptr::from_raw_parts::<Qux>(&*data as *const _, ptr::metadata(obj)); assert_eq!(x.f.foo(), 234); diff --git a/tests/ui/use/use-mod/use-mod-4.rs b/tests/ui/use/use-mod/use-mod-4.rs index 46ae8ddadc0..34ce7c71957 100644 --- a/tests/ui/use/use-mod/use-mod-4.rs +++ b/tests/ui/use/use-mod/use-mod-4.rs @@ -1,4 +1,4 @@ -use foo::self; //~ ERROR unresolved import `foo` +use crate::foo::self; //~ ERROR unresolved import `crate::foo` //~^ ERROR `self` imports are only allowed within a { } list use std::mem::self; diff --git a/tests/ui/use/use-mod/use-mod-4.stderr b/tests/ui/use/use-mod/use-mod-4.stderr index 0b4fbadb458..d4621296c0d 100644 --- a/tests/ui/use/use-mod/use-mod-4.stderr +++ b/tests/ui/use/use-mod/use-mod-4.stderr @@ -1,18 +1,18 @@ error[E0429]: `self` imports are only allowed within a { } list - --> $DIR/use-mod-4.rs:1:8 + --> $DIR/use-mod-4.rs:1:15 | -LL | use foo::self; - | ^^^^^^ +LL | use crate::foo::self; + | ^^^^^^ | help: consider importing the module directly | -LL - use foo::self; -LL + use foo; +LL - use crate::foo::self; +LL + use crate::foo; | help: alternatively, use the multi-path `use` syntax to import `self` | -LL | use foo::{self}; - | + + +LL | use crate::foo::{self}; + | + + error[E0429]: `self` imports are only allowed within a { } list --> $DIR/use-mod-4.rs:4:13 @@ -30,11 +30,11 @@ help: alternatively, use the multi-path `use` syntax to import `self` LL | use std::mem::{self}; | + + -error[E0432]: unresolved import `foo` +error[E0432]: unresolved import `crate::foo` --> $DIR/use-mod-4.rs:1:5 | -LL | use foo::self; - | ^^^^^^^^^ no `foo` in the root +LL | use crate::foo::self; + | ^^^^^^^^^^^^^^^^ no `foo` in the root error: aborting due to 3 previous errors diff --git a/tests/ui/variance/variance-trait-matching.stderr b/tests/ui/variance/variance-trait-matching.stderr index 9c72fe239dd..495669668c5 100644 --- a/tests/ui/variance/variance-trait-matching.stderr +++ b/tests/ui/variance/variance-trait-matching.stderr @@ -1,11 +1,13 @@ error[E0621]: explicit lifetime required in the type of `get` --> $DIR/variance-trait-matching.rs:24:5 | -LL | fn get<'a, G>(get: &G) -> i32 - | -- help: add explicit lifetime `'a` to the type of `get`: `&'a G` -... LL | pick(get, &22) | ^^^^^^^^^^^^^^ lifetime `'a` required + | +help: add explicit lifetime `'a` to the type of `get` + | +LL | fn get<'a, G>(get: &'a G) -> i32 + | ++ error: aborting due to 1 previous error diff --git a/tests/ui/warnings/no-explicit-path-issue-122509.rs b/tests/ui/warnings/no-explicit-path-issue-122509.rs index 4e8eefde5da..5be4b174076 100644 --- a/tests/ui/warnings/no-explicit-path-issue-122509.rs +++ b/tests/ui/warnings/no-explicit-path-issue-122509.rs @@ -7,13 +7,13 @@ fn one() -> usize { pub mod a { pub fn two() -> usize { - ::one() + ::one() + crate::one() + crate::one() } } pub mod b { pub fn three() -> usize { - ::one() + ::a::two() + crate::one() + crate::a::two() } } diff --git a/tests/ui/weird-exprs.rs b/tests/ui/weird-exprs.rs index b24e754a4ec..7db92d46067 100644 --- a/tests/ui/weird-exprs.rs +++ b/tests/ui/weird-exprs.rs @@ -105,7 +105,7 @@ fn u8(u8: u8) { u8!(u8); let &u8: &u8 = u8::u8(&8u8); - ::u8(0u8); + crate::u8(0u8); u8 }); } diff --git a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.rs b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.rs index a95e10b7265..53f07a94fd1 100644 --- a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.rs +++ b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.rs @@ -1,17 +1,11 @@ -trait Trait<const N: Trait = bar> { +trait Trait<const N: dyn Trait = bar> { //~^ ERROR cannot find value `bar` in this scope //~| ERROR cycle detected when computing type of `Trait::N` - //~| WARN trait objects without an explicit `dyn` are deprecated [bare_trait_objects] - //~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! - fn fnc<const N: Trait = u32>(&self) -> Trait { + fn fnc<const N: dyn Trait = u32>(&self) -> dyn Trait { //~^ ERROR the name `N` is already used for a generic parameter in this item's generic parameters //~| ERROR expected value, found builtin type `u32` //~| ERROR defaults for const parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions //~| ERROR associated item referring to unboxed trait object for its own trait - //~| WARN trait objects without an explicit `dyn` are deprecated [bare_trait_objects] - //~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! - //~| WARN trait objects without an explicit `dyn` are deprecated [bare_trait_objects] - //~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! bar //~^ ERROR cannot find value `bar` in this scope } diff --git a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.stderr b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.stderr index 59eef0c6327..a085dd6ac57 100644 --- a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.stderr +++ b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.stderr @@ -1,106 +1,66 @@ error[E0403]: the name `N` is already used for a generic parameter in this item's generic parameters - --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:6:18 + --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:4:18 | -LL | trait Trait<const N: Trait = bar> { +LL | trait Trait<const N: dyn Trait = bar> { | - first use of `N` ... -LL | fn fnc<const N: Trait = u32>(&self) -> Trait { +LL | fn fnc<const N: dyn Trait = u32>(&self) -> dyn Trait { | ^ already used error[E0425]: cannot find value `bar` in this scope - --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:1:30 + --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:1:34 | -LL | trait Trait<const N: Trait = bar> { - | ^^^ not found in this scope +LL | trait Trait<const N: dyn Trait = bar> { + | ^^^ not found in this scope error[E0423]: expected value, found builtin type `u32` - --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:6:29 + --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:4:33 | -LL | fn fnc<const N: Trait = u32>(&self) -> Trait { - | ^^^ not a value +LL | fn fnc<const N: dyn Trait = u32>(&self) -> dyn Trait { + | ^^^ not a value error[E0425]: cannot find value `bar` in this scope - --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:15:9 + --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:9:9 | LL | bar | ^^^ not found in this scope -warning: trait objects without an explicit `dyn` are deprecated - --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:1:22 - | -LL | trait Trait<const N: Trait = bar> { - | ^^^^^ - | - = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! - = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html> - = note: `#[warn(bare_trait_objects)]` on by default -help: if this is a dyn-compatible trait, use `dyn` - | -LL | trait Trait<const N: dyn Trait = bar> { - | +++ - error[E0391]: cycle detected when computing type of `Trait::N` - --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:1:22 + --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:1:26 | -LL | trait Trait<const N: Trait = bar> { - | ^^^^^ +LL | trait Trait<const N: dyn Trait = bar> { + | ^^^^^ | = note: ...which immediately requires computing type of `Trait::N` again note: cycle used when computing explicit predicates of trait `Trait` --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:1:1 | -LL | trait Trait<const N: Trait = bar> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | trait Trait<const N: dyn Trait = bar> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = 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: defaults for const parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions - --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:6:12 + --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:4:12 | -LL | fn fnc<const N: Trait = u32>(&self) -> Trait { - | ^^^^^^^^^^^^^^^^^^^^ - -warning: trait objects without an explicit `dyn` are deprecated - --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:6:44 - | -LL | fn fnc<const N: Trait = u32>(&self) -> Trait { - | ^^^^^ - | - = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! - = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html> -help: if this is a dyn-compatible trait, use `dyn` - | -LL | fn fnc<const N: Trait = u32>(&self) -> dyn Trait { - | +++ - -warning: trait objects without an explicit `dyn` are deprecated - --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:6:21 - | -LL | fn fnc<const N: Trait = u32>(&self) -> Trait { - | ^^^^^ - | - = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! - = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html> -help: if this is a dyn-compatible trait, use `dyn` - | -LL | fn fnc<const N: dyn Trait = u32>(&self) -> Trait { - | +++ +LL | fn fnc<const N: dyn Trait = u32>(&self) -> dyn Trait { + | ^^^^^^^^^^^^^^^^^^^^^^^^ error: associated item referring to unboxed trait object for its own trait - --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:6:44 + --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:4:48 | -LL | trait Trait<const N: Trait = bar> { +LL | trait Trait<const N: dyn Trait = bar> { | ----- in this trait ... -LL | fn fnc<const N: Trait = u32>(&self) -> Trait { - | ^^^^^ +LL | fn fnc<const N: dyn Trait = u32>(&self) -> dyn Trait { + | ^^^^^^^^^ | help: you might have meant to use `Self` to refer to the implementing type | -LL - fn fnc<const N: Trait = u32>(&self) -> Trait { -LL + fn fnc<const N: Trait = u32>(&self) -> Self { +LL - fn fnc<const N: dyn Trait = u32>(&self) -> dyn Trait { +LL + fn fnc<const N: dyn Trait = u32>(&self) -> Self { | -error: aborting due to 7 previous errors; 3 warnings emitted +error: aborting due to 7 previous errors Some errors have detailed explanations: E0391, E0403, E0423, E0425. For more information about an error, try `rustc --explain E0391`. diff --git a/triagebot.toml b/triagebot.toml index 15c56f8861f..e5af77b6d44 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -44,29 +44,6 @@ remove_labels = ["S-waiting-on-author"] # Those labels are added when PR author requests a review from an assignee add_labels = ["S-waiting-on-review"] -[ping.icebreakers-llvm] -message = """\ -Hey LLVM ICE-breakers! This bug has been identified as a good -"LLVM ICE-breaking candidate". In case it's useful, here are some -[instructions] for tackling these sorts of bugs. Maybe take a look? -Thanks! <3 - -[instructions]: https://rustc-dev-guide.rust-lang.org/notification-groups/llvm.html -""" -label = "ICEBreaker-LLVM" - -[ping.icebreakers-cleanup-crew] -alias = ["cleanup", "cleanups", "cleanup-crew", "shrink", "reduce", "bisect"] -message = """\ -Hey Cleanup Crew ICE-breakers! This bug has been identified as a good -"Cleanup ICE-breaking candidate". In case it's useful, here are some -[instructions] for tackling these sorts of bugs. Maybe take a look? -Thanks! <3 - -[instructions]: https://rustc-dev-guide.rust-lang.org/notification-groups/cleanup-crew.html -""" -label = "ICEBreaker-Cleanup-Crew" - [ping.windows] message = """\ Hey Windows Group! This bug has been identified as a good "Windows candidate". @@ -729,6 +706,41 @@ don't know ] message_on_remove = "PR #{number}'s stable-nomination has been removed." +[notify-zulip."beta-nominated".bootstrap] +required_labels = ["T-bootstrap"] +zulip_stream = 507486 # #t-infra/bootstrap/backports +topic = "#{number}: beta-nominated" +message_on_add = [ + """\ +@*T-bootstrap* PR #{number} "{title}" has been nominated for beta backport. +""", + """\ +/poll Approve beta backport of #{number}? +approve +decline +don't know +""", +] +message_on_remove = "PR #{number}'s beta-nomination has been removed." + +[notify-zulip."stable-nominated".bootstrap] +required_labels = ["T-bootstrap"] +zulip_stream = 507486 # #t-infra/bootstrap/backports +topic = "#{number}: stable-nominated" +message_on_add = [ + """\ +@*T-bootstrap* PR #{number} "{title}" has been nominated for stable backport. +""", + """\ +/poll Approve stable backport of #{number}? +approve +approve (but does not justify new dot release on its own) +decline +don't know +""", +] +message_on_remove = "PR #{number}'s stable-nomination has been removed." + [notify-zulip."A-edition-2021"] required_labels = ["C-bug"] zulip_stream = 268952 # #edition @@ -1217,6 +1229,7 @@ compiler = [ "@oli-obk", "@petrochenkov", "@SparrowLii", + "@WaffleLapkin", "@wesleywiser", ] libs = [ @@ -1228,14 +1241,6 @@ libs = [ "@thomcc", "@ibraheemdev", ] -bootstrap = [ - "@Mark-Simulacrum", - "@albertlarsan68", - "@onur-ozkan", - "@kobzol", - "@jieyouxu", - "@clubby789", -] infra-ci = [ "@Mark-Simulacrum", "@Kobzol", @@ -1255,6 +1260,7 @@ codegen = [ "@dianqk", "@saethlin", "@workingjubilee", + "@WaffleLapkin", ] query-system = [ "@oli-obk", @@ -1424,8 +1430,8 @@ compiletest = [ "/src/tools/rustdoc-themes" = ["rustdoc"] "/src/tools/tidy" = ["bootstrap"] "/src/tools/x" = ["bootstrap"] -"/src/tools/rustdoc-gui-test" = ["bootstrap", "@onur-ozkan"] -"/src/tools/libcxx-version" = ["@onur-ozkan"] +"/src/tools/rustdoc-gui-test" = ["bootstrap"] +"/src/tools/libcxx-version" = ["bootstrap"] # Enable review queue tracking # Documentation at: https://forge.rust-lang.org/triagebot/review-queue-tracking.html |
