diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index fd54a153a160..ecf8f993f90b 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -7,6 +7,6 @@ tracking issue or there are none, feel free to ignore this. This PR will get automatically assigned to a reviewer. In case you would like a specific user to review your work, you can assign it to them by using - r​? + r\? (with the `\` removed) --> diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8032154a7365..b6dc27f12346 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -212,6 +212,16 @@ jobs: # erroring about invalid credentials instead. if: github.event_name == 'push' || env.DEPLOY == '1' || env.DEPLOY_ALT == '1' + - name: upload job metrics to DataDog + if: needs.calculate_matrix.outputs.run_type != 'pr' + env: + DATADOG_SITE: datadoghq.com + DATADOG_API_KEY: ${{ secrets.DATADOG_API_KEY }} + DD_GITHUB_JOB_NAME: ${{ matrix.name }} + run: | + npm install -g @datadog/datadog-ci@^2.x.x + python3 src/ci/scripts/upload-build-metrics.py build/cpu-usage.csv + # This job isused to tell bors the final status of the build, as there is no practical way to detect # when a workflow is successful listening to webhooks only in our current bors implementation (homu). outcome: diff --git a/.github/workflows/dependencies.yml b/.github/workflows/dependencies.yml index 83b92b7fa092..b7b5a03bd41f 100644 --- a/.github/workflows/dependencies.yml +++ b/.github/workflows/dependencies.yml @@ -61,9 +61,11 @@ jobs: rustup toolchain install --no-self-update --profile minimal $TOOLCHAIN rustup default $TOOLCHAIN - - name: cargo update + - name: cargo update compiler & tools # Remove first line that always just says "Updating crates.io index" - run: cargo update 2>&1 | sed '/crates.io index/d' | tee -a cargo_update.log + run: | + echo -e "\ncompiler & tools dependencies:" >> cargo_update.log + cargo update 2>&1 | sed '/crates.io index/d' | tee -a cargo_update.log - name: cargo update library run: | echo -e "\nlibrary dependencies:" >> cargo_update.log diff --git a/.gitignore b/.gitignore index 2e6499081a63..d6d8b99f6023 100644 --- a/.gitignore +++ b/.gitignore @@ -25,6 +25,7 @@ Session.vim .favorites.json .settings/ .vs/ +.dir-locals.el ## Tool .valgrindrc diff --git a/Cargo.lock b/Cargo.lock index 7a9701a9cad5..452770edf7b8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,12 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "adler2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + [[package]] name = "aes" version = "0.8.4" @@ -177,9 +183,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.86" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" +checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" dependencies = [ "backtrace", ] @@ -201,9 +207,9 @@ checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" [[package]] name = "autocfg" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "backtrace" @@ -215,7 +221,7 @@ dependencies = [ "cc", "cfg-if", "libc", - "miniz_oxide", + "miniz_oxide 0.7.4", "object 0.32.2", "rustc-demangle", ] @@ -267,12 +273,12 @@ dependencies = [ [[package]] name = "bstr" -version = "1.6.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6798148dccfbff0fae41c7574d2fa8f1ef3492fba0face179de5d8d447d67b05" +checksum = "40723b8fb387abc38f4f4a37c09073622e41dd12327033091ef8950659e6dc0c" dependencies = [ "memchr", - "regex-automata 0.3.9", + "regex-automata 0.4.7", "serde", ] @@ -332,9 +338,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.7.1" +version = "1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" +checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3" [[package]] name = "camino" @@ -349,7 +355,7 @@ dependencies = [ name = "cargo-miri" version = "0.1.0" dependencies = [ - "cargo_metadata 0.18.1", + "cargo_metadata", "directories", "rustc-build-sysroot", "rustc_tools_util", @@ -367,20 +373,6 @@ dependencies = [ "serde", ] -[[package]] -name = "cargo_metadata" -version = "0.15.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eee4243f1f26fc7a42710e7439c149e2b10b05472f88090acce52632f231a73a" -dependencies = [ - "camino", - "cargo-platform", - "semver", - "serde", - "serde_json", - "thiserror", -] - [[package]] name = "cargo_metadata" version = "0.18.1" @@ -401,9 +393,12 @@ version = "0.1.0" [[package]] name = "cc" -version = "1.0.105" +version = "1.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5208975e568d83b6b05cc0a063c8e7e9acc2b43bee6da15616a5b73e109d7437" +checksum = "3bbb537bb4a30b90362caddba8f360c0a56bc13d3a5570028e7197204cb54a17" +dependencies = [ + "shlex", +] [[package]] name = "cfg-if" @@ -463,9 +458,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.16" +version = "4.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed6719fffa43d0d87e5fd8caeab59be1554fb028cd30edc88fc4369b17971019" +checksum = "b0956a43b323ac1afaffc053ed5c4b7c1f1800bacd1683c353aabbb752515dd3" dependencies = [ "clap_builder", "clap_derive", @@ -483,9 +478,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.15" +version = "4.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "216aec2b177652e3846684cbfe25c9964d18ec45234f0f5da5157b207ed1aab6" +checksum = "4d72166dd41634086d5803a47eb71ae740e61d84709c36f3c34110173db3961b" dependencies = [ "anstream", "anstyle", @@ -496,23 +491,23 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.5.18" +version = "4.5.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ee158892bd7ce77aa15c208abbdb73e155d191c287a659b57abd5adb92feb03" +checksum = "8937760c3f4c60871870b8c3ee5f9b30771f792a7045c48bcbba999d7d6b3b8e" dependencies = [ "clap", ] [[package]] name = "clap_derive" -version = "4.5.13" +version = "4.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0" +checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.79", ] [[package]] @@ -526,7 +521,7 @@ name = "clippy" version = "0.1.83" dependencies = [ "anstream", - "cargo_metadata 0.18.1", + "cargo_metadata", "clippy_config", "clippy_lints", "clippy_utils", @@ -541,7 +536,7 @@ dependencies = [ "rustc_tools_util", "serde", "serde_json", - "syn 2.0.75", + "syn 2.0.79", "tempfile", "termize", "tokio", @@ -578,7 +573,7 @@ name = "clippy_lints" version = "0.1.83" dependencies = [ "arrayvec", - "cargo_metadata 0.18.1", + "cargo_metadata", "clippy_config", "clippy_utils", "declare_clippy_lint", @@ -650,7 +645,7 @@ dependencies = [ "nom", "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.79", ] [[package]] @@ -711,7 +706,7 @@ dependencies = [ "tracing-subscriber", "unified-diff", "walkdir", - "windows 0.52.0", + "windows", ] [[package]] @@ -740,16 +735,16 @@ dependencies = [ "anyhow", "leb128", "md-5", - "miniz_oxide", + "miniz_oxide 0.7.4", "regex", "rustc-demangle", ] [[package]] name = "cpufeatures" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51e852e6dc9a5bed1fae92dd2375037bf2b768725bf3be87811edee3249d09ad" +checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" dependencies = [ "libc", ] @@ -834,9 +829,9 @@ dependencies = [ [[package]] name = "curl-sys" -version = "0.4.74+curl-8.9.0" +version = "0.4.76+curl-8.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8af10b986114528fcdc4b63b6f5f021b7057618411046a4de2ba0f0149a097bf" +checksum = "00462dbe9cbb9344e1b2be34d9094d74e3b8aac59a883495b335eafd02e25120" dependencies = [ "cc", "libc", @@ -868,7 +863,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.75", + "syn 2.0.79", ] [[package]] @@ -879,7 +874,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn 2.0.75", + "syn 2.0.79", ] [[package]] @@ -905,7 +900,7 @@ version = "0.1.83" dependencies = [ "itertools", "quote", - "syn 2.0.75", + "syn 2.0.79", ] [[package]] @@ -925,49 +920,38 @@ checksum = "62d671cc41a825ebabc75757b62d3d168c577f9149b2d49ece1dad1f72119d25" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.79", ] [[package]] name = "derive_builder" -version = "0.20.0" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0350b5cb0331628a5916d6c5c0b72e97393b8b6b03b47a9284f4e7f5a405ffd7" +checksum = "cd33f37ee6a119146a1781d3356a7c26028f83d779b2e04ecd45fdc75c76877b" dependencies = [ "derive_builder_macro", ] [[package]] name = "derive_builder_core" -version = "0.20.0" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d48cda787f839151732d396ac69e3473923d54312c070ee21e9effcaa8ca0b1d" +checksum = "7431fa049613920234f22c47fdc33e6cf3ee83067091ea4277a3f8c4587aae38" dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.79", ] [[package]] name = "derive_builder_macro" -version = "0.20.0" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "206868b8242f27cecce124c19fd88157fbd0dd334df2587f36417bafbc85097b" +checksum = "4abae7035bf79b9877b779505d8cf3749285b80c43941eda66604841889451dc" dependencies = [ "derive_builder_core", - "syn 2.0.75", -] - -[[package]] -name = "derive_more" -version = "0.99.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.75", + "syn 2.0.79", ] [[package]] @@ -979,7 +963,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.79", ] [[package]] @@ -1057,7 +1041,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.79", ] [[package]] @@ -1182,9 +1166,9 @@ checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" [[package]] name = "fastrand" -version = "2.1.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" +checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" [[package]] name = "field-offset" @@ -1198,9 +1182,9 @@ dependencies = [ [[package]] name = "filetime" -version = "0.2.24" +version = "0.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf401df4a4e3872c4fe8151134cf483738e74b67fc934d6532c882b3d24a4550" +checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586" dependencies = [ "cfg-if", "libc", @@ -1210,12 +1194,12 @@ dependencies = [ [[package]] name = "flate2" -version = "1.0.31" +version = "1.0.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f211bbe8e69bbd0cfdea405084f128ae8b4aaa6b0b522fc8f2b009084797920" +checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0" dependencies = [ "crc32fast", - "miniz_oxide", + "miniz_oxide 0.8.0", ] [[package]] @@ -1228,7 +1212,7 @@ dependencies = [ "fluent-syntax", "intl-memoizer", "intl_pluralrules", - "rustc-hash", + "rustc-hash 1.1.0", "self_cell 0.10.3", "smallvec", "unic-langid", @@ -1348,7 +1332,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.79", ] [[package]] @@ -1386,7 +1370,7 @@ name = "generate-copyright" version = "0.1.0" dependencies = [ "anyhow", - "cargo_metadata 0.18.1", + "cargo_metadata", "rinja", "serde", "serde_json", @@ -1435,6 +1419,12 @@ name = "gimli" version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" + +[[package]] +name = "gimli" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2e1d97fbe9722ba9bbd0c97051c2956e726562b61f86a25a4360398a40edfc9" dependencies = [ "fallible-iterator", "indexmap", @@ -1460,15 +1450,15 @@ checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "globset" -version = "0.4.13" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "759c97c1e17c55525b57192c06a267cda0ac5210b222d6b82189a2338fa1c13d" +checksum = "15f1ce686646e7f1e19bf7d5533fe443a45dbfb990e00629110797578b42fb19" dependencies = [ "aho-corasick", "bstr", - "fnv", "log", - "regex", + "regex-automata 0.4.7", + "regex-syntax 0.8.4", ] [[package]] @@ -1566,7 +1556,7 @@ dependencies = [ "markup5ever", "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.79", ] [[package]] @@ -1586,9 +1576,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "iana-time-zone" -version = "0.1.60" +version = "0.1.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -1698,7 +1688,7 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.79", ] [[package]] @@ -1731,17 +1721,16 @@ checksum = "cb56e1aa765b4b4f3aadfab769793b7087bb03a4ea4920644a6d238e2df5b9ed" [[package]] name = "ignore" -version = "0.4.20" +version = "0.4.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbe7873dab538a9a44ad79ede1faf5f30d49f9a5c883ddbab48bce81b64b7492" +checksum = "6d89fd380afde86567dfba715db065673989d6253f42b88179abd3eae47bda4b" dependencies = [ + "crossbeam-deque", "globset", - "lazy_static", "log", "memchr", - "regex", + "regex-automata 0.4.7", "same-file", - "thread_local", "walkdir", "winapi-util", ] @@ -1754,9 +1743,9 @@ checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" [[package]] name = "indexmap" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c" +checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" dependencies = [ "equivalent", "hashbrown", @@ -1901,7 +1890,7 @@ dependencies = [ "anyhow", "clap", "fs-err", - "rustc-hash", + "rustc-hash 1.1.0", "rustdoc-json-types", "serde", "serde_json", @@ -1944,9 +1933,9 @@ checksum = "baff4b617f7df3d896f97fe922b64817f6cd9a756bb81d40f8883f2f66dcb401" [[package]] name = "libc" -version = "0.2.157" +version = "0.2.159" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "374af5f94e54fa97cf75e945cce8a6b201e88a1a07e688b47dfd2a59c66dbd86" +checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" [[package]] name = "libdbus-sys" @@ -2006,9 +1995,9 @@ dependencies = [ [[package]] name = "libz-sys" -version = "1.1.19" +version = "1.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdc53a7799a7496ebc9fd29f31f7df80e83c9bda5299768af5f9e59eeea74647" +checksum = "d2d16453e800a8cf6dd2fc3eb4bc99b786a9b90c663b8559a5b1a041bf89e472" dependencies = [ "cc", "libc", @@ -2170,7 +2159,7 @@ dependencies = [ "memmap2", "parking_lot", "perf-event-open-sys", - "rustc-hash", + "rustc-hash 1.1.0", "smallvec", ] @@ -2238,6 +2227,15 @@ dependencies = [ "adler", ] +[[package]] +name = "miniz_oxide" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" +dependencies = [ + "adler2", +] + [[package]] name = "miow" version = "0.6.0" @@ -2433,12 +2431,7 @@ version = "0.32.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" dependencies = [ - "crc32fast", - "flate2", - "hashbrown", - "indexmap", "memchr", - "ruzstd 0.5.0", ] [[package]] @@ -2452,8 +2445,8 @@ dependencies = [ "hashbrown", "indexmap", "memchr", - "ruzstd 0.7.0", - "wasmparser", + "ruzstd", + "wasmparser 0.216.0", ] [[package]] @@ -2473,9 +2466,9 @@ checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "once_map" -version = "0.4.18" +version = "0.4.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa7085055bbe9c8edbd982048dbcf8181794d4a81cb04a11931673e63cc18dc6" +checksum = "30c7f82d6d446dd295845094f3a76bcdc5e6183b66667334e169f019cd05e5a0" dependencies = [ "ahash", "hashbrown", @@ -2641,9 +2634,9 @@ dependencies = [ [[package]] name = "pest" -version = "2.7.11" +version = "2.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd53dff83f26735fdc1ca837098ccf133605d794cdae66acfc2bfac3ec809d95" +checksum = "fdbef9d1d47087a895abd220ed25eb4ad973a5e26f6a4367b038c25e28dfc2d9" dependencies = [ "memchr", "thiserror", @@ -2652,9 +2645,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.7.11" +version = "2.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a548d2beca6773b1c244554d36fcf8548a8a58e74156968211567250e48e49a" +checksum = "4d3a6e3394ec80feb3b6393c725571754c6188490265c61aaf260810d6b95aa0" dependencies = [ "pest", "pest_generator", @@ -2662,22 +2655,22 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.11" +version = "2.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c93a82e8d145725dcbaf44e5ea887c8a869efdcc28706df2d08c69e17077183" +checksum = "94429506bde1ca69d1b5601962c73f4172ab4726571a59ea95931218cb0e930e" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.79", ] [[package]] name = "pest_meta" -version = "2.7.11" +version = "2.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a941429fea7e08bedec25e4f6785b6ffaacc6b755da98df5ef3e7dcf4a124c4f" +checksum = "ac8a071862e93690b6e34e9a5fb8e33ff3734473ac0245b27232222c4906a33f" dependencies = [ "once_cell", "pest", @@ -2755,9 +2748,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" [[package]] name = "polonius-engine" @@ -2767,14 +2760,14 @@ checksum = "c4e8e505342045d397d0b6674dcb82d6faf5cf40484d30eeb88fc82ef14e903f" dependencies = [ "datafrog", "log", - "rustc-hash", + "rustc-hash 1.1.0", ] [[package]] name = "portable-atomic" -version = "1.7.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da544ee218f0d287a911e9c99a39a8c9bc8fcad3cb8db5959940044ecfc67265" +checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2" [[package]] name = "powerfmt" @@ -2824,9 +2817,9 @@ dependencies = [ [[package]] name = "psm" -version = "0.1.21" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5787f7cda34e3033a72192c018bc5883100330f362ef279a8cbccfce8bb4e874" +checksum = "aa37f80ca58604976033fae9515a8a2989fc13797d953f7c04fb8fa36a11f205" dependencies = [ "cc", ] @@ -2856,9 +2849,9 @@ dependencies = [ [[package]] name = "pulldown-cmark" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb4e75767fbc9d92b90e4d0c011f61358cde9513b31ef07ea3631b15ffc3b4fd" +checksum = "679341d22c78c6c649893cbd6c3278dcbe9fc4faa62fea3a9296ae2b50c14625" dependencies = [ "bitflags 2.6.0", "memchr", @@ -2892,9 +2885,9 @@ checksum = "07589615d719a60c8dd8a4622e7946465dfef20d1a428f969e3443e7386d5f45" [[package]] name = "quote" -version = "1.0.36" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] @@ -2960,18 +2953,18 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.3" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" +checksum = "355ae415ccd3a04315d3f8246e86d67689ea74d88d915576e1589a351062a13b" dependencies = [ "bitflags 2.6.0", ] [[package]] name = "redox_users" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ "getrandom", "libredox", @@ -2980,13 +2973,14 @@ dependencies = [ [[package]] name = "regex" -version = "1.8.4" +version = "1.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0ab3ca65655bb1e41f2a8c8cd662eb4fb035e67c3f78da1d61dffe89d07300f" +checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.7.5", + "regex-automata 0.4.7", + "regex-syntax 0.8.4", ] [[package]] @@ -3009,9 +3003,14 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.3.9" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59b23e92ee4318893fa3fe3e6fb365258efbfe6ac6ab30f090cdcbb7aa37efa9" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.8.4", +] [[package]] name = "regex-lite" @@ -3025,12 +3024,6 @@ version = "0.6.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" -[[package]] -name = "regex-syntax" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" - [[package]] name = "regex-syntax" version = "0.8.4" @@ -3055,9 +3048,9 @@ dependencies = [ [[package]] name = "rinja" -version = "0.3.0" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d3762e3740cdbf2fd2be465cc2c26d643ad17353cc2e0223d211c1b096118bd" +checksum = "f28580fecce391f3c0e65a692e5f2b5db258ba2346ee04f355ae56473ab973dc" dependencies = [ "humansize", "itoa", @@ -3068,9 +3061,9 @@ dependencies = [ [[package]] name = "rinja_derive" -version = "0.3.0" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd01fd8e15e7d19c8b8052c1d428325131e02ff1633cdcf695190c2e56ab682c" +checksum = "1f1ae91455a4c82892d9513fcfa1ac8faff6c523602d0041536341882714aede" dependencies = [ "basic-toml", "memchr", @@ -3080,18 +3073,20 @@ dependencies = [ "proc-macro2", "quote", "rinja_parser", + "rustc-hash 2.0.0", "serde", - "syn 2.0.75", + "syn 2.0.79", ] [[package]] name = "rinja_parser" -version = "0.3.0" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2f6bf7cef118c6de21206edf0b3f19f5ede60006be674a58ca21b6e003a1b57" +checksum = "06ea17639e1f35032e1c67539856e498c04cd65fe2a45f55ec437ec55e4be941" dependencies = [ "memchr", "nom", + "serde", ] [[package]] @@ -3113,7 +3108,7 @@ dependencies = [ "regex", "serde_json", "similar", - "wasmparser", + "wasmparser 0.216.0", ] [[package]] @@ -3140,6 +3135,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +[[package]] +name = "rustc-hash" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" + [[package]] name = "rustc-main" version = "0.0.0" @@ -3450,6 +3451,7 @@ dependencies = [ "rustc_span", "rustc_symbol_mangling", "rustc_target", + "rustc_trait_selection", "rustc_type_ir", "serde_json", "smallvec", @@ -3457,8 +3459,8 @@ dependencies = [ "thin-vec", "thorin-dwp", "tracing", - "wasm-encoder", - "windows 0.52.0", + "wasm-encoder 0.216.0", + "windows", ] [[package]] @@ -3502,7 +3504,7 @@ dependencies = [ "memmap2", "parking_lot", "portable-atomic", - "rustc-hash", + "rustc-hash 1.1.0", "rustc-rayon", "rustc-stable-hash", "rustc_arena", @@ -3515,7 +3517,7 @@ dependencies = [ "tempfile", "thin-vec", "tracing", - "windows 0.52.0", + "windows", ] [[package]] @@ -3577,7 +3579,7 @@ dependencies = [ "shlex", "time", "tracing", - "windows 0.52.0", + "windows", ] [[package]] @@ -3628,7 +3630,7 @@ dependencies = [ "termcolor", "termize", "tracing", - "windows 0.52.0", + "windows", ] [[package]] @@ -3672,7 +3674,7 @@ dependencies = [ "fluent-syntax", "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.79", "unic-langid", ] @@ -3806,7 +3808,7 @@ version = "0.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.79", ] [[package]] @@ -3955,7 +3957,7 @@ version = "0.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.79", "synstructure", ] @@ -4196,7 +4198,7 @@ dependencies = [ name = "rustc_pattern_analysis" version = "0.0.0" dependencies = [ - "rustc-hash", + "rustc-hash 1.1.0", "rustc_apfloat", "rustc_arena", "rustc_data_structures", @@ -4280,7 +4282,7 @@ name = "rustc_resolve" version = "0.0.0" dependencies = [ "bitflags 2.6.0", - "pulldown-cmark 0.11.2", + "pulldown-cmark 0.11.3", "rustc_arena", "rustc_ast", "rustc_ast_pretty", @@ -4351,7 +4353,7 @@ dependencies = [ "smallvec", "termize", "tracing", - "windows 0.52.0", + "windows", ] [[package]] @@ -4518,7 +4520,7 @@ dependencies = [ "bitflags 2.6.0", "derive-where", "indexmap", - "rustc-hash", + "rustc-hash 1.1.0", "rustc_ast_ir", "rustc_data_structures", "rustc_index", @@ -4536,15 +4538,15 @@ version = "0.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.79", "synstructure", ] [[package]] name = "rustc_version" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ "semver", ] @@ -4589,7 +4591,7 @@ name = "rustdoc-json-types" version = "0.1.0" dependencies = [ "bincode", - "rustc-hash", + "rustc-hash 1.1.0", "serde", "serde_json", ] @@ -4624,7 +4626,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.75", + "syn 2.0.79", ] [[package]] @@ -4634,7 +4636,7 @@ dependencies = [ "annotate-snippets 0.9.2", "anyhow", "bytecount", - "cargo_metadata 0.18.1", + "cargo_metadata", "clap", "clap-cargo", "diff", @@ -4658,9 +4660,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.34" +version = "0.38.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" dependencies = [ "bitflags 2.6.0", "errno", @@ -4677,22 +4679,10 @@ checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" [[package]] name = "ruzstd" -version = "0.5.0" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58c4eb8a81997cf040a091d1f7e1938aeab6749d3a0dfa73af43cdc32393483d" +checksum = "99c3938e133aac070997ddc684d4b393777d293ba170f2988c8fd5ea2ad4ce21" dependencies = [ - "byteorder", - "derive_more", - "twox-hash", -] - -[[package]] -name = "ruzstd" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5022b253619b1ba797f243056276bed8ed1a73b0f5a7ce7225d524067644bf8f" -dependencies = [ - "byteorder", "twox-hash", ] @@ -4713,11 +4703,11 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" +checksum = "e9aaafd5a2b6e3d657ff009d82fbd630b6bd54dd4eb06f21693925cdf80f9b8b" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -4758,29 +4748,29 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.208" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cff085d2cb684faa248efb494c39b68e522822ac0de72ccf08109abde717cfb2" +checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.208" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24008e81ff7613ed8e5ba0cfaf24e2c2f1e5b8a0495711e44fcd4882fca62bcf" +checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.79", ] [[package]] name = "serde_json" -version = "1.0.125" +version = "1.0.128" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83c8e735a073ccf5be70aa8066aa984eaf2fa000db6c8d0100ae605b366d31ed" +checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" dependencies = [ "indexmap", "itoa", @@ -4791,9 +4781,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.7" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d" +checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" dependencies = [ "serde", ] @@ -5037,9 +5027,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.75" +version = "2.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6af063034fc1935ede7be0122941bafa9bacb949334d090b77ca98b5817c7d9" +checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" dependencies = [ "proc-macro2", "quote", @@ -5054,18 +5044,18 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.79", ] [[package]] name = "sysinfo" -version = "0.31.2" +version = "0.31.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4115055da5f572fff541dd0c4e61b0262977f453cc9fe04be83aba25a89bdab" +checksum = "355dbe4f8799b304b05e1b0f05fc59b2a18d36645cf169607da45bde2f69a1be" dependencies = [ "core-foundation-sys", "libc", - "windows 0.57.0", + "windows", ] [[package]] @@ -5080,9 +5070,9 @@ dependencies = [ [[package]] name = "tar" -version = "0.4.41" +version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb797dad5fb5b76fcf519e702f4a589483b5ef06567f160c392832c1f5e44909" +checksum = "4ff6c40d3aedb5e06b57c6f669ad17ab063dd1e63d977c6a88e7f4dfa4f04020" dependencies = [ "filetime", "libc", @@ -5091,9 +5081,9 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.12.0" +version = "3.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64" +checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b" dependencies = [ "cfg-if", "fastrand", @@ -5172,33 +5162,33 @@ checksum = "a38c90d48152c236a3ab59271da4f4ae63d678c5d7ad6b7714d7cb9760be5e4b" [[package]] name = "thiserror" -version = "1.0.63" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" +checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.63" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" +checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.79", ] [[package]] name = "thorin-dwp" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4db52ee8fec06e119b692ef3dd2c4cf621a99204c1b8c47407870ed050305b9b" +checksum = "813ba76597db32dc4f6992fd8bf8f394715b88d352fd97401da67dab6283b4c6" dependencies = [ - "gimli 0.28.1", + "gimli 0.30.0", "hashbrown", - "object 0.32.2", + "object 0.36.4", "tracing", ] @@ -5226,12 +5216,12 @@ name = "tidy" version = "0.1.0" dependencies = [ "build_helper", - "cargo_metadata 0.15.4", + "cargo_metadata", "fluent-syntax", "ignore", "miropt-test-tools", "regex", - "rustc-hash", + "rustc-hash 1.1.0", "semver", "similar", "termcolor", @@ -5300,9 +5290,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.39.3" +version = "1.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9babc99b9923bfa4804bd74722ff02c0381021eafa4db9949217e3be8e84fff5" +checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" dependencies = [ "backtrace", "bytes", @@ -5378,7 +5368,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.79", ] [[package]] @@ -5460,7 +5450,7 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "deb68604048ff8fa93347f02441e4487594adc20bb8a084f9e564d2b827a0a9f" dependencies = [ - "rustc-hash", + "rustc-hash 1.1.0", ] [[package]] @@ -5494,7 +5484,7 @@ dependencies = [ "anyhow", "bstr", "cargo-platform", - "cargo_metadata 0.18.1", + "cargo_metadata", "color-eyre", "colored", "comma", @@ -5549,7 +5539,7 @@ checksum = "1ed7f4237ba393424195053097c1516bd4590dc82b84f2f97c5c69e12704555b" dependencies = [ "proc-macro-hack", "quote", - "syn 2.0.75", + "syn 2.0.79", "unic-langid-impl", ] @@ -5577,36 +5567,36 @@ checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" [[package]] name = "unicode-normalization" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" +checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" dependencies = [ "tinyvec", ] [[package]] name = "unicode-properties" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4259d9d4425d9f0661581b804cb85fe66a4c631cadd8f490d1c13a35d5d9291" +checksum = "52ea75f83c0137a9b98608359a5f1af8144876eb67bcb1ce837368e906a9f524" [[package]] name = "unicode-script" -version = "0.5.6" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad8d71f5726e5f285a935e9fe8edfd53f0491eb6e9a5774097fdabee7cd8c9cd" +checksum = "9fb421b350c9aff471779e262955939f565ec18b86c15364e6bdf0d662ca7c1f" [[package]] name = "unicode-security" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee9e13753df674873f3c4693b240ae5c03245ddc157dfccf7c26db9329af3a11" +checksum = "2e4ddba1535dd35ed8b61c52166b7155d7f4e4b8847cec6f48e71dc66d8b5e50" dependencies = [ "unicode-normalization", "unicode-script", @@ -5614,21 +5604,21 @@ dependencies = [ [[package]] name = "unicode-segmentation" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" [[package]] name = "unicode-width" -version = "0.1.13" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" [[package]] name = "unicode-xid" -version = "0.2.4" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] name = "unified-diff" @@ -5747,7 +5737,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.79", "wasm-bindgen-shared", ] @@ -5769,7 +5759,7 @@ checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.79", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -5782,16 +5772,16 @@ checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" [[package]] name = "wasm-component-ld" -version = "0.5.7" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13261270d3ac58ffae0219ae34f297a7e24f9ee3b13b29be579132c588a83519" +checksum = "fde17bc96539700198e12516230c76095cc215c84ef39ad206e1af3f84243e0f" dependencies = [ "anyhow", "clap", "lexopt", "tempfile", "wasi-preview1-component-adapter-provider", - "wasmparser", + "wasmparser 0.218.0", "wat", "wit-component", "wit-parser", @@ -5811,14 +5801,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04c23aebea22c8a75833ae08ed31ccc020835b12a41999e58c31464271b94a88" dependencies = [ "leb128", - "wasmparser", +] + +[[package]] +name = "wasm-encoder" +version = "0.218.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22b896fa8ceb71091ace9bcb81e853f54043183a1c9667cf93422c40252ffa0a" +dependencies = [ + "leb128", + "wasmparser 0.218.0", ] [[package]] name = "wasm-metadata" -version = "0.216.0" +version = "0.218.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47c8154d703a6b0e45acf6bd172fa002fc3c7058a9f7615e517220aeca27c638" +checksum = "aa5eeb071abe8a2132fdd5565dabffee70775ee8c24fc7e300ac43f51f4a8a91" dependencies = [ "anyhow", "indexmap", @@ -5826,8 +5825,8 @@ dependencies = [ "serde_derive", "serde_json", "spdx", - "wasm-encoder", - "wasmparser", + "wasm-encoder 0.218.0", + "wasmparser 0.218.0", ] [[package]] @@ -5835,6 +5834,16 @@ name = "wasmparser" version = "0.216.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bcdee6bea3619d311fb4b299721e89a986c3470f804b6d534340e412589028e3" +dependencies = [ + "bitflags 2.6.0", + "indexmap", +] + +[[package]] +name = "wasmparser" +version = "0.218.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b09e46c7fceceaa72b2dd1a8a137ea7fd8f93dfaa69806010a709918e496c5dc" dependencies = [ "ahash", "bitflags 2.6.0", @@ -5846,22 +5855,22 @@ dependencies = [ [[package]] name = "wast" -version = "216.0.0" +version = "218.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7eb1f2eecd913fdde0dc6c3439d0f24530a98ac6db6cb3d14d92a5328554a08" +checksum = "8a53cd1f0fa505df97557e36a58bddb8296e2fcdcd089529545ebfdb18a1b9d7" dependencies = [ "bumpalo", "leb128", "memchr", "unicode-width", - "wasm-encoder", + "wasm-encoder 0.218.0", ] [[package]] name = "wat" -version = "1.216.0" +version = "1.218.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac0409090fb5154f95fb5ba3235675fd9e579e731524d63b6a2f653e1280c82a" +checksum = "4f87f8e14e776762e07927c27c2054d2cf678aab9aae2d431a79b3e31e4dd391" dependencies = [ "wast", ] @@ -5897,16 +5906,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "windows" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" -dependencies = [ - "windows-core 0.52.0", - "windows-targets 0.52.6", -] - [[package]] name = "windows" version = "0.57.0" @@ -5927,7 +5926,7 @@ dependencies = [ "rayon", "serde", "serde_json", - "syn 2.0.75", + "syn 2.0.79", "windows-metadata", ] @@ -5960,7 +5959,7 @@ checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.79", ] [[package]] @@ -5971,7 +5970,7 @@ checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.79", ] [[package]] @@ -6148,9 +6147,9 @@ dependencies = [ [[package]] name = "wit-component" -version = "0.216.0" +version = "0.218.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e2ca3ece38ea2447a9069b43074ba73d96dde1944cba276c54e41371745f9dc" +checksum = "aa53aa7e6bf2b3e8ccaffbcc963fbdb672a603dc0af393a481b6cec24c266406" dependencies = [ "anyhow", "bitflags 2.6.0", @@ -6159,17 +6158,17 @@ dependencies = [ "serde", "serde_derive", "serde_json", - "wasm-encoder", + "wasm-encoder 0.218.0", "wasm-metadata", - "wasmparser", + "wasmparser 0.218.0", "wit-parser", ] [[package]] name = "wit-parser" -version = "0.216.0" +version = "0.218.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4d108165c1167a4ccc8a803dcf5c28e0a51d6739fd228cc7adce768632c764c" +checksum = "0d3d1066ab761b115f97fef2b191090faabcb0f37b555b758d3caf42d4ed9e55" dependencies = [ "anyhow", "id-arena", @@ -6180,7 +6179,7 @@ dependencies = [ "serde_derive", "serde_json", "unicode-xid", - "wasmparser", + "wasmparser 0.218.0", ] [[package]] @@ -6238,7 +6237,7 @@ checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.79", "synstructure", ] @@ -6260,7 +6259,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.79", ] [[package]] @@ -6280,7 +6279,7 @@ checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.79", "synstructure", ] @@ -6303,5 +6302,5 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.75", + "syn 2.0.79", ] diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index 762ebc47ca9d..28d73fbe9f37 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -80,6 +80,10 @@ impl Stability { pub fn is_stable(&self) -> bool { self.level.is_stable() } + + pub fn stable_since(&self) -> Option { + self.level.stable_since() + } } /// Represents the `#[rustc_const_unstable]` and `#[rustc_const_stable]` attributes. @@ -170,6 +174,12 @@ impl StabilityLevel { pub fn is_stable(&self) -> bool { matches!(self, StabilityLevel::Stable { .. }) } + pub fn stable_since(&self) -> Option { + match *self { + StabilityLevel::Stable { since, .. } => Some(since), + StabilityLevel::Unstable { .. } => None, + } + } } #[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)] diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs index 4af5a10f5812..5ea48d3fc7e9 100644 --- a/compiler/rustc_borrowck/src/dataflow.rs +++ b/compiler/rustc_borrowck/src/dataflow.rs @@ -1,5 +1,3 @@ -use std::fmt; - use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::graph; use rustc_index::bit_set::BitSet; @@ -425,10 +423,6 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> { Borrows { tcx, body, borrow_set, borrows_out_of_scope_at_location } } - pub fn location(&self, idx: BorrowIndex) -> &Location { - &self.borrow_set[idx].reserve_location - } - /// Add all borrows to the kill set, if those borrows are out of scope at `location`. /// That means they went out of a nonlexical scope fn kill_loans_out_of_scope_at_location( @@ -615,8 +609,4 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> { } } -impl DebugWithContext> for BorrowIndex { - fn fmt_with(&self, ctxt: &Borrows<'_, '_>, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", ctxt.location(*self)) - } -} +impl DebugWithContext for BorrowIndex {} diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 16e51e82f85e..6b17879de262 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -2437,7 +2437,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { debug!(?src_tty, ?dst_tty, ?src_obj, ?dst_obj); - self.eq_types( + self.sub_types( src_obj, dst_obj, location.to_locations(), diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index 94e40da8c929..75dbb3d8e6ab 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -507,6 +507,7 @@ fn expand_preparsed_asm( let msg = "asm template must be a string literal"; let template_sp = template_expr.span; + let template_is_mac_call = matches!(template_expr.kind, ast::ExprKind::MacCall(_)); let (template_str, template_style, template_span) = { let ExpandResult::Ready(mac) = expr_to_spanned_string(ecx, template_expr, msg) else { return ExpandResult::Retry(()); @@ -596,7 +597,14 @@ fn expand_preparsed_asm( if !parser.errors.is_empty() { let err = parser.errors.remove(0); - let err_sp = template_span.from_inner(InnerSpan::new(err.span.start, err.span.end)); + let err_sp = if template_is_mac_call { + // If the template is a macro call we can't reliably point to the error's + // span so just use the template's span as the error span (fixes #129503) + template_span + } else { + template_span.from_inner(InnerSpan::new(err.span.start, err.span.end)) + }; + let msg = format!("invalid asm template string: {}", err.description); let mut e = ecx.dcx().struct_span_err(err_sp, msg); e.span_label(err_sp, err.label + " in asm template string"); diff --git a/compiler/rustc_builtin_macros/src/cfg.rs b/compiler/rustc_builtin_macros/src/cfg.rs index de198115fa00..cf1d5c68eadd 100644 --- a/compiler/rustc_builtin_macros/src/cfg.rs +++ b/compiler/rustc_builtin_macros/src/cfg.rs @@ -43,7 +43,7 @@ fn parse_cfg<'a>(cx: &ExtCtxt<'a>, span: Span, tts: TokenStream) -> PResult<'a, return Err(cx.dcx().create_err(errors::RequiresCfgPattern { span })); } - let cfg = p.parse_meta_item(AllowLeadingUnsafe::Yes)?; + let cfg = p.parse_meta_item(AllowLeadingUnsafe::No)?; let _ = p.eat(&token::Comma); diff --git a/compiler/rustc_builtin_macros/src/deriving/smart_ptr.rs b/compiler/rustc_builtin_macros/src/deriving/smart_ptr.rs index 12749e87dcbc..78028df2aa0e 100644 --- a/compiler/rustc_builtin_macros/src/deriving/smart_ptr.rs +++ b/compiler/rustc_builtin_macros/src/deriving/smart_ptr.rs @@ -310,7 +310,7 @@ pub(crate) fn expand_deriving_smart_ptr( // Add the impl blocks for `DispatchFromDyn` and `CoerceUnsized`. let gen_args = vec![GenericArg::Type(alt_self_type.clone())]; add_impl_block(impl_generics.clone(), sym::DispatchFromDyn, gen_args.clone()); - add_impl_block(impl_generics.clone(), sym::CoerceUnsized, gen_args.clone()); + add_impl_block(impl_generics.clone(), sym::CoerceUnsized, gen_args); } fn contains_maybe_sized_bound_on_pointee(predicates: &[WherePredicate], pointee: Symbol) -> bool { diff --git a/compiler/rustc_codegen_cranelift/patches/0027-stdlib-128bit-atomic-operations.patch b/compiler/rustc_codegen_cranelift/patches/0027-stdlib-128bit-atomic-operations.patch index a3f370af9169..646928893e96 100644 --- a/compiler/rustc_codegen_cranelift/patches/0027-stdlib-128bit-atomic-operations.patch +++ b/compiler/rustc_codegen_cranelift/patches/0027-stdlib-128bit-atomic-operations.patch @@ -82,19 +82,6 @@ index d9de37e..8293fce 100644 #[cfg(target_has_atomic_load_store = "ptr")] macro_rules! atomic_int_ptr_sized { ( $($target_pointer_width:literal $align:literal)* ) => { $( -diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs -index 58b9ba4..91bbd0a 100644 ---- a/library/core/src/cell.rs -+++ b/library/core/src/cell.rs -@@ -2246,8 +2246,6 @@ unsafe_cell_primitive_into_inner! { - u32 "32" - i64 "64" - u64 "64" -- i128 "128" -- u128 "128" - isize "ptr" - usize "ptr" - } -- 2.26.2.7.g19db9cfb68 diff --git a/compiler/rustc_codegen_cranelift/src/unsize.rs b/compiler/rustc_codegen_cranelift/src/unsize.rs index 339628053a95..5c297ebfadbf 100644 --- a/compiler/rustc_codegen_cranelift/src/unsize.rs +++ b/compiler/rustc_codegen_cranelift/src/unsize.rs @@ -2,6 +2,7 @@ //! //! [`PointerCoercion::Unsize`]: `rustc_middle::ty::adjustment::PointerCoercion::Unsize` +use rustc_codegen_ssa::base::validate_trivial_unsize; use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths}; use crate::base::codegen_panic_nounwind; @@ -34,20 +35,8 @@ pub(crate) fn unsized_info<'tcx>( let old_info = old_info.expect("unsized_info: missing old info for trait upcasting coercion"); if data_a.principal_def_id() == data_b.principal_def_id() { - // Codegen takes advantage of the additional assumption, where if the - // principal trait def id of what's being casted doesn't change, - // then we don't need to adjust the vtable at all. This - // corresponds to the fact that `dyn Tr: Unsize>` - // requires that `A = B`; we don't allow *upcasting* objects - // between the same trait with different args. If we, for - // some reason, were to relax the `Unsize` trait, it could become - // unsound, so let's assert here that the trait refs are *equal*. - // - // We can use `assert_eq` because the binders should have been anonymized, - // and because higher-ranked equality now requires the binders are equal. - debug_assert_eq!( - data_a.principal(), - data_b.principal(), + debug_assert!( + validate_trivial_unsize(fx.tcx, data_a, data_b), "NOP unsize vtable changed principal trait ref: {data_a} -> {data_b}" ); return old_info; diff --git a/compiler/rustc_codegen_gcc/.github/workflows/ci.yml b/compiler/rustc_codegen_gcc/.github/workflows/ci.yml index cd366dbae160..704d7b9c2fd6 100644 --- a/compiler/rustc_codegen_gcc/.github/workflows/ci.yml +++ b/compiler/rustc_codegen_gcc/.github/workflows/ci.yml @@ -36,7 +36,7 @@ jobs: ] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 # `rustup show` installs from rust-toolchain.toml - name: Setup rust toolchain @@ -113,13 +113,13 @@ jobs: duplicates: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - run: python tools/check_intrinsics_duplicates.py build_system: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Test build system run: | cd build_system diff --git a/compiler/rustc_codegen_gcc/.github/workflows/failures.yml b/compiler/rustc_codegen_gcc/.github/workflows/failures.yml index e5d94767fe7d..2c1ed9ad4294 100644 --- a/compiler/rustc_codegen_gcc/.github/workflows/failures.yml +++ b/compiler/rustc_codegen_gcc/.github/workflows/failures.yml @@ -31,7 +31,7 @@ jobs: env_extra: "TEST_FLAGS='-Cpanic=abort -Zpanic-abort-tests' GCC_EXEC_PREFIX=/usr/lib/gcc/" steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 # `rustup show` installs from rust-toolchain.toml - name: Setup rust toolchain diff --git a/compiler/rustc_codegen_gcc/.github/workflows/gcc12.yml b/compiler/rustc_codegen_gcc/.github/workflows/gcc12.yml index 5977ed33c56e..7dcad21a02e1 100644 --- a/compiler/rustc_codegen_gcc/.github/workflows/gcc12.yml +++ b/compiler/rustc_codegen_gcc/.github/workflows/gcc12.yml @@ -33,7 +33,7 @@ jobs: ] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 # `rustup show` installs from rust-toolchain.toml - name: Setup rust toolchain diff --git a/compiler/rustc_codegen_gcc/.github/workflows/m68k.yml b/compiler/rustc_codegen_gcc/.github/workflows/m68k.yml index 34e4f2b0d412..1c864e04413f 100644 --- a/compiler/rustc_codegen_gcc/.github/workflows/m68k.yml +++ b/compiler/rustc_codegen_gcc/.github/workflows/m68k.yml @@ -36,7 +36,7 @@ jobs: ] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 # `rustup show` installs from rust-toolchain.toml - name: Setup rust toolchain @@ -85,14 +85,14 @@ jobs: - name: Build sample project with target defined as JSON spec run: | ./y.sh prepare --only-libcore --cross - ./y.sh build --sysroot --target-triple m68k-unknown-linux-gnu --target ${{ github.workspace }}/target_specs/m68k-unknown-linux-gnu.json + ./y.sh build --sysroot --features compiler_builtins/no-f16-f128 --target-triple m68k-unknown-linux-gnu --target ${{ github.workspace }}/target_specs/m68k-unknown-linux-gnu.json ./y.sh cargo build --manifest-path=./tests/hello-world/Cargo.toml --target ${{ github.workspace }}/target_specs/m68k-unknown-linux-gnu.json ./y.sh clean all - name: Build run: | ./y.sh prepare --only-libcore --cross - ./y.sh build --sysroot --target-triple m68k-unknown-linux-gnu + ./y.sh build --sysroot --features compiler_builtins/no-f16-f128 --target-triple m68k-unknown-linux-gnu CG_GCC_TEST_TARGET=m68k-unknown-linux-gnu cargo test ./y.sh clean all @@ -107,4 +107,4 @@ jobs: - name: Run tests run: | - ./y.sh test --release --clean --build-sysroot ${{ matrix.commands }} + ./y.sh test --release --clean --build-sysroot --sysroot-features compiler_builtins/no-f16-f128 ${{ matrix.commands }} diff --git a/compiler/rustc_codegen_gcc/.github/workflows/release.yml b/compiler/rustc_codegen_gcc/.github/workflows/release.yml index d5242926eb4d..d5c06a836db9 100644 --- a/compiler/rustc_codegen_gcc/.github/workflows/release.yml +++ b/compiler/rustc_codegen_gcc/.github/workflows/release.yml @@ -24,7 +24,7 @@ jobs: ] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 # `rustup show` installs from rust-toolchain.toml - name: Setup rust toolchain diff --git a/compiler/rustc_codegen_gcc/.github/workflows/stdarch.yml b/compiler/rustc_codegen_gcc/.github/workflows/stdarch.yml index e24b25b73690..d8818eefa96d 100644 --- a/compiler/rustc_codegen_gcc/.github/workflows/stdarch.yml +++ b/compiler/rustc_codegen_gcc/.github/workflows/stdarch.yml @@ -13,7 +13,7 @@ env: jobs: build: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 strategy: fail-fast: false @@ -24,7 +24,7 @@ jobs: ] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 # `rustup show` installs from rust-toolchain.toml - name: Setup rust toolchain @@ -36,6 +36,13 @@ jobs: - name: Install packages run: sudo apt-get install ninja-build ripgrep + # TODO: remove when we have binutils version 2.43 in the repo. + - name: Install more recent binutils + run: | + echo "deb http://archive.ubuntu.com/ubuntu oracular main universe" | sudo tee /etc/apt/sources.list.d/oracular-copies.list + sudo apt-get update + sudo apt-get install binutils + - name: Install Intel Software Development Emulator if: ${{ matrix.cargo_runner }} run: | @@ -96,4 +103,5 @@ jobs: run: | # FIXME: these tests fail when the sysroot is compiled with LTO because of a missing symbol in proc-macro. # TODO: remove --skip test_mm512_stream_ps when stdarch is updated in rustc. - STDARCH_TEST_EVERYTHING=1 CHANNEL=release CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_RUNNER="${{ matrix.cargo_runner }}" TARGET=x86_64-unknown-linux-gnu CG_RUSTFLAGS="-Ainternal_features" ./y.sh cargo test --manifest-path build/build_sysroot/sysroot_src/library/stdarch/Cargo.toml -- --skip rtm --skip tbm --skip sse4a --skip test_mm512_stream_ps + # TODO: remove --skip test_tile_ when it's implemented. + STDARCH_TEST_EVERYTHING=1 CHANNEL=release CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_RUNNER="${{ matrix.cargo_runner }}" TARGET=x86_64-unknown-linux-gnu CG_RUSTFLAGS="-Ainternal_features --cfg stdarch_intel_sde" ./y.sh cargo test --manifest-path build/build_sysroot/sysroot_src/library/stdarch/Cargo.toml -- --skip rtm --skip tbm --skip sse4a --skip test_mm512_stream_ps --skip test_tile_ diff --git a/compiler/rustc_codegen_gcc/Cargo.lock b/compiler/rustc_codegen_gcc/Cargo.lock index 0eb264f99eb0..6b06e7d7f278 100644 --- a/compiler/rustc_codegen_gcc/Cargo.lock +++ b/compiler/rustc_codegen_gcc/Cargo.lock @@ -28,18 +28,18 @@ dependencies = [ [[package]] name = "gccjit" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62e0ba949ebee07c5cc21f02cb48f28f2c8db7fcbc15fdc5120476a6c43b4636" +checksum = "4bb376e98c82d9284c3a17fc1d6bf9bc921055418950238d7a553c27a7e1f6ab" dependencies = [ "gccjit_sys", ] [[package]] name = "gccjit_sys" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5bbf85e12c2593772329a9d4e8310271f6706e6045ce4f41b041dd34fba6603" +checksum = "93b4b1be553b5df790bf25ca2a1d6add81727dc29f8d5c8742468ed306d621d1" dependencies = [ "libc", ] diff --git a/compiler/rustc_codegen_gcc/Cargo.toml b/compiler/rustc_codegen_gcc/Cargo.toml index 44fb5eef04a5..4828b7ddb168 100644 --- a/compiler/rustc_codegen_gcc/Cargo.toml +++ b/compiler/rustc_codegen_gcc/Cargo.toml @@ -22,7 +22,9 @@ master = ["gccjit/master"] default = ["master"] [dependencies] -gccjit = "2.1" +gccjit = "2.2" +#gccjit = { git = "https://github.com/rust-lang/gccjit.rs" } + # Local copy. #gccjit = { path = "../gccjit.rs" } diff --git a/compiler/rustc_codegen_gcc/build_system/build_sysroot/Cargo.lock b/compiler/rustc_codegen_gcc/build_system/build_sysroot/Cargo.lock index 771f2f18dce7..51bec5aa9e37 100644 --- a/compiler/rustc_codegen_gcc/build_system/build_sysroot/Cargo.lock +++ b/compiler/rustc_codegen_gcc/build_system/build_sysroot/Cargo.lock @@ -4,12 +4,12 @@ version = 3 [[package]] name = "addr2line" -version = "0.21.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" dependencies = [ "compiler_builtins", - "gimli", + "gimli 0.29.0", "rustc-std-workspace-alloc", "rustc-std-workspace-core", ] @@ -52,7 +52,7 @@ dependencies = [ name = "compiler_builtins" version = "0.1.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f11973008a8cf741fe6d22f339eba21fd0ca81e2760a769ba8243ed6c21edd7e" +checksum = "92afe7344b64cccf3662ca26d5d1c0828ab826f04206b97d856e3625e390e4b5" dependencies = [ "rustc-std-workspace-core", ] @@ -97,9 +97,20 @@ dependencies = [ [[package]] name = "gimli" -version = "0.28.1" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" +dependencies = [ + "compiler_builtins", + "rustc-std-workspace-alloc", + "rustc-std-workspace-core", +] + +[[package]] +name = "gimli" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2e1d97fbe9722ba9bbd0c97051c2956e726562b61f86a25a4360398a40edfc9" dependencies = [ "compiler_builtins", "rustc-std-workspace-alloc", @@ -120,9 +131,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.3.9" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" dependencies = [ "compiler_builtins", "rustc-std-workspace-alloc", @@ -131,18 +142,18 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.153" +version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" dependencies = [ "rustc-std-workspace-core", ] [[package]] name = "memchr" -version = "2.7.2" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" dependencies = [ "compiler_builtins", "rustc-std-workspace-core", @@ -150,9 +161,9 @@ dependencies = [ [[package]] name = "miniz_oxide" -version = "0.7.2" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" +checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" dependencies = [ "adler", "compiler_builtins", @@ -162,9 +173,9 @@ dependencies = [ [[package]] name = "object" -version = "0.32.2" +version = "0.36.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +checksum = "27b64972346851a39438c60b341ebc01bba47464ae329e55cf343eb93964efd9" dependencies = [ "compiler_builtins", "memchr", @@ -205,9 +216,9 @@ dependencies = [ [[package]] name = "r-efi" -version = "4.4.0" +version = "4.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c47196f636c4cc0634b73b0405323d177753c2e15e866952c64ea22902567a34" +checksum = "e9e935efc5854715dfc0a4c9ef18dc69dee0ec3bf9cc3ab740db831c0fdd86a3" dependencies = [ "compiler_builtins", "rustc-std-workspace-core", @@ -226,9 +237,9 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" dependencies = [ "compiler_builtins", "rustc-std-workspace-core", @@ -310,16 +321,14 @@ dependencies = [ "core", "getopts", "libc", - "panic_abort", - "panic_unwind", "std", ] [[package]] name = "unicode-width" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68f5e5f3158ecfd4b8ff6fe086db7c8467a2dfdac97fe420f2b7c4aa97af66d6" +checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" dependencies = [ "compiler_builtins", "rustc-std-workspace-core", @@ -339,12 +348,12 @@ dependencies = [ [[package]] name = "unwinding" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37a19a21a537f635c16c7576f22d0f2f7d63353c1337ad4ce0d8001c7952a25b" +checksum = "dc55842d0db6329a669d55a623c674b02d677b16bfb2d24857d4089d41eba882" dependencies = [ "compiler_builtins", - "gimli", + "gimli 0.30.0", "rustc-std-workspace-core", ] @@ -370,9 +379,9 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", @@ -386,48 +395,48 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" diff --git a/compiler/rustc_codegen_gcc/build_system/build_sysroot/Cargo.toml b/compiler/rustc_codegen_gcc/build_system/build_sysroot/Cargo.toml index 05503128f2af..24152070e645 100644 --- a/compiler/rustc_codegen_gcc/build_system/build_sysroot/Cargo.toml +++ b/compiler/rustc_codegen_gcc/build_system/build_sysroot/Cargo.toml @@ -17,6 +17,22 @@ rustc-std-workspace-core = { path = "./sysroot_src/library/rustc-std-workspace-c rustc-std-workspace-alloc = { path = "./sysroot_src/library/rustc-std-workspace-alloc" } rustc-std-workspace-std = { path = "./sysroot_src/library/rustc-std-workspace-std" } +# For compiler-builtins we always use a high number of codegen units. +# The goal here is to place every single intrinsic into its own object +# file to avoid symbol clashes with the system libgcc if possible. Note +# that this number doesn't actually produce this many object files, we +# just don't create more than this number of object files. +# +# It's a bit of a bummer that we have to pass this here, unfortunately. +# Ideally this would be specified through an env var to Cargo so Cargo +# knows how many CGUs are for this specific crate, but for now +# per-crate configuration isn't specifiable in the environment. +[profile.dev.package.compiler_builtins] +codegen-units = 10000 + +[profile.release.package.compiler_builtins] +codegen-units = 10000 + [profile.release] debug = "limited" #lto = "fat" # TODO(antoyo): re-enable when the failing LTO tests regarding proc-macros are fixed. diff --git a/compiler/rustc_codegen_gcc/build_system/src/build.rs b/compiler/rustc_codegen_gcc/build_system/src/build.rs index 8d9518653c5c..d0ced211a616 100644 --- a/compiler/rustc_codegen_gcc/build_system/src/build.rs +++ b/compiler/rustc_codegen_gcc/build_system/src/build.rs @@ -24,16 +24,6 @@ impl BuildArg { while let Some(arg) = args.next() { match arg.as_str() { - "--features" => { - if let Some(arg) = args.next() { - build_arg.flags.push("--features".to_string()); - build_arg.flags.push(arg.as_str().into()); - } else { - return Err( - "Expected a value after `--features`, found nothing".to_string() - ); - } - } "--sysroot" => { build_arg.build_sysroot = true; } @@ -56,7 +46,6 @@ impl BuildArg { r#" `build` command help: - --features [arg] : Add a new feature [arg] --sysroot : Build with sysroot"# ); ConfigInfo::show_usage(); @@ -142,14 +131,11 @@ pub fn build_sysroot(env: &HashMap, config: &ConfigInfo) -> Resu rustflags.push_str(" -Csymbol-mangling-version=v0"); } - let mut args: Vec<&dyn AsRef> = vec![ - &"cargo", - &"build", - &"--target", - &config.target, - &"--features", - &"compiler-builtins-no-f16-f128", - ]; + let mut args: Vec<&dyn AsRef> = vec![&"cargo", &"build", &"--target", &config.target]; + for feature in &config.features { + args.push(&"--features"); + args.push(feature); + } if config.no_default_features { rustflags.push_str(" -Csymbol-mangling-version=v0"); diff --git a/compiler/rustc_codegen_gcc/build_system/src/config.rs b/compiler/rustc_codegen_gcc/build_system/src/config.rs index a7980dec83b6..37b4b68950e4 100644 --- a/compiler/rustc_codegen_gcc/build_system/src/config.rs +++ b/compiler/rustc_codegen_gcc/build_system/src/config.rs @@ -98,7 +98,7 @@ impl ConfigFile { } } -#[derive(Default, Debug)] +#[derive(Default, Debug, Clone)] pub struct ConfigInfo { pub target: String, pub target_triple: String, @@ -123,6 +123,7 @@ pub struct ConfigInfo { pub no_download: bool, pub no_default_features: bool, pub backend: Option, + pub features: Vec, } impl ConfigInfo { @@ -133,6 +134,13 @@ impl ConfigInfo { args: &mut impl Iterator, ) -> Result { match arg { + "--features" => { + if let Some(arg) = args.next() { + self.features.push(arg); + } else { + return Err("Expected a value after `--features`, found nothing".to_string()); + } + } "--target" => { if let Some(arg) = args.next() { self.target = arg; @@ -443,6 +451,7 @@ impl ConfigInfo { pub fn show_usage() { println!( "\ + --features [arg] : Add a new feature [arg] --target-triple [arg] : Set the target triple to [arg] --target [arg] : Set the target to [arg] --out-dir : Location where the files will be generated diff --git a/compiler/rustc_codegen_gcc/build_system/src/test.rs b/compiler/rustc_codegen_gcc/build_system/src/test.rs index 50e27736aac2..c69e240c01de 100644 --- a/compiler/rustc_codegen_gcc/build_system/src/test.rs +++ b/compiler/rustc_codegen_gcc/build_system/src/test.rs @@ -92,6 +92,7 @@ struct TestArg { current_part: Option, sysroot_panic_abort: bool, config_info: ConfigInfo, + sysroot_features: Vec, } impl TestArg { @@ -127,6 +128,14 @@ impl TestArg { "--sysroot-panic-abort" => { test_arg.sysroot_panic_abort = true; } + "--sysroot-features" => match args.next() { + Some(feature) if !feature.is_empty() => { + test_arg.sysroot_features.push(feature); + } + _ => { + return Err(format!("Expected an argument after `{}`, found nothing", arg)); + } + }, "--help" => { show_usage(); return Ok(None); @@ -250,7 +259,9 @@ fn mini_tests(env: &Env, args: &TestArg) -> Result<(), String> { fn build_sysroot(env: &Env, args: &TestArg) -> Result<(), String> { // FIXME: create a function "display_if_not_quiet" or something along the line. println!("[BUILD] sysroot"); - build::build_sysroot(env, &args.config_info)?; + let mut config = args.config_info.clone(); + config.features.extend(args.sysroot_features.iter().cloned()); + build::build_sysroot(env, &config)?; Ok(()) } @@ -626,7 +637,8 @@ fn test_projects(env: &Env, args: &TestArg) -> Result<(), String> { "https://github.com/BurntSushi/memchr", "https://github.com/dtolnay/itoa", "https://github.com/rust-lang/cfg-if", - "https://github.com/rust-lang-nursery/lazy-static.rs", + //"https://github.com/rust-lang-nursery/lazy-static.rs", // TODO: re-enable when the + //failing test is fixed upstream. //"https://github.com/marshallpierce/rust-base64", // FIXME: one test is OOM-killed. // TODO: ignore the base64 test that is OOM-killed. "https://github.com/time-rs/time", diff --git a/compiler/rustc_codegen_gcc/doc/debugging-gcc-lto.md b/compiler/rustc_codegen_gcc/doc/debugging-gcc-lto.md deleted file mode 100644 index 93b150d76865..000000000000 --- a/compiler/rustc_codegen_gcc/doc/debugging-gcc-lto.md +++ /dev/null @@ -1,3 +0,0 @@ -# How to debug GCC LTO - -Run do the command with `-v -save-temps` and then extract the `lto1` line from the output and run that under the debugger. diff --git a/compiler/rustc_codegen_gcc/doc/debugging.md b/compiler/rustc_codegen_gcc/doc/debugging.md new file mode 100644 index 000000000000..6ff4edf8877c --- /dev/null +++ b/compiler/rustc_codegen_gcc/doc/debugging.md @@ -0,0 +1,38 @@ +# Debugging + +## How to debug GCC LTO + +Run do the command with `-v -save-temps` and then extract the `lto1` line from the output and run that under the debugger. + +## How to debug stdarch tests that cannot be ran locally + +First, run the tests normally: + +---- +cd build/build_sysroot/sysroot_src/library/stdarch/ +STDARCH_TEST_EVERYTHING=1 CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_RUNNER="sde -future -rtm_mode full --" TARGET=x86_64-unknown-linux-gnu ../../../../../y.sh cargo test +---- + +It will show the command it ran, something like this: + +---- + process didn't exit successfully: `sde -future -rtm_mode full -- /home/user/projects/rustc_codegen_gcc/build/build_sysroot/sysroot_src/library/stdarch/target/debug/deps/core_arch-fd2d75f89baae5c6` (signal: 11, SIGSEGV: invalid memory reference) +---- + +Then add the `-debug` flag to it: + +---- +sde -debug -future -rtm_mode full -- /home/user/projects/rustc_codegen_gcc/build/build_sysroot/sysroot_src/library/stdarch/target/debug/deps/core_arch-fd2d75f89baae5c6 +---- + +To see the symbols in `gdb`, specify the executable in your command: + +---- +gdb /home/user/projects/rustc_codegen_gcc/build/build_sysroot/sysroot_src/library/stdarch/target/debug/deps/core_arch-fd2d75f89baae5c6 +---- + +and then write the `gdb` command that `sde` tells you to use, something like: + +---- +target remote :51299 +---- diff --git a/compiler/rustc_codegen_gcc/libgccjit.version b/compiler/rustc_codegen_gcc/libgccjit.version index 23ca7f022155..b9bbbd324c3b 100644 --- a/compiler/rustc_codegen_gcc/libgccjit.version +++ b/compiler/rustc_codegen_gcc/libgccjit.version @@ -1 +1 @@ -341be3b7d7ac6976cfed8ed59da3573c040d0776 +e744a9459d33864067214741daf5c5bc2a7b88c6 diff --git a/compiler/rustc_codegen_gcc/patches/0022-core-Disable-not-compiling-tests.patch b/compiler/rustc_codegen_gcc/patches/0022-core-Disable-not-compiling-tests.patch index ea1a5a8d3553..b2ab05691ecb 100644 --- a/compiler/rustc_codegen_gcc/patches/0022-core-Disable-not-compiling-tests.patch +++ b/compiler/rustc_codegen_gcc/patches/0022-core-Disable-not-compiling-tests.patch @@ -1,26 +1,24 @@ -From f6befc4bb51d84f5f1cf35938a168c953d421350 Mon Sep 17 00:00:00 2001 -From: bjorn3 -Date: Sun, 24 Nov 2019 15:10:23 +0100 +From 18793c6109890493ceb3ff36549849a36e3d8022 Mon Sep 17 00:00:00 2001 +From: None +Date: Sun, 1 Sep 2024 11:42:17 -0400 Subject: [PATCH] [core] Disable not compiling tests --- - library/core/tests/Cargo.toml | 8 ++++++++ - library/core/tests/num/flt2dec/mod.rs | 1 - - library/core/tests/num/int_macros.rs | 2 ++ - library/core/tests/num/uint_macros.rs | 2 ++ - library/core/tests/ptr.rs | 2 ++ - library/core/tests/slice.rs | 2 ++ - 6 files changed, 16 insertions(+), 1 deletion(-) + library/core/tests/Cargo.toml | 14 ++++++++++++++ + library/core/tests/lib.rs | 1 + + 2 files changed, 15 insertions(+) create mode 100644 library/core/tests/Cargo.toml diff --git a/library/core/tests/Cargo.toml b/library/core/tests/Cargo.toml new file mode 100644 -index 0000000..46fd999 +index 0000000..ca326ac --- /dev/null +++ b/library/core/tests/Cargo.toml -@@ -0,0 +1,12 @@ +@@ -0,0 +1,14 @@ ++[workspace] ++ +[package] -+name = "core" ++name = "coretests" +version = "0.0.0" +edition = "2021" + @@ -32,11 +30,14 @@ index 0000000..46fd999 +rand = { version = "0.8.5", default-features = false } +rand_xorshift = { version = "0.3.0", default-features = false } diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs -index 42a26ae..5ac1042 100644 +index 1e336bf..5800ebb 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs -@@ -1,3 +1,4 @@ +@@ -1,4 +1,5 @@ + // tidy-alphabetical-start +#![cfg(test)] - #![feature(alloc_layout_extra)] - #![feature(array_chunks)] - #![feature(array_ptr_get)] + #![cfg_attr(bootstrap, feature(offset_of_nested))] + #![cfg_attr(target_has_atomic = "128", feature(integer_atomics))] + #![cfg_attr(test, feature(cfg_match))] +-- +2.46.0 diff --git a/compiler/rustc_codegen_gcc/patches/libgccjit12/0001-core-Disable-portable-simd-test.patch b/compiler/rustc_codegen_gcc/patches/libgccjit12/0001-core-Disable-portable-simd-test.patch index 42ae534e464d..01461987ffb1 100644 --- a/compiler/rustc_codegen_gcc/patches/libgccjit12/0001-core-Disable-portable-simd-test.patch +++ b/compiler/rustc_codegen_gcc/patches/libgccjit12/0001-core-Disable-portable-simd-test.patch @@ -11,15 +11,15 @@ diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index b71786c..cf484d5 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs -@@ -95,7 +95,6 @@ - #![feature(never_type)] - #![feature(unwrap_infallible)] +@@ -87,7 +87,6 @@ + #![feature(numfmt)] + #![feature(pattern)] #![feature(pointer_is_aligned_to)] -#![feature(portable_simd)] #![feature(ptr_metadata)] - #![feature(unsized_tuple_coercion)] - #![feature(const_option)] -@@ -157,7 +156,6 @@ mod pin; + #![feature(slice_from_ptr_range)] + #![feature(slice_internals)] +@@ -155,7 +154,6 @@ mod pin; mod pin_macro; mod ptr; mod result; diff --git a/compiler/rustc_codegen_gcc/rust-toolchain b/compiler/rustc_codegen_gcc/rust-toolchain index 3c83f4b4608d..dca3b0c22e4e 100644 --- a/compiler/rustc_codegen_gcc/rust-toolchain +++ b/compiler/rustc_codegen_gcc/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2024-07-02" +channel = "nightly-2024-08-11" components = ["rust-src", "rustc-dev", "llvm-tools-preview"] diff --git a/compiler/rustc_codegen_gcc/src/allocator.rs b/compiler/rustc_codegen_gcc/src/allocator.rs index e9498857fb9a..f13a75648aea 100644 --- a/compiler/rustc_codegen_gcc/src/allocator.rs +++ b/compiler/rustc_codegen_gcc/src/allocator.rs @@ -104,10 +104,17 @@ fn create_wrapper_function( false, ); - if tcx.sess.default_hidden_visibility() { - #[cfg(feature = "master")] - func.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden)); + #[cfg(feature = "master")] + match tcx.sess.default_visibility() { + rustc_target::spec::SymbolVisibility::Hidden => { + func.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden)) + } + rustc_target::spec::SymbolVisibility::Protected => { + func.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Protected)) + } + rustc_target::spec::SymbolVisibility::Interposable => {} } + if tcx.sess.must_emit_unwind_tables() { // TODO(antoyo): emit unwind tables. } diff --git a/compiler/rustc_codegen_gcc/src/asm.rs b/compiler/rustc_codegen_gcc/src/asm.rs index 13a00f7e08d8..a04cd4735f47 100644 --- a/compiler/rustc_codegen_gcc/src/asm.rs +++ b/compiler/rustc_codegen_gcc/src/asm.rs @@ -682,6 +682,11 @@ fn reg_to_gcc(reg: InlineAsmRegOrRegClass) -> ConstraintOrRegister { InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg) => "r", InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg_addr) => "a", InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => "f", + InlineAsmRegClass::S390x( + S390xInlineAsmRegClass::vreg | S390xInlineAsmRegClass::areg, + ) => { + unreachable!("clobber-only") + } InlineAsmRegClass::Err => unreachable!(), }, }; @@ -757,6 +762,9 @@ fn dummy_output_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, reg: InlineAsmRegCl S390xInlineAsmRegClass::reg | S390xInlineAsmRegClass::reg_addr, ) => cx.type_i32(), InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => cx.type_f64(), + InlineAsmRegClass::S390x(S390xInlineAsmRegClass::vreg | S390xInlineAsmRegClass::areg) => { + unreachable!("clobber-only") + } InlineAsmRegClass::Msp430(Msp430InlineAsmRegClass::reg) => cx.type_i16(), InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg) => cx.type_i32(), InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg_addr) => cx.type_i32(), diff --git a/compiler/rustc_codegen_gcc/src/base.rs b/compiler/rustc_codegen_gcc/src/base.rs index 9836e654f37f..18aa32754e1d 100644 --- a/compiler/rustc_codegen_gcc/src/base.rs +++ b/compiler/rustc_codegen_gcc/src/base.rs @@ -128,8 +128,19 @@ pub fn compile_codegen_unit( // NOTE: Rust relies on LLVM doing wrapping on overflow. context.add_command_line_option("-fwrapv"); + if let Some(model) = tcx.sess.code_model() { + use rustc_target::spec::CodeModel; + + context.add_command_line_option(match model { + CodeModel::Tiny => "-mcmodel=tiny", + CodeModel::Small => "-mcmodel=small", + CodeModel::Kernel => "-mcmodel=kernel", + CodeModel::Medium => "-mcmodel=medium", + CodeModel::Large => "-mcmodel=large", + }); + } + if tcx.sess.relocation_model() == rustc_target::spec::RelocModel::Static { - context.add_command_line_option("-mcmodel=kernel"); context.add_command_line_option("-fno-pie"); } diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs index b68733043823..acd535888316 100644 --- a/compiler/rustc_codegen_gcc/src/builder.rs +++ b/compiler/rustc_codegen_gcc/src/builder.rs @@ -39,9 +39,6 @@ use crate::type_of::LayoutGccExt; // TODO(antoyo) type Funclet = (); -// TODO(antoyo): remove this variable. -static mut RETURN_VALUE_COUNT: usize = 0; - enum ExtremumOperation { Max, Min, @@ -50,13 +47,18 @@ enum ExtremumOperation { pub struct Builder<'a: 'gcc, 'gcc, 'tcx> { pub cx: &'a CodegenCx<'gcc, 'tcx>, pub block: Block<'gcc>, - stack_var_count: Cell, pub location: Option>, + value_counter: Cell, } impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { fn with_cx(cx: &'a CodegenCx<'gcc, 'tcx>, block: Block<'gcc>) -> Self { - Builder { cx, block, stack_var_count: Cell::new(0), location: None } + Builder { cx, block, location: None, value_counter: Cell::new(0) } + } + + fn next_value_counter(&self) -> u64 { + self.value_counter.set(self.value_counter.get() + 1); + self.value_counter.get() } fn atomic_extremum( @@ -138,7 +140,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { ) -> RValue<'gcc> { let size = get_maybe_pointer_size(src); let compare_exchange = - self.context.get_builtin_function(&format!("__atomic_compare_exchange_{}", size)); + self.context.get_builtin_function(format!("__atomic_compare_exchange_{}", size)); let order = self.context.new_rvalue_from_int(self.i32_type, order.to_gcc()); let failure_order = self.context.new_rvalue_from_int(self.i32_type, failure_order.to_gcc()); let weak = self.context.new_rvalue_from_int(self.bool_type, weak as i32); @@ -270,10 +272,12 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { actual_val.dereference(self.location).to_rvalue() } } else { + // FIXME: this condition seems wrong: it will pass when both types are not + // a vector. assert!( (!expected_ty.is_vector() || actual_ty.is_vector()) && (expected_ty.is_vector() || !actual_ty.is_vector()), - "{:?} ({}) -> {:?} ({}), index: {:?}[{}]", + "{:?} (is vector: {}) -> {:?} (is vector: {}), Function: {:?}[{}]", actual_ty, actual_ty.is_vector(), expected_ty, @@ -283,6 +287,8 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { ); // TODO(antoyo): perhaps use __builtin_convertvector for vector casting. // TODO: remove bitcast now that vector types can be compared? + // ==> We use bitcast to avoid having to do many manual casts from e.g. __m256i to __v32qi (in + // the case of _mm256_aesenc_epi128). self.bitcast(actual_val, expected_ty) } } else { @@ -325,11 +331,10 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let void_type = self.context.new_type::<()>(); let current_func = self.block.get_function(); if return_type != void_type { - unsafe { RETURN_VALUE_COUNT += 1 }; let result = current_func.new_local( self.location, return_type, - &format!("returnValue{}", unsafe { RETURN_VALUE_COUNT }), + format!("returnValue{}", self.next_value_counter()), ); self.block.add_assignment( self.location, @@ -341,7 +346,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { self.block .add_eval(self.location, self.cx.context.new_call(self.location, func, &args)); // Return dummy value when not having return value. - self.context.new_rvalue_from_long(self.isize_type, 0) + self.context.new_rvalue_zero(self.isize_type) } } @@ -367,6 +372,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let args = { let function_address_names = self.function_address_names.borrow(); let original_function_name = function_address_names.get(&func_ptr); + func_ptr = llvm::adjust_function(self.context, &func_name, func_ptr, args); llvm::adjust_intrinsic_arguments( self, gcc_func, @@ -385,7 +391,6 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let current_func = self.block.get_function(); if return_type != void_type { - unsafe { RETURN_VALUE_COUNT += 1 }; let return_value = self.cx.context.new_call_through_ptr(self.location, func_ptr, &args); let return_value = llvm::adjust_intrinsic_return_value( self, @@ -398,7 +403,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let result = current_func.new_local( self.location, return_value.get_type(), - &format!("ptrReturnValue{}", unsafe { RETURN_VALUE_COUNT }), + format!("ptrReturnValue{}", self.next_value_counter()), ); self.block.add_assignment(self.location, result, return_value); result.to_rvalue() @@ -422,17 +427,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { self.cx.context.new_call_through_ptr(self.location, func_ptr, &args), ); // Return dummy value when not having return value. - let result = current_func.new_local( - self.location, - self.isize_type, - "dummyValueThatShouldNeverBeUsed", - ); - self.block.add_assignment( - self.location, - result, - self.context.new_rvalue_from_long(self.isize_type, 0), - ); - result.to_rvalue() + self.context.new_rvalue_zero(self.isize_type) } } @@ -447,11 +442,10 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { let return_type = self.context.new_type::(); let current_func = self.block.get_function(); // TODO(antoyo): return the new_call() directly? Since the overflow function has no side-effects. - unsafe { RETURN_VALUE_COUNT += 1 }; let result = current_func.new_local( self.location, return_type, - &format!("overflowReturnValue{}", unsafe { RETURN_VALUE_COUNT }), + format!("overflowReturnValue{}", self.next_value_counter()), ); self.block.add_assignment( self.location, @@ -930,9 +924,8 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { fn alloca(&mut self, size: Size, align: Align) -> RValue<'gcc> { let ty = self.cx.type_array(self.cx.type_i8(), size.bytes()).get_aligned(align.bytes()); // TODO(antoyo): It might be better to return a LValue, but fixing the rustc API is non-trivial. - self.stack_var_count.set(self.stack_var_count.get() + 1); self.current_func() - .new_local(self.location, ty, &format!("stack_var_{}", self.stack_var_count.get())) + .new_local(self.location, ty, format!("stack_var_{}", self.next_value_counter())) .get_address(self.location) } @@ -955,11 +948,10 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { }; let ptr = self.context.new_cast(self.location, ptr, aligned_type.make_pointer()); let deref = ptr.dereference(self.location).to_rvalue(); - unsafe { RETURN_VALUE_COUNT += 1 }; let loaded_value = function.new_local( self.location, aligned_type, - &format!("loadedValue{}", unsafe { RETURN_VALUE_COUNT }), + format!("loadedValue{}", self.next_value_counter()), ); block.add_assignment(self.location, loaded_value, deref); loaded_value.to_rvalue() @@ -980,7 +972,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { // TODO(antoyo): use ty. // TODO(antoyo): handle alignment. let atomic_load = - self.context.get_builtin_function(&format!("__atomic_load_{}", size.bytes())); + self.context.get_builtin_function(format!("__atomic_load_{}", size.bytes())); let ordering = self.context.new_rvalue_from_int(self.i32_type, order.to_gcc()); let volatile_const_void_ptr_type = @@ -1136,7 +1128,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { ) { // TODO(antoyo): handle alignment. let atomic_store = - self.context.get_builtin_function(&format!("__atomic_store_{}", size.bytes())); + self.context.get_builtin_function(format!("__atomic_store_{}", size.bytes())); let ordering = self.context.new_rvalue_from_int(self.i32_type, order.to_gcc()); let volatile_const_void_ptr_type = self.context.new_type::<()>().make_volatile().make_pointer(); diff --git a/compiler/rustc_codegen_gcc/src/consts.rs b/compiler/rustc_codegen_gcc/src/consts.rs index 5ad5117d7fd4..3029b9341795 100644 --- a/compiler/rustc_codegen_gcc/src/consts.rs +++ b/compiler/rustc_codegen_gcc/src/consts.rs @@ -9,6 +9,7 @@ use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs} use rustc_middle::mir::interpret::{ self, ConstAllocation, ErrorHandled, Scalar as InterpScalar, read_target_uint, }; +use rustc_middle::mir::mono::Linkage; use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::{self, Instance}; use rustc_middle::{bug, span_bug}; @@ -258,7 +259,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { if !self.tcx.is_reachable_non_generic(def_id) { #[cfg(feature = "master")] - global.add_string_attribute(VarAttribute::Visibility(Visibility::Hidden)); + global.add_attribute(VarAttribute::Visibility(Visibility::Hidden)); } global @@ -386,6 +387,11 @@ fn check_and_apply_linkage<'gcc, 'tcx>( let global1 = cx.declare_global_with_linkage(sym, cx.type_i8(), base::global_linkage_to_gcc(linkage)); + if linkage == Linkage::ExternalWeak { + #[cfg(feature = "master")] + global1.add_attribute(VarAttribute::Weak); + } + // Declare an internal global `extern_with_linkage_foo` which // is initialized with the address of `foo`. If `foo` is // discarded during linking (for example, if `foo` has weak diff --git a/compiler/rustc_codegen_gcc/src/context.rs b/compiler/rustc_codegen_gcc/src/context.rs index caccf8296a29..7cb49bf79913 100644 --- a/compiler/rustc_codegen_gcc/src/context.rs +++ b/compiler/rustc_codegen_gcc/src/context.rs @@ -24,6 +24,7 @@ use rustc_target::spec::{HasTargetSpec, HasWasmCAbiOpt, Target, TlsModel, WasmCA use crate::callee::get_fn; use crate::common::SignType; +#[cfg_attr(not(feature = "master"), allow(dead_code))] pub struct CodegenCx<'gcc, 'tcx> { pub codegen_unit: &'tcx CodegenUnit<'tcx>, pub context: &'gcc Context<'gcc>, @@ -226,48 +227,14 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { "__builtin_umul_overflow", "__builtin_usubll_overflow", "__builtin_usub_overflow", - "sqrtf", - "sqrt", "__builtin_powif", "__builtin_powi", - "sinf", - "sin", - "cosf", - "cos", - "powf", - "pow", - "expf", - "exp", - "exp2f", - "exp2", - "logf", - "log", - "log10f", - "log10", - "log2f", - "log2", - "fmaf", - "fma", "fabsf", "fabs", - "fminf", - "fmin", - "fmaxf", - "fmax", "copysignf", "copysign", - "floorf", - "floor", - "ceilf", - "ceil", - "truncf", - "trunc", - "rintf", - "rint", "nearbyintf", "nearbyint", - "roundf", - "round", ]; for builtin in builtins.iter() { diff --git a/compiler/rustc_codegen_gcc/src/debuginfo.rs b/compiler/rustc_codegen_gcc/src/debuginfo.rs index 271d65a82353..9d62ccc95d56 100644 --- a/compiler/rustc_codegen_gcc/src/debuginfo.rs +++ b/compiler/rustc_codegen_gcc/src/debuginfo.rs @@ -55,7 +55,7 @@ impl<'a, 'gcc, 'tcx> DebugInfoBuilderMethods for Builder<'a, 'gcc, 'tcx> { } /// Generate the `debug_context` in an MIR Body. -/// # Souce of Origin +/// # Source of Origin /// Copied from `create_scope_map.rs` of rustc_codegen_llvm fn compute_mir_scopes<'gcc, 'tcx>( cx: &CodegenCx<'gcc, 'tcx>, @@ -90,7 +90,7 @@ fn compute_mir_scopes<'gcc, 'tcx>( /// Update the `debug_context`, adding new scope to it, /// if it's not added as is denoted in `instantiated`. /// -/// # Souce of Origin +/// # Source of Origin /// Copied from `create_scope_map.rs` of rustc_codegen_llvm /// FIXME(tempdragon/?): Add Scope Support Here. fn make_mir_scope<'gcc, 'tcx>( diff --git a/compiler/rustc_codegen_gcc/src/declare.rs b/compiler/rustc_codegen_gcc/src/declare.rs index 46818045f0b7..442488b7fd65 100644 --- a/compiler/rustc_codegen_gcc/src/declare.rs +++ b/compiler/rustc_codegen_gcc/src/declare.rs @@ -168,7 +168,15 @@ fn declare_raw_fn<'gcc>( variadic: bool, ) -> Function<'gcc> { if name.starts_with("llvm.") { - let intrinsic = llvm::intrinsic(name, cx); + let intrinsic = match name { + "llvm.fma.f16" => { + // fma is not a target builtin, but a normal builtin, so we handle it differently + // here. + cx.context.get_builtin_function("fma") + } + _ => llvm::intrinsic(name, cx), + }; + cx.intrinsics.borrow_mut().insert(name.to_string(), intrinsic); return intrinsic; } diff --git a/compiler/rustc_codegen_gcc/src/int.rs b/compiler/rustc_codegen_gcc/src/int.rs index abb473a830c8..5ca440f4c9b1 100644 --- a/compiler/rustc_codegen_gcc/src/int.rs +++ b/compiler/rustc_codegen_gcc/src/int.rs @@ -733,7 +733,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { // TODO(antoyo): check if it's faster to use string literals and a // match instead of format!. - let bswap = self.cx.context.get_builtin_function(&format!("__builtin_bswap{}", width)); + let bswap = self.cx.context.get_builtin_function(format!("__builtin_bswap{}", width)); // FIXME(antoyo): this cast should not be necessary. Remove // when having proper sized integer types. let param_type = bswap.get_param(0).to_rvalue().get_type(); diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/archs.rs b/compiler/rustc_codegen_gcc/src/intrinsic/archs.rs index f75009337898..b8d1cde1d5dd 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/archs.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/archs.rs @@ -31,8 +31,11 @@ match name { "llvm.AMDGPU.trig.preop.v2f64" => "__builtin_amdgpu_trig_preop", "llvm.AMDGPU.trig.preop.v4f32" => "__builtin_amdgpu_trig_preop", // aarch64 + "llvm.aarch64.chkfeat" => "__builtin_arm_chkfeat", "llvm.aarch64.dmb" => "__builtin_arm_dmb", "llvm.aarch64.dsb" => "__builtin_arm_dsb", + "llvm.aarch64.gcspopm" => "__builtin_arm_gcspopm", + "llvm.aarch64.gcsss" => "__builtin_arm_gcsss", "llvm.aarch64.isb" => "__builtin_arm_isb", "llvm.aarch64.prefetch" => "__builtin_arm_prefetch", "llvm.aarch64.sve.aesd" => "__builtin_sve_svaesd_u8", @@ -80,7 +83,6 @@ match name { "llvm.amdgcn.dot4.f32.fp8.fp8" => "__builtin_amdgcn_dot4_f32_fp8_fp8", "llvm.amdgcn.ds.add.gs.reg.rtn" => "__builtin_amdgcn_ds_add_gs_reg_rtn", "llvm.amdgcn.ds.bpermute" => "__builtin_amdgcn_ds_bpermute", - "llvm.amdgcn.ds.fadd.v2bf16" => "__builtin_amdgcn_ds_atomic_fadd_v2bf16", "llvm.amdgcn.ds.gws.barrier" => "__builtin_amdgcn_ds_gws_barrier", "llvm.amdgcn.ds.gws.init" => "__builtin_amdgcn_ds_gws_init", "llvm.amdgcn.ds.gws.sema.br" => "__builtin_amdgcn_ds_gws_sema_br", @@ -96,6 +98,7 @@ match name { "llvm.amdgcn.fdot2.f16.f16" => "__builtin_amdgcn_fdot2_f16_f16", "llvm.amdgcn.fdot2.f32.bf16" => "__builtin_amdgcn_fdot2_f32_bf16", "llvm.amdgcn.fmul.legacy" => "__builtin_amdgcn_fmul_legacy", + "llvm.amdgcn.global.load.lds" => "__builtin_amdgcn_global_load_lds", "llvm.amdgcn.groupstaticsize" => "__builtin_amdgcn_groupstaticsize", "llvm.amdgcn.iglp.opt" => "__builtin_amdgcn_iglp_opt", "llvm.amdgcn.implicit.buffer.ptr" => "__builtin_amdgcn_implicit_buffer_ptr", @@ -154,16 +157,11 @@ match name { "llvm.amdgcn.mqsad.u32.u8" => "__builtin_amdgcn_mqsad_u32_u8", "llvm.amdgcn.msad.u8" => "__builtin_amdgcn_msad_u8", "llvm.amdgcn.perm" => "__builtin_amdgcn_perm", - "llvm.amdgcn.permlane16" => "__builtin_amdgcn_permlane16", "llvm.amdgcn.permlane16.var" => "__builtin_amdgcn_permlane16_var", - "llvm.amdgcn.permlane64" => "__builtin_amdgcn_permlane64", - "llvm.amdgcn.permlanex16" => "__builtin_amdgcn_permlanex16", "llvm.amdgcn.permlanex16.var" => "__builtin_amdgcn_permlanex16_var", "llvm.amdgcn.qsad.pk.u16.u8" => "__builtin_amdgcn_qsad_pk_u16_u8", "llvm.amdgcn.queue.ptr" => "__builtin_amdgcn_queue_ptr", "llvm.amdgcn.rcp.legacy" => "__builtin_amdgcn_rcp_legacy", - "llvm.amdgcn.readfirstlane" => "__builtin_amdgcn_readfirstlane", - "llvm.amdgcn.readlane" => "__builtin_amdgcn_readlane", "llvm.amdgcn.rsq.legacy" => "__builtin_amdgcn_rsq_legacy", "llvm.amdgcn.s.barrier" => "__builtin_amdgcn_s_barrier", "llvm.amdgcn.s.barrier.init" => "__builtin_amdgcn_s_barrier_init", @@ -192,6 +190,8 @@ match name { "llvm.amdgcn.s.setreg" => "__builtin_amdgcn_s_setreg", "llvm.amdgcn.s.sleep" => "__builtin_amdgcn_s_sleep", "llvm.amdgcn.s.sleep.var" => "__builtin_amdgcn_s_sleep_var", + "llvm.amdgcn.s.ttracedata" => "__builtin_amdgcn_s_ttracedata", + "llvm.amdgcn.s.ttracedata.imm" => "__builtin_amdgcn_s_ttracedata_imm", "llvm.amdgcn.s.wait.event.export.ready" => "__builtin_amdgcn_s_wait_event_export_ready", "llvm.amdgcn.s.waitcnt" => "__builtin_amdgcn_s_waitcnt", "llvm.amdgcn.s.wakeup.barrier" => "__builtin_amdgcn_s_wakeup_barrier", @@ -227,7 +227,6 @@ match name { "llvm.amdgcn.workgroup.id.x" => "__builtin_amdgcn_workgroup_id_x", "llvm.amdgcn.workgroup.id.y" => "__builtin_amdgcn_workgroup_id_y", "llvm.amdgcn.workgroup.id.z" => "__builtin_amdgcn_workgroup_id_z", - "llvm.amdgcn.writelane" => "__builtin_amdgcn_writelane", // arm "llvm.arm.cdp" => "__builtin_arm_cdp", "llvm.arm.cdp2" => "__builtin_arm_cdp2", @@ -4536,10 +4535,18 @@ match name { "llvm.nvvm.div.rz.d" => "__nvvm_div_rz_d", "llvm.nvvm.div.rz.f" => "__nvvm_div_rz_f", "llvm.nvvm.div.rz.ftz.f" => "__nvvm_div_rz_ftz_f", + "llvm.nvvm.e4m3x2.to.f16x2.rn" => "__nvvm_e4m3x2_to_f16x2_rn", + "llvm.nvvm.e4m3x2.to.f16x2.rn.relu" => "__nvvm_e4m3x2_to_f16x2_rn_relu", + "llvm.nvvm.e5m2x2.to.f16x2.rn" => "__nvvm_e5m2x2_to_f16x2_rn", + "llvm.nvvm.e5m2x2.to.f16x2.rn.relu" => "__nvvm_e5m2x2_to_f16x2_rn_relu", "llvm.nvvm.ex2.approx.d" => "__nvvm_ex2_approx_d", "llvm.nvvm.ex2.approx.f" => "__nvvm_ex2_approx_f", "llvm.nvvm.ex2.approx.ftz.f" => "__nvvm_ex2_approx_ftz_f", "llvm.nvvm.exit" => "__nvvm_exit", + "llvm.nvvm.f16x2.to.e4m3x2.rn" => "__nvvm_f16x2_to_e4m3x2_rn", + "llvm.nvvm.f16x2.to.e4m3x2.rn.relu" => "__nvvm_f16x2_to_e4m3x2_rn_relu", + "llvm.nvvm.f16x2.to.e5m2x2.rn" => "__nvvm_f16x2_to_e5m2x2_rn", + "llvm.nvvm.f16x2.to.e5m2x2.rn.relu" => "__nvvm_f16x2_to_e5m2x2_rn_relu", "llvm.nvvm.f2bf16.rn" => "__nvvm_f2bf16_rn", "llvm.nvvm.f2bf16.rn.relu" => "__nvvm_f2bf16_rn_relu", "llvm.nvvm.f2bf16.rz" => "__nvvm_f2bf16_rz", @@ -4582,6 +4589,10 @@ match name { "llvm.nvvm.fabs.d" => "__nvvm_fabs_d", "llvm.nvvm.fabs.f" => "__nvvm_fabs_f", "llvm.nvvm.fabs.ftz.f" => "__nvvm_fabs_ftz_f", + "llvm.nvvm.ff.to.e4m3x2.rn" => "__nvvm_ff_to_e4m3x2_rn", + "llvm.nvvm.ff.to.e4m3x2.rn.relu" => "__nvvm_ff_to_e4m3x2_rn_relu", + "llvm.nvvm.ff.to.e5m2x2.rn" => "__nvvm_ff_to_e5m2x2_rn", + "llvm.nvvm.ff.to.e5m2x2.rn.relu" => "__nvvm_ff_to_e5m2x2_rn_relu", "llvm.nvvm.ff2bf16x2.rn" => "__nvvm_ff2bf16x2_rn", "llvm.nvvm.ff2bf16x2.rn.relu" => "__nvvm_ff2bf16x2_rn_relu", "llvm.nvvm.ff2bf16x2.rz" => "__nvvm_ff2bf16x2_rz", @@ -4866,6 +4877,7 @@ match name { "llvm.nvvm.round.ftz.f" => "__nvvm_round_ftz_f", "llvm.nvvm.rsqrt.approx.d" => "__nvvm_rsqrt_approx_d", "llvm.nvvm.rsqrt.approx.f" => "__nvvm_rsqrt_approx_f", + "llvm.nvvm.rsqrt.approx.ftz.d" => "__nvvm_rsqrt_approx_ftz_d", "llvm.nvvm.rsqrt.approx.ftz.f" => "__nvvm_rsqrt_approx_ftz_f", "llvm.nvvm.sad.i" => "__nvvm_sad_i", "llvm.nvvm.sad.ll" => "__nvvm_sad_ll", @@ -5164,6 +5176,8 @@ match name { // ppc "llvm.ppc.addex" => "__builtin_ppc_addex", "llvm.ppc.addf128.round.to.odd" => "__builtin_addf128_round_to_odd", + "llvm.ppc.addg6s" => "__builtin_addg6s", + "llvm.ppc.addg6sd" => "__builtin_ppc_addg6s", "llvm.ppc.altivec.crypto.vcipher" => "__builtin_altivec_crypto_vcipher", "llvm.ppc.altivec.crypto.vcipherlast" => "__builtin_altivec_crypto_vcipherlast", "llvm.ppc.altivec.crypto.vncipher" => "__builtin_altivec_crypto_vncipher", @@ -5461,6 +5475,10 @@ match name { "llvm.ppc.bcdsub" => "__builtin_ppc_bcdsub", "llvm.ppc.bcdsub.p" => "__builtin_ppc_bcdsub_p", "llvm.ppc.bpermd" => "__builtin_bpermd", + "llvm.ppc.cbcdtd" => "__builtin_cbcdtd", + "llvm.ppc.cbcdtdd" => "__builtin_ppc_cbcdtd", + "llvm.ppc.cdtbcd" => "__builtin_cdtbcd", + "llvm.ppc.cdtbcdd" => "__builtin_ppc_cdtbcd", "llvm.ppc.cfuged" => "__builtin_cfuged", "llvm.ppc.cmpeqb" => "__builtin_ppc_cmpeqb", "llvm.ppc.cmprb" => "__builtin_ppc_cmprb", @@ -5627,7 +5645,6 @@ match name { "llvm.ppc.qpx.qvstfs" => "__builtin_qpx_qvstfs", "llvm.ppc.qpx.qvstfsa" => "__builtin_qpx_qvstfsa", "llvm.ppc.readflm" => "__builtin_readflm", - "llvm.ppc.rldimi" => "__builtin_ppc_rldimi", "llvm.ppc.rlwimi" => "__builtin_ppc_rlwimi", "llvm.ppc.rlwnm" => "__builtin_ppc_rlwnm", "llvm.ppc.scalar.extract.expq" => "__builtin_vsx_scalar_extract_expq", @@ -7210,29 +7227,6 @@ match name { "llvm.ve.vl.xorm.MMM" => "__builtin_ve_vl_xorm_MMM", "llvm.ve.vl.xorm.mmm" => "__builtin_ve_vl_xorm_mmm", // x86 - "llvm.x86.3dnow.pavgusb" => "__builtin_ia32_pavgusb", - "llvm.x86.3dnow.pf2id" => "__builtin_ia32_pf2id", - "llvm.x86.3dnow.pfacc" => "__builtin_ia32_pfacc", - "llvm.x86.3dnow.pfadd" => "__builtin_ia32_pfadd", - "llvm.x86.3dnow.pfcmpeq" => "__builtin_ia32_pfcmpeq", - "llvm.x86.3dnow.pfcmpge" => "__builtin_ia32_pfcmpge", - "llvm.x86.3dnow.pfcmpgt" => "__builtin_ia32_pfcmpgt", - "llvm.x86.3dnow.pfmax" => "__builtin_ia32_pfmax", - "llvm.x86.3dnow.pfmin" => "__builtin_ia32_pfmin", - "llvm.x86.3dnow.pfmul" => "__builtin_ia32_pfmul", - "llvm.x86.3dnow.pfrcp" => "__builtin_ia32_pfrcp", - "llvm.x86.3dnow.pfrcpit1" => "__builtin_ia32_pfrcpit1", - "llvm.x86.3dnow.pfrcpit2" => "__builtin_ia32_pfrcpit2", - "llvm.x86.3dnow.pfrsqit1" => "__builtin_ia32_pfrsqit1", - "llvm.x86.3dnow.pfrsqrt" => "__builtin_ia32_pfrsqrt", - "llvm.x86.3dnow.pfsub" => "__builtin_ia32_pfsub", - "llvm.x86.3dnow.pfsubr" => "__builtin_ia32_pfsubr", - "llvm.x86.3dnow.pi2fd" => "__builtin_ia32_pi2fd", - "llvm.x86.3dnow.pmulhrw" => "__builtin_ia32_pmulhrw", - "llvm.x86.3dnowa.pf2iw" => "__builtin_ia32_pf2iw", - "llvm.x86.3dnowa.pfnacc" => "__builtin_ia32_pfnacc", - "llvm.x86.3dnowa.pfpnacc" => "__builtin_ia32_pfpnacc", - "llvm.x86.3dnowa.pi2fw" => "__builtin_ia32_pi2fw", "llvm.x86.aadd32" => "__builtin_ia32_aadd32", "llvm.x86.aadd64" => "__builtin_ia32_aadd64", "llvm.x86.aand32" => "__builtin_ia32_aand32", @@ -7334,6 +7328,207 @@ match name { "llvm.x86.avx.vtestz.ps.256" => "__builtin_ia32_vtestzps256", "llvm.x86.avx.vzeroall" => "__builtin_ia32_vzeroall", "llvm.x86.avx.vzeroupper" => "__builtin_ia32_vzeroupper", + "llvm.x86.avx10.mask.vcvt2ps2phx.128" => "__builtin_ia32_vcvt2ps2phx128_mask", + "llvm.x86.avx10.mask.vcvt2ps2phx.256" => "__builtin_ia32_vcvt2ps2phx256_mask", + "llvm.x86.avx10.mask.vcvt2ps2phx.512" => "__builtin_ia32_vcvt2ps2phx512_mask", + "llvm.x86.avx10.mask.vcvtbiasph2bf8128" => "__builtin_ia32_vcvtbiasph2bf8_128_mask", + "llvm.x86.avx10.mask.vcvtbiasph2bf8256" => "__builtin_ia32_vcvtbiasph2bf8_256_mask", + "llvm.x86.avx10.mask.vcvtbiasph2bf8512" => "__builtin_ia32_vcvtbiasph2bf8_512_mask", + "llvm.x86.avx10.mask.vcvtbiasph2bf8s128" => "__builtin_ia32_vcvtbiasph2bf8s_128_mask", + "llvm.x86.avx10.mask.vcvtbiasph2bf8s256" => "__builtin_ia32_vcvtbiasph2bf8s_256_mask", + "llvm.x86.avx10.mask.vcvtbiasph2bf8s512" => "__builtin_ia32_vcvtbiasph2bf8s_512_mask", + "llvm.x86.avx10.mask.vcvtbiasph2hf8128" => "__builtin_ia32_vcvtbiasph2hf8_128_mask", + "llvm.x86.avx10.mask.vcvtbiasph2hf8256" => "__builtin_ia32_vcvtbiasph2hf8_256_mask", + "llvm.x86.avx10.mask.vcvtbiasph2hf8512" => "__builtin_ia32_vcvtbiasph2hf8_512_mask", + "llvm.x86.avx10.mask.vcvtbiasph2hf8s128" => "__builtin_ia32_vcvtbiasph2hf8s_128_mask", + "llvm.x86.avx10.mask.vcvtbiasph2hf8s256" => "__builtin_ia32_vcvtbiasph2hf8s_256_mask", + "llvm.x86.avx10.mask.vcvtbiasph2hf8s512" => "__builtin_ia32_vcvtbiasph2hf8s_512_mask", + "llvm.x86.avx10.mask.vcvthf82ph128" => "__builtin_ia32_vcvthf8_2ph128_mask", + "llvm.x86.avx10.mask.vcvthf82ph256" => "__builtin_ia32_vcvthf8_2ph256_mask", + "llvm.x86.avx10.mask.vcvthf82ph512" => "__builtin_ia32_vcvthf8_2ph512_mask", + "llvm.x86.avx10.mask.vcvtneph2bf8128" => "__builtin_ia32_vcvtneph2bf8_128_mask", + "llvm.x86.avx10.mask.vcvtneph2bf8256" => "__builtin_ia32_vcvtneph2bf8_256_mask", + "llvm.x86.avx10.mask.vcvtneph2bf8512" => "__builtin_ia32_vcvtneph2bf8_512_mask", + "llvm.x86.avx10.mask.vcvtneph2bf8s128" => "__builtin_ia32_vcvtneph2bf8s_128_mask", + "llvm.x86.avx10.mask.vcvtneph2bf8s256" => "__builtin_ia32_vcvtneph2bf8s_256_mask", + "llvm.x86.avx10.mask.vcvtneph2bf8s512" => "__builtin_ia32_vcvtneph2bf8s_512_mask", + "llvm.x86.avx10.mask.vcvtneph2hf8128" => "__builtin_ia32_vcvtneph2hf8_128_mask", + "llvm.x86.avx10.mask.vcvtneph2hf8256" => "__builtin_ia32_vcvtneph2hf8_256_mask", + "llvm.x86.avx10.mask.vcvtneph2hf8512" => "__builtin_ia32_vcvtneph2hf8_512_mask", + "llvm.x86.avx10.mask.vcvtneph2hf8s128" => "__builtin_ia32_vcvtneph2hf8s_128_mask", + "llvm.x86.avx10.mask.vcvtneph2hf8s256" => "__builtin_ia32_vcvtneph2hf8s_256_mask", + "llvm.x86.avx10.mask.vcvtneph2hf8s512" => "__builtin_ia32_vcvtneph2hf8s_512_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtpd2dq256" => "__builtin_ia32_vcvtpd2dq256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtpd2ph256" => "__builtin_ia32_vcvtpd2ph256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtpd2ps256" => "__builtin_ia32_vcvtpd2ps256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtpd2qq256" => "__builtin_ia32_vcvtpd2qq256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtpd2udq256" => "__builtin_ia32_vcvtpd2udq256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtpd2uqq256" => "__builtin_ia32_vcvtpd2uqq256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtph2dq256" => "__builtin_ia32_vcvtph2dq256_round_mask", + "llvm.x86.avx10.mask.vcvtph2ibs128" => "__builtin_ia32_vcvtph2ibs128_mask", + "llvm.x86.avx10.mask.vcvtph2ibs256" => "__builtin_ia32_vcvtph2ibs256_mask", + "llvm.x86.avx10.mask.vcvtph2ibs512" => "__builtin_ia32_vcvtph2ibs512_mask", + "llvm.x86.avx10.mask.vcvtph2iubs128" => "__builtin_ia32_vcvtph2iubs128_mask", + "llvm.x86.avx10.mask.vcvtph2iubs256" => "__builtin_ia32_vcvtph2iubs256_mask", + "llvm.x86.avx10.mask.vcvtph2iubs512" => "__builtin_ia32_vcvtph2iubs512_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtph2pd256" => "__builtin_ia32_vcvtph2pd256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtph2psx256" => "__builtin_ia32_vcvtph2psx256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtph2qq256" => "__builtin_ia32_vcvtph2qq256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtph2udq256" => "__builtin_ia32_vcvtph2udq256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtph2uqq256" => "__builtin_ia32_vcvtph2uqq256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtph2uw256" => "__builtin_ia32_vcvtph2uw256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtph2w256" => "__builtin_ia32_vcvtph2w256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtps2dq256" => "__builtin_ia32_vcvtps2dq256_round_mask", + "llvm.x86.avx10.mask.vcvtps2ibs128" => "__builtin_ia32_vcvtps2ibs128_mask", + "llvm.x86.avx10.mask.vcvtps2ibs256" => "__builtin_ia32_vcvtps2ibs256_mask", + "llvm.x86.avx10.mask.vcvtps2ibs512" => "__builtin_ia32_vcvtps2ibs512_mask", + "llvm.x86.avx10.mask.vcvtps2iubs128" => "__builtin_ia32_vcvtps2iubs128_mask", + "llvm.x86.avx10.mask.vcvtps2iubs256" => "__builtin_ia32_vcvtps2iubs256_mask", + "llvm.x86.avx10.mask.vcvtps2iubs512" => "__builtin_ia32_vcvtps2iubs512_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtps2pd256" => "__builtin_ia32_vcvtps2pd256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtps2ph256" => "__builtin_ia32_vcvtps2ph256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtps2phx256" => "__builtin_ia32_vcvtps2phx256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtps2qq256" => "__builtin_ia32_vcvtps2qq256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtps2udq256" => "__builtin_ia32_vcvtps2udq256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvtps2uqq256" => "__builtin_ia32_vcvtps2uqq256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvttpd2dq256" => "__builtin_ia32_vcvttpd2dq256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvttpd2qq256" => "__builtin_ia32_vcvttpd2qq256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvttpd2udq256" => "__builtin_ia32_vcvttpd2udq256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvttpd2uqq256" => "__builtin_ia32_vcvttpd2uqq256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvttph2dq256" => "__builtin_ia32_vcvttph2dq256_round_mask", + "llvm.x86.avx10.mask.vcvttph2ibs128" => "__builtin_ia32_vcvttph2ibs128_mask", + "llvm.x86.avx10.mask.vcvttph2ibs256" => "__builtin_ia32_vcvttph2ibs256_mask", + "llvm.x86.avx10.mask.vcvttph2ibs512" => "__builtin_ia32_vcvttph2ibs512_mask", + "llvm.x86.avx10.mask.vcvttph2iubs128" => "__builtin_ia32_vcvttph2iubs128_mask", + "llvm.x86.avx10.mask.vcvttph2iubs256" => "__builtin_ia32_vcvttph2iubs256_mask", + "llvm.x86.avx10.mask.vcvttph2iubs512" => "__builtin_ia32_vcvttph2iubs512_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvttph2qq256" => "__builtin_ia32_vcvttph2qq256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvttph2udq256" => "__builtin_ia32_vcvttph2udq256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvttph2uqq256" => "__builtin_ia32_vcvttph2uqq256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvttph2uw256" => "__builtin_ia32_vcvttph2uw256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvttph2w256" => "__builtin_ia32_vcvttph2w256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvttps2dq256" => "__builtin_ia32_vcvttps2dq256_round_mask", + "llvm.x86.avx10.mask.vcvttps2ibs128" => "__builtin_ia32_vcvttps2ibs128_mask", + "llvm.x86.avx10.mask.vcvttps2ibs256" => "__builtin_ia32_vcvttps2ibs256_mask", + "llvm.x86.avx10.mask.vcvttps2ibs512" => "__builtin_ia32_vcvttps2ibs512_mask", + "llvm.x86.avx10.mask.vcvttps2iubs128" => "__builtin_ia32_vcvttps2iubs128_mask", + "llvm.x86.avx10.mask.vcvttps2iubs256" => "__builtin_ia32_vcvttps2iubs256_mask", + "llvm.x86.avx10.mask.vcvttps2iubs512" => "__builtin_ia32_vcvttps2iubs512_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvttps2qq256" => "__builtin_ia32_vcvttps2qq256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvttps2udq256" => "__builtin_ia32_vcvttps2udq256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vcvttps2uqq256" => "__builtin_ia32_vcvttps2uqq256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vfcmaddcph256" => "__builtin_ia32_vfcmaddcph256_round_mask3", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vfcmulcph256" => "__builtin_ia32_vfcmulcph256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vfixupimmpd256" => "__builtin_ia32_vfixupimmpd256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vfixupimmps256" => "__builtin_ia32_vfixupimmps256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vfmaddcph256" => "__builtin_ia32_vfmaddcph256_round_mask3", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vfmulcph256" => "__builtin_ia32_vfmulcph256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vgetexppd256" => "__builtin_ia32_vgetexppd256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vgetexpph256" => "__builtin_ia32_vgetexpph256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vgetexpps256" => "__builtin_ia32_vgetexpps256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vgetmantpd256" => "__builtin_ia32_vgetmantpd256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vgetmantph256" => "__builtin_ia32_vgetmantph256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vgetmantps256" => "__builtin_ia32_vgetmantps256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vminmaxpd.round" => "__builtin_ia32_vminmaxpd512_round_mask", + "llvm.x86.avx10.mask.vminmaxpd128" => "__builtin_ia32_vminmaxpd128_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vminmaxpd256.round" => "__builtin_ia32_vminmaxpd256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vminmaxph.round" => "__builtin_ia32_vminmaxph512_round_mask", + "llvm.x86.avx10.mask.vminmaxph128" => "__builtin_ia32_vminmaxph128_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vminmaxph256.round" => "__builtin_ia32_vminmaxph256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vminmaxps.round" => "__builtin_ia32_vminmaxps512_round_mask", + "llvm.x86.avx10.mask.vminmaxps128" => "__builtin_ia32_vminmaxps128_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vminmaxps256.round" => "__builtin_ia32_vminmaxps256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vminmaxsd.round" => "__builtin_ia32_vminmaxsd_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vminmaxsh.round" => "__builtin_ia32_vminmaxsh_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vminmaxss.round" => "__builtin_ia32_vminmaxss_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vrangepd256" => "__builtin_ia32_vrangepd256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vrangeps256" => "__builtin_ia32_vrangeps256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vreducepd256" => "__builtin_ia32_vreducepd256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vreduceph256" => "__builtin_ia32_vreduceph256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vreduceps256" => "__builtin_ia32_vreduceps256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vrndscalepd256" => "__builtin_ia32_vrndscalepd256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vrndscaleph256" => "__builtin_ia32_vrndscaleph256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vrndscaleps256" => "__builtin_ia32_vrndscaleps256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vscalefpd256" => "__builtin_ia32_vscalefpd256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vscalefph256" => "__builtin_ia32_vscalefph256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.mask.vscalefps256" => "__builtin_ia32_vscalefps256_round_mask", + // [INVALID CONVERSION]: "llvm.x86.avx10.maskz.vfcmaddcph256" => "__builtin_ia32_vfcmaddcph256_round_maskz", + // [INVALID CONVERSION]: "llvm.x86.avx10.maskz.vfixupimmpd256" => "__builtin_ia32_vfixupimmpd256_round_maskz", + // [INVALID CONVERSION]: "llvm.x86.avx10.maskz.vfixupimmps256" => "__builtin_ia32_vfixupimmps256_round_maskz", + // [INVALID CONVERSION]: "llvm.x86.avx10.maskz.vfmaddcph256" => "__builtin_ia32_vfmaddcph256_round_maskz", + "llvm.x86.avx10.vaddpd256" => "__builtin_ia32_vaddpd256_round", + "llvm.x86.avx10.vaddph256" => "__builtin_ia32_vaddph256_round", + "llvm.x86.avx10.vaddps256" => "__builtin_ia32_vaddps256_round", + "llvm.x86.avx10.vcvtne2ph2bf8128" => "__builtin_ia32_vcvtne2ph2bf8_128", + "llvm.x86.avx10.vcvtne2ph2bf8256" => "__builtin_ia32_vcvtne2ph2bf8_256", + "llvm.x86.avx10.vcvtne2ph2bf8512" => "__builtin_ia32_vcvtne2ph2bf8_512", + "llvm.x86.avx10.vcvtne2ph2bf8s128" => "__builtin_ia32_vcvtne2ph2bf8s_128", + "llvm.x86.avx10.vcvtne2ph2bf8s256" => "__builtin_ia32_vcvtne2ph2bf8s_256", + "llvm.x86.avx10.vcvtne2ph2bf8s512" => "__builtin_ia32_vcvtne2ph2bf8s_512", + "llvm.x86.avx10.vcvtne2ph2hf8128" => "__builtin_ia32_vcvtne2ph2hf8_128", + "llvm.x86.avx10.vcvtne2ph2hf8256" => "__builtin_ia32_vcvtne2ph2hf8_256", + "llvm.x86.avx10.vcvtne2ph2hf8512" => "__builtin_ia32_vcvtne2ph2hf8_512", + "llvm.x86.avx10.vcvtne2ph2hf8s128" => "__builtin_ia32_vcvtne2ph2hf8s_128", + "llvm.x86.avx10.vcvtne2ph2hf8s256" => "__builtin_ia32_vcvtne2ph2hf8s_256", + "llvm.x86.avx10.vcvtne2ph2hf8s512" => "__builtin_ia32_vcvtne2ph2hf8s_512", + "llvm.x86.avx10.vcvtnebf162ibs128" => "__builtin_ia32_vcvtnebf162ibs128", + "llvm.x86.avx10.vcvtnebf162ibs256" => "__builtin_ia32_vcvtnebf162ibs256", + "llvm.x86.avx10.vcvtnebf162ibs512" => "__builtin_ia32_vcvtnebf162ibs512", + "llvm.x86.avx10.vcvtnebf162iubs128" => "__builtin_ia32_vcvtnebf162iubs128", + "llvm.x86.avx10.vcvtnebf162iubs256" => "__builtin_ia32_vcvtnebf162iubs256", + "llvm.x86.avx10.vcvtnebf162iubs512" => "__builtin_ia32_vcvtnebf162iubs512", + "llvm.x86.avx10.vcvttnebf162ibs128" => "__builtin_ia32_vcvttnebf162ibs128", + "llvm.x86.avx10.vcvttnebf162ibs256" => "__builtin_ia32_vcvttnebf162ibs256", + "llvm.x86.avx10.vcvttnebf162ibs512" => "__builtin_ia32_vcvttnebf162ibs512", + "llvm.x86.avx10.vcvttnebf162iubs128" => "__builtin_ia32_vcvttnebf162iubs128", + "llvm.x86.avx10.vcvttnebf162iubs256" => "__builtin_ia32_vcvttnebf162iubs256", + "llvm.x86.avx10.vcvttnebf162iubs512" => "__builtin_ia32_vcvttnebf162iubs512", + "llvm.x86.avx10.vdivpd256" => "__builtin_ia32_vdivpd256_round", + "llvm.x86.avx10.vdivph256" => "__builtin_ia32_vdivph256_round", + "llvm.x86.avx10.vdivps256" => "__builtin_ia32_vdivps256_round", + "llvm.x86.avx10.vdpphps.128" => "__builtin_ia32_vdpphps128", + "llvm.x86.avx10.vdpphps.256" => "__builtin_ia32_vdpphps256", + "llvm.x86.avx10.vdpphps.512" => "__builtin_ia32_vdpphps512", + "llvm.x86.avx10.vfmaddsubpd256" => "__builtin_ia32_vfmaddsubpd256_round", + "llvm.x86.avx10.vfmaddsubph256" => "__builtin_ia32_vfmaddsubph256_round", + "llvm.x86.avx10.vfmaddsubps256" => "__builtin_ia32_vfmaddsubps256_round", + "llvm.x86.avx10.vmaxpd256" => "__builtin_ia32_vmaxpd256_round", + "llvm.x86.avx10.vmaxph256" => "__builtin_ia32_vmaxph256_round", + "llvm.x86.avx10.vmaxps256" => "__builtin_ia32_vmaxps256_round", + "llvm.x86.avx10.vminmaxnepbf16128" => "__builtin_ia32_vminmaxnepbf16128", + "llvm.x86.avx10.vminmaxnepbf16256" => "__builtin_ia32_vminmaxnepbf16256", + "llvm.x86.avx10.vminmaxnepbf16512" => "__builtin_ia32_vminmaxnepbf16512", + "llvm.x86.avx10.vminmaxpd128" => "__builtin_ia32_vminmaxpd128", + "llvm.x86.avx10.vminmaxpd256" => "__builtin_ia32_vminmaxpd256", + "llvm.x86.avx10.vminmaxph128" => "__builtin_ia32_vminmaxph128", + "llvm.x86.avx10.vminmaxph256" => "__builtin_ia32_vminmaxph256", + "llvm.x86.avx10.vminmaxps128" => "__builtin_ia32_vminmaxps128", + "llvm.x86.avx10.vminmaxps256" => "__builtin_ia32_vminmaxps256", + "llvm.x86.avx10.vminpd256" => "__builtin_ia32_vminpd256_round", + "llvm.x86.avx10.vminph256" => "__builtin_ia32_vminph256_round", + "llvm.x86.avx10.vminps256" => "__builtin_ia32_vminps256_round", + "llvm.x86.avx10.vmpsadbw.512" => "__builtin_ia32_mpsadbw512", + "llvm.x86.avx10.vmulpd256" => "__builtin_ia32_vmulpd256_round", + "llvm.x86.avx10.vmulph256" => "__builtin_ia32_vmulph256_round", + "llvm.x86.avx10.vmulps256" => "__builtin_ia32_vmulps256_round", + "llvm.x86.avx10.vpdpbssd.512" => "__builtin_ia32_vpdpbssd512", + "llvm.x86.avx10.vpdpbssds.512" => "__builtin_ia32_vpdpbssds512", + "llvm.x86.avx10.vpdpbsud.512" => "__builtin_ia32_vpdpbsud512", + "llvm.x86.avx10.vpdpbsuds.512" => "__builtin_ia32_vpdpbsuds512", + "llvm.x86.avx10.vpdpbuud.512" => "__builtin_ia32_vpdpbuud512", + "llvm.x86.avx10.vpdpbuuds.512" => "__builtin_ia32_vpdpbuuds512", + "llvm.x86.avx10.vpdpwsud.512" => "__builtin_ia32_vpdpwsud512", + "llvm.x86.avx10.vpdpwsuds.512" => "__builtin_ia32_vpdpwsuds512", + "llvm.x86.avx10.vpdpwusd.512" => "__builtin_ia32_vpdpwusd512", + "llvm.x86.avx10.vpdpwusds.512" => "__builtin_ia32_vpdpwusds512", + "llvm.x86.avx10.vpdpwuud.512" => "__builtin_ia32_vpdpwuud512", + "llvm.x86.avx10.vpdpwuuds.512" => "__builtin_ia32_vpdpwuuds512", + "llvm.x86.avx10.vsqrtpd256" => "__builtin_ia32_vsqrtpd256_round", + "llvm.x86.avx10.vsqrtph256" => "__builtin_ia32_vsqrtph256_round", + "llvm.x86.avx10.vsqrtps256" => "__builtin_ia32_vsqrtps256_round", + "llvm.x86.avx10.vsubpd256" => "__builtin_ia32_vsubpd256_round", + "llvm.x86.avx10.vsubph256" => "__builtin_ia32_vsubph256_round", + "llvm.x86.avx10.vsubps256" => "__builtin_ia32_vsubps256_round", "llvm.x86.avx2.gather.d.d" => "__builtin_ia32_gatherd_d", "llvm.x86.avx2.gather.d.d.256" => "__builtin_ia32_gatherd_d256", "llvm.x86.avx2.gather.d.pd" => "__builtin_ia32_gatherd_pd", @@ -8738,10 +8933,10 @@ match name { "llvm.x86.avx512.rcp14.ss" => "__builtin_ia32_rcp14ss_mask", "llvm.x86.avx512.rcp28.pd" => "__builtin_ia32_rcp28pd_mask", "llvm.x86.avx512.rcp28.ps" => "__builtin_ia32_rcp28ps_mask", - // [INVALID CONVERSION]: "llvm.x86.avx512.rcp28.sd" => "__builtin_ia32_rcp28sd_round_mask", - // [DUPLICATE]: "llvm.x86.avx512.rcp28.sd" => "__builtin_ia32_rcp28sd_mask", - // [INVALID CONVERSION]: "llvm.x86.avx512.rcp28.ss" => "__builtin_ia32_rcp28ss_round_mask", - // [DUPLICATE]: "llvm.x86.avx512.rcp28.ss" => "__builtin_ia32_rcp28ss_mask", + "llvm.x86.avx512.rcp28.sd" => "__builtin_ia32_rcp28sd_mask", + // [DUPLICATE]: "llvm.x86.avx512.rcp28.sd" => "__builtin_ia32_rcp28sd_round_mask", + "llvm.x86.avx512.rcp28.ss" => "__builtin_ia32_rcp28ss_mask", + // [DUPLICATE]: "llvm.x86.avx512.rcp28.ss" => "__builtin_ia32_rcp28ss_round_mask", "llvm.x86.avx512.rndscale.sd" => "__builtin_ia32_rndscalesd", "llvm.x86.avx512.rndscale.ss" => "__builtin_ia32_rndscaless", "llvm.x86.avx512.rsqrt14.pd.128" => "__builtin_ia32_rsqrt14pd128_mask", @@ -8754,10 +8949,10 @@ match name { "llvm.x86.avx512.rsqrt14.ss" => "__builtin_ia32_rsqrt14ss_mask", "llvm.x86.avx512.rsqrt28.pd" => "__builtin_ia32_rsqrt28pd_mask", "llvm.x86.avx512.rsqrt28.ps" => "__builtin_ia32_rsqrt28ps_mask", - // [INVALID CONVERSION]: "llvm.x86.avx512.rsqrt28.sd" => "__builtin_ia32_rsqrt28sd_round_mask", - // [DUPLICATE]: "llvm.x86.avx512.rsqrt28.sd" => "__builtin_ia32_rsqrt28sd_mask", - // [INVALID CONVERSION]: "llvm.x86.avx512.rsqrt28.ss" => "__builtin_ia32_rsqrt28ss_round_mask", - // [DUPLICATE]: "llvm.x86.avx512.rsqrt28.ss" => "__builtin_ia32_rsqrt28ss_mask", + "llvm.x86.avx512.rsqrt28.sd" => "__builtin_ia32_rsqrt28sd_mask", + // [DUPLICATE]: "llvm.x86.avx512.rsqrt28.sd" => "__builtin_ia32_rsqrt28sd_round_mask", + "llvm.x86.avx512.rsqrt28.ss" => "__builtin_ia32_rsqrt28ss_mask", + // [DUPLICATE]: "llvm.x86.avx512.rsqrt28.ss" => "__builtin_ia32_rsqrt28ss_round_mask", "llvm.x86.avx512.scatter.dpd.512" => "__builtin_ia32_scattersiv8df", "llvm.x86.avx512.scatter.dpi.512" => "__builtin_ia32_scattersiv16si", "llvm.x86.avx512.scatter.dpq.512" => "__builtin_ia32_scattersiv8di", @@ -9082,75 +9277,6 @@ match name { "llvm.x86.lwpval64" => "__builtin_ia32_lwpval64", "llvm.x86.mmx.emms" => "__builtin_ia32_emms", "llvm.x86.mmx.femms" => "__builtin_ia32_femms", - "llvm.x86.mmx.maskmovq" => "__builtin_ia32_maskmovq", - "llvm.x86.mmx.movnt.dq" => "__builtin_ia32_movntq", - "llvm.x86.mmx.packssdw" => "__builtin_ia32_packssdw", - "llvm.x86.mmx.packsswb" => "__builtin_ia32_packsswb", - "llvm.x86.mmx.packuswb" => "__builtin_ia32_packuswb", - "llvm.x86.mmx.padd.b" => "__builtin_ia32_paddb", - "llvm.x86.mmx.padd.d" => "__builtin_ia32_paddd", - "llvm.x86.mmx.padd.q" => "__builtin_ia32_paddq", - "llvm.x86.mmx.padd.w" => "__builtin_ia32_paddw", - "llvm.x86.mmx.padds.b" => "__builtin_ia32_paddsb", - "llvm.x86.mmx.padds.w" => "__builtin_ia32_paddsw", - "llvm.x86.mmx.paddus.b" => "__builtin_ia32_paddusb", - "llvm.x86.mmx.paddus.w" => "__builtin_ia32_paddusw", - "llvm.x86.mmx.palignr.b" => "__builtin_ia32_palignr", - "llvm.x86.mmx.pand" => "__builtin_ia32_pand", - "llvm.x86.mmx.pandn" => "__builtin_ia32_pandn", - "llvm.x86.mmx.pavg.b" => "__builtin_ia32_pavgb", - "llvm.x86.mmx.pavg.w" => "__builtin_ia32_pavgw", - "llvm.x86.mmx.pcmpeq.b" => "__builtin_ia32_pcmpeqb", - "llvm.x86.mmx.pcmpeq.d" => "__builtin_ia32_pcmpeqd", - "llvm.x86.mmx.pcmpeq.w" => "__builtin_ia32_pcmpeqw", - "llvm.x86.mmx.pcmpgt.b" => "__builtin_ia32_pcmpgtb", - "llvm.x86.mmx.pcmpgt.d" => "__builtin_ia32_pcmpgtd", - "llvm.x86.mmx.pcmpgt.w" => "__builtin_ia32_pcmpgtw", - "llvm.x86.mmx.pextr.w" => "__builtin_ia32_vec_ext_v4hi", - "llvm.x86.mmx.pinsr.w" => "__builtin_ia32_vec_set_v4hi", - "llvm.x86.mmx.pmadd.wd" => "__builtin_ia32_pmaddwd", - "llvm.x86.mmx.pmaxs.w" => "__builtin_ia32_pmaxsw", - "llvm.x86.mmx.pmaxu.b" => "__builtin_ia32_pmaxub", - "llvm.x86.mmx.pmins.w" => "__builtin_ia32_pminsw", - "llvm.x86.mmx.pminu.b" => "__builtin_ia32_pminub", - "llvm.x86.mmx.pmovmskb" => "__builtin_ia32_pmovmskb", - "llvm.x86.mmx.pmulh.w" => "__builtin_ia32_pmulhw", - "llvm.x86.mmx.pmulhu.w" => "__builtin_ia32_pmulhuw", - "llvm.x86.mmx.pmull.w" => "__builtin_ia32_pmullw", - "llvm.x86.mmx.pmulu.dq" => "__builtin_ia32_pmuludq", - "llvm.x86.mmx.por" => "__builtin_ia32_por", - "llvm.x86.mmx.psad.bw" => "__builtin_ia32_psadbw", - "llvm.x86.mmx.psll.d" => "__builtin_ia32_pslld", - "llvm.x86.mmx.psll.q" => "__builtin_ia32_psllq", - "llvm.x86.mmx.psll.w" => "__builtin_ia32_psllw", - "llvm.x86.mmx.pslli.d" => "__builtin_ia32_pslldi", - "llvm.x86.mmx.pslli.q" => "__builtin_ia32_psllqi", - "llvm.x86.mmx.pslli.w" => "__builtin_ia32_psllwi", - "llvm.x86.mmx.psra.d" => "__builtin_ia32_psrad", - "llvm.x86.mmx.psra.w" => "__builtin_ia32_psraw", - "llvm.x86.mmx.psrai.d" => "__builtin_ia32_psradi", - "llvm.x86.mmx.psrai.w" => "__builtin_ia32_psrawi", - "llvm.x86.mmx.psrl.d" => "__builtin_ia32_psrld", - "llvm.x86.mmx.psrl.q" => "__builtin_ia32_psrlq", - "llvm.x86.mmx.psrl.w" => "__builtin_ia32_psrlw", - "llvm.x86.mmx.psrli.d" => "__builtin_ia32_psrldi", - "llvm.x86.mmx.psrli.q" => "__builtin_ia32_psrlqi", - "llvm.x86.mmx.psrli.w" => "__builtin_ia32_psrlwi", - "llvm.x86.mmx.psub.b" => "__builtin_ia32_psubb", - "llvm.x86.mmx.psub.d" => "__builtin_ia32_psubd", - "llvm.x86.mmx.psub.q" => "__builtin_ia32_psubq", - "llvm.x86.mmx.psub.w" => "__builtin_ia32_psubw", - "llvm.x86.mmx.psubs.b" => "__builtin_ia32_psubsb", - "llvm.x86.mmx.psubs.w" => "__builtin_ia32_psubsw", - "llvm.x86.mmx.psubus.b" => "__builtin_ia32_psubusb", - "llvm.x86.mmx.psubus.w" => "__builtin_ia32_psubusw", - "llvm.x86.mmx.punpckhbw" => "__builtin_ia32_punpckhbw", - "llvm.x86.mmx.punpckhdq" => "__builtin_ia32_punpckhdq", - "llvm.x86.mmx.punpckhwd" => "__builtin_ia32_punpckhwd", - "llvm.x86.mmx.punpcklbw" => "__builtin_ia32_punpcklbw", - "llvm.x86.mmx.punpckldq" => "__builtin_ia32_punpckldq", - "llvm.x86.mmx.punpcklwd" => "__builtin_ia32_punpcklwd", - "llvm.x86.mmx.pxor" => "__builtin_ia32_pxor", "llvm.x86.monitorx" => "__builtin_ia32_monitorx", "llvm.x86.movdir64b" => "__builtin_ia32_movdir64b", "llvm.x86.mwaitx" => "__builtin_ia32_mwaitx", @@ -9193,16 +9319,10 @@ match name { "llvm.x86.sse.comile.ss" => "__builtin_ia32_comile", "llvm.x86.sse.comilt.ss" => "__builtin_ia32_comilt", "llvm.x86.sse.comineq.ss" => "__builtin_ia32_comineq", - "llvm.x86.sse.cvtpd2pi" => "__builtin_ia32_cvtpd2pi", - "llvm.x86.sse.cvtpi2pd" => "__builtin_ia32_cvtpi2pd", - "llvm.x86.sse.cvtpi2ps" => "__builtin_ia32_cvtpi2ps", - "llvm.x86.sse.cvtps2pi" => "__builtin_ia32_cvtps2pi", "llvm.x86.sse.cvtsi2ss" => "__builtin_ia32_cvtsi2ss", "llvm.x86.sse.cvtsi642ss" => "__builtin_ia32_cvtsi642ss", "llvm.x86.sse.cvtss2si" => "__builtin_ia32_cvtss2si", "llvm.x86.sse.cvtss2si64" => "__builtin_ia32_cvtss2si64", - "llvm.x86.sse.cvttpd2pi" => "__builtin_ia32_cvttpd2pi", - "llvm.x86.sse.cvttps2pi" => "__builtin_ia32_cvttps2pi", "llvm.x86.sse.cvttss2si" => "__builtin_ia32_cvttss2si", "llvm.x86.sse.cvttss2si64" => "__builtin_ia32_cvttss2si64", "llvm.x86.sse.div.ss" => "__builtin_ia32_divss", @@ -9212,7 +9332,6 @@ match name { "llvm.x86.sse.min.ss" => "__builtin_ia32_minss", "llvm.x86.sse.movmsk.ps" => "__builtin_ia32_movmskps", "llvm.x86.sse.mul.ss" => "__builtin_ia32_mulss", - "llvm.x86.sse.pshuf.w" => "__builtin_ia32_pshufw", "llvm.x86.sse.rcp.ps" => "__builtin_ia32_rcpps", "llvm.x86.sse.rcp.ss" => "__builtin_ia32_rcpss", "llvm.x86.sse.rsqrt.ps" => "__builtin_ia32_rsqrtps", @@ -9398,35 +9517,20 @@ match name { "llvm.x86.sse4a.insertqi" => "__builtin_ia32_insertqi", "llvm.x86.sse4a.movnt.sd" => "__builtin_ia32_movntsd", "llvm.x86.sse4a.movnt.ss" => "__builtin_ia32_movntss", - "llvm.x86.ssse3.pabs.b" => "__builtin_ia32_pabsb", "llvm.x86.ssse3.pabs.b.128" => "__builtin_ia32_pabsb128", - "llvm.x86.ssse3.pabs.d" => "__builtin_ia32_pabsd", "llvm.x86.ssse3.pabs.d.128" => "__builtin_ia32_pabsd128", - "llvm.x86.ssse3.pabs.w" => "__builtin_ia32_pabsw", "llvm.x86.ssse3.pabs.w.128" => "__builtin_ia32_pabsw128", - "llvm.x86.ssse3.phadd.d" => "__builtin_ia32_phaddd", "llvm.x86.ssse3.phadd.d.128" => "__builtin_ia32_phaddd128", - "llvm.x86.ssse3.phadd.sw" => "__builtin_ia32_phaddsw", "llvm.x86.ssse3.phadd.sw.128" => "__builtin_ia32_phaddsw128", - "llvm.x86.ssse3.phadd.w" => "__builtin_ia32_phaddw", "llvm.x86.ssse3.phadd.w.128" => "__builtin_ia32_phaddw128", - "llvm.x86.ssse3.phsub.d" => "__builtin_ia32_phsubd", "llvm.x86.ssse3.phsub.d.128" => "__builtin_ia32_phsubd128", - "llvm.x86.ssse3.phsub.sw" => "__builtin_ia32_phsubsw", "llvm.x86.ssse3.phsub.sw.128" => "__builtin_ia32_phsubsw128", - "llvm.x86.ssse3.phsub.w" => "__builtin_ia32_phsubw", "llvm.x86.ssse3.phsub.w.128" => "__builtin_ia32_phsubw128", - "llvm.x86.ssse3.pmadd.ub.sw" => "__builtin_ia32_pmaddubsw", "llvm.x86.ssse3.pmadd.ub.sw.128" => "__builtin_ia32_pmaddubsw128", - "llvm.x86.ssse3.pmul.hr.sw" => "__builtin_ia32_pmulhrsw", "llvm.x86.ssse3.pmul.hr.sw.128" => "__builtin_ia32_pmulhrsw128", - "llvm.x86.ssse3.pshuf.b" => "__builtin_ia32_pshufb", "llvm.x86.ssse3.pshuf.b.128" => "__builtin_ia32_pshufb128", - "llvm.x86.ssse3.psign.b" => "__builtin_ia32_psignb", "llvm.x86.ssse3.psign.b.128" => "__builtin_ia32_psignb128", - "llvm.x86.ssse3.psign.d" => "__builtin_ia32_psignd", "llvm.x86.ssse3.psign.d.128" => "__builtin_ia32_psignd128", - "llvm.x86.ssse3.psign.w" => "__builtin_ia32_psignw", "llvm.x86.ssse3.psign.w.128" => "__builtin_ia32_psignw128", "llvm.x86.sttilecfg" => "__builtin_ia32_tile_storeconfig", "llvm.x86.stui" => "__builtin_ia32_stui", diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/llvm.rs b/compiler/rustc_codegen_gcc/src/intrinsic/llvm.rs index 48f96df61e97..0a448ded6b1a 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/llvm.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/llvm.rs @@ -1,11 +1,43 @@ use std::borrow::Cow; -use gccjit::{Function, FunctionPtrType, RValue, ToRValue, UnaryOp}; +use gccjit::{CType, Context, Function, FunctionPtrType, RValue, ToRValue, UnaryOp}; use rustc_codegen_ssa::traits::BuilderMethods; use crate::builder::Builder; use crate::context::CodegenCx; +#[cfg_attr(not(feature = "master"), allow(unused_variables))] +pub fn adjust_function<'gcc>( + context: &'gcc Context<'gcc>, + func_name: &str, + func_ptr: RValue<'gcc>, + args: &[RValue<'gcc>], +) -> RValue<'gcc> { + // FIXME: we should not need this hack: this is required because both _mm_fcmadd_sch + // and _mm_mask3_fcmadd_round_sch calls llvm.x86.avx512fp16.mask.vfcmadd.csh and we + // seem to need to map this one LLVM intrinsic to 2 different GCC builtins. + #[cfg(feature = "master")] + match func_name { + "__builtin_ia32_vfcmaddcsh_mask3_round" => { + if format!("{:?}", args[3]).ends_with("255") { + return context + .get_target_builtin_function("__builtin_ia32_vfcmaddcsh_mask_round") + .get_address(None); + } + } + "__builtin_ia32_vfmaddcsh_mask3_round" => { + if format!("{:?}", args[3]).ends_with("255") { + return context + .get_target_builtin_function("__builtin_ia32_vfmaddcsh_mask_round") + .get_address(None); + } + } + _ => (), + } + + func_ptr +} + pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>( builder: &Builder<'a, 'gcc, 'tcx>, gcc_func: FunctionPtrType<'gcc>, @@ -13,6 +45,11 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>( func_name: &str, original_function_name: Option<&String>, ) -> Cow<'b, [RValue<'gcc>]> { + // TODO: this might not be a good way to workaround the missing tile builtins. + if func_name == "__builtin_trap" { + return vec![].into(); + } + // Some LLVM intrinsics do not map 1-to-1 to GCC intrinsics, so we add the missing // arguments here. if gcc_func.get_param_count() != args.len() { @@ -147,7 +184,11 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>( | "__builtin_ia32_psrav16hi_mask" | "__builtin_ia32_psrav8hi_mask" | "__builtin_ia32_permvarhi256_mask" - | "__builtin_ia32_permvarhi128_mask" => { + | "__builtin_ia32_permvarhi128_mask" + | "__builtin_ia32_maxph128_mask" + | "__builtin_ia32_maxph256_mask" + | "__builtin_ia32_minph128_mask" + | "__builtin_ia32_minph256_mask" => { let mut new_args = args.to_vec(); let arg3_type = gcc_func.get_param_type(2); let vector_type = arg3_type.dyncast_vector().expect("vector type"); @@ -182,7 +223,19 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>( | "__builtin_ia32_vplzcntd_128_mask" | "__builtin_ia32_vplzcntq_512_mask" | "__builtin_ia32_vplzcntq_256_mask" - | "__builtin_ia32_vplzcntq_128_mask" => { + | "__builtin_ia32_vplzcntq_128_mask" + | "__builtin_ia32_cvtqq2pd128_mask" + | "__builtin_ia32_cvtqq2pd256_mask" + | "__builtin_ia32_cvtqq2ps256_mask" + | "__builtin_ia32_cvtuqq2pd128_mask" + | "__builtin_ia32_cvtuqq2pd256_mask" + | "__builtin_ia32_cvtuqq2ps256_mask" + | "__builtin_ia32_vcvtw2ph128_mask" + | "__builtin_ia32_vcvtw2ph256_mask" + | "__builtin_ia32_vcvtuw2ph128_mask" + | "__builtin_ia32_vcvtuw2ph256_mask" + | "__builtin_ia32_vcvtdq2ph256_mask" + | "__builtin_ia32_vcvtudq2ph256_mask" => { let mut new_args = args.to_vec(); // Remove last arg as it doesn't seem to be used in GCC and is always false. new_args.pop(); @@ -281,7 +334,11 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>( new_args.push(last_arg); args = new_args.into(); } - "__builtin_ia32_vfmaddsubps512_mask" | "__builtin_ia32_vfmaddsubpd512_mask" => { + "__builtin_ia32_vfmaddsubps512_mask" + | "__builtin_ia32_vfmaddsubpd512_mask" + | "__builtin_ia32_cmpsh_mask_round" + | "__builtin_ia32_vfmaddph512_mask" + | "__builtin_ia32_vfmaddsubph512_mask" => { let mut new_args = args.to_vec(); let last_arg = new_args.pop().expect("last arg"); let arg4_type = gcc_func.get_param_type(3); @@ -304,9 +361,8 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>( | "__builtin_ia32_vpermi2varpd128_mask" | "__builtin_ia32_vpmadd52huq512_mask" | "__builtin_ia32_vpmadd52luq512_mask" - | "__builtin_ia32_vpmadd52huq256_mask" - | "__builtin_ia32_vpmadd52luq256_mask" - | "__builtin_ia32_vpmadd52huq128_mask" => { + | "__builtin_ia32_vfmaddsubph128_mask" + | "__builtin_ia32_vfmaddsubph256_mask" => { let mut new_args = args.to_vec(); let arg4_type = gcc_func.get_param_type(3); let minus_one = builder.context.new_rvalue_from_int(arg4_type, -1); @@ -355,7 +411,14 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>( let minus_one = builder.context.new_rvalue_from_int(arg4_type, -1); args = vec![new_args[1], new_args[0], new_args[2], minus_one].into(); } - "__builtin_ia32_xrstor" | "__builtin_ia32_xsavec" => { + "__builtin_ia32_xrstor" + | "__builtin_ia32_xrstor64" + | "__builtin_ia32_xsavec" + | "__builtin_ia32_xsavec64" + | "__builtin_ia32_xsave" + | "__builtin_ia32_xsave64" + | "__builtin_ia32_xsaveopt" + | "__builtin_ia32_xsaveopt64" => { let new_args = args.to_vec(); let thirty_two = builder.context.new_rvalue_from_int(new_args[1].get_type(), 32); let arg2 = new_args[1] << thirty_two | new_args[2]; @@ -378,11 +441,76 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>( ); args = vec![arg.get_address(None)].into(); } + "__builtin_ia32_cvtqq2pd512_mask" + | "__builtin_ia32_cvtqq2ps512_mask" + | "__builtin_ia32_cvtuqq2pd512_mask" + | "__builtin_ia32_cvtuqq2ps512_mask" + | "__builtin_ia32_sqrtph512_mask_round" + | "__builtin_ia32_vcvtw2ph512_mask_round" + | "__builtin_ia32_vcvtuw2ph512_mask_round" + | "__builtin_ia32_vcvtdq2ph512_mask_round" + | "__builtin_ia32_vcvtudq2ph512_mask_round" + | "__builtin_ia32_vcvtqq2ph512_mask_round" + | "__builtin_ia32_vcvtuqq2ph512_mask_round" => { + let mut old_args = args.to_vec(); + let mut new_args = vec![]; + new_args.push(old_args.swap_remove(0)); + let arg2_type = gcc_func.get_param_type(1); + let vector_type = arg2_type.dyncast_vector().expect("vector type"); + let zero = builder.context.new_rvalue_zero(vector_type.get_element_type()); + let num_units = vector_type.get_num_units(); + let first_arg = + builder.context.new_rvalue_from_vector(None, arg2_type, &vec![zero; num_units]); + new_args.push(first_arg); + let arg3_type = gcc_func.get_param_type(2); + let minus_one = builder.context.new_rvalue_from_int(arg3_type, -1); + new_args.push(minus_one); + new_args.push(old_args.swap_remove(0)); + args = new_args.into(); + } + "__builtin_ia32_addph512_mask_round" + | "__builtin_ia32_subph512_mask_round" + | "__builtin_ia32_mulph512_mask_round" + | "__builtin_ia32_divph512_mask_round" + | "__builtin_ia32_maxph512_mask_round" + | "__builtin_ia32_minph512_mask_round" => { + let mut new_args = args.to_vec(); + let last_arg = new_args.pop().expect("last arg"); + + let arg3_type = gcc_func.get_param_type(2); + let vector_type = arg3_type.dyncast_vector().expect("vector type"); + let zero = builder.context.new_rvalue_zero(vector_type.get_element_type()); + let num_units = vector_type.get_num_units(); + let first_arg = + builder.context.new_rvalue_from_vector(None, arg3_type, &vec![zero; num_units]); + new_args.push(first_arg); + + let arg4_type = gcc_func.get_param_type(3); + let minus_one = builder.context.new_rvalue_from_int(arg4_type, -1); + new_args.push(minus_one); + new_args.push(last_arg); + args = new_args.into(); + } + // NOTE: the LLVM intrinsics receive 3 floats, but the GCC builtin requires 3 vectors. + "__builtin_ia32_vfmaddsh3_mask" => { + let new_args = args.to_vec(); + let arg1_type = gcc_func.get_param_type(0); + let arg2_type = gcc_func.get_param_type(1); + let arg3_type = gcc_func.get_param_type(2); + let arg4_type = gcc_func.get_param_type(3); + let a = builder.context.new_rvalue_from_vector(None, arg1_type, &[new_args[0]; 8]); + let b = builder.context.new_rvalue_from_vector(None, arg2_type, &[new_args[1]; 8]); + let c = builder.context.new_rvalue_from_vector(None, arg3_type, &[new_args[2]; 8]); + let arg4 = builder.context.new_rvalue_from_int(arg4_type, -1); + args = vec![a, b, c, arg4, new_args[3]].into(); + } _ => (), } } else { match func_name { - "__builtin_ia32_rndscaless_mask_round" | "__builtin_ia32_rndscalesd_mask_round" => { + "__builtin_ia32_rndscaless_mask_round" + | "__builtin_ia32_rndscalesd_mask_round" + | "__builtin_ia32_reducesh_mask_round" => { let new_args = args.to_vec(); let arg3_type = gcc_func.get_param_type(2); let arg3 = builder.context.new_cast(None, new_args[4], arg3_type); @@ -390,7 +518,7 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>( let arg4 = builder.context.new_bitcast(None, new_args[2], arg4_type); args = vec![new_args[0], new_args[1], arg3, arg4, new_args[3], new_args[5]].into(); } - // NOTE: the LLVM intrinsic receives 3 floats, but the GCC builtin requires 3 vectors. + // NOTE: the LLVM intrinsics receive 3 floats, but the GCC builtin requires 3 vectors. // FIXME: the intrinsics like _mm_mask_fmadd_sd should probably directly call the GCC // intrinsic to avoid this. "__builtin_ia32_vfmaddss3_round" => { @@ -473,6 +601,52 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>( let new_args = args.to_vec(); args = vec![new_args[1], new_args[0], new_args[2]].into(); } + "__builtin_ia32_rangesd128_mask_round" + | "__builtin_ia32_rangess128_mask_round" + | "__builtin_ia32_reducesd_mask_round" + | "__builtin_ia32_reducess_mask_round" => { + let new_args = args.to_vec(); + args = vec![ + new_args[0], + new_args[1], + new_args[4], + new_args[2], + new_args[3], + new_args[5], + ] + .into(); + } + "__builtin_ia32_rndscalesh_mask_round" => { + let new_args = args.to_vec(); + args = vec![ + new_args[0], + new_args[1], + new_args[4], + new_args[2], + new_args[3], + new_args[5], + ] + .into(); + } + "fma" => { + let mut new_args = args.to_vec(); + new_args[0] = builder.context.new_cast(None, new_args[0], builder.double_type); + new_args[1] = builder.context.new_cast(None, new_args[1], builder.double_type); + new_args[2] = builder.context.new_cast(None, new_args[2], builder.double_type); + args = new_args.into(); + } + "__builtin_ia32_sqrtsh_mask_round" + | "__builtin_ia32_vcvtss2sh_mask_round" + | "__builtin_ia32_vcvtsd2sh_mask_round" + | "__builtin_ia32_vcvtsh2ss_mask_round" + | "__builtin_ia32_vcvtsh2sd_mask_round" + | "__builtin_ia32_rcpsh_mask" + | "__builtin_ia32_rsqrtsh_mask" => { + // The first two arguments are inverted, so swap them. + let mut new_args = args.to_vec(); + new_args.swap(0, 1); + args = new_args.into(); + } _ => (), } } @@ -489,7 +663,9 @@ pub fn adjust_intrinsic_return_value<'a, 'gcc, 'tcx>( orig_args: &[RValue<'gcc>], ) -> RValue<'gcc> { match func_name { - "__builtin_ia32_vfmaddss3_round" | "__builtin_ia32_vfmaddsd3_round" => { + "__builtin_ia32_vfmaddss3_round" + | "__builtin_ia32_vfmaddsd3_round" + | "__builtin_ia32_vfmaddsh3_mask" => { #[cfg(feature = "master")] { let zero = builder.context.new_rvalue_zero(builder.int_type); @@ -546,6 +722,10 @@ pub fn adjust_intrinsic_return_value<'a, 'gcc, 'tcx>( success_variable.to_rvalue(), ]); } + "fma" => { + let f16_type = builder.context.new_c_type(CType::Float16); + return_value = builder.context.new_cast(None, return_value, f16_type); + } _ => (), } @@ -779,7 +959,9 @@ pub fn intrinsic<'gcc, 'tcx>(name: &str, cx: &CodegenCx<'gcc, 'tcx>) -> Function "llvm.x86.avx512.mask.cmp.b.256" => "__builtin_ia32_cmpb256_mask", "llvm.x86.avx512.mask.cmp.b.128" => "__builtin_ia32_cmpb128_mask", "llvm.x86.xrstor" => "__builtin_ia32_xrstor", + "llvm.x86.xrstor64" => "__builtin_ia32_xrstor64", "llvm.x86.xsavec" => "__builtin_ia32_xsavec", + "llvm.x86.xsavec64" => "__builtin_ia32_xsavec64", "llvm.x86.addcarry.32" => "__builtin_ia32_addcarryx_u32", "llvm.x86.subborrow.32" => "__builtin_ia32_sbb_u32", "llvm.x86.avx512.mask.compress.store.w.512" => "__builtin_ia32_compressstoreuhi512_mask", @@ -968,9 +1150,9 @@ pub fn intrinsic<'gcc, 'tcx>(name: &str, cx: &CodegenCx<'gcc, 'tcx>) -> Function "llvm.x86.avx512.dbpsadbw.128" => "__builtin_ia32_dbpsadbw128_mask", "llvm.x86.avx512.vpmadd52h.uq.512" => "__builtin_ia32_vpmadd52huq512_mask", "llvm.x86.avx512.vpmadd52l.uq.512" => "__builtin_ia32_vpmadd52luq512_mask", - "llvm.x86.avx512.vpmadd52h.uq.256" => "__builtin_ia32_vpmadd52huq256_mask", - "llvm.x86.avx512.vpmadd52l.uq.256" => "__builtin_ia32_vpmadd52luq256_mask", - "llvm.x86.avx512.vpmadd52h.uq.128" => "__builtin_ia32_vpmadd52huq128_mask", + "llvm.x86.avx512.vpmadd52h.uq.256" => "__builtin_ia32_vpmadd52huq256", + "llvm.x86.avx512.vpmadd52l.uq.256" => "__builtin_ia32_vpmadd52luq256", + "llvm.x86.avx512.vpmadd52h.uq.128" => "__builtin_ia32_vpmadd52huq128", "llvm.x86.avx512.vpdpwssd.512" => "__builtin_ia32_vpdpwssd_v16si", "llvm.x86.avx512.vpdpwssd.256" => "__builtin_ia32_vpdpwssd_v8si", "llvm.x86.avx512.vpdpwssd.128" => "__builtin_ia32_vpdpwssd_v4si", @@ -983,6 +1165,180 @@ pub fn intrinsic<'gcc, 'tcx>(name: &str, cx: &CodegenCx<'gcc, 'tcx>) -> Function "llvm.x86.avx512.vpdpbusds.512" => "__builtin_ia32_vpdpbusds_v16si", "llvm.x86.avx512.vpdpbusds.256" => "__builtin_ia32_vpdpbusds_v8si", "llvm.x86.avx512.vpdpbusds.128" => "__builtin_ia32_vpdpbusds_v4si", + "llvm.x86.xsave" => "__builtin_ia32_xsave", + "llvm.x86.xsave64" => "__builtin_ia32_xsave64", + "llvm.x86.xsaveopt" => "__builtin_ia32_xsaveopt", + "llvm.x86.xsaveopt64" => "__builtin_ia32_xsaveopt64", + "llvm.x86.avx512.mask.loadu.w.512" => "__builtin_ia32_loaddquhi512_mask", + "llvm.x86.avx512.mask.loadu.b.512" => "__builtin_ia32_loaddquqi512_mask", + "llvm.x86.avx512.mask.loadu.w.256" => "__builtin_ia32_loaddquhi256_mask", + "llvm.x86.avx512.mask.loadu.b.256" => "__builtin_ia32_loaddquqi256_mask", + "llvm.x86.avx512.mask.loadu.w.128" => "__builtin_ia32_loaddquhi128_mask", + "llvm.x86.avx512.mask.loadu.b.128" => "__builtin_ia32_loaddquqi128_mask", + "llvm.x86.avx512.mask.storeu.w.512" => "__builtin_ia32_storedquhi512_mask", + "llvm.x86.avx512.mask.storeu.b.512" => "__builtin_ia32_storedquqi512_mask", + "llvm.x86.avx512.mask.storeu.w.256" => "__builtin_ia32_storedquhi256_mask", + "llvm.x86.avx512.mask.storeu.b.256" => "__builtin_ia32_storedquqi256_mask", + "llvm.x86.avx512.mask.storeu.w.128" => "__builtin_ia32_storedquhi128_mask", + "llvm.x86.avx512.mask.storeu.b.128" => "__builtin_ia32_storedquqi128_mask", + "llvm.x86.avx512.mask.expand.load.w.512" => "__builtin_ia32_expandloadhi512_mask", + "llvm.x86.avx512.mask.expand.load.w.256" => "__builtin_ia32_expandloadhi256_mask", + "llvm.x86.avx512.mask.expand.load.w.128" => "__builtin_ia32_expandloadhi128_mask", + "llvm.x86.avx512.mask.expand.load.b.512" => "__builtin_ia32_expandloadqi512_mask", + "llvm.x86.avx512.mask.expand.load.b.256" => "__builtin_ia32_expandloadqi256_mask", + "llvm.x86.avx512.mask.expand.load.b.128" => "__builtin_ia32_expandloadqi128_mask", + "llvm.x86.avx512.sitofp.round.v8f64.v8i64" => "__builtin_ia32_cvtqq2pd512_mask", + "llvm.x86.avx512.sitofp.round.v2f64.v2i64" => "__builtin_ia32_cvtqq2pd128_mask", + "llvm.x86.avx512.sitofp.round.v4f64.v4i64" => "__builtin_ia32_cvtqq2pd256_mask", + "llvm.x86.avx512.sitofp.round.v8f32.v8i64" => "__builtin_ia32_cvtqq2ps512_mask", + "llvm.x86.avx512.sitofp.round.v4f32.v4i64" => "__builtin_ia32_cvtqq2ps256_mask", + "llvm.x86.avx512.uitofp.round.v8f64.v8u64" => "__builtin_ia32_cvtuqq2pd512_mask", + "llvm.x86.avx512.uitofp.round.v2f64.v2u64" => "__builtin_ia32_cvtuqq2pd128_mask", + "llvm.x86.avx512.uitofp.round.v4f64.v4u64" => "__builtin_ia32_cvtuqq2pd256_mask", + "llvm.x86.avx512.uitofp.round.v8f32.v8u64" => "__builtin_ia32_cvtuqq2ps512_mask", + "llvm.x86.avx512.uitofp.round.v4f32.v4u64" => "__builtin_ia32_cvtuqq2ps256_mask", + "llvm.x86.avx512.mask.reduce.pd.512" => "__builtin_ia32_reducepd512_mask_round", + "llvm.x86.avx512.mask.reduce.ps.512" => "__builtin_ia32_reduceps512_mask_round", + "llvm.x86.avx512.mask.reduce.sd" => "__builtin_ia32_reducesd_mask_round", + "llvm.x86.avx512.mask.reduce.ss" => "__builtin_ia32_reducess_mask_round", + "llvm.x86.avx512.mask.loadu.d.256" => "__builtin_ia32_loaddqusi256_mask", + "llvm.x86.avx512.mask.loadu.q.256" => "__builtin_ia32_loaddqudi256_mask", + "llvm.x86.avx512.mask.loadu.ps.256" => "__builtin_ia32_loadups256_mask", + "llvm.x86.avx512.mask.loadu.pd.256" => "__builtin_ia32_loadupd256_mask", + "llvm.x86.avx512.mask.loadu.d.128" => "__builtin_ia32_loaddqusi128_mask", + "llvm.x86.avx512.mask.loadu.q.128" => "__builtin_ia32_loaddqudi128_mask", + "llvm.x86.avx512.mask.loadu.ps.128" => "__builtin_ia32_loadups128_mask", + "llvm.x86.avx512.mask.loadu.pd.128" => "__builtin_ia32_loadupd128_mask", + "llvm.x86.avx512.mask.load.d.512" => "__builtin_ia32_movdqa32load512_mask", + "llvm.x86.avx512.mask.load.q.512" => "__builtin_ia32_movdqa64load512_mask", + "llvm.x86.avx512.mask.load.ps.512" => "__builtin_ia32_loadaps512_mask", + "llvm.x86.avx512.mask.load.pd.512" => "__builtin_ia32_loadapd512_mask", + "llvm.x86.avx512.mask.load.d.256" => "__builtin_ia32_movdqa32load256_mask", + "llvm.x86.avx512.mask.load.q.256" => "__builtin_ia32_movdqa64load256_mask", + "llvm.x86.avx512fp16.mask.cmp.sh" => "__builtin_ia32_cmpsh_mask_round", + "llvm.x86.avx512fp16.vcomi.sh" => "__builtin_ia32_cmpsh_mask_round", + "llvm.x86.avx512fp16.add.ph.512" => "__builtin_ia32_addph512_mask_round", + "llvm.x86.avx512fp16.sub.ph.512" => "__builtin_ia32_subph512_mask_round", + "llvm.x86.avx512fp16.mul.ph.512" => "__builtin_ia32_mulph512_mask_round", + "llvm.x86.avx512fp16.div.ph.512" => "__builtin_ia32_divph512_mask_round", + "llvm.x86.avx512fp16.mask.vfmul.cph.512" => "__builtin_ia32_vfmulcph512_mask_round", + "llvm.x86.avx512fp16.mask.vfmul.csh" => "__builtin_ia32_vfmulcsh_mask_round", + "llvm.x86.avx512fp16.mask.vfcmul.cph.512" => "__builtin_ia32_vfcmulcph512_mask_round", + "llvm.x86.avx512fp16.mask.vfcmul.csh" => "__builtin_ia32_vfcmulcsh_mask_round", + "llvm.x86.avx512fp16.mask.vfmadd.cph.512" => "__builtin_ia32_vfmaddcph512_mask3_round", + "llvm.x86.avx512fp16.maskz.vfmadd.cph.512" => "__builtin_ia32_vfmaddcph512_maskz_round", + "llvm.x86.avx512fp16.mask.vfmadd.csh" => "__builtin_ia32_vfmaddcsh_mask3_round", + "llvm.x86.avx512fp16.maskz.vfmadd.csh" => "__builtin_ia32_vfmaddcsh_maskz_round", + "llvm.x86.avx512fp16.mask.vfcmadd.cph.512" => "__builtin_ia32_vfcmaddcph512_mask3_round", + "llvm.x86.avx512fp16.maskz.vfcmadd.cph.512" => "__builtin_ia32_vfcmaddcph512_maskz_round", + "llvm.x86.avx512fp16.mask.vfcmadd.csh" => "__builtin_ia32_vfcmaddcsh_mask3_round", + "llvm.x86.avx512fp16.maskz.vfcmadd.csh" => "__builtin_ia32_vfcmaddcsh_maskz_round", + "llvm.x86.avx512fp16.vfmadd.ph.512" => "__builtin_ia32_vfmaddph512_mask", + "llvm.x86.avx512fp16.vcvtsi642sh" => "__builtin_ia32_vcvtsi2sh64_round", + "llvm.x86.avx512fp16.vcvtusi642sh" => "__builtin_ia32_vcvtusi2sh64_round", + "llvm.x86.avx512fp16.vcvtsh2si64" => "__builtin_ia32_vcvtsh2si64_round", + "llvm.x86.avx512fp16.vcvtsh2usi64" => "__builtin_ia32_vcvtsh2usi64_round", + "llvm.x86.avx512fp16.vcvttsh2si64" => "__builtin_ia32_vcvttsh2si64_round", + "llvm.x86.avx512fp16.vcvttsh2usi64" => "__builtin_ia32_vcvttsh2usi64_round", + "llvm.x86.avx512.mask.load.ps.256" => "__builtin_ia32_loadaps256_mask", + "llvm.x86.avx512.mask.load.pd.256" => "__builtin_ia32_loadapd256_mask", + "llvm.x86.avx512.mask.load.d.128" => "__builtin_ia32_movdqa32load128_mask", + "llvm.x86.avx512.mask.load.q.128" => "__builtin_ia32_movdqa64load128_mask", + "llvm.x86.avx512.mask.load.ps.128" => "__builtin_ia32_loadaps128_mask", + "llvm.x86.avx512.mask.load.pd.128" => "__builtin_ia32_loadapd128_mask", + "llvm.x86.avx512.mask.storeu.d.256" => "__builtin_ia32_storedqusi256_mask", + "llvm.x86.avx512.mask.storeu.q.256" => "__builtin_ia32_storedqudi256_mask", + "llvm.x86.avx512.mask.storeu.ps.256" => "__builtin_ia32_storeups256_mask", + "llvm.x86.avx512.mask.storeu.pd.256" => "__builtin_ia32_storeupd256_mask", + "llvm.x86.avx512.mask.storeu.d.128" => "__builtin_ia32_storedqusi128_mask", + "llvm.x86.avx512.mask.storeu.q.128" => "__builtin_ia32_storedqudi128_mask", + "llvm.x86.avx512.mask.storeu.ps.128" => "__builtin_ia32_storeups128_mask", + "llvm.x86.avx512.mask.storeu.pd.128" => "__builtin_ia32_storeupd128_mask", + "llvm.x86.avx512.mask.store.d.512" => "__builtin_ia32_movdqa32store512_mask", + "llvm.x86.avx512.mask.store.q.512" => "__builtin_ia32_movdqa64store512_mask", + "llvm.x86.avx512.mask.store.ps.512" => "__builtin_ia32_storeaps512_mask", + "llvm.x86.avx512.mask.store.pd.512" => "__builtin_ia32_storeapd512_mask", + "llvm.x86.avx512.mask.store.d.256" => "__builtin_ia32_movdqa32store256_mask", + "llvm.x86.avx512.mask.store.q.256" => "__builtin_ia32_movdqa64store256_mask", + "llvm.x86.avx512.mask.store.ps.256" => "__builtin_ia32_storeaps256_mask", + "llvm.x86.avx512.mask.store.pd.256" => "__builtin_ia32_storeapd256_mask", + "llvm.x86.avx512.mask.store.d.128" => "__builtin_ia32_movdqa32store128_mask", + "llvm.x86.avx512.mask.store.q.128" => "__builtin_ia32_movdqa64store128_mask", + "llvm.x86.avx512.mask.store.ps.128" => "__builtin_ia32_storeaps128_mask", + "llvm.x86.avx512.mask.store.pd.128" => "__builtin_ia32_storeapd128_mask", + "llvm.x86.avx512fp16.vfmadd.f16" => "__builtin_ia32_vfmaddsh3_mask", + "llvm.x86.avx512fp16.vfmaddsub.ph.128" => "__builtin_ia32_vfmaddsubph128_mask", + "llvm.x86.avx512fp16.vfmaddsub.ph.256" => "__builtin_ia32_vfmaddsubph256_mask", + "llvm.x86.avx512fp16.vfmaddsub.ph.512" => "__builtin_ia32_vfmaddsubph512_mask", + "llvm.x86.avx512fp16.sqrt.ph.512" => "__builtin_ia32_sqrtph512_mask_round", + "llvm.x86.avx512fp16.mask.sqrt.sh" => "__builtin_ia32_sqrtsh_mask_round", + "llvm.x86.avx512fp16.max.ph.128" => "__builtin_ia32_maxph128_mask", + "llvm.x86.avx512fp16.max.ph.256" => "__builtin_ia32_maxph256_mask", + "llvm.x86.avx512fp16.max.ph.512" => "__builtin_ia32_maxph512_mask_round", + "llvm.x86.avx512fp16.min.ph.128" => "__builtin_ia32_minph128_mask", + "llvm.x86.avx512fp16.min.ph.256" => "__builtin_ia32_minph256_mask", + "llvm.x86.avx512fp16.min.ph.512" => "__builtin_ia32_minph512_mask_round", + "llvm.x86.avx512fp16.mask.getexp.sh" => "__builtin_ia32_getexpsh_mask_round", + "llvm.x86.avx512fp16.mask.rndscale.ph.128" => "__builtin_ia32_rndscaleph128_mask", + "llvm.x86.avx512fp16.mask.rndscale.ph.256" => "__builtin_ia32_rndscaleph256_mask", + "llvm.x86.avx512fp16.mask.rndscale.ph.512" => "__builtin_ia32_rndscaleph512_mask_round", + "llvm.x86.avx512fp16.mask.scalef.ph.512" => "__builtin_ia32_scalefph512_mask_round", + "llvm.x86.avx512fp16.mask.reduce.ph.512" => "__builtin_ia32_reduceph512_mask_round", + "llvm.x86.avx512fp16.mask.reduce.sh" => "__builtin_ia32_reducesh_mask_round", + "llvm.x86.avx512.sitofp.round.v8f16.v8i16" => "__builtin_ia32_vcvtw2ph128_mask", + "llvm.x86.avx512.sitofp.round.v16f16.v16i16" => "__builtin_ia32_vcvtw2ph256_mask", + "llvm.x86.avx512.sitofp.round.v32f16.v32i16" => "__builtin_ia32_vcvtw2ph512_mask_round", + "llvm.x86.avx512.uitofp.round.v8f16.v8u16" => "__builtin_ia32_vcvtuw2ph128_mask", + "llvm.x86.avx512.uitofp.round.v16f16.v16u16" => "__builtin_ia32_vcvtuw2ph256_mask", + "llvm.x86.avx512.uitofp.round.v32f16.v32u16" => "__builtin_ia32_vcvtuw2ph512_mask_round", + "llvm.x86.avx512.sitofp.round.v8f16.v8i32" => "__builtin_ia32_vcvtdq2ph256_mask", + "llvm.x86.avx512.sitofp.round.v16f16.v16i32" => "__builtin_ia32_vcvtdq2ph512_mask_round", + "llvm.x86.avx512fp16.vcvtsi2sh" => "__builtin_ia32_vcvtsi2sh32_round", + "llvm.x86.avx512.uitofp.round.v8f16.v8u32" => "__builtin_ia32_vcvtudq2ph256_mask", + "llvm.x86.avx512.uitofp.round.v16f16.v16u32" => "__builtin_ia32_vcvtudq2ph512_mask_round", + "llvm.x86.avx512fp16.vcvtusi2sh" => "__builtin_ia32_vcvtusi2sh32_round", + "llvm.x86.avx512.sitofp.round.v8f16.v8i64" => "__builtin_ia32_vcvtqq2ph512_mask_round", + "llvm.x86.avx512.uitofp.round.v8f16.v8u64" => "__builtin_ia32_vcvtuqq2ph512_mask_round", + "llvm.x86.avx512fp16.mask.vcvtps2phx.512" => "__builtin_ia32_vcvtps2phx512_mask_round", + "llvm.x86.avx512fp16.mask.vcvtpd2ph.512" => "__builtin_ia32_vcvtpd2ph512_mask_round", + "llvm.x86.avx512fp16.mask.vcvtph2uw.512" => "__builtin_ia32_vcvtph2uw512_mask_round", + "llvm.x86.avx512fp16.mask.vcvttph2w.512" => "__builtin_ia32_vcvttph2w512_mask_round", + "llvm.x86.avx512fp16.mask.vcvttph2uw.512" => "__builtin_ia32_vcvttph2uw512_mask_round", + "llvm.x86.avx512fp16.mask.vcvtph2dq.512" => "__builtin_ia32_vcvtph2dq512_mask_round", + "llvm.x86.avx512fp16.vcvtsh2si32" => "__builtin_ia32_vcvtsh2si32_round", + "llvm.x86.avx512fp16.mask.vcvtph2udq.512" => "__builtin_ia32_vcvtph2udq512_mask_round", + "llvm.x86.avx512fp16.vcvtsh2usi32" => "__builtin_ia32_vcvtsh2usi32_round", + "llvm.x86.avx512fp16.mask.vcvttph2dq.512" => "__builtin_ia32_vcvttph2dq512_mask_round", + "llvm.x86.avx512fp16.vcvttsh2si32" => "__builtin_ia32_vcvttsh2si32_round", + "llvm.x86.avx512fp16.mask.vcvttph2udq.512" => "__builtin_ia32_vcvttph2udq512_mask_round", + "llvm.x86.avx512fp16.vcvttsh2usi32" => "__builtin_ia32_vcvttsh2usi32_round", + "llvm.x86.avx512fp16.mask.vcvtph2qq.512" => "__builtin_ia32_vcvtph2qq512_mask_round", + "llvm.x86.avx512fp16.mask.vcvtph2uqq.512" => "__builtin_ia32_vcvtph2uqq512_mask_round", + "llvm.x86.avx512fp16.mask.vcvttph2qq.512" => "__builtin_ia32_vcvttph2qq512_mask_round", + "llvm.x86.avx512fp16.mask.vcvttph2uqq.512" => "__builtin_ia32_vcvttph2uqq512_mask_round", + "llvm.x86.avx512fp16.mask.vcvtph2psx.512" => "__builtin_ia32_vcvtph2psx512_mask_round", + "llvm.x86.avx512fp16.mask.vcvtph2pd.512" => "__builtin_ia32_vcvtph2pd512_mask_round", + "llvm.x86.avx512fp16.mask.vfcmadd.cph.256" => "__builtin_ia32_vfcmaddcph256_mask3", + "llvm.x86.avx512fp16.mask.vfmadd.cph.256" => "__builtin_ia32_vfmaddcph256_mask3", + "llvm.x86.avx512fp16.mask.vfcmadd.cph.128" => "__builtin_ia32_vfcmaddcph128_mask3", + "llvm.x86.avx512fp16.mask.vfmadd.cph.128" => "__builtin_ia32_vfmaddcph128_mask3", + + // TODO: support the tile builtins: + "llvm.x86.ldtilecfg" => "__builtin_trap", + "llvm.x86.sttilecfg" => "__builtin_trap", + "llvm.x86.tileloadd64" => "__builtin_trap", + "llvm.x86.tilerelease" => "__builtin_trap", + "llvm.x86.tilestored64" => "__builtin_trap", + "llvm.x86.tileloaddt164" => "__builtin_trap", + "llvm.x86.tilezero" => "__builtin_trap", + "llvm.x86.tdpbf16ps" => "__builtin_trap", + "llvm.x86.tdpbssd" => "__builtin_trap", + "llvm.x86.tdpbsud" => "__builtin_trap", + "llvm.x86.tdpbusd" => "__builtin_trap", + "llvm.x86.tdpbuud" => "__builtin_trap", + "llvm.x86.tdpfp16ps" => "__builtin_trap", + "llvm.x86.tcmmimfp16ps" => "__builtin_trap", + "llvm.x86.tcmmrlfp16ps" => "__builtin_trap", // NOTE: this file is generated by https://github.com/GuillaumeGomez/llvmint/blob/master/generate_list.py _ => include!("archs.rs"), diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs index 753c3a3dfa63..945eedf55566 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs @@ -127,20 +127,13 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc // https://github.com/rust-lang/rust-clippy/issues/12497 // and leave `else if use_integer_compare` to be placed "as is". #[allow(clippy::suspicious_else_formatting)] - let llval = match name { + let value = match name { _ if simple.is_some() => { - // FIXME(antoyo): remove this cast when the API supports function. - let func = unsafe { - std::mem::transmute::, RValue<'gcc>>(simple.expect("simple")) - }; - self.call( - self.type_void(), - None, - None, + let func = simple.expect("simple function"); + self.cx.context.new_call( + self.location, func, &args.iter().map(|arg| arg.immediate()).collect::>(), - None, - None, ) } sym::likely => self.expect(args[0].immediate(), true), @@ -383,7 +376,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc _ if name_str.starts_with("simd_") => { match generic_simd_intrinsic(self, name, callee_ty, args, ret_ty, llret_ty, span) { - Ok(llval) => llval, + Ok(value) => value, Err(()) => return Ok(()), } } @@ -396,9 +389,9 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc if let PassMode::Cast { cast: ref ty, .. } = fn_abi.ret.mode { let ptr_llty = self.type_ptr_to(ty.gcc_type(self)); let ptr = self.pointercast(result.val.llval, ptr_llty); - self.store(llval, ptr, result.val.align); + self.store(value, ptr, result.val.align); } else { - OperandRef::from_immediate_or_packed_pair(self, llval, result.layout) + OperandRef::from_immediate_or_packed_pair(self, value, result.layout) .val .store(self, result); } diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs index d78b3f2eb8e8..eeab2a5f1559 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs @@ -198,7 +198,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( bx.context.new_bitcast(None, shuffled, v_type) }; - if name == sym::simd_bswap || name == sym::simd_bitreverse { + if matches!(name, sym::simd_bswap | sym::simd_bitreverse | sym::simd_ctpop) { require!( bx.type_kind(bx.element_type(llret_ty)) == TypeKind::Integer, InvalidMonomorphization::UnsupportedOperation { span, name, in_ty, in_elem } @@ -209,6 +209,22 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( return Ok(simd_bswap(bx, args[0].immediate())); } + let simd_ctpop = |bx: &mut Builder<'a, 'gcc, 'tcx>, vector: RValue<'gcc>| -> RValue<'gcc> { + let mut vector_elements = vec![]; + let elem_ty = bx.element_type(llret_ty); + for i in 0..in_len { + let index = bx.context.new_rvalue_from_long(bx.ulong_type, i as i64); + let element = bx.extract_element(vector, index).to_rvalue(); + let result = bx.context.new_cast(None, bx.pop_count(element), elem_ty); + vector_elements.push(result); + } + bx.context.new_rvalue_from_vector(None, llret_ty, &vector_elements) + }; + + if name == sym::simd_ctpop { + return Ok(simd_ctpop(bx, args[0].immediate())); + } + // We use a different algorithm from non-vector bitreverse to take advantage of most // processors' vector shuffle units. It works like this: // 1. Generate pre-reversed low and high nibbles as a vector. @@ -718,11 +734,12 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( return Err(()); }}; } - let (elem_ty_str, elem_ty) = if let ty::Float(ref f) = *in_elem.kind() { + let (elem_ty_str, elem_ty, cast_type) = if let ty::Float(ref f) = *in_elem.kind() { let elem_ty = bx.cx.type_float_from_ty(*f); match f.bit_width() { - 32 => ("f", elem_ty), - 64 => ("", elem_ty), + 16 => ("", elem_ty, Some(bx.cx.double_type)), + 32 => ("f", elem_ty, None), + 64 => ("", elem_ty, None), _ => { return_error!(InvalidMonomorphization::FloatingPointVector { span, @@ -758,10 +775,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( _ => return_error!(InvalidMonomorphization::UnrecognizedIntrinsic { span, name }), }; let builtin_name = format!("{}{}", intr_name, elem_ty_str); - let funcs = bx.cx.functions.borrow(); - let function = funcs - .get(&builtin_name) - .unwrap_or_else(|| panic!("unable to find builtin function {}", builtin_name)); + let function = bx.context.get_builtin_function(builtin_name); // TODO(antoyo): add platform-specific behavior here for architectures that have these // intrinsics as instructions (for instance, gpus) @@ -769,17 +783,28 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( for i in 0..in_len { let index = bx.context.new_rvalue_from_long(bx.ulong_type, i as i64); // we have to treat fpowi specially, since fpowi's second argument is always an i32 - let arguments = if name == sym::simd_fpowi { - vec![ + let mut arguments = vec![]; + if name == sym::simd_fpowi { + arguments = vec![ bx.extract_element(args[0].immediate(), index).to_rvalue(), args[1].immediate(), - ] + ]; } else { - args.iter() - .map(|arg| bx.extract_element(arg.immediate(), index).to_rvalue()) - .collect() + for arg in args { + let mut element = bx.extract_element(arg.immediate(), index).to_rvalue(); + // FIXME: it would probably be better to not have casts here and use the proper + // instructions. + if let Some(typ) = cast_type { + element = bx.context.new_cast(None, element, typ); + } + arguments.push(element); + } }; - vector_elements.push(bx.context.new_call(None, *function, &arguments)); + let mut result = bx.context.new_call(None, function, &arguments); + if cast_type.is_some() { + result = bx.context.new_cast(None, result, elem_ty); + } + vector_elements.push(result); } let c = bx.context.new_rvalue_from_vector(None, vec_ty, &vector_elements); Ok(c) diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index edf524ff0b4a..a7a32e285d8f 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -363,7 +363,7 @@ impl Deref for SyncContext { unsafe impl Send for SyncContext {} // FIXME(antoyo): that shouldn't be Sync. Parallel compilation is currently disabled with "-Zno-parallel-llvm". -// TODO: disable it here by returing false in CodegenBackend::supports_parallel(). +// TODO: disable it here by returning false in CodegenBackend::supports_parallel(). unsafe impl Sync for SyncContext {} impl WriteBackendMethods for GccCodegenBackend { diff --git a/compiler/rustc_codegen_gcc/src/mono_item.rs b/compiler/rustc_codegen_gcc/src/mono_item.rs index 8a8b748750c7..b7b282bf2a65 100644 --- a/compiler/rustc_codegen_gcc/src/mono_item.rs +++ b/compiler/rustc_codegen_gcc/src/mono_item.rs @@ -37,7 +37,7 @@ impl<'gcc, 'tcx> PreDefineCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { let is_tls = attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL); let global = self.define_global(symbol_name, gcc_type, is_tls, attrs.link_section); #[cfg(feature = "master")] - global.add_string_attribute(VarAttribute::Visibility(base::visibility_to_gcc(visibility))); + global.add_attribute(VarAttribute::Visibility(base::visibility_to_gcc(visibility))); // TODO(antoyo): set linkage. self.instances.borrow_mut().insert(instance, global); diff --git a/compiler/rustc_codegen_gcc/tests/failing-ice-tests.txt b/compiler/rustc_codegen_gcc/tests/failing-ice-tests.txt index 2084f86b62e1..ff1b6f148946 100644 --- a/compiler/rustc_codegen_gcc/tests/failing-ice-tests.txt +++ b/compiler/rustc_codegen_gcc/tests/failing-ice-tests.txt @@ -34,3 +34,7 @@ tests/ui/sepcomp/sepcomp-unwind.rs tests/ui/extern/issue-64655-extern-rust-must-allow-unwind.rs tests/ui/extern/issue-64655-allow-unwind-when-calling-panic-directly.rs tests/ui/unwind-no-uwtable.rs +tests/ui/delegation/fn-header.rs +tests/ui/simd/intrinsic/generic-arithmetic-pass.rs +tests/ui/simd/masked-load-store.rs +tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.rs diff --git a/compiler/rustc_codegen_gcc/tests/failing-ui-tests.txt b/compiler/rustc_codegen_gcc/tests/failing-ui-tests.txt index 5a55bdb156e3..56b51275a53b 100644 --- a/compiler/rustc_codegen_gcc/tests/failing-ui-tests.txt +++ b/compiler/rustc_codegen_gcc/tests/failing-ui-tests.txt @@ -95,3 +95,29 @@ tests/ui/simd/intrinsic/generic-arithmetic-pass.rs tests/ui/backtrace/backtrace.rs tests/ui/lifetimes/tail-expr-lock-poisoning.rs tests/ui/runtime/rt-explody-panic-payloads.rs +tests/ui/codegen/equal-pointers-unequal/as-cast/function.rs +tests/ui/codegen/equal-pointers-unequal/as-cast/basic.rs +tests/ui/codegen/equal-pointers-unequal/as-cast/inline1.rs +tests/ui/codegen/equal-pointers-unequal/as-cast/print.rs +tests/ui/codegen/equal-pointers-unequal/as-cast/inline2.rs +tests/ui/codegen/equal-pointers-unequal/as-cast/print3.rs +tests/ui/codegen/equal-pointers-unequal/as-cast/segfault.rs +tests/ui/codegen/equal-pointers-unequal/exposed-provenance/function.rs +tests/ui/codegen/equal-pointers-unequal/exposed-provenance/basic.rs +tests/ui/codegen/equal-pointers-unequal/as-cast/zero.rs +tests/ui/codegen/equal-pointers-unequal/exposed-provenance/inline1.rs +tests/ui/codegen/equal-pointers-unequal/exposed-provenance/print.rs +tests/ui/codegen/equal-pointers-unequal/exposed-provenance/print3.rs +tests/ui/codegen/equal-pointers-unequal/exposed-provenance/inline2.rs +tests/ui/codegen/equal-pointers-unequal/exposed-provenance/segfault.rs +tests/ui/codegen/equal-pointers-unequal/exposed-provenance/zero.rs +tests/ui/codegen/equal-pointers-unequal/strict-provenance/basic.rs +tests/ui/codegen/equal-pointers-unequal/strict-provenance/function.rs +tests/ui/codegen/equal-pointers-unequal/strict-provenance/print.rs +tests/ui/codegen/equal-pointers-unequal/strict-provenance/inline1.rs +tests/ui/codegen/equal-pointers-unequal/strict-provenance/print3.rs +tests/ui/codegen/equal-pointers-unequal/strict-provenance/inline2.rs +tests/ui/codegen/equal-pointers-unequal/strict-provenance/segfault.rs +tests/ui/codegen/equal-pointers-unequal/strict-provenance/zero.rs +tests/ui/sanitizer/cfi-sized-associated-ty.rs +tests/ui/sanitizer/cfi-can-reveal-opaques.rs diff --git a/compiler/rustc_codegen_gcc/tests/run/array.rs b/compiler/rustc_codegen_gcc/tests/run/array.rs index 3fe8917c9a3c..432f11ad8d4c 100644 --- a/compiler/rustc_codegen_gcc/tests/run/array.rs +++ b/compiler/rustc_codegen_gcc/tests/run/array.rs @@ -31,6 +31,7 @@ impl Copy for i32 {} impl Copy for u8 {} impl Copy for i8 {} impl Copy for i16 {} +impl Copy for *mut T {} #[lang = "receiver"] trait Receiver { diff --git a/compiler/rustc_codegen_gcc/tests/run/closure.rs b/compiler/rustc_codegen_gcc/tests/run/closure.rs index 355f0acee747..00e61cc001fe 100644 --- a/compiler/rustc_codegen_gcc/tests/run/closure.rs +++ b/compiler/rustc_codegen_gcc/tests/run/closure.rs @@ -33,6 +33,7 @@ impl Copy for i32 {} impl Copy for u32 {} impl Copy for u8 {} impl Copy for i8 {} +impl Copy for *mut T {} #[lang = "receiver"] trait Receiver { diff --git a/compiler/rustc_codegen_gcc/tests/run/condition.rs b/compiler/rustc_codegen_gcc/tests/run/condition.rs index 1b3ae6dc004a..7b05b7decd36 100644 --- a/compiler/rustc_codegen_gcc/tests/run/condition.rs +++ b/compiler/rustc_codegen_gcc/tests/run/condition.rs @@ -34,6 +34,7 @@ impl Copy for i16 {} impl Copy for char {} impl Copy for i8 {} impl Copy for u8 {} +impl Copy for *mut T {} #[lang = "receiver"] trait Receiver { diff --git a/compiler/rustc_codegen_gcc/tests/run/fun_ptr.rs b/compiler/rustc_codegen_gcc/tests/run/fun_ptr.rs index 960303597726..4e96f3765558 100644 --- a/compiler/rustc_codegen_gcc/tests/run/fun_ptr.rs +++ b/compiler/rustc_codegen_gcc/tests/run/fun_ptr.rs @@ -28,6 +28,7 @@ impl Copy for i32 {} impl Copy for u8 {} impl Copy for i8 {} impl Copy for i16 {} +impl Copy for *mut T {} #[lang = "receiver"] trait Receiver { diff --git a/compiler/rustc_codegen_gcc/tests/run/ptr_cast.rs b/compiler/rustc_codegen_gcc/tests/run/ptr_cast.rs index 09d77abe27cf..a94279182d68 100644 --- a/compiler/rustc_codegen_gcc/tests/run/ptr_cast.rs +++ b/compiler/rustc_codegen_gcc/tests/run/ptr_cast.rs @@ -28,6 +28,7 @@ impl Copy for i32 {} impl Copy for u8 {} impl Copy for i8 {} impl Copy for i16 {} +impl Copy for *mut T {} #[lang = "receiver"] trait Receiver { diff --git a/compiler/rustc_codegen_gcc/tests/run/slice.rs b/compiler/rustc_codegen_gcc/tests/run/slice.rs index 1262c86c8109..e86fc823a1ab 100644 --- a/compiler/rustc_codegen_gcc/tests/run/slice.rs +++ b/compiler/rustc_codegen_gcc/tests/run/slice.rs @@ -26,6 +26,7 @@ impl Copy for isize {} impl Copy for usize {} impl Copy for i32 {} impl Copy for u32 {} +impl Copy for *mut T {} #[lang = "receiver"] trait Receiver { diff --git a/compiler/rustc_codegen_gcc/tests/run/static.rs b/compiler/rustc_codegen_gcc/tests/run/static.rs index e7c46ae3fcc8..6247e08f5e3c 100644 --- a/compiler/rustc_codegen_gcc/tests/run/static.rs +++ b/compiler/rustc_codegen_gcc/tests/run/static.rs @@ -34,6 +34,7 @@ trait Copy { } impl Copy for isize {} +impl Copy for *mut T {} #[lang = "receiver"] trait Receiver { diff --git a/compiler/rustc_codegen_gcc/tools/generate_intrinsics.py b/compiler/rustc_codegen_gcc/tools/generate_intrinsics.py index 90fb7bfad27c..8efed3e43af8 100644 --- a/compiler/rustc_codegen_gcc/tools/generate_intrinsics.py +++ b/compiler/rustc_codegen_gcc/tools/generate_intrinsics.py @@ -45,7 +45,7 @@ def convert_to_string(content): return content -def extract_instrinsics_from_llvm(llvm_path, intrinsics): +def extract_intrinsics_from_llvm(llvm_path, intrinsics): command = ["llvm-tblgen", "llvm/IR/Intrinsics.td"] cwd = os.path.join(llvm_path, "llvm/include") print("=> Running command `{}` from `{}`".format(command, cwd)) @@ -88,7 +88,7 @@ def append_translation(json_data, p, array): append_intrinsic(array, content[1], content[3]) -def extract_instrinsics_from_llvmint(llvmint, intrinsics): +def extract_intrinsics_from_llvmint(llvmint, intrinsics): archs = [ "AMDGPU", "aarch64", @@ -152,9 +152,9 @@ def update_intrinsics(llvm_path, llvmint, llvmint2): intrinsics_llvmint = {} all_intrinsics = {} - extract_instrinsics_from_llvm(llvm_path, intrinsics_llvm) - extract_instrinsics_from_llvmint(llvmint, intrinsics_llvmint) - extract_instrinsics_from_llvmint(llvmint2, intrinsics_llvmint) + extract_intrinsics_from_llvm(llvm_path, intrinsics_llvm) + extract_intrinsics_from_llvmint(llvmint, intrinsics_llvmint) + extract_intrinsics_from_llvmint(llvmint2, intrinsics_llvmint) intrinsics = {} # We give priority to translations from LLVM over the ones from llvmint. diff --git a/compiler/rustc_codegen_llvm/src/allocator.rs b/compiler/rustc_codegen_llvm/src/allocator.rs index 2adac278c62f..89f5305840b9 100644 --- a/compiler/rustc_codegen_llvm/src/allocator.rs +++ b/compiler/rustc_codegen_llvm/src/allocator.rs @@ -77,18 +77,20 @@ pub(crate) unsafe fn codegen( // __rust_alloc_error_handler_should_panic let name = OomStrategy::SYMBOL; let ll_g = llvm::LLVMRustGetOrInsertGlobal(llmod, name.as_ptr().cast(), name.len(), i8); - if tcx.sess.default_hidden_visibility() { - llvm::LLVMRustSetVisibility(ll_g, llvm::Visibility::Hidden); - } + llvm::LLVMRustSetVisibility( + ll_g, + llvm::Visibility::from_generic(tcx.sess.default_visibility()), + ); let val = tcx.sess.opts.unstable_opts.oom.should_panic(); let llval = llvm::LLVMConstInt(i8, val as u64, False); llvm::LLVMSetInitializer(ll_g, llval); let name = NO_ALLOC_SHIM_IS_UNSTABLE; let ll_g = llvm::LLVMRustGetOrInsertGlobal(llmod, name.as_ptr().cast(), name.len(), i8); - if tcx.sess.default_hidden_visibility() { - llvm::LLVMRustSetVisibility(ll_g, llvm::Visibility::Hidden); - } + llvm::LLVMRustSetVisibility( + ll_g, + llvm::Visibility::from_generic(tcx.sess.default_visibility()), + ); let llval = llvm::LLVMConstInt(i8, 0, False); llvm::LLVMSetInitializer(ll_g, llval); } @@ -132,9 +134,11 @@ fn create_wrapper_function( None }; - if tcx.sess.default_hidden_visibility() { - llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden); - } + llvm::LLVMRustSetVisibility( + llfn, + llvm::Visibility::from_generic(tcx.sess.default_visibility()), + ); + if tcx.sess.must_emit_unwind_tables() { let uwtable = attributes::uwtable_attr(llcx, tcx.sess.opts.unstable_opts.use_sync_unwind); diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index 7621f111fe25..82ca3f519f74 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -708,6 +708,9 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'_>>) -> S390x(S390xInlineAsmRegClass::reg) => "r", S390x(S390xInlineAsmRegClass::reg_addr) => "a", S390x(S390xInlineAsmRegClass::freg) => "f", + S390x(S390xInlineAsmRegClass::vreg | S390xInlineAsmRegClass::areg) => { + unreachable!("clobber-only") + } Msp430(Msp430InlineAsmRegClass::reg) => "r", M68k(M68kInlineAsmRegClass::reg) => "r", M68k(M68kInlineAsmRegClass::reg_addr) => "a", @@ -866,6 +869,9 @@ fn dummy_output_type<'ll>(cx: &CodegenCx<'ll, '_>, reg: InlineAsmRegClass) -> &' Avr(AvrInlineAsmRegClass::reg_ptr) => cx.type_i16(), S390x(S390xInlineAsmRegClass::reg | S390xInlineAsmRegClass::reg_addr) => cx.type_i32(), S390x(S390xInlineAsmRegClass::freg) => cx.type_f64(), + S390x(S390xInlineAsmRegClass::vreg | S390xInlineAsmRegClass::areg) => { + unreachable!("clobber-only") + } Msp430(Msp430InlineAsmRegClass::reg) => cx.type_i16(), M68k(M68kInlineAsmRegClass::reg) => cx.type_i32(), M68k(M68kInlineAsmRegClass::reg_addr) => cx.type_i32(), diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs index 1b4f6682af02..33a956e552fb 100644 --- a/compiler/rustc_codegen_llvm/src/back/archive.rs +++ b/compiler/rustc_codegen_llvm/src/back/archive.rs @@ -123,7 +123,7 @@ fn get_llvm_object_symbols( llvm::LLVMRustGetSymbols( buf.as_ptr(), buf.len(), - std::ptr::addr_of_mut!(*state) as *mut c_void, + (&raw mut *state) as *mut c_void, callback, error_callback, ) diff --git a/compiler/rustc_codegen_llvm/src/declare.rs b/compiler/rustc_codegen_llvm/src/declare.rs index b0b29ca1280d..7be44dd51b57 100644 --- a/compiler/rustc_codegen_llvm/src/declare.rs +++ b/compiler/rustc_codegen_llvm/src/declare.rs @@ -22,6 +22,7 @@ use tracing::debug; use crate::abi::{FnAbi, FnAbiLlvmExt}; use crate::context::CodegenCx; use crate::llvm::AttributePlace::Function; +use crate::llvm::Visibility; use crate::type_::Type; use crate::value::Value; use crate::{attributes, llvm}; @@ -84,11 +85,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { fn_type: &'ll Type, ) -> &'ll Value { // Declare C ABI functions with the visibility used by C by default. - let visibility = if self.tcx.sess.default_hidden_visibility() { - llvm::Visibility::Hidden - } else { - llvm::Visibility::Default - }; + let visibility = Visibility::from_generic(self.tcx.sess.default_visibility()); declare_raw_fn(self, name, llvm::CCallConv, unnamed, visibility, fn_type) } @@ -107,11 +104,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { unnamed: llvm::UnnamedAddr, fn_type: &'ll Type, ) -> &'ll Value { - let visibility = if self.tcx.sess.default_hidden_visibility() { - llvm::Visibility::Hidden - } else { - llvm::Visibility::Default - }; + let visibility = Visibility::from_generic(self.tcx.sess.default_visibility()); declare_raw_fn(self, name, callconv, unnamed, visibility, fn_type) } diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index bdfc0f626f80..b85d28a2f1f7 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -167,7 +167,7 @@ impl WriteBackendMethods for LlvmCodegenBackend { fn print_pass_timings(&self) { unsafe { let mut size = 0; - let cstr = llvm::LLVMRustPrintPassTimings(std::ptr::addr_of_mut!(size)); + let cstr = llvm::LLVMRustPrintPassTimings(&raw mut size); if cstr.is_null() { println!("failed to get pass timings"); } else { @@ -180,7 +180,7 @@ impl WriteBackendMethods for LlvmCodegenBackend { fn print_statistics(&self) { unsafe { let mut size = 0; - let cstr = llvm::LLVMRustPrintStatistics(std::ptr::addr_of_mut!(size)); + let cstr = llvm::LLVMRustPrintStatistics(&raw mut size); if cstr.is_null() { println!("failed to get pass stats"); } else { diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 9aabfd794bad..d3950df91fbd 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -4,6 +4,7 @@ use std::marker::PhantomData; use libc::{c_char, c_int, c_uint, c_ulonglong, c_void, size_t}; +use rustc_target::spec::SymbolVisibility; use super::RustString; use super::debuginfo::{ @@ -133,6 +134,16 @@ pub enum Visibility { Protected = 2, } +impl Visibility { + pub fn from_generic(visibility: SymbolVisibility) -> Self { + match visibility { + SymbolVisibility::Hidden => Visibility::Hidden, + SymbolVisibility::Protected => Visibility::Protected, + SymbolVisibility::Interposable => Visibility::Default, + } + } +} + /// LLVMUnnamedAddr #[repr(C)] pub enum UnnamedAddr { diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 71fd7afb148c..bd847cd0068e 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -264,6 +264,10 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option { Some(LLVMFeature::new("fast-unaligned-access")) } + // Filter out features that are not supported by the current LLVM version + ("riscv32" | "riscv64", "zaamo") if get_version().0 < 19 => None, + ("riscv32" | "riscv64", "zabha") if get_version().0 < 19 => None, + ("riscv32" | "riscv64", "zalrsc") if get_version().0 < 19 => None, // Enable the evex512 target feature if an avx512 target feature is enabled. ("x86", s) if s.starts_with("avx512") => { Some(LLVMFeature::with_dependency(s, TargetFeatureFoldStrength::EnableOnly("evex512"))) @@ -478,7 +482,7 @@ pub(crate) fn print(req: &PrintRequest, mut out: &mut String, sess: &Session) { &tm, cpu_cstring.as_ptr(), callback, - std::ptr::addr_of_mut!(out) as *mut c_void, + (&raw mut out) as *mut c_void, ); } } @@ -536,6 +540,11 @@ pub(crate) fn global_llvm_features( // -Ctarget-cpu=native match sess.opts.cg.target_cpu { Some(ref s) if s == "native" => { + // We have already figured out the actual CPU name with `LLVMRustGetHostCPUName` and set + // that for LLVM, so the features implied by that CPU name will be available everywhere. + // However, that is not sufficient: e.g. `skylake` alone is not sufficient to tell if + // some of the instructions are available or not. So we have to also explicitly ask for + // the exact set of features available on the host, and enable all of them. let features_string = unsafe { let ptr = llvm::LLVMGetHostCPUFeatures(); let features_string = if !ptr.is_null() { diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml index 3ab4cd0a0f53..58baf40b5812 100644 --- a/compiler/rustc_codegen_ssa/Cargo.toml +++ b/compiler/rustc_codegen_ssa/Cargo.toml @@ -8,7 +8,7 @@ edition = "2021" ar_archive_writer = "0.4.2" arrayvec = { version = "0.7", default-features = false } bitflags = "2.4.1" -cc = "=1.0.105" # FIXME(cc): pinned to keep support for VS2013 +cc = "1.1.23" either = "1.5.0" itertools = "0.12" jobserver = "0.1.28" @@ -34,12 +34,13 @@ rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_symbol_mangling = { path = "../rustc_symbol_mangling" } rustc_target = { path = "../rustc_target" } +rustc_trait_selection = { path = "../rustc_trait_selection" } rustc_type_ir = { path = "../rustc_type_ir" } serde_json = "1.0.59" smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } tempfile = "3.2" thin-vec = "0.2.12" -thorin-dwp = "0.7" +thorin-dwp = "0.8" tracing = "0.1" wasm-encoder = "0.216.0" # tidy-alphabetical-end @@ -55,5 +56,5 @@ default-features = false features = ["read_core", "elf", "macho", "pe", "xcoff", "unaligned", "archive", "write", "wasm"] [target.'cfg(windows)'.dependencies.windows] -version = "0.52.0" +version = "0.57.0" features = ["Win32_Globalization"] diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 69693230ce07..e7b1c63a8225 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -40,7 +40,7 @@ use rustc_target::spec::crt_objects::CrtObjects; use rustc_target::spec::{ Cc, LinkOutputKind, LinkSelfContainedComponents, LinkSelfContainedDefault, LinkerFeatures, LinkerFlavor, LinkerFlavorCli, Lld, PanicStrategy, RelocModel, RelroLevel, SanitizerSet, - SplitDebuginfo, + SplitDebuginfo, current_apple_deployment_target, }; use tempfile::Builder as TempFileBuilder; use tracing::{debug, info, warn}; @@ -2405,6 +2405,8 @@ fn add_order_independent_options( // Take care of the flavors and CLI options requesting the `lld` linker. add_lld_args(cmd, sess, flavor, self_contained_components); + add_apple_link_args(cmd, sess, flavor); + let apple_sdk_root = add_apple_sdk(cmd, sess, flavor); add_link_script(cmd, sess, tmpdir, crate_type); @@ -2488,7 +2490,7 @@ fn add_order_independent_options( } } - cmd.set_output_kind(link_output_kind, out_filename); + cmd.set_output_kind(link_output_kind, crate_type, out_filename); add_relro_args(cmd, sess); @@ -2957,6 +2959,169 @@ pub(crate) fn are_upstream_rust_objects_already_included(sess: &Session) -> bool } } +/// We need to communicate five things to the linker on Apple/Darwin targets: +/// - The architecture. +/// - The operating system (and that it's an Apple platform). +/// - The environment / ABI. +/// - The deployment target. +/// - The SDK version. +fn add_apple_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) { + if !sess.target.is_like_osx { + return; + } + let LinkerFlavor::Darwin(cc, _) = flavor else { + return; + }; + + // `sess.target.arch` (`target_arch`) is not detailed enough. + let llvm_arch = sess.target.llvm_target.split_once('-').expect("LLVM target must have arch").0; + let target_os = &*sess.target.os; + let target_abi = &*sess.target.abi; + + // The architecture name to forward to the linker. + // + // Supported architecture names can be found in the source: + // https://github.com/apple-oss-distributions/ld64/blob/ld64-951.9/src/abstraction/MachOFileAbstraction.hpp#L578-L648 + // + // Intentially verbose to ensure that the list always matches correctly + // with the list in the source above. + let ld64_arch = match llvm_arch { + "armv7k" => "armv7k", + "armv7s" => "armv7s", + "arm64" => "arm64", + "arm64e" => "arm64e", + "arm64_32" => "arm64_32", + // ld64 doesn't understand i686, so fall back to i386 instead. + // + // Same story when linking with cc, since that ends up invoking ld64. + "i386" | "i686" => "i386", + "x86_64" => "x86_64", + "x86_64h" => "x86_64h", + _ => bug!("unsupported architecture in Apple target: {}", sess.target.llvm_target), + }; + + if cc == Cc::No { + // From the man page for ld64 (`man ld`): + // > The linker accepts universal (multiple-architecture) input files, + // > but always creates a "thin" (single-architecture), standard + // > Mach-O output file. The architecture for the output file is + // > specified using the -arch option. + // + // The linker has heuristics to determine the desired architecture, + // but to be safe, and to avoid a warning, we set the architecture + // explicitly. + cmd.link_args(&["-arch", ld64_arch]); + + // Man page says that ld64 supports the following platform names: + // > - macos + // > - ios + // > - tvos + // > - watchos + // > - bridgeos + // > - visionos + // > - xros + // > - mac-catalyst + // > - ios-simulator + // > - tvos-simulator + // > - watchos-simulator + // > - visionos-simulator + // > - xros-simulator + // > - driverkit + let platform_name = match (target_os, target_abi) { + (os, "") => os, + ("ios", "macabi") => "mac-catalyst", + ("ios", "sim") => "ios-simulator", + ("tvos", "sim") => "tvos-simulator", + ("watchos", "sim") => "watchos-simulator", + ("visionos", "sim") => "visionos-simulator", + _ => bug!("invalid OS/ABI combination for Apple target: {target_os}, {target_abi}"), + }; + + let (major, minor, patch) = current_apple_deployment_target(&sess.target); + let min_version = format!("{major}.{minor}.{patch}"); + + // The SDK version is used at runtime when compiling with a newer SDK / version of Xcode: + // - By dyld to give extra warnings and errors, see e.g.: + // + // + // - By system frameworks to change certain behaviour. For example, the default value of + // `-[NSView wantsBestResolutionOpenGLSurface]` is `YES` when the SDK version is >= 10.15. + // + // + // We do not currently know the actual SDK version though, so we have a few options: + // 1. Use the minimum version supported by rustc. + // 2. Use the same as the deployment target. + // 3. Use an arbitary recent version. + // 4. Omit the version. + // + // The first option is too low / too conservative, and means that users will not get the + // same behaviour from a binary compiled with rustc as with one compiled by clang. + // + // The second option is similarly conservative, and also wrong since if the user specified a + // higher deployment target than the SDK they're compiling/linking with, the runtime might + // make invalid assumptions about the capabilities of the binary. + // + // The third option requires that `rustc` is periodically kept up to date with Apple's SDK + // version, and is also wrong for similar reasons as above. + // + // The fourth option is bad because while `ld`, `otool`, `vtool` and such understand it to + // mean "absent" or `n/a`, dyld doesn't actually understand it, and will end up interpreting + // it as 0.0, which is again too low/conservative. + // + // Currently, we lie about the SDK version, and choose the second option. + // + // FIXME(madsmtm): Parse the SDK version from the SDK root instead. + // + let sdk_version = &*min_version; + + // From the man page for ld64 (`man ld`): + // > This is set to indicate the platform, oldest supported version of + // > that platform that output is to be used on, and the SDK that the + // > output was built against. + // + // Like with `-arch`, the linker can figure out the platform versions + // itself from the binaries being linked, but to be safe, we specify + // the desired versions here explicitly. + cmd.link_args(&["-platform_version", platform_name, &*min_version, sdk_version]); + } else { + // cc == Cc::Yes + // + // We'd _like_ to use `-target` everywhere, since that can uniquely + // communicate all the required details except for the SDK version + // (which is read by Clang itself from the SDKROOT), but that doesn't + // work on GCC, and since we don't know whether the `cc` compiler is + // Clang, GCC, or something else, we fall back to other options that + // also work on GCC when compiling for macOS. + // + // Targets other than macOS are ill-supported by GCC (it doesn't even + // support e.g. `-miphoneos-version-min`), so in those cases we can + // fairly safely use `-target`. See also the following, where it is + // made explicit that the recommendation by LLVM developers is to use + // `-target`: + if target_os == "macos" { + // `-arch` communicates the architecture. + // + // CC forwards the `-arch` to the linker, so we use the same value + // here intentionally. + cmd.cc_args(&["-arch", ld64_arch]); + + // The presence of `-mmacosx-version-min` makes CC default to + // macOS, and it sets the deployment target. + let (major, minor, patch) = current_apple_deployment_target(&sess.target); + // Intentionally pass this as a single argument, Clang doesn't + // seem to like it otherwise. + cmd.cc_arg(&format!("-mmacosx-version-min={major}.{minor}.{patch}")); + + // macOS has no environment, so with these two, we've told CC the + // four desired parameters. + // + // We avoid `-m32`/`-m64`, as this is already encoded by `-arch`. + } else { + cmd.cc_args(&["-target", &sess.target.llvm_target]); + } + } +} + fn add_apple_sdk(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) -> Option { let arch = &sess.target.arch; let os = &sess.target.os; diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index a73ec83ee62c..3f3d305da014 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -275,7 +275,12 @@ pub(crate) trait Linker { fn is_cc(&self) -> bool { false } - fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path); + fn set_output_kind( + &mut self, + output_kind: LinkOutputKind, + crate_type: CrateType, + out_filename: &Path, + ); fn link_dylib_by_name(&mut self, _name: &str, _verbatim: bool, _as_needed: bool) { bug!("dylib linked with unsupported linker") } @@ -396,7 +401,7 @@ impl<'a> GccLinker<'a> { ]); } - fn build_dylib(&mut self, out_filename: &Path) { + fn build_dylib(&mut self, crate_type: CrateType, out_filename: &Path) { // On mac we need to tell the linker to let this library be rpathed if self.sess.target.is_like_osx { if !self.is_ld { @@ -427,7 +432,7 @@ impl<'a> GccLinker<'a> { let mut out_implib = OsString::from("--out-implib="); out_implib.push(out_filename.with_file_name(implib_name)); self.link_arg(out_implib); - } else { + } else if crate_type == CrateType::Dylib { // When dylibs are linked by a full path this value will get into `DT_NEEDED` // instead of the full path, so the library can be later found in some other // location than that specific path. @@ -474,7 +479,12 @@ impl<'a> Linker for GccLinker<'a> { !self.is_ld } - fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path) { + fn set_output_kind( + &mut self, + output_kind: LinkOutputKind, + crate_type: CrateType, + out_filename: &Path, + ) { match output_kind { LinkOutputKind::DynamicNoPicExe => { if !self.is_ld && self.is_gnu { @@ -509,10 +519,10 @@ impl<'a> Linker for GccLinker<'a> { self.link_args(&["-static", "-pie", "--no-dynamic-linker", "-z", "text"]); } } - LinkOutputKind::DynamicDylib => self.build_dylib(out_filename), + LinkOutputKind::DynamicDylib => self.build_dylib(crate_type, out_filename), LinkOutputKind::StaticDylib => { self.link_or_cc_arg("-static"); - self.build_dylib(out_filename); + self.build_dylib(crate_type, out_filename); } LinkOutputKind::WasiReactorExe => { self.link_args(&["--entry", "_initialize"]); @@ -866,7 +876,12 @@ impl<'a> Linker for MsvcLinker<'a> { &mut self.cmd } - fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path) { + fn set_output_kind( + &mut self, + output_kind: LinkOutputKind, + _crate_type: CrateType, + out_filename: &Path, + ) { match output_kind { LinkOutputKind::DynamicNoPicExe | LinkOutputKind::DynamicPicExe @@ -1124,7 +1139,13 @@ impl<'a> Linker for EmLinker<'a> { true } - fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {} + fn set_output_kind( + &mut self, + _output_kind: LinkOutputKind, + _crate_type: CrateType, + _out_filename: &Path, + ) { + } fn link_dylib_by_name(&mut self, name: &str, _verbatim: bool, _as_needed: bool) { // Emscripten always links statically @@ -1273,7 +1294,12 @@ impl<'a> Linker for WasmLd<'a> { &mut self.cmd } - fn set_output_kind(&mut self, output_kind: LinkOutputKind, _out_filename: &Path) { + fn set_output_kind( + &mut self, + output_kind: LinkOutputKind, + _crate_type: CrateType, + _out_filename: &Path, + ) { match output_kind { LinkOutputKind::DynamicNoPicExe | LinkOutputKind::DynamicPicExe @@ -1422,7 +1448,13 @@ impl<'a> Linker for L4Bender<'a> { &mut self.cmd } - fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {} + fn set_output_kind( + &mut self, + _output_kind: LinkOutputKind, + _crate_type: CrateType, + _out_filename: &Path, + ) { + } fn link_staticlib_by_name(&mut self, name: &str, _verbatim: bool, whole_archive: bool) { self.hint_static(); @@ -1568,7 +1600,12 @@ impl<'a> Linker for AixLinker<'a> { &mut self.cmd } - fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path) { + fn set_output_kind( + &mut self, + output_kind: LinkOutputKind, + _crate_type: CrateType, + out_filename: &Path, + ) { match output_kind { LinkOutputKind::DynamicDylib => { self.hint_dynamic(); @@ -1775,7 +1812,13 @@ impl<'a> Linker for PtxLinker<'a> { &mut self.cmd } - fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {} + fn set_output_kind( + &mut self, + _output_kind: LinkOutputKind, + _crate_type: CrateType, + _out_filename: &Path, + ) { + } fn link_staticlib_by_name(&mut self, _name: &str, _verbatim: bool, _whole_archive: bool) { panic!("staticlibs not supported") @@ -1841,7 +1884,13 @@ impl<'a> Linker for LlbcLinker<'a> { &mut self.cmd } - fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {} + fn set_output_kind( + &mut self, + _output_kind: LinkOutputKind, + _crate_type: CrateType, + _out_filename: &Path, + ) { + } fn link_staticlib_by_name(&mut self, _name: &str, _verbatim: bool, _whole_archive: bool) { panic!("staticlibs not supported") @@ -1912,7 +1961,13 @@ impl<'a> Linker for BpfLinker<'a> { &mut self.cmd } - fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {} + fn set_output_kind( + &mut self, + _output_kind: LinkOutputKind, + _crate_type: CrateType, + _out_filename: &Path, + ) { + } fn link_staticlib_by_name(&mut self, _name: &str, _verbatim: bool, _whole_archive: bool) { panic!("staticlibs not supported") diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs index 06433484ea3c..8857fda1e972 100644 --- a/compiler/rustc_codegen_ssa/src/back/metadata.rs +++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs @@ -402,13 +402,17 @@ fn macho_object_build_version_for_target(target: &Target) -> object::write::Mach let platform = rustc_target::spec::current_apple_platform(target).expect("unknown Apple target OS"); let min_os = rustc_target::spec::current_apple_deployment_target(target); - let (sdk_major, sdk_minor) = - rustc_target::spec::current_apple_sdk_version(platform).expect("unknown Apple target OS"); let mut build_version = object::write::MachOBuildVersion::default(); build_version.platform = platform; build_version.minos = pack_version(min_os); - build_version.sdk = pack_version((sdk_major, sdk_minor, 0)); + // The version here does not _really_ matter, since it is only used at runtime, and we specify + // it when linking the final binary, so we will omit the version. This is also what LLVM does, + // and the tooling also allows this (and shows the SDK version as `n/a`). Finally, it is the + // semantically correct choice, as the SDK has not influenced the binary generated by rustc at + // this point in time. + build_version.sdk = 0; + build_version } diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 5c67600e4eec..d91c0f0790d9 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -27,6 +27,9 @@ use rustc_session::config::{self, CrateType, EntryFnType, OptLevel, OutputType}; use rustc_span::symbol::sym; use rustc_span::{DUMMY_SP, Symbol}; use rustc_target::abi::FIRST_VARIANT; +use rustc_trait_selection::infer::at::ToTrace; +use rustc_trait_selection::infer::{BoundRegionConversionTime, TyCtxtInferExt}; +use rustc_trait_selection::traits::{ObligationCause, ObligationCtxt}; use tracing::{debug, info}; use crate::assert_module_sources::CguReuse; @@ -101,6 +104,54 @@ pub fn compare_simd_types<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( bx.sext(cmp, ret_ty) } +/// Codegen takes advantage of the additional assumption, where if the +/// principal trait def id of what's being casted doesn't change, +/// then we don't need to adjust the vtable at all. This +/// corresponds to the fact that `dyn Tr: Unsize>` +/// requires that `A = B`; we don't allow *upcasting* objects +/// between the same trait with different args. If we, for +/// some reason, were to relax the `Unsize` trait, it could become +/// unsound, so let's validate here that the trait refs are subtypes. +pub fn validate_trivial_unsize<'tcx>( + tcx: TyCtxt<'tcx>, + source_data: &'tcx ty::List>, + target_data: &'tcx ty::List>, +) -> bool { + match (source_data.principal(), target_data.principal()) { + (Some(hr_source_principal), Some(hr_target_principal)) => { + let infcx = tcx.infer_ctxt().build(); + let universe = infcx.universe(); + let ocx = ObligationCtxt::new(&infcx); + infcx.enter_forall(hr_target_principal, |target_principal| { + let source_principal = infcx.instantiate_binder_with_fresh_vars( + DUMMY_SP, + BoundRegionConversionTime::HigherRankedType, + hr_source_principal, + ); + let Ok(()) = ocx.eq_trace( + &ObligationCause::dummy(), + ty::ParamEnv::reveal_all(), + ToTrace::to_trace( + &ObligationCause::dummy(), + hr_target_principal, + hr_source_principal, + ), + target_principal, + source_principal, + ) else { + return false; + }; + if !ocx.select_all_or_error().is_empty() { + return false; + } + infcx.leak_check(universe, None).is_ok() + }) + } + (None, None) => true, + _ => false, + } +} + /// Retrieves the information we are losing (making dynamic) in an unsizing /// adjustment. /// @@ -133,12 +184,8 @@ fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // between the same trait with different args. If we, for // some reason, were to relax the `Unsize` trait, it could become // unsound, so let's assert here that the trait refs are *equal*. - // - // We can use `assert_eq` because the binders should have been anonymized, - // and because higher-ranked equality now requires the binders are equal. - debug_assert_eq!( - data_a.principal(), - data_b.principal(), + debug_assert!( + validate_trivial_unsize(cx.tcx(), data_a, data_b), "NOP unsize vtable changed principal trait ref: {data_a} -> {data_b}" ); diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs index e1b605979972..2cbf242fcf28 100644 --- a/compiler/rustc_const_eval/src/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/check_consts/check.rs @@ -317,7 +317,6 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> { { self.error_emitted = Some(guar); } - self.check_op_spanned(ops::StaticAccess, span) } /// Returns whether this place can possibly escape the evaluation of the current const/static diff --git a/compiler/rustc_const_eval/src/check_consts/ops.rs b/compiler/rustc_const_eval/src/check_consts/ops.rs index df8313d0e703..6eb33c29e1d8 100644 --- a/compiler/rustc_const_eval/src/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/check_consts/ops.rs @@ -16,7 +16,6 @@ use rustc_middle::ty::{ suggest_constraining_type_param, }; use rustc_middle::util::{CallDesugaringKind, CallKind, call_kind}; -use rustc_session::parse::feature_err; use rustc_span::symbol::sym; use rustc_span::{BytePos, Pos, Span, Symbol}; use rustc_trait_selection::traits::SelectionContext; @@ -477,33 +476,6 @@ impl<'tcx> NonConstOp<'tcx> for RawPtrToIntCast { } } -/// An access to a (non-thread-local) `static`. -#[derive(Debug)] -pub(crate) struct StaticAccess; -impl<'tcx> NonConstOp<'tcx> for StaticAccess { - fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status { - if let hir::ConstContext::Static(_) = ccx.const_kind() { - Status::Allowed - } else { - Status::Unstable(sym::const_refs_to_static) - } - } - - #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> Diag<'tcx> { - let mut err = feature_err( - &ccx.tcx.sess, - sym::const_refs_to_static, - span, - format!("referencing statics in {}s is unstable", ccx.const_kind(),), - ); - err - .note("`static` and `const` variables can refer to other `const` variables. A `const` variable, however, cannot refer to a `static` variable.") - .help("to fix this, the value can be extracted to a `const` and then used."); - err - } -} - /// An access to a thread-local `static`. #[derive(Debug)] pub(crate) struct ThreadLocalAccess; diff --git a/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs b/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs index ed1c912e6cb0..743924faa21d 100644 --- a/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs @@ -6,7 +6,8 @@ use rustc_middle::{bug, span_bug, ty}; use rustc_span::def_id::DefId; use crate::interpret::{ - self, HasStaticRootDefId, ImmTy, Immediate, InterpCx, PointerArithmetic, throw_machine_stop, + self, HasStaticRootDefId, ImmTy, Immediate, InterpCx, PointerArithmetic, interp_ok, + throw_machine_stop, }; /// Macro for machine-specific `InterpError` without allocation. @@ -79,7 +80,7 @@ impl<'tcx> interpret::Machine<'tcx> for DummyMachine { throw_machine_stop_str!("can't access mutable globals in ConstProp"); } - Ok(()) + interp_ok(()) } fn find_mir_or_eval_fn( @@ -127,7 +128,7 @@ impl<'tcx> interpret::Machine<'tcx> for DummyMachine { right: &interpret::ImmTy<'tcx, Self::Provenance>, ) -> interpret::InterpResult<'tcx, ImmTy<'tcx, Self::Provenance>> { use rustc_middle::mir::BinOp::*; - Ok(match bin_op { + interp_ok(match bin_op { Eq | Ne | Lt | Le | Gt | Ge => { // Types can differ, e.g. fn ptrs with different `for`. assert_eq!(left.layout.abi, right.layout.abi); diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index a241edbd77ad..672353e629d4 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -20,7 +20,7 @@ use crate::const_eval::CheckAlignment; use crate::interpret::{ CtfeValidationMode, GlobalId, Immediate, InternKind, InternResult, InterpCx, InterpError, InterpResult, MPlaceTy, MemoryKind, OpTy, RefTracking, StackPopCleanup, create_static_alloc, - eval_nullary_intrinsic, intern_const_alloc_recursive, throw_exhaust, + eval_nullary_intrinsic, intern_const_alloc_recursive, interp_ok, throw_exhaust, }; use crate::{CTRL_C_RECEIVED, errors}; @@ -98,19 +98,19 @@ fn eval_body_using_ecx<'tcx, R: InterpretationResult<'tcx>>( return Err(ecx .tcx .dcx() - .emit_err(errors::DanglingPtrInFinal { span: ecx.tcx.span, kind: intern_kind }) - .into()); + .emit_err(errors::DanglingPtrInFinal { span: ecx.tcx.span, kind: intern_kind })) + .into(); } Err(InternResult::FoundBadMutablePointer) => { return Err(ecx .tcx .dcx() - .emit_err(errors::MutablePtrInFinal { span: ecx.tcx.span, kind: intern_kind }) - .into()); + .emit_err(errors::MutablePtrInFinal { span: ecx.tcx.span, kind: intern_kind })) + .into(); } } - Ok(R::make_result(ret, ecx)) + interp_ok(R::make_result(ret, ecx)) } /// The `InterpCx` is only meant to be used to do field and index projections into constants for @@ -147,7 +147,8 @@ pub fn mk_eval_cx_for_const_val<'tcx>( ty: Ty<'tcx>, ) -> Option<(CompileTimeInterpCx<'tcx>, OpTy<'tcx>)> { let ecx = mk_eval_cx_to_read_const_val(tcx.tcx, tcx.span, param_env, CanAccessMutGlobal::No); - let op = ecx.const_val_to_op(val, ty, None).ok()?; + // FIXME: is it a problem to discard the error here? + let op = ecx.const_val_to_op(val, ty, None).discard_err()?; Some((ecx, op)) } @@ -185,12 +186,16 @@ pub(super) fn op_to_const<'tcx>( _ => false, }; let immediate = if force_as_immediate { - match ecx.read_immediate(op) { + match ecx.read_immediate(op).report_err() { Ok(imm) => Right(imm), - Err(err) if !for_diagnostics => { - panic!("normalization works on validated constants: {err:?}") + Err(err) => { + if for_diagnostics { + // This discard the error, but for diagnostics that's okay. + op.as_mplace_or_imm() + } else { + panic!("normalization works on validated constants: {err:?}") + } } - _ => op.as_mplace_or_imm(), } } else { op.as_mplace_or_imm() @@ -283,17 +288,19 @@ pub fn eval_to_const_value_raw_provider<'tcx>( let ty::FnDef(_, args) = ty.kind() else { bug!("intrinsic with type {:?}", ty); }; - return eval_nullary_intrinsic(tcx, key.param_env, def_id, args).map_err(|error| { - let span = tcx.def_span(def_id); + return eval_nullary_intrinsic(tcx, key.param_env, def_id, args).report_err().map_err( + |error| { + let span = tcx.def_span(def_id); - super::report( - tcx, - error.into_kind(), - span, - || (span, vec![]), - |span, _| errors::NullaryIntrinsicError { span }, - ) - }); + super::report( + tcx, + error.into_kind(), + span, + || (span, vec![]), + |span, _| errors::NullaryIntrinsicError { span }, + ) + }, + ); } tcx.eval_to_allocation_raw(key).map(|val| turn_into_const_value(tcx, val, key)) @@ -376,6 +383,7 @@ fn eval_in_interpreter<'tcx, R: InterpretationResult<'tcx>>( ); let res = ecx.load_mir(cid.instance.def, cid.promoted); res.and_then(|body| eval_body_using_ecx(&mut ecx, cid, body)) + .report_err() .map_err(|error| report_eval_error(&ecx, cid, error)) } @@ -400,6 +408,7 @@ fn const_validate_mplace<'tcx>( } }; ecx.const_validate_operand(&mplace.into(), path, &mut ref_tracking, mode) + .report_err() // Instead of just reporting the `InterpError` via the usual machinery, we give a more targeted // error about the validation failure. .map_err(|error| report_validation_error(&ecx, cid, error, alloc_id))?; diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 6d74998b7d88..4aec74595bc8 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -24,8 +24,8 @@ use crate::fluent_generated as fluent; use crate::interpret::{ self, AllocId, AllocRange, ConstAllocation, CtfeProvenance, FnArg, Frame, GlobalAlloc, ImmTy, InterpCx, InterpResult, MPlaceTy, OpTy, Pointer, PointerArithmetic, RangeSet, Scalar, - StackPopCleanup, compile_time_machine, err_ub, throw_exhaust, throw_inval, throw_ub_custom, - throw_unsup, throw_unsup_format, + StackPopCleanup, compile_time_machine, interp_ok, throw_exhaust, throw_inval, throw_ub, + throw_ub_custom, throw_unsup, throw_unsup_format, }; /// When hitting this many interpreted terminators we emit a deny by default lint @@ -247,7 +247,7 @@ impl<'tcx> CompileTimeInterpCx<'tcx> { let msg = Symbol::intern(self.read_str(&msg_place)?); let span = self.find_closest_untracked_caller_location(); let (file, line, col) = self.location_triple_for_span(span); - return Err(ConstEvalErrKind::Panic { msg, file, line, col }.into()); + return Err(ConstEvalErrKind::Panic { msg, file, line, col }).into(); } else if self.tcx.is_lang_item(def_id, LangItem::PanicFmt) { // For panic_fmt, call const_panic_fmt instead. let const_def_id = self.tcx.require_lang_item(LangItem::ConstPanicFmt, None); @@ -259,16 +259,16 @@ impl<'tcx> CompileTimeInterpCx<'tcx> { self.cur_span(), ); - return Ok(Some(new_instance)); + return interp_ok(Some(new_instance)); } else if self.tcx.is_lang_item(def_id, LangItem::AlignOffset) { let args = self.copy_fn_args(args); // For align_offset, we replace the function call if the pointer has no address. match self.align_offset(instance, &args, dest, ret)? { - ControlFlow::Continue(()) => return Ok(Some(instance)), - ControlFlow::Break(()) => return Ok(None), + ControlFlow::Continue(()) => return interp_ok(Some(instance)), + ControlFlow::Break(()) => return interp_ok(None), } } - Ok(Some(instance)) + interp_ok(Some(instance)) } /// `align_offset(ptr, target_align)` needs special handling in const eval, because the pointer @@ -323,25 +323,25 @@ impl<'tcx> CompileTimeInterpCx<'tcx> { dest, StackPopCleanup::Goto { ret, unwind: mir::UnwindAction::Unreachable }, )?; - Ok(ControlFlow::Break(())) + interp_ok(ControlFlow::Break(())) } else { // Not alignable in const, return `usize::MAX`. let usize_max = Scalar::from_target_usize(self.target_usize_max(), self); self.write_scalar(usize_max, dest)?; self.return_to_block(ret)?; - Ok(ControlFlow::Break(())) + interp_ok(ControlFlow::Break(())) } } Err(_addr) => { // The pointer has an address, continue with function call. - Ok(ControlFlow::Continue(())) + interp_ok(ControlFlow::Continue(())) } } } /// See documentation on the `ptr_guaranteed_cmp` intrinsic. fn guaranteed_cmp(&mut self, a: Scalar, b: Scalar) -> InterpResult<'tcx, u8> { - Ok(match (a, b) { + interp_ok(match (a, b) { // Comparisons between integers are always known. (Scalar::Int { .. }, Scalar::Int { .. }) => { if a == b { @@ -403,8 +403,8 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { instance: ty::InstanceKind<'tcx>, ) -> InterpResult<'tcx, &'tcx mir::Body<'tcx>> { match instance { - ty::InstanceKind::Item(def) => Ok(ecx.tcx.mir_for_ctfe(def)), - _ => Ok(ecx.tcx.instance_mir(instance)), + ty::InstanceKind::Item(def) => interp_ok(ecx.tcx.mir_for_ctfe(def)), + _ => interp_ok(ecx.tcx.instance_mir(instance)), } } @@ -422,7 +422,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { // Replace some functions. let Some(instance) = ecx.hook_special_const_fn(orig_instance, args, dest, ret)? else { // Call has already been handled. - return Ok(None); + return interp_ok(None); }; // Only check non-glue functions @@ -444,14 +444,14 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { // This is a const fn. Call it. // In case of replacement, we return the *original* instance to make backtraces work out // (and we hope this does not confuse the FnAbi checks too much). - Ok(Some((ecx.load_mir(instance.def, None)?, orig_instance))) + interp_ok(Some((ecx.load_mir(instance.def, None)?, orig_instance))) } fn panic_nounwind(ecx: &mut InterpCx<'tcx, Self>, msg: &str) -> InterpResult<'tcx> { let msg = Symbol::intern(msg); let span = ecx.find_closest_untracked_caller_location(); let (file, line, col) = ecx.location_triple_for_span(span); - Err(ConstEvalErrKind::Panic { msg, file, line, col }.into()) + Err(ConstEvalErrKind::Panic { msg, file, line, col }).into() } fn call_intrinsic( @@ -464,7 +464,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { ) -> InterpResult<'tcx, Option>> { // Shared intrinsics. if ecx.eval_intrinsic(instance, args, dest, target)? { - return Ok(None); + return interp_ok(None); } let intrinsic_name = ecx.tcx.item_name(instance.def_id()); @@ -541,7 +541,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { "intrinsic `{intrinsic_name}` is not supported at compile-time" ); } - return Ok(Some(ty::Instance { + return interp_ok(Some(ty::Instance { def: ty::InstanceKind::Item(instance.def_id()), args: instance.args, })); @@ -550,7 +550,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { // Intrinsic is done, jump to next block. ecx.return_to_block(target)?; - Ok(None) + interp_ok(None) } fn assert_panic( @@ -581,7 +581,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { } } }; - Err(ConstEvalErrKind::AssertFailure(err).into()) + Err(ConstEvalErrKind::AssertFailure(err)).into() } fn binary_ptr_op( @@ -652,7 +652,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { } } - Ok(()) + interp_ok(()) } #[inline(always)] @@ -670,7 +670,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { if !ecx.recursion_limit.value_within_limit(ecx.stack().len() + 1) { throw_exhaust!(StackFrameLimitReached) } else { - Ok(frame) + interp_ok(frame) } } @@ -700,22 +700,22 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { if is_write { // Write access. These are never allowed, but we give a targeted error message. match alloc.mutability { - Mutability::Not => Err(err_ub!(WriteToReadOnly(alloc_id)).into()), - Mutability::Mut => Err(ConstEvalErrKind::ModifiedGlobal.into()), + Mutability::Not => throw_ub!(WriteToReadOnly(alloc_id)), + Mutability::Mut => Err(ConstEvalErrKind::ModifiedGlobal).into(), } } else { // Read access. These are usually allowed, with some exceptions. if machine.can_access_mut_global == CanAccessMutGlobal::Yes { // Machine configuration allows us read from anything (e.g., `static` initializer). - Ok(()) + interp_ok(()) } else if alloc.mutability == Mutability::Mut { // Machine configuration does not allow us to read statics (e.g., `const` // initializer). - Err(ConstEvalErrKind::ConstAccessesMutGlobal.into()) + Err(ConstEvalErrKind::ConstAccessesMutGlobal).into() } else { // Immutable global, this read is fine. assert_eq!(alloc.mutability, Mutability::Not); - Ok(()) + interp_ok(()) } } } @@ -748,9 +748,9 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { // even when there is interior mutability.) place.map_provenance(CtfeProvenance::as_shared_ref) }; - Ok(ImmTy::from_immediate(new_place.to_ref(ecx), val.layout)) + interp_ok(ImmTy::from_immediate(new_place.to_ref(ecx), val.layout)) } else { - Ok(val.clone()) + interp_ok(val.clone()) } } @@ -763,20 +763,20 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { ) -> InterpResult<'tcx> { if range.size == Size::ZERO { // Nothing to check. - return Ok(()); + return interp_ok(()); } // Reject writes through immutable pointers. if immutable { - return Err(ConstEvalErrKind::WriteThroughImmutablePointer.into()); + return Err(ConstEvalErrKind::WriteThroughImmutablePointer).into(); } // Everything else is fine. - Ok(()) + interp_ok(()) } fn before_alloc_read(ecx: &InterpCx<'tcx, Self>, alloc_id: AllocId) -> InterpResult<'tcx> { // Check if this is the currently evaluated static. if Some(alloc_id) == ecx.machine.static_root_ids.map(|(id, _)| id) { - return Err(ConstEvalErrKind::RecursiveStatic.into()); + return Err(ConstEvalErrKind::RecursiveStatic).into(); } // If this is another static, make sure we fire off the query to detect cycles. // But only do that when checks for static recursion are enabled. @@ -788,7 +788,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { ecx.ctfe_query(|tcx| tcx.eval_static_initializer(def_id))?; } } - Ok(()) + interp_ok(()) } fn cached_union_data_range<'e>( diff --git a/compiler/rustc_const_eval/src/const_eval/mod.rs b/compiler/rustc_const_eval/src/const_eval/mod.rs index 48aeee2e6f05..ba19f642795a 100644 --- a/compiler/rustc_const_eval/src/const_eval/mod.rs +++ b/compiler/rustc_const_eval/src/const_eval/mod.rs @@ -1,13 +1,12 @@ // Not in interpret to make sure we do not use private implementation details -use rustc_middle::mir::interpret::InterpErrorInfo; use rustc_middle::query::{Key, TyCtxtAt}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::{bug, mir}; use rustc_target::abi::VariantIdx; use tracing::instrument; -use crate::interpret::{InterpCx, format_interp_error}; +use crate::interpret::InterpCx; mod dummy_machine; mod error; @@ -33,17 +32,6 @@ pub(crate) enum ValTreeCreationError<'tcx> { } pub(crate) type ValTreeCreationResult<'tcx> = Result, ValTreeCreationError<'tcx>>; -impl<'tcx> From> for ValTreeCreationError<'tcx> { - fn from(err: InterpErrorInfo<'tcx>) -> Self { - ty::tls::with(|tcx| { - bug!( - "Unexpected Undefined Behavior error during valtree construction: {}", - format_interp_error(tcx.dcx(), err), - ) - }) - } -} - #[instrument(skip(tcx), level = "debug")] pub(crate) fn try_destructure_mir_constant_for_user_output<'tcx>( tcx: TyCtxtAt<'tcx>, @@ -60,8 +48,8 @@ pub(crate) fn try_destructure_mir_constant_for_user_output<'tcx>( return None; } ty::Adt(def, _) => { - let variant = ecx.read_discriminant(&op).ok()?; - let down = ecx.project_downcast(&op, variant).ok()?; + let variant = ecx.read_discriminant(&op).discard_err()?; + let down = ecx.project_downcast(&op, variant).discard_err()?; (def.variants()[variant].fields.len(), Some(variant), down) } ty::Tuple(args) => (args.len(), None, op), @@ -70,7 +58,7 @@ pub(crate) fn try_destructure_mir_constant_for_user_output<'tcx>( let fields_iter = (0..field_count) .map(|i| { - let field_op = ecx.project_field(&down, i).ok()?; + let field_op = ecx.project_field(&down, i).discard_err()?; let val = op_to_const(&ecx, &field_op, /* for diagnostics */ true); Some((val, field_op.layout.ty)) }) diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs index a11d491bdd2c..9e80e666ba91 100644 --- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs +++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs @@ -92,7 +92,7 @@ fn const_to_valtree_inner<'tcx>( Ok(ty::ValTree::zst()) } ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char => { - let val = ecx.read_immediate(place)?; + let val = ecx.read_immediate(place).unwrap(); let val = val.to_scalar_int().unwrap(); *num_nodes += 1; @@ -114,7 +114,7 @@ fn const_to_valtree_inner<'tcx>( // equality at compile-time (see `ptr_guaranteed_cmp`). // However we allow those that are just integers in disguise. // First, get the pointer. Remember it might be wide! - let val = ecx.read_immediate(place)?; + let val = ecx.read_immediate(place).unwrap(); // We could allow wide raw pointers where both sides are integers in the future, // but for now we reject them. if matches!(val.layout.abi, Abi::ScalarPair(..)) { @@ -135,7 +135,7 @@ fn const_to_valtree_inner<'tcx>( ty::FnPtr(..) => Err(ValTreeCreationError::NonSupportedType(ty)), ty::Ref(_, _, _) => { - let derefd_place = ecx.deref_pointer(place)?; + let derefd_place = ecx.deref_pointer(place).unwrap(); const_to_valtree_inner(ecx, &derefd_place, num_nodes) } @@ -159,7 +159,7 @@ fn const_to_valtree_inner<'tcx>( bug!("uninhabited types should have errored and never gotten converted to valtree") } - let variant = ecx.read_discriminant(place)?; + let variant = ecx.read_discriminant(place).unwrap(); branches(ecx, place, def.variant(variant).fields.len(), def.is_enum().then_some(variant), num_nodes) } diff --git a/compiler/rustc_const_eval/src/interpret/call.rs b/compiler/rustc_const_eval/src/interpret/call.rs index f5a0a2c0ee36..4945563f4a4e 100644 --- a/compiler/rustc_const_eval/src/interpret/call.rs +++ b/compiler/rustc_const_eval/src/interpret/call.rs @@ -15,8 +15,8 @@ use tracing::{info, instrument, trace}; use super::{ CtfeProvenance, FnVal, ImmTy, InterpCx, InterpResult, MPlaceTy, Machine, OpTy, PlaceTy, - Projectable, Provenance, ReturnAction, Scalar, StackPopCleanup, StackPopInfo, throw_ub, - throw_ub_custom, throw_unsup_format, + Projectable, Provenance, ReturnAction, Scalar, StackPopCleanup, StackPopInfo, interp_ok, + throw_ub, throw_ub_custom, throw_unsup_format, }; use crate::fluent_generated as fluent; @@ -64,7 +64,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { arg: &FnArg<'tcx, M::Provenance>, field: usize, ) -> InterpResult<'tcx, FnArg<'tcx, M::Provenance>> { - Ok(match arg { + interp_ok(match arg { FnArg::Copy(op) => FnArg::Copy(self.project_field(op, field)?), FnArg::InPlace(mplace) => FnArg::InPlace(self.project_field(mplace, field)?), }) @@ -97,7 +97,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // another type. let ty::Adt(def, args) = layout.ty.kind() else { // Not an ADT, so definitely no NPO. - return Ok(layout); + return interp_ok(layout); }; let inner = if self.tcx.is_diagnostic_item(sym::Option, def.did()) { // The wrapped type is the only arg. @@ -111,10 +111,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } else if rhs.is_1zst() { lhs } else { - return Ok(layout); // no NPO + return interp_ok(layout); // no NPO } } else { - return Ok(layout); // no NPO + return interp_ok(layout); // no NPO }; // Check if the inner type is one of the NPO-guaranteed ones. @@ -126,7 +126,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // Stop at NPO types so that we don't miss that attribute in the check below! def.is_struct() && !is_npo(def) }); - Ok(match inner.ty.kind() { + interp_ok(match inner.ty.kind() { ty::Ref(..) | ty::FnPtr(..) => { // Option<&T> behaves like &T, and same for fn() inner @@ -153,11 +153,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { ) -> InterpResult<'tcx, bool> { // Fast path: equal types are definitely compatible. if caller.ty == callee.ty { - return Ok(true); + return interp_ok(true); } // 1-ZST are compatible with all 1-ZST (and with nothing else). if caller.is_1zst() || callee.is_1zst() { - return Ok(caller.is_1zst() && callee.is_1zst()); + return interp_ok(caller.is_1zst() && callee.is_1zst()); } // Unfold newtypes and NPO optimizations. let unfold = |layout: TyAndLayout<'tcx>| { @@ -180,17 +180,17 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { _ => None, }; if let (Some(caller), Some(callee)) = (thin_pointer(caller), thin_pointer(callee)) { - return Ok(caller == callee); + return interp_ok(caller == callee); } // For wide pointers we have to get the pointee type. let pointee_ty = |ty: Ty<'tcx>| -> InterpResult<'tcx, Option>> { // We cannot use `builtin_deref` here since we need to reject `Box`. - Ok(Some(match ty.kind() { + interp_ok(Some(match ty.kind() { ty::Ref(_, ty, _) => *ty, ty::RawPtr(ty, _) => *ty, // We only accept `Box` with the default allocator. _ if ty.is_box_global(*self.tcx) => ty.expect_boxed_ty(), - _ => return Ok(None), + _ => return interp_ok(None), })) }; if let (Some(caller), Some(callee)) = (pointee_ty(caller.ty)?, pointee_ty(callee.ty)?) { @@ -202,7 +202,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let normalize = |ty| self.tcx.normalize_erasing_regions(self.param_env, ty); ty.ptr_metadata_ty(*self.tcx, normalize) }; - return Ok(meta_ty(caller) == meta_ty(callee)); + return interp_ok(meta_ty(caller) == meta_ty(callee)); } // Compatible integer types (in particular, usize vs ptr-sized-u32/u64). @@ -217,11 +217,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { }; if let (Some(caller), Some(callee)) = (int_ty(caller.ty), int_ty(callee.ty)) { // This is okay if they are the same integer type. - return Ok(caller == callee); + return interp_ok(caller == callee); } // Fall back to exact equality. - Ok(caller == callee) + interp_ok(caller == callee) } fn check_argument_compat( @@ -235,13 +235,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // Ensure that our checks imply actual ABI compatibility for this concrete call. // (This can fail e.g. if `#[rustc_nonnull_optimization_guaranteed]` is used incorrectly.) assert!(caller_abi.eq_abi(callee_abi)); - Ok(true) + interp_ok(true) } else { trace!( "check_argument_compat: incompatible ABIs:\ncaller: {:?}\ncallee: {:?}", caller_abi, callee_abi ); - Ok(false) + interp_ok(false) } } @@ -266,7 +266,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { if !already_live { self.storage_live(callee_arg.as_local().unwrap())?; } - return Ok(()); + return interp_ok(()); } // Find next caller arg. let Some((caller_arg, caller_abi)) = caller_args.next() else { @@ -308,7 +308,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { if let FnArg::InPlace(mplace) = caller_arg { M::protect_in_place_function_argument(self, mplace)?; } - Ok(()) + interp_ok(()) } /// The main entry point for creating a new stack frame: performs ABI checks and initializes @@ -536,7 +536,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { unwind, ); } else { - Ok(()) + interp_ok(()) } } ty::InstanceKind::VTableShim(..) @@ -561,7 +561,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { unwind, )? else { - return Ok(()); + return interp_ok(()); }; // Special handling for the closure ABI: untuple the last argument. @@ -572,7 +572,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { trace!("init_fn_call: Will pass last argument by untupling"); Cow::from( args.iter() - .map(|a| Ok(a.clone())) + .map(|a| interp_ok(a.clone())) .chain( (0..untuple_arg.layout().fields.count()) .map(|i| self.fn_arg_field(untuple_arg, i)), @@ -598,7 +598,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // codegen'd / interpreted as virtual calls through the vtable. ty::InstanceKind::Virtual(def_id, idx) => { let mut args = args.to_vec(); - // We have to implement all "object safe receivers". So we have to go search for a + // We have to implement all "dyn-compatible receivers". So we have to go search for a // pointer or `dyn Trait` type, but it could be wrapped in newtypes. So recursively // unwrap those newtypes until we are there. // An `InPlace` does nothing here, we keep the original receiver intact. We can't @@ -886,27 +886,25 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // this transmute. res } else { - Ok(()) + interp_ok(()) }; // All right, now it is time to actually pop the frame. - let stack_pop_info = self.pop_stack_frame_raw(unwinding)?; - - // Report error from return value copy, if any. - copy_ret_result?; + // An error here takes precedence over the copy error. + let (stack_pop_info, ()) = self.pop_stack_frame_raw(unwinding).and(copy_ret_result)?; match stack_pop_info.return_action { ReturnAction::Normal => {} ReturnAction::NoJump => { // The hook already did everything. - return Ok(()); + return interp_ok(()); } ReturnAction::NoCleanup => { // If we are not doing cleanup, also skip everything else. assert!(self.stack().is_empty(), "only the topmost frame should ever be leaked"); assert!(!unwinding, "tried to skip cleanup during unwinding"); // Skip machine hook. - return Ok(()); + return interp_ok(()); } } @@ -931,7 +929,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { self.stack().is_empty(), "only the bottommost frame can have StackPopCleanup::Root" ); - Ok(()) + interp_ok(()) } } } diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index 85e7d91c2ad5..565a7d162424 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -14,7 +14,8 @@ use tracing::trace; use super::util::ensure_monomorphic_enough; use super::{ - FnVal, ImmTy, Immediate, InterpCx, Machine, OpTy, PlaceTy, err_inval, throw_ub, throw_ub_custom, + FnVal, ImmTy, Immediate, InterpCx, Machine, OpTy, PlaceTy, err_inval, interp_ok, throw_ub, + throw_ub_custom, }; use crate::fluent_generated as fluent; @@ -157,7 +158,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { self.copy_op_allow_transmute(src, dest)?; } } - Ok(()) + interp_ok(()) } /// Handles 'IntToInt' and 'IntToFloat' casts. @@ -169,7 +170,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { assert!(src.layout.ty.is_integral() || src.layout.ty.is_char() || src.layout.ty.is_bool()); assert!(cast_to.ty.is_floating_point() || cast_to.ty.is_integral() || cast_to.ty.is_char()); - Ok(ImmTy::from_scalar( + interp_ok(ImmTy::from_scalar( self.cast_from_int_like(src.to_scalar(), src.layout, cast_to.ty)?, cast_to, )) @@ -192,7 +193,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { FloatTy::F64 => self.cast_from_float(src.to_scalar().to_f64()?, cast_to.ty), FloatTy::F128 => self.cast_from_float(src.to_scalar().to_f128()?, cast_to.ty), }; - Ok(ImmTy::from_scalar(val, cast_to)) + interp_ok(ImmTy::from_scalar(val, cast_to)) } /// Handles 'FnPtrToPtr' and 'PtrToPtr' casts. @@ -206,14 +207,14 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // Handle casting any ptr to raw ptr (might be a fat ptr). if cast_to.size == src.layout.size { // Thin or fat pointer that just has the ptr kind of target type changed. - return Ok(ImmTy::from_immediate(**src, cast_to)); + return interp_ok(ImmTy::from_immediate(**src, cast_to)); } else { // Casting the metadata away from a fat ptr. assert_eq!(src.layout.size, 2 * self.pointer_size()); assert_eq!(cast_to.size, self.pointer_size()); assert!(src.layout.ty.is_unsafe_ptr()); return match **src { - Immediate::ScalarPair(data, _) => Ok(ImmTy::from_scalar(data, cast_to)), + Immediate::ScalarPair(data, _) => interp_ok(ImmTy::from_scalar(data, cast_to)), Immediate::Scalar(..) => span_bug!( self.cur_span(), "{:?} input to a fat-to-thin cast ({} -> {})", @@ -240,7 +241,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { Ok(ptr) => M::expose_ptr(self, ptr)?, Err(_) => {} // Do nothing, exposing an invalid pointer (`None` provenance) is a NOP. }; - Ok(ImmTy::from_scalar(self.cast_from_int_like(scalar, src.layout, cast_to.ty)?, cast_to)) + interp_ok(ImmTy::from_scalar( + self.cast_from_int_like(scalar, src.layout, cast_to.ty)?, + cast_to, + )) } pub fn pointer_with_exposed_provenance_cast( @@ -258,7 +262,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // Then turn address into pointer. let ptr = M::ptr_from_addr_cast(self, addr)?; - Ok(ImmTy::from_scalar(Scalar::from_maybe_pointer(ptr, self), cast_to)) + interp_ok(ImmTy::from_scalar(Scalar::from_maybe_pointer(ptr, self), cast_to)) } /// Low-level cast helper function. This works directly on scalars and can take 'int-like' input @@ -280,7 +284,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { _ => span_bug!(self.cur_span(), "invalid int-like cast from {}", src_layout.ty), }; - Ok(match *cast_ty.kind() { + interp_ok(match *cast_ty.kind() { // int -> int Int(_) | Uint(_) => { let size = match *cast_ty.kind() { @@ -505,7 +509,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { self.unsize_into(&src_field, cast_ty_field, &dst_field)?; } } - Ok(()) + interp_ok(()) } _ => { // Do not ICE if we are not monomorphic enough. diff --git a/compiler/rustc_const_eval/src/interpret/discriminant.rs b/compiler/rustc_const_eval/src/interpret/discriminant.rs index 3bab2b3261e1..81e0b1e12caf 100644 --- a/compiler/rustc_const_eval/src/interpret/discriminant.rs +++ b/compiler/rustc_const_eval/src/interpret/discriminant.rs @@ -7,7 +7,8 @@ use rustc_target::abi::{self, TagEncoding, VariantIdx, Variants}; use tracing::{instrument, trace}; use super::{ - ImmTy, InterpCx, InterpResult, Machine, Projectable, Scalar, Writeable, err_ub, throw_ub, + ImmTy, InterpCx, InterpResult, Machine, Projectable, Scalar, Writeable, err_ub, interp_ok, + throw_ub, }; impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { @@ -48,7 +49,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { if actual_variant != variant_index { throw_ub!(InvalidNichedEnumVariantWritten { enum_ty: dest.layout().ty }); } - Ok(()) + interp_ok(()) } } } @@ -89,7 +90,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { throw_ub!(UninhabitedEnumVariantRead(index)) } } - return Ok(index); + return interp_ok(index); } Variants::Multiple { tag, ref tag_encoding, tag_field, .. } => { (tag, tag_encoding, tag_field) @@ -205,7 +206,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { if op.layout().for_variant(self, index).abi.is_uninhabited() { throw_ub!(UninhabitedEnumVariantRead(index)) } - Ok(index) + interp_ok(index) } pub fn discriminant_for_variant( @@ -226,7 +227,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { Scalar::from_uint(variant.as_u32(), discr_layout.size) } }; - Ok(ImmTy::from_scalar(discr_value, discr_layout)) + interp_ok(ImmTy::from_scalar(discr_value, discr_layout)) } /// Computes how to write the tag of a given variant of enum `ty`: @@ -247,7 +248,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // discriminant is encoded implicitly, so any attempt to write // the wrong discriminant for a `Single` enum will reliably // result in UB. - Ok(None) + interp_ok(None) } abi::Variants::Multiple { @@ -265,7 +266,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let tag_size = tag_layout.size(self); let tag_val = tag_size.truncate(discr_val); let tag = ScalarInt::try_from_uint(tag_val, tag_size).unwrap(); - Ok(Some((tag, tag_field))) + interp_ok(Some((tag, tag_field))) } abi::Variants::Multiple { @@ -274,7 +275,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } if untagged_variant == variant_index => { // The untagged variant is implicitly encoded simply by having a // value that is outside the niche variants. - Ok(None) + interp_ok(None) } abi::Variants::Multiple { @@ -299,7 +300,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let tag = self .binary_op(mir::BinOp::Add, &variant_index_relative_val, &niche_start_val)? .to_scalar_int()?; - Ok(Some((tag, tag_field))) + interp_ok(Some((tag, tag_field))) } } } diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index f4c4a6fb0bf5..5165f95afd5b 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -19,9 +19,9 @@ use rustc_trait_selection::traits::ObligationCtxt; use tracing::{debug, instrument, trace}; use super::{ - Frame, FrameInfo, GlobalId, InterpErrorInfo, InterpResult, MPlaceTy, Machine, MemPlaceMeta, - Memory, OpTy, Place, PlaceTy, PointerArithmetic, Projectable, Provenance, err_inval, - throw_inval, throw_ub, throw_ub_custom, + Frame, FrameInfo, GlobalId, InterpError, InterpErrorInfo, InterpResult, MPlaceTy, Machine, + MemPlaceMeta, Memory, OpTy, Place, PlaceTy, PointerArithmetic, Projectable, Provenance, + err_inval, interp_ok, throw_inval, throw_ub, throw_ub_custom, }; use crate::{ReportErrorExt, fluent_generated as fluent, util}; @@ -73,7 +73,7 @@ where } impl<'tcx, M: Machine<'tcx>> LayoutOfHelpers<'tcx> for InterpCx<'tcx, M> { - type LayoutOfResult = InterpResult<'tcx, TyAndLayout<'tcx>>; + type LayoutOfResult = Result, InterpError<'tcx>>; #[inline] fn layout_tcx_at_span(&self) -> Span { @@ -82,29 +82,24 @@ impl<'tcx, M: Machine<'tcx>> LayoutOfHelpers<'tcx> for InterpCx<'tcx, M> { } #[inline] - fn handle_layout_err( - &self, - err: LayoutError<'tcx>, - _: Span, - _: Ty<'tcx>, - ) -> InterpErrorInfo<'tcx> { - err_inval!(Layout(err)).into() + fn handle_layout_err(&self, err: LayoutError<'tcx>, _: Span, _: Ty<'tcx>) -> InterpError<'tcx> { + err_inval!(Layout(err)) } } impl<'tcx, M: Machine<'tcx>> FnAbiOfHelpers<'tcx> for InterpCx<'tcx, M> { - type FnAbiOfResult = InterpResult<'tcx, &'tcx FnAbi<'tcx, Ty<'tcx>>>; + type FnAbiOfResult = Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, InterpError<'tcx>>; fn handle_fn_abi_err( &self, err: FnAbiError<'tcx>, _span: Span, _fn_abi_request: FnAbiRequest<'tcx>, - ) -> InterpErrorInfo<'tcx> { + ) -> InterpError<'tcx> { match err { - FnAbiError::Layout(err) => err_inval!(Layout(err)).into(), + FnAbiError::Layout(err) => err_inval!(Layout(err)), FnAbiError::AdjustForForeignAbi(err) => { - err_inval!(FnAbiAdjustForForeignAbi(err)).into() + err_inval!(FnAbiAdjustForForeignAbi(err)) } } } @@ -160,7 +155,7 @@ pub(super) fn from_known_layout<'tcx>( ); } } - Ok(known_layout) + interp_ok(known_layout) } } } @@ -262,7 +257,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { if let Some(err) = body.tainted_by_errors { throw_inval!(AlreadyReported(ReportedErrorInfo::tainted_by_errors(err))); } - Ok(body) + interp_ok(body) } /// Call this on things you got out of the MIR (so it is as generic as the current @@ -305,7 +300,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { trace!("param_env: {:#?}", self.param_env); trace!("args: {:#?}", args); match ty::Instance::try_resolve(*self.tcx, self.param_env, def, args) { - Ok(Some(instance)) => Ok(instance), + Ok(Some(instance)) => interp_ok(instance), Ok(None) => throw_inval!(TooGeneric), // FIXME(eddyb) this could be a bit more specific than `AlreadyReported`. @@ -401,7 +396,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { layout: &TyAndLayout<'tcx>, ) -> InterpResult<'tcx, Option<(Size, Align)>> { if layout.is_sized() { - return Ok(Some((layout.size, layout.align.abi))); + return interp_ok(Some((layout.size, layout.align.abi))); } match layout.ty.kind() { ty::Adt(..) | ty::Tuple(..) => { @@ -425,7 +420,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { else { // A field with an extern type. We don't know the actual dynamic size // or the alignment. - return Ok(None); + return interp_ok(None); }; // # First compute the dynamic alignment @@ -456,12 +451,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { if full_size > self.max_size_of_val() { throw_ub!(InvalidMeta(InvalidMetaKind::TooBig)); } - Ok(Some((full_size, full_align))) + interp_ok(Some((full_size, full_align))) } ty::Dynamic(expected_trait, _, ty::Dyn) => { let vtable = metadata.unwrap_meta().to_pointer(self)?; // Read size and align from vtable (already checks size). - Ok(Some(self.get_vtable_size_and_align(vtable, Some(expected_trait))?)) + interp_ok(Some(self.get_vtable_size_and_align(vtable, Some(expected_trait))?)) } ty::Slice(_) | ty::Str => { @@ -474,10 +469,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { if size > self.max_size_of_val() { throw_ub!(InvalidMeta(InvalidMetaKind::SliceTooBig)); } - Ok(Some((size, elem.align.abi))) + interp_ok(Some((size, elem.align.abi))) } - ty::Foreign(_) => Ok(None), + ty::Foreign(_) => interp_ok(None), _ => span_bug!(self.cur_span(), "size_and_align_of::<{}> not supported", layout.ty), } @@ -503,7 +498,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { pub fn return_to_block(&mut self, target: Option) -> InterpResult<'tcx> { if let Some(target) = target { self.go_to_block(target); - Ok(()) + interp_ok(()) } else { throw_ub!(Unreachable) } @@ -530,10 +525,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { M::unwind_terminate(self, reason)?; // This might have pushed a new stack frame, or it terminated execution. // Either way, `loc` will not be updated. - return Ok(()); + return interp_ok(()); } }; - Ok(()) + interp_ok(()) } /// Call a query that can return `ErrorHandled`. Should be used for statics and other globals. diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs index 81659df7c533..7a1b92601a44 100644 --- a/compiler/rustc_const_eval/src/interpret/intern.rs +++ b/compiler/rustc_const_eval/src/interpret/intern.rs @@ -26,7 +26,9 @@ use rustc_span::def_id::LocalDefId; use rustc_span::sym; use tracing::{instrument, trace}; -use super::{AllocId, Allocation, InterpCx, MPlaceTy, Machine, MemoryKind, PlaceTy, err_ub}; +use super::{ + AllocId, Allocation, InterpCx, MPlaceTy, Machine, MemoryKind, PlaceTy, err_ub, interp_ok, +}; use crate::const_eval; use crate::errors::NestedStaticInThreadLocal; @@ -307,7 +309,7 @@ pub fn intern_const_alloc_for_constprop<'tcx, T, M: CompileTimeMachine<'tcx, T>> ) -> InterpResult<'tcx, ()> { if ecx.tcx.try_get_global_alloc(alloc_id).is_some() { // The constant is already in global memory. Do nothing. - return Ok(()); + return interp_ok(()); } // Move allocation to `tcx`. if let Some(_) = @@ -318,7 +320,7 @@ pub fn intern_const_alloc_for_constprop<'tcx, T, M: CompileTimeMachine<'tcx, T>> // proper recursive interning loop -- or just call `intern_const_alloc_recursive`. panic!("`intern_const_alloc_for_constprop` called on allocation with nested provenance") } - Ok(()) + interp_ok(()) } impl<'tcx, M: super::intern::CompileTimeMachine<'tcx, !>> InterpCx<'tcx, M> { @@ -342,6 +344,6 @@ impl<'tcx, M: super::intern::CompileTimeMachine<'tcx, !>> InterpCx<'tcx, M> { panic!("`intern_with_temp_alloc` with nested allocations"); } } - Ok(alloc_id) + interp_ok(alloc_id) } } diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index e1fd8bea1f30..52780cc6a3a6 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -18,7 +18,7 @@ use super::util::ensure_monomorphic_enough; use super::{ Allocation, CheckInAllocMsg, ConstAllocation, GlobalId, ImmTy, InterpCx, InterpResult, MPlaceTy, Machine, OpTy, Pointer, PointerArithmetic, Provenance, Scalar, err_inval, - err_ub_custom, err_unsup_format, throw_inval, throw_ub_custom, throw_ub_format, + err_ub_custom, err_unsup_format, interp_ok, throw_inval, throw_ub_custom, throw_ub_format, }; use crate::fluent_generated as fluent; @@ -39,7 +39,7 @@ pub(crate) fn eval_nullary_intrinsic<'tcx>( ) -> InterpResult<'tcx, ConstValue<'tcx>> { let tp_ty = args.type_at(0); let name = tcx.item_name(def_id); - Ok(match name { + interp_ok(match name { sym::type_name => { ensure_monomorphic_enough(tcx, tp_ty)?; let alloc = alloc_type_name(tcx, tp_ty); @@ -329,6 +329,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { fluent::const_eval_offset_from_different_allocations, name = intrinsic_name, ) + .into() })?; // Perform division by size to compute return value. @@ -378,7 +379,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { M::panic_nounwind(self, &msg)?; // Skip the `return_to_block` at the end (we panicked, we do not return). - return Ok(true); + return interp_ok(true); } } sym::simd_insert => { @@ -396,11 +397,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { for i in 0..dest_len { let place = self.project_index(&dest, i)?; - let value = if i == index { - elem.clone() - } else { - self.project_index(&input, i)?.into() - }; + let value = + if i == index { elem.clone() } else { self.project_index(&input, i)? }; self.copy_op(&value, &place)?; } } @@ -441,12 +439,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } // Unsupported intrinsic: skip the return_to_block below. - _ => return Ok(false), + _ => return interp_ok(false), } trace!("{:?}", self.dump_place(&dest.clone().into())); self.return_to_block(ret)?; - Ok(true) + interp_ok(true) } pub(super) fn eval_nondiverging_intrinsic( @@ -460,7 +458,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { if !cond { throw_ub_custom!(fluent::const_eval_assume_false); } - Ok(()) + interp_ok(()) } NonDivergingIntrinsic::CopyNonOverlapping(mir::CopyNonOverlapping { count, @@ -502,7 +500,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } _ => bug!("not a numeric intrinsic: {}", name), }; - Ok(Scalar::from_uint(bits_out, ret_layout.size)) + interp_ok(Scalar::from_uint(bits_out, ret_layout.size)) } pub fn exact_div( @@ -543,7 +541,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let (val, overflowed) = self.binary_op(mir_op.wrapping_to_overflowing().unwrap(), l, r)?.to_scalar_pair(); - Ok(if overflowed.to_bool()? { + interp_ok(if overflowed.to_bool()? { let size = l.layout.size; if l.layout.abi.is_signed() { // For signed ints the saturated value depends on the sign of the first @@ -585,7 +583,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // The offset must be in bounds starting from `ptr`. self.check_ptr_access_signed(ptr, offset_bytes, CheckInAllocMsg::PointerArithmeticTest)?; // This also implies that there is no overflow, so we are done. - Ok(ptr.wrapping_signed_offset(offset_bytes, self)) + interp_ok(ptr.wrapping_signed_offset(offset_bytes, self)) } /// Copy `count*size_of::()` many bytes from `*src` to `*dst`. @@ -631,7 +629,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { self.copy_op(&right, &left)?; self.copy_op(&temp, &right)?; self.deallocate_ptr(temp.ptr(), None, kind)?; - Ok(()) + interp_ok(()) } pub fn write_bytes_intrinsic( @@ -672,7 +670,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // `Ordering`'s discriminants are -1/0/+1, so casting does the right thing. let result = Ord::cmp(left_bytes, right_bytes) as i32; - Ok(Scalar::from_i32(result)) + interp_ok(Scalar::from_i32(result)) } pub(crate) fn raw_eq_intrinsic( @@ -690,13 +688,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { this.check_ptr_align(ptr, layout.align.abi)?; let Some(alloc_ref) = self.get_ptr_alloc(ptr, layout.size)? else { // zero-sized access - return Ok(&[]); + return interp_ok(&[]); }; alloc_ref.get_bytes_strip_provenance() }; let lhs_bytes = get_bytes(self, lhs)?; let rhs_bytes = get_bytes(self, rhs)?; - Ok(Scalar::from_bool(lhs_bytes == rhs_bytes)) + interp_ok(Scalar::from_bool(lhs_bytes == rhs_bytes)) } } diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index a809f74e8eb9..0f796c312221 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -20,7 +20,8 @@ use rustc_target::spec::abi::Abi as CallAbi; use super::{ AllocBytes, AllocId, AllocKind, AllocRange, Allocation, CTFE_ALLOC_SALT, ConstAllocation, CtfeProvenance, FnArg, Frame, ImmTy, InterpCx, InterpResult, MPlaceTy, MemoryKind, - Misalignment, OpTy, PlaceTy, Pointer, Provenance, RangeSet, throw_unsup, throw_unsup_format, + Misalignment, OpTy, PlaceTy, Pointer, Provenance, RangeSet, interp_ok, throw_unsup, + throw_unsup_format, }; /// Data returned by [`Machine::after_stack_pop`], and consumed by @@ -185,7 +186,7 @@ pub trait Machine<'tcx>: Sized { ecx: &InterpCx<'tcx, Self>, instance: ty::InstanceKind<'tcx>, ) -> InterpResult<'tcx, &'tcx mir::Body<'tcx>> { - Ok(ecx.tcx.instance_mir(instance)) + interp_ok(ecx.tcx.instance_mir(instance)) } /// Entry point to all function calls. @@ -280,7 +281,7 @@ pub trait Machine<'tcx>: Sized { /// Called before a basic block terminator is executed. #[inline] fn before_terminator(_ecx: &mut InterpCx<'tcx, Self>) -> InterpResult<'tcx> { - Ok(()) + interp_ok(()) } /// Determines the result of a `NullaryOp::UbChecks` invocation. @@ -290,7 +291,7 @@ pub trait Machine<'tcx>: Sized { /// You can use this to detect long or endlessly running programs. #[inline] fn increment_const_eval_counter(_ecx: &mut InterpCx<'tcx, Self>) -> InterpResult<'tcx> { - Ok(()) + interp_ok(()) } /// Called before a global allocation is accessed. @@ -304,7 +305,7 @@ pub trait Machine<'tcx>: Sized { _static_def_id: Option, _is_write: bool, ) -> InterpResult<'tcx> { - Ok(()) + interp_ok(()) } /// Return the `AllocId` for the given thread-local static in the current thread. @@ -422,7 +423,7 @@ pub trait Machine<'tcx>: Sized { _prov: (AllocId, Self::ProvenanceExtra), _range: AllocRange, ) -> InterpResult<'tcx> { - Ok(()) + interp_ok(()) } /// Hook for performing extra checks on any memory read access, @@ -433,7 +434,7 @@ pub trait Machine<'tcx>: Sized { /// Used to prevent statics from self-initializing by reading from their own memory /// as it is being initialized. fn before_alloc_read(_ecx: &InterpCx<'tcx, Self>, _alloc_id: AllocId) -> InterpResult<'tcx> { - Ok(()) + interp_ok(()) } /// Hook for performing extra checks on a memory write access. @@ -446,7 +447,7 @@ pub trait Machine<'tcx>: Sized { _prov: (AllocId, Self::ProvenanceExtra), _range: AllocRange, ) -> InterpResult<'tcx> { - Ok(()) + interp_ok(()) } /// Hook for performing extra operations on a memory deallocation. @@ -460,7 +461,7 @@ pub trait Machine<'tcx>: Sized { _align: Align, _kind: MemoryKind, ) -> InterpResult<'tcx> { - Ok(()) + interp_ok(()) } /// Executes a retagging operation for a single pointer. @@ -471,7 +472,7 @@ pub trait Machine<'tcx>: Sized { _kind: mir::RetagKind, val: &ImmTy<'tcx, Self::Provenance>, ) -> InterpResult<'tcx, ImmTy<'tcx, Self::Provenance>> { - Ok(val.clone()) + interp_ok(val.clone()) } /// Executes a retagging operation on a compound value. @@ -482,7 +483,7 @@ pub trait Machine<'tcx>: Sized { _kind: mir::RetagKind, _place: &PlaceTy<'tcx, Self::Provenance>, ) -> InterpResult<'tcx> { - Ok(()) + interp_ok(()) } /// Called on places used for in-place function argument and return value handling. @@ -516,7 +517,7 @@ pub trait Machine<'tcx>: Sized { /// Called immediately after a stack frame got pushed and its locals got initialized. fn after_stack_push(_ecx: &mut InterpCx<'tcx, Self>) -> InterpResult<'tcx> { - Ok(()) + interp_ok(()) } /// Called just before the return value is copied to the caller-provided return place. @@ -524,7 +525,7 @@ pub trait Machine<'tcx>: Sized { _ecx: &InterpCx<'tcx, Self>, _frame: &Frame<'tcx, Self::Provenance, Self::FrameExtra>, ) -> InterpResult<'tcx> { - Ok(()) + interp_ok(()) } /// Called immediately after a stack frame got popped, but before jumping back to the caller. @@ -537,14 +538,14 @@ pub trait Machine<'tcx>: Sized { ) -> InterpResult<'tcx, ReturnAction> { // By default, we do not support unwinding from panics assert!(!unwinding); - Ok(ReturnAction::Normal) + interp_ok(ReturnAction::Normal) } /// Called immediately after an "immediate" local variable is read /// (i.e., this is called for reads that do not end up accessing addressable memory). #[inline(always)] fn after_local_read(_ecx: &InterpCx<'tcx, Self>, _local: mir::Local) -> InterpResult<'tcx> { - Ok(()) + interp_ok(()) } /// Called immediately after an "immediate" local variable is assigned a new value @@ -556,7 +557,7 @@ pub trait Machine<'tcx>: Sized { _local: mir::Local, _storage_live: bool, ) -> InterpResult<'tcx> { - Ok(()) + interp_ok(()) } /// Called immediately after actual memory was allocated for a local @@ -567,7 +568,7 @@ pub trait Machine<'tcx>: Sized { _local: mir::Local, _mplace: &MPlaceTy<'tcx, Self::Provenance>, ) -> InterpResult<'tcx> { - Ok(()) + interp_ok(()) } /// Evaluate the given constant. The `eval` function will do all the required evaluation, @@ -645,7 +646,7 @@ pub macro compile_time_machine(<$tcx: lifetime>) { ) -> InterpResult<$tcx> { // For now we don't do any checking here. We can't use `tcx.sess` because that can differ // between crates, and we need to ensure that const-eval always behaves the same. - Ok(()) + interp_ok(()) } #[inline(always)] @@ -665,7 +666,7 @@ pub macro compile_time_machine(<$tcx: lifetime>) { fn ub_checks(_ecx: &InterpCx<$tcx, Self>) -> InterpResult<$tcx, bool> { // We can't look at `tcx.sess` here as that can differ across crates, which can lead to // unsound differences in evaluating the same constant at different instantiation sites. - Ok(true) + interp_ok(true) } #[inline(always)] @@ -675,7 +676,7 @@ pub macro compile_time_machine(<$tcx: lifetime>) { alloc: &'b Allocation, ) -> InterpResult<$tcx, Cow<'b, Allocation>> { // Overwrite default implementation: no need to adjust anything. - Ok(Cow::Borrowed(alloc)) + interp_ok(Cow::Borrowed(alloc)) } fn init_alloc_extra( @@ -685,7 +686,7 @@ pub macro compile_time_machine(<$tcx: lifetime>) { _size: Size, _align: Align, ) -> InterpResult<$tcx, Self::AllocExtra> { - Ok(()) + interp_ok(()) } fn extern_static_pointer( @@ -693,7 +694,7 @@ pub macro compile_time_machine(<$tcx: lifetime>) { def_id: DefId, ) -> InterpResult<$tcx, Pointer> { // Use the `AllocId` associated with the `DefId`. Any actual *access* will fail. - Ok(Pointer::new(ecx.tcx.reserve_and_set_static_alloc(def_id).into(), Size::ZERO)) + interp_ok(Pointer::new(ecx.tcx.reserve_and_set_static_alloc(def_id).into(), Size::ZERO)) } #[inline(always)] @@ -702,7 +703,7 @@ pub macro compile_time_machine(<$tcx: lifetime>) { ptr: Pointer, _kind: Option>, ) -> InterpResult<$tcx, Pointer> { - Ok(ptr) + interp_ok(ptr) } #[inline(always)] @@ -713,7 +714,7 @@ pub macro compile_time_machine(<$tcx: lifetime>) { // Allow these casts, but make the pointer not dereferenceable. // (I.e., they behave like transmutation.) // This is correct because no pointers can ever be exposed in compile-time evaluation. - Ok(Pointer::from_addr_invalid(addr)) + interp_ok(Pointer::from_addr_invalid(addr)) } #[inline(always)] diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index c3b506d848cd..e6ab8ca12a88 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -23,7 +23,7 @@ use tracing::{debug, instrument, trace}; use super::{ AllocBytes, AllocId, AllocMap, AllocRange, Allocation, CheckAlignMsg, CheckInAllocMsg, CtfeProvenance, GlobalAlloc, InterpCx, InterpResult, Machine, MayLeak, Misalignment, Pointer, - PointerArithmetic, Provenance, Scalar, alloc_range, err_ub, err_ub_custom, throw_ub, + PointerArithmetic, Provenance, Scalar, alloc_range, err_ub, err_ub_custom, interp_ok, throw_ub, throw_ub_custom, throw_unsup, throw_unsup_format, }; use crate::fluent_generated as fluent; @@ -82,7 +82,7 @@ pub enum FnVal<'tcx, Other> { impl<'tcx, Other> FnVal<'tcx, Other> { pub fn as_instance(self) -> InterpResult<'tcx, Instance<'tcx>> { match self { - FnVal::Instance(instance) => Ok(instance), + FnVal::Instance(instance) => interp_ok(instance), FnVal::Other(_) => { throw_unsup_format!("'foreign' function pointers are not supported in this context") } @@ -284,7 +284,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { self.mem_copy(ptr, new_ptr.into(), old_size.min(new_size), /*nonoverlapping*/ true)?; self.deallocate_ptr(ptr, old_size_and_align, kind)?; - Ok(new_ptr) + interp_ok(new_ptr) } #[instrument(skip(self), level = "debug")] @@ -330,8 +330,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { ) } None => err_ub!(PointerUseAfterFree(alloc_id, CheckInAllocMsg::MemoryAccessTest)), - } - .into()); + }) + .into(); }; if alloc.mutability.is_not() { @@ -376,7 +376,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { bug!("Nothing can be deallocated twice"); } - Ok(()) + interp_ok(()) } /// Internal helper function to determine the allocation and offset of a pointer (if any). @@ -395,7 +395,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { |this, alloc_id, offset, prov| { let (size, align) = this .get_live_alloc_size_and_align(alloc_id, CheckInAllocMsg::MemoryAccessTest)?; - Ok((size, align, (alloc_id, offset, prov))) + interp_ok((size, align, (alloc_id, offset, prov))) }, ) } @@ -412,9 +412,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let size = i64::try_from(size.bytes()).unwrap(); // it would be an error to even ask for more than isize::MAX bytes Self::check_and_deref_ptr(self, ptr, size, msg, |this, alloc_id, _, _| { let (size, align) = this.get_live_alloc_size_and_align(alloc_id, msg)?; - Ok((size, align, ())) + interp_ok((size, align, ())) })?; - Ok(()) + interp_ok(()) } /// Check whether the given pointer points to live memory for a signed amount of bytes. @@ -428,9 +428,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { ) -> InterpResult<'tcx> { Self::check_and_deref_ptr(self, ptr, size, msg, |this, alloc_id, _, _| { let (size, align) = this.get_live_alloc_size_and_align(alloc_id, msg)?; - Ok((size, align, ())) + interp_ok((size, align, ())) })?; - Ok(()) + interp_ok(()) } /// Low-level helper function to check if a ptr is in-bounds and potentially return a reference @@ -455,10 +455,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { ) -> InterpResult<'tcx, Option> { // Everything is okay with size 0. if size == 0 { - return Ok(None); + return interp_ok(None); } - Ok(match this.borrow().ptr_try_get_alloc_id(ptr, size) { + interp_ok(match this.borrow().ptr_try_get_alloc_id(ptr, size) { Err(addr) => { // We couldn't get a proper allocation. throw_ub!(DanglingIntPointer { addr, inbounds_size: size, msg }); @@ -498,7 +498,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { if let Some(misaligned) = misaligned { throw_ub!(AlignmentCheckFailed(misaligned, msg)) } - Ok(()) + interp_ok(()) } pub(super) fn is_ptr_misaligned( @@ -634,7 +634,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // `get_global_alloc` that we can actually use directly without inserting anything anywhere. // So the error type is `InterpResult<'tcx, &Allocation>`. let a = self.memory.alloc_map.get_or(id, || { - let alloc = self.get_global_alloc(id, /*is_write*/ false).map_err(Err)?; + // We have to funnel the `InterpErrorInfo` through a `Result` to match the `get_or` API, + // so we use `report_err` for that. + let alloc = self.get_global_alloc(id, /*is_write*/ false).report_err().map_err(Err)?; match alloc { Cow::Borrowed(alloc) => { // We got a ref, cheaply return that as an "error" so that the @@ -653,8 +655,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { }); // Now unpack that funny error type match a { - Ok(a) => Ok(&a.1), - Err(a) => a, + Ok(a) => interp_ok(&a.1), + Err(a) => a.into(), } } @@ -662,7 +664,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { /// The caller is responsible for calling the access hooks! pub fn get_alloc_bytes_unchecked_raw(&self, id: AllocId) -> InterpResult<'tcx, *const u8> { let alloc = self.get_alloc_raw(id)?; - Ok(alloc.get_bytes_unchecked_raw()) + interp_ok(alloc.get_bytes_unchecked_raw()) } /// Bounds-checked *but not align-checked* allocation access. @@ -680,7 +682,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { CheckInAllocMsg::MemoryAccessTest, |this, alloc_id, offset, prov| { let alloc = this.get_alloc_raw(alloc_id)?; - Ok((alloc.size(), alloc.align, (alloc_id, offset, prov, alloc))) + interp_ok((alloc.size(), alloc.align, (alloc_id, offset, prov, alloc))) }, )?; // We want to call the hook on *all* accesses that involve an AllocId, including zero-sized @@ -703,20 +705,20 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { range, )?; } - Ok(Some(AllocRef { alloc, range, tcx: *self.tcx, alloc_id })) + interp_ok(Some(AllocRef { alloc, range, tcx: *self.tcx, alloc_id })) } else { - Ok(None) + interp_ok(None) } } /// Return the `extra` field of the given allocation. pub fn get_alloc_extra<'a>(&'a self, id: AllocId) -> InterpResult<'tcx, &'a M::AllocExtra> { - Ok(&self.get_alloc_raw(id)?.extra) + interp_ok(&self.get_alloc_raw(id)?.extra) } /// Return the `mutability` field of the given allocation. pub fn get_alloc_mutability<'a>(&'a self, id: AllocId) -> InterpResult<'tcx, Mutability> { - Ok(self.get_alloc_raw(id)?.mutability) + interp_ok(self.get_alloc_raw(id)?.mutability) } /// Gives raw mutable access to the `Allocation`, without bounds or alignment checks. @@ -750,7 +752,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { if alloc.mutability.is_not() { throw_ub!(WriteToReadOnly(id)) } - Ok((alloc, &mut self.machine)) + interp_ok((alloc, &mut self.machine)) } /// Gives raw, mutable access to the `Allocation` address, without bounds or alignment checks. @@ -760,7 +762,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { id: AllocId, ) -> InterpResult<'tcx, *mut u8> { let alloc = self.get_alloc_raw_mut(id)?.0; - Ok(alloc.get_bytes_unchecked_raw_mut()) + interp_ok(alloc.get_bytes_unchecked_raw_mut()) } /// Bounds-checked *but not align-checked* allocation access. @@ -781,7 +783,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { CheckInAllocMsg::MemoryAccessTest, |this, alloc_id, offset, prov| { let (alloc, machine) = this.get_alloc_raw_mut(alloc_id)?; - Ok((alloc.size(), alloc.align, (alloc_id, offset, prov, alloc, machine))) + interp_ok((alloc.size(), alloc.align, (alloc_id, offset, prov, alloc, machine))) }, )?; @@ -790,9 +792,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { if !validation_in_progress { M::before_memory_write(tcx, machine, &mut alloc.extra, (alloc_id, prov), range)?; } - Ok(Some(AllocRefMut { alloc, range, tcx: *tcx, alloc_id })) + interp_ok(Some(AllocRefMut { alloc, range, tcx: *tcx, alloc_id })) } else { - Ok(None) + interp_ok(None) } } @@ -802,7 +804,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { id: AllocId, ) -> InterpResult<'tcx, (&'a mut M::AllocExtra, &'a mut M)> { let (alloc, machine) = self.get_alloc_raw_mut(id)?; - Ok((&mut alloc.extra, machine)) + interp_ok((&mut alloc.extra, machine)) } /// Check whether an allocation is live. This is faster than calling @@ -904,7 +906,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { if matches!(kind, AllocKind::Dead) { throw_ub!(PointerUseAfterFree(id, msg)) } - Ok((size, align)) + interp_ok((size, align)) } fn get_fn_alloc(&self, id: AllocId) -> Option> { @@ -928,7 +930,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { throw_ub!(InvalidFunctionPointer(Pointer::new(alloc_id, offset))) } self.get_fn_alloc(alloc_id) - .ok_or_else(|| err_ub!(InvalidFunctionPointer(Pointer::new(alloc_id, offset))).into()) + .ok_or_else(|| err_ub!(InvalidFunctionPointer(Pointer::new(alloc_id, offset)))) + .into() } /// Get the dynamic type of the given vtable pointer. @@ -951,12 +954,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { if let Some(expected_dyn_type) = expected_trait { self.check_vtable_for_type(vtable_dyn_type, expected_dyn_type)?; } - Ok(ty) + interp_ok(ty) } pub fn alloc_mark_immutable(&mut self, id: AllocId) -> InterpResult<'tcx> { self.get_alloc_raw_mut(id)?.0.mutability = Mutability::Not; - Ok(()) + interp_ok(()) } /// Create a lazy debug printer that prints the given allocation and all allocations it points @@ -1144,10 +1147,11 @@ impl<'a, 'tcx, Prov: Provenance, Extra, Bytes: AllocBytes> pub fn write_scalar(&mut self, range: AllocRange, val: Scalar) -> InterpResult<'tcx> { let range = self.range.subrange(range); debug!("write_scalar at {:?}{range:?}: {val:?}", self.alloc_id); - Ok(self - .alloc + + self.alloc .write_scalar(&self.tcx, range, val) - .map_err(|e| e.to_interp_error(self.alloc_id))?) + .map_err(|e| e.to_interp_error(self.alloc_id)) + .into() } /// `offset` is relative to this allocation reference, not the base of the allocation. @@ -1158,26 +1162,27 @@ impl<'a, 'tcx, Prov: Provenance, Extra, Bytes: AllocBytes> /// Mark the given sub-range (relative to this allocation reference) as uninitialized. pub fn write_uninit(&mut self, range: AllocRange) -> InterpResult<'tcx> { let range = self.range.subrange(range); - Ok(self - .alloc + + self.alloc .write_uninit(&self.tcx, range) - .map_err(|e| e.to_interp_error(self.alloc_id))?) + .map_err(|e| e.to_interp_error(self.alloc_id)) + .into() } /// Mark the entire referenced range as uninitialized pub fn write_uninit_full(&mut self) -> InterpResult<'tcx> { - Ok(self - .alloc + self.alloc .write_uninit(&self.tcx, self.range) - .map_err(|e| e.to_interp_error(self.alloc_id))?) + .map_err(|e| e.to_interp_error(self.alloc_id)) + .into() } /// Remove all provenance in the reference range. pub fn clear_provenance(&mut self) -> InterpResult<'tcx> { - Ok(self - .alloc + self.alloc .clear_provenance(&self.tcx, self.range) - .map_err(|e| e.to_interp_error(self.alloc_id))?) + .map_err(|e| e.to_interp_error(self.alloc_id)) + .into() } } @@ -1189,12 +1194,10 @@ impl<'a, 'tcx, Prov: Provenance, Extra, Bytes: AllocBytes> AllocRef<'a, 'tcx, Pr read_provenance: bool, ) -> InterpResult<'tcx, Scalar> { let range = self.range.subrange(range); - let res = self - .alloc + self.alloc .read_scalar(&self.tcx, range, read_provenance) - .map_err(|e| e.to_interp_error(self.alloc_id))?; - debug!("read_scalar at {:?}{range:?}: {res:?}", self.alloc_id); - Ok(res) + .map_err(|e| e.to_interp_error(self.alloc_id)) + .into() } /// `range` is relative to this allocation reference, not the base of the allocation. @@ -1212,10 +1215,10 @@ impl<'a, 'tcx, Prov: Provenance, Extra, Bytes: AllocBytes> AllocRef<'a, 'tcx, Pr /// `range` is relative to this allocation reference, not the base of the allocation. pub fn get_bytes_strip_provenance<'b>(&'b self) -> InterpResult<'tcx, &'a [u8]> { - Ok(self - .alloc + self.alloc .get_bytes_strip_provenance(&self.tcx, self.range) - .map_err(|e| e.to_interp_error(self.alloc_id))?) + .map_err(|e| e.to_interp_error(self.alloc_id)) + .into() } /// Returns whether the allocation has provenance anywhere in the range of the `AllocRef`. @@ -1236,14 +1239,16 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { ) -> InterpResult<'tcx, &[u8]> { let Some(alloc_ref) = self.get_ptr_alloc(ptr, size)? else { // zero-sized access - return Ok(&[]); + return interp_ok(&[]); }; // Side-step AllocRef and directly access the underlying bytes more efficiently. // (We are staying inside the bounds here so all is good.) - Ok(alloc_ref - .alloc - .get_bytes_strip_provenance(&alloc_ref.tcx, alloc_ref.range) - .map_err(|e| e.to_interp_error(alloc_ref.alloc_id))?) + interp_ok( + alloc_ref + .alloc + .get_bytes_strip_provenance(&alloc_ref.tcx, alloc_ref.range) + .map_err(|e| e.to_interp_error(alloc_ref.alloc_id))?, + ) } /// Writes the given stream of bytes into memory. @@ -1263,7 +1268,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let Some(alloc_ref) = self.get_ptr_alloc_mut(ptr, size)? else { // zero-sized access assert_matches!(src.next(), None, "iterator said it was empty but returned an element"); - return Ok(()); + return interp_ok(()); }; // Side-step AllocRef and directly access the underlying bytes more efficiently. @@ -1279,7 +1284,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { *dest = src.next().expect("iterator was shorter than it said it would be"); } assert_matches!(src.next(), None, "iterator was longer than it said it would be"); - Ok(()) + interp_ok(()) } pub fn mem_copy( @@ -1316,7 +1321,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // Source alloc preparations and access hooks. let Some((src_alloc_id, src_offset, src_prov)) = src_parts else { // Zero-sized *source*, that means dest is also zero-sized and we have nothing to do. - return Ok(()); + return interp_ok(()); }; let src_alloc = self.get_alloc_raw(src_alloc_id)?; let src_range = alloc_range(src_offset, size); @@ -1332,7 +1337,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // We already did the source checks and called the hooks so we are good to return early. let Some((dest_alloc_id, dest_offset, dest_prov)) = dest_parts else { // Zero-sized *destination*. - return Ok(()); + return interp_ok(()); }; // Prepare getting source provenance. @@ -1375,7 +1380,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { .write_uninit(&tcx, dest_range) .map_err(|e| e.to_interp_error(dest_alloc_id))?; // We can forget about the provenance, this is all not initialized anyway. - return Ok(()); + return interp_ok(()); } // SAFE: The above indexing would have panicked if there weren't at least `size` bytes @@ -1432,7 +1437,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // copy the provenance to the destination dest_alloc.provenance_apply_copy(provenance); - Ok(()) + interp_ok(()) } } @@ -1441,7 +1446,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { /// Test if this value might be null. /// If the machine does not support ptr-to-int casts, this is conservative. pub fn scalar_may_be_null(&self, scalar: Scalar) -> InterpResult<'tcx, bool> { - Ok(match scalar.try_to_scalar_int() { + interp_ok(match scalar.try_to_scalar_int() { Ok(int) => int.is_null(), Err(_) => { // Can only happen during CTFE. @@ -1508,13 +1513,14 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { ptr: Pointer>, size: i64, ) -> InterpResult<'tcx, (AllocId, Size, M::ProvenanceExtra)> { - self.ptr_try_get_alloc_id(ptr, size).map_err(|offset| { - err_ub!(DanglingIntPointer { - addr: offset, - inbounds_size: size, - msg: CheckInAllocMsg::InboundsTest + self.ptr_try_get_alloc_id(ptr, size) + .map_err(|offset| { + err_ub!(DanglingIntPointer { + addr: offset, + inbounds_size: size, + msg: CheckInAllocMsg::InboundsTest + }) }) .into() - }) } } diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index 31ee3e6519af..291664d556af 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -16,7 +16,7 @@ use tracing::trace; use super::{ CtfeProvenance, InterpCx, InterpResult, MPlaceTy, Machine, MemPlace, MemPlaceMeta, OffsetMode, PlaceTy, Pointer, Projectable, Provenance, Scalar, alloc_range, err_ub, from_known_layout, - mir_assign_valid_types, throw_ub, + interp_ok, mir_assign_valid_types, throw_ub, }; /// An `Immediate` represents a single immediate self-contained Rust value. @@ -118,6 +118,7 @@ impl Immediate { (Immediate::Scalar(scalar), Abi::Scalar(s)) => { assert_eq!(scalar.size(), s.size(cx)); if !matches!(s.primitive(), abi::Pointer(..)) { + // This is not a pointer, it should not carry provenance. assert!(matches!(scalar, Scalar::Int(..))); } } @@ -149,7 +150,7 @@ impl Immediate { } Immediate::Uninit => {} } - Ok(()) + interp_ok(()) } } @@ -307,7 +308,7 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> { data_size: s.size().bytes(), })); } - Ok(s) + interp_ok(s) } #[inline] @@ -430,7 +431,7 @@ impl<'tcx, Prov: Provenance> Projectable<'tcx, Prov> for ImmTy<'tcx, Prov> { ecx: &InterpCx<'tcx, M>, ) -> InterpResult<'tcx, Self> { assert_matches!(meta, MemPlaceMeta::None); // we can't store this anywhere anyway - Ok(self.offset_(offset, layout, ecx)) + interp_ok(self.offset_(offset, layout, ecx)) } #[inline(always)] @@ -438,7 +439,7 @@ impl<'tcx, Prov: Provenance> Projectable<'tcx, Prov> for ImmTy<'tcx, Prov> { &self, _ecx: &InterpCx<'tcx, M>, ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { - Ok(self.clone().into()) + interp_ok(self.clone().into()) } } @@ -514,11 +515,13 @@ impl<'tcx, Prov: Provenance> Projectable<'tcx, Prov> for OpTy<'tcx, Prov> { ecx: &InterpCx<'tcx, M>, ) -> InterpResult<'tcx, Self> { match self.as_mplace_or_imm() { - Left(mplace) => Ok(mplace.offset_with_meta(offset, mode, meta, layout, ecx)?.into()), + Left(mplace) => { + interp_ok(mplace.offset_with_meta(offset, mode, meta, layout, ecx)?.into()) + } Right(imm) => { assert_matches!(meta, MemPlaceMeta::None); // no place to store metadata here // Every part of an uninit is uninit. - Ok(imm.offset_(offset, layout, ecx).into()) + interp_ok(imm.offset_(offset, layout, ecx).into()) } } } @@ -528,7 +531,7 @@ impl<'tcx, Prov: Provenance> Projectable<'tcx, Prov> for OpTy<'tcx, Prov> { &self, _ecx: &InterpCx<'tcx, M>, ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { - Ok(self.clone()) + interp_ok(self.clone()) } } @@ -543,12 +546,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { ) -> InterpResult<'tcx, Option>> { if mplace.layout.is_unsized() { // Don't touch unsized - return Ok(None); + return interp_ok(None); } let Some(alloc) = self.get_place_alloc(mplace)? else { // zero-sized type can be left uninit - return Ok(Some(ImmTy::uninit(mplace.layout))); + return interp_ok(Some(ImmTy::uninit(mplace.layout))); }; // It may seem like all types with `Scalar` or `ScalarPair` ABI are fair game at this point. @@ -557,7 +560,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // case where some of the bytes are initialized and others are not. So, we need an extra // check that walks over the type of `mplace` to make sure it is truly correct to treat this // like a `Scalar` (or `ScalarPair`). - Ok(match mplace.layout.abi { + interp_ok(match mplace.layout.abi { Abi::Scalar(abi::Scalar::Initialized { value: s, .. }) => { let size = s.size(self); assert_eq!(size, mplace.layout.size, "abi::Scalar size does not match layout size"); @@ -606,7 +609,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { &self, src: &impl Projectable<'tcx, M::Provenance>, ) -> InterpResult<'tcx, Either, ImmTy<'tcx, M::Provenance>>> { - Ok(match src.to_op(self)?.as_mplace_or_imm() { + interp_ok(match src.to_op(self)?.as_mplace_or_imm() { Left(ref mplace) => { if let Some(val) = self.read_immediate_from_mplace_raw(mplace)? { Right(val) @@ -637,7 +640,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { if matches!(*imm, Immediate::Uninit) { throw_ub!(InvalidUninitBytes(None)); } - Ok(imm) + interp_ok(imm) } /// Read a scalar from a place @@ -645,7 +648,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { &self, op: &impl Projectable<'tcx, M::Provenance>, ) -> InterpResult<'tcx, Scalar> { - Ok(self.read_immediate(op)?.to_scalar()) + interp_ok(self.read_immediate(op)?.to_scalar()) } // Pointer-sized reads are fairly common and need target layout access, so we wrap them in @@ -678,7 +681,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let len = mplace.len(self)?; let bytes = self.read_bytes_ptr_strip_provenance(mplace.ptr(), Size::from_bytes(len))?; let str = std::str::from_utf8(bytes).map_err(|err| err_ub!(InvalidStr(err)))?; - Ok(str) + interp_ok(str) } /// Read from a local of the current frame. @@ -698,7 +701,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { assert!(!layout.is_unsized()); } M::after_local_read(self, local)?; - Ok(OpTy { op, layout }) + interp_ok(OpTy { op, layout }) } /// Every place can be read from, so we can turn them into an operand. @@ -709,12 +712,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { place: &PlaceTy<'tcx, M::Provenance>, ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { match place.as_mplace_or_local() { - Left(mplace) => Ok(mplace.into()), + Left(mplace) => interp_ok(mplace.into()), Right((local, offset, locals_addr, _)) => { debug_assert!(place.layout.is_sized()); // only sized locals can ever be `Place::Local`. debug_assert_eq!(locals_addr, self.frame().locals_addr()); let base = self.local_to_op(local, None)?; - Ok(match offset { + interp_ok(match offset { Some(offset) => base.offset(offset, place.layout, self)?, None => { // In the common case this hasn't been projected. @@ -764,7 +767,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { ) } } - Ok(op) + interp_ok(op) } /// Evaluate the operand, returning a place where you can then find the data. @@ -794,7 +797,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } }; trace!("{:?}: {:?}", mir_op, op); - Ok(op) + interp_ok(op) } pub(crate) fn const_val_to_op( @@ -805,12 +808,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { // Other cases need layout. let adjust_scalar = |scalar| -> InterpResult<'tcx, _> { - Ok(match scalar { + interp_ok(match scalar { Scalar::Ptr(ptr, size) => Scalar::Ptr(self.global_root_pointer(ptr)?, size), Scalar::Int(int) => Scalar::Int(int), }) }; - let layout = from_known_layout(self.tcx, self.param_env, layout, || self.layout_of(ty))?; + let layout = + from_known_layout(self.tcx, self.param_env, layout, || self.layout_of(ty).into())?; let imm = match val_val { mir::ConstValue::Indirect { alloc_id, offset } => { // This is const data, no mutation allowed. @@ -818,7 +822,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { CtfeProvenance::from(alloc_id).as_immutable(), offset, ))?; - return Ok(self.ptr_to_mplace(ptr.into(), layout).into()); + return interp_ok(self.ptr_to_mplace(ptr.into(), layout).into()); } mir::ConstValue::Scalar(x) => adjust_scalar(x)?.into(), mir::ConstValue::ZeroSized => Immediate::Uninit, @@ -829,7 +833,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { Immediate::new_slice(self.global_root_pointer(ptr)?.into(), meta, self) } }; - Ok(OpTy { op: Operand::Immediate(imm), layout }) + interp_ok(OpTy { op: Operand::Immediate(imm), layout }) } } diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs index 863b330a74cd..52cd9b898bb7 100644 --- a/compiler/rustc_const_eval/src/interpret/operator.rs +++ b/compiler/rustc_const_eval/src/interpret/operator.rs @@ -9,7 +9,7 @@ use rustc_span::symbol::sym; use rustc_target::abi::Size; use tracing::trace; -use super::{ImmTy, InterpCx, Machine, MemPlaceMeta, throw_ub}; +use super::{ImmTy, InterpCx, Machine, MemPlaceMeta, interp_ok, throw_ub}; impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { fn three_way_compare(&self, lhs: T, rhs: T) -> ImmTy<'tcx, M::Provenance> { @@ -156,7 +156,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { }); } - return Ok(ImmTy::from_scalar_int(result, left.layout)); + return interp_ok(ImmTy::from_scalar_int(result, left.layout)); } // For the remaining ops, the types must be the same on both sides @@ -181,10 +181,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { _ => None, }; if let Some(op) = op { - return Ok(ImmTy::from_bool(op(&l_signed(), &r_signed()), *self.tcx)); + return interp_ok(ImmTy::from_bool(op(&l_signed(), &r_signed()), *self.tcx)); } if bin_op == Cmp { - return Ok(self.three_way_compare(l_signed(), r_signed())); + return interp_ok(self.three_way_compare(l_signed(), r_signed())); } let op: Option (i128, bool)> = match bin_op { Div if r.is_null() => throw_ub!(DivisionByZero), @@ -221,7 +221,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { throw_ub!(ArithOverflow { intrinsic }); } let res = ImmTy::from_scalar_int(result, left.layout); - return Ok(if with_overflow { + return interp_ok(if with_overflow { let overflow = ImmTy::from_bool(overflow, *self.tcx); ImmTy::from_pair(res, overflow, *self.tcx) } else { @@ -234,10 +234,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let r = r_unsigned(); if bin_op == Cmp { - return Ok(self.three_way_compare(l, r)); + return interp_ok(self.three_way_compare(l, r)); } - Ok(match bin_op { + interp_ok(match bin_op { Eq => ImmTy::from_bool(l == r, *self.tcx), Ne => ImmTy::from_bool(l != r, *self.tcx), @@ -339,7 +339,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { throw_ub!(PointerArithOverflow) } let offset_ptr = self.ptr_offset_inbounds(ptr, offset_bytes)?; - Ok(ImmTy::from_scalar(Scalar::from_maybe_pointer(offset_ptr, self), left.layout)) + interp_ok(ImmTy::from_scalar( + Scalar::from_maybe_pointer(offset_ptr, self), + left.layout, + )) } // Fall back to machine hook so Miri can support more pointer ops. @@ -366,20 +369,20 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { assert_eq!(left.layout.ty, right.layout.ty); let left = left.to_scalar(); let right = right.to_scalar(); - Ok(self.binary_char_op(bin_op, left.to_char()?, right.to_char()?)) + interp_ok(self.binary_char_op(bin_op, left.to_char()?, right.to_char()?)) } ty::Bool => { assert_eq!(left.layout.ty, right.layout.ty); let left = left.to_scalar(); let right = right.to_scalar(); - Ok(self.binary_bool_op(bin_op, left.to_bool()?, right.to_bool()?)) + interp_ok(self.binary_bool_op(bin_op, left.to_bool()?, right.to_bool()?)) } ty::Float(fty) => { assert_eq!(left.layout.ty, right.layout.ty); let layout = left.layout; let left = left.to_scalar(); let right = right.to_scalar(); - Ok(match fty { + interp_ok(match fty { FloatTy::F16 => { self.binary_float_op(bin_op, layout, left.to_f16()?, right.to_f16()?) } @@ -447,7 +450,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { Not => !val, _ => span_bug!(self.cur_span(), "Invalid bool op {:?}", un_op), }; - Ok(ImmTy::from_bool(res, *self.tcx)) + interp_ok(ImmTy::from_bool(res, *self.tcx)) } ty::Float(fty) => { let val = val.to_scalar(); @@ -462,7 +465,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { FloatTy::F64 => Scalar::from_f64(-val.to_f64()?), FloatTy::F128 => Scalar::from_f128(-val.to_f128()?), }; - Ok(ImmTy::from_scalar(res, layout)) + interp_ok(ImmTy::from_scalar(res, layout)) } ty::Int(..) => { let val = val.to_scalar().to_int(layout.size)?; @@ -472,7 +475,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { _ => span_bug!(self.cur_span(), "Invalid integer op {:?}", un_op), }; let res = ScalarInt::truncate_from_int(res, layout.size).0; - Ok(ImmTy::from_scalar(res.into(), layout)) + interp_ok(ImmTy::from_scalar(res.into(), layout)) } ty::Uint(..) => { let val = val.to_scalar().to_uint(layout.size)?; @@ -481,12 +484,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { _ => span_bug!(self.cur_span(), "Invalid unsigned integer op {:?}", un_op), }; let res = ScalarInt::truncate_from_uint(res, layout.size).0; - Ok(ImmTy::from_scalar(res.into(), layout)) + interp_ok(ImmTy::from_scalar(res.into(), layout)) } ty::RawPtr(..) | ty::Ref(..) => { assert_eq!(un_op, PtrMetadata); let (_, meta) = val.to_scalar_and_meta(); - Ok(match meta { + interp_ok(match meta { MemPlaceMeta::Meta(scalar) => { let ty = un_op.ty(*self.tcx, val.layout.ty); let layout = self.layout_of(ty)?; @@ -514,7 +517,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let layout = self.layout_of(arg_ty)?; let usize_layout = || self.layout_of(self.tcx.types.usize).unwrap(); - Ok(match null_op { + interp_ok(match null_op { SizeOf => { if !layout.abi.is_sized() { span_bug!(self.cur_span(), "unsized type for `NullaryOp::SizeOf`"); diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index 32f90254a947..49656e10f2a2 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -15,7 +15,7 @@ use tracing::{instrument, trace}; use super::{ AllocRef, AllocRefMut, CheckAlignMsg, CtfeProvenance, ImmTy, Immediate, InterpCx, InterpResult, Machine, MemoryKind, Misalignment, OffsetMode, OpTy, Operand, Pointer, Projectable, Provenance, - Scalar, alloc_range, mir_assign_valid_types, + Scalar, alloc_range, interp_ok, mir_assign_valid_types, }; #[derive(Copy, Clone, Hash, PartialEq, Eq, Debug)] @@ -90,7 +90,7 @@ impl MemPlace { } OffsetMode::Wrapping => self.ptr.wrapping_offset(offset, ecx), }; - Ok(MemPlace { ptr, meta, misaligned: self.misaligned }) + interp_ok(MemPlace { ptr, meta, misaligned: self.misaligned }) } } @@ -163,7 +163,10 @@ impl<'tcx, Prov: Provenance> Projectable<'tcx, Prov> for MPlaceTy<'tcx, Prov> { layout: TyAndLayout<'tcx>, ecx: &InterpCx<'tcx, M>, ) -> InterpResult<'tcx, Self> { - Ok(MPlaceTy { mplace: self.mplace.offset_with_meta_(offset, mode, meta, ecx)?, layout }) + interp_ok(MPlaceTy { + mplace: self.mplace.offset_with_meta_(offset, mode, meta, ecx)?, + layout, + }) } #[inline(always)] @@ -171,7 +174,7 @@ impl<'tcx, Prov: Provenance> Projectable<'tcx, Prov> for MPlaceTy<'tcx, Prov> { &self, _ecx: &InterpCx<'tcx, M>, ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> { - Ok(self.clone().into()) + interp_ok(self.clone().into()) } } @@ -279,7 +282,7 @@ impl<'tcx, Prov: Provenance> Projectable<'tcx, Prov> for PlaceTy<'tcx, Prov> { layout: TyAndLayout<'tcx>, ecx: &InterpCx<'tcx, M>, ) -> InterpResult<'tcx, Self> { - Ok(match self.as_mplace_or_local() { + interp_ok(match self.as_mplace_or_local() { Left(mplace) => mplace.offset_with_meta(offset, mode, meta, layout, ecx)?.into(), Right((local, old_offset, locals_addr, _)) => { debug_assert!(layout.is_sized(), "unsized locals should live in memory"); @@ -367,7 +370,7 @@ impl<'tcx, Prov: Provenance> Writeable<'tcx, Prov> for MPlaceTy<'tcx, Prov> { &self, _ecx: &mut InterpCx<'tcx, M>, ) -> InterpResult<'tcx, MPlaceTy<'tcx, Prov>> { - Ok(self.clone()) + interp_ok(self.clone()) } } @@ -425,7 +428,7 @@ where // `ref_to_mplace` is called on raw pointers even if they don't actually get dereferenced; // we hence can't call `size_and_align_of` since that asserts more validity than we want. let ptr = ptr.to_pointer(self)?; - Ok(self.ptr_with_meta_to_mplace(ptr, meta, layout, /*unaligned*/ false)) + interp_ok(self.ptr_with_meta_to_mplace(ptr, meta, layout, /*unaligned*/ false)) } /// Turn a mplace into a (thin or wide) mutable raw pointer, pointing to the same space. @@ -437,7 +440,7 @@ where ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> { let imm = mplace.mplace.to_ref(self); let layout = self.layout_of(Ty::new_mut_ptr(self.tcx.tcx, mplace.layout.ty))?; - Ok(ImmTy::from_immediate(imm, layout)) + interp_ok(ImmTy::from_immediate(imm, layout)) } /// Take an operand, representing a pointer, and dereference it to a place. @@ -458,7 +461,7 @@ where trace!("deref to {} on {:?}", val.layout.ty, *val); let mplace = self.ref_to_mplace(&val)?; - Ok(mplace) + interp_ok(mplace) } #[inline] @@ -474,7 +477,7 @@ where // If an access is both OOB and misaligned, we want to see the bounds error. let a = self.get_ptr_alloc(mplace.ptr(), size)?; self.check_misalign(mplace.mplace.misaligned, CheckAlignMsg::BasedOn)?; - Ok(a) + interp_ok(a) } #[inline] @@ -489,10 +492,10 @@ where // We check alignment separately, and raise that error *after* checking everything else. // If an access is both OOB and misaligned, we want to see the bounds error. // However we have to call `check_misalign` first to make the borrow checker happy. - let misalign_err = self.check_misalign(mplace.mplace.misaligned, CheckAlignMsg::BasedOn); - let a = self.get_ptr_alloc_mut(mplace.ptr(), size)?; - misalign_err?; - Ok(a) + let misalign_res = self.check_misalign(mplace.mplace.misaligned, CheckAlignMsg::BasedOn); + // An error from get_ptr_alloc_mut takes precedence. + let (a, ()) = self.get_ptr_alloc_mut(mplace.ptr(), size).and(misalign_res)?; + interp_ok(a) } /// Turn a local in the current frame into a place. @@ -512,7 +515,7 @@ where Operand::Indirect(mplace) => Place::Ptr(*mplace), } }; - Ok(PlaceTy { place, layout }) + interp_ok(PlaceTy { place, layout }) } /// Computes a place. You should only use this if you intend to write into this @@ -549,7 +552,7 @@ where ) } } - Ok(place) + interp_ok(place) } /// Given a place, returns either the underlying mplace or a reference to where the value of @@ -565,7 +568,7 @@ where (&mut Immediate, TyAndLayout<'tcx>, mir::Local), >, > { - Ok(match place.to_place().as_mplace_or_local() { + interp_ok(match place.to_place().as_mplace_or_local() { Left(mplace) => Left(mplace), Right((local, offset, locals_addr, layout)) => { if offset.is_some() { @@ -610,7 +613,7 @@ where )?; } - Ok(()) + interp_ok(()) } /// Write a scalar to a place @@ -652,6 +655,8 @@ where M::after_local_write(self, local, /*storage_live*/ false)?; } // Double-check that the value we are storing and the local fit to each other. + // Things can ge wrong in quite weird ways when this is violated. + // Unfortunately this is too expensive to do in release builds. if cfg!(debug_assertions) { src.assert_matches_abi(local_layout.abi, self); } @@ -660,7 +665,7 @@ where self.write_immediate_to_mplace_no_validate(src, mplace.layout, mplace.mplace)?; } } - Ok(()) + interp_ok(()) } /// Write an immediate to memory. @@ -672,9 +677,9 @@ where layout: TyAndLayout<'tcx>, dest: MemPlace, ) -> InterpResult<'tcx> { - if cfg!(debug_assertions) { - value.assert_matches_abi(layout.abi, self); - } + // We use the sizes from `value` below. + // Ensure that matches the type of the place it is written to. + value.assert_matches_abi(layout.abi, self); // Note that it is really important that the type here is the right one, and matches the // type things are read at. In case `value` is a `ScalarPair`, we don't do any magic here // to handle padding properly, which is only correct if we never look at this data with the @@ -683,7 +688,7 @@ where let tcx = *self.tcx; let Some(mut alloc) = self.get_place_alloc_mut(&MPlaceTy { mplace: dest, layout })? else { // zero-sized access - return Ok(()); + return interp_ok(()); }; match value { @@ -708,7 +713,7 @@ where alloc.write_scalar(alloc_range(Size::ZERO, a_val.size()), a_val)?; alloc.write_scalar(alloc_range(b_offset, b_val.size()), b_val)?; // We don't have to reset padding here, `write_immediate` will anyway do a validation run. - Ok(()) + interp_ok(()) } Immediate::Uninit => alloc.write_uninit_full(), } @@ -729,12 +734,12 @@ where Left(mplace) => { let Some(mut alloc) = self.get_place_alloc_mut(&mplace)? else { // Zero-sized access - return Ok(()); + return interp_ok(()); }; alloc.write_uninit_full()?; } } - Ok(()) + interp_ok(()) } /// Remove all provenance in the given place. @@ -753,12 +758,12 @@ where Left(mplace) => { let Some(mut alloc) = self.get_place_alloc_mut(&mplace)? else { // Zero-sized access - return Ok(()); + return interp_ok(()); }; alloc.clear_provenance()?; } } - Ok(()) + interp_ok(()) } /// Copies the data from an operand to a place. @@ -841,7 +846,7 @@ where )?; } - Ok(()) + interp_ok(()) } /// Copies the data from an operand to a place. @@ -918,7 +923,7 @@ where self.mem_copy(src.ptr(), dest.ptr(), dest_size, /*nonoverlapping*/ true)?; self.check_misalign(src.mplace.misaligned, CheckAlignMsg::BasedOn)?; self.check_misalign(dest.mplace.misaligned, CheckAlignMsg::BasedOn)?; - Ok(()) + interp_ok(()) } /// Ensures that a place is in memory, and returns where it is. @@ -980,7 +985,7 @@ where Place::Ptr(mplace) => mplace, }; // Return with the original layout and align, so that the caller can go on - Ok(MPlaceTy { mplace, layout: place.layout }) + interp_ok(MPlaceTy { mplace, layout: place.layout }) } pub fn allocate_dyn( @@ -993,7 +998,7 @@ where span_bug!(self.cur_span(), "cannot allocate space for `extern` type, size is not known") }; let ptr = self.allocate_ptr(size, align, kind)?; - Ok(self.ptr_with_meta_to_mplace(ptr.into(), meta, layout, /*unaligned*/ false)) + interp_ok(self.ptr_with_meta_to_mplace(ptr.into(), meta, layout, /*unaligned*/ false)) } pub fn allocate( @@ -1028,7 +1033,7 @@ where }; let meta = Scalar::from_target_usize(u64::try_from(str.len()).unwrap(), self); let layout = self.layout_of(self.tcx.types.str_).unwrap(); - Ok(self.ptr_with_meta_to_mplace( + interp_ok(self.ptr_with_meta_to_mplace( ptr.into(), MemPlaceMeta::Meta(meta), layout, @@ -1044,7 +1049,7 @@ where let _ = self.tcx.global_alloc(raw.alloc_id); let ptr = self.global_root_pointer(Pointer::from(raw.alloc_id))?; let layout = self.layout_of(raw.ty)?; - Ok(self.ptr_to_mplace(ptr.into(), layout)) + interp_ok(self.ptr_to_mplace(ptr.into(), layout)) } } diff --git a/compiler/rustc_const_eval/src/interpret/projection.rs b/compiler/rustc_const_eval/src/interpret/projection.rs index 621afdb1050a..cc49d7cebf45 100644 --- a/compiler/rustc_const_eval/src/interpret/projection.rs +++ b/compiler/rustc_const_eval/src/interpret/projection.rs @@ -18,7 +18,7 @@ use tracing::{debug, instrument}; use super::{ InterpCx, InterpResult, MPlaceTy, Machine, MemPlaceMeta, OpTy, Provenance, Scalar, err_ub, - throw_ub, throw_unsup, + interp_ok, throw_ub, throw_unsup, }; /// Describes the constraints placed on offset-projections. @@ -54,7 +54,7 @@ pub trait Projectable<'tcx, Prov: Provenance>: Sized + std::fmt::Debug { // Go through the layout. There are lots of types that support a length, // e.g., SIMD types. (But not all repr(simd) types even have FieldsShape::Array!) match layout.fields { - abi::FieldsShape::Array { count, .. } => Ok(count), + abi::FieldsShape::Array { count, .. } => interp_ok(count), _ => bug!("len not supported on sized type {:?}", layout.ty), } } @@ -115,9 +115,9 @@ impl<'a, 'tcx, Prov: Provenance, P: Projectable<'tcx, Prov>> ArrayIterator<'a, ' &mut self, ecx: &InterpCx<'tcx, M>, ) -> InterpResult<'tcx, Option<(u64, P)>> { - let Some(idx) = self.range.next() else { return Ok(None) }; + let Some(idx) = self.range.next() else { return interp_ok(None) }; // We use `Wrapping` here since the offset has already been checked when the iterator was created. - Ok(Some(( + interp_ok(Some(( idx, self.base.offset_with_meta( self.stride * idx, @@ -258,7 +258,7 @@ where // SIMD types must be newtypes around arrays, so all we have to do is project to their only field. let array = self.project_field(base, 0)?; let len = array.len(self)?; - Ok((array, len)) + interp_ok((array, len)) } fn project_constant_index>( @@ -300,7 +300,13 @@ where debug!("project_array_fields: {base:?} {len}"); base.offset(len * stride, self.layout_of(self.tcx.types.unit).unwrap(), self)?; // Create the iterator. - Ok(ArrayIterator { base, range: 0..len, stride, field_layout, _phantom: PhantomData }) + interp_ok(ArrayIterator { + base, + range: 0..len, + stride, + field_layout, + _phantom: PhantomData, + }) } /// Subslicing @@ -367,7 +373,7 @@ where P: Projectable<'tcx, M::Provenance> + From> + std::fmt::Debug, { use rustc_middle::mir::ProjectionElem::*; - Ok(match proj_elem { + interp_ok(match proj_elem { OpaqueCast(ty) => { span_bug!(self.cur_span(), "OpaqueCast({ty}) encountered after borrowck") } diff --git a/compiler/rustc_const_eval/src/interpret/stack.rs b/compiler/rustc_const_eval/src/interpret/stack.rs index 15868f1b02d9..3bc9f46aea06 100644 --- a/compiler/rustc_const_eval/src/interpret/stack.rs +++ b/compiler/rustc_const_eval/src/interpret/stack.rs @@ -17,7 +17,7 @@ use tracing::{info_span, instrument, trace}; use super::{ AllocId, CtfeProvenance, Immediate, InterpCx, InterpResult, MPlaceTy, Machine, MemPlace, MemPlaceMeta, MemoryKind, Operand, Pointer, Provenance, ReturnAction, Scalar, - from_known_layout, throw_ub, throw_unsup, + from_known_layout, interp_ok, throw_ub, throw_unsup, }; use crate::errors; @@ -189,7 +189,7 @@ impl<'tcx, Prov: Provenance> LocalState<'tcx, Prov> { pub(super) fn access(&self) -> InterpResult<'tcx, &Operand> { match &self.value { LocalValue::Dead => throw_ub!(DeadLocal), // could even be "invalid program"? - LocalValue::Live(val) => Ok(val), + LocalValue::Live(val) => interp_ok(val), } } @@ -199,7 +199,7 @@ impl<'tcx, Prov: Provenance> LocalState<'tcx, Prov> { pub(super) fn access_mut(&mut self) -> InterpResult<'tcx, &mut Operand> { match &mut self.value { LocalValue::Dead => throw_ub!(DeadLocal), // could even be "invalid program"? - LocalValue::Live(val) => Ok(val), + LocalValue::Live(val) => interp_ok(val), } } } @@ -391,7 +391,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let span = info_span!("frame", "{}", instance); self.frame_mut().tracing_span.enter(span); - Ok(()) + interp_ok(()) } /// Low-level helper that pops a stack frame from the stack and returns some information about @@ -426,7 +426,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { return_action = ReturnAction::NoCleanup; }; - Ok(StackPopInfo { return_action, return_to_block, return_place }) + interp_ok(StackPopInfo { return_action, return_to_block, return_place }) } /// A private helper for [`pop_stack_frame_raw`](InterpCx::pop_stack_frame_raw). @@ -449,7 +449,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } } - Ok(cleanup) + interp_ok(cleanup) } /// In the current stack frame, mark all locals as live that are not arguments and don't have @@ -464,7 +464,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { self.storage_live(local)?; } } - Ok(()) + interp_ok(()) } pub fn storage_live_dyn( @@ -550,7 +550,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // If the local is already live, deallocate its old memory. let old = mem::replace(&mut self.frame_mut().locals[local].value, local_val); self.deallocate_local(old)?; - Ok(()) + interp_ok(()) } /// Mark a storage as live, killing the previous content. @@ -566,7 +566,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // If the local is already dead, this is a NOP. let old = mem::replace(&mut self.frame_mut().locals[local].value, LocalValue::Dead); self.deallocate_local(old)?; - Ok(()) + interp_ok(()) } fn deallocate_local(&mut self, local: LocalValue) -> InterpResult<'tcx> { @@ -581,7 +581,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { ); self.deallocate_ptr(ptr, None, MemoryKind::Stack)?; }; - Ok(()) + interp_ok(()) } #[inline(always)] @@ -593,19 +593,19 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { ) -> InterpResult<'tcx, TyAndLayout<'tcx>> { let state = &frame.locals[local]; if let Some(layout) = state.layout.get() { - return Ok(layout); + return interp_ok(layout); } let layout = from_known_layout(self.tcx, self.param_env, layout, || { let local_ty = frame.body.local_decls[local].ty; let local_ty = self.instantiate_from_frame_and_normalize_erasing_regions(frame, local_ty)?; - self.layout_of(local_ty) + self.layout_of(local_ty).into() })?; // Layouts of locals are requested a lot, so we cache them. state.layout.set(Some(layout)); - Ok(layout) + interp_ok(layout) } } diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index 8e2367e0d214..aa7529556754 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -14,7 +14,7 @@ use tracing::{info, instrument, trace}; use super::{ FnArg, FnVal, ImmTy, Immediate, InterpCx, InterpResult, Machine, MemPlaceMeta, PlaceTy, - Projectable, Scalar, throw_ub, + Projectable, Scalar, interp_ok, throw_ub, }; use crate::util; @@ -36,7 +36,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { #[inline(always)] pub fn step(&mut self) -> InterpResult<'tcx, bool> { if self.stack().is_empty() { - return Ok(false); + return interp_ok(false); } let Either::Left(loc) = self.frame().loc else { @@ -44,7 +44,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // Just go on unwinding. trace!("unwinding: skipping frame"); self.return_from_current_stack_frame(/* unwinding */ true)?; - return Ok(true); + return interp_ok(true); }; let basic_block = &self.body().basic_blocks[loc.block]; @@ -55,7 +55,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { assert_eq!(old_frames, self.frame_idx()); // Advance the program counter. self.frame_mut().loc.as_mut().left().unwrap().statement_index += 1; - return Ok(true); + return interp_ok(true); } M::before_terminator(self)?; @@ -67,7 +67,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { info!("// executing {:?}", loc.block); } } - Ok(true) + interp_ok(true) } /// Runs the interpretation logic for the given `mir::Statement` at the current frame and @@ -145,7 +145,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { Nop => {} } - Ok(()) + interp_ok(()) } /// Evaluate an assignment statement. @@ -277,7 +277,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { trace!("{:?}", self.dump_place(&dest)); - Ok(()) + interp_ok(()) } /// Writes the aggregate to the destination. @@ -313,7 +313,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let ptr_imm = Immediate::new_pointer_with_meta(data, meta, self); let ptr = ImmTy::from_immediate(ptr_imm, dest.layout); self.copy_op(&ptr, dest)?; - return Ok(()); + return interp_ok(()); } _ => (FIRST_VARIANT, dest.clone(), None), }; @@ -365,7 +365,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { )?; } - Ok(()) + interp_ok(()) } /// Evaluate the arguments of a function call @@ -373,7 +373,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { &self, op: &mir::Operand<'tcx>, ) -> InterpResult<'tcx, FnArg<'tcx, M::Provenance>> { - Ok(match op { + interp_ok(match op { mir::Operand::Copy(_) | mir::Operand::Constant(_) => { // Make a regular copy. let op = self.eval_operand(op, None)?; @@ -442,7 +442,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } }; - Ok(EvaluatedCalleeAndArgs { callee, args, fn_sig, fn_abi, with_caller_location }) + interp_ok(EvaluatedCalleeAndArgs { callee, args, fn_sig, fn_abi, with_caller_location }) } fn eval_terminator(&mut self, terminator: &mir::Terminator<'tcx>) -> InterpResult<'tcx> { @@ -537,7 +537,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // generic. In order to make sure that generic and non-generic code behaves // roughly the same (and in keeping with Mir semantics) we do nothing here. self.go_to_block(target); - return Ok(()); + return interp_ok(()); } trace!("TerminatorKind::drop: {:?}, type {}", place, place.layout.ty); self.init_drop_in_place_call(&place, instance, target, unwind)?; @@ -566,7 +566,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // By definition, a Resume terminator means // that we're unwinding self.return_from_current_stack_frame(/* unwinding */ true)?; - return Ok(()); + return interp_ok(()); } // It is UB to ever encounter this. @@ -584,6 +584,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } } - Ok(()) + interp_ok(()) } } diff --git a/compiler/rustc_const_eval/src/interpret/traits.rs b/compiler/rustc_const_eval/src/interpret/traits.rs index 8eead6018ac4..da7d6853c0ea 100644 --- a/compiler/rustc_const_eval/src/interpret/traits.rs +++ b/compiler/rustc_const_eval/src/interpret/traits.rs @@ -5,7 +5,9 @@ use rustc_target::abi::{Align, Size}; use tracing::trace; use super::util::ensure_monomorphic_enough; -use super::{InterpCx, MPlaceTy, Machine, MemPlaceMeta, OffsetMode, Projectable, throw_ub}; +use super::{ + InterpCx, MPlaceTy, Machine, MemPlaceMeta, OffsetMode, Projectable, interp_ok, throw_ub, +}; impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { /// Creates a dynamic vtable for the given type and vtable origin. This is used only for @@ -31,7 +33,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let salt = M::get_global_alloc_salt(self, None); let vtable_symbolic_allocation = self.tcx.reserve_and_set_vtable_alloc(ty, dyn_ty, salt); let vtable_ptr = self.global_root_pointer(Pointer::from(vtable_symbolic_allocation))?; - Ok(vtable_ptr.into()) + interp_ok(vtable_ptr.into()) } pub fn get_vtable_size_and_align( @@ -42,7 +44,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let ty = self.get_ptr_vtable_ty(vtable, expected_trait)?; let layout = self.layout_of(ty)?; assert!(layout.is_sized(), "there are no vtables for unsized types"); - Ok((layout.size, layout.align.abi)) + interp_ok((layout.size, layout.align.abi)) } pub(super) fn vtable_entries( @@ -102,7 +104,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } } - Ok(()) + interp_ok(()) } /// Turn a place with a `dyn Trait` type into a place with the actual dynamic type. @@ -127,7 +129,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { layout, self, )?; - Ok(mplace) + interp_ok(mplace) } /// Turn a `dyn* Trait` type into an value with the actual dynamic type. @@ -147,6 +149,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // `data` is already the right thing but has the wrong type. So we transmute it. let layout = self.layout_of(ty)?; let data = data.transmute(layout, self)?; - Ok(data) + interp_ok(data) } } diff --git a/compiler/rustc_const_eval/src/interpret/util.rs b/compiler/rustc_const_eval/src/interpret/util.rs index 2d53badf0f96..8bb5f173a564 100644 --- a/compiler/rustc_const_eval/src/interpret/util.rs +++ b/compiler/rustc_const_eval/src/interpret/util.rs @@ -9,7 +9,7 @@ use rustc_middle::ty::{ }; use tracing::debug; -use super::{InterpCx, MPlaceTy, MemoryKind, throw_inval}; +use super::{InterpCx, MPlaceTy, MemoryKind, interp_ok, throw_inval}; use crate::const_eval::{CompileTimeInterpCx, CompileTimeMachine, InterpretationResult}; /// Checks whether a type contains generic parameters which must be instantiated. @@ -23,7 +23,7 @@ where { debug!("ensure_monomorphic_enough: ty={:?}", ty); if !ty.has_param() { - return Ok(()); + return interp_ok(()); } struct FoundParam; @@ -78,7 +78,7 @@ where if matches!(ty.visit_with(&mut vis), ControlFlow::Break(FoundParam)) { throw_inval!(TooGeneric); } else { - Ok(()) + interp_ok(()) } } @@ -103,5 +103,5 @@ pub(crate) fn create_static_alloc<'tcx>( assert_eq!(ecx.machine.static_root_ids, None); ecx.machine.static_root_ids = Some((alloc_id, static_def_id)); assert!(ecx.memory.alloc_map.insert(alloc_id, (MemoryKind::Stack, alloc)).is_none()); - Ok(ecx.ptr_to_mplace(Pointer::from(alloc_id).into(), layout)) + interp_ok(ecx.ptr_to_mplace(Pointer::from(alloc_id).into(), layout)) } diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index 203cceccd9d1..13641ef2bd3f 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -17,8 +17,8 @@ use rustc_hir as hir; use rustc_middle::bug; use rustc_middle::mir::interpret::ValidationErrorKind::{self, *}; use rustc_middle::mir::interpret::{ - ExpectedKind, InterpError, InvalidMetaKind, Misalignment, PointerKind, Provenance, - UnsupportedOpInfo, ValidationErrorInfo, alloc_range, + ExpectedKind, InterpError, InterpErrorInfo, InvalidMetaKind, Misalignment, PointerKind, + Provenance, UnsupportedOpInfo, ValidationErrorInfo, alloc_range, interp_ok, }; use rustc_middle::ty::layout::{LayoutCx, LayoutOf, TyAndLayout}; use rustc_middle::ty::{self, Ty}; @@ -32,7 +32,7 @@ use super::machine::AllocMap; use super::{ AllocId, AllocKind, CheckInAllocMsg, GlobalAlloc, ImmTy, Immediate, InterpCx, InterpResult, MPlaceTy, Machine, MemPlaceMeta, PlaceTy, Pointer, Projectable, Scalar, ValueVisitor, err_ub, - format_interp_error, throw_ub, + format_interp_error, }; // for the validation errors @@ -42,7 +42,7 @@ use super::InterpError::Unsupported as Unsup; use super::UndefinedBehaviorInfo::*; use super::UnsupportedOpInfo::*; -macro_rules! throw_validation_failure { +macro_rules! err_validation_failure { ($where:expr, $kind: expr) => {{ let where_ = &$where; let path = if !where_.is_empty() { @@ -53,10 +53,16 @@ macro_rules! throw_validation_failure { None }; - throw_ub!(ValidationError(ValidationErrorInfo { path, kind: $kind })) + err_ub!(ValidationError(ValidationErrorInfo { path, kind: $kind })) }}; } +macro_rules! throw_validation_failure { + ($where:expr, $kind: expr) => { + do yeet err_validation_failure!($where, $kind) + }; +} + /// If $e throws an error matching the pattern, throw a validation failure. /// Other errors are passed back to the caller, unchanged -- and if they reach the root of /// the visitor, we make sure only validation errors and `InvalidProgram` errors are left. @@ -91,22 +97,22 @@ macro_rules! try_validation { ($e:expr, $where:expr, $( $( $p:pat_param )|+ => $kind: expr ),+ $(,)? ) => {{ - match $e { - Ok(x) => x, + $e.map_err(|e| { // We catch the error and turn it into a validation failure. We are okay with // allocation here as this can only slow down builds that fail anyway. - Err(e) => match e.kind() { + let (kind, backtrace) = e.into_parts(); + match kind { $( - $($p)|+ => - throw_validation_failure!( + $($p)|+ => { + err_validation_failure!( $where, $kind - ) + ).into() + } ),+, - #[allow(unreachable_patterns)] - _ => Err::(e)?, + _ => InterpErrorInfo::from_parts(kind, backtrace), } - } + })? }}; } @@ -378,7 +384,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { // Undo changes self.path.truncate(path_len); // Done - Ok(r) + interp_ok(r) } fn read_immediate( @@ -386,7 +392,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { val: &PlaceTy<'tcx, M::Provenance>, expected: ExpectedKind, ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> { - Ok(try_validation!( + interp_ok(try_validation!( self.ecx.read_immediate(val), self.path, Ub(InvalidUninitBytes(None)) => @@ -404,7 +410,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { val: &PlaceTy<'tcx, M::Provenance>, expected: ExpectedKind, ) -> InterpResult<'tcx, Scalar> { - Ok(self.read_immediate(val, expected)?.to_scalar()) + interp_ok(self.read_immediate(val, expected)?.to_scalar()) } fn deref_pointer( @@ -469,7 +475,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { _ => bug!("Unexpected unsized type tail: {:?}", tail), } - Ok(()) + interp_ok(()) } /// Check a reference or `Box`. @@ -510,7 +516,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { Ub(DanglingIntPointer { addr: i, .. }) => DanglingPtrNoProvenance { ptr_kind, // FIXME this says "null pointer" when null but we need translate - pointer: format!("{}", Pointer::>::from_addr_invalid(*i)) + pointer: format!("{}", Pointer::>::from_addr_invalid(i)) }, Ub(PointerOutOfBounds { .. }) => DanglingPtrOutOfBounds { ptr_kind @@ -632,7 +638,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { } // Potentially skip recursive check. if skip_recursive_check { - return Ok(()); + return interp_ok(()); } } else { // This is not CTFE, so it's Miri with recursive checking. @@ -641,7 +647,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { // FIXME: should we also skip `UnsafeCell` behind shared references? Currently that is not // needed since validation reads bypass Stacked Borrows and data race checks. if matches!(ptr_kind, PointerKind::Box) { - return Ok(()); + return interp_ok(()); } } let path = &self.path; @@ -654,7 +660,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { new_path }); } - Ok(()) + interp_ok(()) } /// Check if this is a value of primitive type, and if yes check the validity of the value @@ -681,7 +687,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { self.ecx.clear_provenance(value)?; self.add_data_range_place(value); } - Ok(true) + interp_ok(true) } ty::Char => { let scalar = self.read_scalar(value, ExpectedKind::Char)?; @@ -696,7 +702,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { self.ecx.clear_provenance(value)?; self.add_data_range_place(value); } - Ok(true) + interp_ok(true) } ty::Float(_) | ty::Int(_) | ty::Uint(_) => { // NOTE: Keep this in sync with the array optimization for int/float @@ -713,18 +719,18 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { self.ecx.clear_provenance(value)?; self.add_data_range_place(value); } - Ok(true) + interp_ok(true) } ty::RawPtr(..) => { let place = self.deref_pointer(value, ExpectedKind::RawPtr)?; if place.layout.is_unsized() { self.check_wide_ptr_meta(place.meta(), place.layout)?; } - Ok(true) + interp_ok(true) } ty::Ref(_, _ty, mutbl) => { self.check_safe_pointer(value, PointerKind::Ref(*mutbl))?; - Ok(true) + interp_ok(true) } ty::FnPtr(..) => { let scalar = self.read_scalar(value, ExpectedKind::FnPtr)?; @@ -753,12 +759,12 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { } self.add_data_range_place(value); } - Ok(true) + interp_ok(true) } ty::Never => throw_validation_failure!(self.path, NeverVal), ty::Foreign(..) | ty::FnDef(..) => { // Nothing to check. - Ok(true) + interp_ok(true) } // The above should be all the primitive types. The rest is compound, we // check them by visiting their fields/variants. @@ -771,7 +777,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { | ty::Closure(..) | ty::Pat(..) | ty::CoroutineClosure(..) - | ty::Coroutine(..) => Ok(false), + | ty::Coroutine(..) => interp_ok(false), // Some types only occur during typechecking, they have no layout. // We should not see them here and we could not check them anyway. ty::Error(_) @@ -808,11 +814,11 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { max_value }) } else { - return Ok(()); + return interp_ok(()); } } else if scalar_layout.is_always_valid(self.ecx) { // Easy. (This is reachable if `enforce_number_validity` is set.) - return Ok(()); + return interp_ok(()); } else { // Conservatively, we reject, because the pointer *could* have a bad // value. @@ -825,7 +831,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { }; // Now compare. if valid_range.contains(bits) { - Ok(()) + interp_ok(()) } else { throw_validation_failure!(self.path, OutOfRange { value: format!("{bits}"), @@ -884,7 +890,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { } fn reset_padding(&mut self, place: &PlaceTy<'tcx, M::Provenance>) -> InterpResult<'tcx> { - let Some(data_bytes) = self.data_bytes.as_mut() else { return Ok(()) }; + let Some(data_bytes) = self.data_bytes.as_mut() else { return interp_ok(()) }; // Our value must be in memory, otherwise we would not have set up `data_bytes`. let mplace = self.ecx.force_allocation(place)?; // Determine starting offset and size. @@ -896,14 +902,14 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { // If there is no padding at all, we can skip the rest: check for // a single data range covering the entire value. if data_bytes.0 == &[(start_offset, size)] { - return Ok(()); + return interp_ok(()); } // Get a handle for the allocation. Do this only once, to avoid looking up the same // allocation over and over again. (Though to be fair, iterating the value already does // exactly that.) let Some(mut alloc) = self.ecx.get_ptr_alloc_mut(mplace.ptr(), size)? else { // A ZST, no padding to clear. - return Ok(()); + return interp_ok(()); }; // Add a "finalizer" data range at the end, so that the iteration below finds all gaps // between ranges. @@ -930,7 +936,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { padding_cleared_until = offset + size; } assert!(padding_cleared_until == start_offset + size); - Ok(()) + interp_ok(()) } /// Computes the data range of this union type: @@ -1070,7 +1076,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt, val: &PlaceTy<'tcx, M::Provenance>, ) -> InterpResult<'tcx, VariantIdx> { self.with_elem(PathElem::EnumTag, move |this| { - Ok(try_validation!( + interp_ok(try_validation!( this.ecx.read_discriminant(val), this.path, Ub(InvalidTag(val)) => InvalidEnumTag { @@ -1134,7 +1140,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt, data_bytes.add_range(base_offset + offset, size); } } - Ok(()) + interp_ok(()) } #[inline] @@ -1144,7 +1150,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt, val: &PlaceTy<'tcx, M::Provenance>, ) -> InterpResult<'tcx> { self.check_safe_pointer(val, PointerKind::Box)?; - Ok(()) + interp_ok(()) } #[inline] @@ -1157,7 +1163,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt, // We assume that the Scalar validity range does not restrict these values // any further than `try_visit_primitive` does! if self.try_visit_primitive(val)? { - return Ok(()); + return interp_ok(()); } // Special check preventing `UnsafeCell` in the inner part of constants @@ -1204,7 +1210,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt, // If the size is 0, there is nothing to check. // (`size` can only be 0 if `len` is 0, and empty arrays are always valid.) if size == Size::ZERO { - return Ok(()); + return interp_ok(()); } // Now that we definitely have a non-ZST array, we know it lives in memory -- except it may // be an uninitialized local variable, those are also "immediate". @@ -1224,36 +1230,33 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt, // No need for an alignment check here, this is not an actual memory access. let alloc = self.ecx.get_ptr_alloc(mplace.ptr(), size)?.expect("we already excluded size 0"); - match alloc.get_bytes_strip_provenance() { - // In the happy case, we needn't check anything else. - Ok(_) => {} + alloc.get_bytes_strip_provenance().map_err(|err| { // Some error happened, try to provide a more detailed description. - Err(err) => { - // For some errors we might be able to provide extra information. - // (This custom logic does not fit the `try_validation!` macro.) - match err.kind() { - Ub(InvalidUninitBytes(Some((_alloc_id, access)))) | Unsup(ReadPointerAsInt(Some((_alloc_id, access)))) => { - // Some byte was uninitialized, determine which - // element that byte belongs to so we can - // provide an index. - let i = usize::try_from( - access.bad.start.bytes() / layout.size.bytes(), - ) - .unwrap(); - self.path.push(PathElem::ArrayElem(i)); + // For some errors we might be able to provide extra information. + // (This custom logic does not fit the `try_validation!` macro.) + let (kind, backtrace) = err.into_parts(); + match kind { + Ub(InvalidUninitBytes(Some((_alloc_id, access)))) | Unsup(ReadPointerAsInt(Some((_alloc_id, access)))) => { + // Some byte was uninitialized, determine which + // element that byte belongs to so we can + // provide an index. + let i = usize::try_from( + access.bad.start.bytes() / layout.size.bytes(), + ) + .unwrap(); + self.path.push(PathElem::ArrayElem(i)); - if matches!(err.kind(), Ub(InvalidUninitBytes(_))) { - throw_validation_failure!(self.path, Uninit { expected }) - } else { - throw_validation_failure!(self.path, PointerAsInt { expected }) - } + if matches!(kind, Ub(InvalidUninitBytes(_))) { + err_validation_failure!(self.path, Uninit { expected }).into() + } else { + err_validation_failure!(self.path, PointerAsInt { expected }).into() } - - // Propagate upwards (that will also check for unexpected errors). - _ => return Err(err), } + + // Propagate upwards (that will also check for unexpected errors). + _ => return InterpErrorInfo::from_parts(kind, backtrace), } - } + })?; // Don't forget that these are all non-pointer types, and thus do not preserve // provenance. @@ -1282,7 +1285,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt, // It's not great to catch errors here, since we can't give a very good path, // but it's better than ICEing. Ub(InvalidVTableTrait { vtable_dyn_type, expected_dyn_type }) => { - InvalidMetaWrongTrait { vtable_dyn_type, expected_dyn_type: *expected_dyn_type } + InvalidMetaWrongTrait { vtable_dyn_type, expected_dyn_type } }, ); } @@ -1331,7 +1334,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValueVisitor<'tcx, M> for ValidityVisitor<'rt, } } - Ok(()) + interp_ok(()) } } @@ -1347,7 +1350,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { trace!("validate_operand_internal: {:?}, {:?}", *val, val.layout.ty); // Run the visitor. - match self.run_for_validation(|ecx| { + self.run_for_validation(|ecx| { let reset_padding = reset_provenance_and_padding && { // Check if `val` is actually stored in memory. If not, padding is not even // represented and we need not reset it. @@ -1363,29 +1366,22 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { }; v.visit_value(val)?; v.reset_padding(val)?; - InterpResult::Ok(()) - }) { - Ok(()) => Ok(()), - // Pass through validation failures and "invalid program" issues. - Err(err) - if matches!( - err.kind(), - err_ub!(ValidationError { .. }) - | InterpError::InvalidProgram(_) - | InterpError::Unsupported(UnsupportedOpInfo::ExternTypeField) - ) => - { - Err(err) - } - // Complain about any other kind of error -- those are bad because we'd like to - // report them in a way that shows *where* in the value the issue lies. - Err(err) => { + interp_ok(()) + }) + .map_err(|err| { + if !matches!( + err.kind(), + err_ub!(ValidationError { .. }) + | InterpError::InvalidProgram(_) + | InterpError::Unsupported(UnsupportedOpInfo::ExternTypeField) + ) { bug!( "Unexpected error during validation: {}", format_interp_error(self.tcx.dcx(), err) ); } - } + err + }) } /// This function checks the data at `op` to be const-valid. @@ -1456,6 +1452,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { /*reset_provenance_and_padding*/ false, )?; } - Ok(()) + interp_ok(()) } } diff --git a/compiler/rustc_const_eval/src/interpret/visitor.rs b/compiler/rustc_const_eval/src/interpret/visitor.rs index d004a3f08929..647917dbb67e 100644 --- a/compiler/rustc_const_eval/src/interpret/visitor.rs +++ b/compiler/rustc_const_eval/src/interpret/visitor.rs @@ -10,7 +10,7 @@ use rustc_middle::ty::{self, Ty}; use rustc_target::abi::{FieldIdx, FieldsShape, VariantIdx, Variants}; use tracing::trace; -use super::{InterpCx, MPlaceTy, Machine, Projectable, throw_inval}; +use super::{InterpCx, MPlaceTy, Machine, Projectable, interp_ok, throw_inval}; /// How to traverse a value and what to do when we are at the leaves. pub trait ValueVisitor<'tcx, M: Machine<'tcx>>: Sized { @@ -46,14 +46,14 @@ pub trait ValueVisitor<'tcx, M: Machine<'tcx>>: Sized { /// Visits the given value as a union. No automatic recursion can happen here. #[inline(always)] fn visit_union(&mut self, _v: &Self::V, _fields: NonZero) -> InterpResult<'tcx> { - Ok(()) + interp_ok(()) } /// Visits the given value as the pointer of a `Box`. There is nothing to recurse into. /// The type of `v` will be a raw pointer to `T`, but this is a field of `Box` and the /// pointee type is the actual `T`. `box_ty` provides the full type of the `Box` itself. #[inline(always)] fn visit_box(&mut self, _box_ty: Ty<'tcx>, _v: &Self::V) -> InterpResult<'tcx> { - Ok(()) + interp_ok(()) } /// Called each time we recurse down to a field of a "product-like" aggregate @@ -165,7 +165,7 @@ pub trait ValueVisitor<'tcx, M: Machine<'tcx>>: Sized { self.visit_field(v, 1, &alloc)?; // We visited all parts of this one. - return Ok(()); + return interp_ok(()); } // Non-normalized types should never show up here. @@ -222,6 +222,6 @@ pub trait ValueVisitor<'tcx, M: Machine<'tcx>>: Sized { Variants::Single { .. } => {} } - Ok(()) + interp_ok(()) } } diff --git a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs index 19393188c9ad..649179d5b1e0 100644 --- a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs +++ b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs @@ -75,7 +75,8 @@ fn check_validity_requirement_strict<'tcx>( /*recursive*/ false, /*reset_provenance_and_padding*/ false, ) - .is_ok()) + .discard_err() + .is_some()) } /// Implements the 'lax' (default) version of the [`check_validity_requirement`] checks; see that diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml index 38c6c8a8d11c..d73cf11ee64d 100644 --- a/compiler/rustc_data_structures/Cargo.toml +++ b/compiler/rustc_data_structures/Cargo.toml @@ -32,7 +32,7 @@ tracing = "0.1" version = "0.12" [target.'cfg(windows)'.dependencies.windows] -version = "0.52.0" +version = "0.57.0" features = [ "Win32_Foundation", "Win32_Storage_FileSystem", diff --git a/compiler/rustc_data_structures/src/sync.rs b/compiler/rustc_data_structures/src/sync.rs index 6df94bc0e944..a3491dbfec7d 100644 --- a/compiler/rustc_data_structures/src/sync.rs +++ b/compiler/rustc_data_structures/src/sync.rs @@ -437,7 +437,7 @@ impl RwLock { #[inline(always)] pub fn leak(&self) -> &T { let guard = self.read(); - let ret = unsafe { &*std::ptr::addr_of!(*guard) }; + let ret = unsafe { &*(&raw const *guard) }; std::mem::forget(guard); ret } diff --git a/compiler/rustc_driver_impl/Cargo.toml b/compiler/rustc_driver_impl/Cargo.toml index 6d6d3f35a4b1..ef577c032189 100644 --- a/compiler/rustc_driver_impl/Cargo.toml +++ b/compiler/rustc_driver_impl/Cargo.toml @@ -59,7 +59,7 @@ libc = "0.2" # tidy-alphabetical-end [target.'cfg(windows)'.dependencies.windows] -version = "0.52.0" +version = "0.57.0" features = [ "Win32_System_Diagnostics_Debug", ] diff --git a/compiler/rustc_error_codes/src/error_codes/E0013.md b/compiler/rustc_error_codes/src/error_codes/E0013.md index 9f4848343ff1..c4d65225ece9 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0013.md +++ b/compiler/rustc_error_codes/src/error_codes/E0013.md @@ -5,7 +5,7 @@ variable cannot refer to a static variable. Erroneous code example: -```compile_fail,E0658 +``` static X: i32 = 42; const Y: i32 = X; ``` diff --git a/compiler/rustc_error_codes/src/error_codes/E0038.md b/compiler/rustc_error_codes/src/error_codes/E0038.md index 8f8eabb15190..014d8c4f761c 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0038.md +++ b/compiler/rustc_error_codes/src/error_codes/E0038.md @@ -5,9 +5,9 @@ trait, written in type positions) but this was a bit too confusing, so we now write `dyn Trait`. Some traits are not allowed to be used as trait object types. The traits that -are allowed to be used as trait object types are called "object-safe" traits. -Attempting to use a trait object type for a trait that is not object-safe will -trigger error E0038. +are allowed to be used as trait object types are called "dyn-compatible"[^1] +traits. Attempting to use a trait object type for a trait that is not +dyn-compatible will trigger error E0038. Two general aspects of trait object types give rise to the restrictions: @@ -25,13 +25,16 @@ Two general aspects of trait object types give rise to the restrictions: objects with the same trait object type may point to vtables from different implementations. -The specific conditions that violate object-safety follow, most of which relate -to missing size information and vtable polymorphism arising from these aspects. +The specific conditions that violate dyn-compatibility follow, most of which +relate to missing size information and vtable polymorphism arising from these +aspects. + +[^1]: Formerly known as "object-safe". ### The trait requires `Self: Sized` Traits that are declared as `Trait: Sized` or which otherwise inherit a -constraint of `Self:Sized` are not object-safe. +constraint of `Self:Sized` are not dyn-compatible. The reasoning behind this is somewhat subtle. It derives from the fact that Rust requires (and defines) that every trait object type `dyn Trait` automatically @@ -58,7 +61,7 @@ implement a sized trait like `Trait:Sized`. So, rather than allow an exception to the rule that `dyn Trait` always implements `Trait`, Rust chooses to prohibit such a `dyn Trait` from existing at all. -Only unsized traits are considered object-safe. +Only unsized traits are considered dyn-compatible. Generally, `Self: Sized` is used to indicate that the trait should not be used as a trait object. If the trait comes from your own crate, consider removing @@ -103,8 +106,8 @@ fn call_foo(x: Box) { } ``` -If only some methods aren't object-safe, you can add a `where Self: Sized` bound -on them to mark them as explicitly unavailable to trait objects. The +If only some methods aren't dyn-compatible, you can add a `where Self: Sized` +bound on them to mark them as explicitly unavailable to trait objects. The functionality will still be available to all other implementers, including `Box` which is itself sized (assuming you `impl Trait for Box`). @@ -117,7 +120,7 @@ trait Trait { ``` Now, `foo()` can no longer be called on a trait object, but you will now be -allowed to make a trait object, and that will be able to call any object-safe +allowed to make a trait object, and that will be able to call any dyn-compatible methods. With such a bound, one can still call `foo()` on types implementing that trait that aren't behind trait objects. @@ -306,7 +309,7 @@ Here, the supertrait might have methods as follows: ``` trait Super { - fn get_a(&self) -> &A; // note that this is object safe! + fn get_a(&self) -> &A; // note that this is dyn-compatible! } ``` @@ -314,10 +317,10 @@ If the trait `Trait` was deriving from something like `Super` or `Super` (where `Foo` itself is `Foo`), this is okay, because given a type `get_a()` will definitely return an object of that type. -However, if it derives from `Super`, even though `Super` is object safe, -the method `get_a()` would return an object of unknown type when called on the -function. `Self` type parameters let us make object safe traits no longer safe, -so they are forbidden when specifying supertraits. +However, if it derives from `Super`, even though `Super` is +dyn-compatible, the method `get_a()` would return an object of unknown type when +called on the function. `Self` type parameters let us make dyn-compatible traits +no longer compatible, so they are forbidden when specifying supertraits. There's no easy fix for this. Generally, code will need to be refactored so that you no longer need to derive from `Super`. diff --git a/compiler/rustc_error_codes/src/lib.rs b/compiler/rustc_error_codes/src/lib.rs index 8631de65ec82..27a34d6003db 100644 --- a/compiler/rustc_error_codes/src/lib.rs +++ b/compiler/rustc_error_codes/src/lib.rs @@ -623,7 +623,7 @@ E0800: 0800, // E0314, // closure outlives stack frame // E0315, // cannot invoke closure outside of its lifetime // E0319, // trait impls for defaulted traits allowed just for structs/enums -// E0372, // coherence not object safe +// E0372, // coherence not dyn-compatible // E0385, // {} in an aliasable location // E0402, // cannot use an outer type parameter in this context // E0406, // merged into 420 diff --git a/compiler/rustc_errors/Cargo.toml b/compiler/rustc_errors/Cargo.toml index 59cf4e5f210b..00eaf4d5a862 100644 --- a/compiler/rustc_errors/Cargo.toml +++ b/compiler/rustc_errors/Cargo.toml @@ -29,7 +29,7 @@ tracing = "0.1" # tidy-alphabetical-end [target.'cfg(windows)'.dependencies.windows] -version = "0.52.0" +version = "0.57.0" features = [ "Win32_Foundation", "Win32_Security", diff --git a/compiler/rustc_expand/src/mbe/macro_check.rs b/compiler/rustc_expand/src/mbe/macro_check.rs index b1d898b69494..1498b9cbd5d6 100644 --- a/compiler/rustc_expand/src/mbe/macro_check.rs +++ b/compiler/rustc_expand/src/mbe/macro_check.rs @@ -119,7 +119,7 @@ use rustc_span::symbol::{MacroRulesNormalizedIdent, kw}; use rustc_span::{ErrorGuaranteed, Span}; use smallvec::SmallVec; -use super::quoted::VALID_FRAGMENT_NAMES_MSG_2021; +use super::quoted::VALID_FRAGMENT_NAMES_MSG; use crate::errors; use crate::mbe::{KleeneToken, TokenTree}; @@ -274,7 +274,7 @@ fn check_binders( psess.dcx().emit_err(errors::MissingFragmentSpecifier { span, add_span: span.shrink_to_hi(), - valid: VALID_FRAGMENT_NAMES_MSG_2021, + valid: VALID_FRAGMENT_NAMES_MSG, }); } else { psess.buffer_lint( diff --git a/compiler/rustc_expand/src/mbe/quoted.rs b/compiler/rustc_expand/src/mbe/quoted.rs index f0a6c841f312..2edd289625e1 100644 --- a/compiler/rustc_expand/src/mbe/quoted.rs +++ b/compiler/rustc_expand/src/mbe/quoted.rs @@ -1,4 +1,3 @@ -use rustc_ast::token::NtExprKind::*; use rustc_ast::token::{self, Delimiter, IdentIsRaw, NonterminalKind, Token}; use rustc_ast::{NodeId, tokenstream}; use rustc_ast_pretty::pprust; @@ -13,12 +12,9 @@ use crate::errors; use crate::mbe::macro_parser::count_metavar_decls; use crate::mbe::{Delimited, KleeneOp, KleeneToken, MetaVarExpr, SequenceRepetition, TokenTree}; -const VALID_FRAGMENT_NAMES_MSG: &str = "valid fragment specifiers are \ - `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, \ - `item` and `vis`"; -pub(crate) const VALID_FRAGMENT_NAMES_MSG_2021: &str = "valid fragment specifiers are \ - `ident`, `block`, `stmt`, `expr`, `expr_2021`, `pat`, `ty`, `lifetime`, `literal`, `path`, \ - `meta`, `tt`, `item` and `vis`"; +pub(crate) const VALID_FRAGMENT_NAMES_MSG: &str = "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"; /// Takes a `tokenstream::TokenStream` and returns a `Vec`. Specifically, this /// takes a generic `TokenStream`, such as is used in the rest of the compiler, and returns a @@ -92,39 +88,13 @@ pub(super) fn parse( }; let kind = NonterminalKind::from_symbol(fragment.name, edition) .unwrap_or_else(|| { - let help = match fragment.name { - sym::expr_2021 => { - format!( - "fragment specifier `expr_2021` \ - requires Rust 2021 or later\n\ - {VALID_FRAGMENT_NAMES_MSG}" - ) - } - _ if edition().at_least_rust_2021() - && features.expr_fragment_specifier_2024 => - { - VALID_FRAGMENT_NAMES_MSG_2021.into() - } - _ => VALID_FRAGMENT_NAMES_MSG.into(), - }; sess.dcx().emit_err(errors::InvalidFragmentSpecifier { span, fragment, - help, + help: VALID_FRAGMENT_NAMES_MSG.into(), }); NonterminalKind::Ident }); - if kind == NonterminalKind::Expr(Expr2021 { inferred: false }) - && !features.expr_fragment_specifier_2024 - { - rustc_session::parse::feature_err( - sess, - sym::expr_fragment_specifier_2024, - span, - "fragment specifier `expr_2021` is unstable", - ) - .emit(); - } result.push(TokenTree::MetaVarDecl(span, ident, Some(kind))); continue; } diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs index a7b251ab2527..0dc35618ff88 100644 --- a/compiler/rustc_expand/src/proc_macro_server.rs +++ b/compiler/rustc_expand/src/proc_macro_server.rs @@ -627,8 +627,7 @@ impl server::TokenStream for Rustc<'_, '_> { base: Option, trees: Vec>, ) -> Self::TokenStream { - let mut stream = - if let Some(base) = base { base } else { tokenstream::TokenStream::default() }; + let mut stream = base.unwrap_or_default(); for tree in trees { for tt in (tree, &mut *self).to_internal() { stream.push_tree(tt); @@ -642,8 +641,7 @@ impl server::TokenStream for Rustc<'_, '_> { base: Option, streams: Vec, ) -> Self::TokenStream { - let mut stream = - if let Some(base) = base { base } else { tokenstream::TokenStream::default() }; + let mut stream = base.unwrap_or_default(); for s in streams { stream.push_stream(s); } diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index 70e92f545c63..a850eb956207 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -151,6 +151,8 @@ declare_features! ( (accepted, const_raw_ptr_deref, "1.58.0", Some(51911)), /// Allows references to types with interior mutability within constants (accepted, const_refs_to_cell, "CURRENT_RUSTC_VERSION", Some(80384)), + /// Allows creating pointers and references to `static` items in constants. + (accepted, const_refs_to_static, "CURRENT_RUSTC_VERSION", Some(119618)), /// Allows implementing `Copy` for closures where possible (RFC 2132). (accepted, copy_closures, "1.26.0", Some(44490)), /// Allows `crate` in paths. @@ -187,6 +189,8 @@ declare_features! ( (accepted, exhaustive_integer_patterns, "1.33.0", Some(50907)), /// Allows explicit generic arguments specification with `impl Trait` present. (accepted, explicit_generic_args_with_impl_trait, "1.63.0", Some(83701)), + /// Uses 2024 rules for matching `expr` fragments in macros. Also enables `expr_2021` fragment. + (accepted, expr_fragment_specifier_2024, "CURRENT_RUSTC_VERSION", Some(123742)), /// Allows arbitrary expressions in key-value attributes at parse time. (accepted, extended_key_value_attributes, "1.54.0", Some(78835)), /// Allows resolving absolute paths as paths from other crates. diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 63b4b272f76c..c5530097e960 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -407,8 +407,6 @@ declare_features! ( (unstable, const_for, "1.56.0", Some(87575)), /// Be more precise when looking for live drops in a const context. (unstable, const_precise_live_drops, "1.46.0", Some(73255)), - /// Allows creating pointers and references to `static` items in constants. - (unstable, const_refs_to_static, "1.78.0", Some(119618)), /// Allows `impl const Trait for T` syntax. (unstable, const_trait_impl, "1.42.0", Some(67792)), /// Allows the `?` operator in const contexts. @@ -452,8 +450,6 @@ declare_features! ( (unstable, exhaustive_patterns, "1.13.0", Some(51085)), /// Allows explicit tail calls via `become` expression. (incomplete, explicit_tail_calls, "1.72.0", Some(112788)), - /// Uses 2024 rules for matching `expr` fragments in macros. Also enables `expr_2021` fragment. - (incomplete, expr_fragment_specifier_2024, "1.80.0", Some(123742)), /// Allows using `efiapi`, `sysv64` and `win64` as calling convention /// for functions with varargs. (unstable, extended_varargs_abi_support, "1.65.0", Some(100189)), @@ -548,9 +544,12 @@ declare_features! ( (unstable, non_exhaustive_omitted_patterns_lint, "1.57.0", Some(89554)), /// Allows `for` binders in where-clauses (incomplete, non_lifetime_binders, "1.69.0", Some(108185)), - /// Allows making `dyn Trait` well-formed even if `Trait` is not object safe. + /// Allows making `dyn Trait` well-formed even if `Trait` is not dyn-compatible[^1]. /// In that case, `dyn Trait: Trait` does not hold. Moreover, coercions and /// casts in safe Rust to `dyn Trait` for such a `Trait` is also forbidden. + /// + /// [^1]: Formerly known as "object safe". + // FIXME(dyn_compat_renaming): Rename feature. (unstable, object_safe_for_dispatch, "1.40.0", Some(43561)), /// Allows using enums in offset_of! (unstable, offset_of_enum, "1.75.0", Some(120141)), diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index 09d466339ff6..c73826c489f9 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -558,7 +558,7 @@ hir_analysis_unrecognized_intrinsic_function = .help = if you're adding an intrinsic, be sure to update `check_intrinsic_type` hir_analysis_unused_associated_type_bounds = - unnecessary associated type bound for not object safe associated type + unnecessary associated type bound for dyn-incompatible associated type .note = this associated type has a `where Self: Sized` bound, and while the associated type can be specified, it cannot be used because trait objects are never `Sized` .suggestion = remove this bound diff --git a/compiler/rustc_hir_analysis/src/bounds.rs b/compiler/rustc_hir_analysis/src/bounds.rs index caf9960741d7..8947e7a22167 100644 --- a/compiler/rustc_hir_analysis/src/bounds.rs +++ b/compiler/rustc_hir_analysis/src/bounds.rs @@ -91,12 +91,46 @@ impl<'tcx> Bounds<'tcx> { } tcx.consts.true_ } + (DefKind::Trait, ty::BoundConstness::ConstIfConst) => { + // we are in a trait, where `bound_trait_ref` could be: + // (1) a super trait `trait Foo: ~const Bar`. + // - This generates `::Effects: TyCompat<::Effects>` + // + // (2) a where clause `where for<..> Something: ~const Bar`. + // - This generates `for<..> ::Effects: TyCompat<::Effects>` + let Some(own_fx) = tcx.associated_type_for_effects(defining_def_id) else { + tcx.dcx().span_delayed_bug(span, "should not have allowed `~const` on a trait that doesn't have `#[const_trait]`"); + return; + }; + let own_fx_ty = Ty::new_projection( + tcx, + own_fx, + ty::GenericArgs::identity_for_item(tcx, own_fx), + ); + let Some(their_fx) = tcx.associated_type_for_effects(bound_trait_ref.def_id()) + else { + tcx.dcx().span_delayed_bug(span, "`~const` on trait without Effects assoc"); + return; + }; + let their_fx_ty = + Ty::new_projection(tcx, their_fx, bound_trait_ref.skip_binder().args); + let compat = tcx.require_lang_item(LangItem::EffectsTyCompat, Some(span)); + let clause = bound_trait_ref + .map_bound(|_| { + let trait_ref = ty::TraitRef::new(tcx, compat, [own_fx_ty, their_fx_ty]); + ty::ClauseKind::Trait(ty::TraitPredicate { + trait_ref, + polarity: ty::PredicatePolarity::Positive, + }) + }) + .upcast(tcx); - ( - DefKind::Trait | DefKind::Impl { of_trait: true }, - ty::BoundConstness::ConstIfConst, - ) => { - // this is either a where clause on an impl/trait header or on a trait. + self.clauses.push((clause, span)); + return; + } + + (DefKind::Impl { of_trait: true }, ty::BoundConstness::ConstIfConst) => { + // this is a where clause on an impl header. // push `::Effects` into the set for the `Min` bound. let Some(assoc) = tcx.associated_type_for_effects(bound_trait_ref.def_id()) else { tcx.dcx().span_delayed_bug(span, "`~const` on trait without Effects assoc"); diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index f8a19e93a412..02d23b95d46e 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -2,7 +2,7 @@ use std::cell::LazyCell; use std::ops::{ControlFlow, Deref}; use hir::intravisit::{self, Visitor}; -use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; +use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_errors::codes::*; use rustc_errors::{Applicability, ErrorGuaranteed, pluralize, struct_span_code_err}; use rustc_hir::ItemKind; @@ -374,7 +374,7 @@ fn check_trait_item<'tcx>( hir::TraitItemKind::Type(_bounds, Some(ty)) => (None, ty.span), _ => (None, trait_item.span), }; - check_object_unsafe_self_trait_by_name(tcx, trait_item); + check_dyn_incompatible_self_trait_by_name(tcx, trait_item); let mut res = check_associated_item(tcx, def_id, span, method_sig); if matches!(trait_item.kind, hir::TraitItemKind::Fn(..)) { @@ -404,7 +404,7 @@ fn check_trait_item<'tcx>( /// ``` fn check_gat_where_clauses(tcx: TyCtxt<'_>, trait_def_id: LocalDefId) { // Associates every GAT's def_id to a list of possibly missing bounds detected by this lint. - let mut required_bounds_by_item = FxHashMap::default(); + let mut required_bounds_by_item = FxIndexMap::default(); let associated_items = tcx.associated_items(trait_def_id); // Loop over all GATs together, because if this lint suggests adding a where-clause bound @@ -430,7 +430,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, trait_def_id: LocalDefId) { // Gather the bounds with which all other items inside of this trait constrain the GAT. // This is calculated by taking the intersection of the bounds that each item // constrains the GAT with individually. - let mut new_required_bounds: Option>> = None; + let mut new_required_bounds: Option>> = None; for item in associated_items.in_definition_order() { let item_def_id = item.def_id.expect_local(); // Skip our own GAT, since it does not constrain itself at all. @@ -589,7 +589,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, trait_def_id: LocalDefId) { fn augment_param_env<'tcx>( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, - new_predicates: Option<&FxHashSet>>, + new_predicates: Option<&FxIndexSet>>, ) -> ty::ParamEnv<'tcx> { let Some(new_predicates) = new_predicates else { return param_env; @@ -625,9 +625,9 @@ fn gather_gat_bounds<'tcx, T: TypeFoldable>>( wf_tys: &FxIndexSet>, gat_def_id: LocalDefId, gat_generics: &'tcx ty::Generics, -) -> Option>> { +) -> Option>> { // The bounds we that we would require from `to_check` - let mut bounds = FxHashSet::default(); + let mut bounds = FxIndexSet::default(); let (regions, types) = GATArgsCollector::visit(gat_def_id.to_def_id(), to_check); @@ -789,18 +789,18 @@ fn test_region_obligations<'tcx>( struct GATArgsCollector<'tcx> { gat: DefId, // Which region appears and which parameter index its instantiated with - regions: FxHashSet<(ty::Region<'tcx>, usize)>, + regions: FxIndexSet<(ty::Region<'tcx>, usize)>, // Which params appears and which parameter index its instantiated with - types: FxHashSet<(Ty<'tcx>, usize)>, + types: FxIndexSet<(Ty<'tcx>, usize)>, } impl<'tcx> GATArgsCollector<'tcx> { fn visit>>( gat: DefId, t: T, - ) -> (FxHashSet<(ty::Region<'tcx>, usize)>, FxHashSet<(Ty<'tcx>, usize)>) { + ) -> (FxIndexSet<(ty::Region<'tcx>, usize)>, FxIndexSet<(Ty<'tcx>, usize)>) { let mut visitor = - GATArgsCollector { gat, regions: FxHashSet::default(), types: FxHashSet::default() }; + GATArgsCollector { gat, regions: FxIndexSet::default(), types: FxIndexSet::default() }; t.visit_with(&mut visitor); (visitor.regions, visitor.types) } @@ -838,9 +838,10 @@ fn could_be_self(trait_def_id: LocalDefId, ty: &hir::Ty<'_>) -> bool { } } -/// Detect when an object unsafe trait is referring to itself in one of its associated items. -/// When this is done, suggest using `Self` instead. -fn check_object_unsafe_self_trait_by_name(tcx: TyCtxt<'_>, item: &hir::TraitItem<'_>) { +/// Detect when a dyn-incompatible trait is referring to itself in one of its associated items. +/// +/// In such cases, suggest using `Self` instead. +fn check_dyn_incompatible_self_trait_by_name(tcx: TyCtxt<'_>, item: &hir::TraitItem<'_>) { let (trait_name, trait_def_id) = match tcx.hir_node_by_def_id(tcx.hir().get_parent_item(item.hir_id()).def_id) { hir::Node::Item(item) => match item.kind { @@ -872,7 +873,7 @@ fn check_object_unsafe_self_trait_by_name(tcx: TyCtxt<'_>, item: &hir::TraitItem _ => {} } if !trait_should_be_self.is_empty() { - if tcx.is_object_safe(trait_def_id) { + if tcx.is_dyn_compatible(trait_def_id) { return; } let sugg = trait_should_be_self.iter().map(|span| (*span, "Self".to_string())).collect(); @@ -960,13 +961,20 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(), hir_ty.span, "using raw pointers as const generic parameters is forbidden", ), - _ => tcx.dcx().struct_span_err( - hir_ty.span, - format!("`{}` is forbidden as the type of a const generic parameter", ty), - ), + _ => { + // Avoid showing "{type error}" to users. See #118179. + ty.error_reported()?; + + tcx.dcx().struct_span_err( + hir_ty.span, + format!( + "`{ty}` is forbidden as the type of a const generic parameter", + ), + ) + } }; - diag.note("the only supported types are integers, `bool` and `char`"); + diag.note("the only supported types are integers, `bool`, and `char`"); let cause = ObligationCause::misc(hir_ty.span, param.def_id); let adt_const_params_feature_string = diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs index b8066b4b47d9..d1c888a185ed 100644 --- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs +++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs @@ -1,4 +1,4 @@ -use rustc_data_structures::fx::{FxHashSet, FxIndexMap, IndexEntry}; +use rustc_data_structures::fx::{FxIndexMap, FxIndexSet, IndexEntry}; use rustc_errors::codes::*; use rustc_errors::struct_span_code_err; use rustc_hir as hir; @@ -215,7 +215,7 @@ impl<'tcx> InherentOverlapChecker<'tcx> { struct ConnectedRegion { idents: SmallVec<[Symbol; 8]>, - impl_blocks: FxHashSet, + impl_blocks: FxIndexSet, } let mut connected_regions: IndexVec = Default::default(); // Reverse map from the Symbol to the connected region id. diff --git a/compiler/rustc_hir_analysis/src/coherence/mod.rs b/compiler/rustc_hir_analysis/src/coherence/mod.rs index b25406583f6c..69d364264470 100644 --- a/compiler/rustc_hir_analysis/src/coherence/mod.rs +++ b/compiler/rustc_hir_analysis/src/coherence/mod.rs @@ -183,8 +183,8 @@ fn check_object_overlap<'tcx>( // check for overlap with the automatic `impl Trait for dyn Trait` if let ty::Dynamic(data, ..) = trait_ref.self_ty().kind() { - // This is something like impl Trait1 for Trait2. Illegal - // if Trait1 is a supertrait of Trait2 or Trait2 is not object safe. + // This is something like `impl Trait1 for Trait2`. Illegal if + // Trait1 is a supertrait of Trait2 or Trait2 is not dyn-compatible. let component_def_ids = data.iter().flat_map(|predicate| { match predicate.skip_binder() { @@ -197,7 +197,8 @@ fn check_object_overlap<'tcx>( }); for component_def_id in component_def_ids { - if !tcx.is_object_safe(component_def_id) { + if !tcx.is_dyn_compatible(component_def_id) { + // FIXME(dyn_compat_renaming): Rename test and update comment. // Without the 'object_safe_for_dispatch' feature this is an error // which will be reported by wfcheck. Ignore it here. // This is tested by `coherence-impl-trait-for-trait-object-safe.rs`. diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index 5fdaba41fb26..04770469132b 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -109,16 +109,16 @@ pub(crate) fn orphan_check_impl( // // auto trait AutoTrait {} // - // trait ObjectSafeTrait { + // trait DynCompatibleTrait { // fn f(&self) where Self: AutoTrait; // } // - // We can allow f to be called on `dyn ObjectSafeTrait + AutoTrait`. + // We can allow f to be called on `dyn DynCompatibleTrait + AutoTrait`. // // If we didn't deny `impl AutoTrait for dyn Trait`, it would be unsound - // for the ObjectSafeTrait shown above to be object safe because someone - // could take some type implementing ObjectSafeTrait but not AutoTrait, - // unsize it to `dyn ObjectSafeTrait`, and call .f() which has no + // for the `DynCompatibleTrait` shown above to be dyn-compatible because someone + // could take some type implementing `DynCompatibleTrait` but not `AutoTrait`, + // unsize it to `dyn DynCompatibleTrait`, and call `.f()` which has no // concrete implementation (issue #50781). enum LocalImpl { Allow, diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index 7557219aaa69..f44b4728ad53 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -360,33 +360,10 @@ pub(super) fn explicit_item_bounds_with_filter( None => {} } - if tcx.is_effects_desugared_assoc_ty(def_id.to_def_id()) { - let mut predicates = Vec::new(); - - let parent = tcx.local_parent(def_id); - - let preds = tcx.explicit_predicates_of(parent); - - if let ty::AssocItemContainer::TraitContainer = tcx.associated_item(def_id).container { - // for traits, emit `type Effects: TyCompat<<(T1::Effects, ..) as Min>::Output>` - let tup = Ty::new(tcx, ty::Tuple(preds.effects_min_tys)); - // FIXME(effects) span - let span = tcx.def_span(def_id); - let assoc = tcx.require_lang_item(hir::LangItem::EffectsIntersectionOutput, Some(span)); - let proj = Ty::new_projection(tcx, assoc, [tup]); - let self_proj = Ty::new_projection( - tcx, - def_id.to_def_id(), - ty::GenericArgs::identity_for_item(tcx, def_id), - ); - let trait_ = tcx.require_lang_item(hir::LangItem::EffectsTyCompat, Some(span)); - let trait_ref = ty::TraitRef::new(tcx, trait_, [self_proj, proj]); - predicates.push((ty::Binder::dummy(trait_ref).upcast(tcx), span)); - } - return ty::EarlyBinder::bind(tcx.arena.alloc_from_iter(predicates)); - } - let bounds = match tcx.hir_node_by_def_id(def_id) { + _ if tcx.is_effects_desugared_assoc_ty(def_id.to_def_id()) => { + associated_type_bounds(tcx, def_id, &[], tcx.def_span(def_id), filter) + } hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Type(bounds, _), span, diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs similarity index 96% rename from compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs rename to compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs index 87a240f626c3..e7b8e6e69b0c 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs @@ -11,8 +11,8 @@ use rustc_middle::ty::{ self, DynKind, ExistentialPredicateStableCmpExt as _, Ty, TyCtxt, TypeFoldable, Upcast, }; use rustc_span::{ErrorGuaranteed, Span}; -use rustc_trait_selection::error_reporting::traits::report_object_safety_error; -use rustc_trait_selection::traits::{self, hir_ty_lowering_object_safety_violations}; +use rustc_trait_selection::error_reporting::traits::report_dyn_incompatibility; +use rustc_trait_selection::traits::{self, hir_ty_lowering_dyn_compatibility_violations}; use smallvec::{SmallVec, smallvec}; use tracing::{debug, instrument}; @@ -99,19 +99,19 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { return Ty::new_error(tcx, reported); } - // Check that there are no gross object safety violations; + // Check that there are no gross dyn-compatibility violations; // most importantly, that the supertraits don't contain `Self`, // to avoid ICEs. for item in ®ular_traits { - let object_safety_violations = - hir_ty_lowering_object_safety_violations(tcx, item.trait_ref().def_id()); - if !object_safety_violations.is_empty() { - let reported = report_object_safety_error( + let violations = + hir_ty_lowering_dyn_compatibility_violations(tcx, item.trait_ref().def_id()); + if !violations.is_empty() { + let reported = report_dyn_incompatibility( tcx, span, Some(hir_id), item.trait_ref().def_id(), - &object_safety_violations, + &violations, ) .emit(); return Ty::new_error(tcx, reported); @@ -275,8 +275,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { tcx.item_name(def_id), ) .with_note( - rustc_middle::traits::ObjectSafetyViolation::SupertraitSelf(smallvec![]) - .error_msg(), + rustc_middle::traits::DynCompatibilityViolation::SupertraitSelf( + smallvec![], + ) + .error_msg(), ) .emit(); } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs index 5775a8867b16..a735b8cc2a45 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs @@ -19,9 +19,9 @@ use rustc_session::parse::feature_err; use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::symbol::{Ident, kw, sym}; use rustc_span::{BytePos, DUMMY_SP, Span, Symbol}; -use rustc_trait_selection::error_reporting::traits::report_object_safety_error; +use rustc_trait_selection::error_reporting::traits::report_dyn_incompatibility; use rustc_trait_selection::traits::{ - FulfillmentError, TraitAliasExpansionInfo, object_safety_violations_for_assoc_item, + FulfillmentError, TraitAliasExpansionInfo, dyn_compatibility_violations_for_assoc_item, }; use crate::errors::{ @@ -739,7 +739,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // Account for things like `dyn Foo + 'a`, like in tests `issue-22434.rs` and // `issue-22560.rs`. let mut trait_bound_spans: Vec = vec![]; - let mut object_safety_violations = false; + let mut dyn_compatibility_violations = false; for (span, items) in &associated_types { if !items.is_empty() { trait_bound_spans.push(*span); @@ -750,14 +750,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { names_len += 1; let violations = - object_safety_violations_for_assoc_item(tcx, trait_def_id, *assoc_item); + dyn_compatibility_violations_for_assoc_item(tcx, trait_def_id, *assoc_item); if !violations.is_empty() { - report_object_safety_error(tcx, *span, None, trait_def_id, &violations).emit(); - object_safety_violations = true; + report_dyn_incompatibility(tcx, *span, None, trait_def_id, &violations).emit(); + dyn_compatibility_violations = true; } } } - if object_safety_violations { + if dyn_compatibility_violations { return; } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs index 1fbf70fa2015..a70f881f5fed 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs @@ -77,7 +77,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { if self_ty.span.can_be_used_for_suggestions() && !self.maybe_suggest_impl_trait(self_ty, &mut diag) { - // FIXME: Only emit this suggestion if the trait is object safe. + // FIXME: Only emit this suggestion if the trait is dyn-compatible. diag.multipart_suggestion_verbose(label, sugg, Applicability::MachineApplicable); } // Check if the impl trait that we are considering is an impl of a local trait. @@ -89,7 +89,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { lint.primary_message("trait objects without an explicit `dyn` are deprecated"); if self_ty.span.can_be_used_for_suggestions() { lint.multipart_suggestion_verbose( - "if this is an object-safe trait, use `dyn`", + "if this is a dyn-compatible trait, use `dyn`", sugg, Applicability::MachineApplicable, ); @@ -196,7 +196,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let mut is_downgradable = true; // Check if trait object is safe for suggesting dynamic dispatch. - let is_object_safe = match self_ty.kind { + let is_dyn_compatible = match self_ty.kind { hir::TyKind::TraitObject(objects, ..) => { objects.iter().all(|(o, _)| match o.trait_ref.path.res { Res::Def(DefKind::Trait, id) => { @@ -204,7 +204,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // For recursive traits, don't downgrade the error. (#119652) is_downgradable = false; } - tcx.is_object_safe(id) + tcx.is_dyn_compatible(id) } _ => false, }) @@ -221,8 +221,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { if let hir::FnRetTy::Return(ty) = sig.decl.output && ty.peel_refs().hir_id == self_ty.hir_id { - let pre = if !is_object_safe { - format!("`{trait_name}` is not object safe, ") + let pre = if !is_dyn_compatible { + format!("`{trait_name}` is dyn-incompatible, ") } else { String::new() }; @@ -234,7 +234,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { diag.multipart_suggestion_verbose(msg, impl_sugg, Applicability::MachineApplicable); // Suggest `Box` for return type - if is_object_safe { + if is_dyn_compatible { // If the return type is `&Trait`, we don't want // the ampersand to be displayed in the `Box` // suggestion. @@ -253,7 +253,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { Applicability::MachineApplicable, ); } else if is_downgradable { - // We'll emit the object safety error already, with a structured suggestion. + // We'll emit the dyn-compatibility error already, with a structured suggestion. diag.downgrade_to_delayed_bug(); } return true; @@ -276,10 +276,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { impl_sugg, Applicability::MachineApplicable, ); - if !is_object_safe { - diag.note(format!("`{trait_name}` it is not object safe, so it can't be `dyn`")); + if !is_dyn_compatible { + diag.note(format!("`{trait_name}` it is dyn-incompatible, so it can't be `dyn`")); if is_downgradable { - // We'll emit the object safety error already, with a structured suggestion. + // We'll emit the dyn-compatibility error already, with a structured suggestion. diag.downgrade_to_delayed_bug(); } } else { 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 d7d4a98e63fe..6dd3a06ef377 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -15,15 +15,15 @@ mod bounds; mod cmse; +mod dyn_compatibility; pub mod errors; pub mod generics; mod lint; -mod object_safety; use std::slice; use rustc_ast::TraitObjectSyntax; -use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; +use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_errors::codes::*; use rustc_errors::{ Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, FatalError, struct_span_code_err, @@ -2394,8 +2394,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { #[instrument(level = "trace", skip(self, generate_err))] fn validate_late_bound_regions<'cx>( &'cx self, - constrained_regions: FxHashSet, - referenced_regions: FxHashSet, + constrained_regions: FxIndexSet, + referenced_regions: FxIndexSet, generate_err: impl Fn(&str) -> Diag<'cx>, ) { for br in referenced_regions.difference(&constrained_regions) { diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 92d85d48a42c..7d40a7746b97 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -58,7 +58,6 @@ This API is completely unstable and subject to change. // tidy-alphabetical-start #![allow(internal_features)] #![allow(rustc::diagnostic_outside_of_impl)] -#![allow(rustc::potential_query_instability)] #![allow(rustc::untranslatable_diagnostic)] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs index f2d3a3b509a0..2d8943c61592 100644 --- a/compiler/rustc_hir_typeck/src/check.rs +++ b/compiler/rustc_hir_typeck/src/check.rs @@ -99,7 +99,7 @@ pub(super) fn check_fn<'a, 'tcx>( if !params_can_be_unsized { fcx.require_type_is_sized( param_ty, - param.pat.span, + param.ty_span, // ty.span == binding_span iff this is a closure parameter with no type ascription, // or if it's an implicit `self` parameter ObligationCauseCode::SizedArgumentType( diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index b08c5bc6d9a3..fb462eec1b9a 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -655,7 +655,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { return Err(TypeError::Mismatch); } - // Object safety violations or miscellaneous. + // Dyn-compatibility violations or miscellaneous. Err(err) => { self.err_ctxt().report_selection_error(obligation.clone(), &obligation, &err); // Treat this like an obligation and follow through diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 2c469c0d52c4..62107877283a 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -757,7 +757,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // give us a `QPath::TypeRelative` with a trait object as // `qself`. In that case, we want to avoid registering a WF obligation // for `dyn MyTrait`, since we don't actually need the trait - // to be object-safe. + // to be dyn-compatible. // We manually call `register_wf_obligation` in the success path // below. let ty = self.lowerer().lower_ty(qself); 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 2dcab9ed0044..2aad9a043f97 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs @@ -50,7 +50,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(..)) | ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(..)) | ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(..)) - | ty::PredicateKind::ObjectSafe(..) + | ty::PredicateKind::DynCompatible(..) | ty::PredicateKind::NormalizesTo(..) | ty::PredicateKind::AliasRelate(..) | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 5f89f7dedc2c..487cc7e55cd9 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -882,7 +882,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ty = self.lowerer().lower_ty(hir_ty); debug!(?ty, "return type (lowered)"); debug!(?expected, "expected type"); - let bound_vars = self.tcx.late_bound_vars(hir_ty.hir_id.owner.into()); + let bound_vars = + self.tcx.late_bound_vars(self.tcx.local_def_id_to_hir_id(fn_id)); let ty = Binder::bind_with_vars(ty, bound_vars); let ty = self.normalize(hir_ty.span, ty); let ty = self.tcx.instantiate_bound_regions_with_erased(ty); diff --git a/compiler/rustc_hir_typeck/src/gather_locals.rs b/compiler/rustc_hir_typeck/src/gather_locals.rs index 83c9a4878d2f..5ae8d2230f8f 100644 --- a/compiler/rustc_hir_typeck/src/gather_locals.rs +++ b/compiler/rustc_hir_typeck/src/gather_locals.rs @@ -144,7 +144,7 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> { if !self.fcx.tcx.features().unsized_fn_params { self.fcx.require_type_is_sized( var_ty, - p.span, + ty_span, // ty_span == ident.span iff this is a closure parameter with no type // ascription, or if it's an implicit `self` parameter ObligationCauseCode::SizedArgumentType( diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index e3b0fa78eb70..72842075fec0 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -292,7 +292,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { // distinct types (e.g., if `Self` appeared as an // argument type), but those cases have already // been ruled out when we deemed the trait to be - // "object safe". + // "dyn-compatible". let original_poly_trait_ref = principal.with_self_ty(this.tcx, object_ty); let upcast_poly_trait_ref = this.upcast(original_poly_trait_ref, trait_def_id); let upcast_trait_ref = diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 1a8afcf003d2..371380e575db 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -779,8 +779,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { }); // It is illegal to invoke a method on a trait instance that refers to - // the `Self` type. An [`ObjectSafetyViolation::SupertraitSelf`] error - // will be reported by `object_safety.rs` if the method refers to the + // the `Self` type. An [`DynCompatibilityViolation::SupertraitSelf`] error + // will be reported by `dyn_compatibility.rs` if the method refers to the // `Self` type anywhere other than the receiver. Here, we use a // instantiation that replaces `Self` with the object type itself. Hence, // a `&self` method will wind up with an argument type like `&dyn Trait`. diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index c5843b883a17..63cf483aa227 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -1369,13 +1369,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { for (&var_hir_id, _) in upvars.iter() { let mut diagnostics_info = Vec::new(); - let auto_trait_diagnostic = if let Some(diagnostics_info) = - self.compute_2229_migrations_for_trait(min_captures, var_hir_id, closure_clause) - { - diagnostics_info - } else { - FxIndexMap::default() - }; + let auto_trait_diagnostic = self + .compute_2229_migrations_for_trait(min_captures, var_hir_id, closure_clause) + .unwrap_or_default(); let drop_reorder_diagnostic = if let Some(diagnostics_info) = self .compute_2229_migrations_for_drop( diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs index 9f6a17638664..6ce47db8b9bd 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -92,12 +92,7 @@ impl<'tcx> InferCtxt<'tcx> { } pub trait ToTrace<'tcx>: Relate> + Copy { - fn to_trace( - cause: &ObligationCause<'tcx>, - a_is_expected: bool, - a: Self, - b: Self, - ) -> TypeTrace<'tcx>; + fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx>; } impl<'a, 'tcx> At<'a, 'tcx> { @@ -116,7 +111,7 @@ impl<'a, 'tcx> At<'a, 'tcx> { { let mut fields = CombineFields::new( self.infcx, - ToTrace::to_trace(self.cause, true, expected, actual), + ToTrace::to_trace(self.cause, expected, actual), self.param_env, define_opaque_types, ); @@ -136,7 +131,7 @@ impl<'a, 'tcx> At<'a, 'tcx> { { let mut fields = CombineFields::new( self.infcx, - ToTrace::to_trace(self.cause, true, expected, actual), + ToTrace::to_trace(self.cause, expected, actual), self.param_env, define_opaque_types, ); @@ -154,12 +149,26 @@ impl<'a, 'tcx> At<'a, 'tcx> { where T: ToTrace<'tcx>, { - let mut fields = CombineFields::new( - self.infcx, - ToTrace::to_trace(self.cause, true, expected, actual), - self.param_env, + self.eq_trace( define_opaque_types, - ); + ToTrace::to_trace(self.cause, expected, actual), + expected, + actual, + ) + } + + /// Makes `expected == actual`. + pub fn eq_trace( + self, + define_opaque_types: DefineOpaqueTypes, + trace: TypeTrace<'tcx>, + expected: T, + actual: T, + ) -> InferResult<'tcx, ()> + where + T: Relate>, + { + let mut fields = CombineFields::new(self.infcx, trace, self.param_env, define_opaque_types); fields.equate(StructurallyRelateAliases::No).relate(expected, actual)?; Ok(InferOk { value: (), @@ -192,7 +201,7 @@ impl<'a, 'tcx> At<'a, 'tcx> { assert!(self.infcx.next_trait_solver()); let mut fields = CombineFields::new( self.infcx, - ToTrace::to_trace(self.cause, true, expected, actual), + ToTrace::to_trace(self.cause, expected, actual), self.param_env, DefineOpaqueTypes::Yes, ); @@ -284,7 +293,7 @@ impl<'a, 'tcx> At<'a, 'tcx> { { let mut fields = CombineFields::new( self.infcx, - ToTrace::to_trace(self.cause, true, expected, actual), + ToTrace::to_trace(self.cause, expected, actual), self.param_env, define_opaque_types, ); @@ -306,7 +315,7 @@ impl<'a, 'tcx> At<'a, 'tcx> { { let mut fields = CombineFields::new( self.infcx, - ToTrace::to_trace(self.cause, true, expected, actual), + ToTrace::to_trace(self.cause, expected, actual), self.param_env, define_opaque_types, ); @@ -316,18 +325,13 @@ impl<'a, 'tcx> At<'a, 'tcx> { } impl<'tcx> ToTrace<'tcx> for ImplSubject<'tcx> { - fn to_trace( - cause: &ObligationCause<'tcx>, - a_is_expected: bool, - a: Self, - b: Self, - ) -> TypeTrace<'tcx> { + fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> { match (a, b) { (ImplSubject::Trait(trait_ref_a), ImplSubject::Trait(trait_ref_b)) => { - ToTrace::to_trace(cause, a_is_expected, trait_ref_a, trait_ref_b) + ToTrace::to_trace(cause, trait_ref_a, trait_ref_b) } (ImplSubject::Inherent(ty_a), ImplSubject::Inherent(ty_b)) => { - ToTrace::to_trace(cause, a_is_expected, ty_a, ty_b) + ToTrace::to_trace(cause, ty_a, ty_b) } (ImplSubject::Trait(_), ImplSubject::Inherent(_)) | (ImplSubject::Inherent(_), ImplSubject::Trait(_)) => { @@ -338,65 +342,45 @@ impl<'tcx> ToTrace<'tcx> for ImplSubject<'tcx> { } impl<'tcx> ToTrace<'tcx> for Ty<'tcx> { - fn to_trace( - cause: &ObligationCause<'tcx>, - a_is_expected: bool, - a: Self, - b: Self, - ) -> TypeTrace<'tcx> { + fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> { TypeTrace { cause: cause.clone(), - values: ValuePairs::Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())), + values: ValuePairs::Terms(ExpectedFound::new(true, a.into(), b.into())), } } } impl<'tcx> ToTrace<'tcx> for ty::Region<'tcx> { - fn to_trace( - cause: &ObligationCause<'tcx>, - a_is_expected: bool, - a: Self, - b: Self, - ) -> TypeTrace<'tcx> { + fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> { TypeTrace { cause: cause.clone(), - values: ValuePairs::Regions(ExpectedFound::new(a_is_expected, a, b)), + values: ValuePairs::Regions(ExpectedFound::new(true, a, b)), } } } impl<'tcx> ToTrace<'tcx> for Const<'tcx> { - fn to_trace( - cause: &ObligationCause<'tcx>, - a_is_expected: bool, - a: Self, - b: Self, - ) -> TypeTrace<'tcx> { + fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> { TypeTrace { cause: cause.clone(), - values: ValuePairs::Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())), + values: ValuePairs::Terms(ExpectedFound::new(true, a.into(), b.into())), } } } impl<'tcx> ToTrace<'tcx> for ty::GenericArg<'tcx> { - fn to_trace( - cause: &ObligationCause<'tcx>, - a_is_expected: bool, - a: Self, - b: Self, - ) -> TypeTrace<'tcx> { + fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> { TypeTrace { cause: cause.clone(), values: match (a.unpack(), b.unpack()) { (GenericArgKind::Lifetime(a), GenericArgKind::Lifetime(b)) => { - ValuePairs::Regions(ExpectedFound::new(a_is_expected, a, b)) + ValuePairs::Regions(ExpectedFound::new(true, a, b)) } (GenericArgKind::Type(a), GenericArgKind::Type(b)) => { - ValuePairs::Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())) + ValuePairs::Terms(ExpectedFound::new(true, a.into(), b.into())) } (GenericArgKind::Const(a), GenericArgKind::Const(b)) => { - ValuePairs::Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())) + ValuePairs::Terms(ExpectedFound::new(true, a.into(), b.into())) } ( @@ -419,72 +403,47 @@ impl<'tcx> ToTrace<'tcx> for ty::GenericArg<'tcx> { } impl<'tcx> ToTrace<'tcx> for ty::Term<'tcx> { - fn to_trace( - cause: &ObligationCause<'tcx>, - a_is_expected: bool, - a: Self, - b: Self, - ) -> TypeTrace<'tcx> { + fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> { TypeTrace { cause: cause.clone(), - values: ValuePairs::Terms(ExpectedFound::new(a_is_expected, a, b)), + values: ValuePairs::Terms(ExpectedFound::new(true, a, b)), } } } impl<'tcx> ToTrace<'tcx> for ty::TraitRef<'tcx> { - fn to_trace( - cause: &ObligationCause<'tcx>, - a_is_expected: bool, - a: Self, - b: Self, - ) -> TypeTrace<'tcx> { + fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> { TypeTrace { cause: cause.clone(), - values: ValuePairs::TraitRefs(ExpectedFound::new(a_is_expected, a, b)), + values: ValuePairs::TraitRefs(ExpectedFound::new(true, a, b)), } } } impl<'tcx> ToTrace<'tcx> for ty::AliasTy<'tcx> { - fn to_trace( - cause: &ObligationCause<'tcx>, - a_is_expected: bool, - a: Self, - b: Self, - ) -> TypeTrace<'tcx> { + fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> { TypeTrace { cause: cause.clone(), - values: ValuePairs::Aliases(ExpectedFound::new(a_is_expected, a.into(), b.into())), + values: ValuePairs::Aliases(ExpectedFound::new(true, a.into(), b.into())), } } } impl<'tcx> ToTrace<'tcx> for ty::AliasTerm<'tcx> { - fn to_trace( - cause: &ObligationCause<'tcx>, - a_is_expected: bool, - a: Self, - b: Self, - ) -> TypeTrace<'tcx> { + fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> { TypeTrace { cause: cause.clone(), - values: ValuePairs::Aliases(ExpectedFound::new(a_is_expected, a, b)), + values: ValuePairs::Aliases(ExpectedFound::new(true, a, b)), } } } impl<'tcx> ToTrace<'tcx> for ty::FnSig<'tcx> { - fn to_trace( - cause: &ObligationCause<'tcx>, - a_is_expected: bool, - a: Self, - b: Self, - ) -> TypeTrace<'tcx> { + fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> { TypeTrace { cause: cause.clone(), values: ValuePairs::PolySigs(ExpectedFound::new( - a_is_expected, + true, ty::Binder::dummy(a), ty::Binder::dummy(b), )), @@ -493,43 +452,28 @@ impl<'tcx> ToTrace<'tcx> for ty::FnSig<'tcx> { } impl<'tcx> ToTrace<'tcx> for ty::PolyFnSig<'tcx> { - fn to_trace( - cause: &ObligationCause<'tcx>, - a_is_expected: bool, - a: Self, - b: Self, - ) -> TypeTrace<'tcx> { + fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> { TypeTrace { cause: cause.clone(), - values: ValuePairs::PolySigs(ExpectedFound::new(a_is_expected, a, b)), + values: ValuePairs::PolySigs(ExpectedFound::new(true, a, b)), } } } impl<'tcx> ToTrace<'tcx> for ty::PolyExistentialTraitRef<'tcx> { - fn to_trace( - cause: &ObligationCause<'tcx>, - a_is_expected: bool, - a: Self, - b: Self, - ) -> TypeTrace<'tcx> { + fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> { TypeTrace { cause: cause.clone(), - values: ValuePairs::ExistentialTraitRef(ExpectedFound::new(a_is_expected, a, b)), + values: ValuePairs::ExistentialTraitRef(ExpectedFound::new(true, a, b)), } } } impl<'tcx> ToTrace<'tcx> for ty::PolyExistentialProjection<'tcx> { - fn to_trace( - cause: &ObligationCause<'tcx>, - a_is_expected: bool, - a: Self, - b: Self, - ) -> TypeTrace<'tcx> { + fn to_trace(cause: &ObligationCause<'tcx>, a: Self, b: Self) -> TypeTrace<'tcx> { TypeTrace { cause: cause.clone(), - values: ValuePairs::ExistentialProjection(ExpectedFound::new(a_is_expected, a, b)), + values: ValuePairs::ExistentialProjection(ExpectedFound::new(true, a, b)), } } } diff --git a/compiler/rustc_infer/src/infer/relate/combine.rs b/compiler/rustc_infer/src/infer/relate/combine.rs index e75d7b7db145..3b2ef3fe981e 100644 --- a/compiler/rustc_infer/src/infer/relate/combine.rs +++ b/compiler/rustc_infer/src/infer/relate/combine.rs @@ -36,10 +36,15 @@ use crate::traits::{Obligation, PredicateObligation}; #[derive(Clone)] pub struct CombineFields<'infcx, 'tcx> { pub infcx: &'infcx InferCtxt<'tcx>, + // Immutable fields pub trace: TypeTrace<'tcx>, pub param_env: ty::ParamEnv<'tcx>, - pub goals: Vec>>, pub define_opaque_types: DefineOpaqueTypes, + // Mutable fields + // + // Adding any additional field likely requires + // changes to the cache of `TypeRelating`. + pub goals: Vec>>, } impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { diff --git a/compiler/rustc_infer/src/infer/relate/type_relating.rs b/compiler/rustc_infer/src/infer/relate/type_relating.rs index a402a8009ff8..7acfea643dd1 100644 --- a/compiler/rustc_infer/src/infer/relate/type_relating.rs +++ b/compiler/rustc_infer/src/infer/relate/type_relating.rs @@ -4,6 +4,7 @@ use rustc_middle::ty::relate::{ }; use rustc_middle::ty::{self, Ty, TyCtxt, TyVar}; use rustc_span::Span; +use rustc_type_ir::data_structures::DelayedSet; use tracing::{debug, instrument}; use super::combine::CombineFields; @@ -13,9 +14,38 @@ use crate::infer::{DefineOpaqueTypes, InferCtxt, SubregionOrigin}; /// Enforce that `a` is equal to or a subtype of `b`. pub struct TypeRelating<'combine, 'a, 'tcx> { + // Immutable except for the `InferCtxt` and the + // resulting nested `goals`. fields: &'combine mut CombineFields<'a, 'tcx>, + + // Immutable field. structurally_relate_aliases: StructurallyRelateAliases, + // Mutable field. ambient_variance: ty::Variance, + + /// The cache only tracks the `ambient_variance` as it's the + /// only field which is mutable and which meaningfully changes + /// the result when relating types. + /// + /// The cache does not track whether the state of the + /// `InferCtxt` has been changed or whether we've added any + /// obligations to `self.fields.goals`. Whether a goal is added + /// once or multiple times is not really meaningful. + /// + /// Changes in the inference state may delay some type inference to + /// the next fulfillment loop. Given that this loop is already + /// necessary, this is also not a meaningful change. Consider + /// the following three relations: + /// ```text + /// Vec sub Vec + /// ?0 eq u32 + /// Vec sub Vec + /// ``` + /// Without a cache, the second `Vec sub Vec` would eagerly + /// constrain `?1` to `u32`. When using the cache entry from the + /// first time we've related these types, this only happens when + /// later proving the `Subtype(?0, ?1)` goal from the first relation. + cache: DelayedSet<(ty::Variance, Ty<'tcx>, Ty<'tcx>)>, } impl<'combine, 'infcx, 'tcx> TypeRelating<'combine, 'infcx, 'tcx> { @@ -24,7 +54,12 @@ impl<'combine, 'infcx, 'tcx> TypeRelating<'combine, 'infcx, 'tcx> { structurally_relate_aliases: StructurallyRelateAliases, ambient_variance: ty::Variance, ) -> TypeRelating<'combine, 'infcx, 'tcx> { - TypeRelating { fields: f, structurally_relate_aliases, ambient_variance } + TypeRelating { + fields: f, + structurally_relate_aliases, + ambient_variance, + cache: Default::default(), + } } } @@ -78,6 +113,10 @@ impl<'tcx> TypeRelation> for TypeRelating<'_, '_, 'tcx> { let a = infcx.shallow_resolve(a); let b = infcx.shallow_resolve(b); + if self.cache.contains(&(self.ambient_variance, a, b)) { + return Ok(a); + } + match (a.kind(), b.kind()) { (&ty::Infer(TyVar(a_id)), &ty::Infer(TyVar(b_id))) => { match self.ambient_variance { @@ -160,6 +199,8 @@ impl<'tcx> TypeRelation> for TypeRelating<'_, '_, 'tcx> { } } + assert!(self.cache.insert((self.ambient_variance, a, b))); + Ok(a) } diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs index 34625ffb7787..671a66d504f9 100644 --- a/compiler/rustc_infer/src/infer/resolve.rs +++ b/compiler/rustc_infer/src/infer/resolve.rs @@ -2,6 +2,7 @@ use rustc_middle::bug; use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFolder, TypeSuperFoldable}; use rustc_middle::ty::visit::TypeVisitableExt; use rustc_middle::ty::{self, Const, InferConst, Ty, TyCtxt, TypeFoldable}; +use rustc_type_ir::data_structures::DelayedMap; use super::{FixupError, FixupResult, InferCtxt}; @@ -15,12 +16,15 @@ use super::{FixupError, FixupResult, InferCtxt}; /// points for correctness. pub struct OpportunisticVarResolver<'a, 'tcx> { infcx: &'a InferCtxt<'tcx>, + /// We're able to use a cache here as the folder does + /// not have any mutable state. + cache: DelayedMap, Ty<'tcx>>, } impl<'a, 'tcx> OpportunisticVarResolver<'a, 'tcx> { #[inline] pub fn new(infcx: &'a InferCtxt<'tcx>) -> Self { - OpportunisticVarResolver { infcx } + OpportunisticVarResolver { infcx, cache: Default::default() } } } @@ -33,9 +37,13 @@ impl<'a, 'tcx> TypeFolder> for OpportunisticVarResolver<'a, 'tcx> { fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { if !t.has_non_region_infer() { t // micro-optimize -- if there is nothing in this type that this fold affects... + } else if let Some(&ty) = self.cache.get(&t) { + return ty; } else { - let t = self.infcx.shallow_resolve(t); - t.super_fold_with(self) + let shallow = self.infcx.shallow_resolve(t); + let res = shallow.super_fold_with(self); + assert!(self.cache.insert(t, res)); + res } } diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index c2241773c8cc..bd38b3c109a4 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -174,7 +174,7 @@ pub(crate) fn parse_check_cfg(dcx: DiagCtxtHandle<'_>, specs: Vec) -> Ch } }; - let meta_item = match parser.parse_meta_item(AllowLeadingUnsafe::Yes) { + let meta_item = match parser.parse_meta_item(AllowLeadingUnsafe::No) { Ok(meta_item) if parser.token == token::Eof => meta_item, Ok(..) => expected_error(), Err(err) => { @@ -427,7 +427,7 @@ pub fn run_compiler(config: Config, f: impl FnOnce(&Compiler) -> R + Se Err(e) => early_dcx.early_fatal(format!("failed to load fluent bundle: {e}")), }; - let mut locale_resources = Vec::from(config.locale_resources); + let mut locale_resources = config.locale_resources; locale_resources.push(codegen_backend.locale_resource()); let mut sess = rustc_session::build_session( diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index bba517915a2d..84b320975bba 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -912,7 +912,7 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> { let traits = tcx.traits(LOCAL_CRATE); for &tr in traits { - if !tcx.is_object_safe(tr) { + if !tcx.is_dyn_compatible(tr) { continue; } diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 57aa3deae806..895897eca6b8 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -770,7 +770,7 @@ fn test_unstable_options_tracking_hash() { tracked!(crate_attr, vec!["abc".to_string()]); tracked!(cross_crate_inline_threshold, InliningThreshold::Always); tracked!(debug_info_for_profiling, true); - tracked!(default_hidden_visibility, Some(true)); + tracked!(default_visibility, Some(rustc_target::spec::SymbolVisibility::Hidden)); tracked!(dep_info_omit_d_target, true); tracked!(direct_access_external_data, Some(true)); tracked!(dual_proc_macros, true); diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 375cfccbe9f7..8acb986bfc9d 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -514,7 +514,7 @@ lint_mixed_script_confusables = .includes_note = the usage includes {$includes} .note = please recheck to make sure their usages are indeed what you want -lint_multiple_supertrait_upcastable = `{$ident}` is object-safe and has multiple supertraits +lint_multiple_supertrait_upcastable = `{$ident}` is dyn-compatible and has multiple supertraits lint_named_argument_used_positionally = named argument `{$named_arg_name}` is not used by name .label_named_arg = this named argument is referred to by position in formatting string @@ -531,7 +531,7 @@ lint_non_binding_let_multi_suggestion = consider immediately dropping the value lint_non_binding_let_on_drop_type = - non-binding let on a type that implements `Drop` + non-binding let on a type that has a destructor lint_non_binding_let_on_sync_lock = non-binding let on a synchronization lock .label = this lock is not assigned to a binding and is immediately dropped diff --git a/compiler/rustc_lint/src/foreign_modules.rs b/compiler/rustc_lint/src/foreign_modules.rs index 1ead377607f1..816882962bef 100644 --- a/compiler/rustc_lint/src/foreign_modules.rs +++ b/compiler/rustc_lint/src/foreign_modules.rs @@ -280,7 +280,7 @@ fn structurally_same_type_impl<'tcx>( ensure_sufficient_stack(|| { match (a.kind(), b.kind()) { - (&Adt(a_def, _), &Adt(b_def, _)) => { + (&Adt(a_def, a_gen_args), &Adt(b_def, b_gen_args)) => { // Only `repr(C)` types can be compared structurally. if !(a_def.repr().c() && b_def.repr().c()) { return false; @@ -304,8 +304,8 @@ fn structurally_same_type_impl<'tcx>( seen_types, tcx, param_env, - tcx.type_of(a_did).instantiate_identity(), - tcx.type_of(b_did).instantiate_identity(), + tcx.type_of(a_did).instantiate(tcx, a_gen_args), + tcx.type_of(b_did).instantiate(tcx, b_gen_args), ckind, ) }, diff --git a/compiler/rustc_lint/src/if_let_rescope.rs b/compiler/rustc_lint/src/if_let_rescope.rs index 229d0c364217..cdd0e80c4589 100644 --- a/compiler/rustc_lint/src/if_let_rescope.rs +++ b/compiler/rustc_lint/src/if_let_rescope.rs @@ -122,7 +122,11 @@ impl IfLetRescope { } let tcx = cx.tcx; let source_map = tcx.sess.source_map(); - let expr_end = expr.span.shrink_to_hi(); + let expr_end = match expr.kind { + hir::ExprKind::If(_cond, conseq, None) => conseq.span.shrink_to_hi(), + hir::ExprKind::If(_cond, _conseq, Some(alt)) => alt.span.shrink_to_hi(), + _ => return, + }; let mut add_bracket_to_match_head = match_head_needs_bracket(tcx, expr); let mut significant_droppers = vec![]; let mut lifetime_ends = vec![]; @@ -145,7 +149,10 @@ impl IfLetRescope { recovered: Recovered::No, }) = cond.kind { - let if_let_pat = expr.span.shrink_to_lo().between(init.span); + // Peel off round braces + let if_let_pat = source_map + .span_take_while(expr.span, |&ch| ch == '(' || ch.is_whitespace()) + .between(init.span); // The consequent fragment is always a block. let before_conseq = conseq.span.shrink_to_lo(); let lifetime_end = source_map.end_point(conseq.span); @@ -159,6 +166,8 @@ impl IfLetRescope { if ty_ascription.is_some() || !expr.span.can_be_used_for_suggestions() || !pat.span.can_be_used_for_suggestions() + || !if_let_pat.can_be_used_for_suggestions() + || !before_conseq.can_be_used_for_suggestions() { // Our `match` rewrites does not support type ascription, // so we just bail. @@ -240,6 +249,23 @@ impl<'tcx> LateLintPass<'tcx> for IfLetRescope { if let (Level::Allow, _) = cx.tcx.lint_level_at_node(IF_LET_RESCOPE, expr.hir_id) { return; } + if let hir::ExprKind::Loop(block, _label, hir::LoopSource::While, _span) = expr.kind + && let Some(value) = block.expr + && let hir::ExprKind::If(cond, _conseq, _alt) = value.kind + && let hir::ExprKind::Let(..) = cond.kind + { + // Recall that `while let` is lowered into this: + // ``` + // loop { + // if let .. { body } else { break; } + // } + // ``` + // There is no observable change in drop order on the overall `if let` expression + // given that the `{ break; }` block is trivial so the edition change + // means nothing substantial to this `while` statement. + self.skip.insert(value.hir_id); + return; + } if expr_parent_is_stmt(cx.tcx, expr.hir_id) && matches!(expr.kind, hir::ExprKind::If(_cond, _conseq, None)) { @@ -304,7 +330,7 @@ impl Subdiagnostic for IfLetRescopeRewrite { .chain(repeat('}').take(closing_brackets.count)) .collect(), )); - let msg = f(diag, crate::fluent_generated::lint_suggestion.into()); + let msg = f(diag, crate::fluent_generated::lint_suggestion); diag.multipart_suggestion_with_style( msg, suggestions, diff --git a/compiler/rustc_lint/src/let_underscore.rs b/compiler/rustc_lint/src/let_underscore.rs index a12a97ee5730..abee9ee78699 100644 --- a/compiler/rustc_lint/src/let_underscore.rs +++ b/compiler/rustc_lint/src/let_underscore.rs @@ -51,7 +51,7 @@ declare_lint! { /// intent. pub LET_UNDERSCORE_DROP, Allow, - "non-binding let on a type that implements `Drop`" + "non-binding let on a type that has a destructor" } declare_lint! { diff --git a/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs b/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs index 78468020c4d5..9fde35f82d82 100644 --- a/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs +++ b/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs @@ -4,7 +4,7 @@ use rustc_session::{declare_lint, declare_lint_pass}; use crate::{LateContext, LateLintPass, LintContext}; declare_lint! { - /// The `multiple_supertrait_upcastable` lint detects when an object-safe trait has multiple + /// The `multiple_supertrait_upcastable` lint detects when a dyn-compatible trait has multiple /// supertraits. /// /// ### Example @@ -28,7 +28,7 @@ declare_lint! { /// additional overhead is justified. pub MULTIPLE_SUPERTRAIT_UPCASTABLE, Allow, - "detect when an object-safe trait has multiple supertraits", + "detect when a dyn-compatible trait has multiple supertraits", @feature_gate = multiple_supertrait_upcastable; } @@ -37,10 +37,10 @@ declare_lint_pass!(MultipleSupertraitUpcastable => [MULTIPLE_SUPERTRAIT_UPCASTAB impl<'tcx> LateLintPass<'tcx> for MultipleSupertraitUpcastable { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) { let def_id = item.owner_id.to_def_id(); - // NOTE(nbdd0121): use `object_safety_violations` instead of `is_object_safe` because + // NOTE(nbdd0121): use `object_safety_violations` instead of `is_dyn_compatible` because // the latter will report `where_clause_object_safety` lint. if let hir::ItemKind::Trait(_, _, _, _, _) = item.kind - && cx.tcx.is_object_safe(def_id) + && cx.tcx.is_dyn_compatible(def_id) { let direct_super_traits_iter = cx .tcx diff --git a/compiler/rustc_llvm/Cargo.toml b/compiler/rustc_llvm/Cargo.toml index 1f74aaf9965a..b29d6b79250f 100644 --- a/compiler/rustc_llvm/Cargo.toml +++ b/compiler/rustc_llvm/Cargo.toml @@ -10,5 +10,5 @@ libc = "0.2.73" [build-dependencies] # tidy-alphabetical-start -cc = "=1.0.105" # FIXME(cc): pinned to keep support for VS2013 +cc = "1.1.23" # tidy-alphabetical-end diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 165fb7aa6c3d..8f0b1b812765 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -732,12 +732,7 @@ extern "C" LLVMRustResult LLVMRustOptimize( PTO.SLPVectorization = SLPVectorize; PTO.MergeFunctions = MergeFunctions; - // FIXME: We may want to expose this as an option. - bool DebugPassManager = false; - PassInstrumentationCallbacks PIC; - StandardInstrumentations SI(TheModule->getContext(), DebugPassManager); - SI.registerCallbacks(PIC); if (LlvmSelfProfiler) { LLVMSelfProfileInitializeCallbacks(PIC, LlvmSelfProfiler, @@ -784,6 +779,12 @@ extern "C" LLVMRustResult LLVMRustOptimize( CGSCCAnalysisManager CGAM; ModuleAnalysisManager MAM; + // FIXME: We may want to expose this as an option. + bool DebugPassManager = false; + + StandardInstrumentations SI(TheModule->getContext(), DebugPassManager); + SI.registerCallbacks(PIC, &MAM); + if (LLVMPluginsLen) { auto PluginsStr = StringRef(LLVMPlugins, LLVMPluginsLen); SmallVector Plugins; diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 4425c93211a0..2157324d5cc3 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -1622,56 +1622,63 @@ impl<'a> CrateMetadataRef<'a> { ); for virtual_dir in virtual_rust_source_base_dir.iter().flatten() { - if let Some(real_dir) = &sess.opts.real_rust_source_base_dir { - if let rustc_span::FileName::Real(old_name) = name { - if let rustc_span::RealFileName::Remapped { local_path: _, virtual_name } = - old_name - { - if let Ok(rest) = virtual_name.strip_prefix(virtual_dir) { - let virtual_name = virtual_name.clone(); + if let Some(real_dir) = &sess.opts.real_rust_source_base_dir + && let rustc_span::FileName::Real(old_name) = name + && let rustc_span::RealFileName::Remapped { local_path: _, virtual_name } = + 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)); - // 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 = if is_std_lib { - real_dir.join("library").join(rest) - } else { - real_dir.join(rest) - }; + debug!( + "try_to_translate_virtual_to_real: `{}` -> `{}`", + virtual_name.display(), + new_path.display(), + ); - debug!( - "try_to_translate_virtual_to_real: `{}` -> `{}`", - virtual_name.display(), - new_path.display(), - ); - let new_name = rustc_span::RealFileName::Remapped { - local_path: Some(new_path), - virtual_name, - }; - *old_name = new_name; - } + // Check if the translated real path is affected by any user-requested + // remaps via --remap-path-prefix. Apply them if so. + // Note that this is a special case for imported rust-src paths specified by + // https://rust-lang.github.io/rfcs/3127-trim-paths.html#handling-sysroot-paths. + // Other imported paths are not currently remapped (see #66251). + let (user_remapped, applied) = + sess.source_map().path_mapping().map_prefix(&new_path); + let new_name = if applied { + rustc_span::RealFileName::Remapped { + local_path: Some(new_path.clone()), + virtual_name: user_remapped.to_path_buf(), } - } + } else { + rustc_span::RealFileName::LocalPath(new_path) + }; + *old_name = new_name; } } }; diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index 7050a06b8dc2..52fe9956b477 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -83,7 +83,7 @@ macro_rules! arena_types { >, [] effective_visibilities: rustc_middle::middle::privacy::EffectiveVisibilities, [] upvars_mentioned: rustc_data_structures::fx::FxIndexMap, - [] object_safety_violations: rustc_middle::traits::ObjectSafetyViolation, + [] dyn_compatibility_violations: rustc_middle::traits::DynCompatibilityViolation, [] codegen_unit: rustc_middle::mir::mono::CodegenUnit<'tcx>, [decode] attribute: rustc_ast::Attribute, [] name_set: rustc_data_structures::unord::UnordSet, diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index a32b19b067a5..70e61df1ab4d 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -61,6 +61,8 @@ #![feature(trait_upcasting)] #![feature(trusted_len)] #![feature(try_blocks)] +#![feature(try_trait_v2)] +#![feature(try_trait_v2_yeet)] #![feature(type_alias_impl_trait)] #![feature(yeet_expr)] #![warn(unreachable_pub)] diff --git a/compiler/rustc_middle/src/macros.rs b/compiler/rustc_middle/src/macros.rs index d385be007d33..39816c17b985 100644 --- a/compiler/rustc_middle/src/macros.rs +++ b/compiler/rustc_middle/src/macros.rs @@ -67,7 +67,7 @@ macro_rules! TrivialLiftImpls { }; } -/// Used for types that are `Copy` and which **do not care arena +/// Used for types that are `Copy` and which **do not care about arena /// allocated data** (i.e., don't need to be folded). #[macro_export] macro_rules! TrivialTypeTraversalImpls { diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index 54cfd9958321..ee34ccd889f7 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -217,7 +217,7 @@ pub fn early_report_macro_deprecation( suggestion_span: span, note: depr.note, path, - since_kind: deprecated_since_kind(is_in_effect, depr.since.clone()), + since_kind: deprecated_since_kind(is_in_effect, depr.since), }; lint_buffer.buffer_lint(deprecation_lint(is_in_effect), node_id, span, diag); } diff --git a/compiler/rustc_middle/src/mir/consts.rs b/compiler/rustc_middle/src/mir/consts.rs index 89d4c4601600..4262460d928b 100644 --- a/compiler/rustc_middle/src/mir/consts.rs +++ b/compiler/rustc_middle/src/mir/consts.rs @@ -148,7 +148,7 @@ impl<'tcx> ConstValue<'tcx> { /* read_provenance */ true, ) .ok()?; - let ptr = ptr.to_pointer(&tcx).ok()?; + let ptr = ptr.to_pointer(&tcx).discard_err()?; let len = a .read_scalar( &tcx, @@ -156,7 +156,7 @@ impl<'tcx> ConstValue<'tcx> { /* read_provenance */ false, ) .ok()?; - let len = len.to_target_usize(&tcx).ok()?; + let len = len.to_target_usize(&tcx).discard_err()?; if len == 0 { return Some(&[]); } @@ -221,7 +221,9 @@ pub enum Const<'tcx> { } impl<'tcx> Const<'tcx> { - pub fn identity_unevaluated( + /// Creates an unevaluated const from a `DefId` for a const item. + /// The binders of the const item still need to be instantiated. + pub fn from_unevaluated( tcx: TyCtxt<'tcx>, def_id: DefId, ) -> ty::EarlyBinder<'tcx, Const<'tcx>> { @@ -329,18 +331,6 @@ impl<'tcx> Const<'tcx> { } } - /// Normalizes the constant to a value or an error if possible. - #[inline] - pub fn normalize(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Self { - match self.eval(tcx, param_env, DUMMY_SP) { - Ok(val) => Self::Val(val, self.ty()), - Err(ErrorHandled::Reported(guar, _span)) => { - Self::Ty(Ty::new_error(tcx, guar.into()), ty::Const::new_error(tcx, guar.into())) - } - Err(ErrorHandled::TooGeneric(_span)) => self, - } - } - #[inline] pub fn try_eval_scalar( self, diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs index b8ecfa3c3f94..04d035e27ba3 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs @@ -20,7 +20,7 @@ use rustc_target::abi::{Align, HasDataLayout, Size}; use super::{ AllocId, BadBytesAccess, CtfeProvenance, InterpError, InterpResult, Pointer, PointerArithmetic, Provenance, ResourceExhaustionInfo, Scalar, ScalarSizeMismatch, UndefinedBehaviorInfo, - UnsupportedOpInfo, read_target_uint, write_target_uint, + UnsupportedOpInfo, interp_ok, read_target_uint, write_target_uint, }; use crate::ty; @@ -318,8 +318,9 @@ impl Allocation { pub fn try_uninit<'tcx>(size: Size, align: Align) -> InterpResult<'tcx, Self> { Self::uninit_inner(size, align, || { ty::tls::with(|tcx| tcx.dcx().delayed_bug("exhausted memory during interpretation")); - InterpError::ResourceExhaustion(ResourceExhaustionInfo::MemoryExhausted).into() + InterpError::ResourceExhaustion(ResourceExhaustionInfo::MemoryExhausted) }) + .into() } /// Try to create an Allocation of `size` bytes, panics if there is not enough memory @@ -355,12 +356,12 @@ impl Allocation { impl Allocation { /// Adjust allocation from the ones in `tcx` to a custom Machine instance /// with a different `Provenance` and `Byte` type. - pub fn adjust_from_tcx( + pub fn adjust_from_tcx<'tcx, Prov: Provenance, Bytes: AllocBytes>( &self, cx: &impl HasDataLayout, - mut alloc_bytes: impl FnMut(&[u8], Align) -> Result, - mut adjust_ptr: impl FnMut(Pointer) -> Result, Err>, - ) -> Result, Err> { + mut alloc_bytes: impl FnMut(&[u8], Align) -> InterpResult<'tcx, Bytes>, + mut adjust_ptr: impl FnMut(Pointer) -> InterpResult<'tcx, Pointer>, + ) -> InterpResult<'tcx, Allocation> { // Copy the data. let mut bytes = alloc_bytes(&*self.bytes, self.align)?; // Adjust provenance of pointers stored in this allocation. @@ -377,7 +378,7 @@ impl Allocation { new_provenance.push((offset, ptr_prov)); } // Create allocation. - Ok(Allocation { + interp_ok(Allocation { bytes, provenance: ProvenanceMap::from_presorted_ptrs(new_provenance), init_mask: self.init_mask.clone(), diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index 46646e759d59..431043b04319 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -1,7 +1,7 @@ use std::any::Any; use std::backtrace::Backtrace; use std::borrow::Cow; -use std::fmt; +use std::{convert, fmt, mem, ops}; use either::Either; use rustc_ast_ir::Mutability; @@ -104,6 +104,10 @@ rustc_data_structures::static_assert_size!(InterpErrorInfo<'_>, 8); /// These should always be constructed by calling `.into()` on /// an `InterpError`. In `rustc_mir::interpret`, we have `throw_err_*` /// macros for this. +/// +/// Interpreter errors must *not* be silently discarded (that will lead to a panic). Instead, +/// explicitly call `discard_err` if this is really the right thing to do. Note that if +/// this happens during const-eval or in Miri, it could lead to a UB error being lost! #[derive(Debug)] pub struct InterpErrorInfo<'tcx>(Box>); @@ -156,8 +160,11 @@ impl<'tcx> InterpErrorInfo<'tcx> { } pub fn into_kind(self) -> InterpError<'tcx> { - let InterpErrorInfo(box InterpErrorInfoInner { kind, .. }) = self; - kind + self.0.kind + } + + pub fn from_parts(kind: InterpError<'tcx>, backtrace: InterpErrorBacktrace) -> Self { + Self(Box::new(InterpErrorInfoInner { kind, backtrace })) } #[inline] @@ -599,8 +606,6 @@ pub enum InterpError<'tcx> { MachineStop(Box), } -pub type InterpResult<'tcx, T = ()> = Result>; - impl InterpError<'_> { /// Some errors do string formatting even if the error is never printed. /// To avoid performance issues, there are places where we want to be sure to never raise these formatting errors, @@ -728,3 +733,182 @@ macro_rules! throw_exhaust { macro_rules! throw_machine_stop { ($($tt:tt)*) => { do yeet $crate::err_machine_stop!($($tt)*) }; } + +/// Guard type that panics on drop. +#[derive(Debug)] +struct Guard; + +impl Drop for Guard { + fn drop(&mut self) { + // We silence the guard if we are already panicking, to avoid double-panics. + if !std::thread::panicking() { + panic!( + "an interpreter error got improperly discarded; use `discard_err()` if this is intentional" + ); + } + } +} + +/// The result type used by the interpreter. This is a newtype around `Result` +/// to block access to operations like `ok()` that discard UB errors. +/// +/// We also make things panic if this type is ever implicitly dropped. +#[derive(Debug)] +pub struct InterpResult_<'tcx, T> { + res: Result>, + guard: Guard, +} + +// Type alias to be able to set a default type argument. +pub type InterpResult<'tcx, T = ()> = InterpResult_<'tcx, T>; + +impl<'tcx, T> ops::Try for InterpResult_<'tcx, T> { + type Output = T; + type Residual = InterpResult_<'tcx, convert::Infallible>; + + #[inline] + fn from_output(output: Self::Output) -> Self { + InterpResult_::new(Ok(output)) + } + + #[inline] + fn branch(self) -> ops::ControlFlow { + match self.disarm() { + Ok(v) => ops::ControlFlow::Continue(v), + Err(e) => ops::ControlFlow::Break(InterpResult_::new(Err(e))), + } + } +} + +impl<'tcx, T> ops::FromResidual for InterpResult_<'tcx, T> { + #[inline] + #[track_caller] + fn from_residual(residual: InterpResult_<'tcx, convert::Infallible>) -> Self { + match residual.disarm() { + Err(e) => Self::new(Err(e)), + } + } +} + +// Allow `yeet`ing `InterpError` in functions returning `InterpResult_`. +impl<'tcx, T> ops::FromResidual>> for InterpResult_<'tcx, T> { + #[inline] + fn from_residual(ops::Yeet(e): ops::Yeet>) -> Self { + Self::new(Err(e.into())) + } +} + +// Allow `?` on `Result<_, InterpError>` in functions returning `InterpResult_`. +// This is useful e.g. for `option.ok_or_else(|| err_ub!(...))`. +impl<'tcx, T, E: Into>> ops::FromResidual> + for InterpResult_<'tcx, T> +{ + #[inline] + fn from_residual(residual: Result) -> Self { + match residual { + Err(e) => Self::new(Err(e.into())), + } + } +} + +impl<'tcx, T, E: Into>> From> for InterpResult<'tcx, T> { + #[inline] + fn from(value: Result) -> Self { + Self::new(value.map_err(|e| e.into())) + } +} + +impl<'tcx, T, V: FromIterator> FromIterator> for InterpResult<'tcx, V> { + fn from_iter>>(iter: I) -> Self { + Self::new(iter.into_iter().map(|x| x.disarm()).collect()) + } +} + +impl<'tcx, T> InterpResult_<'tcx, T> { + #[inline(always)] + fn new(res: Result>) -> Self { + Self { res, guard: Guard } + } + + #[inline(always)] + fn disarm(self) -> Result> { + mem::forget(self.guard); + self.res + } + + /// Discard the error information in this result. Only use this if ignoring Undefined Behavior is okay! + #[inline] + pub fn discard_err(self) -> Option { + self.disarm().ok() + } + + /// Look at the `Result` wrapped inside of this. + /// Must only be used to report the error! + #[inline] + pub fn report_err(self) -> Result> { + self.disarm() + } + + #[inline] + pub fn map(self, f: impl FnOnce(T) -> U) -> InterpResult<'tcx, U> { + InterpResult_::new(self.disarm().map(f)) + } + + #[inline] + pub fn map_err( + self, + f: impl FnOnce(InterpErrorInfo<'tcx>) -> InterpErrorInfo<'tcx>, + ) -> InterpResult<'tcx, T> { + InterpResult_::new(self.disarm().map_err(f)) + } + + #[inline] + pub fn inspect_err(self, f: impl FnOnce(&InterpErrorInfo<'tcx>)) -> InterpResult<'tcx, T> { + InterpResult_::new(self.disarm().inspect_err(f)) + } + + #[inline] + #[track_caller] + pub fn unwrap(self) -> T { + self.disarm().unwrap() + } + + #[inline] + #[track_caller] + pub fn unwrap_or_else(self, f: impl FnOnce(InterpErrorInfo<'tcx>) -> T) -> T { + self.disarm().unwrap_or_else(f) + } + + #[inline] + #[track_caller] + pub fn expect(self, msg: &str) -> T { + self.disarm().expect(msg) + } + + #[inline] + pub fn and_then(self, f: impl FnOnce(T) -> InterpResult<'tcx, U>) -> InterpResult<'tcx, U> { + InterpResult_::new(self.disarm().and_then(|t| f(t).disarm())) + } + + /// Returns success if both `self` and `other` succeed, while ensuring we don't + /// accidentally drop an error. + /// + /// If both are an error, `self` will be reported. + #[inline] + pub fn and(self, other: InterpResult<'tcx, U>) -> InterpResult<'tcx, (T, U)> { + match self.disarm() { + Ok(t) => interp_ok((t, other?)), + Err(e) => { + // Discard the other error. + drop(other.disarm()); + // Return `self`. + InterpResult_::new(Err(e)) + } + } + } +} + +#[inline(always)] +pub fn interp_ok<'tcx, T>(x: T) -> InterpResult<'tcx, T> { + InterpResult_::new(Ok(x)) +} diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index d7809cc4343d..115bcdbc5898 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -39,7 +39,7 @@ pub use self::error::{ InterpError, InterpErrorInfo, InterpResult, InvalidMetaKind, InvalidProgramInfo, MachineStopType, Misalignment, PointerKind, ReportedErrorInfo, ResourceExhaustionInfo, ScalarSizeMismatch, UndefinedBehaviorInfo, UnsupportedOpInfo, ValidationErrorInfo, - ValidationErrorKind, + ValidationErrorKind, interp_ok, }; pub use self::pointer::{CtfeProvenance, Pointer, PointerArithmetic, Provenance}; pub use self::value::Scalar; diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs index c6c2ab414ed4..061a55bfda8d 100644 --- a/compiler/rustc_middle/src/mir/interpret/value.rs +++ b/compiler/rustc_middle/src/mir/interpret/value.rs @@ -8,7 +8,7 @@ use rustc_target::abi::{HasDataLayout, Size}; use super::{ AllocId, CtfeProvenance, InterpResult, Pointer, PointerArithmetic, Provenance, - ScalarSizeMismatch, + ScalarSizeMismatch, interp_ok, }; use crate::ty::ScalarInt; @@ -273,10 +273,10 @@ impl<'tcx, Prov: Provenance> Scalar { .to_bits_or_ptr_internal(cx.pointer_size()) .map_err(|s| err_ub!(ScalarSizeMismatch(s)))? { - Right(ptr) => Ok(ptr.into()), + Right(ptr) => interp_ok(ptr.into()), Left(bits) => { let addr = u64::try_from(bits).unwrap(); - Ok(Pointer::from_addr_invalid(addr)) + interp_ok(Pointer::from_addr_invalid(addr)) } } } @@ -311,12 +311,12 @@ impl<'tcx, Prov: Provenance> Scalar { if matches!(self, Scalar::Ptr(..)) { *self = self.to_scalar_int()?.into(); } - Ok(()) + interp_ok(()) } #[inline(always)] pub fn to_scalar_int(self) -> InterpResult<'tcx, ScalarInt> { - self.try_to_scalar_int().map_err(|_| err_unsup!(ReadPointerAsInt(None)).into()) + self.try_to_scalar_int().map_err(|_| err_unsup!(ReadPointerAsInt(None))).into() } #[inline(always)] @@ -330,20 +330,22 @@ impl<'tcx, Prov: Provenance> Scalar { #[inline] pub fn to_bits(self, target_size: Size) -> InterpResult<'tcx, u128> { assert_ne!(target_size.bytes(), 0, "you should never look at the bits of a ZST"); - self.to_scalar_int()?.try_to_bits(target_size).map_err(|size| { - err_ub!(ScalarSizeMismatch(ScalarSizeMismatch { - target_size: target_size.bytes(), - data_size: size.bytes(), - })) + self.to_scalar_int()? + .try_to_bits(target_size) + .map_err(|size| { + err_ub!(ScalarSizeMismatch(ScalarSizeMismatch { + target_size: target_size.bytes(), + data_size: size.bytes(), + })) + }) .into() - }) } pub fn to_bool(self) -> InterpResult<'tcx, bool> { let val = self.to_u8()?; match val { - 0 => Ok(false), - 1 => Ok(true), + 0 => interp_ok(false), + 1 => interp_ok(true), _ => throw_ub!(InvalidBool(val)), } } @@ -351,7 +353,7 @@ impl<'tcx, Prov: Provenance> Scalar { pub fn to_char(self) -> InterpResult<'tcx, char> { let val = self.to_u32()?; match std::char::from_u32(val) { - Some(c) => Ok(c), + Some(c) => interp_ok(c), None => throw_ub!(InvalidChar(val)), } } @@ -392,7 +394,7 @@ impl<'tcx, Prov: Provenance> Scalar { /// Fails if the scalar is a pointer. pub fn to_target_usize(self, cx: &impl HasDataLayout) -> InterpResult<'tcx, u64> { let b = self.to_uint(cx.data_layout().pointer_size)?; - Ok(u64::try_from(b).unwrap()) + interp_ok(u64::try_from(b).unwrap()) } /// Converts the scalar to produce a signed integer of the given size. @@ -400,7 +402,7 @@ impl<'tcx, Prov: Provenance> Scalar { #[inline] pub fn to_int(self, size: Size) -> InterpResult<'tcx, i128> { let b = self.to_bits(size)?; - Ok(size.sign_extend(b)) + interp_ok(size.sign_extend(b)) } /// Converts the scalar to produce an `i8`. Fails if the scalar is a pointer. @@ -432,13 +434,13 @@ impl<'tcx, Prov: Provenance> Scalar { /// Fails if the scalar is a pointer. pub fn to_target_isize(self, cx: &impl HasDataLayout) -> InterpResult<'tcx, i64> { let b = self.to_int(cx.data_layout().pointer_size)?; - Ok(i64::try_from(b).unwrap()) + interp_ok(i64::try_from(b).unwrap()) } #[inline] pub fn to_float(self) -> InterpResult<'tcx, F> { // Going through `to_bits` to check size and truncation. - Ok(F::from_bits(self.to_bits(Size::from_bits(F::BITS))?)) + interp_ok(F::from_bits(self.to_bits(Size::from_bits(F::BITS))?)) } #[inline] diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index 954f746ce5b6..56ca9167d4da 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -15,6 +15,7 @@ use rustc_query_system::ich::StableHashingContext; use rustc_session::config::OptLevel; use rustc_span::Span; use rustc_span::symbol::Symbol; +use rustc_target::spec::SymbolVisibility; use tracing::debug; use crate::dep_graph::{DepNode, WorkProduct, WorkProductId}; @@ -305,6 +306,16 @@ pub enum Visibility { Protected, } +impl From for Visibility { + fn from(value: SymbolVisibility) -> Self { + match value { + SymbolVisibility::Hidden => Visibility::Hidden, + SymbolVisibility::Protected => Visibility::Protected, + SymbolVisibility::Interposable => Visibility::Default, + } + } +} + impl<'tcx> CodegenUnit<'tcx> { #[inline] pub fn new(name: Symbol) -> CodegenUnit<'tcx> { diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 9609ef46d5c3..989fbd711c3c 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -70,8 +70,8 @@ use crate::traits::query::{ MethodAutoderefStepsResult, NoSolution, NormalizationResult, OutlivesBound, }; use crate::traits::{ - CodegenObligationError, EvaluationResult, ImplSource, ObjectSafetyViolation, ObligationCause, - OverflowError, WellFormedLoc, specialization_graph, + CodegenObligationError, DynCompatibilityViolation, EvaluationResult, ImplSource, + ObligationCause, OverflowError, WellFormedLoc, specialization_graph, }; use crate::ty::fast_reject::SimplifiedType; use crate::ty::layout::ValidityRequirement; @@ -1344,11 +1344,11 @@ rustc_queries! { cache_on_disk_if { true } ensure_forwards_result_if_red } - query object_safety_violations(trait_id: DefId) -> &'tcx [ObjectSafetyViolation] { - desc { |tcx| "determining object safety of trait `{}`", tcx.def_path_str(trait_id) } + query dyn_compatibility_violations(trait_id: DefId) -> &'tcx [DynCompatibilityViolation] { + desc { |tcx| "determining dyn-compatibility of trait `{}`", tcx.def_path_str(trait_id) } } - query is_object_safe(trait_id: DefId) -> bool { - desc { |tcx| "checking if trait `{}` is object safe", tcx.def_path_str(trait_id) } + query is_dyn_compatible(trait_id: DefId) -> bool { + desc { |tcx| "checking if trait `{}` is dyn-compatible", tcx.def_path_str(trait_id) } } /// Gets the ParameterEnvironment for a given item; this environment diff --git a/compiler/rustc_middle/src/query/on_disk_cache.rs b/compiler/rustc_middle/src/query/on_disk_cache.rs index 06c9ebc87b5a..35a16684615d 100644 --- a/compiler/rustc_middle/src/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/query/on_disk_cache.rs @@ -233,7 +233,7 @@ impl<'sess> OnDiskCache<'sess> { for (index, file) in files.iter().enumerate() { let index = SourceFileIndex(index as u32); - let file_ptr: *const SourceFile = std::ptr::addr_of!(**file); + let file_ptr: *const SourceFile = &raw const **file; file_to_file_index.insert(file_ptr, index); let source_file_id = EncodedSourceFileId::new(tcx, file); file_index_to_stable_id.insert(index, source_file_id); @@ -827,7 +827,7 @@ pub struct CacheEncoder<'a, 'tcx> { impl<'a, 'tcx> CacheEncoder<'a, 'tcx> { #[inline] fn source_file_index(&mut self, source_file: Lrc) -> SourceFileIndex { - self.file_to_file_index[&std::ptr::addr_of!(*source_file)] + self.file_to_file_index[&(&raw const *source_file)] } /// Encode something with additional information that allows to do some diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index c3295a9ce51c..caa86da8a858 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -556,8 +556,8 @@ pub enum SelectionError<'tcx> { /// (which for closures includes the "input" type params) and they /// didn't resolve. See `confirm_poly_trait_refs` for more. SignatureMismatch(Box>), - /// The trait pointed by `DefId` is not object safe. - TraitNotObjectSafe(DefId), + /// The trait pointed by `DefId` is dyn-incompatible. + TraitDynIncompatible(DefId), /// A given constant couldn't be evaluated. NotConstEvaluatable(NotConstEvaluatable), /// Exceeded the recursion depth during type projection. @@ -690,7 +690,7 @@ pub struct ImplSourceUserDefinedData<'tcx, N> { } #[derive(Clone, Debug, PartialEq, Eq, Hash, HashStable, PartialOrd, Ord)] -pub enum ObjectSafetyViolation { +pub enum DynCompatibilityViolation { /// `Self: Sized` declared on the trait. SizedSelf(SmallVec<[Span; 1]>), @@ -711,11 +711,11 @@ pub enum ObjectSafetyViolation { GAT(Symbol, Span), } -impl ObjectSafetyViolation { +impl DynCompatibilityViolation { pub fn error_msg(&self) -> Cow<'static, str> { match self { - ObjectSafetyViolation::SizedSelf(_) => "it requires `Self: Sized`".into(), - ObjectSafetyViolation::SupertraitSelf(ref spans) => { + DynCompatibilityViolation::SizedSelf(_) => "it requires `Self: Sized`".into(), + DynCompatibilityViolation::SupertraitSelf(ref spans) => { if spans.iter().any(|sp| *sp != DUMMY_SP) { "it uses `Self` as a type parameter".into() } else { @@ -723,81 +723,87 @@ impl ObjectSafetyViolation { .into() } } - ObjectSafetyViolation::SupertraitNonLifetimeBinder(_) => { + DynCompatibilityViolation::SupertraitNonLifetimeBinder(_) => { "where clause cannot reference non-lifetime `for<...>` variables".into() } - ObjectSafetyViolation::Method(name, MethodViolationCode::StaticMethod(_), _) => { + DynCompatibilityViolation::Method(name, MethodViolationCode::StaticMethod(_), _) => { format!("associated function `{name}` has no `self` parameter").into() } - ObjectSafetyViolation::Method( + DynCompatibilityViolation::Method( name, MethodViolationCode::ReferencesSelfInput(_), DUMMY_SP, ) => format!("method `{name}` references the `Self` type in its parameters").into(), - ObjectSafetyViolation::Method(name, MethodViolationCode::ReferencesSelfInput(_), _) => { - format!("method `{name}` references the `Self` type in this parameter").into() - } - ObjectSafetyViolation::Method(name, MethodViolationCode::ReferencesSelfOutput, _) => { - format!("method `{name}` references the `Self` type in its return type").into() - } - ObjectSafetyViolation::Method( + DynCompatibilityViolation::Method( + name, + MethodViolationCode::ReferencesSelfInput(_), + _, + ) => format!("method `{name}` references the `Self` type in this parameter").into(), + DynCompatibilityViolation::Method( + name, + MethodViolationCode::ReferencesSelfOutput, + _, + ) => format!("method `{name}` references the `Self` type in its return type").into(), + DynCompatibilityViolation::Method( name, MethodViolationCode::ReferencesImplTraitInTrait(_), _, ) => { format!("method `{name}` references an `impl Trait` type in its return type").into() } - ObjectSafetyViolation::Method(name, MethodViolationCode::AsyncFn, _) => { + DynCompatibilityViolation::Method(name, MethodViolationCode::AsyncFn, _) => { format!("method `{name}` is `async`").into() } - ObjectSafetyViolation::Method( + DynCompatibilityViolation::Method( name, MethodViolationCode::WhereClauseReferencesSelf, _, ) => format!("method `{name}` references the `Self` type in its `where` clause").into(), - ObjectSafetyViolation::Method(name, MethodViolationCode::Generic, _) => { + DynCompatibilityViolation::Method(name, MethodViolationCode::Generic, _) => { format!("method `{name}` has generic type parameters").into() } - ObjectSafetyViolation::Method( + DynCompatibilityViolation::Method( name, MethodViolationCode::UndispatchableReceiver(_), _, ) => format!("method `{name}`'s `self` parameter cannot be dispatched on").into(), - ObjectSafetyViolation::AssocConst(name, DUMMY_SP) => { + DynCompatibilityViolation::AssocConst(name, DUMMY_SP) => { format!("it contains associated `const` `{name}`").into() } - ObjectSafetyViolation::AssocConst(..) => "it contains this associated `const`".into(), - ObjectSafetyViolation::GAT(name, _) => { + DynCompatibilityViolation::AssocConst(..) => { + "it contains this associated `const`".into() + } + DynCompatibilityViolation::GAT(name, _) => { format!("it contains the generic associated type `{name}`").into() } } } - pub fn solution(&self) -> ObjectSafetyViolationSolution { + pub fn solution(&self) -> DynCompatibilityViolationSolution { match self { - ObjectSafetyViolation::SizedSelf(_) - | ObjectSafetyViolation::SupertraitSelf(_) - | ObjectSafetyViolation::SupertraitNonLifetimeBinder(..) => { - ObjectSafetyViolationSolution::None + DynCompatibilityViolation::SizedSelf(_) + | DynCompatibilityViolation::SupertraitSelf(_) + | DynCompatibilityViolation::SupertraitNonLifetimeBinder(..) => { + DynCompatibilityViolationSolution::None } - ObjectSafetyViolation::Method( + DynCompatibilityViolation::Method( name, MethodViolationCode::StaticMethod(Some((add_self_sugg, make_sized_sugg))), _, - ) => ObjectSafetyViolationSolution::AddSelfOrMakeSized { + ) => DynCompatibilityViolationSolution::AddSelfOrMakeSized { name: *name, add_self_sugg: add_self_sugg.clone(), make_sized_sugg: make_sized_sugg.clone(), }, - ObjectSafetyViolation::Method( + DynCompatibilityViolation::Method( name, MethodViolationCode::UndispatchableReceiver(Some(span)), _, - ) => ObjectSafetyViolationSolution::ChangeToRefSelf(*name, *span), - ObjectSafetyViolation::AssocConst(name, _) - | ObjectSafetyViolation::GAT(name, _) - | ObjectSafetyViolation::Method(name, ..) => { - ObjectSafetyViolationSolution::MoveToAnotherTrait(*name) + ) => DynCompatibilityViolationSolution::ChangeToRefSelf(*name, *span), + DynCompatibilityViolation::AssocConst(name, _) + | DynCompatibilityViolation::GAT(name, _) + | DynCompatibilityViolation::Method(name, ..) => { + DynCompatibilityViolationSolution::MoveToAnotherTrait(*name) } } } @@ -806,12 +812,12 @@ impl ObjectSafetyViolation { // When `span` comes from a separate crate, it'll be `DUMMY_SP`. Treat it as `None` so // diagnostics use a `note` instead of a `span_label`. match self { - ObjectSafetyViolation::SupertraitSelf(spans) - | ObjectSafetyViolation::SizedSelf(spans) - | ObjectSafetyViolation::SupertraitNonLifetimeBinder(spans) => spans.clone(), - ObjectSafetyViolation::AssocConst(_, span) - | ObjectSafetyViolation::GAT(_, span) - | ObjectSafetyViolation::Method(_, _, span) + DynCompatibilityViolation::SupertraitSelf(spans) + | DynCompatibilityViolation::SizedSelf(spans) + | DynCompatibilityViolation::SupertraitNonLifetimeBinder(spans) => spans.clone(), + DynCompatibilityViolation::AssocConst(_, span) + | DynCompatibilityViolation::GAT(_, span) + | DynCompatibilityViolation::Method(_, _, span) if *span != DUMMY_SP => { smallvec![*span] @@ -822,7 +828,7 @@ impl ObjectSafetyViolation { } #[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -pub enum ObjectSafetyViolationSolution { +pub enum DynCompatibilityViolationSolution { None, AddSelfOrMakeSized { name: Symbol, @@ -833,11 +839,11 @@ pub enum ObjectSafetyViolationSolution { MoveToAnotherTrait(Symbol), } -impl ObjectSafetyViolationSolution { +impl DynCompatibilityViolationSolution { pub fn add_to(self, err: &mut Diag<'_, G>) { match self { - ObjectSafetyViolationSolution::None => {} - ObjectSafetyViolationSolution::AddSelfOrMakeSized { + DynCompatibilityViolationSolution::None => {} + DynCompatibilityViolationSolution::AddSelfOrMakeSized { name, add_self_sugg, make_sized_sugg, @@ -860,7 +866,7 @@ impl ObjectSafetyViolationSolution { Applicability::MaybeIncorrect, ); } - ObjectSafetyViolationSolution::ChangeToRefSelf(name, span) => { + DynCompatibilityViolationSolution::ChangeToRefSelf(name, span) => { err.span_suggestion( span, format!("consider changing method `{name}`'s `self` parameter to be `&self`"), @@ -868,14 +874,14 @@ impl ObjectSafetyViolationSolution { Applicability::MachineApplicable, ); } - ObjectSafetyViolationSolution::MoveToAnotherTrait(name) => { + DynCompatibilityViolationSolution::MoveToAnotherTrait(name) => { err.help(format!("consider moving `{name}` to another trait")); } } } } -/// Reasons a method might not be object-safe. +/// Reasons a method might not be dyn-compatible. #[derive(Clone, Debug, PartialEq, Eq, Hash, HashStable, PartialOrd, Ord)] pub enum MethodViolationCode { /// e.g., `fn foo()` diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index 73d0acf95f4f..389d20f315ff 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -519,7 +519,7 @@ impl<'tcx> Const<'tcx> { } pub fn try_to_bool(self) -> Option { - self.try_to_scalar()?.to_bool().ok() + self.try_to_valtree()?.try_to_scalar_int()?.try_to_bool().ok() } #[inline] diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index f017216489d0..2ffb273cb6fc 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -527,8 +527,8 @@ impl<'tcx> Interner for TyCtxt<'tcx> { self.trait_is_alias(trait_def_id) } - fn trait_is_object_safe(self, trait_def_id: DefId) -> bool { - self.is_object_safe(trait_def_id) + fn trait_is_dyn_compatible(self, trait_def_id: DefId) -> bool { + self.is_dyn_compatible(trait_def_id) } fn trait_is_fundamental(self, def_id: DefId) -> bool { @@ -622,11 +622,13 @@ bidirectional_lang_item_map! { Destruct, DiscriminantKind, DynMetadata, + EffectsCompat, EffectsIntersection, EffectsIntersectionOutput, EffectsMaybe, EffectsNoRuntime, EffectsRuntime, + EffectsTyCompat, Fn, FnMut, FnOnce, diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs index fc079592583e..92a975c028e5 100644 --- a/compiler/rustc_middle/src/ty/flags.rs +++ b/compiler/rustc_middle/src/ty/flags.rs @@ -301,7 +301,7 @@ impl FlagComputation { ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => { self.add_args(slice::from_ref(&arg)); } - ty::PredicateKind::ObjectSafe(_def_id) => {} + ty::PredicateKind::DynCompatible(_def_id) => {} ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(uv)) => { self.add_const(uv); } diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index 2ee7497497aa..b5a77b3c9423 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -1,5 +1,6 @@ use rustc_data_structures::fx::FxIndexMap; use rustc_hir::def_id::DefId; +use rustc_type_ir::data_structures::DelayedMap; pub use rustc_type_ir::fold::{ FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldable, shift_region, shift_vars, }; @@ -131,12 +132,20 @@ impl<'a, 'tcx> TypeFolder> for RegionFolder<'a, 'tcx> { /////////////////////////////////////////////////////////////////////////// // Bound vars replacer +/// A delegate used when instantiating bound vars. +/// +/// Any implementation must make sure that each bound variable always +/// gets mapped to the same result. `BoundVarReplacer` caches by using +/// a `DelayedMap` which does not cache the first few types it encounters. pub trait BoundVarReplacerDelegate<'tcx> { fn replace_region(&mut self, br: ty::BoundRegion) -> ty::Region<'tcx>; fn replace_ty(&mut self, bt: ty::BoundTy) -> Ty<'tcx>; fn replace_const(&mut self, bv: ty::BoundVar) -> ty::Const<'tcx>; } +/// A simple delegate taking 3 mutable functions. The used functions must +/// always return the same result for each bound variable, no matter how +/// frequently they are called. pub struct FnMutDelegate<'a, 'tcx> { pub regions: &'a mut (dyn FnMut(ty::BoundRegion) -> ty::Region<'tcx> + 'a), pub types: &'a mut (dyn FnMut(ty::BoundTy) -> Ty<'tcx> + 'a), @@ -164,11 +173,15 @@ struct BoundVarReplacer<'tcx, D> { current_index: ty::DebruijnIndex, delegate: D, + + /// This cache only tracks the `DebruijnIndex` and assumes that it does not matter + /// for the delegate how often its methods get used. + cache: DelayedMap<(ty::DebruijnIndex, Ty<'tcx>), Ty<'tcx>>, } impl<'tcx, D: BoundVarReplacerDelegate<'tcx>> BoundVarReplacer<'tcx, D> { fn new(tcx: TyCtxt<'tcx>, delegate: D) -> Self { - BoundVarReplacer { tcx, current_index: ty::INNERMOST, delegate } + BoundVarReplacer { tcx, current_index: ty::INNERMOST, delegate, cache: Default::default() } } } @@ -197,8 +210,17 @@ where debug_assert!(!ty.has_vars_bound_above(ty::INNERMOST)); ty::fold::shift_vars(self.tcx, ty, self.current_index.as_u32()) } - _ if t.has_vars_bound_at_or_above(self.current_index) => t.super_fold_with(self), - _ => t, + _ => { + if !t.has_vars_bound_at_or_above(self.current_index) { + t + } else if let Some(&t) = self.cache.get(&(self.current_index, t)) { + t + } else { + let res = t.super_fold_with(self); + assert!(self.cache.insert((self.current_index, t), res)); + res + } + } } } diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index bfef4c4c8c6b..b1c5ff50fdc8 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -50,7 +50,7 @@ pub enum ReifyReason { /// * A vtable entry is directly converted to a function call (e.g. creating a fn ptr from a /// method on a `dyn` object). /// * A function with `#[track_caller]` is converted to a function pointer - /// * If KCFI is enabled, creating a function pointer from a method on an object-safe trait. + /// * If KCFI is enabled, creating a function pointer from a method on a dyn-compatible trait. /// This includes the case of converting `::call`-like methods on closure-likes to function /// pointers. FnPtr, diff --git a/compiler/rustc_middle/src/ty/list.rs b/compiler/rustc_middle/src/ty/list.rs index ec9ca65dbda8..ea07cd3a1b9f 100644 --- a/compiler/rustc_middle/src/ty/list.rs +++ b/compiler/rustc_middle/src/ty/list.rs @@ -103,13 +103,13 @@ impl RawList { let mem = arena.dropless.alloc_raw(layout) as *mut RawList; unsafe { // Write the header - ptr::addr_of_mut!((*mem).skel.header).write(header); + (&raw mut (*mem).skel.header).write(header); // Write the length - ptr::addr_of_mut!((*mem).skel.len).write(slice.len()); + (&raw mut (*mem).skel.len).write(slice.len()); // Write the elements - ptr::addr_of_mut!((*mem).skel.data) + (&raw mut (*mem).skel.data) .cast::() .copy_from_nonoverlapping(slice.as_ptr(), slice.len()); @@ -160,7 +160,7 @@ macro_rules! impl_list_empty { // SAFETY: `EMPTY` is sufficiently aligned to be an empty list for all // types with `align_of(T) <= align_of(MaxAlign)`, which we checked above. - unsafe { &*(std::ptr::addr_of!(EMPTY) as *const RawList<$header_ty, T>) } + unsafe { &*((&raw const EMPTY) as *const RawList<$header_ty, T>) } } } }; @@ -238,7 +238,7 @@ impl Deref for RawList { impl AsRef<[T]> for RawList { #[inline(always)] fn as_ref(&self) -> &[T] { - let data_ptr = ptr::addr_of!(self.skel.data).cast::(); + let data_ptr = (&raw const self.skel.data).cast::(); // SAFETY: `data_ptr` has the same provenance as `self` and can therefore // access the `self.skel.len` elements stored at `self.skel.data`. // Note that we specifically don't reborrow `&self.skel.data`, because that diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 2b1212a5eb56..c4a28845085d 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -186,7 +186,7 @@ pub struct ResolverGlobalCtxt { pub proc_macros: Vec, /// Mapping from ident span to path span for paths that don't exist as written, but that /// exist under `std`. For example, wrote `str::from_utf8` instead of `std::str::from_utf8`. - pub confused_type_with_std_module: FxHashMap, + pub confused_type_with_std_module: FxIndexMap, pub doc_link_resolutions: FxHashMap, pub doc_link_traits_in_scope: FxHashMap>, pub all_macro_rules: FxHashMap>, diff --git a/compiler/rustc_middle/src/ty/predicate.rs b/compiler/rustc_middle/src/ty/predicate.rs index 534a8c99c5ad..fd4e8f1cd4e7 100644 --- a/compiler/rustc_middle/src/ty/predicate.rs +++ b/compiler/rustc_middle/src/ty/predicate.rs @@ -36,7 +36,7 @@ pub type PolyProjectionPredicate<'tcx> = ty::Binder<'tcx, ProjectionPredicate<'t /// A statement that can be proven by a trait solver. This includes things that may /// show up in where clauses, such as trait predicates and projection predicates, -/// and also things that are emitted as part of type checking such as `ObjectSafe` +/// and also things that are emitted as part of type checking such as `DynCompatible` /// predicate which is emitted when a type is coerced to a trait object. /// /// Use this rather than `PredicateKind`, whenever possible. @@ -147,7 +147,7 @@ impl<'tcx> Predicate<'tcx> { | PredicateKind::Clause(ClauseKind::TypeOutlives(_)) | PredicateKind::Clause(ClauseKind::Projection(_)) | PredicateKind::Clause(ClauseKind::ConstArgHasType(..)) - | PredicateKind::ObjectSafe(_) + | PredicateKind::DynCompatible(_) | PredicateKind::Subtype(_) | PredicateKind::Coerce(_) | PredicateKind::Clause(ClauseKind::ConstEvaluatable(_)) @@ -647,7 +647,7 @@ impl<'tcx> Predicate<'tcx> { | PredicateKind::Coerce(..) | PredicateKind::Clause(ClauseKind::RegionOutlives(..)) | PredicateKind::Clause(ClauseKind::WellFormed(..)) - | PredicateKind::ObjectSafe(..) + | PredicateKind::DynCompatible(..) | PredicateKind::Clause(ClauseKind::TypeOutlives(..)) | PredicateKind::Clause(ClauseKind::ConstEvaluatable(..)) | PredicateKind::ConstEquate(..) @@ -667,7 +667,7 @@ impl<'tcx> Predicate<'tcx> { | PredicateKind::Coerce(..) | PredicateKind::Clause(ClauseKind::RegionOutlives(..)) | PredicateKind::Clause(ClauseKind::WellFormed(..)) - | PredicateKind::ObjectSafe(..) + | PredicateKind::DynCompatible(..) | PredicateKind::Clause(ClauseKind::TypeOutlives(..)) | PredicateKind::Clause(ClauseKind::ConstEvaluatable(..)) | PredicateKind::ConstEquate(..) diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 5b4ee2791f8d..7ada5fd93ba7 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1951,19 +1951,18 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { fn pretty_print_bound_constness( &mut self, - trait_ref: ty::TraitRef<'tcx>, + constness: ty::BoundConstness, ) -> Result<(), PrintError> { define_scoped_cx!(self); - let Some(idx) = self.tcx().generics_of(trait_ref.def_id).host_effect_index else { - return Ok(()); - }; - let arg = trait_ref.args.const_at(idx); - - if arg == self.tcx().consts.false_ { - p!("const "); - } else if arg != self.tcx().consts.true_ && !arg.has_infer() { - p!("~const "); + match constness { + ty::BoundConstness::NotConst => {} + ty::BoundConstness::Const => { + p!("const "); + } + ty::BoundConstness::ConstIfConst => { + p!("~const "); + } } Ok(()) } @@ -2948,6 +2947,15 @@ impl<'tcx> ty::TraitPredicate<'tcx> { } } +#[derive(Copy, Clone, TypeFoldable, TypeVisitable, Lift)] +pub struct TraitPredPrintWithBoundConstness<'tcx>(ty::TraitPredicate<'tcx>, ty::BoundConstness); + +impl<'tcx> fmt::Debug for TraitPredPrintWithBoundConstness<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(self, f) + } +} + #[extension(pub trait PrintPolyTraitPredicateExt<'tcx>)] impl<'tcx> ty::PolyTraitPredicate<'tcx> { fn print_modifiers_and_trait_path( @@ -2955,6 +2963,13 @@ impl<'tcx> ty::PolyTraitPredicate<'tcx> { ) -> ty::Binder<'tcx, TraitPredPrintModifiersAndPath<'tcx>> { self.map_bound(TraitPredPrintModifiersAndPath) } + + fn print_with_bound_constness( + self, + constness: ty::BoundConstness, + ) -> ty::Binder<'tcx, TraitPredPrintWithBoundConstness<'tcx>> { + self.map_bound(|trait_pred| TraitPredPrintWithBoundConstness(trait_pred, constness)) + } } #[derive(Debug, Copy, Clone, Lift)] @@ -3052,7 +3067,6 @@ define_print! { ty::TraitPredicate<'tcx> { p!(print(self.trait_ref.self_ty()), ": "); - p!(pretty_print_bound_constness(self.trait_ref)); if let ty::PredicatePolarity::Negative = self.polarity { p!("!"); } @@ -3088,8 +3102,8 @@ define_print! { } ty::PredicateKind::Subtype(predicate) => p!(print(predicate)), ty::PredicateKind::Coerce(predicate) => p!(print(predicate)), - ty::PredicateKind::ObjectSafe(trait_def_id) => { - p!("the trait `", print_def_path(trait_def_id, &[]), "` is object-safe") + ty::PredicateKind::DynCompatible(trait_def_id) => { + p!("the trait `", print_def_path(trait_def_id, &[]), "` is dyn-compatible") } ty::PredicateKind::ConstEquate(c1, c2) => { p!("the constant `", print(c1), "` equals `", print(c2), "`") @@ -3184,13 +3198,21 @@ define_print_and_forward_display! { } TraitPredPrintModifiersAndPath<'tcx> { - p!(pretty_print_bound_constness(self.0.trait_ref)); if let ty::PredicatePolarity::Negative = self.0.polarity { p!("!") } p!(print(self.0.trait_ref.print_trait_sugared())); } + TraitPredPrintWithBoundConstness<'tcx> { + p!(print(self.0.trait_ref.self_ty()), ": "); + p!(pretty_print_bound_constness(self.1)); + if let ty::PredicatePolarity::Negative = self.0.polarity { + p!("!"); + } + p!(print(self.0.trait_ref.print_trait_sugared())) + } + PrintClosureAsImpl<'tcx> { p!(pretty_closure_as_impl(self.closure)) } diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 321b51289fb0..0a917120b3ba 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -1602,7 +1602,7 @@ impl<'tcx> ExplicitSelf<'tcx> { /// `Other`. /// This is mainly used to require the arbitrary_self_types feature /// in the case of `Other`, to improve error messages in the common cases, - /// and to make `Other` non-object-safe. + /// and to make `Other` dyn-incompatible. /// /// Examples: /// diff --git a/compiler/rustc_middle/src/ty/visit.rs b/compiler/rustc_middle/src/ty/visit.rs index 78d83004c14e..4efaccefcf74 100644 --- a/compiler/rustc_middle/src/ty/visit.rs +++ b/compiler/rustc_middle/src/ty/visit.rs @@ -1,6 +1,6 @@ use std::ops::ControlFlow; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::fx::FxIndexSet; use rustc_type_ir::fold::TypeFoldable; pub use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor}; @@ -110,7 +110,7 @@ impl<'tcx> TyCtxt<'tcx> { pub fn collect_constrained_late_bound_regions( self, value: Binder<'tcx, T>, - ) -> FxHashSet + ) -> FxIndexSet where T: TypeFoldable>, { @@ -121,7 +121,7 @@ impl<'tcx> TyCtxt<'tcx> { pub fn collect_referenced_late_bound_regions( self, value: Binder<'tcx, T>, - ) -> FxHashSet + ) -> FxIndexSet where T: TypeFoldable>, { @@ -132,7 +132,7 @@ impl<'tcx> TyCtxt<'tcx> { self, value: Binder<'tcx, T>, just_constrained: bool, - ) -> FxHashSet + ) -> FxIndexSet where T: TypeFoldable>, { @@ -148,7 +148,7 @@ impl<'tcx> TyCtxt<'tcx> { /// into a hash set. struct LateBoundRegionsCollector { current_index: ty::DebruijnIndex, - regions: FxHashSet, + regions: FxIndexSet, /// `true` if we only want regions that are known to be /// "constrained" when you equate this type with another type. In diff --git a/compiler/rustc_middle/src/values.rs b/compiler/rustc_middle/src/values.rs index c98d88e22d40..48ca38344cf2 100644 --- a/compiler/rustc_middle/src/values.rs +++ b/compiler/rustc_middle/src/values.rs @@ -358,7 +358,7 @@ fn find_item_ty_spans( match ty.kind { hir::TyKind::Path(hir::QPath::Resolved(_, path)) => { if let Res::Def(kind, def_id) = path.res - && !matches!(kind, DefKind::TyAlias) + && matches!(kind, DefKind::Enum | DefKind::Struct | DefKind::Union) { let check_params = def_id.as_local().map_or(true, |def_id| { if def_id == needle { diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index fbd45f59a4fb..2ffad0b4834a 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -699,23 +699,17 @@ impl<'tcx> Cx<'tcx> { } } hir::InlineAsmOperand::Const { ref anon_const } => { - let value = mir::Const::identity_unevaluated( - tcx, - anon_const.def_id.to_def_id(), - ) - .instantiate_identity() - .normalize(tcx, self.param_env); + let value = + mir::Const::from_unevaluated(tcx, anon_const.def_id.to_def_id()) + .instantiate_identity(); let span = tcx.def_span(anon_const.def_id); InlineAsmOperand::Const { value, span } } hir::InlineAsmOperand::SymFn { ref anon_const } => { - let value = mir::Const::identity_unevaluated( - tcx, - anon_const.def_id.to_def_id(), - ) - .instantiate_identity() - .normalize(tcx, self.param_env); + let value = + mir::Const::from_unevaluated(tcx, anon_const.def_id.to_def_id()) + .instantiate_identity(); let span = tcx.def_span(anon_const.def_id); InlineAsmOperand::SymFn { value, span } diff --git a/compiler/rustc_mir_dataflow/src/framework/engine.rs b/compiler/rustc_mir_dataflow/src/framework/engine.rs index da01a9740943..faf5c610a0c4 100644 --- a/compiler/rustc_mir_dataflow/src/framework/engine.rs +++ b/compiler/rustc_mir_dataflow/src/framework/engine.rs @@ -285,7 +285,7 @@ where } None if dump_enabled(tcx, A::NAME, def_id) => { - create_dump_file(tcx, ".dot", false, A::NAME, &pass_name.unwrap_or("-----"), body)? + create_dump_file(tcx, "dot", false, A::NAME, &pass_name.unwrap_or("-----"), body)? } _ => return (Ok(()), results), diff --git a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs index 65442877d2dd..cc4b7689d407 100644 --- a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs +++ b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs @@ -223,14 +223,14 @@ pub(crate) fn coroutine_by_move_body_def_id<'tcx>( // Inherited from the by-ref coroutine. body_def.codegen_fn_attrs(tcx.codegen_fn_attrs(coroutine_def_id).clone()); - body_def.constness(tcx.constness(coroutine_def_id).clone()); - body_def.coroutine_kind(tcx.coroutine_kind(coroutine_def_id).clone()); + body_def.constness(tcx.constness(coroutine_def_id)); + body_def.coroutine_kind(tcx.coroutine_kind(coroutine_def_id)); body_def.def_ident_span(tcx.def_ident_span(coroutine_def_id)); body_def.def_span(tcx.def_span(coroutine_def_id)); - body_def.explicit_predicates_of(tcx.explicit_predicates_of(coroutine_def_id).clone()); + body_def.explicit_predicates_of(tcx.explicit_predicates_of(coroutine_def_id)); body_def.generics_of(tcx.generics_of(coroutine_def_id).clone()); - body_def.param_env(tcx.param_env(coroutine_def_id).clone()); - body_def.predicates_of(tcx.predicates_of(coroutine_def_id).clone()); + body_def.param_env(tcx.param_env(coroutine_def_id)); + body_def.predicates_of(tcx.predicates_of(coroutine_def_id)); // The type of the coroutine is the `by_move_coroutine_ty`. body_def.type_of(ty::EarlyBinder::bind(by_move_coroutine_ty)); diff --git a/compiler/rustc_mir_transform/src/coverage/query.rs b/compiler/rustc_mir_transform/src/coverage/query.rs index e65a5fdd5e7f..df151f8cca35 100644 --- a/compiler/rustc_mir_transform/src/coverage/query.rs +++ b/compiler/rustc_mir_transform/src/coverage/query.rs @@ -63,7 +63,8 @@ fn coverage_attr_on(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { Some([item]) if item.has_name(sym::on) => return true, Some(_) | None => { // Other possibilities should have been rejected by `rustc_parse::validate_attr`. - tcx.dcx().span_bug(attr.span, "unexpected value of coverage attribute"); + // Use `span_delayed_bug` to avoid an ICE in failing builds (#127880). + tcx.dcx().span_delayed_bug(attr.span, "unexpected value of coverage attribute"); } } } diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index 88dc8e74a8c2..002216f50f2d 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -3,7 +3,9 @@ //! Currently, this pass only propagates scalar values. use rustc_const_eval::const_eval::{DummyMachine, throw_machine_stop_str}; -use rustc_const_eval::interpret::{ImmTy, Immediate, InterpCx, OpTy, PlaceTy, Projectable}; +use rustc_const_eval::interpret::{ + ImmTy, Immediate, InterpCx, OpTy, PlaceTy, Projectable, interp_ok, +}; use rustc_data_structures::fx::FxHashMap; use rustc_hir::def::DefKind; use rustc_middle::bug; @@ -236,6 +238,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { FlatSet::Elem(op) => self .ecx .int_to_int_or_float(&op, layout) + .discard_err() .map_or(FlatSet::Top, |result| self.wrap_immediate(*result)), FlatSet::Bottom => FlatSet::Bottom, FlatSet::Top => FlatSet::Top, @@ -249,6 +252,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { FlatSet::Elem(op) => self .ecx .float_to_float_or_int(&op, layout) + .discard_err() .map_or(FlatSet::Top, |result| self.wrap_immediate(*result)), FlatSet::Bottom => FlatSet::Bottom, FlatSet::Top => FlatSet::Top, @@ -271,6 +275,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { FlatSet::Elem(value) => self .ecx .unary_op(*op, &value) + .discard_err() .map_or(FlatSet::Top, |val| self.wrap_immediate(*val)), FlatSet::Bottom => FlatSet::Bottom, FlatSet::Top => FlatSet::Top, @@ -364,8 +369,8 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { } } Operand::Constant(box constant) => { - if let Ok(constant) = - self.ecx.eval_mir_constant(&constant.const_, constant.span, None) + if let Some(constant) = + self.ecx.eval_mir_constant(&constant.const_, constant.span, None).discard_err() { self.assign_constant(state, place, constant, &[]); } @@ -387,7 +392,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { for &(mut proj_elem) in projection { if let PlaceElem::Index(index) = proj_elem { if let FlatSet::Elem(index) = state.get(index.into(), &self.map) - && let Ok(offset) = index.to_target_usize(&self.tcx) + && let Some(offset) = index.to_target_usize(&self.tcx).discard_err() && let Some(min_length) = offset.checked_add(1) { proj_elem = PlaceElem::ConstantIndex { offset, min_length, from_end: false }; @@ -395,7 +400,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { return; } } - operand = if let Ok(operand) = self.ecx.project(&operand, proj_elem) { + operand = if let Some(operand) = self.ecx.project(&operand, proj_elem).discard_err() { operand } else { return; @@ -406,24 +411,24 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { place, operand, &mut |elem, op| match elem { - TrackElem::Field(idx) => self.ecx.project_field(op, idx.as_usize()).ok(), - TrackElem::Variant(idx) => self.ecx.project_downcast(op, idx).ok(), + TrackElem::Field(idx) => self.ecx.project_field(op, idx.as_usize()).discard_err(), + TrackElem::Variant(idx) => self.ecx.project_downcast(op, idx).discard_err(), TrackElem::Discriminant => { - let variant = self.ecx.read_discriminant(op).ok()?; + let variant = self.ecx.read_discriminant(op).discard_err()?; let discr_value = - self.ecx.discriminant_for_variant(op.layout.ty, variant).ok()?; + self.ecx.discriminant_for_variant(op.layout.ty, variant).discard_err()?; Some(discr_value.into()) } TrackElem::DerefLen => { - let op: OpTy<'_> = self.ecx.deref_pointer(op).ok()?.into(); - let len_usize = op.len(&self.ecx).ok()?; + let op: OpTy<'_> = self.ecx.deref_pointer(op).discard_err()?.into(); + let len_usize = op.len(&self.ecx).discard_err()?; let layout = self.tcx.layout_of(self.param_env.and(self.tcx.types.usize)).unwrap(); Some(ImmTy::from_uint(len_usize, layout).into()) } }, &mut |place, op| { - if let Ok(imm) = self.ecx.read_immediate_raw(op) + if let Some(imm) = self.ecx.read_immediate_raw(op).discard_err() && let Some(imm) = imm.right() { let elem = self.wrap_immediate(*imm); @@ -447,11 +452,11 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { (FlatSet::Bottom, _) | (_, FlatSet::Bottom) => (FlatSet::Bottom, FlatSet::Bottom), // Both sides are known, do the actual computation. (FlatSet::Elem(left), FlatSet::Elem(right)) => { - match self.ecx.binary_op(op, &left, &right) { + match self.ecx.binary_op(op, &left, &right).discard_err() { // Ideally this would return an Immediate, since it's sometimes // a pair and sometimes not. But as a hack we always return a pair // and just make the 2nd component `Bottom` when it does not exist. - Ok(val) => { + Some(val) => { if matches!(val.layout.abi, Abi::ScalarPair(..)) { let (val, overflow) = val.to_scalar_pair(); (FlatSet::Elem(val), FlatSet::Elem(overflow)) @@ -470,7 +475,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { } let arg_scalar = const_arg.to_scalar(); - let Ok(arg_value) = arg_scalar.to_bits(layout.size) else { + let Some(arg_value) = arg_scalar.to_bits(layout.size).discard_err() else { return (FlatSet::Top, FlatSet::Top); }; @@ -519,7 +524,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { } let enum_ty_layout = self.tcx.layout_of(self.param_env.and(enum_ty)).ok()?; let discr_value = - self.ecx.discriminant_for_variant(enum_ty_layout.ty, variant_index).ok()?; + self.ecx.discriminant_for_variant(enum_ty_layout.ty, variant_index).discard_err()?; Some(discr_value.to_scalar()) } @@ -595,7 +600,7 @@ impl<'a, 'tcx> Collector<'a, 'tcx> { .intern_with_temp_alloc(layout, |ecx, dest| { try_write_constant(ecx, dest, place, ty, state, map) }) - .ok()?; + .discard_err()?; return Some(Const::Val(ConstValue::Indirect { alloc_id, offset: Size::ZERO }, ty)); } @@ -632,7 +637,7 @@ fn try_write_constant<'tcx>( // Fast path for ZSTs. if layout.is_zst() { - return Ok(()); + return interp_ok(()); } // Fast path for scalars. @@ -717,7 +722,7 @@ fn try_write_constant<'tcx>( ty::Error(_) | ty::Infer(..) | ty::CoroutineWitness(..) => bug!(), } - Ok(()) + interp_ok(()) } impl<'mir, 'tcx> @@ -830,7 +835,7 @@ impl<'tcx> MutVisitor<'tcx> for Patch<'tcx> { if let PlaceElem::Index(local) = elem { let offset = self.before_effect.get(&(location, local.into()))?; let offset = offset.try_to_scalar()?; - let offset = offset.to_target_usize(&self.tcx).ok()?; + let offset = offset.to_target_usize(&self.tcx).discard_err()?; let min_length = offset.checked_add(1)?; Some(PlaceElem::ConstantIndex { offset, min_length, from_end: false }) } else { diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index f735d08fca57..50c9702cb9b0 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -393,7 +393,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { Repeat(..) => return None, Constant { ref value, disambiguator: _ } => { - self.ecx.eval_mir_constant(value, DUMMY_SP, None).ok()? + self.ecx.eval_mir_constant(value, DUMMY_SP, None).discard_err()? } Aggregate(kind, variant, ref fields) => { let fields = fields @@ -419,29 +419,32 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { ImmTy::uninit(ty).into() } else if matches!(kind, AggregateTy::RawPtr { .. }) { // Pointers don't have fields, so don't `project_field` them. - let data = self.ecx.read_pointer(fields[0]).ok()?; + let data = self.ecx.read_pointer(fields[0]).discard_err()?; let meta = if fields[1].layout.is_zst() { MemPlaceMeta::None } else { - MemPlaceMeta::Meta(self.ecx.read_scalar(fields[1]).ok()?) + MemPlaceMeta::Meta(self.ecx.read_scalar(fields[1]).discard_err()?) }; let ptr_imm = Immediate::new_pointer_with_meta(data, meta, &self.ecx); ImmTy::from_immediate(ptr_imm, ty).into() } else if matches!(ty.abi, Abi::Scalar(..) | Abi::ScalarPair(..)) { - let dest = self.ecx.allocate(ty, MemoryKind::Stack).ok()?; + let dest = self.ecx.allocate(ty, MemoryKind::Stack).discard_err()?; let variant_dest = if let Some(variant) = variant { - self.ecx.project_downcast(&dest, variant).ok()? + self.ecx.project_downcast(&dest, variant).discard_err()? } else { dest.clone() }; for (field_index, op) in fields.into_iter().enumerate() { - let field_dest = self.ecx.project_field(&variant_dest, field_index).ok()?; - self.ecx.copy_op(op, &field_dest).ok()?; + let field_dest = + self.ecx.project_field(&variant_dest, field_index).discard_err()?; + self.ecx.copy_op(op, &field_dest).discard_err()?; } - self.ecx.write_discriminant(variant.unwrap_or(FIRST_VARIANT), &dest).ok()?; + self.ecx + .write_discriminant(variant.unwrap_or(FIRST_VARIANT), &dest) + .discard_err()?; self.ecx .alloc_mark_immutable(dest.ptr().provenance.unwrap().alloc_id()) - .ok()?; + .discard_err()?; dest.into() } else { return None; @@ -467,7 +470,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { // This should have been replaced by a `ConstantIndex` earlier. ProjectionElem::Index(_) => return None, }; - self.ecx.project(value, elem).ok()? + self.ecx.project(value, elem).discard_err()? } Address { place, kind, provenance: _ } => { if !place.is_indirect_first_projection() { @@ -475,14 +478,14 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } let local = self.locals[place.local]?; let pointer = self.evaluated[local].as_ref()?; - let mut mplace = self.ecx.deref_pointer(pointer).ok()?; + let mut mplace = self.ecx.deref_pointer(pointer).discard_err()?; for proj in place.projection.iter().skip(1) { // We have no call stack to associate a local with a value, so we cannot // interpret indexing. if matches!(proj, ProjectionElem::Index(_)) { return None; } - mplace = self.ecx.project(&mplace, proj).ok()?; + mplace = self.ecx.project(&mplace, proj).discard_err()?; } let pointer = mplace.to_ref(&self.ecx); let ty = match kind { @@ -500,15 +503,15 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { Discriminant(base) => { let base = self.evaluated[base].as_ref()?; - let variant = self.ecx.read_discriminant(base).ok()?; + let variant = self.ecx.read_discriminant(base).discard_err()?; let discr_value = - self.ecx.discriminant_for_variant(base.layout.ty, variant).ok()?; + self.ecx.discriminant_for_variant(base.layout.ty, variant).discard_err()?; discr_value.into() } Len(slice) => { let slice = self.evaluated[slice].as_ref()?; let usize_layout = self.ecx.layout_of(self.tcx.types.usize).unwrap(); - let len = slice.len(&self.ecx).ok()?; + let len = slice.len(&self.ecx).discard_err()?; let imm = ImmTy::from_uint(len, usize_layout); imm.into() } @@ -535,31 +538,31 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } UnaryOp(un_op, operand) => { let operand = self.evaluated[operand].as_ref()?; - let operand = self.ecx.read_immediate(operand).ok()?; - let val = self.ecx.unary_op(un_op, &operand).ok()?; + let operand = self.ecx.read_immediate(operand).discard_err()?; + let val = self.ecx.unary_op(un_op, &operand).discard_err()?; val.into() } BinaryOp(bin_op, lhs, rhs) => { let lhs = self.evaluated[lhs].as_ref()?; - let lhs = self.ecx.read_immediate(lhs).ok()?; + let lhs = self.ecx.read_immediate(lhs).discard_err()?; let rhs = self.evaluated[rhs].as_ref()?; - let rhs = self.ecx.read_immediate(rhs).ok()?; - let val = self.ecx.binary_op(bin_op, &lhs, &rhs).ok()?; + let rhs = self.ecx.read_immediate(rhs).discard_err()?; + let val = self.ecx.binary_op(bin_op, &lhs, &rhs).discard_err()?; val.into() } Cast { kind, value, from: _, to } => match kind { CastKind::IntToInt | CastKind::IntToFloat => { let value = self.evaluated[value].as_ref()?; - let value = self.ecx.read_immediate(value).ok()?; + let value = self.ecx.read_immediate(value).discard_err()?; let to = self.ecx.layout_of(to).ok()?; - let res = self.ecx.int_to_int_or_float(&value, to).ok()?; + let res = self.ecx.int_to_int_or_float(&value, to).discard_err()?; res.into() } CastKind::FloatToFloat | CastKind::FloatToInt => { let value = self.evaluated[value].as_ref()?; - let value = self.ecx.read_immediate(value).ok()?; + let value = self.ecx.read_immediate(value).discard_err()?; let to = self.ecx.layout_of(to).ok()?; - let res = self.ecx.float_to_float_or_int(&value, to).ok()?; + let res = self.ecx.float_to_float_or_int(&value, to).discard_err()?; res.into() } CastKind::Transmute => { @@ -574,28 +577,28 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { _ => return None, } } - value.offset(Size::ZERO, to, &self.ecx).ok()? + value.offset(Size::ZERO, to, &self.ecx).discard_err()? } CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize, _) => { let src = self.evaluated[value].as_ref()?; let to = self.ecx.layout_of(to).ok()?; - let dest = self.ecx.allocate(to, MemoryKind::Stack).ok()?; - self.ecx.unsize_into(src, to, &dest.clone().into()).ok()?; + let dest = self.ecx.allocate(to, MemoryKind::Stack).discard_err()?; + self.ecx.unsize_into(src, to, &dest.clone().into()).discard_err()?; self.ecx .alloc_mark_immutable(dest.ptr().provenance.unwrap().alloc_id()) - .ok()?; + .discard_err()?; dest.into() } CastKind::FnPtrToPtr | CastKind::PtrToPtr => { let src = self.evaluated[value].as_ref()?; - let src = self.ecx.read_immediate(src).ok()?; + let src = self.ecx.read_immediate(src).discard_err()?; let to = self.ecx.layout_of(to).ok()?; - let ret = self.ecx.ptr_to_ptr(&src, to).ok()?; + let ret = self.ecx.ptr_to_ptr(&src, to).discard_err()?; ret.into() } CastKind::PointerCoercion(ty::adjustment::PointerCoercion::UnsafeFnPointer, _) => { let src = self.evaluated[value].as_ref()?; - let src = self.ecx.read_immediate(src).ok()?; + let src = self.ecx.read_immediate(src).discard_err()?; let to = self.ecx.layout_of(to).ok()?; ImmTy::from_immediate(*src, to).into() } @@ -708,7 +711,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { && let Some(idx) = self.locals[idx_local] { if let Some(offset) = self.evaluated[idx].as_ref() - && let Ok(offset) = self.ecx.read_target_usize(offset) + && let Some(offset) = self.ecx.read_target_usize(offset).discard_err() && let Some(min_length) = offset.checked_add(1) { projection.to_mut()[i] = @@ -868,7 +871,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { && let DefKind::Enum = self.tcx.def_kind(enum_did) { let enum_ty = self.tcx.type_of(enum_did).instantiate(self.tcx, enum_args); - let discr = self.ecx.discriminant_for_variant(enum_ty, variant).ok()?; + let discr = self.ecx.discriminant_for_variant(enum_ty, variant).discard_err()?; return Some(self.insert_scalar(discr.to_scalar(), discr.layout.ty)); } @@ -1223,8 +1226,8 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { let as_bits = |value| { let constant = self.evaluated[value].as_ref()?; if layout.abi.is_scalar() { - let scalar = self.ecx.read_scalar(constant).ok()?; - scalar.to_bits(constant.layout.size).ok() + let scalar = self.ecx.read_scalar(constant).discard_err()?; + scalar.to_bits(constant.layout.size).discard_err() } else { // `constant` is a wide pointer. Do not evaluate to bits. None @@ -1484,7 +1487,7 @@ fn op_to_prop_const<'tcx>( // If this constant has scalar ABI, return it as a `ConstValue::Scalar`. if let Abi::Scalar(abi::Scalar::Initialized { .. }) = op.layout.abi - && let Ok(scalar) = ecx.read_scalar(op) + && let Some(scalar) = ecx.read_scalar(op).discard_err() { if !scalar.try_to_scalar_int().is_ok() { // Check that we do not leak a pointer. @@ -1498,12 +1501,12 @@ fn op_to_prop_const<'tcx>( // If this constant is already represented as an `Allocation`, // try putting it into global memory to return it. if let Either::Left(mplace) = op.as_mplace_or_imm() { - let (size, _align) = ecx.size_and_align_of_mplace(&mplace).ok()??; + let (size, _align) = ecx.size_and_align_of_mplace(&mplace).discard_err()??; // Do not try interning a value that contains provenance. // Due to https://github.com/rust-lang/rust/issues/79738, doing so could lead to bugs. // FIXME: remove this hack once that issue is fixed. - let alloc_ref = ecx.get_ptr_alloc(mplace.ptr(), size).ok()??; + let alloc_ref = ecx.get_ptr_alloc(mplace.ptr(), size).discard_err()??; if alloc_ref.has_provenance() { return None; } @@ -1511,7 +1514,7 @@ fn op_to_prop_const<'tcx>( let pointer = mplace.ptr().into_pointer_or_addr().ok()?; let (prov, offset) = pointer.into_parts(); let alloc_id = prov.alloc_id(); - intern_const_alloc_for_constprop(ecx, alloc_id).ok()?; + intern_const_alloc_for_constprop(ecx, alloc_id).discard_err()?; // `alloc_id` may point to a static. Codegen will choke on an `Indirect` with anything // by `GlobalAlloc::Memory`, so do fall through to copying if needed. @@ -1526,7 +1529,8 @@ fn op_to_prop_const<'tcx>( } // Everything failed: create a new allocation to hold the data. - let alloc_id = ecx.intern_with_temp_alloc(op.layout, |ecx, dest| ecx.copy_op(op, dest)).ok()?; + let alloc_id = + ecx.intern_with_temp_alloc(op.layout, |ecx, dest| ecx.copy_op(op, dest)).discard_err()?; let value = ConstValue::Indirect { alloc_id, offset: Size::ZERO }; // Check that we do not leak a pointer. diff --git a/compiler/rustc_mir_transform/src/jump_threading.rs b/compiler/rustc_mir_transform/src/jump_threading.rs index 9d85b5ba5a71..1844b97887ab 100644 --- a/compiler/rustc_mir_transform/src/jump_threading.rs +++ b/compiler/rustc_mir_transform/src/jump_threading.rs @@ -200,7 +200,9 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { debug!(?discr, ?bb); let discr_ty = discr.ty(self.body, self.tcx).ty; - let Ok(discr_layout) = self.ecx.layout_of(discr_ty) else { return }; + let Ok(discr_layout) = self.ecx.layout_of(discr_ty) else { + return; + }; let Some(discr) = self.map.find(discr.as_ref()) else { return }; debug!(?discr); @@ -388,24 +390,24 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { lhs, constant, &mut |elem, op| match elem { - TrackElem::Field(idx) => self.ecx.project_field(op, idx.as_usize()).ok(), - TrackElem::Variant(idx) => self.ecx.project_downcast(op, idx).ok(), + TrackElem::Field(idx) => self.ecx.project_field(op, idx.as_usize()).discard_err(), + TrackElem::Variant(idx) => self.ecx.project_downcast(op, idx).discard_err(), TrackElem::Discriminant => { - let variant = self.ecx.read_discriminant(op).ok()?; + let variant = self.ecx.read_discriminant(op).discard_err()?; let discr_value = - self.ecx.discriminant_for_variant(op.layout.ty, variant).ok()?; + self.ecx.discriminant_for_variant(op.layout.ty, variant).discard_err()?; Some(discr_value.into()) } TrackElem::DerefLen => { - let op: OpTy<'_> = self.ecx.deref_pointer(op).ok()?.into(); - let len_usize = op.len(&self.ecx).ok()?; + let op: OpTy<'_> = self.ecx.deref_pointer(op).discard_err()?.into(); + let len_usize = op.len(&self.ecx).discard_err()?; let layout = self.ecx.layout_of(self.tcx.types.usize).unwrap(); Some(ImmTy::from_uint(len_usize, layout).into()) } }, &mut |place, op| { if let Some(conditions) = state.try_get_idx(place, &self.map) - && let Ok(imm) = self.ecx.read_immediate_raw(op) + && let Some(imm) = self.ecx.read_immediate_raw(op).discard_err() && let Some(imm) = imm.right() && let Immediate::Scalar(Scalar::Int(int)) = *imm { @@ -429,8 +431,8 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { match rhs { // If we expect `lhs ?= A`, we have an opportunity if we assume `constant == A`. Operand::Constant(constant) => { - let Ok(constant) = - self.ecx.eval_mir_constant(&constant.const_, constant.span, None) + let Some(constant) = + self.ecx.eval_mir_constant(&constant.const_, constant.span, None).discard_err() else { return; }; @@ -469,8 +471,10 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { AggregateKind::Adt(.., Some(_)) => return, AggregateKind::Adt(_, variant_index, ..) if agg_ty.is_enum() => { if let Some(discr_target) = self.map.apply(lhs, TrackElem::Discriminant) - && let Ok(discr_value) = - self.ecx.discriminant_for_variant(agg_ty, *variant_index) + && let Some(discr_value) = self + .ecx + .discriminant_for_variant(agg_ty, *variant_index) + .discard_err() { self.process_immediate(bb, discr_target, discr_value, state); } @@ -516,9 +520,7 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { // Avoid handling them, though this could be extended in the future. return; } - let Some(value) = - value.const_.normalize(self.tcx, self.param_env).try_to_scalar_int() - else { + let Some(value) = value.const_.try_eval_scalar_int(self.tcx, self.param_env) else { return; }; let conds = conditions.map(self.arena, |c| Condition { @@ -557,7 +559,9 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { // `SetDiscriminant` may be a no-op if the assigned variant is the untagged variant // of a niche encoding. If we cannot ensure that we write to the discriminant, do // nothing. - let Ok(enum_layout) = self.ecx.layout_of(enum_ty) else { return }; + let Ok(enum_layout) = self.ecx.layout_of(enum_ty) else { + return; + }; let writes_discriminant = match enum_layout.variants { Variants::Single { index } => { assert_eq!(index, *variant_index); @@ -570,7 +574,8 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { } => *variant_index != untagged_variant, }; if writes_discriminant { - let Ok(discr) = self.ecx.discriminant_for_variant(enum_ty, *variant_index) + let Some(discr) = + self.ecx.discriminant_for_variant(enum_ty, *variant_index).discard_err() else { return; }; @@ -647,7 +652,9 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> { let Some(discr) = discr.place() else { return }; let discr_ty = discr.ty(self.body, self.tcx).ty; - let Ok(discr_layout) = self.ecx.layout_of(discr_ty) else { return }; + let Ok(discr_layout) = self.ecx.layout_of(discr_ty) else { + return; + }; let Some(conditions) = state.try_get(discr.as_ref(), &self.map) else { return }; if let Some((value, _)) = targets.iter().find(|&(_, target)| target == target_bb) { diff --git a/compiler/rustc_mir_transform/src/known_panics_lint.rs b/compiler/rustc_mir_transform/src/known_panics_lint.rs index 783e7aabe854..ccc029b1e281 100644 --- a/compiler/rustc_mir_transform/src/known_panics_lint.rs +++ b/compiler/rustc_mir_transform/src/known_panics_lint.rs @@ -6,7 +6,7 @@ use std::fmt::Debug; use rustc_const_eval::const_eval::DummyMachine; use rustc_const_eval::interpret::{ - ImmTy, InterpCx, InterpResult, Projectable, Scalar, format_interp_error, + ImmTy, InterpCx, InterpResult, Projectable, Scalar, format_interp_error, interp_ok, }; use rustc_data_structures::fx::FxHashSet; use rustc_hir::HirId; @@ -101,7 +101,7 @@ impl<'tcx> Value<'tcx> { } (PlaceElem::Index(idx), Value::Aggregate { fields, .. }) => { let idx = prop.get_const(idx.into())?.immediate()?; - let idx = prop.ecx.read_target_usize(idx).ok()?.try_into().ok()?; + let idx = prop.ecx.read_target_usize(idx).discard_err()?.try_into().ok()?; if idx <= FieldIdx::MAX_AS_U32 { fields.get(FieldIdx::from_u32(idx)).unwrap_or(&Value::Uninit) } else { @@ -231,21 +231,20 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { where F: FnOnce(&mut Self) -> InterpResult<'tcx, T>, { - match f(self) { - Ok(val) => Some(val), - Err(error) => { - trace!("InterpCx operation failed: {:?}", error); + f(self) + .map_err(|err| { + trace!("InterpCx operation failed: {:?}", err); // Some errors shouldn't come up because creating them causes // an allocation, which we should avoid. When that happens, // dedicated error variants should be introduced instead. assert!( - !error.kind().formatted_string(), + !err.kind().formatted_string(), "known panics lint encountered formatting error: {}", - format_interp_error(self.ecx.tcx.dcx(), error), + format_interp_error(self.ecx.tcx.dcx(), err), ); - None - } - } + err + }) + .discard_err() } /// Returns the value, if any, of evaluating `c`. @@ -315,7 +314,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { .ecx .binary_op(BinOp::SubWithOverflow, &ImmTy::from_int(0, arg.layout), &arg)? .to_scalar_pair(); - Ok((arg, overflow.to_bool()?)) + interp_ok((arg, overflow.to_bool()?)) })?; if overflow { self.report_assert_as_lint( @@ -349,7 +348,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { let left_ty = left.ty(self.local_decls(), self.tcx); let left_size = self.ecx.layout_of(left_ty).ok()?.size; let right_size = r.layout.size; - let r_bits = r.to_scalar().to_bits(right_size).ok(); + let r_bits = r.to_scalar().to_bits(right_size).discard_err(); if r_bits.is_some_and(|b| b >= left_size.bits() as u128) { debug!("check_binary_op: reporting assert for {:?}", location); let panic = AssertKind::Overflow( @@ -496,7 +495,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { // This can be `None` if the lhs wasn't const propagated and we just // triggered the assert on the value of the rhs. self.eval_operand(op) - .and_then(|op| self.ecx.read_immediate(&op).ok()) + .and_then(|op| self.ecx.read_immediate(&op).discard_err()) .map_or(DbgVal::Underscore, |op| DbgVal::Val(op.to_const_int())) }; let msg = match msg { @@ -602,7 +601,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { Len(place) => { let len = match self.get_const(place)? { - Value::Immediate(src) => src.len(&self.ecx).ok()?, + Value::Immediate(src) => src.len(&self.ecx).discard_err()?, Value::Aggregate { fields, .. } => fields.len() as u64, Value::Uninit => match place.ty(self.local_decls(), self.tcx).ty.kind() { ty::Array(_, n) => n.try_eval_target_usize(self.tcx, self.param_env)?, @@ -615,7 +614,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { Ref(..) | RawPtr(..) => return None, NullaryOp(ref null_op, ty) => { - let op_layout = self.use_ecx(|this| this.ecx.layout_of(ty))?; + let op_layout = self.ecx.layout_of(ty).ok()?; let val = match null_op { NullOp::SizeOf => op_layout.size.bytes(), NullOp::AlignOf => op_layout.align.abi.bytes(), @@ -633,16 +632,16 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { Cast(ref kind, ref value, to) => match kind { CastKind::IntToInt | CastKind::IntToFloat => { let value = self.eval_operand(value)?; - let value = self.ecx.read_immediate(&value).ok()?; + let value = self.ecx.read_immediate(&value).discard_err()?; let to = self.ecx.layout_of(to).ok()?; - let res = self.ecx.int_to_int_or_float(&value, to).ok()?; + let res = self.ecx.int_to_int_or_float(&value, to).discard_err()?; res.into() } CastKind::FloatToFloat | CastKind::FloatToInt => { let value = self.eval_operand(value)?; - let value = self.ecx.read_immediate(&value).ok()?; + let value = self.ecx.read_immediate(&value).discard_err()?; let to = self.ecx.layout_of(to).ok()?; - let res = self.ecx.float_to_float_or_int(&value, to).ok()?; + let res = self.ecx.float_to_float_or_int(&value, to).discard_err()?; res.into() } CastKind::Transmute => { @@ -656,7 +655,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { _ => return None, } - value.offset(Size::ZERO, to, &self.ecx).ok()?.into() + value.offset(Size::ZERO, to, &self.ecx).discard_err()?.into() } _ => return None, }, @@ -781,7 +780,7 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> { TerminatorKind::SwitchInt { ref discr, ref targets } => { if let Some(ref value) = self.eval_operand(discr) && let Some(value_const) = self.use_ecx(|this| this.ecx.read_scalar(value)) - && let Ok(constant) = value_const.to_bits(value_const.size()) + && let Some(constant) = value_const.to_bits(value_const.size()).discard_err() { // We managed to evaluate the discriminant, so we know we only need to visit // one target. diff --git a/compiler/rustc_mir_transform/src/single_use_consts.rs b/compiler/rustc_mir_transform/src/single_use_consts.rs index 9884b6dd1c35..277a33c03115 100644 --- a/compiler/rustc_mir_transform/src/single_use_consts.rs +++ b/compiler/rustc_mir_transform/src/single_use_consts.rs @@ -185,15 +185,14 @@ impl<'tcx> MutVisitor<'tcx> for LocalReplacer<'tcx> { && let Some(local) = place.as_local() && local == self.local { - let const_op = self + let const_op = *self .operand .as_ref() .unwrap_or_else(|| { bug!("the operand was already stolen"); }) .constant() - .unwrap() - .clone(); + .unwrap(); var_debug_info.value = VarDebugInfoContents::Const(const_op); } } diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 276098a84007..05b3859e554e 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -120,7 +120,7 @@ //! #### Unsizing Casts //! A subtle way of introducing use edges is by casting to a trait object. //! Since the resulting fat-pointer contains a reference to a vtable, we need to -//! instantiate all object-safe methods of the trait, as we need to store +//! instantiate all dyn-compatible methods of the trait, as we need to store //! pointers to these functions even if they never get called anywhere. This can //! be seen as a special case of taking a function reference. //! diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs index ad05cca66cab..5bd484d7bb00 100644 --- a/compiler/rustc_monomorphize/src/partitioning.rs +++ b/compiler/rustc_monomorphize/src/partitioning.rs @@ -904,26 +904,22 @@ fn mono_item_visibility<'tcx>( } fn default_visibility(tcx: TyCtxt<'_>, id: DefId, is_generic: bool) -> Visibility { - if !tcx.sess.default_hidden_visibility() { - return Visibility::Default; - } + let export_level = if is_generic { + // Generic functions never have export-level C. + SymbolExportLevel::Rust + } else { + match tcx.reachable_non_generics(id.krate).get(&id) { + Some(SymbolExportInfo { level: SymbolExportLevel::C, .. }) => SymbolExportLevel::C, + _ => SymbolExportLevel::Rust, + } + }; + match export_level { + // C-export level items remain at `Default` to allow C code to + // access and interpose them. + SymbolExportLevel::C => Visibility::Default, - // Generic functions never have export-level C. - if is_generic { - return Visibility::Hidden; - } - - // Things with export level C don't get instantiated in - // downstream crates. - if !id.is_local() { - return Visibility::Hidden; - } - - // C-export level items remain at `Default`, all other internal - // items become `Hidden`. - match tcx.reachable_non_generics(id.krate).get(&id) { - Some(SymbolExportInfo { level: SymbolExportLevel::C, .. }) => Visibility::Default, - _ => Visibility::Hidden, + // For all other symbols, `default_visibility` determines which visibility to use. + SymbolExportLevel::Rust => tcx.sess.default_visibility().into(), } } diff --git a/compiler/rustc_next_trait_solver/src/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonicalizer.rs index 196ddeb24430..0bf9d7b92495 100644 --- a/compiler/rustc_next_trait_solver/src/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonicalizer.rs @@ -1,5 +1,6 @@ use std::cmp::Ordering; +use rustc_type_ir::data_structures::HashMap; use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; use rustc_type_ir::inherent::*; use rustc_type_ir::visit::TypeVisitableExt; @@ -41,11 +42,20 @@ pub enum CanonicalizeMode { pub struct Canonicalizer<'a, D: SolverDelegate, I: Interner> { delegate: &'a D, + + // Immutable field. canonicalize_mode: CanonicalizeMode, + // Mutable fields. variables: &'a mut Vec, primitive_var_infos: Vec>, + variable_lookup_table: HashMap, binder_index: ty::DebruijnIndex, + + /// We only use the debruijn index during lookup. We don't need to + /// track the `variables` as each generic arg only results in a single + /// bound variable regardless of how many times it is encountered. + cache: HashMap<(ty::DebruijnIndex, I::Ty), I::Ty>, } impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { @@ -60,12 +70,14 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { canonicalize_mode, variables, + variable_lookup_table: Default::default(), primitive_var_infos: Vec::new(), binder_index: ty::INNERMOST, + + cache: Default::default(), }; let value = value.fold_with(&mut canonicalizer); - // FIXME: Restore these assertions. Should we uplift type flags? assert!(!value.has_infer(), "unexpected infer in {value:?}"); assert!(!value.has_placeholders(), "unexpected placeholders in {value:?}"); @@ -75,6 +87,37 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { Canonical { defining_opaque_types, max_universe, variables, value } } + fn get_or_insert_bound_var( + &mut self, + arg: impl Into, + canonical_var_info: CanonicalVarInfo, + ) -> ty::BoundVar { + // FIXME: 16 is made up and arbitrary. We should look at some + // perf data here. + let arg = arg.into(); + let idx = if self.variables.len() > 16 { + if self.variable_lookup_table.is_empty() { + self.variable_lookup_table.extend(self.variables.iter().copied().zip(0..)); + } + + *self.variable_lookup_table.entry(arg).or_insert_with(|| { + let var = self.variables.len(); + self.variables.push(arg); + self.primitive_var_infos.push(canonical_var_info); + var + }) + } else { + self.variables.iter().position(|&v| v == arg).unwrap_or_else(|| { + let var = self.variables.len(); + self.variables.push(arg); + self.primitive_var_infos.push(canonical_var_info); + var + }) + }; + + ty::BoundVar::from(idx) + } + fn finalize(self) -> (ty::UniverseIndex, I::CanonicalVars) { let mut var_infos = self.primitive_var_infos; // See the rustc-dev-guide section about how we deal with universes @@ -124,8 +167,8 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { // - var_infos: [E0, U1, E2, U1, E1, E6, U6], curr_compressed_uv: 2, next_orig_uv: 6 // - var_infos: [E0, U1, E1, U1, E1, E3, U3], curr_compressed_uv: 2, next_orig_uv: - // - // This algorithm runs in `O(n²)` where `n` is the number of different universe - // indices in the input. This should be fine as `n` is expected to be small. + // This algorithm runs in `O(mn)` where `n` is the number of different universes and + // `m` the number of variables. This should be fine as both are expected to be small. let mut curr_compressed_uv = ty::UniverseIndex::ROOT; let mut existential_in_new_uv = None; let mut next_orig_uv = Some(ty::UniverseIndex::ROOT); @@ -185,14 +228,16 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { for var in var_infos.iter_mut() { // We simply put all regions from the input into the highest // compressed universe, so we only deal with them at the end. - if !var.is_region() && is_existential == var.is_existential() { - update_uv(var, orig_uv, is_existential) + if !var.is_region() { + if is_existential == var.is_existential() { + update_uv(var, orig_uv, is_existential) + } } } } } - // We uniquify regions and always put them into their own universe + // We put all regions into a separate universe. let mut first_region = true; for var in var_infos.iter_mut() { if var.is_region() { @@ -208,93 +253,8 @@ impl<'a, D: SolverDelegate, I: Interner> Canonicalizer<'a, D, I> { let var_infos = self.delegate.cx().mk_canonical_var_infos(&var_infos); (curr_compressed_uv, var_infos) } -} -impl, I: Interner> TypeFolder for Canonicalizer<'_, D, I> { - fn cx(&self) -> I { - self.delegate.cx() - } - - fn fold_binder(&mut self, t: ty::Binder) -> ty::Binder - where - T: TypeFoldable, - { - self.binder_index.shift_in(1); - let t = t.super_fold_with(self); - self.binder_index.shift_out(1); - t - } - - fn fold_region(&mut self, r: I::Region) -> I::Region { - let kind = match r.kind() { - ty::ReBound(..) => return r, - - // We may encounter `ReStatic` in item signatures or the hidden type - // of an opaque. `ReErased` should only be encountered in the hidden - // type of an opaque for regions that are ignored for the purposes of - // captures. - // - // FIXME: We should investigate the perf implications of not uniquifying - // `ReErased`. We may be able to short-circuit registering region - // obligations if we encounter a `ReErased` on one side, for example. - ty::ReStatic | ty::ReErased | ty::ReError(_) => match self.canonicalize_mode { - CanonicalizeMode::Input => CanonicalVarKind::Region(ty::UniverseIndex::ROOT), - CanonicalizeMode::Response { .. } => return r, - }, - - ty::ReEarlyParam(_) | ty::ReLateParam(_) => match self.canonicalize_mode { - CanonicalizeMode::Input => CanonicalVarKind::Region(ty::UniverseIndex::ROOT), - CanonicalizeMode::Response { .. } => { - panic!("unexpected region in response: {r:?}") - } - }, - - ty::RePlaceholder(placeholder) => match self.canonicalize_mode { - // We canonicalize placeholder regions as existentials in query inputs. - CanonicalizeMode::Input => CanonicalVarKind::Region(ty::UniverseIndex::ROOT), - CanonicalizeMode::Response { max_input_universe } => { - // If we have a placeholder region inside of a query, it must be from - // a new universe. - if max_input_universe.can_name(placeholder.universe()) { - panic!("new placeholder in universe {max_input_universe:?}: {r:?}"); - } - CanonicalVarKind::PlaceholderRegion(placeholder) - } - }, - - ty::ReVar(vid) => { - assert_eq!( - self.delegate.opportunistic_resolve_lt_var(vid), - r, - "region vid should have been resolved fully before canonicalization" - ); - match self.canonicalize_mode { - CanonicalizeMode::Input => CanonicalVarKind::Region(ty::UniverseIndex::ROOT), - CanonicalizeMode::Response { .. } => { - CanonicalVarKind::Region(self.delegate.universe_of_lt(vid).unwrap()) - } - } - } - }; - - let existing_bound_var = match self.canonicalize_mode { - CanonicalizeMode::Input => None, - CanonicalizeMode::Response { .. } => { - self.variables.iter().position(|&v| v == r.into()).map(ty::BoundVar::from) - } - }; - - let var = existing_bound_var.unwrap_or_else(|| { - let var = ty::BoundVar::from(self.variables.len()); - self.variables.push(r.into()); - self.primitive_var_infos.push(CanonicalVarInfo { kind }); - var - }); - - Region::new_anon_bound(self.cx(), self.binder_index, var) - } - - fn fold_ty(&mut self, t: I::Ty) -> I::Ty { + fn cached_fold_ty(&mut self, t: I::Ty) -> I::Ty { let kind = match t.kind() { ty::Infer(i) => match i { ty::TyVar(vid) => { @@ -368,20 +328,98 @@ impl, I: Interner> TypeFolder for Canonicaliz | ty::Tuple(_) | ty::Alias(_, _) | ty::Bound(_, _) - | ty::Error(_) => return t.super_fold_with(self), + | ty::Error(_) => { + return t.super_fold_with(self); + } }; - let var = ty::BoundVar::from( - self.variables.iter().position(|&v| v == t.into()).unwrap_or_else(|| { - let var = self.variables.len(); - self.variables.push(t.into()); - self.primitive_var_infos.push(CanonicalVarInfo { kind }); - var - }), - ); + let var = self.get_or_insert_bound_var(t, CanonicalVarInfo { kind }); Ty::new_anon_bound(self.cx(), self.binder_index, var) } +} + +impl, I: Interner> TypeFolder for Canonicalizer<'_, D, I> { + fn cx(&self) -> I { + self.delegate.cx() + } + + fn fold_binder(&mut self, t: ty::Binder) -> ty::Binder + where + T: TypeFoldable, + { + self.binder_index.shift_in(1); + let t = t.super_fold_with(self); + self.binder_index.shift_out(1); + t + } + + fn fold_region(&mut self, r: I::Region) -> I::Region { + let kind = match r.kind() { + ty::ReBound(..) => return r, + + // We may encounter `ReStatic` in item signatures or the hidden type + // of an opaque. `ReErased` should only be encountered in the hidden + // type of an opaque for regions that are ignored for the purposes of + // captures. + // + // FIXME: We should investigate the perf implications of not uniquifying + // `ReErased`. We may be able to short-circuit registering region + // obligations if we encounter a `ReErased` on one side, for example. + ty::ReStatic | ty::ReErased | ty::ReError(_) => match self.canonicalize_mode { + CanonicalizeMode::Input => CanonicalVarKind::Region(ty::UniverseIndex::ROOT), + CanonicalizeMode::Response { .. } => return r, + }, + + ty::ReEarlyParam(_) | ty::ReLateParam(_) => match self.canonicalize_mode { + CanonicalizeMode::Input => CanonicalVarKind::Region(ty::UniverseIndex::ROOT), + CanonicalizeMode::Response { .. } => { + panic!("unexpected region in response: {r:?}") + } + }, + + ty::RePlaceholder(placeholder) => match self.canonicalize_mode { + // We canonicalize placeholder regions as existentials in query inputs. + CanonicalizeMode::Input => CanonicalVarKind::Region(ty::UniverseIndex::ROOT), + CanonicalizeMode::Response { max_input_universe } => { + // If we have a placeholder region inside of a query, it must be from + // a new universe. + if max_input_universe.can_name(placeholder.universe()) { + panic!("new placeholder in universe {max_input_universe:?}: {r:?}"); + } + CanonicalVarKind::PlaceholderRegion(placeholder) + } + }, + + ty::ReVar(vid) => { + assert_eq!( + self.delegate.opportunistic_resolve_lt_var(vid), + r, + "region vid should have been resolved fully before canonicalization" + ); + match self.canonicalize_mode { + CanonicalizeMode::Input => CanonicalVarKind::Region(ty::UniverseIndex::ROOT), + CanonicalizeMode::Response { .. } => { + CanonicalVarKind::Region(self.delegate.universe_of_lt(vid).unwrap()) + } + } + } + }; + + let var = self.get_or_insert_bound_var(r, CanonicalVarInfo { kind }); + + Region::new_anon_bound(self.cx(), self.binder_index, var) + } + + fn fold_ty(&mut self, t: I::Ty) -> I::Ty { + if let Some(&ty) = self.cache.get(&(self.binder_index, t)) { + ty + } else { + let res = self.cached_fold_ty(t); + assert!(self.cache.insert((self.binder_index, t), res).is_none()); + res + } + } fn fold_const(&mut self, c: I::Const) -> I::Const { let kind = match c.kind() { @@ -419,14 +457,7 @@ impl, I: Interner> TypeFolder for Canonicaliz | ty::ConstKind::Expr(_) => return c.super_fold_with(self), }; - let var = ty::BoundVar::from( - self.variables.iter().position(|&v| v == c.into()).unwrap_or_else(|| { - let var = self.variables.len(); - self.variables.push(c.into()); - self.primitive_var_infos.push(CanonicalVarInfo { kind }); - var - }), - ); + let var = self.get_or_insert_bound_var(c, CanonicalVarInfo { kind }); Const::new_anon_bound(self.cx(), self.binder_index, var) } diff --git a/compiler/rustc_next_trait_solver/src/resolve.rs b/compiler/rustc_next_trait_solver/src/resolve.rs index 132b7400300c..f2654f7534e1 100644 --- a/compiler/rustc_next_trait_solver/src/resolve.rs +++ b/compiler/rustc_next_trait_solver/src/resolve.rs @@ -1,3 +1,4 @@ +use rustc_type_ir::data_structures::DelayedMap; use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; use rustc_type_ir::inherent::*; use rustc_type_ir::visit::TypeVisitableExt; @@ -15,11 +16,14 @@ where I: Interner, { delegate: &'a D, + /// We're able to use a cache here as the folder does not have any + /// mutable state. + cache: DelayedMap, } impl<'a, D: SolverDelegate> EagerResolver<'a, D> { pub fn new(delegate: &'a D) -> Self { - EagerResolver { delegate } + EagerResolver { delegate, cache: Default::default() } } } @@ -42,7 +46,12 @@ impl, I: Interner> TypeFolder for EagerResolv ty::Infer(ty::FloatVar(vid)) => self.delegate.opportunistic_resolve_float_var(vid), _ => { if t.has_infer() { - t.super_fold_with(self) + if let Some(&ty) = self.cache.get(&t) { + return ty; + } + let res = t.super_fold_with(self); + assert!(self.cache.insert(t, res)); + res } else { t } diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs index 520afbeb645c..cebeef76bfc0 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -639,8 +639,8 @@ where ty::Dynamic(bounds, ..) => bounds, }; - // Do not consider built-in object impls for non-object-safe types. - if bounds.principal_def_id().is_some_and(|def_id| !cx.trait_is_object_safe(def_id)) { + // Do not consider built-in object impls for dyn-incompatible types. + if bounds.principal_def_id().is_some_and(|def_id| !cx.trait_is_dyn_compatible(def_id)) { return; } diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index 12ad0724b5cb..ffa800348f2c 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -3,7 +3,7 @@ use std::ops::ControlFlow; use derive_where::derive_where; #[cfg(feature = "nightly")] use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable}; -use rustc_type_ir::data_structures::ensure_sufficient_stack; +use rustc_type_ir::data_structures::{HashMap, HashSet, ensure_sufficient_stack}; use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; use rustc_type_ir::inherent::*; use rustc_type_ir::relate::Relate; @@ -423,8 +423,8 @@ where ty::PredicateKind::Coerce(predicate) => { self.compute_coerce_goal(Goal { param_env, predicate }) } - ty::PredicateKind::ObjectSafe(trait_def_id) => { - self.compute_object_safe_goal(trait_def_id) + ty::PredicateKind::DynCompatible(trait_def_id) => { + self.compute_dyn_compatible_goal(trait_def_id) } ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => { self.compute_well_formed_goal(Goal { param_env, predicate: arg }) @@ -448,10 +448,10 @@ where } } } else { - self.delegate.enter_forall(kind, |kind| { - let goal = goal.with(self.cx(), ty::Binder::dummy(kind)); - self.add_goal(GoalSource::InstantiateHigherRanked, goal); - self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + self.enter_forall(kind, |ecx, kind| { + let goal = goal.with(ecx.cx(), ty::Binder::dummy(kind)); + ecx.add_goal(GoalSource::InstantiateHigherRanked, goal); + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) }) } } @@ -579,18 +579,16 @@ where #[instrument(level = "trace", skip(self))] pub(super) fn add_normalizes_to_goal(&mut self, mut goal: Goal>) { - goal.predicate = goal - .predicate - .fold_with(&mut ReplaceAliasWithInfer { ecx: self, param_env: goal.param_env }); + goal.predicate = + goal.predicate.fold_with(&mut ReplaceAliasWithInfer::new(self, goal.param_env)); self.inspect.add_normalizes_to_goal(self.delegate, self.max_input_universe, goal); self.nested_goals.normalizes_to_goals.push(goal); } #[instrument(level = "debug", skip(self))] pub(super) fn add_goal(&mut self, source: GoalSource, mut goal: Goal) { - goal.predicate = goal - .predicate - .fold_with(&mut ReplaceAliasWithInfer { ecx: self, param_env: goal.param_env }); + goal.predicate = + goal.predicate.fold_with(&mut ReplaceAliasWithInfer::new(self, goal.param_env)); self.inspect.add_goal(self.delegate, self.max_input_universe, source, goal); self.nested_goals.goals.push((source, goal)); } @@ -654,6 +652,7 @@ where term: I::Term, universe_of_term: ty::UniverseIndex, delegate: &'a D, + cache: HashSet, } impl, I: Interner> ContainsTermOrNotNameable<'_, D, I> { @@ -671,6 +670,10 @@ where { type Result = ControlFlow<()>; fn visit_ty(&mut self, t: I::Ty) -> Self::Result { + if self.cache.contains(&t) { + return ControlFlow::Continue(()); + } + match t.kind() { ty::Infer(ty::TyVar(vid)) => { if let ty::TermKind::Ty(term) = self.term.kind() { @@ -683,17 +686,18 @@ where } } - self.check_nameable(self.delegate.universe_of_ty(vid).unwrap()) + self.check_nameable(self.delegate.universe_of_ty(vid).unwrap())?; } - ty::Placeholder(p) => self.check_nameable(p.universe()), + ty::Placeholder(p) => self.check_nameable(p.universe())?, _ => { if t.has_non_region_infer() || t.has_placeholders() { - t.super_visit_with(self) - } else { - ControlFlow::Continue(()) + t.super_visit_with(self)? } } } + + assert!(self.cache.insert(t)); + ControlFlow::Continue(()) } fn visit_const(&mut self, c: I::Const) -> Self::Result { @@ -728,6 +732,7 @@ where delegate: self.delegate, universe_of_term, term: goal.predicate.term, + cache: Default::default(), }; goal.predicate.alias.visit_with(&mut visitor).is_continue() && goal.param_env.visit_with(&mut visitor).is_continue() @@ -840,12 +845,14 @@ where self.delegate.instantiate_binder_with_infer(value) } + /// `enter_forall`, but takes `&mut self` and passes it back through the + /// callback since it can't be aliased during the call. pub(super) fn enter_forall + Copy, U>( - &self, + &mut self, value: ty::Binder, - f: impl FnOnce(T) -> U, + f: impl FnOnce(&mut Self, T) -> U, ) -> U { - self.delegate.enter_forall(value, f) + self.delegate.enter_forall(value, |value| f(self, value)) } pub(super) fn resolve_vars_if_possible(&self, value: T) -> T @@ -1015,6 +1022,17 @@ where { ecx: &'me mut EvalCtxt<'a, D>, param_env: I::ParamEnv, + cache: HashMap, +} + +impl<'me, 'a, D, I> ReplaceAliasWithInfer<'me, 'a, D, I> +where + D: SolverDelegate, + I: Interner, +{ + fn new(ecx: &'me mut EvalCtxt<'a, D>, param_env: I::ParamEnv) -> Self { + ReplaceAliasWithInfer { ecx, param_env, cache: Default::default() } + } } impl TypeFolder for ReplaceAliasWithInfer<'_, '_, D, I> @@ -1041,7 +1059,17 @@ where ); infer_ty } - _ => ty.super_fold_with(self), + _ => { + if !ty.has_aliases() { + ty + } else if let Some(&entry) = self.cache.get(&ty) { + return entry; + } else { + let res = ty.super_fold_with(self); + assert!(self.cache.insert(ty, res).is_none()); + res + } + } } } diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs index 536b502136ad..309ab7f28d15 100644 --- a/compiler/rustc_next_trait_solver/src/solve/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs @@ -111,8 +111,8 @@ where } } - fn compute_object_safe_goal(&mut self, trait_def_id: I::DefId) -> QueryResult { - if self.cx().trait_is_object_safe(trait_def_id) { + fn compute_dyn_compatible_goal(&mut self, trait_def_id: I::DefId) -> QueryResult { + if self.cx().trait_is_dyn_compatible(trait_def_id) { self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } else { Err(NoSolution) 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 781ca127e151..2074bdec4853 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -832,8 +832,8 @@ where let cx = self.cx(); let Goal { predicate: (a_ty, _), .. } = goal; - // Can only unsize to an object-safe trait. - if b_data.principal_def_id().is_some_and(|def_id| !cx.trait_is_object_safe(def_id)) { + // Can only unsize to an dyn-compatible trait. + if b_data.principal_def_id().is_some_and(|def_id| !cx.trait_is_dyn_compatible(def_id)) { return Err(NoSolution); } @@ -895,10 +895,13 @@ where source_projection.item_def_id() == target_projection.item_def_id() && ecx .probe(|_| ProbeKind::UpcastProjectionCompatibility) - .enter(|ecx| -> Result<(), NoSolution> { - ecx.eq(param_env, source_projection, target_projection)?; - let _ = ecx.try_evaluate_added_goals()?; - Ok(()) + .enter(|ecx| -> Result<_, NoSolution> { + ecx.enter_forall(target_projection, |ecx, target_projection| { + let source_projection = + ecx.instantiate_binder_with_infer(source_projection); + ecx.eq(param_env, source_projection, target_projection)?; + ecx.try_evaluate_added_goals() + }) }) .is_ok() }; @@ -909,11 +912,14 @@ where // Check that a's supertrait (upcast_principal) is compatible // with the target (b_ty). ty::ExistentialPredicate::Trait(target_principal) => { - ecx.eq( - param_env, - upcast_principal.unwrap(), - bound.rebind(target_principal), - )?; + let source_principal = upcast_principal.unwrap(); + let target_principal = bound.rebind(target_principal); + ecx.enter_forall(target_principal, |ecx, target_principal| { + let source_principal = + ecx.instantiate_binder_with_infer(source_principal); + ecx.eq(param_env, source_principal, target_principal)?; + ecx.try_evaluate_added_goals() + })?; } // Check that b_ty's projection is satisfied by exactly one of // a_ty's projections. First, we look through the list to see if @@ -934,7 +940,12 @@ where Certainty::AMBIGUOUS, ); } - ecx.eq(param_env, source_projection, target_projection)?; + ecx.enter_forall(target_projection, |ecx, target_projection| { + let source_projection = + ecx.instantiate_binder_with_infer(source_projection); + ecx.eq(param_env, source_projection, target_projection)?; + ecx.try_evaluate_added_goals() + })?; } // Check that b_ty's auto traits are present in a_ty's bounds. ty::ExistentialPredicate::AutoTrait(def_id) => { @@ -1187,17 +1198,15 @@ where ) -> Result>, NoSolution>, ) -> Result, NoSolution> { self.probe_trait_candidate(source).enter(|ecx| { - ecx.add_goals( - GoalSource::ImplWhereBound, - constituent_tys(ecx, goal.predicate.self_ty())? - .into_iter() - .map(|ty| { - ecx.enter_forall(ty, |ty| { - goal.with(ecx.cx(), goal.predicate.with_self_ty(ecx.cx(), ty)) - }) + let goals = constituent_tys(ecx, goal.predicate.self_ty())? + .into_iter() + .map(|ty| { + ecx.enter_forall(ty, |ecx, ty| { + goal.with(ecx.cx(), goal.predicate.with_self_ty(ecx.cx(), ty)) }) - .collect::>(), - ); + }) + .collect::>(); + ecx.add_goals(GoalSource::ImplWhereBound, goals); ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) }) } diff --git a/compiler/rustc_pattern_analysis/src/constructor.rs b/compiler/rustc_pattern_analysis/src/constructor.rs index 3cb7576154fc..8fce42663453 100644 --- a/compiler/rustc_pattern_analysis/src/constructor.rs +++ b/compiler/rustc_pattern_analysis/src/constructor.rs @@ -735,10 +735,10 @@ impl Clone for Constructor { Constructor::UnionField => Constructor::UnionField, Constructor::Bool(b) => Constructor::Bool(*b), Constructor::IntRange(range) => Constructor::IntRange(*range), - Constructor::F16Range(lo, hi, end) => Constructor::F16Range(lo.clone(), *hi, *end), - Constructor::F32Range(lo, hi, end) => Constructor::F32Range(lo.clone(), *hi, *end), - Constructor::F64Range(lo, hi, end) => Constructor::F64Range(lo.clone(), *hi, *end), - Constructor::F128Range(lo, hi, end) => Constructor::F128Range(lo.clone(), *hi, *end), + Constructor::F16Range(lo, hi, end) => Constructor::F16Range(*lo, *hi, *end), + Constructor::F32Range(lo, hi, end) => Constructor::F32Range(*lo, *hi, *end), + Constructor::F64Range(lo, hi, end) => Constructor::F64Range(*lo, *hi, *end), + Constructor::F128Range(lo, hi, end) => Constructor::F128Range(*lo, *hi, *end), Constructor::Str(value) => Constructor::Str(value.clone()), Constructor::Opaque(inner) => Constructor::Opaque(inner.clone()), Constructor::Or => Constructor::Or, diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index 72737fb98cbf..70a9319d6668 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -1027,7 +1027,7 @@ impl<'p, 'tcx: 'p> PatCx for RustcPatCtxt<'p, 'tcx> { // Point at this range. first_range: thir_pat.span, // That's the gap that isn't covered. - max: gap_as_pat.to_string(), + max: gap_as_pat, // Suggest `lo..=max` instead. suggestion: suggested_range, }, diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 46e30c614ab4..582db97e1ce8 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1469,11 +1469,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } let unused_macro = self.unused_macros.iter().find_map(|(def_id, (_, unused_ident))| { - if unused_ident.name == ident.name { - Some((def_id.clone(), unused_ident.clone())) - } else { - None - } + if unused_ident.name == ident.name { Some((def_id, unused_ident)) } else { None } }); if let Some((def_id, unused_ident)) = unused_macro { diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index b84408cd0cb7..0c1a0038f9c7 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1188,7 +1188,7 @@ pub struct Resolver<'ra, 'tcx> { /// A list of proc macro LocalDefIds, written out in the order in which /// they are declared in the static array generated by proc_macro_harness. proc_macros: Vec, - confused_type_with_std_module: FxHashMap, + confused_type_with_std_module: FxIndexMap, /// Whether lifetime elision was successful. lifetime_elision_allowed: FxHashSet, diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs index 80a9ba79c285..5f7184a42407 100644 --- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs +++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs @@ -475,7 +475,7 @@ fn implemented_method<'tcx>( } else { return None; }; - let vtable_possible = - traits::is_vtable_safe_method(tcx, trait_id, trait_method) && tcx.is_object_safe(trait_id); + let vtable_possible = traits::is_vtable_safe_method(tcx, trait_id, trait_method) + && tcx.is_dyn_compatible(trait_id); vtable_possible.then_some((trait_ref, method_id, ancestor)) } diff --git a/compiler/rustc_session/Cargo.toml b/compiler/rustc_session/Cargo.toml index 721a9275d018..75cc8f18a545 100644 --- a/compiler/rustc_session/Cargo.toml +++ b/compiler/rustc_session/Cargo.toml @@ -30,7 +30,7 @@ libc = "0.2" # tidy-alphabetical-end [target.'cfg(windows)'.dependencies.windows] -version = "0.52.0" +version = "0.57.0" features = [ "Win32_Foundation", "Win32_System_LibraryLoader", diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index b052d8d72c7d..0d293415aa9c 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -3008,7 +3008,8 @@ pub(crate) mod dep_tracking { use rustc_span::edition::Edition; use rustc_target::spec::{ CodeModel, FramePointer, MergeFunctions, OnBrokenPipe, PanicStrategy, RelocModel, - RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TargetTriple, TlsModel, WasmCAbi, + RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, SymbolVisibility, TargetTriple, + TlsModel, WasmCAbi, }; use super::{ @@ -3101,6 +3102,7 @@ pub(crate) mod dep_tracking { StackProtector, SwitchWithOptPath, SymbolManglingVersion, + SymbolVisibility, RemapPathScopeComponents, SourceFileHashAlgorithm, OutFileName, diff --git a/compiler/rustc_session/src/config/cfg.rs b/compiler/rustc_session/src/config/cfg.rs index 44b96d92b199..ccc01728958b 100644 --- a/compiler/rustc_session/src/config/cfg.rs +++ b/compiler/rustc_session/src/config/cfg.rs @@ -402,18 +402,18 @@ impl CheckCfg { // Get all values map at once otherwise it would be costly. // (8 values * 220 targets ~= 1760 times, at the time of writing this comment). let [ - values_target_abi, - values_target_arch, - values_target_endian, - values_target_env, - values_target_family, - values_target_os, - values_target_pointer_width, - values_target_vendor, - ] = self - .expecteds - .get_many_mut(VALUES) - .expect("unable to get all the check-cfg values buckets"); + Some(values_target_abi), + Some(values_target_arch), + Some(values_target_endian), + Some(values_target_env), + Some(values_target_family), + Some(values_target_os), + Some(values_target_pointer_width), + Some(values_target_vendor), + ] = self.expecteds.get_many_mut(VALUES) + else { + panic!("unable to get all the check-cfg values buckets"); + }; for target in TARGETS .iter() diff --git a/compiler/rustc_session/src/lib.rs b/compiler/rustc_session/src/lib.rs index 7e059a88c279..0b4470b2b0fb 100644 --- a/compiler/rustc_session/src/lib.rs +++ b/compiler/rustc_session/src/lib.rs @@ -3,7 +3,6 @@ #![feature(iter_intersperse)] #![feature(let_chains)] #![feature(map_many_mut)] -#![feature(option_get_or_insert_default)] #![feature(rustc_attrs)] #![warn(unreachable_pub)] // tidy-alphabetical-end diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index aac776d2919a..1de09b8be4d6 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -13,8 +13,8 @@ use rustc_span::edition::Edition; use rustc_span::{RealFileName, SourceFileHashAlgorithm}; use rustc_target::spec::{ CodeModel, FramePointer, LinkerFlavorCli, MergeFunctions, OnBrokenPipe, PanicStrategy, - RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, TargetTriple, TlsModel, - WasmCAbi, + RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo, StackProtector, SymbolVisibility, + TargetTriple, TlsModel, WasmCAbi, }; use crate::config::*; @@ -416,6 +416,8 @@ mod desc { "one of: `disabled`, `trampolines`, or `aliases`"; pub(crate) const parse_symbol_mangling_version: &str = "one of: `legacy`, `v0` (RFC 2603), or `hashed`"; + pub(crate) const parse_opt_symbol_visibility: &str = + "one of: `hidden`, `protected`, or `interposable`"; pub(crate) const parse_src_file_hash: &str = "either `md5` or `sha1`"; pub(crate) const parse_relocation_model: &str = "one of supported relocation models (`rustc --print relocation-models`)"; @@ -922,6 +924,20 @@ mod parse { true } + pub(crate) fn parse_opt_symbol_visibility( + slot: &mut Option, + v: Option<&str>, + ) -> bool { + if let Some(v) = v { + if let Ok(vis) = SymbolVisibility::from_str(v) { + *slot = Some(vis); + } else { + return false; + } + } + true + } + pub(crate) fn parse_optimization_fuel( slot: &mut Option<(String, u64)>, v: Option<&str>, @@ -1688,8 +1704,8 @@ options! { "compress debug info sections (none, zlib, zstd, default: none)"), deduplicate_diagnostics: bool = (true, parse_bool, [UNTRACKED], "deduplicate identical diagnostics (default: yes)"), - default_hidden_visibility: Option = (None, parse_opt_bool, [TRACKED], - "overrides the `default_hidden_visibility` setting of the target"), + default_visibility: Option = (None, parse_opt_symbol_visibility, [TRACKED], + "overrides the `default_visibility` setting of the target"), dep_info_omit_d_target: bool = (false, parse_bool, [TRACKED], "in dep-info output, omit targets for tracking dependencies of the dep-info files \ themselves (default: no)"), diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index adc28e384625..d67e69fe0fb7 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -31,7 +31,8 @@ use rustc_span::{FileNameDisplayPreference, RealFileName, Span, Symbol}; use rustc_target::asm::InlineAsmArch; use rustc_target::spec::{ CodeModel, DebuginfoKind, PanicStrategy, RelocModel, RelroLevel, SanitizerSet, - SmallDataThresholdSupport, SplitDebuginfo, StackProtector, Target, TargetTriple, TlsModel, + SmallDataThresholdSupport, SplitDebuginfo, StackProtector, SymbolVisibility, Target, + TargetTriple, TlsModel, }; use crate::code_stats::CodeStats; @@ -617,12 +618,13 @@ impl Session { } } - /// Whether the default visibility of symbols should be "hidden" rather than "default". - pub fn default_hidden_visibility(&self) -> bool { + /// Returns the default symbol visibility. + pub fn default_visibility(&self) -> SymbolVisibility { self.opts .unstable_opts - .default_hidden_visibility - .unwrap_or(self.target.options.default_hidden_visibility) + .default_visibility + .or(self.target.options.default_visibility) + .unwrap_or(SymbolVisibility::Interposable) } } diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs index ac9a02357626..b9372283febf 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs @@ -633,8 +633,8 @@ impl<'tcx> Stable<'tcx> for ty::PredicateKind<'tcx> { PredicateKind::Clause(clause_kind) => { stable_mir::ty::PredicateKind::Clause(clause_kind.stable(tables)) } - PredicateKind::ObjectSafe(did) => { - stable_mir::ty::PredicateKind::ObjectSafe(tables.trait_def(*did)) + PredicateKind::DynCompatible(did) => { + stable_mir::ty::PredicateKind::DynCompatible(tables.trait_def(*did)) } PredicateKind::Subtype(subtype_predicate) => { stable_mir::ty::PredicateKind::SubType(subtype_predicate.stable(tables)) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 8f226b26befd..e8aa129c6cdb 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -411,6 +411,7 @@ symbols! { arbitrary_enum_discriminant, arbitrary_self_types, arbitrary_self_types_pointers, + areg, args, arith_offset, arm, diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs index 4d8c5cea8a83..df13d24cb9e2 100644 --- a/compiler/rustc_target/src/asm/mod.rs +++ b/compiler/rustc_target/src/asm/mod.rs @@ -439,7 +439,7 @@ impl InlineAsmReg { Self::Hexagon(r) => r.overlapping_regs(|r| cb(Self::Hexagon(r))), Self::LoongArch(_) => cb(self), Self::Mips(_) => cb(self), - Self::S390x(_) => cb(self), + Self::S390x(r) => r.overlapping_regs(|r| cb(Self::S390x(r))), Self::Bpf(r) => r.overlapping_regs(|r| cb(Self::Bpf(r))), Self::Avr(r) => r.overlapping_regs(|r| cb(Self::Avr(r))), Self::Msp430(_) => cb(self), @@ -892,6 +892,7 @@ pub enum InlineAsmClobberAbi { AArch64NoX18, RiscV, LoongArch, + S390x, } impl InlineAsmClobberAbi { @@ -941,6 +942,10 @@ impl InlineAsmClobberAbi { "C" | "system" => Ok(InlineAsmClobberAbi::LoongArch), _ => Err(&["C", "system"]), }, + InlineAsmArch::S390x => match name { + "C" | "system" => Ok(InlineAsmClobberAbi::S390x), + _ => Err(&["C", "system"]), + }, _ => Err(&[]), } } @@ -1098,6 +1103,28 @@ impl InlineAsmClobberAbi { f16, f17, f18, f19, f20, f21, f22, f23, } }, + InlineAsmClobberAbi::S390x => clobbered_regs! { + S390x S390xInlineAsmReg { + r0, r1, r2, r3, r4, r5, + r14, + + // f0-f7, v0-v7 + f0, f1, f2, f3, f4, f5, f6, f7, + v0, v1, v2, v3, v4, v5, v6, v7, + + // Technically the left halves of v8-v15 (i.e., f8-f15) are saved, but + // we have no way of expressing this using clobbers. + v8, v9, v10, v11, v12, v13, v14, v15, + + // Other vector registers are volatile + v16, v17, v18, v19, v20, v21, v22, v23, + v24, v25, v26, v27, v28, v29, v30, v31, + + // a0-a1 are reserved, other access registers are volatile + a2, a3, a4, a5, a6, a7, + a8, a9, a10, a11, a12, a13, a14, a15, + } + }, } } } diff --git a/compiler/rustc_target/src/asm/s390x.rs b/compiler/rustc_target/src/asm/s390x.rs index 4258b23ac57e..9b31190a72ba 100644 --- a/compiler/rustc_target/src/asm/s390x.rs +++ b/compiler/rustc_target/src/asm/s390x.rs @@ -9,6 +9,8 @@ def_reg_class! { reg, reg_addr, freg, + vreg, + areg, } } @@ -35,11 +37,13 @@ impl S390xInlineAsmRegClass { pub fn supported_types( self, - arch: InlineAsmArch, + _arch: InlineAsmArch, ) -> &'static [(InlineAsmType, Option)] { - match (self, arch) { - (Self::reg | Self::reg_addr, _) => types! { _: I8, I16, I32, I64; }, - (Self::freg, _) => types! { _: F32, F64; }, + match self { + Self::reg | Self::reg_addr => types! { _: I8, I16, I32, I64; }, + Self::freg => types! { _: F32, F64; }, + Self::vreg => &[], + Self::areg => &[], } } } @@ -76,6 +80,52 @@ def_regs! { f13: freg = ["f13"], f14: freg = ["f14"], f15: freg = ["f15"], + v0: vreg = ["v0"], + v1: vreg = ["v1"], + v2: vreg = ["v2"], + v3: vreg = ["v3"], + v4: vreg = ["v4"], + v5: vreg = ["v5"], + v6: vreg = ["v6"], + v7: vreg = ["v7"], + v8: vreg = ["v8"], + v9: vreg = ["v9"], + v10: vreg = ["v10"], + v11: vreg = ["v11"], + v12: vreg = ["v12"], + v13: vreg = ["v13"], + v14: vreg = ["v14"], + v15: vreg = ["v15"], + v16: vreg = ["v16"], + v17: vreg = ["v17"], + v18: vreg = ["v18"], + v19: vreg = ["v19"], + v20: vreg = ["v20"], + v21: vreg = ["v21"], + v22: vreg = ["v22"], + v23: vreg = ["v23"], + v24: vreg = ["v24"], + v25: vreg = ["v25"], + v26: vreg = ["v26"], + v27: vreg = ["v27"], + v28: vreg = ["v28"], + v29: vreg = ["v29"], + v30: vreg = ["v30"], + v31: vreg = ["v31"], + a2: areg = ["a2"], + a3: areg = ["a3"], + a4: areg = ["a4"], + a5: areg = ["a5"], + a6: areg = ["a6"], + a7: areg = ["a7"], + a8: areg = ["a8"], + a9: areg = ["a9"], + a10: areg = ["a10"], + a11: areg = ["a11"], + a12: areg = ["a12"], + a13: areg = ["a13"], + a14: areg = ["a14"], + a15: areg = ["a15"], #error = ["r11"] => "The frame pointer cannot be used as an operand for inline asm", #error = ["r15"] => @@ -87,13 +137,8 @@ def_regs! { "c12", "c13", "c14", "c15" ] => "control registers are reserved by the kernel and cannot be used as operands for inline asm", - #error = [ - "a0", "a1", "a2", "a3", - "a4", "a5", "a6", "a7", - "a8", "a9", "a10", "a11", - "a12", "a13", "a14", "a15" - ] => - "access registers are not supported and cannot be used as operands for inline asm", + #error = ["a0", "a1"] => + "a0 and a1 are reserved for system use and cannot be used as operands for inline asm", } } @@ -106,4 +151,48 @@ impl S390xInlineAsmReg { ) -> fmt::Result { write!(out, "%{}", self.name()) } + + pub fn overlapping_regs(self, mut cb: impl FnMut(S390xInlineAsmReg)) { + macro_rules! reg_conflicts { + ( + $( + $full:ident : $($field:ident)* + ),*; + ) => { + match self { + $( + Self::$full => { + cb(Self::$full); + $(cb(Self::$field);)* + } + $(Self::$field)|* => { + cb(Self::$full); + cb(self); + } + )* + r => cb(r), + } + }; + } + + // The left halves of v0-v15 are aliased to f0-f15. + reg_conflicts! { + v0 : f0, + v1 : f1, + v2 : f2, + v3 : f3, + v4 : f4, + v5 : f5, + v6 : f6, + v7 : f7, + v8 : f8, + v9 : f9, + v10 : f10, + v11 : f11, + v12 : f12, + v13 : f13, + v14 : f14, + v15 : f15; + } + } } diff --git a/compiler/rustc_target/src/spec/base/apple/mod.rs b/compiler/rustc_target/src/spec/base/apple/mod.rs index fdecd330c2d8..73763cf034ca 100644 --- a/compiler/rustc_target/src/spec/base/apple/mod.rs +++ b/compiler/rustc_target/src/spec/base/apple/mod.rs @@ -3,8 +3,8 @@ use std::env; use std::num::ParseIntError; use crate::spec::{ - Cc, DebuginfoKind, FramePointer, LinkArgs, LinkerFlavor, Lld, SplitDebuginfo, StackProbeType, - StaticCow, Target, TargetOptions, add_link_args, add_link_args_iter, cvs, + Cc, DebuginfoKind, FramePointer, LinkerFlavor, Lld, SplitDebuginfo, StackProbeType, StaticCow, + Target, TargetOptions, cvs, }; #[cfg(test)] @@ -40,25 +40,6 @@ impl Arch { } } - /// The architecture name to forward to the linker. - fn ld_arch(self) -> &'static str { - // Supported architecture names can be found in the source: - // https://github.com/apple-oss-distributions/ld64/blob/ld64-951.9/src/abstraction/MachOFileAbstraction.hpp#L578-L648 - match self { - Armv7k => "armv7k", - Armv7s => "armv7s", - Arm64 => "arm64", - Arm64e => "arm64e", - Arm64_32 => "arm64_32", - // ld64 doesn't understand i686, so fall back to i386 instead - // - // Same story when linking with cc, since that ends up invoking ld64. - I386 | I686 => "i386", - X86_64 => "x86_64", - X86_64h => "x86_64h", - } - } - pub(crate) fn target_arch(self) -> Cow<'static, str> { Cow::Borrowed(match self { Armv7k | Armv7s => "arm", @@ -116,104 +97,6 @@ impl TargetAbi { } } -fn pre_link_args(os: &'static str, arch: Arch, abi: TargetAbi) -> LinkArgs { - // From the man page for ld64 (`man ld`): - // > The linker accepts universal (multiple-architecture) input files, - // > but always creates a "thin" (single-architecture), standard Mach-O - // > output file. The architecture for the output file is specified using - // > the -arch option. - // - // The linker has heuristics to determine the desired architecture, but to - // be safe, and to avoid a warning, we set the architecture explicitly. - let mut args = - TargetOptions::link_args(LinkerFlavor::Darwin(Cc::No, Lld::No), &["-arch", arch.ld_arch()]); - - // From the man page for ld64 (`man ld`): - // > This is set to indicate the platform, oldest supported version of - // > that platform that output is to be used on, and the SDK that the - // > output was built against. platform [...] may be one of the following - // > strings: - // > - macos - // > - ios - // > - tvos - // > - watchos - // > - bridgeos - // > - visionos - // > - xros - // > - mac-catalyst - // > - ios-simulator - // > - tvos-simulator - // > - watchos-simulator - // > - visionos-simulator - // > - xros-simulator - // > - driverkit - // - // Like with `-arch`, the linker can figure out the platform versions - // itself from the binaries being linked, but to be safe, we specify the - // desired versions here explicitly. - let platform_name: StaticCow = match abi { - TargetAbi::Normal => os.into(), - TargetAbi::Simulator => format!("{os}-simulator").into(), - TargetAbi::MacCatalyst => "mac-catalyst".into(), - }; - let min_version: StaticCow = { - let (major, minor, patch) = deployment_target(os, arch, abi); - format!("{major}.{minor}.{patch}").into() - }; - // Lie about the SDK version, we don't know it here - let sdk_version = min_version.clone(); - add_link_args_iter( - &mut args, - LinkerFlavor::Darwin(Cc::No, Lld::No), - ["-platform_version".into(), platform_name, min_version, sdk_version].into_iter(), - ); - - // We need to communicate four things to the C compiler to be able to link: - // - The architecture. - // - The operating system (and that it's an Apple platform). - // - The deployment target. - // - The environment / ABI. - // - // We'd like to use `-target` everywhere, since that can uniquely - // communicate all of these, but that doesn't work on GCC, and since we - // don't know whether the `cc` compiler is Clang, GCC, or something else, - // we fall back to other options that also work on GCC when compiling for - // macOS. - // - // Targets other than macOS are ill-supported by GCC (it doesn't even - // support e.g. `-miphoneos-version-min`), so in those cases we can fairly - // safely use `-target`. See also the following, where it is made explicit - // that the recommendation by LLVM developers is to use `-target`: - // - if os == "macos" { - // `-arch` communicates the architecture. - // - // CC forwards the `-arch` to the linker, so we use the same value - // here intentionally. - add_link_args(&mut args, LinkerFlavor::Darwin(Cc::Yes, Lld::No), &[ - "-arch", - arch.ld_arch(), - ]); - // The presence of `-mmacosx-version-min` makes CC default to macOS, - // and it sets the deployment target. - let (major, minor, patch) = deployment_target(os, arch, abi); - let opt = format!("-mmacosx-version-min={major}.{minor}.{patch}").into(); - add_link_args_iter(&mut args, LinkerFlavor::Darwin(Cc::Yes, Lld::No), [opt].into_iter()); - // macOS has no environment, so with these two, we've told CC all the - // desired parameters. - // - // We avoid `-m32`/`-m64`, as this is already encoded by `-arch`. - } else { - add_link_args_iter( - &mut args, - LinkerFlavor::Darwin(Cc::Yes, Lld::No), - ["-target".into(), llvm_target(os, arch, abi)].into_iter(), - ); - } - - args -} - /// Get the base target options, LLVM target and `target_arch` from the three /// things that uniquely identify Rust's Apple targets: The OS, the /// architecture, and the ABI. @@ -232,7 +115,6 @@ pub(crate) fn base( // macOS has -dead_strip, which doesn't rely on function_sections function_sections: false, dynamic_linking: true, - pre_link_args: pre_link_args(os, arch, abi), families: cvs!["unix"], is_like_osx: true, // LLVM notes that macOS 10.11+ and iOS 9+ default @@ -276,23 +158,6 @@ pub(crate) fn base( (opts, llvm_target(os, arch, abi), arch.target_arch()) } -pub fn sdk_version(platform: u32) -> Option<(u16, u8)> { - // NOTE: These values are from an arbitrary point in time but shouldn't make it into the final - // binary since the final link command will have the current SDK version passed to it. - match platform { - object::macho::PLATFORM_MACOS => Some((13, 1)), - object::macho::PLATFORM_IOS - | object::macho::PLATFORM_IOSSIMULATOR - | object::macho::PLATFORM_TVOS - | object::macho::PLATFORM_TVOSSIMULATOR - | object::macho::PLATFORM_MACCATALYST => Some((16, 2)), - object::macho::PLATFORM_WATCHOS | object::macho::PLATFORM_WATCHOSSIMULATOR => Some((9, 1)), - // FIXME: Upgrade to `object-rs` 0.33+ implementation with visionOS platform definition - 11 | 12 => Some((1, 0)), - _ => None, - } -} - pub fn platform(target: &Target) -> Option { Some(match (&*target.os, &*target.abi) { ("macos", _) => object::macho::PLATFORM_MACOS, diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index f327c1fd1790..c557091242e9 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -61,7 +61,7 @@ pub mod crt_objects; mod base; pub use base::apple::{ deployment_target_for_target as current_apple_deployment_target, - platform as current_apple_platform, sdk_version as current_apple_sdk_version, + platform as current_apple_platform, }; pub use base::avr_gnu::ef_avr_arch; @@ -830,6 +830,46 @@ impl RelroLevel { } } +#[derive(Clone, Copy, Debug, PartialEq, Hash)] +pub enum SymbolVisibility { + Hidden, + Protected, + Interposable, +} + +impl SymbolVisibility { + pub fn desc(&self) -> &str { + match *self { + SymbolVisibility::Hidden => "hidden", + SymbolVisibility::Protected => "protected", + SymbolVisibility::Interposable => "interposable", + } + } +} + +impl FromStr for SymbolVisibility { + type Err = (); + + fn from_str(s: &str) -> Result { + match s { + "hidden" => Ok(SymbolVisibility::Hidden), + "protected" => Ok(SymbolVisibility::Protected), + "interposable" => Ok(SymbolVisibility::Interposable), + _ => Err(()), + } + } +} + +impl ToJson for SymbolVisibility { + fn to_json(&self) -> Json { + match *self { + SymbolVisibility::Hidden => "hidden".to_json(), + SymbolVisibility::Protected => "protected".to_json(), + SymbolVisibility::Interposable => "interposable".to_json(), + } + } +} + impl FromStr for RelroLevel { type Err = (); @@ -2326,13 +2366,12 @@ pub struct TargetOptions { /// for this target unconditionally. pub no_builtins: bool, - /// The default visibility for symbols in this target should be "hidden" - /// rather than "default". + /// The default visibility for symbols in this target. /// - /// This value typically shouldn't be accessed directly, but through - /// the `rustc_session::Session::default_hidden_visibility` method, which - /// allows `rustc` users to override this setting using cmdline flags. - pub default_hidden_visibility: bool, + /// This value typically shouldn't be accessed directly, but through the + /// `rustc_session::Session::default_visibility` method, which allows `rustc` users to override + /// this setting using cmdline flags. + pub default_visibility: Option, /// Whether a .debug_gdb_scripts section will be added to the output object file pub emit_debug_gdb_scripts: bool, @@ -2623,7 +2662,7 @@ impl Default for TargetOptions { requires_lto: false, singlethread: false, no_builtins: false, - default_hidden_visibility: false, + default_visibility: None, emit_debug_gdb_scripts: true, requires_uwtable: false, default_uwtable: false, @@ -2963,6 +3002,18 @@ impl Target { Some(Ok(())) })).unwrap_or(Ok(())) } ); + ($key_name:ident, Option) => ( { + let name = (stringify!($key_name)).replace("_", "-"); + obj.remove(&name).and_then(|o| o.as_str().and_then(|s| { + match s.parse::() { + Ok(level) => base.$key_name = Some(level), + _ => return Some(Err(format!("'{}' is not a valid value for \ + symbol-visibility. Use 'hidden', 'protected, or 'interposable'.", + s))), + } + Some(Ok(())) + })).unwrap_or(Ok(())) + } ); ($key_name:ident, DebuginfoKind) => ( { let name = (stringify!($key_name)).replace("_", "-"); obj.remove(&name).and_then(|o| o.as_str().and_then(|s| { @@ -3353,7 +3404,7 @@ impl Target { key!(requires_lto, bool); key!(singlethread, bool); key!(no_builtins, bool); - key!(default_hidden_visibility, bool); + key!(default_visibility, Option)?; key!(emit_debug_gdb_scripts, bool); key!(requires_uwtable, bool); key!(default_uwtable, bool); @@ -3633,7 +3684,7 @@ impl ToJson for Target { target_option_val!(requires_lto); target_option_val!(singlethread); target_option_val!(no_builtins); - target_option_val!(default_hidden_visibility); + target_option_val!(default_visibility); target_option_val!(emit_debug_gdb_scripts); target_option_val!(requires_uwtable); target_option_val!(default_uwtable); diff --git a/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_gnu.rs index a8163e228e69..3efbb4648361 100644 --- a/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_gnu.rs @@ -6,9 +6,8 @@ pub(crate) fn target() -> Target { base.endian = Endian::Big; // z10 is the oldest CPU supported by LLVM base.cpu = "z10".into(); - // FIXME: The ABI implementation in cabi_s390x.rs is for now hard-coded to assume the no-vector - // ABI. Pass the -vector feature string to LLVM to respect this assumption. On LLVM < 16, we - // also strip v128 from the data_layout below to match the older LLVM's expectation. + // FIXME: The ABI implementation in abi/call/s390x.rs is for now hard-coded to assume the no-vector + // ABI. Pass the -vector feature string to LLVM to respect this assumption. base.features = "-vector".into(); base.max_atomic_width = Some(128); base.min_global_align = Some(16); diff --git a/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_musl.rs index e52bcc987f9b..65b5c1167bdd 100644 --- a/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/targets/s390x_unknown_linux_musl.rs @@ -6,9 +6,8 @@ pub(crate) fn target() -> Target { base.endian = Endian::Big; // z10 is the oldest CPU supported by LLVM base.cpu = "z10".into(); - // FIXME: The ABI implementation in cabi_s390x.rs is for now hard-coded to assume the no-vector - // ABI. Pass the -vector feature string to LLVM to respect this assumption. On LLVM < 16, we - // also strip v128 from the data_layout below to match the older LLVM's expectation. + // FIXME: The ABI implementation in abi/call/s390x.rs is for now hard-coded to assume the no-vector + // ABI. Pass the -vector feature string to LLVM to respect this assumption. base.features = "-vector".into(); base.max_atomic_width = Some(128); base.min_global_align = Some(16); diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index b9e86269d459..0a98b363b1a6 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -352,11 +352,13 @@ const HEXAGON_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ const POWERPC_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ // tidy-alphabetical-start ("altivec", Unstable(sym::powerpc_target_feature), &[]), + ("partword-atomics", Unstable(sym::powerpc_target_feature), &[]), ("power10-vector", Unstable(sym::powerpc_target_feature), &["power9-vector"]), ("power8-altivec", Unstable(sym::powerpc_target_feature), &["altivec"]), ("power8-vector", Unstable(sym::powerpc_target_feature), &["vsx", "power8-altivec"]), ("power9-altivec", Unstable(sym::powerpc_target_feature), &["power8-altivec"]), ("power9-vector", Unstable(sym::powerpc_target_feature), &["power8-vector", "power9-altivec"]), + ("quadword-atomics", Unstable(sym::powerpc_target_feature), &[]), ("vsx", Unstable(sym::powerpc_target_feature), &["altivec"]), // tidy-alphabetical-end ]; @@ -371,7 +373,7 @@ const MIPS_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ const RISCV_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ // tidy-alphabetical-start - ("a", Stable, &[]), + ("a", Stable, &["zaamo", "zalrsc"]), ("c", Stable, &[]), ("d", Unstable(sym::riscv_target_feature), &["f"]), ("e", Unstable(sym::riscv_target_feature), &[]), @@ -380,6 +382,9 @@ const RISCV_ALLOWED_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ ("relax", Unstable(sym::riscv_target_feature), &[]), ("unaligned-scalar-mem", Unstable(sym::riscv_target_feature), &[]), ("v", Unstable(sym::riscv_target_feature), &[]), + ("zaamo", Unstable(sym::riscv_target_feature), &[]), + ("zabha", Unstable(sym::riscv_target_feature), &["zaamo"]), + ("zalrsc", Unstable(sym::riscv_target_feature), &[]), ("zba", Stable, &[]), ("zbb", Stable, &[]), ("zbc", 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 19e2679ae4da..5af117a3f48c 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 @@ -19,8 +19,8 @@ use rustc_middle::ty::abstract_const::NotConstEvaluatable; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable}; use rustc_middle::ty::print::{ - FmtPrinter, Print, PrintTraitPredicateExt as _, PrintTraitRefExt as _, - with_forced_trimmed_paths, + FmtPrinter, Print, PrintPolyTraitPredicateExt, PrintTraitPredicateExt as _, + PrintTraitRefExt as _, with_forced_trimmed_paths, }; use rustc_middle::ty::{ self, ToPolyTraitRef, TraitRef, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, Upcast, @@ -33,11 +33,12 @@ use tracing::{debug, instrument}; use super::on_unimplemented::{AppendConstMessage, OnUnimplementedNote}; use super::suggestions::get_explanation_based_on_obligation; use super::{ - ArgKind, CandidateSimilarity, GetSafeTransmuteErrorAndReason, ImplCandidate, UnsatisfiedConst, + ArgKind, CandidateSimilarity, FindExprBySpan, GetSafeTransmuteErrorAndReason, ImplCandidate, + UnsatisfiedConst, }; use crate::error_reporting::TypeErrCtxt; use crate::error_reporting::infer::TyCategory; -use crate::error_reporting::traits::report_object_safety_error; +use crate::error_reporting::traits::report_dyn_incompatibility; use crate::errors::{ AsyncClosureNotFn, ClosureFnMutLabel, ClosureFnOnceLabel, ClosureKindMismatch, }; @@ -46,7 +47,7 @@ use crate::traits::query::evaluate_obligation::InferCtxtExt as _; use crate::traits::{ MismatchedProjectionTypes, NormalizeExt, Obligation, ObligationCause, ObligationCauseCode, ObligationCtxt, Overflow, PredicateObligation, SelectionError, SignatureMismatch, - TraitNotObjectSafe, elaborate, + TraitDynIncompatible, elaborate, }; impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { @@ -153,6 +154,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } else { (leaf_trait_predicate, &obligation) }; + + let (main_trait_predicate, leaf_trait_predicate, predicate_constness) = self.get_effects_trait_pred_override(main_trait_predicate, leaf_trait_predicate, span); + let main_trait_ref = main_trait_predicate.to_poly_trait_ref(); let leaf_trait_ref = leaf_trait_predicate.to_poly_trait_ref(); @@ -163,9 +167,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { return guar; } - // FIXME(effects) - let predicate_is_const = false; - if let Err(guar) = leaf_trait_predicate.error_reported() { return guar; @@ -226,7 +227,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let err_msg = self.get_standard_error_message( main_trait_predicate, message, - predicate_is_const, + predicate_constness, append_const_msg, post_message, ); @@ -285,7 +286,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } if tcx.is_lang_item(leaf_trait_ref.def_id(), LangItem::Drop) - && predicate_is_const + && matches!(predicate_constness, ty::BoundConstness::ConstIfConst | ty::BoundConstness::Const) { err.note("`~const Drop` was renamed to `~const Destruct`"); err.note("See for more details"); @@ -378,14 +379,34 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { if let (ty::FnPtr(..), ty::FnDef(..)) = (cand.self_ty().kind(), main_trait_ref.self_ty().skip_binder().kind()) { - err.span_suggestion( - span.shrink_to_hi(), + // Wrap method receivers and `&`-references in parens + let suggestion = if self.tcx.sess.source_map().span_look_ahead(span, ".", Some(50)).is_some() { + vec![ + (span.shrink_to_lo(), format!("(")), + (span.shrink_to_hi(), format!(" as {})", cand.self_ty())), + ] + } else if let Some(body) = self.tcx.hir().maybe_body_owned_by(obligation.cause.body_id) { + let mut expr_finder = FindExprBySpan::new(span, self.tcx); + expr_finder.visit_expr(body.value); + if let Some(expr) = expr_finder.result && + let hir::ExprKind::AddrOf(_, _, expr) = expr.kind { + vec![ + (expr.span.shrink_to_lo(), format!("(")), + (expr.span.shrink_to_hi(), format!(" as {})", cand.self_ty())), + ] + } else { + vec![(span.shrink_to_hi(), format!(" as {}", cand.self_ty()))] + } + } else { + vec![(span.shrink_to_hi(), format!(" as {}", cand.self_ty()))] + }; + err.multipart_suggestion( format!( "the trait `{}` is implemented for fn pointer `{}`, try casting using `as`", cand.print_trait_sugared(), cand.self_ty(), ), - format!(" as {}", cand.self_ty()), + suggestion, Applicability::MaybeIncorrect, ); true @@ -547,9 +568,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ) } - ty::PredicateKind::ObjectSafe(trait_def_id) => { - let violations = self.tcx.object_safety_violations(trait_def_id); - report_object_safety_error(self.tcx, span, None, trait_def_id, violations) + ty::PredicateKind::DynCompatible(trait_def_id) => { + let violations = self.tcx.dyn_compatibility_violations(trait_def_id); + report_dyn_incompatibility(self.tcx, span, None, trait_def_id, violations) } ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(ty)) => { @@ -624,9 +645,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { def_id, ), - TraitNotObjectSafe(did) => { - let violations = self.tcx.object_safety_violations(did); - report_object_safety_error(self.tcx, span, None, did, violations) + TraitDynIncompatible(did) => { + let violations = self.tcx.dyn_compatibility_violations(did); + report_dyn_incompatibility(self.tcx, span, None, did, violations) } SelectionError::NotConstEvaluatable(NotConstEvaluatable::MentionsInfer) => { @@ -2166,29 +2187,34 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { &self, trait_predicate: ty::PolyTraitPredicate<'tcx>, message: Option, - predicate_is_const: bool, + predicate_constness: ty::BoundConstness, append_const_msg: Option, post_message: String, ) -> String { message .and_then(|cannot_do_this| { - match (predicate_is_const, append_const_msg) { + match (predicate_constness, append_const_msg) { // do nothing if predicate is not const - (false, _) => Some(cannot_do_this), + (ty::BoundConstness::NotConst, _) => Some(cannot_do_this), // suggested using default post message - (true, Some(AppendConstMessage::Default)) => { - Some(format!("{cannot_do_this} in const contexts")) - } + ( + ty::BoundConstness::Const | ty::BoundConstness::ConstIfConst, + Some(AppendConstMessage::Default), + ) => Some(format!("{cannot_do_this} in const contexts")), // overridden post message - (true, Some(AppendConstMessage::Custom(custom_msg, _))) => { - Some(format!("{cannot_do_this}{custom_msg}")) - } + ( + ty::BoundConstness::Const | ty::BoundConstness::ConstIfConst, + Some(AppendConstMessage::Custom(custom_msg, _)), + ) => Some(format!("{cannot_do_this}{custom_msg}")), // fallback to generic message - (true, None) => None, + (ty::BoundConstness::Const | ty::BoundConstness::ConstIfConst, None) => None, } }) .unwrap_or_else(|| { - format!("the trait bound `{trait_predicate}` is not satisfied{post_message}") + format!( + "the trait bound `{}` is not satisfied{post_message}", + trait_predicate.print_with_bound_constness(predicate_constness) + ) }) } @@ -2312,6 +2338,51 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } + /// For effects predicates such as `::Effects: Compat`, pretend that the + /// predicate that failed was `u32: Add`. Return the constness of such predicate to later + /// print as `u32: ~const Add`. + fn get_effects_trait_pred_override( + &self, + p: ty::PolyTraitPredicate<'tcx>, + leaf: ty::PolyTraitPredicate<'tcx>, + span: Span, + ) -> (ty::PolyTraitPredicate<'tcx>, ty::PolyTraitPredicate<'tcx>, ty::BoundConstness) { + let trait_ref = p.to_poly_trait_ref(); + if !self.tcx.is_lang_item(trait_ref.def_id(), LangItem::EffectsCompat) { + return (p, leaf, ty::BoundConstness::NotConst); + } + + let Some(ty::Alias(ty::AliasTyKind::Projection, projection)) = + trait_ref.self_ty().no_bound_vars().map(Ty::kind) + else { + return (p, leaf, ty::BoundConstness::NotConst); + }; + + let constness = trait_ref.skip_binder().args.const_at(1); + + let constness = if constness == self.tcx.consts.true_ || constness.is_ct_infer() { + ty::BoundConstness::NotConst + } else if constness == self.tcx.consts.false_ { + ty::BoundConstness::Const + } else if matches!(constness.kind(), ty::ConstKind::Param(_)) { + ty::BoundConstness::ConstIfConst + } else { + self.dcx().span_bug(span, format!("Unknown constness argument: {constness:?}")); + }; + + let new_pred = p.map_bound(|mut trait_pred| { + trait_pred.trait_ref = projection.trait_ref(self.tcx); + trait_pred + }); + + let new_leaf = leaf.map_bound(|mut trait_pred| { + trait_pred.trait_ref = projection.trait_ref(self.tcx); + trait_pred + }); + + (new_pred, new_leaf, constness) + } + fn add_tuple_trait_message( &self, obligation_cause_code: &ObligationCauseCode<'tcx>, @@ -2635,49 +2706,47 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // This shouldn't be common unless manually implementing one of the // traits manually, but don't make it more confusing when it does // happen. - Ok( - if Some(expected_trait_ref.def_id) != self.tcx.lang_items().coroutine_trait() - && not_tupled - { - self.report_and_explain_type_error( - TypeTrace::trait_refs( - &obligation.cause, - true, - expected_trait_ref, - found_trait_ref, - ), - ty::error::TypeError::Mismatch, - ) - } else if found.len() == expected.len() { - self.report_closure_arg_mismatch( - span, - found_span, - found_trait_ref, - expected_trait_ref, - obligation.cause.code(), - found_node, - obligation.param_env, - ) - } else { - let (closure_span, closure_arg_span, found) = found_did - .and_then(|did| { - let node = self.tcx.hir().get_if_local(did)?; - let (found_span, closure_arg_span, found) = - self.get_fn_like_arguments(node)?; - Some((Some(found_span), closure_arg_span, found)) - }) - .unwrap_or((found_span, None, found)); + if Some(expected_trait_ref.def_id) != self.tcx.lang_items().coroutine_trait() && not_tupled + { + return Ok(self.report_and_explain_type_error( + TypeTrace::trait_refs(&obligation.cause, true, expected_trait_ref, found_trait_ref), + ty::error::TypeError::Mismatch, + )); + } + if found.len() != expected.len() { + let (closure_span, closure_arg_span, found) = found_did + .and_then(|did| { + let node = self.tcx.hir().get_if_local(did)?; + let (found_span, closure_arg_span, found) = self.get_fn_like_arguments(node)?; + Some((Some(found_span), closure_arg_span, found)) + }) + .unwrap_or((found_span, None, found)); - self.report_arg_count_mismatch( + // If the coroutine take a single () as its argument, + // the trait argument would found the coroutine take 0 arguments, + // but get_fn_like_arguments would give 1 argument. + // This would result in "Expected to take 1 argument, but it takes 1 argument". + // Check again to avoid this. + if found.len() != expected.len() { + return Ok(self.report_arg_count_mismatch( span, closure_span, expected, found, found_trait_ty.is_closure(), closure_arg_span, - ) - }, - ) + )); + } + } + Ok(self.report_closure_arg_mismatch( + span, + found_span, + found_trait_ref, + expected_trait_ref, + obligation.cause.code(), + found_node, + obligation.param_env, + )) } /// Given some node representing a fn-like thing in the HIR map, diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs index b229499a9f4c..109bae10b54c 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs @@ -12,8 +12,8 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::Visitor; use rustc_hir::{self as hir, LangItem}; use rustc_infer::traits::{ - ObjectSafetyViolation, Obligation, ObligationCause, ObligationCauseCode, PredicateObligation, - SelectionError, + DynCompatibilityViolation, Obligation, ObligationCause, ObligationCauseCode, + PredicateObligation, SelectionError, }; use rustc_middle::ty::print::{PrintTraitRefExt as _, with_no_trimmed_paths}; use rustc_middle::ty::{self, Ty, TyCtxt}; @@ -406,12 +406,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } -pub fn report_object_safety_error<'tcx>( +pub fn report_dyn_incompatibility<'tcx>( tcx: TyCtxt<'tcx>, span: Span, hir_id: Option, trait_def_id: DefId, - violations: &[ObjectSafetyViolation], + violations: &[DynCompatibilityViolation], ) -> Diag<'tcx> { let trait_str = tcx.def_path_str(trait_def_id); let trait_span = tcx.hir().get_if_local(trait_def_id).and_then(|node| match node { @@ -449,12 +449,12 @@ pub fn report_object_safety_error<'tcx>( let mut multi_span = vec![]; let mut messages = vec![]; for violation in violations { - if let ObjectSafetyViolation::SizedSelf(sp) = &violation + if let DynCompatibilityViolation::SizedSelf(sp) = &violation && !sp.is_empty() { // Do not report `SizedSelf` without spans pointing at `SizedSelf` obligations // with a `Span`. - reported_violations.insert(ObjectSafetyViolation::SizedSelf(vec![].into())); + reported_violations.insert(DynCompatibilityViolation::SizedSelf(vec![].into())); } if reported_violations.insert(violation.clone()) { let spans = violation.spans(); @@ -481,9 +481,10 @@ pub fn report_object_safety_error<'tcx>( for (span, msg) in iter::zip(multi_span, messages) { note_span.push_span_label(span, msg); } + // FIXME(dyn_compat_renaming): Update the URL. err.span_note( note_span, - "for a trait to be \"object safe\" it needs to allow building a vtable to allow the call \ + "for a trait to be \"dyn-compatible\" it needs to allow building a vtable to allow the call \ to be resolvable dynamically; for more information visit \ ", ); diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index fc15f5b5906f..c6e3ba3c9573 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -275,7 +275,7 @@ fn fulfillment_error_for_no_solution<'tcx>( FulfillmentErrorCode::Subtype(expected_found, TypeError::Sorts(expected_found)) } ty::PredicateKind::Clause(_) - | ty::PredicateKind::ObjectSafe(_) + | ty::PredicateKind::DynCompatible(_) | ty::PredicateKind::Ambiguous => { FulfillmentErrorCode::Select(SelectionError::Unimplemented) } diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index f68e05833079..12aeee0d02fe 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -802,7 +802,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..)) | ty::PredicateKind::NormalizesTo(..) | ty::PredicateKind::AliasRelate(..) - | ty::PredicateKind::ObjectSafe(..) + | ty::PredicateKind::DynCompatible(..) | ty::PredicateKind::Subtype(..) // FIXME(generic_const_exprs): you can absolutely add this as a where clauses | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs similarity index 94% rename from compiler/rustc_trait_selection/src/traits/object_safety.rs rename to compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs index b6169f8508d5..d5d7681a8d60 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs @@ -28,43 +28,43 @@ use tracing::{debug, instrument}; use super::elaborate; use crate::infer::TyCtxtInferExt; -pub use crate::traits::ObjectSafetyViolation; +pub use crate::traits::DynCompatibilityViolation; use crate::traits::query::evaluate_obligation::InferCtxtExt; use crate::traits::{MethodViolationCode, Obligation, ObligationCause, util}; -/// Returns the object safety violations that affect HIR ty lowering. +/// Returns the dyn-compatibility violations that affect HIR ty lowering. /// /// Currently that is `Self` in supertraits. This is needed -/// because `object_safety_violations` can't be used during +/// because `dyn_compatibility_violations` can't be used during /// type collection. -#[instrument(level = "debug", skip(tcx))] -pub fn hir_ty_lowering_object_safety_violations( +#[instrument(level = "debug", skip(tcx), ret)] +pub fn hir_ty_lowering_dyn_compatibility_violations( tcx: TyCtxt<'_>, trait_def_id: DefId, -) -> Vec { +) -> Vec { debug_assert!(tcx.generics_of(trait_def_id).has_self); - let violations = tcx - .supertrait_def_ids(trait_def_id) + tcx.supertrait_def_ids(trait_def_id) .map(|def_id| predicates_reference_self(tcx, def_id, true)) .filter(|spans| !spans.is_empty()) - .map(ObjectSafetyViolation::SupertraitSelf) - .collect(); - debug!(?violations); - violations + .map(DynCompatibilityViolation::SupertraitSelf) + .collect() } -fn object_safety_violations(tcx: TyCtxt<'_>, trait_def_id: DefId) -> &'_ [ObjectSafetyViolation] { +fn dyn_compatibility_violations( + tcx: TyCtxt<'_>, + trait_def_id: DefId, +) -> &'_ [DynCompatibilityViolation] { debug_assert!(tcx.generics_of(trait_def_id).has_self); - debug!("object_safety_violations: {:?}", trait_def_id); + debug!("dyn_compatibility_violations: {:?}", trait_def_id); tcx.arena.alloc_from_iter( tcx.supertrait_def_ids(trait_def_id) - .flat_map(|def_id| object_safety_violations_for_trait(tcx, def_id)), + .flat_map(|def_id| dyn_compatibility_violations_for_trait(tcx, def_id)), ) } -fn is_object_safe(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool { - tcx.object_safety_violations(trait_def_id).is_empty() +fn is_dyn_compatible(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool { + tcx.dyn_compatibility_violations(trait_def_id).is_empty() } /// We say a method is *vtable safe* if it can be invoked on a trait @@ -82,34 +82,35 @@ pub fn is_vtable_safe_method(tcx: TyCtxt<'_>, trait_def_id: DefId, method: ty::A virtual_call_violations_for_method(tcx, trait_def_id, method).is_empty() } -fn object_safety_violations_for_trait( +#[instrument(level = "debug", skip(tcx), ret)] +fn dyn_compatibility_violations_for_trait( tcx: TyCtxt<'_>, trait_def_id: DefId, -) -> Vec { +) -> Vec { // Check assoc items for violations. let mut violations: Vec<_> = tcx .associated_items(trait_def_id) .in_definition_order() - .flat_map(|&item| object_safety_violations_for_assoc_item(tcx, trait_def_id, item)) + .flat_map(|&item| dyn_compatibility_violations_for_assoc_item(tcx, trait_def_id, item)) .collect(); // Check the trait itself. if trait_has_sized_self(tcx, trait_def_id) { // We don't want to include the requirement from `Sized` itself to be `Sized` in the list. let spans = get_sized_bounds(tcx, trait_def_id); - violations.push(ObjectSafetyViolation::SizedSelf(spans)); + violations.push(DynCompatibilityViolation::SizedSelf(spans)); } let spans = predicates_reference_self(tcx, trait_def_id, false); if !spans.is_empty() { - violations.push(ObjectSafetyViolation::SupertraitSelf(spans)); + violations.push(DynCompatibilityViolation::SupertraitSelf(spans)); } let spans = bounds_reference_self(tcx, trait_def_id); if !spans.is_empty() { - violations.push(ObjectSafetyViolation::SupertraitSelf(spans)); + violations.push(DynCompatibilityViolation::SupertraitSelf(spans)); } let spans = super_predicates_have_non_lifetime_binders(tcx, trait_def_id); if !spans.is_empty() { - violations.push(ObjectSafetyViolation::SupertraitNonLifetimeBinder(spans)); + violations.push(DynCompatibilityViolation::SupertraitNonLifetimeBinder(spans)); } if violations.is_empty() { @@ -120,11 +121,6 @@ fn object_safety_violations_for_trait( } } - debug!( - "object_safety_violations_for_trait(trait_def_id={:?}) = {:?}", - trait_def_id, violations - ); - violations } @@ -296,13 +292,13 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool { }) } -/// Returns `Some(_)` if this item makes the containing trait not object safe. +/// Returns `Some(_)` if this item makes the containing trait dyn-incompatible. #[instrument(level = "debug", skip(tcx), ret)] -pub fn object_safety_violations_for_assoc_item( +pub fn dyn_compatibility_violations_for_assoc_item( tcx: TyCtxt<'_>, trait_def_id: DefId, item: ty::AssocItem, -) -> Vec { +) -> Vec { // Any item that has a `Self : Sized` requisite is otherwise // exempt from the regulations. if tcx.generics_require_sized_self(item.def_id) { @@ -310,10 +306,10 @@ pub fn object_safety_violations_for_assoc_item( } match item.kind { - // Associated consts are never object safe, as they can't have `where` bounds yet at all, + // Associated consts are never dyn-compatible, as they can't have `where` bounds yet at all, // and associated const bounds in trait objects aren't a thing yet either. ty::AssocKind::Const => { - vec![ObjectSafetyViolation::AssocConst(item.name, item.ident(tcx).span)] + vec![DynCompatibilityViolation::AssocConst(item.name, item.ident(tcx).span)] } ty::AssocKind::Fn => virtual_call_violations_for_method(tcx, trait_def_id, item) .into_iter() @@ -330,16 +326,16 @@ pub fn object_safety_violations_for_assoc_item( _ => item.ident(tcx).span, }; - ObjectSafetyViolation::Method(item.name, v, span) + DynCompatibilityViolation::Method(item.name, v, span) }) .collect(), - // Associated types can only be object safe if they have `Self: Sized` bounds. + // Associated types can only be dyn-compatible if they have `Self: Sized` bounds. ty::AssocKind::Type => { if !tcx.features().generic_associated_types_extended && !tcx.generics_of(item.def_id).is_own_empty() && !item.is_impl_trait_in_trait() { - vec![ObjectSafetyViolation::GAT(item.name, item.ident(tcx).span)] + vec![DynCompatibilityViolation::GAT(item.name, item.ident(tcx).span)] } else { // We will permit associated types if they are explicitly mentioned in the trait object. // We can't check this here, as here we only check if it is guaranteed to not be possible. @@ -351,8 +347,8 @@ pub fn object_safety_violations_for_assoc_item( /// Returns `Some(_)` if this method cannot be called on a trait /// object; this does not necessarily imply that the enclosing trait -/// is not object safe, because the method might have a where clause -/// `Self:Sized`. +/// is dyn-incompatible, because the method might have a where clause +/// `Self: Sized`. fn virtual_call_violations_for_method<'tcx>( tcx: TyCtxt<'tcx>, trait_def_id: DefId, @@ -932,8 +928,8 @@ fn contains_illegal_impl_trait_in_trait<'tcx>( pub(crate) fn provide(providers: &mut Providers) { *providers = Providers { - object_safety_violations, - is_object_safe, + dyn_compatibility_violations, + is_dyn_compatible, generics_require_sized_self, ..*providers }; diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs index de1d4ef15ace..d562692c1a86 100644 --- a/compiler/rustc_trait_selection/src/traits/engine.rs +++ b/compiler/rustc_trait_selection/src/traits/engine.rs @@ -9,12 +9,13 @@ use rustc_infer::infer::canonical::{ Canonical, CanonicalQueryResponse, CanonicalVarValues, QueryResponse, }; use rustc_infer::infer::outlives::env::OutlivesEnvironment; -use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk, RegionResolutionError}; +use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk, RegionResolutionError, TypeTrace}; use rustc_macros::extension; use rustc_middle::arena::ArenaAllocatable; use rustc_middle::traits::query::NoSolution; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, Upcast, Variance}; +use rustc_type_ir::relate::Relate; use super::{FromSolverError, FulfillmentContext, ScrubbedTraitError, TraitEngine}; use crate::error_reporting::InferCtxtErrorExt; @@ -133,6 +134,20 @@ where .map(|infer_ok| self.register_infer_ok_obligations(infer_ok)) } + pub fn eq_trace>>( + &self, + cause: &ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + trace: TypeTrace<'tcx>, + expected: T, + actual: T, + ) -> Result<(), TypeError<'tcx>> { + self.infcx + .at(cause, param_env) + .eq_trace(DefineOpaqueTypes::Yes, trace, expected, actual) + .map(|infer_ok| self.register_infer_ok_obligations(infer_ok)) + } + /// Checks whether `expected` is a subtype of `actual`: `expected <: actual`. pub fn sub>( &self, diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index fcd0936c055c..33b8cf037017 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -363,7 +363,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { | ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(_)) | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..)) | ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) - | ty::PredicateKind::ObjectSafe(_) + | ty::PredicateKind::DynCompatible(_) | ty::PredicateKind::Subtype(_) | ty::PredicateKind::Coerce(_) | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) @@ -418,8 +418,8 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { ) } - ty::PredicateKind::ObjectSafe(trait_def_id) => { - if !self.selcx.tcx().is_object_safe(trait_def_id) { + ty::PredicateKind::DynCompatible(trait_def_id) => { + if !self.selcx.tcx().is_dyn_compatible(trait_def_id) { ProcessResult::Error(FulfillmentErrorCode::Select(Unimplemented)) } else { ProcessResult::Changed(vec![]) diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 61592d477847..655bef0bab74 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -5,11 +5,11 @@ pub mod auto_trait; pub(crate) mod coherence; pub mod const_evaluatable; +mod dyn_compatibility; mod engine; mod fulfill; pub mod misc; pub mod normalize; -mod object_safety; pub mod outlives_bounds; pub mod project; pub mod query; @@ -43,13 +43,13 @@ pub use self::coherence::{ InCrate, IsFirstInputType, OrphanCheckErr, OrphanCheckMode, OverlapResult, UncoveredTyParams, add_placeholder_note, orphan_check_trait_ref, overlapping_impls, }; +pub use self::dyn_compatibility::{ + DynCompatibilityViolation, dyn_compatibility_violations_for_assoc_item, + hir_ty_lowering_dyn_compatibility_violations, is_vtable_safe_method, +}; pub use self::engine::{ObligationCtxt, TraitEngineExt}; pub use self::fulfill::{FulfillmentContext, OldSolverError, PendingPredicateObligation}; pub use self::normalize::NormalizeExt; -pub use self::object_safety::{ - ObjectSafetyViolation, hir_ty_lowering_object_safety_violations, is_vtable_safe_method, - object_safety_violations_for_assoc_item, -}; pub use self::project::{normalize_inherent_projection, normalize_projection_ty}; pub use self::select::{ EvaluationCache, EvaluationResult, IntercrateAmbiguityCause, OverflowError, SelectionCache, @@ -593,7 +593,7 @@ fn is_impossible_associated_item( } pub fn provide(providers: &mut Providers) { - object_safety::provide(providers); + dyn_compatibility::provide(providers); vtable::provide(providers); *providers = Providers { specialization_graph_of: specialize::specialization_graph_provider, diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs index 3d9dc1a8d4d5..bab038af9ed2 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs @@ -113,7 +113,7 @@ pub fn compute_implied_outlives_bounds_inner<'tcx>( | ty::PredicateKind::Subtype(..) | ty::PredicateKind::Coerce(..) | ty::PredicateKind::Clause(ty::ClauseKind::Projection(..)) - | ty::PredicateKind::ObjectSafe(..) + | ty::PredicateKind::DynCompatible(..) | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) | ty::PredicateKind::ConstEquate(..) | ty::PredicateKind::Ambiguous @@ -217,7 +217,7 @@ pub fn compute_implied_outlives_bounds_compat_inner<'tcx>( | ty::PredicateKind::Subtype(..) | ty::PredicateKind::Coerce(..) | ty::PredicateKind::Clause(ty::ClauseKind::Projection(..)) - | ty::PredicateKind::ObjectSafe(..) + | ty::PredicateKind::DynCompatible(..) | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) | ty::PredicateKind::ConstEquate(..) | ty::PredicateKind::Ambiguous diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index e5f1d5c36daf..084b61115dbc 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -883,7 +883,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { if let Some(principal) = data.principal() { if !self.infcx.tcx.features().object_safe_for_dispatch { principal.with_self_ty(self.tcx(), self_ty) - } else if self.tcx().is_object_safe(principal.def_id()) { + } else if self.tcx().is_dyn_compatible(principal.def_id()) { principal.with_self_ty(self.tcx(), self_ty) } else { return; diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index d15acd51c86e..5141e969608e 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -30,7 +30,7 @@ use crate::traits::util::{self, closure_trait_ref_and_return_type}; use crate::traits::{ ImplDerivedCause, ImplSource, ImplSourceUserDefinedData, Normalized, Obligation, ObligationCause, PolyTraitObligation, PredicateObligation, Selection, SelectionError, - SignatureMismatch, TraitNotObjectSafe, TraitObligation, Unimplemented, + SignatureMismatch, TraitDynIncompatible, TraitObligation, Unimplemented, }; impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { @@ -630,7 +630,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.cause.span, "GATs in trait object shouldn't have been considered", ); - return Err(SelectionError::TraitNotObjectSafe(trait_predicate.trait_ref.def_id)); + return Err(SelectionError::TraitDynIncompatible(trait_predicate.trait_ref.def_id)); } // This maybe belongs in wf, but that can't (doesn't) handle @@ -1187,11 +1187,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ImplSource::Builtin(BuiltinImplSource::Misc, obligations) } - // `T` -> `Trait` + // `T` -> `dyn Trait` (_, &ty::Dynamic(data, r, ty::Dyn)) => { let mut object_dids = data.auto_traits().chain(data.principal_def_id()); - if let Some(did) = object_dids.find(|did| !tcx.is_object_safe(*did)) { - return Err(TraitNotObjectSafe(did)); + if let Some(did) = object_dids.find(|did| !tcx.is_dyn_compatible(*did)) { + return Err(TraitDynIncompatible(did)); } let predicate_to_obligation = |predicate| { diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index cbc17a058f6d..fba1d1025ca6 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -16,6 +16,7 @@ use rustc_hir::LangItem; use rustc_hir::def_id::DefId; use rustc_infer::infer::BoundRegionConversionTime::{self, HigherRankedType}; use rustc_infer::infer::DefineOpaqueTypes; +use rustc_infer::infer::at::ToTrace; use rustc_infer::infer::relate::TypeRelation; use rustc_infer::traits::TraitObligation; use rustc_middle::bug; @@ -44,7 +45,7 @@ use super::{ TraitQueryMode, const_evaluatable, project, util, wf, }; use crate::error_reporting::InferCtxtErrorExt; -use crate::infer::{InferCtxt, InferCtxtExt, InferOk, TypeFreshener}; +use crate::infer::{InferCtxt, InferOk, TypeFreshener}; use crate::solve::InferCtxtSelectExt as _; use crate::traits::normalize::{normalize_with_depth, normalize_with_depth_to}; use crate::traits::project::{ProjectAndUnifyResult, ProjectionCacheKeyExt}; @@ -772,8 +773,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { Ok(EvaluatedToOkModuloRegions) } - ty::PredicateKind::ObjectSafe(trait_def_id) => { - if self.tcx().is_object_safe(trait_def_id) { + ty::PredicateKind::DynCompatible(trait_def_id) => { + if self.tcx().is_dyn_compatible(trait_def_id) { Ok(EvaluatedToOk) } else { Ok(EvaluatedToErr) @@ -2579,16 +2580,31 @@ impl<'tcx> SelectionContext<'_, 'tcx> { // Check that a_ty's supertrait (upcast_principal) is compatible // with the target (b_ty). ty::ExistentialPredicate::Trait(target_principal) => { + let hr_source_principal = upcast_principal.map_bound(|trait_ref| { + ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref) + }); + let hr_target_principal = bound.rebind(target_principal); + nested.extend( self.infcx - .at(&obligation.cause, obligation.param_env) - .eq( - DefineOpaqueTypes::Yes, - upcast_principal.map_bound(|trait_ref| { - ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref) - }), - bound.rebind(target_principal), - ) + .enter_forall(hr_target_principal, |target_principal| { + let source_principal = + self.infcx.instantiate_binder_with_fresh_vars( + obligation.cause.span, + HigherRankedType, + hr_source_principal, + ); + self.infcx.at(&obligation.cause, obligation.param_env).eq_trace( + DefineOpaqueTypes::Yes, + ToTrace::to_trace( + &obligation.cause, + hr_target_principal, + hr_source_principal, + ), + target_principal, + source_principal, + ) + }) .map_err(|_| SelectionError::Unimplemented)? .into_obligations(), ); @@ -2599,19 +2615,40 @@ impl<'tcx> SelectionContext<'_, 'tcx> { // return ambiguity. Otherwise, if exactly one matches, equate // it with b_ty's projection. ty::ExistentialPredicate::Projection(target_projection) => { - let target_projection = bound.rebind(target_projection); + let hr_target_projection = bound.rebind(target_projection); + let mut matching_projections = - a_data.projection_bounds().filter(|source_projection| { + a_data.projection_bounds().filter(|&hr_source_projection| { // Eager normalization means that we can just use can_eq // here instead of equating and processing obligations. - source_projection.item_def_id() == target_projection.item_def_id() - && self.infcx.can_eq( - obligation.param_env, - *source_projection, - target_projection, - ) + hr_source_projection.item_def_id() == hr_target_projection.item_def_id() + && self.infcx.probe(|_| { + self.infcx + .enter_forall(hr_target_projection, |target_projection| { + let source_projection = + self.infcx.instantiate_binder_with_fresh_vars( + obligation.cause.span, + HigherRankedType, + hr_source_projection, + ); + self.infcx + .at(&obligation.cause, obligation.param_env) + .eq_trace( + DefineOpaqueTypes::Yes, + ToTrace::to_trace( + &obligation.cause, + hr_target_projection, + hr_source_projection, + ), + target_projection, + source_projection, + ) + }) + .is_ok() + }) }); - let Some(source_projection) = matching_projections.next() else { + + let Some(hr_source_projection) = matching_projections.next() else { return Err(SelectionError::Unimplemented); }; if matching_projections.next().is_some() { @@ -2619,8 +2656,24 @@ impl<'tcx> SelectionContext<'_, 'tcx> { } nested.extend( self.infcx - .at(&obligation.cause, obligation.param_env) - .eq(DefineOpaqueTypes::Yes, source_projection, target_projection) + .enter_forall(hr_target_projection, |target_projection| { + let source_projection = + self.infcx.instantiate_binder_with_fresh_vars( + obligation.cause.span, + HigherRankedType, + hr_source_projection, + ); + self.infcx.at(&obligation.cause, obligation.param_env).eq_trace( + DefineOpaqueTypes::Yes, + ToTrace::to_trace( + &obligation.cause, + hr_target_projection, + hr_source_projection, + ), + target_projection, + source_projection, + ) + }) .map_err(|_| SelectionError::Unimplemented)? .into_obligations(), ); diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs index a2760fe6049b..6e6f948a2cdc 100644 --- a/compiler/rustc_trait_selection/src/traits/vtable.rs +++ b/compiler/rustc_trait_selection/src/traits/vtable.rs @@ -2,6 +2,9 @@ use std::fmt::Debug; use std::ops::ControlFlow; use rustc_hir::def_id::DefId; +use rustc_infer::infer::at::ToTrace; +use rustc_infer::infer::{BoundRegionConversionTime, TyCtxtInferExt}; +use rustc_infer::traits::ObligationCause; use rustc_infer::traits::util::PredicateSet; use rustc_middle::bug; use rustc_middle::query::Providers; @@ -13,7 +16,7 @@ use smallvec::{SmallVec, smallvec}; use tracing::debug; use crate::errors::DumpVTableEntries; -use crate::traits::{impossible_predicates, is_vtable_safe_method}; +use crate::traits::{ObligationCtxt, impossible_predicates, is_vtable_safe_method}; #[derive(Clone, Debug)] pub enum VtblSegment<'tcx> { @@ -22,6 +25,8 @@ pub enum VtblSegment<'tcx> { } /// Prepare the segments for a vtable +// FIXME: This should take a `PolyExistentialTraitRef`, since we don't care +// about our `Self` type here. pub fn prepare_vtable_segments<'tcx, T>( tcx: TyCtxt<'tcx>, trait_ref: ty::PolyTraitRef<'tcx>, @@ -327,14 +332,10 @@ pub(crate) fn first_method_vtable_slot<'tcx>(tcx: TyCtxt<'tcx>, key: ty::TraitRe let ty::Dynamic(source, _, _) = *key.self_ty().kind() else { bug!(); }; - let source_principal = tcx - .normalize_erasing_regions(ty::ParamEnv::reveal_all(), source.principal().unwrap()) - .with_self_ty(tcx, tcx.types.trait_object_dummy_self); + let source_principal = + source.principal().unwrap().with_self_ty(tcx, tcx.types.trait_object_dummy_self); - let target_principal = tcx - .normalize_erasing_regions(ty::ParamEnv::reveal_all(), key) - // We don't care about the self type, since it will always be the same thing. - .with_self_ty(tcx, tcx.types.trait_object_dummy_self); + let target_principal = ty::Binder::dummy(ty::ExistentialTraitRef::erase_self_ty(tcx, key)); let vtable_segment_callback = { let mut vptr_offset = 0; @@ -343,15 +344,18 @@ pub(crate) fn first_method_vtable_slot<'tcx>(tcx: TyCtxt<'tcx>, key: ty::TraitRe VtblSegment::MetadataDSA => { vptr_offset += TyCtxt::COMMON_VTABLE_ENTRIES.len(); } - VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => { - if tcx - .normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), trait_ref) - == target_principal - { + VtblSegment::TraitOwnEntries { trait_ref: vtable_principal, emit_vptr } => { + if trait_refs_are_compatible( + tcx, + vtable_principal + .map_bound(|t| ty::ExistentialTraitRef::erase_self_ty(tcx, t)), + target_principal, + ) { return ControlFlow::Break(vptr_offset); } - vptr_offset += tcx.own_existential_vtable_entries(trait_ref.def_id()).len(); + vptr_offset += + tcx.own_existential_vtable_entries(vtable_principal.def_id()).len(); if emit_vptr { vptr_offset += 1; @@ -383,17 +387,14 @@ pub(crate) fn supertrait_vtable_slot<'tcx>( let ty::Dynamic(target, _, _) = *target.kind() else { bug!(); }; - let target_principal = tcx - .normalize_erasing_regions(ty::ParamEnv::reveal_all(), target.principal()?) - .with_self_ty(tcx, tcx.types.trait_object_dummy_self); + let target_principal = target.principal()?; // Given that we have a target principal, it is a bug for there not to be a source principal. let ty::Dynamic(source, _, _) = *source.kind() else { bug!(); }; - let source_principal = tcx - .normalize_erasing_regions(ty::ParamEnv::reveal_all(), source.principal().unwrap()) - .with_self_ty(tcx, tcx.types.trait_object_dummy_self); + let source_principal = + source.principal().unwrap().with_self_ty(tcx, tcx.types.trait_object_dummy_self); let vtable_segment_callback = { let mut vptr_offset = 0; @@ -402,11 +403,15 @@ pub(crate) fn supertrait_vtable_slot<'tcx>( VtblSegment::MetadataDSA => { vptr_offset += TyCtxt::COMMON_VTABLE_ENTRIES.len(); } - VtblSegment::TraitOwnEntries { trait_ref, emit_vptr } => { - vptr_offset += tcx.own_existential_vtable_entries(trait_ref.def_id()).len(); - if tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), trait_ref) - == target_principal - { + VtblSegment::TraitOwnEntries { trait_ref: vtable_principal, emit_vptr } => { + vptr_offset += + tcx.own_existential_vtable_entries(vtable_principal.def_id()).len(); + if trait_refs_are_compatible( + tcx, + vtable_principal + .map_bound(|t| ty::ExistentialTraitRef::erase_self_ty(tcx, t)), + target_principal, + ) { if emit_vptr { return ControlFlow::Break(Some(vptr_offset)); } else { @@ -426,6 +431,41 @@ pub(crate) fn supertrait_vtable_slot<'tcx>( prepare_vtable_segments(tcx, source_principal, vtable_segment_callback).unwrap() } +fn trait_refs_are_compatible<'tcx>( + tcx: TyCtxt<'tcx>, + hr_vtable_principal: ty::PolyExistentialTraitRef<'tcx>, + hr_target_principal: ty::PolyExistentialTraitRef<'tcx>, +) -> bool { + if hr_vtable_principal.def_id() != hr_target_principal.def_id() { + return false; + } + + let infcx = tcx.infer_ctxt().build(); + let param_env = ty::ParamEnv::reveal_all(); + let ocx = ObligationCtxt::new(&infcx); + let hr_source_principal = + ocx.normalize(&ObligationCause::dummy(), param_env, hr_vtable_principal); + let hr_target_principal = + ocx.normalize(&ObligationCause::dummy(), param_env, hr_target_principal); + infcx.enter_forall(hr_target_principal, |target_principal| { + let source_principal = infcx.instantiate_binder_with_fresh_vars( + DUMMY_SP, + BoundRegionConversionTime::HigherRankedType, + hr_source_principal, + ); + let Ok(()) = ocx.eq_trace( + &ObligationCause::dummy(), + param_env, + ToTrace::to_trace(&ObligationCause::dummy(), hr_target_principal, hr_source_principal), + target_principal, + source_principal, + ) else { + return false; + }; + ocx.select_all_or_error().is_empty() + }) +} + pub(super) fn provide(providers: &mut Providers) { *providers = Providers { own_existential_vtable_entries, diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 354f3034b8ac..7e140ecfee08 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -838,7 +838,7 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { self.cause(ObligationCauseCode::WellFormed(None)), self.recursion_depth, self.param_env, - ty::Binder::dummy(ty::PredicateKind::ObjectSafe(principal)), + ty::Binder::dummy(ty::PredicateKind::DynCompatible(principal)), )); } } diff --git a/compiler/rustc_traits/src/normalize_erasing_regions.rs b/compiler/rustc_traits/src/normalize_erasing_regions.rs index c5ebc2d26a79..f01a12b0a00c 100644 --- a/compiler/rustc_traits/src/normalize_erasing_regions.rs +++ b/compiler/rustc_traits/src/normalize_erasing_regions.rs @@ -59,7 +59,7 @@ fn not_outlives_predicate(p: ty::Predicate<'_>) -> bool { | ty::PredicateKind::NormalizesTo(..) | ty::PredicateKind::AliasRelate(..) | ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(..)) - | ty::PredicateKind::ObjectSafe(..) + | ty::PredicateKind::DynCompatible(..) | ty::PredicateKind::Subtype(..) | ty::PredicateKind::Coerce(..) | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(..)) diff --git a/compiler/rustc_type_ir/src/data_structures/delayed_map.rs b/compiler/rustc_type_ir/src/data_structures/delayed_map.rs new file mode 100644 index 000000000000..7e7406e37066 --- /dev/null +++ b/compiler/rustc_type_ir/src/data_structures/delayed_map.rs @@ -0,0 +1,92 @@ +use std::hash::Hash; + +use crate::data_structures::{HashMap, HashSet}; + +const CACHE_CUTOFF: u32 = 32; + +/// A hashmap which only starts hashing after ignoring the first few inputs. +/// +/// This is used in type folders as in nearly all cases caching is not worth it +/// as nearly all folded types are tiny. However, there are very rare incredibly +/// large types for which caching is necessary to avoid hangs. +#[derive(Debug)] +pub struct DelayedMap { + cache: HashMap, + count: u32, +} + +impl Default for DelayedMap { + fn default() -> Self { + DelayedMap { cache: Default::default(), count: 0 } + } +} + +impl DelayedMap { + #[inline(always)] + pub fn insert(&mut self, key: K, value: V) -> bool { + if self.count >= CACHE_CUTOFF { + self.cold_insert(key, value) + } else { + self.count += 1; + true + } + } + + #[cold] + #[inline(never)] + fn cold_insert(&mut self, key: K, value: V) -> bool { + self.cache.insert(key, value).is_none() + } + + #[inline(always)] + pub fn get(&self, key: &K) -> Option<&V> { + if self.cache.is_empty() { None } else { self.cold_get(key) } + } + + #[cold] + #[inline(never)] + fn cold_get(&self, key: &K) -> Option<&V> { + self.cache.get(key) + } +} + +#[derive(Debug)] +pub struct DelayedSet { + cache: HashSet, + count: u32, +} + +impl Default for DelayedSet { + fn default() -> Self { + DelayedSet { cache: Default::default(), count: 0 } + } +} + +impl DelayedSet { + #[inline(always)] + pub fn insert(&mut self, value: T) -> bool { + if self.count >= CACHE_CUTOFF { + self.cold_insert(value) + } else { + self.count += 1; + true + } + } + + #[cold] + #[inline(never)] + fn cold_insert(&mut self, value: T) -> bool { + self.cache.insert(value) + } + + #[inline(always)] + pub fn contains(&self, value: &T) -> bool { + !self.cache.is_empty() && self.cold_contains(value) + } + + #[cold] + #[inline(never)] + fn cold_contains(&self, value: &T) -> bool { + self.cache.contains(value) + } +} diff --git a/compiler/rustc_type_ir/src/data_structures.rs b/compiler/rustc_type_ir/src/data_structures/mod.rs similarity index 92% rename from compiler/rustc_type_ir/src/data_structures.rs rename to compiler/rustc_type_ir/src/data_structures/mod.rs index 96036e53b0ab..d9766d91845c 100644 --- a/compiler/rustc_type_ir/src/data_structures.rs +++ b/compiler/rustc_type_ir/src/data_structures/mod.rs @@ -6,6 +6,8 @@ pub use rustc_hash::{FxHashMap as HashMap, FxHashSet as HashSet}; pub type IndexMap = indexmap::IndexMap>; pub type IndexSet = indexmap::IndexSet>; +mod delayed_map; + #[cfg(feature = "nightly")] mod impl_ { pub use rustc_data_structures::sso::{SsoHashMap, SsoHashSet}; @@ -24,4 +26,5 @@ mod impl_ { } } +pub use delayed_map::{DelayedMap, DelayedSet}; pub use impl_::*; diff --git a/compiler/rustc_type_ir/src/elaborate.rs b/compiler/rustc_type_ir/src/elaborate.rs index 3db9b8b06610..61736633cfa2 100644 --- a/compiler/rustc_type_ir/src/elaborate.rs +++ b/compiler/rustc_type_ir/src/elaborate.rs @@ -4,6 +4,7 @@ use smallvec::smallvec; use crate::data_structures::HashSet; use crate::inherent::*; +use crate::lang_items::TraitSolverLangItem; use crate::outlives::{Component, push_outlives_components}; use crate::{self as ty, Interner, Upcast as _}; @@ -89,6 +90,70 @@ impl> Elaborator { return; } + // HACK(effects): The following code is required to get implied bounds for effects associated + // types to work with super traits. + // + // Suppose `data` is a trait predicate with the form `::Fx: EffectsCompat` + // and we know that `trait Tr: ~const SuperTr`, we need to elaborate this predicate into + // `::Fx: EffectsCompat`. + // + // Since the semantics for elaborating bounds about effects is equivalent to elaborating + // bounds about super traits (elaborate `T: Tr` into `T: SuperTr`), we place effects elaboration + // next to super trait elaboration. + if cx.is_lang_item(data.def_id(), TraitSolverLangItem::EffectsCompat) + && matches!(self.mode, Filter::All) + { + // first, ensure that the predicate we've got looks like a `::Fx: EffectsCompat`. + if let ty::Alias(ty::AliasTyKind::Projection, alias_ty) = data.self_ty().kind() + { + // look for effects-level bounds that look like `::Fx: TyCompat<::Fx>` + // on the trait, which is proof to us that `Tr: ~const SuperTr`. We're looking for bounds on the + // associated trait, so we use `explicit_implied_predicates_of` since it gives us more than just + // `Self: SuperTr` bounds. + let bounds = cx.explicit_implied_predicates_of(cx.parent(alias_ty.def_id)); + + // instantiate the implied bounds, so we get `::Fx` and not `::Fx`. + let elaborated = bounds.iter_instantiated(cx, alias_ty.args).filter_map( + |(clause, _)| { + let ty::ClauseKind::Trait(tycompat_bound) = + clause.kind().skip_binder() + else { + return None; + }; + if !cx.is_lang_item( + tycompat_bound.def_id(), + TraitSolverLangItem::EffectsTyCompat, + ) { + return None; + } + + // extract `::Fx` from the `TyCompat` bound. + let supertrait_effects_ty = + tycompat_bound.trait_ref.args.type_at(1); + let ty::Alias(ty::AliasTyKind::Projection, supertrait_alias_ty) = + supertrait_effects_ty.kind() + else { + return None; + }; + + // The self types (`T`) must be equal for `::Fx` and `::Fx`. + if supertrait_alias_ty.self_ty() != alias_ty.self_ty() { + return None; + }; + + // replace the self type in the original bound `::Fx: EffectsCompat` + // to the effects type of the super trait. (`::Fx`) + let elaborated_bound = data.with_self_ty(cx, supertrait_effects_ty); + Some( + elaboratable + .child(bound_clause.rebind(elaborated_bound).upcast(cx)), + ) + }, + ); + self.extend_deduped(elaborated); + } + } + let map_to_child_clause = |(index, (clause, span)): (usize, (I::Clause, I::Span))| { elaboratable.child_with_derived_cause( diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 8dec2133a45d..b2ac67efef61 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -255,7 +255,7 @@ pub trait Interner: fn trait_is_alias(self, trait_def_id: Self::DefId) -> bool; - fn trait_is_object_safe(self, trait_def_id: Self::DefId) -> bool; + fn trait_is_dyn_compatible(self, trait_def_id: Self::DefId) -> bool; fn trait_is_fundamental(self, def_id: Self::DefId) -> bool; diff --git a/compiler/rustc_type_ir/src/lang_items.rs b/compiler/rustc_type_ir/src/lang_items.rs index 265a41188273..c680c8447460 100644 --- a/compiler/rustc_type_ir/src/lang_items.rs +++ b/compiler/rustc_type_ir/src/lang_items.rs @@ -20,11 +20,13 @@ pub enum TraitSolverLangItem { Destruct, DiscriminantKind, DynMetadata, + EffectsCompat, EffectsIntersection, EffectsIntersectionOutput, EffectsMaybe, EffectsNoRuntime, EffectsRuntime, + EffectsTyCompat, Fn, FnMut, FnOnce, diff --git a/compiler/rustc_type_ir/src/predicate.rs b/compiler/rustc_type_ir/src/predicate.rs index 7e300fe02dca..8146181df6c1 100644 --- a/compiler/rustc_type_ir/src/predicate.rs +++ b/compiler/rustc_type_ir/src/predicate.rs @@ -668,8 +668,8 @@ impl fmt::Debug for ProjectionPredicate { } } -/// Used by the new solver. Unlike a `ProjectionPredicate` this can only be -/// proven by actually normalizing `alias`. +/// Used by the new solver to normalize an alias. This always expects the `term` to +/// be an unconstrained inference variable which is used as the output. #[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] #[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] @@ -755,3 +755,10 @@ impl fmt::Display for BoundConstness { } } } + +impl Lift for BoundConstness { + type Lifted = BoundConstness; + fn lift_to_interner(self, _: I) -> Option { + Some(self) + } +} diff --git a/compiler/rustc_type_ir/src/predicate_kind.rs b/compiler/rustc_type_ir/src/predicate_kind.rs index c8a210285883..46202dbb0f27 100644 --- a/compiler/rustc_type_ir/src/predicate_kind.rs +++ b/compiler/rustc_type_ir/src/predicate_kind.rs @@ -46,8 +46,8 @@ pub enum PredicateKind { /// Prove a clause Clause(ClauseKind), - /// Trait must be object-safe. - ObjectSafe(I::DefId), + /// Trait must be dyn-compatible. + DynCompatible(I::DefId), /// `T1 <: T2` /// @@ -74,13 +74,13 @@ pub enum PredicateKind { Ambiguous, /// This should only be used inside of the new solver for `AliasRelate` and expects - /// the `term` to be an unconstrained inference variable. + /// the `term` to be always be an unconstrained inference variable. It is used to + /// normalize `alias` as much as possible. In case the alias is rigid - i.e. it cannot + /// be normalized in the current environment - this constrains `term` to be equal to + /// the alias itself. /// - /// The alias normalizes to `term`. Unlike `Projection`, this always fails if the - /// alias cannot be normalized in the current context. For the rigid alias - /// `T as Trait>::Assoc`, `Projection(::Assoc, ?x)` constrains `?x` - /// to `::Assoc` while `NormalizesTo(::Assoc, ?x)` - /// results in `NoSolution`. + /// It is likely more useful to think of this as a function `normalizes_to(alias)`, + /// whose return value is written into `term`. NormalizesTo(ty::NormalizesTo), /// Separate from `ClauseKind::Projection` which is used for normalization in new solver. @@ -128,8 +128,8 @@ impl fmt::Debug for PredicateKind { PredicateKind::Clause(a) => a.fmt(f), PredicateKind::Subtype(pair) => pair.fmt(f), PredicateKind::Coerce(pair) => pair.fmt(f), - PredicateKind::ObjectSafe(trait_def_id) => { - write!(f, "ObjectSafe({trait_def_id:?})") + PredicateKind::DynCompatible(trait_def_id) => { + write!(f, "DynCompatible({trait_def_id:?})") } PredicateKind::ConstEquate(c1, c2) => write!(f, "ConstEquate({c1:?}, {c2:?})"), PredicateKind::Ambiguous => write!(f, "Ambiguous"), diff --git a/compiler/stable_mir/src/compiler_interface.rs b/compiler/stable_mir/src/compiler_interface.rs index 9060a869f7fb..4b7707ebccfe 100644 --- a/compiler/stable_mir/src/compiler_interface.rs +++ b/compiler/stable_mir/src/compiler_interface.rs @@ -255,7 +255,7 @@ where if TLV.is_set() { Err(Error::from("StableMIR already running")) } else { - let ptr: *const () = std::ptr::addr_of!(context) as _; + let ptr: *const () = (&raw const context) as _; TLV.set(&Cell::new(ptr), || Ok(f())) } } diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs index b3dc4d9bb820..9e6fbc8ea0c1 100644 --- a/compiler/stable_mir/src/ty.rs +++ b/compiler/stable_mir/src/ty.rs @@ -1420,7 +1420,7 @@ pub struct GenericPredicates { #[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub enum PredicateKind { Clause(ClauseKind), - ObjectSafe(TraitDef), + DynCompatible(TraitDef), SubType(SubtypePredicate), Coerce(CoercePredicate), ConstEquate(TyConst, TyConst), diff --git a/library/Cargo.lock b/library/Cargo.lock index 2343b2baf834..209e30b30402 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -42,9 +42,12 @@ checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" [[package]] name = "cc" -version = "1.0.99" +version = "1.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96c51067fd44124faa7f870b4b1c969379ad32b2ba805aa959430ceaa384f695" +checksum = "9540e661f81799159abee814118cc139a2004b3a3aa3ea37724a1b66530b90e0" +dependencies = [ + "shlex", +] [[package]] name = "cfg-if" @@ -58,9 +61,9 @@ dependencies = [ [[package]] name = "compiler_builtins" -version = "0.1.125" +version = "0.1.130" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd02a01d7bc069bed818e956600fe437ee222dd1d6ad92bfb9db87b43b71fd87" +checksum = "e64c30475571756801eff60a811520c3d18e0ceb9c56c97bad2047ae601f6709" dependencies = [ "cc", "rustc-std-workspace-core", @@ -108,17 +111,6 @@ dependencies = [ "unicode-width", ] -[[package]] -name = "gimli" -version = "0.28.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" -dependencies = [ - "compiler_builtins", - "rustc-std-workspace-alloc", - "rustc-std-workspace-core", -] - [[package]] name = "gimli" version = "0.29.0" @@ -131,10 +123,21 @@ dependencies = [ ] [[package]] -name = "hashbrown" -version = "0.14.5" +name = "gimli" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +checksum = "e2e1d97fbe9722ba9bbd0c97051c2956e726562b61f86a25a4360398a40edfc9" +dependencies = [ + "compiler_builtins", + "rustc-std-workspace-alloc", + "rustc-std-workspace-core", +] + +[[package]] +name = "hashbrown" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" dependencies = [ "allocator-api2", "compiler_builtins", @@ -155,9 +158,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.158" +version = "0.2.159" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" +checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" dependencies = [ "rustc-std-workspace-core", ] @@ -186,9 +189,9 @@ dependencies = [ [[package]] name = "object" -version = "0.36.2" +version = "0.36.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f203fa8daa7bb185f760ae12bd8e097f63d17041dcdcaf675ac54cdf863170e" +checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a" dependencies = [ "compiler_builtins", "memchr", @@ -312,6 +315,12 @@ dependencies = [ "std", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "std" version = "0.0.0" @@ -375,9 +384,9 @@ dependencies = [ [[package]] name = "unicode-width" -version = "0.1.13" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" dependencies = [ "compiler_builtins", "rustc-std-workspace-core", @@ -397,12 +406,12 @@ dependencies = [ [[package]] name = "unwinding" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37a19a21a537f635c16c7576f22d0f2f7d63353c1337ad4ce0d8001c7952a25b" +checksum = "dc55842d0db6329a669d55a623c674b02d677b16bfb2d24857d4089d41eba882" dependencies = [ "compiler_builtins", - "gimli 0.28.1", + "gimli 0.30.0", "rustc-std-workspace-core", ] @@ -423,7 +432,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.5", + "windows-targets 0.52.6", ] [[package]] @@ -432,9 +441,9 @@ version = "0.0.0" [[package]] name = "windows-targets" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", @@ -448,48 +457,48 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" diff --git a/library/alloc/Cargo.toml b/library/alloc/Cargo.toml index 1da947d196fd..11db50a0fdf3 100644 --- a/library/alloc/Cargo.toml +++ b/library/alloc/Cargo.toml @@ -10,7 +10,7 @@ edition = "2021" [dependencies] core = { path = "../core" } -compiler_builtins = { version = "0.1.125", features = ['rustc-dep-of-std'] } +compiler_builtins = { version = "0.1.130", features = ['rustc-dep-of-std'] } [dev-dependencies] rand = { version = "0.8.5", default-features = false, features = ["alloc"] } diff --git a/library/alloc/benches/str.rs b/library/alloc/benches/str.rs index f020638e9927..98c7c5413cae 100644 --- a/library/alloc/benches/str.rs +++ b/library/alloc/benches/str.rs @@ -347,3 +347,5 @@ make_test!(rsplitn_space_char, s, s.rsplitn(10, ' ').count()); make_test!(split_space_str, s, s.split(" ").count()); make_test!(split_ad_str, s, s.split("ad").count()); + +make_test!(to_lowercase, s, s.to_lowercase()); diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index f61a484499f9..5f2072956835 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -199,7 +199,7 @@ use core::ops::{ DerefPure, DispatchFromDyn, Receiver, }; use core::pin::{Pin, PinCoerceUnsized}; -use core::ptr::{self, NonNull, Unique, addr_of_mut}; +use core::ptr::{self, NonNull, Unique}; use core::task::{Context, Poll}; use core::{borrow, fmt, slice}; @@ -228,6 +228,7 @@ mod thin; #[lang = "owned_box"] #[fundamental] #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_insignificant_dtor] // The declaration of the `Box` struct must be kept in sync with the // compiler or ICEs will happen. pub struct Box< @@ -1277,7 +1278,7 @@ impl Box { #[inline] pub fn into_raw(b: Self) -> *mut T { // Make sure Miri realizes that we transition from a noalias pointer to a raw pointer here. - unsafe { addr_of_mut!(*&mut *Self::into_raw_with_allocator(b).0) } + unsafe { &raw mut *&mut *Self::into_raw_with_allocator(b).0 } } /// Consumes the `Box`, returning a wrapped `NonNull` pointer. @@ -1396,7 +1397,7 @@ impl Box { // want *no* aliasing requirements here! // In case `A` *is* `Global`, this does not quite have the right behavior; `into_raw` // works around that. - let ptr = addr_of_mut!(**b); + let ptr = &raw mut **b; let alloc = unsafe { ptr::read(&b.1) }; (ptr, alloc) } @@ -1506,7 +1507,7 @@ impl Box { pub fn as_mut_ptr(b: &mut Self) -> *mut T { // This is a primitive deref, not going through `DerefMut`, and therefore not materializing // any references. - ptr::addr_of_mut!(**b) + &raw mut **b } /// Returns a raw pointer to the `Box`'s contents. @@ -1554,7 +1555,7 @@ impl Box { pub fn as_ptr(b: &Self) -> *const T { // This is a primitive deref, not going through `DerefMut`, and therefore not materializing // any references. - ptr::addr_of!(**b) + &raw const **b } /// Returns a reference to the underlying allocator. diff --git a/library/alloc/src/boxed/thin.rs b/library/alloc/src/boxed/thin.rs index 9baded3a5214..78e5aec09b18 100644 --- a/library/alloc/src/boxed/thin.rs +++ b/library/alloc/src/boxed/thin.rs @@ -186,7 +186,7 @@ impl ThinBox { fn with_header(&self) -> &WithHeader<::Metadata> { // SAFETY: both types are transparent to `NonNull` - unsafe { &*(core::ptr::addr_of!(self.ptr) as *const WithHeader<_>) } + unsafe { &*((&raw const self.ptr) as *const WithHeader<_>) } } } diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs index 78ccb3af66db..5c513d34fc9d 100644 --- a/library/alloc/src/collections/btree/node.rs +++ b/library/alloc/src/collections/btree/node.rs @@ -72,8 +72,8 @@ impl LeafNode { // be both slightly faster and easier to track in Valgrind. unsafe { // parent_idx, keys, and vals are all MaybeUninit - ptr::addr_of_mut!((*this).parent).write(None); - ptr::addr_of_mut!((*this).len).write(0); + (&raw mut (*this).parent).write(None); + (&raw mut (*this).len).write(0); } } @@ -114,7 +114,7 @@ impl InternalNode { unsafe { let mut node = Box::::new_uninit_in(alloc); // We only need to initialize the data; the edges are MaybeUninit. - LeafNode::init(ptr::addr_of_mut!((*node.as_mut_ptr()).data)); + LeafNode::init(&raw mut (*node.as_mut_ptr()).data); node.assume_init() } } @@ -525,8 +525,8 @@ impl<'a, K, V, Type> NodeRef, K, V, Type> { // to avoid aliasing with outstanding references to other elements, // in particular, those returned to the caller in earlier iterations. let leaf = Self::as_leaf_ptr(&mut self); - let keys = unsafe { ptr::addr_of!((*leaf).keys) }; - let vals = unsafe { ptr::addr_of_mut!((*leaf).vals) }; + let keys = unsafe { &raw const (*leaf).keys }; + let vals = unsafe { &raw mut (*leaf).vals }; // We must coerce to unsized array pointers because of Rust issue #74679. let keys: *const [_] = keys; let vals: *mut [_] = vals; diff --git a/library/alloc/src/ffi/c_str.rs b/library/alloc/src/ffi/c_str.rs index 797d591a8b51..d496899e72bc 100644 --- a/library/alloc/src/ffi/c_str.rs +++ b/library/alloc/src/ffi/c_str.rs @@ -696,6 +696,7 @@ impl CString { // memory-unsafe code from working by accident. Inline // to prevent LLVM from optimizing it away in debug builds. #[stable(feature = "cstring_drop", since = "1.13.0")] +#[rustc_insignificant_dtor] impl Drop for CString { #[inline] fn drop(&mut self) { diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 54669bd310a6..0e2c35845e8f 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -787,7 +787,7 @@ impl Rc { let strong = unsafe { let inner = init_ptr.as_ptr(); - ptr::write(ptr::addr_of_mut!((*inner).value), data); + ptr::write(&raw mut (*inner).value, data); let prev_value = (*inner).strong.get(); debug_assert_eq!(prev_value, 0, "No prior strong references should exist"); @@ -1442,7 +1442,7 @@ impl Rc { // SAFETY: This cannot go through Deref::deref or Rc::inner because // this is required to retain raw/mut provenance such that e.g. `get_mut` can // write through the pointer after the Rc is recovered through `from_raw`. - unsafe { ptr::addr_of_mut!((*ptr).value) } + unsafe { &raw mut (*ptr).value } } /// Constructs an `Rc` from a raw pointer in the provided allocator. @@ -2042,8 +2042,8 @@ impl Rc { unsafe { debug_assert_eq!(Layout::for_value_raw(inner), layout); - ptr::addr_of_mut!((*inner).strong).write(Cell::new(1)); - ptr::addr_of_mut!((*inner).weak).write(Cell::new(1)); + (&raw mut (*inner).strong).write(Cell::new(1)); + (&raw mut (*inner).weak).write(Cell::new(1)); } Ok(inner) @@ -2072,8 +2072,8 @@ impl Rc { // Copy value as bytes ptr::copy_nonoverlapping( - core::ptr::addr_of!(*src) as *const u8, - ptr::addr_of_mut!((*ptr).value) as *mut u8, + (&raw const *src) as *const u8, + (&raw mut (*ptr).value) as *mut u8, value_size, ); @@ -2107,11 +2107,7 @@ impl Rc<[T]> { unsafe fn copy_from_slice(v: &[T]) -> Rc<[T]> { unsafe { let ptr = Self::allocate_for_slice(v.len()); - ptr::copy_nonoverlapping( - v.as_ptr(), - ptr::addr_of_mut!((*ptr).value) as *mut T, - v.len(), - ); + ptr::copy_nonoverlapping(v.as_ptr(), (&raw mut (*ptr).value) as *mut T, v.len()); Self::from_ptr(ptr) } } @@ -2149,7 +2145,7 @@ impl Rc<[T]> { let layout = Layout::for_value_raw(ptr); // Pointer to first element - let elems = ptr::addr_of_mut!((*ptr).value) as *mut T; + let elems = (&raw mut (*ptr).value) as *mut T; let mut guard = Guard { mem: NonNull::new_unchecked(mem), elems, layout, n_elems: 0 }; @@ -2577,7 +2573,7 @@ impl fmt::Debug for Rc { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Pointer for Rc { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Pointer::fmt(&core::ptr::addr_of!(**self), f) + fmt::Pointer::fmt(&(&raw const **self), f) } } @@ -2718,7 +2714,7 @@ impl From> for Rc<[T], A> { let (vec_ptr, len, cap, alloc) = v.into_raw_parts_with_alloc(); let rc_ptr = Self::allocate_for_slice_in(len, &alloc); - ptr::copy_nonoverlapping(vec_ptr, ptr::addr_of_mut!((*rc_ptr).value) as *mut T, len); + ptr::copy_nonoverlapping(vec_ptr, (&raw mut (*rc_ptr).value) as *mut T, len); // Create a `Vec` with length 0, to deallocate the buffer // without dropping its contents or the allocator @@ -3084,7 +3080,7 @@ impl Weak { // SAFETY: if is_dangling returns false, then the pointer is dereferenceable. // The payload may be dropped at this point, and we have to maintain provenance, // so use raw pointer manipulation. - unsafe { ptr::addr_of_mut!((*ptr).value) } + unsafe { &raw mut (*ptr).value } } } diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index f636f10d5c08..a92d22b1c309 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -180,10 +180,9 @@ impl [T] { /// This sort is stable (i.e., does not reorder equal elements) and *O*(*n* \* log(*n*)) /// worst-case. /// - /// If the implementation of [`Ord`] for `T` does not implement a [total order] the resulting - /// order of elements in the slice is unspecified. All original elements will remain in the - /// slice and any possible modifications via interior mutability are observed in the input. Same - /// is true if the implementation of [`Ord`] for `T` panics. + /// If the implementation of [`Ord`] for `T` does not implement a [total order], the function + /// may panic; even if the function exits normally, the resulting order of elements in the slice + /// is unspecified. See also the note on panicking below. /// /// When applicable, unstable sorting is preferred because it is generally faster than stable /// sorting and it doesn't allocate auxiliary memory. See @@ -212,7 +211,15 @@ impl [T] { /// /// # Panics /// - /// May panic if the implementation of [`Ord`] for `T` does not implement a [total order]. + /// May panic if the implementation of [`Ord`] for `T` does not implement a [total order], or if + /// the [`Ord`] implementation itself panics. + /// + /// All safe functions on slices preserve the invariant that even if the function panics, all + /// original elements will remain in the slice and any possible modifications via interior + /// mutability are observed in the input. This ensures that recovery code (for instance inside + /// of a `Drop` or following a `catch_unwind`) will still have access to all the original + /// elements. For instance, if the slice belongs to a `Vec`, the `Vec::drop` method will be able + /// to dispose of all contained elements. /// /// # Examples /// @@ -241,10 +248,9 @@ impl [T] { /// This sort is stable (i.e., does not reorder equal elements) and *O*(*n* \* log(*n*)) /// worst-case. /// - /// If the comparison function `compare` does not implement a [total order] the resulting order - /// of elements in the slice is unspecified. All original elements will remain in the slice and - /// any possible modifications via interior mutability are observed in the input. Same is true - /// if `compare` panics. + /// If the comparison function `compare` does not implement a [total order], the function may + /// panic; even if the function exits normally, the resulting order of elements in the slice is + /// unspecified. See also the note on panicking below. /// /// For example `|a, b| (a - b).cmp(a)` is a comparison function that is neither transitive nor /// reflexive nor total, `a < b < c < a` with `a = 1, b = 2, c = 3`. For more information and @@ -263,7 +269,14 @@ impl [T] { /// /// # Panics /// - /// May panic if `compare` does not implement a [total order]. + /// May panic if `compare` does not implement a [total order], or if `compare` itself panics. + /// + /// All safe functions on slices preserve the invariant that even if the function panics, all + /// original elements will remain in the slice and any possible modifications via interior + /// mutability are observed in the input. This ensures that recovery code (for instance inside + /// of a `Drop` or following a `catch_unwind`) will still have access to all the original + /// elements. For instance, if the slice belongs to a `Vec`, the `Vec::drop` method will be able + /// to dispose of all contained elements. /// /// # Examples /// @@ -295,10 +308,9 @@ impl [T] { /// This sort is stable (i.e., does not reorder equal elements) and *O*(*m* \* *n* \* log(*n*)) /// worst-case, where the key function is *O*(*m*). /// - /// If the implementation of [`Ord`] for `K` does not implement a [total order] the resulting - /// order of elements in the slice is unspecified. All original elements will remain in the - /// slice and any possible modifications via interior mutability are observed in the input. Same - /// is true if the implementation of [`Ord`] for `K` panics. + /// If the implementation of [`Ord`] for `K` does not implement a [total order], the function + /// may panic; even if the function exits normally, the resulting order of elements in the slice + /// is unspecified. See also the note on panicking below. /// /// # Current implementation /// @@ -313,7 +325,15 @@ impl [T] { /// /// # Panics /// - /// May panic if the implementation of [`Ord`] for `K` does not implement a [total order]. + /// May panic if the implementation of [`Ord`] for `K` does not implement a [total order], or if + /// the [`Ord`] implementation or the key-function `f` panics. + /// + /// All safe functions on slices preserve the invariant that even if the function panics, all + /// original elements will remain in the slice and any possible modifications via interior + /// mutability are observed in the input. This ensures that recovery code (for instance inside + /// of a `Drop` or following a `catch_unwind`) will still have access to all the original + /// elements. For instance, if the slice belongs to a `Vec`, the `Vec::drop` method will be able + /// to dispose of all contained elements. /// /// # Examples /// @@ -347,10 +367,9 @@ impl [T] { /// storage to remember the results of key evaluation. The order of calls to the key function is /// unspecified and may change in future versions of the standard library. /// - /// If the implementation of [`Ord`] for `K` does not implement a [total order] the resulting - /// order of elements in the slice is unspecified. All original elements will remain in the - /// slice and any possible modifications via interior mutability are observed in the input. Same - /// is true if the implementation of [`Ord`] for `K` panics. + /// If the implementation of [`Ord`] for `K` does not implement a [total order], the function + /// may panic; even if the function exits normally, the resulting order of elements in the slice + /// is unspecified. See also the note on panicking below. /// /// For simple key functions (e.g., functions that are property accesses or basic operations), /// [`sort_by_key`](slice::sort_by_key) is likely to be faster. @@ -369,7 +388,15 @@ impl [T] { /// /// # Panics /// - /// May panic if the implementation of [`Ord`] for `K` does not implement a [total order]. + /// May panic if the implementation of [`Ord`] for `K` does not implement a [total order], or if + /// the [`Ord`] implementation panics. + /// + /// All safe functions on slices preserve the invariant that even if the function panics, all + /// original elements will remain in the slice and any possible modifications via interior + /// mutability are observed in the input. This ensures that recovery code (for instance inside + /// of a `Drop` or following a `catch_unwind`) will still have access to all the original + /// elements. For instance, if the slice belongs to a `Vec`, the `Vec::drop` method will be able + /// to dispose of all contained elements. /// /// # Examples /// diff --git a/library/alloc/src/str.rs b/library/alloc/src/str.rs index 32212b61c6e8..42501f9c3159 100644 --- a/library/alloc/src/str.rs +++ b/library/alloc/src/str.rs @@ -9,6 +9,7 @@ use core::borrow::{Borrow, BorrowMut}; use core::iter::FusedIterator; +use core::mem::MaybeUninit; #[stable(feature = "encode_utf16", since = "1.8.0")] pub use core::str::EncodeUtf16; #[stable(feature = "split_ascii_whitespace", since = "1.34.0")] @@ -365,14 +366,9 @@ impl str { without modifying the original"] #[stable(feature = "unicode_case_mapping", since = "1.2.0")] pub fn to_lowercase(&self) -> String { - let out = convert_while_ascii(self.as_bytes(), u8::to_ascii_lowercase); + let (mut s, rest) = convert_while_ascii(self, u8::to_ascii_lowercase); - // Safety: we know this is a valid char boundary since - // out.len() is only progressed if ascii bytes are found - let rest = unsafe { self.get_unchecked(out.len()..) }; - - // Safety: We have written only valid ASCII to our vec - let mut s = unsafe { String::from_utf8_unchecked(out) }; + let prefix_len = s.len(); for (i, c) in rest.char_indices() { if c == 'Σ' { @@ -381,8 +377,7 @@ impl str { // in `SpecialCasing.txt`, // so hard-code it rather than have a generic "condition" mechanism. // See https://github.com/rust-lang/rust/issues/26035 - let out_len = self.len() - rest.len(); - let sigma_lowercase = map_uppercase_sigma(&self, i + out_len); + let sigma_lowercase = map_uppercase_sigma(self, prefix_len + i); s.push(sigma_lowercase); } else { match conversions::to_lower(c) { @@ -458,14 +453,7 @@ impl str { without modifying the original"] #[stable(feature = "unicode_case_mapping", since = "1.2.0")] pub fn to_uppercase(&self) -> String { - let out = convert_while_ascii(self.as_bytes(), u8::to_ascii_uppercase); - - // Safety: we know this is a valid char boundary since - // out.len() is only progressed if ascii bytes are found - let rest = unsafe { self.get_unchecked(out.len()..) }; - - // Safety: We have written only valid ASCII to our vec - let mut s = unsafe { String::from_utf8_unchecked(out) }; + let (mut s, rest) = convert_while_ascii(self, u8::to_ascii_uppercase); for c in rest.chars() { match conversions::to_upper(c) { @@ -614,50 +602,87 @@ pub unsafe fn from_boxed_utf8_unchecked(v: Box<[u8]>) -> Box { unsafe { Box::from_raw(Box::into_raw(v) as *mut str) } } -/// Converts the bytes while the bytes are still ascii. +/// Converts leading ascii bytes in `s` by calling the `convert` function. +/// /// For better average performance, this happens in chunks of `2*size_of::()`. -/// Returns a vec with the converted bytes. +/// +/// Returns a tuple of the converted prefix and the remainder starting from +/// the first non-ascii character. +/// +/// This function is only public so that it can be verified in a codegen test, +/// see `issue-123712-str-to-lower-autovectorization.rs`. +#[unstable(feature = "str_internals", issue = "none")] +#[doc(hidden)] #[inline] #[cfg(not(test))] #[cfg(not(no_global_oom_handling))] -fn convert_while_ascii(b: &[u8], convert: fn(&u8) -> u8) -> Vec { - let mut out = Vec::with_capacity(b.len()); +pub fn convert_while_ascii(s: &str, convert: fn(&u8) -> u8) -> (String, &str) { + // Process the input in chunks of 16 bytes to enable auto-vectorization. + // Previously the chunk size depended on the size of `usize`, + // but on 32-bit platforms with sse or neon is also the better choice. + // The only downside on other platforms would be a bit more loop-unrolling. + const N: usize = 16; - const USIZE_SIZE: usize = mem::size_of::(); - const MAGIC_UNROLL: usize = 2; - const N: usize = USIZE_SIZE * MAGIC_UNROLL; - const NONASCII_MASK: usize = usize::from_ne_bytes([0x80; USIZE_SIZE]); + let mut slice = s.as_bytes(); + let mut out = Vec::with_capacity(slice.len()); + let mut out_slice = out.spare_capacity_mut(); - let mut i = 0; - unsafe { - while i + N <= b.len() { - // Safety: we have checks the sizes `b` and `out` to know that our - let in_chunk = b.get_unchecked(i..i + N); - let out_chunk = out.spare_capacity_mut().get_unchecked_mut(i..i + N); + let mut ascii_prefix_len = 0_usize; + let mut is_ascii = [false; N]; - let mut bits = 0; - for j in 0..MAGIC_UNROLL { - // read the bytes 1 usize at a time (unaligned since we haven't checked the alignment) - // safety: in_chunk is valid bytes in the range - bits |= in_chunk.as_ptr().cast::().add(j).read_unaligned(); - } - // if our chunks aren't ascii, then return only the prior bytes as init - if bits & NONASCII_MASK != 0 { - break; - } + while slice.len() >= N { + // SAFETY: checked in loop condition + let chunk = unsafe { slice.get_unchecked(..N) }; + // SAFETY: out_slice has at least same length as input slice and gets sliced with the same offsets + let out_chunk = unsafe { out_slice.get_unchecked_mut(..N) }; - // perform the case conversions on N bytes (gets heavily autovec'd) - for j in 0..N { - // safety: in_chunk and out_chunk is valid bytes in the range - let out = out_chunk.get_unchecked_mut(j); - out.write(convert(in_chunk.get_unchecked(j))); - } - - // mark these bytes as initialised - i += N; + for j in 0..N { + is_ascii[j] = chunk[j] <= 127; } - out.set_len(i); + + // Auto-vectorization for this check is a bit fragile, sum and comparing against the chunk + // size gives the best result, specifically a pmovmsk instruction on x86. + // See https://github.com/llvm/llvm-project/issues/96395 for why llvm currently does not + // currently recognize other similar idioms. + if is_ascii.iter().map(|x| *x as u8).sum::() as usize != N { + break; + } + + for j in 0..N { + out_chunk[j] = MaybeUninit::new(convert(&chunk[j])); + } + + ascii_prefix_len += N; + slice = unsafe { slice.get_unchecked(N..) }; + out_slice = unsafe { out_slice.get_unchecked_mut(N..) }; } - out + // handle the remainder as individual bytes + while slice.len() > 0 { + let byte = slice[0]; + if byte > 127 { + break; + } + // SAFETY: out_slice has at least same length as input slice + unsafe { + *out_slice.get_unchecked_mut(0) = MaybeUninit::new(convert(&byte)); + } + ascii_prefix_len += 1; + slice = unsafe { slice.get_unchecked(1..) }; + out_slice = unsafe { out_slice.get_unchecked_mut(1..) }; + } + + unsafe { + // SAFETY: ascii_prefix_len bytes have been initialized above + out.set_len(ascii_prefix_len); + + // SAFETY: We have written only valid ascii to the output vec + let ascii_string = String::from_utf8_unchecked(out); + + // SAFETY: we know this is a valid char boundary + // since we only skipped over leading ascii bytes + let rest = core::str::from_utf8_unchecked(slice); + + (ascii_string, rest) + } } diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 50886244d582..5d099a49854a 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -237,6 +237,7 @@ macro_rules! acquire { /// [rc_examples]: crate::rc#examples #[cfg_attr(not(test), rustc_diagnostic_item = "Arc")] #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_insignificant_dtor] pub struct Arc< T: ?Sized, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global, @@ -797,7 +798,7 @@ impl Arc { // reference into a strong reference. let strong = unsafe { let inner = init_ptr.as_ptr(); - ptr::write(ptr::addr_of_mut!((*inner).data), data); + ptr::write(&raw mut (*inner).data, data); // The above write to the data field must be visible to any threads which // observe a non-zero strong count. Therefore we need at least "Release" ordering @@ -1583,7 +1584,7 @@ impl Arc { // SAFETY: This cannot go through Deref::deref or RcBoxPtr::inner because // this is required to retain raw/mut provenance such that e.g. `get_mut` can // write through the pointer after the Rc is recovered through `from_raw`. - unsafe { ptr::addr_of_mut!((*ptr).data) } + unsafe { &raw mut (*ptr).data } } /// Constructs an `Arc` from a raw pointer. @@ -1955,8 +1956,8 @@ impl Arc { debug_assert_eq!(unsafe { Layout::for_value_raw(inner) }, layout); unsafe { - ptr::addr_of_mut!((*inner).strong).write(atomic::AtomicUsize::new(1)); - ptr::addr_of_mut!((*inner).weak).write(atomic::AtomicUsize::new(1)); + (&raw mut (*inner).strong).write(atomic::AtomicUsize::new(1)); + (&raw mut (*inner).weak).write(atomic::AtomicUsize::new(1)); } inner @@ -1986,8 +1987,8 @@ impl Arc { // Copy value as bytes ptr::copy_nonoverlapping( - core::ptr::addr_of!(*src) as *const u8, - ptr::addr_of_mut!((*ptr).data) as *mut u8, + (&raw const *src) as *const u8, + (&raw mut (*ptr).data) as *mut u8, value_size, ); @@ -2022,7 +2023,7 @@ impl Arc<[T]> { unsafe { let ptr = Self::allocate_for_slice(v.len()); - ptr::copy_nonoverlapping(v.as_ptr(), ptr::addr_of_mut!((*ptr).data) as *mut T, v.len()); + ptr::copy_nonoverlapping(v.as_ptr(), (&raw mut (*ptr).data) as *mut T, v.len()); Self::from_ptr(ptr) } @@ -2061,7 +2062,7 @@ impl Arc<[T]> { let layout = Layout::for_value_raw(ptr); // Pointer to first element - let elems = ptr::addr_of_mut!((*ptr).data) as *mut T; + let elems = (&raw mut (*ptr).data) as *mut T; let mut guard = Guard { mem: NonNull::new_unchecked(mem), elems, layout, n_elems: 0 }; @@ -2805,7 +2806,7 @@ impl Weak { // SAFETY: if is_dangling returns false, then the pointer is dereferenceable. // The payload may be dropped at this point, and we have to maintain provenance, // so use raw pointer manipulation. - unsafe { ptr::addr_of_mut!((*ptr).data) } + unsafe { &raw mut (*ptr).data } } } @@ -3428,7 +3429,7 @@ impl fmt::Debug for Arc { #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Pointer for Arc { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Pointer::fmt(&core::ptr::addr_of!(**self), f) + fmt::Pointer::fmt(&(&raw const **self), f) } } @@ -3678,7 +3679,7 @@ impl From> for Arc<[T], A> { let (vec_ptr, len, cap, alloc) = v.into_raw_parts_with_alloc(); let rc_ptr = Self::allocate_for_slice_in(len, &alloc); - ptr::copy_nonoverlapping(vec_ptr, ptr::addr_of_mut!((*rc_ptr).data) as *mut T, len); + ptr::copy_nonoverlapping(vec_ptr, (&raw mut (*rc_ptr).data) as *mut T, len); // Create a `Vec` with length 0, to deallocate the buffer // without dropping its contents or the allocator diff --git a/library/alloc/src/vec/into_iter.rs b/library/alloc/src/vec/into_iter.rs index f7aad56695d5..9a6745fdbc0a 100644 --- a/library/alloc/src/vec/into_iter.rs +++ b/library/alloc/src/vec/into_iter.rs @@ -21,11 +21,11 @@ use crate::raw_vec::RawVec; macro non_null { (mut $place:expr, $t:ident) => {{ #![allow(unused_unsafe)] // we're sometimes used within an unsafe block - unsafe { &mut *(ptr::addr_of_mut!($place) as *mut NonNull<$t>) } + unsafe { &mut *((&raw mut $place) as *mut NonNull<$t>) } }}, ($place:expr, $t:ident) => {{ #![allow(unused_unsafe)] // we're sometimes used within an unsafe block - unsafe { *(ptr::addr_of!($place) as *const NonNull<$t>) } + unsafe { *((&raw const $place) as *const NonNull<$t>) } }}, } diff --git a/library/alloc/tests/str.rs b/library/alloc/tests/str.rs index a80e5275dab6..6f930ab08535 100644 --- a/library/alloc/tests/str.rs +++ b/library/alloc/tests/str.rs @@ -1854,7 +1854,10 @@ fn to_lowercase() { assert_eq!("ΑΣ''Α".to_lowercase(), "ασ''α"); // https://github.com/rust-lang/rust/issues/124714 + // input lengths around the boundary of the chunk size used by the ascii prefix optimization + assert_eq!("abcdefghijklmnoΣ".to_lowercase(), "abcdefghijklmnoς"); assert_eq!("abcdefghijklmnopΣ".to_lowercase(), "abcdefghijklmnopς"); + assert_eq!("abcdefghijklmnopqΣ".to_lowercase(), "abcdefghijklmnopqς"); // a really long string that has it's lowercase form // even longer. this tests that implementations don't assume diff --git a/library/core/src/alloc/global.rs b/library/core/src/alloc/global.rs index a6f799c4a7de..68f00d07529b 100644 --- a/library/core/src/alloc/global.rs +++ b/library/core/src/alloc/global.rs @@ -124,8 +124,8 @@ pub unsafe trait GlobalAlloc { /// /// # Safety /// - /// This function is unsafe because undefined behavior can result - /// if the caller does not ensure that `layout` has non-zero size. + /// `layout` must have non-zero size. Attempting to allocate for a zero-sized `layout` may + /// result in undefined behavior. /// /// (Extension subtraits might provide more specific bounds on /// behavior, e.g., guarantee a sentinel address or a null pointer @@ -156,14 +156,14 @@ pub unsafe trait GlobalAlloc { /// /// # Safety /// - /// This function is unsafe because undefined behavior can result - /// if the caller does not ensure all of the following: + /// The caller must ensure: /// - /// * `ptr` must denote a block of memory currently allocated via - /// this allocator, + /// * `ptr` is a block of memory currently allocated via this allocator and, /// - /// * `layout` must be the same layout that was used - /// to allocate that block of memory. + /// * `layout` is the same layout that was used to allocate that block of + /// memory. + /// + /// Otherwise undefined behavior can result. #[stable(feature = "global_alloc", since = "1.28.0")] unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout); @@ -172,7 +172,8 @@ pub unsafe trait GlobalAlloc { /// /// # Safety /// - /// This function is unsafe for the same reasons that `alloc` is. + /// The caller has to ensure that `layout` has non-zero size. Like `alloc` + /// zero sized `layout` can result in undefined behaviour. /// However the allocated block of memory is guaranteed to be initialized. /// /// # Errors @@ -220,20 +221,21 @@ pub unsafe trait GlobalAlloc { /// /// # Safety /// - /// This function is unsafe because undefined behavior can result - /// if the caller does not ensure all of the following: + /// The caller must ensure that: /// - /// * `ptr` must be currently allocated via this allocator, + /// * `ptr` is allocated via this allocator, /// - /// * `layout` must be the same layout that was used + /// * `layout` is the same layout that was used /// to allocate that block of memory, /// - /// * `new_size` must be greater than zero. + /// * `new_size` is greater than zero. /// /// * `new_size`, when rounded up to the nearest multiple of `layout.align()`, - /// must not overflow `isize` (i.e., the rounded value must be less than or + /// does not overflow `isize` (i.e., the rounded value must be less than or /// equal to `isize::MAX`). /// + /// If these are not followed, undefined behaviour can result. + /// /// (Extension subtraits might provide more specific bounds on /// behavior, e.g., guarantee a sentinel address or a null pointer /// in response to a zero-size allocation request.) diff --git a/library/core/src/arch.rs b/library/core/src/arch.rs index be734d194be8..4945c045bc63 100644 --- a/library/core/src/arch.rs +++ b/library/core/src/arch.rs @@ -3,6 +3,9 @@ #[allow(unused_imports)] #[stable(feature = "simd_arch", since = "1.27.0")] pub use crate::core_arch::arch::*; +#[unstable(feature = "naked_functions", issue = "90957")] +#[cfg(bootstrap)] +pub use crate::naked_asm; /// Inline assembly. /// @@ -17,6 +20,37 @@ pub macro asm("assembly template", $(operands,)* $(options($(option),*))?) { /* compiler built-in */ } +/// Inline assembly used in combination with `#[naked]` functions. +/// +/// Refer to [Rust By Example] for a usage guide and the [reference] for +/// detailed information about the syntax and available options. +/// +/// [Rust By Example]: https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html +/// [reference]: https://doc.rust-lang.org/nightly/reference/inline-assembly.html +#[unstable(feature = "naked_functions", issue = "90957")] +#[macro_export] +#[cfg(bootstrap)] +macro_rules! naked_asm { + ([$last:expr], [$($pushed:expr),*]) => { + #[cfg(any(target_arch = "x86_64", target_arch = "x86"))] + { + core::arch::asm!($($pushed),*, options(att_syntax, noreturn)) + } + #[cfg(not(any(target_arch = "x86_64", target_arch = "x86")))] + { + core::arch::asm!($($pushed),* , $last, options(noreturn)) + } + }; + + ([$first:expr $(, $rest:expr)*], [$($pushed:expr),*]) => { + naked_asm!([$($rest),*], [$($pushed,)* $first]); + }; + + ($($expr:expr),* $(,)?) => { + naked_asm!([$($expr),*], []); + }; +} + /// Inline assembly used in combination with `#[naked]` functions. /// /// Refer to [Rust By Example] for a usage guide and the [reference] for diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index a3e91bc06709..de212581e825 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -514,7 +514,8 @@ impl Cell { /// assert_eq!(five, 5); /// ``` #[stable(feature = "move_cell", since = "1.17.0")] - #[rustc_const_unstable(feature = "const_cell_into_inner", issue = "78729")] + #[rustc_const_stable(feature = "const_cell_into_inner", since = "CURRENT_RUSTC_VERSION")] + #[rustc_allow_const_fn_unstable(const_precise_live_drops)] pub const fn into_inner(self) -> T { self.value.into_inner() } @@ -857,7 +858,8 @@ impl RefCell { /// let five = c.into_inner(); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_cell_into_inner", issue = "78729")] + #[rustc_const_stable(feature = "const_cell_into_inner", since = "CURRENT_RUSTC_VERSION")] + #[rustc_allow_const_fn_unstable(const_precise_live_drops)] #[inline] pub const fn into_inner(self) -> T { // Since this function takes `self` (the `RefCell`) by value, the @@ -1895,11 +1897,17 @@ impl fmt::Display for RefMut<'_, T> { /// uniqueness guarantee for mutable references is unaffected. There is *no* legal way to obtain /// aliasing `&mut`, not even with `UnsafeCell`. /// +/// `UnsafeCell` does nothing to avoid data races; they are still undefined behavior. If multiple +/// threads have access to the same `UnsafeCell`, they must follow the usual rules of the +/// [concurrent memory model]: conflicting non-synchronized accesses must be done via the APIs in +/// [`core::sync::atomic`]. +/// /// The `UnsafeCell` API itself is technically very simple: [`.get()`] gives you a raw pointer /// `*mut T` to its contents. It is up to _you_ as the abstraction designer to use that raw pointer /// correctly. /// /// [`.get()`]: `UnsafeCell::get` +/// [concurrent memory model]: ../sync/atomic/index.html#memory-model-for-atomic-accesses /// /// The precise Rust aliasing rules are somewhat in flux, but the main points are not contentious: /// @@ -1922,10 +1930,6 @@ impl fmt::Display for RefMut<'_, T> { /// live memory and the compiler is allowed to insert spurious reads if it can prove that this /// memory has not yet been deallocated. /// -/// - At all times, you must avoid data races. If multiple threads have access to -/// the same `UnsafeCell`, then any writes must have a proper happens-before relation to all other -/// accesses (or use atomics). -/// /// To assist with proper design, the following scenarios are explicitly declared legal /// for single-threaded code: /// @@ -2098,8 +2102,8 @@ impl UnsafeCell { /// ``` #[inline(always)] #[stable(feature = "rust1", since = "1.0.0")] - // When this is const stabilized, please remove `primitive_into_inner` below. - #[rustc_const_unstable(feature = "const_cell_into_inner", issue = "78729")] + #[rustc_const_stable(feature = "const_cell_into_inner", since = "CURRENT_RUSTC_VERSION")] + #[rustc_allow_const_fn_unstable(const_precise_live_drops)] pub const fn into_inner(self) -> T { self.value } @@ -2245,47 +2249,6 @@ impl, U> CoerceUnsized> for UnsafeCell {} #[unstable(feature = "dispatch_from_dyn", issue = "none")] impl, U> DispatchFromDyn> for UnsafeCell {} -// Special cases of UnsafeCell::into_inner where T is a primitive. These are -// used by Atomic*::into_inner. -// -// The real UnsafeCell::into_inner cannot be used yet in a stable const function. -// That is blocked on a "precise drop analysis" unstable const feature. -// https://github.com/rust-lang/rust/issues/73255 -macro_rules! unsafe_cell_primitive_into_inner { - ($($primitive:ident $atomic:literal)*) => { - $( - #[cfg(target_has_atomic_load_store = $atomic)] - impl UnsafeCell<$primitive> { - pub(crate) const fn primitive_into_inner(self) -> $primitive { - self.value - } - } - )* - }; -} - -unsafe_cell_primitive_into_inner! { - i8 "8" - u8 "8" - i16 "16" - u16 "16" - i32 "32" - u32 "32" - i64 "64" - u64 "64" - i128 "128" - u128 "128" - isize "ptr" - usize "ptr" -} - -#[cfg(target_has_atomic_load_store = "ptr")] -impl UnsafeCell<*mut T> { - pub(crate) const fn primitive_into_inner(self) -> *mut T { - self.value - } -} - /// [`UnsafeCell`], but [`Sync`]. /// /// This is just an `UnsafeCell`, except it implements `Sync` diff --git a/library/core/src/cell/once.rs b/library/core/src/cell/once.rs index 87df8a4e272e..14c587e0c482 100644 --- a/library/core/src/cell/once.rs +++ b/library/core/src/cell/once.rs @@ -309,7 +309,8 @@ impl OnceCell { /// ``` #[inline] #[stable(feature = "once_cell", since = "1.70.0")] - #[rustc_const_unstable(feature = "const_cell_into_inner", issue = "78729")] + #[rustc_const_stable(feature = "const_cell_into_inner", since = "CURRENT_RUSTC_VERSION")] + #[rustc_allow_const_fn_unstable(const_precise_live_drops)] pub const fn into_inner(self) -> Option { // Because `into_inner` takes `self` by value, the compiler statically verifies // that it is not currently borrowed. So it is safe to move out `Option`. diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs index 55e67e5c255e..7f3c998aaa5b 100644 --- a/library/core/src/char/methods.rs +++ b/library/core/src/char/methods.rs @@ -69,7 +69,7 @@ impl char { /// assert_eq!(char::from_u32(value_at_max + 1), None); /// ``` #[stable(feature = "assoc_char_consts", since = "1.52.0")] - pub const MAX: char = '\u{10ffff}'; + pub const MAX: char = '\u{10FFFF}'; /// `U+FFFD REPLACEMENT CHARACTER` (�) is used in Unicode to represent a /// decoding error. @@ -1841,7 +1841,6 @@ pub const fn encode_utf16_raw(mut code: u32, dst: &mut [u16]) -> &mut [u16] { } (2, [a, b, ..]) => { code -= 0x1_0000; - *a = (code >> 10) as u16 | 0xD800; *b = (code & 0x3FF) as u16 | 0xDC00; } diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index 818a36002e75..4377b4993b8f 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -275,49 +275,56 @@ pub macro PartialEq($item:item) { /// Trait for comparisons corresponding to [equivalence relations]( /// https://en.wikipedia.org/wiki/Equivalence_relation). /// -/// This means, that in addition to `a == b` and `a != b` being strict inverses, -/// the relation must be (for all `a`, `b` and `c`): +/// The primary difference to [`PartialEq`] is the additional requirement for reflexivity. A type +/// that implements [`PartialEq`] guarantees that for all `a`, `b` and `c`: /// -/// - reflexive: `a == a`; -/// - symmetric: `a == b` implies `b == a` (required by `PartialEq` as well); and -/// - transitive: `a == b` and `b == c` implies `a == c` (required by `PartialEq` as well). +/// - symmetric: `a == b` implies `b == a` and `a != b` implies `!(a == b)` +/// - transitive: `a == b` and `b == c` implies `a == c` /// -/// This property cannot be checked by the compiler, and therefore `Eq` implies -/// [`PartialEq`], and has no extra methods. +/// `Eq`, which builds on top of [`PartialEq`] also implies: +/// +/// - reflexive: `a == a` +/// +/// This property cannot be checked by the compiler, and therefore `Eq` is a trait without methods. /// /// Violating this property is a logic error. The behavior resulting from a logic error is not /// specified, but users of the trait must ensure that such logic errors do *not* result in /// undefined behavior. This means that `unsafe` code **must not** rely on the correctness of these /// methods. /// -/// Implement `Eq` in addition to `PartialEq` if it's guaranteed that -/// `PartialEq::eq(a, a)` always returns `true` (reflexivity), in addition to -/// the symmetric and transitive properties already required by `PartialEq`. +/// Floating point types such as [`f32`] and [`f64`] implement only [`PartialEq`] but *not* `Eq` +/// because `NaN` != `NaN`. /// /// ## Derivable /// -/// This trait can be used with `#[derive]`. When `derive`d, because `Eq` has -/// no extra methods, it is only informing the compiler that this is an -/// equivalence relation rather than a partial equivalence relation. Note that -/// the `derive` strategy requires all fields are `Eq`, which isn't +/// This trait can be used with `#[derive]`. When `derive`d, because `Eq` has no extra methods, it +/// is only informing the compiler that this is an equivalence relation rather than a partial +/// equivalence relation. Note that the `derive` strategy requires all fields are `Eq`, which isn't /// always desired. /// /// ## How can I implement `Eq`? /// -/// If you cannot use the `derive` strategy, specify that your type implements -/// `Eq`, which has no methods: +/// If you cannot use the `derive` strategy, specify that your type implements `Eq`, which has no +/// extra methods: /// /// ``` -/// enum BookFormat { Paperback, Hardback, Ebook } +/// enum BookFormat { +/// Paperback, +/// Hardback, +/// Ebook, +/// } +/// /// struct Book { /// isbn: i32, /// format: BookFormat, /// } +/// /// impl PartialEq for Book { /// fn eq(&self, other: &Self) -> bool { /// self.isbn == other.isbn /// } /// } +/// /// impl Eq for Book {} /// ``` #[doc(alias = "==")] @@ -325,11 +332,9 @@ pub macro PartialEq($item:item) { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_diagnostic_item = "Eq"] pub trait Eq: PartialEq { - // this method is used solely by #[derive(Eq)] to assert - // that every component of a type implements `Eq` - // itself. The current deriving infrastructure means doing this - // assertion without using a method on this trait is nearly - // impossible. + // this method is used solely by `impl Eq or #[derive(Eq)]` to assert that every component of a + // type implements `Eq` itself. The current deriving infrastructure means doing this assertion + // without using a method on this trait is nearly impossible. // // This should never be implemented by hand. #[doc(hidden)] @@ -693,17 +698,14 @@ impl Clone for Reverse { /// Trait for types that form a [total order](https://en.wikipedia.org/wiki/Total_order). /// -/// Implementations must be consistent with the [`PartialOrd`] implementation, and ensure -/// `max`, `min`, and `clamp` are consistent with `cmp`: +/// Implementations must be consistent with the [`PartialOrd`] implementation, and ensure `max`, +/// `min`, and `clamp` are consistent with `cmp`: /// /// - `partial_cmp(a, b) == Some(cmp(a, b))`. /// - `max(a, b) == max_by(a, b, cmp)` (ensured by the default implementation). /// - `min(a, b) == min_by(a, b, cmp)` (ensured by the default implementation). -/// - For `a.clamp(min, max)`, see the [method docs](#method.clamp) -/// (ensured by the default implementation). -/// -/// It's easy to accidentally make `cmp` and `partial_cmp` disagree by -/// deriving some of the traits and manually implementing others. +/// - For `a.clamp(min, max)`, see the [method docs](#method.clamp) (ensured by the default +/// implementation). /// /// Violating these requirements is a logic error. The behavior resulting from a logic error is not /// specified, but users of the trait must ensure that such logic errors do *not* result in @@ -712,15 +714,14 @@ impl Clone for Reverse { /// /// ## Corollaries /// -/// From the above and the requirements of `PartialOrd`, it follows that for -/// all `a`, `b` and `c`: +/// From the above and the requirements of `PartialOrd`, it follows that for all `a`, `b` and `c`: /// /// - exactly one of `a < b`, `a == b` or `a > b` is true; and -/// - `<` is transitive: `a < b` and `b < c` implies `a < c`. The same must hold for both `==` and `>`. +/// - `<` is transitive: `a < b` and `b < c` implies `a < c`. The same must hold for both `==` and +/// `>`. /// -/// Mathematically speaking, the `<` operator defines a strict [weak order]. In -/// cases where `==` conforms to mathematical equality, it also defines a -/// strict [total order]. +/// Mathematically speaking, the `<` operator defines a strict [weak order]. In cases where `==` +/// conforms to mathematical equality, it also defines a strict [total order]. /// /// [weak order]: https://en.wikipedia.org/wiki/Weak_ordering /// [total order]: https://en.wikipedia.org/wiki/Total_order @@ -730,13 +731,12 @@ impl Clone for Reverse { /// This trait can be used with `#[derive]`. /// /// When `derive`d on structs, it will produce a -/// [lexicographic](https://en.wikipedia.org/wiki/Lexicographic_order) ordering -/// based on the top-to-bottom declaration order of the struct's members. +/// [lexicographic](https://en.wikipedia.org/wiki/Lexicographic_order) ordering based on the +/// top-to-bottom declaration order of the struct's members. /// -/// When `derive`d on enums, variants are ordered primarily by their discriminants. -/// Secondarily, they are ordered by their fields. -/// By default, the discriminant is smallest for variants at the top, and -/// largest for variants at the bottom. Here's an example: +/// When `derive`d on enums, variants are ordered primarily by their discriminants. Secondarily, +/// they are ordered by their fields. By default, the discriminant is smallest for variants at the +/// top, and largest for variants at the bottom. Here's an example: /// /// ``` /// #[derive(PartialEq, Eq, PartialOrd, Ord)] @@ -748,8 +748,7 @@ impl Clone for Reverse { /// assert!(E::Top < E::Bottom); /// ``` /// -/// However, manually setting the discriminants can override this default -/// behavior: +/// However, manually setting the discriminants can override this default behavior: /// /// ``` /// #[derive(PartialEq, Eq, PartialOrd, Ord)] @@ -765,51 +764,178 @@ impl Clone for Reverse { /// /// Lexicographical comparison is an operation with the following properties: /// - Two sequences are compared element by element. -/// - The first mismatching element defines which sequence is lexicographically less or greater than the other. -/// - If one sequence is a prefix of another, the shorter sequence is lexicographically less than the other. -/// - If two sequences have equivalent elements and are of the same length, then the sequences are lexicographically equal. +/// - The first mismatching element defines which sequence is lexicographically less or greater +/// than the other. +/// - If one sequence is a prefix of another, the shorter sequence is lexicographically less than +/// the other. +/// - If two sequences have equivalent elements and are of the same length, then the sequences are +/// lexicographically equal. /// - An empty sequence is lexicographically less than any non-empty sequence. /// - Two empty sequences are lexicographically equal. /// /// ## How can I implement `Ord`? /// -/// `Ord` requires that the type also be [`PartialOrd`] and [`Eq`] (which requires [`PartialEq`]). +/// `Ord` requires that the type also be [`PartialOrd`], [`PartialEq`], and [`Eq`]. /// -/// Then you must define an implementation for [`cmp`]. You may find it useful to use -/// [`cmp`] on your type's fields. +/// Because `Ord` implies a stronger ordering relationship than [`PartialOrd`], and both `Ord` and +/// [`PartialOrd`] must agree, you must choose how to implement `Ord` **first**. You can choose to +/// derive it, or implement it manually. If you derive it, you should derive all four traits. If you +/// implement it manually, you should manually implement all four traits, based on the +/// implementation of `Ord`. /// -/// Here's an example where you want to sort people by height only, disregarding `id` -/// and `name`: +/// Here's an example where you want to define the `Character` comparison by `health` and +/// `experience` only, disregarding the field `mana`: /// /// ``` /// use std::cmp::Ordering; /// -/// #[derive(Eq)] -/// struct Person { -/// id: u32, -/// name: String, -/// height: u32, +/// struct Character { +/// health: u32, +/// experience: u32, +/// mana: f32, /// } /// -/// impl Ord for Person { -/// fn cmp(&self, other: &Self) -> Ordering { -/// self.height.cmp(&other.height) +/// impl Ord for Character { +/// fn cmp(&self, other: &Self) -> std::cmp::Ordering { +/// self.experience +/// .cmp(&other.experience) +/// .then(self.health.cmp(&other.health)) /// } /// } /// -/// impl PartialOrd for Person { +/// impl PartialOrd for Character { /// fn partial_cmp(&self, other: &Self) -> Option { /// Some(self.cmp(other)) /// } /// } /// -/// impl PartialEq for Person { +/// impl PartialEq for Character { /// fn eq(&self, other: &Self) -> bool { -/// self.height == other.height +/// self.health == other.health && self.experience == other.experience /// } /// } +/// +/// impl Eq for Character {} /// ``` /// +/// If all you need is to `slice::sort` a type by a field value, it can be simpler to use +/// `slice::sort_by_key`. +/// +/// ## Examples of incorrect `Ord` implementations +/// +/// ``` +/// use std::cmp::Ordering; +/// +/// #[derive(Debug)] +/// struct Character { +/// health: f32, +/// } +/// +/// impl Ord for Character { +/// fn cmp(&self, other: &Self) -> std::cmp::Ordering { +/// if self.health < other.health { +/// Ordering::Less +/// } else if self.health > other.health { +/// Ordering::Greater +/// } else { +/// Ordering::Equal +/// } +/// } +/// } +/// +/// impl PartialOrd for Character { +/// fn partial_cmp(&self, other: &Self) -> Option { +/// Some(self.cmp(other)) +/// } +/// } +/// +/// impl PartialEq for Character { +/// fn eq(&self, other: &Self) -> bool { +/// self.health == other.health +/// } +/// } +/// +/// impl Eq for Character {} +/// +/// let a = Character { health: 4.5 }; +/// let b = Character { health: f32::NAN }; +/// +/// // Mistake: floating-point values do not form a total order and using the built-in comparison +/// // operands to implement `Ord` irregardless of that reality does not change it. Use +/// // `f32::total_cmp` if you need a total order for floating-point values. +/// +/// // Reflexivity requirement of `Ord` is not given. +/// assert!(a == a); +/// assert!(b != b); +/// +/// // Antisymmetry requirement of `Ord` is not given. Only one of a < c and c < a is allowed to be +/// // true, not both or neither. +/// assert_eq!((a < b) as u8 + (b < a) as u8, 0); +/// ``` +/// +/// ``` +/// use std::cmp::Ordering; +/// +/// #[derive(Debug)] +/// struct Character { +/// health: u32, +/// experience: u32, +/// } +/// +/// impl PartialOrd for Character { +/// fn partial_cmp(&self, other: &Self) -> Option { +/// Some(self.cmp(other)) +/// } +/// } +/// +/// impl Ord for Character { +/// fn cmp(&self, other: &Self) -> std::cmp::Ordering { +/// if self.health < 50 { +/// self.health.cmp(&other.health) +/// } else { +/// self.experience.cmp(&other.experience) +/// } +/// } +/// } +/// +/// // For performance reasons implementing `PartialEq` this way is not the idiomatic way, but it +/// // ensures consistent behavior between `PartialEq`, `PartialOrd` and `Ord` in this example. +/// impl PartialEq for Character { +/// fn eq(&self, other: &Self) -> bool { +/// self.cmp(other) == Ordering::Equal +/// } +/// } +/// +/// impl Eq for Character {} +/// +/// let a = Character { +/// health: 3, +/// experience: 5, +/// }; +/// let b = Character { +/// health: 10, +/// experience: 77, +/// }; +/// let c = Character { +/// health: 143, +/// experience: 2, +/// }; +/// +/// // Mistake: The implementation of `Ord` compares different fields depending on the value of +/// // `self.health`, the resulting order is not total. +/// +/// // Transitivity requirement of `Ord` is not given. If a is smaller than b and b is smaller than +/// // c, by transitive property a must also be smaller than c. +/// assert!(a < b && b < c && c < a); +/// +/// // Antisymmetry requirement of `Ord` is not given. Only one of a < c and c < a is allowed to be +/// // true, not both or neither. +/// assert_eq!((a < c) as u8 + (c < a) as u8, 2); +/// ``` +/// +/// The documentation of [`PartialOrd`] contains further examples, for example it's wrong for +/// [`PartialOrd`] and [`PartialEq`] to disagree. +/// /// [`cmp`]: Ord::cmp #[doc(alias = "<")] #[doc(alias = ">")] @@ -924,8 +1050,12 @@ pub macro Ord($item:item) { /// Trait for types that form a [partial order](https://en.wikipedia.org/wiki/Partial_order). /// -/// The `lt`, `le`, `gt`, and `ge` methods of this trait can be called using -/// the `<`, `<=`, `>`, and `>=` operators, respectively. +/// The `lt`, `le`, `gt`, and `ge` methods of this trait can be called using the `<`, `<=`, `>`, and +/// `>=` operators, respectively. +/// +/// This trait should **only** contain the comparison logic for a type **if one plans on only +/// implementing `PartialOrd` but not [`Ord`]**. Otherwise the comparison logic should be in [`Ord`] +/// and this trait implemented with `Some(self.cmp(other))`. /// /// The methods of this trait must be consistent with each other and with those of [`PartialEq`]. /// The following conditions must hold: @@ -937,26 +1067,25 @@ pub macro Ord($item:item) { /// 5. `a >= b` if and only if `a > b || a == b` /// 6. `a != b` if and only if `!(a == b)`. /// -/// Conditions 2–5 above are ensured by the default implementation. -/// Condition 6 is already ensured by [`PartialEq`]. +/// Conditions 2–5 above are ensured by the default implementation. Condition 6 is already ensured +/// by [`PartialEq`]. /// /// If [`Ord`] is also implemented for `Self` and `Rhs`, it must also be consistent with -/// `partial_cmp` (see the documentation of that trait for the exact requirements). It's -/// easy to accidentally make them disagree by deriving some of the traits and manually -/// implementing others. +/// `partial_cmp` (see the documentation of that trait for the exact requirements). It's easy to +/// accidentally make them disagree by deriving some of the traits and manually implementing others. /// -/// The comparison relations must satisfy the following conditions -/// (for all `a`, `b`, `c` of type `A`, `B`, `C`): +/// The comparison relations must satisfy the following conditions (for all `a`, `b`, `c` of type +/// `A`, `B`, `C`): /// -/// - **Transitivity**: if `A: PartialOrd` and `B: PartialOrd` and `A: -/// PartialOrd`, then `a < b` and `b < c` implies `a < c`. The same must hold for both `==` and `>`. -/// This must also work for longer chains, such as when `A: PartialOrd`, `B: PartialOrd`, -/// `C: PartialOrd`, and `A: PartialOrd` all exist. -/// - **Duality**: if `A: PartialOrd` and `B: PartialOrd`, then `a < b` if and only if `b > a`. +/// - **Transitivity**: if `A: PartialOrd` and `B: PartialOrd` and `A: PartialOrd`, then `a +/// < b` and `b < c` implies `a < c`. The same must hold for both `==` and `>`. This must also +/// work for longer chains, such as when `A: PartialOrd`, `B: PartialOrd`, `C: +/// PartialOrd`, and `A: PartialOrd` all exist. +/// - **Duality**: if `A: PartialOrd` and `B: PartialOrd`, then `a < b` if and only if `b > +/// a`. /// -/// Note that the `B: PartialOrd` (dual) and `A: PartialOrd` -/// (transitive) impls are not forced to exist, but these requirements apply -/// whenever they do exist. +/// Note that the `B: PartialOrd` (dual) and `A: PartialOrd` (transitive) impls are not forced +/// to exist, but these requirements apply whenever they do exist. /// /// Violating these requirements is a logic error. The behavior resulting from a logic error is not /// specified, but users of the trait must ensure that such logic errors do *not* result in @@ -992,12 +1121,10 @@ pub macro Ord($item:item) { /// /// ## Strict and non-strict partial orders /// -/// The `<` and `>` operators behave according to a *strict* partial order. -/// However, `<=` and `>=` do **not** behave according to a *non-strict* -/// partial order. -/// That is because mathematically, a non-strict partial order would require -/// reflexivity, i.e. `a <= a` would need to be true for every `a`. This isn't -/// always the case for types that implement `PartialOrd`, for example: +/// The `<` and `>` operators behave according to a *strict* partial order. However, `<=` and `>=` +/// do **not** behave according to a *non-strict* partial order. That is because mathematically, a +/// non-strict partial order would require reflexivity, i.e. `a <= a` would need to be true for +/// every `a`. This isn't always the case for types that implement `PartialOrd`, for example: /// /// ``` /// let a = f64::sqrt(-1.0); @@ -1009,13 +1136,12 @@ pub macro Ord($item:item) { /// This trait can be used with `#[derive]`. /// /// When `derive`d on structs, it will produce a -/// [lexicographic](https://en.wikipedia.org/wiki/Lexicographic_order) ordering -/// based on the top-to-bottom declaration order of the struct's members. +/// [lexicographic](https://en.wikipedia.org/wiki/Lexicographic_order) ordering based on the +/// top-to-bottom declaration order of the struct's members. /// -/// When `derive`d on enums, variants are primarily ordered by their discriminants. -/// Secondarily, they are ordered by their fields. -/// By default, the discriminant is smallest for variants at the top, and -/// largest for variants at the bottom. Here's an example: +/// When `derive`d on enums, variants are primarily ordered by their discriminants. Secondarily, +/// they are ordered by their fields. By default, the discriminant is smallest for variants at the +/// top, and largest for variants at the bottom. Here's an example: /// /// ``` /// #[derive(PartialEq, PartialOrd)] @@ -1027,8 +1153,7 @@ pub macro Ord($item:item) { /// assert!(E::Top < E::Bottom); /// ``` /// -/// However, manually setting the discriminants can override this default -/// behavior: +/// However, manually setting the discriminants can override this default behavior: /// /// ``` /// #[derive(PartialEq, PartialOrd)] @@ -1046,8 +1171,8 @@ pub macro Ord($item:item) { /// generated from default implementations. /// /// However it remains possible to implement the others separately for types which do not have a -/// total order. For example, for floating point numbers, `NaN < 0 == false` and `NaN >= 0 == -/// false` (cf. IEEE 754-2008 section 5.11). +/// total order. For example, for floating point numbers, `NaN < 0 == false` and `NaN >= 0 == false` +/// (cf. IEEE 754-2008 section 5.11). /// /// `PartialOrd` requires your type to be [`PartialEq`]. /// @@ -1056,7 +1181,6 @@ pub macro Ord($item:item) { /// ``` /// use std::cmp::Ordering; /// -/// #[derive(Eq)] /// struct Person { /// id: u32, /// name: String, @@ -1080,11 +1204,13 @@ pub macro Ord($item:item) { /// self.height == other.height /// } /// } +/// +/// impl Eq for Person {} /// ``` /// -/// You may also find it useful to use [`partial_cmp`] on your type's fields. Here -/// is an example of `Person` types who have a floating-point `height` field that -/// is the only field to be used for sorting: +/// You may also find it useful to use [`partial_cmp`] on your type's fields. Here is an example of +/// `Person` types who have a floating-point `height` field that is the only field to be used for +/// sorting: /// /// ``` /// use std::cmp::Ordering; @@ -1108,6 +1234,38 @@ pub macro Ord($item:item) { /// } /// ``` /// +/// ## Examples of incorrect `PartialOrd` implementations +/// +/// ``` +/// use std::cmp::Ordering; +/// +/// #[derive(PartialEq, Debug)] +/// struct Character { +/// health: u32, +/// experience: u32, +/// } +/// +/// impl PartialOrd for Character { +/// fn partial_cmp(&self, other: &Self) -> Option { +/// Some(self.health.cmp(&other.health)) +/// } +/// } +/// +/// let a = Character { +/// health: 10, +/// experience: 5, +/// }; +/// let b = Character { +/// health: 10, +/// experience: 77, +/// }; +/// +/// // Mistake: `PartialEq` and `PartialOrd` disagree with each other. +/// +/// assert_eq!(a.partial_cmp(&b).unwrap(), Ordering::Equal); // a == b according to `PartialOrd`. +/// assert_ne!(a, b); // a != b according to `PartialEq`. +/// ``` +/// /// # Examples /// /// ``` diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index 930f8a766207..15b00b9aa442 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs @@ -5,7 +5,7 @@ use crate::error::Error; use crate::ffi::c_char; use crate::iter::FusedIterator; use crate::marker::PhantomData; -use crate::ptr::{NonNull, addr_of}; +use crate::ptr::NonNull; use crate::slice::memchr; use crate::{fmt, intrinsics, ops, slice, str}; @@ -623,7 +623,7 @@ impl CStr { pub const fn to_bytes_with_nul(&self) -> &[u8] { // SAFETY: Transmuting a slice of `c_char`s to a slice of `u8`s // is safe on all supported targets. - unsafe { &*(addr_of!(self.inner) as *const [u8]) } + unsafe { &*((&raw const self.inner) as *const [u8]) } } /// Iterates over the bytes in this C string. diff --git a/library/core/src/fmt/num.rs b/library/core/src/fmt/num.rs index e7726da8d91f..aecd725eca56 100644 --- a/library/core/src/fmt/num.rs +++ b/library/core/src/fmt/num.rs @@ -208,75 +208,119 @@ static DEC_DIGITS_LUT: &[u8; 200] = b"0001020304050607080910111213141516171819\ 8081828384858687888990919293949596979899"; macro_rules! impl_Display { - ($($t:ident),* as $u:ident via $conv_fn:ident named $name:ident) => { - #[cfg(not(feature = "optimize_for_size"))] - fn $name(mut n: $u, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result { - // 2^128 is about 3*10^38, so 39 gives an extra byte of space - let mut buf = [MaybeUninit::::uninit(); 39]; - let mut curr = buf.len(); - let buf_ptr = MaybeUninit::slice_as_mut_ptr(&mut buf); - let lut_ptr = DEC_DIGITS_LUT.as_ptr(); + ($($t:ident $(as $positive:ident)? named $name:ident,)* ; as $u:ident via $conv_fn:ident named $gen_name:ident) => { - // SAFETY: Since `d1` and `d2` are always less than or equal to `198`, we - // can copy from `lut_ptr[d1..d1 + 1]` and `lut_ptr[d2..d2 + 1]`. To show - // that it's OK to copy into `buf_ptr`, notice that at the beginning - // `curr == buf.len() == 39 > log(n)` since `n < 2^128 < 10^39`, and at - // each step this is kept the same as `n` is divided. Since `n` is always - // non-negative, this means that `curr > 0` so `buf_ptr[curr..curr + 1]` - // is safe to access. - unsafe { - // need at least 16 bits for the 4-characters-at-a-time to work. - assert!(crate::mem::size_of::<$u>() >= 2); + $( + #[stable(feature = "rust1", since = "1.0.0")] + impl fmt::Display for $t { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // If it's a signed integer. + $( + let is_nonnegative = *self >= 0; - // eagerly decode 4 characters at a time - while n >= 10000 { - let rem = (n % 10000) as usize; - n /= 10000; - - let d1 = (rem / 100) << 1; - let d2 = (rem % 100) << 1; - curr -= 4; - - // We are allowed to copy to `buf_ptr[curr..curr + 3]` here since - // otherwise `curr < 0`. But then `n` was originally at least `10000^10` - // which is `10^40 > 2^128 > n`. - ptr::copy_nonoverlapping(lut_ptr.add(d1), buf_ptr.add(curr), 2); - ptr::copy_nonoverlapping(lut_ptr.add(d2), buf_ptr.add(curr + 2), 2); + #[cfg(not(feature = "optimize_for_size"))] + { + if !is_nonnegative { + // convert the negative num to positive by summing 1 to its 2s complement + return (!self as $positive).wrapping_add(1)._fmt(false, f); + } + } + #[cfg(feature = "optimize_for_size")] + { + if !is_nonnegative { + // convert the negative num to positive by summing 1 to its 2s complement + return $gen_name((!self.$conv_fn()).wrapping_add(1), false, f); + } + } + )? + // If it's a positive integer. + #[cfg(not(feature = "optimize_for_size"))] + { + self._fmt(true, f) } - - // if we reach here numbers are <= 9999, so at most 4 chars long - let mut n = n as usize; // possibly reduce 64bit math - - // decode 2 more chars, if > 2 chars - if n >= 100 { - let d1 = (n % 100) << 1; - n /= 100; - curr -= 2; - ptr::copy_nonoverlapping(lut_ptr.add(d1), 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), buf_ptr.add(curr), 2); + #[cfg(feature = "optimize_for_size")] + { + $gen_name(self.$conv_fn(), true, f) } } - - // 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 { - str::from_utf8_unchecked( - slice::from_raw_parts(buf_ptr.add(curr), buf.len() - curr)) - }; - f.pad_integral(is_nonnegative, "", buf_slice) } + #[cfg(not(feature = "optimize_for_size"))] + impl $t { + fn _fmt(mut self: $t, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result { + const SIZE: usize = $t::MAX.ilog(10) as usize + 1; + let mut buf = [MaybeUninit::::uninit(); SIZE]; + let mut curr = SIZE; + let buf_ptr = MaybeUninit::slice_as_mut_ptr(&mut buf); + let lut_ptr = DEC_DIGITS_LUT.as_ptr(); + + // SAFETY: Since `d1` and `d2` are always less than or equal to `198`, we + // can copy from `lut_ptr[d1..d1 + 1]` and `lut_ptr[d2..d2 + 1]`. To show + // that it's OK to copy into `buf_ptr`, notice that at the beginning + // `curr == buf.len() == 39 > log(n)` since `n < 2^128 < 10^39`, and at + // each step this is kept the same as `n` is divided. Since `n` is always + // non-negative, this means that `curr > 0` so `buf_ptr[curr..curr + 1]` + // is safe to access. + unsafe { + // need at least 16 bits for the 4-characters-at-a-time to work. + #[allow(overflowing_literals)] + #[allow(unused_comparisons)] + // This block will be removed for smaller types at compile time and in the worst + // case, it will prevent to have the `10000` literal to overflow for `i8` and `u8`. + if core::mem::size_of::<$t>() >= 2 { + // eagerly decode 4 characters at a time + while self >= 10000 { + let rem = (self % 10000) as usize; + self /= 10000; + + let d1 = (rem / 100) << 1; + let d2 = (rem % 100) << 1; + curr -= 4; + + // We are allowed to copy to `buf_ptr[curr..curr + 3]` here since + // otherwise `curr < 0`. But then `n` was originally at least `10000^10` + // which is `10^40 > 2^128 > n`. + ptr::copy_nonoverlapping(lut_ptr.add(d1 as usize), buf_ptr.add(curr), 2); + ptr::copy_nonoverlapping(lut_ptr.add(d2 as usize), buf_ptr.add(curr + 2), 2); + } + } + + // if we reach here numbers are <= 9999, so at most 4 chars long + let mut n = self as usize; // possibly reduce 64bit math + + // decode 2 more chars, if > 2 chars + if n >= 100 { + let d1 = (n % 100) << 1; + n /= 100; + curr -= 2; + ptr::copy_nonoverlapping(lut_ptr.add(d1), buf_ptr.add(curr), 2); + } + + // if we reach here numbers are <= 100, so at most 2 chars long + // The biggest it can be is 99, and 99 << 1 == 198, so a `u8` is enough. + // 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), buf_ptr.add(curr), 2); + } + } + + // 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 { + str::from_utf8_unchecked( + slice::from_raw_parts(buf_ptr.add(curr), buf.len() - curr)) + }; + f.pad_integral(is_nonnegative, "", buf_slice) + } + })* + #[cfg(feature = "optimize_for_size")] - fn $name(mut n: $u, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fn $gen_name(mut n: $u, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result { // 2^128 is about 3*10^38, so 39 gives an extra byte of space let mut buf = [MaybeUninit::::uninit(); 39]; let mut curr = buf.len(); @@ -306,21 +350,6 @@ macro_rules! impl_Display { }; f.pad_integral(is_nonnegative, "", buf_slice) } - - $(#[stable(feature = "rust1", since = "1.0.0")] - impl fmt::Display for $t { - #[allow(unused_comparisons)] - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let is_nonnegative = *self >= 0; - let n = if is_nonnegative { - self.$conv_fn() - } else { - // convert the negative num to positive by summing 1 to it's 2 complement - (!self.$conv_fn()).wrapping_add(1) - }; - $name(n, is_nonnegative, f) - } - })* }; } @@ -374,7 +403,6 @@ macro_rules! impl_Exp { (n, exponent, exponent, added_precision) }; - // 39 digits (worst case u128) + . = 40 // Since `curr` always decreases by the number of digits copied, this means // that `curr >= 0`. let mut buf = [MaybeUninit::::uninit(); 40]; @@ -469,7 +497,7 @@ macro_rules! impl_Exp { let n = if is_nonnegative { self.$conv_fn() } else { - // convert the negative num to positive by summing 1 to it's 2 complement + // convert the negative num to positive by summing 1 to its 2s complement (!self.$conv_fn()).wrapping_add(1) }; $name(n, is_nonnegative, false, f) @@ -484,7 +512,7 @@ macro_rules! impl_Exp { let n = if is_nonnegative { self.$conv_fn() } else { - // convert the negative num to positive by summing 1 to it's 2 complement + // convert the negative num to positive by summing 1 to its 2s complement (!self.$conv_fn()).wrapping_add(1) }; $name(n, is_nonnegative, true, f) @@ -499,8 +527,17 @@ macro_rules! impl_Exp { mod imp { use super::*; impl_Display!( - i8, u8, i16, u16, i32, u32, i64, u64, usize, isize - as u64 via to_u64 named fmt_u64 + i8 as u8 named fmt_i8, + u8 named fmt_u8, + i16 as u16 named fmt_i16, + u16 named fmt_u16, + i32 as u32 named fmt_i32, + u32 named fmt_u32, + i64 as u64 named fmt_i64, + u64 named fmt_u64, + isize as usize named fmt_isize, + usize named fmt_usize, + ; as u64 via to_u64 named fmt_u64 ); impl_Exp!( i8, u8, i16, u16, i32, u32, i64, u64, usize, isize @@ -511,8 +548,21 @@ mod imp { #[cfg(not(any(target_pointer_width = "64", target_arch = "wasm32")))] mod imp { use super::*; - impl_Display!(i8, u8, i16, u16, i32, u32, isize, usize as u32 via to_u32 named fmt_u32); - impl_Display!(i64, u64 as u64 via to_u64 named fmt_u64); + impl_Display!( + i8 as u8 named fmt_i8, + u8 named fmt_u8, + i16 as u16 named fmt_i16, + u16 named fmt_u16, + i32 as u32 named fmt_i32, + u32 named fmt_u32, + isize as usize named fmt_isize, + usize named fmt_usize, + ; as u32 via to_u32 named fmt_u32); + impl_Display!( + i64 as u64 named fmt_i64, + u64 named fmt_u64, + ; as u64 via to_u64 named fmt_u64); + impl_Exp!(i8, u8, i16, u16, i32, u32, isize, usize as u32 via to_u32 named exp_u32); impl_Exp!(i64, u64 as u64 via to_u64 named exp_u64); } @@ -619,7 +669,7 @@ impl fmt::Display for i128 { let n = if is_nonnegative { self.to_u128() } else { - // convert the negative num to positive by summing 1 to it's 2 complement + // 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) diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 881a89f4d109..d7a2f1909cab 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -1425,8 +1425,7 @@ extern "rust-intrinsic" { /// /// If the computed offset is non-zero, then both the starting and resulting pointer must be /// either in bounds or at the end of an allocated object. If either pointer is out - /// of bounds or arithmetic overflow occurs then any further use of the returned value will - /// result in undefined behavior. + /// of bounds or arithmetic overflow occurs then this operation is undefined behavior. /// /// The stabilized version of this intrinsic is [`pointer::offset`]. #[must_use = "returns a new pointer rather than modifying its argument"] @@ -2659,12 +2658,17 @@ extern "rust-intrinsic" { /// /// `catch_fn` must not unwind. /// - /// The third argument is a function called if an unwind occurs (both Rust unwinds and foreign - /// unwinds). This function takes the data pointer and a pointer to the target-specific - /// exception object that was caught. For more information, see the compiler's source as well as - /// std's `catch_unwind` implementation. + /// The third argument is a function called if an unwind occurs (both Rust `panic` and foreign + /// unwinds). This function takes the data pointer and a pointer to the target- and + /// runtime-specific exception object that was caught. /// - /// The stable version of this intrinsic is `std::panic::catch_unwind`. + /// Note that in the case of a foreign unwinding operation, the exception object data may not be + /// safely usable from Rust, and should not be directly exposed via the standard library. To + /// prevent unsafe access, the library implementation may either abort the process or present an + /// opaque error type to the user. + /// + /// For more information, see the compiler's source, as well as the documentation for the stable + /// version of this intrinsic, `std::panic::catch_unwind`. #[rustc_nounwind] pub fn catch_unwind(try_fn: fn(*mut u8), data: *mut u8, catch_fn: fn(*mut u8, *mut u8)) -> i32; @@ -3160,7 +3164,7 @@ pub const fn type_id() -> u128 { /// change the possible layouts of pointers. #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] -#[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")] +#[rustc_const_stable(feature = "ptr_metadata_const", since = "CURRENT_RUSTC_VERSION")] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const fn aggregate_raw_ptr, D, M>(_data: D, _meta: M) -> P { @@ -3185,7 +3189,7 @@ impl AggregateRawPtr<*mut T> for *mut P { /// This is used to implement functions like `ptr::metadata`. #[rustc_nounwind] #[unstable(feature = "core_intrinsics", issue = "none")] -#[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")] +#[rustc_const_stable(feature = "ptr_metadata_const", since = "CURRENT_RUSTC_VERSION")] #[rustc_intrinsic] #[rustc_intrinsic_must_be_overridden] pub const fn ptr_metadata + ?Sized, M>(_ptr: *const P) -> M { diff --git a/library/core/src/iter/adapters/filter_map.rs b/library/core/src/iter/adapters/filter_map.rs index 914ef6131771..cc64ceb13f76 100644 --- a/library/core/src/iter/adapters/filter_map.rs +++ b/library/core/src/iter/adapters/filter_map.rs @@ -3,7 +3,6 @@ use crate::iter::{FusedIterator, InPlaceIterable, TrustedFused}; use crate::mem::{ManuallyDrop, MaybeUninit}; use crate::num::NonZero; use crate::ops::{ControlFlow, Try}; -use crate::ptr::addr_of; use crate::{array, fmt}; /// An iterator that uses `f` to both filter and map elements from `iter`. @@ -101,7 +100,7 @@ where unsafe { let opt_payload_at: *const MaybeUninit = - addr_of!(val).byte_add(core::mem::offset_of!(Option, Some.0)).cast(); + (&raw const val).byte_add(core::mem::offset_of!(Option, Some.0)).cast(); let dst = guard.array.as_mut_ptr().add(idx); crate::ptr::copy_nonoverlapping(opt_payload_at, dst, 1); crate::mem::forget(val); diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 01cadd78cc09..817d9e3b962e 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -118,7 +118,6 @@ #![feature(const_array_into_iter_constructors)] #![feature(const_bigint_helper_methods)] #![feature(const_black_box)] -#![feature(const_cell_into_inner)] #![feature(const_char_encode_utf16)] #![feature(const_char_encode_utf8)] #![feature(const_eval_select)] diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index 888832251f6d..aa0646846e43 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -229,8 +229,8 @@ pub macro assert_matches { pub macro cfg_match { // with a final wildcard ( - $(cfg($initial_meta:meta) => { $($initial_tokens:item)* })+ - _ => { $($extra_tokens:item)* } + $(cfg($initial_meta:meta) => { $($initial_tokens:tt)* })+ + _ => { $($extra_tokens:tt)* } ) => { cfg_match! { @__items (); @@ -241,7 +241,7 @@ pub macro cfg_match { // without a final wildcard ( - $(cfg($extra_meta:meta) => { $($extra_tokens:item)* })* + $(cfg($extra_meta:meta) => { $($extra_tokens:tt)* })* ) => { cfg_match! { @__items (); @@ -256,7 +256,7 @@ pub macro cfg_match { (@__items ($($_:meta,)*);) => {}, ( @__items ($($no:meta,)*); - (($($yes:meta)?) ($($tokens:item)*)), + (($($yes:meta)?) ($($tokens:tt)*)), $($rest:tt,)* ) => { // Emit all items within one block, applying an appropriate #[cfg]. The @@ -279,7 +279,7 @@ pub macro cfg_match { // Internal macro to make __apply work out right for different match types, // because of how macros match/expand stuff. - (@__identity $($tokens:item)*) => { + (@__identity $($tokens:tt)*) => { $($tokens)* } } diff --git a/library/core/src/mem/manually_drop.rs b/library/core/src/mem/manually_drop.rs index 3e47785ee488..7d519384e373 100644 --- a/library/core/src/mem/manually_drop.rs +++ b/library/core/src/mem/manually_drop.rs @@ -1,22 +1,21 @@ use crate::ops::{Deref, DerefMut, DerefPure}; use crate::ptr; -/// A wrapper to inhibit the compiler from automatically calling `T`’s destructor. -/// This wrapper is 0-cost. +/// A wrapper to inhibit the compiler from automatically calling `T`’s +/// destructor. This wrapper is 0-cost. /// /// `ManuallyDrop` is guaranteed to have the same layout and bit validity as -/// `T`, and is subject to the same layout optimizations as `T`. As a consequence, -/// it has *no effect* on the assumptions that the compiler makes about its -/// contents. For example, initializing a `ManuallyDrop<&mut T>` with [`mem::zeroed`] -/// is undefined behavior. If you need to handle uninitialized data, use -/// [`MaybeUninit`] instead. +/// `T`, and is subject to the same layout optimizations as `T`. As a +/// consequence, it has *no effect* on the assumptions that the compiler makes +/// about its contents. For example, initializing a `ManuallyDrop<&mut T>` with +/// [`mem::zeroed`] is undefined behavior. If you need to handle uninitialized +/// data, use [`MaybeUninit`] instead. /// -/// Note that accessing the value inside a `ManuallyDrop` is safe. -/// This means that a `ManuallyDrop` whose content has been dropped must not -/// be exposed through a public safe API. -/// Correspondingly, `ManuallyDrop::drop` is unsafe. +/// Note that accessing the value inside a `ManuallyDrop` is safe. This means +/// that a `ManuallyDrop` whose content has been dropped must not be exposed +/// through a public safe API. Correspondingly, `ManuallyDrop::drop` is unsafe. /// -/// # `ManuallyDrop` and drop order. +/// # `ManuallyDrop` and drop order /// /// Rust has a well-defined [drop order] of values. To make sure that fields or /// locals are dropped in a specific order, reorder the declarations such that @@ -40,9 +39,116 @@ use crate::ptr; /// } /// ``` /// +/// # Interaction with `Box` +/// +/// Currently, if you have a `ManuallyDrop`, where the type `T` is a `Box` or +/// contains a `Box` inside, then dropping the `T` followed by moving the +/// `ManuallyDrop` is [considered to be undefined +/// behavior](https://github.com/rust-lang/unsafe-code-guidelines/issues/245). +/// That is, the following code causes undefined behavior: +/// +/// ```no_run +/// use std::mem::ManuallyDrop; +/// +/// let mut x = ManuallyDrop::new(Box::new(42)); +/// unsafe { +/// ManuallyDrop::drop(&mut x); +/// } +/// let y = x; // Undefined behavior! +/// ``` +/// +/// This is [likely to change in the +/// future](https://rust-lang.github.io/rfcs/3336-maybe-dangling.html). In the +/// meantime, consider using [`MaybeUninit`] instead. +/// +/// # Safety hazards when storing `ManuallyDrop` in a struct or an enum. +/// +/// Special care is needed when all of the conditions below are met: +/// * A struct or enum contains a `ManuallyDrop`. +/// * The `ManuallyDrop` is not inside a `union`. +/// * The struct or enum is part of public API, or is stored in a struct or an +/// enum that is part of public API. +/// * There is code that drops the contents of the `ManuallyDrop` field, and +/// this code is outside the struct or enum's `Drop` implementation. +/// +/// In particular, the following hazards may occur: +/// +/// #### Storing generic types +/// +/// If the `ManuallyDrop` contains a client-supplied generic type, the client +/// might provide a `Box` as that type. This would cause undefined behavior when +/// the struct or enum is later moved, as mentioned in the previous section. For +/// example, the following code causes undefined behavior: +/// +/// ```no_run +/// use std::mem::ManuallyDrop; +/// +/// pub struct BadOption { +/// // Invariant: Has been dropped iff `is_some` is false. +/// value: ManuallyDrop, +/// is_some: bool, +/// } +/// impl BadOption { +/// pub fn new(value: T) -> Self { +/// Self { value: ManuallyDrop::new(value), is_some: true } +/// } +/// pub fn change_to_none(&mut self) { +/// if self.is_some { +/// self.is_some = false; +/// unsafe { +/// // SAFETY: `value` hasn't been dropped yet, as per the invariant +/// // (This is actually unsound!) +/// ManuallyDrop::drop(&mut self.value); +/// } +/// } +/// } +/// } +/// +/// // In another crate: +/// +/// let mut option = BadOption::new(Box::new(42)); +/// option.change_to_none(); +/// let option2 = option; // Undefined behavior! +/// ``` +/// +/// #### Deriving traits +/// +/// Deriving `Debug`, `Clone`, `PartialEq`, `PartialOrd`, `Ord`, or `Hash` on +/// the struct or enum could be unsound, since the derived implementations of +/// these traits would access the `ManuallyDrop` field. For example, the +/// following code causes undefined behavior: +/// +/// ```no_run +/// use std::mem::ManuallyDrop; +/// +/// // This derive is unsound in combination with the `ManuallyDrop::drop` call. +/// #[derive(Debug)] +/// pub struct Foo { +/// value: ManuallyDrop, +/// } +/// impl Foo { +/// pub fn new() -> Self { +/// let mut temp = Self { +/// value: ManuallyDrop::new(String::from("Unsafe rust is hard.")) +/// }; +/// unsafe { +/// // SAFETY: `value` hasn't been dropped yet. +/// ManuallyDrop::drop(&mut temp.value); +/// } +/// temp +/// } +/// } +/// +/// // In another crate: +/// +/// let foo = Foo::new(); +/// println!("{:?}", foo); // Undefined behavior! +/// ``` +/// /// [drop order]: https://doc.rust-lang.org/reference/destructors.html /// [`mem::zeroed`]: crate::mem::zeroed /// [`MaybeUninit`]: crate::mem::MaybeUninit +/// [`MaybeUninit`]: crate::mem::MaybeUninit #[stable(feature = "manually_drop", since = "1.20.0")] #[lang = "manually_drop"] #[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 30c667e2494b..154e52e288bc 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -1639,8 +1639,6 @@ impl Option { /// # Examples /// /// ``` - /// #![feature(option_get_or_insert_default)] - /// /// let mut x = None; /// /// { @@ -1653,7 +1651,7 @@ impl Option { /// assert_eq!(x, Some(7)); /// ``` #[inline] - #[unstable(feature = "option_get_or_insert_default", issue = "82901")] + #[stable(feature = "option_get_or_insert_default", since = "CURRENT_RUSTC_VERSION")] pub fn get_or_insert_default(&mut self) -> &mut T where T: Default, @@ -2545,3 +2543,27 @@ impl Option> { } } } + +impl [Option; N] { + /// Transposes a `[Option; N]` into a `Option<[T; N]>`. + /// + /// # Examples + /// + /// ``` + /// #![feature(option_array_transpose)] + /// # use std::option::Option; + /// + /// let data = [Some(0); 1000]; + /// let data: Option<[u8; 1000]> = data.transpose(); + /// assert_eq!(data, Some([0; 1000])); + /// + /// let data = [Some(0), None]; + /// let data: Option<[u8; 2]> = data.transpose(); + /// assert_eq!(data, None); + /// ``` + #[inline] + #[unstable(feature = "option_array_transpose", issue = "130828")] + pub fn transpose(self) -> Option<[T; N]> { + self.try_map(core::convert::identity) + } +} diff --git a/library/core/src/panic/location.rs b/library/core/src/panic/location.rs index e2a842046a96..1ad5c07d15cd 100644 --- a/library/core/src/panic/location.rs +++ b/library/core/src/panic/location.rs @@ -44,7 +44,7 @@ impl<'a> Location<'a> { /// /// # Examples /// - /// ```standalone + /// ```standalone_crate /// use std::panic::Location; /// /// /// Returns the [`Location`] at which it is called. diff --git a/library/core/src/ptr/alignment.rs b/library/core/src/ptr/alignment.rs index ceb5906d226e..50706fca5b0f 100644 --- a/library/core/src/ptr/alignment.rs +++ b/library/core/src/ptr/alignment.rs @@ -155,7 +155,7 @@ impl Alignment { !(unsafe { self.as_usize().unchecked_sub(1) }) } - // Remove me once `Ord::max` is usable in const + // FIXME(const-hack) Remove me once `Ord::max` is usable in const pub(crate) const fn max(a: Self, b: Self) -> Self { if a.as_usize() > b.as_usize() { a } else { b } } diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 1146ca6ef430..332c5e904d7e 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -92,7 +92,7 @@ impl *const T { /// } /// ``` #[unstable(feature = "set_ptr_value", issue = "75091")] - #[rustc_const_unstable(feature = "set_ptr_value", issue = "75091")] + #[rustc_const_stable(feature = "ptr_metadata_const", since = "CURRENT_RUSTC_VERSION")] #[must_use = "returns a new pointer rather than modifying its argument"] #[inline] pub const fn with_metadata_of(self, meta: *const U) -> *const U @@ -346,7 +346,7 @@ impl *const T { if self.is_null() { None } else { Some(unsafe { &*(self as *const MaybeUninit) }) } } - /// Adds an offset to a pointer. + /// Adds a signed offset to a pointer. /// /// `count` is in units of T; e.g., a `count` of 3 represents a pointer /// offset of `3 * size_of::()` bytes. @@ -355,7 +355,8 @@ impl *const T { /// /// If any of the following conditions are violated, the result is Undefined Behavior: /// - /// * The computed offset, `count * size_of::()` bytes, must not overflow `isize`. + /// * The offset in bytes, `count * size_of::()`, computed on mathematical integers (without + /// "wrapping around"), must fit in an `isize`. /// /// * If the computed offset is non-zero, then `self` must be derived from a pointer to some /// [allocated object], and the entire memory range between `self` and the result must be in @@ -398,7 +399,7 @@ impl *const T { unsafe { intrinsics::offset(self, count) } } - /// Calculates the offset from a pointer in bytes. + /// Adds a signed offset in bytes to a pointer. /// /// `count` is in units of **bytes**. /// @@ -412,14 +413,13 @@ impl *const T { #[inline(always)] #[stable(feature = "pointer_byte_offsets", since = "1.75.0")] #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "1.75.0")] - #[rustc_allow_const_fn_unstable(set_ptr_value)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn byte_offset(self, count: isize) -> Self { // SAFETY: the caller must uphold the safety contract for `offset`. unsafe { self.cast::().offset(count).with_metadata_of(self) } } - /// Calculates the offset from a pointer using wrapping arithmetic. + /// Adds a signed offset to a pointer using wrapping arithmetic. /// /// `count` is in units of T; e.g., a `count` of 3 represents a pointer /// offset of `3 * size_of::()` bytes. @@ -481,7 +481,7 @@ impl *const T { unsafe { intrinsics::arith_offset(self, count) } } - /// Calculates the offset from a pointer in bytes using wrapping arithmetic. + /// Adds a signed offset in bytes to a pointer using wrapping arithmetic. /// /// `count` is in units of **bytes**. /// @@ -495,7 +495,6 @@ impl *const T { #[inline(always)] #[stable(feature = "pointer_byte_offsets", since = "1.75.0")] #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "1.75.0")] - #[rustc_allow_const_fn_unstable(set_ptr_value)] pub const fn wrapping_byte_offset(self, count: isize) -> Self { self.cast::().wrapping_offset(count).with_metadata_of(self) } @@ -645,7 +644,6 @@ impl *const T { #[inline(always)] #[stable(feature = "pointer_byte_offsets", since = "1.75.0")] #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "1.75.0")] - #[rustc_allow_const_fn_unstable(set_ptr_value)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn byte_offset_from(self, origin: *const U) -> isize { // SAFETY: the caller must uphold the safety contract for `offset_from`. @@ -807,7 +805,11 @@ impl *const T { } } - /// Adds an offset to a pointer (convenience for `.offset(count as isize)`). + /// Adds an unsigned offset to a pointer. + /// + /// This can only move the pointer forward (or not move it). If you need to move forward or + /// backward depending on the value, then you might want [`offset`](#method.offset) instead + /// which takes a signed offset. /// /// `count` is in units of T; e.g., a `count` of 3 represents a pointer /// offset of `3 * size_of::()` bytes. @@ -816,7 +818,8 @@ impl *const T { /// /// If any of the following conditions are violated, the result is Undefined Behavior: /// - /// * The computed offset, `count * size_of::()` bytes, must not overflow `isize`. + /// * The offset in bytes, `count * size_of::()`, computed on mathematical integers (without + /// "wrapping around"), must fit in an `isize`. /// /// * If the computed offset is non-zero, then `self` must be derived from a pointer to some /// [allocated object], and the entire memory range between `self` and the result must be in @@ -859,7 +862,7 @@ impl *const T { unsafe { intrinsics::offset(self, count) } } - /// Calculates the offset from a pointer in bytes (convenience for `.byte_offset(count as isize)`). + /// Adds an unsigned offset in bytes to a pointer. /// /// `count` is in units of bytes. /// @@ -873,15 +876,17 @@ impl *const T { #[inline(always)] #[stable(feature = "pointer_byte_offsets", since = "1.75.0")] #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "1.75.0")] - #[rustc_allow_const_fn_unstable(set_ptr_value)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn byte_add(self, count: usize) -> Self { // SAFETY: the caller must uphold the safety contract for `add`. unsafe { self.cast::().add(count).with_metadata_of(self) } } - /// Subtracts an offset from a pointer (convenience for - /// `.offset((count as isize).wrapping_neg())`). + /// Subtracts an unsigned offset from a pointer. + /// + /// This can only move the pointer backward (or not move it). If you need to move forward or + /// backward depending on the value, then you might want [`offset`](#method.offset) instead + /// which takes a signed offset. /// /// `count` is in units of T; e.g., a `count` of 3 represents a pointer /// offset of `3 * size_of::()` bytes. @@ -890,7 +895,8 @@ impl *const T { /// /// If any of the following conditions are violated, the result is Undefined Behavior: /// - /// * The computed offset, `count * size_of::()` bytes, must not overflow `isize`. + /// * The offset in bytes, `count * size_of::()`, computed on mathematical integers (without + /// "wrapping around"), must fit in an `isize`. /// /// * If the computed offset is non-zero, then `self` must be derived from a pointer to some /// [allocated object], and the entire memory range between `self` and the result must be in @@ -941,8 +947,7 @@ impl *const T { } } - /// Calculates the offset from a pointer in bytes (convenience for - /// `.byte_offset((count as isize).wrapping_neg())`). + /// Subtracts an unsigned offset in bytes from a pointer. /// /// `count` is in units of bytes. /// @@ -956,15 +961,13 @@ impl *const T { #[inline(always)] #[stable(feature = "pointer_byte_offsets", since = "1.75.0")] #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "1.75.0")] - #[rustc_allow_const_fn_unstable(set_ptr_value)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn byte_sub(self, count: usize) -> Self { // SAFETY: the caller must uphold the safety contract for `sub`. unsafe { self.cast::().sub(count).with_metadata_of(self) } } - /// Calculates the offset from a pointer using wrapping arithmetic. - /// (convenience for `.wrapping_offset(count as isize)`) + /// Adds an unsigned offset to a pointer using wrapping arithmetic. /// /// `count` is in units of T; e.g., a `count` of 3 represents a pointer /// offset of `3 * size_of::()` bytes. @@ -1025,8 +1028,7 @@ impl *const T { self.wrapping_offset(count as isize) } - /// Calculates the offset from a pointer in bytes using wrapping arithmetic. - /// (convenience for `.wrapping_byte_offset(count as isize)`) + /// Adds an unsigned offset in bytes to a pointer using wrapping arithmetic. /// /// `count` is in units of bytes. /// @@ -1039,13 +1041,11 @@ impl *const T { #[inline(always)] #[stable(feature = "pointer_byte_offsets", since = "1.75.0")] #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "1.75.0")] - #[rustc_allow_const_fn_unstable(set_ptr_value)] pub const fn wrapping_byte_add(self, count: usize) -> Self { self.cast::().wrapping_add(count).with_metadata_of(self) } - /// Calculates the offset from a pointer using wrapping arithmetic. - /// (convenience for `.wrapping_offset((count as isize).wrapping_neg())`) + /// Subtracts an unsigned offset from a pointer using wrapping arithmetic. /// /// `count` is in units of T; e.g., a `count` of 3 represents a pointer /// offset of `3 * size_of::()` bytes. @@ -1106,8 +1106,7 @@ impl *const T { self.wrapping_offset((count as isize).wrapping_neg()) } - /// Calculates the offset from a pointer in bytes using wrapping arithmetic. - /// (convenience for `.wrapping_offset((count as isize).wrapping_neg())`) + /// Subtracts an unsigned offset in bytes from a pointer using wrapping arithmetic. /// /// `count` is in units of bytes. /// @@ -1120,7 +1119,6 @@ impl *const T { #[inline(always)] #[stable(feature = "pointer_byte_offsets", since = "1.75.0")] #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "1.75.0")] - #[rustc_allow_const_fn_unstable(set_ptr_value)] pub const fn wrapping_byte_sub(self, count: usize) -> Self { self.cast::().wrapping_sub(count).with_metadata_of(self) } @@ -1554,7 +1552,6 @@ impl *const [T] { #[inline] #[stable(feature = "slice_ptr_len", since = "1.79.0")] #[rustc_const_stable(feature = "const_slice_ptr_len", since = "1.79.0")] - #[rustc_allow_const_fn_unstable(ptr_metadata)] pub const fn len(self) -> usize { metadata(self) } diff --git a/library/core/src/ptr/metadata.rs b/library/core/src/ptr/metadata.rs index 76a0e2ba7748..feeaf78d3e72 100644 --- a/library/core/src/ptr/metadata.rs +++ b/library/core/src/ptr/metadata.rs @@ -92,7 +92,7 @@ pub trait Thin = Pointee; /// /// assert_eq!(std::ptr::metadata("foo"), 3_usize); /// ``` -#[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")] +#[rustc_const_stable(feature = "ptr_metadata_const", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn metadata(ptr: *const T) -> ::Metadata { ptr_metadata(ptr) @@ -106,7 +106,7 @@ pub const fn metadata(ptr: *const T) -> ::Metadata { /// /// [`slice::from_raw_parts`]: crate::slice::from_raw_parts #[unstable(feature = "ptr_metadata", issue = "81513")] -#[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")] +#[rustc_const_stable(feature = "ptr_metadata_const", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn from_raw_parts( data_pointer: *const impl Thin, @@ -120,7 +120,7 @@ pub const fn from_raw_parts( /// /// See the documentation of [`from_raw_parts`] for more details. #[unstable(feature = "ptr_metadata", issue = "81513")] -#[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")] +#[rustc_const_stable(feature = "ptr_metadata_const", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn from_raw_parts_mut( data_pointer: *mut impl Thin, diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index cac33a329b99..b6df780fe2f4 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -599,7 +599,6 @@ pub unsafe fn drop_in_place(to_drop: *mut T) { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_promotable] #[rustc_const_stable(feature = "const_ptr_null", since = "1.24.0")] -#[rustc_allow_const_fn_unstable(ptr_metadata)] #[rustc_diagnostic_item = "ptr_null"] pub const fn null() -> *const T { from_raw_parts(without_provenance::<()>(0), ()) @@ -625,7 +624,6 @@ pub const fn null() -> *const T { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_promotable] #[rustc_const_stable(feature = "const_ptr_null", since = "1.24.0")] -#[rustc_allow_const_fn_unstable(ptr_metadata)] #[rustc_diagnostic_item = "ptr_null_mut"] pub const fn null_mut() -> *mut T { from_raw_parts_mut(without_provenance_mut::<()>(0), ()) @@ -949,7 +947,6 @@ pub const fn from_mut(r: &mut T) -> *mut T { #[inline] #[stable(feature = "slice_from_raw_parts", since = "1.42.0")] #[rustc_const_stable(feature = "const_slice_from_raw_parts", since = "1.64.0")] -#[rustc_allow_const_fn_unstable(ptr_metadata)] #[rustc_diagnostic_item = "ptr_slice_from_raw_parts"] pub const fn slice_from_raw_parts(data: *const T, len: usize) -> *const [T] { from_raw_parts(data, len) @@ -1730,7 +1727,7 @@ pub const unsafe fn write_unaligned(dst: *mut T, src: T) { // `dst` cannot overlap `src` because the caller has mutable access // to `dst` while `src` is owned by this function. unsafe { - copy_nonoverlapping(addr_of!(src) as *const u8, dst as *mut u8, mem::size_of::()); + copy_nonoverlapping((&raw const src) as *const u8, dst as *mut u8, mem::size_of::()); // We are calling the intrinsic directly to avoid function calls in the generated code. intrinsics::forget(src); } @@ -2348,7 +2345,6 @@ impl fmt::Debug for F { /// no difference whether the pointer is null or dangling.) #[stable(feature = "raw_ref_macros", since = "1.51.0")] #[rustc_macro_transparency = "semitransparent"] -#[allow_internal_unstable(raw_ref_op)] pub macro addr_of($place:expr) { &raw const $place } @@ -2439,7 +2435,6 @@ pub macro addr_of($place:expr) { /// makes no difference whether the pointer is null or dangling.) #[stable(feature = "raw_ref_macros", since = "1.51.0")] #[rustc_macro_transparency = "semitransparent"] -#[allow_internal_unstable(raw_ref_op)] pub macro addr_of_mut($place:expr) { &raw mut $place } diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 8e33cf081ba6..287073497f82 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -74,7 +74,7 @@ impl *mut T { /// } /// ``` #[unstable(feature = "set_ptr_value", issue = "75091")] - #[rustc_const_unstable(feature = "set_ptr_value", issue = "75091")] + #[rustc_const_stable(feature = "ptr_metadata_const", since = "CURRENT_RUSTC_VERSION")] #[must_use = "returns a new pointer rather than modifying its argument"] #[inline] pub const fn with_metadata_of(self, meta: *const U) -> *mut U @@ -344,7 +344,7 @@ impl *mut T { if self.is_null() { None } else { Some(unsafe { &*(self as *const MaybeUninit) }) } } - /// Adds an offset to a pointer. + /// Adds a signed offset to a pointer. /// /// `count` is in units of T; e.g., a `count` of 3 represents a pointer /// offset of `3 * size_of::()` bytes. @@ -353,7 +353,8 @@ impl *mut T { /// /// If any of the following conditions are violated, the result is Undefined Behavior: /// - /// * The computed offset, `count * size_of::()` bytes, must not overflow `isize`. + /// * The offset in bytes, `count * size_of::()`, computed on mathematical integers (without + /// "wrapping around"), must fit in an `isize`. /// /// * If the computed offset is non-zero, then `self` must be derived from a pointer to some /// [allocated object], and the entire memory range between `self` and the result must be in @@ -398,7 +399,7 @@ impl *mut T { unsafe { intrinsics::offset(self, count) } } - /// Calculates the offset from a pointer in bytes. + /// Adds a signed offset in bytes to a pointer. /// /// `count` is in units of **bytes**. /// @@ -412,14 +413,14 @@ impl *mut T { #[inline(always)] #[stable(feature = "pointer_byte_offsets", since = "1.75.0")] #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "1.75.0")] - #[rustc_allow_const_fn_unstable(set_ptr_value)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn byte_offset(self, count: isize) -> Self { // SAFETY: the caller must uphold the safety contract for `offset`. unsafe { self.cast::().offset(count).with_metadata_of(self) } } - /// Calculates the offset from a pointer using wrapping arithmetic. + /// Adds a signed offset to a pointer using wrapping arithmetic. + /// /// `count` is in units of T; e.g., a `count` of 3 represents a pointer /// offset of `3 * size_of::()` bytes. /// @@ -478,7 +479,7 @@ impl *mut T { unsafe { intrinsics::arith_offset(self, count) as *mut T } } - /// Calculates the offset from a pointer in bytes using wrapping arithmetic. + /// Adds a signed offset in bytes to a pointer using wrapping arithmetic. /// /// `count` is in units of **bytes**. /// @@ -492,7 +493,6 @@ impl *mut T { #[inline(always)] #[stable(feature = "pointer_byte_offsets", since = "1.75.0")] #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "1.75.0")] - #[rustc_allow_const_fn_unstable(set_ptr_value)] pub const fn wrapping_byte_offset(self, count: isize) -> Self { self.cast::().wrapping_offset(count).with_metadata_of(self) } @@ -808,7 +808,6 @@ impl *mut T { #[inline(always)] #[stable(feature = "pointer_byte_offsets", since = "1.75.0")] #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "1.75.0")] - #[rustc_allow_const_fn_unstable(set_ptr_value)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn byte_offset_from(self, origin: *const U) -> isize { // SAFETY: the caller must uphold the safety contract for `offset_from`. @@ -888,7 +887,11 @@ impl *mut T { unsafe { (self as *const T).sub_ptr(origin) } } - /// Adds an offset to a pointer (convenience for `.offset(count as isize)`). + /// Adds an unsigned offset to a pointer. + /// + /// This can only move the pointer forward (or not move it). If you need to move forward or + /// backward depending on the value, then you might want [`offset`](#method.offset) instead + /// which takes a signed offset. /// /// `count` is in units of T; e.g., a `count` of 3 represents a pointer /// offset of `3 * size_of::()` bytes. @@ -897,7 +900,8 @@ impl *mut T { /// /// If any of the following conditions are violated, the result is Undefined Behavior: /// - /// * The computed offset, `count * size_of::()` bytes, must not overflow `isize`. + /// * The offset in bytes, `count * size_of::()`, computed on mathematical integers (without + /// "wrapping around"), must fit in an `isize`. /// /// * If the computed offset is non-zero, then `self` must be derived from a pointer to some /// [allocated object], and the entire memory range between `self` and the result must be in @@ -940,7 +944,7 @@ impl *mut T { unsafe { intrinsics::offset(self, count) } } - /// Calculates the offset from a pointer in bytes (convenience for `.byte_offset(count as isize)`). + /// Adds an unsigned offset in bytes to a pointer. /// /// `count` is in units of bytes. /// @@ -954,15 +958,17 @@ impl *mut T { #[inline(always)] #[stable(feature = "pointer_byte_offsets", since = "1.75.0")] #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "1.75.0")] - #[rustc_allow_const_fn_unstable(set_ptr_value)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn byte_add(self, count: usize) -> Self { // SAFETY: the caller must uphold the safety contract for `add`. unsafe { self.cast::().add(count).with_metadata_of(self) } } - /// Subtracts an offset from a pointer (convenience for - /// `.offset((count as isize).wrapping_neg())`). + /// Subtracts an unsigned offset from a pointer. + /// + /// This can only move the pointer backward (or not move it). If you need to move forward or + /// backward depending on the value, then you might want [`offset`](#method.offset) instead + /// which takes a signed offset. /// /// `count` is in units of T; e.g., a `count` of 3 represents a pointer /// offset of `3 * size_of::()` bytes. @@ -971,7 +977,8 @@ impl *mut T { /// /// If any of the following conditions are violated, the result is Undefined Behavior: /// - /// * The computed offset, `count * size_of::()` bytes, must not overflow `isize`. + /// * The offset in bytes, `count * size_of::()`, computed on mathematical integers (without + /// "wrapping around"), must fit in an `isize`. /// /// * If the computed offset is non-zero, then `self` must be derived from a pointer to some /// [allocated object], and the entire memory range between `self` and the result must be in @@ -1022,8 +1029,7 @@ impl *mut T { } } - /// Calculates the offset from a pointer in bytes (convenience for - /// `.byte_offset((count as isize).wrapping_neg())`). + /// Subtracts an unsigned offset in bytes from a pointer. /// /// `count` is in units of bytes. /// @@ -1037,15 +1043,13 @@ impl *mut T { #[inline(always)] #[stable(feature = "pointer_byte_offsets", since = "1.75.0")] #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "1.75.0")] - #[rustc_allow_const_fn_unstable(set_ptr_value)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn byte_sub(self, count: usize) -> Self { // SAFETY: the caller must uphold the safety contract for `sub`. unsafe { self.cast::().sub(count).with_metadata_of(self) } } - /// Calculates the offset from a pointer using wrapping arithmetic. - /// (convenience for `.wrapping_offset(count as isize)`) + /// Adds an unsigned offset to a pointer using wrapping arithmetic. /// /// `count` is in units of T; e.g., a `count` of 3 represents a pointer /// offset of `3 * size_of::()` bytes. @@ -1104,8 +1108,7 @@ impl *mut T { self.wrapping_offset(count as isize) } - /// Calculates the offset from a pointer in bytes using wrapping arithmetic. - /// (convenience for `.wrapping_byte_offset(count as isize)`) + /// Adds an unsigned offset in bytes to a pointer using wrapping arithmetic. /// /// `count` is in units of bytes. /// @@ -1118,13 +1121,11 @@ impl *mut T { #[inline(always)] #[stable(feature = "pointer_byte_offsets", since = "1.75.0")] #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "1.75.0")] - #[rustc_allow_const_fn_unstable(set_ptr_value)] pub const fn wrapping_byte_add(self, count: usize) -> Self { self.cast::().wrapping_add(count).with_metadata_of(self) } - /// Calculates the offset from a pointer using wrapping arithmetic. - /// (convenience for `.wrapping_offset((count as isize).wrapping_neg())`) + /// Subtracts an unsigned offset from a pointer using wrapping arithmetic. /// /// `count` is in units of T; e.g., a `count` of 3 represents a pointer /// offset of `3 * size_of::()` bytes. @@ -1183,8 +1184,7 @@ impl *mut T { self.wrapping_offset((count as isize).wrapping_neg()) } - /// Calculates the offset from a pointer in bytes using wrapping arithmetic. - /// (convenience for `.wrapping_offset((count as isize).wrapping_neg())`) + /// Subtracts an unsigned offset in bytes from a pointer using wrapping arithmetic. /// /// `count` is in units of bytes. /// @@ -1197,7 +1197,6 @@ impl *mut T { #[inline(always)] #[stable(feature = "pointer_byte_offsets", since = "1.75.0")] #[rustc_const_stable(feature = "const_pointer_byte_offsets", since = "1.75.0")] - #[rustc_allow_const_fn_unstable(set_ptr_value)] pub const fn wrapping_byte_sub(self, count: usize) -> Self { self.cast::().wrapping_sub(count).with_metadata_of(self) } @@ -1804,7 +1803,6 @@ impl *mut [T] { #[inline(always)] #[stable(feature = "slice_ptr_len", since = "1.79.0")] #[rustc_const_stable(feature = "const_slice_ptr_len", since = "1.79.0")] - #[rustc_allow_const_fn_unstable(ptr_metadata)] pub const fn len(self) -> usize { metadata(self) } diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index daa40b3c9d2e..e7a265f7e2b7 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -567,7 +567,6 @@ impl NonNull { #[must_use] #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - #[rustc_allow_const_fn_unstable(set_ptr_value)] #[stable(feature = "non_null_convenience", since = "1.80.0")] #[rustc_const_stable(feature = "non_null_convenience", since = "1.80.0")] pub const unsafe fn byte_add(self, count: usize) -> Self { @@ -651,7 +650,6 @@ impl NonNull { #[must_use] #[inline(always)] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces - #[rustc_allow_const_fn_unstable(set_ptr_value)] #[stable(feature = "non_null_convenience", since = "1.80.0")] #[rustc_const_stable(feature = "non_null_convenience", since = "1.80.0")] pub const unsafe fn byte_sub(self, count: usize) -> Self { diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index 1168f36da154..c5746157d01b 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -11,7 +11,7 @@ use crate::iter::{ use crate::marker::PhantomData; use crate::mem::{self, SizedTypeProperties}; use crate::num::NonZero; -use crate::ptr::{self, NonNull, without_provenance, without_provenance_mut}; +use crate::ptr::{NonNull, without_provenance, without_provenance_mut}; use crate::{cmp, fmt}; #[stable(feature = "boxed_slice_into_iter", since = "1.80.0")] diff --git a/library/core/src/slice/iter/macros.rs b/library/core/src/slice/iter/macros.rs index c2a381946441..830debe02ea2 100644 --- a/library/core/src/slice/iter/macros.rs +++ b/library/core/src/slice/iter/macros.rs @@ -14,11 +14,11 @@ macro_rules! if_zst { if T::IS_ZST { // SAFETY: for ZSTs, the pointer is storing a provenance-free length, // so consuming and updating it as a `usize` is fine. - let $len = unsafe { &mut *ptr::addr_of_mut!($this.end_or_len).cast::() }; + let $len = unsafe { &mut *(&raw mut $this.end_or_len).cast::() }; $zst_body } else { // SAFETY: for non-ZSTs, the type invariant ensures it cannot be null - let $end = unsafe { &mut *ptr::addr_of_mut!($this.end_or_len).cast::>() }; + let $end = unsafe { &mut *(&raw mut $this.end_or_len).cast::>() }; $other_body } }}; @@ -30,7 +30,7 @@ macro_rules! if_zst { $zst_body } else { // SAFETY: for non-ZSTs, the type invariant ensures it cannot be null - let $end = unsafe { *ptr::addr_of!($this.end_or_len).cast::>() }; + let $end = unsafe { *(&raw const $this.end_or_len).cast::>() }; $other_body } }}; diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 11c9f483f369..922168b9e8ef 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -111,7 +111,6 @@ impl [T] { #[lang = "slice_len_fn"] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "const_slice_len", since = "1.39.0")] - #[rustc_allow_const_fn_unstable(ptr_metadata)] #[inline] #[must_use] pub const fn len(&self) -> usize { @@ -883,8 +882,8 @@ impl [T] { pub const fn swap(&mut self, a: usize, b: usize) { // FIXME: use swap_unchecked here (https://github.com/rust-lang/rust/pull/88540#issuecomment-944344343) // Can't take two mutable loans from one vector, so instead use raw pointers. - let pa = ptr::addr_of_mut!(self[a]); - let pb = ptr::addr_of_mut!(self[b]); + let pa = &raw mut self[a]; + let pb = &raw mut self[b]; // SAFETY: `pa` and `pb` have been created from safe mutable references and refer // to elements in the slice and therefore are guaranteed to be valid and aligned. // Note that accessing the elements behind `a` and `b` is checked and will diff --git a/library/core/src/str/lossy.rs b/library/core/src/str/lossy.rs index 3f31107acf05..e7677c8317a9 100644 --- a/library/core/src/str/lossy.rs +++ b/library/core/src/str/lossy.rs @@ -8,6 +8,8 @@ impl [u8] { /// Creates an iterator over the contiguous valid UTF-8 ranges of this /// slice, and the non-UTF-8 fragments in between. /// + /// See the [`Utf8Chunk`] type for documenation of the items yielded by this iterator. + /// /// # Examples /// /// This function formats arbitrary but mostly-UTF-8 bytes into Rust source @@ -148,6 +150,8 @@ impl fmt::Debug for Debug<'_> { /// If you want a simple conversion from UTF-8 byte slices to string slices, /// [`from_utf8`] is easier to use. /// +/// See the [`Utf8Chunk`] type for documenation of the items yielded by this iterator. +/// /// [byteslice]: slice /// [`from_utf8`]: super::from_utf8 /// diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index b06a3bd4487d..42b68e28273e 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -24,25 +24,42 @@ //! //! ## Memory model for atomic accesses //! -//! Rust atomics currently follow the same rules as [C++20 atomics][cpp], specifically `atomic_ref`. -//! Basically, creating a *shared reference* to one of the Rust atomic types corresponds to creating -//! an `atomic_ref` in C++; the `atomic_ref` is destroyed when the lifetime of the shared reference -//! ends. A Rust atomic type that is exclusively owned or behind a mutable reference does *not* -//! correspond to an “atomic object” in C++, since the underlying primitive can be mutably accessed, -//! for example with `get_mut`, to perform non-atomic operations. +//! Rust atomics currently follow the same rules as [C++20 atomics][cpp], specifically the rules +//! from the [`intro.races`][cpp-intro.races] section, without the "consume" memory ordering. Since +//! C++ uses an object-based memory model whereas Rust is access-based, a bit of translation work +//! has to be done to apply the C++ rules to Rust: whenever C++ talks about "the value of an +//! object", we understand that to mean the resulting bytes obtained when doing a read. When the C++ +//! standard talks about "the value of an atomic object", this refers to the result of doing an +//! atomic load (via the operations provided in this module). A "modification of an atomic object" +//! refers to an atomic store. +//! +//! The end result is *almost* equivalent to saying that creating a *shared reference* to one of the +//! Rust atomic types corresponds to creating an `atomic_ref` in C++, with the `atomic_ref` being +//! destroyed when the lifetime of the shared reference ends. The main difference is that Rust +//! permits concurrent atomic and non-atomic reads to the same memory as those cause no issue in the +//! C++ memory model, they are just forbidden in C++ because memory is partitioned into "atomic +//! objects" and "non-atomic objects" (with `atomic_ref` temporarily converting a non-atomic object +//! into an atomic object). +//! +//! The most important aspect of this model is that *data races* are undefined behavior. A data race +//! is defined as conflicting non-synchronized accesses where at least one of the accesses is +//! non-atomic. Here, accesses are *conflicting* if they affect overlapping regions of memory and at +//! least one of them is a write. They are *non-synchronized* if neither of them *happens-before* +//! the other, according to the happens-before order of the memory model. +//! +//! The other possible cause of undefined behavior in the memory model are mixed-size accesses: Rust +//! inherits the C++ limitation that non-synchronized conflicting atomic accesses may not partially +//! overlap. In other words, every pair of non-synchronized atomic accesses must be either disjoint, +//! access the exact same memory (including using the same access size), or both be reads. +//! +//! Each atomic access takes an [`Ordering`] which defines how the operation interacts with the +//! happens-before order. These orderings behave the same as the corresponding [C++20 atomic +//! orderings][cpp_memory_order]. For more information, see the [nomicon]. //! //! [cpp]: https://en.cppreference.com/w/cpp/atomic -//! -//! Each method takes an [`Ordering`] which represents the strength of -//! the memory barrier for that operation. These orderings are the -//! same as the [C++20 atomic orderings][1]. For more information see the [nomicon][2]. -//! -//! [1]: https://en.cppreference.com/w/cpp/atomic/memory_order -//! [2]: ../../../nomicon/atomics.html -//! -//! Since C++ does not support mixing atomic and non-atomic accesses, or non-synchronized -//! different-sized accesses to the same data, Rust does not support those operations either. -//! Note that both of those restrictions only apply if the accesses are non-synchronized. +//! [cpp-intro.races]: https://timsong-cpp.github.io/cppwp/n4868/intro.multithread#intro.races +//! [cpp_memory_order]: https://en.cppreference.com/w/cpp/atomic/memory_order +//! [nomicon]: ../../../nomicon/atomics.html //! //! ```rust,no_run undefined_behavior //! use std::sync::atomic::{AtomicU16, AtomicU8, Ordering}; @@ -52,27 +69,29 @@ //! let atomic = AtomicU16::new(0); //! //! thread::scope(|s| { -//! // This is UB: mixing atomic and non-atomic accesses -//! s.spawn(|| atomic.store(1, Ordering::Relaxed)); -//! s.spawn(|| unsafe { atomic.as_ptr().write(2) }); +//! // This is UB: conflicting non-synchronized accesses, at least one of which is non-atomic. +//! s.spawn(|| atomic.store(1, Ordering::Relaxed)); // atomic store +//! s.spawn(|| unsafe { atomic.as_ptr().write(2) }); // non-atomic write //! }); //! //! thread::scope(|s| { -//! // This is UB: even reads are not allowed to be mixed -//! s.spawn(|| atomic.load(Ordering::Relaxed)); -//! s.spawn(|| unsafe { atomic.as_ptr().read() }); +//! // This is fine: the accesses do not conflict (as none of them performs any modification). +//! // In C++ this would be disallowed since creating an `atomic_ref` precludes +//! // further non-atomic accesses, but Rust does not have that limitation. +//! s.spawn(|| atomic.load(Ordering::Relaxed)); // atomic load +//! s.spawn(|| unsafe { atomic.as_ptr().read() }); // non-atomic read //! }); //! //! thread::scope(|s| { -//! // This is fine, `join` synchronizes the code in a way such that atomic -//! // and non-atomic accesses can't happen "at the same time" -//! let handle = s.spawn(|| atomic.store(1, Ordering::Relaxed)); -//! handle.join().unwrap(); -//! s.spawn(|| unsafe { atomic.as_ptr().write(2) }); +//! // This is fine: `join` synchronizes the code in a way such that the atomic +//! // store happens-before the non-atomic write. +//! let handle = s.spawn(|| atomic.store(1, Ordering::Relaxed)); // atomic store +//! handle.join().unwrap(); // synchronize +//! s.spawn(|| unsafe { atomic.as_ptr().write(2) }); // non-atomic write //! }); //! //! thread::scope(|s| { -//! // This is UB: using different-sized atomic accesses to the same data +//! // This is UB: non-synchronized conflicting differently-sized atomic accesses. //! s.spawn(|| atomic.store(1, Ordering::Relaxed)); //! s.spawn(|| unsafe { //! let differently_sized = transmute::<&AtomicU16, &AtomicU8>(&atomic); @@ -81,8 +100,8 @@ //! }); //! //! thread::scope(|s| { -//! // This is fine, `join` synchronizes the code in a way such that -//! // differently-sized accesses can't happen "at the same time" +//! // This is fine: `join` synchronizes the code in a way such that +//! // the 1-byte store happens-before the 2-byte store. //! let handle = s.spawn(|| atomic.store(1, Ordering::Relaxed)); //! handle.join().unwrap(); //! s.spawn(|| unsafe { @@ -137,7 +156,7 @@ //! //! # Atomic accesses to read-only memory //! -//! In general, *all* atomic accesses on read-only memory are Undefined Behavior. For instance, attempting +//! In general, *all* atomic accesses on read-only memory are undefined behavior. For instance, attempting //! to do a `compare_exchange` that will definitely fail (making it conceptually a read-only //! operation) can still cause a segmentation fault if the underlying memory page is mapped read-only. Since //! atomic `load`s might be implemented using compare-exchange operations, even a `load` can fault @@ -153,7 +172,7 @@ //! //! As an exception from the general rule stated above, "sufficiently small" atomic loads with //! `Ordering::Relaxed` are implemented in a way that works on read-only memory, and are hence not -//! Undefined Behavior. The exact size limit for what makes a load "sufficiently small" varies +//! undefined behavior. The exact size limit for what makes a load "sufficiently small" varies //! depending on the target: //! //! | `target_arch` | Size limit | @@ -577,7 +596,7 @@ impl AtomicBool { #[stable(feature = "atomic_access", since = "1.15.0")] #[rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0")] pub const fn into_inner(self) -> bool { - self.v.primitive_into_inner() != 0 + self.v.into_inner() != 0 } /// Loads a value from the bool. @@ -1394,7 +1413,7 @@ impl AtomicPtr { #[stable(feature = "atomic_access", since = "1.15.0")] #[rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0")] pub const fn into_inner(self) -> *mut T { - self.p.primitive_into_inner() + self.p.into_inner() } /// Loads a value from the pointer. @@ -2389,7 +2408,7 @@ macro_rules! atomic_int { #[$stable_access] #[rustc_const_stable(feature = "const_atomic_into_inner", since = "1.79.0")] pub const fn into_inner(self) -> $int_type { - self.v.primitive_into_inner() + self.v.into_inner() } /// Loads a value from the atomic integer. diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 604c0d487436..4f2190f78bf5 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -18,7 +18,6 @@ #![feature(const_align_offset)] #![feature(const_array_from_ref)] #![feature(const_black_box)] -#![feature(const_cell_into_inner)] #![feature(const_hash)] #![feature(const_heap)] #![feature(const_ip)] diff --git a/library/core/tests/macros.rs b/library/core/tests/macros.rs index 09994fbcbdb7..fdb4ea294128 100644 --- a/library/core/tests/macros.rs +++ b/library/core/tests/macros.rs @@ -1,3 +1,5 @@ +#![allow(unused_must_use)] + #[allow(dead_code)] trait Trait { fn blah(&self); @@ -173,3 +175,21 @@ fn cfg_match_two_functions() { bar2(); } } + +fn _accepts_expressions() -> i32 { + cfg_match! { + cfg(unix) => { 1 } + _ => { 2 } + } +} + +// The current implementation expands to a macro call, which allows the use of expression +// statements. +fn _allows_stmt_expr_attributes() { + let one = 1; + let two = 2; + cfg_match! { + cfg(unix) => { one * two; } + _ => { one + two; } + } +} diff --git a/library/panic_unwind/src/emcc.rs b/library/panic_unwind/src/emcc.rs index a4cbb1875d53..b986fc1c2a82 100644 --- a/library/panic_unwind/src/emcc.rs +++ b/library/panic_unwind/src/emcc.rs @@ -78,7 +78,7 @@ pub unsafe fn cleanup(ptr: *mut u8) -> Box { super::__rust_foreign_exception(); } - let canary = ptr::addr_of!((*adjusted_ptr).canary).read(); + let canary = (&raw const (*adjusted_ptr).canary).read(); if !ptr::eq(canary, &EXCEPTION_TYPE_INFO) { super::__rust_foreign_exception(); } diff --git a/library/panic_unwind/src/gcc.rs b/library/panic_unwind/src/gcc.rs index d8c1dcaaefe7..925af6c08322 100644 --- a/library/panic_unwind/src/gcc.rs +++ b/library/panic_unwind/src/gcc.rs @@ -92,7 +92,7 @@ pub unsafe fn cleanup(ptr: *mut u8) -> Box { let exception = exception.cast::(); // Just access the canary field, avoid accessing the entire `Exception` as // it can be a foreign Rust exception. - let canary = ptr::addr_of!((*exception).canary).read(); + let canary = (&raw const (*exception).canary).read(); if !ptr::eq(canary, &CANARY) { // A foreign Rust exception, treat it slightly differently from other // foreign exceptions, because call into `_Unwind_DeleteException` will @@ -107,4 +107,4 @@ pub unsafe fn cleanup(ptr: *mut u8) -> Box { // Rust's exception class identifier. This is used by personality routines to // determine whether the exception was thrown by their own runtime. -const RUST_EXCEPTION_CLASS: uw::_Unwind_Exception_Class = u64::from_be_bytes(*b"MOZ\0RUST"); +const RUST_EXCEPTION_CLASS: uw::_Unwind_Exception_Class = u64::from_ne_bytes(*b"MOZ\0RUST"); diff --git a/library/panic_unwind/src/seh.rs b/library/panic_unwind/src/seh.rs index 9e74a45a0e26..565a2b8c573b 100644 --- a/library/panic_unwind/src/seh.rs +++ b/library/panic_unwind/src/seh.rs @@ -50,7 +50,6 @@ use alloc::boxed::Box; use core::any::Any; use core::ffi::{c_int, c_uint, c_void}; use core::mem::{self, ManuallyDrop}; -use core::ptr::{addr_of, addr_of_mut}; // NOTE(nbdd0121): The `canary` field is part of stable ABI. #[repr(C)] @@ -131,8 +130,6 @@ mod imp { #[cfg(not(target_arch = "x86"))] mod imp { - use core::ptr::addr_of; - // On 64-bit systems, SEH represents pointers as 32-bit offsets from `__ImageBase`. #[repr(transparent)] #[derive(Copy, Clone)] @@ -157,7 +154,7 @@ mod imp { // going to be cross-lang LTOed anyway. However, using expose is shorter and // requires less unsafe. let addr: usize = ptr.expose_provenance(); - let image_base = addr_of!(__ImageBase).addr(); + let image_base = (&raw const __ImageBase).addr(); let offset: usize = addr - image_base; Self(offset as u32) } @@ -250,7 +247,7 @@ extern "C" { // This is fine since the MSVC runtime uses string comparison on the type name // to match TypeDescriptors rather than pointer equality. static mut TYPE_DESCRIPTOR: _TypeDescriptor = _TypeDescriptor { - pVFTable: addr_of!(TYPE_INFO_VTABLE) as *const _, + pVFTable: (&raw const TYPE_INFO_VTABLE) as *const _, spare: core::ptr::null_mut(), name: TYPE_NAME, }; @@ -304,8 +301,8 @@ pub unsafe fn panic(data: Box) -> u32 { // dropped when unwinding. Instead it will be dropped by exception_cleanup // which is invoked by the C++ runtime. let mut exception = - ManuallyDrop::new(Exception { canary: addr_of!(TYPE_DESCRIPTOR), data: Some(data) }); - let throw_ptr = addr_of_mut!(exception) as *mut _; + ManuallyDrop::new(Exception { canary: (&raw const TYPE_DESCRIPTOR), data: Some(data) }); + let throw_ptr = (&raw mut exception) as *mut _; // This... may seems surprising, and justifiably so. On 32-bit MSVC the // pointers between these structure are just that, pointers. On 64-bit MSVC, @@ -328,23 +325,23 @@ pub unsafe fn panic(data: Box) -> u32 { // In any case, we basically need to do something like this until we can // express more operations in statics (and we may never be able to). atomic_store_seqcst( - addr_of_mut!(THROW_INFO.pmfnUnwind).cast(), + (&raw mut THROW_INFO.pmfnUnwind).cast(), ptr_t::new(exception_cleanup as *mut u8).raw(), ); atomic_store_seqcst( - addr_of_mut!(THROW_INFO.pCatchableTypeArray).cast(), - ptr_t::new(addr_of_mut!(CATCHABLE_TYPE_ARRAY).cast()).raw(), + (&raw mut THROW_INFO.pCatchableTypeArray).cast(), + ptr_t::new((&raw mut CATCHABLE_TYPE_ARRAY).cast()).raw(), ); atomic_store_seqcst( - addr_of_mut!(CATCHABLE_TYPE_ARRAY.arrayOfCatchableTypes[0]).cast(), - ptr_t::new(addr_of_mut!(CATCHABLE_TYPE).cast()).raw(), + (&raw mut CATCHABLE_TYPE_ARRAY.arrayOfCatchableTypes[0]).cast(), + ptr_t::new((&raw mut CATCHABLE_TYPE).cast()).raw(), ); atomic_store_seqcst( - addr_of_mut!(CATCHABLE_TYPE.pType).cast(), - ptr_t::new(addr_of_mut!(TYPE_DESCRIPTOR).cast()).raw(), + (&raw mut CATCHABLE_TYPE.pType).cast(), + ptr_t::new((&raw mut TYPE_DESCRIPTOR).cast()).raw(), ); atomic_store_seqcst( - addr_of_mut!(CATCHABLE_TYPE.copyFunction).cast(), + (&raw mut CATCHABLE_TYPE.copyFunction).cast(), ptr_t::new(exception_copy as *mut u8).raw(), ); @@ -352,7 +349,7 @@ pub unsafe fn panic(data: Box) -> u32 { fn _CxxThrowException(pExceptionObject: *mut c_void, pThrowInfo: *mut u8) -> !; } - _CxxThrowException(throw_ptr, addr_of_mut!(THROW_INFO) as *mut _); + _CxxThrowException(throw_ptr, (&raw mut THROW_INFO) as *mut _); } pub unsafe fn cleanup(payload: *mut u8) -> Box { @@ -362,8 +359,8 @@ pub unsafe fn cleanup(payload: *mut u8) -> Box { super::__rust_foreign_exception(); } let exception = payload as *mut Exception; - let canary = addr_of!((*exception).canary).read(); - if !core::ptr::eq(canary, addr_of!(TYPE_DESCRIPTOR)) { + let canary = (&raw const (*exception).canary).read(); + if !core::ptr::eq(canary, &raw const TYPE_DESCRIPTOR) { // A foreign Rust exception. super::__rust_foreign_exception(); } diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index ea11586f9a51..63c65b8ef399 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -17,10 +17,10 @@ cfg-if = { version = "1.0", features = ['rustc-dep-of-std'] } panic_unwind = { path = "../panic_unwind", optional = true } panic_abort = { path = "../panic_abort" } core = { path = "../core", public = true } -compiler_builtins = { version = "0.1.125" } +compiler_builtins = { version = "0.1.130" } profiler_builtins = { path = "../profiler_builtins", optional = true } unwind = { path = "../unwind" } -hashbrown = { version = "0.14", default-features = false, features = [ +hashbrown = { version = "0.15", default-features = false, features = [ 'rustc-dep-of-std', ] } # FIXME(#127890): `object` depends on `memchr`, but `memchr` > v2.5 causes diff --git a/library/std/build.rs b/library/std/build.rs index 359ae4f20eea..7d37d4e9d7d8 100644 --- a/library/std/build.rs +++ b/library/std/build.rs @@ -96,30 +96,24 @@ fn main() { let has_reliable_f16 = match (target_arch.as_str(), target_os.as_str()) { // We can always enable these in Miri as that is not affected by codegen bugs. _ if is_miri => true, - // Selection failure until recent LLVM - // FIXME(llvm19): can probably be removed at the version bump - ("loongarch64", _) => false, // Selection failure ("s390x", _) => false, // Unsupported ("arm64ec", _) => false, // MinGW ABI bugs - ("x86_64", "windows") => false, - // Apple has a special ABI for `f16` that we do not yet support - // FIXME(builtins): fixed by - ("x86" | "x86_64", _) if target_vendor == "apple" => false, - // Missing `__gnu_h2f_ieee` and `__gnu_f2h_ieee` + ("x86_64", "windows") if target_env == "gnu" => false, + // Infinite recursion + ("csky", _) => false, + ("hexagon", _) => false, + ("loongarch64", _) => false, + ("mips" | "mips64" | "mips32r6" | "mips64r6", _) => false, ("powerpc" | "powerpc64", _) => false, - // Missing `__gnu_h2f_ieee` and `__gnu_f2h_ieee` - ("mips" | "mips32r6" | "mips64" | "mips64r6", _) => false, - // Missing `__extendhfsf` and `__truncsfhf` - ("riscv32" | "riscv64", _) => false, - // Most OSs are missing `__extendhfsf` and `__truncsfhf` - (_, "linux" | "macos") => true, - // Almost all OSs besides Linux and MacOS are missing symbols until compiler-builtins can - // be updated. will get some of these, the - // next CB update should get the rest. - _ => false, + ("sparc" | "sparc64", _) => false, + ("wasm32" | "wasm64", _) => false, + // `f16` support only requires that symbols converting to and from `f32` are available. We + // provide these in `compiler-builtins`, so `f16` should be available on all platforms that + // do not have other ABI issues or LLVM crashes. + _ => true, }; let has_reliable_f128 = match (target_arch.as_str(), target_os.as_str()) { @@ -135,10 +129,10 @@ fn main() { // ABI unsupported ("sparc", _) => false, // MinGW ABI bugs - ("x86_64", "windows") => false, + ("x86_64", "windows") if target_env == "gnu" => false, // 64-bit Linux is about the only platform to have f128 symbols by default (_, "linux") if target_pointer_width == 64 => true, - // Same as for f16, except MacOS is also missing f128 symbols. + // Almost all OSs are missing symbol. compiler-builtins will have to add them. _ => false, }; diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index 1a18721b15e9..6f2b4100620e 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -909,8 +909,11 @@ where /// Attempts to get mutable references to `N` values in the map at once. /// /// Returns an array of length `N` with the results of each query. For soundness, at most one - /// mutable reference will be returned to any value. `None` will be returned if any of the - /// keys are duplicates or missing. + /// mutable reference will be returned to any value. `None` will be used if the key is missing. + /// + /// # Panics + /// + /// Panics if any keys are overlapping. /// /// # Examples /// @@ -924,16 +927,23 @@ where /// libraries.insert("Herzogin-Anna-Amalia-Bibliothek".to_string(), 1691); /// libraries.insert("Library of Congress".to_string(), 1800); /// + /// // Get Athenæum and Bodleian Library + /// let [Some(a), Some(b)] = libraries.get_many_mut([ + /// "Athenæum", + /// "Bodleian Library", + /// ]) else { panic!() }; + /// + /// // Assert values of Athenæum and Library of Congress /// let got = libraries.get_many_mut([ /// "Athenæum", /// "Library of Congress", /// ]); /// assert_eq!( /// got, - /// Some([ - /// &mut 1807, - /// &mut 1800, - /// ]), + /// [ + /// Some(&mut 1807), + /// Some(&mut 1800), + /// ], /// ); /// /// // Missing keys result in None @@ -941,18 +951,31 @@ where /// "Athenæum", /// "New York Public Library", /// ]); - /// assert_eq!(got, None); + /// assert_eq!( + /// got, + /// [ + /// Some(&mut 1807), + /// None + /// ] + /// ); + /// ``` /// - /// // Duplicate keys result in None + /// ```should_panic + /// #![feature(map_many_mut)] + /// use std::collections::HashMap; + /// + /// let mut libraries = HashMap::new(); + /// libraries.insert("Athenæum".to_string(), 1807); + /// + /// // Duplicate keys panic! /// let got = libraries.get_many_mut([ /// "Athenæum", /// "Athenæum", /// ]); - /// assert_eq!(got, None); /// ``` #[inline] #[unstable(feature = "map_many_mut", issue = "97601")] - pub fn get_many_mut(&mut self, ks: [&Q; N]) -> Option<[&'_ mut V; N]> + pub fn get_many_mut(&mut self, ks: [&Q; N]) -> [Option<&'_ mut V>; N] where K: Borrow, Q: Hash + Eq, @@ -963,10 +986,10 @@ where /// Attempts to get mutable references to `N` values in the map at once, without validating that /// the values are unique. /// - /// Returns an array of length `N` with the results of each query. `None` will be returned if - /// any of the keys are missing. + /// Returns an array of length `N` with the results of each query. `None` will be used if + /// the key is missing. /// - /// For a safe alternative see [`get_many_mut`](Self::get_many_mut). + /// For a safe alternative see [`get_many_mut`](`HashMap::get_many_mut`). /// /// # Safety /// @@ -987,31 +1010,39 @@ where /// libraries.insert("Herzogin-Anna-Amalia-Bibliothek".to_string(), 1691); /// libraries.insert("Library of Congress".to_string(), 1800); /// - /// let got = libraries.get_many_mut([ + /// // SAFETY: The keys do not overlap. + /// let [Some(a), Some(b)] = (unsafe { libraries.get_many_unchecked_mut([ + /// "Athenæum", + /// "Bodleian Library", + /// ]) }) else { panic!() }; + /// + /// // SAFETY: The keys do not overlap. + /// let got = unsafe { libraries.get_many_unchecked_mut([ /// "Athenæum", /// "Library of Congress", - /// ]); + /// ]) }; /// assert_eq!( /// got, - /// Some([ - /// &mut 1807, - /// &mut 1800, - /// ]), + /// [ + /// Some(&mut 1807), + /// Some(&mut 1800), + /// ], /// ); /// - /// // Missing keys result in None - /// let got = libraries.get_many_mut([ + /// // SAFETY: The keys do not overlap. + /// let got = unsafe { libraries.get_many_unchecked_mut([ /// "Athenæum", /// "New York Public Library", - /// ]); - /// assert_eq!(got, None); + /// ]) }; + /// // Missing keys result in None + /// assert_eq!(got, [Some(&mut 1807), None]); /// ``` #[inline] #[unstable(feature = "map_many_mut", issue = "97601")] pub unsafe fn get_many_unchecked_mut( &mut self, ks: [&Q; N], - ) -> Option<[&'_ mut V; N]> + ) -> [Option<&'_ mut V>; N] where K: Borrow, Q: Hash + Eq, @@ -2978,64 +3009,6 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> { pub fn remove(self) -> V { self.base.remove() } - - /// Replaces the entry, returning the old key and value. The new key in the hash map will be - /// the key used to create this entry. - /// - /// # Examples - /// - /// ``` - /// #![feature(map_entry_replace)] - /// use std::collections::hash_map::{Entry, HashMap}; - /// use std::rc::Rc; - /// - /// let mut map: HashMap, u32> = HashMap::new(); - /// map.insert(Rc::new("Stringthing".to_string()), 15); - /// - /// let my_key = Rc::new("Stringthing".to_string()); - /// - /// if let Entry::Occupied(entry) = map.entry(my_key) { - /// // Also replace the key with a handle to our other key. - /// let (old_key, old_value): (Rc, u32) = entry.replace_entry(16); - /// } - /// - /// ``` - #[inline] - #[unstable(feature = "map_entry_replace", issue = "44286")] - pub fn replace_entry(self, value: V) -> (K, V) { - self.base.replace_entry(value) - } - - /// Replaces the key in the hash map with the key used to create this entry. - /// - /// # Examples - /// - /// ``` - /// #![feature(map_entry_replace)] - /// use std::collections::hash_map::{Entry, HashMap}; - /// use std::rc::Rc; - /// - /// let mut map: HashMap, u32> = HashMap::new(); - /// let known_strings: Vec> = Vec::new(); - /// - /// // Initialise known strings, run program, etc. - /// - /// reclaim_memory(&mut map, &known_strings); - /// - /// fn reclaim_memory(map: &mut HashMap, u32>, known_strings: &[Rc] ) { - /// for s in known_strings { - /// if let Entry::Occupied(entry) = map.entry(Rc::clone(s)) { - /// // Replaces the entry's key with our version of it in `known_strings`. - /// entry.replace_key(); - /// } - /// } - /// } - /// ``` - #[inline] - #[unstable(feature = "map_entry_replace", issue = "44286")] - pub fn replace_key(self) -> K { - self.base.replace_key() - } } impl<'a, K: 'a, V: 'a> VacantEntry<'a, K, V> { diff --git a/library/std/src/collections/hash/map/tests.rs b/library/std/src/collections/hash/map/tests.rs index c28dd7b6b505..fa8ea95b8914 100644 --- a/library/std/src/collections/hash/map/tests.rs +++ b/library/std/src/collections/hash/map/tests.rs @@ -274,7 +274,7 @@ fn test_lots_of_insertions() { for _ in 0..loops { assert!(m.is_empty()); - let count = if cfg!(miri) { 101 } else { 1001 }; + let count = if cfg!(miri) { 66 } else { 1001 }; for i in 1..count { assert!(m.insert(i, i).is_none()); @@ -1018,6 +1018,7 @@ mod test_extract_if { } #[test] + #[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn drop_panic_leak() { static PREDS: AtomicUsize = AtomicUsize::new(0); static DROPS: AtomicUsize = AtomicUsize::new(0); @@ -1047,6 +1048,7 @@ mod test_extract_if { } #[test] + #[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn pred_panic_leak() { static PREDS: AtomicUsize = AtomicUsize::new(0); static DROPS: AtomicUsize = AtomicUsize::new(0); @@ -1076,6 +1078,7 @@ mod test_extract_if { // Same as above, but attempt to use the iterator again after the panic in the predicate #[test] + #[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn pred_panic_reuse() { static PREDS: AtomicUsize = AtomicUsize::new(0); static DROPS: AtomicUsize = AtomicUsize::new(0); diff --git a/library/std/src/collections/hash/set.rs b/library/std/src/collections/hash/set.rs index 4a113ddea3a6..e69fb0878e7d 100644 --- a/library/std/src/collections/hash/set.rs +++ b/library/std/src/collections/hash/set.rs @@ -724,38 +724,6 @@ where self.base.get_or_insert(value) } - /// Inserts an owned copy of the given `value` into the set if it is not - /// present, then returns a reference to the value in the set. - /// - /// # Examples - /// - /// ``` - /// #![feature(hash_set_entry)] - /// - /// use std::collections::HashSet; - /// - /// let mut set: HashSet = ["cat", "dog", "horse"] - /// .iter().map(|&pet| pet.to_owned()).collect(); - /// - /// assert_eq!(set.len(), 3); - /// for &pet in &["cat", "dog", "fish"] { - /// let value = set.get_or_insert_owned(pet); - /// assert_eq!(value, pet); - /// } - /// assert_eq!(set.len(), 4); // a new "fish" was inserted - /// ``` - #[inline] - #[unstable(feature = "hash_set_entry", issue = "60896")] - pub fn get_or_insert_owned(&mut self, value: &Q) -> &T - where - T: Borrow, - Q: Hash + Eq + ToOwned, - { - // Although the raw entry gives us `&mut T`, we only return `&T` to be consistent with - // `get`. Key mutation is "raw" because you're not supposed to affect `Eq` or `Hash`. - self.base.get_or_insert_owned(value) - } - /// Inserts a value computed from `f` into the set if the given `value` is /// not present, then returns a reference to the value in the set. /// diff --git a/library/std/src/collections/hash/set/tests.rs b/library/std/src/collections/hash/set/tests.rs index 7aa2167e2132..8ee8a3e8bf6a 100644 --- a/library/std/src/collections/hash/set/tests.rs +++ b/library/std/src/collections/hash/set/tests.rs @@ -429,6 +429,7 @@ fn test_extract_if() { } #[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_extract_if_drop_panic_leak() { static PREDS: AtomicU32 = AtomicU32::new(0); static DROPS: AtomicU32 = AtomicU32::new(0); @@ -459,6 +460,7 @@ fn test_extract_if_drop_panic_leak() { } #[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_extract_if_pred_panic_leak() { static PREDS: AtomicU32 = AtomicU32::new(0); static DROPS: AtomicU32 = AtomicU32::new(0); diff --git a/library/std/src/env/tests.rs b/library/std/src/env/tests.rs index fc7aee297332..d02172610687 100644 --- a/library/std/src/env/tests.rs +++ b/library/std/src/env/tests.rs @@ -1,7 +1,7 @@ use super::*; #[test] -#[cfg_attr(any(target_os = "emscripten", target_env = "sgx"), ignore)] +#[cfg_attr(any(target_os = "emscripten", target_os = "wasi", target_env = "sgx"), ignore)] fn test_self_exe_path() { let path = current_exe(); assert!(path.is_ok()); diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index 0f905803bb8b..2243f100643d 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -9,7 +9,6 @@ use crate::borrow::{Borrow, Cow}; use crate::collections::TryReserveError; use crate::hash::{Hash, Hasher}; use crate::ops::{self, Range}; -use crate::ptr::addr_of_mut; use crate::rc::Rc; use crate::str::FromStr; use crate::sync::Arc; @@ -1272,7 +1271,7 @@ unsafe impl CloneToUninit for OsStr { #[cfg_attr(debug_assertions, track_caller)] unsafe fn clone_to_uninit(&self, dst: *mut Self) { // SAFETY: we're just a wrapper around a platform-specific Slice - unsafe { self.inner.clone_to_uninit(addr_of_mut!((*dst).inner)) } + unsafe { self.inner.clone_to_uninit(&raw mut (*dst).inner) } } } diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index db7867337dd5..124ef121b186 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -8,7 +8,15 @@ #![stable(feature = "rust1", since = "1.0.0")] #![deny(unsafe_op_in_unsafe_fn)] -#[cfg(all(test, not(any(target_os = "emscripten", target_env = "sgx", target_os = "xous"))))] +#[cfg(all( + test, + not(any( + target_os = "emscripten", + target_os = "wasi", + target_env = "sgx", + target_os = "xous" + )) +))] mod tests; use crate::ffi::OsString; diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs index 412603ddea3d..0672fe6f7718 100644 --- a/library/std/src/fs/tests.rs +++ b/library/std/src/fs/tests.rs @@ -1732,7 +1732,7 @@ fn windows_unix_socket_exists() { let bytes = core::slice::from_raw_parts(bytes.as_ptr().cast::(), bytes.len()); addr.sun_path[..bytes.len()].copy_from_slice(bytes); let len = mem::size_of_val(&addr) as i32; - let result = c::bind(socket, ptr::addr_of!(addr).cast::(), len); + let result = c::bind(socket, (&raw const addr).cast::(), len); c::closesocket(socket); assert_eq!(result, 0); } diff --git a/library/std/src/io/buffered/bufreader.rs b/library/std/src/io/buffered/bufreader.rs index fcb3e36027ba..8b46738ab8ae 100644 --- a/library/std/src/io/buffered/bufreader.rs +++ b/library/std/src/io/buffered/bufreader.rs @@ -357,7 +357,7 @@ impl Read for BufReader { let prev = cursor.written(); let mut rem = self.fill_buf()?; - rem.read_buf(cursor.reborrow())?; + rem.read_buf(cursor.reborrow())?; // actually never fails self.consume(cursor.written() - prev); //slice impl of read_buf known to never unfill buf diff --git a/library/std/src/io/buffered/bufreader/buffer.rs b/library/std/src/io/buffered/bufreader/buffer.rs index 3df7e3971dac..52fe49985c65 100644 --- a/library/std/src/io/buffered/bufreader/buffer.rs +++ b/library/std/src/io/buffered/bufreader/buffer.rs @@ -143,11 +143,13 @@ impl Buffer { buf.set_init(self.initialized); } - reader.read_buf(buf.unfilled())?; + let result = reader.read_buf(buf.unfilled()); self.pos = 0; self.filled = buf.len(); self.initialized = buf.init_len(); + + result?; } Ok(self.buffer()) } diff --git a/library/std/src/io/buffered/tests.rs b/library/std/src/io/buffered/tests.rs index d89ecd317d6e..bff0f823c4b5 100644 --- a/library/std/src/io/buffered/tests.rs +++ b/library/std/src/io/buffered/tests.rs @@ -164,6 +164,7 @@ fn test_buffered_reader_stream_position() { } #[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn test_buffered_reader_stream_position_panic() { let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4]; let mut reader = BufReader::with_capacity(4, io::Cursor::new(inner)); @@ -487,7 +488,7 @@ fn dont_panic_in_drop_on_panicked_flush() { } #[test] -#[cfg_attr(target_os = "emscripten", ignore)] +#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads fn panic_in_write_doesnt_flush_in_drop() { static WRITES: AtomicUsize = AtomicUsize::new(0); diff --git a/library/std/src/io/error/repr_bitpacked.rs b/library/std/src/io/error/repr_bitpacked.rs index 80ba8455df34..a839a2fbac11 100644 --- a/library/std/src/io/error/repr_bitpacked.rs +++ b/library/std/src/io/error/repr_bitpacked.rs @@ -124,6 +124,7 @@ const TAG_SIMPLE: usize = 0b11; /// is_unwind_safe::(); /// ``` #[repr(transparent)] +#[rustc_insignificant_dtor] pub(super) struct Repr(NonNull<()>, PhantomData>>); // All the types `Repr` stores internally are Send + Sync, and so is it. diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 0b57d01f2734..dd6458c38c6e 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -474,18 +474,28 @@ pub(crate) fn default_read_to_end( } let mut cursor = read_buf.unfilled(); - loop { + let result = loop { match r.read_buf(cursor.reborrow()) { - Ok(()) => break, Err(e) if e.is_interrupted() => continue, - Err(e) => return Err(e), + // Do not stop now in case of error: we might have received both data + // and an error + res => break res, } - } + }; let unfilled_but_initialized = cursor.init_ref().len(); let bytes_read = cursor.written(); let was_fully_initialized = read_buf.init_len() == buf_len; + // SAFETY: BorrowedBuf's invariants mean this much memory is initialized. + unsafe { + let new_len = bytes_read + buf.len(); + buf.set_len(new_len); + } + + // Now that all data is pushed to the vector, we can fail without data loss + result?; + if bytes_read == 0 { return Ok(buf.len() - start_len); } @@ -499,12 +509,6 @@ pub(crate) fn default_read_to_end( // store how much was initialized but not filled initialized = unfilled_but_initialized; - // SAFETY: BorrowedBuf's invariants mean this much memory is initialized. - unsafe { - let new_len = bytes_read + buf.len(); - buf.set_len(new_len); - } - // Use heuristics to determine the max read size if no initial size hint was provided if size_hint.is_none() { // The reader is returning short reads but it doesn't call ensure_init(). @@ -974,6 +978,8 @@ pub trait Read { /// with uninitialized buffers. The new data will be appended to any existing contents of `buf`. /// /// The default implementation delegates to `read`. + /// + /// This method makes it possible to return both data and an error but it is advised against. #[unstable(feature = "read_buf", issue = "78485")] fn read_buf(&mut self, buf: BorrowedCursor<'_>) -> Result<()> { default_read_buf(|b| self.read(b), buf) @@ -2941,7 +2947,7 @@ impl Read for Take { } let mut cursor = sliced_buf.unfilled(); - self.inner.read_buf(cursor.reborrow())?; + let result = self.inner.read_buf(cursor.reborrow()); let new_init = cursor.init_ref().len(); let filled = sliced_buf.len(); @@ -2956,13 +2962,14 @@ impl Read for Take { } self.limit -= filled as u64; + + result } else { let written = buf.written(); - self.inner.read_buf(buf.reborrow())?; + let result = self.inner.read_buf(buf.reborrow()); self.limit -= (buf.written() - written) as u64; + result } - - Ok(()) } } diff --git a/library/std/src/io/stdio/tests.rs b/library/std/src/io/stdio/tests.rs index ea76a271d12b..bf8f3a5adfb6 100644 --- a/library/std/src/io/stdio/tests.rs +++ b/library/std/src/io/stdio/tests.rs @@ -25,7 +25,7 @@ fn stderrlock_unwind_safe() { fn assert_unwind_safe() {} #[test] -#[cfg_attr(target_os = "emscripten", ignore)] +#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads fn panic_doesnt_poison() { thread::spawn(|| { let _a = stdin(); @@ -48,17 +48,17 @@ fn panic_doesnt_poison() { } #[test] -#[cfg_attr(target_os = "emscripten", ignore)] +#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads fn test_lock_stderr() { test_lock(stderr, || stderr().lock()); } #[test] -#[cfg_attr(target_os = "emscripten", ignore)] +#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads fn test_lock_stdin() { test_lock(stdin, || stdin().lock()); } #[test] -#[cfg_attr(target_os = "emscripten", ignore)] +#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads fn test_lock_stdout() { test_lock(stdout, || stdout().lock()); } diff --git a/library/std/src/io/tests.rs b/library/std/src/io/tests.rs index f551dcd401ef..56b71c47dc73 100644 --- a/library/std/src/io/tests.rs +++ b/library/std/src/io/tests.rs @@ -735,6 +735,69 @@ fn read_buf_full_read() { assert_eq!(BufReader::new(FullRead).fill_buf().unwrap().len(), DEFAULT_BUF_SIZE); } +struct DataAndErrorReader(&'static [u8]); + +impl Read for DataAndErrorReader { + fn read(&mut self, _buf: &mut [u8]) -> io::Result { + panic!("We want tests to use `read_buf`") + } + + fn read_buf(&mut self, buf: io::BorrowedCursor<'_>) -> io::Result<()> { + self.0.read_buf(buf).unwrap(); + Err(io::Error::other("error")) + } +} + +#[test] +fn read_buf_data_and_error_take() { + let mut buf = [0; 64]; + let mut buf = io::BorrowedBuf::from(buf.as_mut_slice()); + + let mut r = DataAndErrorReader(&[4, 5, 6]).take(1); + assert!(r.read_buf(buf.unfilled()).is_err()); + assert_eq!(buf.filled(), &[4]); + + assert!(r.read_buf(buf.unfilled()).is_ok()); + assert_eq!(buf.filled(), &[4]); + assert_eq!(r.get_ref().0, &[5, 6]); +} + +#[test] +fn read_buf_data_and_error_buf() { + let mut r = BufReader::new(DataAndErrorReader(&[4, 5, 6])); + + assert!(r.fill_buf().is_err()); + assert_eq!(r.fill_buf().unwrap(), &[4, 5, 6]); +} + +#[test] +fn read_buf_data_and_error_read_to_end() { + let mut r = DataAndErrorReader(&[4, 5, 6]); + + let mut v = Vec::with_capacity(200); + assert!(r.read_to_end(&mut v).is_err()); + + assert_eq!(v, &[4, 5, 6]); +} + +#[test] +fn read_to_end_error() { + struct ErrorReader; + + impl Read for ErrorReader { + fn read(&mut self, _buf: &mut [u8]) -> io::Result { + Err(io::Error::other("error")) + } + } + + let mut r = [4, 5, 6].chain(ErrorReader); + + let mut v = Vec::with_capacity(200); + assert!(r.read_to_end(&mut v).is_err()); + + assert_eq!(v, &[4, 5, 6]); +} + #[test] // Miri does not support signalling OOM #[cfg_attr(miri, ignore)] diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index b81e7c18abbb..65a9aa66c7cc 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -153,7 +153,7 @@ //! the [`io`], [`fs`], and [`net`] modules. //! //! The [`thread`] module contains Rust's threading abstractions. [`sync`] -//! contains further primitive shared memory types, including [`atomic`] and +//! contains further primitive shared memory types, including [`atomic`], [`mpmc`] and //! [`mpsc`], which contains the channel types for message passing. //! //! # Use before and after `main()` @@ -177,6 +177,7 @@ //! - after-main use of thread-locals, which also affects additional features: //! - [`thread::current()`] //! - [`thread::scope()`] +//! - [`sync::mpmc`] //! - [`sync::mpsc`] //! - before-main stdio file descriptors are not guaranteed to be open on unix platforms //! @@ -202,6 +203,7 @@ //! [`atomic`]: sync::atomic //! [`for`]: ../book/ch03-05-control-flow.html#looping-through-a-collection-with-for //! [`str`]: prim@str +//! [`mpmc`]: sync::mpmc //! [`mpsc`]: sync::mpsc //! [`std::cmp`]: cmp //! [`std::slice`]: mod@slice diff --git a/library/std/src/net/ip_addr.rs b/library/std/src/net/ip_addr.rs index 8a9426b61f99..4d673a1d66db 100644 --- a/library/std/src/net/ip_addr.rs +++ b/library/std/src/net/ip_addr.rs @@ -1,5 +1,5 @@ // Tests for this module -#[cfg(all(test, not(target_os = "emscripten")))] +#[cfg(all(test, not(any(target_os = "emscripten", all(target_os = "wasi", target_env = "p1")))))] mod tests; #[stable(feature = "ip_addr", since = "1.7.0")] diff --git a/library/std/src/net/socket_addr.rs b/library/std/src/net/socket_addr.rs index 84922aabdb56..ba9c948a2e96 100644 --- a/library/std/src/net/socket_addr.rs +++ b/library/std/src/net/socket_addr.rs @@ -1,5 +1,5 @@ // Tests for this module -#[cfg(all(test, not(target_os = "emscripten")))] +#[cfg(all(test, not(any(target_os = "emscripten", all(target_os = "wasi", target_env = "p1")))))] mod tests; #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/std/src/net/tcp.rs b/library/std/src/net/tcp.rs index 06ed4f6a03d4..67a0f7e439d5 100644 --- a/library/std/src/net/tcp.rs +++ b/library/std/src/net/tcp.rs @@ -1,6 +1,13 @@ #![deny(unsafe_op_in_unsafe_fn)] -#[cfg(all(test, not(any(target_os = "emscripten", target_os = "xous"))))] +#[cfg(all( + test, + not(any( + target_os = "emscripten", + all(target_os = "wasi", target_env = "p1"), + target_os = "xous" + )) +))] mod tests; use crate::fmt; @@ -561,7 +568,7 @@ impl TcpStream { /// Moves this TCP stream into or out of nonblocking mode. /// - /// This will result in `read`, `write`, `recv` and `send` operations + /// This will result in `read`, `write`, `recv` and `send` system operations /// becoming nonblocking, i.e., immediately returning from their calls. /// If the IO operation is successful, `Ok` is returned and no further /// action is required. If the IO operation could not be completed and needs diff --git a/library/std/src/net/tcp/tests.rs b/library/std/src/net/tcp/tests.rs index d26517d74e49..a7b5cdf4ec06 100644 --- a/library/std/src/net/tcp/tests.rs +++ b/library/std/src/net/tcp/tests.rs @@ -57,6 +57,7 @@ fn connect_timeout_error() { } #[test] +#[cfg_attr(target_os = "wasi", ignore)] // no threads fn listen_localhost() { let socket_addr = next_test_ip4(); let listener = t!(TcpListener::bind(&socket_addr)); @@ -73,6 +74,7 @@ fn listen_localhost() { } #[test] +#[cfg_attr(target_os = "wasi", ignore)] // no threads fn connect_loopback() { each_ip(&mut |addr| { let acceptor = t!(TcpListener::bind(&addr)); @@ -94,6 +96,7 @@ fn connect_loopback() { } #[test] +#[cfg_attr(target_os = "wasi", ignore)] // no threads fn smoke_test() { each_ip(&mut |addr| { let acceptor = t!(TcpListener::bind(&addr)); @@ -114,6 +117,7 @@ fn smoke_test() { } #[test] +#[cfg_attr(target_os = "wasi", ignore)] // no threads fn read_eof() { each_ip(&mut |addr| { let acceptor = t!(TcpListener::bind(&addr)); @@ -133,6 +137,7 @@ fn read_eof() { } #[test] +#[cfg_attr(target_os = "wasi", ignore)] // no threads fn write_close() { each_ip(&mut |addr| { let acceptor = t!(TcpListener::bind(&addr)); @@ -161,6 +166,7 @@ fn write_close() { } #[test] +#[cfg_attr(target_os = "wasi", ignore)] // no threads fn multiple_connect_serial() { each_ip(&mut |addr| { let max = 10; @@ -183,6 +189,7 @@ fn multiple_connect_serial() { } #[test] +#[cfg_attr(target_os = "wasi", ignore)] // no threads fn multiple_connect_interleaved_greedy_schedule() { const MAX: usize = 10; each_ip(&mut |addr| { @@ -220,6 +227,7 @@ fn multiple_connect_interleaved_greedy_schedule() { } #[test] +#[cfg_attr(target_os = "wasi", ignore)] // no threads fn multiple_connect_interleaved_lazy_schedule() { const MAX: usize = 10; each_ip(&mut |addr| { @@ -255,6 +263,7 @@ fn multiple_connect_interleaved_lazy_schedule() { } #[test] +#[cfg_attr(target_os = "wasi", ignore)] // no threads fn socket_and_peer_name() { each_ip(&mut |addr| { let listener = t!(TcpListener::bind(&addr)); @@ -270,6 +279,7 @@ fn socket_and_peer_name() { } #[test] +#[cfg_attr(target_os = "wasi", ignore)] // no threads fn partial_read() { each_ip(&mut |addr| { let (tx, rx) = channel(); @@ -291,6 +301,7 @@ fn partial_read() { } #[test] +#[cfg_attr(target_os = "wasi", ignore)] // no threads fn read_buf() { each_ip(&mut |addr| { let srv = t!(TcpListener::bind(&addr)); @@ -389,6 +400,7 @@ fn double_bind() { } #[test] +#[cfg_attr(target_os = "wasi", ignore)] // no threads fn tcp_clone_smoke() { each_ip(&mut |addr| { let acceptor = t!(TcpListener::bind(&addr)); @@ -420,6 +432,7 @@ fn tcp_clone_smoke() { } #[test] +#[cfg_attr(target_os = "wasi", ignore)] // no threads fn tcp_clone_two_read() { each_ip(&mut |addr| { let acceptor = t!(TcpListener::bind(&addr)); @@ -454,6 +467,7 @@ fn tcp_clone_two_read() { } #[test] +#[cfg_attr(target_os = "wasi", ignore)] // no threads fn tcp_clone_two_write() { each_ip(&mut |addr| { let acceptor = t!(TcpListener::bind(&addr)); @@ -483,6 +497,7 @@ fn tcp_clone_two_write() { #[test] // FIXME: https://github.com/fortanix/rust-sgx/issues/110 #[cfg_attr(target_env = "sgx", ignore)] +#[cfg_attr(target_os = "wasi", ignore)] // no threads fn shutdown_smoke() { each_ip(&mut |addr| { let a = t!(TcpListener::bind(&addr)); @@ -505,6 +520,7 @@ fn shutdown_smoke() { #[test] // FIXME: https://github.com/fortanix/rust-sgx/issues/110 #[cfg_attr(target_env = "sgx", ignore)] +#[cfg_attr(target_os = "wasi", ignore)] // no threads fn close_readwrite_smoke() { each_ip(&mut |addr| { let a = t!(TcpListener::bind(&addr)); @@ -547,6 +563,7 @@ fn close_readwrite_smoke() { #[cfg_attr(target_env = "sgx", ignore)] // On windows, shutdown will not wake up blocking I/O operations. #[cfg_attr(windows, ignore)] +#[cfg_attr(target_os = "wasi", ignore)] // no threads fn close_read_wakes_up() { each_ip(&mut |addr| { let listener = t!(TcpListener::bind(&addr)); @@ -574,6 +591,7 @@ fn close_read_wakes_up() { } #[test] +#[cfg_attr(target_os = "wasi", ignore)] // no threads fn clone_while_reading() { each_ip(&mut |addr| { let accept = t!(TcpListener::bind(&addr)); @@ -614,6 +632,7 @@ fn clone_while_reading() { } #[test] +#[cfg_attr(target_os = "wasi", ignore)] // no threads fn clone_accept_smoke() { each_ip(&mut |addr| { let a = t!(TcpListener::bind(&addr)); @@ -632,6 +651,7 @@ fn clone_accept_smoke() { } #[test] +#[cfg_attr(target_os = "wasi", ignore)] // no threads fn clone_accept_concurrent() { each_ip(&mut |addr| { let a = t!(TcpListener::bind(&addr)); @@ -670,10 +690,10 @@ fn debug() { addr.to_string() } + #[cfg(any(unix, target_os = "wasi"))] + use crate::os::fd::AsRawFd; #[cfg(target_env = "sgx")] use crate::os::fortanix_sgx::io::AsRawFd; - #[cfg(unix)] - use crate::os::unix::io::AsRawFd; #[cfg(not(windows))] fn render_inner(addr: &dyn AsRawFd) -> impl fmt::Debug { addr.as_raw_fd() @@ -714,6 +734,7 @@ fn debug() { ignore )] #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 +#[cfg_attr(target_os = "wasi", ignore)] // timeout not supported #[test] fn timeouts() { let addr = next_test_ip4(); @@ -742,6 +763,7 @@ fn timeouts() { #[test] #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 +#[cfg_attr(target_os = "wasi", ignore)] // timeout not supported fn test_read_timeout() { let addr = next_test_ip4(); let listener = t!(TcpListener::bind(&addr)); @@ -763,6 +785,7 @@ fn test_read_timeout() { #[test] #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 +#[cfg_attr(target_os = "wasi", ignore)] // timeout not supported fn test_read_with_timeout() { let addr = next_test_ip4(); let listener = t!(TcpListener::bind(&addr)); @@ -810,6 +833,7 @@ fn test_timeout_zero_duration() { #[test] #[cfg_attr(target_env = "sgx", ignore)] +#[cfg_attr(target_os = "wasi", ignore)] // linger not supported fn linger() { let addr = next_test_ip4(); let _listener = t!(TcpListener::bind(&addr)); @@ -879,6 +903,7 @@ fn set_nonblocking() { #[test] #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 +#[cfg_attr(target_os = "wasi", ignore)] // no threads fn peek() { each_ip(&mut |addr| { let (txdone, rxdone) = channel(); diff --git a/library/std/src/net/udp.rs b/library/std/src/net/udp.rs index d4252cb87ac2..6df47d7b0e0c 100644 --- a/library/std/src/net/udp.rs +++ b/library/std/src/net/udp.rs @@ -1,4 +1,12 @@ -#[cfg(all(test, not(any(target_os = "emscripten", target_env = "sgx", target_os = "xous"))))] +#[cfg(all( + test, + not(any( + target_os = "emscripten", + all(target_os = "wasi", target_env = "p1"), + target_env = "sgx", + target_os = "xous" + )) +))] mod tests; use crate::fmt; @@ -579,8 +587,8 @@ impl UdpSocket { /// This function specifies a new multicast group for this socket to join. /// The address must be a valid multicast address, and `interface` is the /// address of the local interface with which the system should join the - /// multicast group. If it's equal to `INADDR_ANY` then an appropriate - /// interface is chosen by the system. + /// multicast group. If it's equal to [`UNSPECIFIED`](Ipv4Addr::UNSPECIFIED) + /// then an appropriate interface is chosen by the system. #[stable(feature = "net2_mutators", since = "1.9.0")] pub fn join_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> { self.0.join_multicast_v4(multiaddr, interface) @@ -764,7 +772,7 @@ impl UdpSocket { /// Moves this UDP socket into or out of nonblocking mode. /// - /// This will result in `recv`, `recv_from`, `send`, and `send_to` + /// This will result in `recv`, `recv_from`, `send`, and `send_to` system /// operations becoming nonblocking, i.e., immediately returning from their /// calls. If the IO operation is successful, `Ok` is returned and no /// further action is required. If the IO operation could not be completed diff --git a/library/std/src/net/udp/tests.rs b/library/std/src/net/udp/tests.rs index 0cf993664529..1c8c58d18795 100644 --- a/library/std/src/net/udp/tests.rs +++ b/library/std/src/net/udp/tests.rs @@ -27,6 +27,7 @@ fn bind_error() { } #[test] +#[cfg_attr(target_os = "wasi", ignore)] // no threads fn socket_smoke_test_ip4() { each_ip(&mut |server_ip, client_ip| { let (tx1, rx1) = channel(); @@ -69,6 +70,7 @@ fn socket_peer() { } #[test] +#[cfg_attr(target_os = "wasi", ignore)] // no threads fn udp_clone_smoke() { each_ip(&mut |addr1, addr2| { let sock1 = t!(UdpSocket::bind(&addr1)); @@ -98,6 +100,7 @@ fn udp_clone_smoke() { } #[test] +#[cfg_attr(target_os = "wasi", ignore)] // no threads fn udp_clone_two_read() { each_ip(&mut |addr1, addr2| { let sock1 = t!(UdpSocket::bind(&addr1)); @@ -130,6 +133,7 @@ fn udp_clone_two_read() { } #[test] +#[cfg_attr(target_os = "wasi", ignore)] // no threads fn udp_clone_two_write() { each_ip(&mut |addr1, addr2| { let sock1 = t!(UdpSocket::bind(&addr1)); @@ -183,6 +187,7 @@ fn debug() { any(target_os = "netbsd", target_os = "openbsd", target_os = "vxworks", target_os = "nto"), ignore )] +#[cfg_attr(target_os = "wasi", ignore)] // timeout not supported #[test] fn timeouts() { let addr = next_test_ip4(); @@ -208,6 +213,7 @@ fn timeouts() { } #[test] +#[cfg_attr(target_os = "wasi", ignore)] // timeout not supported fn test_read_timeout() { let addr = next_test_ip4(); @@ -232,6 +238,7 @@ fn test_read_timeout() { } #[test] +#[cfg_attr(target_os = "wasi", ignore)] // timeout not supported fn test_read_with_timeout() { let addr = next_test_ip4(); @@ -291,6 +298,7 @@ fn connect_send_recv() { } #[test] +#[cfg_attr(target_os = "wasi", ignore)] // peek not supported fn connect_send_peek_recv() { each_ip(&mut |addr, _| { let socket = t!(UdpSocket::bind(&addr)); @@ -313,6 +321,7 @@ fn connect_send_peek_recv() { } #[test] +#[cfg_attr(target_os = "wasi", ignore)] // peek_from not supported fn peek_from() { each_ip(&mut |addr, _| { let socket = t!(UdpSocket::bind(&addr)); diff --git a/library/std/src/os/unix/net/addr.rs b/library/std/src/os/unix/net/addr.rs index 79f2c365025b..253e1503cf7a 100644 --- a/library/std/src/os/unix/net/addr.rs +++ b/library/std/src/os/unix/net/addr.rs @@ -15,15 +15,12 @@ mod libc { pub type socklen_t = u32; pub struct sockaddr; #[derive(Clone)] - pub struct sockaddr_un; + pub struct sockaddr_un { + pub sun_path: [u8; 1], + } } -fn sun_path_offset(addr: &libc::sockaddr_un) -> usize { - // Work with an actual instance of the type since using a null pointer is UB - let base = (addr as *const libc::sockaddr_un).addr(); - let path = core::ptr::addr_of!(addr.sun_path).addr(); - path - base -} +const SUN_PATH_OFFSET: usize = mem::offset_of!(libc::sockaddr_un, sun_path); pub(super) fn sockaddr_un(path: &Path) -> io::Result<(libc::sockaddr_un, libc::socklen_t)> { // SAFETY: All zeros is a valid representation for `sockaddr_un`. @@ -53,7 +50,7 @@ pub(super) fn sockaddr_un(path: &Path) -> io::Result<(libc::sockaddr_un, libc::s ptr::copy_nonoverlapping(bytes.as_ptr(), addr.sun_path.as_mut_ptr().cast(), bytes.len()) }; - let mut len = sun_path_offset(&addr) + bytes.len(); + let mut len = SUN_PATH_OFFSET + bytes.len(); match bytes.get(0) { Some(&0) | None => {} Some(_) => len += 1, @@ -98,7 +95,7 @@ impl SocketAddr { unsafe { let mut addr: libc::sockaddr_un = mem::zeroed(); let mut len = mem::size_of::() as libc::socklen_t; - cvt(f(core::ptr::addr_of_mut!(addr) as *mut _, &mut len))?; + cvt(f((&raw mut addr) as *mut _, &mut len))?; SocketAddr::from_parts(addr, len) } } @@ -114,13 +111,13 @@ impl SocketAddr { let sun_path: &[u8] = unsafe { mem::transmute::<&[libc::c_char], &[u8]>(&addr.sun_path) }; len = core::slice::memchr::memchr(0, sun_path) - .map_or(len, |new_len| (new_len + sun_path_offset(&addr)) as libc::socklen_t); + .map_or(len, |new_len| (new_len + SUN_PATH_OFFSET) as libc::socklen_t); } if len == 0 { // When there is a datagram from unnamed unix socket // linux returns zero bytes of address - len = sun_path_offset(&addr) as libc::socklen_t; // i.e., zero-length address + len = SUN_PATH_OFFSET as libc::socklen_t; // i.e., zero-length address } else if addr.sun_family != libc::AF_UNIX as libc::sa_family_t { return Err(io::const_io_error!( io::ErrorKind::InvalidInput, @@ -238,7 +235,7 @@ impl SocketAddr { } fn address(&self) -> AddressKind<'_> { - let len = self.len as usize - sun_path_offset(&self.addr); + let len = self.len as usize - SUN_PATH_OFFSET; let path = unsafe { mem::transmute::<&[libc::c_char], &[u8]>(&self.addr.sun_path) }; // macOS seems to return a len of 16 and a zeroed sun_path for unnamed addresses @@ -287,7 +284,7 @@ impl linux_ext::addr::SocketAddrExt for SocketAddr { addr.sun_path.as_mut_ptr().add(1) as *mut u8, name.len(), ); - let len = (sun_path_offset(&addr) + 1 + name.len()) as libc::socklen_t; + let len = (SUN_PATH_OFFSET + 1 + name.len()) as libc::socklen_t; SocketAddr::from_parts(addr, len) } } diff --git a/library/std/src/os/unix/net/ancillary.rs b/library/std/src/os/unix/net/ancillary.rs index c34a3b4e184a..36967fc3f98b 100644 --- a/library/std/src/os/unix/net/ancillary.rs +++ b/library/std/src/os/unix/net/ancillary.rs @@ -37,7 +37,7 @@ pub(super) fn recv_vectored_with_ancillary_from( unsafe { let mut msg_name: libc::sockaddr_un = zeroed(); let mut msg: libc::msghdr = zeroed(); - msg.msg_name = core::ptr::addr_of_mut!(msg_name) as *mut _; + msg.msg_name = (&raw mut msg_name) as *mut _; msg.msg_namelen = size_of::() as libc::socklen_t; msg.msg_iov = bufs.as_mut_ptr().cast(); msg.msg_iovlen = bufs.len() as _; @@ -70,7 +70,7 @@ pub(super) fn send_vectored_with_ancillary_to( if let Some(path) = path { sockaddr_un(path)? } else { (zeroed(), 0) }; let mut msg: libc::msghdr = zeroed(); - msg.msg_name = core::ptr::addr_of_mut!(msg_name) as *mut _; + msg.msg_name = (&raw mut msg_name) as *mut _; msg.msg_namelen = msg_namelen; msg.msg_iov = bufs.as_ptr() as *mut _; msg.msg_iovlen = bufs.len() as _; diff --git a/library/std/src/os/unix/net/datagram.rs b/library/std/src/os/unix/net/datagram.rs index 48aaddd2d529..82446ea107fe 100644 --- a/library/std/src/os/unix/net/datagram.rs +++ b/library/std/src/os/unix/net/datagram.rs @@ -100,7 +100,7 @@ impl UnixDatagram { let socket = UnixDatagram::unbound()?; let (addr, len) = sockaddr_un(path.as_ref())?; - cvt(libc::bind(socket.as_raw_fd(), core::ptr::addr_of!(addr) as *const _, len as _))?; + cvt(libc::bind(socket.as_raw_fd(), (&raw const addr) as *const _, len as _))?; Ok(socket) } @@ -133,7 +133,7 @@ impl UnixDatagram { let socket = UnixDatagram::unbound()?; cvt(libc::bind( socket.as_raw_fd(), - core::ptr::addr_of!(socket_addr.addr) as *const _, + (&raw const socket_addr.addr) as *const _, socket_addr.len as _, ))?; Ok(socket) @@ -215,7 +215,7 @@ impl UnixDatagram { unsafe { let (addr, len) = sockaddr_un(path.as_ref())?; - cvt(libc::connect(self.as_raw_fd(), core::ptr::addr_of!(addr) as *const _, len))?; + cvt(libc::connect(self.as_raw_fd(), (&raw const addr) as *const _, len))?; } Ok(()) } @@ -247,7 +247,7 @@ impl UnixDatagram { unsafe { cvt(libc::connect( self.as_raw_fd(), - core::ptr::addr_of!(socket_addr.addr) as *const _, + (&raw const socket_addr.addr) as *const _, socket_addr.len, ))?; } @@ -514,7 +514,7 @@ impl UnixDatagram { buf.as_ptr() as *const _, buf.len(), MSG_NOSIGNAL, - core::ptr::addr_of!(addr) as *const _, + (&raw const addr) as *const _, len, ))?; Ok(count as usize) @@ -549,7 +549,7 @@ impl UnixDatagram { buf.as_ptr() as *const _, buf.len(), MSG_NOSIGNAL, - core::ptr::addr_of!(socket_addr.addr) as *const _, + (&raw const socket_addr.addr) as *const _, socket_addr.len, ))?; Ok(count as usize) diff --git a/library/std/src/os/unix/net/listener.rs b/library/std/src/os/unix/net/listener.rs index 440408eb13fa..be236317d047 100644 --- a/library/std/src/os/unix/net/listener.rs +++ b/library/std/src/os/unix/net/listener.rs @@ -103,11 +103,7 @@ impl UnixListener { )))] const backlog: libc::c_int = libc::SOMAXCONN; - cvt(libc::bind( - inner.as_inner().as_raw_fd(), - core::ptr::addr_of!(addr) as *const _, - len as _, - ))?; + cvt(libc::bind(inner.as_inner().as_raw_fd(), (&raw const addr) as *const _, len as _))?; cvt(libc::listen(inner.as_inner().as_raw_fd(), backlog))?; Ok(UnixListener(inner)) @@ -147,7 +143,7 @@ impl UnixListener { const backlog: core::ffi::c_int = 128; cvt(libc::bind( inner.as_raw_fd(), - core::ptr::addr_of!(socket_addr.addr) as *const _, + (&raw const socket_addr.addr) as *const _, socket_addr.len as _, ))?; cvt(libc::listen(inner.as_raw_fd(), backlog))?; @@ -182,7 +178,7 @@ impl UnixListener { pub fn accept(&self) -> io::Result<(UnixStream, SocketAddr)> { let mut storage: libc::sockaddr_un = unsafe { mem::zeroed() }; let mut len = mem::size_of_val(&storage) as libc::socklen_t; - let sock = self.0.accept(core::ptr::addr_of_mut!(storage) as *mut _, &mut len)?; + let sock = self.0.accept((&raw mut storage) as *mut _, &mut len)?; let addr = SocketAddr::from_parts(storage, len)?; Ok((UnixStream(sock), addr)) } diff --git a/library/std/src/os/unix/net/stream.rs b/library/std/src/os/unix/net/stream.rs index 4967c5b89ecc..cb210b41eae1 100644 --- a/library/std/src/os/unix/net/stream.rs +++ b/library/std/src/os/unix/net/stream.rs @@ -84,7 +84,7 @@ impl UnixStream { let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; let (addr, len) = sockaddr_un(path.as_ref())?; - cvt(libc::connect(inner.as_raw_fd(), core::ptr::addr_of!(addr) as *const _, len))?; + cvt(libc::connect(inner.as_raw_fd(), (&raw const addr) as *const _, len))?; Ok(UnixStream(inner)) } } @@ -118,7 +118,7 @@ impl UnixStream { let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; cvt(libc::connect( inner.as_raw_fd(), - core::ptr::addr_of!(socket_addr.addr) as *const _, + (&raw const socket_addr.addr) as *const _, socket_addr.len, ))?; Ok(UnixStream(inner)) diff --git a/library/std/src/os/unix/net/ucred.rs b/library/std/src/os/unix/net/ucred.rs index c818bd058586..e1014a4f296d 100644 --- a/library/std/src/os/unix/net/ucred.rs +++ b/library/std/src/os/unix/net/ucred.rs @@ -60,7 +60,7 @@ mod impl_linux { socket.as_raw_fd(), SOL_SOCKET, SO_PEERCRED, - core::ptr::addr_of_mut!(ucred) as *mut c_void, + (&raw mut ucred) as *mut c_void, &mut ucred_size, ); @@ -121,7 +121,7 @@ mod impl_apple { socket.as_raw_fd(), SOL_LOCAL, LOCAL_PEERPID, - core::ptr::addr_of_mut!(pid) as *mut c_void, + (&raw mut pid) as *mut c_void, &mut pid_size, ); diff --git a/library/std/src/panic.rs b/library/std/src/panic.rs index 015cab894854..d649357a56d7 100644 --- a/library/std/src/panic.rs +++ b/library/std/src/panic.rs @@ -288,45 +288,55 @@ pub use core::panic::abort_unwind; /// Invokes a closure, capturing the cause of an unwinding panic if one occurs. /// -/// This function will return `Ok` with the closure's result if the closure -/// does not panic, and will return `Err(cause)` if the closure panics. The -/// `cause` returned is the object with which panic was originally invoked. +/// This function will return `Ok` with the closure's result if the closure does +/// not panic, and will return `Err(cause)` if the closure panics. The `cause` +/// returned is the object with which panic was originally invoked. /// -/// It is currently undefined behavior to unwind from Rust code into foreign -/// code, so this function is particularly useful when Rust is called from -/// another language (normally C). This can run arbitrary Rust code, capturing a -/// panic and allowing a graceful handling of the error. +/// Rust functions that are expected to be called from foreign code that does +/// not support unwinding (such as C compiled with `-fno-exceptions`) should be +/// defined using `extern "C"`, which ensures that if the Rust code panics, it +/// is automatically caught and the process is aborted. If this is the desired +/// behavior, it is not necessary to use `catch_unwind` explicitly. This +/// function should instead be used when more graceful error-handling is needed. /// /// It is **not** recommended to use this function for a general try/catch /// mechanism. The [`Result`] type is more appropriate to use for functions that /// can fail on a regular basis. Additionally, this function is not guaranteed /// to catch all panics, see the "Notes" section below. /// -/// The closure provided is required to adhere to the [`UnwindSafe`] trait to ensure -/// that all captured variables are safe to cross this boundary. The purpose of -/// this bound is to encode the concept of [exception safety][rfc] in the type -/// system. Most usage of this function should not need to worry about this -/// bound as programs are naturally unwind safe without `unsafe` code. If it -/// becomes a problem the [`AssertUnwindSafe`] wrapper struct can be used to quickly -/// assert that the usage here is indeed unwind safe. +/// The closure provided is required to adhere to the [`UnwindSafe`] trait to +/// ensure that all captured variables are safe to cross this boundary. The +/// purpose of this bound is to encode the concept of [exception safety][rfc] in +/// the type system. Most usage of this function should not need to worry about +/// this bound as programs are naturally unwind safe without `unsafe` code. If +/// it becomes a problem the [`AssertUnwindSafe`] wrapper struct can be used to +/// quickly assert that the usage here is indeed unwind safe. /// /// [rfc]: https://github.com/rust-lang/rfcs/blob/master/text/1236-stabilize-catch-panic.md /// /// # Notes /// -/// Note that this function **might not catch all panics** in Rust. A panic in -/// Rust is not always implemented via unwinding, but can be implemented by -/// aborting the process as well. This function *only* catches unwinding panics, -/// not those that abort the process. +/// This function **might not catch all Rust panics**. A Rust panic is not +/// always implemented via unwinding, but can be implemented by aborting the +/// process as well. This function *only* catches unwinding panics, not those +/// that abort the process. /// -/// Note that if a custom panic hook has been set, it will be invoked before -/// the panic is caught, before unwinding. +/// If a custom panic hook has been set, it will be invoked before the panic is +/// caught, before unwinding. /// -/// Also note that unwinding into Rust code with a foreign exception (e.g. -/// an exception thrown from C++ code) is undefined behavior. +/// Although unwinding into Rust code with a foreign exception (e.g. an +/// exception thrown from C++ code, or a `panic!` in Rust code compiled or +/// linked with a different runtime) via an appropriate ABI (e.g. `"C-unwind"`) +/// is permitted, catching such an exception using this function will have one +/// of two behaviors, and it is unspecified which will occur: /// -/// Finally, be **careful in how you drop the result of this function**. -/// If it is `Err`, it contains the panic payload, and dropping that may in turn panic! +/// * The process aborts, after executing all destructors of `f` and the +/// functions it called. +/// * The function returns a `Result::Err` containing an opaque type. +/// +/// Finally, be **careful in how you drop the result of this function**. If it +/// is `Err`, it contains the panic payload, and dropping that may in turn +/// panic! /// /// # Examples /// diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs index 336e34d7b95e..ac1f547c9143 100644 --- a/library/std/src/panicking.rs +++ b/library/std/src/panicking.rs @@ -23,8 +23,8 @@ use crate::mem::{self, ManuallyDrop}; use crate::panic::{BacktraceStyle, PanicHookInfo}; use crate::sync::atomic::{AtomicBool, Ordering}; use crate::sync::{PoisonError, RwLock}; +use crate::sys::backtrace; use crate::sys::stdio::panic_output; -use crate::sys::{backtrace, dbg}; use crate::{fmt, intrinsics, process, thread}; // Binary interface to the panic runtime that the standard library depends on. @@ -506,7 +506,7 @@ pub unsafe fn r#try R>(f: F) -> Result> // method of calling a catch panic whilst juggling ownership. let mut data = Data { f: ManuallyDrop::new(f) }; - let data_ptr = core::ptr::addr_of_mut!(data) as *mut u8; + let data_ptr = (&raw mut data) as *mut u8; // SAFETY: // // Access to the union's fields: this is `std` and we know that the `r#try` @@ -859,14 +859,6 @@ pub fn rust_panic_without_hook(payload: Box) -> ! { #[cfg_attr(not(test), rustc_std_internal_symbol)] #[cfg(not(feature = "panic_immediate_abort"))] fn rust_panic(msg: &mut dyn PanicPayload) -> ! { - // Break into the debugger if it is attached. - // The return value is not currently used. - // - // This function isn't used anywhere else, and - // using inside `#[panic_handler]` doesn't seem - // to count, so a warning is issued. - let _ = dbg::breakpoint_if_debugging(); - let code = unsafe { __rust_start_panic(msg) }; rtabort!("failed to initiate panic, error {code}") } @@ -874,14 +866,6 @@ fn rust_panic(msg: &mut dyn PanicPayload) -> ! { #[cfg_attr(not(test), rustc_std_internal_symbol)] #[cfg(feature = "panic_immediate_abort")] fn rust_panic(_: &mut dyn PanicPayload) -> ! { - // Break into the debugger if it is attached. - // The return value is not currently used. - // - // This function isn't used anywhere else, and - // using inside `#[panic_handler]` doesn't seem - // to count, so a warning is issued. - let _ = dbg::breakpoint_if_debugging(); - unsafe { crate::intrinsics::abort(); } diff --git a/library/std/src/path.rs b/library/std/src/path.rs index e3ff7d199ccc..63edfdb82f36 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -3144,7 +3144,7 @@ unsafe impl CloneToUninit for Path { #[cfg_attr(debug_assertions, track_caller)] unsafe fn clone_to_uninit(&self, dst: *mut Self) { // SAFETY: Path is just a wrapper around OsStr - unsafe { self.inner.clone_to_uninit(core::ptr::addr_of_mut!((*dst).inner)) } + unsafe { self.inner.clone_to_uninit(&raw mut (*dst).inner) } } } diff --git a/library/std/src/path/tests.rs b/library/std/src/path/tests.rs index 6436872087d6..b75793d2bc99 100644 --- a/library/std/src/path/tests.rs +++ b/library/std/src/path/tests.rs @@ -139,7 +139,7 @@ fn test_pathbuf_leak() { } #[test] -#[cfg(unix)] +#[cfg(any(unix, target_os = "wasi"))] pub fn test_decompositions_unix() { t!("", iter: [], @@ -1201,7 +1201,10 @@ pub fn test_push() { }); ); - if cfg!(unix) || cfg!(all(target_env = "sgx", target_vendor = "fortanix")) { + if cfg!(unix) + || cfg!(target_os = "wasi") + || cfg!(all(target_env = "sgx", target_vendor = "fortanix")) + { tp!("", "foo", "foo"); tp!("foo", "bar", "foo/bar"); tp!("foo/", "bar", "foo/bar"); @@ -1358,7 +1361,10 @@ pub fn test_set_file_name() { tfn!("foo", "bar", "bar"); tfn!("foo", "", ""); tfn!("", "foo", "foo"); - if cfg!(unix) || cfg!(all(target_env = "sgx", target_vendor = "fortanix")) { + if cfg!(unix) + || cfg!(target_os = "wasi") + || cfg!(all(target_env = "sgx", target_vendor = "fortanix")) + { tfn!(".", "foo", "./foo"); tfn!("foo/", "bar", "bar"); tfn!("foo/.", "bar", "bar"); @@ -1758,7 +1764,7 @@ fn test_components_debug() { assert_eq!(expected, actual); } -#[cfg(unix)] +#[cfg(any(unix, target_os = "wasi"))] #[test] fn test_iter_debug() { let path = Path::new("/tmp"); @@ -1859,7 +1865,7 @@ fn test_ord() { } #[test] -#[cfg(unix)] +#[cfg(any(unix, target_os = "wasi"))] fn test_unix_absolute() { use crate::path::absolute; diff --git a/library/std/src/process.rs b/library/std/src/process.rs index c84a5c652639..f24fe353e55b 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -148,7 +148,15 @@ #![stable(feature = "process", since = "1.0.0")] #![deny(unsafe_op_in_unsafe_fn)] -#[cfg(all(test, not(any(target_os = "emscripten", target_env = "sgx", target_os = "xous"))))] +#[cfg(all( + test, + not(any( + target_os = "emscripten", + target_os = "wasi", + target_env = "sgx", + target_os = "xous" + )) +))] mod tests; use crate::convert::Infallible; diff --git a/library/std/src/sync/barrier/tests.rs b/library/std/src/sync/barrier/tests.rs index c5620cd91d85..0fbcd9988127 100644 --- a/library/std/src/sync/barrier/tests.rs +++ b/library/std/src/sync/barrier/tests.rs @@ -3,7 +3,7 @@ use crate::sync::{Arc, Barrier}; use crate::thread; #[test] -#[cfg_attr(target_os = "emscripten", ignore)] +#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads fn test_barrier() { const N: usize = 10; diff --git a/library/std/src/sync/condvar/tests.rs b/library/std/src/sync/condvar/tests.rs index 12d13a6b20be..f9e9066bc92a 100644 --- a/library/std/src/sync/condvar/tests.rs +++ b/library/std/src/sync/condvar/tests.rs @@ -12,7 +12,7 @@ fn smoke() { } #[test] -#[cfg_attr(target_os = "emscripten", ignore)] +#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads fn notify_one() { let m = Arc::new(Mutex::new(())); let m2 = m.clone(); @@ -29,7 +29,7 @@ fn notify_one() { } #[test] -#[cfg_attr(target_os = "emscripten", ignore)] +#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads fn notify_all() { const N: usize = 10; @@ -66,7 +66,7 @@ fn notify_all() { } #[test] -#[cfg_attr(target_os = "emscripten", ignore)] +#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads fn wait_while() { let pair = Arc::new((Mutex::new(false), Condvar::new())); let pair2 = pair.clone(); @@ -87,7 +87,7 @@ fn wait_while() { } #[test] -#[cfg_attr(target_os = "emscripten", ignore)] +#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // condvar wait not supported fn wait_timeout_wait() { let m = Arc::new(Mutex::new(())); let c = Arc::new(Condvar::new()); @@ -106,7 +106,7 @@ fn wait_timeout_wait() { } #[test] -#[cfg_attr(target_os = "emscripten", ignore)] +#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // condvar wait not supported fn wait_timeout_while_wait() { let m = Arc::new(Mutex::new(())); let c = Arc::new(Condvar::new()); @@ -118,7 +118,7 @@ fn wait_timeout_while_wait() { } #[test] -#[cfg_attr(target_os = "emscripten", ignore)] +#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // condvar wait not supported fn wait_timeout_while_instant_satisfy() { let m = Arc::new(Mutex::new(())); let c = Arc::new(Condvar::new()); @@ -130,7 +130,7 @@ fn wait_timeout_while_instant_satisfy() { } #[test] -#[cfg_attr(target_os = "emscripten", ignore)] +#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads fn wait_timeout_while_wake() { let pair = Arc::new((Mutex::new(false), Condvar::new())); let pair_copy = pair.clone(); @@ -153,7 +153,7 @@ fn wait_timeout_while_wake() { } #[test] -#[cfg_attr(target_os = "emscripten", ignore)] +#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads fn wait_timeout_wake() { let m = Arc::new(Mutex::new(())); let c = Arc::new(Condvar::new()); diff --git a/library/std/src/sync/lazy_lock/tests.rs b/library/std/src/sync/lazy_lock/tests.rs index 94044368305b..7d7dde543499 100644 --- a/library/std/src/sync/lazy_lock/tests.rs +++ b/library/std/src/sync/lazy_lock/tests.rs @@ -34,6 +34,7 @@ fn lazy_default() { } #[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn lazy_poisoning() { let x: LazyCell = LazyCell::new(|| panic!("kaboom")); for _ in 0..2 { @@ -43,7 +44,7 @@ fn lazy_poisoning() { } #[test] -#[cfg_attr(target_os = "emscripten", ignore)] +#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads fn sync_lazy_new() { static CALLED: AtomicUsize = AtomicUsize::new(0); static SYNC_LAZY: LazyLock = LazyLock::new(|| { @@ -90,7 +91,7 @@ fn sync_lazy_default() { } #[test] -#[cfg_attr(target_os = "emscripten", ignore)] +#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads fn static_sync_lazy() { static XS: LazyLock> = LazyLock::new(|| { let mut xs = Vec::new(); @@ -123,6 +124,7 @@ fn static_sync_lazy_via_fn() { } #[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn sync_lazy_poisoning() { let x: LazyLock = LazyLock::new(|| panic!("kaboom")); for _ in 0..2 { diff --git a/library/std/src/sync/mod.rs b/library/std/src/sync/mod.rs index 0fb8e669bf86..0fb77331293f 100644 --- a/library/std/src/sync/mod.rs +++ b/library/std/src/sync/mod.rs @@ -133,6 +133,11 @@ //! inter-thread synchronisation mechanism, at the cost of some //! extra memory. //! +//! - [`mpmc`]: Multi-producer, multi-consumer queues, used for +//! message-based communication. Can provide a lightweight +//! inter-thread synchronisation mechanism, at the cost of some +//! extra memory. +//! //! - [`Mutex`]: Mutual Exclusion mechanism, which ensures that at //! most one thread at a time is able to access some data. //! @@ -153,6 +158,7 @@ //! [`Arc`]: crate::sync::Arc //! [`Barrier`]: crate::sync::Barrier //! [`Condvar`]: crate::sync::Condvar +//! [`mpmc`]: crate::sync::mpmc //! [`mpsc`]: crate::sync::mpsc //! [`Mutex`]: crate::sync::Mutex //! [`Once`]: crate::sync::Once @@ -193,12 +199,13 @@ pub use self::rwlock::{MappedRwLockReadGuard, MappedRwLockWriteGuard}; #[stable(feature = "rust1", since = "1.0.0")] pub use self::rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard}; +#[unstable(feature = "mpmc_channel", issue = "126840")] +pub mod mpmc; pub mod mpsc; mod barrier; mod condvar; mod lazy_lock; -mod mpmc; mod mutex; pub(crate) mod once; mod once_lock; diff --git a/library/std/src/sync/mpmc/error.rs b/library/std/src/sync/mpmc/error.rs index e3aec7e76232..e34b56d08312 100644 --- a/library/std/src/sync/mpmc/error.rs +++ b/library/std/src/sync/mpmc/error.rs @@ -7,6 +7,7 @@ use crate::{error, fmt}; /// /// [`send_timeout`]: super::Sender::send_timeout #[derive(PartialEq, Eq, Clone, Copy)] +#[unstable(feature = "mpmc_channel", issue = "126840")] pub enum SendTimeoutError { /// The message could not be sent because the channel is full and the operation timed out. /// @@ -18,12 +19,14 @@ pub enum SendTimeoutError { Disconnected(T), } +#[unstable(feature = "mpmc_channel", issue = "126840")] impl fmt::Debug for SendTimeoutError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { "SendTimeoutError(..)".fmt(f) } } +#[unstable(feature = "mpmc_channel", issue = "126840")] impl fmt::Display for SendTimeoutError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { @@ -33,8 +36,10 @@ impl fmt::Display for SendTimeoutError { } } +#[unstable(feature = "mpmc_channel", issue = "126840")] impl error::Error for SendTimeoutError {} +#[unstable(feature = "mpmc_channel", issue = "126840")] impl From> for SendTimeoutError { fn from(err: SendError) -> SendTimeoutError { match err { diff --git a/library/std/src/sync/mpmc/mod.rs b/library/std/src/sync/mpmc/mod.rs index c640e07348ea..44e146a89baf 100644 --- a/library/std/src/sync/mpmc/mod.rs +++ b/library/std/src/sync/mpmc/mod.rs @@ -1,8 +1,114 @@ -//! Multi-producer multi-consumer channels. +//! Multi-producer, multi-consumer FIFO queue communication primitives. +//! +//! This module provides message-based communication over channels, concretely +//! defined by two types: +//! +//! * [`Sender`] +//! * [`Receiver`] +//! +//! [`Sender`]s are used to send data to a set of [`Receiver`]s. Both +//! sender and receiver are cloneable (multi-producer) such that many threads can send +//! simultaneously to receivers (multi-consumer). +//! +//! These channels come in two flavors: +//! +//! 1. An asynchronous, infinitely buffered channel. The [`channel`] function +//! will return a `(Sender, Receiver)` tuple where all sends will be +//! **asynchronous** (they never block). The channel conceptually has an +//! infinite buffer. +//! +//! 2. A synchronous, bounded channel. The [`sync_channel`] function will +//! return a `(SyncSender, Receiver)` tuple where the storage for pending +//! messages is a pre-allocated buffer of a fixed size. All sends will be +//! **synchronous** by blocking until there is buffer space available. Note +//! that a bound of 0 is allowed, causing the channel to become a "rendezvous" +//! channel where each sender atomically hands off a message to a receiver. +//! +//! [`send`]: Sender::send +//! +//! ## Disconnection +//! +//! The send and receive operations on channels will all return a [`Result`] +//! indicating whether the operation succeeded or not. An unsuccessful operation +//! is normally indicative of the other half of a channel having "hung up" by +//! being dropped in its corresponding thread. +//! +//! Once half of a channel has been deallocated, most operations can no longer +//! continue to make progress, so [`Err`] will be returned. Many applications +//! will continue to [`unwrap`] the results returned from this module, +//! instigating a propagation of failure among threads if one unexpectedly dies. +//! +//! [`unwrap`]: Result::unwrap +//! +//! # Examples +//! +//! Simple usage: +//! +//! ``` +//! #![feature(mpmc_channel)] +//! +//! use std::thread; +//! use std::sync::mpmc::channel; +//! +//! // Create a simple streaming channel +//! let (tx, rx) = channel(); +//! thread::spawn(move || { +//! tx.send(10).unwrap(); +//! }); +//! assert_eq!(rx.recv().unwrap(), 10); +//! ``` +//! +//! Shared usage: +//! +//! ``` +//! #![feature(mpmc_channel)] +//! +//! use std::thread; +//! use std::sync::mpmc::channel; +//! +//! thread::scope(|s| { +//! // Create a shared channel that can be sent along from many threads +//! // where tx is the sending half (tx for transmission), and rx is the receiving +//! // half (rx for receiving). +//! let (tx, rx) = channel(); +//! for i in 0..10 { +//! let tx = tx.clone(); +//! s.spawn(move || { +//! tx.send(i).unwrap(); +//! }); +//! } +//! +//! for _ in 0..5 { +//! let rx1 = rx.clone(); +//! let rx2 = rx.clone(); +//! s.spawn(move || { +//! let j = rx1.recv().unwrap(); +//! assert!(0 <= j && j < 10); +//! }); +//! s.spawn(move || { +//! let j = rx2.recv().unwrap(); +//! assert!(0 <= j && j < 10); +//! }); +//! } +//! }) +//! ``` +//! +//! Propagating panics: +//! +//! ``` +//! #![feature(mpmc_channel)] +//! +//! use std::sync::mpmc::channel; +//! +//! // The call to recv() will return an error because the channel has already +//! // hung up (or been deallocated) +//! let (tx, rx) = channel::(); +//! drop(tx); +//! assert!(rx.recv().is_err()); +//! ``` -// This module is not currently exposed publicly, but is used -// as the implementation for the channels in `sync::mpsc`. The -// implementation comes from the crossbeam-channel crate: +// This module is used as the implementation for the channels in `sync::mpsc`. +// The implementation comes from the crossbeam-channel crate: // // Copyright (c) 2019 The Crossbeam Project Developers // @@ -46,9 +152,47 @@ use crate::fmt; use crate::panic::{RefUnwindSafe, UnwindSafe}; use crate::time::{Duration, Instant}; -/// Creates a channel of unbounded capacity. +/// Creates a new asynchronous channel, returning the sender/receiver halves. +/// All data sent on the [`Sender`] will become available on the [`Receiver`] in +/// the same order as it was sent, and no [`send`] will block the calling thread +/// (this channel has an "infinite buffer", unlike [`sync_channel`], which will +/// block after its buffer limit is reached). [`recv`] will block until a message +/// is available while there is at least one [`Sender`] alive (including clones). /// -/// This channel has a growable buffer that can hold any number of messages at a time. +/// The [`Sender`] can be cloned to [`send`] to the same channel multiple times. +/// The [`Receiver`] also can be cloned to have multi receivers. +/// +/// If the [`Receiver`] is disconnected while trying to [`send`] with the +/// [`Sender`], the [`send`] method will return a [`SendError`]. Similarly, if the +/// [`Sender`] is disconnected while trying to [`recv`], the [`recv`] method will +/// return a [`RecvError`]. +/// +/// [`send`]: Sender::send +/// [`recv`]: Receiver::recv +/// +/// # Examples +/// +/// ``` +/// #![feature(mpmc_channel)] +/// +/// use std::sync::mpmc::channel; +/// use std::thread; +/// +/// let (sender, receiver) = channel(); +/// +/// // Spawn off an expensive computation +/// thread::spawn(move || { +/// # fn expensive_computation() {} +/// sender.send(expensive_computation()).unwrap(); +/// }); +/// +/// // Do some useful work for awhile +/// +/// // Let's see what that answer was +/// println!("{:?}", receiver.recv().unwrap()); +/// ``` +#[must_use] +#[unstable(feature = "mpmc_channel", issue = "126840")] pub fn channel() -> (Sender, Receiver) { let (s, r) = counter::new(list::Channel::new()); let s = Sender { flavor: SenderFlavor::List(s) }; @@ -56,12 +200,50 @@ pub fn channel() -> (Sender, Receiver) { (s, r) } -/// Creates a channel of bounded capacity. +/// Creates a new synchronous, bounded channel. +/// All data sent on the [`Sender`] will become available on the [`Receiver`] +/// in the same order as it was sent. Like asynchronous [`channel`]s, the +/// [`Receiver`] will block until a message becomes available. `sync_channel` +/// differs greatly in the semantics of the sender, however. /// -/// This channel has a buffer that can hold at most `cap` messages at a time. +/// This channel has an internal buffer on which messages will be queued. +/// `bound` specifies the buffer size. When the internal buffer becomes full, +/// future sends will *block* waiting for the buffer to open up. Note that a +/// buffer size of 0 is valid, in which case this becomes "rendezvous channel" +/// where each [`send`] will not return until a [`recv`] is paired with it. /// -/// A special case is zero-capacity channel, which cannot hold any messages. Instead, send and -/// receive operations must appear at the same time in order to pair up and pass the message over. +/// The [`Sender`] can be cloned to [`send`] to the same channel multiple +/// times. The [`Receiver`] also can be cloned to have multi receivers. +/// +/// Like asynchronous channels, if the [`Receiver`] is disconnected while trying +/// to [`send`] with the [`Sender`], the [`send`] method will return a +/// [`SendError`]. Similarly, If the [`Sender`] is disconnected while trying +/// to [`recv`], the [`recv`] method will return a [`RecvError`]. +/// +/// [`send`]: Sender::send +/// [`recv`]: Receiver::recv +/// +/// # Examples +/// +/// ``` +/// use std::sync::mpsc::sync_channel; +/// use std::thread; +/// +/// let (sender, receiver) = sync_channel(1); +/// +/// // this returns immediately +/// sender.send(1).unwrap(); +/// +/// thread::spawn(move || { +/// // this will block until the previous message has been received +/// sender.send(2).unwrap(); +/// }); +/// +/// assert_eq!(receiver.recv().unwrap(), 1); +/// assert_eq!(receiver.recv().unwrap(), 2); +/// ``` +#[must_use] +#[unstable(feature = "mpmc_channel", issue = "126840")] pub fn sync_channel(cap: usize) -> (Sender, Receiver) { if cap == 0 { let (s, r) = counter::new(zero::Channel::new()); @@ -76,7 +258,42 @@ pub fn sync_channel(cap: usize) -> (Sender, Receiver) { } } -/// The sending side of a channel. +/// The sending-half of Rust's synchronous [`channel`] type. +/// +/// Messages can be sent through this channel with [`send`]. +/// +/// Note: all senders (the original and its clones) need to be dropped for the receiver +/// to stop blocking to receive messages with [`Receiver::recv`]. +/// +/// [`send`]: Sender::send +/// +/// # Examples +/// +/// ```rust +/// #![feature(mpmc_channel)] +/// +/// use std::sync::mpmc::channel; +/// use std::thread; +/// +/// let (sender, receiver) = channel(); +/// let sender2 = sender.clone(); +/// +/// // First thread owns sender +/// thread::spawn(move || { +/// sender.send(1).unwrap(); +/// }); +/// +/// // Second thread owns sender2 +/// thread::spawn(move || { +/// sender2.send(2).unwrap(); +/// }); +/// +/// let msg = receiver.recv().unwrap(); +/// let msg2 = receiver.recv().unwrap(); +/// +/// assert_eq!(3, msg + msg2); +/// ``` +#[unstable(feature = "mpmc_channel", issue = "126840")] pub struct Sender { flavor: SenderFlavor, } @@ -93,10 +310,14 @@ enum SenderFlavor { Zero(counter::Sender>), } +#[unstable(feature = "mpmc_channel", issue = "126840")] unsafe impl Send for Sender {} +#[unstable(feature = "mpmc_channel", issue = "126840")] unsafe impl Sync for Sender {} +#[unstable(feature = "mpmc_channel", issue = "126840")] impl UnwindSafe for Sender {} +#[unstable(feature = "mpmc_channel", issue = "126840")] impl RefUnwindSafe for Sender {} impl Sender { @@ -107,6 +328,19 @@ impl Sender { /// /// If called on a zero-capacity channel, this method will send the message only if there /// happens to be a receive operation on the other side of the channel at the same time. + /// + /// # Examples + /// + /// ```rust + /// #![feature(mpmc_channel)] + /// + /// use std::sync::mpmc::{channel, Receiver, Sender}; + /// + /// let (sender, _receiver): (Sender, Receiver) = channel(); + /// + /// assert!(sender.try_send(1).is_ok()); + /// ``` + #[unstable(feature = "mpmc_channel", issue = "126840")] pub fn try_send(&self, msg: T) -> Result<(), TrySendError> { match &self.flavor { SenderFlavor::Array(chan) => chan.try_send(msg), @@ -115,14 +349,36 @@ impl Sender { } } - /// Blocks the current thread until a message is sent or the channel is disconnected. + /// Attempts to send a value on this channel, returning it back if it could + /// not be sent. /// - /// If the channel is full and not disconnected, this call will block until the send operation - /// can proceed. If the channel becomes disconnected, this call will wake up and return an - /// error. The returned error contains the original message. + /// A successful send occurs when it is determined that the other end of + /// the channel has not hung up already. An unsuccessful send would be one + /// where the corresponding receiver has already been deallocated. Note + /// that a return value of [`Err`] means that the data will never be + /// received, but a return value of [`Ok`] does *not* mean that the data + /// will be received. It is possible for the corresponding receiver to + /// hang up immediately after this function returns [`Ok`]. /// - /// If called on a zero-capacity channel, this method will wait for a receive operation to - /// appear on the other side of the channel. + /// This method will never block the current thread. + /// + /// # Examples + /// + /// ``` + /// #![feature(mpmc_channel)] + /// + /// use std::sync::mpmc::channel; + /// + /// let (tx, rx) = channel(); + /// + /// // This send is always successful + /// tx.send(1).unwrap(); + /// + /// // This send will fail because the receiver is gone + /// drop(rx); + /// assert!(tx.send(1).is_err()); + /// ``` + #[unstable(feature = "mpmc_channel", issue = "126840")] pub fn send(&self, msg: T) -> Result<(), SendError> { match &self.flavor { SenderFlavor::Array(chan) => chan.send(msg, None), @@ -136,10 +392,6 @@ impl Sender { } } -// The methods below are not used by `sync::mpsc`, but -// are useful and we'll likely want to expose them -// eventually -#[allow(unused)] impl Sender { /// Waits for a message to be sent into the channel, but only for a limited time. /// @@ -149,6 +401,20 @@ impl Sender { /// /// If called on a zero-capacity channel, this method will wait for a receive operation to /// appear on the other side of the channel. + /// + /// # Examples + /// + /// ``` + /// #![feature(mpmc_channel)] + /// + /// use std::sync::mpmc::channel; + /// use std::time::Duration; + /// + /// let (tx, rx) = channel(); + /// + /// tx.send_timeout(1, Duration::from_millis(400)).unwrap(); + /// ``` + #[unstable(feature = "mpmc_channel", issue = "126840")] pub fn send_timeout(&self, msg: T, timeout: Duration) -> Result<(), SendTimeoutError> { match Instant::now().checked_add(timeout) { Some(deadline) => self.send_deadline(msg, deadline), @@ -165,6 +431,21 @@ impl Sender { /// /// If called on a zero-capacity channel, this method will wait for a receive operation to /// appear on the other side of the channel. + /// + /// # Examples + /// + /// ``` + /// #![feature(mpmc_channel)] + /// + /// use std::sync::mpmc::channel; + /// use std::time::{Duration, Instant}; + /// + /// let (tx, rx) = channel(); + /// + /// let t = Instant::now() + Duration::from_millis(400); + /// tx.send_deadline(1, t).unwrap(); + /// ``` + #[unstable(feature = "mpmc_channel", issue = "126840")] pub fn send_deadline(&self, msg: T, deadline: Instant) -> Result<(), SendTimeoutError> { match &self.flavor { SenderFlavor::Array(chan) => chan.send(msg, Some(deadline)), @@ -176,6 +457,31 @@ impl Sender { /// Returns `true` if the channel is empty. /// /// Note: Zero-capacity channels are always empty. + /// + /// # Examples + /// + /// ``` + /// #![feature(mpmc_channel)] + /// + /// use std::sync::mpmc; + /// use std::thread; + /// + /// let (send, _recv) = mpmc::channel(); + /// + /// let tx1 = send.clone(); + /// let tx2 = send.clone(); + /// + /// assert!(tx1.is_empty()); + /// + /// let handle = thread::spawn(move || { + /// tx2.send(1u8).unwrap(); + /// }); + /// + /// handle.join().unwrap(); + /// + /// assert!(!tx1.is_empty()); + /// ``` + #[unstable(feature = "mpmc_channel", issue = "126840")] pub fn is_empty(&self) -> bool { match &self.flavor { SenderFlavor::Array(chan) => chan.is_empty(), @@ -187,6 +493,29 @@ impl Sender { /// Returns `true` if the channel is full. /// /// Note: Zero-capacity channels are always full. + /// + /// # Examples + /// + /// ``` + /// #![feature(mpmc_channel)] + /// + /// use std::sync::mpmc; + /// use std::thread; + /// + /// let (send, _recv) = mpmc::sync_channel(1); + /// + /// let (tx1, tx2) = (send.clone(), send.clone()); + /// assert!(!tx1.is_full()); + /// + /// let handle = thread::spawn(move || { + /// tx2.send(1u8).unwrap(); + /// }); + /// + /// handle.join().unwrap(); + /// + /// assert!(tx1.is_full()); + /// ``` + #[unstable(feature = "mpmc_channel", issue = "126840")] pub fn is_full(&self) -> bool { match &self.flavor { SenderFlavor::Array(chan) => chan.is_full(), @@ -196,6 +525,29 @@ impl Sender { } /// Returns the number of messages in the channel. + /// + /// # Examples + /// + /// ``` + /// #![feature(mpmc_channel)] + /// + /// use std::sync::mpmc; + /// use std::thread; + /// + /// let (send, _recv) = mpmc::channel(); + /// let (tx1, tx2) = (send.clone(), send.clone()); + /// + /// assert_eq!(tx1.len(), 0); + /// + /// let handle = thread::spawn(move || { + /// tx2.send(1u8).unwrap(); + /// }); + /// + /// handle.join().unwrap(); + /// + /// assert_eq!(tx1.len(), 1); + /// ``` + #[unstable(feature = "mpmc_channel", issue = "126840")] pub fn len(&self) -> usize { match &self.flavor { SenderFlavor::Array(chan) => chan.len(), @@ -205,6 +557,29 @@ impl Sender { } /// If the channel is bounded, returns its capacity. + /// + /// # Examples + /// + /// ``` + /// #![feature(mpmc_channel)] + /// + /// use std::sync::mpmc; + /// use std::thread; + /// + /// let (send, _recv) = mpmc::sync_channel(3); + /// let (tx1, tx2) = (send.clone(), send.clone()); + /// + /// assert_eq!(tx1.capacity(), Some(3)); + /// + /// let handle = thread::spawn(move || { + /// tx2.send(1u8).unwrap(); + /// }); + /// + /// handle.join().unwrap(); + /// + /// assert_eq!(tx1.capacity(), Some(3)); + /// ``` + #[unstable(feature = "mpmc_channel", issue = "126840")] pub fn capacity(&self) -> Option { match &self.flavor { SenderFlavor::Array(chan) => chan.capacity(), @@ -214,6 +589,21 @@ impl Sender { } /// Returns `true` if senders belong to the same channel. + /// + /// # Examples + /// + /// ``` + /// #![feature(mpmc_channel)] + /// + /// use std::sync::mpmc; + /// + /// let (tx1, _) = mpmc::channel::(); + /// let (tx2, _) = mpmc::channel::(); + /// + /// assert!(tx1.same_channel(&tx1)); + /// assert!(!tx1.same_channel(&tx2)); + /// ``` + #[unstable(feature = "mpmc_channel", issue = "126840")] pub fn same_channel(&self, other: &Sender) -> bool { match (&self.flavor, &other.flavor) { (SenderFlavor::Array(ref a), SenderFlavor::Array(ref b)) => a == b, @@ -224,6 +614,7 @@ impl Sender { } } +#[unstable(feature = "mpmc_channel", issue = "126840")] impl Drop for Sender { fn drop(&mut self) { unsafe { @@ -236,6 +627,7 @@ impl Drop for Sender { } } +#[unstable(feature = "mpmc_channel", issue = "126840")] impl Clone for Sender { fn clone(&self) -> Self { let flavor = match &self.flavor { @@ -248,17 +640,216 @@ impl Clone for Sender { } } +#[unstable(feature = "mpmc_channel", issue = "126840")] impl fmt::Debug for Sender { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.pad("Sender { .. }") } } -/// The receiving side of a channel. +/// The receiving half of Rust's [`channel`] (or [`sync_channel`]) type. +/// Different threads can share this [`Sender`] by cloning it. +/// +/// Messages sent to the channel can be retrieved using [`recv`]. +/// +/// [`recv`]: Receiver::recv +/// +/// # Examples +/// +/// ```rust +/// #![feature(mpmc_channel)] +/// +/// use std::sync::mpmc::channel; +/// use std::thread; +/// use std::time::Duration; +/// +/// let (send, recv) = channel(); +/// +/// let tx_thread = thread::spawn(move || { +/// send.send("Hello world!").unwrap(); +/// thread::sleep(Duration::from_secs(2)); // block for two seconds +/// send.send("Delayed for 2 seconds").unwrap(); +/// }); +/// +/// let (rx1, rx2) = (recv.clone(), recv.clone()); +/// let rx_thread_1 = thread::spawn(move || { +/// println!("{}", rx1.recv().unwrap()); // Received immediately +/// }); +/// let rx_thread_2 = thread::spawn(move || { +/// println!("{}", rx2.recv().unwrap()); // Received after 2 seconds +/// }); +/// +/// tx_thread.join().unwrap(); +/// rx_thread_1.join().unwrap(); +/// rx_thread_2.join().unwrap(); +/// ``` +#[unstable(feature = "mpmc_channel", issue = "126840")] pub struct Receiver { flavor: ReceiverFlavor, } +/// An iterator over messages on a [`Receiver`], created by [`iter`]. +/// +/// This iterator will block whenever [`next`] is called, +/// waiting for a new message, and [`None`] will be returned +/// when the corresponding channel has hung up. +/// +/// [`iter`]: Receiver::iter +/// [`next`]: Iterator::next +/// +/// # Examples +/// +/// ```rust +/// #![feature(mpmc_channel)] +/// +/// use std::sync::mpmc::channel; +/// use std::thread; +/// +/// let (send, recv) = channel(); +/// +/// thread::spawn(move || { +/// send.send(1u8).unwrap(); +/// send.send(2u8).unwrap(); +/// send.send(3u8).unwrap(); +/// }); +/// +/// for x in recv.iter() { +/// println!("Got: {x}"); +/// } +/// ``` +#[unstable(feature = "mpmc_channel", issue = "126840")] +#[derive(Debug)] +pub struct Iter<'a, T: 'a> { + rx: &'a Receiver, +} + +/// An iterator that attempts to yield all pending values for a [`Receiver`], +/// created by [`try_iter`]. +/// +/// [`None`] will be returned when there are no pending values remaining or +/// if the corresponding channel has hung up. +/// +/// This iterator will never block the caller in order to wait for data to +/// become available. Instead, it will return [`None`]. +/// +/// [`try_iter`]: Receiver::try_iter +/// +/// # Examples +/// +/// ```rust +/// #![feature(mpmc_channel)] +/// +/// use std::sync::mpmc::channel; +/// use std::thread; +/// use std::time::Duration; +/// +/// let (sender, receiver) = channel(); +/// +/// // Nothing is in the buffer yet +/// assert!(receiver.try_iter().next().is_none()); +/// println!("Nothing in the buffer..."); +/// +/// thread::spawn(move || { +/// sender.send(1).unwrap(); +/// sender.send(2).unwrap(); +/// sender.send(3).unwrap(); +/// }); +/// +/// println!("Going to sleep..."); +/// thread::sleep(Duration::from_secs(2)); // block for two seconds +/// +/// for x in receiver.try_iter() { +/// println!("Got: {x}"); +/// } +/// ``` +#[unstable(feature = "mpmc_channel", issue = "126840")] +#[derive(Debug)] +pub struct TryIter<'a, T: 'a> { + rx: &'a Receiver, +} + +/// An owning iterator over messages on a [`Receiver`], +/// created by [`into_iter`]. +/// +/// This iterator will block whenever [`next`] +/// is called, waiting for a new message, and [`None`] will be +/// returned if the corresponding channel has hung up. +/// +/// [`into_iter`]: Receiver::into_iter +/// [`next`]: Iterator::next +/// +/// # Examples +/// +/// ```rust +/// #![feature(mpmc_channel)] +/// +/// use std::sync::mpmc::channel; +/// use std::thread; +/// +/// let (send, recv) = channel(); +/// +/// thread::spawn(move || { +/// send.send(1u8).unwrap(); +/// send.send(2u8).unwrap(); +/// send.send(3u8).unwrap(); +/// }); +/// +/// for x in recv.into_iter() { +/// println!("Got: {x}"); +/// } +/// ``` +#[unstable(feature = "mpmc_channel", issue = "126840")] +#[derive(Debug)] +pub struct IntoIter { + rx: Receiver, +} + +#[unstable(feature = "mpmc_channel", issue = "126840")] +impl<'a, T> Iterator for Iter<'a, T> { + type Item = T; + + fn next(&mut self) -> Option { + self.rx.recv().ok() + } +} + +#[unstable(feature = "mpmc_channel", issue = "126840")] +impl<'a, T> Iterator for TryIter<'a, T> { + type Item = T; + + fn next(&mut self) -> Option { + self.rx.try_recv().ok() + } +} + +#[unstable(feature = "mpmc_channel", issue = "126840")] +impl<'a, T> IntoIterator for &'a Receiver { + type Item = T; + type IntoIter = Iter<'a, T>; + + fn into_iter(self) -> Iter<'a, T> { + self.iter() + } +} + +#[unstable(feature = "mpmc_channel", issue = "126840")] +impl Iterator for IntoIter { + type Item = T; + fn next(&mut self) -> Option { + self.rx.recv().ok() + } +} + +#[unstable(feature = "mpmc_channel", issue = "126840")] +impl IntoIterator for Receiver { + type Item = T; + type IntoIter = IntoIter; + + fn into_iter(self) -> IntoIter { + IntoIter { rx: self } + } +} + /// Receiver flavors. enum ReceiverFlavor { /// Bounded channel based on a preallocated array. @@ -271,20 +862,46 @@ enum ReceiverFlavor { Zero(counter::Receiver>), } +#[unstable(feature = "mpmc_channel", issue = "126840")] unsafe impl Send for Receiver {} +#[unstable(feature = "mpmc_channel", issue = "126840")] unsafe impl Sync for Receiver {} +#[unstable(feature = "mpmc_channel", issue = "126840")] impl UnwindSafe for Receiver {} +#[unstable(feature = "mpmc_channel", issue = "126840")] impl RefUnwindSafe for Receiver {} impl Receiver { /// Attempts to receive a message from the channel without blocking. /// - /// This method will either receive a message from the channel immediately or return an error - /// if the channel is empty. + /// This method will never block the caller in order to wait for data to + /// become available. Instead, this will always return immediately with a + /// possible option of pending data on the channel. /// /// If called on a zero-capacity channel, this method will receive a message only if there /// happens to be a send operation on the other side of the channel at the same time. + /// + /// This is useful for a flavor of "optimistic check" before deciding to + /// block on a receiver. + /// + /// Compared with [`recv`], this function has two failure cases instead of one + /// (one for disconnection, one for an empty buffer). + /// + /// [`recv`]: Self::recv + /// + /// # Examples + /// + /// ```rust + /// #![feature(mpmc_channel)] + /// + /// use std::sync::mpmc::{Receiver, channel}; + /// + /// let (_, receiver): (_, Receiver) = channel(); + /// + /// assert!(receiver.try_recv().is_err()); + /// ``` + #[unstable(feature = "mpmc_channel", issue = "126840")] pub fn try_recv(&self) -> Result { match &self.flavor { ReceiverFlavor::Array(chan) => chan.try_recv(), @@ -293,15 +910,64 @@ impl Receiver { } } - /// Blocks the current thread until a message is received or the channel is empty and - /// disconnected. + /// Attempts to wait for a value on this receiver, returning an error if the + /// corresponding channel has hung up. /// - /// If the channel is empty and not disconnected, this call will block until the receive - /// operation can proceed. If the channel is empty and becomes disconnected, this call will - /// wake up and return an error. + /// This function will always block the current thread if there is no data + /// available and it's possible for more data to be sent (at least one sender + /// still exists). Once a message is sent to the corresponding [`Sender`], + /// this receiver will wake up and return that message. /// - /// If called on a zero-capacity channel, this method will wait for a send operation to appear - /// on the other side of the channel. + /// If the corresponding [`Sender`] has disconnected, or it disconnects while + /// this call is blocking, this call will wake up and return [`Err`] to + /// indicate that no more messages can ever be received on this channel. + /// However, since channels are buffered, messages sent before the disconnect + /// will still be properly received. + /// + /// # Examples + /// + /// ``` + /// #![feature(mpmc_channel)] + /// + /// use std::sync::mpmc; + /// use std::thread; + /// + /// let (send, recv) = mpmc::channel(); + /// let handle = thread::spawn(move || { + /// send.send(1u8).unwrap(); + /// }); + /// + /// handle.join().unwrap(); + /// + /// assert_eq!(Ok(1), recv.recv()); + /// ``` + /// + /// Buffering behavior: + /// + /// ``` + /// #![feature(mpmc_channel)] + /// + /// use std::sync::mpmc; + /// use std::thread; + /// use std::sync::mpmc::RecvError; + /// + /// let (send, recv) = mpmc::channel(); + /// let handle = thread::spawn(move || { + /// send.send(1u8).unwrap(); + /// send.send(2).unwrap(); + /// send.send(3).unwrap(); + /// drop(send); + /// }); + /// + /// // wait for the thread to join so we ensure the sender is dropped + /// handle.join().unwrap(); + /// + /// assert_eq!(Ok(1), recv.recv()); + /// assert_eq!(Ok(2), recv.recv()); + /// assert_eq!(Ok(3), recv.recv()); + /// assert_eq!(Err(RecvError), recv.recv()); + /// ``` + #[unstable(feature = "mpmc_channel", issue = "126840")] pub fn recv(&self) -> Result { match &self.flavor { ReceiverFlavor::Array(chan) => chan.recv(None), @@ -311,14 +977,65 @@ impl Receiver { .map_err(|_| RecvError) } - /// Waits for a message to be received from the channel, but only for a limited time. + /// Attempts to wait for a value on this receiver, returning an error if the + /// corresponding channel has hung up, or if it waits more than `timeout`. /// - /// If the channel is empty and not disconnected, this call will block until the receive - /// operation can proceed or the operation times out. If the channel is empty and becomes - /// disconnected, this call will wake up and return an error. + /// This function will always block the current thread if there is no data + /// available and it's possible for more data to be sent (at least one sender + /// still exists). Once a message is sent to the corresponding [`Sender`], + /// this receiver will wake up and return that message. /// - /// If called on a zero-capacity channel, this method will wait for a send operation to appear - /// on the other side of the channel. + /// If the corresponding [`Sender`] has disconnected, or it disconnects while + /// this call is blocking, this call will wake up and return [`Err`] to + /// indicate that no more messages can ever be received on this channel. + /// However, since channels are buffered, messages sent before the disconnect + /// will still be properly received. + /// + /// # Examples + /// + /// Successfully receiving value before encountering timeout: + /// + /// ```no_run + /// #![feature(mpmc_channel)] + /// + /// use std::thread; + /// use std::time::Duration; + /// use std::sync::mpmc; + /// + /// let (send, recv) = mpmc::channel(); + /// + /// thread::spawn(move || { + /// send.send('a').unwrap(); + /// }); + /// + /// assert_eq!( + /// recv.recv_timeout(Duration::from_millis(400)), + /// Ok('a') + /// ); + /// ``` + /// + /// Receiving an error upon reaching timeout: + /// + /// ```no_run + /// #![feature(mpmc_channel)] + /// + /// use std::thread; + /// use std::time::Duration; + /// use std::sync::mpmc; + /// + /// let (send, recv) = mpmc::channel(); + /// + /// thread::spawn(move || { + /// thread::sleep(Duration::from_millis(800)); + /// send.send('a').unwrap(); + /// }); + /// + /// assert_eq!( + /// recv.recv_timeout(Duration::from_millis(400)), + /// Err(mpmc::RecvTimeoutError::Timeout) + /// ); + /// ``` + #[unstable(feature = "mpmc_channel", issue = "126840")] pub fn recv_timeout(&self, timeout: Duration) -> Result { match Instant::now().checked_add(timeout) { Some(deadline) => self.recv_deadline(deadline), @@ -327,14 +1044,65 @@ impl Receiver { } } - /// Waits for a message to be received from the channel, but only for a limited time. + /// Attempts to wait for a value on this receiver, returning an error if the + /// corresponding channel has hung up, or if `deadline` is reached. /// - /// If the channel is empty and not disconnected, this call will block until the receive - /// operation can proceed or the operation times out. If the channel is empty and becomes - /// disconnected, this call will wake up and return an error. + /// This function will always block the current thread if there is no data + /// available and it's possible for more data to be sent. Once a message is + /// sent to the corresponding [`Sender`], then this receiver will wake up + /// and return that message. /// - /// If called on a zero-capacity channel, this method will wait for a send operation to appear - /// on the other side of the channel. + /// If the corresponding [`Sender`] has disconnected, or it disconnects while + /// this call is blocking, this call will wake up and return [`Err`] to + /// indicate that no more messages can ever be received on this channel. + /// However, since channels are buffered, messages sent before the disconnect + /// will still be properly received. + /// + /// # Examples + /// + /// Successfully receiving value before reaching deadline: + /// + /// ```no_run + /// #![feature(mpmc_channel)] + /// + /// use std::thread; + /// use std::time::{Duration, Instant}; + /// use std::sync::mpmc; + /// + /// let (send, recv) = mpmc::channel(); + /// + /// thread::spawn(move || { + /// send.send('a').unwrap(); + /// }); + /// + /// assert_eq!( + /// recv.recv_deadline(Instant::now() + Duration::from_millis(400)), + /// Ok('a') + /// ); + /// ``` + /// + /// Receiving an error upon reaching deadline: + /// + /// ```no_run + /// #![feature(mpmc_channel)] + /// + /// use std::thread; + /// use std::time::{Duration, Instant}; + /// use std::sync::mpmc; + /// + /// let (send, recv) = mpmc::channel(); + /// + /// thread::spawn(move || { + /// thread::sleep(Duration::from_millis(800)); + /// send.send('a').unwrap(); + /// }); + /// + /// assert_eq!( + /// recv.recv_deadline(Instant::now() + Duration::from_millis(400)), + /// Err(mpmc::RecvTimeoutError::Timeout) + /// ); + /// ``` + #[unstable(feature = "mpmc_channel", issue = "126840")] pub fn recv_deadline(&self, deadline: Instant) -> Result { match &self.flavor { ReceiverFlavor::Array(chan) => chan.recv(Some(deadline)), @@ -342,16 +1110,77 @@ impl Receiver { ReceiverFlavor::Zero(chan) => chan.recv(Some(deadline)), } } + + /// Returns an iterator that will attempt to yield all pending values. + /// It will return `None` if there are no more pending values or if the + /// channel has hung up. The iterator will never [`panic!`] or block the + /// user by waiting for values. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(mpmc_channel)] + /// + /// use std::sync::mpmc::channel; + /// use std::thread; + /// use std::time::Duration; + /// + /// let (sender, receiver) = channel(); + /// + /// // nothing is in the buffer yet + /// assert!(receiver.try_iter().next().is_none()); + /// + /// thread::spawn(move || { + /// thread::sleep(Duration::from_secs(1)); + /// sender.send(1).unwrap(); + /// sender.send(2).unwrap(); + /// sender.send(3).unwrap(); + /// }); + /// + /// // nothing is in the buffer yet + /// assert!(receiver.try_iter().next().is_none()); + /// + /// // block for two seconds + /// thread::sleep(Duration::from_secs(2)); + /// + /// let mut iter = receiver.try_iter(); + /// assert_eq!(iter.next(), Some(1)); + /// assert_eq!(iter.next(), Some(2)); + /// assert_eq!(iter.next(), Some(3)); + /// assert_eq!(iter.next(), None); + /// ``` + #[unstable(feature = "mpmc_channel", issue = "126840")] + pub fn try_iter(&self) -> TryIter<'_, T> { + TryIter { rx: self } + } } -// The methods below are not used by `sync::mpsc`, but -// are useful and we'll likely want to expose them -// eventually -#[allow(unused)] impl Receiver { /// Returns `true` if the channel is empty. /// /// Note: Zero-capacity channels are always empty. + /// + /// # Examples + /// + /// ``` + /// #![feature(mpmc_channel)] + /// + /// use std::sync::mpmc; + /// use std::thread; + /// + /// let (send, recv) = mpmc::channel(); + /// + /// assert!(recv.is_empty()); + /// + /// let handle = thread::spawn(move || { + /// send.send(1u8).unwrap(); + /// }); + /// + /// handle.join().unwrap(); + /// + /// assert!(!recv.is_empty()); + /// ``` + #[unstable(feature = "mpmc_channel", issue = "126840")] pub fn is_empty(&self) -> bool { match &self.flavor { ReceiverFlavor::Array(chan) => chan.is_empty(), @@ -363,6 +1192,28 @@ impl Receiver { /// Returns `true` if the channel is full. /// /// Note: Zero-capacity channels are always full. + /// + /// # Examples + /// + /// ``` + /// #![feature(mpmc_channel)] + /// + /// use std::sync::mpmc; + /// use std::thread; + /// + /// let (send, recv) = mpmc::sync_channel(1); + /// + /// assert!(!recv.is_full()); + /// + /// let handle = thread::spawn(move || { + /// send.send(1u8).unwrap(); + /// }); + /// + /// handle.join().unwrap(); + /// + /// assert!(recv.is_full()); + /// ``` + #[unstable(feature = "mpmc_channel", issue = "126840")] pub fn is_full(&self) -> bool { match &self.flavor { ReceiverFlavor::Array(chan) => chan.is_full(), @@ -372,6 +1223,28 @@ impl Receiver { } /// Returns the number of messages in the channel. + /// + /// # Examples + /// + /// ``` + /// #![feature(mpmc_channel)] + /// + /// use std::sync::mpmc; + /// use std::thread; + /// + /// let (send, recv) = mpmc::channel(); + /// + /// assert_eq!(recv.len(), 0); + /// + /// let handle = thread::spawn(move || { + /// send.send(1u8).unwrap(); + /// }); + /// + /// handle.join().unwrap(); + /// + /// assert_eq!(recv.len(), 1); + /// ``` + #[unstable(feature = "mpmc_channel", issue = "126840")] pub fn len(&self) -> usize { match &self.flavor { ReceiverFlavor::Array(chan) => chan.len(), @@ -381,6 +1254,28 @@ impl Receiver { } /// If the channel is bounded, returns its capacity. + /// + /// # Examples + /// + /// ``` + /// #![feature(mpmc_channel)] + /// + /// use std::sync::mpmc; + /// use std::thread; + /// + /// let (send, recv) = mpmc::sync_channel(3); + /// + /// assert_eq!(recv.capacity(), Some(3)); + /// + /// let handle = thread::spawn(move || { + /// send.send(1u8).unwrap(); + /// }); + /// + /// handle.join().unwrap(); + /// + /// assert_eq!(recv.capacity(), Some(3)); + /// ``` + #[unstable(feature = "mpmc_channel", issue = "126840")] pub fn capacity(&self) -> Option { match &self.flavor { ReceiverFlavor::Array(chan) => chan.capacity(), @@ -390,6 +1285,21 @@ impl Receiver { } /// Returns `true` if receivers belong to the same channel. + /// + /// # Examples + /// + /// ``` + /// #![feature(mpmc_channel)] + /// + /// use std::sync::mpmc; + /// + /// let (_, rx1) = mpmc::channel::(); + /// let (_, rx2) = mpmc::channel::(); + /// + /// assert!(rx1.same_channel(&rx1)); + /// assert!(!rx1.same_channel(&rx2)); + /// ``` + #[unstable(feature = "mpmc_channel", issue = "126840")] pub fn same_channel(&self, other: &Receiver) -> bool { match (&self.flavor, &other.flavor) { (ReceiverFlavor::Array(a), ReceiverFlavor::Array(b)) => a == b, @@ -398,8 +1308,39 @@ impl Receiver { _ => false, } } + + /// Returns an iterator that will block waiting for messages, but never + /// [`panic!`]. It will return [`None`] when the channel has hung up. + /// + /// # Examples + /// + /// ```rust + /// #![feature(mpmc_channel)] + /// + /// use std::sync::mpmc::channel; + /// use std::thread; + /// + /// let (send, recv) = channel(); + /// + /// thread::spawn(move || { + /// send.send(1).unwrap(); + /// send.send(2).unwrap(); + /// send.send(3).unwrap(); + /// }); + /// + /// let mut iter = recv.iter(); + /// assert_eq!(iter.next(), Some(1)); + /// assert_eq!(iter.next(), Some(2)); + /// assert_eq!(iter.next(), Some(3)); + /// assert_eq!(iter.next(), None); + /// ``` + #[unstable(feature = "mpmc_channel", issue = "126840")] + pub fn iter(&self) -> Iter<'_, T> { + Iter { rx: self } + } } +#[unstable(feature = "mpmc_channel", issue = "126840")] impl Drop for Receiver { fn drop(&mut self) { unsafe { @@ -412,6 +1353,7 @@ impl Drop for Receiver { } } +#[unstable(feature = "mpmc_channel", issue = "126840")] impl Clone for Receiver { fn clone(&self) -> Self { let flavor = match &self.flavor { @@ -424,6 +1366,7 @@ impl Clone for Receiver { } } +#[unstable(feature = "mpmc_channel", issue = "126840")] impl fmt::Debug for Receiver { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.pad("Receiver { .. }") diff --git a/library/std/src/sync/mpmc/tests.rs b/library/std/src/sync/mpmc/tests.rs new file mode 100644 index 000000000000..ab14050df6c9 --- /dev/null +++ b/library/std/src/sync/mpmc/tests.rs @@ -0,0 +1,728 @@ +use super::*; +use crate::{env, thread}; + +pub fn stress_factor() -> usize { + match env::var("RUST_TEST_STRESS") { + Ok(val) => val.parse().unwrap(), + Err(..) => 1, + } +} + +#[test] +fn smoke() { + let (tx, rx) = channel::(); + tx.send(1).unwrap(); + assert_eq!(rx.recv().unwrap(), 1); +} + +#[test] +fn drop_full() { + let (tx, _rx) = channel::>(); + tx.send(Box::new(1)).unwrap(); +} + +#[test] +fn drop_full_shared() { + let (tx, _rx) = channel::>(); + drop(tx.clone()); + drop(tx.clone()); + tx.send(Box::new(1)).unwrap(); +} + +#[test] +fn smoke_shared() { + let (tx, rx) = channel::(); + tx.send(1).unwrap(); + assert_eq!(rx.recv().unwrap(), 1); + let tx = tx.clone(); + tx.send(1).unwrap(); + assert_eq!(rx.recv().unwrap(), 1); +} + +#[test] +fn smoke_threads() { + let (tx, rx) = channel::(); + let t1 = thread::spawn(move || { + for i in 0..2 { + tx.send(i).unwrap(); + } + }); + let t2 = thread::spawn(move || { + assert_eq!(rx.recv().unwrap(), 0); + assert_eq!(rx.recv().unwrap(), 1); + }); + t1.join().unwrap(); + t2.join().unwrap(); +} + +#[test] +fn smoke_port_gone() { + let (tx, rx) = channel::(); + drop(rx); + assert!(tx.send(1).is_err()); +} + +#[test] +fn smoke_shared_port_gone() { + let (tx, rx) = channel::(); + drop(rx); + assert!(tx.send(1).is_err()) +} + +#[test] +fn smoke_shared_port_gone2() { + let (tx, rx) = channel::(); + drop(rx); + let tx2 = tx.clone(); + drop(tx); + assert!(tx2.send(1).is_err()); +} + +#[test] +fn port_gone_concurrent() { + let (tx, rx) = channel::(); + let _t = thread::spawn(move || { + rx.recv().unwrap(); + }); + while tx.send(1).is_ok() {} +} + +#[test] +fn port_gone_concurrent_shared() { + let (tx, rx) = channel::(); + let tx2 = tx.clone(); + let _t = thread::spawn(move || { + rx.recv().unwrap(); + }); + while tx.send(1).is_ok() && tx2.send(1).is_ok() {} +} + +#[test] +fn smoke_chan_gone() { + let (tx, rx) = channel::(); + drop(tx); + assert!(rx.recv().is_err()); +} + +#[test] +fn smoke_chan_gone_shared() { + let (tx, rx) = channel::<()>(); + let tx2 = tx.clone(); + drop(tx); + drop(tx2); + assert!(rx.recv().is_err()); +} + +#[test] +fn chan_gone_concurrent() { + let (tx, rx) = channel::(); + let _t = thread::spawn(move || { + tx.send(1).unwrap(); + tx.send(1).unwrap(); + }); + while rx.recv().is_ok() {} +} + +#[test] +fn stress() { + let count = if cfg!(miri) { 100 } else { 10000 }; + let (tx, rx) = channel::(); + let t = thread::spawn(move || { + for _ in 0..count { + tx.send(1).unwrap(); + } + }); + for _ in 0..count { + assert_eq!(rx.recv().unwrap(), 1); + } + t.join().ok().expect("thread panicked"); +} + +#[test] +fn stress_shared() { + const AMT: u32 = if cfg!(miri) { 100 } else { 10000 }; + const NTHREADS: u32 = 8; + let (tx, rx) = channel::(); + + let t = thread::spawn(move || { + for _ in 0..AMT * NTHREADS { + assert_eq!(rx.recv().unwrap(), 1); + } + match rx.try_recv() { + Ok(..) => panic!(), + _ => {} + } + }); + + for _ in 0..NTHREADS { + let tx = tx.clone(); + thread::spawn(move || { + for _ in 0..AMT { + tx.send(1).unwrap(); + } + }); + } + drop(tx); + t.join().ok().expect("thread panicked"); +} + +#[test] +fn send_from_outside_runtime() { + let (tx1, rx1) = channel::<()>(); + let (tx2, rx2) = channel::(); + let t1 = thread::spawn(move || { + tx1.send(()).unwrap(); + for _ in 0..40 { + assert_eq!(rx2.recv().unwrap(), 1); + } + }); + rx1.recv().unwrap(); + let t2 = thread::spawn(move || { + for _ in 0..40 { + tx2.send(1).unwrap(); + } + }); + t1.join().ok().expect("thread panicked"); + t2.join().ok().expect("thread panicked"); +} + +#[test] +fn recv_from_outside_runtime() { + let (tx, rx) = channel::(); + let t = thread::spawn(move || { + for _ in 0..40 { + assert_eq!(rx.recv().unwrap(), 1); + } + }); + for _ in 0..40 { + tx.send(1).unwrap(); + } + t.join().ok().expect("thread panicked"); +} + +#[test] +fn no_runtime() { + let (tx1, rx1) = channel::(); + let (tx2, rx2) = channel::(); + let t1 = thread::spawn(move || { + assert_eq!(rx1.recv().unwrap(), 1); + tx2.send(2).unwrap(); + }); + let t2 = thread::spawn(move || { + tx1.send(1).unwrap(); + assert_eq!(rx2.recv().unwrap(), 2); + }); + t1.join().ok().expect("thread panicked"); + t2.join().ok().expect("thread panicked"); +} + +#[test] +fn oneshot_single_thread_close_port_first() { + // Simple test of closing without sending + let (_tx, rx) = channel::(); + drop(rx); +} + +#[test] +fn oneshot_single_thread_close_chan_first() { + // Simple test of closing without sending + let (tx, _rx) = channel::(); + drop(tx); +} + +#[test] +fn oneshot_single_thread_send_port_close() { + // Testing that the sender cleans up the payload if receiver is closed + let (tx, rx) = channel::>(); + drop(rx); + assert!(tx.send(Box::new(0)).is_err()); +} + +#[test] +fn oneshot_single_thread_recv_chan_close() { + // Receiving on a closed chan will panic + let res = thread::spawn(move || { + let (tx, rx) = channel::(); + drop(tx); + rx.recv().unwrap(); + }) + .join(); + // What is our res? + assert!(res.is_err()); +} + +#[test] +fn oneshot_single_thread_send_then_recv() { + let (tx, rx) = channel::>(); + tx.send(Box::new(10)).unwrap(); + assert!(*rx.recv().unwrap() == 10); +} + +#[test] +fn oneshot_single_thread_try_send_open() { + let (tx, rx) = channel::(); + assert!(tx.send(10).is_ok()); + assert!(rx.recv().unwrap() == 10); +} + +#[test] +fn oneshot_single_thread_try_send_closed() { + let (tx, rx) = channel::(); + drop(rx); + assert!(tx.send(10).is_err()); +} + +#[test] +fn oneshot_single_thread_try_recv_open() { + let (tx, rx) = channel::(); + tx.send(10).unwrap(); + assert!(rx.recv() == Ok(10)); +} + +#[test] +fn oneshot_single_thread_try_recv_closed() { + let (tx, rx) = channel::(); + drop(tx); + assert!(rx.recv().is_err()); +} + +#[test] +fn oneshot_single_thread_peek_data() { + let (tx, rx) = channel::(); + assert_eq!(rx.try_recv(), Err(TryRecvError::Empty)); + tx.send(10).unwrap(); + assert_eq!(rx.try_recv(), Ok(10)); +} + +#[test] +fn oneshot_single_thread_peek_close() { + let (tx, rx) = channel::(); + drop(tx); + assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected)); + assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected)); +} + +#[test] +fn oneshot_single_thread_peek_open() { + let (_tx, rx) = channel::(); + assert_eq!(rx.try_recv(), Err(TryRecvError::Empty)); +} + +#[test] +fn oneshot_multi_task_recv_then_send() { + let (tx, rx) = channel::>(); + let _t = thread::spawn(move || { + assert!(*rx.recv().unwrap() == 10); + }); + + tx.send(Box::new(10)).unwrap(); +} + +#[test] +fn oneshot_multi_task_recv_then_close() { + let (tx, rx) = channel::>(); + let _t = thread::spawn(move || { + drop(tx); + }); + let res = thread::spawn(move || { + assert!(*rx.recv().unwrap() == 10); + }) + .join(); + assert!(res.is_err()); +} + +#[test] +fn oneshot_multi_thread_close_stress() { + for _ in 0..stress_factor() { + let (tx, rx) = channel::(); + let _t = thread::spawn(move || { + drop(rx); + }); + drop(tx); + } +} + +#[test] +fn oneshot_multi_thread_send_close_stress() { + for _ in 0..stress_factor() { + let (tx, rx) = channel::(); + let _t = thread::spawn(move || { + drop(rx); + }); + let _ = thread::spawn(move || { + tx.send(1).unwrap(); + }) + .join(); + } +} + +#[test] +fn oneshot_multi_thread_recv_close_stress() { + for _ in 0..stress_factor() { + let (tx, rx) = channel::(); + thread::spawn(move || { + let res = thread::spawn(move || { + rx.recv().unwrap(); + }) + .join(); + assert!(res.is_err()); + }); + let _t = thread::spawn(move || { + thread::spawn(move || { + drop(tx); + }); + }); + } +} + +#[test] +fn oneshot_multi_thread_send_recv_stress() { + for _ in 0..stress_factor() { + let (tx, rx) = channel::>(); + let _t = thread::spawn(move || { + tx.send(Box::new(10)).unwrap(); + }); + assert!(*rx.recv().unwrap() == 10); + } +} + +#[test] +fn stream_send_recv_stress() { + for _ in 0..stress_factor() { + let (tx, rx) = channel(); + + send(tx, 0); + recv(rx, 0); + + fn send(tx: Sender>, i: i32) { + if i == 10 { + return; + } + + thread::spawn(move || { + tx.send(Box::new(i)).unwrap(); + send(tx, i + 1); + }); + } + + fn recv(rx: Receiver>, i: i32) { + if i == 10 { + return; + } + + thread::spawn(move || { + assert!(*rx.recv().unwrap() == i); + recv(rx, i + 1); + }); + } + } +} + +#[test] +fn oneshot_single_thread_recv_timeout() { + let (tx, rx) = channel(); + tx.send(()).unwrap(); + assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Ok(())); + assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Err(RecvTimeoutError::Timeout)); + tx.send(()).unwrap(); + assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Ok(())); +} + +#[test] +fn stress_recv_timeout_two_threads() { + let (tx, rx) = channel(); + let stress = stress_factor() + 100; + let timeout = Duration::from_millis(100); + + thread::spawn(move || { + for i in 0..stress { + if i % 2 == 0 { + thread::sleep(timeout * 2); + } + tx.send(1usize).unwrap(); + } + }); + + let mut recv_count = 0; + loop { + match rx.recv_timeout(timeout) { + Ok(n) => { + assert_eq!(n, 1usize); + recv_count += 1; + } + Err(RecvTimeoutError::Timeout) => continue, + Err(RecvTimeoutError::Disconnected) => break, + } + } + + assert_eq!(recv_count, stress); +} + +#[test] +fn recv_timeout_upgrade() { + let (tx, rx) = channel::<()>(); + let timeout = Duration::from_millis(1); + let _tx_clone = tx.clone(); + + let start = Instant::now(); + assert_eq!(rx.recv_timeout(timeout), Err(RecvTimeoutError::Timeout)); + assert!(Instant::now() >= start + timeout); +} + +#[test] +fn stress_recv_timeout_shared() { + let (tx, rx) = channel(); + let stress = stress_factor() + 100; + + for i in 0..stress { + let tx = tx.clone(); + thread::spawn(move || { + thread::sleep(Duration::from_millis(i as u64 * 10)); + tx.send(1usize).unwrap(); + }); + } + + drop(tx); + + let mut recv_count = 0; + loop { + match rx.recv_timeout(Duration::from_millis(10)) { + Ok(n) => { + assert_eq!(n, 1usize); + recv_count += 1; + } + Err(RecvTimeoutError::Timeout) => continue, + Err(RecvTimeoutError::Disconnected) => break, + } + } + + assert_eq!(recv_count, stress); +} + +#[test] +fn very_long_recv_timeout_wont_panic() { + let (tx, rx) = channel::<()>(); + let join_handle = thread::spawn(move || rx.recv_timeout(Duration::from_secs(u64::MAX))); + thread::sleep(Duration::from_secs(1)); + assert!(tx.send(()).is_ok()); + assert_eq!(join_handle.join().unwrap(), Ok(())); +} + +#[test] +fn recv_a_lot() { + let count = if cfg!(miri) { 1000 } else { 10000 }; + // Regression test that we don't run out of stack in scheduler context + let (tx, rx) = channel(); + for _ in 0..count { + tx.send(()).unwrap(); + } + for _ in 0..count { + rx.recv().unwrap(); + } +} + +#[test] +fn shared_recv_timeout() { + let (tx, rx) = channel(); + let total = 5; + for _ in 0..total { + let tx = tx.clone(); + thread::spawn(move || { + tx.send(()).unwrap(); + }); + } + + for _ in 0..total { + rx.recv().unwrap(); + } + + assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Err(RecvTimeoutError::Timeout)); + tx.send(()).unwrap(); + assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Ok(())); +} + +#[test] +fn shared_chan_stress() { + let (tx, rx) = channel(); + let total = stress_factor() + 100; + for _ in 0..total { + let tx = tx.clone(); + thread::spawn(move || { + tx.send(()).unwrap(); + }); + } + + for _ in 0..total { + rx.recv().unwrap(); + } +} + +#[test] +fn test_nested_recv_iter() { + let (tx, rx) = channel::(); + let (total_tx, total_rx) = channel::(); + + let _t = thread::spawn(move || { + let mut acc = 0; + for x in rx.iter() { + acc += x; + } + total_tx.send(acc).unwrap(); + }); + + tx.send(3).unwrap(); + tx.send(1).unwrap(); + tx.send(2).unwrap(); + drop(tx); + assert_eq!(total_rx.recv().unwrap(), 6); +} + +#[test] +fn test_recv_iter_break() { + let (tx, rx) = channel::(); + let (count_tx, count_rx) = channel(); + + let _t = thread::spawn(move || { + let mut count = 0; + for x in rx.iter() { + if count >= 3 { + break; + } else { + count += x; + } + } + count_tx.send(count).unwrap(); + }); + + tx.send(2).unwrap(); + tx.send(2).unwrap(); + tx.send(2).unwrap(); + let _ = tx.send(2); + drop(tx); + assert_eq!(count_rx.recv().unwrap(), 4); +} + +#[test] +fn test_recv_try_iter() { + let (request_tx, request_rx) = channel(); + let (response_tx, response_rx) = channel(); + + // Request `x`s until we have `6`. + let t = thread::spawn(move || { + let mut count = 0; + loop { + for x in response_rx.try_iter() { + count += x; + if count == 6 { + return count; + } + } + request_tx.send(()).unwrap(); + } + }); + + for _ in request_rx.iter() { + if response_tx.send(2).is_err() { + break; + } + } + + assert_eq!(t.join().unwrap(), 6); +} + +#[test] +fn test_recv_into_iter_owned() { + let mut iter = { + let (tx, rx) = channel::(); + tx.send(1).unwrap(); + tx.send(2).unwrap(); + + rx.into_iter() + }; + assert_eq!(iter.next().unwrap(), 1); + assert_eq!(iter.next().unwrap(), 2); + assert_eq!(iter.next().is_none(), true); +} + +#[test] +fn test_recv_into_iter_borrowed() { + let (tx, rx) = channel::(); + tx.send(1).unwrap(); + tx.send(2).unwrap(); + drop(tx); + let mut iter = (&rx).into_iter(); + assert_eq!(iter.next().unwrap(), 1); + assert_eq!(iter.next().unwrap(), 2); + assert_eq!(iter.next().is_none(), true); +} + +#[test] +fn try_recv_states() { + let (tx1, rx1) = channel::(); + let (tx2, rx2) = channel::<()>(); + let (tx3, rx3) = channel::<()>(); + let _t = thread::spawn(move || { + rx2.recv().unwrap(); + tx1.send(1).unwrap(); + tx3.send(()).unwrap(); + rx2.recv().unwrap(); + drop(tx1); + tx3.send(()).unwrap(); + }); + + assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty)); + tx2.send(()).unwrap(); + rx3.recv().unwrap(); + assert_eq!(rx1.try_recv(), Ok(1)); + assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty)); + tx2.send(()).unwrap(); + rx3.recv().unwrap(); + assert_eq!(rx1.try_recv(), Err(TryRecvError::Disconnected)); +} + +// This bug used to end up in a livelock inside of the Receiver destructor +// because the internal state of the Shared packet was corrupted +#[test] +fn destroy_upgraded_shared_port_when_sender_still_active() { + let (tx, rx) = channel(); + let (tx2, rx2) = channel(); + let _t = thread::spawn(move || { + rx.recv().unwrap(); // wait on a oneshot + drop(rx); // destroy a shared + tx2.send(()).unwrap(); + }); + // make sure the other thread has gone to sleep + for _ in 0..5000 { + thread::yield_now(); + } + + // upgrade to a shared chan and send a message + let t = tx.clone(); + drop(tx); + t.send(()).unwrap(); + + // wait for the child thread to exit before we exit + rx2.recv().unwrap(); +} + +#[test] +fn issue_32114() { + let (tx, _) = channel(); + let _ = tx.send(123); + assert_eq!(tx.send(123), Err(SendError(123))); +} + +#[test] +fn issue_39364() { + let (tx, rx) = channel::<()>(); + let t = thread::spawn(move || { + thread::sleep(Duration::from_millis(300)); + let _ = tx.clone(); + // Don't drop; hand back to caller. + tx + }); + + let _ = rx.recv_timeout(Duration::from_millis(500)); + let _tx = t.join().unwrap(); // delay dropping until end of test + let _ = rx.recv_timeout(Duration::from_millis(500)); +} diff --git a/library/std/src/sync/mpmc/zero.rs b/library/std/src/sync/mpmc/zero.rs index 2451d7b79d19..446881291e68 100644 --- a/library/std/src/sync/mpmc/zero.rs +++ b/library/std/src/sync/mpmc/zero.rs @@ -185,11 +185,7 @@ impl Channel { // Prepare for blocking until a receiver wakes us up. let oper = Operation::hook(token); let mut packet = Packet::::message_on_stack(msg); - inner.senders.register_with_packet( - oper, - core::ptr::addr_of_mut!(packet) as *mut (), - cx, - ); + inner.senders.register_with_packet(oper, (&raw mut packet) as *mut (), cx); inner.receivers.notify(); drop(inner); @@ -256,11 +252,7 @@ impl Channel { // Prepare for blocking until a sender wakes us up. let oper = Operation::hook(token); let mut packet = Packet::::empty_on_stack(); - inner.receivers.register_with_packet( - oper, - core::ptr::addr_of_mut!(packet) as *mut (), - cx, - ); + inner.receivers.register_with_packet(oper, (&raw mut packet) as *mut (), cx); inner.senders.notify(); drop(inner); diff --git a/library/std/src/sync/mpsc/mod.rs b/library/std/src/sync/mpsc/mod.rs index 26d5b9515a24..83a93a063695 100644 --- a/library/std/src/sync/mpsc/mod.rs +++ b/library/std/src/sync/mpsc/mod.rs @@ -137,10 +137,10 @@ #![stable(feature = "rust1", since = "1.0.0")] -#[cfg(all(test, not(target_os = "emscripten")))] +#[cfg(all(test, not(any(target_os = "emscripten", target_os = "wasi"))))] mod tests; -#[cfg(all(test, not(target_os = "emscripten")))] +#[cfg(all(test, not(any(target_os = "emscripten", target_os = "wasi"))))] mod sync_tests; // MPSC channels are built as a wrapper around MPMC channels, which diff --git a/library/std/src/sync/mutex.rs b/library/std/src/sync/mutex.rs index f3de1f7bf495..fe2aca031a24 100644 --- a/library/std/src/sync/mutex.rs +++ b/library/std/src/sync/mutex.rs @@ -1,4 +1,4 @@ -#[cfg(all(test, not(target_os = "emscripten")))] +#[cfg(all(test, not(any(target_os = "emscripten", target_os = "wasi"))))] mod tests; use crate::cell::UnsafeCell; diff --git a/library/std/src/sync/once.rs b/library/std/src/sync/once.rs index 5a1cd7d0b8b1..993df9314fce 100644 --- a/library/std/src/sync/once.rs +++ b/library/std/src/sync/once.rs @@ -3,7 +3,7 @@ //! This primitive is meant to be used to run one-time initialization. An //! example use case would be for initializing an FFI library. -#[cfg(all(test, not(target_os = "emscripten")))] +#[cfg(all(test, not(any(target_os = "emscripten", target_os = "wasi"))))] mod tests; use crate::fmt; diff --git a/library/std/src/sync/once_lock/tests.rs b/library/std/src/sync/once_lock/tests.rs index 1fff3273d202..5113d436c3c9 100644 --- a/library/std/src/sync/once_lock/tests.rs +++ b/library/std/src/sync/once_lock/tests.rs @@ -9,7 +9,7 @@ fn spawn_and_wait(f: impl FnOnce() -> R + Send + 'static) -> } #[test] -#[cfg_attr(target_os = "emscripten", ignore)] +#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads fn sync_once_cell() { static ONCE_CELL: OnceLock = OnceLock::new(); @@ -43,7 +43,7 @@ fn sync_once_cell_get_unchecked() { } #[test] -#[cfg_attr(target_os = "emscripten", ignore)] +#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads fn sync_once_cell_drop() { static DROP_CNT: AtomicUsize = AtomicUsize::new(0); struct Dropper; @@ -81,6 +81,7 @@ fn clone() { } #[test] +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn get_or_try_init() { let cell: OnceLock = OnceLock::new(); assert!(cell.get().is_none()); @@ -154,7 +155,7 @@ fn eval_once_macro() { } #[test] -#[cfg_attr(target_os = "emscripten", ignore)] +#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads fn sync_once_cell_does_not_leak_partially_constructed_boxes() { static ONCE_CELL: OnceLock = OnceLock::new(); diff --git a/library/std/src/sync/reentrant_lock.rs b/library/std/src/sync/reentrant_lock.rs index 39f23a14441c..0140e0d21299 100644 --- a/library/std/src/sync/reentrant_lock.rs +++ b/library/std/src/sync/reentrant_lock.rs @@ -1,4 +1,4 @@ -#[cfg(all(test, not(target_os = "emscripten")))] +#[cfg(all(test, not(any(target_os = "emscripten", target_os = "wasi"))))] mod tests; use cfg_if::cfg_if; diff --git a/library/std/src/sync/rwlock.rs b/library/std/src/sync/rwlock.rs index 143bdef736d2..da2da6f9dfc5 100644 --- a/library/std/src/sync/rwlock.rs +++ b/library/std/src/sync/rwlock.rs @@ -1,4 +1,4 @@ -#[cfg(all(test, not(target_os = "emscripten")))] +#[cfg(all(test, not(any(target_os = "emscripten", target_os = "wasi"))))] mod tests; use crate::cell::UnsafeCell; diff --git a/library/std/src/sys/dbg.rs b/library/std/src/sys/dbg.rs deleted file mode 100644 index 7266a739e785..000000000000 --- a/library/std/src/sys/dbg.rs +++ /dev/null @@ -1,152 +0,0 @@ -//! Debugging aids. - -/// Presence of a debugger. The debugger being concerned -/// is expected to use the OS API to debug this process. -#[derive(Copy, Clone, Debug)] -#[allow(unused)] -pub(crate) enum DebuggerPresence { - /// The debugger is attached to this process. - Detected, - /// The debugger is not attached to this process. - NotDetected, -} - -#[cfg(target_os = "windows")] -mod os { - use super::DebuggerPresence; - - #[link(name = "kernel32")] - extern "system" { - fn IsDebuggerPresent() -> i32; - } - - pub(super) fn is_debugger_present() -> Option { - // SAFETY: No state is shared between threads. The call reads - // a field from the Thread Environment Block using the OS API - // as required by the documentation. - if unsafe { IsDebuggerPresent() } != 0 { - Some(DebuggerPresence::Detected) - } else { - Some(DebuggerPresence::NotDetected) - } - } -} - -#[cfg(any(target_vendor = "apple", target_os = "freebsd"))] -mod os { - use libc::{CTL_KERN, KERN_PROC, KERN_PROC_PID, c_int, sysctl}; - - use super::DebuggerPresence; - use crate::io::{Cursor, Read, Seek, SeekFrom}; - use crate::process; - - const P_TRACED: i32 = 0x00000800; - - // The assumption is that the kernel structures available to the - // user space may not shrink or repurpose the existing fields over - // time. The kernels normally adhere to that for the backward - // compatibility of the user space. - - // The macOS 14.5 SDK comes with a header `MacOSX14.5.sdk/usr/include/sys/sysctl.h` - // that defines `struct kinfo_proc` be of `648` bytes on the 64-bit system. That has - // not changed since macOS 10.13 (released in 2017) at least, validated by building - // a C program in XCode while changing the build target. Apple provides this example - // for reference: https://developer.apple.com/library/archive/qa/qa1361/_index.html. - #[cfg(target_vendor = "apple")] - const KINFO_PROC_SIZE: usize = if cfg!(target_pointer_width = "64") { 648 } else { 492 }; - #[cfg(target_vendor = "apple")] - const KINFO_PROC_FLAGS_OFFSET: u64 = if cfg!(target_pointer_width = "64") { 32 } else { 16 }; - - // Works for FreeBSD stable (13.3, 13.4) and current (14.0, 14.1). - // The size of the structure has stayed the same for a long time, - // at least since 2005: - // https://lists.freebsd.org/pipermail/freebsd-stable/2005-November/019899.html - #[cfg(target_os = "freebsd")] - const KINFO_PROC_SIZE: usize = if cfg!(target_pointer_width = "64") { 1088 } else { 768 }; - #[cfg(target_os = "freebsd")] - const KINFO_PROC_FLAGS_OFFSET: u64 = if cfg!(target_pointer_width = "64") { 368 } else { 296 }; - - pub(super) fn is_debugger_present() -> Option { - debug_assert_ne!(KINFO_PROC_SIZE, 0); - - let mut flags = [0u8; 4]; // `ki_flag` under FreeBSD and `p_flag` under macOS. - let mut mib = [CTL_KERN, KERN_PROC, KERN_PROC_PID, process::id() as c_int]; - let mut info_size = KINFO_PROC_SIZE; - let mut kinfo_proc = [0u8; KINFO_PROC_SIZE]; - - // SAFETY: No state is shared with other threads. The sysctl call - // is safe according to the documentation. - if unsafe { - sysctl( - mib.as_mut_ptr(), - mib.len() as u32, - kinfo_proc.as_mut_ptr().cast(), - &mut info_size, - core::ptr::null_mut(), - 0, - ) - } != 0 - { - return None; - } - debug_assert_eq!(info_size, KINFO_PROC_SIZE); - - let mut reader = Cursor::new(kinfo_proc); - reader.seek(SeekFrom::Start(KINFO_PROC_FLAGS_OFFSET)).ok()?; - reader.read_exact(&mut flags).ok()?; - // Just in case, not limiting this to the little-endian systems. - let flags = i32::from_ne_bytes(flags); - - if flags & P_TRACED != 0 { - Some(DebuggerPresence::Detected) - } else { - Some(DebuggerPresence::NotDetected) - } - } -} - -#[cfg(not(any(target_os = "windows", target_vendor = "apple", target_os = "freebsd")))] -mod os { - pub(super) fn is_debugger_present() -> Option { - None - } -} - -/// Detect the debugger presence. -/// -/// The code does not try to detect the debugger at all costs (e.g., when anti-debugger -/// tricks are at play), it relies on the interfaces provided by the OS. -/// -/// Return value: -/// * `None`: it's not possible to conclude whether the debugger is attached to this -/// process or not. When checking for the presence of the debugger, the detection logic -/// encountered an issue, such as the OS API throwing an error or the feature not being -/// implemented. -/// * `Some(DebuggerPresence::Detected)`: yes, the debugger is attached -/// to this process. -/// * `Some(DebuggerPresence::NotDetected)`: no, the debugger is not -/// attached to this process. -pub(crate) fn is_debugger_present() -> Option { - if cfg!(miri) { None } else { os::is_debugger_present() } -} - -/// Execute the breakpoint instruction if the debugger presence is detected. -/// Useful for breaking into the debugger without the need to set a breakpoint -/// in the debugger. -/// -/// Note that there is a race between attaching or detaching the debugger, and running the -/// breakpoint instruction. This is nonetheless memory-safe, like [`crate::process::abort`] -/// is. In case the debugger is attached and the function is about -/// to run the breakpoint instruction yet right before that the debugger detaches, the -/// process will crash due to running the breakpoint instruction and the debugger not -/// handling the trap exception. -pub(crate) fn breakpoint_if_debugging() -> Option { - let debugger_present = is_debugger_present(); - if let Some(DebuggerPresence::Detected) = debugger_present { - // SAFETY: Executing the breakpoint instruction. No state is shared - // or modified by this code. - unsafe { core::intrinsics::breakpoint() }; - } - - debugger_present -} diff --git a/library/std/src/sys/mod.rs b/library/std/src/sys/mod.rs index df25b84fbbe5..f17dd47deced 100644 --- a/library/std/src/sys/mod.rs +++ b/library/std/src/sys/mod.rs @@ -11,7 +11,6 @@ mod personality; pub mod anonymous_pipe; pub mod backtrace; pub mod cmath; -pub mod dbg; pub mod exit_guard; pub mod os_str; pub mod path; diff --git a/library/std/src/sys/os_str/bytes.rs b/library/std/src/sys/os_str/bytes.rs index 992767211d08..8e0609fe48c5 100644 --- a/library/std/src/sys/os_str/bytes.rs +++ b/library/std/src/sys/os_str/bytes.rs @@ -2,7 +2,6 @@ //! systems: just a `Vec`/`[u8]`. use core::clone::CloneToUninit; -use core::ptr::addr_of_mut; use crate::borrow::Cow; use crate::collections::TryReserveError; @@ -355,6 +354,6 @@ unsafe impl CloneToUninit for Slice { #[cfg_attr(debug_assertions, track_caller)] unsafe fn clone_to_uninit(&self, dst: *mut Self) { // SAFETY: we're just a wrapper around [u8] - unsafe { self.inner.clone_to_uninit(addr_of_mut!((*dst).inner)) } + unsafe { self.inner.clone_to_uninit(&raw mut (*dst).inner) } } } diff --git a/library/std/src/sys/os_str/wtf8.rs b/library/std/src/sys/os_str/wtf8.rs index 6fbbec7a9458..b3834388df68 100644 --- a/library/std/src/sys/os_str/wtf8.rs +++ b/library/std/src/sys/os_str/wtf8.rs @@ -1,7 +1,6 @@ //! The underlying OsString/OsStr implementation on Windows is a //! wrapper around the "WTF-8" encoding; see the `wtf8` module for more. use core::clone::CloneToUninit; -use core::ptr::addr_of_mut; use crate::borrow::Cow; use crate::collections::TryReserveError; @@ -278,6 +277,6 @@ unsafe impl CloneToUninit for Slice { #[cfg_attr(debug_assertions, track_caller)] unsafe fn clone_to_uninit(&self, dst: *mut Self) { // SAFETY: we're just a wrapper around Wtf8 - unsafe { self.inner.clone_to_uninit(addr_of_mut!((*dst).inner)) } + unsafe { self.inner.clone_to_uninit(&raw mut (*dst).inner) } } } diff --git a/library/std/src/sys/pal/hermit/net.rs b/library/std/src/sys/pal/hermit/net.rs index 416469c00373..d9baa091a232 100644 --- a/library/std/src/sys/pal/hermit/net.rs +++ b/library/std/src/sys/pal/hermit/net.rs @@ -192,7 +192,7 @@ impl Socket { buf.as_mut_ptr(), buf.len(), flags, - core::ptr::addr_of_mut!(storage) as *mut _, + (&raw mut storage) as *mut _, &mut addrlen, ) })?; @@ -298,7 +298,7 @@ impl Socket { netc::ioctl( self.as_raw_fd(), netc::FIONBIO, - core::ptr::addr_of_mut!(nonblocking) as *mut core::ffi::c_void, + (&raw mut nonblocking) as *mut core::ffi::c_void, ) }) .map(drop) diff --git a/library/std/src/sys/pal/hermit/time.rs b/library/std/src/sys/pal/hermit/time.rs index 99166b15602a..e0b6eb76b03a 100644 --- a/library/std/src/sys/pal/hermit/time.rs +++ b/library/std/src/sys/pal/hermit/time.rs @@ -107,8 +107,7 @@ pub struct Instant(Timespec); impl Instant { pub fn now() -> Instant { let mut time: Timespec = Timespec::zero(); - let _ = - unsafe { hermit_abi::clock_gettime(CLOCK_MONOTONIC, core::ptr::addr_of_mut!(time.t)) }; + let _ = unsafe { hermit_abi::clock_gettime(CLOCK_MONOTONIC, &raw mut time.t) }; Instant(time) } @@ -209,8 +208,7 @@ impl SystemTime { pub fn now() -> SystemTime { let mut time: Timespec = Timespec::zero(); - let _ = - unsafe { hermit_abi::clock_gettime(CLOCK_REALTIME, core::ptr::addr_of_mut!(time.t)) }; + let _ = unsafe { hermit_abi::clock_gettime(CLOCK_REALTIME, &raw mut time.t) }; SystemTime(time) } diff --git a/library/std/src/sys/pal/unix/fs.rs b/library/std/src/sys/pal/unix/fs.rs index 86342c2add0e..39aabf0b2d67 100644 --- a/library/std/src/sys/pal/unix/fs.rs +++ b/library/std/src/sys/pal/unix/fs.rs @@ -740,7 +740,7 @@ impl Iterator for ReadDir { // // Like for uninitialized contents, converting entry_ptr to `&dirent64` // would not be legal. However, unique to dirent64 is that we don't even - // get to use `addr_of!((*entry_ptr).d_name)` because that operation + // get to use `&raw const (*entry_ptr).d_name` because that operation // requires the full extent of *entry_ptr to be in bounds of the same // allocation, which is not necessarily the case here. // @@ -754,7 +754,7 @@ impl Iterator for ReadDir { } else { #[allow(deref_nullptr)] { - ptr::addr_of!((*ptr::null::()).$field) + &raw const (*ptr::null::()).$field } } }}; @@ -1385,7 +1385,7 @@ impl File { } cvt(unsafe { libc::fsetattrlist( self.as_raw_fd(), - core::ptr::addr_of!(attrlist).cast::().cast_mut(), + (&raw const attrlist).cast::().cast_mut(), buf.as_ptr().cast::().cast_mut(), num_times * mem::size_of::(), 0 @@ -1944,7 +1944,7 @@ pub fn copy(from: &Path, to: &Path) -> io::Result { libc::copyfile_state_get( state.0, libc::COPYFILE_STATE_COPIED as u32, - core::ptr::addr_of_mut!(bytes_copied) as *mut libc::c_void, + (&raw mut bytes_copied) as *mut libc::c_void, ) })?; Ok(bytes_copied as u64) diff --git a/library/std/src/sys/pal/unix/net.rs b/library/std/src/sys/pal/unix/net.rs index 0f2e015bbcdd..6a67bb0a101e 100644 --- a/library/std/src/sys/pal/unix/net.rs +++ b/library/std/src/sys/pal/unix/net.rs @@ -329,7 +329,7 @@ impl Socket { buf.as_mut_ptr() as *mut c_void, buf.len(), flags, - core::ptr::addr_of_mut!(storage) as *mut _, + (&raw mut storage) as *mut _, &mut addrlen, ) })?; diff --git a/library/std/src/sys/pal/unix/os.rs b/library/std/src/sys/pal/unix/os.rs index d99bde2f9a50..f983d174ed61 100644 --- a/library/std/src/sys/pal/unix/os.rs +++ b/library/std/src/sys/pal/unix/os.rs @@ -612,7 +612,7 @@ pub unsafe fn environ() -> *mut *const *const c_char { extern "C" { static mut environ: *const *const c_char; } - ptr::addr_of_mut!(environ) + &raw mut environ } static ENV_LOCK: RwLock<()> = RwLock::new(()); diff --git a/library/std/src/sys/pal/unix/process/process_fuchsia.rs b/library/std/src/sys/pal/unix/process/process_fuchsia.rs index 34ff464aa37f..5d0110cf55dc 100644 --- a/library/std/src/sys/pal/unix/process/process_fuchsia.rs +++ b/library/std/src/sys/pal/unix/process/process_fuchsia.rs @@ -178,7 +178,7 @@ impl Process { zx_cvt(zx_object_get_info( self.handle.raw(), ZX_INFO_PROCESS, - core::ptr::addr_of_mut!(proc_info) as *mut libc::c_void, + (&raw mut proc_info) as *mut libc::c_void, mem::size_of::(), &mut actual, &mut avail, @@ -215,7 +215,7 @@ impl Process { zx_cvt(zx_object_get_info( self.handle.raw(), ZX_INFO_PROCESS, - core::ptr::addr_of_mut!(proc_info) as *mut libc::c_void, + (&raw mut proc_info) as *mut libc::c_void, mem::size_of::(), &mut actual, &mut avail, diff --git a/library/std/src/sys/pal/unix/process/process_unix.rs b/library/std/src/sys/pal/unix/process/process_unix.rs index d812aa0e02cf..5d30f388da18 100644 --- a/library/std/src/sys/pal/unix/process/process_unix.rs +++ b/library/std/src/sys/pal/unix/process/process_unix.rs @@ -788,15 +788,15 @@ impl Command { let mut iov = [IoSlice::new(b"")]; let mut msg: libc::msghdr = mem::zeroed(); - msg.msg_iov = core::ptr::addr_of_mut!(iov) as *mut _; + msg.msg_iov = (&raw mut iov) as *mut _; msg.msg_iovlen = 1; // only attach cmsg if we successfully acquired the pidfd if pidfd >= 0 { msg.msg_controllen = mem::size_of_val(&cmsg.buf) as _; - msg.msg_control = core::ptr::addr_of_mut!(cmsg.buf) as *mut _; + msg.msg_control = (&raw mut cmsg.buf) as *mut _; - let hdr = CMSG_FIRSTHDR(core::ptr::addr_of_mut!(msg) as *mut _); + let hdr = CMSG_FIRSTHDR((&raw mut msg) as *mut _); (*hdr).cmsg_level = SOL_SOCKET; (*hdr).cmsg_type = SCM_RIGHTS; (*hdr).cmsg_len = CMSG_LEN(SCM_MSG_LEN as _) as _; @@ -838,17 +838,17 @@ impl Command { let mut msg: libc::msghdr = mem::zeroed(); - msg.msg_iov = core::ptr::addr_of_mut!(iov) as *mut _; + msg.msg_iov = (&raw mut iov) as *mut _; msg.msg_iovlen = 1; msg.msg_controllen = mem::size_of::() as _; - msg.msg_control = core::ptr::addr_of_mut!(cmsg) as *mut _; + msg.msg_control = (&raw mut cmsg) as *mut _; match cvt_r(|| libc::recvmsg(sock.as_raw(), &mut msg, libc::MSG_CMSG_CLOEXEC)) { Err(_) => return -1, Ok(_) => {} } - let hdr = CMSG_FIRSTHDR(core::ptr::addr_of_mut!(msg) as *mut _); + let hdr = CMSG_FIRSTHDR((&raw mut msg) as *mut _); if hdr.is_null() || (*hdr).cmsg_level != SOL_SOCKET || (*hdr).cmsg_type != SCM_RIGHTS diff --git a/library/std/src/sys/pal/unix/stack_overflow.rs b/library/std/src/sys/pal/unix/stack_overflow.rs index e0a0d0973c65..ac0858e1de87 100644 --- a/library/std/src/sys/pal/unix/stack_overflow.rs +++ b/library/std/src/sys/pal/unix/stack_overflow.rs @@ -426,8 +426,8 @@ mod imp { match sysctlbyname.get() { Some(fcn) if unsafe { fcn(oid.as_ptr(), - ptr::addr_of_mut!(guard).cast(), - ptr::addr_of_mut!(size), + (&raw mut guard).cast(), + &raw mut size, ptr::null_mut(), 0) == 0 } => guard, diff --git a/library/std/src/sys/pal/unix/thread.rs b/library/std/src/sys/pal/unix/thread.rs index cb6133274d9c..2f2d6e6add39 100644 --- a/library/std/src/sys/pal/unix/thread.rs +++ b/library/std/src/sys/pal/unix/thread.rs @@ -258,7 +258,7 @@ impl Thread { tv_nsec: nsecs, }; secs -= ts.tv_sec as u64; - let ts_ptr = core::ptr::addr_of_mut!(ts); + let ts_ptr = &raw mut ts; if libc::nanosleep(ts_ptr, ts_ptr) == -1 { assert_eq!(os::errno(), libc::EINTR); secs += ts.tv_sec as u64; @@ -447,8 +447,8 @@ pub fn available_parallelism() -> io::Result> { libc::sysctl( mib.as_mut_ptr(), 2, - core::ptr::addr_of_mut!(cpus) as *mut _, - core::ptr::addr_of_mut!(cpus_size) as *mut _, + (&raw mut cpus) as *mut _, + (&raw mut cpus_size) as *mut _, ptr::null_mut(), 0, ) diff --git a/library/std/src/sys/pal/wasip2/mod.rs b/library/std/src/sys/pal/wasip2/mod.rs index 17b26543bd75..320712fdcc9f 100644 --- a/library/std/src/sys/pal/wasip2/mod.rs +++ b/library/std/src/sys/pal/wasip2/mod.rs @@ -20,7 +20,6 @@ pub mod futex; #[path = "../wasi/io.rs"] pub mod io; -#[path = "../wasi/net.rs"] pub mod net; #[path = "../wasi/os.rs"] pub mod os; diff --git a/library/std/src/sys/pal/wasip2/net.rs b/library/std/src/sys/pal/wasip2/net.rs new file mode 100644 index 000000000000..c40eb229ba9a --- /dev/null +++ b/library/std/src/sys/pal/wasip2/net.rs @@ -0,0 +1,379 @@ +#![deny(unsafe_op_in_unsafe_fn)] + +use libc::{c_int, c_void, size_t}; + +use super::fd::WasiFd; +use crate::ffi::CStr; +use crate::io::{self, BorrowedBuf, BorrowedCursor, IoSlice, IoSliceMut}; +use crate::net::{Shutdown, SocketAddr}; +use crate::os::wasi::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd}; +use crate::sys::unsupported; +use crate::sys_common::net::{TcpListener, getsockopt, setsockopt, sockaddr_to_addr}; +use crate::sys_common::{AsInner, FromInner, IntoInner}; +use crate::time::{Duration, Instant}; +use crate::{cmp, mem, str}; + +pub extern crate libc as netc; + +#[allow(non_camel_case_types)] +pub type wrlen_t = size_t; + +#[doc(hidden)] +pub trait IsMinusOne { + fn is_minus_one(&self) -> bool; +} + +macro_rules! impl_is_minus_one { + ($($t:ident)*) => ($(impl IsMinusOne for $t { + fn is_minus_one(&self) -> bool { + *self == -1 + } + })*) +} + +impl_is_minus_one! { i8 i16 i32 i64 isize } + +pub fn cvt(t: T) -> crate::io::Result { + if t.is_minus_one() { Err(crate::io::Error::last_os_error()) } else { Ok(t) } +} + +pub fn cvt_r(mut f: F) -> crate::io::Result +where + T: IsMinusOne, + F: FnMut() -> T, +{ + loop { + match cvt(f()) { + Err(ref e) if e.is_interrupted() => {} + other => return other, + } + } +} + +pub fn cvt_gai(err: c_int) -> io::Result<()> { + if err == 0 { + return Ok(()); + } + + if err == netc::EAI_SYSTEM { + return Err(io::Error::last_os_error()); + } + + let detail = unsafe { + str::from_utf8(CStr::from_ptr(netc::gai_strerror(err)).to_bytes()).unwrap().to_owned() + }; + + Err(io::Error::new( + io::ErrorKind::Uncategorized, + &format!("failed to lookup address information: {detail}")[..], + )) +} + +pub fn init() {} + +pub struct Socket(WasiFd); + +impl Socket { + pub fn new(addr: &SocketAddr, ty: c_int) -> io::Result { + let fam = match *addr { + SocketAddr::V4(..) => netc::AF_INET, + SocketAddr::V6(..) => netc::AF_INET6, + }; + Socket::new_raw(fam, ty) + } + + pub fn new_raw(fam: c_int, ty: c_int) -> io::Result { + let fd = cvt(unsafe { netc::socket(fam, ty, 0) })?; + Ok(unsafe { Self::from_raw_fd(fd) }) + } + + pub fn connect(&self, addr: &SocketAddr) -> io::Result<()> { + let (addr, len) = addr.into_inner(); + cvt_r(|| unsafe { netc::connect(self.as_raw_fd(), addr.as_ptr(), len) })?; + Ok(()) + } + + pub fn connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Result<()> { + self.set_nonblocking(true)?; + let r = self.connect(addr); + self.set_nonblocking(false)?; + + match r { + Ok(_) => return Ok(()), + // there's no ErrorKind for EINPROGRESS + Err(ref e) if e.raw_os_error() == Some(netc::EINPROGRESS) => {} + Err(e) => return Err(e), + } + + let mut pollfd = netc::pollfd { fd: self.as_raw_fd(), events: netc::POLLOUT, revents: 0 }; + + if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 { + return Err(io::Error::ZERO_TIMEOUT); + } + + let start = Instant::now(); + + loop { + let elapsed = start.elapsed(); + if elapsed >= timeout { + return Err(io::const_io_error!(io::ErrorKind::TimedOut, "connection timed out")); + } + + let timeout = timeout - elapsed; + let mut timeout = timeout + .as_secs() + .saturating_mul(1_000) + .saturating_add(timeout.subsec_nanos() as u64 / 1_000_000); + if timeout == 0 { + timeout = 1; + } + + let timeout = cmp::min(timeout, c_int::MAX as u64) as c_int; + + match unsafe { netc::poll(&mut pollfd, 1, timeout) } { + -1 => { + let err = io::Error::last_os_error(); + if !err.is_interrupted() { + return Err(err); + } + } + 0 => {} + _ => { + // WASI poll does not return POLLHUP or POLLERR in revents. Check if the + // connnection actually succeeded and return ok only when the socket is + // ready and no errors were found. + if let Some(e) = self.take_error()? { + return Err(e); + } + + return Ok(()); + } + } + } + } + + pub fn accept( + &self, + storage: *mut netc::sockaddr, + len: *mut netc::socklen_t, + ) -> io::Result { + let fd = cvt_r(|| unsafe { netc::accept(self.as_raw_fd(), storage, len) })?; + Ok(unsafe { Self::from_raw_fd(fd) }) + } + + pub fn duplicate(&self) -> io::Result { + unsupported() + } + + fn recv_with_flags(&self, mut buf: BorrowedCursor<'_>, flags: c_int) -> io::Result<()> { + let ret = cvt(unsafe { + netc::recv( + self.as_raw_fd(), + buf.as_mut().as_mut_ptr() as *mut c_void, + buf.capacity(), + flags, + ) + })?; + unsafe { + buf.advance_unchecked(ret as usize); + } + Ok(()) + } + + pub fn read(&self, buf: &mut [u8]) -> io::Result { + let mut buf = BorrowedBuf::from(buf); + self.recv_with_flags(buf.unfilled(), 0)?; + Ok(buf.len()) + } + + pub fn peek(&self, buf: &mut [u8]) -> io::Result { + let mut buf = BorrowedBuf::from(buf); + self.recv_with_flags(buf.unfilled(), netc::MSG_PEEK)?; + Ok(buf.len()) + } + + pub fn read_buf(&self, buf: BorrowedCursor<'_>) -> io::Result<()> { + self.recv_with_flags(buf, 0) + } + + pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { + io::default_read_vectored(|b| self.read(b), bufs) + } + + #[inline] + pub fn is_read_vectored(&self) -> bool { + false + } + + fn recv_from_with_flags( + &self, + buf: &mut [u8], + flags: c_int, + ) -> io::Result<(usize, SocketAddr)> { + let mut storage: netc::sockaddr_storage = unsafe { mem::zeroed() }; + let mut addrlen = mem::size_of_val(&storage) as netc::socklen_t; + + let n = cvt(unsafe { + netc::recvfrom( + self.as_raw_fd(), + buf.as_mut_ptr() as *mut c_void, + buf.len(), + flags, + core::ptr::addr_of_mut!(storage) as *mut _, + &mut addrlen, + ) + })?; + Ok((n as usize, sockaddr_to_addr(&storage, addrlen as usize)?)) + } + + pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { + self.recv_from_with_flags(buf, 0) + } + + pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { + self.recv_from_with_flags(buf, netc::MSG_PEEK) + } + + fn write(&self, buf: &[u8]) -> io::Result { + let len = cmp::min(buf.len(), ::MAX as usize) as wrlen_t; + let ret = cvt(unsafe { + netc::send(self.as_raw(), buf.as_ptr() as *const c_void, len, netc::MSG_NOSIGNAL) + })?; + Ok(ret as usize) + } + + pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { + io::default_write_vectored(|b| self.write(b), bufs) + } + + #[inline] + pub fn is_write_vectored(&self) -> bool { + false + } + + pub fn set_timeout(&self, dur: Option, kind: c_int) -> io::Result<()> { + let timeout = match dur { + Some(dur) => { + if dur.as_secs() == 0 && dur.subsec_nanos() == 0 { + return Err(io::Error::ZERO_TIMEOUT); + } + + let secs = dur.as_secs().try_into().unwrap_or(netc::time_t::MAX); + let mut timeout = netc::timeval { + tv_sec: secs, + tv_usec: dur.subsec_micros() as netc::suseconds_t, + }; + if timeout.tv_sec == 0 && timeout.tv_usec == 0 { + timeout.tv_usec = 1; + } + timeout + } + None => netc::timeval { tv_sec: 0, tv_usec: 0 }, + }; + setsockopt(self, netc::SOL_SOCKET, kind, timeout) + } + + pub fn timeout(&self, kind: c_int) -> io::Result> { + let raw: netc::timeval = getsockopt(self, netc::SOL_SOCKET, kind)?; + if raw.tv_sec == 0 && raw.tv_usec == 0 { + Ok(None) + } else { + let sec = raw.tv_sec as u64; + let nsec = (raw.tv_usec as u32) * 1000; + Ok(Some(Duration::new(sec, nsec))) + } + } + + pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { + let how = match how { + Shutdown::Write => netc::SHUT_WR, + Shutdown::Read => netc::SHUT_RD, + Shutdown::Both => netc::SHUT_RDWR, + }; + cvt(unsafe { netc::shutdown(self.as_raw_fd(), how) })?; + Ok(()) + } + + pub fn set_linger(&self, _linger: Option) -> io::Result<()> { + unsupported() + } + + pub fn linger(&self) -> io::Result> { + unsupported() + } + + pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> { + setsockopt(self, netc::IPPROTO_TCP, netc::TCP_NODELAY, nodelay as c_int) + } + + pub fn nodelay(&self) -> io::Result { + let raw: c_int = getsockopt(self, netc::IPPROTO_TCP, netc::TCP_NODELAY)?; + Ok(raw != 0) + } + + pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { + let mut nonblocking = nonblocking as c_int; + cvt(unsafe { netc::ioctl(self.as_raw_fd(), netc::FIONBIO, &mut nonblocking) }).map(drop) + } + + pub fn take_error(&self) -> io::Result> { + let raw: c_int = getsockopt(self, netc::SOL_SOCKET, netc::SO_ERROR)?; + if raw == 0 { Ok(None) } else { Ok(Some(io::Error::from_raw_os_error(raw as i32))) } + } + + // This is used by sys_common code to abstract over Windows and Unix. + pub fn as_raw(&self) -> RawFd { + self.as_raw_fd() + } +} + +impl AsInner for Socket { + #[inline] + fn as_inner(&self) -> &WasiFd { + &self.0 + } +} + +impl IntoInner for Socket { + fn into_inner(self) -> WasiFd { + self.0 + } +} + +impl FromInner for Socket { + fn from_inner(inner: WasiFd) -> Socket { + Socket(inner) + } +} + +impl AsFd for Socket { + fn as_fd(&self) -> BorrowedFd<'_> { + self.0.as_fd() + } +} + +impl AsRawFd for Socket { + #[inline] + fn as_raw_fd(&self) -> RawFd { + self.0.as_raw_fd() + } +} + +impl IntoRawFd for Socket { + fn into_raw_fd(self) -> RawFd { + self.0.into_raw_fd() + } +} + +impl FromRawFd for Socket { + unsafe fn from_raw_fd(raw_fd: RawFd) -> Self { + unsafe { Self(FromRawFd::from_raw_fd(raw_fd)) } + } +} + +impl AsInner for TcpListener { + #[inline] + fn as_inner(&self) -> &Socket { + &self.socket() + } +} diff --git a/library/std/src/sys/pal/windows/api.rs b/library/std/src/sys/pal/windows/api.rs index 9e336ff2d473..ebe207fde935 100644 --- a/library/std/src/sys/pal/windows/api.rs +++ b/library/std/src/sys/pal/windows/api.rs @@ -30,7 +30,6 @@ //! should go in sys/pal/windows/mod.rs rather than here. See `IoResult` as an example. use core::ffi::c_void; -use core::ptr::addr_of; use super::c; @@ -186,7 +185,7 @@ unsafe trait SizedSetFileInformation: Sized { unsafe impl SetFileInformation for T { const CLASS: i32 = T::CLASS; fn as_ptr(&self) -> *const c_void { - addr_of!(*self).cast::() + (&raw const *self).cast::() } fn size(&self) -> u32 { win32_size_of::() diff --git a/library/std/src/sys/pal/windows/fs.rs b/library/std/src/sys/pal/windows/fs.rs index be26356bb406..aab471e28eae 100644 --- a/library/std/src/sys/pal/windows/fs.rs +++ b/library/std/src/sys/pal/windows/fs.rs @@ -1,5 +1,3 @@ -use core::ptr::addr_of; - use super::api::{self, WinError}; use super::{IoResult, to_u16s}; use crate::borrow::Cow; @@ -325,7 +323,7 @@ impl File { let result = c::SetFileInformationByHandle( handle.as_raw_handle(), c::FileEndOfFileInfo, - ptr::addr_of!(eof).cast::(), + (&raw const eof).cast::(), mem::size_of::() as u32, ); if result == 0 { @@ -364,7 +362,7 @@ impl File { cvt(c::GetFileInformationByHandleEx( self.handle.as_raw_handle(), c::FileAttributeTagInfo, - ptr::addr_of_mut!(attr_tag).cast(), + (&raw mut attr_tag).cast(), mem::size_of::().try_into().unwrap(), ))?; if attr_tag.FileAttributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 { @@ -396,7 +394,7 @@ impl File { cvt(c::GetFileInformationByHandleEx( self.handle.as_raw_handle(), c::FileBasicInfo, - core::ptr::addr_of_mut!(info) as *mut c_void, + (&raw mut info) as *mut c_void, size as u32, ))?; let mut attr = FileAttr { @@ -428,7 +426,7 @@ impl File { cvt(c::GetFileInformationByHandleEx( self.handle.as_raw_handle(), c::FileStandardInfo, - core::ptr::addr_of_mut!(info) as *mut c_void, + (&raw mut info) as *mut c_void, size as u32, ))?; attr.file_size = info.AllocationSize as u64; @@ -438,7 +436,7 @@ impl File { cvt(c::GetFileInformationByHandleEx( self.handle.as_raw_handle(), c::FileAttributeTagInfo, - ptr::addr_of_mut!(attr_tag).cast(), + (&raw mut attr_tag).cast(), mem::size_of::().try_into().unwrap(), ))?; if attr_tag.FileAttributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 { @@ -545,22 +543,20 @@ impl File { unsafe { let (path_buffer, subst_off, subst_len, relative) = match (*buf).ReparseTag { c::IO_REPARSE_TAG_SYMLINK => { - let info: *mut c::SYMBOLIC_LINK_REPARSE_BUFFER = - ptr::addr_of_mut!((*buf).rest).cast(); + let info: *mut c::SYMBOLIC_LINK_REPARSE_BUFFER = (&raw mut (*buf).rest).cast(); assert!(info.is_aligned()); ( - ptr::addr_of_mut!((*info).PathBuffer).cast::(), + (&raw mut (*info).PathBuffer).cast::(), (*info).SubstituteNameOffset / 2, (*info).SubstituteNameLength / 2, (*info).Flags & c::SYMLINK_FLAG_RELATIVE != 0, ) } c::IO_REPARSE_TAG_MOUNT_POINT => { - let info: *mut c::MOUNT_POINT_REPARSE_BUFFER = - ptr::addr_of_mut!((*buf).rest).cast(); + let info: *mut c::MOUNT_POINT_REPARSE_BUFFER = (&raw mut (*buf).rest).cast(); assert!(info.is_aligned()); ( - ptr::addr_of_mut!((*info).PathBuffer).cast::(), + (&raw mut (*info).PathBuffer).cast::(), (*info).SubstituteNameOffset / 2, (*info).SubstituteNameLength / 2, false, @@ -643,7 +639,7 @@ impl File { cvt(c::GetFileInformationByHandleEx( self.handle.as_raw_handle(), c::FileBasicInfo, - core::ptr::addr_of_mut!(info) as *mut c_void, + (&raw mut info) as *mut c_void, size as u32, ))?; Ok(info) @@ -790,11 +786,11 @@ impl<'a> Iterator for DirBuffIter<'a> { // it does not seem that reality is so kind, and assuming this // caused crashes in some cases (https://github.com/rust-lang/rust/issues/104530) // presumably, this can be blamed on buggy filesystem drivers, but who knows. - let next_entry = ptr::addr_of!((*info).NextEntryOffset).read_unaligned() as usize; - let length = ptr::addr_of!((*info).FileNameLength).read_unaligned() as usize; - let attrs = ptr::addr_of!((*info).FileAttributes).read_unaligned(); + let next_entry = (&raw const (*info).NextEntryOffset).read_unaligned() as usize; + let length = (&raw const (*info).FileNameLength).read_unaligned() as usize; + let attrs = (&raw const (*info).FileAttributes).read_unaligned(); let name = from_maybe_unaligned( - ptr::addr_of!((*info).FileName).cast::(), + (&raw const (*info).FileName).cast::(), length / size_of::(), ); let is_directory = (attrs & c::FILE_ATTRIBUTE_DIRECTORY) != 0; @@ -1326,7 +1322,7 @@ pub fn copy(from: &Path, to: &Path) -> io::Result { pfrom.as_ptr(), pto.as_ptr(), Some(callback), - core::ptr::addr_of_mut!(size) as *mut _, + (&raw mut size) as *mut _, ptr::null_mut(), 0, ) @@ -1405,7 +1401,7 @@ pub fn junction_point(original: &Path, link: &Path) -> io::Result<()> { cvt(c::DeviceIoControl( d.as_raw_handle(), c::FSCTL_SET_REPARSE_POINT, - addr_of!(header).cast::(), + (&raw const header).cast::(), data_len as u32 + 8, ptr::null_mut(), 0, diff --git a/library/std/src/sys/pal/windows/futex.rs b/library/std/src/sys/pal/windows/futex.rs index f16a9f534a3e..4d6c4df9a5a9 100644 --- a/library/std/src/sys/pal/windows/futex.rs +++ b/library/std/src/sys/pal/windows/futex.rs @@ -57,7 +57,7 @@ pub fn wait_on_address( unsafe { let addr = ptr::from_ref(address).cast::(); let size = mem::size_of::(); - let compare_addr = ptr::addr_of!(compare).cast::(); + let compare_addr = (&raw const compare).cast::(); let timeout = timeout.map(dur2timeout).unwrap_or(c::INFINITE); c::WaitOnAddress(addr, compare_addr, size, timeout) == c::TRUE } diff --git a/library/std/src/sys/pal/windows/io.rs b/library/std/src/sys/pal/windows/io.rs index 785a3f6768b7..1e7d02908f63 100644 --- a/library/std/src/sys/pal/windows/io.rs +++ b/library/std/src/sys/pal/windows/io.rs @@ -122,7 +122,7 @@ fn msys_tty_on(handle: BorrowedHandle<'_>) -> bool { c::GetFileInformationByHandleEx( handle.as_raw_handle(), c::FileNameInfo, - core::ptr::addr_of_mut!(name_info) as *mut c_void, + (&raw mut name_info) as *mut c_void, size_of::() as u32, ) }; diff --git a/library/std/src/sys/pal/windows/net.rs b/library/std/src/sys/pal/windows/net.rs index 61a4504cf654..fd62d1f407c2 100644 --- a/library/std/src/sys/pal/windows/net.rs +++ b/library/std/src/sys/pal/windows/net.rs @@ -390,7 +390,7 @@ impl Socket { buf.as_mut_ptr() as *mut _, length, flags, - core::ptr::addr_of_mut!(storage) as *mut _, + (&raw mut storage) as *mut _, &mut addrlen, ) }; diff --git a/library/std/src/sys/pal/windows/pipe.rs b/library/std/src/sys/pal/windows/pipe.rs index d8200ef9ca46..a8f6617c9dc8 100644 --- a/library/std/src/sys/pal/windows/pipe.rs +++ b/library/std/src/sys/pal/windows/pipe.rs @@ -375,7 +375,7 @@ impl AnonPipe { let mut overlapped: c::OVERLAPPED = unsafe { crate::mem::zeroed() }; // `hEvent` is unused by `ReadFileEx` and `WriteFileEx`. // Therefore the documentation suggests using it to smuggle a pointer to the callback. - overlapped.hEvent = core::ptr::addr_of_mut!(async_result) as *mut _; + overlapped.hEvent = (&raw mut async_result) as *mut _; // Asynchronous read of the pipe. // If successful, `callback` will be called once it completes. diff --git a/library/std/src/sys/pal/windows/process.rs b/library/std/src/sys/pal/windows/process.rs index 93a6c45ce300..95b51e704f9d 100644 --- a/library/std/src/sys/pal/windows/process.rs +++ b/library/std/src/sys/pal/windows/process.rs @@ -368,10 +368,10 @@ impl Command { StartupInfo: si, lpAttributeList: proc_thread_attribute_list.0.as_mut_ptr() as _, }; - si_ptr = core::ptr::addr_of_mut!(si_ex) as _; + si_ptr = (&raw mut si_ex) as _; } else { si.cb = mem::size_of::() as u32; - si_ptr = core::ptr::addr_of_mut!(si) as _; + si_ptr = (&raw mut si) as _; } unsafe { @@ -953,7 +953,7 @@ fn make_proc_thread_attribute_list( // It's theoretically possible for the attribute count to exceed a u32 value. // Therefore, we ensure that we don't add more attributes than the buffer was initialized for. for (&attribute, value) in attributes.iter().take(attribute_count as usize) { - let value_ptr = core::ptr::addr_of!(*value.data) as _; + let value_ptr = (&raw const *value.data) as _; cvt(unsafe { c::UpdateProcThreadAttribute( proc_thread_attribute_list.0.as_mut_ptr() as _, diff --git a/library/std/src/sys/sync/thread_parking/pthread.rs b/library/std/src/sys/sync/thread_parking/pthread.rs index c64600e9e29c..5f195d0bb0cf 100644 --- a/library/std/src/sys/sync/thread_parking/pthread.rs +++ b/library/std/src/sys/sync/thread_parking/pthread.rs @@ -3,7 +3,6 @@ use crate::cell::UnsafeCell; use crate::marker::PhantomPinned; use crate::pin::Pin; -use crate::ptr::addr_of_mut; use crate::sync::atomic::AtomicUsize; use crate::sync::atomic::Ordering::{Acquire, Relaxed, Release}; #[cfg(not(target_os = "nto"))] @@ -101,8 +100,8 @@ impl Parker { // This could lead to undefined behaviour when deadlocking. This is avoided // by not deadlocking. Note in particular the unlocking operation before any // panic, as code after the panic could try to park again. - addr_of_mut!((*parker).state).write(AtomicUsize::new(EMPTY)); - addr_of_mut!((*parker).lock).write(UnsafeCell::new(libc::PTHREAD_MUTEX_INITIALIZER)); + (&raw mut (*parker).state).write(AtomicUsize::new(EMPTY)); + (&raw mut (*parker).lock).write(UnsafeCell::new(libc::PTHREAD_MUTEX_INITIALIZER)); cfg_if::cfg_if! { if #[cfg(any( @@ -112,9 +111,9 @@ impl Parker { target_os = "vita", target_vendor = "apple", ))] { - addr_of_mut!((*parker).cvar).write(UnsafeCell::new(libc::PTHREAD_COND_INITIALIZER)); + (&raw mut (*parker).cvar).write(UnsafeCell::new(libc::PTHREAD_COND_INITIALIZER)); } else if #[cfg(any(target_os = "espidf", target_os = "horizon"))] { - let r = libc::pthread_cond_init(addr_of_mut!((*parker).cvar).cast(), crate::ptr::null()); + let r = libc::pthread_cond_init((&raw mut (*parker).cvar).cast(), crate::ptr::null()); assert_eq!(r, 0); } else { use crate::mem::MaybeUninit; @@ -123,7 +122,7 @@ impl Parker { assert_eq!(r, 0); let r = libc::pthread_condattr_setclock(attr.as_mut_ptr(), libc::CLOCK_MONOTONIC); assert_eq!(r, 0); - let r = libc::pthread_cond_init(addr_of_mut!((*parker).cvar).cast(), attr.as_ptr()); + let r = libc::pthread_cond_init((&raw mut (*parker).cvar).cast(), attr.as_ptr()); assert_eq!(r, 0); let r = libc::pthread_condattr_destroy(attr.as_mut_ptr()); assert_eq!(r, 0); diff --git a/library/std/src/sys/sync/thread_parking/windows7.rs b/library/std/src/sys/sync/thread_parking/windows7.rs index cdd59757fe2c..8f7e66c46ef7 100644 --- a/library/std/src/sys/sync/thread_parking/windows7.rs +++ b/library/std/src/sys/sync/thread_parking/windows7.rs @@ -178,7 +178,7 @@ impl Parker { } fn ptr(&self) -> *const c_void { - core::ptr::addr_of!(self.state).cast::() + (&raw const self.state).cast::() } } diff --git a/library/std/src/sys/thread_local/destructors/linux_like.rs b/library/std/src/sys/thread_local/destructors/linux_like.rs index c381be0bf8c7..f473dc4d79df 100644 --- a/library/std/src/sys/thread_local/destructors/linux_like.rs +++ b/library/std/src/sys/thread_local/destructors/linux_like.rs @@ -47,7 +47,7 @@ pub unsafe fn register(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) { dtor, ), t.cast(), - core::ptr::addr_of!(__dso_handle) as *mut _, + (&raw const __dso_handle) as *mut _, ); } } else { diff --git a/library/std/src/sys_common/io.rs b/library/std/src/sys_common/io.rs index e386c955f376..6f6f282d432d 100644 --- a/library/std/src/sys_common/io.rs +++ b/library/std/src/sys_common/io.rs @@ -3,7 +3,7 @@ pub const DEFAULT_BUF_SIZE: usize = if cfg!(target_os = "espidf") { 512 } else { 8 * 1024 }; #[cfg(test)] -#[allow(dead_code)] // not used on emscripten +#[allow(dead_code)] // not used on emscripten and wasi pub mod test { use rand::RngCore; diff --git a/library/std/src/sys_common/mod.rs b/library/std/src/sys_common/mod.rs index 1c884f107bee..aa27886ff6f9 100644 --- a/library/std/src/sys_common/mod.rs +++ b/library/std/src/sys_common/mod.rs @@ -32,7 +32,8 @@ cfg_if::cfg_if! { all(unix, not(target_os = "l4re")), windows, target_os = "hermit", - target_os = "solid_asp3" + target_os = "solid_asp3", + all(target_os = "wasi", target_env = "p2") ))] { pub mod net; } else { diff --git a/library/std/src/sys_common/net.rs b/library/std/src/sys_common/net.rs index 57f07d05cae3..5a0ad9075810 100644 --- a/library/std/src/sys_common/net.rs +++ b/library/std/src/sys_common/net.rs @@ -74,7 +74,7 @@ pub fn setsockopt( sock.as_raw(), level, option_name, - core::ptr::addr_of!(option_value) as *const _, + (&raw const option_value) as *const _, mem::size_of::() as c::socklen_t, ))?; Ok(()) @@ -89,7 +89,7 @@ pub fn getsockopt(sock: &Socket, level: c_int, option_name: c_int) -> i sock.as_raw(), level, option_name, - core::ptr::addr_of_mut!(option_value) as *mut _, + (&raw mut option_value) as *mut _, &mut option_len, ))?; Ok(option_value) @@ -103,7 +103,7 @@ where unsafe { let mut storage: c::sockaddr_storage = mem::zeroed(); let mut len = mem::size_of_val(&storage) as c::socklen_t; - cvt(f(core::ptr::addr_of_mut!(storage) as *mut _, &mut len))?; + cvt(f((&raw mut storage) as *mut _, &mut len))?; sockaddr_to_addr(&storage, len as usize) } } @@ -452,7 +452,7 @@ impl TcpListener { pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> { let mut storage: c::sockaddr_storage = unsafe { mem::zeroed() }; let mut len = mem::size_of_val(&storage) as c::socklen_t; - let sock = self.inner.accept(core::ptr::addr_of_mut!(storage) as *mut _, &mut len)?; + let sock = self.inner.accept((&raw mut storage) as *mut _, &mut len)?; let addr = sockaddr_to_addr(&storage, len as usize)?; Ok((TcpStream { inner: sock }, addr)) } diff --git a/library/std/src/sys_common/wtf8.rs b/library/std/src/sys_common/wtf8.rs index 554e07c1e59b..19d4c94f4509 100644 --- a/library/std/src/sys_common/wtf8.rs +++ b/library/std/src/sys_common/wtf8.rs @@ -26,7 +26,6 @@ use crate::borrow::Cow; use crate::collections::TryReserveError; use crate::hash::{Hash, Hasher}; use crate::iter::FusedIterator; -use crate::ptr::addr_of_mut; use crate::rc::Rc; use crate::sync::Arc; use crate::sys_common::AsInner; @@ -1055,6 +1054,6 @@ unsafe impl CloneToUninit for Wtf8 { #[cfg_attr(debug_assertions, track_caller)] unsafe fn clone_to_uninit(&self, dst: *mut Self) { // SAFETY: we're just a wrapper around [u8] - unsafe { self.bytes.clone_to_uninit(addr_of_mut!((*dst).bytes)) } + unsafe { self.bytes.clone_to_uninit(&raw mut (*dst).bytes) } } } diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs index f147c5fdcd14..88bf186700f3 100644 --- a/library/std/src/thread/local.rs +++ b/library/std/src/thread/local.rs @@ -2,7 +2,7 @@ #![unstable(feature = "thread_local_internals", issue = "none")] -#[cfg(all(test, not(target_os = "emscripten")))] +#[cfg(all(test, not(any(target_os = "emscripten", target_os = "wasi"))))] mod tests; #[cfg(test)] diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index a53e3565dfe3..22d655833650 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -155,7 +155,7 @@ // Under `test`, `__FastLocalKeyInner` seems unused. #![cfg_attr(test, allow(dead_code))] -#[cfg(all(test, not(target_os = "emscripten")))] +#[cfg(all(test, not(any(target_os = "emscripten", target_os = "wasi"))))] mod tests; use crate::any::Any; @@ -165,7 +165,6 @@ use crate::marker::PhantomData; use crate::mem::{self, ManuallyDrop, forget}; use crate::num::NonZero; use crate::pin::Pin; -use crate::ptr::addr_of_mut; use crate::sync::Arc; use crate::sync::atomic::{AtomicUsize, Ordering}; use crate::sys::sync::Parker; @@ -665,6 +664,19 @@ impl Builder { /// println!("{result}"); /// ``` /// +/// # Notes +/// +/// This function has the same minimal guarantee regarding "foreign" unwinding operations (e.g. +/// an exception thrown from C++ code, or a `panic!` in Rust code compiled or linked with a +/// different runtime) as [`catch_unwind`]; namely, if the thread created with `thread::spawn` +/// unwinds all the way to the root with such an exception, one of two behaviors are possible, +/// and it is unspecified which will occur: +/// +/// * The process aborts. +/// * The process does not abort, and [`join`] will return a `Result::Err` +/// containing an opaque type. +/// +/// [`catch_unwind`]: ../../std/panic/fn.catch_unwind.html /// [`channels`]: crate::sync::mpsc /// [`join`]: JoinHandle::join /// [`Err`]: crate::result::Result::Err @@ -1386,9 +1398,9 @@ impl Thread { let inner = unsafe { let mut arc = Arc::::new_uninit(); let ptr = Arc::get_mut_unchecked(&mut arc).as_mut_ptr(); - addr_of_mut!((*ptr).name).write(name); - addr_of_mut!((*ptr).id).write(ThreadId::new()); - Parker::new_in_place(addr_of_mut!((*ptr).parker)); + (&raw mut (*ptr).name).write(name); + (&raw mut (*ptr).id).write(ThreadId::new()); + Parker::new_in_place(&raw mut (*ptr).parker); Pin::new_unchecked(arc.assume_init()) }; @@ -1785,7 +1797,7 @@ impl JoinHandle { /// operations that happen after `join` returns. /// /// If the associated thread panics, [`Err`] is returned with the parameter given - /// to [`panic!`]. + /// to [`panic!`] (though see the Notes below). /// /// [`Err`]: crate::result::Result::Err /// [atomic memory orderings]: crate::sync::atomic @@ -1807,6 +1819,18 @@ impl JoinHandle { /// }).unwrap(); /// join_handle.join().expect("Couldn't join on the associated thread"); /// ``` + /// + /// # Notes + /// + /// If a "foreign" unwinding operation (e.g. an exception thrown from C++ + /// code, or a `panic!` in Rust code compiled or linked with a different + /// runtime) unwinds all the way to the thread root, the process may be + /// aborted; see the Notes on [`thread::spawn`]. If the process is not + /// aborted, this function will return a `Result::Err` containing an opaque + /// type. + /// + /// [`catch_unwind`]: ../../std/panic/fn.catch_unwind.html + /// [`thread::spawn`]: spawn #[stable(feature = "rust1", since = "1.0.0")] pub fn join(self) -> Result { self.0.join() diff --git a/library/std/tests/create_dir_all_bare.rs b/library/std/tests/create_dir_all_bare.rs index 8becf713205e..30f800c5aa2e 100644 --- a/library/std/tests/create_dir_all_bare.rs +++ b/library/std/tests/create_dir_all_bare.rs @@ -1,4 +1,4 @@ -#![cfg(all(test, not(any(target_os = "emscripten", target_env = "sgx"))))] +#![cfg(all(test, not(any(target_os = "emscripten", target_os = "wasi", target_env = "sgx"))))] //! Note that this test changes the current directory so //! should not be in the same process as other tests. diff --git a/library/std/tests/process_spawning.rs b/library/std/tests/process_spawning.rs index d249eb7d50aa..3e72e371ade1 100644 --- a/library/std/tests/process_spawning.rs +++ b/library/std/tests/process_spawning.rs @@ -5,7 +5,7 @@ use std::{env, fs, process, str}; mod common; #[test] -#[cfg_attr(miri, ignore)] // Process spawning not supported by Miri +#[cfg_attr(any(miri, target_os = "wasi"), ignore)] // Process spawning not supported by Miri and wasi fn issue_15149() { // If we're the parent, copy our own binary to a new directory. let my_path = env::current_exe().unwrap(); diff --git a/library/std/tests/thread.rs b/library/std/tests/thread.rs index fc9917178b24..83574176186a 100644 --- a/library/std/tests/thread.rs +++ b/library/std/tests/thread.rs @@ -4,7 +4,7 @@ use std::thread; use std::time::Duration; #[test] -#[cfg_attr(target_os = "emscripten", ignore)] +#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads #[cfg_attr(miri, ignore)] // Miri does not like the thread leak fn sleep_very_long() { let finished = Arc::new(Mutex::new(false)); diff --git a/library/unwind/src/libunwind.rs b/library/unwind/src/libunwind.rs index 1d856ce1879a..715f8b57876a 100644 --- a/library/unwind/src/libunwind.rs +++ b/library/unwind/src/libunwind.rs @@ -222,14 +222,14 @@ if #[cfg(any(target_vendor = "apple", target_os = "netbsd", not(target_arch = "a pub unsafe fn _Unwind_GetGR(ctx: *mut _Unwind_Context, reg_index: c_int) -> _Unwind_Word { let mut val: _Unwind_Word = core::ptr::null(); _Unwind_VRS_Get(ctx, _UVRSC_CORE, reg_index as _Unwind_Word, _UVRSD_UINT32, - core::ptr::addr_of_mut!(val) as *mut c_void); + (&raw mut val) as *mut c_void); val } pub unsafe fn _Unwind_SetGR(ctx: *mut _Unwind_Context, reg_index: c_int, value: _Unwind_Word) { let mut value = value; _Unwind_VRS_Set(ctx, _UVRSC_CORE, reg_index as _Unwind_Word, _UVRSD_UINT32, - core::ptr::addr_of_mut!(value) as *mut c_void); + (&raw mut value) as *mut c_void); } pub unsafe fn _Unwind_GetIP(ctx: *mut _Unwind_Context) diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock index 952db063636e..efcac4f0953d 100644 --- a/src/bootstrap/Cargo.lock +++ b/src/bootstrap/Cargo.lock @@ -84,9 +84,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.1.19" +version = "1.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d74707dde2ba56f86ae90effb3b43ddd369504387e718014de010cec7959800" +checksum = "9540e661f81799159abee814118cc139a2004b3a3aa3ea37724a1b66530b90e0" dependencies = [ "shlex", ] @@ -99,9 +99,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clap" -version = "4.5.16" +version = "4.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed6719fffa43d0d87e5fd8caeab59be1554fb028cd30edc88fc4369b17971019" +checksum = "b0956a43b323ac1afaffc053ed5c4b7c1f1800bacd1683c353aabbb752515dd3" dependencies = [ "clap_builder", "clap_derive", @@ -109,9 +109,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.15" +version = "4.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "216aec2b177652e3846684cbfe25c9964d18ec45234f0f5da5157b207ed1aab6" +checksum = "4d72166dd41634086d5803a47eb71ae740e61d84709c36f3c34110173db3961b" dependencies = [ "anstyle", "clap_lex", @@ -119,18 +119,18 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.5.18" +version = "4.5.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ee158892bd7ce77aa15c208abbdb73e155d191c287a659b57abd5adb92feb03" +checksum = "8937760c3f4c60871870b8c3ee5f9b30771f792a7045c48bcbba999d7d6b3b8e" dependencies = [ "clap", ] [[package]] name = "clap_derive" -version = "4.5.13" +version = "4.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0" +checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" dependencies = [ "heck", "proc-macro2", @@ -161,9 +161,9 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpufeatures" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51e852e6dc9a5bed1fae92dd2375037bf2b768725bf3be87811edee3249d09ad" +checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" dependencies = [ "libc", ] @@ -242,9 +242,9 @@ dependencies = [ [[package]] name = "filetime" -version = "0.2.24" +version = "0.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf401df4a4e3872c4fe8151134cf483738e74b67fc934d6532c882b3d24a4550" +checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586" dependencies = [ "cfg-if", "libc", @@ -264,9 +264,9 @@ dependencies = [ [[package]] name = "globset" -version = "0.4.14" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57da3b9b5b85bd66f31093f8c408b90a74431672542466497dcbdfdc02034be1" +checksum = "15f1ce686646e7f1e19bf7d5533fe443a45dbfb990e00629110797578b42fb19" dependencies = [ "aho-corasick", "bstr", @@ -292,9 +292,9 @@ dependencies = [ [[package]] name = "ignore" -version = "0.4.22" +version = "0.4.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b46810df39e66e925525d6e38ce1e7f6e1d208f72dc39757880fcb66e2c58af1" +checksum = "6d89fd380afde86567dfba715db065673989d6253f42b88179abd3eae47bda4b" dependencies = [ "crossbeam-deque", "globset", @@ -314,9 +314,9 @@ checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "junction" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c9c415a9b7b1e86cd5738f39d34c9e78c765da7fb1756dbd7d31b3b0d2e7afa" +checksum = "72bbdfd737a243da3dfc1f99ee8d6e166480f17ab4ac84d7c34aacd73fc7bd16" dependencies = [ "scopeguard", "windows-sys 0.52.0", @@ -324,9 +324,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.157" +version = "0.2.159" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "374af5f94e54fa97cf75e945cce8a6b201e88a1a07e688b47dfd2a59c66dbd86" +checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" [[package]] name = "libredox" @@ -379,9 +379,9 @@ dependencies = [ [[package]] name = "object" -version = "0.36.3" +version = "0.36.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27b64972346851a39438c60b341ebc01bba47464ae329e55cf343eb93964efd9" +checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a" dependencies = [ "memchr", ] @@ -398,15 +398,15 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" [[package]] name = "pretty_assertions" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af7cee1a6c8a5b9208b3cb1061f10c0cb689087b3d8ce85fb9d2dd7a29b6ba66" +checksum = "3ae130e2f271fbc2ac3a40fb1d07180839cdbbe443c7a27e1e3c13c5cac0116d" dependencies = [ "diff", "yansi", @@ -423,18 +423,18 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.36" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] [[package]] name = "redox_syscall" -version = "0.5.3" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" +checksum = "355ae415ccd3a04315d3f8246e86d67689ea74d88d915576e1589a351062a13b" dependencies = [ "bitflags", ] @@ -458,9 +458,9 @@ checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" [[package]] name = "rustix" -version = "0.38.34" +version = "0.38.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" dependencies = [ "bitflags", "errno", @@ -498,18 +498,18 @@ checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" [[package]] name = "serde" -version = "1.0.208" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cff085d2cb684faa248efb494c39b68e522822ac0de72ccf08109abde717cfb2" +checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.208" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24008e81ff7613ed8e5ba0cfaf24e2c2f1e5b8a0495711e44fcd4882fca62bcf" +checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ "proc-macro2", "quote", @@ -518,9 +518,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.125" +version = "1.0.128" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83c8e735a073ccf5be70aa8066aa984eaf2fa000db6c8d0100ae605b366d31ed" +checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" dependencies = [ "itoa", "memchr", @@ -547,9 +547,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "syn" -version = "2.0.75" +version = "2.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6af063034fc1935ede7be0122941bafa9bacb949334d090b77ca98b5817c7d9" +checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" dependencies = [ "proc-macro2", "quote", @@ -558,9 +558,9 @@ dependencies = [ [[package]] name = "sysinfo" -version = "0.31.2" +version = "0.31.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4115055da5f572fff541dd0c4e61b0262977f453cc9fe04be83aba25a89bdab" +checksum = "355dbe4f8799b304b05e1b0f05fc59b2a18d36645cf169607da45bde2f69a1be" dependencies = [ "core-foundation-sys", "libc", @@ -571,9 +571,9 @@ dependencies = [ [[package]] name = "tar" -version = "0.4.41" +version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb797dad5fb5b76fcf519e702f4a589483b5ef06567f160c392832c1f5e44909" +checksum = "4ff6c40d3aedb5e06b57c6f669ad17ab063dd1e63d977c6a88e7f4dfa4f04020" dependencies = [ "filetime", "libc", @@ -606,9 +606,9 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" [[package]] name = "version_check" @@ -833,6 +833,6 @@ dependencies = [ [[package]] name = "yansi" -version = "0.5.1" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" +checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index 1959d0a9662d..ba505089a000 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -37,7 +37,7 @@ test = false # Most of the time updating these dependencies requires modifications to the # bootstrap codebase(e.g., https://github.com/rust-lang/rust/issues/124565); # otherwise, some targets will fail. That's why these dependencies are explicitly pinned. -cc = "=1.1.19" +cc = "=1.1.22" cmake = "=0.1.48" build_helper = { path = "../tools/build_helper" } diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 666df49012c1..04909cd79214 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -625,9 +625,9 @@ class RustBuild(object): try: # FIXME: A cheap workaround for https://github.com/rust-lang/rust/issues/125578, # remove this once the issue is closed. - bootstrap_out = self.bootstrap_out() - if os.path.exists(bootstrap_out): - shutil.rmtree(bootstrap_out) + bootstrap_build_artifacts = os.path.join(self.bootstrap_out(), "debug") + if os.path.exists(bootstrap_build_artifacts): + shutil.rmtree(bootstrap_build_artifacts) p.map(unpack_component, tarballs_download_info) finally: diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py index 49d564642bd6..a555a26367d5 100755 --- a/src/bootstrap/configure.py +++ b/src/bootstrap/configure.py @@ -193,7 +193,7 @@ if '--help' in sys.argv or '-h' in sys.argv: if option.value: print('\t{:30} {}'.format('--{}=VAL'.format(option.name), option.desc)) else: - print('\t{:30} {}'.format('--enable-{}'.format(option.name), option.desc)) + print('\t{:30} {}'.format('--enable-{} OR --disable-{}'.format(option.name, option.name), option.desc)) print('') print('This configure script is a thin configuration shim over the true') print('configuration system, `config.toml`. You can explore the comments') diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 0e596f0da0ec..eaa982d4e2bb 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -1205,7 +1205,8 @@ pub fn rustc_cargo_env( // busting caches (e.g. like #71152). if builder.config.llvm_enabled(target) { let building_is_expensive = - crate::core::build_steps::llvm::prebuilt_llvm_config(builder, target).should_build(); + 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 should_skip_build = building_is_expensive && can_skip_build; diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index 4c557366297e..90e6a10d9d68 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -2036,7 +2036,7 @@ fn maybe_install_llvm( } !builder.config.dry_run() } else if let llvm::LlvmBuildStatus::AlreadyBuilt(llvm::LlvmResult { llvm_config, .. }) = - llvm::prebuilt_llvm_config(builder, target) + llvm::prebuilt_llvm_config(builder, target, true) { let mut cmd = command(llvm_config); cmd.arg("--libfiles"); diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index b3bc6df1f87f..302135841579 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -87,10 +87,14 @@ impl LdFlags { /// /// This will return the llvm-config if it can get it (but it will not build it /// if not). -pub fn prebuilt_llvm_config(builder: &Builder<'_>, target: TargetSelection) -> LlvmBuildStatus { - // If we have llvm submodule initialized already, sync it. - builder.update_existing_submodule("src/llvm-project"); - +pub fn prebuilt_llvm_config( + builder: &Builder<'_>, + target: TargetSelection, + // Certain commands (like `x test mir-opt --bless`) may call this function with different targets, + // which could bypass the CI LLVM early-return even if `builder.config.llvm_from_ci` is true. + // This flag should be `true` only if the caller needs the LLVM sources (e.g., if it will build LLVM). + handle_submodule_when_needed: bool, +) -> LlvmBuildStatus { builder.config.maybe_download_ci_llvm(); // If we're using a custom LLVM bail out here, but we can only use a @@ -109,9 +113,10 @@ pub fn prebuilt_llvm_config(builder: &Builder<'_>, target: TargetSelection) -> L } } - // Initialize the llvm submodule if not initialized already. - // If submodules are disabled, this does nothing. - builder.config.update_submodule("src/llvm-project"); + if handle_submodule_when_needed { + // If submodules are disabled, this does nothing. + builder.config.update_submodule("src/llvm-project"); + } let root = "src/llvm-project/llvm"; let out_dir = builder.llvm_out(target); @@ -237,7 +242,7 @@ pub(crate) fn is_ci_llvm_available(config: &Config, asserts: bool) -> bool { /// Returns true if we're running in CI with modified LLVM (and thus can't download it) pub(crate) fn is_ci_llvm_modified(config: &Config) -> bool { - CiEnv::is_ci() && config.rust_info.is_managed_git_subrepository() && { + CiEnv::is_rust_lang_managed_ci_job() && config.rust_info.is_managed_git_subrepository() && { // We assume we have access to git, so it's okay to unconditionally pass // `true` here. let llvm_sha = detect_llvm_sha(config, true); @@ -284,7 +289,7 @@ impl Step for Llvm { }; // If LLVM has already been built or been downloaded through download-ci-llvm, we avoid building it again. - let Meta { stamp, res, out_dir, root } = match prebuilt_llvm_config(builder, target) { + let Meta { stamp, res, out_dir, root } = match prebuilt_llvm_config(builder, target, true) { LlvmBuildStatus::AlreadyBuilt(p) => return p, LlvmBuildStatus::ShouldBuild(m) => m, }; @@ -339,6 +344,7 @@ impl Step for Llvm { .define("LLVM_INCLUDE_DOCS", "OFF") .define("LLVM_INCLUDE_BENCHMARKS", "OFF") .define("LLVM_INCLUDE_TESTS", enable_tests) + // FIXME: remove this when minimal llvm is 19 .define("LLVM_ENABLE_TERMINFO", "OFF") .define("LLVM_ENABLE_LIBEDIT", "OFF") .define("LLVM_ENABLE_BINDINGS", "OFF") diff --git a/src/bootstrap/src/core/build_steps/setup.rs b/src/bootstrap/src/core/build_steps/setup.rs index f4c5fe5ff941..0ee2cb451f39 100644 --- a/src/bootstrap/src/core/build_steps/setup.rs +++ b/src/bootstrap/src/core/build_steps/setup.rs @@ -46,6 +46,7 @@ static SETTINGS_HASHES: &[&str] = &[ "47d227f424bf889b0d899b9cc992d5695e1b78c406e183cd78eafefbe5488923", "b526bd58d0262dd4dda2bff5bc5515b705fb668a46235ace3e057f807963a11a", "828666b021d837a33e78d870b56d34c88a5e2c85de58b693607ec574f0c27000", + "811fb3b063c739d261fd8590dd30242e117908f5a095d594fa04585daa18ec4d", ]; static RUST_ANALYZER_SETTINGS: &str = include_str!("../../../../etc/rust_analyzer_settings.json"); diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 870fe6a9f165..7283b0e9574c 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -1792,6 +1792,10 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the cmd.arg("--host").arg(&*compiler.host.triple); cmd.arg("--llvm-filecheck").arg(builder.llvm_filecheck(builder.config.build)); + if builder.build.config.llvm_enzyme { + cmd.arg("--has-enzyme"); + } + if builder.config.cmd.bless() { cmd.arg("--bless"); } diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs index 47420f8fe72f..c35384ce3c0b 100644 --- a/src/bootstrap/src/core/builder.rs +++ b/src/bootstrap/src/core/builder.rs @@ -1537,7 +1537,9 @@ impl<'a> Builder<'a> { // rustc_llvm. But if LLVM is stale, that'll be a tiny amount // of work comparatively, and we'd likely need to rebuild it anyway, // so that's okay. - if crate::core::build_steps::llvm::prebuilt_llvm_config(self, target).should_build() { + if crate::core::build_steps::llvm::prebuilt_llvm_config(self, target, false) + .should_build() + { cargo.env("RUST_CHECK", "1"); } } @@ -1562,8 +1564,8 @@ impl<'a> Builder<'a> { let libdir = self.rustc_libdir(compiler); let sysroot_str = sysroot.as_os_str().to_str().expect("sysroot should be UTF-8"); - if !matches!(self.config.dry_run, DryRun::SelfCheck) { - self.verbose_than(0, || println!("using sysroot {sysroot_str}")); + if self.is_verbose() && !matches!(self.config.dry_run, DryRun::SelfCheck) { + println!("using sysroot {sysroot_str}"); } let mut rustflags = Rustflags::new(target); @@ -2012,6 +2014,11 @@ impl<'a> Builder<'a> { cargo.env("RUSTC_BACKTRACE_ON_ICE", "1"); } + if self.is_verbose() { + // This provides very useful logs especially when debugging build cache-related stuff. + cargo.env("CARGO_LOG", "cargo::core::compiler::fingerprint=info"); + } + cargo.env("RUSTC_VERBOSE", self.verbosity.to_string()); // Downstream forks of the Rust compiler might want to use a custom libc to add support for diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 77e0ece31047..07460b81412a 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -343,6 +343,15 @@ pub struct Config { pub out: PathBuf, pub rust_info: channel::GitInfo, + pub cargo_info: channel::GitInfo, + pub rust_analyzer_info: channel::GitInfo, + pub clippy_info: channel::GitInfo, + pub miri_info: channel::GitInfo, + pub rustfmt_info: channel::GitInfo, + pub enzyme_info: channel::GitInfo, + pub in_tree_llvm_info: channel::GitInfo, + pub in_tree_gcc_info: channel::GitInfo, + // These are either the stage0 downloaded binaries or the locally installed ones. pub initial_cargo: PathBuf, pub initial_rustc: PathBuf, @@ -1796,6 +1805,19 @@ impl Config { config.omit_git_hash = 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_analyzer_info = + GitInfo::new(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.rustfmt_info = + GitInfo::new(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")); + // We need to override `rust.channel` if it's manually specified when using the CI rustc. // This is because if the compiler uses a different channel than the one specified in config.toml, // tests may fail due to using a different channel than the one used by the compiler during tests. @@ -2428,7 +2450,7 @@ impl Config { /// Runs a function if verbosity is greater than 0 pub fn verbose(&self, f: impl Fn()) { - if self.verbose > 0 { + if self.is_verbose() { f() } } @@ -2713,7 +2735,7 @@ impl Config { .success(); if has_changes { if if_unchanged { - if self.verbose > 0 { + if self.is_verbose() { println!( "WARNING: saw changes to compiler/ or library/ since {commit}; \ ignoring `download-rustc`" @@ -2810,7 +2832,7 @@ impl Config { let has_changes = !t!(git.as_command_mut().status()).success(); if has_changes { if if_unchanged { - if self.verbose > 0 { + if self.is_verbose() { println!( "warning: saw changes to one of {modified_paths:?} since {commit}; \ ignoring `{option_name}`" diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index 7bf5b4e23d29..75659f46431a 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -305,18 +305,15 @@ impl Build { #[cfg(not(unix))] let is_sudo = false; - let omit_git_hash = config.omit_git_hash; - let rust_info = GitInfo::new(omit_git_hash, &src); - let cargo_info = GitInfo::new(omit_git_hash, &src.join("src/tools/cargo")); - let rust_analyzer_info = GitInfo::new(omit_git_hash, &src.join("src/tools/rust-analyzer")); - let clippy_info = GitInfo::new(omit_git_hash, &src.join("src/tools/clippy")); - let miri_info = GitInfo::new(omit_git_hash, &src.join("src/tools/miri")); - let rustfmt_info = GitInfo::new(omit_git_hash, &src.join("src/tools/rustfmt")); - let enzyme_info = GitInfo::new(omit_git_hash, &src.join("src/tools/enzyme")); - - // we always try to use git for LLVM builds - let in_tree_llvm_info = GitInfo::new(false, &src.join("src/llvm-project")); - let in_tree_gcc_info = GitInfo::new(false, &src.join("src/gcc")); + let rust_info = config.rust_info.clone(); + let cargo_info = config.cargo_info.clone(); + let rust_analyzer_info = config.rust_analyzer_info.clone(); + let clippy_info = config.clippy_info.clone(); + let miri_info = config.miri_info.clone(); + let rustfmt_info = config.rustfmt_info.clone(); + let enzyme_info = config.enzyme_info.clone(); + let in_tree_llvm_info = config.in_tree_llvm_info.clone(); + let in_tree_gcc_info = config.in_tree_gcc_info.clone(); let initial_target_libdir_str = if config.dry_run() { "/dummy/lib/path/to/lib/".to_string() @@ -1373,7 +1370,7 @@ Executed at: {executed_at}"#, } if target.starts_with("wasm") && target.contains("wasi") { - self.default_wasi_runner() + self.default_wasi_runner(target) } else { None } @@ -1382,7 +1379,7 @@ Executed at: {executed_at}"#, /// When a `runner` configuration is not provided and a WASI-looking target /// is being tested this is consulted to prove the environment to see if /// there's a runtime already lying around that seems reasonable to use. - fn default_wasi_runner(&self) -> Option { + fn default_wasi_runner(&self, target: TargetSelection) -> Option { let mut finder = crate::core::sanity::Finder::new(); // Look for Wasmtime, and for its default options be sure to disable @@ -1398,6 +1395,11 @@ Executed at: {executed_at}"#, // inherit the entire environment rather than just this single // environment variable. path.push_str(" --env RUSTC_BOOTSTRAP"); + + if target.contains("wasip2") { + path.push_str(" --wasi inherit-network --wasi allow-ip-name-lookup"); + } + return Some(path); } } diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-gccjit.sh b/src/ci/docker/host-x86_64/dist-x86_64-linux/build-gccjit.sh index 4c80e895fd2f..c565922dcd13 100755 --- a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-gccjit.sh +++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/build-gccjit.sh @@ -3,7 +3,7 @@ GIT_REPO="https://github.com/rust-lang/gcc" # This commit hash needs to be updated to use a more recent gcc fork version. -GIT_COMMIT="341be3b7d7ac6976cfed8ed59da3573c040d0776" +GIT_COMMIT="e744a9459d33864067214741daf5c5bc2a7b88c6" set -ex diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version index 47d04a528837..6b2d58c8ef35 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version +++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version @@ -1 +1 @@ -0.18.0 \ No newline at end of file +0.18.1 \ No newline at end of file diff --git a/src/ci/scripts/select-xcode.sh b/src/ci/scripts/select-xcode.sh index d635d4384727..569c4a4136d9 100755 --- a/src/ci/scripts/select-xcode.sh +++ b/src/ci/scripts/select-xcode.sh @@ -1,6 +1,5 @@ #!/bin/bash # This script selects the Xcode instance to use. -# It also tries to do some cleanup in CI jobs of unused Xcodes. set -euo pipefail IFS=$'\n\t' @@ -8,21 +7,5 @@ IFS=$'\n\t' source "$(cd "$(dirname "$0")" && pwd)/../shared.sh" if isMacOS; then - # This additional step is to try to remove an Xcode we aren't using because each one is HUGE - old_xcode="$(xcode-select --print-path)" - old_xcode="${old_xcode%/*}" # pop a dir - old_xcode="${old_xcode%/*}" # twice - if [[ $old_xcode =~ $SELECT_XCODE ]]; then - echo "xcode-select.sh's brutal hack may not be necessary?" - exit 1 - elif [[ $SELECT_XCODE =~ "16" ]]; then - echo "Using Xcode 16? Please fix xcode-select.sh" - exit 1 - fi - if [ $CI ]; then # just in case someone sources this on their real computer - sudo rm -rf "${old_xcode}" - xcode_16="${old_xcode%/*}/Xcode-16.0.0.app" - sudo rm -rf "${xcode_16}" - fi sudo xcode-select -s "${SELECT_XCODE}" fi diff --git a/src/ci/scripts/upload-artifacts.sh b/src/ci/scripts/upload-artifacts.sh index 61c187fa77c0..0bc91f6ba715 100755 --- a/src/ci/scripts/upload-artifacts.sh +++ b/src/ci/scripts/upload-artifacts.sh @@ -23,14 +23,14 @@ if [[ "${DEPLOY-0}" -eq "1" ]] || [[ "${DEPLOY_ALT-0}" -eq "1" ]]; then fi # CPU usage statistics. -mv build/cpu-usage.csv "${upload_dir}/cpu-${CI_JOB_NAME}.csv" +cp build/cpu-usage.csv "${upload_dir}/cpu-${CI_JOB_NAME}.csv" # Build metrics generated by x.py. -mv "${build_dir}/metrics.json" "${upload_dir}/metrics-${CI_JOB_NAME}.json" +cp "${build_dir}/metrics.json" "${upload_dir}/metrics-${CI_JOB_NAME}.json" # Toolstate data. if [[ -n "${DEPLOY_TOOLSTATES_JSON+x}" ]]; then - mv /tmp/toolstate/toolstates.json "${upload_dir}/${DEPLOY_TOOLSTATES_JSON}" + cp /tmp/toolstate/toolstates.json "${upload_dir}/${DEPLOY_TOOLSTATES_JSON}" fi echo "Files that will be uploaded:" diff --git a/src/ci/scripts/upload-build-metrics.py b/src/ci/scripts/upload-build-metrics.py new file mode 100644 index 000000000000..a95e0949d700 --- /dev/null +++ b/src/ci/scripts/upload-build-metrics.py @@ -0,0 +1,81 @@ +""" +This script postprocesses data gathered during a CI run, computes certain metrics +from them, and uploads these metrics to DataDog. + +This script is expected to be executed from within a GitHub Actions job. + +It expects the following environment variables: +- DATADOG_SITE: path to the DataDog API endpoint +- DATADOG_API_KEY: DataDog API token +- DD_GITHUB_JOB_NAME: Name of the current GitHub Actions job + +And it also expects the presence of a binary called `datadog-ci` to be in PATH. +It can be installed with `npm install -g @datadog/datadog-ci`. + +Usage: +```bash +$ python3 upload-build-metrics.py +``` + +`path-to-CPU-usage-CSV` is a path to a CSV generated by the `src/ci/cpu-usage-over-time.py` script. +""" +import argparse +import csv +import os +import subprocess +import sys +from pathlib import Path +from typing import List + + +def load_cpu_usage(path: Path) -> List[float]: + usage = [] + with open(path) as f: + reader = csv.reader(f, delimiter=',') + for row in reader: + # The log might contain incomplete rows or some Python exception + if len(row) == 2: + try: + idle = float(row[1]) + usage.append(100.0 - idle) + except ValueError: + pass + return usage + + +def upload_datadog_measure(name: str, value: float): + """ + Uploads a single numeric metric for the current GitHub Actions job to DataDog. + """ + print(f"Metric {name}: {value:.4f}") + + datadog_cmd = "datadog-ci" + if os.getenv("GITHUB_ACTIONS") is not None and sys.platform.lower().startswith("win"): + # Due to weird interaction of MSYS2 and Python, we need to use an absolute path, + # and also specify the ".cmd" at the end. See https://github.com/rust-lang/rust/pull/125771. + datadog_cmd = "C:\\npm\\prefix\\datadog-ci.cmd" + + subprocess.run([ + datadog_cmd, + "measure", + "--level", "job", + "--measures", f"{name}:{value}" + ], + check=False + ) + + +if __name__ == "__main__": + parser = argparse.ArgumentParser( + prog="DataDog metric uploader" + ) + parser.add_argument("cpu-usage-history-csv") + args = parser.parse_args() + + build_usage_csv = vars(args)["cpu-usage-history-csv"] + usage_timeseries = load_cpu_usage(Path(build_usage_csv)) + if len(usage_timeseries) > 0: + avg_cpu_usage = sum(usage_timeseries) / len(usage_timeseries) + else: + avg_cpu_usage = 0 + upload_datadog_measure("avg-cpu-usage", avg_cpu_usage) diff --git a/src/doc/rustdoc/src/write-documentation/documentation-tests.md b/src/doc/rustdoc/src/write-documentation/documentation-tests.md index 7ed2e9720fed..c93893b5ada8 100644 --- a/src/doc/rustdoc/src/write-documentation/documentation-tests.md +++ b/src/doc/rustdoc/src/write-documentation/documentation-tests.md @@ -414,11 +414,11 @@ In some cases, doctests cannot be merged. For example, if you have: The problem with this code is that, if you change any other doctests, it'll likely break when runing `rustdoc --test`, making it tricky to maintain. -This is where the `standalone` attribute comes in: it tells `rustdoc` that a doctest +This is where the `standalone_crate` attribute comes in: it tells `rustdoc` that a doctest should not be merged with the others. So the previous code should use it: ```rust -//! ```standalone +//! ```standalone_crate //! let location = std::panic::Location::caller(); //! assert_eq!(location.line(), 4); //! ``` diff --git a/src/doc/rustdoc/src/write-documentation/linking-to-items-by-name.md b/src/doc/rustdoc/src/write-documentation/linking-to-items-by-name.md index 1a367b8274b9..5e7854834028 100644 --- a/src/doc/rustdoc/src/write-documentation/linking-to-items-by-name.md +++ b/src/doc/rustdoc/src/write-documentation/linking-to-items-by-name.md @@ -89,8 +89,8 @@ fn Foo() {} These prefixes will be stripped when displayed in the documentation, so `[struct@Foo]` will be rendered as `Foo`. The following prefixes are available: `struct`, `enum`, `trait`, `union`, -`mod`, `module`, `const`, `constant`, `fn`, `function`, `method`, `derive`, `type`, `value`, -`macro`, `prim` or `primitive`. +`mod`, `module`, `const`, `constant`, `fn`, `function`, `field`, `variant`, `method`, `derive`, +`type`, `value`, `macro`, `prim` or `primitive`. You can also disambiguate for functions by adding `()` after the function name, or for macros by adding `!` after the macro name. The macro `!` can be followed by `()`, `{}`, diff --git a/src/doc/unstable-book/src/compiler-flags/default-hidden-visibility.md b/src/doc/unstable-book/src/compiler-flags/default-hidden-visibility.md deleted file mode 100644 index 579add4a9d98..000000000000 --- a/src/doc/unstable-book/src/compiler-flags/default-hidden-visibility.md +++ /dev/null @@ -1,12 +0,0 @@ -# `default-hidden-visibility` - -The tracking issue for this feature is: https://github.com/rust-lang/compiler-team/issues/656 - ------------------------- - -This flag can be used to override the target's -[`default_hidden_visibility`](https://doc.rust-lang.org/beta/nightly-rustc/rustc_target/spec/struct.TargetOptions.html#structfield.default_hidden_visibility) -setting. -Using `-Zdefault_hidden_visibility=yes` is roughly equivalent to Clang's -[`-fvisibility=hidden`](https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-fvisibility) -cmdline flag. diff --git a/src/doc/unstable-book/src/compiler-flags/default-visibility.md b/src/doc/unstable-book/src/compiler-flags/default-visibility.md new file mode 100644 index 000000000000..ad9e5d84bba8 --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/default-visibility.md @@ -0,0 +1,44 @@ +# `default-visibility` + +The tracking issue for this feature is: https://github.com/rust-lang/rust/issues/131090 + +------------------------ + +This flag can be used to override the target's +[`default_visibility`](https://doc.rust-lang.org/beta/nightly-rustc/rustc_target/spec/struct.TargetOptions.html#structfield.default_visibility) +setting. + +This option only affects building of shared objects and should have no effect on executables. + +Visibility an be set to one of three options: + +* protected +* hidden +* interposable + +## Hidden visibility + +Using `-Zdefault-visibility=hidden` is roughly equivalent to Clang's +[`-fvisibility=hidden`](https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-fvisibility) +cmdline flag. Hidden symbols will not be exported from the created shared object, so cannot be +referenced from other shared objects or from executables. + +## Protected visibility + +Using `-Zdefault-visibility=protected` will cause rust-mangled symbols to be emitted with +"protected" visibility. This signals the compiler, the linker and the runtime linker that these +symbols cannot be overridden by the executable or by other shared objects earlier in the load order. + +This will allow the compiler to emit direct references to symbols, which may improve performance. It +also removes the need for these symbols to be resolved when a shared object built with this option +is loaded. + +Using protected visibility when linking with GNU ld prior to 2.40 will result in linker errors when +building for Linux. Other linkers such as LLD are not affected. + +## Interposable + +Using `-Zdefault-visibility=interposable` will cause symbols to be emitted with "default" +visibility. On platforms that support it, this makes it so that symbols can be interposed, which +means that they can be overridden by symbols with the same name from the executable or by other +shared objects earier in the load order. diff --git a/src/doc/unstable-book/src/compiler-flags/print-check-cfg.md b/src/doc/unstable-book/src/compiler-flags/print-check-cfg.md index ab63c986e856..8d314aa62d4c 100644 --- a/src/doc/unstable-book/src/compiler-flags/print-check-cfg.md +++ b/src/doc/unstable-book/src/compiler-flags/print-check-cfg.md @@ -4,23 +4,28 @@ The tracking issue for this feature is: [#125704](https://github.com/rust-lang/r ------------------------ -This option of the `--print` flag print the list of expected cfgs. +This option of the `--print` flag print the list of all the expected cfgs. -This is related to the `--check-cfg` flag which allows specifying arbitrary expected +This is related to the [`--check-cfg` flag][check-cfg] which allows specifying arbitrary expected names and values. -This print option works similarly to `--print=cfg` (modulo check-cfg specifics): - - *check_cfg syntax*: *output of --print=check-cfg* - - `cfg(windows)`: `windows` - - `cfg(feature, values("foo", "bar"))`: `feature="foo"` and `feature="bar"` - - `cfg(feature, values(none(), ""))`: `feature` and `feature=""` - - `cfg(feature, values(any()))`: `feature=any()` - - `cfg(feature, values())`: `feature=` - - `cfg(any())`: `any()` - - *nothing*: `any()=any()` +This print option works similarly to `--print=cfg` (modulo check-cfg specifics). + +| `--check-cfg` | `--print=check-cfg` | +|-----------------------------------|-----------------------------| +| `cfg(foo)` | `foo` | +| `cfg(foo, values("bar"))` | `foo="bar"` | +| `cfg(foo, values(none(), "bar"))` | `foo` & `foo="bar"` | +| | *check-cfg specific syntax* | +| `cfg(foo, values(any())` | `foo=any()` | +| `cfg(foo, values())` | `foo=` | +| `cfg(any())` | `any()` | +| *none* | `any()=any()` | To be used like this: ```bash rustc --print=check-cfg -Zunstable-options lib.rs ``` + +[check-cfg]: https://doc.rust-lang.org/nightly/rustc/check-cfg.html 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 43e11b6d57dc..b1c429c7676e 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 @@ -51,7 +51,10 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | CSKY | `reg` | `r[0-31]` | `r` | | CSKY | `freg` | `f[0-31]` | `f` | | s390x | `reg` | `r[0-10]`, `r[12-14]` | `r` | +| s390x | `reg_addr` | `r[1-10]`, `r[12-14]` | `a` | | s390x | `freg` | `f[0-15]` | `f` | +| s390x | `vreg` | `v[0-31]` | Only clobbers | +| s390x | `areg` | `a[2-15]` | Only clobbers | | Arm64EC | `reg` | `x[0-12]`, `x[15-22]`, `x[25-27]`, `x30` | `r` | | Arm64EC | `vreg` | `v[0-15]` | `w` | | Arm64EC | `vreg_low16` | `v[0-15]` | `x` | @@ -90,6 +93,8 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | CSKY | `freg` | None | `f32`, | | s390x | `reg`, `reg_addr` | None | `i8`, `i16`, `i32`, `i64` | | s390x | `freg` | None | `f32`, `f64` | +| s390x | `vreg` | N/A | Only clobbers | +| s390x | `areg` | N/A | Only clobbers | | Arm64EC | `reg` | None | `i8`, `i16`, `i32`, `f32`, `i64`, `f64` | | Arm64EC | `vreg` | None | `i8`, `i16`, `i32`, `f32`, `i64`, `f64`,
`i8x8`, `i16x4`, `i32x2`, `i64x1`, `f32x2`, `f64x1`,
`i8x16`, `i16x8`, `i32x4`, `i64x2`, `f32x4`, `f64x2` | @@ -157,6 +162,8 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | CSKY | `r15` | This is the link register. | | CSKY | `r[26-30]` | Reserved by its ABI. | | CSKY | `r31` | This is the TLS register. | +| s390x | `c[0-15]` | Reserved by the kernel. | +| s390x | `a[0-1]` | Reserved for system use. | | Arm64EC | `xzr` | This is a constant zero register which can't be modified. | | Arm64EC | `x18` | This is an OS-reserved register. | | Arm64EC | `x13`, `x14`, `x23`, `x24`, `x28`, `v[16-31]` | These are AArch64 registers that are not supported for Arm64EC. | diff --git a/src/etc/rust_analyzer_eglot.el b/src/etc/rust_analyzer_eglot.el new file mode 100644 index 000000000000..e55d80d98dec --- /dev/null +++ b/src/etc/rust_analyzer_eglot.el @@ -0,0 +1,29 @@ +((rustic-mode + .((eglot-workspace-configuration + . (:rust-analyzer + ( :check ( :invocationLocation "root" + :invocationStrategy "once" + :overrideCommand ["python3" + "x.py" + "check" + "--json-output"]) + :linkedProjects ["Cargo.toml" + "src/tools/x/Cargo.toml" + "src/bootstrap/Cargo.toml" + "src/tools/rust-analyzer/Cargo.toml" + "compiler/rustc_codegen_cranelift/Cargo.toml" + "compiler/rustc_codegen_gcc/Cargo.toml"] + :rustfmt ( :overrideCommand ["build/host/rustfmt/bin/rustfmt" + "--edition=2021"]) + :procMacro ( :server "build/host/stage0/libexec/rust-analyzer-proc-macro-srv" + :enable t) + :cargo ( :buildScripts ( :enable t + :invocationLocation "root" + :invocationStrategy "once" + :overrideCommand ["python3" + "x.py" + "check" + "--json-output"]) + :sysrootSrc "./library" + :extraEnv (:RUSTC_BOOTSTRAP "1")) + :rustc ( :source "./Cargo.toml" ))))))) diff --git a/src/etc/rust_analyzer_helix.toml b/src/etc/rust_analyzer_helix.toml new file mode 100644 index 000000000000..642350cad343 --- /dev/null +++ b/src/etc/rust_analyzer_helix.toml @@ -0,0 +1,49 @@ +[language-server.rust-analyzer.config] +linkedProjects = [ + "Cargo.toml", + "src/tools/x/Cargo.toml", + "src/bootstrap/Cargo.toml", + "src/tools/rust-analyzer/Cargo.toml", + "compiler/rustc_codegen_cranelift/Cargo.toml", + "compiler/rustc_codegen_gcc/Cargo.toml" +] + +[language-server.rust-analyzer.config.check] +invocationLocation = "root" +invocationStrategy = "once" +overrideCommand = [ + "python3", + "x.py", + "check", + "--json-output", +] + +[language-server.rust-analyzer.config.rustfmt] +overrideCommand = [ + "build-rust-analyzer/host/rustfmt/bin/rustfmt", + "--edition=2021" +] + +[language-server.rust-analyzer.config.procMacro] +server = "build-rust-analyzer/host/stage0/libexec/rust-analyzer-proc-macro-srv" +enable = true + +[language-server.rust-analyzer.config.rustc] +source = "./Cargo.toml" + +[language-server.rust-analyzer.config.cargo] +sysrootSrc = "./library" + +[language-server.rust-analyzer.config.cargo.extraEnv] +RUSTC_BOOTSTRAP = "1" + +[language-server.rust-analyzer.config.cargo.buildScripts] +enable = true +invocationLocation = "root" +invocationStrategy = "once" +overrideCommand = [ + "python3", + "x.py", + "check", + "--json-output", +] diff --git a/src/etc/rust_analyzer_settings.json b/src/etc/rust_analyzer_settings.json index d329fe997cd7..a20105f0ef37 100644 --- a/src/etc/rust_analyzer_settings.json +++ b/src/etc/rust_analyzer_settings.json @@ -10,6 +10,7 @@ ], "rust-analyzer.linkedProjects": [ "Cargo.toml", + "library/Cargo.toml", "src/tools/x/Cargo.toml", "src/bootstrap/Cargo.toml", "src/tools/rust-analyzer/Cargo.toml", diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index 08c88fc950d7..d966f9931045 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -117,6 +117,7 @@ fn synthesize_auto_trait_impl<'tcx>( name: None, inner: Box::new(clean::ItemInner { attrs: Default::default(), + stability: None, kind: clean::ImplItem(Box::new(clean::Impl { safety: hir::Safety::Safe, generics, diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs index 368212948859..1f3cb4a61b89 100644 --- a/src/librustdoc/clean/blanket_impl.rs +++ b/src/librustdoc/clean/blanket_impl.rs @@ -87,6 +87,7 @@ pub(crate) fn synthesize_blanket_impls( item_id: clean::ItemId::Blanket { impl_id: impl_def_id, for_: item_def_id }, inner: Box::new(clean::ItemInner { attrs: Default::default(), + stability: None, kind: clean::ImplItem(Box::new(clean::Impl { safety: hir::Safety::Safe, generics: clean_ty_generics( diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index b7d6b3dda72b..e7f921eef7fc 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -672,6 +672,7 @@ fn build_module_items( item_id: ItemId::DefId(did), inner: Box::new(clean::ItemInner { attrs: Default::default(), + stability: None, kind: clean::ImportItem(clean::Import::new_simple( item.ident.name, clean::ImportSource { @@ -837,8 +838,7 @@ pub(crate) fn record_extern_trait(cx: &mut DocContext<'_>, did: DefId) { } { - if cx.external_traits.borrow().contains_key(&did) || cx.active_extern_traits.contains(&did) - { + if cx.external_traits.contains_key(&did) || cx.active_extern_traits.contains(&did) { return; } } @@ -850,6 +850,6 @@ pub(crate) fn record_extern_trait(cx: &mut DocContext<'_>, did: DefId) { debug!("record_extern_trait: {did:?}"); let trait_ = build_external_trait(cx, did); - cx.external_traits.borrow_mut().insert(did, trait_); + cx.external_traits.insert(did, trait_); cx.active_extern_traits.remove(&did); } diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index bc6b5a7d3e31..a3277e8ca921 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1,14 +1,12 @@ use std::borrow::Cow; -use std::cell::RefCell; use std::hash::Hash; use std::path::PathBuf; -use std::rc::Rc; use std::sync::{Arc, OnceLock as OnceCell}; use std::{fmt, iter}; use arrayvec::ArrayVec; use rustc_ast_pretty::pprust; -use rustc_attr::{ConstStability, Deprecation, Stability, StabilityLevel, StableSince}; +use rustc_attr::{ConstStability, Deprecation, Stability, StableSince}; use rustc_const_eval::const_eval::is_unstable_const_fn; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::def::{CtorKind, DefKind, Res}; @@ -115,7 +113,7 @@ impl From for ItemId { pub(crate) struct Crate { pub(crate) module: Item, /// Only here so that they can be filtered through the rustdoc passes. - pub(crate) external_traits: Rc>>, + pub(crate) external_traits: Box>, } impl Crate { @@ -335,6 +333,8 @@ pub(crate) struct ItemInner { /// E.g., struct vs enum vs function. pub(crate) kind: ItemKind, pub(crate) attrs: Attributes, + /// The effective stability, filled out by the `propagate-stability` pass. + pub(crate) stability: Option, } impl std::ops::Deref for Item { @@ -383,46 +383,17 @@ fn is_field_vis_inherited(tcx: TyCtxt<'_>, def_id: DefId) -> bool { } impl Item { + /// Returns the effective stability of the item. + /// + /// This method should only be called after the `propagate-stability` pass has been run. pub(crate) fn stability(&self, tcx: TyCtxt<'_>) -> Option { - let (mut def_id, mut stability) = if let Some(inlined) = self.inline_stmt_id { - let inlined_def_id = inlined.to_def_id(); - if let Some(stability) = tcx.lookup_stability(inlined_def_id) { - (inlined_def_id, stability) - } else { - // For re-exports into crates without `staged_api`, reuse the original stability. - // This is necessary, because we always want to mark unstable items. - let def_id = self.def_id()?; - return tcx.lookup_stability(def_id); - } - } else { - let def_id = self.def_id()?; - let stability = tcx.lookup_stability(def_id)?; - (def_id, stability) - }; - - let StabilityLevel::Stable { mut since, allowed_through_unstable_modules: false } = - stability.level - else { - return Some(stability); - }; - - // If any of the item's ancestors was stabilized later or is still unstable, - // then report the ancestor's stability instead. - while let Some(parent_def_id) = tcx.opt_parent(def_id) { - if let Some(parent_stability) = tcx.lookup_stability(parent_def_id) { - match parent_stability.level { - StabilityLevel::Unstable { .. } => return Some(parent_stability), - StabilityLevel::Stable { since: parent_since, .. } => { - if parent_since > since { - stability = parent_stability; - since = parent_since; - } - } - } - } - def_id = parent_def_id; - } - Some(stability) + let stability = self.inner.stability; + debug_assert!( + stability.is_some() + || self.def_id().is_none_or(|did| tcx.lookup_stability(did).is_none()), + "missing stability for cleaned item: {self:?}", + ); + stability } pub(crate) fn const_stability(&self, tcx: TyCtxt<'_>) -> Option { @@ -504,7 +475,7 @@ impl Item { Item { item_id: def_id.into(), - inner: Box::new(ItemInner { kind, attrs }), + inner: Box::new(ItemInner { kind, attrs, stability: None }), name, cfg, inline_stmt_id: None, @@ -640,10 +611,7 @@ impl Item { } pub(crate) fn stable_since(&self, tcx: TyCtxt<'_>) -> Option { - match self.stability(tcx)?.level { - StabilityLevel::Stable { since, .. } => Some(since), - StabilityLevel::Unstable { .. } => None, - } + self.stability(tcx).and_then(|stability| stability.stable_since()) } pub(crate) fn is_non_exhaustive(&self) -> bool { @@ -1482,7 +1450,7 @@ impl Trait { tcx.trait_def(self.def_id).safety } pub(crate) fn is_object_safe(&self, tcx: TyCtxt<'_>) -> bool { - tcx.is_object_safe(self.def_id) + tcx.is_dyn_compatible(self.def_id) } } diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index b91c1725d0c8..fdf628b50fbe 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -74,7 +74,7 @@ pub(crate) fn krate(cx: &mut DocContext<'_>) -> Crate { })); } - Crate { module, external_traits: cx.external_traits.clone() } + Crate { module, external_traits: Box::new(mem::take(&mut cx.external_traits)) } } pub(crate) fn clean_middle_generic_args<'tcx>( diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 8e46d93c28e0..4c48c075a944 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -1,5 +1,3 @@ -use std::cell::RefCell; -use std::rc::Rc; use std::sync::atomic::AtomicBool; use std::sync::{Arc, LazyLock}; use std::{io, mem}; @@ -41,7 +39,7 @@ pub(crate) struct DocContext<'tcx> { /// Most of this logic is copied from rustc_lint::late. pub(crate) param_env: ParamEnv<'tcx>, /// Later on moved through `clean::Crate` into `cache` - pub(crate) external_traits: Rc>>, + pub(crate) external_traits: FxHashMap, /// Used while populating `external_traits` to ensure we don't process the same trait twice at /// the same time. pub(crate) active_extern_traits: DefIdSet, @@ -359,7 +357,7 @@ pub(crate) fn run_global_ctxt( // Note that in case of `#![no_core]`, the trait is not available. if let Some(sized_trait_did) = ctxt.tcx.lang_items().sized_trait() { let sized_trait = build_external_trait(&mut ctxt, sized_trait_did); - ctxt.external_traits.borrow_mut().insert(sized_trait_did, sized_trait); + ctxt.external_traits.insert(sized_trait_did, sized_trait); } debug!("crate: {:?}", tcx.hir().krate()); diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 3ee6b24ac92c..bdd6fbe8c0cf 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -837,7 +837,7 @@ impl CreateRunnableDocTests { let is_standalone = !doctest.can_be_merged || scraped_test.langstr.compile_fail || scraped_test.langstr.test_harness - || scraped_test.langstr.standalone + || scraped_test.langstr.standalone_crate || self.rustdoc_options.nocapture || self.rustdoc_options.test_args.iter().any(|arg| arg == "--show-output"); if is_standalone { diff --git a/src/librustdoc/doctest/make.rs b/src/librustdoc/doctest/make.rs index d560e3a476b1..efbb332d12d8 100644 --- a/src/librustdoc/doctest/make.rs +++ b/src/librustdoc/doctest/make.rs @@ -48,7 +48,7 @@ impl DocTestBuilder { ) -> Self { let can_merge_doctests = can_merge_doctests && lang_str.is_some_and(|lang_str| { - !lang_str.compile_fail && !lang_str.test_harness && !lang_str.standalone + !lang_str.compile_fail && !lang_str.test_harness && !lang_str.standalone_crate }); let SourceInfo { crate_attrs, maybe_crate_attrs, crates, everything_else } = diff --git a/src/librustdoc/fold.rs b/src/librustdoc/fold.rs index c25a4ddb6f36..95e495205aea 100644 --- a/src/librustdoc/fold.rs +++ b/src/librustdoc/fold.rs @@ -1,3 +1,5 @@ +use std::mem; + use crate::clean::*; pub(crate) fn strip_item(mut item: Item) -> Item { @@ -116,10 +118,11 @@ pub(crate) trait DocFolder: Sized { fn fold_crate(&mut self, mut c: Crate) -> Crate { c.module = self.fold_item(c.module).unwrap(); - let external_traits = { std::mem::take(&mut *c.external_traits.borrow_mut()) }; - for (k, mut v) in external_traits { - v.items = v.items.into_iter().filter_map(|i| self.fold_item(i)).collect(); - c.external_traits.borrow_mut().insert(k, v); + for trait_ in c.external_traits.values_mut() { + trait_.items = mem::take(&mut trait_.items) + .into_iter() + .filter_map(|i| self.fold_item(i)) + .collect(); } c diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index 8597d2e2b63e..db1a0bd0af93 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -153,7 +153,8 @@ impl Cache { // Crawl the crate to build various caches used for the output debug!(?cx.cache.crate_version); - cx.cache.traits = krate.external_traits.take(); + assert!(cx.external_traits.is_empty()); + cx.cache.traits = mem::take(&mut krate.external_traits); // Cache where all our extern crates are located // FIXME: this part is specific to HTML so it'd be nice to remove it from the common code diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index b18d621478c7..8ae5484feda7 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -871,7 +871,7 @@ pub(crate) struct LangString { pub(crate) rust: bool, pub(crate) test_harness: bool, pub(crate) compile_fail: bool, - pub(crate) standalone: bool, + pub(crate) standalone_crate: bool, pub(crate) error_codes: Vec, pub(crate) edition: Option, pub(crate) added_classes: Vec, @@ -1194,7 +1194,7 @@ impl Default for LangString { rust: true, test_harness: false, compile_fail: false, - standalone: false, + standalone_crate: false, error_codes: Vec::new(), edition: None, added_classes: Vec::new(), @@ -1264,8 +1264,8 @@ impl LangString { seen_rust_tags = !seen_other_tags || seen_rust_tags; data.no_run = true; } - LangStringToken::LangToken("standalone") => { - data.standalone = true; + LangStringToken::LangToken("standalone_crate") => { + data.standalone_crate = true; seen_rust_tags = !seen_other_tags || seen_rust_tags; } LangStringToken::LangToken(x) if x.starts_with("edition") => { @@ -1298,44 +1298,47 @@ impl LangString { } LangStringToken::LangToken(x) if extra.is_some() => { let s = x.to_lowercase(); - if let Some((flag, help)) = if s == "compile-fail" - || s == "compile_fail" - || s == "compilefail" - { - Some(( - "compile_fail", - "the code block will either not be tested if not marked as a rust one \ - or won't fail if it compiles successfully", - )) - } else if s == "should-panic" || s == "should_panic" || s == "shouldpanic" { - Some(( - "should_panic", - "the code block will either not be tested if not marked as a rust one \ - or won't fail if it doesn't panic when running", - )) - } else if s == "no-run" || s == "no_run" || s == "norun" { - Some(( - "no_run", - "the code block will either not be tested if not marked as a rust one \ - or will be run (which you might not want)", - )) - } else if s == "test-harness" || s == "test_harness" || s == "testharness" { - Some(( - "test_harness", - "the code block will either not be tested if not marked as a rust one \ - or the code will be wrapped inside a main function", - )) - } else { - None + if let Some(help) = match s.as_str() { + "compile-fail" | "compile_fail" | "compilefail" => Some( + "use `compile_fail` to invert the results of this test, so that it \ + passes if it cannot be compiled and fails if it can", + ), + "should-panic" | "should_panic" | "shouldpanic" => Some( + "use `should_panic` to invert the results of this test, so that if \ + passes if it panics and fails if it does not", + ), + "no-run" | "no_run" | "norun" => Some( + "use `no_run` to compile, but not run, the code sample during \ + testing", + ), + "test-harness" | "test_harness" | "testharness" => Some( + "use `test_harness` to run functions marked `#[test]` instead of a \ + potentially-implicit `main` function", + ), + "standalone" | "standalone_crate" | "standalone-crate" => { + if let Some(extra) = extra + && extra.sp.at_least_rust_2024() + { + Some( + "use `standalone_crate` to compile this code block \ + separately", + ) + } else { + None + } + } + _ => None, } { if let Some(extra) = extra { extra.error_invalid_codeblock_attr_with_help( format!("unknown attribute `{x}`"), |lint| { - lint.help(format!( - "there is an attribute with a similar name: `{flag}`" - )) - .help(help); + lint.help(help).help( + "this code block may be skipped during testing, \ + because unknown attributes are treated as markers for \ + code samples written in other programming languages, \ + unless it is also explicitly marked as `rust`", + ); }, ); } diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index d120e7f36eb6..38276e4d20c2 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -436,16 +436,9 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items: } clean::ImportItem(ref import) => { - let stab_tags = if let Some(import_def_id) = import.source.did { - // Just need an item with the correct def_id and attrs - let import_item = - clean::Item { item_id: import_def_id.into(), ..(*myitem).clone() }; - - let stab_tags = Some(extra_info_tags(&import_item, item, tcx).to_string()); - stab_tags - } else { - None - }; + let stab_tags = import.source.did.map_or_else(String::new, |import_def_id| { + extra_info_tags(tcx, myitem, item, Some(import_def_id)).to_string() + }); w.write_str(ITEM_TABLE_ROW_OPEN); let id = match import.kind { @@ -454,7 +447,6 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items: } clean::ImportKind::Glob => String::new(), }; - let stab_tags = stab_tags.unwrap_or_default(); let (stab_tags_before, stab_tags_after) = if stab_tags.is_empty() { ("", "") } else { @@ -521,7 +513,7 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items: {docs_before}{docs}{docs_after}", name = EscapeBodyTextWithWbr(myitem.name.unwrap().as_str()), visibility_and_hidden = visibility_and_hidden, - stab_tags = extra_info_tags(myitem, item, tcx), + stab_tags = extra_info_tags(tcx, myitem, item, None), class = myitem.type_(), unsafety_flag = unsafety_flag, href = item_path(myitem.type_(), myitem.name.unwrap().as_str()), @@ -544,9 +536,10 @@ fn item_module(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Item, items: /// Render the stability, deprecation and portability tags that are displayed in the item's summary /// at the module level. fn extra_info_tags<'a, 'tcx: 'a>( + tcx: TyCtxt<'tcx>, item: &'a clean::Item, parent: &'a clean::Item, - tcx: TyCtxt<'tcx>, + import_def_id: Option, ) -> impl fmt::Display + 'a + Captures<'tcx> { display_fn(move |f| { fn tag_html<'a>( @@ -564,18 +557,18 @@ fn extra_info_tags<'a, 'tcx: 'a>( } // The trailing space after each tag is to space it properly against the rest of the docs. - if let Some(depr) = &item.deprecation(tcx) { + let deprecation = import_def_id + .map_or_else(|| item.deprecation(tcx), |import_did| tcx.lookup_deprecation(import_did)); + if let Some(depr) = deprecation { let message = if depr.is_in_effect() { "Deprecated" } else { "Deprecation planned" }; write!(f, "{}", tag_html("deprecated", "", message))?; } // The "rustc_private" crates are permanently unstable so it makes no sense // to render "unstable" everywhere. - if item - .stability(tcx) - .as_ref() - .is_some_and(|s| s.is_unstable() && s.feature != sym::rustc_private) - { + let stability = import_def_id + .map_or_else(|| item.stability(tcx), |import_did| tcx.lookup_stability(import_did)); + if stability.is_some_and(|s| s.is_unstable() && s.feature != sym::rustc_private) { write!(f, "{}", tag_html("unstable", "", "Experimental"))?; } diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs index 12246b0d416a..af94b1042c05 100644 --- a/src/librustdoc/html/render/write_shared.rs +++ b/src/librustdoc/html/render/write_shared.rs @@ -824,9 +824,9 @@ impl Serialize for Implementor { /// this visitor works to reverse that: `aliased_types` is a map /// from target to the aliases that reference it, and each one /// will generate one file. -struct TypeImplCollector<'cx, 'cache> { +struct TypeImplCollector<'cx, 'cache, 'item> { /// Map from DefId-of-aliased-type to its data. - aliased_types: IndexMap>, + aliased_types: IndexMap>, visited_aliases: FxHashSet, cache: &'cache Cache, cx: &'cache mut Context<'cx>, @@ -847,26 +847,26 @@ struct TypeImplCollector<'cx, 'cache> { /// ] /// ) /// ``` -struct AliasedType<'cache> { +struct AliasedType<'cache, 'item> { /// This is used to generate the actual filename of this aliased type. target_fqp: &'cache [Symbol], target_type: ItemType, /// This is the data stored inside the file. /// ItemId is used to deduplicate impls. - impl_: IndexMap>, + impl_: IndexMap>, } /// The `impl_` contains data that's used to figure out if an alias will work, /// and to generate the HTML at the end. /// /// The `type_aliases` list is built up with each type alias that matches. -struct AliasedTypeImpl<'cache> { +struct AliasedTypeImpl<'cache, 'item> { impl_: &'cache Impl, - type_aliases: Vec<(&'cache [Symbol], Item)>, + type_aliases: Vec<(&'cache [Symbol], &'item Item)>, } -impl<'cx, 'cache> DocVisitor for TypeImplCollector<'cx, 'cache> { - fn visit_item(&mut self, it: &Item) { +impl<'cx, 'cache, 'item> DocVisitor<'item> for TypeImplCollector<'cx, 'cache, 'item> { + fn visit_item(&mut self, it: &'item Item) { self.visit_item_recur(it); let cache = self.cache; let ItemKind::TypeAliasItem(ref t) = it.kind else { return }; @@ -927,7 +927,7 @@ impl<'cx, 'cache> DocVisitor for TypeImplCollector<'cx, 'cache> { continue; } // This impl was not found in the set of rejected impls - aliased_type_impl.type_aliases.push((&self_fqp[..], it.clone())); + aliased_type_impl.type_aliases.push((&self_fqp[..], it)); } } } diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs index 9ba0fb7b83c9..7be9cc0b8858 100644 --- a/src/librustdoc/html/sources.rs +++ b/src/librustdoc/html/sources.rs @@ -103,7 +103,7 @@ impl LocalSourcesCollector<'_, '_> { } } -impl DocVisitor for LocalSourcesCollector<'_, '_> { +impl DocVisitor<'_> for LocalSourcesCollector<'_, '_> { fn visit_item(&mut self, item: &clean::Item) { self.add_local_source(item); @@ -122,7 +122,7 @@ struct SourceCollector<'a, 'tcx> { crate_name: &'a str, } -impl DocVisitor for SourceCollector<'_, '_> { +impl DocVisitor<'_> for SourceCollector<'_, '_> { fn visit_item(&mut self, item: &clean::Item) { if !self.cx.include_sources { return; diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index ae9727a4d4f5..beac7e73c62d 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -182,17 +182,18 @@ h1, h2, h3, h4 { "main-heading-breadcrumbs main-heading-breadcrumbs" "main-heading-h1 main-heading-toolbar" "main-heading-sub-heading main-heading-toolbar"; - grid-template-columns: 1fr max-content; - grid-template-rows: 25px min-content min-content; + grid-template-columns: minmax(105px, 1fr) minmax(0, max-content); + grid-template-rows: minmax(25px, min-content) min-content min-content; padding-bottom: 6px; margin-bottom: 11px; } .rustdoc-breadcrumbs { grid-area: main-heading-breadcrumbs; - height: 25px; line-height: 1.25; display: flex; + flex-wrap: wrap; align-items: end; + padding-top: 5px; } .rustdoc-breadcrumbs a { padding: 4px 0; @@ -928,6 +929,7 @@ rustdoc-toolbar { display: flex; flex-direction: row; flex-wrap: nowrap; + min-height: 60px; } .docblock code, .docblock-short code, @@ -958,6 +960,13 @@ pre, .rustdoc.src .example-wrap, .example-wrap .src-line-numbers { display: inline-block; } +.docblock li { + margin-bottom: .8em; +} +.docblock li p { + margin-bottom: .1em; +} + /* "where ..." clauses with block display are also smaller */ div.where { white-space: pre-wrap; @@ -1104,17 +1113,17 @@ table, .search-results-title + .sub-heading { color: var(--main-color); display: flex; - align-items: center; + align-items: baseline; + white-space: nowrap; } #crate-search-div { /* ensures that 100% in properties of #crate-search-div:after are relative to the size of this div */ position: relative; /* allows this div (and with it the from overflowing the containing div in case it's shrunk */ max-width: 100%; @@ -1687,7 +1696,6 @@ instead, we check that it's not a "finger" cursor. padding-right: 3px; background-color: var(--target-background-color); border-right: 3px solid var(--target-border-color); - animation: 0.65s cubic-bezier(0, 0, 0.1, 1.0) 0.1s targetfadein; } .code-header a.tooltip { @@ -1712,12 +1720,18 @@ a.tooltip:hover::after { content: "\00a0"; } -/* This animation is layered onto the mistake-proofing delay for dismissing - a hovered tooltip, to ensure it feels responsive even with the delay. - */ -.fade-out { - opacity: 0; - transition: opacity 0.45s cubic-bezier(0, 0, 0.1, 1.0); +@media not (prefers-reduced-motion) { + :target { + animation: 0.65s cubic-bezier(0, 0, 0.1, 1.0) 0.1s targetfadein; + } + + /* This animation is layered onto the mistake-proofing delay for dismissing + a hovered tooltip, to ensure it feels responsive even with the delay. + */ + .fade-out { + opacity: 0; + transition: opacity 0.45s cubic-bezier(0, 0, 0.1, 1.0); + } } .popover.tooltip .content { @@ -1820,6 +1834,7 @@ a.tooltip:hover::after { margin-left: var(--button-left-margin); display: flex; line-height: 1.25; + min-width: 14px; } #sidebar-button { display: none; @@ -1856,6 +1871,9 @@ a.tooltip:hover::after { width: 80px; border-radius: var(--toolbar-button-border-radius); } +#settings-menu > a, #help-button > a { + min-width: 0; +} #sidebar-button > a { background-color: var(--button-background-color); border-color: var(--border-color); diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index 0d556e0a6827..984b0877d8de 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -1828,11 +1828,15 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm return; } but.onclick = () => { - const path = []; - onEachLazy(document.querySelectorAll(".rustdoc-breadcrumbs a"), a => { - path.push(a.textContent); - }); - path.push(document.querySelector("title").textContent.split(" ")[0]); + // Most page titles are ' in - Rust', except + // modules (which don't have the first part) and keywords/primitives + // (which don't have a module path) + const title = document.querySelector("title").textContent.replace(" - Rust", ""); + const [item, module] = title.split(" in "); + const path = [item]; + if (module !== undefined) { + path.unshift(module); + } copyContentToClipboard(path.join("::")); copyButtonAnimation(but); diff --git a/src/librustdoc/html/templates/item_info.html b/src/librustdoc/html/templates/item_info.html index 9e65ae95e15d..9fee268622e8 100644 --- a/src/librustdoc/html/templates/item_info.html +++ b/src/librustdoc/html/templates/item_info.html @@ -1,7 +1,7 @@ {% if !items.is_empty() %} {% for item in items %} - {{item|safe}} {# #} + {{item|safe}} {% endfor %} {% endif %} diff --git a/src/librustdoc/html/templates/page.html b/src/librustdoc/html/templates/page.html index 65c4304e2020..a05d6ca83132 100644 --- a/src/librustdoc/html/templates/page.html +++ b/src/librustdoc/html/templates/page.html @@ -12,13 +12,13 @@ {# #} {# #} + href="{{static_root_path|safe}}{{files.rustdoc_css}}"> {% if !layout.default_settings.is_empty() %} {# #} + > {% endif %} {# #} - {# #} + {% if page.css_class.contains("crate") %} - {# #} + {% else if page.css_class == "src" %} {# #} - {# #} + {% else if !page.css_class.contains("mod") %} - {# #} + {% else if !page.css_class.contains("sys") %} - {# #} + {% endif %} - {# #} + {% if layout.scrape_examples_extension %} - {# #} + {% endif %} {# #} + {% if layout.css_file_extension.is_some() %} {# #} + href="{{page.root_path|safe}}theme{{page.resource_suffix}}.css"> {% endif %} {% if !layout.favicon.is_empty() %} - {# #} + {% else %} {# #} {# #} + href="{{static_root_path|safe}}{{files.rust_favicon_svg}}"> {% endif %} {{ layout.external_html.in_header|safe }} {# #} @@ -69,60 +69,60 @@
{# #} This old browser is unsupported and will most likely display funky things. {# #}
{# #} - {# #} + {{ layout.external_html.before_content|safe }} {% if page.css_class != "src" %}
{% endif %} -