Merge from rustc

This commit is contained in:
The rustc-dev-guide Cronjob Bot 2025-05-08 07:16:31 +00:00
commit 659f0b606d
1900 changed files with 24583 additions and 13251 deletions

View file

@ -25,12 +25,19 @@ jobs:
env:
GH_TOKEN: ${{ github.token }}
run: |
# Give GitHub some time to propagate the information that the PR was merged
sleep 60
# Get closest bors merge commit
PARENT_COMMIT=`git rev-list --author='bors <bors@rust-lang.org>' -n1 --first-parent HEAD^1`
echo "Parent: ${PARENT_COMMIT}"
# Find PR for the current commit
HEAD_PR=`gh pr list --search "${{ github.sha }}" --state merged --json number --jq '.[0].number'`
if [ -z "${HEAD_PR}" ]; then
echo "PR for commit SHA ${{ github.sha }} not found, exiting"
exit 1
fi
echo "HEAD: ${{ github.sha }} (#${HEAD_PR})"
cd src/ci/citool

View file

@ -158,12 +158,9 @@ dependencies = [
[[package]]
name = "anyhow"
version = "1.0.97"
version = "1.0.98"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f"
dependencies = [
"backtrace",
]
checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
[[package]]
name = "ar_archive_writer"
@ -188,9 +185,9 @@ checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
[[package]]
name = "askama"
version = "0.13.0"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a4e46abb203e00ef226442d452769233142bbfdd79c3941e84c8e61c4112543"
checksum = "5d4744ed2eef2645831b441d8f5459689ade2ab27c854488fbab1fbe94fce1a7"
dependencies = [
"askama_derive",
"itoa",
@ -201,9 +198,9 @@ dependencies = [
[[package]]
name = "askama_derive"
version = "0.13.0"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "54398906821fd32c728135f7b351f0c7494ab95ae421d41b6f5a020e158f28a6"
checksum = "d661e0f57be36a5c14c48f78d09011e67e0cb618f269cca9f2fd8d15b68c46ac"
dependencies = [
"askama_parser",
"basic-toml",
@ -213,7 +210,7 @@ dependencies = [
"rustc-hash 2.1.1",
"serde",
"serde_derive",
"syn 2.0.100",
"syn 2.0.101",
]
[[package]]
@ -225,7 +222,7 @@ dependencies = [
"memchr",
"serde",
"serde_derive",
"winnow 0.7.6",
"winnow 0.7.9",
]
[[package]]
@ -281,9 +278,9 @@ checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
[[package]]
name = "blake3"
version = "1.8.1"
version = "1.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "389a099b34312839e16420d499a9cad9650541715937ffbdd40d36f49e77eeb3"
checksum = "3888aaa89e4b2a40fca9848e400f6a658a5a3978de7be858e209cafa8be9a4a0"
dependencies = [
"arrayref",
"arrayvec",
@ -452,9 +449,9 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
[[package]]
name = "chrono"
version = "0.4.40"
version = "0.4.41"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c"
checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d"
dependencies = [
"android-tzdata",
"iana-time-zone",
@ -496,9 +493,9 @@ dependencies = [
[[package]]
name = "clap"
version = "4.5.36"
version = "4.5.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2df961d8c8a0d08aa9945718ccf584145eee3f3aa06cddbeac12933781102e04"
checksum = "eccb054f56cbd38340b380d4a8e69ef1f02f1af43db2f0cc817a4774d80ae071"
dependencies = [
"clap_builder",
"clap_derive",
@ -516,9 +513,9 @@ dependencies = [
[[package]]
name = "clap_builder"
version = "4.5.36"
version = "4.5.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "132dbda40fb6753878316a489d5a1242a8ef2f0d9e47ba01c951ea8aa7d013a5"
checksum = "efd9466fac8543255d3b1fcad4762c5e116ffe808c8a3043d4263cd4fd4862a2"
dependencies = [
"anstream",
"anstyle",
@ -535,7 +532,7 @@ dependencies = [
"heck 0.5.0",
"proc-macro2",
"quote",
"syn 2.0.100",
"syn 2.0.101",
]
[[package]]
@ -561,13 +558,13 @@ dependencies = [
"if_chain",
"itertools",
"parking_lot",
"pulldown-cmark 0.11.3",
"pulldown-cmark",
"quote",
"regex",
"rustc_tools_util 0.4.2",
"serde",
"serde_json",
"syn 2.0.100",
"syn 2.0.101",
"tempfile",
"termize",
"tokio",
@ -653,16 +650,16 @@ dependencies = [
[[package]]
name = "color-eyre"
version = "0.6.3"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55146f5e46f237f7423d74111267d4597b59b0dad0ffaf7303bce9945d843ad5"
checksum = "e6e1761c0e16f8883bbbb8ce5990867f4f06bf11a0253da6495a04ce4b6ef0ec"
dependencies = [
"backtrace",
"color-spantrace",
"eyre",
"indenter",
"once_cell",
"owo-colors",
"owo-colors 4.2.0",
"tracing-error",
]
@ -684,17 +681,17 @@ dependencies = [
"nom",
"proc-macro2",
"quote",
"syn 2.0.100",
"syn 2.0.101",
]
[[package]]
name = "color-spantrace"
version = "0.2.1"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd6be1b2a7e382e2b98b43b2adcca6bb0e465af0bdd38123873ae61eb17a72c2"
checksum = "2ddd8d5bfda1e11a501d0a7303f3bfed9aa632ebdb859be40d0fd70478ed70d5"
dependencies = [
"once_cell",
"owo-colors",
"owo-colors 4.2.0",
"tracing-core",
"tracing-error",
]
@ -780,6 +777,7 @@ name = "coverage-dump"
version = "0.1.0"
dependencies = [
"anyhow",
"itertools",
"leb128",
"md-5",
"miniz_oxide 0.7.4",
@ -910,7 +908,7 @@ dependencies = [
"proc-macro2",
"quote",
"strsim",
"syn 2.0.100",
"syn 2.0.101",
]
[[package]]
@ -921,7 +919,7 @@ checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead"
dependencies = [
"darling_core",
"quote",
"syn 2.0.100",
"syn 2.0.101",
]
[[package]]
@ -943,13 +941,13 @@ dependencies = [
[[package]]
name = "derive-where"
version = "1.2.7"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62d671cc41a825ebabc75757b62d3d168c577f9149b2d49ece1dad1f72119d25"
checksum = "e73f2692d4bd3cac41dca28934a39894200c9fabf49586d77d0e5954af1d7902"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.100",
"syn 2.0.101",
]
[[package]]
@ -970,7 +968,7 @@ dependencies = [
"darling",
"proc-macro2",
"quote",
"syn 2.0.100",
"syn 2.0.101",
]
[[package]]
@ -980,7 +978,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c"
dependencies = [
"derive_builder_core",
"syn 2.0.100",
"syn 2.0.101",
]
[[package]]
@ -992,7 +990,7 @@ dependencies = [
"darling",
"proc-macro2",
"quote",
"syn 2.0.100",
"syn 2.0.101",
]
[[package]]
@ -1082,7 +1080,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.100",
"syn 2.0.101",
]
[[package]]
@ -1361,7 +1359,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.100",
"syn 2.0.101",
]
[[package]]
@ -1434,9 +1432,9 @@ dependencies = [
[[package]]
name = "getrandom"
version = "0.2.15"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592"
dependencies = [
"cfg-if",
"libc",
@ -1502,9 +1500,9 @@ dependencies = [
[[package]]
name = "hashbrown"
version = "0.15.2"
version = "0.15.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3"
dependencies = [
"allocator-api2",
"equivalent",
@ -1761,7 +1759,7 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.100",
"syn 2.0.101",
]
[[package]]
@ -1919,9 +1917,9 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
[[package]]
name = "jiff"
version = "0.2.6"
version = "0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f33145a5cbea837164362c7bd596106eb7c5198f97d1ba6f6ebb3223952e488"
checksum = "d07d8d955d798e7a4d6f9c58cd1f1916e790b42b092758a9ef6e16fef9f1b3fd"
dependencies = [
"jiff-static",
"log",
@ -1932,13 +1930,13 @@ dependencies = [
[[package]]
name = "jiff-static"
version = "0.2.6"
version = "0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43ce13c40ec6956157a3635d97a1ee2df323b263f09ea14165131289cb0f5c19"
checksum = "f244cfe006d98d26f859c7abd1318d85327e1882dc9cef80f62daeeb0adcf300"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.100",
"syn 2.0.101",
]
[[package]]
@ -2071,14 +2069,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34"
dependencies = [
"cfg-if",
"windows-targets 0.52.6",
"windows-targets 0.48.5",
]
[[package]]
name = "libm"
version = "0.2.11"
version = "0.2.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa"
checksum = "c9627da5196e5d8ed0b0495e61e518847578da83483c37288316d9b2e03a7f72"
[[package]]
name = "libredox"
@ -2202,7 +2200,7 @@ checksum = "88a9689d8d44bf9964484516275f5cd4c9b59457a6940c1d5d0ecbb94510a36b"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.100",
"syn 2.0.101",
]
[[package]]
@ -2307,7 +2305,7 @@ dependencies = [
"libffi",
"libloading",
"measureme",
"rand 0.9.0",
"rand 0.9.1",
"regex",
"rustc_version",
"smallvec",
@ -2466,6 +2464,25 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
[[package]]
name = "objc2-core-foundation"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c10c2894a6fed806ade6027bcd50662746363a9589d3ec9d9bef30a4e4bc166"
dependencies = [
"bitflags",
]
[[package]]
name = "objc2-io-kit"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71c1c64d6120e51cd86033f67176b1cb66780c2efe34dec55176f77befd93c0a"
dependencies = [
"libc",
"objc2-core-foundation",
]
[[package]]
name = "object"
version = "0.32.2"
@ -2525,9 +2542,9 @@ checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e"
[[package]]
name = "openssl-sys"
version = "0.9.107"
version = "0.9.108"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8288979acd84749c744a9014b4382d42b8f7b2592847b5afb2ed29e5d16ede07"
checksum = "e145e1651e858e820e4860f7b9c5e169bc1d8ce1c86043be79fa7b7634821847"
dependencies = [
"cc",
"libc",
@ -2577,6 +2594,12 @@ version = "3.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f"
[[package]]
name = "owo-colors"
version = "4.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1036865bb9422d3300cf723f657c2851d0e9ab12567854b1f4eba3d77decf564"
[[package]]
name = "pad"
version = "0.1.6"
@ -2681,7 +2704,7 @@ dependencies = [
"pest_meta",
"proc-macro2",
"quote",
"syn 2.0.100",
"syn 2.0.101",
]
[[package]]
@ -2798,7 +2821,7 @@ version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "abec3fb083c10660b3854367697da94c674e9e82aa7511014dc958beeb7215e9"
dependencies = [
"owo-colors",
"owo-colors 3.5.0",
"pad",
]
@ -2810,33 +2833,22 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068"
[[package]]
name = "proc-macro2"
version = "1.0.94"
version = "1.0.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84"
checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
dependencies = [
"unicode-ident",
]
[[package]]
name = "psm"
version = "0.1.25"
version = "0.1.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f58e5423e24c18cc840e1c98370b3993c6649cd1678b4d24318bcf0a083cbe88"
checksum = "6e944464ec8536cd1beb0bbfd96987eb5e3b72f2ecdafdc5c769a37f1fa2ae1f"
dependencies = [
"cc",
]
[[package]]
name = "pulldown-cmark"
version = "0.9.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57206b407293d2bcd3af849ce869d52068623f19e1b5ff8e8778e3309439682b"
dependencies = [
"bitflags",
"memchr",
"unicase",
]
[[package]]
name = "pulldown-cmark"
version = "0.11.3"
@ -2895,13 +2907,12 @@ dependencies = [
[[package]]
name = "rand"
version = "0.9.0"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94"
checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97"
dependencies = [
"rand_chacha 0.9.0",
"rand_core 0.9.3",
"zerocopy",
]
[[package]]
@ -2930,7 +2941,7 @@ version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [
"getrandom 0.2.15",
"getrandom 0.2.16",
]
[[package]]
@ -2973,9 +2984,9 @@ dependencies = [
[[package]]
name = "redox_syscall"
version = "0.5.11"
version = "0.5.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2f103c6d277498fbceb16e84d317e2a400f160f46904d5f5410848c829511a3"
checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af"
dependencies = [
"bitflags",
]
@ -2986,7 +2997,7 @@ version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43"
dependencies = [
"getrandom 0.2.15",
"getrandom 0.2.16",
"libredox",
"thiserror 1.0.69",
]
@ -2997,7 +3008,7 @@ version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b"
dependencies = [
"getrandom 0.2.15",
"getrandom 0.2.16",
"libredox",
"thiserror 2.0.12",
]
@ -3179,7 +3190,7 @@ name = "rustc_abi"
version = "0.0.0"
dependencies = [
"bitflags",
"rand 0.9.0",
"rand 0.9.1",
"rand_xoshiro",
"rustc_data_structures",
"rustc_hashes",
@ -3583,13 +3594,13 @@ dependencies = [
"rustc_query_system",
"rustc_resolve",
"rustc_session",
"rustc_smir",
"rustc_span",
"rustc_target",
"rustc_trait_selection",
"rustc_ty_utils",
"serde_json",
"shlex",
"stable_mir",
"tracing",
"windows 0.59.0",
]
@ -3693,7 +3704,7 @@ dependencies = [
"fluent-syntax",
"proc-macro2",
"quote",
"syn 2.0.100",
"syn 2.0.101",
"unic-langid",
]
@ -3805,7 +3816,7 @@ dependencies = [
name = "rustc_incremental"
version = "0.0.0"
dependencies = [
"rand 0.9.0",
"rand 0.9.1",
"rustc_ast",
"rustc_data_structures",
"rustc_errors",
@ -3839,7 +3850,7 @@ version = "0.0.0"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.100",
"syn 2.0.101",
]
[[package]]
@ -3985,7 +3996,7 @@ version = "0.0.0"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.100",
"syn 2.0.101",
"synstructure",
]
@ -4015,6 +4026,7 @@ dependencies = [
"rustc_session",
"rustc_span",
"rustc_target",
"tempfile",
"tracing",
]
@ -4314,7 +4326,7 @@ version = "0.0.0"
dependencies = [
"bitflags",
"itertools",
"pulldown-cmark 0.11.3",
"pulldown-cmark",
"rustc_arena",
"rustc_ast",
"rustc_ast_pretty",
@ -4371,7 +4383,7 @@ dependencies = [
"bitflags",
"getopts",
"libc",
"rand 0.9.0",
"rand 0.9.1",
"rustc_abi",
"rustc_ast",
"rustc_data_structures",
@ -4481,7 +4493,6 @@ dependencies = [
"itertools",
"rustc_abi",
"rustc_ast",
"rustc_attr_parsing",
"rustc_data_structures",
"rustc_errors",
"rustc_fluent_macro",
@ -4575,7 +4586,7 @@ version = "0.0.0"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.100",
"syn 2.0.101",
"synstructure",
]
@ -4599,7 +4610,6 @@ dependencies = [
"indexmap",
"itertools",
"minifier",
"pulldown-cmark 0.9.6",
"pulldown-cmark-escape",
"regex",
"rustdoc-json-types",
@ -4666,7 +4676,7 @@ dependencies = [
"proc-macro2",
"quote",
"serde",
"syn 2.0.100",
"syn 2.0.101",
]
[[package]]
@ -4700,9 +4710,9 @@ dependencies = [
[[package]]
name = "rustix"
version = "1.0.5"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d97817398dd4bb2e6da002002db259209759911da105da92bec29ccb12cf58bf"
checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266"
dependencies = [
"bitflags",
"errno",
@ -4803,7 +4813,7 @@ checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.100",
"syn 2.0.101",
]
[[package]]
@ -4840,9 +4850,9 @@ dependencies = [
[[package]]
name = "sha2"
version = "0.10.8"
version = "0.10.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
dependencies = [
"cfg-if",
"cpufeatures",
@ -4961,9 +4971,9 @@ dependencies = [
[[package]]
name = "stacker"
version = "0.1.20"
version = "0.1.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "601f9201feb9b09c00266478bf459952b9ef9a6b94edb2f21eba14ab681a60a9"
checksum = "cddb07e32ddb770749da91081d8d0ac3a16f1a569a18b20348cd371f5dead06b"
dependencies = [
"cc",
"cfg-if",
@ -5049,9 +5059,9 @@ dependencies = [
[[package]]
name = "syn"
version = "2.0.100"
version = "2.0.101"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0"
checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf"
dependencies = [
"proc-macro2",
"quote",
@ -5060,24 +5070,25 @@ dependencies = [
[[package]]
name = "synstructure"
version = "0.13.1"
version = "0.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971"
checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.100",
"syn 2.0.101",
]
[[package]]
name = "sysinfo"
version = "0.31.4"
version = "0.35.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "355dbe4f8799b304b05e1b0f05fc59b2a18d36645cf169607da45bde2f69a1be"
checksum = "b897c8ea620e181c7955369a31be5f48d9a9121cb59fd33ecef9ff2a34323422"
dependencies = [
"core-foundation-sys",
"libc",
"windows 0.57.0",
"objc2-core-foundation",
"objc2-io-kit",
"windows 0.61.1",
]
[[package]]
@ -5161,7 +5172,7 @@ version = "0.1.0"
dependencies = [
"indicatif",
"num",
"rand 0.9.0",
"rand 0.9.1",
"rand_chacha 0.9.0",
"rayon",
]
@ -5198,7 +5209,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.100",
"syn 2.0.101",
]
[[package]]
@ -5209,7 +5220,7 @@ checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.100",
"syn 2.0.101",
]
[[package]]
@ -5335,9 +5346,9 @@ dependencies = [
[[package]]
name = "toml_datetime"
version = "0.6.8"
version = "0.6.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41"
checksum = "3da5db5a963e24bc68be8b17b6fa82814bb22ee8660f192bb182771d498f09a3"
dependencies = [
"serde",
]
@ -5375,7 +5386,7 @@ checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.100",
"syn 2.0.101",
]
[[package]]
@ -5546,7 +5557,7 @@ checksum = "1ed7f4237ba393424195053097c1516bd4590dc82b84f2f97c5c69e12704555b"
dependencies = [
"proc-macro-hack",
"quote",
"syn 2.0.100",
"syn 2.0.101",
"unic-langid-impl",
]
@ -5762,7 +5773,7 @@ dependencies = [
"log",
"proc-macro2",
"quote",
"syn 2.0.100",
"syn 2.0.101",
"wasm-bindgen-shared",
]
@ -5784,7 +5795,7 @@ checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.100",
"syn 2.0.101",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
@ -5952,16 +5963,6 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows"
version = "0.57.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12342cb4d8e3b046f3d80effd474a7a02447231330ef77d71daa6fbc40681143"
dependencies = [
"windows-core 0.57.0",
"windows-targets 0.52.6",
]
[[package]]
name = "windows"
version = "0.59.0"
@ -5972,6 +5973,19 @@ dependencies = [
"windows-targets 0.53.0",
]
[[package]]
name = "windows"
version = "0.61.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c5ee8f3d025738cb02bad7868bbb5f8a6327501e870bf51f1b455b0a2454a419"
dependencies = [
"windows-collections",
"windows-core 0.61.0",
"windows-future",
"windows-link",
"windows-numerics",
]
[[package]]
name = "windows-bindgen"
version = "0.61.0"
@ -5984,15 +5998,12 @@ dependencies = [
]
[[package]]
name = "windows-core"
version = "0.57.0"
name = "windows-collections"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2ed2439a290666cd67ecce2b0ffaad89c2a56b976b736e6ece670297897832d"
checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8"
dependencies = [
"windows-implement 0.57.0",
"windows-interface 0.57.0",
"windows-result 0.1.2",
"windows-targets 0.52.6",
"windows-core 0.61.0",
]
[[package]]
@ -6002,8 +6013,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "810ce18ed2112484b0d4e15d022e5f598113e220c53e373fb31e67e21670c1ce"
dependencies = [
"windows-implement 0.59.0",
"windows-interface 0.59.1",
"windows-result 0.3.2",
"windows-interface",
"windows-result",
"windows-strings 0.3.1",
"windows-targets 0.53.0",
]
@ -6015,21 +6026,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980"
dependencies = [
"windows-implement 0.60.0",
"windows-interface 0.59.1",
"windows-interface",
"windows-link",
"windows-result 0.3.2",
"windows-result",
"windows-strings 0.4.0",
]
[[package]]
name = "windows-implement"
version = "0.57.0"
name = "windows-future"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7"
checksum = "7a1d6bbefcb7b60acd19828e1bc965da6fcf18a7e39490c5f8be71e54a19ba32"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.100",
"windows-core 0.61.0",
"windows-link",
]
[[package]]
@ -6040,7 +6050,7 @@ checksum = "83577b051e2f49a058c308f17f273b570a6a758386fc291b5f6a934dd84e48c1"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.100",
"syn 2.0.101",
]
[[package]]
@ -6051,18 +6061,7 @@ checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.100",
]
[[package]]
name = "windows-interface"
version = "0.57.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.100",
"syn 2.0.101",
]
[[package]]
@ -6073,7 +6072,7 @@ checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.100",
"syn 2.0.101",
]
[[package]]
@ -6083,12 +6082,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38"
[[package]]
name = "windows-result"
version = "0.1.2"
name = "windows-numerics"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8"
checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1"
dependencies = [
"windows-targets 0.52.6",
"windows-core 0.61.0",
"windows-link",
]
[[package]]
@ -6341,9 +6341,9 @@ dependencies = [
[[package]]
name = "winnow"
version = "0.7.6"
version = "0.7.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "63d3fcd9bba44b03821e7d699eeee959f3126dcc4aa8e4ae18ec617c2a5cea10"
checksum = "d9fb597c990f03753e08d3c29efbfcf2019a003b4bf4ba19225c158e1549f0f3"
dependencies = [
"memchr",
]
@ -6464,28 +6464,28 @@ checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.100",
"syn 2.0.101",
"synstructure",
]
[[package]]
name = "zerocopy"
version = "0.8.24"
version = "0.8.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2586fea28e186957ef732a5f8b3be2da217d65c5969d4b1e17f973ebbe876879"
checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb"
dependencies = [
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.8.24"
version = "0.8.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a996a8f63c5c4448cd959ac1bab0aaa3306ccfd060472f85943ee0750f0169be"
checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.100",
"syn 2.0.101",
]
[[package]]
@ -6505,7 +6505,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.100",
"syn 2.0.101",
"synstructure",
]
@ -6528,5 +6528,5 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.100",
"syn 2.0.101",
]

View file

@ -1633,6 +1633,9 @@ pub enum ExprKind {
/// An `if` block, with an optional `else` block.
///
/// `if expr { block } else { expr }`
///
/// If present, the "else" expr is always `ExprKind::Block` (for `else`) or
/// `ExprKind::If` (for `else if`).
If(P<Expr>, P<Block>, Option<P<Expr>>),
/// A while loop, with an optional label.
///

View file

@ -492,9 +492,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
let mut generic_args = ThinVec::new();
for (idx, arg) in args.iter().cloned().enumerate() {
if legacy_args_idx.contains(&idx) {
let parent_def_id = self.current_hir_id_owner.def_id;
let node_id = self.next_node_id();
self.create_def(parent_def_id, node_id, None, DefKind::AnonConst, f.span);
self.create_def(node_id, None, DefKind::AnonConst, f.span);
let mut visitor = WillCreateDefIdsVisitor {};
let const_value = if let ControlFlow::Break(span) = visitor.visit_expr(&arg) {
AstP(Expr {

View file

@ -1310,7 +1310,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
// create a fake body so that the entire rest of the compiler doesn't have to deal with
// this as a special case.
return self.lower_fn_body(decl, contract, |this| {
if attrs.iter().any(|a| a.has_name(sym::rustc_intrinsic)) {
if attrs.iter().any(|a| a.has_name(sym::rustc_intrinsic))
|| this.tcx.is_sdylib_interface_build()
{
let span = this.lower_span(span);
let empty_block = hir::Block {
hir_id: this.next_id(),

View file

@ -55,8 +55,8 @@ use rustc_errors::{DiagArgFromDisplay, DiagCtxtHandle, StashKey};
use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res};
use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId};
use rustc_hir::{
self as hir, ConstArg, GenericArg, HirId, ItemLocalMap, LangItem, LifetimeSource,
LifetimeSyntax, ParamName, TraitCandidate,
self as hir, AngleBrackets, ConstArg, GenericArg, HirId, ItemLocalMap, LangItem,
LifetimeSource, LifetimeSyntax, ParamName, TraitCandidate,
};
use rustc_index::{Idx, IndexSlice, IndexVec};
use rustc_macros::extension;
@ -500,12 +500,12 @@ enum GenericArgsMode {
impl<'a, 'hir> LoweringContext<'a, 'hir> {
fn create_def(
&mut self,
parent: LocalDefId,
node_id: ast::NodeId,
name: Option<Symbol>,
def_kind: DefKind,
span: Span,
) -> LocalDefId {
let parent = self.current_hir_id_owner.def_id;
debug_assert_ne!(node_id, ast::DUMMY_NODE_ID);
assert!(
self.opt_local_def_id(node_id).is_none(),
@ -515,7 +515,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
self.tcx.hir_def_key(self.local_def_id(node_id)),
);
let def_id = self.tcx.at(span).create_def(parent, name, def_kind).def_id();
let def_id = self
.tcx
.at(span)
.create_def(parent, name, def_kind, None, &mut self.resolver.disambiguator)
.def_id();
debug!("create_def: def_id_to_node_id[{:?}] <-> {:?}", def_id, node_id);
self.resolver.node_id_to_def_id.insert(node_id, def_id);
@ -787,7 +791,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
LifetimeRes::Fresh { param, kind, .. } => {
// Late resolution delegates to us the creation of the `LocalDefId`.
let _def_id = self.create_def(
self.current_hir_id_owner.def_id,
param,
Some(kw::UnderscoreLifetime),
DefKind::LifetimeParam,
@ -1087,7 +1090,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
match arg {
ast::GenericArg::Lifetime(lt) => GenericArg::Lifetime(self.lower_lifetime(
lt,
LifetimeSource::Path { with_angle_brackets: true },
LifetimeSource::Path { angle_brackets: hir::AngleBrackets::Full },
lt.ident.into(),
)),
ast::GenericArg::Type(ty) => {
@ -1779,13 +1782,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
&mut self,
id: NodeId,
span: Span,
with_angle_brackets: bool,
angle_brackets: AngleBrackets,
) -> &'hir hir::Lifetime {
self.new_named_lifetime(
id,
id,
Ident::new(kw::UnderscoreLifetime, span),
LifetimeSource::Path { with_angle_brackets },
LifetimeSource::Path { angle_brackets },
LifetimeSyntax::Hidden,
)
}
@ -2113,8 +2116,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
hir::ConstArgKind::Path(qpath)
} else {
// Construct an AnonConst where the expr is the "ty"'s path.
let parent_def_id = self.current_hir_id_owner.def_id;
let node_id = self.next_node_id();
let span = self.lower_span(span);
@ -2122,7 +2123,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
// We're lowering a const argument that was originally thought to be a type argument,
// so the def collector didn't create the def ahead of time. That's why we have to do
// it here.
let def_id = self.create_def(parent_def_id, node_id, None, DefKind::AnonConst, span);
let def_id = self.create_def(node_id, None, DefKind::AnonConst, span);
let hir_id = self.lower_node_id(node_id);
let path_expr = Expr {

View file

@ -522,14 +522,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
span: Span,
base_type: Span,
) -> &'hir hir::ConstArg<'hir> {
let parent_def_id = self.current_hir_id_owner.def_id;
let node_id = self.next_node_id();
// Add a definition for the in-band const def.
// We're generating a range end that didn't exist in the AST,
// so the def collector didn't create the def ahead of time. That's why we have to do
// it here.
let def_id = self.create_def(parent_def_id, node_id, None, DefKind::AnonConst, span);
let def_id = self.create_def(node_id, None, DefKind::AnonConst, span);
let hir_id = self.lower_node_id(node_id);
let unstable_span = self.mark_span_with_reason(

View file

@ -432,27 +432,31 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
// Note: these spans are used for diagnostics when they can't be inferred.
// See rustc_resolve::late::lifetimes::LifetimeContext::add_missing_lifetime_specifiers_label
let (elided_lifetime_span, with_angle_brackets) = if generic_args.span.is_empty() {
// If there are no brackets, use the identifier span.
let (elided_lifetime_span, angle_brackets) = if generic_args.span.is_empty() {
// No brackets, e.g. `Path`: use an empty span just past the end of the identifier.
// HACK: we use find_ancestor_inside to properly suggest elided spans in paths
// originating from macros, since the segment's span might be from a macro arg.
(segment_ident_span.find_ancestor_inside(path_span).unwrap_or(path_span), false)
} else if generic_args.is_empty() {
// If there are brackets, but not generic arguments, then use the opening bracket
(generic_args.span.with_hi(generic_args.span.lo() + BytePos(1)), true)
(
segment_ident_span.find_ancestor_inside(path_span).unwrap_or(path_span),
hir::AngleBrackets::Missing,
)
} else {
// Else use an empty span right after the opening bracket.
(generic_args.span.with_lo(generic_args.span.lo() + BytePos(1)).shrink_to_lo(), true)
// Brackets, e.g. `Path<>` or `Path<T>`: use an empty span just after the `<`.
(
generic_args.span.with_lo(generic_args.span.lo() + BytePos(1)).shrink_to_lo(),
if generic_args.is_empty() {
hir::AngleBrackets::Empty
} else {
hir::AngleBrackets::Full
},
)
};
generic_args.args.insert_many(
0,
(start..end).map(|id| {
let l = self.lower_lifetime_hidden_in_path(
id,
elided_lifetime_span,
with_angle_brackets,
);
let l =
self.lower_lifetime_hidden_in_path(id, elided_lifetime_span, angle_brackets);
GenericArg::Lifetime(l)
}),
);

View file

@ -82,6 +82,10 @@ struct AstValidator<'a> {
/// Used to ban explicit safety on foreign items when the extern block is not marked as unsafe.
extern_mod_safety: Option<Safety>,
lint_node_id: NodeId,
is_sdylib_interface: bool,
lint_buffer: &'a mut LintBuffer,
}
@ -826,7 +830,7 @@ fn validate_generic_param_order(dcx: DiagCtxtHandle<'_>, generics: &[GenericPara
impl<'a> Visitor<'a> for AstValidator<'a> {
fn visit_attribute(&mut self, attr: &Attribute) {
validate_attr::check_attr(&self.sess.psess, attr);
validate_attr::check_attr(&self.sess.psess, attr, self.lint_node_id);
}
fn visit_ty(&mut self, ty: &'a Ty) {
@ -839,6 +843,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
self.has_proc_macro_decls = true;
}
let previous_lint_node_id = mem::replace(&mut self.lint_node_id, item.id);
if let Some(ident) = item.kind.ident()
&& attr::contains_name(&item.attrs, sym::no_mangle)
{
@ -948,7 +954,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
self.check_defaultness(item.span, *defaultness);
let is_intrinsic = item.attrs.iter().any(|a| a.has_name(sym::rustc_intrinsic));
if body.is_none() && !is_intrinsic {
if body.is_none() && !is_intrinsic && !self.is_sdylib_interface {
self.dcx().emit_err(errors::FnWithoutBody {
span: item.span,
replace_span: self.ending_semi_or_hi(item.span),
@ -1128,6 +1134,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
}
_ => visit::walk_item(self, item),
}
self.lint_node_id = previous_lint_node_id;
}
fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
@ -1435,7 +1443,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
});
}
AssocItemKind::Fn(box Fn { body, .. }) => {
if body.is_none() {
if body.is_none() && !self.is_sdylib_interface {
self.dcx().emit_err(errors::AssocFnWithoutBody {
span: item.span,
replace_span: self.ending_semi_or_hi(item.span),
@ -1683,6 +1691,7 @@ pub fn check_crate(
sess: &Session,
features: &Features,
krate: &Crate,
is_sdylib_interface: bool,
lints: &mut LintBuffer,
) -> bool {
let mut validator = AstValidator {
@ -1694,6 +1703,8 @@ pub fn check_crate(
outer_impl_trait_span: None,
disallow_tilde_const: Some(TildeConstReason::Item),
extern_mod_safety: None,
lint_node_id: CRATE_NODE_ID,
is_sdylib_interface,
lint_buffer: lints,
};
visit::walk_crate(&mut validator, krate);

View file

@ -514,6 +514,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
gate_all!(contracts_internals, "contract internal machinery is for internal use only");
gate_all!(where_clause_attrs, "attributes in `where` clause are unstable");
gate_all!(super_let, "`super let` is experimental");
gate_all!(frontmatter, "frontmatters are experimental");
if !visitor.features.never_patterns() {
if let Some(spans) = spans.get(&sym::never_patterns) {

View file

@ -244,9 +244,6 @@ struct BufEntry {
// forgotten will trigger a panic in `drop`. (Closing a box more than once
// isn't possible because `BoxMarker` doesn't implement `Copy` or `Clone`.)
//
// FIXME(nnethercote): the panic in `drop` is currently disabled because a few
// places fail to close their boxes. It can be enabled once they are fixed.
//
// Note: it would be better to make open/close mismatching impossible and avoid
// the need for this marker type altogether by having functions like
// `with_ibox` that open a box, call a closure, and then close the box. That
@ -261,8 +258,7 @@ impl !Copy for BoxMarker {}
impl Drop for BoxMarker {
fn drop(&mut self) {
// FIXME(nnethercote): enable once the bad cases are fixed
//panic!("BoxMarker not ended with `Printer::end()`");
panic!("BoxMarker not ended with `Printer::end()`");
}
}

View file

@ -7,7 +7,9 @@ use std::borrow::Cow;
use rustc_ast as ast;
use rustc_ast::token::{Token, TokenKind};
use rustc_ast::tokenstream::{TokenStream, TokenTree};
pub use state::{AnnNode, Comments, PpAnn, PrintState, State, print_crate};
pub use state::{
AnnNode, Comments, PpAnn, PrintState, State, print_crate, print_crate_as_interface,
};
/// Print the token kind precisely, without converting `$crate` into its respective crate name.
pub fn token_kind_to_string(tok: &TokenKind) -> Cow<'static, str> {

View file

@ -221,6 +221,7 @@ pub struct State<'a> {
pub s: pp::Printer,
comments: Option<Comments<'a>>,
ann: &'a (dyn PpAnn + 'a),
is_sdylib_interface: bool,
}
const INDENT_UNIT: isize = 4;
@ -236,9 +237,41 @@ pub fn print_crate<'a>(
is_expanded: bool,
edition: Edition,
g: &AttrIdGenerator,
) -> String {
let mut s = State {
s: pp::Printer::new(),
comments: Some(Comments::new(sm, filename, input)),
ann,
is_sdylib_interface: false,
};
print_crate_inner(&mut s, krate, is_expanded, edition, g);
s.s.eof()
}
pub fn print_crate_as_interface(
krate: &ast::Crate,
edition: Edition,
g: &AttrIdGenerator,
) -> String {
let mut s =
State { s: pp::Printer::new(), comments: Some(Comments::new(sm, filename, input)), ann };
State { s: pp::Printer::new(), comments: None, ann: &NoAnn, is_sdylib_interface: true };
print_crate_inner(&mut s, krate, false, edition, g);
s.s.eof()
}
fn print_crate_inner<'a>(
s: &mut State<'a>,
krate: &ast::Crate,
is_expanded: bool,
edition: Edition,
g: &AttrIdGenerator,
) {
// We need to print shebang before anything else
// otherwise the resulting code will not compile
// and shebang will be useless.
s.maybe_print_shebang();
if is_expanded && !krate.attrs.iter().any(|attr| attr.has_name(sym::no_core)) {
// We need to print `#![no_std]` (and its feature gate) so that
@ -277,8 +310,7 @@ pub fn print_crate<'a>(
s.print_item(item);
}
s.print_remaining_comments();
s.ann.post(&mut s, AnnNode::Crate(krate));
s.s.eof()
s.ann.post(s, AnnNode::Crate(krate));
}
/// Should two consecutive tokens be printed with a space between them?
@ -560,6 +592,20 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
self.word(st)
}
fn maybe_print_shebang(&mut self) {
if let Some(cmnt) = self.peek_comment() {
// Comment is a shebang if it's:
// Isolated, starts with #! and doesn't continue with `[`
// See [rustc_lexer::strip_shebang] and [gather_comments] from pprust/state.rs for details
if cmnt.style == CommentStyle::Isolated
&& cmnt.lines.first().map_or(false, |l| l.starts_with("#!"))
{
let cmnt = self.next_comment().unwrap();
self.print_comment(cmnt);
}
}
}
fn print_inner_attributes(&mut self, attrs: &[ast::Attribute]) -> bool {
self.print_either_attributes(attrs, ast::AttrStyle::Inner, false, true)
}
@ -1092,7 +1138,7 @@ impl<'a> PrintState<'a> for State<'a> {
impl<'a> State<'a> {
pub fn new() -> State<'a> {
State { s: pp::Printer::new(), comments: None, ann: &NoAnn }
State { s: pp::Printer::new(), comments: None, ann: &NoAnn, is_sdylib_interface: false }
}
fn commasep_cmnt<T, F, G>(&mut self, b: Breaks, elts: &[T], mut op: F, mut get_span: G)

View file

@ -13,7 +13,7 @@ use rustc_ast::{
use crate::pp::Breaks::Inconsistent;
use crate::pprust::state::fixup::FixupContext;
use crate::pprust::state::{AnnNode, BoxMarker, INDENT_UNIT, PrintState, State};
use crate::pprust::state::{AnnNode, INDENT_UNIT, PrintState, State};
impl<'a> State<'a> {
fn print_else(&mut self, els: Option<&ast::Expr>) {
@ -485,12 +485,12 @@ impl<'a> State<'a> {
self.print_block_with_attrs(body, attrs, cb, ib);
}
ast::ExprKind::Loop(blk, opt_label, _) => {
let cb = self.cbox(0);
let ib = self.ibox(0);
if let Some(label) = opt_label {
self.print_ident(label.ident);
self.word_space(":");
}
let cb = self.cbox(0);
let ib = self.ibox(0);
self.word_nbsp("loop");
self.print_block_with_attrs(blk, attrs, cb, ib);
}
@ -542,15 +542,6 @@ impl<'a> State<'a> {
self.print_fn_params_and_ret(fn_decl, true);
self.space();
self.print_expr(body, FixupContext::default());
// FIXME(nnethercote): Bogus. Reduce visibility of `ended` once it's fixed.
let fake_ib = BoxMarker;
self.end(fake_ib);
// A box will be closed by print_expr, but we didn't want an overall
// wrapper so we closed the corresponding opening. so create an
// empty box to satisfy the close.
// FIXME(nnethercote): Bogus.
let _ib = self.ibox(0);
}
ast::ExprKind::Block(blk, opt_label) => {
if let Some(label) = opt_label {

View file

@ -160,6 +160,10 @@ impl<'a> State<'a> {
/// Pretty-prints an item.
pub(crate) fn print_item(&mut self, item: &ast::Item) {
if self.is_sdylib_interface && item.span.is_dummy() {
// Do not print prelude for interface files.
return;
}
self.hardbreak_if_not_bol();
self.maybe_print_comment(item.span.lo());
self.print_outer_attributes(&item.attrs);
@ -682,6 +686,13 @@ impl<'a> State<'a> {
self.print_contract(contract);
}
if let Some((body, (cb, ib))) = body_cb_ib {
if self.is_sdylib_interface {
self.word(";");
self.end(ib); // end inner head-block
self.end(cb); // end outer head-block
return;
}
self.nbsp();
self.print_block_with_attrs(body, attrs, cb, ib);
} else {

View file

@ -7,7 +7,7 @@ use rustc_middle::ty::{RegionVid, TyCtxt, VarianceDiagInfo};
use rustc_span::Span;
use tracing::{debug, instrument};
use crate::region_infer::{ConstraintSccs, RegionDefinition, RegionTracker};
use crate::region_infer::{AnnotatedSccs, ConstraintSccs, RegionDefinition, SccAnnotations};
use crate::type_check::Locations;
use crate::universal_regions::UniversalRegions;
@ -61,12 +61,14 @@ impl<'tcx> OutlivesConstraintSet<'tcx> {
&self,
static_region: RegionVid,
definitions: &IndexVec<RegionVid, RegionDefinition<'tcx>>,
) -> ConstraintSccs {
) -> AnnotatedSccs {
let constraint_graph = self.graph(definitions.len());
let region_graph = &constraint_graph.region_graph(self, static_region);
ConstraintSccs::new_with_annotation(&region_graph, |r| {
RegionTracker::new(r, &definitions[r])
})
let mut annotation_visitor = SccAnnotations::new(definitions);
(
ConstraintSccs::new_with_annotation(&region_graph, &mut annotation_visitor),
annotation_visitor.scc_to_annotation,
)
}
/// This method handles Universe errors by rewriting the constraint
@ -79,12 +81,12 @@ impl<'tcx> OutlivesConstraintSet<'tcx> {
/// eventually go away.
///
/// For a more precise definition, see the documentation for
/// [`RegionTracker::has_incompatible_universes()`].
/// [`crate::region_infer::RegionTracker`].
///
/// This edge case used to be handled during constraint propagation
/// by iterating over the strongly connected components in the constraint
/// graph while maintaining a set of bookkeeping mappings similar
/// to what is stored in `RegionTracker` and manually adding 'sttaic as
/// to what is stored in `RegionTracker` and manually adding 'static as
/// needed.
///
/// It was rewritten as part of the Polonius project with the goal of moving
@ -108,9 +110,9 @@ impl<'tcx> OutlivesConstraintSet<'tcx> {
&mut self,
universal_regions: &UniversalRegions<'tcx>,
definitions: &IndexVec<RegionVid, RegionDefinition<'tcx>>,
) -> ConstraintSccs {
) -> AnnotatedSccs {
let fr_static = universal_regions.fr_static;
let sccs = self.compute_sccs(fr_static, definitions);
let (sccs, annotations) = self.compute_sccs(fr_static, definitions);
// Changed to `true` if we added any constraints to `self` and need to
// recompute SCCs.
@ -124,7 +126,7 @@ impl<'tcx> OutlivesConstraintSet<'tcx> {
continue;
}
let annotation = sccs.annotation(scc);
let annotation = annotations[scc];
// If this SCC participates in a universe violation,
// e.g. if it reaches a region with a universe smaller than
@ -154,7 +156,7 @@ impl<'tcx> OutlivesConstraintSet<'tcx> {
self.compute_sccs(fr_static, definitions)
} else {
// If we didn't add any back-edges; no more work needs doing
sccs
(sccs, annotations)
}
}
}

View file

@ -2954,12 +2954,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
}
}
let name = if borrow_span.in_external_macro(self.infcx.tcx.sess.source_map()) {
// Don't name local variables in external macros.
"value".to_string()
} else {
format!("`{name}`")
};
let name = format!("`{name}`");
let mut err = self.path_does_not_live_long_enough(borrow_span, &name);

View file

@ -317,6 +317,14 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
opt: DescribePlaceOpt,
) -> Option<String> {
let local = place.local;
if self.body.local_decls[local]
.source_info
.span
.in_external_macro(self.infcx.tcx.sess.source_map())
{
return None;
}
let mut autoderef_index = None;
let mut buf = String::new();
let mut ok = self.append_local_to_string(local, &mut buf);

View file

@ -47,7 +47,7 @@ use rustc_mir_dataflow::impls::{
use rustc_mir_dataflow::move_paths::{
InitIndex, InitLocation, LookupResult, MoveData, MovePathIndex,
};
use rustc_mir_dataflow::{Analysis, EntryStates, Results, ResultsVisitor, visit_results};
use rustc_mir_dataflow::{Analysis, Results, ResultsVisitor, visit_results};
use rustc_session::lint::builtin::{TAIL_EXPR_DROP_ORDER, UNUSED_MUT};
use rustc_span::{ErrorGuaranteed, Span, Symbol};
use smallvec::SmallVec;
@ -127,6 +127,14 @@ fn mir_borrowck(
Ok(tcx.arena.alloc(opaque_types))
} else {
let mut root_cx = BorrowCheckRootCtxt::new(tcx, def);
// We need to manually borrowck all nested bodies from the HIR as
// we do not generate MIR for dead code. Not doing so causes us to
// never check closures in dead code.
let nested_bodies = tcx.nested_bodies_within(def);
for def_id in nested_bodies {
root_cx.get_or_insert_nested(def_id);
}
let PropagatedBorrowCheckResults { closure_requirements, used_mut_upvars } =
do_mir_borrowck(&mut root_cx, def, None).0;
debug_assert!(closure_requirements.is_none());
@ -461,11 +469,13 @@ fn do_mir_borrowck<'tcx>(
// Compute and report region errors, if any.
mbcx.report_region_errors(nll_errors);
let mut flow_results = get_flow_results(tcx, body, &move_data, &borrow_set, &regioncx);
let (mut flow_analysis, flow_entry_states) =
get_flow_results(tcx, body, &move_data, &borrow_set, &regioncx);
visit_results(
body,
traversal::reverse_postorder(body).map(|(bb, _)| bb),
&mut flow_results,
&mut flow_analysis,
&flow_entry_states,
&mut mbcx,
);
@ -525,7 +535,7 @@ fn get_flow_results<'a, 'tcx>(
move_data: &'a MoveData<'tcx>,
borrow_set: &'a BorrowSet<'tcx>,
regioncx: &RegionInferenceContext<'tcx>,
) -> Results<'tcx, Borrowck<'a, 'tcx>> {
) -> (Borrowck<'a, 'tcx>, Results<BorrowckDomain>) {
// We compute these three analyses individually, but them combine them into
// a single results so that `mbcx` can visit them all together.
let borrows = Borrows::new(tcx, body, regioncx, borrow_set).iterate_to_fixpoint(
@ -550,14 +560,14 @@ fn get_flow_results<'a, 'tcx>(
ever_inits: ever_inits.analysis,
};
assert_eq!(borrows.entry_states.len(), uninits.entry_states.len());
assert_eq!(borrows.entry_states.len(), ever_inits.entry_states.len());
let entry_states: EntryStates<'_, Borrowck<'_, '_>> =
itertools::izip!(borrows.entry_states, uninits.entry_states, ever_inits.entry_states)
assert_eq!(borrows.results.len(), uninits.results.len());
assert_eq!(borrows.results.len(), ever_inits.results.len());
let results: Results<_> =
itertools::izip!(borrows.results, uninits.results, ever_inits.results)
.map(|(borrows, uninits, ever_inits)| BorrowckDomain { borrows, uninits, ever_inits })
.collect();
Results { analysis, entry_states }
(analysis, results)
}
pub(crate) struct BorrowckInferCtxt<'tcx> {
@ -705,7 +715,7 @@ struct MirBorrowckCtxt<'a, 'infcx, 'tcx> {
impl<'a, 'tcx> ResultsVisitor<'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt<'a, '_, 'tcx> {
fn visit_after_early_statement_effect(
&mut self,
_results: &mut Results<'tcx, Borrowck<'a, 'tcx>>,
_analysis: &mut Borrowck<'a, 'tcx>,
state: &BorrowckDomain,
stmt: &Statement<'tcx>,
location: Location,
@ -781,7 +791,7 @@ impl<'a, 'tcx> ResultsVisitor<'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt<'a,
fn visit_after_early_terminator_effect(
&mut self,
_results: &mut Results<'tcx, Borrowck<'a, 'tcx>>,
_analysis: &mut Borrowck<'a, 'tcx>,
state: &BorrowckDomain,
term: &Terminator<'tcx>,
loc: Location,
@ -901,7 +911,7 @@ impl<'a, 'tcx> ResultsVisitor<'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt<'a,
fn visit_after_primary_terminator_effect(
&mut self,
_results: &mut Results<'tcx, Borrowck<'a, 'tcx>>,
_analysis: &mut Borrowck<'a, 'tcx>,
state: &BorrowckDomain,
term: &Terminator<'tcx>,
loc: Location,

View file

@ -47,12 +47,13 @@ mod reverse_sccs;
pub(crate) mod values;
pub(crate) type ConstraintSccs = Sccs<RegionVid, ConstraintSccIndex, RegionTracker>;
pub(crate) type ConstraintSccs = Sccs<RegionVid, ConstraintSccIndex>;
pub(crate) type AnnotatedSccs = (ConstraintSccs, IndexVec<ConstraintSccIndex, RegionTracker>);
/// An annotation for region graph SCCs that tracks
/// the values of its elements.
/// the values of its elements. This annotates a single SCC.
#[derive(Copy, Debug, Clone)]
pub struct RegionTracker {
pub(crate) struct RegionTracker {
/// The largest universe of a placeholder reached from this SCC.
/// This includes placeholders within this SCC.
max_placeholder_universe_reached: UniverseIndex,
@ -97,6 +98,32 @@ impl scc::Annotation for RegionTracker {
}
}
/// A Visitor for SCC annotation construction.
pub(crate) struct SccAnnotations<'d, 'tcx, A: scc::Annotation> {
pub(crate) scc_to_annotation: IndexVec<ConstraintSccIndex, A>,
definitions: &'d IndexVec<RegionVid, RegionDefinition<'tcx>>,
}
impl<'d, 'tcx, A: scc::Annotation> SccAnnotations<'d, 'tcx, A> {
pub(crate) fn new(definitions: &'d IndexVec<RegionVid, RegionDefinition<'tcx>>) -> Self {
Self { scc_to_annotation: IndexVec::new(), definitions }
}
}
impl scc::Annotations<RegionVid> for SccAnnotations<'_, '_, RegionTracker> {
fn new(&self, element: RegionVid) -> RegionTracker {
RegionTracker::new(element, &self.definitions[element])
}
fn annotate_scc(&mut self, scc: ConstraintSccIndex, annotation: RegionTracker) {
let idx = self.scc_to_annotation.push(annotation);
assert!(idx == scc);
}
type Ann = RegionTracker;
type SccIdx = ConstraintSccIndex;
}
impl RegionTracker {
pub(crate) fn new(rvid: RegionVid, definition: &RegionDefinition<'_>) -> Self {
let (representative_is_placeholder, representative_is_existential) = match definition.origin
@ -166,6 +193,8 @@ pub struct RegionInferenceContext<'tcx> {
/// compute the values of each region.
constraint_sccs: ConstraintSccs,
scc_annotations: IndexVec<ConstraintSccIndex, RegionTracker>,
/// Reverse of the SCC constraint graph -- i.e., an edge `A -> B` exists if
/// `B: A`. This is used to compute the universal regions that are required
/// to outlive a given SCC. Computed lazily.
@ -446,7 +475,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
let definitions = create_definitions(infcx, &universal_regions);
let constraint_sccs =
let (constraint_sccs, scc_annotations) =
outlives_constraints.add_outlives_static(&universal_regions, &definitions);
let constraints = Frozen::freeze(outlives_constraints);
let constraint_graph = Frozen::freeze(constraints.graph(definitions.len()));
@ -472,6 +501,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
constraints,
constraint_graph,
constraint_sccs,
scc_annotations,
rev_scc_graph: None,
member_constraints,
member_constraints_applied: Vec::new(),
@ -798,7 +828,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
// If the member region lives in a higher universe, we currently choose
// the most conservative option by leaving it unchanged.
if !self.constraint_sccs().annotation(scc).min_universe().is_root() {
if !self.scc_universe(scc).is_root() {
return;
}
@ -874,8 +904,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
/// in `scc_a`. Used during constraint propagation, and only once
/// the value of `scc_b` has been computed.
fn universe_compatible(&self, scc_b: ConstraintSccIndex, scc_a: ConstraintSccIndex) -> bool {
let a_annotation = self.constraint_sccs().annotation(scc_a);
let b_annotation = self.constraint_sccs().annotation(scc_b);
let a_annotation = self.scc_annotations[scc_a];
let b_annotation = self.scc_annotations[scc_b];
let a_universe = a_annotation.min_universe();
// If scc_b's declared universe is a subset of
@ -991,7 +1021,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
"lower_bound = {:?} r_scc={:?} universe={:?}",
lower_bound,
r_scc,
self.constraint_sccs.annotation(r_scc).min_universe()
self.scc_universe(r_scc)
);
// If the type test requires that `T: 'a` where `'a` is a
// placeholder from another universe, that effectively requires
@ -1472,7 +1502,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
/// The minimum universe of any variable reachable from this
/// SCC, inside or outside of it.
fn scc_universe(&self, scc: ConstraintSccIndex) -> UniverseIndex {
self.constraint_sccs().annotation(scc).min_universe()
self.scc_annotations[scc].min_universe()
}
/// Checks the final value for the free region `fr` to see if it
@ -2216,7 +2246,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
/// they *must* be equal (though not having the same repr does not
/// mean they are unequal).
fn scc_representative(&self, scc: ConstraintSccIndex) -> RegionVid {
self.constraint_sccs.annotation(scc).representative
self.scc_annotations[scc].representative
}
pub(crate) fn liveness_constraints(&self) -> &LivenessValues {

View file

@ -267,13 +267,13 @@ impl<'tcx> InferCtxt<'tcx> {
return Ty::new_error(self.tcx, e);
}
if let Err(guar) = check_opaque_type_parameter_valid(
if let Err(err) = check_opaque_type_parameter_valid(
self,
opaque_type_key,
instantiated_ty.span,
DefiningScopeKind::MirBorrowck,
) {
return Ty::new_error(self.tcx, guar);
return Ty::new_error(self.tcx, err.report(self));
}
let definition_ty = instantiated_ty

View file

@ -7,6 +7,8 @@ use rustc_middle::ty::RegionVid;
use crate::RegionInferenceContext;
use crate::constraints::ConstraintSccIndex;
use crate::region_infer::ConstraintSccs;
use crate::universal_regions::UniversalRegions;
pub(crate) struct ReverseSccGraph {
graph: VecGraph<ConstraintSccIndex>,
@ -19,6 +21,29 @@ pub(crate) struct ReverseSccGraph {
}
impl ReverseSccGraph {
pub(super) fn compute(
constraint_sccs: &ConstraintSccs,
universal_regions: &UniversalRegions<'_>,
) -> Self {
let graph = constraint_sccs.reverse();
let mut paired_scc_regions = universal_regions
.universal_regions_iter()
.map(|region| (constraint_sccs.scc(region), region))
.collect::<Vec<_>>();
paired_scc_regions.sort();
let universal_regions = paired_scc_regions.iter().map(|&(_, region)| region).collect();
let mut scc_regions = FxIndexMap::default();
let mut start = 0;
for chunk in paired_scc_regions.chunk_by(|&(scc1, _), &(scc2, _)| scc1 == scc2) {
let (scc, _) = chunk[0];
scc_regions.insert(scc, start..start + chunk.len());
start += chunk.len();
}
ReverseSccGraph { graph, scc_regions, universal_regions }
}
/// Find all universal regions that are required to outlive the given SCC.
pub(super) fn upper_bounds(&self, scc0: ConstraintSccIndex) -> impl Iterator<Item = RegionVid> {
let mut duplicates = FxIndexSet::default();
@ -40,23 +65,7 @@ impl RegionInferenceContext<'_> {
return;
}
let graph = self.constraint_sccs.reverse();
let mut paired_scc_regions = self
.universal_regions()
.universal_regions_iter()
.map(|region| (self.constraint_sccs.scc(region), region))
.collect::<Vec<_>>();
paired_scc_regions.sort();
let universal_regions = paired_scc_regions.iter().map(|&(_, region)| region).collect();
let mut scc_regions = FxIndexMap::default();
let mut start = 0;
for chunk in paired_scc_regions.chunk_by(|&(scc1, _), &(scc2, _)| scc1 == scc2) {
let (scc, _) = chunk[0];
scc_regions.insert(scc, start..start + chunk.len());
start += chunk.len();
}
self.rev_scc_graph = Some(ReverseSccGraph { graph, scc_regions, universal_regions });
self.rev_scc_graph =
Some(ReverseSccGraph::compute(&self.constraint_sccs, self.universal_regions()));
}
}

View file

@ -62,7 +62,10 @@ impl<'tcx> BorrowCheckRootCtxt<'tcx> {
self.tainted_by_errors = Some(guar);
}
fn get_or_insert_nested(&mut self, def_id: LocalDefId) -> &PropagatedBorrowCheckResults<'tcx> {
pub(super) fn get_or_insert_nested(
&mut self,
def_id: LocalDefId,
) -> &PropagatedBorrowCheckResults<'tcx> {
debug_assert_eq!(
self.tcx.typeck_root_def_id(def_id.to_def_id()),
self.root_def_id.to_def_id()

View file

@ -41,8 +41,8 @@ type NormalizedInputsAndOutput<'tcx> = Vec<Ty<'tcx>>;
pub(crate) struct CreateResult<'tcx> {
pub(crate) universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
pub(crate) region_bound_pairs: RegionBoundPairs<'tcx>,
pub(crate) known_type_outlives_obligations: Vec<ty::PolyTypeOutlivesPredicate<'tcx>>,
pub(crate) region_bound_pairs: Frozen<RegionBoundPairs<'tcx>>,
pub(crate) known_type_outlives_obligations: Frozen<Vec<ty::PolyTypeOutlivesPredicate<'tcx>>>,
pub(crate) normalized_inputs_and_output: NormalizedInputsAndOutput<'tcx>,
}
@ -333,8 +333,8 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
outlives: self.outlives.freeze(),
inverse_outlives: self.inverse_outlives.freeze(),
}),
known_type_outlives_obligations,
region_bound_pairs: self.region_bound_pairs,
known_type_outlives_obligations: Frozen::freeze(known_type_outlives_obligations),
region_bound_pairs: Frozen::freeze(self.region_bound_pairs),
normalized_inputs_and_output,
}
}

View file

@ -151,8 +151,8 @@ pub(crate) fn type_check<'a, 'tcx>(
body,
promoted,
user_type_annotations: &body.user_type_annotations,
region_bound_pairs,
known_type_outlives_obligations,
region_bound_pairs: &region_bound_pairs,
known_type_outlives_obligations: &known_type_outlives_obligations,
reported_errors: Default::default(),
universal_regions: &universal_region_relations.universal_regions,
location_table,
@ -216,8 +216,8 @@ struct TypeChecker<'a, 'tcx> {
/// User type annotations are shared between the main MIR and the MIR of
/// all of the promoted items.
user_type_annotations: &'a CanonicalUserTypeAnnotations<'tcx>,
region_bound_pairs: RegionBoundPairs<'tcx>,
known_type_outlives_obligations: Vec<ty::PolyTypeOutlivesPredicate<'tcx>>,
region_bound_pairs: &'a RegionBoundPairs<'tcx>,
known_type_outlives_obligations: &'a [ty::PolyTypeOutlivesPredicate<'tcx>],
reported_errors: FxIndexSet<(Ty<'tcx>, Span)>,
universal_regions: &'a UniversalRegions<'tcx>,
location_table: &'a PoloniusLocationTable,
@ -412,9 +412,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
constraint_conversion::ConstraintConversion::new(
self.infcx,
self.universal_regions,
&self.region_bound_pairs,
self.region_bound_pairs,
self.infcx.param_env,
&self.known_type_outlives_obligations,
self.known_type_outlives_obligations,
locations,
locations.span(self.body),
category,
@ -2506,9 +2506,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
constraint_conversion::ConstraintConversion::new(
self.infcx,
self.universal_regions,
&self.region_bound_pairs,
self.region_bound_pairs,
self.infcx.param_env,
&self.known_type_outlives_obligations,
self.known_type_outlives_obligations,
locations,
self.body.span, // irrelevant; will be overridden.
ConstraintCategory::Boring, // same as above.

View file

@ -1,3 +1,5 @@
use std::ops::Range;
use parse::Position::ArgumentNamed;
use rustc_ast::ptr::P;
use rustc_ast::tokenstream::TokenStream;
@ -335,7 +337,7 @@ fn make_format_args(
return ExpandResult::Ready(Err(guar));
}
let to_span = |inner_span: parse::InnerSpan| {
let to_span = |inner_span: Range<usize>| {
is_source_literal.then(|| {
fmt_span.from_inner(InnerSpan { start: inner_span.start, end: inner_span.end })
})
@ -407,7 +409,7 @@ fn make_format_args(
let mut placeholder_index = 0;
for piece in &pieces {
match *piece {
match piece.clone() {
parse::Piece::Lit(s) => {
unfinished_literal.push_str(s);
}
@ -417,7 +419,8 @@ fn make_format_args(
unfinished_literal.clear();
}
let span = parser.arg_places.get(placeholder_index).and_then(|&s| to_span(s));
let span =
parser.arg_places.get(placeholder_index).and_then(|s| to_span(s.clone()));
placeholder_index += 1;
let position_span = to_span(position_span);
@ -609,7 +612,7 @@ fn make_format_args(
fn invalid_placeholder_type_error(
ecx: &ExtCtxt<'_>,
ty: &str,
ty_span: Option<parse::InnerSpan>,
ty_span: Option<Range<usize>>,
fmt_span: Span,
) {
let sp = ty_span.map(|sp| fmt_span.from_inner(InnerSpan::new(sp.start, sp.end)));

View file

@ -1282,7 +1282,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
intrinsic.name,
);
}
return Err(Instance::new(instance.def_id(), instance.args));
return Err(Instance::new_raw(instance.def_id(), instance.args));
}
}

View file

@ -44,7 +44,11 @@ use crate::{GccCodegenBackend, GccContext, SyncContext, to_gcc_opt_level};
pub fn crate_type_allows_lto(crate_type: CrateType) -> bool {
match crate_type {
CrateType::Executable | CrateType::Dylib | CrateType::Staticlib | CrateType::Cdylib => true,
CrateType::Executable
| CrateType::Dylib
| CrateType::Staticlib
| CrateType::Cdylib
| CrateType::Sdylib => true,
CrateType::Rlib | CrateType::ProcMacro => false,
}
}

View file

@ -399,7 +399,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc
}
// Fall back to default body
_ => return Err(Instance::new(instance.def_id(), instance.args)),
_ => return Err(Instance::new_raw(instance.def_id(), instance.args)),
};
if !fn_abi.ret.is_ignore() {

View file

@ -42,7 +42,8 @@ fn crate_type_allows_lto(crate_type: CrateType) -> bool {
| CrateType::Dylib
| CrateType::Staticlib
| CrateType::Cdylib
| CrateType::ProcMacro => true,
| CrateType::ProcMacro
| CrateType::Sdylib => true,
CrateType::Rlib => false,
}
}

View file

@ -157,7 +157,7 @@ fn make_dummy_instance<'tcx>(tcx: TyCtxt<'tcx>, local_def_id: LocalDefId) -> ty:
let def_id = local_def_id.to_def_id();
// Make a dummy instance that fills in all generics with placeholders.
ty::Instance::new(
ty::Instance::new_raw(
def_id,
ty::GenericArgs::for_item(tcx, def_id, |param, _| {
if let ty::GenericParamDefKind::Lifetime = param.kind {

View file

@ -95,7 +95,11 @@ pub(crate) fn needs_gdb_debug_scripts_section(cx: &CodegenCx<'_, '_>) -> bool {
// in the `.debug_gdb_scripts` section. For that reason, we make sure that the
// section is only emitted for leaf crates.
let embed_visualizers = cx.tcx.crate_types().iter().any(|&crate_type| match crate_type {
CrateType::Executable | CrateType::Dylib | CrateType::Cdylib | CrateType::Staticlib => {
CrateType::Executable
| CrateType::Dylib
| CrateType::Cdylib
| CrateType::Staticlib
| CrateType::Sdylib => {
// These are crate types for which we will embed pretty printers since they
// are treated as leaf crates.
true

View file

@ -613,7 +613,7 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
_ => {
debug!("unknown intrinsic '{}' -- falling back to default body", name);
// Call the fallback body instead of generating the intrinsic code
return Err(ty::Instance::new(instance.def_id(), instance.args));
return Err(ty::Instance::new_raw(instance.def_id(), instance.args));
}
};

View file

@ -19,6 +19,7 @@ use rustc_session::config::{PrintKind, PrintRequest};
use rustc_span::Symbol;
use rustc_target::spec::{MergeFunctions, PanicStrategy, SmallDataThresholdSupport};
use rustc_target::target_features::{RUSTC_SPECIAL_FEATURES, RUSTC_SPECIFIC_FEATURES};
use smallvec::{SmallVec, smallvec};
use crate::back::write::create_informational_target_machine;
use crate::errors::{
@ -180,27 +181,27 @@ impl<'a> TargetFeatureFoldStrength<'a> {
pub(crate) struct LLVMFeature<'a> {
llvm_feature_name: &'a str,
dependency: Option<TargetFeatureFoldStrength<'a>>,
dependencies: SmallVec<[TargetFeatureFoldStrength<'a>; 1]>,
}
impl<'a> LLVMFeature<'a> {
fn new(llvm_feature_name: &'a str) -> Self {
Self { llvm_feature_name, dependency: None }
Self { llvm_feature_name, dependencies: SmallVec::new() }
}
fn with_dependency(
fn with_dependencies(
llvm_feature_name: &'a str,
dependency: TargetFeatureFoldStrength<'a>,
dependencies: SmallVec<[TargetFeatureFoldStrength<'a>; 1]>,
) -> Self {
Self { llvm_feature_name, dependency: Some(dependency) }
Self { llvm_feature_name, dependencies }
}
fn contains(&self, feat: &str) -> bool {
fn contains(&'a self, feat: &str) -> bool {
self.iter().any(|dep| dep == feat)
}
fn iter(&'a self) -> impl Iterator<Item = &'a str> {
let dependencies = self.dependency.iter().map(|feat| feat.as_str());
let dependencies = self.dependencies.iter().map(|feat| feat.as_str());
std::iter::once(self.llvm_feature_name).chain(dependencies)
}
}
@ -210,7 +211,7 @@ impl<'a> IntoIterator for LLVMFeature<'a> {
type IntoIter = impl Iterator<Item = &'a str>;
fn into_iter(self) -> Self::IntoIter {
let dependencies = self.dependency.into_iter().map(|feat| feat.as_str());
let dependencies = self.dependencies.into_iter().map(|feat| feat.as_str());
std::iter::once(self.llvm_feature_name).chain(dependencies)
}
}
@ -240,9 +241,9 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option<LLVMFea
&*sess.target.arch
};
match (arch, s) {
("x86", "sse4.2") => Some(LLVMFeature::with_dependency(
("x86", "sse4.2") => Some(LLVMFeature::with_dependencies(
"sse4.2",
TargetFeatureFoldStrength::EnableOnly("crc32"),
smallvec![TargetFeatureFoldStrength::EnableOnly("crc32")],
)),
("x86", "pclmulqdq") => Some(LLVMFeature::new("pclmul")),
("x86", "rdrand") => Some(LLVMFeature::new("rdrnd")),
@ -262,9 +263,10 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option<LLVMFea
("aarch64", "sme-b16b16") if get_version().0 < 20 => Some(LLVMFeature::new("b16b16")),
("aarch64", "flagm2") => Some(LLVMFeature::new("altnzcv")),
// Rust ties fp and neon together.
("aarch64", "neon") => {
Some(LLVMFeature::with_dependency("neon", TargetFeatureFoldStrength::Both("fp-armv8")))
}
("aarch64", "neon") => Some(LLVMFeature::with_dependencies(
"neon",
smallvec![TargetFeatureFoldStrength::Both("fp-armv8")],
)),
// In LLVM neon implicitly enables fp, but we manually enable
// neon when a feature only implicitly enables fp
("aarch64", "fhm") => Some(LLVMFeature::new("fp16fml")),
@ -273,11 +275,18 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option<LLVMFea
("aarch64", "fpmr") => None, // only existed in 18
("arm", "fp16") => Some(LLVMFeature::new("fullfp16")),
// Filter out features that are not supported by the current LLVM version
("loongarch64", "div32" | "lam-bh" | "lamcas" | "ld-seq-sa" | "scq")
if get_version().0 < 20 =>
{
None
}
// Filter out features that are not supported by the current LLVM version
("riscv32" | "riscv64", "zacas") if get_version().0 < 20 => None,
// Enable the evex512 target feature if an avx512 target feature is enabled.
("x86", s) if s.starts_with("avx512") => {
Some(LLVMFeature::with_dependency(s, TargetFeatureFoldStrength::EnableOnly("evex512")))
}
("x86", s) if s.starts_with("avx512") => Some(LLVMFeature::with_dependencies(
s,
smallvec![TargetFeatureFoldStrength::EnableOnly("evex512")],
)),
// Support for `wide-arithmetic` will first land in LLVM 20 as part of
// llvm/llvm-project#111598
("wasm32" | "wasm64", "wide-arithmetic") if get_version() < (20, 0, 0) => None,
@ -295,6 +304,21 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option<LLVMFea
None
}
("x86", "movrs") if get_version().0 < 20 => None,
("x86", "avx10.1") => Some(LLVMFeature::new("avx10.1-512")),
("x86", "avx10.2") if get_version().0 < 20 => None,
("x86", "avx10.2") if get_version().0 >= 20 => Some(LLVMFeature::new("avx10.2-512")),
("x86", "apxf") => Some(LLVMFeature::with_dependencies(
"egpr",
smallvec![
TargetFeatureFoldStrength::Both("push2pop2"),
TargetFeatureFoldStrength::Both("ppx"),
TargetFeatureFoldStrength::Both("ndd"),
TargetFeatureFoldStrength::Both("ccmp"),
TargetFeatureFoldStrength::Both("cf"),
TargetFeatureFoldStrength::Both("nf"),
TargetFeatureFoldStrength::Both("zu"),
],
)),
(_, s) => Some(LLVMFeature::new(s)),
}
}
@ -844,7 +868,7 @@ pub(crate) fn global_llvm_features(
"{}{}",
enable_disable, llvm_feature.llvm_feature_name
))
.chain(llvm_feature.dependency.into_iter().filter_map(
.chain(llvm_feature.dependencies.into_iter().filter_map(
move |feat| match (enable, feat) {
(_, TargetFeatureFoldStrength::Both(f))
| (true, TargetFeatureFoldStrength::EnableOnly(f)) => {

View file

@ -1053,9 +1053,10 @@ fn link_natively(
strip_with_external_utility(sess, stripcmd, out_filename, &["--strip-debug"])
}
// Per the manpage, `-x` is the maximum safe strip level for dynamic libraries. (#93988)
(Strip::Symbols, CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro) => {
strip_with_external_utility(sess, stripcmd, out_filename, &["-x"])
}
(
Strip::Symbols,
CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro | CrateType::Sdylib,
) => strip_with_external_utility(sess, stripcmd, out_filename, &["-x"]),
(Strip::Symbols, _) => {
strip_with_external_utility(sess, stripcmd, out_filename, &["--strip-all"])
}
@ -1243,8 +1244,10 @@ fn add_sanitizer_libraries(
// which should be linked to both executables and dynamic libraries.
// Everywhere else the runtimes are currently distributed as static
// libraries which should be linked to executables only.
if matches!(crate_type, CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro)
&& !(sess.target.is_like_darwin || sess.target.is_like_msvc)
if matches!(
crate_type,
CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro | CrateType::Sdylib
) && !(sess.target.is_like_darwin || sess.target.is_like_msvc)
{
return;
}
@ -1938,6 +1941,7 @@ fn add_late_link_args(
codegen_results: &CodegenResults,
) {
let any_dynamic_crate = crate_type == CrateType::Dylib
|| crate_type == CrateType::Sdylib
|| codegen_results.crate_info.dependency_formats.iter().any(|(ty, list)| {
*ty == crate_type && list.iter().any(|&linkage| linkage == Linkage::Dynamic)
});

View file

@ -816,7 +816,9 @@ impl<'a> Linker for GccLinker<'a> {
writeln!(f, "EXPORTS")?;
for symbol in symbols {
debug!(" _{symbol}");
writeln!(f, " {symbol}")?;
// Quote the name in case it's reserved by linker in some way
// (this accounts for names with dots in particular).
writeln!(f, " \"{symbol}\"")?;
}
};
if let Err(error) = res {
@ -1815,7 +1817,7 @@ pub(crate) fn linked_symbols(
crate_type: CrateType,
) -> Vec<(String, SymbolExportKind)> {
match crate_type {
CrateType::Executable | CrateType::Cdylib | CrateType::Dylib => (),
CrateType::Executable | CrateType::Cdylib | CrateType::Dylib | CrateType::Sdylib => (),
CrateType::Staticlib | CrateType::ProcMacro | CrateType::Rlib => {
return Vec::new();
}

View file

@ -270,45 +270,61 @@ pub(super) fn elf_os_abi(sess: &Session) -> u8 {
pub(super) fn elf_e_flags(architecture: Architecture, sess: &Session) -> u32 {
match architecture {
Architecture::Mips => {
let arch = match sess.target.options.cpu.as_ref() {
"mips1" => elf::EF_MIPS_ARCH_1,
"mips2" => elf::EF_MIPS_ARCH_2,
Architecture::Mips | Architecture::Mips64 | Architecture::Mips64_N32 => {
// "N32" indicates an "ILP32" data model on a 64-bit MIPS CPU
// like SPARC's "v8+", x86_64's "x32", or the watchOS "arm64_32".
let is_32bit = architecture == Architecture::Mips;
let mut e_flags = match sess.target.options.cpu.as_ref() {
"mips1" if is_32bit => elf::EF_MIPS_ARCH_1,
"mips2" if is_32bit => elf::EF_MIPS_ARCH_2,
"mips3" => elf::EF_MIPS_ARCH_3,
"mips4" => elf::EF_MIPS_ARCH_4,
"mips5" => elf::EF_MIPS_ARCH_5,
s if s.contains("r6") => elf::EF_MIPS_ARCH_32R6,
_ => elf::EF_MIPS_ARCH_32R2,
"mips32r2" if is_32bit => elf::EF_MIPS_ARCH_32R2,
"mips32r6" if is_32bit => elf::EF_MIPS_ARCH_32R6,
"mips64r2" if !is_32bit => elf::EF_MIPS_ARCH_64R2,
"mips64r6" if !is_32bit => elf::EF_MIPS_ARCH_64R6,
s if s.starts_with("mips32") && !is_32bit => {
sess.dcx().fatal(format!("invalid CPU `{}` for 64-bit MIPS target", s))
}
s if s.starts_with("mips64") && is_32bit => {
sess.dcx().fatal(format!("invalid CPU `{}` for 32-bit MIPS target", s))
}
_ if is_32bit => elf::EF_MIPS_ARCH_32R2,
_ => elf::EF_MIPS_ARCH_64R2,
};
let mut e_flags = elf::EF_MIPS_CPIC | arch;
// If the ABI is explicitly given, use it or default to O32.
match sess.target.options.llvm_abiname.to_lowercase().as_str() {
"n32" => e_flags |= elf::EF_MIPS_ABI2,
"o32" => e_flags |= elf::EF_MIPS_ABI_O32,
_ => e_flags |= elf::EF_MIPS_ABI_O32,
// If the ABI is explicitly given, use it, or default to O32 on 32-bit MIPS,
// which is the only "true" 32-bit option that LLVM supports.
match sess.target.options.llvm_abiname.as_ref() {
"o32" if is_32bit => e_flags |= elf::EF_MIPS_ABI_O32,
"n32" if !is_32bit => e_flags |= elf::EF_MIPS_ABI2,
"n64" if !is_32bit => {}
"" if is_32bit => e_flags |= elf::EF_MIPS_ABI_O32,
"" => sess.dcx().fatal("LLVM ABI must be specifed for 64-bit MIPS targets"),
s if is_32bit => {
sess.dcx().fatal(format!("invalid LLVM ABI `{}` for 32-bit MIPS target", s))
}
s => sess.dcx().fatal(format!("invalid LLVM ABI `{}` for 64-bit MIPS target", s)),
};
if sess.target.options.relocation_model != RelocModel::Static {
e_flags |= elf::EF_MIPS_PIC;
// PIC means position-independent code. CPIC means "calls PIC".
// CPIC was mutually exclusive with PIC according to
// the SVR4 MIPS ABI https://refspecs.linuxfoundation.org/elf/mipsabi.pdf
// and should have only appeared on static objects with dynamically calls.
// At some point someone (GCC?) decided to set CPIC even for PIC.
// Nowadays various things expect both set on the same object file
// and may even error if you mix CPIC and non-CPIC object files,
// despite that being the entire point of the CPIC ABI extension!
// As we are in Rome, we do as the Romans do.
e_flags |= elf::EF_MIPS_PIC | elf::EF_MIPS_CPIC;
}
if sess.target.options.cpu.contains("r6") {
e_flags |= elf::EF_MIPS_NAN2008;
}
e_flags
}
Architecture::Mips64 => {
// copied from `mips64el-linux-gnuabi64-gcc foo.c -c`
let e_flags = elf::EF_MIPS_CPIC
| elf::EF_MIPS_PIC
| if sess.target.options.cpu.contains("r6") {
elf::EF_MIPS_ARCH_64R6 | elf::EF_MIPS_NAN2008
} else {
elf::EF_MIPS_ARCH_64R2
};
e_flags
}
Architecture::Riscv32 | Architecture::Riscv64 => {
// Source: https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/079772828bd10933d34121117a222b4cc0ee2200/riscv-elf.adoc
let mut e_flags: u32 = 0x0;

View file

@ -29,7 +29,7 @@ fn crate_export_threshold(crate_type: CrateType) -> SymbolExportLevel {
CrateType::Executable | CrateType::Staticlib | CrateType::ProcMacro | CrateType::Cdylib => {
SymbolExportLevel::C
}
CrateType::Rlib | CrateType::Dylib => SymbolExportLevel::Rust,
CrateType::Rlib | CrateType::Dylib | CrateType::Sdylib => SymbolExportLevel::Rust,
}
}
@ -45,7 +45,7 @@ pub fn crates_export_threshold(crate_types: &[CrateType]) -> SymbolExportLevel {
}
fn reachable_non_generics_provider(tcx: TyCtxt<'_>, _: LocalCrate) -> DefIdMap<SymbolExportInfo> {
if !tcx.sess.opts.output_types.should_codegen() {
if !tcx.sess.opts.output_types.should_codegen() && !tcx.is_sdylib_interface_build() {
return Default::default();
}
@ -164,11 +164,11 @@ fn is_reachable_non_generic_provider_extern(tcx: TyCtxt<'_>, def_id: DefId) -> b
tcx.reachable_non_generics(def_id.krate).contains_key(&def_id)
}
fn exported_symbols_provider_local(
tcx: TyCtxt<'_>,
fn exported_symbols_provider_local<'tcx>(
tcx: TyCtxt<'tcx>,
_: LocalCrate,
) -> &[(ExportedSymbol<'_>, SymbolExportInfo)] {
if !tcx.sess.opts.output_types.should_codegen() {
) -> &'tcx [(ExportedSymbol<'tcx>, SymbolExportInfo)] {
if !tcx.sess.opts.output_types.should_codegen() && !tcx.is_sdylib_interface_build() {
return &[];
}
@ -321,6 +321,38 @@ fn exported_symbols_provider_local(
let cgus = tcx.collect_and_partition_mono_items(()).codegen_units;
// Do not export symbols that cannot be instantiated by downstream crates.
let reachable_set = tcx.reachable_set(());
let is_local_to_current_crate = |ty: Ty<'_>| {
let no_refs = ty.peel_refs();
let root_def_id = match no_refs.kind() {
ty::Closure(closure, _) => *closure,
ty::FnDef(def_id, _) => *def_id,
ty::Coroutine(def_id, _) => *def_id,
ty::CoroutineClosure(def_id, _) => *def_id,
ty::CoroutineWitness(def_id, _) => *def_id,
_ => return false,
};
let Some(root_def_id) = root_def_id.as_local() else {
return false;
};
let is_local = !reachable_set.contains(&root_def_id);
is_local
};
let is_instantiable_downstream =
|did: Option<DefId>, generic_args: GenericArgsRef<'tcx>| {
generic_args
.types()
.chain(did.into_iter().map(move |did| tcx.type_of(did).skip_binder()))
.all(move |arg| {
arg.walk().all(|ty| {
ty.as_type().map_or(true, |ty| !is_local_to_current_crate(ty))
})
})
};
// The symbols created in this loop are sorted below it
#[allow(rustc::potential_query_instability)]
for (mono_item, data) in cgus.iter().flat_map(|cgu| cgu.items().iter()) {
@ -349,7 +381,12 @@ fn exported_symbols_provider_local(
match *mono_item {
MonoItem::Fn(Instance { def: InstanceKind::Item(def), args }) => {
if args.non_erasable_generics().next().is_some() {
let has_generics = args.non_erasable_generics().next().is_some();
let should_export =
has_generics && is_instantiable_downstream(Some(def), &args);
if should_export {
let symbol = ExportedSymbol::Generic(def, args);
symbols.push((
symbol,
@ -364,14 +401,24 @@ fn exported_symbols_provider_local(
MonoItem::Fn(Instance { def: InstanceKind::DropGlue(_, Some(ty)), args }) => {
// A little sanity-check
assert_eq!(args.non_erasable_generics().next(), Some(GenericArgKind::Type(ty)));
symbols.push((
ExportedSymbol::DropGlue(ty),
SymbolExportInfo {
level: SymbolExportLevel::Rust,
kind: SymbolExportKind::Text,
used: false,
},
));
// Drop glue did is always going to be non-local outside of libcore, thus we don't need to check it's locality (which includes invoking `type_of` query).
let should_export = match ty.kind() {
ty::Adt(_, args) => is_instantiable_downstream(None, args),
ty::Closure(_, args) => is_instantiable_downstream(None, args),
_ => true,
};
if should_export {
symbols.push((
ExportedSymbol::DropGlue(ty),
SymbolExportInfo {
level: SymbolExportLevel::Rust,
kind: SymbolExportKind::Text,
used: false,
},
));
}
}
MonoItem::Fn(Instance {
def: InstanceKind::AsyncDropGlueCtorShim(_, ty),
@ -565,7 +612,7 @@ pub(crate) fn symbol_name_for_instance_in_crate<'tcx>(
ExportedSymbol::Generic(def_id, args) => {
rustc_symbol_mangling::symbol_name_for_instance_in_crate(
tcx,
Instance::new(def_id, args),
Instance::new_raw(def_id, args),
instantiating_crate,
)
}
@ -613,7 +660,7 @@ fn calling_convention_for_symbol<'tcx>(
None
}
ExportedSymbol::NonGeneric(def_id) => Some(Instance::mono(tcx, def_id)),
ExportedSymbol::Generic(def_id, args) => Some(Instance::new(def_id, args)),
ExportedSymbol::Generic(def_id, args) => Some(Instance::new_raw(def_id, args)),
// DropGlue always use the Rust calling convention and thus follow the target's default
// symbol decoration scheme.
ExportedSymbol::DropGlue(..) => None,

View file

@ -457,7 +457,13 @@ where
rustc_hir::InlineAsmOperand::SymFn { expr } => {
let ty = cx.tcx().typeck(item_id.owner_id).expr_ty(expr);
let instance = match ty.kind() {
&ty::FnDef(def_id, args) => Instance::new(def_id, args),
&ty::FnDef(def_id, args) => Instance::expect_resolve(
cx.tcx(),
ty::TypingEnv::fully_monomorphized(),
def_id,
args,
expr.span,
),
_ => span_bug!(*op_sp, "asm sym is not a function"),
};
@ -1092,7 +1098,7 @@ impl CrateInfo {
}
let embed_visualizers = tcx.crate_types().iter().any(|&crate_type| match crate_type {
CrateType::Executable | CrateType::Dylib | CrateType::Cdylib => {
CrateType::Executable | CrateType::Dylib | CrateType::Cdylib | CrateType::Sdylib => {
// These are crate types for which we invoke the linker and can embed
// NatVis visualizers.
true

View file

@ -95,7 +95,9 @@ fn inline_to_global_operand<'a, 'tcx, Cx: LayoutOf<'tcx, LayoutOfResult = TyAndL
);
let instance = match mono_type.kind() {
&ty::FnDef(def_id, args) => Instance::new(def_id, args),
&ty::FnDef(def_id, args) => {
Instance::expect_resolve(cx.tcx(), cx.typing_env(), def_id, args, value.span)
}
_ => bug!("asm sym is not a function"),
};

View file

@ -12,6 +12,27 @@ const_eval_already_reported =
const_eval_assume_false =
`assume` called with `false`
const_eval_bad_pointer_op = {$operation ->
[MemoryAccess] memory access failed
[InboundsPointerArithmetic] in-bounds pointer arithmetic failed
*[Dereferenceable] pointer not dereferenceable
}
const_eval_bad_pointer_op_attempting = {const_eval_bad_pointer_op}: {$operation ->
[MemoryAccess] attempting to access {$inbounds_size ->
[1] 1 byte
*[x] {$inbounds_size} bytes
}
[InboundsPointerArithmetic] attempting to offset pointer by {$inbounds_size ->
[1] 1 byte
*[x] {$inbounds_size} bytes
}
*[Dereferenceable] pointer must {$inbounds_size ->
[0] point to some allocation
[1] be dereferenceable for 1 byte
*[x] be dereferenceable for {$inbounds_size} bytes
}
}
const_eval_bounds_check_failed =
indexing out of bounds: the len is {$len} but the index is {$index}
const_eval_call_nonzero_intrinsic =
@ -39,9 +60,9 @@ const_eval_copy_nonoverlapping_overlapping =
`copy_nonoverlapping` called on overlapping ranges
const_eval_dangling_int_pointer =
{$bad_pointer_message}: {const_eval_expected_inbounds_pointer}, but got {$pointer} which is a dangling pointer (it has no provenance)
{const_eval_bad_pointer_op_attempting}, but got {$pointer} which is a dangling pointer (it has no provenance)
const_eval_dangling_null_pointer =
{$bad_pointer_message}: {const_eval_expected_inbounds_pointer}, but got a null pointer
{const_eval_bad_pointer_op_attempting}, but got null pointer
const_eval_dangling_ptr_in_final = encountered dangling pointer in final value of {const_eval_intern_kind}
const_eval_dead_local =
@ -77,21 +98,6 @@ const_eval_error = {$error_kind ->
const_eval_exact_div_has_remainder =
exact_div: {$a} cannot be divided by {$b} without remainder
const_eval_expected_inbounds_pointer =
expected a pointer to {$inbounds_size_abs ->
[0] some allocation
*[x] {$inbounds_size_is_neg ->
[false] {$inbounds_size_abs ->
[1] 1 byte of memory
*[x] {$inbounds_size_abs} bytes of memory
}
*[true] the end of {$inbounds_size_abs ->
[1] 1 byte of memory
*[x] {$inbounds_size_abs} bytes of memory
}
}
}
const_eval_extern_static =
cannot access extern static `{$did}`
const_eval_extern_type_field = `extern type` field does not have a known offset
@ -111,7 +117,6 @@ const_eval_frame_note_inner = inside {$where_ ->
const_eval_frame_note_last = the failure occurred here
const_eval_in_bounds_test = out-of-bounds pointer use
const_eval_incompatible_calling_conventions =
calling a function with calling convention {$callee_conv} using calling convention {$caller_conv}
@ -206,7 +211,6 @@ const_eval_long_running =
const_eval_max_num_nodes_in_const = maximum number of nodes exceeded in constant {$global_const_id}
const_eval_memory_access_test = memory access failed
const_eval_memory_exhausted =
tried to allocate more memory than available to compiler
@ -287,8 +291,6 @@ const_eval_offset_from_out_of_bounds =
`{$name}` called on two different pointers where the memory range between them is not in-bounds of an allocation
const_eval_offset_from_overflow =
`{$name}` called when first pointer is too far ahead of second
const_eval_offset_from_test =
out-of-bounds `offset_from` origin
const_eval_offset_from_underflow =
`{$name}` called when first pointer is too far before second
const_eval_offset_from_unsigned_overflow =
@ -312,27 +314,25 @@ const_eval_partial_pointer_overwrite =
unable to overwrite parts of a pointer in memory at {$ptr}
const_eval_pointer_arithmetic_overflow =
overflowing pointer arithmetic: the total offset in bytes does not fit in an `isize`
const_eval_pointer_arithmetic_test = out-of-bounds pointer arithmetic
const_eval_pointer_out_of_bounds =
{$bad_pointer_message}: {const_eval_expected_inbounds_pointer}, but got {$pointer} {$ptr_offset_is_neg ->
[true] which points to before the beginning of the allocation
*[false] {$inbounds_size_is_neg ->
[true] {$ptr_offset_abs ->
[0] which is at the beginning of the allocation
*[other] which does not have enough space to the beginning of the allocation
}
*[false] {$alloc_size_minus_ptr_offset ->
[0] which is at or beyond the end of the allocation of size {$alloc_size ->
{const_eval_bad_pointer_op_attempting}, but got {$pointer} which {$inbounds_size_is_neg ->
[false] {$alloc_size_minus_ptr_offset ->
[0] is at or beyond the end of the allocation of size {$alloc_size ->
[1] 1 byte
*[x] {$alloc_size} bytes
}
[1] which is only 1 byte from the end of the allocation
*[x] which is only {$alloc_size_minus_ptr_offset} bytes from the end of the allocation
[1] is only 1 byte from the end of the allocation
*[x] is only {$alloc_size_minus_ptr_offset} bytes from the end of the allocation
}
*[true] {$ptr_offset_abs ->
[0] is at the beginning of the allocation
*[other] is only {$ptr_offset_abs} bytes from the beginning of the allocation
}
}
}
const_eval_pointer_use_after_free =
{$bad_pointer_message}: {$alloc_id} has been freed, so this pointer is dangling
{const_eval_bad_pointer_op}: {$alloc_id} has been freed, so this pointer is dangling
const_eval_ptr_as_bytes_1 =
this code performed an operation that depends on the underlying bytes representing a pointer
const_eval_ptr_as_bytes_2 =

View file

@ -352,7 +352,7 @@ fn build_error_for_const_call<'tcx>(
);
err
}
_ if tcx.opt_parent(callee) == tcx.get_diagnostic_item(sym::ArgumentMethods) => {
_ if tcx.opt_parent(callee) == tcx.get_diagnostic_item(sym::FmtArgumentsNew) => {
ccx.dcx().create_err(errors::NonConstFmtMacroCall {
span,
kind: ccx.const_kind(),

View file

@ -5,15 +5,14 @@ use either::Either;
use rustc_abi::WrappingRange;
use rustc_errors::codes::*;
use rustc_errors::{
Diag, DiagArgValue, DiagCtxtHandle, DiagMessage, Diagnostic, EmissionGuarantee, Level,
MultiSpan, Subdiagnostic,
Diag, DiagArgValue, DiagMessage, Diagnostic, EmissionGuarantee, Level, MultiSpan, Subdiagnostic,
};
use rustc_hir::ConstContext;
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
use rustc_middle::mir::interpret::{
CheckInAllocMsg, CtfeProvenance, ExpectedKind, InterpErrorKind, InvalidMetaKind,
InvalidProgramInfo, Misalignment, Pointer, PointerKind, ResourceExhaustionInfo,
UndefinedBehaviorInfo, UnsupportedOpInfo, ValidationErrorInfo,
CtfeProvenance, ExpectedKind, InterpErrorKind, InvalidMetaKind, InvalidProgramInfo,
Misalignment, Pointer, PointerKind, ResourceExhaustionInfo, UndefinedBehaviorInfo,
UnsupportedOpInfo, ValidationErrorInfo,
};
use rustc_middle::ty::{self, Mutability, Ty};
use rustc_span::{Span, Symbol};
@ -498,19 +497,6 @@ pub trait ReportErrorExt {
}
}
fn bad_pointer_message(msg: CheckInAllocMsg, dcx: DiagCtxtHandle<'_>) -> String {
use crate::fluent_generated::*;
let msg = match msg {
CheckInAllocMsg::MemoryAccessTest => const_eval_memory_access_test,
CheckInAllocMsg::PointerArithmeticTest => const_eval_pointer_arithmetic_test,
CheckInAllocMsg::OffsetFromTest => const_eval_offset_from_test,
CheckInAllocMsg::InboundsTest => const_eval_in_bounds_test,
};
dcx.eagerly_translate_to_string(msg, [].into_iter())
}
impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
fn diagnostic_message(&self) -> DiagMessage {
use UndefinedBehaviorInfo::*;
@ -564,7 +550,6 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
fn add_args<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
use UndefinedBehaviorInfo::*;
let dcx = diag.dcx;
match self {
Ub(_) => {}
Custom(custom) => {
@ -612,12 +597,10 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
diag.arg("vtable_dyn_type", vtable_dyn_type.to_string());
}
PointerUseAfterFree(alloc_id, msg) => {
diag.arg("alloc_id", alloc_id)
.arg("bad_pointer_message", bad_pointer_message(msg, dcx));
diag.arg("alloc_id", alloc_id).arg("operation", format!("{:?}", msg));
}
PointerOutOfBounds { alloc_id, alloc_size, ptr_offset, inbounds_size, msg } => {
diag.arg("alloc_size", alloc_size.bytes());
diag.arg("bad_pointer_message", bad_pointer_message(msg, dcx));
diag.arg("pointer", {
let mut out = format!("{:?}", alloc_id);
if ptr_offset > 0 {
@ -627,14 +610,17 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
}
out
});
diag.arg("inbounds_size", inbounds_size);
diag.arg("inbounds_size_is_neg", inbounds_size < 0);
diag.arg("inbounds_size_abs", inbounds_size.unsigned_abs());
diag.arg("ptr_offset", ptr_offset);
diag.arg("ptr_offset_is_neg", ptr_offset < 0);
diag.arg("ptr_offset_abs", ptr_offset.unsigned_abs());
diag.arg(
"alloc_size_minus_ptr_offset",
alloc_size.bytes().saturating_sub(ptr_offset as u64),
);
diag.arg("operation", format!("{:?}", msg));
}
DanglingIntPointer { addr, inbounds_size, msg } => {
if addr != 0 {
@ -644,9 +630,10 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
);
}
diag.arg("inbounds_size", inbounds_size);
diag.arg("inbounds_size_is_neg", inbounds_size < 0);
diag.arg("inbounds_size_abs", inbounds_size.unsigned_abs());
diag.arg("bad_pointer_message", bad_pointer_message(msg, dcx));
diag.arg("operation", format!("{:?}", msg));
}
AlignmentCheckFailed(Misalignment { required, has }, msg) => {
diag.arg("required", required.bytes());

View file

@ -17,13 +17,13 @@ use hir::def::DefKind;
use rustc_ast::Mutability;
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
use rustc_hir as hir;
use rustc_hir::definitions::{DefPathData, DisambiguatorState};
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
use rustc_middle::mir::interpret::{ConstAllocation, CtfeProvenance, InterpResult};
use rustc_middle::query::TyCtxtAt;
use rustc_middle::span_bug;
use rustc_middle::ty::layout::TyAndLayout;
use rustc_span::def_id::LocalDefId;
use rustc_span::sym;
use tracing::{instrument, trace};
use super::{
@ -66,6 +66,7 @@ fn intern_shallow<'tcx, T, M: CompileTimeMachine<'tcx, T>>(
ecx: &mut InterpCx<'tcx, M>,
alloc_id: AllocId,
mutability: Mutability,
disambiguator: Option<&mut DisambiguatorState>,
) -> Result<impl Iterator<Item = CtfeProvenance> + 'tcx, ()> {
trace!("intern_shallow {:?}", alloc_id);
// remove allocation
@ -88,7 +89,13 @@ fn intern_shallow<'tcx, T, M: CompileTimeMachine<'tcx, T>>(
// link the alloc id to the actual allocation
let alloc = ecx.tcx.mk_const_alloc(alloc);
if let Some(static_id) = ecx.machine.static_def_id() {
intern_as_new_static(ecx.tcx, static_id, alloc_id, alloc);
intern_as_new_static(
ecx.tcx,
static_id,
alloc_id,
alloc,
disambiguator.expect("disambiguator needed"),
);
} else {
ecx.tcx.set_alloc_id_memory(alloc_id, alloc);
}
@ -102,11 +109,18 @@ fn intern_as_new_static<'tcx>(
static_id: LocalDefId,
alloc_id: AllocId,
alloc: ConstAllocation<'tcx>,
disambiguator: &mut DisambiguatorState,
) {
// `intern_const_alloc_recursive` is called once per static and it contains the `DisambiguatorState`.
// The `<static_id>::{{nested}}` path is thus unique to `intern_const_alloc_recursive` and the
// `DisambiguatorState` ensures the generated path is unique for this call as we generate
// `<static_id>::{{nested#n}}` where `n` is the `n`th `intern_as_new_static` call.
let feed = tcx.create_def(
static_id,
Some(sym::nested),
None,
DefKind::Static { safety: hir::Safety::Safe, mutability: alloc.0.mutability, nested: true },
Some(DefPathData::NestedStatic),
disambiguator,
);
tcx.set_nested_alloc_id_static(alloc_id, feed.def_id());
@ -154,6 +168,8 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx, const_eval
intern_kind: InternKind,
ret: &MPlaceTy<'tcx>,
) -> Result<(), InternResult> {
let mut disambiguator = DisambiguatorState::new();
// We are interning recursively, and for mutability we are distinguishing the "root" allocation
// that we are starting in, and all other allocations that we are encountering recursively.
let (base_mutability, inner_mutability, is_static) = match intern_kind {
@ -197,7 +213,9 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx, const_eval
alloc.1.mutability = base_mutability;
alloc.1.provenance().ptrs().iter().map(|&(_, prov)| prov).collect()
} else {
intern_shallow(ecx, base_alloc_id, base_mutability).unwrap().collect()
intern_shallow(ecx, base_alloc_id, base_mutability, Some(&mut disambiguator))
.unwrap()
.collect()
};
// We need to distinguish "has just been interned" from "was already in `tcx`",
// so we track this in a separate set.
@ -291,7 +309,7 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx, const_eval
// okay with losing some potential for immutability here. This can anyway only affect
// `static mut`.
just_interned.insert(alloc_id);
match intern_shallow(ecx, alloc_id, inner_mutability) {
match intern_shallow(ecx, alloc_id, inner_mutability, Some(&mut disambiguator)) {
Ok(nested) => todo.extend(nested),
Err(()) => {
ecx.tcx.dcx().delayed_bug("found dangling pointer during const interning");
@ -313,8 +331,9 @@ pub fn intern_const_alloc_for_constprop<'tcx, T, M: CompileTimeMachine<'tcx, T>>
return interp_ok(());
}
// Move allocation to `tcx`.
if let Some(_) =
(intern_shallow(ecx, alloc_id, Mutability::Not).map_err(|()| err_ub!(DeadLocal))?).next()
if let Some(_) = intern_shallow(ecx, alloc_id, Mutability::Not, None)
.map_err(|()| err_ub!(DeadLocal))?
.next()
{
// We are not doing recursive interning, so we don't currently support provenance.
// (If this assertion ever triggers, we should just implement a
@ -340,7 +359,7 @@ impl<'tcx> InterpCx<'tcx, DummyMachine> {
let dest = self.allocate(layout, MemoryKind::Stack)?;
f(self, &dest.clone().into())?;
let alloc_id = dest.ptr().provenance.unwrap().alloc_id(); // this was just allocated, it must have provenance
for prov in intern_shallow(self, alloc_id, Mutability::Not).unwrap() {
for prov in intern_shallow(self, alloc_id, Mutability::Not, None).unwrap() {
// We are not doing recursive interning, so we don't currently support provenance.
// (If this assertion ever triggers, we should just implement a
// proper recursive interning loop -- or just call `intern_const_alloc_recursive`.

View file

@ -348,7 +348,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
// Check that the memory between them is dereferenceable at all, starting from the
// origin pointer: `dist` is `a - b`, so it is based on `b`.
self.check_ptr_access_signed(b, dist, CheckInAllocMsg::OffsetFromTest)
self.check_ptr_access_signed(b, dist, CheckInAllocMsg::Dereferenceable)
.map_err_kind(|_| {
// This could mean they point to different allocations, or they point to the same allocation
// but not the entire range between the pointers is in-bounds.
@ -372,7 +372,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
self.check_ptr_access_signed(
a,
dist.checked_neg().unwrap(), // i64::MIN is impossible as no allocation can be that large
CheckInAllocMsg::OffsetFromTest,
CheckInAllocMsg::Dereferenceable,
)
.map_err_kind(|_| {
// Make the error more specific.
@ -651,7 +651,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
offset_bytes: i64,
) -> InterpResult<'tcx, Pointer<Option<M::Provenance>>> {
// The offset must be in bounds starting from `ptr`.
self.check_ptr_access_signed(ptr, offset_bytes, CheckInAllocMsg::PointerArithmeticTest)?;
self.check_ptr_access_signed(
ptr,
offset_bytes,
CheckInAllocMsg::InboundsPointerArithmetic,
)?;
// This also implies that there is no overflow, so we are done.
interp_ok(ptr.wrapping_signed_offset(offset_bytes, self))
}

View file

@ -351,7 +351,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
kind = "static_mem"
)
}
None => err_ub!(PointerUseAfterFree(alloc_id, CheckInAllocMsg::MemoryAccessTest)),
None => err_ub!(PointerUseAfterFree(alloc_id, CheckInAllocMsg::MemoryAccess)),
})
.into();
};
@ -414,10 +414,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
self,
ptr,
size,
CheckInAllocMsg::MemoryAccessTest,
CheckInAllocMsg::MemoryAccess,
|this, alloc_id, offset, prov| {
let (size, align) = this
.get_live_alloc_size_and_align(alloc_id, CheckInAllocMsg::MemoryAccessTest)?;
let (size, align) =
this.get_live_alloc_size_and_align(alloc_id, CheckInAllocMsg::MemoryAccess)?;
interp_ok((size, align, (alloc_id, offset, prov)))
},
)
@ -613,7 +613,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
}
Some(GlobalAlloc::Function { .. }) => throw_ub!(DerefFunctionPointer(id)),
Some(GlobalAlloc::VTable(..)) => throw_ub!(DerefVTablePointer(id)),
None => throw_ub!(PointerUseAfterFree(id, CheckInAllocMsg::MemoryAccessTest)),
None => throw_ub!(PointerUseAfterFree(id, CheckInAllocMsg::MemoryAccess)),
Some(GlobalAlloc::Static(def_id)) => {
assert!(self.tcx.is_static(def_id));
// Thread-local statics do not have a constant address. They *must* be accessed via
@ -707,7 +707,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
self,
ptr,
size_i64,
CheckInAllocMsg::MemoryAccessTest,
CheckInAllocMsg::MemoryAccess,
|this, alloc_id, offset, prov| {
let alloc = this.get_alloc_raw(alloc_id)?;
interp_ok((alloc.size(), alloc.align, (alloc_id, offset, prov, alloc)))
@ -809,7 +809,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
self,
ptr,
size_i64,
CheckInAllocMsg::MemoryAccessTest,
CheckInAllocMsg::MemoryAccess,
|this, alloc_id, offset, prov| {
let (alloc, machine) = this.get_alloc_raw_mut(alloc_id)?;
interp_ok((alloc.size(), alloc.align, (alloc_id, offset, prov, alloc, machine)))
@ -1615,7 +1615,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
err_ub!(DanglingIntPointer {
addr: offset,
inbounds_size: size,
msg: CheckInAllocMsg::InboundsTest
msg: CheckInAllocMsg::Dereferenceable
})
})
.into()

View file

@ -510,7 +510,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
self.ecx.check_ptr_access(
place.ptr(),
size,
CheckInAllocMsg::InboundsTest, // will anyway be replaced by validity message
CheckInAllocMsg::Dereferenceable, // will anyway be replaced by validity message
),
self.path,
Ub(DanglingIntPointer { addr: 0, .. }) => NullPtr { ptr_kind },

View file

@ -1,4 +1,4 @@
//! A graph module for use in dataflow, region resolution, and elsewhere.
//! See [`LinkedGraph`].
//!
//! # Interface details
//!
@ -28,7 +28,23 @@ use tracing::debug;
#[cfg(test)]
mod tests;
pub struct Graph<N, E> {
/// A concrete graph implementation that supports:
/// - Nodes and/or edges labelled with custom data types (`N` and `E` respectively).
/// - Incremental addition of new nodes/edges (but not removal).
/// - Flat storage of node/edge data in a pair of vectors.
/// - Iteration over any node's out-edges or in-edges, via linked lists
/// threaded through the node/edge data.
///
/// # Caution
/// This is an older graph implementation that is still used by some pieces
/// of diagnostic/debugging code. New code that needs a graph data structure
/// should consider using `VecGraph` instead, or implementing its own
/// special-purpose graph with the specific features needed.
///
/// This graph implementation predates the later [graph traits](crate::graph),
/// and does not implement those traits, so it has its own implementations of a
/// few basic graph algorithms.
pub struct LinkedGraph<N, E> {
nodes: Vec<Node<N>>,
edges: Vec<Edge<E>>,
}
@ -71,13 +87,13 @@ impl NodeIndex {
}
}
impl<N: Debug, E: Debug> Graph<N, E> {
pub fn new() -> Graph<N, E> {
Graph { nodes: Vec::new(), edges: Vec::new() }
impl<N: Debug, E: Debug> LinkedGraph<N, E> {
pub fn new() -> Self {
Self { nodes: Vec::new(), edges: Vec::new() }
}
pub fn with_capacity(nodes: usize, edges: usize) -> Graph<N, E> {
Graph { nodes: Vec::with_capacity(nodes), edges: Vec::with_capacity(edges) }
pub fn with_capacity(nodes: usize, edges: usize) -> Self {
Self { nodes: Vec::with_capacity(nodes), edges: Vec::with_capacity(edges) }
}
// # Simple accessors
@ -249,7 +265,7 @@ impl<N: Debug, E: Debug> Graph<N, E> {
// # Iterators
pub struct AdjacentEdges<'g, N, E> {
graph: &'g Graph<N, E>,
graph: &'g LinkedGraph<N, E>,
direction: Direction,
next: EdgeIndex,
}
@ -285,7 +301,7 @@ impl<'g, N: Debug, E: Debug> Iterator for AdjacentEdges<'g, N, E> {
}
pub struct DepthFirstTraversal<'g, N, E> {
graph: &'g Graph<N, E>,
graph: &'g LinkedGraph<N, E>,
stack: Vec<NodeIndex>,
visited: DenseBitSet<usize>,
direction: Direction,
@ -293,7 +309,7 @@ pub struct DepthFirstTraversal<'g, N, E> {
impl<'g, N: Debug, E: Debug> DepthFirstTraversal<'g, N, E> {
pub fn with_start_node(
graph: &'g Graph<N, E>,
graph: &'g LinkedGraph<N, E>,
start_node: NodeIndex,
direction: Direction,
) -> Self {

View file

@ -1,11 +1,11 @@
use tracing::debug;
use crate::graph::implementation::*;
use super::{Debug, LinkedGraph, NodeIndex};
type TestGraph = Graph<&'static str, &'static str>;
type TestGraph = LinkedGraph<&'static str, &'static str>;
fn create_graph() -> TestGraph {
let mut graph = Graph::new();
let mut graph = LinkedGraph::new();
// Create a simple graph
//
@ -56,7 +56,7 @@ fn each_edge() {
}
fn test_adjacent_edges<N: PartialEq + Debug, E: PartialEq + Debug>(
graph: &Graph<N, E>,
graph: &LinkedGraph<N, E>,
start_index: NodeIndex,
start_data: N,
expected_incoming: &[(E, N)],

View file

@ -1,8 +1,8 @@
use rustc_index::Idx;
pub mod dominators;
pub mod implementation;
pub mod iterate;
pub mod linked_graph;
mod reference;
pub mod reversed;
pub mod scc;

View file

@ -10,10 +10,11 @@
use std::assert_matches::debug_assert_matches;
use std::fmt::Debug;
use std::marker::PhantomData;
use std::ops::Range;
use rustc_index::{Idx, IndexSlice, IndexVec};
use tracing::{debug, instrument};
use tracing::{debug, instrument, trace};
use crate::fx::FxHashSet;
use crate::graph::vec_graph::VecGraph;
@ -48,6 +49,25 @@ pub trait Annotation: Debug + Copy {
}
}
/// An accumulator for annotations.
pub trait Annotations<N: Idx> {
type Ann: Annotation;
type SccIdx: Idx + Ord;
fn new(&self, element: N) -> Self::Ann;
fn annotate_scc(&mut self, scc: Self::SccIdx, annotation: Self::Ann);
}
/// The nil annotation accumulator, which does nothing.
struct NoAnnotations<S: Idx + Ord>(PhantomData<S>);
impl<N: Idx, S: Idx + Ord> Annotations<N> for NoAnnotations<S> {
type SccIdx = S;
type Ann = ();
fn new(&self, _element: N) {}
fn annotate_scc(&mut self, _scc: S, _annotation: ()) {}
}
/// The empty annotation, which does nothing.
impl Annotation for () {
fn merge_reached(self, _other: Self) -> Self {
@ -62,23 +82,20 @@ impl Annotation for () {
/// the index type for the graph nodes and `S` is the index type for
/// the SCCs. We can map from each node to the SCC that it
/// participates in, and we also have the successors of each SCC.
pub struct Sccs<N: Idx, S: Idx, A: Annotation = ()> {
pub struct Sccs<N: Idx, S: Idx> {
/// For each node, what is the SCC index of the SCC to which it
/// belongs.
scc_indices: IndexVec<N, S>,
/// Data about all the SCCs.
scc_data: SccData<S, A>,
scc_data: SccData<S>,
}
/// Information about an invidividual SCC node.
struct SccDetails<A: Annotation> {
struct SccDetails {
/// For this SCC, the range of `all_successors` where its
/// successors can be found.
range: Range<usize>,
/// User-specified metadata about the SCC.
annotation: A,
}
// The name of this struct should discourage you from making it public and leaking
@ -87,10 +104,10 @@ struct SccDetails<A: Annotation> {
// is difficult when it's publicly inspectable.
//
// Obey the law of Demeter!
struct SccData<S: Idx, A: Annotation> {
struct SccData<S: Idx> {
/// Maps SCC indices to their metadata, including
/// offsets into `all_successors`.
scc_details: IndexVec<S, SccDetails<A>>,
scc_details: IndexVec<S, SccDetails>,
/// Contains the successors for all the Sccs, concatenated. The
/// range of indices corresponding to a given SCC is found in its
@ -98,24 +115,18 @@ struct SccData<S: Idx, A: Annotation> {
all_successors: Vec<S>,
}
impl<N: Idx, S: Idx + Ord> Sccs<N, S, ()> {
impl<N: Idx, S: Idx + Ord> Sccs<N, S> {
/// Compute SCCs without annotations.
pub fn new(graph: &impl Successors<Node = N>) -> Self {
Self::new_with_annotation(graph, |_| ())
Self::new_with_annotation(graph, &mut NoAnnotations(PhantomData::<S>))
}
}
impl<N: Idx, S: Idx + Ord, A: Annotation> Sccs<N, S, A> {
/// Compute SCCs and annotate them with a user-supplied annotation
pub fn new_with_annotation<F: Fn(N) -> A>(
pub fn new_with_annotation<A: Annotations<N, SccIdx = S>>(
graph: &impl Successors<Node = N>,
to_annotation: F,
annotations: &mut A,
) -> Self {
SccsConstruction::construct(graph, to_annotation)
}
pub fn annotation(&self, scc: S) -> A {
self.scc_data.annotation(scc)
SccsConstruction::construct(graph, annotations)
}
pub fn scc_indices(&self) -> &IndexSlice<N, S> {
@ -160,7 +171,7 @@ impl<N: Idx, S: Idx + Ord, A: Annotation> Sccs<N, S, A> {
}
}
impl<N: Idx, S: Idx + Ord, A: Annotation> DirectedGraph for Sccs<N, S, A> {
impl<N: Idx, S: Idx + Ord> DirectedGraph for Sccs<N, S> {
type Node = S;
fn num_nodes(&self) -> usize {
@ -168,19 +179,19 @@ impl<N: Idx, S: Idx + Ord, A: Annotation> DirectedGraph for Sccs<N, S, A> {
}
}
impl<N: Idx, S: Idx + Ord, A: Annotation> NumEdges for Sccs<N, S, A> {
impl<N: Idx, S: Idx + Ord> NumEdges for Sccs<N, S> {
fn num_edges(&self) -> usize {
self.scc_data.all_successors.len()
}
}
impl<N: Idx, S: Idx + Ord, A: Annotation> Successors for Sccs<N, S, A> {
impl<N: Idx, S: Idx + Ord> Successors for Sccs<N, S> {
fn successors(&self, node: S) -> impl Iterator<Item = Self::Node> {
self.successors(node).iter().cloned()
}
}
impl<S: Idx, A: Annotation> SccData<S, A> {
impl<S: Idx> SccData<S> {
/// Number of SCCs,
fn len(&self) -> usize {
self.scc_details.len()
@ -192,9 +203,8 @@ impl<S: Idx, A: Annotation> SccData<S, A> {
}
/// Creates a new SCC with `successors` as its successors and
/// the maximum weight of its internal nodes `scc_max_weight` and
/// returns the resulting index.
fn create_scc(&mut self, successors: impl IntoIterator<Item = S>, annotation: A) -> S {
fn create_scc(&mut self, successors: impl IntoIterator<Item = S>) -> S {
// Store the successors on `scc_successors_vec`, remembering
// the range of indices.
let all_successors_start = self.all_successors.len();
@ -202,35 +212,28 @@ impl<S: Idx, A: Annotation> SccData<S, A> {
let all_successors_end = self.all_successors.len();
debug!(
"create_scc({:?}) successors={:?}, annotation={:?}",
"create_scc({:?}) successors={:?}",
self.len(),
&self.all_successors[all_successors_start..all_successors_end],
annotation
);
let range = all_successors_start..all_successors_end;
let metadata = SccDetails { range, annotation };
let metadata = SccDetails { range };
self.scc_details.push(metadata)
}
fn annotation(&self, scc: S) -> A {
self.scc_details[scc].annotation
}
}
struct SccsConstruction<'c, G, S, A, F>
struct SccsConstruction<'c, 'a, G, A>
where
G: DirectedGraph + Successors,
S: Idx,
A: Annotation,
F: Fn(G::Node) -> A,
A: Annotations<G::Node>,
{
graph: &'c G,
/// The state of each node; used during walk to record the stack
/// and after walk to record what cycle each node ended up being
/// in.
node_states: IndexVec<G::Node, NodeState<G::Node, S, A>>,
node_states: IndexVec<G::Node, NodeState<G::Node, A::SccIdx, A::Ann>>,
/// The stack of nodes that we are visiting as part of the DFS.
node_stack: Vec<G::Node>,
@ -239,23 +242,21 @@ where
/// position in this stack, and when we encounter a successor SCC,
/// we push it on the stack. When we complete an SCC, we can pop
/// everything off the stack that was found along the way.
successors_stack: Vec<S>,
successors_stack: Vec<A::SccIdx>,
/// A set used to strip duplicates. As we accumulate successors
/// into the successors_stack, we sometimes get duplicate entries.
/// We use this set to remove those -- we also keep its storage
/// around between successors to amortize memory allocation costs.
duplicate_set: FxHashSet<S>,
duplicate_set: FxHashSet<A::SccIdx>,
scc_data: SccData<S, A>,
scc_data: SccData<A::SccIdx>,
/// A function that constructs an initial SCC annotation
/// out of a single node.
to_annotation: F,
annotations: &'a mut A,
}
#[derive(Copy, Clone, Debug)]
enum NodeState<N, S, A> {
enum NodeState<N, S, A: Annotation> {
/// This node has not yet been visited as part of the DFS.
///
/// After SCC construction is complete, this state ought to be
@ -286,7 +287,7 @@ enum NodeState<N, S, A> {
/// The state of walking a given node.
#[derive(Copy, Clone, Debug)]
enum WalkReturn<S, A> {
enum WalkReturn<S, A: Annotation> {
/// The walk found a cycle, but the entire component is not known to have
/// been fully walked yet. We only know the minimum depth of this
/// component in a minimum spanning tree of the graph. This component
@ -299,12 +300,10 @@ enum WalkReturn<S, A> {
Complete { scc_index: S, annotation: A },
}
impl<'c, G, S, A, F> SccsConstruction<'c, G, S, A, F>
impl<'c, 'a, G, A> SccsConstruction<'c, 'a, G, A>
where
G: DirectedGraph + Successors,
S: Idx,
F: Fn(G::Node) -> A,
A: Annotation,
A: Annotations<G::Node>,
{
/// Identifies SCCs in the graph `G` and computes the resulting
/// DAG. This uses a variant of [Tarjan's
@ -320,7 +319,7 @@ where
/// Additionally, we keep track of a current annotation of the SCC.
///
/// [wikipedia]: https://bit.ly/2EZIx84
fn construct(graph: &'c G, to_annotation: F) -> Sccs<G::Node, S, A> {
fn construct(graph: &'c G, annotations: &'a mut A) -> Sccs<G::Node, A::SccIdx> {
let num_nodes = graph.num_nodes();
let mut this = Self {
@ -330,7 +329,7 @@ where
successors_stack: Vec::new(),
scc_data: SccData { scc_details: IndexVec::new(), all_successors: Vec::new() },
duplicate_set: FxHashSet::default(),
to_annotation,
annotations,
};
let scc_indices = graph
@ -346,7 +345,7 @@ where
Sccs { scc_indices, scc_data: this.scc_data }
}
fn start_walk_from(&mut self, node: G::Node) -> WalkReturn<S, A> {
fn start_walk_from(&mut self, node: G::Node) -> WalkReturn<A::SccIdx, A::Ann> {
self.inspect_node(node).unwrap_or_else(|| self.walk_unvisited_node(node))
}
@ -362,7 +361,7 @@ where
/// Otherwise, we are looking at a node that has already been
/// completely visited. We therefore return `WalkReturn::Complete`
/// with its associated SCC index.
fn inspect_node(&mut self, node: G::Node) -> Option<WalkReturn<S, A>> {
fn inspect_node(&mut self, node: G::Node) -> Option<WalkReturn<A::SccIdx, A::Ann>> {
Some(match self.find_state(node) {
NodeState::InCycle { scc_index, annotation } => {
WalkReturn::Complete { scc_index, annotation }
@ -385,7 +384,7 @@ where
/// of `r2` (and updates `r` to reflect current result). This is
/// basically the "find" part of a standard union-find algorithm
/// (with path compression).
fn find_state(&mut self, mut node: G::Node) -> NodeState<G::Node, S, A> {
fn find_state(&mut self, mut node: G::Node) -> NodeState<G::Node, A::SccIdx, A::Ann> {
// To avoid recursion we temporarily reuse the `parent` of each
// InCycleWith link to encode a downwards link while compressing
// the path. After we have found the root or deepest node being
@ -408,7 +407,7 @@ where
// a potentially derived version of the root state for non-root nodes in the chain.
let (root_state, assigned_state) = {
loop {
debug!("find_state(r = {node:?} in state {:?})", self.node_states[node]);
trace!("find_state(r = {node:?} in state {:?})", self.node_states[node]);
match self.node_states[node] {
// This must have been the first and only state since it is unexplored*;
// no update needed! * Unless there is a bug :')
@ -482,7 +481,7 @@ where
if previous_node == node {
return root_state;
}
debug!("Compressing {node:?} down to {previous_node:?} with state {assigned_state:?}");
trace!("Compressing {node:?} down to {previous_node:?} with state {assigned_state:?}");
// Update to previous node in the link.
match self.node_states[previous_node] {
@ -507,9 +506,9 @@ where
/// Call this method when `inspect_node` has returned `None`. Having the
/// caller decide avoids mutual recursion between the two methods and allows
/// us to maintain an allocated stack for nodes on the path between calls.
#[instrument(skip(self, initial), level = "debug")]
fn walk_unvisited_node(&mut self, initial: G::Node) -> WalkReturn<S, A> {
debug!("Walk unvisited node: {initial:?}");
#[instrument(skip(self, initial), level = "trace")]
fn walk_unvisited_node(&mut self, initial: G::Node) -> WalkReturn<A::SccIdx, A::Ann> {
trace!("Walk unvisited node: {initial:?}");
struct VisitingNodeFrame<G: DirectedGraph, Successors, A> {
node: G::Node,
successors: Option<Successors>,
@ -537,7 +536,7 @@ where
successors_len: 0,
min_cycle_root: initial,
successor_node: initial,
current_component_annotation: (self.to_annotation)(initial),
current_component_annotation: self.annotations.new(initial),
}];
let mut return_value = None;
@ -556,11 +555,7 @@ where
let node = *node;
let depth = *depth;
// node is definitely in the current component, add it to the annotation.
if node != initial {
current_component_annotation.update_scc((self.to_annotation)(node));
}
debug!(
trace!(
"Visiting {node:?} at depth {depth:?}, annotation: {current_component_annotation:?}"
);
@ -568,7 +563,7 @@ where
Some(successors) => successors,
None => {
// This None marks that we still have the initialize this node's frame.
debug!(?depth, ?node);
trace!(?depth, ?node);
debug_assert_matches!(self.node_states[node], NodeState::NotVisited);
@ -598,7 +593,7 @@ where
return_value.take().into_iter().map(|walk| (*successor_node, Some(walk)));
let successor_walk = successors.map(|successor_node| {
debug!(?node, ?successor_node);
trace!(?node, ?successor_node);
(successor_node, self.inspect_node(successor_node))
});
for (successor_node, walk) in returned_walk.chain(successor_walk) {
@ -609,13 +604,13 @@ where
min_depth: successor_min_depth,
annotation: successor_annotation,
}) => {
debug!(
trace!(
"Cycle found from {node:?}, minimum depth: {successor_min_depth:?}, annotation: {successor_annotation:?}"
);
// Track the minimum depth we can reach.
assert!(successor_min_depth <= depth);
if successor_min_depth < *min_depth {
debug!(?node, ?successor_min_depth);
trace!(?node, ?successor_min_depth);
*min_depth = successor_min_depth;
*min_cycle_root = successor_node;
}
@ -627,20 +622,20 @@ where
scc_index: successor_scc_index,
annotation: successor_annotation,
}) => {
debug!(
trace!(
"Complete; {node:?} is root of complete-visited SCC idx {successor_scc_index:?} with annotation {successor_annotation:?}"
);
// Push the completed SCC indices onto
// the `successors_stack` for later.
debug!(?node, ?successor_scc_index);
trace!(?node, ?successor_scc_index);
successors_stack.push(successor_scc_index);
current_component_annotation.update_reachable(successor_annotation);
}
// `node` has no more (direct) successors; search recursively.
None => {
let depth = depth + 1;
debug!("Recursing down into {successor_node:?} at depth {depth:?}");
debug!(?depth, ?successor_node);
trace!("Recursing down into {successor_node:?} at depth {depth:?}");
trace!(?depth, ?successor_node);
// Remember which node the return value will come from.
frame.successor_node = successor_node;
// Start a new stack frame, then step into it.
@ -652,14 +647,14 @@ where
min_depth: depth,
min_cycle_root: successor_node,
successor_node,
current_component_annotation: (self.to_annotation)(successor_node),
current_component_annotation: self.annotations.new(successor_node),
});
continue 'recurse;
}
}
}
debug!("Finished walk from {node:?} with annotation: {current_component_annotation:?}");
trace!("Finished walk from {node:?} with annotation: {current_component_annotation:?}");
// Completed walk, remove `node` from the stack.
let r = self.node_stack.pop();
@ -691,8 +686,9 @@ where
debug!("Creating SCC rooted in {node:?} with successor {:?}", frame.successor_node);
let scc_index =
self.scc_data.create_scc(deduplicated_successors, current_component_annotation);
let scc_index = self.scc_data.create_scc(deduplicated_successors);
self.annotations.annotate_scc(scc_index, current_component_annotation);
self.node_states[node] =
NodeState::InCycle { scc_index, annotation: current_component_annotation };

View file

@ -5,8 +5,31 @@ use crate::graph::tests::TestGraph;
#[derive(Copy, Clone, Debug)]
struct MaxReached(usize);
type UsizeSccs = Sccs<usize, usize, ()>;
type MaxReachedSccs = Sccs<usize, usize, MaxReached>;
struct Maxes(IndexVec<usize, MaxReached>, fn(usize) -> usize);
type UsizeSccs = Sccs<usize, usize>;
impl Annotations<usize> for Maxes {
fn new(&self, element: usize) -> MaxReached {
MaxReached(self.1(element))
}
fn annotate_scc(&mut self, scc: usize, annotation: MaxReached) {
let i = self.0.push(annotation);
assert!(i == scc);
}
type Ann = MaxReached;
type SccIdx = usize;
}
impl Maxes {
fn annotation(&self, scc: usize) -> MaxReached {
self.0[scc]
}
fn new(mapping: fn(usize) -> usize) -> Self {
Self(IndexVec::new(), mapping)
}
}
impl Annotation for MaxReached {
fn merge_scc(self, other: Self) -> Self {
@ -14,7 +37,7 @@ impl Annotation for MaxReached {
}
fn merge_reached(self, other: Self) -> Self {
self.merge_scc(other)
Self(std::cmp::max(other.0, self.0))
}
}
@ -24,17 +47,32 @@ impl PartialEq<usize> for MaxReached {
}
}
impl MaxReached {
fn from_usize(nr: usize) -> Self {
Self(nr)
}
}
#[derive(Copy, Clone, Debug)]
struct MinMaxIn {
min: usize,
max: usize,
}
struct MinMaxes(IndexVec<usize, MinMaxIn>, fn(usize) -> MinMaxIn);
impl MinMaxes {
fn annotation(&self, scc: usize) -> MinMaxIn {
self.0[scc]
}
}
impl Annotations<usize> for MinMaxes {
fn new(&self, element: usize) -> MinMaxIn {
self.1(element)
}
fn annotate_scc(&mut self, scc: usize, annotation: MinMaxIn) {
let i = self.0.push(annotation);
assert!(i == scc);
}
type Ann = MinMaxIn;
type SccIdx = usize;
}
impl Annotation for MinMaxIn {
fn merge_scc(self, other: Self) -> Self {
@ -261,67 +299,68 @@ fn bench_sccc(b: &mut test::Bencher) {
#[test]
fn test_max_self_loop() {
let graph = TestGraph::new(0, &[(0, 0)]);
let sccs: MaxReachedSccs =
Sccs::new_with_annotation(&graph, |n| if n == 0 { MaxReached(17) } else { MaxReached(0) });
assert_eq!(sccs.annotation(0), 17);
let mut annotations = Maxes(IndexVec::new(), |n| if n == 0 { 17 } else { 0 });
Sccs::new_with_annotation(&graph, &mut annotations);
assert_eq!(annotations.0[0], 17);
}
#[test]
fn test_max_branch() {
let graph = TestGraph::new(0, &[(0, 1), (0, 2), (1, 3), (2, 4)]);
let sccs: MaxReachedSccs = Sccs::new_with_annotation(&graph, MaxReached::from_usize);
assert_eq!(sccs.annotation(sccs.scc(0)), 4);
assert_eq!(sccs.annotation(sccs.scc(1)), 3);
assert_eq!(sccs.annotation(sccs.scc(2)), 4);
}
#[test]
fn test_single_cycle_max() {
let graph = TestGraph::new(0, &[(0, 2), (2, 3), (2, 4), (4, 1), (1, 2)]);
let sccs: MaxReachedSccs = Sccs::new_with_annotation(&graph, MaxReached::from_usize);
assert_eq!(sccs.annotation(sccs.scc(2)), 4);
assert_eq!(sccs.annotation(sccs.scc(0)), 4);
let mut annotations = Maxes(IndexVec::new(), |n| n);
let sccs = Sccs::new_with_annotation(&graph, &mut annotations);
assert_eq!(annotations.0[sccs.scc(0)], 4);
assert_eq!(annotations.0[sccs.scc(1)], 3);
assert_eq!(annotations.0[sccs.scc(2)], 4);
}
#[test]
fn test_simple_cycle_max() {
let graph = TestGraph::new(0, &[(0, 1), (1, 2), (2, 0)]);
let sccs: MaxReachedSccs = Sccs::new_with_annotation(&graph, MaxReached::from_usize);
assert_eq!(sccs.num_sccs(), 1);
fn test_single_cycle_max() {
let graph = TestGraph::new(0, &[(0, 2), (2, 3), (2, 4), (4, 1), (1, 2)]);
let mut annotations = Maxes(IndexVec::new(), |n| n);
let sccs = Sccs::new_with_annotation(&graph, &mut annotations);
assert_eq!(annotations.0[sccs.scc(2)], 4);
assert_eq!(annotations.0[sccs.scc(0)], 4);
}
#[test]
fn test_double_cycle_max() {
let graph =
TestGraph::new(0, &[(0, 1), (1, 2), (1, 4), (2, 3), (2, 4), (3, 5), (4, 1), (5, 4)]);
let sccs: MaxReachedSccs =
Sccs::new_with_annotation(&graph, |n| if n == 5 { MaxReached(2) } else { MaxReached(1) });
let mut annotations = Maxes(IndexVec::new(), |n| if n == 5 { 2 } else { 1 });
assert_eq!(sccs.annotation(sccs.scc(0)).0, 2);
let sccs = Sccs::new_with_annotation(&graph, &mut annotations);
assert_eq!(annotations.0[sccs.scc(0)].0, 2);
}
#[test]
fn test_bug_minimised() {
let graph = TestGraph::new(0, &[(0, 3), (0, 1), (3, 2), (2, 3), (1, 4), (4, 5), (5, 4)]);
let sccs: MaxReachedSccs = Sccs::new_with_annotation(&graph, |n| match n {
3 => MaxReached(1),
_ => MaxReached(0),
let mut annotations = Maxes(IndexVec::new(), |n| match n {
3 => 1,
_ => 0,
});
assert_eq!(sccs.annotation(sccs.scc(2)), 1);
assert_eq!(sccs.annotation(sccs.scc(1)), 0);
assert_eq!(sccs.annotation(sccs.scc(4)), 0);
let sccs = Sccs::new_with_annotation(&graph, &mut annotations);
assert_eq!(annotations.annotation(sccs.scc(2)), 1);
assert_eq!(annotations.annotation(sccs.scc(1)), 0);
assert_eq!(annotations.annotation(sccs.scc(4)), 0);
}
#[test]
fn test_bug_max_leak_minimised() {
let graph = TestGraph::new(0, &[(0, 1), (0, 2), (1, 3), (3, 0), (3, 4), (4, 3)]);
let sccs: MaxReachedSccs = Sccs::new_with_annotation(&graph, |w| match w {
4 => MaxReached(1),
_ => MaxReached(0),
let mut annotations = Maxes(IndexVec::new(), |w| match w {
4 => 1,
_ => 0,
});
assert_eq!(sccs.annotation(sccs.scc(2)), 0);
assert_eq!(sccs.annotation(sccs.scc(3)), 1);
assert_eq!(sccs.annotation(sccs.scc(0)), 1);
let sccs = Sccs::new_with_annotation(&graph, &mut annotations);
assert_eq!(annotations.annotation(sccs.scc(2)), 0);
assert_eq!(annotations.annotation(sccs.scc(3)), 1);
assert_eq!(annotations.annotation(sccs.scc(0)), 1);
}
#[test]
@ -369,48 +408,49 @@ fn test_bug_max_leak() {
(23, 24),
],
);
let sccs: MaxReachedSccs = Sccs::new_with_annotation(&graph, |w| match w {
22 => MaxReached(1),
24 => MaxReached(2),
27 => MaxReached(2),
_ => MaxReached(0),
let mut annotations = Maxes::new(|w| match w {
22 => 1,
24 => 2,
27 => 2,
_ => 0,
});
let sccs = Sccs::new_with_annotation(&graph, &mut annotations);
assert_eq!(sccs.annotation(sccs.scc(2)), 0);
assert_eq!(sccs.annotation(sccs.scc(7)), 0);
assert_eq!(sccs.annotation(sccs.scc(8)), 2);
assert_eq!(sccs.annotation(sccs.scc(23)), 2);
assert_eq!(sccs.annotation(sccs.scc(3)), 2);
assert_eq!(sccs.annotation(sccs.scc(0)), 2);
assert_eq!(annotations.annotation(sccs.scc(2)), 0);
assert_eq!(annotations.annotation(sccs.scc(7)), 0);
assert_eq!(annotations.annotation(sccs.scc(8)), 2);
assert_eq!(annotations.annotation(sccs.scc(23)), 2);
assert_eq!(annotations.annotation(sccs.scc(3)), 2);
assert_eq!(annotations.annotation(sccs.scc(0)), 2);
}
#[test]
fn test_bug_max_zero_stick_shape() {
let graph = TestGraph::new(0, &[(0, 1), (1, 2), (2, 3), (3, 2), (3, 4)]);
let sccs: MaxReachedSccs = Sccs::new_with_annotation(&graph, |w| match w {
4 => MaxReached(1),
_ => MaxReached(0),
let mut annotations = Maxes::new(|w| match w {
4 => 1,
_ => 0,
});
let sccs = Sccs::new_with_annotation(&graph, &mut annotations);
assert_eq!(sccs.annotation(sccs.scc(0)), 1);
assert_eq!(sccs.annotation(sccs.scc(1)), 1);
assert_eq!(sccs.annotation(sccs.scc(2)), 1);
assert_eq!(sccs.annotation(sccs.scc(3)), 1);
assert_eq!(sccs.annotation(sccs.scc(4)), 1);
assert_eq!(annotations.annotation(sccs.scc(0)), 1);
assert_eq!(annotations.annotation(sccs.scc(1)), 1);
assert_eq!(annotations.annotation(sccs.scc(2)), 1);
assert_eq!(annotations.annotation(sccs.scc(3)), 1);
assert_eq!(annotations.annotation(sccs.scc(4)), 1);
}
#[test]
fn test_min_max_in() {
let graph = TestGraph::new(0, &[(0, 1), (0, 2), (1, 3), (3, 0), (3, 4), (4, 3), (3, 5)]);
let sccs: Sccs<usize, usize, MinMaxIn> =
Sccs::new_with_annotation(&graph, |w| MinMaxIn { min: w, max: w });
let mut annotations = MinMaxes(IndexVec::new(), |w| MinMaxIn { min: w, max: w });
let sccs = Sccs::new_with_annotation(&graph, &mut annotations);
assert_eq!(sccs.annotation(sccs.scc(2)).min, 2);
assert_eq!(sccs.annotation(sccs.scc(2)).max, 2);
assert_eq!(sccs.annotation(sccs.scc(0)).min, 0);
assert_eq!(sccs.annotation(sccs.scc(0)).max, 4);
assert_eq!(sccs.annotation(sccs.scc(3)).min, 0);
assert_eq!(sccs.annotation(sccs.scc(3)).max, 4);
assert_eq!(sccs.annotation(sccs.scc(5)).min, 5);
assert_eq!(annotations.annotation(sccs.scc(2)).min, 2);
assert_eq!(annotations.annotation(sccs.scc(2)).max, 2);
assert_eq!(annotations.annotation(sccs.scc(0)).min, 0);
assert_eq!(annotations.annotation(sccs.scc(0)).max, 4);
assert_eq!(annotations.annotation(sccs.scc(3)).min, 0);
assert_eq!(annotations.annotation(sccs.scc(3)).max, 4);
assert_eq!(annotations.annotation(sccs.scc(5)).min, 5);
}

View file

@ -1,7 +1,8 @@
use std::sync::{LazyLock, OnceLock};
use std::sync::{Arc, LazyLock, OnceLock};
pub use jobserver_crate::{Acquired, Client, HelperThread};
use jobserver_crate::{FromEnv, FromEnvErrorKind};
use parking_lot::{Condvar, Mutex};
// We can only call `from_env_ext` once per process
@ -71,10 +72,93 @@ pub fn client() -> Client {
GLOBAL_CLIENT_CHECKED.get().expect(ACCESS_ERROR).clone()
}
pub fn acquire_thread() {
GLOBAL_CLIENT_CHECKED.get().expect(ACCESS_ERROR).acquire_raw().ok();
struct ProxyData {
/// The number of tokens assigned to threads.
/// If this is 0, a single token is still assigned to this process, but is unused.
used: u16,
/// The number of threads requesting a token
pending: u16,
}
pub fn release_thread() {
GLOBAL_CLIENT_CHECKED.get().expect(ACCESS_ERROR).release_raw().ok();
/// This is a jobserver proxy used to ensure that we hold on to at least one token.
pub struct Proxy {
client: Client,
data: Mutex<ProxyData>,
/// Threads which are waiting on a token will wait on this.
wake_pending: Condvar,
helper: OnceLock<HelperThread>,
}
impl Proxy {
pub fn new() -> Arc<Self> {
let proxy = Arc::new(Proxy {
client: client(),
data: Mutex::new(ProxyData { used: 1, pending: 0 }),
wake_pending: Condvar::new(),
helper: OnceLock::new(),
});
let proxy_ = Arc::clone(&proxy);
let helper = proxy
.client
.clone()
.into_helper_thread(move |token| {
if let Ok(token) = token {
let mut data = proxy_.data.lock();
if data.pending > 0 {
// Give the token to a waiting thread
token.drop_without_releasing();
assert!(data.used > 0);
data.used += 1;
data.pending -= 1;
proxy_.wake_pending.notify_one();
} else {
// The token is no longer needed, drop it.
drop(data);
drop(token);
}
}
})
.expect("failed to create helper thread");
proxy.helper.set(helper).unwrap();
proxy
}
pub fn acquire_thread(&self) {
let mut data = self.data.lock();
if data.used == 0 {
// There was a free token around. This can
// happen when all threads release their token.
assert_eq!(data.pending, 0);
data.used += 1;
} else {
// Request a token from the helper thread. We can't directly use `acquire_raw`
// as we also need to be able to wait for the final token in the process which
// does not get a corresponding `release_raw` call.
self.helper.get().unwrap().request_token();
data.pending += 1;
self.wake_pending.wait(&mut data);
}
}
pub fn release_thread(&self) {
let mut data = self.data.lock();
if data.pending > 0 {
// Give the token to a waiting thread
data.pending -= 1;
self.wake_pending.notify_one();
} else {
data.used -= 1;
// Release the token unless it's the last one in the process
if data.used > 0 {
drop(data);
self.client.release_raw().ok();
}
}
}
}

View file

@ -59,8 +59,8 @@ macro_rules! already_send {
// These structures are already `Send`.
already_send!(
[std::backtrace::Backtrace][std::io::Stdout][std::io::Stderr][std::io::Error][std::fs::File]
[rustc_arena::DroplessArena][crate::memmap::Mmap][crate::profiling::SelfProfiler]
[crate::owned_slice::OwnedSlice]
[rustc_arena::DroplessArena][jobserver_crate::Client][jobserver_crate::HelperThread]
[crate::memmap::Mmap][crate::profiling::SelfProfiler][crate::owned_slice::OwnedSlice]
);
macro_rules! impl_dyn_send {
@ -134,8 +134,8 @@ macro_rules! already_sync {
already_sync!(
[std::sync::atomic::AtomicBool][std::sync::atomic::AtomicUsize][std::sync::atomic::AtomicU8]
[std::sync::atomic::AtomicU32][std::backtrace::Backtrace][std::io::Error][std::fs::File]
[jobserver_crate::Client][crate::memmap::Mmap][crate::profiling::SelfProfiler]
[crate::owned_slice::OwnedSlice]
[jobserver_crate::Client][jobserver_crate::HelperThread][crate::memmap::Mmap]
[crate::profiling::SelfProfiler][crate::owned_slice::OwnedSlice]
);
// Use portable AtomicU64 for targets without native 64-bit atomics

View file

@ -43,7 +43,7 @@ pub use self::freeze::{FreezeLock, FreezeReadGuard, FreezeWriteGuard};
pub use self::lock::{Lock, LockGuard, Mode};
pub use self::mode::{is_dyn_thread_safe, set_dyn_thread_safe_mode};
pub use self::parallel::{
join, par_for_each_in, par_map, parallel_guard, scope, spawn, try_par_for_each_in,
broadcast, join, par_for_each_in, par_map, parallel_guard, scope, spawn, try_par_for_each_in,
};
pub use self::vec::{AppendOnlyIndexVec, AppendOnlyVec};
pub use self::worker_local::{Registry, WorkerLocal};

View file

@ -237,3 +237,13 @@ pub fn par_map<I: DynSend, T: IntoIterator<Item = I>, R: DynSend, C: FromIterato
}
})
}
pub fn broadcast<R: DynSend>(op: impl Fn(usize) -> R + DynSync) -> Vec<R> {
if mode::is_dyn_thread_safe() {
let op = FromDyn::from(op);
let results = rayon_core::broadcast(|context| op.derive(op(context.index())));
results.into_iter().map(|r| r.into_inner()).collect()
} else {
vec![op(0)]
}
}

View file

@ -44,13 +44,13 @@ rustc_privacy = { path = "../rustc_privacy" }
rustc_query_system = { path = "../rustc_query_system" }
rustc_resolve = { path = "../rustc_resolve" }
rustc_session = { path = "../rustc_session" }
rustc_smir = { path = "../rustc_smir" }
rustc_span = { path = "../rustc_span" }
rustc_target = { path = "../rustc_target" }
rustc_trait_selection = { path = "../rustc_trait_selection" }
rustc_ty_utils = { path = "../rustc_ty_utils" }
serde_json = "1.0.59"
shlex = "1.0"
stable_mir = { path = "../stable_mir", features = ["rustc_internal"] }
tracing = { version = "0.1.35" }
# tidy-alphabetical-end

View file

@ -54,8 +54,8 @@ use rustc_metadata::locator;
use rustc_middle::ty::TyCtxt;
use rustc_parse::{new_parser_from_file, new_parser_from_source_str, unwrap_or_emit_fatal};
use rustc_session::config::{
CG_OPTIONS, ErrorOutputType, Input, OptionDesc, OutFileName, OutputType, UnstableOptions,
Z_OPTIONS, nightly_options, parse_target_triple,
CG_OPTIONS, CrateType, ErrorOutputType, Input, OptionDesc, OutFileName, OutputType,
UnstableOptions, Z_OPTIONS, nightly_options, parse_target_triple,
};
use rustc_session::getopts::{self, Matches};
use rustc_session::lint::{Lint, LintId};
@ -352,6 +352,8 @@ pub fn run_compiler(at_args: &[String], callbacks: &mut (dyn Callbacks + Send))
passes::write_dep_info(tcx);
passes::write_interface(tcx);
if sess.opts.output_types.contains_key(&OutputType::DepInfo)
&& sess.opts.output_types.len() == 1
{
@ -461,6 +463,7 @@ fn handle_explain(early_dcx: &EarlyDiagCtxt, registry: Registry, code: &str, col
// Allow "E0123" or "0123" form.
let upper_cased_code = code.to_ascii_uppercase();
if let Ok(code) = upper_cased_code.strip_prefix('E').unwrap_or(&upper_cased_code).parse::<u32>()
&& code <= ErrCode::MAX_AS_U32
&& let Ok(description) = registry.try_find_description(ErrCode::from_u32(code))
{
let mut is_in_code_block = false;
@ -816,6 +819,7 @@ fn print_crate_info(
let supported_crate_types = CRATE_TYPES
.iter()
.filter(|(_, crate_type)| !invalid_output_for_target(&sess, *crate_type))
.filter(|(_, crate_type)| *crate_type != CrateType::Sdylib)
.map(|(crate_type_sym, _)| *crate_type_sym)
.collect::<BTreeSet<_>>();
for supported_crate_type in supported_crate_types {

View file

@ -10,8 +10,8 @@ use rustc_middle::ty::{self, TyCtxt};
use rustc_mir_build::thir::print::{thir_flat, thir_tree};
use rustc_session::Session;
use rustc_session::config::{OutFileName, PpHirMode, PpMode, PpSourceMode};
use rustc_smir::rustc_internal::pretty::write_smir_pretty;
use rustc_span::{FileName, Ident};
use stable_mir::rustc_internal::pretty::write_smir_pretty;
use tracing::debug;
use {rustc_ast as ast, rustc_hir_pretty as pprust_hir};

View file

@ -195,7 +195,7 @@ impl<'a> Contains for Foo {
Please note that unconstrained lifetime parameters are not supported if they are
being used by an associated type.
In cases where the associated type's lifetime is meant to be tied to the the
In cases where the associated type's lifetime is meant to be tied to the
self type, and none of the methods on the trait need ownership or different
mutability, then an option is to implement the trait on a borrowed type:

View file

@ -1,9 +1,13 @@
#### Note: this error code is no longer emitted by the compiler.
Attempt was made to import an unimportable type. This can happen when trying
to import a type from a trait.
Erroneous code example:
```compile_fail,E0253
```
#![feature(import_trait_associated_functions)]
mod foo {
pub trait MyTrait {
type SomeType;

View file

@ -274,7 +274,12 @@ impl<'a> StripUnconfigured<'a> {
/// is in the original source file. Gives a compiler error if the syntax of
/// the attribute is incorrect.
pub(crate) fn expand_cfg_attr(&self, cfg_attr: &Attribute, recursive: bool) -> Vec<Attribute> {
validate_attr::check_attribute_safety(&self.sess.psess, AttributeSafety::Normal, &cfg_attr);
validate_attr::check_attribute_safety(
&self.sess.psess,
Some(AttributeSafety::Normal),
&cfg_attr,
ast::CRATE_NODE_ID,
);
// A trace attribute left in AST in place of the original `cfg_attr` attribute.
// It can later be used by lints or other diagnostics.

View file

@ -1983,7 +1983,11 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
let mut span: Option<Span> = None;
while let Some(attr) = attrs.next() {
rustc_ast_passes::feature_gate::check_attribute(attr, self.cx.sess, features);
validate_attr::check_attr(&self.cx.sess.psess, attr);
validate_attr::check_attr(
&self.cx.sess.psess,
attr,
self.cx.current_expansion.lint_node_id,
);
let current_span = if let Some(sp) = span { sp.to(attr.span) } else { attr.span };
span = Some(current_span);

View file

@ -536,6 +536,12 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
// Unstable attributes:
// ==========================================================================
// Linking:
gated!(
export_stable, Normal, template!(Word), WarnFollowing,
EncodeCrossCrate::No, experimental!(export_stable)
),
// Testing:
gated!(
test_runner, CrateLevel, template!(List: "path"), ErrorFollowing,

View file

@ -316,6 +316,7 @@ declare_features! (
// Unstable `#[target_feature]` directives.
(unstable, aarch64_unstable_target_feature, "1.82.0", Some(44839)),
(unstable, aarch64_ver_target_feature, "1.27.0", Some(44839)),
(unstable, apx_target_feature, "CURRENT_RUSTC_VERSION", Some(139284)),
(unstable, arm_target_feature, "1.27.0", Some(44839)),
(unstable, avx512_target_feature, "1.27.0", Some(44839)),
(unstable, bpf_target_feature, "1.54.0", Some(44839)),
@ -393,6 +394,8 @@ declare_features! (
(unstable, async_for_loop, "1.77.0", Some(118898)),
/// Allows `async` trait bound modifier.
(unstable, async_trait_bounds, "1.85.0", Some(62290)),
/// Allows using Intel AVX10 target features and intrinsics
(unstable, avx10_target_feature, "CURRENT_RUSTC_VERSION", Some(138843)),
/// Allows using C-variadics.
(unstable, c_variadic, "1.34.0", Some(44930)),
/// Allows the use of `#[cfg(contract_checks)` to check if contract checks are enabled.
@ -483,6 +486,8 @@ declare_features! (
(unstable, explicit_extern_abis, "CURRENT_RUSTC_VERSION", Some(134986)),
/// Allows explicit tail calls via `become` expression.
(incomplete, explicit_tail_calls, "1.72.0", Some(112788)),
/// Allows using `#[export_stable]` which indicates that an item is exportable.
(incomplete, export_stable, "CURRENT_RUSTC_VERSION", Some(139939)),
/// Allows using `aapcs`, `efiapi`, `sysv64` and `win64` as calling conventions
/// for functions with varargs.
(unstable, extended_varargs_abi_support, "1.65.0", Some(100189)),
@ -506,6 +511,8 @@ declare_features! (
(incomplete, fn_delegation, "1.76.0", Some(118212)),
/// Allows impls for the Freeze trait.
(internal, freeze_impls, "1.78.0", Some(121675)),
/// Frontmatter `---` blocks for use by external tools.
(unstable, frontmatter, "CURRENT_RUSTC_VERSION", Some(136889)),
/// Allows defining gen blocks and `gen fn`.
(unstable, gen_blocks, "1.75.0", Some(117078)),
/// Infer generic args for both consts and types.

View file

@ -269,18 +269,10 @@ impl DefKind {
| DefKind::TyParam
| DefKind::ExternCrate => DefPathData::TypeNs(name.unwrap()),
// An associated type name will be missing for an RPITIT.
DefKind::AssocTy => {
if let Some(name) = name {
DefPathData::TypeNs(name)
} else {
DefPathData::AnonAssocTy
}
}
// An associated type name will be missing for an RPITIT (DefPathData::AnonAssocTy),
// but those provide their own DefPathData.
DefKind::AssocTy => DefPathData::TypeNs(name.unwrap()),
// It's not exactly an anon const, but wrt DefPathData, there
// is no difference.
DefKind::Static { nested: true, .. } => DefPathData::AnonConst,
DefKind::Fn
| DefKind::Const
| DefKind::ConstParam

View file

@ -68,7 +68,7 @@ impl DefPathTable {
//
// See the documentation for DefPathHash for more information.
panic!(
"found DefPathHash collision between {def_path1:?} and {def_path2:?}. \
"found DefPathHash collision between {def_path1:#?} and {def_path2:#?}. \
Compilation cannot continue."
);
}
@ -97,13 +97,31 @@ impl DefPathTable {
}
}
#[derive(Debug)]
pub struct DisambiguatorState {
next: UnordMap<(LocalDefId, DefPathData), u32>,
}
impl DisambiguatorState {
pub fn new() -> Self {
Self { next: Default::default() }
}
/// Creates a `DisambiguatorState` where the next allocated `(LocalDefId, DefPathData)` pair
/// will have `index` as the disambiguator.
pub fn with(def_id: LocalDefId, data: DefPathData, index: u32) -> Self {
let mut this = Self::new();
this.next.insert((def_id, data), index);
this
}
}
/// The definition table containing node definitions.
/// It holds the `DefPathTable` for `LocalDefId`s/`DefPath`s.
/// It also stores mappings to convert `LocalDefId`s to/from `HirId`s.
#[derive(Debug)]
pub struct Definitions {
table: DefPathTable,
next_disambiguator: UnordMap<(LocalDefId, DefPathData), u32>,
}
/// A unique identifier that we can use to lookup a definition
@ -127,7 +145,7 @@ impl DefKey {
let DisambiguatedDefPathData { ref data, disambiguator } = self.disambiguated_data;
std::mem::discriminant(data).hash(&mut hasher);
if let Some(name) = data.get_opt_name() {
if let Some(name) = data.hashed_symbol() {
// Get a stable hash by considering the symbol chars rather than
// the symbol index.
name.as_str().hash(&mut hasher);
@ -173,7 +191,11 @@ impl DisambiguatedDefPathData {
}
}
DefPathDataName::Anon { namespace } => {
write!(writer, "{{{}#{}}}", namespace, self.disambiguator)
if let DefPathData::AnonAssocTy(method) = self.data {
write!(writer, "{}::{{{}#{}}}", method, namespace, self.disambiguator)
} else {
write!(writer, "{{{}#{}}}", namespace, self.disambiguator)
}
}
}
}
@ -287,10 +309,13 @@ pub enum DefPathData {
/// An existential `impl Trait` type node.
/// Argument position `impl Trait` have a `TypeNs` with their pretty-printed name.
OpaqueTy,
/// An anonymous associated type from an RPITIT.
AnonAssocTy,
/// An anonymous associated type from an RPITIT. The symbol refers to the name of the method
/// that defined the type.
AnonAssocTy(Symbol),
/// A synthetic body for a coroutine's by-move body.
SyntheticCoroutineBody,
/// Additional static data referred to by a static.
NestedStatic,
}
impl Definitions {
@ -342,11 +367,20 @@ impl Definitions {
let root = LocalDefId { local_def_index: table.allocate(key, def_path_hash) };
assert_eq!(root.local_def_index, CRATE_DEF_INDEX);
Definitions { table, next_disambiguator: Default::default() }
Definitions { table }
}
/// Adds a definition with a parent definition.
pub fn create_def(&mut self, parent: LocalDefId, data: DefPathData) -> LocalDefId {
/// Creates a definition with a parent definition.
/// If there are multiple definitions with the same DefPathData and the same parent, use
/// `disambiguator` to differentiate them. Distinct `DisambiguatorState` instances are not
/// guaranteed to generate unique disambiguators and should instead ensure that the `parent`
/// and `data` pair is distinct from other instances.
pub fn create_def(
&mut self,
parent: LocalDefId,
data: DefPathData,
disambiguator: &mut DisambiguatorState,
) -> LocalDefId {
// We can't use `Debug` implementation for `LocalDefId` here, since it tries to acquire a
// reference to `Definitions` and we're already holding a mutable reference.
debug!(
@ -354,12 +388,12 @@ impl Definitions {
self.def_path(parent).to_string_no_crate_verbose(),
);
// The root node must be created with `create_root_def()`.
// The root node must be created in `new()`.
assert!(data != DefPathData::CrateRoot);
// Find the next free disambiguator for this key.
let disambiguator = {
let next_disamb = self.next_disambiguator.entry((parent, data)).or_insert(0);
let next_disamb = disambiguator.next.entry((parent, data)).or_insert(0);
let disambiguator = *next_disamb;
*next_disamb = next_disamb.checked_add(1).expect("disambiguator overflow");
disambiguator
@ -422,8 +456,30 @@ impl DefPathData {
| Ctor
| AnonConst
| OpaqueTy
| AnonAssocTy
| SyntheticCoroutineBody => None,
| AnonAssocTy(..)
| SyntheticCoroutineBody
| NestedStatic => None,
}
}
fn hashed_symbol(&self) -> Option<Symbol> {
use self::DefPathData::*;
match *self {
TypeNs(name) | ValueNs(name) | MacroNs(name) | LifetimeNs(name) | AnonAssocTy(name) => {
Some(name)
}
Impl
| ForeignMod
| CrateRoot
| Use
| GlobalAsm
| Closure
| Ctor
| AnonConst
| OpaqueTy
| SyntheticCoroutineBody
| NestedStatic => None,
}
}
@ -443,8 +499,9 @@ impl DefPathData {
Ctor => DefPathDataName::Anon { namespace: sym::constructor },
AnonConst => DefPathDataName::Anon { namespace: sym::constant },
OpaqueTy => DefPathDataName::Anon { namespace: sym::opaque },
AnonAssocTy => DefPathDataName::Anon { namespace: sym::anon_assoc },
AnonAssocTy(..) => DefPathDataName::Anon { namespace: sym::anon_assoc },
SyntheticCoroutineBody => DefPathDataName::Anon { namespace: sym::synthetic },
NestedStatic => DefPathDataName::Anon { namespace: sym::nested },
}
}
}

View file

@ -35,18 +35,24 @@ use crate::def_id::{DefId, LocalDefIdMap};
pub(crate) use crate::hir_id::{HirId, ItemLocalId, ItemLocalMap, OwnerId};
use crate::intravisit::{FnKind, VisitorExt};
#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable_Generic)]
pub enum AngleBrackets {
/// E.g. `Path`.
Missing,
/// E.g. `Path<>`.
Empty,
/// E.g. `Path<T>`.
Full,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable_Generic)]
pub enum LifetimeSource {
/// E.g. `&Type`, `&'_ Type`, `&'a Type`, `&mut Type`, `&'_ mut Type`, `&'a mut Type`
Reference,
/// E.g. `ContainsLifetime`, `ContainsLifetime<'_>`, `ContainsLifetime<'a>`
Path {
/// - true for `ContainsLifetime<'_>`, `ContainsLifetime<'a>`,
/// `ContainsLifetime<'_, T>`, `ContainsLifetime<'a, T>`
/// - false for `ContainsLifetime`
with_angle_brackets: bool,
},
/// E.g. `ContainsLifetime`, `ContainsLifetime<>`, `ContainsLifetime<'_>`,
/// `ContainsLifetime<'a>`
Path { angle_brackets: AngleBrackets },
/// E.g. `impl Trait + '_`, `impl Trait + 'a`
OutlivesBound,
@ -304,12 +310,17 @@ impl Lifetime {
(Named | Anonymous, _) => (self.ident.span, format!("{new_lifetime}")),
// The user wrote `Path<T>`, and omitted the `'_,`.
(Hidden, Path { with_angle_brackets: true }) => {
(Hidden, Path { angle_brackets: AngleBrackets::Full }) => {
(self.ident.span, format!("{new_lifetime}, "))
}
// The user wrote `Path<>`, and omitted the `'_`..
(Hidden, Path { angle_brackets: AngleBrackets::Empty }) => {
(self.ident.span, format!("{new_lifetime}"))
}
// The user wrote `Path` and omitted the `<'_>`.
(Hidden, Path { with_angle_brackets: false }) => {
(Hidden, Path { angle_brackets: AngleBrackets::Missing }) => {
(self.ident.span.shrink_to_hi(), format!("<{new_lifetime}>"))
}
@ -2730,6 +2741,9 @@ pub enum ExprKind<'hir> {
/// An `if` block, with an optional else block.
///
/// I.e., `if <expr> { <expr> } else { <expr> }`.
///
/// The "then" expr is always `ExprKind::Block`. If present, the "else" expr is always
/// `ExprKind::Block` (for `else`) or `ExprKind::If` (for `else if`).
If(&'hir Expr<'hir>, &'hir Expr<'hir>, Option<&'hir Expr<'hir>>),
/// A conditionless loop (can be exited with `break`, `continue`, or `return`).
///

View file

@ -76,6 +76,36 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> {
)
}
/// Convenience function to *deeply* normalize during wfcheck. In the old solver,
/// this just dispatches to [`WfCheckingCtxt::normalize`], but in the new solver
/// this calls `deeply_normalize` and reports errors if they are encountered.
///
/// This function should be called in favor of `normalize` in cases where we will
/// then check the well-formedness of the type, since we only use the normalized
/// signature types for implied bounds when checking regions.
// FIXME(-Znext-solver): This should be removed when we compute implied outlives
// bounds using the unnormalized signature of the function we're checking.
fn deeply_normalize<T>(&self, span: Span, loc: Option<WellFormedLoc>, value: T) -> T
where
T: TypeFoldable<TyCtxt<'tcx>>,
{
if self.infcx.next_trait_solver() {
match self.ocx.deeply_normalize(
&ObligationCause::new(span, self.body_def_id, ObligationCauseCode::WellFormed(loc)),
self.param_env,
value.clone(),
) {
Ok(value) => value,
Err(errors) => {
self.infcx.err_ctxt().report_fulfillment_errors(errors);
value
}
}
} else {
self.normalize(span, loc, value)
}
}
fn register_wf_obligation(&self, span: Span, loc: Option<WellFormedLoc>, term: ty::Term<'tcx>) {
let cause = traits::ObligationCause::new(
span,
@ -297,7 +327,8 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) -> Result<()
{
let res = enter_wf_checking_ctxt(tcx, item.span, def_id, |wfcx| {
let ty = tcx.type_of(def_id).instantiate_identity();
let item_ty = wfcx.normalize(hir_ty.span, Some(WellFormedLoc::Ty(def_id)), ty);
let item_ty =
wfcx.deeply_normalize(hir_ty.span, Some(WellFormedLoc::Ty(def_id)), ty);
wfcx.register_wf_obligation(
hir_ty.span,
Some(WellFormedLoc::Ty(def_id)),
@ -1073,7 +1104,7 @@ fn check_associated_item(
match item.kind {
ty::AssocKind::Const { .. } => {
let ty = tcx.type_of(item.def_id).instantiate_identity();
let ty = wfcx.normalize(span, Some(WellFormedLoc::Ty(item_id)), ty);
let ty = wfcx.deeply_normalize(span, Some(WellFormedLoc::Ty(item_id)), ty);
wfcx.register_wf_obligation(span, loc, ty.into());
check_sized_if_body(
wfcx,
@ -1102,7 +1133,7 @@ fn check_associated_item(
}
if item.defaultness(tcx).has_value() {
let ty = tcx.type_of(item.def_id).instantiate_identity();
let ty = wfcx.normalize(span, Some(WellFormedLoc::Ty(item_id)), ty);
let ty = wfcx.deeply_normalize(span, Some(WellFormedLoc::Ty(item_id)), ty);
wfcx.register_wf_obligation(span, loc, ty.into());
}
Ok(())
@ -1149,7 +1180,7 @@ fn check_type_defn<'tcx>(
let field_id = field.did.expect_local();
let hir::FieldDef { ty: hir_ty, .. } =
tcx.hir_node_by_def_id(field_id).expect_field();
let ty = wfcx.normalize(
let ty = wfcx.deeply_normalize(
hir_ty.span,
None,
tcx.type_of(field.did).instantiate_identity(),
@ -1310,7 +1341,7 @@ fn check_item_type(
enter_wf_checking_ctxt(tcx, ty_span, item_id, |wfcx| {
let ty = tcx.type_of(item_id).instantiate_identity();
let item_ty = wfcx.normalize(ty_span, Some(WellFormedLoc::Ty(item_id)), ty);
let item_ty = wfcx.deeply_normalize(ty_span, Some(WellFormedLoc::Ty(item_id)), ty);
let forbid_unsized = match unsized_handling {
UnsizedHandling::Forbid => true,
@ -1375,7 +1406,7 @@ fn check_impl<'tcx>(
// other `Foo` impls are incoherent.
tcx.ensure_ok().coherent_trait(trait_ref.def_id)?;
let trait_span = hir_trait_ref.path.span;
let trait_ref = wfcx.normalize(
let trait_ref = wfcx.deeply_normalize(
trait_span,
Some(WellFormedLoc::Ty(item.hir_id().expect_owner().def_id)),
trait_ref,
@ -1435,7 +1466,7 @@ fn check_impl<'tcx>(
}
None => {
let self_ty = tcx.type_of(item.owner_id).instantiate_identity();
let self_ty = wfcx.normalize(
let self_ty = wfcx.deeply_normalize(
item.span,
Some(WellFormedLoc::Ty(item.hir_id().expect_owner().def_id)),
self_ty,
@ -1640,7 +1671,7 @@ fn check_fn_or_method<'tcx>(
sig.inputs_and_output =
tcx.mk_type_list_from_iter(sig.inputs_and_output.iter().enumerate().map(|(idx, ty)| {
wfcx.normalize(
wfcx.deeply_normalize(
arg_span(idx),
Some(WellFormedLoc::Param {
function: def_id,

View file

@ -14,6 +14,7 @@ use rustc_ast::visit::walk_list;
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
use rustc_errors::ErrorGuaranteed;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::definitions::DisambiguatorState;
use rustc_hir::intravisit::{self, InferKind, Visitor, VisitorExt};
use rustc_hir::{
self as hir, AmbigArg, GenericArg, GenericParam, GenericParamKind, HirId, LifetimeKind, Node,
@ -63,6 +64,7 @@ impl ResolvedArg {
struct BoundVarContext<'a, 'tcx> {
tcx: TyCtxt<'tcx>,
rbv: &'a mut ResolveBoundVars,
disambiguator: &'a mut DisambiguatorState,
scope: ScopeRef<'a>,
}
@ -245,8 +247,12 @@ pub(crate) fn provide(providers: &mut Providers) {
#[instrument(level = "debug", skip(tcx))]
fn resolve_bound_vars(tcx: TyCtxt<'_>, local_def_id: hir::OwnerId) -> ResolveBoundVars {
let mut rbv = ResolveBoundVars::default();
let mut visitor =
BoundVarContext { tcx, rbv: &mut rbv, scope: &Scope::Root { opt_parent_item: None } };
let mut visitor = BoundVarContext {
tcx,
rbv: &mut rbv,
scope: &Scope::Root { opt_parent_item: None },
disambiguator: &mut DisambiguatorState::new(),
};
match tcx.hir_owner_node(local_def_id) {
hir::OwnerNode::Item(item) => visitor.visit_item(item),
hir::OwnerNode::ForeignItem(item) => visitor.visit_foreign_item(item),
@ -515,9 +521,10 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
let capture_all_in_scope_lifetimes = opaque_captures_all_in_scope_lifetimes(opaque);
if capture_all_in_scope_lifetimes {
let tcx = self.tcx;
let lifetime_ident = |def_id: LocalDefId| {
let name = self.tcx.item_name(def_id.to_def_id());
let span = self.tcx.def_span(def_id);
let name = tcx.item_name(def_id.to_def_id());
let span = tcx.def_span(def_id);
Ident::new(name, span)
};
@ -1091,8 +1098,8 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
where
F: for<'b> FnOnce(&mut BoundVarContext<'b, 'tcx>),
{
let BoundVarContext { tcx, rbv, .. } = self;
let mut this = BoundVarContext { tcx: *tcx, rbv, scope: &wrap_scope };
let BoundVarContext { tcx, rbv, disambiguator, .. } = self;
let mut this = BoundVarContext { tcx: *tcx, rbv, disambiguator, scope: &wrap_scope };
let span = debug_span!("scope", scope = ?this.scope.debug_truncated());
{
let _enter = span.enter();
@ -1446,7 +1453,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
#[instrument(level = "trace", skip(self, opaque_capture_scopes), ret)]
fn remap_opaque_captures(
&self,
&mut self,
opaque_capture_scopes: &Vec<(LocalDefId, &RefCell<FxIndexMap<ResolvedArg, LocalDefId>>)>,
mut lifetime: ResolvedArg,
ident: Ident,
@ -1462,8 +1469,17 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
for &(opaque_def_id, captures) in opaque_capture_scopes.iter().rev() {
let mut captures = captures.borrow_mut();
let remapped = *captures.entry(lifetime).or_insert_with(|| {
let feed =
self.tcx.create_def(opaque_def_id, Some(ident.name), DefKind::LifetimeParam);
// `opaque_def_id` is unique to the `BoundVarContext` pass which is executed once
// per `resolve_bound_vars` query. This is the only location that creates nested
// lifetime inside a opaque type. `<opaque_def_id>::LifetimeNs(..)` is thus unique
// to this query and duplicates within the query are handled by `self.disambiguator`.
let feed = self.tcx.create_def(
opaque_def_id,
Some(ident.name),
DefKind::LifetimeParam,
None,
&mut self.disambiguator,
);
feed.def_span(ident.span);
feed.def_ident_span(Some(ident.span));
feed.def_id()

View file

@ -1770,7 +1770,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
span: Span,
opt_self_ty: Option<Ty<'tcx>>,
item_def_id: DefId,
trait_segment: &hir::PathSegment<'tcx>,
trait_segment: Option<&hir::PathSegment<'tcx>>,
item_segment: &hir::PathSegment<'tcx>,
) -> Ty<'tcx> {
match self.lower_qpath_shared(
@ -1795,7 +1795,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
span: Span,
opt_self_ty: Option<Ty<'tcx>>,
item_def_id: DefId,
trait_segment: &hir::PathSegment<'tcx>,
trait_segment: Option<&hir::PathSegment<'tcx>>,
item_segment: &hir::PathSegment<'tcx>,
) -> Const<'tcx> {
match self.lower_qpath_shared(
@ -1820,7 +1820,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
span: Span,
opt_self_ty: Option<Ty<'tcx>>,
item_def_id: DefId,
trait_segment: &hir::PathSegment<'tcx>,
trait_segment: Option<&hir::PathSegment<'tcx>>,
item_segment: &hir::PathSegment<'tcx>,
assoc_tag: ty::AssocTag,
) -> Result<(DefId, GenericArgsRef<'tcx>), ErrorGuaranteed> {
@ -1840,7 +1840,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
debug!(?self_ty);
let trait_ref =
self.lower_mono_trait_ref(span, trait_def_id, self_ty, trait_segment, false);
self.lower_mono_trait_ref(span, trait_def_id, self_ty, trait_segment.unwrap(), false);
debug!(?trait_ref);
let item_args =
@ -2196,16 +2196,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
}
}
Res::Def(DefKind::AssocTy, def_id) => {
debug_assert!(path.segments.len() >= 2);
let _ = self.prohibit_generic_args(
path.segments[..path.segments.len() - 2].iter(),
GenericsArgsErrExtend::None,
);
let trait_segment = if let [modules @ .., trait_, _item] = path.segments {
let _ = self.prohibit_generic_args(modules.iter(), GenericsArgsErrExtend::None);
Some(trait_)
} else {
None
};
self.lower_qpath_ty(
span,
opt_self_ty,
def_id,
&path.segments[path.segments.len() - 2],
trait_segment,
path.segments.last().unwrap(),
)
}
@ -2413,16 +2414,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
ty::Const::new_unevaluated(tcx, ty::UnevaluatedConst::new(did, args))
}
Res::Def(DefKind::AssocConst, did) => {
debug_assert!(path.segments.len() >= 2);
let _ = self.prohibit_generic_args(
path.segments[..path.segments.len() - 2].iter(),
GenericsArgsErrExtend::None,
);
let trait_segment = if let [modules @ .., trait_, _item] = path.segments {
let _ = self.prohibit_generic_args(modules.iter(), GenericsArgsErrExtend::None);
Some(trait_)
} else {
None
};
self.lower_qpath_const(
span,
opt_self_ty,
did,
&path.segments[path.segments.len() - 2],
trait_segment,
path.segments.last().unwrap(),
)
}

View file

@ -216,7 +216,7 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
check::maybe_check_static_with_link_section(tcx, item_def_id);
}
DefKind::Const if tcx.generics_of(item_def_id).is_empty() => {
let instance = ty::Instance::new(item_def_id.into(), ty::GenericArgs::empty());
let instance = ty::Instance::new_raw(item_def_id.into(), ty::GenericArgs::empty());
let cid = GlobalId { instance, promoted: None };
let typing_env = ty::TypingEnv::fully_monomorphized();
tcx.ensure_ok().eval_to_const_value_raw(typing_env.as_query_input(cid));

View file

@ -110,6 +110,7 @@ impl<'a> State<'a> {
}
self.print_attr_item(&unparsed, unparsed.span);
self.word("]");
self.hardbreak()
}
hir::Attribute::Parsed(AttributeKind::DocComment { style, kind, comment, .. }) => {
self.word(rustc_ast_pretty::pprust::state::doc_comment_to_string(
@ -183,7 +184,7 @@ impl<'a> State<'a> {
Node::Ty(a) => self.print_type(a),
Node::AssocItemConstraint(a) => self.print_assoc_item_constraint(a),
Node::TraitRef(a) => self.print_trait_ref(a),
Node::OpaqueTy(o) => self.print_opaque_ty(o),
Node::OpaqueTy(_) => panic!("cannot print Node::OpaqueTy"),
Node::Pat(a) => self.print_pat(a),
Node::TyPat(a) => self.print_ty_pat(a),
Node::PatField(a) => self.print_patfield(a),
@ -654,10 +655,11 @@ impl<'a> State<'a> {
self.bclose(item.span, cb);
}
hir::ItemKind::GlobalAsm { asm, .. } => {
// FIXME(nnethercote): `ib` is unclosed
let (cb, _ib) = self.head("global_asm!");
let (cb, ib) = self.head("global_asm!");
self.print_inline_asm(asm);
self.end(cb)
self.word(";");
self.end(cb);
self.end(ib);
}
hir::ItemKind::TyAlias(ident, ty, generics) => {
let (cb, ib) = self.head("type");
@ -764,14 +766,6 @@ impl<'a> State<'a> {
self.print_path(t.path, false);
}
fn print_opaque_ty(&mut self, o: &hir::OpaqueTy<'_>) {
// FIXME(nnethercote): `cb` and `ib` are unclosed
let (_cb, _ib) = self.head("opaque");
self.word("{");
self.print_bounds("impl", o.bounds);
self.word("}");
}
fn print_formal_generic_params(&mut self, generic_params: &[hir::GenericParam<'_>]) {
if !generic_params.is_empty() {
self.word("for");
@ -1509,7 +1503,7 @@ impl<'a> State<'a> {
}
hir::ExprKind::DropTemps(init) => {
// Print `{`:
let cb = self.cbox(INDENT_UNIT);
let cb = self.cbox(0);
let ib = self.ibox(0);
self.bopen(ib);
@ -1532,16 +1526,18 @@ impl<'a> State<'a> {
self.print_if(test, blk, elseopt);
}
hir::ExprKind::Loop(blk, opt_label, _, _) => {
let cb = self.cbox(0);
let ib = self.ibox(0);
if let Some(label) = opt_label {
self.print_ident(label.ident);
self.word_space(":");
}
let (cb, ib) = self.head("loop");
self.word_nbsp("loop");
self.print_block(blk, cb, ib);
}
hir::ExprKind::Match(expr, arms, _) => {
let cb = self.cbox(INDENT_UNIT);
let ib = self.ibox(INDENT_UNIT);
let cb = self.cbox(0);
let ib = self.ibox(0);
self.word_nbsp("match");
self.print_expr_as_cond(expr);
self.space();
@ -1572,15 +1568,6 @@ impl<'a> State<'a> {
// This is a bare expression.
self.ann.nested(self, Nested::Body(body));
// FIXME(nnethercote): this is bogus
let fake_ib = BoxMarker;
self.end(fake_ib);
// A box will be closed by `print_expr`, but we didn't want an overall
// wrapper so we closed the corresponding opening. so create an
// empty box to satisfy the close.
// FIXME(nnethercote): this is bogus, and `print_expr` is missing
let _ib = self.ibox(0);
}
hir::ExprKind::Block(blk, opt_label) => {
if let Some(label) = opt_label {

View file

@ -11,7 +11,7 @@ use rustc_trait_selection::traits::{
use tracing::{debug, instrument};
use crate::coercion::{AsCoercionSite, CoerceMany};
use crate::{Diverges, Expectation, FnCtxt, Needs};
use crate::{Diverges, Expectation, FnCtxt, GatherLocalsVisitor, Needs};
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
#[instrument(skip(self), level = "debug", ret)]
@ -43,6 +43,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// #55810: Type check patterns first so we get types for all bindings.
let scrut_span = scrut.span.find_ancestor_inside(expr.span).unwrap_or(scrut.span);
for arm in arms {
GatherLocalsVisitor::gather_from_arm(self, arm);
self.check_pat_top(arm.pat, scrutinee_ty, Some(scrut_span), Some(scrut), None);
}
@ -601,7 +603,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// FIXME(-Znext-solver): Remove this branch once `replace_opaque_types_with_infer` is gone.
ty::Infer(ty::TyVar(_)) => self
.inner
.borrow()
.borrow_mut()
.opaque_types()
.iter_opaque_types()
.find(|(_, v)| v.ty == expected_ty)
.map(|(k, _)| (k.def_id, k.args))?,

View file

@ -1051,20 +1051,19 @@ impl<'a, 'tcx> CastCheck<'tcx> {
fn check_ref_cast(
&self,
fcx: &FnCtxt<'a, 'tcx>,
m_expr: ty::TypeAndMut<'tcx>,
m_cast: ty::TypeAndMut<'tcx>,
mut m_expr: ty::TypeAndMut<'tcx>,
mut m_cast: ty::TypeAndMut<'tcx>,
) -> Result<CastKind, CastError<'tcx>> {
// array-ptr-cast: allow mut-to-mut, mut-to-const, const-to-const
m_expr.ty = fcx.try_structurally_resolve_type(self.expr_span, m_expr.ty);
m_cast.ty = fcx.try_structurally_resolve_type(self.cast_span, m_cast.ty);
if m_expr.mutbl >= m_cast.mutbl
&& let ty::Array(ety, _) = m_expr.ty.kind()
&& fcx.can_eq(fcx.param_env, *ety, m_cast.ty)
{
// Due to the limitations of LLVM global constants,
// region pointers end up pointing at copies of
// vector elements instead of the original values.
// To allow raw pointers to work correctly, we
// need to special-case obtaining a raw pointer
// from a region pointer to a vector.
// Due to historical reasons we allow directly casting references of
// arrays into raw pointers of their element type.
// Coerce to a raw pointer so that we generate RawPtr in MIR.
let array_ptr_type = Ty::new_ptr(fcx.tcx, m_expr.ty, m_expr.mutbl);

View file

@ -3,7 +3,6 @@ use std::cell::RefCell;
use rustc_abi::ExternAbi;
use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_hir::intravisit::Visitor;
use rustc_hir::lang_items::LangItem;
use rustc_hir_analysis::check::check_function_signature;
use rustc_infer::infer::RegionVariableOrigin;
@ -50,7 +49,9 @@ pub(super) fn check_fn<'a, 'tcx>(
let span = body.value.span;
GatherLocalsVisitor::new(fcx).visit_body(body);
for param in body.params {
GatherLocalsVisitor::gather_from_param(fcx, param);
}
// C-variadic fns also have a `VaList` input that's not listed in `fn_sig`
// (as it's created inside the body itself, not passed in from outside).

View file

@ -16,7 +16,6 @@ use rustc_errors::{
};
use rustc_hir::def::{CtorKind, DefKind, Res};
use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::Visitor;
use rustc_hir::lang_items::LangItem;
use rustc_hir::{ExprKind, HirId, QPath};
use rustc_hir_analysis::NoVariantNamed;
@ -50,8 +49,8 @@ use crate::errors::{
YieldExprOutsideOfCoroutine,
};
use crate::{
BreakableCtxt, CoroutineTypes, Diverges, FnCtxt, Needs, TupleArgumentsFlag, cast,
fatally_break_rust, report_unexpected_variant_res, type_error_struct,
BreakableCtxt, CoroutineTypes, Diverges, FnCtxt, GatherLocalsVisitor, Needs,
TupleArgumentsFlag, cast, fatally_break_rust, report_unexpected_variant_res, type_error_struct,
};
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
@ -1518,11 +1517,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let_expr: &'tcx hir::LetExpr<'tcx>,
hir_id: HirId,
) -> Ty<'tcx> {
GatherLocalsVisitor::gather_from_let_expr(self, let_expr, hir_id);
// for let statements, this is done in check_stmt
let init = let_expr.init;
self.warn_if_unreachable(init.hir_id, init.span, "block in `let` expression");
// otherwise check exactly as a let statement
self.check_decl((let_expr, hir_id).into());
// but return a bool, for this is a boolean expression
if let ast::Recovered::Yes(error_guaranteed) = let_expr.recovered {
self.set_tainted_by_errors(error_guaranteed);
@ -1827,7 +1830,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Create a new function context.
let def_id = block.def_id;
let fcx = FnCtxt::new(self, self.param_env, def_id);
crate::GatherLocalsVisitor::new(&fcx).visit_body(body);
let ty = fcx.check_expr_with_expectation(body.value, expected);
fcx.require_type_is_sized(ty, body.value.span, ObligationCauseCode::SizedConstOrStatic);

View file

@ -158,7 +158,7 @@ pub trait TypeInformationCtxt<'tcx> {
fn resolve_vars_if_possible<T: TypeFoldable<TyCtxt<'tcx>>>(&self, t: T) -> T;
fn try_structurally_resolve_type(&self, span: Span, ty: Ty<'tcx>) -> Ty<'tcx>;
fn structurally_resolve_type(&self, span: Span, ty: Ty<'tcx>) -> Ty<'tcx>;
fn report_bug(&self, span: Span, msg: impl ToString) -> Self::Error;
@ -191,8 +191,8 @@ impl<'tcx> TypeInformationCtxt<'tcx> for &FnCtxt<'_, 'tcx> {
self.infcx.resolve_vars_if_possible(t)
}
fn try_structurally_resolve_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
(**self).try_structurally_resolve_type(sp, ty)
fn structurally_resolve_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
(**self).structurally_resolve_type(sp, ty)
}
fn report_bug(&self, span: Span, msg: impl ToString) -> Self::Error {
@ -236,7 +236,7 @@ impl<'tcx> TypeInformationCtxt<'tcx> for (&LateContext<'tcx>, LocalDefId) {
self.0.maybe_typeck_results().expect("expected typeck results")
}
fn try_structurally_resolve_type(&self, _span: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
fn structurally_resolve_type(&self, _span: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
// FIXME: Maybe need to normalize here.
ty
}
@ -776,7 +776,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
// Select just those fields of the `with`
// expression that will actually be used
match self.cx.try_structurally_resolve_type(with_expr.span, with_place.place.ty()).kind() {
match self.cx.structurally_resolve_type(with_expr.span, with_place.place.ty()).kind() {
ty::Adt(adt, args) if adt.is_struct() => {
// Consume those fields of the with expression that are needed.
for (f_index, with_field) in adt.non_enum_variant().fields.iter_enumerated() {
@ -1176,7 +1176,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
/// two operations: a dereference to reach the array data and then an index to
/// jump forward to the relevant item.
impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx, Cx, D> {
fn resolve_type_vars_or_bug(
fn expect_and_resolve_type(
&self,
id: HirId,
ty: Option<Ty<'tcx>>,
@ -1185,12 +1185,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
Some(ty) => {
let ty = self.cx.resolve_vars_if_possible(ty);
self.cx.error_reported_in_ty(ty)?;
if ty.is_ty_var() {
debug!("resolve_type_vars_or_bug: infer var from {:?}", ty);
Err(self.cx.report_bug(self.cx.tcx().hir_span(id), "encountered type variable"))
} else {
Ok(ty)
}
Ok(ty)
}
None => {
// FIXME: We shouldn't be relying on the infcx being tainted.
@ -1201,15 +1196,15 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
}
fn node_ty(&self, hir_id: HirId) -> Result<Ty<'tcx>, Cx::Error> {
self.resolve_type_vars_or_bug(hir_id, self.cx.typeck_results().node_type_opt(hir_id))
self.expect_and_resolve_type(hir_id, self.cx.typeck_results().node_type_opt(hir_id))
}
fn expr_ty(&self, expr: &hir::Expr<'_>) -> Result<Ty<'tcx>, Cx::Error> {
self.resolve_type_vars_or_bug(expr.hir_id, self.cx.typeck_results().expr_ty_opt(expr))
self.expect_and_resolve_type(expr.hir_id, self.cx.typeck_results().expr_ty_opt(expr))
}
fn expr_ty_adjusted(&self, expr: &hir::Expr<'_>) -> Result<Ty<'tcx>, Cx::Error> {
self.resolve_type_vars_or_bug(
self.expect_and_resolve_type(
expr.hir_id,
self.cx.typeck_results().expr_ty_adjusted_opt(expr),
)
@ -1264,10 +1259,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
// a bind-by-ref means that the base_ty will be the type of the ident itself,
// but what we want here is the type of the underlying value being borrowed.
// So peel off one-level, turning the &T into T.
match self
.cx
.try_structurally_resolve_type(pat.span, base_ty)
.builtin_deref(false)
match self.cx.structurally_resolve_type(pat.span, base_ty).builtin_deref(false)
{
Some(ty) => Ok(ty),
None => {
@ -1513,10 +1505,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
if node_ty != place_ty
&& self
.cx
.try_structurally_resolve_type(
self.cx.tcx().hir_span(base_place.hir_id),
place_ty,
)
.structurally_resolve_type(self.cx.tcx().hir_span(base_place.hir_id), place_ty)
.is_impl_trait()
{
projections.push(Projection { kind: ProjectionKind::OpaqueCast, ty: node_ty });
@ -1538,7 +1527,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
let base_ty = self.expr_ty_adjusted(base)?;
let ty::Ref(region, _, mutbl) =
*self.cx.try_structurally_resolve_type(base.span, base_ty).kind()
*self.cx.structurally_resolve_type(base.span, base_ty).kind()
else {
span_bug!(expr.span, "cat_overloaded_place: base is not a reference");
};
@ -1556,7 +1545,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
let base_curr_ty = base_place.place.ty();
let deref_ty = match self
.cx
.try_structurally_resolve_type(self.cx.tcx().hir_span(base_place.hir_id), base_curr_ty)
.structurally_resolve_type(self.cx.tcx().hir_span(base_place.hir_id), base_curr_ty)
.builtin_deref(true)
{
Some(ty) => ty,
@ -1584,7 +1573,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
) -> Result<VariantIdx, Cx::Error> {
let res = self.cx.typeck_results().qpath_res(qpath, pat_hir_id);
let ty = self.cx.typeck_results().node_type(pat_hir_id);
let ty::Adt(adt_def, _) = self.cx.try_structurally_resolve_type(span, ty).kind() else {
let ty::Adt(adt_def, _) = self.cx.structurally_resolve_type(span, ty).kind() else {
return Err(self
.cx
.report_bug(span, "struct or tuple struct pattern not applied to an ADT"));
@ -1616,7 +1605,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
span: Span,
) -> Result<usize, Cx::Error> {
let ty = self.cx.typeck_results().node_type(pat_hir_id);
match self.cx.try_structurally_resolve_type(span, ty).kind() {
match self.cx.structurally_resolve_type(span, ty).kind() {
ty::Adt(adt_def, _) => Ok(adt_def.variant(variant_index).fields.len()),
_ => {
self.cx
@ -1631,7 +1620,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
/// Here `pat_hir_id` is the HirId of the pattern itself.
fn total_fields_in_tuple(&self, pat_hir_id: HirId, span: Span) -> Result<usize, Cx::Error> {
let ty = self.cx.typeck_results().node_type(pat_hir_id);
match self.cx.try_structurally_resolve_type(span, ty).kind() {
match self.cx.structurally_resolve_type(span, ty).kind() {
ty::Tuple(args) => Ok(args.len()),
_ => Err(self.cx.report_bug(span, "tuple pattern not applied to a tuple")),
}
@ -1820,7 +1809,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
PatKind::Slice(before, ref slice, after) => {
let Some(element_ty) = self
.cx
.try_structurally_resolve_type(pat.span, place_with_id.place.ty())
.structurally_resolve_type(pat.span, place_with_id.place.ty())
.builtin_index()
else {
debug!("explicit index of non-indexable type {:?}", place_with_id);
@ -1890,7 +1879,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
}
fn is_multivariant_adt(&self, ty: Ty<'tcx>, span: Span) -> bool {
if let ty::Adt(def, _) = self.cx.try_structurally_resolve_type(span, ty).kind() {
if let ty::Adt(def, _) = self.cx.structurally_resolve_type(span, ty).kind() {
// Note that if a non-exhaustive SingleVariant is defined in another crate, we need
// to assume that more cases will be added to the variant in the future. This mean
// that we should handle non-exhaustive SingleVariant the same way we would handle

View file

@ -37,8 +37,8 @@ use crate::method::probe::IsSuggestion;
use crate::method::probe::Mode::MethodCall;
use crate::method::probe::ProbeScope::TraitsInScope;
use crate::{
BreakableCtxt, Diverges, Expectation, FnCtxt, LoweredTy, Needs, TupleArgumentsFlag, errors,
struct_span_code_err,
BreakableCtxt, Diverges, Expectation, FnCtxt, GatherLocalsVisitor, LoweredTy, Needs,
TupleArgumentsFlag, errors, struct_span_code_err,
};
rustc_index::newtype_index! {
@ -1765,6 +1765,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// Type check a `let` statement.
fn check_decl_local(&self, local: &'tcx hir::LetStmt<'tcx>) {
GatherLocalsVisitor::gather_from_local(self, local);
let ty = self.check_decl(local.into());
self.write_ty(local.hir_id, ty);
if local.pat.is_never_pattern() {

View file

@ -55,6 +55,14 @@ impl<'a> From<(&'a hir::LetExpr<'a>, HirId)> for Declaration<'a> {
}
}
/// The `GatherLocalsVisitor` is responsible for initializing local variable types
/// in the [`ty::TypeckResults`] for all subpatterns in statements and expressions
/// like `let`, `match`, and params of function bodies. It also adds `Sized` bounds
/// for these types (with exceptions for unsized feature gates like `unsized_fn_params`).
///
/// Failure to visit locals will cause an ICE in writeback when the local's type is
/// resolved. Visiting locals twice will ICE in the `GatherLocalsVisitor`, since it
/// will overwrite the type previously stored in the local.
pub(super) struct GatherLocalsVisitor<'a, 'tcx> {
fcx: &'a FnCtxt<'a, 'tcx>,
// parameters are special cases of patterns, but we want to handle them as
@ -63,9 +71,37 @@ pub(super) struct GatherLocalsVisitor<'a, 'tcx> {
outermost_fn_param_pat: Option<(Span, HirId)>,
}
// N.B. additional `gather_*` functions should be careful to only walk the pattern
// for new expressions, since visiting sub-expressions or nested bodies may initialize
// locals which are not conceptually owned by the gathered statement or expression.
impl<'a, 'tcx> GatherLocalsVisitor<'a, 'tcx> {
pub(super) fn new(fcx: &'a FnCtxt<'a, 'tcx>) -> Self {
Self { fcx, outermost_fn_param_pat: None }
pub(crate) fn gather_from_local(fcx: &'a FnCtxt<'a, 'tcx>, local: &'tcx hir::LetStmt<'tcx>) {
let mut visitor = GatherLocalsVisitor { fcx, outermost_fn_param_pat: None };
visitor.declare(local.into());
visitor.visit_pat(local.pat);
}
pub(crate) fn gather_from_let_expr(
fcx: &'a FnCtxt<'a, 'tcx>,
let_expr: &'tcx hir::LetExpr<'tcx>,
expr_hir_id: hir::HirId,
) {
let mut visitor = GatherLocalsVisitor { fcx, outermost_fn_param_pat: None };
visitor.declare((let_expr, expr_hir_id).into());
visitor.visit_pat(let_expr.pat);
}
pub(crate) fn gather_from_param(fcx: &'a FnCtxt<'a, 'tcx>, param: &'tcx hir::Param<'tcx>) {
let mut visitor = GatherLocalsVisitor {
fcx,
outermost_fn_param_pat: Some((param.ty_span, param.hir_id)),
};
visitor.visit_pat(param.pat);
}
pub(crate) fn gather_from_arm(fcx: &'a FnCtxt<'a, 'tcx>, local: &'tcx hir::Arm<'tcx>) {
let mut visitor = GatherLocalsVisitor { fcx, outermost_fn_param_pat: None };
visitor.visit_pat(local.pat);
}
fn assign(&mut self, span: Span, nid: HirId, ty_opt: Option<Ty<'tcx>>) -> Ty<'tcx> {
@ -73,12 +109,12 @@ impl<'a, 'tcx> GatherLocalsVisitor<'a, 'tcx> {
None => {
// Infer the variable's type.
let var_ty = self.fcx.next_ty_var(span);
self.fcx.locals.borrow_mut().insert(nid, var_ty);
assert_eq!(self.fcx.locals.borrow_mut().insert(nid, var_ty), None);
var_ty
}
Some(typ) => {
// Take type that the user specified.
self.fcx.locals.borrow_mut().insert(nid, typ);
assert_eq!(self.fcx.locals.borrow_mut().insert(nid, typ), None);
typ
}
}
@ -133,13 +169,6 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> {
intravisit::walk_expr(self, expr)
}
fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) {
let old_outermost_fn_param_pat =
self.outermost_fn_param_pat.replace((param.ty_span, param.hir_id));
intravisit::walk_param(self, param);
self.outermost_fn_param_pat = old_outermost_fn_param_pat;
}
// Add pattern bindings.
fn visit_pat(&mut self, p: &'tcx hir::Pat<'tcx>) {
if let PatKind::Binding(_, _, ident, _) = p.kind {

View file

@ -46,7 +46,6 @@ use rustc_errors::codes::*;
use rustc_errors::{Applicability, ErrorGuaranteed, pluralize, struct_span_code_err};
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::intravisit::Visitor;
use rustc_hir::{HirId, HirIdMap, Node};
use rustc_hir_analysis::check::check_abi;
use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer;
@ -191,9 +190,6 @@ fn typeck_with_inspect<'tcx>(
let wf_code = ObligationCauseCode::WellFormed(Some(WellFormedLoc::Ty(def_id)));
fcx.register_wf_obligation(expected_type.into(), body.value.span, wf_code);
// Gather locals in statics (because of block expressions).
GatherLocalsVisitor::new(&fcx).visit_body(body);
fcx.check_expr_coercible_to_type(body.value, expected_type, None);
fcx.write_ty(id, expected_type);

View file

@ -177,16 +177,20 @@ enum PeelKind {
/// Only peel reference types. This is used for explicit `deref!(_)` patterns, which dereference
/// any number of `&`/`&mut` references, plus a single smart pointer.
ExplicitDerefPat,
/// Implicitly peel any number of references, and if `deref_patterns` is enabled, smart pointer
/// ADTs. In order to peel only as much as necessary for the pattern to match, the `until_adt`
/// field contains the ADT def that the pattern is a constructor for, if applicable, so that we
/// don't peel it. See [`ResolvedPat`] for more information.
Implicit { until_adt: Option<DefId> },
/// Implicitly peel references, and if `deref_patterns` is enabled, smart pointer ADTs.
Implicit {
/// The ADT the pattern is a constructor for, if applicable, so that we don't peel it. See
/// [`ResolvedPat`] for more information.
until_adt: Option<DefId>,
/// The number of references at the head of the pattern's type, so we can leave that many
/// untouched. This is `1` for string literals, and `0` for most patterns.
pat_ref_layers: usize,
},
}
impl AdjustMode {
const fn peel_until_adt(opt_adt_def: Option<DefId>) -> AdjustMode {
AdjustMode::Peel { kind: PeelKind::Implicit { until_adt: opt_adt_def } }
AdjustMode::Peel { kind: PeelKind::Implicit { until_adt: opt_adt_def, pat_ref_layers: 0 } }
}
const fn peel_all() -> AdjustMode {
AdjustMode::peel_until_adt(None)
@ -488,9 +492,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
match pat.kind {
// Peel off a `&` or `&mut` from the scrutinee type. See the examples in
// `tests/ui/rfcs/rfc-2005-default-binding-mode`.
_ if let AdjustMode::Peel { .. } = adjust_mode
_ if let AdjustMode::Peel { kind: peel_kind } = adjust_mode
&& pat.default_binding_modes
&& let ty::Ref(_, inner_ty, inner_mutability) = *expected.kind() =>
&& let ty::Ref(_, inner_ty, inner_mutability) = *expected.kind()
&& self.should_peel_ref(peel_kind, expected) =>
{
debug!("inspecting {:?}", expected);
@ -531,24 +536,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// If `deref_patterns` is enabled, peel a smart pointer from the scrutinee type. See the
// examples in `tests/ui/pattern/deref_patterns/`.
_ if self.tcx.features().deref_patterns()
&& let AdjustMode::Peel { kind: PeelKind::Implicit { until_adt } } = adjust_mode
&& let AdjustMode::Peel { kind: peel_kind } = adjust_mode
&& pat.default_binding_modes
// For simplicity, only apply overloaded derefs if `expected` is a known ADT.
// FIXME(deref_patterns): we'll get better diagnostics for users trying to
// implicitly deref generics if we allow them here, but primitives, tuples, and
// inference vars definitely should be stopped. Figure out what makes most sense.
&& let ty::Adt(scrutinee_adt, _) = *expected.kind()
// Don't peel if the pattern type already matches the scrutinee. E.g., stop here if
// matching on a `Cow<'a, T>` scrutinee with a `Cow::Owned(_)` pattern.
&& until_adt != Some(scrutinee_adt.did())
// At this point, the pattern isn't able to match `expected` without peeling. Check
// that it implements `Deref` before assuming it's a smart pointer, to get a normal
// type error instead of a missing impl error if not. This only checks for `Deref`,
// not `DerefPure`: we require that too, but we want a trait error if it's missing.
&& let Some(deref_trait) = self.tcx.lang_items().deref_trait()
&& self
.type_implements_trait(deref_trait, [expected], self.param_env)
.may_apply() =>
&& self.should_peel_smart_pointer(peel_kind, expected) =>
{
debug!("scrutinee ty {expected:?} is a smart pointer, inserting overloaded deref");
// The scrutinee is a smart pointer; implicitly dereference it. This adds a
@ -680,21 +670,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// String and byte-string literals result in types `&str` and `&[u8]` respectively.
// All other literals result in non-reference types.
// As a result, we allow `if let 0 = &&0 {}` but not `if let "foo" = &&"foo" {}`.
//
// Call `resolve_vars_if_possible` here for inline const blocks.
PatKind::Expr(lt) => match self.resolve_vars_if_possible(self.check_pat_expr_unadjusted(lt)).kind() {
ty::Ref(..) => AdjustMode::Pass,
_ => {
// Path patterns have already been handled, and inline const blocks currently
// aren't possible to write, so any handling for them would be untested.
if cfg!(debug_assertions)
&& self.tcx.features().deref_patterns()
&& !matches!(lt.kind, PatExprKind::Lit { .. })
{
span_bug!(lt.span, "FIXME(deref_patterns): adjust mode unimplemented for {:?}", lt.kind);
// As a result, we allow `if let 0 = &&0 {}` but not `if let "foo" = &&"foo" {}` unless
// `deref_patterns` is enabled.
PatKind::Expr(lt) => {
// Path patterns have already been handled, and inline const blocks currently
// aren't possible to write, so any handling for them would be untested.
if cfg!(debug_assertions)
&& self.tcx.features().deref_patterns()
&& !matches!(lt.kind, PatExprKind::Lit { .. })
{
span_bug!(lt.span, "FIXME(deref_patterns): adjust mode unimplemented for {:?}", lt.kind);
}
// Call `resolve_vars_if_possible` here for inline const blocks.
let lit_ty = self.resolve_vars_if_possible(self.check_pat_expr_unadjusted(lt));
// If `deref_patterns` is enabled, allow `if let "foo" = &&"foo" {}`.
if self.tcx.features().deref_patterns() {
let mut peeled_ty = lit_ty;
let mut pat_ref_layers = 0;
while let ty::Ref(_, inner_ty, mutbl) = *peeled_ty.kind() {
// We rely on references at the head of constants being immutable.
debug_assert!(mutbl.is_not());
pat_ref_layers += 1;
peeled_ty = inner_ty;
}
AdjustMode::peel_all()
AdjustMode::Peel { kind: PeelKind::Implicit { until_adt: None, pat_ref_layers } }
} else {
if lit_ty.is_ref() { AdjustMode::Pass } else { AdjustMode::peel_all() }
}
},
@ -720,6 +721,67 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
/// Assuming `expected` is a reference type, determine whether to peel it before matching.
fn should_peel_ref(&self, peel_kind: PeelKind, mut expected: Ty<'tcx>) -> bool {
debug_assert!(expected.is_ref());
let pat_ref_layers = match peel_kind {
PeelKind::ExplicitDerefPat => 0,
PeelKind::Implicit { pat_ref_layers, .. } => pat_ref_layers,
};
// Most patterns don't have reference types, so we'll want to peel all references from the
// scrutinee before matching. To optimize for the common case, return early.
if pat_ref_layers == 0 {
return true;
}
debug_assert!(
self.tcx.features().deref_patterns(),
"Peeling for patterns with reference types is gated by `deref_patterns`."
);
// If the pattern has as many or more layers of reference as the expected type, we can match
// without peeling more, unless we find a smart pointer or `&mut` that we also need to peel.
// We don't treat `&` and `&mut` as interchangeable, but by peeling `&mut`s before matching,
// we can still, e.g., match on a `&mut str` with a string literal pattern. This is because
// string literal patterns may be used where `str` is expected.
let mut expected_ref_layers = 0;
while let ty::Ref(_, inner_ty, mutbl) = *expected.kind() {
if mutbl.is_mut() {
// Mutable references can't be in the final value of constants, thus they can't be
// at the head of their types, thus we should always peel `&mut`.
return true;
}
expected_ref_layers += 1;
expected = inner_ty;
}
pat_ref_layers < expected_ref_layers || self.should_peel_smart_pointer(peel_kind, expected)
}
/// Determine whether `expected` is a smart pointer type that should be peeled before matching.
fn should_peel_smart_pointer(&self, peel_kind: PeelKind, expected: Ty<'tcx>) -> bool {
// Explicit `deref!(_)` patterns match against smart pointers; don't peel in that case.
if let PeelKind::Implicit { until_adt, .. } = peel_kind
// For simplicity, only apply overloaded derefs if `expected` is a known ADT.
// FIXME(deref_patterns): we'll get better diagnostics for users trying to
// implicitly deref generics if we allow them here, but primitives, tuples, and
// inference vars definitely should be stopped. Figure out what makes most sense.
&& let ty::Adt(scrutinee_adt, _) = *expected.kind()
// Don't peel if the pattern type already matches the scrutinee. E.g., stop here if
// matching on a `Cow<'a, T>` scrutinee with a `Cow::Owned(_)` pattern.
&& until_adt != Some(scrutinee_adt.did())
// At this point, the pattern isn't able to match `expected` without peeling. Check
// that it implements `Deref` before assuming it's a smart pointer, to get a normal
// type error instead of a missing impl error if not. This only checks for `Deref`,
// not `DerefPure`: we require that too, but we want a trait error if it's missing.
&& let Some(deref_trait) = self.tcx.lang_items().deref_trait()
&& self.type_implements_trait(deref_trait, [expected], self.param_env).may_apply()
{
true
} else {
false
}
}
fn check_pat_expr_unadjusted(&self, lt: &'tcx hir::PatExpr<'tcx>) -> Ty<'tcx> {
let ty = match &lt.kind {
rustc_hir::PatExprKind::Lit { lit, negated } => {

View file

@ -555,15 +555,16 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
}
}
if let Err(guar) = check_opaque_type_parameter_valid(
if let Err(err) = check_opaque_type_parameter_valid(
&self.fcx,
opaque_type_key,
hidden_type.span,
DefiningScopeKind::HirTypeck,
) {
self.typeck_results
.concrete_opaque_types
.insert(opaque_type_key.def_id, ty::OpaqueHiddenType::new_error(tcx, guar));
self.typeck_results.concrete_opaque_types.insert(
opaque_type_key.def_id,
ty::OpaqueHiddenType::new_error(tcx, err.report(self.fcx)),
);
}
let hidden_type = hidden_type.remap_generic_params_to_declaration_params(

View file

@ -38,7 +38,7 @@ use std::fs::{self, File};
use std::io::Write;
use rustc_data_structures::fx::FxIndexSet;
use rustc_data_structures::graph::implementation::{Direction, INCOMING, NodeIndex, OUTGOING};
use rustc_data_structures::graph::linked_graph::{Direction, INCOMING, NodeIndex, OUTGOING};
use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId};
use rustc_hir::intravisit::{self, Visitor};
use rustc_middle::dep_graph::{

View file

@ -44,10 +44,6 @@ pub(crate) fn save_dep_graph(tcx: TyCtxt<'_>) {
sess.time("assert_dep_graph", || assert_dep_graph(tcx));
sess.time("check_dirty_clean", || dirty_clean::check_dirty_clean_annotations(tcx));
if sess.opts.unstable_opts.incremental_info {
tcx.dep_graph.print_incremental_info()
}
join(
move || {
sess.time("incr_comp_persist_dep_graph", || {
@ -172,12 +168,5 @@ pub(crate) fn build_dep_graph(
// First encode the commandline arguments hash
sess.opts.dep_tracking_hash(false).encode(&mut encoder);
Some(DepGraph::new(
sess,
prev_graph,
prev_work_products,
encoder,
sess.opts.unstable_opts.query_dep_graph,
sess.opts.unstable_opts.incremental_info,
))
Some(DepGraph::new(sess, prev_graph, prev_work_products, encoder))
}

View file

@ -132,7 +132,13 @@ impl<'tcx> InferCtxt<'tcx> {
let certainty = if errors.is_empty() { Certainty::Proven } else { Certainty::Ambiguous };
let opaque_types = self.take_opaque_types_for_query_response();
let opaque_types = self
.inner
.borrow_mut()
.opaque_type_storage
.take_opaque_types()
.map(|(k, v)| (k, v.ty))
.collect();
Ok(QueryResponse {
var_values: inference_vars,
@ -143,24 +149,6 @@ impl<'tcx> InferCtxt<'tcx> {
})
}
/// Used by the new solver as that one takes the opaque types at the end of a probe
/// to deal with multiple candidates without having to recompute them.
pub fn clone_opaque_types_for_query_response(
&self,
) -> Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)> {
self.inner
.borrow()
.opaque_type_storage
.opaque_types
.iter()
.map(|(k, v)| (*k, v.ty))
.collect()
}
fn take_opaque_types_for_query_response(&self) -> Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)> {
self.take_opaque_types().into_iter().map(|(k, v)| (k, v.ty)).collect()
}
/// Given the (canonicalized) result to a canonical query,
/// instantiates the result so it can be used, plugging in the
/// values from the canonical query. (Note that the result may

View file

@ -121,19 +121,19 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> {
self.enter_forall(value, f)
}
fn equate_ty_vids_raw(&self, a: rustc_type_ir::TyVid, b: rustc_type_ir::TyVid) {
fn equate_ty_vids_raw(&self, a: ty::TyVid, b: ty::TyVid) {
self.inner.borrow_mut().type_variables().equate(a, b);
}
fn equate_int_vids_raw(&self, a: rustc_type_ir::IntVid, b: rustc_type_ir::IntVid) {
fn equate_int_vids_raw(&self, a: ty::IntVid, b: ty::IntVid) {
self.inner.borrow_mut().int_unification_table().union(a, b);
}
fn equate_float_vids_raw(&self, a: rustc_type_ir::FloatVid, b: rustc_type_ir::FloatVid) {
fn equate_float_vids_raw(&self, a: ty::FloatVid, b: ty::FloatVid) {
self.inner.borrow_mut().float_unification_table().union(a, b);
}
fn equate_const_vids_raw(&self, a: rustc_type_ir::ConstVid, b: rustc_type_ir::ConstVid) {
fn equate_const_vids_raw(&self, a: ty::ConstVid, b: ty::ConstVid) {
self.inner.borrow_mut().const_unification_table().union(a, b);
}
@ -141,8 +141,8 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> {
&self,
relation: &mut R,
target_is_expected: bool,
target_vid: rustc_type_ir::TyVid,
instantiation_variance: rustc_type_ir::Variance,
target_vid: ty::TyVid,
instantiation_variance: ty::Variance,
source_ty: Ty<'tcx>,
) -> RelateResult<'tcx, ()> {
self.instantiate_ty_var(
@ -154,19 +154,11 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> {
)
}
fn instantiate_int_var_raw(
&self,
vid: rustc_type_ir::IntVid,
value: rustc_type_ir::IntVarValue,
) {
fn instantiate_int_var_raw(&self, vid: ty::IntVid, value: ty::IntVarValue) {
self.inner.borrow_mut().int_unification_table().union_value(vid, value);
}
fn instantiate_float_var_raw(
&self,
vid: rustc_type_ir::FloatVid,
value: rustc_type_ir::FloatVarValue,
) {
fn instantiate_float_var_raw(&self, vid: ty::FloatVid, value: ty::FloatVarValue) {
self.inner.borrow_mut().float_unification_table().union_value(vid, value);
}
@ -174,7 +166,7 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> {
&self,
relation: &mut R,
target_is_expected: bool,
target_vid: rustc_type_ir::ConstVid,
target_vid: ty::ConstVid,
source_ct: ty::Const<'tcx>,
) -> RelateResult<'tcx, ()> {
self.instantiate_const_var(relation, target_is_expected, target_vid, source_ct)

View file

@ -3,8 +3,8 @@
use std::fmt;
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::graph::implementation::{
Direction, Graph, INCOMING, NodeIndex, OUTGOING,
use rustc_data_structures::graph::linked_graph::{
Direction, INCOMING, LinkedGraph, NodeIndex, OUTGOING,
};
use rustc_data_structures::intern::Interned;
use rustc_data_structures::unord::UnordSet;
@ -118,7 +118,7 @@ struct RegionAndOrigin<'tcx> {
origin: SubregionOrigin<'tcx>,
}
type RegionGraph<'tcx> = Graph<(), Constraint<'tcx>>;
type RegionGraph<'tcx> = LinkedGraph<(), Constraint<'tcx>>;
struct LexicalResolver<'cx, 'tcx> {
region_rels: &'cx RegionRelations<'cx, 'tcx>,
@ -668,7 +668,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
fn construct_graph(&self) -> RegionGraph<'tcx> {
let num_vars = self.num_vars();
let mut graph = Graph::new();
let mut graph = LinkedGraph::new();
for _ in 0..num_vars {
graph.add_node(());

View file

@ -31,9 +31,9 @@ use rustc_middle::traits::solve::Goal;
use rustc_middle::ty::error::{ExpectedFound, TypeError};
use rustc_middle::ty::{
self, BoundVarReplacerDelegate, ConstVid, FloatVid, GenericArg, GenericArgKind, GenericArgs,
GenericArgsRef, GenericParamDefKind, InferConst, IntVid, PseudoCanonicalInput, Term, TermKind,
Ty, TyCtxt, TyVid, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable,
TypeVisitableExt, TypingEnv, TypingMode, fold_regions,
GenericArgsRef, GenericParamDefKind, InferConst, IntVid, OpaqueHiddenType, OpaqueTypeKey,
PseudoCanonicalInput, Term, TermKind, Ty, TyCtxt, TyVid, TypeFoldable, TypeFolder,
TypeSuperFoldable, TypeVisitable, TypeVisitableExt, TypingEnv, TypingMode, fold_regions,
};
use rustc_span::{Span, Symbol};
use snapshot::undo_log::InferCtxtUndoLogs;
@ -198,7 +198,7 @@ impl<'tcx> InferCtxtInner<'tcx> {
}
#[inline]
fn opaque_types(&mut self) -> opaque_types::OpaqueTypeTable<'_, 'tcx> {
pub fn opaque_types(&mut self) -> opaque_types::OpaqueTypeTable<'_, 'tcx> {
self.opaque_type_storage.with_log(&mut self.undo_log)
}
@ -224,15 +224,6 @@ impl<'tcx> InferCtxtInner<'tcx> {
.expect("region constraints already solved")
.with_log(&mut self.undo_log)
}
// Iterates through the opaque type definitions without taking them; this holds the
// `InferCtxtInner` lock, so make sure to not do anything with `InferCtxt` side-effects
// while looping through this.
pub fn iter_opaque_types(
&self,
) -> impl Iterator<Item = (ty::OpaqueTypeKey<'tcx>, ty::OpaqueHiddenType<'tcx>)> {
self.opaque_type_storage.opaque_types.iter().map(|(&k, &v)| (k, v))
}
}
pub struct InferCtxt<'tcx> {
@ -954,13 +945,13 @@ impl<'tcx> InferCtxt<'tcx> {
}
#[instrument(level = "debug", skip(self), ret)]
pub fn take_opaque_types(&self) -> opaque_types::OpaqueTypeMap<'tcx> {
std::mem::take(&mut self.inner.borrow_mut().opaque_type_storage.opaque_types)
pub fn take_opaque_types(&self) -> Vec<(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)> {
self.inner.borrow_mut().opaque_type_storage.take_opaque_types().collect()
}
#[instrument(level = "debug", skip(self), ret)]
pub fn clone_opaque_types(&self) -> opaque_types::OpaqueTypeMap<'tcx> {
self.inner.borrow().opaque_type_storage.opaque_types.clone()
pub fn clone_opaque_types(&self) -> Vec<(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)> {
self.inner.borrow_mut().opaque_type_storage.iter_opaque_types().collect()
}
#[inline(always)]

View file

@ -1,5 +1,4 @@
use hir::def_id::{DefId, LocalDefId};
use rustc_data_structures::fx::FxIndexMap;
use rustc_hir as hir;
use rustc_middle::bug;
use rustc_middle::traits::ObligationCause;
@ -19,7 +18,6 @@ use crate::traits::{self, Obligation, PredicateObligations};
mod table;
pub(crate) type OpaqueTypeMap<'tcx> = FxIndexMap<OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>>;
pub(crate) use table::{OpaqueTypeStorage, OpaqueTypeTable};
impl<'tcx> InferCtxt<'tcx> {

View file

@ -1,18 +1,17 @@
use std::ops::Deref;
use rustc_data_structures::fx::FxIndexMap;
use rustc_data_structures::undo_log::UndoLogs;
use rustc_middle::bug;
use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey, Ty};
use tracing::instrument;
use super::OpaqueTypeMap;
use crate::infer::snapshot::undo_log::{InferCtxtUndoLogs, UndoLog};
#[derive(Default, Debug, Clone)]
pub(crate) struct OpaqueTypeStorage<'tcx> {
/// Opaque types found in explicit return types and their
/// associated fresh inference variable. Writeback resolves these
/// variables to get the concrete type, which can be used to
/// 'de-opaque' OpaqueHiddenType, after typeck is done with all functions.
pub opaque_types: OpaqueTypeMap<'tcx>,
pub struct OpaqueTypeStorage<'tcx> {
opaque_types: FxIndexMap<OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>>,
duplicate_entries: Vec<(OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)>,
}
impl<'tcx> OpaqueTypeStorage<'tcx> {
@ -33,6 +32,52 @@ impl<'tcx> OpaqueTypeStorage<'tcx> {
}
}
pub(crate) fn pop_duplicate_entry(&mut self) {
let entry = self.duplicate_entries.pop();
assert!(entry.is_some());
}
pub(crate) fn is_empty(&self) -> bool {
let OpaqueTypeStorage { opaque_types, duplicate_entries } = self;
opaque_types.is_empty() && duplicate_entries.is_empty()
}
pub(crate) fn take_opaque_types(
&mut self,
) -> impl Iterator<Item = (OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)> {
let OpaqueTypeStorage { opaque_types, duplicate_entries } = self;
std::mem::take(opaque_types).into_iter().chain(std::mem::take(duplicate_entries))
}
/// Only returns the opaque types from the lookup table. These are used
/// when normalizing opaque types and have a unique key.
///
/// Outside of canonicalization one should generally use `iter_opaque_types`
/// to also consider duplicate entries.
pub fn iter_lookup_table(
&self,
) -> impl Iterator<Item = (OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)> {
self.opaque_types.iter().map(|(k, v)| (*k, *v))
}
/// Only returns the opaque types which are stored in `duplicate_entries`.
///
/// These have to considered when checking all opaque type uses but are e.g.
/// irrelevant for canonical inputs as nested queries never meaningfully
/// accesses them.
pub fn iter_duplicate_entries(
&self,
) -> impl Iterator<Item = (OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)> {
self.duplicate_entries.iter().copied()
}
pub fn iter_opaque_types(
&self,
) -> impl Iterator<Item = (OpaqueTypeKey<'tcx>, OpaqueHiddenType<'tcx>)> {
let OpaqueTypeStorage { opaque_types, duplicate_entries } = self;
opaque_types.iter().map(|(k, v)| (*k, *v)).chain(duplicate_entries.iter().copied())
}
#[inline]
pub(crate) fn with_log<'a>(
&'a mut self,
@ -44,21 +89,27 @@ impl<'tcx> OpaqueTypeStorage<'tcx> {
impl<'tcx> Drop for OpaqueTypeStorage<'tcx> {
fn drop(&mut self) {
if !self.opaque_types.is_empty() {
if !self.is_empty() {
ty::tls::with(|tcx| tcx.dcx().delayed_bug(format!("{:?}", self.opaque_types)));
}
}
}
pub(crate) struct OpaqueTypeTable<'a, 'tcx> {
pub struct OpaqueTypeTable<'a, 'tcx> {
storage: &'a mut OpaqueTypeStorage<'tcx>,
undo_log: &'a mut InferCtxtUndoLogs<'tcx>,
}
impl<'tcx> Deref for OpaqueTypeTable<'_, 'tcx> {
type Target = OpaqueTypeStorage<'tcx>;
fn deref(&self) -> &Self::Target {
self.storage
}
}
impl<'a, 'tcx> OpaqueTypeTable<'a, 'tcx> {
#[instrument(skip(self), level = "debug")]
pub(crate) fn register(
pub fn register(
&mut self,
key: OpaqueTypeKey<'tcx>,
hidden_type: OpaqueHiddenType<'tcx>,
@ -72,4 +123,9 @@ impl<'a, 'tcx> OpaqueTypeTable<'a, 'tcx> {
self.undo_log.push(UndoLog::OpaqueTypes(key, None));
None
}
pub fn add_duplicate(&mut self, key: OpaqueTypeKey<'tcx>, hidden_type: OpaqueHiddenType<'tcx>) {
self.storage.duplicate_entries.push((key, hidden_type));
self.undo_log.push(UndoLog::DuplicateOpaqueType);
}
}

View file

@ -63,11 +63,11 @@ use rustc_data_structures::undo_log::UndoLogs;
use rustc_middle::bug;
use rustc_middle::mir::ConstraintCategory;
use rustc_middle::traits::query::NoSolution;
use rustc_middle::ty::outlives::{Component, push_outlives_components};
use rustc_middle::ty::{
self, GenericArgKind, GenericArgsRef, PolyTypeOutlivesPredicate, Region, Ty, TyCtxt,
TypeFoldable as _, TypeVisitableExt,
};
use rustc_type_ir::outlives::{Component, push_outlives_components};
use smallvec::smallvec;
use tracing::{debug, instrument};

View file

@ -1,7 +1,7 @@
use std::assert_matches::assert_matches;
use rustc_middle::ty::outlives::{Component, compute_alias_components_recursive};
use rustc_middle::ty::{self, OutlivesPredicate, Ty, TyCtxt};
use rustc_type_ir::outlives::{Component, compute_alias_components_recursive};
use smallvec::smallvec;
use tracing::{debug, instrument, trace};

View file

@ -1,7 +1,8 @@
use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::{self, Ty};
use rustc_middle::ty;
use super::InferCtxt;
use crate::infer::Term;
use crate::traits::{Obligation, PredicateObligations};
impl<'tcx> InferCtxt<'tcx> {
@ -11,24 +12,32 @@ impl<'tcx> InferCtxt<'tcx> {
/// of the given projection. This allows us to proceed with projections
/// while they cannot be resolved yet due to missing information or
/// simply due to the lack of access to the trait resolution machinery.
pub fn projection_ty_to_infer(
pub fn projection_term_to_infer(
&self,
param_env: ty::ParamEnv<'tcx>,
projection_ty: ty::AliasTy<'tcx>,
alias_term: ty::AliasTerm<'tcx>,
cause: ObligationCause<'tcx>,
recursion_depth: usize,
obligations: &mut PredicateObligations<'tcx>,
) -> Ty<'tcx> {
) -> Term<'tcx> {
debug_assert!(!self.next_trait_solver());
let ty_var = self.next_ty_var(self.tcx.def_span(projection_ty.def_id));
let span = self.tcx.def_span(alias_term.def_id);
let infer_var = if alias_term.kind(self.tcx).is_type() {
self.next_ty_var(span).into()
} else {
self.next_const_var(span).into()
};
let projection =
ty::PredicateKind::Clause(ty::ClauseKind::Projection(ty::ProjectionPredicate {
projection_term: projection_ty.into(),
term: ty_var.into(),
projection_term: alias_term,
term: infer_var,
}));
let obligation =
Obligation::with_depth(self.tcx, cause, recursion_depth, param_env, projection);
obligations.push(obligation);
ty_var
infer_var
}
}

View file

@ -2,9 +2,8 @@
//! (except for some relations used for diagnostics and heuristics in the compiler).
//! As well as the implementation of `Relate` for interned things (`Ty`/`Const`/etc).
pub use rustc_middle::ty::relate::RelateResult;
pub use rustc_type_ir::relate::combine::PredicateEmittingRelation;
pub use rustc_type_ir::relate::*;
pub use rustc_middle::ty::relate::combine::PredicateEmittingRelation;
pub use rustc_middle::ty::relate::{RelateResult, *};
mod generalize;
mod higher_ranked;

View file

@ -3,9 +3,8 @@ use rustc_middle::ty::relate::combine::{super_combine_consts, super_combine_tys}
use rustc_middle::ty::relate::{
Relate, RelateResult, TypeRelation, relate_args_invariantly, relate_args_with_variances,
};
use rustc_middle::ty::{self, Ty, TyCtxt, TyVar};
use rustc_middle::ty::{self, DelayedSet, Ty, TyCtxt, TyVar};
use rustc_span::Span;
use rustc_type_ir::data_structures::DelayedSet;
use tracing::{debug, instrument};
use crate::infer::BoundRegionConversionTime::HigherRankedType;

View file

@ -1,9 +1,8 @@
use rustc_middle::bug;
use rustc_middle::ty::{
self, Const, FallibleTypeFolder, InferConst, Ty, TyCtxt, TypeFoldable, TypeFolder,
self, Const, DelayedMap, FallibleTypeFolder, InferConst, Ty, TyCtxt, TypeFoldable, TypeFolder,
TypeSuperFoldable, TypeVisitableExt,
};
use rustc_type_ir::data_structures::DelayedMap;
use super::{FixupError, FixupResult, InferCtxt};

View file

@ -3,9 +3,8 @@ use std::ops::Range;
use rustc_data_structures::{snapshot_vec as sv, unify as ut};
use rustc_middle::ty::{
self, ConstVid, FloatVid, IntVid, RegionVid, Ty, TyCtxt, TyVid, TypeFoldable, TypeFolder,
TypeSuperFoldable,
TypeSuperFoldable, TypeVisitableExt,
};
use rustc_type_ir::TypeVisitableExt;
use tracing::instrument;
use ut::UnifyKey;

View file

@ -17,6 +17,7 @@ pub struct Snapshot<'tcx> {
/// Records the "undo" data for a single operation that affects some form of inference variable.
#[derive(Clone)]
pub(crate) enum UndoLog<'tcx> {
DuplicateOpaqueType,
OpaqueTypes(OpaqueTypeKey<'tcx>, Option<OpaqueHiddenType<'tcx>>),
TypeVariables(sv::UndoLog<ut::Delegate<type_variable::TyVidEqKey<'tcx>>>),
ConstUnificationTable(sv::UndoLog<ut::Delegate<ConstVidKey<'tcx>>>),
@ -58,6 +59,7 @@ impl_from! {
impl<'tcx> Rollback<UndoLog<'tcx>> for InferCtxtInner<'tcx> {
fn reverse(&mut self, undo: UndoLog<'tcx>) {
match undo {
UndoLog::DuplicateOpaqueType => self.opaque_type_storage.pop_duplicate_entry(),
UndoLog::OpaqueTypes(key, idx) => self.opaque_type_storage.remove(key, idx),
UndoLog::TypeVariables(undo) => self.type_variable_storage.reverse(undo),
UndoLog::ConstUnificationTable(undo) => self.const_unification_storage.reverse(undo),

View file

@ -1,7 +1,7 @@
use rustc_data_structures::fx::FxHashSet;
pub use rustc_middle::ty::elaborate::*;
use rustc_middle::ty::{self, TyCtxt};
use rustc_span::{Ident, Span};
pub use rustc_type_ir::elaborate::*;
use crate::traits::{self, Obligation, ObligationCauseCode, PredicateObligation};

Some files were not shown because too many files have changed in this diff Show more