diff --git a/Cargo.lock b/Cargo.lock index 54b1bf593e0a2..58d95f927bf95 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -131,9 +131,9 @@ dependencies = [ [[package]] name = "annotate-snippets" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5a59f105fb9635e9eebdc1e29d53e764fa5795b9cf899a638a53e61567ef61" +checksum = "086b0afab3b349e5691143adbfb26983821e3eec4ba4c51957104d372c2e1b7d" dependencies = [ "anstyle", "unicode-width", @@ -189,9 +189,9 @@ dependencies = [ [[package]] name = "anstyle-query" -version = "1.0.3" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a64c907d4e79225ac72e2a354c9ce84d50ebb4586dee56c82b3ee73004f537f5" +checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391" dependencies = [ "windows-sys 0.52.0", ] @@ -266,7 +266,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.64", + "syn 2.0.66", ] [[package]] @@ -501,9 +501,9 @@ version = "0.1.0" [[package]] name = "cc" -version = "1.0.97" +version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "099a5357d84c4c61eb35fc8eafa9a79a902c2f76911e5747ced4e032edd8d9b4" +checksum = "96c51067fd44124faa7f870b4b1c969379ad32b2ba805aa959430ceaa384f695" [[package]] name = "cfg-if" @@ -568,9 +568,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.4" +version = "4.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" +checksum = "a9689a29b593160de5bc4aacab7b5d54fb52231de70122626c178e6a368994c7" dependencies = [ "clap_builder", "clap_derive", @@ -588,9 +588,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.2" +version = "4.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" +checksum = "2e5387378c84f6faa26890ebf9f0a92989f8873d4d380467bcd0d8d8620424df" dependencies = [ "anstream", "anstyle", @@ -601,30 +601,30 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.5.2" +version = "4.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd79504325bf38b10165b02e89b4347300f855f273c4cb30c4a3209e6583275e" +checksum = "d2020fa13af48afc65a9a87335bda648309ab3d154cd03c7ff95b378c7ed39c4" dependencies = [ "clap", ] [[package]] name = "clap_derive" -version = "4.5.4" +version = "4.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" +checksum = "c780290ccf4fb26629baa7a1081e68ced113f1d3ec302fa5948f1c381ebf06c6" dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.64", + "syn 2.0.66", ] [[package]] name = "clap_lex" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" +checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70" [[package]] name = "clippy" @@ -644,7 +644,7 @@ dependencies = [ "regex", "rustc_tools_util", "serde", - "syn 2.0.64", + "syn 2.0.66", "tempfile", "termize", "tokio", @@ -754,7 +754,7 @@ dependencies = [ "nom", "proc-macro2", "quote", - "syn 2.0.64", + "syn 2.0.66", ] [[package]] @@ -878,18 +878,18 @@ dependencies = [ [[package]] name = "crc32fast" -version = "1.4.0" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" dependencies = [ "cfg-if", ] [[package]] name = "crossbeam-channel" -version = "0.5.12" +version = "0.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab3db02a9c5b5121e1e42fbdb1aeb65f5e02624cc58c43f2884c6ccac0b82f95" +checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" dependencies = [ "crossbeam-utils", ] @@ -915,9 +915,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.19" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" [[package]] name = "crypto-common" @@ -990,7 +990,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.64", + "syn 2.0.66", ] [[package]] @@ -1001,7 +1001,7 @@ checksum = "733cabb43482b1a1b53eee8583c2b9e8684d592215ea83efd305dd31bc2f0178" dependencies = [ "darling_core", "quote", - "syn 2.0.64", + "syn 2.0.66", ] [[package]] @@ -1027,7 +1027,7 @@ version = "0.1.80" dependencies = [ "itertools 0.12.1", "quote", - "syn 2.0.64", + "syn 2.0.66", ] [[package]] @@ -1068,7 +1068,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.64", + "syn 2.0.66", ] [[package]] @@ -1078,7 +1078,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "206868b8242f27cecce124c19fd88157fbd0dd334df2587f36417bafbc85097b" dependencies = [ "derive_builder_core", - "syn 2.0.64", + "syn 2.0.66", ] [[package]] @@ -1101,7 +1101,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.64", + "syn 2.0.66", ] [[package]] @@ -1196,7 +1196,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.64", + "syn 2.0.66", ] [[package]] @@ -1516,7 +1516,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.64", + "syn 2.0.66", ] [[package]] @@ -1588,9 +1588,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "libc", @@ -1757,7 +1757,7 @@ dependencies = [ "markup5ever 0.12.1", "proc-macro2", "quote", - "syn 2.0.64", + "syn 2.0.66", ] [[package]] @@ -1800,9 +1800,9 @@ dependencies = [ [[package]] name = "icu_list" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe6c04ec71ad1bacdbfb47164d4801f80a0533d9340f94f1a880f521eff59f54" +checksum = "bbfeda1d7775b6548edd4e8b7562304a559a91ed56ab56e18961a053f367c365" dependencies = [ "displaydoc", "icu_list_data", @@ -1814,15 +1814,15 @@ dependencies = [ [[package]] name = "icu_list_data" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f6afcf7a9a7fedece70b7f17d7a7ecdfb8df145d37ae46d0277cd1e3932532" +checksum = "e1825170d2c6679cb20dbd96a589d034e49f698aed9a2ef4fafc9a0101ed298f" [[package]] name = "icu_locid" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c0aa2536adc14c07e2a521e95512b75ed8ef832f0fdf9299d4a0a45d2be2a9d" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" dependencies = [ "displaydoc", "litemap", @@ -1833,9 +1833,9 @@ dependencies = [ [[package]] name = "icu_locid_transform" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c17d8f6524fdca4471101dd71f0a132eb6382b5d6d7f2970441cb25f6f435a" +checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" dependencies = [ "displaydoc", "icu_locid", @@ -1847,15 +1847,15 @@ dependencies = [ [[package]] name = "icu_locid_transform_data" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "545c6c3e8bf9580e2dafee8de6f9ec14826aaf359787789c7724f1f85f47d3dc" +checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" [[package]] name = "icu_provider" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba58e782287eb6950247abbf11719f83f5d4e4a5c1f2cd490d30a334bc47c2f4" +checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" dependencies = [ "displaydoc", "icu_locid", @@ -1870,9 +1870,9 @@ dependencies = [ [[package]] name = "icu_provider_adapters" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a229f978260da7c3aabb68cb7dc7316589936680570fe55e50fdd3f97711a4dd" +checksum = "d6324dfd08348a8e0374a447ebd334044d766b1839bb8d5ccf2482a99a77c0bc" dependencies = [ "icu_locid", "icu_locid_transform", @@ -1883,13 +1883,13 @@ dependencies = [ [[package]] name = "icu_provider_macros" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2abdd3a62551e8337af119c5899e600ca0c88ec8f23a46c60ba216c803dcf1a" +checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.64", + "syn 2.0.66", ] [[package]] @@ -2196,9 +2196,9 @@ dependencies = [ [[package]] name = "libz-sys" -version = "1.1.16" +version = "1.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e143b5e666b2695d28f6bca6497720813f699c9602dd7f5cac91008b8ada7f9" +checksum = "c15da26e5af7e25c90b37a2d75cdbf940cf4a55316de9d84c679c9b8bfabf82e" dependencies = [ "cc", "libc", @@ -2252,9 +2252,9 @@ checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" [[package]] name = "litemap" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9d642685b028806386b2b6e75685faadd3eb65a85fff7df711ce18446a422da" +checksum = "643cb0b8d4fcc284004d5fd0d67ccf61dfffadb7f75e1e71bc420f4688a3a704" [[package]] name = "lld-wrapper" @@ -2415,7 +2415,7 @@ dependencies = [ "pulldown-cmark-to-cmark", "serde_json", "thiserror", - "toml 0.8.13", + "toml 0.8.14", "xmlparser", ] @@ -2608,9 +2608,9 @@ dependencies = [ [[package]] name = "nu-ansi-term" -version = "0.49.0" +version = "0.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c073d3c1930d0751774acf49e66653acecb416c3a54c6ec095a9b11caddb5a68" +checksum = "dd2800e1520bdc966782168a627aa5d1ad92e33b984bf7c7615d31280c83ff14" dependencies = [ "windows-sys 0.48.0", ] @@ -2849,9 +2849,9 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.12.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e4af0ca4f6caed20e900d564c242b8e5d4903fdacf31d3daf527b66fe6f42fb" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", "parking_lot_core", @@ -2931,7 +2931,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.64", + "syn 2.0.66", ] [[package]] @@ -3142,9 +3142,9 @@ checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" [[package]] name = "proc-macro2" -version = "1.0.82" +version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ad3d49ab951a01fbaafe34f2ec74122942fe18a3f9814c3268f1bb72042131b" +checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23" dependencies = [ "unicode-ident", ] @@ -3246,9 +3246,9 @@ dependencies = [ [[package]] name = "r-efi" -version = "4.4.0" +version = "4.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c47196f636c4cc0634b73b0405323d177753c2e15e866952c64ea22902567a34" +checksum = "e9e935efc5854715dfc0a4c9ef18dc69dee0ec3bf9cc3ab740db831c0fdd86a3" dependencies = [ "compiler_builtins", "rustc-std-workspace-core", @@ -4058,7 +4058,7 @@ dependencies = [ "fluent-syntax", "proc-macro2", "quote", - "syn 2.0.64", + "syn 2.0.66", "unic-langid", ] @@ -4192,7 +4192,7 @@ version = "0.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.64", + "syn 2.0.66", "synstructure", ] @@ -4341,7 +4341,7 @@ version = "0.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.64", + "syn 2.0.66", "synstructure", ] @@ -4920,7 +4920,7 @@ version = "0.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.64", + "syn 2.0.66", "synstructure", ] @@ -5018,7 +5018,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.64", + "syn 2.0.66", ] [[package]] @@ -5154,22 +5154,22 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.202" +version = "1.0.203" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "226b61a0d411b2ba5ff6d7f73a476ac4f8bb900373459cd00fab8512828ba395" +checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.202" +version = "1.0.203" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6048858004bcff69094cd972ed40a32500f153bd3be9f716b2eed2e8217c4838" +checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" dependencies = [ "proc-macro2", "quote", - "syn 2.0.64", + "syn 2.0.66", ] [[package]] @@ -5281,9 +5281,9 @@ dependencies = [ [[package]] name = "spanned" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccdf4f5590b7e6fbd4f2e80d442789079a6fff7c12ef921a9de358b7b353098e" +checksum = "ed14ba8b4b82241bd5daba2c49185d4a0581a0058355fe96537338f002b8605d" dependencies = [ "bstr", "color-eyre", @@ -5463,9 +5463,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.64" +version = "2.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ad3dee41f36859875573074334c200d1add8e4a87bb37113ebd31d926b7b11f" +checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" dependencies = [ "proc-macro2", "quote", @@ -5480,7 +5480,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn 2.0.64", + "syn 2.0.66", ] [[package]] @@ -5540,9 +5540,9 @@ dependencies = [ [[package]] name = "tar" -version = "0.4.40" +version = "0.4.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b16afcea1f22891c49a00c751c7b63b2233284064f11a200fc624137c51e2ddb" +checksum = "cb797dad5fb5b76fcf519e702f4a589483b5ef06567f160c392832c1f5e44909" dependencies = [ "filetime", "libc", @@ -5659,7 +5659,7 @@ checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" dependencies = [ "proc-macro2", "quote", - "syn 2.0.64", + "syn 2.0.66", ] [[package]] @@ -5744,9 +5744,9 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.7.5" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83c02bf3c538ab32ba913408224323915f4ef9a6d61c0e85d493f355921c0ece" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" dependencies = [ "displaydoc", "zerovec", @@ -5769,9 +5769,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.37.0" +version = "1.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" +checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a" dependencies = [ "backtrace", "bytes", @@ -5801,14 +5801,14 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.13" +version = "0.8.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4e43f8cc456c9704c851ae29c67e17ef65d2c30017c17a9765b89c382dc8bba" +checksum = "6f49eb2ab21d2f26bd6db7bf383edc527a7ebaee412d17af4d40fdccd442f335" dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit 0.22.13", + "toml_edit 0.22.14", ] [[package]] @@ -5835,15 +5835,15 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.22.13" +version = "0.22.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c127785850e8c20836d49732ae6abfa47616e60bf9d9f57c43c250361a9db96c" +checksum = "f21c7aaf97f1bd9ca9d4f9e73b0a6c74bd5afef56f2bc931943a6e1c37e04e38" dependencies = [ "indexmap", "serde", "serde_spanned", "toml_datetime", - "winnow 0.6.8", + "winnow 0.6.13", ] [[package]] @@ -5872,7 +5872,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.64", + "syn 2.0.66", ] [[package]] @@ -5927,11 +5927,11 @@ dependencies = [ [[package]] name = "tracing-tree" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65139ecd2c3f6484c3b99bc01c77afe21e95473630747c7aca525e78b0666675" +checksum = "b56c62d2c80033cb36fae448730a2f2ef99410fe3ecbffc916681a32f6807dbe" dependencies = [ - "nu-ansi-term 0.49.0", + "nu-ansi-term 0.50.0", "tracing-core", "tracing-log", "tracing-subscriber", @@ -6011,7 +6011,7 @@ version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29e5f4ffcbab82453958fbf59990e981b8e8a177dcd60c2bd8f9b52c3036a6e1" dependencies = [ - "annotate-snippets 0.11.2", + "annotate-snippets 0.11.3", "anyhow", "bstr", "cargo-platform", @@ -6072,7 +6072,7 @@ checksum = "1ed7f4237ba393424195053097c1516bd4590dc82b84f2f97c5c69e12704555b" dependencies = [ "proc-macro-hack", "quote", - "syn 2.0.64", + "syn 2.0.66", "unic-langid-impl", ] @@ -6143,9 +6143,9 @@ checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" [[package]] name = "unicode-width" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68f5e5f3158ecfd4b8ff6fe086db7c8467a2dfdac97fe420f2b7c4aa97af66d6" +checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" dependencies = [ "compiler_builtins", "rustc-std-workspace-core", @@ -6222,9 +6222,9 @@ checksum = "86bd8d4e895da8537e5315b8254664e6b769c4ff3db18321b297a1e7004392e3" [[package]] name = "utf8parse" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" @@ -6304,7 +6304,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.64", + "syn 2.0.66", "wasm-bindgen-shared", ] @@ -6326,7 +6326,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.64", + "syn 2.0.66", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -6407,7 +6407,7 @@ dependencies = [ "rayon", "serde", "serde_json", - "syn 2.0.64", + "syn 2.0.66", "windows-metadata", ] @@ -6576,18 +6576,18 @@ dependencies = [ [[package]] name = "winnow" -version = "0.6.8" +version = "0.6.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3c52e9c97a68071b23e836c9380edae937f17b9c4667bd021973efc689f618d" +checksum = "59b5e5f6c299a3c7890b876a2a587f3115162487e704907d9b6cd29473052ba1" dependencies = [ "memchr", ] [[package]] name = "writeable" -version = "0.5.4" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dad7bb64b8ef9c0aa27b6da38b452b0ee9fd82beaf276a87dd796fb55cbae14e" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" [[package]] name = "xattr" @@ -6635,9 +6635,9 @@ dependencies = [ [[package]] name = "yoke" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65e71b2e4f287f467794c671e2b8f8a5f3716b3c829079a1c44740148eff07e4" +checksum = "6c5b1314b079b0930c31e3af543d8ee1757b1951ae1e1565ec704403a7240ca5" dependencies = [ "serde", "stable_deref_trait", @@ -6647,13 +6647,13 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e6936f0cce458098a201c245a11bef556c6a0181129c7034d10d76d1ec3a2b8" +checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95" dependencies = [ "proc-macro2", "quote", - "syn 2.0.64", + "syn 2.0.66", "synstructure", ] @@ -6674,35 +6674,35 @@ checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.64", + "syn 2.0.66", ] [[package]] name = "zerofrom" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "655b0814c5c0b19ade497851070c640773304939a6c0fd5f5fb43da0696d05b7" +checksum = "91ec111ce797d0e0784a1116d0ddcdbea84322cd79e5d5ad173daeba4f93ab55" dependencies = [ "zerofrom-derive", ] [[package]] name = "zerofrom-derive" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6a647510471d372f2e6c2e6b7219e44d8c574d24fdc11c610a61455782f18c3" +checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.64", + "syn 2.0.66", "synstructure", ] [[package]] name = "zerovec" -version = "0.10.1" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eff4439ae91fb5c72b8abc12f3f2dbf51bd27e6eadb9f8a5bc8898dddb0e27ea" +checksum = "bb2cc8827d6c0994478a15c53f374f46fbd41bea663d809b14744bc42e6b109c" dependencies = [ "yoke", "zerofrom", @@ -6711,11 +6711,11 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.10.1" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b4e5997cbf58990550ef1f0e5124a05e47e1ebd33a84af25739be6031a62c20" +checksum = "97cf56601ee5052b4417d90c8755c6683473c926039908196cf35d99f893ebe7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.64", + "syn 2.0.66", ] diff --git a/RELEASES.md b/RELEASES.md index 3080f03c7210b..c1311ab14c534 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,131 @@ +Version 1.79.0 (2024-06-13) +========================== + + + +Language +-------- +- [Stabilize inline `const {}` expressions.](https://github.com/rust-lang/rust/pull/104087/) +- [Prevent opaque types being instantiated twice with different regions within the same function.](https://github.com/rust-lang/rust/pull/116935/) +- [Stabilize WebAssembly target features that are in phase 4 and 5.](https://github.com/rust-lang/rust/pull/117457/) +- [Add the `redundant_lifetimes` lint to detect lifetimes which are semantically redundant.](https://github.com/rust-lang/rust/pull/118391/) +- [Stabilize the `unnameable_types` lint for public types that can't be named.](https://github.com/rust-lang/rust/pull/120144/) +- [Enable debuginfo in macros, and stabilize `-C collapse-macro-debuginfo` and `#[collapse_debuginfo]`.](https://github.com/rust-lang/rust/pull/120845/) +- [Propagate temporary lifetime extension into `if` and `match` expressions.](https://github.com/rust-lang/rust/pull/121346/) +- [Restrict promotion of `const fn` calls.](https://github.com/rust-lang/rust/pull/121557/) +- [Warn against refining impls of crate-private traits with `refining_impl_trait` lint.](https://github.com/rust-lang/rust/pull/121720/) +- [Stabilize associated type bounds (RFC 2289).](https://github.com/rust-lang/rust/pull/122055/) +- [Stabilize importing `main` from other modules or crates.](https://github.com/rust-lang/rust/pull/122060/) +- [Check return types of function types for well-formedness](https://github.com/rust-lang/rust/pull/115538) +- [Rework `impl Trait` lifetime inference](https://github.com/rust-lang/rust/pull/116891/) +- [Change inductive trait solver cycles to be ambiguous](https://github.com/rust-lang/rust/pull/122791) + + + +Compiler +-------- +- [Define `-C strip` to only affect binaries, not artifacts like `.pdb`.](https://github.com/rust-lang/rust/pull/115120/) +- [Stabilize `-Crelro-level` for controlling runtime link hardening.](https://github.com/rust-lang/rust/pull/121694/) +- [Stabilize checking of `cfg` names and values at compile-time with `--check-cfg`.](https://github.com/rust-lang/rust/pull/123501/) + *Note that this only stabilizes the compiler part, the Cargo part is still unstable in this release.* +- [Add `aarch64-apple-visionos` and `aarch64-apple-visionos-sim` tier 3 targets.](https://github.com/rust-lang/rust/pull/121419/) +- [Add `riscv32ima-unknown-none-elf` tier 3 target.](https://github.com/rust-lang/rust/pull/122696/) +- [Promote several Windows targets to tier 2](https://github.com/rust-lang/rust/pull/121712): `aarch64-pc-windows-gnullvm`, `i686-pc-windows-gnullvm`, and `x86_64-pc-windows-gnullvm`. + +Refer to Rust's [platform support page][platform-support-doc] +for more information on Rust's tiered platform support. + + + +Libraries +--------- + +- [Implement `FromIterator` for `(impl Default + Extend, impl Default + Extend)`.](https://github.com/rust-lang/rust/pull/107462/) +- [Implement `{Div,Rem}Assign>` on `X`.](https://github.com/rust-lang/rust/pull/121952/) +- [Document overrides of `clone_from()` in core/std.](https://github.com/rust-lang/rust/pull/122201/) +- [Link MSVC default lib in core.](https://github.com/rust-lang/rust/pull/122268/) +- [Caution against using `transmute` between pointers and integers.](https://github.com/rust-lang/rust/pull/122379/) +- [Enable frame pointers for the standard library.](https://github.com/rust-lang/rust/pull/122646/) + + + +Stabilized APIs +--------------- + +- [`{integer}::unchecked_add`](https://doc.rust-lang.org/stable/core/primitive.i32.html#method.unchecked_add) +- [`{integer}::unchecked_mul`](https://doc.rust-lang.org/stable/core/primitive.i32.html#method.unchecked_mul) +- [`{integer}::unchecked_sub`](https://doc.rust-lang.org/stable/core/primitive.i32.html#method.unchecked_sub) +- [`<[T]>::split_at_unchecked`](https://doc.rust-lang.org/stable/core/primitive.slice.html#method.split_at_unchecked) +- [`<[T]>::split_at_mut_unchecked`](https://doc.rust-lang.org/stable/core/primitive.slice.html#method.split_at_mut_unchecked) +- [`<[u8]>::utf8_chunks`](https://doc.rust-lang.org/stable/core/primitive.slice.html#method.utf8_chunks) +- [`str::Utf8Chunks`](https://doc.rust-lang.org/stable/core/str/struct.Utf8Chunks.html) +- [`str::Utf8Chunk`](https://doc.rust-lang.org/stable/core/str/struct.Utf8Chunk.html) +- [`<*const T>::is_aligned`](https://doc.rust-lang.org/stable/core/primitive.pointer.html#method.is_aligned) +- [`<*mut T>::is_aligned`](https://doc.rust-lang.org/stable/core/primitive.pointer.html#method.is_aligned-1) +- [`NonNull::is_aligned`](https://doc.rust-lang.org/stable/core/ptr/struct.NonNull.html#method.is_aligned) +- [`<*const [T]>::len`](https://doc.rust-lang.org/stable/core/primitive.pointer.html#method.len) +- [`<*mut [T]>::len`](https://doc.rust-lang.org/stable/core/primitive.pointer.html#method.len-1) +- [`<*const [T]>::is_empty`](https://doc.rust-lang.org/stable/core/primitive.pointer.html#method.is_empty) +- [`<*mut [T]>::is_empty`](https://doc.rust-lang.org/stable/core/primitive.pointer.html#method.is_empty-1) +- [`NonNull::<[T]>::is_empty`](https://doc.rust-lang.org/stable/core/ptr/struct.NonNull.html#method.is_empty) +- [`CStr::count_bytes`](https://doc.rust-lang.org/stable/core/ffi/c_str/struct.CStr.html#method.count_bytes) +- [`io::Error::downcast`](https://doc.rust-lang.org/stable/std/io/struct.Error.html#method.downcast) +- [`num::NonZero`](https://doc.rust-lang.org/stable/core/num/struct.NonZero.html) +- [`path::absolute`](https://doc.rust-lang.org/stable/std/path/fn.absolute.html) +- [`proc_macro::Literal::byte_character`](https://doc.rust-lang.org/stable/proc_macro/struct.Literal.html#method.byte_character) +- [`proc_macro::Literal::c_string`](https://doc.rust-lang.org/stable/proc_macro/struct.Literal.html#method.c_string) + +These APIs are now stable in const contexts: + +- [`Atomic*::into_inner`](https://doc.rust-lang.org/stable/core/sync/atomic/struct.AtomicUsize.html#method.into_inner) +- [`io::Cursor::new`](https://doc.rust-lang.org/stable/std/io/struct.Cursor.html#method.new) +- [`io::Cursor::get_ref`](https://doc.rust-lang.org/stable/std/io/struct.Cursor.html#method.get_ref) +- [`io::Cursor::position`](https://doc.rust-lang.org/stable/std/io/struct.Cursor.html#method.position) +- [`io::empty`](https://doc.rust-lang.org/stable/std/io/fn.empty.html) +- [`io::repeat`](https://doc.rust-lang.org/stable/std/io/fn.repeat.html) +- [`io::sink`](https://doc.rust-lang.org/stable/std/io/fn.sink.html) +- [`panic::Location::caller`](https://doc.rust-lang.org/stable/std/panic/struct.Location.html#method.caller) +- [`panic::Location::file`](https://doc.rust-lang.org/stable/std/panic/struct.Location.html#method.file) +- [`panic::Location::line`](https://doc.rust-lang.org/stable/std/panic/struct.Location.html#method.line) +- [`panic::Location::column`](https://doc.rust-lang.org/stable/std/panic/struct.Location.html#method.column) + + + +Cargo +----- + +- [Prevent dashes in `lib.name`, always normalizing to `_`.](https://github.com/rust-lang/cargo/pull/12783/) +- [Stabilize MSRV-aware version requirement selection in `cargo add`.](https://github.com/rust-lang/cargo/pull/13608/) +- [Switch to using `gitoxide` by default for listing files.](https://github.com/rust-lang/cargo/pull/13696/) +- [Error on `[project]` in Edition 2024; `cargo fix --edition` will change it to `[package]`.](https://github.com/rust-lang/cargo/pull/13747/) + + + +Rustdoc +----- + +- [Always display stability version even if it's the same as the containing item.](https://github.com/rust-lang/rust/pull/118441/) +- [Show a single search result for items with multiple paths.](https://github.com/rust-lang/rust/pull/119912/) +- [Support typing `/` in docs to begin a search.](https://github.com/rust-lang/rust/pull/123355/) + + + +Misc +---- + + + +Compatibility Notes +------------------- + +- [Update the minimum external LLVM to 17.](https://github.com/rust-lang/rust/pull/122649/) +- [`RustcEncodable` and `RustcDecodable` are soft-destabilized, to be removed + from the prelude in next edition.](https://github.com/rust-lang/rust/pull/116016/) +- [The `wasm_c_abi` future-incompatibility lint will warn about use of the + non-spec-compliant C ABI.](https://github.com/rust-lang/rust/pull/117918/) + Use `wasm-bindgen v0.2.88` to generate forward-compatible bindings. +- [Check return types of function types for well-formedness](https://github.com/rust-lang/rust/pull/115538) + Version 1.78.0 (2024-05-02) ========================== diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index 963e5de91cefe..6d26ca0b899b2 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -832,9 +832,10 @@ fn codegen_stmt<'tcx>( let val = match null_op { NullOp::SizeOf => layout.size.bytes(), NullOp::AlignOf => layout.align.abi.bytes(), - NullOp::OffsetOf(fields) => { - layout.offset_of_subfield(fx, fields.iter()).bytes() - } + NullOp::OffsetOf(fields) => fx + .tcx + .offset_of_subfield(ParamEnv::reveal_all(), layout, fields.iter()) + .bytes(), NullOp::UbChecks => { let val = fx.tcx.sess.ub_checks(); let val = CValue::by_val( diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 7b1038d561765..ad4e753fe9d77 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -1109,10 +1109,12 @@ fn generic_simd_intrinsic<'ll, 'tcx>( tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), callee_ty.fn_sig(tcx)); let arg_tys = sig.inputs(); - // Vectors must be immediates (non-power-of-2 #[repr(packed)] are not) - for (ty, arg) in arg_tys.iter().zip(args) { - if ty.is_simd() && !matches!(arg.val, OperandValue::Immediate(_)) { - return_error!(InvalidMonomorphization::SimdArgument { span, name, ty: *ty }); + // Sanity-check: all vector arguments must be immediates. + if cfg!(debug_assertions) { + for (ty, arg) in arg_tys.iter().zip(args) { + if ty.is_simd() { + assert!(matches!(arg.val, OperandValue::Immediate(_))); + } } } diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index c23867be3a10d..ad6b3f1159dec 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -680,7 +680,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx.cx().const_usize(val) } mir::NullOp::OffsetOf(fields) => { - let val = layout.offset_of_subfield(bx.cx(), fields.iter()).bytes(); + let val = bx + .tcx() + .offset_of_subfield(bx.param_env(), layout, fields.iter()) + .bytes(); bx.cx().const_usize(val) } mir::NullOp::UbChecks => { diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index d0bb821862aa2..1baf62baa816f 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -253,7 +253,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { Scalar::from_target_usize(val, self) } mir::NullOp::OffsetOf(fields) => { - let val = layout.offset_of_subfield(self, fields.iter()).bytes(); + let val = self + .tcx + .offset_of_subfield(self.param_env, layout, fields.iter()) + .bytes(); Scalar::from_target_usize(val, self) } mir::NullOp::UbChecks => Scalar::from_bool(self.tcx.sess.ub_checks()), diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index d67422849d8a6..2410019868a19 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -559,6 +559,8 @@ declare_features! ( (unstable, offset_of_enum, "1.75.0", Some(120141)), /// Allows using multiple nested field accesses in offset_of! (unstable, offset_of_nested, "1.77.0", Some(120140)), + /// Allows using fields with slice type in offset_of! + (unstable, offset_of_slice, "CURRENT_RUSTC_VERSION", Some(126151)), /// Allows using `#[optimize(X)]`. (unstable, optimize_attribute, "1.34.0", Some(54882)), /// Allows postfix match `expr.match { ... }` diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index d5d360ca0479f..5b27ebe3416ae 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -3363,7 +3363,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let field_ty = self.field_ty(expr.span, field, args); - // FIXME: DSTs with static alignment should be allowed + // Enums are anyway always sized. But just to safeguard against future + // language extensions, let's double-check. self.require_type_is_sized(field_ty, expr.span, ObligationCauseCode::Misc); if field.vis.is_accessible_from(sub_def_scope, self.tcx) { @@ -3391,8 +3392,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { let field_ty = self.field_ty(expr.span, field, args); - // FIXME: DSTs with static alignment should be allowed - self.require_type_is_sized(field_ty, expr.span, ObligationCauseCode::Misc); + if self.tcx.features().offset_of_slice { + self.require_type_has_static_alignment( + field_ty, + expr.span, + ObligationCauseCode::Misc, + ); + } else { + self.require_type_is_sized( + field_ty, + expr.span, + ObligationCauseCode::Misc, + ); + } if field.vis.is_accessible_from(def_scope, self.tcx) { self.tcx.check_stability(field.did, Some(expr.hir_id), expr.span, None); @@ -3412,10 +3424,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Ok(index) = field.as_str().parse::() && field.name == sym::integer(index) { - for ty in tys.iter().take(index + 1) { - self.require_type_is_sized(ty, expr.span, ObligationCauseCode::Misc); - } if let Some(&field_ty) = tys.get(index) { + if self.tcx.features().offset_of_slice { + self.require_type_has_static_alignment( + field_ty, + expr.span, + ObligationCauseCode::Misc, + ); + } else { + self.require_type_is_sized( + field_ty, + expr.span, + ObligationCauseCode::Misc, + ); + } + field_indices.push((FIRST_VARIANT, index.into())); current_container = field_ty; diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 85c6d4dc12c55..e354e1ec59c63 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -386,6 +386,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + pub fn require_type_has_static_alignment( + &self, + ty: Ty<'tcx>, + span: Span, + code: traits::ObligationCauseCode<'tcx>, + ) { + if !ty.references_error() { + let tail = + self.tcx.struct_tail_with_normalize(ty, |ty| self.normalize(span, ty), || {}); + // Sized types have static alignment, and so do slices. + if tail.is_trivially_sized(self.tcx) || matches!(tail.kind(), ty::Slice(..)) { + // Nothing else is required here. + } else { + // We can't be sure, let's required full `Sized`. + let lang_item = self.tcx.require_lang_item(LangItem::Sized, None); + self.require_type_meets(ty, span, code, lang_item); + } + } + } + pub fn register_bound( &self, ty: Ty<'tcx>, diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 142872009bf21..56945bf6be4f8 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -1351,3 +1351,37 @@ pub trait FnAbiOf<'tcx>: FnAbiOfHelpers<'tcx> { } impl<'tcx, C: FnAbiOfHelpers<'tcx>> FnAbiOf<'tcx> for C {} + +impl<'tcx> TyCtxt<'tcx> { + pub fn offset_of_subfield( + self, + param_env: ty::ParamEnv<'tcx>, + mut layout: TyAndLayout<'tcx>, + indices: I, + ) -> Size + where + I: Iterator, + { + let cx = LayoutCx { tcx: self, param_env }; + let mut offset = Size::ZERO; + + for (variant, field) in indices { + layout = layout.for_variant(&cx, variant); + let index = field.index(); + offset += layout.fields.offset(index); + layout = layout.field(&cx, index); + if !layout.is_sized() { + // If it is not sized, then the tail must still have at least a known static alignment. + let tail = self.struct_tail_erasing_lifetimes(layout.ty, param_env); + if !matches!(tail.kind(), ty::Slice(..)) { + bug!( + "offset of not-statically-aligned field (type {:?}) cannot be computed statically", + layout.ty + ); + } + } + } + + offset + } +} diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index a8caead46f2f9..eba5d13d33f64 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -10,7 +10,7 @@ use rustc_middle::bug; use rustc_middle::mir::interpret::{InterpResult, Scalar}; use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor}; use rustc_middle::mir::*; -use rustc_middle::ty::layout::LayoutOf; +use rustc_middle::ty::layout::{HasParamEnv, LayoutOf}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_mir_dataflow::value_analysis::{ Map, PlaceIndex, State, TrackElem, ValueAnalysis, ValueAnalysisWrapper, ValueOrPlace, @@ -285,9 +285,11 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> { let val = match null_op { NullOp::SizeOf if layout.is_sized() => layout.size.bytes(), NullOp::AlignOf if layout.is_sized() => layout.align.abi.bytes(), - NullOp::OffsetOf(fields) => { - layout.offset_of_subfield(&self.ecx, fields.iter()).bytes() - } + NullOp::OffsetOf(fields) => self + .ecx + .tcx + .offset_of_subfield(self.ecx.param_env(), layout, fields.iter()) + .bytes(), _ => return ValueOrPlace::Value(FlatSet::Top), }; FlatSet::Elem(Scalar::from_target_usize(val, &self.tcx)) diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index acde16fcb7579..459d15b1cacc3 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -83,8 +83,8 @@ //! that contain `AllocId`s. use rustc_const_eval::const_eval::DummyMachine; -use rustc_const_eval::interpret::{intern_const_alloc_for_constprop, MemoryKind}; -use rustc_const_eval::interpret::{ImmTy, InterpCx, OpTy, Projectable, Scalar}; +use rustc_const_eval::interpret::{intern_const_alloc_for_constprop, MemPlaceMeta, MemoryKind}; +use rustc_const_eval::interpret::{ImmTy, Immediate, InterpCx, OpTy, Projectable, Scalar}; use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::graph::dominators::Dominators; use rustc_hir::def::DefKind; @@ -95,11 +95,11 @@ use rustc_middle::bug; use rustc_middle::mir::interpret::GlobalAlloc; use rustc_middle::mir::visit::*; use rustc_middle::mir::*; -use rustc_middle::ty::layout::LayoutOf; +use rustc_middle::ty::layout::{HasParamEnv, LayoutOf}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::def_id::DefId; use rustc_span::DUMMY_SP; -use rustc_target::abi::{self, Abi, Size, VariantIdx, FIRST_VARIANT}; +use rustc_target::abi::{self, Abi, FieldIdx, Size, VariantIdx, FIRST_VARIANT}; use smallvec::SmallVec; use std::borrow::Cow; @@ -177,6 +177,12 @@ enum AggregateTy<'tcx> { Array, Tuple, Def(DefId, ty::GenericArgsRef<'tcx>), + RawPtr { + /// Needed for cast propagation. + data_pointer_ty: Ty<'tcx>, + /// The data pointer can be anything thin, so doesn't determine the output. + output_pointer_ty: Ty<'tcx>, + }, } #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] @@ -385,11 +391,22 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { AggregateTy::Def(def_id, args) => { self.tcx.type_of(def_id).instantiate(self.tcx, args) } + AggregateTy::RawPtr { output_pointer_ty, .. } => output_pointer_ty, }; let variant = if ty.is_enum() { Some(variant) } else { None }; let ty = self.ecx.layout_of(ty).ok()?; if ty.is_zst() { ImmTy::uninit(ty).into() + } else if matches!(kind, AggregateTy::RawPtr { .. }) { + // Pointers don't have fields, so don't `project_field` them. + let data = self.ecx.read_pointer(fields[0]).ok()?; + let meta = if fields[1].layout.is_zst() { + MemPlaceMeta::None + } else { + MemPlaceMeta::Meta(self.ecx.read_scalar(fields[1]).ok()?) + }; + let ptr_imm = Immediate::new_pointer_with_meta(data, meta, &self.ecx); + ImmTy::from_immediate(ptr_imm, ty).into() } else if matches!(ty.abi, Abi::Scalar(..) | Abi::ScalarPair(..)) { let dest = self.ecx.allocate(ty, MemoryKind::Stack).ok()?; let variant_dest = if let Some(variant) = variant { @@ -484,9 +501,11 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { let val = match null_op { NullOp::SizeOf => layout.size.bytes(), NullOp::AlignOf => layout.align.abi.bytes(), - NullOp::OffsetOf(fields) => { - layout.offset_of_subfield(&self.ecx, fields.iter()).bytes() - } + NullOp::OffsetOf(fields) => self + .ecx + .tcx + .offset_of_subfield(self.ecx.param_env(), layout, fields.iter()) + .bytes(), NullOp::UbChecks => return None, }; let usize_layout = self.ecx.layout_of(self.tcx.types.usize).unwrap(); @@ -862,10 +881,10 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { rvalue: &mut Rvalue<'tcx>, location: Location, ) -> Option { - let Rvalue::Aggregate(box ref kind, ref mut fields) = *rvalue else { bug!() }; + let Rvalue::Aggregate(box ref kind, ref mut field_ops) = *rvalue else { bug!() }; let tcx = self.tcx; - if fields.is_empty() { + if field_ops.is_empty() { let is_zst = match *kind { AggregateKind::Array(..) | AggregateKind::Tuple @@ -884,13 +903,13 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } } - let (ty, variant_index) = match *kind { + let (mut ty, variant_index) = match *kind { AggregateKind::Array(..) => { - assert!(!fields.is_empty()); + assert!(!field_ops.is_empty()); (AggregateTy::Array, FIRST_VARIANT) } AggregateKind::Tuple => { - assert!(!fields.is_empty()); + assert!(!field_ops.is_empty()); (AggregateTy::Tuple, FIRST_VARIANT) } AggregateKind::Closure(did, args) @@ -901,15 +920,49 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } // Do not track unions. AggregateKind::Adt(_, _, _, _, Some(_)) => return None, - // FIXME: Do the extra work to GVN `from_raw_parts` - AggregateKind::RawPtr(..) => return None, + AggregateKind::RawPtr(pointee_ty, mtbl) => { + assert_eq!(field_ops.len(), 2); + let data_pointer_ty = field_ops[FieldIdx::ZERO].ty(self.local_decls, self.tcx); + let output_pointer_ty = Ty::new_ptr(self.tcx, pointee_ty, mtbl); + (AggregateTy::RawPtr { data_pointer_ty, output_pointer_ty }, FIRST_VARIANT) + } }; - let fields: Option> = fields + let fields: Option> = field_ops .iter_mut() .map(|op| self.simplify_operand(op, location).or_else(|| self.new_opaque())) .collect(); - let fields = fields?; + let mut fields = fields?; + + if let AggregateTy::RawPtr { data_pointer_ty, output_pointer_ty } = &mut ty { + let mut was_updated = false; + + // Any thin pointer of matching mutability is fine as the data pointer. + while let Value::Cast { + kind: CastKind::PtrToPtr, + value: cast_value, + from: cast_from, + to: _, + } = self.get(fields[0]) + && let ty::RawPtr(from_pointee_ty, from_mtbl) = cast_from.kind() + && let ty::RawPtr(_, output_mtbl) = output_pointer_ty.kind() + && from_mtbl == output_mtbl + && from_pointee_ty.is_sized(self.tcx, self.param_env) + { + fields[0] = *cast_value; + *data_pointer_ty = *cast_from; + was_updated = true; + } + + if was_updated { + if let Some(const_) = self.try_as_constant(fields[0]) { + field_ops[FieldIdx::ZERO] = Operand::Constant(Box::new(const_)); + } else if let Some(local) = self.try_as_local(fields[0], location) { + field_ops[FieldIdx::ZERO] = Operand::Copy(Place::from(local)); + self.reused_locals.insert(local); + } + } + } if let AggregateTy::Array = ty && fields.len() > 4 @@ -941,6 +994,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { (UnOp::Not, Value::BinaryOp(BinOp::Ne, lhs, rhs)) => { Value::BinaryOp(BinOp::Eq, *lhs, *rhs) } + (UnOp::PtrMetadata, Value::Aggregate(AggregateTy::RawPtr { .. }, _, fields)) => { + return Some(fields[1]); + } _ => return None, }; @@ -1092,6 +1148,23 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { return self.new_opaque(); } + let mut was_updated = false; + + // If that cast just casts away the metadata again, + if let PtrToPtr = kind + && let Value::Aggregate(AggregateTy::RawPtr { data_pointer_ty, .. }, _, fields) = + self.get(value) + && let ty::RawPtr(to_pointee, _) = to.kind() + && to_pointee.is_sized(self.tcx, self.param_env) + { + from = *data_pointer_ty; + value = fields[0]; + was_updated = true; + if *data_pointer_ty == to { + return Some(fields[0]); + } + } + if let PtrToPtr | PointerCoercion(MutToConstPointer) = kind && let Value::Cast { kind: inner_kind, value: inner_value, from: inner_from, to: _ } = *self.get(value) @@ -1100,9 +1173,13 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { from = inner_from; value = inner_value; *kind = PtrToPtr; + was_updated = true; if inner_from == to { return Some(inner_value); } + } + + if was_updated { if let Some(const_) = self.try_as_constant(value) { *operand = Operand::Constant(Box::new(const_)); } else if let Some(local) = self.try_as_local(value, location) { diff --git a/compiler/rustc_mir_transform/src/known_panics_lint.rs b/compiler/rustc_mir_transform/src/known_panics_lint.rs index 8b46658b3225e..47bbddbc31d49 100644 --- a/compiler/rustc_mir_transform/src/known_panics_lint.rs +++ b/compiler/rustc_mir_transform/src/known_panics_lint.rs @@ -625,9 +625,10 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { let val = match null_op { NullOp::SizeOf => op_layout.size.bytes(), NullOp::AlignOf => op_layout.align.abi.bytes(), - NullOp::OffsetOf(fields) => { - op_layout.offset_of_subfield(self, fields.iter()).bytes() - } + NullOp::OffsetOf(fields) => self + .tcx + .offset_of_subfield(self.param_env, op_layout, fields.iter()) + .bytes(), NullOp::UbChecks => return None, }; ImmTy::from_scalar(Scalar::from_target_usize(val, self), layout).into() diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 935942641677a..e245dfb9f5d77 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1304,6 +1304,7 @@ symbols! { offset_of, offset_of_enum, offset_of_nested, + offset_of_slice, ok_or_else, omit_gdb_pretty_printer_section, on, diff --git a/compiler/rustc_target/src/abi/mod.rs b/compiler/rustc_target/src/abi/mod.rs index 666efd9deca28..737e9a8eab022 100644 --- a/compiler/rustc_target/src/abi/mod.rs +++ b/compiler/rustc_target/src/abi/mod.rs @@ -256,29 +256,6 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { Ty::is_transparent(self) } - pub fn offset_of_subfield(self, cx: &C, indices: I) -> Size - where - Ty: TyAbiInterface<'a, C>, - I: Iterator, - { - let mut layout = self; - let mut offset = Size::ZERO; - - for (variant, field) in indices { - layout = layout.for_variant(cx, variant); - let index = field.index(); - offset += layout.fields.offset(index); - layout = layout.field(cx, index); - assert!( - layout.is_sized(), - "offset of unsized field (type {:?}) cannot be computed statically", - layout.ty - ); - } - - offset - } - /// Finds the one field that is not a 1-ZST. /// Returns `None` if there are multiple non-1-ZST fields or only 1-ZST-fields. pub fn non_1zst_field(&self, cx: &C) -> Option<(usize, Self)> diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs index 9362dc8765492..129f62fb43d1a 100644 --- a/library/core/src/num/f128.rs +++ b/library/core/src/num/f128.rs @@ -68,6 +68,13 @@ pub mod consts { pub const FRAC_1_SQRT_PI: f128 = 0.564189583547756286948079451560772585844050629328998856844086_f128; + /// 1/sqrt(2π) + #[doc(alias = "FRAC_1_SQRT_TAU")] + #[unstable(feature = "f128", issue = "116909")] + // Also, #[unstable(feature = "more_float_constants", issue = "103883")] + pub const FRAC_1_SQRT_2PI: f128 = + 0.398942280401432677939946059934381868475858631164934657665926_f128; + /// 2/π #[unstable(feature = "f128", issue = "116909")] pub const FRAC_2_PI: f128 = 0.636619772367581343075535053490057448137838582961825794990669_f128; diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs index c4d4584544bad..7a488cd6bf6fa 100644 --- a/library/core/src/num/f16.rs +++ b/library/core/src/num/f16.rs @@ -67,6 +67,12 @@ pub mod consts { // Also, #[unstable(feature = "more_float_constants", issue = "103883")] pub const FRAC_1_SQRT_PI: f16 = 0.564189583547756286948079451560772586_f16; + /// 1/sqrt(2π) + #[doc(alias = "FRAC_1_SQRT_TAU")] + #[unstable(feature = "f16", issue = "116909")] + // Also, #[unstable(feature = "more_float_constants", issue = "103883")] + pub const FRAC_1_SQRT_2PI: f16 = 0.398942280401432677939946059934381868_f16; + /// 2/π #[unstable(feature = "f16", issue = "116909")] pub const FRAC_2_PI: f16 = 0.636619772367581343075535053490057448_f16; diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index 22b24937cbce2..9d34d3da9e955 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -327,6 +327,11 @@ pub mod consts { #[unstable(feature = "more_float_constants", issue = "103883")] pub const FRAC_1_SQRT_PI: f32 = 0.564189583547756286948079451560772586_f32; + /// 1/sqrt(2π) + #[doc(alias = "FRAC_1_SQRT_TAU")] + #[unstable(feature = "more_float_constants", issue = "103883")] + pub const FRAC_1_SQRT_2PI: f32 = 0.398942280401432677939946059934381868_f32; + /// 2/π #[stable(feature = "rust1", since = "1.0.0")] pub const FRAC_2_PI: f32 = 0.636619772367581343075535053490057448_f32; diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index 34357d1b05ad5..95f021b2541ab 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -327,6 +327,11 @@ pub mod consts { #[unstable(feature = "more_float_constants", issue = "103883")] pub const FRAC_1_SQRT_PI: f64 = 0.564189583547756286948079451560772586_f64; + /// 1/sqrt(2π) + #[doc(alias = "FRAC_1_SQRT_TAU")] + #[unstable(feature = "more_float_constants", issue = "103883")] + pub const FRAC_1_SQRT_2PI: f64 = 0.398942280401432677939946059934381868_f64; + /// 2/π #[stable(feature = "rust1", since = "1.0.0")] pub const FRAC_2_PI: f64 = 0.636619772367581343075535053490057448_f64; diff --git a/library/std/src/sys/pal/unix/os.rs b/library/std/src/sys/pal/unix/os.rs index b5c7d30da7bc0..ae1e42c419b91 100644 --- a/library/std/src/sys/pal/unix/os.rs +++ b/library/std/src/sys/pal/unix/os.rs @@ -462,21 +462,21 @@ pub fn current_exe() -> io::Result { #[cfg(target_os = "haiku")] pub fn current_exe() -> io::Result { + let mut name = vec![0; libc::PATH_MAX as usize]; unsafe { - let mut info: mem::MaybeUninit = mem::MaybeUninit::uninit(); - let mut cookie: i32 = 0; - // the executable can be found at team id 0 - let result = libc::_get_next_image_info( - 0, - &mut cookie, - info.as_mut_ptr(), - mem::size_of::(), + let result = libc::find_path( + std::ptr::null_mut(), + libc::path_base_directory::B_FIND_PATH_IMAGE_PATH, + std::ptr::null_mut(), + name.as_mut_ptr(), + name.len(), ); - if result != 0 { + if result != libc::B_OK { use crate::io::ErrorKind; Err(io::const_io_error!(ErrorKind::Uncategorized, "Error getting executable path")) } else { - let name = CStr::from_ptr((*info.as_ptr()).name.as_ptr()).to_bytes(); + // find_path adds the null terminator. + let name = CStr::from_ptr(name.as_ptr()).to_bytes(); Ok(PathBuf::from(OsStr::from_bytes(name))) } } diff --git a/library/std/src/sys/pal/unix/process/process_unix.rs b/library/std/src/sys/pal/unix/process/process_unix.rs index e2fca8c7e63dc..72bda90a9ba71 100644 --- a/library/std/src/sys/pal/unix/process/process_unix.rs +++ b/library/std/src/sys/pal/unix/process/process_unix.rs @@ -1053,6 +1053,10 @@ fn signal_string(signal: i32) -> &'static str { libc::SIGINFO => " (SIGINFO)", #[cfg(target_os = "hurd")] libc::SIGLOST => " (SIGLOST)", + #[cfg(target_os = "freebsd")] + libc::SIGTHR => " (SIGTHR)", + #[cfg(target_os = "freebsd")] + libc::SIGLIBRT => " (SIGLIBRT)", _ => "", } } diff --git a/library/std/src/sys/pal/windows/api.rs b/library/std/src/sys/pal/windows/api.rs index 555ad581b8568..17a0e47ad5950 100644 --- a/library/std/src/sys/pal/windows/api.rs +++ b/library/std/src/sys/pal/windows/api.rs @@ -251,3 +251,39 @@ pub fn get_last_error() -> WinError { pub struct WinError { pub code: u32, } +impl WinError { + const fn new(code: u32) -> Self { + Self { code } + } +} + +// Error code constants. +// The constant names should be the same as the winapi constants except for the leading `ERROR_`. +// Due to the sheer number of codes, error codes should only be added here on an as-needed basis. +// However, they should never be removed as the assumption is they may be useful again in the future. +#[allow(unused)] +impl WinError { + /// Success is not an error. + /// Some Windows APIs do use this to distinguish between a zero return and an error return + /// but we should never return this to users as an error. + pub const SUCCESS: Self = Self::new(c::ERROR_SUCCESS); + // tidy-alphabetical-start + pub const ACCESS_DENIED: Self = Self::new(c::ERROR_ACCESS_DENIED); + pub const ALREADY_EXISTS: Self = Self::new(c::ERROR_ALREADY_EXISTS); + pub const CANT_ACCESS_FILE: Self = Self::new(c::ERROR_CANT_ACCESS_FILE); + pub const DELETE_PENDING: Self = Self::new(c::ERROR_DELETE_PENDING); + pub const DIRECTORY: Self = Self::new(c::ERROR_DIRECTORY); + pub const FILE_NOT_FOUND: Self = Self::new(c::ERROR_FILE_NOT_FOUND); + pub const INSUFFICIENT_BUFFER: Self = Self::new(c::ERROR_INSUFFICIENT_BUFFER); + pub const INVALID_FUNCTION: Self = Self::new(c::ERROR_INVALID_FUNCTION); + pub const INVALID_HANDLE: Self = Self::new(c::ERROR_INVALID_HANDLE); + pub const INVALID_PARAMETER: Self = Self::new(c::ERROR_INVALID_PARAMETER); + pub const NO_MORE_FILES: Self = Self::new(c::ERROR_NO_MORE_FILES); + pub const NOT_FOUND: Self = Self::new(c::ERROR_NOT_FOUND); + pub const NOT_SUPPORTED: Self = Self::new(c::ERROR_NOT_SUPPORTED); + pub const OPERATION_ABORTED: Self = Self::new(c::ERROR_OPERATION_ABORTED); + pub const PATH_NOT_FOUND: Self = Self::new(c::ERROR_PATH_NOT_FOUND); + pub const SHARING_VIOLATION: Self = Self::new(c::ERROR_SHARING_VIOLATION); + pub const TIMEOUT: Self = Self::new(c::ERROR_TIMEOUT); + // tidy-alphabetical-end +} diff --git a/library/std/src/sys/pal/windows/fs.rs b/library/std/src/sys/pal/windows/fs.rs index e92c5e80eac9c..629ff114b5a88 100644 --- a/library/std/src/sys/pal/windows/fs.rs +++ b/library/std/src/sys/pal/windows/fs.rs @@ -18,7 +18,8 @@ use crate::sys::{c, cvt, Align8}; use crate::sys_common::{AsInner, FromInner, IntoInner}; use crate::thread; -use super::{api, to_u16s, IoResult}; +use super::api::{self, WinError}; +use super::{to_u16s, IoResult}; use crate::sys::path::maybe_verbatim; pub struct File { @@ -130,10 +131,11 @@ impl Iterator for ReadDir { let mut wfd = mem::zeroed(); loop { if c::FindNextFileW(self.handle.0, &mut wfd) == 0 { - if api::get_last_error().code == c::ERROR_NO_MORE_FILES { - return None; - } else { - return Some(Err(Error::last_os_error())); + match api::get_last_error() { + WinError::NO_MORE_FILES => return None, + WinError { code } => { + return Some(Err(Error::from_raw_os_error(code as i32))); + } } } if let Some(e) = DirEntry::new(&self.root, &wfd) { @@ -244,8 +246,6 @@ impl OpenOptions { } fn get_access_mode(&self) -> io::Result { - const ERROR_INVALID_PARAMETER: i32 = 87; - match (self.read, self.write, self.append, self.access_mode) { (.., Some(mode)) => Ok(mode), (true, false, false, None) => Ok(c::GENERIC_READ), @@ -255,23 +255,23 @@ impl OpenOptions { (true, _, true, None) => { Ok(c::GENERIC_READ | (c::FILE_GENERIC_WRITE & !c::FILE_WRITE_DATA)) } - (false, false, false, None) => Err(Error::from_raw_os_error(ERROR_INVALID_PARAMETER)), + (false, false, false, None) => { + Err(Error::from_raw_os_error(c::ERROR_INVALID_PARAMETER as i32)) + } } } fn get_creation_mode(&self) -> io::Result { - const ERROR_INVALID_PARAMETER: i32 = 87; - match (self.write, self.append) { (true, false) => {} (false, false) => { if self.truncate || self.create || self.create_new { - return Err(Error::from_raw_os_error(ERROR_INVALID_PARAMETER)); + return Err(Error::from_raw_os_error(c::ERROR_INVALID_PARAMETER as i32)); } } (_, true) => { if self.truncate && !self.create_new { - return Err(Error::from_raw_os_error(ERROR_INVALID_PARAMETER)); + return Err(Error::from_raw_os_error(c::ERROR_INVALID_PARAMETER as i32)); } } } @@ -315,7 +315,7 @@ impl File { // Manual truncation. See #115745. if opts.truncate && creation == c::OPEN_ALWAYS - && unsafe { c::GetLastError() } == c::ERROR_ALREADY_EXISTS + && api::get_last_error() == WinError::ALREADY_EXISTS { unsafe { // This originally used `FileAllocationInfo` instead of @@ -845,7 +845,7 @@ fn open_link_no_reparse(parent: &File, name: &[u16], access: u32) -> io::Result< // We make a special exception for `STATUS_DELETE_PENDING` because // otherwise this will be mapped to `ERROR_ACCESS_DENIED` which is // very unhelpful. - Err(io::Error::from_raw_os_error(c::ERROR_DELETE_PENDING as _)) + Err(io::Error::from_raw_os_error(c::ERROR_DELETE_PENDING as i32)) } else if status == c::STATUS_INVALID_PARAMETER && ATTRIBUTES.load(Ordering::Relaxed) == c::OBJ_DONT_REPARSE { @@ -1097,7 +1097,7 @@ pub fn readdir(p: &Path) -> io::Result { // // See issue #120040: https://github.com/rust-lang/rust/issues/120040. let last_error = api::get_last_error(); - if last_error.code == c::ERROR_FILE_NOT_FOUND { + if last_error == WinError::FILE_NOT_FOUND { return Ok(ReadDir { handle: FindNextFileHandle(find_handle), root: Arc::new(root), diff --git a/library/std/src/sys/pal/windows/futex.rs b/library/std/src/sys/pal/windows/futex.rs index bc19c402d9c12..08b7fe300dc3c 100644 --- a/library/std/src/sys/pal/windows/futex.rs +++ b/library/std/src/sys/pal/windows/futex.rs @@ -1,4 +1,4 @@ -use super::api; +use super::api::{self, WinError}; use crate::sys::c; use crate::sys::dur2timeout; use core::ffi::c_void; @@ -72,7 +72,7 @@ pub fn wake_by_address_all(address: &T) { pub fn futex_wait(futex: &W::Atomic, expected: W, timeout: Option) -> bool { // return false only on timeout - wait_on_address(futex, expected, timeout) || api::get_last_error().code != c::ERROR_TIMEOUT + wait_on_address(futex, expected, timeout) || api::get_last_error() != WinError::TIMEOUT } pub fn futex_wake(futex: &T) -> bool { diff --git a/library/std/src/sys/pal/windows/os.rs b/library/std/src/sys/pal/windows/os.rs index 483b8b0072c8f..62199c16bfed3 100644 --- a/library/std/src/sys/pal/windows/os.rs +++ b/library/std/src/sys/pal/windows/os.rs @@ -17,7 +17,8 @@ use crate::ptr; use crate::slice; use crate::sys::{c, cvt}; -use super::{api, to_u16s}; +use super::api::{self, WinError}; +use super::to_u16s; pub fn errno() -> i32 { api::get_last_error().code as i32 @@ -333,7 +334,7 @@ fn home_dir_crt() -> Option { buf, &mut sz, ) { - 0 if api::get_last_error().code != c::ERROR_INSUFFICIENT_BUFFER => 0, + 0 if api::get_last_error() != WinError::INSUFFICIENT_BUFFER => 0, 0 => sz, _ => sz - 1, // sz includes the null terminator } @@ -358,7 +359,7 @@ fn home_dir_crt() -> Option { super::fill_utf16_buf( |buf, mut sz| { match c::GetUserProfileDirectoryW(token, buf, &mut sz) { - 0 if api::get_last_error().code != c::ERROR_INSUFFICIENT_BUFFER => 0, + 0 if api::get_last_error() != WinError::INSUFFICIENT_BUFFER => 0, 0 => sz, _ => sz - 1, // sz includes the null terminator } diff --git a/library/std/src/sys/pal/windows/pipe.rs b/library/std/src/sys/pal/windows/pipe.rs index dfa938d4d5769..67ef3ca82da02 100644 --- a/library/std/src/sys/pal/windows/pipe.rs +++ b/library/std/src/sys/pal/windows/pipe.rs @@ -12,6 +12,7 @@ use crate::sys::c; use crate::sys::fs::{File, OpenOptions}; use crate::sys::handle::Handle; use crate::sys::hashmap_random_keys; +use crate::sys::pal::windows::api::{self, WinError}; use crate::sys_common::{FromInner, IntoInner}; //////////////////////////////////////////////////////////////////////////////// @@ -124,20 +125,19 @@ pub fn anon_pipe(ours_readable: bool, their_handle_inheritable: bool) -> io::Res // testing strategy // For more info, see https://github.com/rust-lang/rust/pull/37677. if handle == c::INVALID_HANDLE_VALUE { - let err = io::Error::last_os_error(); - let raw_os_err = err.raw_os_error(); + let error = api::get_last_error(); if tries < 10 { - if raw_os_err == Some(c::ERROR_ACCESS_DENIED as i32) { + if error == WinError::ACCESS_DENIED { continue; } else if reject_remote_clients_flag != 0 - && raw_os_err == Some(c::ERROR_INVALID_PARAMETER as i32) + && error == WinError::INVALID_PARAMETER { reject_remote_clients_flag = 0; tries -= 1; continue; } } - return Err(err); + return Err(io::Error::from_raw_os_error(error.code as i32)); } ours = Handle::from_raw_handle(handle); break; diff --git a/library/std/src/sys/pal/windows/process.rs b/library/std/src/sys/pal/windows/process.rs index e4ab2ca7da1ce..2da986a1494ef 100644 --- a/library/std/src/sys/pal/windows/process.rs +++ b/library/std/src/sys/pal/windows/process.rs @@ -31,6 +31,8 @@ use crate::sys_common::IntoInner; use core::ffi::c_void; +use super::api::{self, WinError}; + //////////////////////////////////////////////////////////////////////////////// // Command //////////////////////////////////////////////////////////////////////////////// @@ -645,12 +647,12 @@ impl Process { pub fn kill(&mut self) -> io::Result<()> { let result = unsafe { c::TerminateProcess(self.handle.as_raw_handle(), 1) }; if result == c::FALSE { - let error = unsafe { c::GetLastError() }; + let error = api::get_last_error(); // TerminateProcess returns ERROR_ACCESS_DENIED if the process has already been // terminated (by us, or for any other reason). So check if the process was actually // terminated, and if so, do not return an error. - if error != c::ERROR_ACCESS_DENIED || self.try_wait().is_err() { - return Err(crate::io::Error::from_raw_os_error(error as i32)); + if error != WinError::ACCESS_DENIED || self.try_wait().is_err() { + return Err(crate::io::Error::from_raw_os_error(error.code as i32)); } } Ok(()) diff --git a/library/std/src/sys/pal/windows/stdio.rs b/library/std/src/sys/pal/windows/stdio.rs index 96c23f82aec2e..690b60d1decca 100644 --- a/library/std/src/sys/pal/windows/stdio.rs +++ b/library/std/src/sys/pal/windows/stdio.rs @@ -1,6 +1,6 @@ #![unstable(issue = "none", feature = "windows_stdio")] -use super::api; +use super::api::{self, WinError}; use crate::cmp; use crate::io; use crate::mem::MaybeUninit; @@ -370,7 +370,7 @@ fn read_u16s(handle: c::HANDLE, buf: &mut [MaybeUninit]) -> io::Result Builder<'a> { test::RustAnalyzer, test::ErrorIndex, test::Distcheck, - test::RunMakeFullDeps, test::Nomicon, test::Reference, test::RustdocBook, @@ -1038,14 +1036,26 @@ impl<'a> Builder<'a> { } pub fn doc_rust_lang_org_channel(&self) -> String { - let channel = match &*self.config.channel { - "stable" => &self.version, - "beta" => "beta", - "nightly" | "dev" => "nightly", - // custom build of rustdoc maybe? link to the latest stable docs just in case - _ => "stable", + // When using precompiled compiler from CI, we need to use CI rustc's channel and + // ignore `rust.channel` from the configuration. Otherwise most of the rustdoc tests + // will fail due to incompatible `DOC_RUST_LANG_ORG_CHANNEL`. + let channel = if let Some(commit) = self.config.download_rustc_commit() { + self.config + .read_file_by_commit(&PathBuf::from("src/ci/channel"), commit) + .trim() + .to_owned() + } else { + match &*self.config.channel { + "stable" => &self.version, + "beta" => "beta", + "nightly" | "dev" => "nightly", + // custom build of rustdoc maybe? link to the latest stable docs just in case + _ => "stable", + } + .to_owned() }; - "https://doc.rust-lang.org/".to_owned() + channel + + format!("https://doc.rust-lang.org/{channel}") } fn run_step_descriptions(&self, v: &[StepDescription], paths: &[PathBuf]) { diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 17e37c1ecd238..36b44d0169c9c 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -1608,19 +1608,8 @@ impl Config { set(&mut config.channel, channel); config.download_rustc_commit = config.download_ci_rustc_commit(download_rustc); - // This list is incomplete, please help by expanding it! - if config.download_rustc_commit.is_some() { - // We need the channel used by the downloaded compiler to match the one we set for rustdoc; - // otherwise rustdoc-ui tests break. - if config.channel != ci_channel - && !(config.channel == "dev" && ci_channel == "nightly") - { - panic!( - "setting rust.channel={} is incompatible with download-rustc", - config.channel - ); - } - } + + // FIXME: handle download-rustc incompatible options. debug = debug_toml; debug_assertions = debug_assertions_toml; @@ -2134,17 +2123,29 @@ impl Config { args } + /// Returns the content of the given file at a specific commit. + pub(crate) fn read_file_by_commit(&self, file: &Path, commit: &str) -> String { + assert!( + self.rust_info.is_managed_git_subrepository(), + "`Config::read_file_by_commit` is not supported in non-git sources." + ); + + let mut git = self.git(); + git.arg("show").arg(format!("{commit}:{}", file.to_str().unwrap())); + output(&mut git) + } + /// Bootstrap embeds a version number into the name of shared libraries it uploads in CI. /// Return the version it would have used for the given commit. pub(crate) fn artifact_version_part(&self, commit: &str) -> String { let (channel, version) = if self.rust_info.is_managed_git_subrepository() { - let mut channel = self.git(); - channel.arg("show").arg(format!("{commit}:src/ci/channel")); - let channel = output(&mut channel); - let mut version = self.git(); - version.arg("show").arg(format!("{commit}:src/version")); - let version = output(&mut version); - (channel.trim().to_owned(), version.trim().to_owned()) + let channel = self + .read_file_by_commit(&PathBuf::from("src/ci/channel"), commit) + .trim() + .to_owned(); + let version = + self.read_file_by_commit(&PathBuf::from("src/version"), commit).trim().to_owned(); + (channel, version) } else { let channel = fs::read_to_string(self.src.join("src/ci/channel")); let version = fs::read_to_string(self.src.join("src/version")); diff --git a/src/ci/docker/README.md b/src/ci/docker/README.md index 9af368ef44504..824c904e17f75 100644 --- a/src/ci/docker/README.md +++ b/src/ci/docker/README.md @@ -233,7 +233,7 @@ For targets: `aarch64-unknown-linux-gnu` - Operating System > Linux kernel version = 4.1.49 - Binary utilities > Version of binutils = 2.29.1 - C-library > glibc version = 2.17 -- aarch64 support was introduced in this version -- C compiler > gcc version = 8.5.0 +- C compiler > gcc version = 13.2.0 - C compiler > C++ = ENABLE -- to cross compile LLVM ### `i586-linux-gnu.defconfig` diff --git a/src/ci/docker/host-x86_64/dist-aarch64-linux/aarch64-linux-gnu.defconfig b/src/ci/docker/host-x86_64/dist-aarch64-linux/aarch64-linux-gnu.defconfig index 47e984ef85a21..520b1667c8be1 100644 --- a/src/ci/docker/host-x86_64/dist-aarch64-linux/aarch64-linux-gnu.defconfig +++ b/src/ci/docker/host-x86_64/dist-aarch64-linux/aarch64-linux-gnu.defconfig @@ -6,7 +6,5 @@ CT_ARCH_ARM=y CT_ARCH_64=y CT_KERNEL_LINUX=y CT_LINUX_V_4_1=y -CT_BINUTILS_V_2_29=y CT_GLIBC_V_2_17=y -CT_GCC_V_8=y CT_CC_LANG_CXX=y diff --git a/src/ci/docker/host-x86_64/test-various/uefi_qemu_test/Cargo.lock b/src/ci/docker/host-x86_64/test-various/uefi_qemu_test/Cargo.lock index b0c17d9a296c8..dacf531e4048d 100644 --- a/src/ci/docker/host-x86_64/test-various/uefi_qemu_test/Cargo.lock +++ b/src/ci/docker/host-x86_64/test-various/uefi_qemu_test/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "r-efi" -version = "4.4.0" +version = "4.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c47196f636c4cc0634b73b0405323d177753c2e15e866952c64ea22902567a34" +checksum = "e9e935efc5854715dfc0a4c9ef18dc69dee0ec3bf9cc3ab740db831c0fdd86a3" [[package]] name = "uefi_qemu_test" diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-debug/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-debug/Dockerfile index e4534d0f8408c..64a1fb093b49b 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-debug/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-debug/Dockerfile @@ -44,6 +44,14 @@ ENV RUST_CONFIGURE_ARGS \ --set target.x86_64-unknown-linux-gnu.cc=clang \ --set target.x86_64-unknown-linux-gnu.cxx=clang++ +# This job appears to be checking two separate things: +# - That we can build the compiler with `--enable-debug` +# (without necessarily testing the result). +# - That the tests with `//@ needs-matching-clang` pass, since they +# don't run by default unless RUSTBUILD_FORCE_CLANG_BASED_TESTS is set. +# - FIXME(https://github.com/rust-lang/rust/pull/126155#issuecomment-2156314273): +# Currently we only run the subset of tests with "clang" in their name. + ENV SCRIPT \ python3 ../x.py --stage 2 build && \ - python3 ../x.py --stage 2 test tests/run-make-fulldeps --test-args clang + python3 ../x.py --stage 2 test tests/run-make --test-args clang diff --git a/src/ci/docker/scripts/x86_64-gnu-llvm.sh b/src/ci/docker/scripts/x86_64-gnu-llvm.sh index 876b300d35c6b..b3921f114217d 100755 --- a/src/ci/docker/scripts/x86_64-gnu-llvm.sh +++ b/src/ci/docker/scripts/x86_64-gnu-llvm.sh @@ -4,13 +4,7 @@ set -ex # Only run the stage 1 tests on merges, not on PR CI jobs. if [[ -z "${PR_CI_JOB}" ]]; then - # When running gcc backend tests, we need to install `libgccjit` and to not run llvm codegen - # tests as it will fail them. - if [[ "${ENABLE_GCC_CODEGEN}" == "1" ]]; then - ../x.py --stage 1 test --skip src/tools/tidy --skip tests/codegen - else - ../x.py --stage 1 test --skip src/tools/tidy - fi + ../x.py --stage 1 test --skip src/tools/tidy # Run the `mir-opt` tests again but this time for a 32-bit target. # This enforces that tests using `// EMIT_MIR_FOR_EACH_BIT_WIDTH` have @@ -29,14 +23,8 @@ if [[ -z "${PR_CI_JOB}" ]]; then --rustc-args "--cfg feature=\"optimize_for_size\"" fi -# When running gcc backend tests, we need to install `libgccjit` and to not run llvm codegen -# tests as it will fail them. # NOTE: intentionally uses all of `x.py`, `x`, and `x.ps1` to make sure they all work on Linux. -if [[ "${ENABLE_GCC_CODEGEN}" == "1" ]]; then - ../x.py --stage 2 test --skip src/tools/tidy --skip tests/codegen -else - ../x.py --stage 2 test --skip src/tools/tidy -fi +../x.py --stage 2 test --skip src/tools/tidy # Run the `mir-opt` tests again but this time for a 32-bit target. # This enforces that tests using `// EMIT_MIR_FOR_EACH_BIT_WIDTH` have diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 8c84e721f5de5..48c39d2c33e56 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -37,7 +37,7 @@ runners: envs: env-x86_64-apple-tests: &env-x86_64-apple-tests - SCRIPT: ./x.py --stage 2 test --skip tests/ui --skip tests/rustdoc --skip tests/run-make-fulldeps + SCRIPT: ./x.py --stage 2 test --skip tests/ui --skip tests/rustdoc RUST_CONFIGURE_ARGS: --build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 MACOSX_DEPLOYMENT_TARGET: 10.12 @@ -294,7 +294,7 @@ auto: - image: x86_64-apple-2 env: - SCRIPT: ./x.py --stage 2 test tests/ui tests/rustdoc tests/run-make-fulldeps + SCRIPT: ./x.py --stage 2 test tests/ui tests/rustdoc <<: *env-x86_64-apple-tests <<: *job-macos-xl diff --git a/src/doc/rustc/src/platform-support/nto-qnx.md b/src/doc/rustc/src/platform-support/nto-qnx.md index 56070c2ec34e3..51a397a38d209 100644 --- a/src/doc/rustc/src/platform-support/nto-qnx.md +++ b/src/doc/rustc/src/platform-support/nto-qnx.md @@ -160,8 +160,7 @@ export exclude_tests=' --exclude src/tools/linkchecker --exclude tests/ui-fulldeps --exclude rustc - --exclude rustdoc - --exclude tests/run-make-fulldeps' + --exclude rustdoc' env $build_env \ ./x.py test \ diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 012afada1e5ee..78d4129f6422c 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -128,6 +128,8 @@ pub(crate) struct Options { pub(crate) enable_per_target_ignores: bool, /// Do not run doctests, compile them if should_test is active. pub(crate) no_run: bool, + /// What sources are being mapped. + pub(crate) remap_path_prefix: Vec<(PathBuf, PathBuf)>, /// The path to a rustc-like binary to build tests with. If not set, we /// default to loading from `$sysroot/bin/rustc`. @@ -211,6 +213,7 @@ impl fmt::Debug for Options { .field("run_check", &self.run_check) .field("no_run", &self.no_run) .field("test_builder_wrappers", &self.test_builder_wrappers) + .field("remap-file-prefix", &self.remap_path_prefix) .field("nocapture", &self.nocapture) .field("scrape_examples_options", &self.scrape_examples_options) .field("unstable_features", &self.unstable_features) @@ -372,6 +375,13 @@ impl Options { let codegen_options = CodegenOptions::build(early_dcx, matches); let unstable_opts = UnstableOptions::build(early_dcx, matches); + let remap_path_prefix = match parse_remap_path_prefix(&matches) { + Ok(prefix_mappings) => prefix_mappings, + Err(err) => { + early_dcx.early_fatal(err); + } + }; + let dcx = new_dcx(error_format, None, diagnostic_width, &unstable_opts); // check for deprecated options @@ -772,6 +782,7 @@ impl Options { run_check, no_run, test_builder_wrappers, + remap_path_prefix, nocapture, crate_name, output_format, @@ -820,6 +831,21 @@ impl Options { } } +fn parse_remap_path_prefix( + matches: &getopts::Matches, +) -> Result, &'static str> { + matches + .opt_strs("remap-path-prefix") + .into_iter() + .map(|remap| { + remap + .rsplit_once('=') + .ok_or("--remap-path-prefix must contain '=' between FROM and TO") + .map(|(from, to)| (PathBuf::from(from), PathBuf::from(to))) + }) + .collect() +} + /// Prints deprecation warnings for deprecated options fn check_deprecated_options(matches: &getopts::Matches, dcx: &rustc_errors::DiagCtxt) { let deprecated_flags = []; diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index a732e645b6baa..81a7463decadc 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -129,6 +129,7 @@ pub(crate) fn run( edition: options.edition, target_triple: options.target.clone(), crate_name: options.crate_name.clone(), + remap_path_prefix: options.remap_path_prefix.clone(), ..config::Options::default() }; @@ -572,7 +573,6 @@ fn make_maybe_absolute_path(path: PathBuf) -> PathBuf { std::env::current_dir().map(|c| c.join(&path)).unwrap_or_else(|_| path) } } - struct IndividualTestOptions { outdir: DirState, test_id: String, @@ -651,7 +651,7 @@ impl CreateRunnableDoctests { if !item_path.is_empty() { item_path.push(' '); } - format!("{} - {item_path}(line {line})", filename.prefer_local()) + format!("{} - {item_path}(line {line})", filename.prefer_remapped_unconditionaly()) } fn add_test(&mut self, test: ScrapedDoctest) { diff --git a/src/librustdoc/doctest/rust.rs b/src/librustdoc/doctest/rust.rs index e6bef395fa9ce..fc8e119ccc232 100644 --- a/src/librustdoc/doctest/rust.rs +++ b/src/librustdoc/doctest/rust.rs @@ -27,11 +27,13 @@ struct RustCollector { impl RustCollector { fn get_filename(&self) -> FileName { let filename = self.source_map.span_to_filename(self.position); - if let FileName::Real(ref filename) = filename - && let Ok(cur_dir) = env::current_dir() - && let Some(local_path) = filename.local_path() - && let Ok(path) = local_path.strip_prefix(&cur_dir) - { + if let FileName::Real(ref filename) = filename { + let path = filename.remapped_path_if_available(); + // Strip the cwd prefix from the path. This will likely exist if + // the path was not remapped. + let path = env::current_dir() + .map(|cur_dir| path.strip_prefix(&cur_dir).unwrap_or(path)) + .unwrap_or(path); return path.to_owned().into(); } filename diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 3b6bddf263a9f..d6e715d48ea5a 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -555,6 +555,14 @@ fn opts() -> Vec { unstable("no-run", |o| { o.optflagmulti("", "no-run", "Compile doctests without running them") }), + unstable("remap-path-prefix", |o| { + o.optmulti( + "", + "remap-path-prefix", + "Remap source names in compiler messages", + "FROM=TO", + ) + }), unstable("show-type-layout", |o| { o.optflagmulti("", "show-type-layout", "Include the memory layout of types in the docs") }), diff --git a/src/tools/build_helper/README.md b/src/tools/build_helper/README.md new file mode 100644 index 0000000000000..f81b631c3fdbf --- /dev/null +++ b/src/tools/build_helper/README.md @@ -0,0 +1 @@ +Types and functions shared across tools in this workspace. diff --git a/src/tools/build_helper/src/lib.rs b/src/tools/build_helper/src/lib.rs index 2abda5d3ebf27..15807d1c0d8f8 100644 --- a/src/tools/build_helper/src/lib.rs +++ b/src/tools/build_helper/src/lib.rs @@ -1,5 +1,30 @@ +//! Types and functions shared across tools in this workspace. + pub mod ci; pub mod git; pub mod metrics; pub mod stage0_parser; pub mod util; + +/// The default set of crates for opt-dist to collect LLVM profiles. +pub const LLVM_PGO_CRATES: &[&str] = &[ + "syn-1.0.89", + "cargo-0.60.0", + "serde-1.0.136", + "ripgrep-13.0.0", + "regex-1.5.5", + "clap-3.1.6", + "hyper-0.14.18", +]; + +/// The default set of crates for opt-dist to collect rustc profiles. +pub const RUSTC_PGO_CRATES: &[&str] = &[ + "externs", + "ctfe-stress-5", + "cargo-0.60.0", + "token-stream-stress", + "match-stress", + "tuple-stress", + "diesel-1.4.8", + "bitmaps-3.1.0", +]; diff --git a/src/tools/clippy/tests/ui/unicode.stderr b/src/tools/clippy/tests/ui/unicode.stderr index 9c365e1097dbc..b004493300eed 100644 --- a/src/tools/clippy/tests/ui/unicode.stderr +++ b/src/tools/clippy/tests/ui/unicode.stderr @@ -11,7 +11,7 @@ error: invisible character detected --> tests/ui/unicode.rs:7:12 | LL | print!("Here >­< is a SHY, and ­another"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider replacing the string with: `"Here >\u{AD}< is a SHY, and \u{AD}another"` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider replacing the string with: `"Here >\u{AD}< is a SHY, and \u{AD}another"` error: invisible character detected --> tests/ui/unicode.rs:9:12 diff --git a/src/tools/miri/CONTRIBUTING.md b/src/tools/miri/CONTRIBUTING.md index 092ad46a7cad3..9067cbc603261 100644 --- a/src/tools/miri/CONTRIBUTING.md +++ b/src/tools/miri/CONTRIBUTING.md @@ -223,7 +223,7 @@ will eventually sync those changes back into this repository. When working on Miri in the rustc tree, here's how you can run tests: ``` -./x.py test miri --stage 0 +./x.py test miri ``` `--bless` will work, too. @@ -231,7 +231,7 @@ When working on Miri in the rustc tree, here's how you can run tests: You can also directly run Miri on a Rust source file: ``` -./x.py run miri --stage 0 --args src/tools/miri/tests/pass/hello.rs +./x.py run miri --stage 1 --args src/tools/miri/tests/pass/hello.rs ``` ## Advanced topic: Syncing with the rustc repo @@ -287,7 +287,22 @@ https. Add the following to your `.gitconfig`: pushInsteadOf = https://github.com/ ``` -## Internal environment variables +## Further environment variables + +The following environment variables are relevant to `./miri`: + +* `MIRI_AUTO_OPS` indicates whether the automatic execution of rustfmt, clippy and toolchain setup + (as controlled by the `./auto-*` files) should be skipped. If it is set to `no`, they are skipped. + This is used to allow automated IDE actions to avoid the auto ops. +* `MIRI_LOG`, `MIRI_BACKTRACE` control logging and backtrace printing during Miri executions. +* `MIRI_TEST_THREADS` (recognized by `./miri test`) sets the number of threads to use for running + tests. By default, the number of cores is used. +* `MIRI_SKIP_UI_CHECKS` (recognized by `./miri test`) disables checking that the `stderr` or + `stdout` files match the actual output. + +Furthermore, the usual environment variables recognized by `cargo miri` also work for `./miri`, e.g. +`MIRI_LIB_SRC`. Note that `MIRIFLAGS` is ignored by `./miri test` as each test controls the flags it +is run with. The following environment variables are *internal* and must not be used by anyone but Miri itself. They are used to communicate between different Miri diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md index 208a8b9ee617d..c437619a76eab 100644 --- a/src/tools/miri/README.md +++ b/src/tools/miri/README.md @@ -448,28 +448,19 @@ Some native rustc `-Z` flags are also very relevant for Miri: * `-Zmir-emit-retag` controls whether `Retag` statements are emitted. Miri enables this per default because it is needed for [Stacked Borrows] and [Tree Borrows]. -Moreover, Miri recognizes some environment variables (unless noted otherwise, these are supported -by all intended entry points, i.e. `cargo miri` and `./miri {test,run}`): - -* `MIRI_AUTO_OPS` indicates whether the automatic execution of rustfmt, clippy and toolchain setup - should be skipped. If it is set to `no`, they are skipped. This is used to allow automated IDE - actions to avoid the auto ops. -* `MIRI_LOG`, `MIRI_BACKTRACE` control logging and backtrace printing during - Miri executions, also [see "Testing the Miri driver" in `CONTRIBUTING.md`][testing-miri]. +Moreover, Miri recognizes some environment variables: + * `MIRIFLAGS` defines extra flags to be passed to Miri. * `MIRI_LIB_SRC` defines the directory where Miri expects the sources of the standard library that it will build and use for interpretation. This directory must point to the `library` subdirectory of a `rust-lang/rust` repository checkout. -* `MIRI_SYSROOT` indicates the sysroot to use. When using `cargo miri`, this skips the automatic +* `MIRI_SYSROOT` indicates the sysroot to use. When using `cargo miri test`/`cargo miri run`, this skips the automatic setup -- only set this if you do not want to use the automatically created sysroot. When invoking `cargo miri setup`, this indicates where the sysroot will be put. -* `MIRI_TEST_THREADS` (recognized by `./miri test`): set the number of threads to use for running tests. - By default, the number of cores is used. * `MIRI_NO_STD` makes sure that the target's sysroot is built without libstd. This allows testing - and running no_std programs. (Miri has a heuristic to detect no-std targets based on the target - name; this environment variable is only needed when that heuristic fails.) -* `MIRI_SKIP_UI_CHECKS` (recognized by `./miri test`): don't check whether the - `stderr` or `stdout` files match the actual output. + and running no_std programs. This should *not usually be used*; Miri has a heuristic to detect + no-std targets based on the target name. Setting this on a target that does support libstd can + lead to confusing results. [testing-miri]: CONTRIBUTING.md#testing-the-miri-driver diff --git a/src/tools/miri/bench-cargo-miri/big-allocs/Cargo.lock b/src/tools/miri/bench-cargo-miri/big-allocs/Cargo.lock new file mode 100644 index 0000000000000..da0db7f47ea44 --- /dev/null +++ b/src/tools/miri/bench-cargo-miri/big-allocs/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "big-allocs" +version = "0.1.0" diff --git a/src/tools/miri/bench-cargo-miri/big-allocs/Cargo.toml b/src/tools/miri/bench-cargo-miri/big-allocs/Cargo.toml new file mode 100644 index 0000000000000..7234c9371cff3 --- /dev/null +++ b/src/tools/miri/bench-cargo-miri/big-allocs/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "big-allocs" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/src/tools/miri/bench-cargo-miri/big-allocs/src/main.rs b/src/tools/miri/bench-cargo-miri/big-allocs/src/main.rs new file mode 100644 index 0000000000000..a1c1708cf3baa --- /dev/null +++ b/src/tools/miri/bench-cargo-miri/big-allocs/src/main.rs @@ -0,0 +1,13 @@ +//! This is a regression test for https://github.com/rust-lang/miri/issues/3637. +//! `Allocation`s are backed by a `Box<[u8]>`, which we create using `alloc_zeroed`, which should +//! make very large allocations cheap. But then we also need to not clone those `Allocation`s, or +//! we end up slow anyway. + +fn main() { + // We can't use too big of an allocation or this code will encounter an allocation failure in + // CI. Since the allocation can't be huge, we need to do a few iterations so that the effect + // we're trying to measure is clearly visible above the interpreter's startup time. + for _ in 0..10 { + drop(Vec::::with_capacity(512 * 1024 * 1024)); + } +} diff --git a/src/tools/miri/cargo-miri/src/main.rs b/src/tools/miri/cargo-miri/src/main.rs index 9fdd4c3e47043..7d9f77f3752d9 100644 --- a/src/tools/miri/cargo-miri/src/main.rs +++ b/src/tools/miri/cargo-miri/src/main.rs @@ -1,15 +1,14 @@ #![allow(clippy::useless_format, clippy::derive_partial_eq_without_eq, rustc::internal)] -#[macro_use] -mod util; - mod arg; mod phases; mod setup; +mod util; use std::{env, iter}; use crate::phases::*; +use crate::util::show_error; /// Returns `true` if our flags look like they may be for rustdoc, i.e., this is cargo calling us to /// be rustdoc. It's hard to be sure as cargo does not have a RUSTDOC_WRAPPER or an env var that diff --git a/src/tools/miri/cargo-miri/src/util.rs b/src/tools/miri/cargo-miri/src/util.rs index 28a824e54f65c..f36cff1f7981e 100644 --- a/src/tools/miri/cargo-miri/src/util.rs +++ b/src/tools/miri/cargo-miri/src/util.rs @@ -1,3 +1,4 @@ +use std::collections::HashMap; use std::env; use std::ffi::OsString; use std::fs::File; @@ -11,14 +12,15 @@ use serde::{Deserialize, Serialize}; pub use crate::arg::*; -pub fn show_error(msg: &impl std::fmt::Display) -> ! { +pub fn show_error_(msg: &impl std::fmt::Display) -> ! { eprintln!("fatal error: {msg}"); std::process::exit(1) } macro_rules! show_error { - ($($tt:tt)*) => { crate::util::show_error(&format_args!($($tt)*)) }; + ($($tt:tt)*) => { crate::util::show_error_(&format_args!($($tt)*)) }; } +pub(crate) use show_error; /// The information to run a crate with the given environment. #[derive(Clone, Serialize, Deserialize)] @@ -232,21 +234,18 @@ pub fn get_cargo_metadata() -> Metadata { } /// Pulls all the crates in this workspace from the cargo metadata. -/// Workspace members are emitted like "miri 0.1.0 (path+file:///path/to/miri)" /// Additionally, somewhere between cargo metadata and TyCtxt, '-' gets replaced with '_' so we /// make that same transformation here. pub fn local_crates(metadata: &Metadata) -> String { assert!(!metadata.workspace_members.is_empty()); - let mut local_crates = String::new(); - for member in &metadata.workspace_members { - let name = member.repr.split(' ').next().unwrap(); - let name = name.replace('-', "_"); - local_crates.push_str(&name); - local_crates.push(','); - } - local_crates.pop(); // Remove the trailing ',' - - local_crates + let package_name_by_id: HashMap<_, _> = + metadata.packages.iter().map(|package| (&package.id, package.name.as_str())).collect(); + metadata + .workspace_members + .iter() + .map(|id| package_name_by_id[id].replace('-', "_")) + .collect::>() + .join(",") } /// Debug-print a command that is going to be run. diff --git a/src/tools/miri/ci/ci.sh b/src/tools/miri/ci/ci.sh index f97a611b36407..67985f9b7d6e9 100755 --- a/src/tools/miri/ci/ci.sh +++ b/src/tools/miri/ci/ci.sh @@ -148,8 +148,8 @@ case $HOST_TARGET in UNIX="panic/panic panic/unwind concurrency/simple atomic libc-mem libc-misc libc-random env num_cpus" # the things that are very similar across all Unixes, and hence easily supported there TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal $BASIC $UNIX threadname libc-time fs TEST_TARGET=i686-unknown-freebsd run_tests_minimal $BASIC $UNIX threadname libc-time fs - TEST_TARGET=x86_64-unknown-illumos run_tests_minimal $BASIC $UNIX threadname pthread-sync libc-time - TEST_TARGET=x86_64-pc-solaris run_tests_minimal $BASIC $UNIX threadname pthread-sync libc-time + TEST_TARGET=x86_64-unknown-illumos run_tests_minimal $BASIC $UNIX threadname pthread-sync available-parallelism libc-time + TEST_TARGET=x86_64-pc-solaris run_tests_minimal $BASIC $UNIX threadname pthread-sync available-parallelism libc-time TEST_TARGET=aarch64-linux-android run_tests_minimal $BASIC $UNIX TEST_TARGET=wasm32-wasip2 run_tests_minimal empty_main wasm heap_alloc libc-mem TEST_TARGET=wasm32-unknown-unknown run_tests_minimal empty_main wasm diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index aa06a0dbcdc5b..0f738653b14a7 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -21e6de7eb64c09102de3f100420a09edc1a2a8d7 +565cadb514d35e7b851540edbc172af0f606014f diff --git a/src/tools/miri/src/alloc_addresses/mod.rs b/src/tools/miri/src/alloc_addresses/mod.rs index 002e106206102..ae95d28d3eb65 100644 --- a/src/tools/miri/src/alloc_addresses/mod.rs +++ b/src/tools/miri/src/alloc_addresses/mod.rs @@ -257,7 +257,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Ok(()) } - fn ptr_from_addr_cast(&self, addr: u64) -> InterpResult<'tcx, Pointer>> { + fn ptr_from_addr_cast(&self, addr: u64) -> InterpResult<'tcx, Pointer> { trace!("Casting {:#x} to a pointer", addr); let ecx = self.eval_context_ref(); @@ -297,10 +297,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// Convert a relative (tcx) pointer to a Miri pointer. fn adjust_alloc_root_pointer( &self, - ptr: Pointer, + ptr: interpret::Pointer, tag: BorTag, kind: MemoryKind, - ) -> InterpResult<'tcx, Pointer> { + ) -> InterpResult<'tcx, interpret::Pointer> { let ecx = self.eval_context_ref(); let (prov, offset) = ptr.into_parts(); // offset is relative (AllocId provenance) @@ -310,12 +310,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Add offset with the right kind of pointer-overflowing arithmetic. let dl = ecx.data_layout(); let absolute_addr = dl.overflowing_offset(base_addr, offset.bytes()).0; - Ok(Pointer::new(Provenance::Concrete { alloc_id, tag }, Size::from_bytes(absolute_addr))) + Ok(interpret::Pointer::new( + Provenance::Concrete { alloc_id, tag }, + Size::from_bytes(absolute_addr), + )) } /// When a pointer is used for a memory access, this computes where in which allocation the /// access is going. - fn ptr_get_alloc(&self, ptr: Pointer) -> Option<(AllocId, Size)> { + fn ptr_get_alloc(&self, ptr: interpret::Pointer) -> Option<(AllocId, Size)> { let ecx = self.eval_context_ref(); let (tag, addr) = ptr.into_parts(); // addr is absolute (Tag provenance) diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs index d748febeed4b1..829bfa7cd7086 100644 --- a/src/tools/miri/src/bin/miri.rs +++ b/src/tools/miri/src/bin/miri.rs @@ -8,7 +8,6 @@ )] // Some "regular" crates we want to share with rustc -#[macro_use] extern crate tracing; // The rustc crates we need @@ -26,6 +25,8 @@ use std::num::NonZero; use std::path::PathBuf; use std::str::FromStr; +use tracing::debug; + use rustc_data_structures::sync::Lrc; use rustc_driver::Compilation; use rustc_hir::{self as hir, Node}; diff --git a/src/tools/miri/src/borrow_tracker/mod.rs b/src/tools/miri/src/borrow_tracker/mod.rs index a55ec427d5f08..c9e7e300593bc 100644 --- a/src/tools/miri/src/borrow_tracker/mod.rs +++ b/src/tools/miri/src/borrow_tracker/mod.rs @@ -281,8 +281,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn retag_ptr_value( &mut self, kind: RetagKind, - val: &ImmTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, ImmTy<'tcx, Provenance>> { + val: &ImmTy<'tcx>, + ) -> InterpResult<'tcx, ImmTy<'tcx>> { let this = self.eval_context_mut(); let method = this.machine.borrow_tracker.as_ref().unwrap().borrow().borrow_tracker_method; match method { @@ -294,7 +294,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn retag_place_contents( &mut self, kind: RetagKind, - place: &PlaceTy<'tcx, Provenance>, + place: &PlaceTy<'tcx>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let method = this.machine.borrow_tracker.as_ref().unwrap().borrow().borrow_tracker_method; @@ -304,10 +304,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } } - fn protect_place( - &mut self, - place: &MPlaceTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, MPlaceTy<'tcx, Provenance>> { + fn protect_place(&mut self, place: &MPlaceTy<'tcx>) -> InterpResult<'tcx, MPlaceTy<'tcx>> { let this = self.eval_context_mut(); let method = this.machine.borrow_tracker.as_ref().unwrap().borrow().borrow_tracker_method; match method { @@ -327,7 +324,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn give_pointer_debug_name( &mut self, - ptr: Pointer>, + ptr: Pointer, nth_parent: u8, name: &str, ) -> InterpResult<'tcx> { diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/diagnostics.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/diagnostics.rs index 8270a8c321ce1..87d9057cb89dc 100644 --- a/src/tools/miri/src/borrow_tracker/stacked_borrows/diagnostics.rs +++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/diagnostics.rs @@ -149,11 +149,7 @@ impl<'ecx, 'tcx> DiagnosticCxBuilder<'ecx, 'tcx> { DiagnosticCxBuilder { machine, operation } } - pub fn read( - machine: &'ecx MiriMachine<'tcx>, - tag: ProvenanceExtra, - range: AllocRange, - ) -> Self { + pub fn read(machine: &'ecx MiriMachine<'tcx>, tag: ProvenanceExtra, range: AllocRange) -> Self { let operation = Operation::Access(AccessOp { kind: AccessKind::Read, tag, range }); DiagnosticCxBuilder { machine, operation } } diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs index 2786668695e27..603733f9dc000 100644 --- a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs @@ -531,7 +531,7 @@ impl Stacks { trace!( "read access with tag {:?}: {:?}, size {}", tag, - Pointer::new(alloc_id, range.start), + interpret::Pointer::new(alloc_id, range.start), range.size.bytes() ); let dcx = DiagnosticCxBuilder::read(machine, tag, range); @@ -552,7 +552,7 @@ impl Stacks { trace!( "write access with tag {:?}: {:?}, size {}", tag, - Pointer::new(alloc_id, range.start), + interpret::Pointer::new(alloc_id, range.start), range.size.bytes() ); let dcx = DiagnosticCxBuilder::write(machine, tag, range); @@ -587,7 +587,7 @@ trait EvalContextPrivExt<'tcx, 'ecx>: crate::MiriInterpCxExt<'tcx> { /// Returns the provenance that should be used henceforth. fn sb_reborrow( &mut self, - place: &MPlaceTy<'tcx, Provenance>, + place: &MPlaceTy<'tcx>, size: Size, new_perm: NewPermission, new_tag: BorTag, @@ -692,7 +692,7 @@ trait EvalContextPrivExt<'tcx, 'ecx>: crate::MiriInterpCxExt<'tcx> { new_tag, orig_tag, place.layout.ty, - Pointer::new(alloc_id, base_offset), + interpret::Pointer::new(alloc_id, base_offset), size.bytes() ); @@ -809,10 +809,10 @@ trait EvalContextPrivExt<'tcx, 'ecx>: crate::MiriInterpCxExt<'tcx> { fn sb_retag_place( &mut self, - place: &MPlaceTy<'tcx, Provenance>, + place: &MPlaceTy<'tcx>, new_perm: NewPermission, info: RetagInfo, // diagnostics info about this retag - ) -> InterpResult<'tcx, MPlaceTy<'tcx, Provenance>> { + ) -> InterpResult<'tcx, MPlaceTy<'tcx>> { let this = self.eval_context_mut(); let size = this.size_and_align_of_mplace(place)?.map(|(size, _)| size); // FIXME: If we cannot determine the size (because the unsized tail is an `extern type`), @@ -839,10 +839,10 @@ trait EvalContextPrivExt<'tcx, 'ecx>: crate::MiriInterpCxExt<'tcx> { /// `kind` indicates what kind of reference is being created. fn sb_retag_reference( &mut self, - val: &ImmTy<'tcx, Provenance>, + val: &ImmTy<'tcx>, new_perm: NewPermission, info: RetagInfo, // diagnostics info about this retag - ) -> InterpResult<'tcx, ImmTy<'tcx, Provenance>> { + ) -> InterpResult<'tcx, ImmTy<'tcx>> { let this = self.eval_context_mut(); let place = this.ref_to_mplace(val)?; let new_place = this.sb_retag_place(&place, new_perm, info)?; @@ -855,8 +855,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn sb_retag_ptr_value( &mut self, kind: RetagKind, - val: &ImmTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, ImmTy<'tcx, Provenance>> { + val: &ImmTy<'tcx>, + ) -> InterpResult<'tcx, ImmTy<'tcx>> { let this = self.eval_context_mut(); let new_perm = NewPermission::from_ref_ty(val.layout.ty, kind, this); let cause = match kind { @@ -870,7 +870,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn sb_retag_place_contents( &mut self, kind: RetagKind, - place: &PlaceTy<'tcx, Provenance>, + place: &PlaceTy<'tcx>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let retag_fields = this.machine.borrow_tracker.as_mut().unwrap().get_mut().retag_fields; @@ -895,7 +895,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { #[inline(always)] // yes this helps in our benchmarks fn retag_ptr_inplace( &mut self, - place: &PlaceTy<'tcx, Provenance>, + place: &PlaceTy<'tcx>, new_perm: NewPermission, ) -> InterpResult<'tcx> { let val = self.ecx.read_immediate(&self.ecx.place_to_op(place)?)?; @@ -909,18 +909,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } } impl<'ecx, 'tcx> ValueVisitor<'tcx, MiriMachine<'tcx>> for RetagVisitor<'ecx, 'tcx> { - type V = PlaceTy<'tcx, Provenance>; + type V = PlaceTy<'tcx>; #[inline(always)] fn ecx(&self) -> &MiriInterpCx<'tcx> { self.ecx } - fn visit_box( - &mut self, - box_ty: Ty<'tcx>, - place: &PlaceTy<'tcx, Provenance>, - ) -> InterpResult<'tcx> { + fn visit_box(&mut self, box_ty: Ty<'tcx>, place: &PlaceTy<'tcx>) -> InterpResult<'tcx> { // Only boxes for the global allocator get any special treatment. if box_ty.is_box_global(*self.ecx.tcx) { // Boxes get a weak protectors, since they may be deallocated. @@ -930,7 +926,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Ok(()) } - fn visit_value(&mut self, place: &PlaceTy<'tcx, Provenance>) -> InterpResult<'tcx> { + fn visit_value(&mut self, place: &PlaceTy<'tcx>) -> InterpResult<'tcx> { // If this place is smaller than a pointer, we know that it can't contain any // pointers we need to retag, so we can stop recursion early. // This optimization is crucial for ZSTs, because they can contain way more fields @@ -984,10 +980,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// call. /// /// This is used to ensure soundness of in-place function argument/return passing. - fn sb_protect_place( - &mut self, - place: &MPlaceTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, MPlaceTy<'tcx, Provenance>> { + fn sb_protect_place(&mut self, place: &MPlaceTy<'tcx>) -> InterpResult<'tcx, MPlaceTy<'tcx>> { let this = self.eval_context_mut(); // Retag it. With protection! That is the entire point. diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs index 3b6c29b5eb154..f65f49a75ddd9 100644 --- a/src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs +++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs @@ -2,6 +2,7 @@ use std::ops::Range; use rustc_data_structures::fx::FxHashSet; +use tracing::trace; use crate::borrow_tracker::{ stacked_borrows::{Item, Permission}, diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs index e1c06b2bd98e5..77e003ab8a789 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs @@ -56,7 +56,7 @@ impl<'tcx> Tree { "{} with tag {:?}: {:?}, size {}", access_kind, prov, - Pointer::new(alloc_id, range.start), + interpret::Pointer::new(alloc_id, range.start), range.size.bytes(), ); // TODO: for now we bail out on wildcard pointers. Eventually we should @@ -195,7 +195,7 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// Returns the provenance that should be used henceforth. fn tb_reborrow( &mut self, - place: &MPlaceTy<'tcx, Provenance>, // parent tag extracted from here + place: &MPlaceTy<'tcx>, // parent tag extracted from here ptr_size: Size, new_perm: NewPermission, new_tag: BorTag, @@ -258,7 +258,7 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> { new_tag, orig_tag, place.layout.ty, - Pointer::new(alloc_id, base_offset), + interpret::Pointer::new(alloc_id, base_offset), ptr_size.bytes() ); @@ -327,9 +327,9 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn tb_retag_place( &mut self, - place: &MPlaceTy<'tcx, Provenance>, + place: &MPlaceTy<'tcx>, new_perm: NewPermission, - ) -> InterpResult<'tcx, MPlaceTy<'tcx, Provenance>> { + ) -> InterpResult<'tcx, MPlaceTy<'tcx>> { let this = self.eval_context_mut(); // Determine the size of the reborrow. @@ -366,9 +366,9 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// Retags an individual pointer, returning the retagged version. fn tb_retag_reference( &mut self, - val: &ImmTy<'tcx, Provenance>, + val: &ImmTy<'tcx>, new_perm: NewPermission, - ) -> InterpResult<'tcx, ImmTy<'tcx, Provenance>> { + ) -> InterpResult<'tcx, ImmTy<'tcx>> { let this = self.eval_context_mut(); let place = this.ref_to_mplace(val)?; let new_place = this.tb_retag_place(&place, new_perm)?; @@ -383,8 +383,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn tb_retag_ptr_value( &mut self, kind: RetagKind, - val: &ImmTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, ImmTy<'tcx, Provenance>> { + val: &ImmTy<'tcx>, + ) -> InterpResult<'tcx, ImmTy<'tcx>> { let this = self.eval_context_mut(); let new_perm = match val.layout.ty.kind() { &ty::Ref(_, pointee, mutability) => @@ -402,7 +402,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn tb_retag_place_contents( &mut self, kind: RetagKind, - place: &PlaceTy<'tcx, Provenance>, + place: &PlaceTy<'tcx>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let options = this.machine.borrow_tracker.as_mut().unwrap().get_mut(); @@ -423,7 +423,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { #[inline(always)] // yes this helps in our benchmarks fn retag_ptr_inplace( &mut self, - place: &PlaceTy<'tcx, Provenance>, + place: &PlaceTy<'tcx>, new_perm: Option, ) -> InterpResult<'tcx> { if let Some(new_perm) = new_perm { @@ -435,7 +435,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } } impl<'ecx, 'tcx> ValueVisitor<'tcx, MiriMachine<'tcx>> for RetagVisitor<'ecx, 'tcx> { - type V = PlaceTy<'tcx, Provenance>; + type V = PlaceTy<'tcx>; #[inline(always)] fn ecx(&self) -> &MiriInterpCx<'tcx> { @@ -445,11 +445,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// Regardless of how `Unique` is handled, Boxes are always reborrowed. /// When `Unique` is also reborrowed, then it behaves exactly like `Box` /// except for the fact that `Box` has a non-zero-sized reborrow. - fn visit_box( - &mut self, - box_ty: Ty<'tcx>, - place: &PlaceTy<'tcx, Provenance>, - ) -> InterpResult<'tcx> { + fn visit_box(&mut self, box_ty: Ty<'tcx>, place: &PlaceTy<'tcx>) -> InterpResult<'tcx> { // Only boxes for the global allocator get any special treatment. if box_ty.is_box_global(*self.ecx.tcx) { let new_perm = NewPermission::from_unique_ty( @@ -463,7 +459,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Ok(()) } - fn visit_value(&mut self, place: &PlaceTy<'tcx, Provenance>) -> InterpResult<'tcx> { + fn visit_value(&mut self, place: &PlaceTy<'tcx>) -> InterpResult<'tcx> { // If this place is smaller than a pointer, we know that it can't contain any // pointers we need to retag, so we can stop recursion early. // This optimization is crucial for ZSTs, because they can contain way more fields @@ -526,10 +522,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// call. /// /// This is used to ensure soundness of in-place function argument/return passing. - fn tb_protect_place( - &mut self, - place: &MPlaceTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, MPlaceTy<'tcx, Provenance>> { + fn tb_protect_place(&mut self, place: &MPlaceTy<'tcx>) -> InterpResult<'tcx, MPlaceTy<'tcx>> { let this = self.eval_context_mut(); // Retag it. With protection! That is the entire point. @@ -581,7 +574,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// of `ptr` (with 0 representing `ptr` itself) fn tb_give_pointer_debug_name( &mut self, - ptr: Pointer>, + ptr: Pointer, nth_parent: u8, name: &str, ) -> InterpResult<'tcx> { @@ -604,8 +597,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// and output can be used by `retag_ptr_inplace`. fn inner_ptr_of_unique<'tcx>( ecx: &MiriInterpCx<'tcx>, - place: &PlaceTy<'tcx, Provenance>, -) -> InterpResult<'tcx, PlaceTy<'tcx, Provenance>> { + place: &PlaceTy<'tcx>, +) -> InterpResult<'tcx, PlaceTy<'tcx>> { // Follows the same layout as `interpret/visitor.rs:walk_value` for `Box` in // `rustc_const_eval`, just with one fewer layer. // Here we have a `Unique(NonNull(*mut), PhantomData)` diff --git a/src/tools/miri/src/clock.rs b/src/tools/miri/src/clock.rs index fd0c121626b65..c9bffc449f7f0 100644 --- a/src/tools/miri/src/clock.rs +++ b/src/tools/miri/src/clock.rs @@ -6,7 +6,7 @@ use std::time::{Duration, Instant as StdInstant}; /// This number is pretty random, but it has been shown to approximately cause /// some sample programs to run within an order of magnitude of real time on desktop CPUs. /// (See `tests/pass/shims/time-with-isolation*.rs`.) -const NANOSECONDS_PER_BASIC_BLOCK: u64 = 5000; +const NANOSECONDS_PER_BASIC_BLOCK: u128 = 5000; #[derive(Debug)] pub struct Instant { @@ -16,19 +16,24 @@ pub struct Instant { #[derive(Debug)] enum InstantKind { Host(StdInstant), - Virtual { nanoseconds: u64 }, + Virtual { nanoseconds: u128 }, } impl Instant { - pub fn checked_add(&self, duration: Duration) -> Option { + /// Will try to add `duration`, but if that overflows it may add less. + pub fn add_lossy(&self, duration: Duration) -> Instant { match self.kind { - InstantKind::Host(instant) => - instant.checked_add(duration).map(|i| Instant { kind: InstantKind::Host(i) }), - InstantKind::Virtual { nanoseconds } => - u128::from(nanoseconds) - .checked_add(duration.as_nanos()) - .and_then(|n| u64::try_from(n).ok()) - .map(|nanoseconds| Instant { kind: InstantKind::Virtual { nanoseconds } }), + InstantKind::Host(instant) => { + // If this overflows, try adding just 1h and assume that will not overflow. + let i = instant + .checked_add(duration) + .unwrap_or_else(|| instant.checked_add(Duration::from_secs(3600)).unwrap()); + Instant { kind: InstantKind::Host(i) } + } + InstantKind::Virtual { nanoseconds } => { + let n = nanoseconds.saturating_add(duration.as_nanos()); + Instant { kind: InstantKind::Virtual { nanoseconds: n } } + } } } @@ -39,7 +44,17 @@ impl Instant { ( InstantKind::Virtual { nanoseconds }, InstantKind::Virtual { nanoseconds: earlier }, - ) => Duration::from_nanos(nanoseconds.saturating_sub(earlier)), + ) => { + let duration = nanoseconds.saturating_sub(earlier); + // `Duration` does not provide a nice constructor from a `u128` of nanoseconds, + // so we have to implement this ourselves. + // It is possible for second to overflow because u64::MAX < (u128::MAX / 1e9). + // It will be saturated to u64::MAX seconds if the value after division exceeds u64::MAX. + let seconds = u64::try_from(duration / 1_000_000_000).unwrap_or(u64::MAX); + // It is impossible for nanosecond to overflow because u32::MAX > 1e9. + let nanosecond = u32::try_from(duration.wrapping_rem(1_000_000_000)).unwrap(); + Duration::new(seconds, nanosecond) + } _ => panic!("all `Instant` must be of the same kind"), } } @@ -54,12 +69,13 @@ pub struct Clock { #[derive(Debug)] enum ClockKind { Host { - /// The "time anchor" for this machine's monotone clock. - time_anchor: StdInstant, + /// The "epoch" for this machine's monotone clock: + /// the moment we consider to be time = 0. + epoch: StdInstant, }, Virtual { /// The "current virtual time". - nanoseconds: Cell, + nanoseconds: Cell, }, } @@ -67,7 +83,7 @@ impl Clock { /// Create a new clock based on the availability of communication with the host. pub fn new(communicate: bool) -> Self { let kind = if communicate { - ClockKind::Host { time_anchor: StdInstant::now() } + ClockKind::Host { epoch: StdInstant::now() } } else { ClockKind::Virtual { nanoseconds: 0.into() } }; @@ -93,16 +109,19 @@ impl Clock { ClockKind::Host { .. } => std::thread::sleep(duration), ClockKind::Virtual { nanoseconds } => { // Just pretend that we have slept for some time. - let nanos: u64 = duration.as_nanos().try_into().unwrap(); - nanoseconds.update(|x| x + nanos); + let nanos: u128 = duration.as_nanos(); + nanoseconds.update(|x| { + x.checked_add(nanos) + .expect("Miri's virtual clock cannot represent an execution this long") + }); } } } - /// Return the `anchor` instant, to convert between monotone instants and durations relative to the anchor. - pub fn anchor(&self) -> Instant { + /// Return the `epoch` instant (time = 0), to convert between monotone instants and absolute durations. + pub fn epoch(&self) -> Instant { match &self.kind { - ClockKind::Host { time_anchor } => Instant { kind: InstantKind::Host(*time_anchor) }, + ClockKind::Host { epoch } => Instant { kind: InstantKind::Host(*epoch) }, ClockKind::Virtual { .. } => Instant { kind: InstantKind::Virtual { nanoseconds: 0 } }, } } diff --git a/src/tools/miri/src/concurrency/data_race.rs b/src/tools/miri/src/concurrency/data_race.rs index 719c262290ef2..2baa09bec168b 100644 --- a/src/tools/miri/src/concurrency/data_race.rs +++ b/src/tools/miri/src/concurrency/data_race.rs @@ -606,9 +606,9 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { /// Perform an atomic read operation at the memory location. fn read_scalar_atomic( &self, - place: &MPlaceTy<'tcx, Provenance>, + place: &MPlaceTy<'tcx>, atomic: AtomicReadOrd, - ) -> InterpResult<'tcx, Scalar> { + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_ref(); this.atomic_access_check(place, AtomicAccessType::Load(atomic))?; // This will read from the last store in the modification order of this location. In case @@ -625,8 +625,8 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { /// Perform an atomic write operation at the memory location. fn write_scalar_atomic( &mut self, - val: Scalar, - dest: &MPlaceTy<'tcx, Provenance>, + val: Scalar, + dest: &MPlaceTy<'tcx>, atomic: AtomicWriteOrd, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -645,12 +645,12 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { /// Perform an atomic RMW operation on a memory location. fn atomic_rmw_op_immediate( &mut self, - place: &MPlaceTy<'tcx, Provenance>, - rhs: &ImmTy<'tcx, Provenance>, + place: &MPlaceTy<'tcx>, + rhs: &ImmTy<'tcx>, op: mir::BinOp, not: bool, atomic: AtomicRwOrd, - ) -> InterpResult<'tcx, ImmTy<'tcx, Provenance>> { + ) -> InterpResult<'tcx, ImmTy<'tcx>> { let this = self.eval_context_mut(); this.atomic_access_check(place, AtomicAccessType::Rmw)?; @@ -670,10 +670,10 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { /// scalar value, the old value is returned. fn atomic_exchange_scalar( &mut self, - place: &MPlaceTy<'tcx, Provenance>, - new: Scalar, + place: &MPlaceTy<'tcx>, + new: Scalar, atomic: AtomicRwOrd, - ) -> InterpResult<'tcx, Scalar> { + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); this.atomic_access_check(place, AtomicAccessType::Rmw)?; @@ -690,11 +690,11 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { /// scalar value, the old value is returned. fn atomic_min_max_scalar( &mut self, - place: &MPlaceTy<'tcx, Provenance>, - rhs: ImmTy<'tcx, Provenance>, + place: &MPlaceTy<'tcx>, + rhs: ImmTy<'tcx>, min: bool, atomic: AtomicRwOrd, - ) -> InterpResult<'tcx, ImmTy<'tcx, Provenance>> { + ) -> InterpResult<'tcx, ImmTy<'tcx>> { let this = self.eval_context_mut(); this.atomic_access_check(place, AtomicAccessType::Rmw)?; @@ -726,9 +726,9 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { /// identical. fn atomic_compare_exchange_scalar( &mut self, - place: &MPlaceTy<'tcx, Provenance>, - expect_old: &ImmTy<'tcx, Provenance>, - new: Scalar, + place: &MPlaceTy<'tcx>, + expect_old: &ImmTy<'tcx>, + new: Scalar, success: AtomicRwOrd, fail: AtomicReadOrd, can_fail_spuriously: bool, @@ -948,7 +948,7 @@ impl VClockAlloc { mem_clocks: &MemoryCellClocks, access: AccessType, access_size: Size, - ptr_dbg: Pointer, + ptr_dbg: interpret::Pointer, ty: Option>, ) -> InterpResult<'tcx> { let (active_index, active_clocks) = global.active_thread_state(thread_mgr); @@ -1063,7 +1063,7 @@ impl VClockAlloc { mem_clocks, AccessType::NaRead(read_type), access_range.size, - Pointer::new(alloc_id, Size::from_bytes(mem_clocks_range.start)), + interpret::Pointer::new(alloc_id, Size::from_bytes(mem_clocks_range.start)), ty, ); } @@ -1108,7 +1108,7 @@ impl VClockAlloc { mem_clocks, AccessType::NaWrite(write_type), access_range.size, - Pointer::new(alloc_id, Size::from_bytes(mem_clocks_range.start)), + interpret::Pointer::new(alloc_id, Size::from_bytes(mem_clocks_range.start)), ty, ); } @@ -1163,7 +1163,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { /// Checks that an atomic access is legal at the given place. fn atomic_access_check( &self, - place: &MPlaceTy<'tcx, Provenance>, + place: &MPlaceTy<'tcx>, access_type: AtomicAccessType, ) -> InterpResult<'tcx> { let this = self.eval_context_ref(); @@ -1219,7 +1219,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { /// associated memory-place and on the current thread. fn validate_atomic_load( &self, - place: &MPlaceTy<'tcx, Provenance>, + place: &MPlaceTy<'tcx>, atomic: AtomicReadOrd, ) -> InterpResult<'tcx> { let this = self.eval_context_ref(); @@ -1241,7 +1241,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { /// associated memory-place and on the current thread. fn validate_atomic_store( &mut self, - place: &MPlaceTy<'tcx, Provenance>, + place: &MPlaceTy<'tcx>, atomic: AtomicWriteOrd, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -1263,7 +1263,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { /// at the associated memory place and on the current thread. fn validate_atomic_rmw( &mut self, - place: &MPlaceTy<'tcx, Provenance>, + place: &MPlaceTy<'tcx>, atomic: AtomicRwOrd, ) -> InterpResult<'tcx> { use AtomicRwOrd::*; @@ -1292,7 +1292,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { /// Generic atomic operation implementation fn validate_atomic_op( &self, - place: &MPlaceTy<'tcx, Provenance>, + place: &MPlaceTy<'tcx>, atomic: A, access: AccessType, mut op: impl FnMut( @@ -1337,7 +1337,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { mem_clocks, access, place.layout.size, - Pointer::new( + interpret::Pointer::new( alloc_id, Size::from_bytes(mem_clocks_range.start), ), diff --git a/src/tools/miri/src/concurrency/init_once.rs b/src/tools/miri/src/concurrency/init_once.rs index ed10c12802692..9145ef32c525b 100644 --- a/src/tools/miri/src/concurrency/init_once.rs +++ b/src/tools/miri/src/concurrency/init_once.rs @@ -7,7 +7,7 @@ use super::sync::EvalContextExtPriv as _; use super::vector_clock::VClock; use crate::*; -declare_id!(InitOnceId); +super::sync::declare_id!(InitOnceId); #[derive(Default, Debug, Copy, Clone, PartialEq, Eq)] /// The current status of a one time initialization. @@ -33,10 +33,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { #[inline] fn init_once_get_or_create(&mut self, existing: F) -> InterpResult<'tcx, InitOnceId> where - F: FnOnce( - &mut MiriInterpCx<'tcx>, - InitOnceId, - ) -> InterpResult<'tcx, Option>, + F: FnOnce(&mut MiriInterpCx<'tcx>, InitOnceId) -> InterpResult<'tcx, Option>, { let this = self.eval_context_mut(); let next_index = this.machine.sync.init_onces.next_index(); @@ -54,7 +51,7 @@ impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn init_once_get_or_create_id( &mut self, - lock_op: &OpTy<'tcx, Provenance>, + lock_op: &OpTy<'tcx>, lock_layout: TyAndLayout<'tcx>, offset: u64, ) -> InterpResult<'tcx, InitOnceId> { diff --git a/src/tools/miri/src/concurrency/mod.rs b/src/tools/miri/src/concurrency/mod.rs index 15e1a94d6db0e..822d173ac06a7 100644 --- a/src/tools/miri/src/concurrency/mod.rs +++ b/src/tools/miri/src/concurrency/mod.rs @@ -1,8 +1,7 @@ pub mod data_race; +pub mod init_once; mod range_object_map; -#[macro_use] pub mod sync; -pub mod init_once; pub mod thread; mod vector_clock; pub mod weak_memory; diff --git a/src/tools/miri/src/concurrency/sync.rs b/src/tools/miri/src/concurrency/sync.rs index 52036f4ed2c1d..76a045c4dc166 100644 --- a/src/tools/miri/src/concurrency/sync.rs +++ b/src/tools/miri/src/concurrency/sync.rs @@ -1,5 +1,6 @@ use std::collections::{hash_map::Entry, VecDeque}; use std::ops::Not; +use std::time::Duration; use rustc_data_structures::fx::FxHashMap; use rustc_index::{Idx, IndexVec}; @@ -55,12 +56,13 @@ macro_rules! declare_id { } impl $name { - pub fn to_u32_scalar(&self) -> Scalar { + pub fn to_u32_scalar(&self) -> Scalar { Scalar::from_u32(self.0.get()) } } }; } +pub(super) use declare_id; declare_id!(MutexId); @@ -160,16 +162,14 @@ pub struct SynchronizationObjects { // Private extension trait for local helper methods impl<'tcx> EvalContextExtPriv<'tcx> for crate::MiriInterpCx<'tcx> {} -pub(super) trait EvalContextExtPriv<'tcx>: - crate::MiriInterpCxExt<'tcx> -{ +pub(super) trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { /// Lazily initialize the ID of this Miri sync structure. /// ('0' indicates uninit.) #[inline] fn get_or_create_id( &mut self, next_id: Id, - lock_op: &OpTy<'tcx, Provenance>, + lock_op: &OpTy<'tcx>, lock_layout: TyAndLayout<'tcx>, offset: u64, ) -> InterpResult<'tcx, Option> { @@ -244,10 +244,7 @@ pub(super) trait EvalContextExtPriv<'tcx>: #[inline] fn condvar_get_or_create(&mut self, existing: F) -> InterpResult<'tcx, CondvarId> where - F: FnOnce( - &mut MiriInterpCx<'tcx>, - CondvarId, - ) -> InterpResult<'tcx, Option>, + F: FnOnce(&mut MiriInterpCx<'tcx>, CondvarId) -> InterpResult<'tcx, Option>, { let this = self.eval_context_mut(); let next_index = this.machine.sync.condvars.next_index(); @@ -266,8 +263,8 @@ pub(super) trait EvalContextExtPriv<'tcx>: fn condvar_reacquire_mutex( &mut self, mutex: MutexId, - retval: Scalar, - dest: MPlaceTy<'tcx, Provenance>, + retval: Scalar, + dest: MPlaceTy<'tcx>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); if this.mutex_is_locked(mutex) { @@ -291,7 +288,7 @@ impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn mutex_get_or_create_id( &mut self, - lock_op: &OpTy<'tcx, Provenance>, + lock_op: &OpTy<'tcx>, lock_layout: TyAndLayout<'tcx>, offset: u64, ) -> InterpResult<'tcx, MutexId> { @@ -303,7 +300,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn rwlock_get_or_create_id( &mut self, - lock_op: &OpTy<'tcx, Provenance>, + lock_op: &OpTy<'tcx>, lock_layout: TyAndLayout<'tcx>, offset: u64, ) -> InterpResult<'tcx, RwLockId> { @@ -315,7 +312,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn condvar_get_or_create_id( &mut self, - lock_op: &OpTy<'tcx, Provenance>, + lock_op: &OpTy<'tcx>, lock_layout: TyAndLayout<'tcx>, offset: u64, ) -> InterpResult<'tcx, CondvarId> { @@ -397,12 +394,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// Put the thread into the queue waiting for the mutex. /// Once the Mutex becomes available, `retval` will be written to `dest`. #[inline] - fn mutex_enqueue_and_block( - &mut self, - id: MutexId, - retval: Scalar, - dest: MPlaceTy<'tcx, Provenance>, - ) { + fn mutex_enqueue_and_block(&mut self, id: MutexId, retval: Scalar, dest: MPlaceTy<'tcx>) { let this = self.eval_context_mut(); assert!(this.mutex_is_locked(id), "queing on unlocked mutex"); let thread = this.active_thread(); @@ -413,8 +405,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { callback!( @capture<'tcx> { id: MutexId, - retval: Scalar, - dest: MPlaceTy<'tcx, Provenance>, + retval: Scalar, + dest: MPlaceTy<'tcx>, } @unblock = |this| { assert!(!this.mutex_is_locked(id)); @@ -510,8 +502,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn rwlock_enqueue_and_block_reader( &mut self, id: RwLockId, - retval: Scalar, - dest: MPlaceTy<'tcx, Provenance>, + retval: Scalar, + dest: MPlaceTy<'tcx>, ) { let this = self.eval_context_mut(); let thread = this.active_thread(); @@ -523,8 +515,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { callback!( @capture<'tcx> { id: RwLockId, - retval: Scalar, - dest: MPlaceTy<'tcx, Provenance>, + retval: Scalar, + dest: MPlaceTy<'tcx>, } @unblock = |this| { this.rwlock_reader_lock(id); @@ -593,8 +585,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn rwlock_enqueue_and_block_writer( &mut self, id: RwLockId, - retval: Scalar, - dest: MPlaceTy<'tcx, Provenance>, + retval: Scalar, + dest: MPlaceTy<'tcx>, ) { let this = self.eval_context_mut(); assert!(this.rwlock_is_locked(id), "write-queueing on unlocked rwlock"); @@ -606,8 +598,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { callback!( @capture<'tcx> { id: RwLockId, - retval: Scalar, - dest: MPlaceTy<'tcx, Provenance>, + retval: Scalar, + dest: MPlaceTy<'tcx>, } @unblock = |this| { this.rwlock_writer_lock(id); @@ -632,10 +624,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { &mut self, condvar: CondvarId, mutex: MutexId, - timeout: Option, - retval_succ: Scalar, - retval_timeout: Scalar, - dest: MPlaceTy<'tcx, Provenance>, + timeout: Option<(TimeoutClock, TimeoutAnchor, Duration)>, + retval_succ: Scalar, + retval_timeout: Scalar, + dest: MPlaceTy<'tcx>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); if let Some(old_locked_count) = this.mutex_unlock(mutex)? { @@ -659,9 +651,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { @capture<'tcx> { condvar: CondvarId, mutex: MutexId, - retval_succ: Scalar, - retval_timeout: Scalar, - dest: MPlaceTy<'tcx, Provenance>, + retval_succ: Scalar, + retval_timeout: Scalar, + dest: MPlaceTy<'tcx>, } @unblock = |this| { // The condvar was signaled. Make sure we get the clock for that. @@ -713,11 +705,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { &mut self, addr: u64, bitset: u32, - timeout: Option, - retval_succ: Scalar, - retval_timeout: Scalar, - dest: MPlaceTy<'tcx, Provenance>, - errno_timeout: Scalar, + timeout: Option<(TimeoutClock, TimeoutAnchor, Duration)>, + retval_succ: Scalar, + retval_timeout: Scalar, + dest: MPlaceTy<'tcx>, + errno_timeout: Scalar, ) { let this = self.eval_context_mut(); let thread = this.active_thread(); @@ -731,10 +723,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { callback!( @capture<'tcx> { addr: u64, - retval_succ: Scalar, - retval_timeout: Scalar, - dest: MPlaceTy<'tcx, Provenance>, - errno_timeout: Scalar, + retval_succ: Scalar, + retval_timeout: Scalar, + dest: MPlaceTy<'tcx>, + errno_timeout: Scalar, } @unblock = |this| { let futex = this.machine.sync.futexes.get(&addr).unwrap(); diff --git a/src/tools/miri/src/concurrency/thread.rs b/src/tools/miri/src/concurrency/thread.rs index 06af72dadbd38..6a2b99825adc4 100644 --- a/src/tools/miri/src/concurrency/thread.rs +++ b/src/tools/miri/src/concurrency/thread.rs @@ -256,10 +256,10 @@ pub struct Thread<'tcx> { /// which then forwards it to 'Resume'. However this argument is implicit in MIR, /// so we have to store it out-of-band. When there are multiple active unwinds, /// the innermost one is always caught first, so we can store them as a stack. - pub(crate) panic_payloads: Vec>, + pub(crate) panic_payloads: Vec, /// Last OS error location in memory. It is a 32-bit integer. - pub(crate) last_error: Option>, + pub(crate) last_error: Option>, } pub type StackEmptyCallback<'tcx> = @@ -407,7 +407,7 @@ impl VisitProvenance for Frame<'_, Provenance, FrameExtra<'_>> { /// The moment in time when a blocked thread should be woken up. #[derive(Debug)] -pub enum Timeout { +enum Timeout { Monotonic(Instant), RealTime(SystemTime), } @@ -421,6 +421,34 @@ impl Timeout { time.duration_since(SystemTime::now()).unwrap_or(Duration::ZERO), } } + + /// Will try to add `duration`, but if that overflows it may add less. + fn add_lossy(&self, duration: Duration) -> Self { + match self { + Timeout::Monotonic(i) => Timeout::Monotonic(i.add_lossy(duration)), + Timeout::RealTime(s) => { + // If this overflows, try adding just 1h and assume that will not overflow. + Timeout::RealTime( + s.checked_add(duration) + .unwrap_or_else(|| s.checked_add(Duration::from_secs(3600)).unwrap()), + ) + } + } + } +} + +/// The clock to use for the timeout you are asking for. +#[derive(Debug, Copy, Clone)] +pub enum TimeoutClock { + Monotonic, + RealTime, +} + +/// Whether the timeout is relative or absolute. +#[derive(Debug, Copy, Clone)] +pub enum TimeoutAnchor { + Relative, + Absolute, } /// A set of threads. @@ -432,9 +460,8 @@ pub struct ThreadManager<'tcx> { /// /// Note that this vector also contains terminated threads. threads: IndexVec>, - /// A mapping from a thread-local static to an allocation id of a thread - /// specific allocation. - thread_local_alloc_ids: FxHashMap<(DefId, ThreadId), Pointer>, + /// A mapping from a thread-local static to the thread specific allocation. + thread_local_allocs: FxHashMap<(DefId, ThreadId), StrictPointer>, /// A flag that indicates that we should change the active thread. yield_active_thread: bool, } @@ -443,7 +470,7 @@ impl VisitProvenance for ThreadManager<'_> { fn visit_provenance(&self, visit: &mut VisitWith<'_>) { let ThreadManager { threads, - thread_local_alloc_ids, + thread_local_allocs, active_thread: _, yield_active_thread: _, } = self; @@ -451,7 +478,7 @@ impl VisitProvenance for ThreadManager<'_> { for thread in threads { thread.visit_provenance(visit); } - for ptr in thread_local_alloc_ids.values() { + for ptr in thread_local_allocs.values() { ptr.visit_provenance(visit); } } @@ -465,7 +492,7 @@ impl<'tcx> Default for ThreadManager<'tcx> { Self { active_thread: ThreadId::MAIN_THREAD, threads, - thread_local_alloc_ids: Default::default(), + thread_local_allocs: Default::default(), yield_active_thread: false, } } @@ -487,16 +514,16 @@ impl<'tcx> ThreadManager<'tcx> { /// Check if we have an allocation for the given thread local static for the /// active thread. - fn get_thread_local_alloc_id(&self, def_id: DefId) -> Option> { - self.thread_local_alloc_ids.get(&(def_id, self.active_thread)).cloned() + fn get_thread_local_alloc_id(&self, def_id: DefId) -> Option { + self.thread_local_allocs.get(&(def_id, self.active_thread)).cloned() } /// Set the pointer for the allocation of the given thread local /// static for the active thread. /// /// Panics if a thread local is initialized twice for the same thread. - fn set_thread_local_alloc(&mut self, def_id: DefId, ptr: Pointer) { - self.thread_local_alloc_ids.try_insert((def_id, self.active_thread), ptr).unwrap(); + fn set_thread_local_alloc(&mut self, def_id: DefId, ptr: StrictPointer) { + self.thread_local_allocs.try_insert((def_id, self.active_thread), ptr).unwrap(); } /// Borrow the stack of the active thread. @@ -848,7 +875,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn get_or_create_thread_local_alloc( &mut self, def_id: DefId, - ) -> InterpResult<'tcx, Pointer> { + ) -> InterpResult<'tcx, StrictPointer> { let this = self.eval_context_mut(); let tcx = this.tcx; if let Some(old_alloc) = this.machine.threads.get_thread_local_alloc_id(def_id) { @@ -864,7 +891,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } let alloc = this.ctfe_query(|tcx| tcx.eval_static_initializer(def_id))?; // We make a full copy of this allocation. - let mut alloc = alloc.inner().adjust_from_tcx(&this.tcx, |ptr| this.global_root_pointer(ptr))?; + let mut alloc = + alloc.inner().adjust_from_tcx(&this.tcx, |ptr| this.global_root_pointer(ptr))?; // This allocation will be deallocated when the thread dies, so it is not in read-only memory. alloc.mutability = Mutability::Mut; // Create a fresh allocation with this content. @@ -878,10 +906,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { #[inline] fn start_regular_thread( &mut self, - thread: Option>, - start_routine: Pointer>, + thread: Option>, + start_routine: Pointer, start_abi: Abi, - func_arg: ImmTy<'tcx, Provenance>, + func_arg: ImmTy<'tcx>, ret_layout: TyAndLayout<'tcx>, ) -> InterpResult<'tcx, ThreadId> { let this = self.eval_context_mut(); @@ -948,18 +976,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let gone_thread = this.active_thread(); { let mut free_tls_statics = Vec::new(); - this.machine.threads.thread_local_alloc_ids.retain( - |&(_def_id, thread), &mut alloc_id| { - if thread != gone_thread { - // A different thread, keep this static around. - return true; - } - // Delete this static from the map and from memory. - // We cannot free directly here as we cannot use `?` in this context. - free_tls_statics.push(alloc_id); - false - }, - ); + this.machine.threads.thread_local_allocs.retain(|&(_def_id, thread), &mut alloc_id| { + if thread != gone_thread { + // A different thread, keep this static around. + return true; + } + // Delete this static from the map and from memory. + // We cannot free directly here as we cannot use `?` in this context. + free_tls_statics.push(alloc_id); + false + }); // Now free the TLS statics. for ptr in free_tls_statics { match tls_alloc_action { @@ -997,13 +1023,30 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn block_thread( &mut self, reason: BlockReason, - timeout: Option, + timeout: Option<(TimeoutClock, TimeoutAnchor, Duration)>, callback: impl UnblockCallback<'tcx> + 'tcx, ) { let this = self.eval_context_mut(); - if !this.machine.communicate() && matches!(timeout, Some(Timeout::RealTime(..))) { - panic!("cannot have `RealTime` callback with isolation enabled!") - } + let timeout = timeout.map(|(clock, anchor, duration)| { + let anchor = match clock { + TimeoutClock::RealTime => { + assert!( + this.machine.communicate(), + "cannot have `RealTime` timeout with isolation enabled!" + ); + Timeout::RealTime(match anchor { + TimeoutAnchor::Absolute => SystemTime::UNIX_EPOCH, + TimeoutAnchor::Relative => SystemTime::now(), + }) + } + TimeoutClock::Monotonic => + Timeout::Monotonic(match anchor { + TimeoutAnchor::Absolute => this.machine.clock.epoch(), + TimeoutAnchor::Relative => this.machine.clock.now(), + }), + }; + anchor.add_lossy(duration) + }); this.machine.threads.block_thread(reason, timeout, callback); } diff --git a/src/tools/miri/src/concurrency/weak_memory.rs b/src/tools/miri/src/concurrency/weak_memory.rs index 7a49f6d34707b..e92eaa8f91f75 100644 --- a/src/tools/miri/src/concurrency/weak_memory.rs +++ b/src/tools/miri/src/concurrency/weak_memory.rs @@ -148,7 +148,7 @@ struct StoreElement { // FIXME: this means the store must be fully initialized; // we will have to change this if we want to support atomics on // (partially) uninitialized data. - val: Scalar, + val: Scalar, /// Metadata about loads from this store element, /// behind a RefCell to keep load op take &self @@ -197,7 +197,7 @@ impl StoreBufferAlloc { fn get_or_create_store_buffer<'tcx>( &self, range: AllocRange, - init: Scalar, + init: Scalar, ) -> InterpResult<'tcx, Ref<'_, StoreBuffer>> { let access_type = self.store_buffers.borrow().access_type(range); let pos = match access_type { @@ -222,7 +222,7 @@ impl StoreBufferAlloc { fn get_or_create_store_buffer_mut<'tcx>( &mut self, range: AllocRange, - init: Scalar, + init: Scalar, ) -> InterpResult<'tcx, &mut StoreBuffer> { let buffers = self.store_buffers.get_mut(); let access_type = buffers.access_type(range); @@ -244,7 +244,7 @@ impl StoreBufferAlloc { } impl<'tcx> StoreBuffer { - fn new(init: Scalar) -> Self { + fn new(init: Scalar) -> Self { let mut buffer = VecDeque::new(); buffer.reserve(STORE_BUFFER_LIMIT); let mut ret = Self { buffer }; @@ -282,7 +282,7 @@ impl<'tcx> StoreBuffer { is_seqcst: bool, rng: &mut (impl rand::Rng + ?Sized), validate: impl FnOnce() -> InterpResult<'tcx>, - ) -> InterpResult<'tcx, (Scalar, LoadRecency)> { + ) -> InterpResult<'tcx, (Scalar, LoadRecency)> { // Having a live borrow to store_buffer while calling validate_atomic_load is fine // because the race detector doesn't touch store_buffer @@ -307,7 +307,7 @@ impl<'tcx> StoreBuffer { fn buffered_write( &mut self, - val: Scalar, + val: Scalar, global: &DataRaceState, thread_mgr: &ThreadManager<'_>, is_seqcst: bool, @@ -408,7 +408,7 @@ impl<'tcx> StoreBuffer { /// ATOMIC STORE IMPL in the paper (except we don't need the location's vector clock) fn store_impl( &mut self, - val: Scalar, + val: Scalar, index: VectorIdx, thread_clock: &VClock, is_seqcst: bool, @@ -450,12 +450,7 @@ impl StoreElement { /// buffer regardless of subsequent loads by the same thread; if the earliest load of another /// thread doesn't happen before the current one, then no subsequent load by the other thread /// can happen before the current one. - fn load_impl( - &self, - index: VectorIdx, - clocks: &ThreadClockSet, - is_seqcst: bool, - ) -> Scalar { + fn load_impl(&self, index: VectorIdx, clocks: &ThreadClockSet, is_seqcst: bool) -> Scalar { let mut load_info = self.load_info.borrow_mut(); load_info.sc_loaded |= is_seqcst; let _ = load_info.timestamps.try_insert(index, clocks.clock[index]); @@ -467,10 +462,10 @@ impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn buffered_atomic_rmw( &mut self, - new_val: Scalar, - place: &MPlaceTy<'tcx, Provenance>, + new_val: Scalar, + place: &MPlaceTy<'tcx>, atomic: AtomicRwOrd, - init: Scalar, + init: Scalar, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr())?; @@ -493,11 +488,11 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn buffered_atomic_read( &self, - place: &MPlaceTy<'tcx, Provenance>, + place: &MPlaceTy<'tcx>, atomic: AtomicReadOrd, - latest_in_mo: Scalar, + latest_in_mo: Scalar, validate: impl FnOnce() -> InterpResult<'tcx>, - ) -> InterpResult<'tcx, Scalar> { + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_ref(); if let Some(global) = &this.machine.data_race { let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr())?; @@ -534,10 +529,10 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn buffered_atomic_write( &mut self, - val: Scalar, - dest: &MPlaceTy<'tcx, Provenance>, + val: Scalar, + dest: &MPlaceTy<'tcx>, atomic: AtomicWriteOrd, - init: Scalar, + init: Scalar, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(dest.ptr())?; @@ -579,9 +574,9 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// to perform load_impl on the latest store element fn perform_read_on_buffered_latest( &self, - place: &MPlaceTy<'tcx, Provenance>, + place: &MPlaceTy<'tcx>, atomic: AtomicReadOrd, - init: Scalar, + init: Scalar, ) -> InterpResult<'tcx> { let this = self.eval_context_ref(); diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs index d55f21d74efc8..14e29aa423d8d 100644 --- a/src/tools/miri/src/diagnostics.rs +++ b/src/tools/miri/src/diagnostics.rs @@ -42,7 +42,7 @@ pub enum TerminationInfo { }, DataRace { involves_non_atomic: bool, - ptr: Pointer, + ptr: interpret::Pointer, op1: RacingOp, op2: RacingOp, extra: Option<&'static str>, @@ -128,7 +128,7 @@ pub enum NonHaltingDiagnostic { details: bool, }, WeakMemoryOutdatedLoad { - ptr: Pointer>, + ptr: Pointer, }, } diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index c3282c1af036f..87b53d87ac87e 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -255,7 +255,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } /// Evaluates the scalar at the specified path. - fn eval_path(&self, path: &[&str]) -> OpTy<'tcx, Provenance> { + fn eval_path(&self, path: &[&str]) -> OpTy<'tcx> { let this = self.eval_context_ref(); let instance = this.resolve_path(path, Namespace::ValueNS); // We don't give a span -- this isn't actually used directly by the program anyway. @@ -264,7 +264,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { }); const_val.into() } - fn eval_path_scalar(&self, path: &[&str]) -> Scalar { + fn eval_path_scalar(&self, path: &[&str]) -> Scalar { let this = self.eval_context_ref(); let val = this.eval_path(path); this.read_scalar(&val) @@ -272,7 +272,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } /// Helper function to get a `libc` constant as a `Scalar`. - fn eval_libc(&self, name: &str) -> Scalar { + fn eval_libc(&self, name: &str) -> Scalar { self.eval_path_scalar(&["libc", name]) } @@ -293,7 +293,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } /// Helper function to get a `windows` constant as a `Scalar`. - fn eval_windows(&self, module: &str, name: &str) -> Scalar { + fn eval_windows(&self, module: &str, name: &str) -> Scalar { self.eval_context_ref().eval_path_scalar(&["std", "sys", "pal", "windows", module, name]) } @@ -374,7 +374,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let val = if dest.layout().abi.is_signed() { Scalar::from_int(i, dest.layout().size) } else { - Scalar::from_uint(u64::try_from(i.into()).unwrap(), dest.layout().size) + // `unwrap` can only fail here if `i` is negative + Scalar::from_uint(u128::try_from(i.into()).unwrap(), dest.layout().size) }; self.eval_context_mut().write_scalar(val, dest) } @@ -413,12 +414,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } /// Test if this pointer equals 0. - fn ptr_is_null(&self, ptr: Pointer>) -> InterpResult<'tcx, bool> { + fn ptr_is_null(&self, ptr: Pointer) -> InterpResult<'tcx, bool> { Ok(ptr.addr().bytes() == 0) } /// Generate some random bytes, and write them to `dest`. - fn gen_random(&mut self, ptr: Pointer>, len: u64) -> InterpResult<'tcx> { + fn gen_random(&mut self, ptr: Pointer, len: u64) -> InterpResult<'tcx> { // Some programs pass in a null pointer and a length of 0 // to their platform's random-generation function (e.g. getrandom()) // on Linux. For compatibility with these programs, we don't perform @@ -453,7 +454,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { f: ty::Instance<'tcx>, caller_abi: Abi, args: &[Immediate], - dest: Option<&MPlaceTy<'tcx, Provenance>>, + dest: Option<&MPlaceTy<'tcx>>, stack_pop: StackPopCleanup, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -501,7 +502,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// The range is relative to `place`. fn visit_freeze_sensitive( &self, - place: &MPlaceTy<'tcx, Provenance>, + place: &MPlaceTy<'tcx>, size: Size, mut action: impl FnMut(AllocRange, bool) -> InterpResult<'tcx>, ) -> InterpResult<'tcx> { @@ -520,8 +521,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let mut cur_addr = start_addr; // Called when we detected an `UnsafeCell` at the given offset and size. // Calls `action` and advances `cur_ptr`. - let mut unsafe_cell_action = |unsafe_cell_ptr: &Pointer>, - unsafe_cell_size: Size| { + let mut unsafe_cell_action = |unsafe_cell_ptr: &Pointer, unsafe_cell_size: Size| { // We assume that we are given the fields in increasing offset order, // and nothing else changes. let unsafe_cell_addr = unsafe_cell_ptr.addr(); @@ -575,7 +575,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// whether we are inside an `UnsafeCell` or not. struct UnsafeCellVisitor<'ecx, 'tcx, F> where - F: FnMut(&MPlaceTy<'tcx, Provenance>) -> InterpResult<'tcx>, + F: FnMut(&MPlaceTy<'tcx>) -> InterpResult<'tcx>, { ecx: &'ecx MiriInterpCx<'tcx>, unsafe_cell_action: F, @@ -583,9 +583,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { impl<'ecx, 'tcx, F> ValueVisitor<'tcx, MiriMachine<'tcx>> for UnsafeCellVisitor<'ecx, 'tcx, F> where - F: FnMut(&MPlaceTy<'tcx, Provenance>) -> InterpResult<'tcx>, + F: FnMut(&MPlaceTy<'tcx>) -> InterpResult<'tcx>, { - type V = MPlaceTy<'tcx, Provenance>; + type V = MPlaceTy<'tcx>; #[inline(always)] fn ecx(&self) -> &MiriInterpCx<'tcx> { @@ -603,7 +603,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } // Hook to detect `UnsafeCell`. - fn visit_value(&mut self, v: &MPlaceTy<'tcx, Provenance>) -> InterpResult<'tcx> { + fn visit_value(&mut self, v: &MPlaceTy<'tcx>) -> InterpResult<'tcx> { trace!("UnsafeCellVisitor: {:?} {:?}", *v, v.layout.ty); let is_unsafe_cell = match v.layout.ty.kind() { ty::Adt(adt, _) => @@ -649,7 +649,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn visit_union( &mut self, - _v: &MPlaceTy<'tcx, Provenance>, + _v: &MPlaceTy<'tcx>, _fields: NonZero, ) -> InterpResult<'tcx> { bug!("we should have already handled unions in `visit_value`") @@ -720,7 +720,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// Get last error variable as a place, lazily allocating thread-local storage for it if /// necessary. - fn last_error_place(&mut self) -> InterpResult<'tcx, MPlaceTy<'tcx, Provenance>> { + fn last_error_place(&mut self) -> InterpResult<'tcx, MPlaceTy<'tcx>> { let this = self.eval_context_mut(); if let Some(errno_place) = this.active_thread_ref().last_error.as_ref() { Ok(errno_place.clone()) @@ -735,14 +735,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } /// Sets the last error variable. - fn set_last_error(&mut self, scalar: Scalar) -> InterpResult<'tcx> { + fn set_last_error(&mut self, scalar: Scalar) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let errno_place = this.last_error_place()?; this.write_scalar(scalar, &errno_place) } /// Gets the last error variable. - fn get_last_error(&mut self) -> InterpResult<'tcx, Scalar> { + fn get_last_error(&mut self) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let errno_place = this.last_error_place()?; this.read_scalar(&errno_place) @@ -750,7 +750,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// This function tries to produce the most similar OS error from the `std::io::ErrorKind` /// as a platform-specific errnum. - fn io_error_to_errnum(&self, err: std::io::Error) -> InterpResult<'tcx, Scalar> { + fn io_error_to_errnum(&self, err: std::io::Error) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_ref(); let target = &this.tcx.sess.target; if target.families.iter().any(|f| f == "unix") { @@ -779,7 +779,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { #[allow(clippy::needless_return)] fn try_errnum_to_io_error( &self, - errnum: Scalar, + errnum: Scalar, ) -> InterpResult<'tcx, Option> { let this = self.eval_context_ref(); let target = &this.tcx.sess.target; @@ -836,7 +836,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { &self, op: &impl Readable<'tcx, Provenance>, layout: TyAndLayout<'tcx>, - ) -> InterpResult<'tcx, MPlaceTy<'tcx, Provenance>> { + ) -> InterpResult<'tcx, MPlaceTy<'tcx>> { let this = self.eval_context_ref(); let ptr = this.read_pointer(op)?; Ok(this.ptr_to_mplace(ptr, layout)) @@ -849,7 +849,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { offset: u64, base_layout: TyAndLayout<'tcx>, value_layout: TyAndLayout<'tcx>, - ) -> InterpResult<'tcx, MPlaceTy<'tcx, Provenance>> { + ) -> InterpResult<'tcx, MPlaceTy<'tcx>> { let this = self.eval_context_ref(); let op_place = this.deref_pointer_as(op, base_layout)?; let offset = Size::from_bytes(offset); @@ -866,7 +866,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { offset: u64, base_layout: TyAndLayout<'tcx>, value_layout: TyAndLayout<'tcx>, - ) -> InterpResult<'tcx, Scalar> { + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_ref(); let value_place = this.deref_pointer_and_offset(op, offset, base_layout, value_layout)?; this.read_scalar(&value_place) @@ -876,7 +876,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { &mut self, op: &impl Readable<'tcx, Provenance>, offset: u64, - value: impl Into>, + value: impl Into, base_layout: TyAndLayout<'tcx>, value_layout: TyAndLayout<'tcx>, ) -> InterpResult<'tcx, ()> { @@ -888,10 +888,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// Parse a `timespec` struct and return it as a `std::time::Duration`. It returns `None` /// if the value in the `timespec` struct is invalid. Some libc functions will return /// `EINVAL` in this case. - fn read_timespec( - &mut self, - tp: &MPlaceTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, Option> { + fn read_timespec(&mut self, tp: &MPlaceTy<'tcx>) -> InterpResult<'tcx, Option> { let this = self.eval_context_mut(); let seconds_place = this.project_field(tp, 0)?; let seconds_scalar = this.read_scalar(&seconds_place)?; @@ -914,10 +911,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } /// Read bytes from a byte slice. - fn read_byte_slice<'a>( - &'a self, - slice: &ImmTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, &'a [u8]> + fn read_byte_slice<'a>(&'a self, slice: &ImmTy<'tcx>) -> InterpResult<'tcx, &'a [u8]> where 'tcx: 'a, { @@ -930,7 +924,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } /// Read a sequence of bytes until the first null terminator. - fn read_c_str<'a>(&'a self, ptr: Pointer>) -> InterpResult<'tcx, &'a [u8]> + fn read_c_str<'a>(&'a self, ptr: Pointer) -> InterpResult<'tcx, &'a [u8]> where 'tcx: 'a, { @@ -963,7 +957,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn write_c_str( &mut self, c_str: &[u8], - ptr: Pointer>, + ptr: Pointer, size: u64, ) -> InterpResult<'tcx, (bool, u64)> { // If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required null @@ -982,7 +976,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// until the first null terminator. fn read_c_str_with_char_size( &self, - mut ptr: Pointer>, + mut ptr: Pointer, size: Size, align: Align, ) -> InterpResult<'tcx, Vec> @@ -1014,7 +1008,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } /// Read a sequence of u16 until the first null terminator. - fn read_wide_str(&self, ptr: Pointer>) -> InterpResult<'tcx, Vec> { + fn read_wide_str(&self, ptr: Pointer) -> InterpResult<'tcx, Vec> { self.read_c_str_with_char_size(ptr, Size::from_bytes(2), Align::from_bytes(2).unwrap()) } @@ -1027,7 +1021,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn write_wide_str( &mut self, wide_str: &[u16], - ptr: Pointer>, + ptr: Pointer, size: u64, ) -> InterpResult<'tcx, (bool, u64)> { // If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required @@ -1052,7 +1046,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// Read a sequence of wchar_t until the first null terminator. /// Always returns a `Vec` no matter the size of `wchar_t`. - fn read_wchar_t_str(&self, ptr: Pointer>) -> InterpResult<'tcx, Vec> { + fn read_wchar_t_str(&self, ptr: Pointer) -> InterpResult<'tcx, Vec> { let this = self.eval_context_ref(); let wchar_t = this.libc_ty_layout("wchar_t"); self.read_c_str_with_char_size(ptr, wchar_t.size, wchar_t.align.abi) @@ -1138,17 +1132,17 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { abi: Abi, exp_abi: Abi, link_name: Symbol, - args: &'a [OpTy<'tcx, Provenance>], - ) -> InterpResult<'tcx, &'a [OpTy<'tcx, Provenance>; N]> + args: &'a [OpTy<'tcx>], + ) -> InterpResult<'tcx, &'a [OpTy<'tcx>; N]> where - &'a [OpTy<'tcx, Provenance>; N]: TryFrom<&'a [OpTy<'tcx, Provenance>]>, + &'a [OpTy<'tcx>; N]: TryFrom<&'a [OpTy<'tcx>]>, { self.check_abi_and_shim_symbol_clash(abi, exp_abi, link_name)?; check_arg_count(args) } /// Mark a machine allocation that was just created as immutable. - fn mark_immutable(&mut self, mplace: &MPlaceTy<'tcx, Provenance>) { + fn mark_immutable(&mut self, mplace: &MPlaceTy<'tcx>) { let this = self.eval_context_mut(); // This got just allocated, so there definitely is a pointer here. let provenance = mplace.ptr().into_pointer_or_addr().unwrap().provenance; @@ -1168,10 +1162,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// Returns `None` if `f` is NaN or out of range. fn float_to_int_checked( &self, - src: &ImmTy<'tcx, Provenance>, + src: &ImmTy<'tcx>, cast_to: TyAndLayout<'tcx>, round: rustc_apfloat::Round, - ) -> InterpResult<'tcx, Option>> { + ) -> InterpResult<'tcx, Option>> { let this = self.eval_context_ref(); fn float_to_int_inner<'tcx, F: rustc_apfloat::Float>( @@ -1179,7 +1173,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { src: F, cast_to: TyAndLayout<'tcx>, round: rustc_apfloat::Round, - ) -> (Scalar, rustc_apfloat::Status) { + ) -> (Scalar, rustc_apfloat::Status) { let int_size = cast_to.layout.size; match cast_to.ty.kind() { // Unsigned @@ -1267,10 +1261,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } /// Lookup an array of immediates stored as a linker section of name `name`. - fn lookup_link_section( - &mut self, - name: &str, - ) -> InterpResult<'tcx, Vec>> { + fn lookup_link_section(&mut self, name: &str) -> InterpResult<'tcx, Vec>> { let this = self.eval_context_mut(); let tcx = this.tcx.tcx; @@ -1338,10 +1329,10 @@ impl<'tcx> MiriMachine<'tcx> { /// Check that the number of args is what we expect. pub fn check_arg_count<'a, 'tcx, const N: usize>( - args: &'a [OpTy<'tcx, Provenance>], -) -> InterpResult<'tcx, &'a [OpTy<'tcx, Provenance>; N]> + args: &'a [OpTy<'tcx>], +) -> InterpResult<'tcx, &'a [OpTy<'tcx>; N]> where - &'a [OpTy<'tcx, Provenance>; N]: TryFrom<&'a [OpTy<'tcx, Provenance>]>, + &'a [OpTy<'tcx>; N]: TryFrom<&'a [OpTy<'tcx>]>, { if let Ok(ops) = args.try_into() { return Ok(ops); @@ -1374,7 +1365,7 @@ pub fn get_local_crates(tcx: TyCtxt<'_>) -> Vec { local_crates } -pub(crate) fn bool_to_simd_element(b: bool, size: Size) -> Scalar { +pub(crate) fn bool_to_simd_element(b: bool, size: Size) -> Scalar { // SIMD uses all-1 as pattern for "true". In two's complement, // -1 has all its bits set to one and `from_int` will truncate or // sign-extend it to `size` as required. @@ -1382,7 +1373,7 @@ pub(crate) fn bool_to_simd_element(b: bool, size: Size) -> Scalar { Scalar::from_int(val, size) } -pub(crate) fn simd_element_to_bool(elem: ImmTy<'_, Provenance>) -> InterpResult<'_, bool> { +pub(crate) fn simd_element_to_bool(elem: ImmTy<'_>) -> InterpResult<'_, bool> { let val = elem.to_scalar().to_int(elem.layout.size)?; Ok(match val { 0 => false, diff --git a/src/tools/miri/src/intrinsics/atomic.rs b/src/tools/miri/src/intrinsics/atomic.rs index 17f95df9aa150..d76f622e84baf 100644 --- a/src/tools/miri/src/intrinsics/atomic.rs +++ b/src/tools/miri/src/intrinsics/atomic.rs @@ -18,8 +18,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn emulate_atomic_intrinsic( &mut self, intrinsic_name: &str, - args: &[OpTy<'tcx, Provenance>], - dest: &MPlaceTy<'tcx, Provenance>, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, EmulateItemResult> { let this = self.eval_context_mut(); @@ -124,8 +124,8 @@ impl<'tcx> EvalContextPrivExt<'tcx> for MiriInterpCx<'tcx> {} trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { fn atomic_load( &mut self, - args: &[OpTy<'tcx, Provenance>], - dest: &MPlaceTy<'tcx, Provenance>, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, atomic: AtomicReadOrd, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -140,11 +140,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { Ok(()) } - fn atomic_store( - &mut self, - args: &[OpTy<'tcx, Provenance>], - atomic: AtomicWriteOrd, - ) -> InterpResult<'tcx> { + fn atomic_store(&mut self, args: &[OpTy<'tcx>], atomic: AtomicWriteOrd) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let [place, val] = check_arg_count(args)?; @@ -159,7 +155,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { fn compiler_fence_intrinsic( &mut self, - args: &[OpTy<'tcx, Provenance>], + args: &[OpTy<'tcx>], atomic: AtomicFenceOrd, ) -> InterpResult<'tcx> { let [] = check_arg_count(args)?; @@ -170,7 +166,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { fn atomic_fence_intrinsic( &mut self, - args: &[OpTy<'tcx, Provenance>], + args: &[OpTy<'tcx>], atomic: AtomicFenceOrd, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -181,8 +177,8 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { fn atomic_rmw_op( &mut self, - args: &[OpTy<'tcx, Provenance>], - dest: &MPlaceTy<'tcx, Provenance>, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, atomic_op: AtomicOp, atomic: AtomicRwOrd, ) -> InterpResult<'tcx> { @@ -223,8 +219,8 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { fn atomic_exchange( &mut self, - args: &[OpTy<'tcx, Provenance>], - dest: &MPlaceTy<'tcx, Provenance>, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, atomic: AtomicRwOrd, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -240,8 +236,8 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { fn atomic_compare_exchange_impl( &mut self, - args: &[OpTy<'tcx, Provenance>], - dest: &MPlaceTy<'tcx, Provenance>, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, success: AtomicRwOrd, fail: AtomicReadOrd, can_fail_spuriously: bool, @@ -269,8 +265,8 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { fn atomic_compare_exchange( &mut self, - args: &[OpTy<'tcx, Provenance>], - dest: &MPlaceTy<'tcx, Provenance>, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, success: AtomicRwOrd, fail: AtomicReadOrd, ) -> InterpResult<'tcx> { @@ -279,8 +275,8 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { fn atomic_compare_exchange_weak( &mut self, - args: &[OpTy<'tcx, Provenance>], - dest: &MPlaceTy<'tcx, Provenance>, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, success: AtomicRwOrd, fail: AtomicReadOrd, ) -> InterpResult<'tcx> { diff --git a/src/tools/miri/src/intrinsics/mod.rs b/src/tools/miri/src/intrinsics/mod.rs index e39b78d3816f7..74e39ffd9332a 100644 --- a/src/tools/miri/src/intrinsics/mod.rs +++ b/src/tools/miri/src/intrinsics/mod.rs @@ -1,3 +1,5 @@ +#![warn(clippy::arithmetic_side_effects)] + mod atomic; mod simd; @@ -23,8 +25,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn call_intrinsic( &mut self, instance: ty::Instance<'tcx>, - args: &[OpTy<'tcx, Provenance>], - dest: &MPlaceTy<'tcx, Provenance>, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, ret: Option, unwind: mir::UnwindAction, ) -> InterpResult<'tcx, Option>> { @@ -79,8 +81,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { &mut self, intrinsic_name: &str, generic_args: ty::GenericArgsRef<'tcx>, - args: &[OpTy<'tcx, Provenance>], - dest: &MPlaceTy<'tcx, Provenance>, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, ret: Option, ) -> InterpResult<'tcx, EmulateItemResult> { let this = self.eval_context_mut(); @@ -385,7 +387,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "frem_fast" => mir::BinOp::Rem, _ => bug!(), }; - let float_finite = |x: &ImmTy<'tcx, _>| -> InterpResult<'tcx, bool> { + let float_finite = |x: &ImmTy<'tcx>| -> InterpResult<'tcx, bool> { let ty::Float(fty) = x.layout.ty.kind() else { bug!("float_finite: non-float input type {}", x.layout.ty) }; diff --git a/src/tools/miri/src/intrinsics/simd.rs b/src/tools/miri/src/intrinsics/simd.rs index 8ba4964ff896b..b2b81df55bb31 100644 --- a/src/tools/miri/src/intrinsics/simd.rs +++ b/src/tools/miri/src/intrinsics/simd.rs @@ -23,8 +23,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { &mut self, intrinsic_name: &str, generic_args: ty::GenericArgsRef<'tcx>, - args: &[OpTy<'tcx, Provenance>], - dest: &MPlaceTy<'tcx, Provenance>, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, EmulateItemResult> { let this = self.eval_context_mut(); match intrinsic_name { @@ -452,28 +452,54 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let (no, no_len) = this.operand_to_simd(no)?; let (dest, dest_len) = this.mplace_to_simd(dest)?; let bitmask_len = dest_len.next_multiple_of(8); + if bitmask_len > 64 { + throw_unsup_format!( + "simd_select_bitmask: vectors larger than 64 elements are currently not supported" + ); + } - // The mask must be an integer or an array. - assert!( - mask.layout.ty.is_integral() - || matches!(mask.layout.ty.kind(), ty::Array(elemty, _) if elemty == &this.tcx.types.u8) - ); - assert!(bitmask_len <= 64); - assert_eq!(bitmask_len, mask.layout.size.bits()); assert_eq!(dest_len, yes_len); assert_eq!(dest_len, no_len); - let dest_len = u32::try_from(dest_len).unwrap(); - let bitmask_len = u32::try_from(bitmask_len).unwrap(); - // To read the mask, we transmute it to an integer. - // That does the right thing wrt endianness. - let mask_ty = this.machine.layouts.uint(mask.layout.size).unwrap(); - let mask = mask.transmute(mask_ty, this)?; - let mask: u64 = this.read_scalar(&mask)?.to_bits(mask_ty.size)?.try_into().unwrap(); + // Read the mask, either as an integer or as an array. + let mask: u64 = match mask.layout.ty.kind() { + ty::Uint(_) => { + // Any larger integer type is fine. + assert!(mask.layout.size.bits() >= bitmask_len); + this.read_scalar(mask)?.to_bits(mask.layout.size)?.try_into().unwrap() + } + ty::Array(elem, _len) if elem == &this.tcx.types.u8 => { + // The array must have exactly the right size. + assert_eq!(mask.layout.size.bits(), bitmask_len); + // Read the raw bytes. + let mask = mask.assert_mem_place(); // arrays cannot be immediate + let mask_bytes = + this.read_bytes_ptr_strip_provenance(mask.ptr(), mask.layout.size)?; + // Turn them into a `u64` in the right way. + let mask_size = mask.layout.size.bytes_usize(); + let mut mask_arr = [0u8; 8]; + match this.data_layout().endian { + Endian::Little => { + // Fill the first N bytes. + mask_arr[..mask_size].copy_from_slice(mask_bytes); + u64::from_le_bytes(mask_arr) + } + Endian::Big => { + // Fill the last N bytes. + let i = mask_arr.len().strict_sub(mask_size); + mask_arr[i..].copy_from_slice(mask_bytes); + u64::from_be_bytes(mask_arr) + } + } + } + _ => bug!("simd_select_bitmask: invalid mask type {}", mask.layout.ty), + }; + let dest_len = u32::try_from(dest_len).unwrap(); + let bitmask_len = u32::try_from(bitmask_len).unwrap(); for i in 0..dest_len { let bit_i = simd_bitmask_index(i, dest_len, this.data_layout().endian); - let mask = mask & 1u64.checked_shl(bit_i).unwrap(); + let mask = mask & 1u64.strict_shl(bit_i); let yes = this.read_immediate(&this.project_index(&yes, i.into())?)?; let no = this.read_immediate(&this.project_index(&no, i.into())?)?; let dest = this.project_index(&dest, i.into())?; @@ -485,7 +511,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // If the mask is "padded", ensure that padding is all-zero. // This deliberately does not use `simd_bitmask_index`; these bits are outside // the bitmask. It does not matter in which order we check them. - let mask = mask & 1u64.checked_shl(i).unwrap(); + let mask = mask & 1u64.strict_shl(i); if mask != 0 { throw_ub_format!( "a SIMD bitmask less than 8 bits long must be filled with 0s for the remaining bits" @@ -498,30 +524,49 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let [op] = check_arg_count(args)?; let (op, op_len) = this.operand_to_simd(op)?; let bitmask_len = op_len.next_multiple_of(8); + if bitmask_len > 64 { + throw_unsup_format!( + "simd_bitmask: vectors larger than 64 elements are currently not supported" + ); + } - // Returns either an unsigned integer or array of `u8`. - assert!( - dest.layout.ty.is_integral() - || matches!(dest.layout.ty.kind(), ty::Array(elemty, _) if elemty == &this.tcx.types.u8) - ); - assert!(bitmask_len <= 64); - assert_eq!(bitmask_len, dest.layout.size.bits()); let op_len = u32::try_from(op_len).unwrap(); - let mut res = 0u64; for i in 0..op_len { let op = this.read_immediate(&this.project_index(&op, i.into())?)?; if simd_element_to_bool(op)? { - res |= 1u64 - .checked_shl(simd_bitmask_index(i, op_len, this.data_layout().endian)) - .unwrap(); + let bit_i = simd_bitmask_index(i, op_len, this.data_layout().endian); + res |= 1u64.strict_shl(bit_i); + } + } + // Write the result, depending on the `dest` type. + // Returns either an unsigned integer or array of `u8`. + match dest.layout.ty.kind() { + ty::Uint(_) => { + // Any larger integer type is fine, it will be zero-extended. + assert!(dest.layout.size.bits() >= bitmask_len); + this.write_int(res, dest)?; + } + ty::Array(elem, _len) if elem == &this.tcx.types.u8 => { + // The array must have exactly the right size. + assert_eq!(dest.layout.size.bits(), bitmask_len); + // We have to write the result byte-for-byte. + let res_size = dest.layout.size.bytes_usize(); + let res_bytes; + let res_bytes_slice = match this.data_layout().endian { + Endian::Little => { + res_bytes = res.to_le_bytes(); + &res_bytes[..res_size] // take the first N bytes + } + Endian::Big => { + res_bytes = res.to_be_bytes(); + &res_bytes[res_bytes.len().strict_sub(res_size)..] // take the last N bytes + } + }; + this.write_bytes_ptr(dest.ptr(), res_bytes_slice.iter().cloned())?; } + _ => bug!("simd_bitmask: invalid return type {}", dest.layout.ty), } - // We have to change the type of the place to be able to write `res` into it. This - // transmutes the integer to an array, which does the right thing wrt endianness. - let dest = - dest.transmute(this.machine.layouts.uint(dest.layout.size).unwrap(), this)?; - this.write_int(res, &dest)?; } "cast" | "as" | "cast_ptr" | "expose_provenance" | "with_exposed_provenance" => { let [op] = check_arg_count(args)?; @@ -607,8 +652,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let val = if src_index < left_len { this.read_immediate(&this.project_index(&left, src_index)?)? - } else if src_index < left_len.checked_add(right_len).unwrap() { - let right_idx = src_index.checked_sub(left_len).unwrap(); + } else if src_index < left_len.strict_add(right_len) { + let right_idx = src_index.strict_sub(left_len); this.read_immediate(&this.project_index(&right, right_idx)?)? } else { throw_ub_format!( @@ -647,8 +692,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let val = if src_index < left_len { this.read_immediate(&this.project_index(&left, src_index)?)? - } else if src_index < left_len.checked_add(right_len).unwrap() { - let right_idx = src_index.checked_sub(left_len).unwrap(); + } else if src_index < left_len.strict_add(right_len) { + let right_idx = src_index.strict_sub(left_len); this.read_immediate(&this.project_index(&right, right_idx)?)? } else { throw_ub_format!( @@ -761,9 +806,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn fminmax_op( &self, op: MinMax, - left: &ImmTy<'tcx, Provenance>, - right: &ImmTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, Scalar> { + left: &ImmTy<'tcx>, + right: &ImmTy<'tcx>, + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_ref(); assert_eq!(left.layout.ty, right.layout.ty); let ty::Float(float_ty) = left.layout.ty.kind() else { diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs index 2fa88b6a24619..11cbbde06aa08 100644 --- a/src/tools/miri/src/lib.rs +++ b/src/tools/miri/src/lib.rs @@ -53,7 +53,6 @@ // Some "regular" crates we want to share with rustc extern crate either; -#[macro_use] extern crate tracing; // The rustc crates we need @@ -64,7 +63,6 @@ extern crate rustc_data_structures; extern crate rustc_errors; extern crate rustc_hir; extern crate rustc_index; -#[macro_use] extern crate rustc_middle; extern crate rustc_session; extern crate rustc_span; @@ -91,13 +89,24 @@ mod range_map; mod shims; // Establish a "crate-wide prelude": we often import `crate::*`. +use rustc_middle::{bug, span_bug}; +use tracing::{info, trace}; // Make all those symbols available in the same place as our own. #[doc(no_inline)] pub use rustc_const_eval::interpret::*; // Resolve ambiguity. #[doc(no_inline)] -pub use rustc_const_eval::interpret::{self, AllocMap, PlaceTy, Provenance as _}; +pub use rustc_const_eval::interpret::{self, AllocMap, Provenance as _}; + +// Type aliases that set the provenance parameter. +pub type Pointer = interpret::Pointer>; +pub type StrictPointer = interpret::Pointer; +pub type Scalar = interpret::Scalar; +pub type ImmTy<'tcx> = interpret::ImmTy<'tcx, machine::Provenance>; +pub type OpTy<'tcx> = interpret::OpTy<'tcx, machine::Provenance>; +pub type PlaceTy<'tcx> = interpret::PlaceTy<'tcx, machine::Provenance>; +pub type MPlaceTy<'tcx> = interpret::MPlaceTy<'tcx, machine::Provenance>; pub use crate::intrinsics::EvalContextExt as _; pub use crate::shims::env::{EnvVars, EvalContextExt as _}; @@ -123,8 +132,8 @@ pub use crate::concurrency::{ init_once::{EvalContextExt as _, InitOnceId}, sync::{CondvarId, EvalContextExt as _, MutexId, RwLockId, SynchronizationObjects}, thread::{ - BlockReason, EvalContextExt as _, StackEmptyCallback, ThreadId, ThreadManager, Timeout, - UnblockCallback, + BlockReason, EvalContextExt as _, StackEmptyCallback, ThreadId, ThreadManager, + TimeoutAnchor, TimeoutClock, UnblockCallback, }, }; pub use crate::diagnostics::{ diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index c9b390eb67e1d..0d91279f9f4c4 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -240,12 +240,12 @@ pub enum ProvenanceExtra { } #[cfg(target_pointer_width = "64")] -static_assert_size!(Pointer, 24); +static_assert_size!(StrictPointer, 24); // FIXME: this would with in 24bytes but layout optimizations are not smart enough // #[cfg(target_pointer_width = "64")] -//static_assert_size!(Pointer>, 24); +//static_assert_size!(Pointer, 24); #[cfg(target_pointer_width = "64")] -static_assert_size!(Scalar, 32); +static_assert_size!(Scalar, 32); impl fmt::Debug for Provenance { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { @@ -269,7 +269,7 @@ impl fmt::Debug for Provenance { } impl interpret::Provenance for Provenance { - /// We use absolute addresses in the `offset` of a `Pointer`. + /// We use absolute addresses in the `offset` of a `StrictPointer`. const OFFSET_IS_ADDR: bool = true; fn get_alloc_id(self) -> Option { @@ -279,7 +279,7 @@ impl interpret::Provenance for Provenance { } } - fn fmt(ptr: &Pointer, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fn fmt(ptr: &interpret::Pointer, f: &mut fmt::Formatter<'_>) -> fmt::Result { let (prov, addr) = ptr.into_parts(); // address is absolute write!(f, "{:#x}", addr.bytes())?; if f.alternate() { @@ -441,14 +441,14 @@ pub struct MiriMachine<'tcx> { pub(crate) env_vars: EnvVars<'tcx>, /// Return place of the main function. - pub(crate) main_fn_ret_place: Option>, + pub(crate) main_fn_ret_place: Option>, /// Program arguments (`Option` because we can only initialize them after creating the ecx). /// These are *pointers* to argc/argv because macOS. /// We also need the full command line as one string because of Windows. - pub(crate) argc: Option>>, - pub(crate) argv: Option>>, - pub(crate) cmd_line: Option>>, + pub(crate) argc: Option, + pub(crate) argv: Option, + pub(crate) cmd_line: Option, /// TLS state. pub(crate) tls: TlsData<'tcx>, @@ -503,7 +503,7 @@ pub struct MiriMachine<'tcx> { pub(crate) local_crates: Vec, /// Mapping extern static names to their pointer. - extern_statics: FxHashMap>, + extern_statics: FxHashMap, /// The random number generator used for resolving non-determinism. /// Needs to be queried by ptr_to_int, hence needs interior mutability. @@ -564,7 +564,7 @@ pub struct MiriMachine<'tcx> { /// Maps MIR consts to their evaluated result. We combine the const with a "salt" (`usize`) /// that is fixed per stack frame; this lets us have sometimes different results for the /// same const while ensuring consistent results within a single call. - const_cache: RefCell, usize), OpTy<'tcx, Provenance>>>, + const_cache: RefCell, usize), OpTy<'tcx>>>, /// For each allocation, an offset inside that allocation that was deemed aligned even for /// symbolic alignment checks. This cannot be stored in `AllocExtra` since it needs to be @@ -715,11 +715,7 @@ impl<'tcx> MiriMachine<'tcx> { Ok(()) } - pub(crate) fn add_extern_static( - this: &mut MiriInterpCx<'tcx>, - name: &str, - ptr: Pointer>, - ) { + pub(crate) fn add_extern_static(this: &mut MiriInterpCx<'tcx>, name: &str, ptr: Pointer) { // This got just allocated, so there definitely is a pointer here. let ptr = ptr.into_pointer_or_addr().unwrap(); this.machine.extern_statics.try_insert(Symbol::intern(name), ptr).unwrap(); @@ -945,7 +941,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { instance: ty::Instance<'tcx>, abi: Abi, args: &[FnArg<'tcx, Provenance>], - dest: &MPlaceTy<'tcx, Provenance>, + dest: &MPlaceTy<'tcx>, ret: Option, unwind: mir::UnwindAction, ) -> InterpResult<'tcx, Option<(&'tcx mir::Body<'tcx>, ty::Instance<'tcx>)>> { @@ -972,7 +968,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { fn_val: DynSym, abi: Abi, args: &[FnArg<'tcx, Provenance>], - dest: &MPlaceTy<'tcx, Provenance>, + dest: &MPlaceTy<'tcx>, ret: Option, unwind: mir::UnwindAction, ) -> InterpResult<'tcx> { @@ -984,8 +980,8 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { fn call_intrinsic( ecx: &mut MiriInterpCx<'tcx>, instance: ty::Instance<'tcx>, - args: &[OpTy<'tcx, Provenance>], - dest: &MPlaceTy<'tcx, Provenance>, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, ret: Option, unwind: mir::UnwindAction, ) -> InterpResult<'tcx, Option>> { @@ -1026,9 +1022,9 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { fn binary_ptr_op( ecx: &MiriInterpCx<'tcx>, bin_op: mir::BinOp, - left: &ImmTy<'tcx, Provenance>, - right: &ImmTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, ImmTy<'tcx, Provenance>> { + left: &ImmTy<'tcx>, + right: &ImmTy<'tcx>, + ) -> InterpResult<'tcx, ImmTy<'tcx>> { ecx.binary_ptr_op(bin_op, left, right) } @@ -1046,14 +1042,14 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { fn thread_local_static_pointer( ecx: &mut MiriInterpCx<'tcx>, def_id: DefId, - ) -> InterpResult<'tcx, Pointer> { + ) -> InterpResult<'tcx, StrictPointer> { ecx.get_or_create_thread_local_alloc(def_id) } fn extern_static_pointer( ecx: &MiriInterpCx<'tcx>, def_id: DefId, - ) -> InterpResult<'tcx, Pointer> { + ) -> InterpResult<'tcx, StrictPointer> { let link_name = ecx.item_link_name(def_id); if let Some(&ptr) = ecx.machine.extern_statics.get(&link_name) { // Various parts of the engine rely on `get_alloc_info` for size and alignment @@ -1134,9 +1130,9 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { fn adjust_alloc_root_pointer( ecx: &MiriInterpCx<'tcx>, - ptr: Pointer, + ptr: interpret::Pointer, kind: Option, - ) -> InterpResult<'tcx, Pointer> { + ) -> InterpResult<'tcx, interpret::Pointer> { let kind = kind.expect("we set our GLOBAL_KIND so this cannot be None"); let alloc_id = ptr.provenance.alloc_id(); if cfg!(debug_assertions) { @@ -1163,20 +1159,14 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { /// Called on `usize as ptr` casts. #[inline(always)] - fn ptr_from_addr_cast( - ecx: &MiriInterpCx<'tcx>, - addr: u64, - ) -> InterpResult<'tcx, Pointer>> { + fn ptr_from_addr_cast(ecx: &MiriInterpCx<'tcx>, addr: u64) -> InterpResult<'tcx, Pointer> { ecx.ptr_from_addr_cast(addr) } /// Called on `ptr as usize` casts. /// (Actually computing the resulting `usize` doesn't need machine help, /// that's just `Scalar::try_to_int`.) - fn expose_ptr( - ecx: &mut InterpCx<'tcx, Self>, - ptr: Pointer, - ) -> InterpResult<'tcx> { + fn expose_ptr(ecx: &mut InterpCx<'tcx, Self>, ptr: StrictPointer) -> InterpResult<'tcx> { match ptr.provenance { Provenance::Concrete { alloc_id, tag } => ecx.expose_ptr(alloc_id, tag), Provenance::Wildcard => { @@ -1197,7 +1187,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { /// stored in machine state). fn ptr_get_alloc( ecx: &MiriInterpCx<'tcx>, - ptr: Pointer, + ptr: StrictPointer, ) -> Option<(AllocId, Size, Self::ProvenanceExtra)> { let rel = ecx.ptr_get_alloc(ptr); @@ -1295,8 +1285,8 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { fn retag_ptr_value( ecx: &mut InterpCx<'tcx, Self>, kind: mir::RetagKind, - val: &ImmTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, ImmTy<'tcx, Provenance>> { + val: &ImmTy<'tcx>, + ) -> InterpResult<'tcx, ImmTy<'tcx>> { if ecx.machine.borrow_tracker.is_some() { ecx.retag_ptr_value(kind, val) } else { @@ -1308,7 +1298,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { fn retag_place_contents( ecx: &mut InterpCx<'tcx, Self>, kind: mir::RetagKind, - place: &PlaceTy<'tcx, Provenance>, + place: &PlaceTy<'tcx>, ) -> InterpResult<'tcx> { if ecx.machine.borrow_tracker.is_some() { ecx.retag_place_contents(kind, place)?; @@ -1318,7 +1308,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { fn protect_in_place_function_argument( ecx: &mut InterpCx<'tcx, Self>, - place: &MPlaceTy<'tcx, Provenance>, + place: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx> { // If we have a borrow tracker, we also have it set up protection so that all reads *and // writes* during this call are insta-UB. @@ -1473,7 +1463,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { fn after_local_allocated( ecx: &mut InterpCx<'tcx, Self>, local: mir::Local, - mplace: &MPlaceTy<'tcx, Provenance>, + mplace: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx> { let Some(Provenance::Concrete { alloc_id, .. }) = mplace.ptr().provenance else { panic!("after_local_allocated should only be called on fresh allocations"); @@ -1490,14 +1480,14 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { span: Span, layout: Option>, eval: F, - ) -> InterpResult<'tcx, OpTy<'tcx, Self::Provenance>> + ) -> InterpResult<'tcx, OpTy<'tcx>> where F: Fn( &InterpCx<'tcx, Self>, mir::Const<'tcx>, Span, Option>, - ) -> InterpResult<'tcx, OpTy<'tcx, Self::Provenance>>, + ) -> InterpResult<'tcx, OpTy<'tcx>>, { let frame = ecx.active_thread_stack().last().unwrap(); let mut cache = ecx.machine.const_cache.borrow_mut(); diff --git a/src/tools/miri/src/operator.rs b/src/tools/miri/src/operator.rs index c04f12c339e0c..bc44e672bd85e 100644 --- a/src/tools/miri/src/operator.rs +++ b/src/tools/miri/src/operator.rs @@ -12,9 +12,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn binary_ptr_op( &self, bin_op: mir::BinOp, - left: &ImmTy<'tcx, Provenance>, - right: &ImmTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, ImmTy<'tcx, Provenance>> { + left: &ImmTy<'tcx>, + right: &ImmTy<'tcx>, + ) -> InterpResult<'tcx, ImmTy<'tcx>> { use rustc_middle::mir::BinOp::*; let this = self.eval_context_ref(); diff --git a/src/tools/miri/src/provenance_gc.rs b/src/tools/miri/src/provenance_gc.rs index 03b6cfdce7bc0..af980ca48197c 100644 --- a/src/tools/miri/src/provenance_gc.rs +++ b/src/tools/miri/src/provenance_gc.rs @@ -56,21 +56,21 @@ impl VisitProvenance for Provenance { } } -impl VisitProvenance for Pointer { +impl VisitProvenance for StrictPointer { fn visit_provenance(&self, visit: &mut VisitWith<'_>) { let (prov, _offset) = self.into_parts(); prov.visit_provenance(visit); } } -impl VisitProvenance for Pointer> { +impl VisitProvenance for Pointer { fn visit_provenance(&self, visit: &mut VisitWith<'_>) { let (prov, _offset) = self.into_parts(); prov.visit_provenance(visit); } } -impl VisitProvenance for Scalar { +impl VisitProvenance for Scalar { fn visit_provenance(&self, visit: &mut VisitWith<'_>) { match self { Scalar::Ptr(ptr, _) => ptr.visit_provenance(visit), @@ -103,20 +103,20 @@ impl VisitProvenance for MemPlaceMeta { } } -impl VisitProvenance for ImmTy<'_, Provenance> { +impl VisitProvenance for ImmTy<'_> { fn visit_provenance(&self, visit: &mut VisitWith<'_>) { (**self).visit_provenance(visit) } } -impl VisitProvenance for MPlaceTy<'_, Provenance> { +impl VisitProvenance for MPlaceTy<'_> { fn visit_provenance(&self, visit: &mut VisitWith<'_>) { self.ptr().visit_provenance(visit); self.meta().visit_provenance(visit); } } -impl VisitProvenance for PlaceTy<'_, Provenance> { +impl VisitProvenance for PlaceTy<'_> { fn visit_provenance(&self, visit: &mut VisitWith<'_>) { match self.as_mplace_or_local() { Either::Left(mplace) => mplace.visit_provenance(visit), @@ -125,7 +125,7 @@ impl VisitProvenance for PlaceTy<'_, Provenance> { } } -impl VisitProvenance for OpTy<'_, Provenance> { +impl VisitProvenance for OpTy<'_> { fn visit_provenance(&self, visit: &mut VisitWith<'_>) { match self.as_mplace_or_imm() { Either::Left(mplace) => mplace.visit_provenance(visit), diff --git a/src/tools/miri/src/shims/alloc.rs b/src/tools/miri/src/shims/alloc.rs index bbe4bdd8450ca..7b0c54d763e41 100644 --- a/src/tools/miri/src/shims/alloc.rs +++ b/src/tools/miri/src/shims/alloc.rs @@ -92,11 +92,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } } - fn malloc( - &mut self, - size: u64, - zero_init: bool, - ) -> InterpResult<'tcx, Pointer>> { + fn malloc(&mut self, size: u64, zero_init: bool) -> InterpResult<'tcx, Pointer> { let this = self.eval_context_mut(); let align = this.malloc_align(size); let ptr = this.allocate_ptr(Size::from_bytes(size), align, MiriMemoryKind::C.into())?; @@ -113,10 +109,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn posix_memalign( &mut self, - memptr: &OpTy<'tcx, Provenance>, - align: &OpTy<'tcx, Provenance>, - size: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, Scalar> { + memptr: &OpTy<'tcx>, + align: &OpTy<'tcx>, + size: &OpTy<'tcx>, + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let memptr = this.deref_pointer(memptr)?; let align = this.read_target_usize(align)?; @@ -137,7 +133,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } } - fn free(&mut self, ptr: Pointer>) -> InterpResult<'tcx> { + fn free(&mut self, ptr: Pointer) -> InterpResult<'tcx> { let this = self.eval_context_mut(); if !this.ptr_is_null(ptr)? { this.deallocate_ptr(ptr, None, MiriMemoryKind::C.into())?; @@ -145,11 +141,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Ok(()) } - fn realloc( - &mut self, - old_ptr: Pointer>, - new_size: u64, - ) -> InterpResult<'tcx, Pointer>> { + fn realloc(&mut self, old_ptr: Pointer, new_size: u64) -> InterpResult<'tcx, Pointer> { let this = self.eval_context_mut(); let new_align = this.malloc_align(new_size); if this.ptr_is_null(old_ptr)? { @@ -175,9 +167,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn aligned_alloc( &mut self, - align: &OpTy<'tcx, Provenance>, - size: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, Pointer>> { + align: &OpTy<'tcx>, + size: &OpTy<'tcx>, + ) -> InterpResult<'tcx, Pointer> { let this = self.eval_context_mut(); let align = this.read_target_usize(align)?; let size = this.read_target_usize(size)?; diff --git a/src/tools/miri/src/shims/backtrace.rs b/src/tools/miri/src/shims/backtrace.rs index 6ec65a16b8a45..06be9c1e63e06 100644 --- a/src/tools/miri/src/shims/backtrace.rs +++ b/src/tools/miri/src/shims/backtrace.rs @@ -11,8 +11,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { &mut self, abi: Abi, link_name: Symbol, - args: &[OpTy<'tcx, Provenance>], - dest: &MPlaceTy<'tcx, Provenance>, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let [flags] = this.check_shim(abi, Abi::Rust, link_name, args)?; @@ -31,8 +31,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { &mut self, abi: Abi, link_name: Symbol, - args: &[OpTy<'tcx, Provenance>], - dest: &MPlaceTy<'tcx, Provenance>, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let tcx = this.tcx; @@ -110,7 +110,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn resolve_frame_pointer( &mut self, - ptr: &OpTy<'tcx, Provenance>, + ptr: &OpTy<'tcx>, ) -> InterpResult<'tcx, (Instance<'tcx>, Loc, String, String)> { let this = self.eval_context_mut(); @@ -140,8 +140,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { &mut self, abi: Abi, link_name: Symbol, - args: &[OpTy<'tcx, Provenance>], - dest: &MPlaceTy<'tcx, Provenance>, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let [ptr, flags] = this.check_shim(abi, Abi::Rust, link_name, args)?; @@ -218,7 +218,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { &mut self, abi: Abi, link_name: Symbol, - args: &[OpTy<'tcx, Provenance>], + args: &[OpTy<'tcx>], ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); diff --git a/src/tools/miri/src/shims/extern_static.rs b/src/tools/miri/src/shims/extern_static.rs index 9330ac0b4dd8d..17ac2638a69f4 100644 --- a/src/tools/miri/src/shims/extern_static.rs +++ b/src/tools/miri/src/shims/extern_static.rs @@ -6,7 +6,7 @@ impl<'tcx> MiriMachine<'tcx> { fn alloc_extern_static( this: &mut MiriInterpCx<'tcx>, name: &str, - val: ImmTy<'tcx, Provenance>, + val: ImmTy<'tcx>, ) -> InterpResult<'tcx> { let place = this.allocate(val.layout, MiriMemoryKind::ExternStatic.into())?; this.write_immediate(*val, &place)?; diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs index 6dfd9866cae97..898fc111fd43f 100644 --- a/src/tools/miri/src/shims/foreign_items.rs +++ b/src/tools/miri/src/shims/foreign_items.rs @@ -40,8 +40,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { &mut self, link_name: Symbol, abi: Abi, - args: &[OpTy<'tcx, Provenance>], - dest: &MPlaceTy<'tcx, Provenance>, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, ret: Option, unwind: mir::UnwindAction, ) -> InterpResult<'tcx, Option<(&'tcx mir::Body<'tcx>, ty::Instance<'tcx>)>> { @@ -123,8 +123,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { &mut self, sym: DynSym, abi: Abi, - args: &[OpTy<'tcx, Provenance>], - dest: &MPlaceTy<'tcx, Provenance>, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, ret: Option, unwind: mir::UnwindAction, ) -> InterpResult<'tcx> { @@ -208,8 +208,8 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { &mut self, link_name: Symbol, abi: Abi, - args: &[OpTy<'tcx, Provenance>], - dest: &MPlaceTy<'tcx, Provenance>, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, EmulateItemResult> { let this = self.eval_context_mut(); @@ -238,11 +238,11 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { // ``` // fn shim_name( // &mut self, - // arg1: &OpTy<'tcx, Provenance>, - // arg2: &OpTy<'tcx, Provenance>, - // arg3: &OpTy<'tcx, Provenance>, - // arg4: &OpTy<'tcx, Provenance>) - // -> InterpResult<'tcx, Scalar> { + // arg1: &OpTy<'tcx>, + // arg2: &OpTy<'tcx>, + // arg3: &OpTy<'tcx>, + // arg4: &OpTy<'tcx>) + // -> InterpResult<'tcx, Scalar> { // let this = self.eval_context_mut(); // // // First thing: load all the arguments. Details depend on the shim. diff --git a/src/tools/miri/src/shims/native_lib.rs b/src/tools/miri/src/shims/native_lib.rs index cc5cc75332aa6..40697e17ba193 100644 --- a/src/tools/miri/src/shims/native_lib.rs +++ b/src/tools/miri/src/shims/native_lib.rs @@ -14,10 +14,10 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { fn call_native_with_args<'a>( &mut self, link_name: Symbol, - dest: &MPlaceTy<'tcx, Provenance>, + dest: &MPlaceTy<'tcx>, ptr: CodePtr, libffi_args: Vec>, - ) -> InterpResult<'tcx, ImmTy<'tcx, Provenance>> { + ) -> InterpResult<'tcx, ImmTy<'tcx>> { let this = self.eval_context_mut(); // Call the function (`ptr`) with arguments `libffi_args`, and obtain the return value @@ -132,8 +132,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn call_native_fn( &mut self, link_name: Symbol, - dest: &MPlaceTy<'tcx, Provenance>, - args: &[OpTy<'tcx, Provenance>], + dest: &MPlaceTy<'tcx>, + args: &[OpTy<'tcx>], ) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); // Get the pointer to the function in the shared object file if it exists. @@ -216,10 +216,7 @@ impl<'a> CArg { /// Extract the scalar value from the result of reading a scalar from the machine, /// and convert it to a `CArg`. -fn imm_to_carg<'tcx>( - v: ImmTy<'tcx, Provenance>, - cx: &impl HasDataLayout, -) -> InterpResult<'tcx, CArg> { +fn imm_to_carg<'tcx>(v: ImmTy<'tcx>, cx: &impl HasDataLayout) -> InterpResult<'tcx, CArg> { Ok(match v.layout.ty.kind() { // If the primitive provided can be converted to a type matching the type pattern // then create a `CArg` of this primitive value with the corresponding `CArg` constructor. diff --git a/src/tools/miri/src/shims/os_str.rs b/src/tools/miri/src/shims/os_str.rs index c00e4384bab41..68eca5a3a0ffd 100644 --- a/src/tools/miri/src/shims/os_str.rs +++ b/src/tools/miri/src/shims/os_str.rs @@ -34,10 +34,7 @@ impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// Helper function to read an OsString from a null-terminated sequence of bytes, which is what /// the Unix APIs usually handle. - fn read_os_str_from_c_str<'a>( - &'a self, - ptr: Pointer>, - ) -> InterpResult<'tcx, &'a OsStr> + fn read_os_str_from_c_str<'a>(&'a self, ptr: Pointer) -> InterpResult<'tcx, &'a OsStr> where 'tcx: 'a, { @@ -48,10 +45,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// Helper function to read an OsString from a 0x0000-terminated sequence of u16, /// which is what the Windows APIs usually handle. - fn read_os_str_from_wide_str<'a>( - &'a self, - ptr: Pointer>, - ) -> InterpResult<'tcx, OsString> + fn read_os_str_from_wide_str<'a>(&'a self, ptr: Pointer) -> InterpResult<'tcx, OsString> where 'tcx: 'a, { @@ -76,7 +70,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn write_os_str_to_c_str( &mut self, os_str: &OsStr, - ptr: Pointer>, + ptr: Pointer, size: u64, ) -> InterpResult<'tcx, (bool, u64)> { let bytes = os_str.as_encoded_bytes(); @@ -88,7 +82,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn write_os_str_to_wide_str_helper( &mut self, os_str: &OsStr, - ptr: Pointer>, + ptr: Pointer, size: u64, truncate: bool, ) -> InterpResult<'tcx, (bool, u64)> { @@ -125,7 +119,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn write_os_str_to_wide_str( &mut self, os_str: &OsStr, - ptr: Pointer>, + ptr: Pointer, size: u64, ) -> InterpResult<'tcx, (bool, u64)> { self.write_os_str_to_wide_str_helper(os_str, ptr, size, /*truncate*/ false) @@ -136,7 +130,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn write_os_str_to_wide_str_truncated( &mut self, os_str: &OsStr, - ptr: Pointer>, + ptr: Pointer, size: u64, ) -> InterpResult<'tcx, (bool, u64)> { self.write_os_str_to_wide_str_helper(os_str, ptr, size, /*truncate*/ true) @@ -147,7 +141,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { &mut self, os_str: &OsStr, memkind: MemoryKind, - ) -> InterpResult<'tcx, Pointer>> { + ) -> InterpResult<'tcx, Pointer> { let size = u64::try_from(os_str.len()).unwrap().checked_add(1).unwrap(); // Make space for `0` terminator. let this = self.eval_context_mut(); @@ -163,7 +157,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { &mut self, os_str: &OsStr, memkind: MemoryKind, - ) -> InterpResult<'tcx, Pointer>> { + ) -> InterpResult<'tcx, Pointer> { let size = u64::try_from(os_str.len()).unwrap().checked_add(1).unwrap(); // Make space for `0x0000` terminator. let this = self.eval_context_mut(); @@ -175,10 +169,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } /// Read a null-terminated sequence of bytes, and perform path separator conversion if needed. - fn read_path_from_c_str<'a>( - &'a self, - ptr: Pointer>, - ) -> InterpResult<'tcx, Cow<'a, Path>> + fn read_path_from_c_str<'a>(&'a self, ptr: Pointer) -> InterpResult<'tcx, Cow<'a, Path>> where 'tcx: 'a, { @@ -192,10 +183,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } /// Read a null-terminated sequence of `u16`s, and perform path separator conversion if needed. - fn read_path_from_wide_str( - &self, - ptr: Pointer>, - ) -> InterpResult<'tcx, PathBuf> { + fn read_path_from_wide_str(&self, ptr: Pointer) -> InterpResult<'tcx, PathBuf> { let this = self.eval_context_ref(); let os_str = this.read_os_str_from_wide_str(ptr)?; @@ -207,7 +195,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn write_path_to_c_str( &mut self, path: &Path, - ptr: Pointer>, + ptr: Pointer, size: u64, ) -> InterpResult<'tcx, (bool, u64)> { let this = self.eval_context_mut(); @@ -221,7 +209,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn write_path_to_wide_str( &mut self, path: &Path, - ptr: Pointer>, + ptr: Pointer, size: u64, ) -> InterpResult<'tcx, (bool, u64)> { let this = self.eval_context_mut(); @@ -235,7 +223,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn write_path_to_wide_str_truncated( &mut self, path: &Path, - ptr: Pointer>, + ptr: Pointer, size: u64, ) -> InterpResult<'tcx, (bool, u64)> { let this = self.eval_context_mut(); @@ -250,7 +238,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { &mut self, path: &Path, memkind: MemoryKind, - ) -> InterpResult<'tcx, Pointer>> { + ) -> InterpResult<'tcx, Pointer> { let this = self.eval_context_mut(); let os_str = this.convert_path(Cow::Borrowed(path.as_os_str()), PathConversion::HostToTarget); @@ -263,7 +251,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { &mut self, path: &Path, memkind: MemoryKind, - ) -> InterpResult<'tcx, Pointer>> { + ) -> InterpResult<'tcx, Pointer> { let this = self.eval_context_mut(); let os_str = this.convert_path(Cow::Borrowed(path.as_os_str()), PathConversion::HostToTarget); diff --git a/src/tools/miri/src/shims/panic.rs b/src/tools/miri/src/shims/panic.rs index 8aed6d4f463fa..ef832f5bbbd15 100644 --- a/src/tools/miri/src/shims/panic.rs +++ b/src/tools/miri/src/shims/panic.rs @@ -23,11 +23,11 @@ use helpers::check_arg_count; #[derive(Debug)] pub struct CatchUnwindData<'tcx> { /// The `catch_fn` callback to call in case of a panic. - catch_fn: Pointer>, + catch_fn: Pointer, /// The `data` argument for that callback. - data: Scalar, + data: Scalar, /// The return place from the original call to `try`. - dest: MPlaceTy<'tcx, Provenance>, + dest: MPlaceTy<'tcx>, /// The return block from the original call to `try`. ret: Option, } @@ -45,7 +45,7 @@ impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// Handles the special `miri_start_unwind` intrinsic, which is called /// by libpanic_unwind to delegate the actual unwinding process to Miri. - fn handle_miri_start_unwind(&mut self, payload: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx> { + fn handle_miri_start_unwind(&mut self, payload: &OpTy<'tcx>) -> InterpResult<'tcx> { let this = self.eval_context_mut(); trace!("miri_start_unwind: {:?}", this.frame().instance); @@ -60,8 +60,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// Handles the `try` intrinsic, the underlying implementation of `std::panicking::try`. fn handle_catch_unwind( &mut self, - args: &[OpTy<'tcx, Provenance>], - dest: &MPlaceTy<'tcx, Provenance>, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, ret: Option, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); diff --git a/src/tools/miri/src/shims/time.rs b/src/tools/miri/src/shims/time.rs index 9fb7a735c30b3..ae17196f0b78d 100644 --- a/src/tools/miri/src/shims/time.rs +++ b/src/tools/miri/src/shims/time.rs @@ -18,9 +18,9 @@ impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn clock_gettime( &mut self, - clk_id_op: &OpTy<'tcx, Provenance>, - tp_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, Scalar> { + clk_id_op: &OpTy<'tcx>, + tp_op: &OpTy<'tcx>, + ) -> InterpResult<'tcx, Scalar> { // This clock support is deliberately minimal because a lot of clock types have fiddly // properties (is it possible for Miri to be suspended independently of the host?). If you // have a use for another clock type, please open an issue. @@ -78,7 +78,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.check_no_isolation("`clock_gettime` with `REALTIME` clocks")?; system_time_to_duration(&SystemTime::now())? } else if relative_clocks.contains(&clk_id) { - this.machine.clock.now().duration_since(this.machine.clock.anchor()) + this.machine.clock.now().duration_since(this.machine.clock.epoch()) } else { let einval = this.eval_libc("EINVAL"); this.set_last_error(einval)?; @@ -93,11 +93,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Ok(Scalar::from_i32(0)) } - fn gettimeofday( - &mut self, - tv_op: &OpTy<'tcx, Provenance>, - tz_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, i32> { + fn gettimeofday(&mut self, tv_op: &OpTy<'tcx>, tz_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.assert_target_os_is_unix("gettimeofday"); @@ -127,9 +123,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // https://linux.die.net/man/3/localtime_r fn localtime_r( &mut self, - timep: &OpTy<'tcx, Provenance>, - result_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, Pointer>> { + timep: &OpTy<'tcx>, + result_op: &OpTy<'tcx>, + ) -> InterpResult<'tcx, Pointer> { let this = self.eval_context_mut(); this.assert_target_os_is_unix("localtime_r"); @@ -212,7 +208,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn GetSystemTimeAsFileTime( &mut self, shim_name: &str, - LPFILETIME_op: &OpTy<'tcx, Provenance>, + LPFILETIME_op: &OpTy<'tcx>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -242,15 +238,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { #[allow(non_snake_case)] fn QueryPerformanceCounter( &mut self, - lpPerformanceCount_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, Scalar> { + lpPerformanceCount_op: &OpTy<'tcx>, + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); this.assert_target_os("windows", "QueryPerformanceCounter"); // QueryPerformanceCounter uses a hardware counter as its basis. // Miri will emulate a counter with a resolution of 1 nanosecond. - let duration = this.machine.clock.now().duration_since(this.machine.clock.anchor()); + let duration = this.machine.clock.now().duration_since(this.machine.clock.epoch()); let qpc = i64::try_from(duration.as_nanos()).map_err(|_| { err_unsup_format!("programs running longer than 2^63 nanoseconds are not supported") })?; @@ -261,8 +257,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { #[allow(non_snake_case)] fn QueryPerformanceFrequency( &mut self, - lpFrequency_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, Scalar> { + lpFrequency_op: &OpTy<'tcx>, + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); this.assert_target_os("windows", "QueryPerformanceFrequency"); @@ -279,24 +275,21 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Ok(Scalar::from_i32(-1)) // Return non-zero on success } - fn mach_absolute_time(&self) -> InterpResult<'tcx, Scalar> { + fn mach_absolute_time(&self) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_ref(); this.assert_target_os("macos", "mach_absolute_time"); // This returns a u64, with time units determined dynamically by `mach_timebase_info`. // We return plain nanoseconds. - let duration = this.machine.clock.now().duration_since(this.machine.clock.anchor()); + let duration = this.machine.clock.now().duration_since(this.machine.clock.epoch()); let res = u64::try_from(duration.as_nanos()).map_err(|_| { err_unsup_format!("programs running longer than 2^64 nanoseconds are not supported") })?; Ok(Scalar::from_u64(res)) } - fn mach_timebase_info( - &mut self, - info_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, Scalar> { + fn mach_timebase_info(&mut self, info_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); this.assert_target_os("macos", "mach_timebase_info"); @@ -313,8 +306,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn nanosleep( &mut self, - req_op: &OpTy<'tcx, Provenance>, - _rem: &OpTy<'tcx, Provenance>, // Signal handlers are not supported, so rem will never be written to. + req_op: &OpTy<'tcx>, + _rem: &OpTy<'tcx>, // Signal handlers are not supported, so rem will never be written to. ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -330,16 +323,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { return Ok(-1); } }; - // If adding the duration overflows, let's just sleep for an hour. Waking up early is always acceptable. - let now = this.machine.clock.now(); - let timeout_time = now - .checked_add(duration) - .unwrap_or_else(|| now.checked_add(Duration::from_secs(3600)).unwrap()); - let timeout_time = Timeout::Monotonic(timeout_time); this.block_thread( BlockReason::Sleep, - Some(timeout_time), + Some((TimeoutClock::Monotonic, TimeoutAnchor::Relative, duration)), callback!( @capture<'tcx> {} @unblock = |_this| { panic!("sleeping thread unblocked before time is up") } @@ -350,7 +337,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } #[allow(non_snake_case)] - fn Sleep(&mut self, timeout: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx> { + fn Sleep(&mut self, timeout: &OpTy<'tcx>) -> InterpResult<'tcx> { let this = self.eval_context_mut(); this.assert_target_os("windows", "Sleep"); @@ -358,12 +345,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let timeout_ms = this.read_scalar(timeout)?.to_u32()?; let duration = Duration::from_millis(timeout_ms.into()); - let timeout_time = this.machine.clock.now().checked_add(duration).unwrap(); - let timeout_time = Timeout::Monotonic(timeout_time); this.block_thread( BlockReason::Sleep, - Some(timeout_time), + Some((TimeoutClock::Monotonic, TimeoutAnchor::Relative, duration)), callback!( @capture<'tcx> {} @unblock = |_this| { panic!("sleeping thread unblocked before time is up") } diff --git a/src/tools/miri/src/shims/tls.rs b/src/tools/miri/src/shims/tls.rs index fa52b036ce948..c91386fa877fb 100644 --- a/src/tools/miri/src/shims/tls.rs +++ b/src/tools/miri/src/shims/tls.rs @@ -16,7 +16,7 @@ pub type TlsKey = u128; pub struct TlsEntry<'tcx> { /// The data for this key. None is used to represent NULL. /// (We normalize this early to avoid having to do a NULL-ptr-test each time we access the data.) - data: BTreeMap>, + data: BTreeMap, dtor: Option>, } @@ -38,7 +38,7 @@ pub struct TlsData<'tcx> { /// A single per thread destructor of the thread local storage (that's how /// things work on macOS) with a data argument. - macos_thread_dtors: BTreeMap, Scalar)>, + macos_thread_dtors: BTreeMap, Scalar)>, } impl<'tcx> Default for TlsData<'tcx> { @@ -86,7 +86,7 @@ impl<'tcx> TlsData<'tcx> { key: TlsKey, thread_id: ThreadId, cx: &impl HasDataLayout, - ) -> InterpResult<'tcx, Scalar> { + ) -> InterpResult<'tcx, Scalar> { match self.keys.get(&key) { Some(TlsEntry { data, .. }) => { let value = data.get(&thread_id).copied(); @@ -101,7 +101,7 @@ impl<'tcx> TlsData<'tcx> { &mut self, key: TlsKey, thread_id: ThreadId, - new_data: Scalar, + new_data: Scalar, cx: &impl HasDataLayout, ) -> InterpResult<'tcx> { match self.keys.get_mut(&key) { @@ -132,7 +132,7 @@ impl<'tcx> TlsData<'tcx> { &mut self, thread: ThreadId, dtor: ty::Instance<'tcx>, - data: Scalar, + data: Scalar, ) -> InterpResult<'tcx> { if self.macos_thread_dtors.insert(thread, (dtor, data)).is_some() { throw_unsup_format!( @@ -165,7 +165,7 @@ impl<'tcx> TlsData<'tcx> { &mut self, key: Option, thread_id: ThreadId, - ) -> Option<(ty::Instance<'tcx>, Scalar, TlsKey)> { + ) -> Option<(ty::Instance<'tcx>, Scalar, TlsKey)> { use std::ops::Bound::*; let thread_local = &mut self.keys; @@ -228,7 +228,7 @@ enum TlsDtorsStatePriv<'tcx> { PthreadDtors(RunningDtorState), /// For Windows Dtors, we store the list of functions that we still have to call. /// These are functions from the magic `.CRT$XLB` linker section. - WindowsDtors(Vec>), + WindowsDtors(Vec>), Done, } @@ -297,7 +297,7 @@ impl<'tcx> EvalContextPrivExt<'tcx> for crate::MiriInterpCx<'tcx> {} trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// Schedule TLS destructors for Windows. /// On windows, TLS destructors are managed by std. - fn lookup_windows_tls_dtors(&mut self) -> InterpResult<'tcx, Vec>> { + fn lookup_windows_tls_dtors(&mut self) -> InterpResult<'tcx, Vec>> { let this = self.eval_context_mut(); // Windows has a special magic linker section that is run on certain events. @@ -305,7 +305,7 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Ok(this.lookup_link_section(".CRT$XLB")?) } - fn schedule_windows_tls_dtor(&mut self, dtor: ImmTy<'tcx, Provenance>) -> InterpResult<'tcx> { + fn schedule_windows_tls_dtor(&mut self, dtor: ImmTy<'tcx>) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let dtor = dtor.to_scalar().to_pointer(this)?; diff --git a/src/tools/miri/src/shims/unix/android/foreign_items.rs b/src/tools/miri/src/shims/unix/android/foreign_items.rs index 8a6e025ee18f9..42552a51edae3 100644 --- a/src/tools/miri/src/shims/unix/android/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/android/foreign_items.rs @@ -13,8 +13,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { &mut self, link_name: Symbol, abi: Abi, - args: &[OpTy<'tcx, Provenance>], - dest: &MPlaceTy<'tcx, Provenance>, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, EmulateItemResult> { let this = self.eval_context_mut(); match link_name.as_str() { diff --git a/src/tools/miri/src/shims/unix/env.rs b/src/tools/miri/src/shims/unix/env.rs index 26096910aa196..2f78d0f42967a 100644 --- a/src/tools/miri/src/shims/unix/env.rs +++ b/src/tools/miri/src/shims/unix/env.rs @@ -13,10 +13,10 @@ use crate::*; pub struct UnixEnvVars<'tcx> { /// Stores pointers to the environment variables. These variables must be stored as /// null-terminated target strings (c_str or wide_str) with the `"{name}={value}"` format. - map: FxHashMap>>, + map: FxHashMap, /// Place where the `environ` static is stored. Lazily initialized, but then never changes. - environ: MPlaceTy<'tcx, Provenance>, + environ: MPlaceTy<'tcx>, } impl VisitProvenance for UnixEnvVars<'_> { @@ -65,7 +65,7 @@ impl<'tcx> UnixEnvVars<'tcx> { Ok(()) } - pub(crate) fn environ(&self) -> Pointer> { + pub(crate) fn environ(&self) -> Pointer { self.environ.ptr() } @@ -73,7 +73,7 @@ impl<'tcx> UnixEnvVars<'tcx> { &self, ecx: &InterpCx<'tcx, MiriMachine<'tcx>>, name: &OsStr, - ) -> InterpResult<'tcx, Option>>> { + ) -> InterpResult<'tcx, Option> { // We don't care about the value as we have the `map` to keep track of everything, // but we do want to do this read so it shows up as a data race. let _vars_ptr = ecx.read_pointer(&self.environ)?; @@ -109,7 +109,7 @@ fn alloc_env_var<'tcx>( ecx: &mut InterpCx<'tcx, MiriMachine<'tcx>>, name: &OsStr, value: &OsStr, -) -> InterpResult<'tcx, Pointer>> { +) -> InterpResult<'tcx, Pointer> { let mut name_osstring = name.to_os_string(); name_osstring.push("="); name_osstring.push(value); @@ -119,8 +119,8 @@ fn alloc_env_var<'tcx>( /// Allocates an `environ` block with the given list of pointers. fn alloc_environ_block<'tcx>( ecx: &mut InterpCx<'tcx, MiriMachine<'tcx>>, - mut vars: Vec>>, -) -> InterpResult<'tcx, Pointer>> { + mut vars: Vec, +) -> InterpResult<'tcx, Pointer> { // Add trailing null. vars.push(Pointer::null()); // Make an array with all these pointers inside Miri. @@ -139,10 +139,7 @@ fn alloc_environ_block<'tcx>( impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { - fn getenv( - &mut self, - name_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, Pointer>> { + fn getenv(&mut self, name_op: &OpTy<'tcx>) -> InterpResult<'tcx, Pointer> { let this = self.eval_context_mut(); this.assert_target_os_is_unix("getenv"); @@ -153,11 +150,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Ok(var_ptr.unwrap_or_else(Pointer::null)) } - fn setenv( - &mut self, - name_op: &OpTy<'tcx, Provenance>, - value_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, i32> { + fn setenv(&mut self, name_op: &OpTy<'tcx>, value_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.assert_target_os_is_unix("setenv"); @@ -187,7 +180,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } } - fn unsetenv(&mut self, name_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> { + fn unsetenv(&mut self, name_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.assert_target_os_is_unix("unsetenv"); @@ -213,11 +206,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } } - fn getcwd( - &mut self, - buf_op: &OpTy<'tcx, Provenance>, - size_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, Pointer>> { + fn getcwd(&mut self, buf_op: &OpTy<'tcx>, size_op: &OpTy<'tcx>) -> InterpResult<'tcx, Pointer> { let this = self.eval_context_mut(); this.assert_target_os_is_unix("getcwd"); @@ -245,7 +234,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Ok(Pointer::null()) } - fn chdir(&mut self, path_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> { + fn chdir(&mut self, path_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.assert_target_os_is_unix("chdir"); diff --git a/src/tools/miri/src/shims/unix/fd.rs b/src/tools/miri/src/shims/unix/fd.rs index 5fdd77a0cbdb0..b6ac841dc9f45 100644 --- a/src/tools/miri/src/shims/unix/fd.rs +++ b/src/tools/miri/src/shims/unix/fd.rs @@ -273,7 +273,7 @@ impl FdTable { impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { - fn fcntl(&mut self, args: &[OpTy<'tcx, Provenance>]) -> InterpResult<'tcx, i32> { + fn fcntl(&mut self, args: &[OpTy<'tcx>]) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); if args.len() < 2 { @@ -329,7 +329,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } } - fn close(&mut self, fd_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, Scalar> { + fn close(&mut self, fd_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let fd = this.read_scalar(fd_op)?.to_i32()?; @@ -355,12 +355,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Ok((-1).into()) } - fn read( - &mut self, - fd: i32, - buf: Pointer>, - count: u64, - ) -> InterpResult<'tcx, i64> { + fn read(&mut self, fd: i32, buf: Pointer, count: u64) -> InterpResult<'tcx, i64> { let this = self.eval_context_mut(); // Isolation check is done via `FileDescriptor` trait. @@ -409,12 +404,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } } - fn write( - &mut self, - fd: i32, - buf: Pointer>, - count: u64, - ) -> InterpResult<'tcx, i64> { + fn write(&mut self, fd: i32, buf: Pointer, count: u64) -> InterpResult<'tcx, i64> { let this = self.eval_context_mut(); // Isolation check is done via `FileDescriptor` trait. diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs index 052715e239f23..2282099fa0d23 100644 --- a/src/tools/miri/src/shims/unix/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/foreign_items.rs @@ -43,8 +43,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { &mut self, link_name: Symbol, abi: Abi, - args: &[OpTy<'tcx, Provenance>], - dest: &MPlaceTy<'tcx, Provenance>, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, EmulateItemResult> { let this = self.eval_context_mut(); @@ -326,7 +326,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let name = this.read_scalar(name)?.to_i32()?; // FIXME: Which of these are POSIX, and which are GNU/Linux? // At least the names seem to all also exist on macOS. - let sysconfs: &[(&str, fn(&MiriInterpCx<'_>) -> Scalar)] = &[ + let sysconfs: &[(&str, fn(&MiriInterpCx<'_>) -> Scalar)] = &[ ("_SC_PAGESIZE", |this| Scalar::from_int(this.machine.page_size, this.pointer_size())), ("_SC_NPROCESSORS_CONF", |this| Scalar::from_int(this.machine.num_cpus, this.pointer_size())), ("_SC_NPROCESSORS_ONLN", |this| Scalar::from_int(this.machine.num_cpus, this.pointer_size())), diff --git a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs index 30eb88151e4b7..36f25767a8ea0 100644 --- a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs @@ -14,8 +14,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { &mut self, link_name: Symbol, abi: Abi, - args: &[OpTy<'tcx, Provenance>], - dest: &MPlaceTy<'tcx, Provenance>, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, EmulateItemResult> { let this = self.eval_context_mut(); match link_name.as_str() { diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs index 8e3d547b0750c..c8805f054ecca 100644 --- a/src/tools/miri/src/shims/unix/fs.rs +++ b/src/tools/miri/src/shims/unix/fs.rs @@ -91,7 +91,7 @@ trait EvalContextExtPrivate<'tcx>: crate::MiriInterpCxExt<'tcx> { fn macos_stat_write_buf( &mut self, metadata: FileMetadata, - buf_op: &OpTy<'tcx, Provenance>, + buf_op: &OpTy<'tcx>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -180,7 +180,7 @@ struct OpenDir { read_dir: ReadDir, /// The most recent entry returned by readdir(). /// Will be freed by the next call. - entry: Option>>, + entry: Option, } impl OpenDir { @@ -256,7 +256,7 @@ fn maybe_sync_file( impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { - fn open(&mut self, args: &[OpTy<'tcx, Provenance>]) -> InterpResult<'tcx, i32> { + fn open(&mut self, args: &[OpTy<'tcx>]) -> InterpResult<'tcx, i32> { if args.len() < 2 { throw_ub_format!( "incorrect number of arguments for `open`: got {}, expected at least 2", @@ -389,12 +389,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.try_unwrap_io_result(fd) } - fn lseek64( - &mut self, - fd: i32, - offset: i128, - whence: i32, - ) -> InterpResult<'tcx, Scalar> { + fn lseek64(&mut self, fd: i32, offset: i128, whence: i32) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); // Isolation check is done via `FileDescriptor` trait. @@ -425,7 +420,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Ok(Scalar::from_i64(result)) } - fn unlink(&mut self, path_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> { + fn unlink(&mut self, path_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let path = this.read_path_from_c_str(this.read_pointer(path_op)?)?; @@ -443,8 +438,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn symlink( &mut self, - target_op: &OpTy<'tcx, Provenance>, - linkpath_op: &OpTy<'tcx, Provenance>, + target_op: &OpTy<'tcx>, + linkpath_op: &OpTy<'tcx>, ) -> InterpResult<'tcx, i32> { #[cfg(unix)] fn create_link(src: &Path, dst: &Path) -> std::io::Result<()> { @@ -474,9 +469,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn macos_fbsd_stat( &mut self, - path_op: &OpTy<'tcx, Provenance>, - buf_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, Scalar> { + path_op: &OpTy<'tcx>, + buf_op: &OpTy<'tcx>, + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); if !matches!(&*this.tcx.sess.target.os, "macos" | "freebsd") { @@ -506,9 +501,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // `lstat` is used to get symlink metadata. fn macos_fbsd_lstat( &mut self, - path_op: &OpTy<'tcx, Provenance>, - buf_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, Scalar> { + path_op: &OpTy<'tcx>, + buf_op: &OpTy<'tcx>, + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); if !matches!(&*this.tcx.sess.target.os, "macos" | "freebsd") { @@ -536,9 +531,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn macos_fbsd_fstat( &mut self, - fd_op: &OpTy<'tcx, Provenance>, - buf_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, Scalar> { + fd_op: &OpTy<'tcx>, + buf_op: &OpTy<'tcx>, + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); if !matches!(&*this.tcx.sess.target.os, "macos" | "freebsd") { @@ -563,11 +558,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn linux_statx( &mut self, - dirfd_op: &OpTy<'tcx, Provenance>, // Should be an `int` - pathname_op: &OpTy<'tcx, Provenance>, // Should be a `const char *` - flags_op: &OpTy<'tcx, Provenance>, // Should be an `int` - mask_op: &OpTy<'tcx, Provenance>, // Should be an `unsigned int` - statxbuf_op: &OpTy<'tcx, Provenance>, // Should be a `struct statx *` + dirfd_op: &OpTy<'tcx>, // Should be an `int` + pathname_op: &OpTy<'tcx>, // Should be a `const char *` + flags_op: &OpTy<'tcx>, // Should be an `int` + mask_op: &OpTy<'tcx>, // Should be an `unsigned int` + statxbuf_op: &OpTy<'tcx>, // Should be a `struct statx *` ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -745,8 +740,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn rename( &mut self, - oldpath_op: &OpTy<'tcx, Provenance>, - newpath_op: &OpTy<'tcx, Provenance>, + oldpath_op: &OpTy<'tcx>, + newpath_op: &OpTy<'tcx>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -774,11 +769,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.try_unwrap_io_result(result) } - fn mkdir( - &mut self, - path_op: &OpTy<'tcx, Provenance>, - mode_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, i32> { + fn mkdir(&mut self, path_op: &OpTy<'tcx>, mode_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); #[cfg_attr(not(unix), allow(unused_variables))] @@ -813,7 +804,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.try_unwrap_io_result(result) } - fn rmdir(&mut self, path_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> { + fn rmdir(&mut self, path_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let path = this.read_path_from_c_str(this.read_pointer(path_op)?)?; @@ -830,10 +821,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.try_unwrap_io_result(result) } - fn opendir( - &mut self, - name_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, Scalar> { + fn opendir(&mut self, name_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let name = this.read_path_from_c_str(this.read_pointer(name_op)?)?; @@ -864,10 +852,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } } - fn linux_readdir64( - &mut self, - dirp_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, Scalar> { + fn linux_readdir64(&mut self, dirp_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); this.assert_target_os("linux", "readdir64"); @@ -915,7 +900,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { dirent64_layout.align.abi, MiriMemoryKind::Runtime.into(), )?; - let entry: Pointer> = entry.into(); + let entry: Pointer = entry.into(); // If the host is a Unix system, fill in the inode number with its real value. // If not, use 0 as a fallback value. @@ -962,10 +947,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn macos_fbsd_readdir_r( &mut self, - dirp_op: &OpTy<'tcx, Provenance>, - entry_op: &OpTy<'tcx, Provenance>, - result_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, Scalar> { + dirp_op: &OpTy<'tcx>, + entry_op: &OpTy<'tcx>, + result_op: &OpTy<'tcx>, + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); if !matches!(&*this.tcx.sess.target.os, "macos" | "freebsd") { @@ -1083,7 +1068,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { })) } - fn closedir(&mut self, dirp_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> { + fn closedir(&mut self, dirp_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let dirp = this.read_target_usize(dirp_op)?; @@ -1106,7 +1091,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } } - fn ftruncate64(&mut self, fd: i32, length: i128) -> InterpResult<'tcx, Scalar> { + fn ftruncate64(&mut self, fd: i32, length: i128) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); // Reject if isolation is enabled. @@ -1147,7 +1132,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } } - fn fsync(&mut self, fd_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> { + fn fsync(&mut self, fd_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> { // On macOS, `fsync` (unlike `fcntl(F_FULLFSYNC)`) does not wait for the // underlying disk to finish writing. In the interest of host compatibility, // we conservatively implement this with `sync_all`, which @@ -1182,7 +1167,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.try_unwrap_io_result(io_result) } - fn fdatasync(&mut self, fd_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> { + fn fdatasync(&mut self, fd_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let fd = this.read_scalar(fd_op)?.to_i32()?; @@ -1209,11 +1194,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn sync_file_range( &mut self, - fd_op: &OpTy<'tcx, Provenance>, - offset_op: &OpTy<'tcx, Provenance>, - nbytes_op: &OpTy<'tcx, Provenance>, - flags_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, Scalar> { + fd_op: &OpTy<'tcx>, + offset_op: &OpTy<'tcx>, + nbytes_op: &OpTy<'tcx>, + flags_op: &OpTy<'tcx>, + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let fd = this.read_scalar(fd_op)?.to_i32()?; @@ -1259,9 +1244,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn readlink( &mut self, - pathname_op: &OpTy<'tcx, Provenance>, - buf_op: &OpTy<'tcx, Provenance>, - bufsize_op: &OpTy<'tcx, Provenance>, + pathname_op: &OpTy<'tcx>, + buf_op: &OpTy<'tcx>, + bufsize_op: &OpTy<'tcx>, ) -> InterpResult<'tcx, i64> { let this = self.eval_context_mut(); @@ -1302,10 +1287,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } } - fn isatty( - &mut self, - miri_fd: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, Scalar> { + fn isatty(&mut self, miri_fd: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); // "returns 1 if fd is an open file descriptor referring to a terminal; // otherwise 0 is returned, and errno is set to indicate the error" @@ -1326,9 +1308,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn realpath( &mut self, - path_op: &OpTy<'tcx, Provenance>, - processed_path_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, Scalar> { + path_op: &OpTy<'tcx>, + processed_path_op: &OpTy<'tcx>, + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); this.assert_target_os_is_unix("realpath"); @@ -1384,7 +1366,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } } } - fn mkstemp(&mut self, template_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> { + fn mkstemp(&mut self, template_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> { use rand::seq::SliceRandom; // POSIX defines the template string. @@ -1531,7 +1513,7 @@ fn extract_sec_and_nsec<'tcx>( /// Stores a file's metadata in order to avoid code duplication in the different metadata related /// shims. struct FileMetadata { - mode: Scalar, + mode: Scalar, size: u64, created: Option<(u64, u32)>, accessed: Option<(u64, u32)>, diff --git a/src/tools/miri/src/shims/unix/linux/epoll.rs b/src/tools/miri/src/shims/unix/linux/epoll.rs index 50868e60e9510..aa4dc98287016 100644 --- a/src/tools/miri/src/shims/unix/linux/epoll.rs +++ b/src/tools/miri/src/shims/unix/linux/epoll.rs @@ -25,10 +25,10 @@ struct Epoll { struct EpollEvent { #[allow(dead_code)] events: u32, - /// `Scalar` is used to represent the + /// `Scalar` is used to represent the /// `epoll_data` type union. #[allow(dead_code)] - data: Scalar, + data: Scalar, } impl FileDescription for Epoll { @@ -51,10 +51,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// is 0, then this function is the same as `epoll_create()`. /// /// - fn epoll_create1( - &mut self, - flags: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, Scalar> { + fn epoll_create1(&mut self, flags: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let flags = this.read_scalar(flags)?.to_i32()?; @@ -85,11 +82,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// fn epoll_ctl( &mut self, - epfd: &OpTy<'tcx, Provenance>, - op: &OpTy<'tcx, Provenance>, - fd: &OpTy<'tcx, Provenance>, - event: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, Scalar> { + epfd: &OpTy<'tcx>, + op: &OpTy<'tcx>, + fd: &OpTy<'tcx>, + event: &OpTy<'tcx>, + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let epfd = this.read_scalar(epfd)?.to_i32()?; @@ -167,11 +164,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// fn epoll_wait( &mut self, - epfd: &OpTy<'tcx, Provenance>, - events: &OpTy<'tcx, Provenance>, - maxevents: &OpTy<'tcx, Provenance>, - timeout: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, Scalar> { + epfd: &OpTy<'tcx>, + events: &OpTy<'tcx>, + maxevents: &OpTy<'tcx>, + timeout: &OpTy<'tcx>, + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let epfd = this.read_scalar(epfd)?.to_i32()?; diff --git a/src/tools/miri/src/shims/unix/linux/eventfd.rs b/src/tools/miri/src/shims/unix/linux/eventfd.rs index 1447e498fd7d1..cae5abca3bd08 100644 --- a/src/tools/miri/src/shims/unix/linux/eventfd.rs +++ b/src/tools/miri/src/shims/unix/linux/eventfd.rs @@ -1,14 +1,21 @@ //! Linux `eventfd` implementation. -//! Currently just a stub. use std::io; +use std::io::{Error, ErrorKind}; +use std::mem; use rustc_target::abi::Endian; use crate::shims::unix::*; -use crate::*; +use crate::{concurrency::VClock, *}; use self::shims::unix::fd::FileDescriptor; +// We'll only do reads and writes in chunks of size u64. +const U64_ARRAY_SIZE: usize = mem::size_of::(); + +/// Maximum value that the eventfd counter can hold. +const MAX_COUNTER: u64 = u64::MAX - 1; + /// A kind of file descriptor created by `eventfd`. /// The `Event` type isn't currently written to by `eventfd`. /// The interface is meant to keep track of objects associated @@ -20,7 +27,9 @@ use self::shims::unix::fd::FileDescriptor; struct Event { /// The object contains an unsigned 64-bit integer (uint64_t) counter that is maintained by the /// kernel. This counter is initialized with the value specified in the argument initval. - val: u64, + counter: u64, + is_nonblock: bool, + clock: VClock, } impl FileDescription for Event { @@ -35,6 +44,38 @@ impl FileDescription for Event { Ok(Ok(())) } + /// Read the counter in the buffer and return the counter if succeeded. + fn read<'tcx>( + &mut self, + _communicate_allowed: bool, + bytes: &mut [u8], + ecx: &mut MiriInterpCx<'tcx>, + ) -> InterpResult<'tcx, io::Result> { + // Check the size of slice, and return error only if the size of the slice < 8. + let Some(bytes) = bytes.first_chunk_mut::() else { + return Ok(Err(Error::from(ErrorKind::InvalidInput))); + }; + // Block when counter == 0. + if self.counter == 0 { + if self.is_nonblock { + return Ok(Err(Error::from(ErrorKind::WouldBlock))); + } else { + //FIXME: blocking is not supported + throw_unsup_format!("eventfd: blocking is unsupported"); + } + } else { + // Synchronize with all prior `write` calls to this FD. + ecx.acquire_clock(&self.clock); + // Return the counter in the host endianness using the buffer provided by caller. + *bytes = match ecx.tcx.sess.target.endian { + Endian::Little => self.counter.to_le_bytes(), + Endian::Big => self.counter.to_be_bytes(), + }; + self.counter = 0; + return Ok(Ok(U64_ARRAY_SIZE)); + } + } + /// A write call adds the 8-byte integer value supplied in /// its buffer (in native endianness) to the counter. The maximum value that may be /// stored in the counter is the largest unsigned 64-bit value @@ -53,16 +94,39 @@ impl FileDescription for Event { bytes: &[u8], ecx: &mut MiriInterpCx<'tcx>, ) -> InterpResult<'tcx, io::Result> { - let bytes: [u8; 8] = bytes.try_into().unwrap(); // FIXME fail gracefully when this has the wrong size - // Convert from target endianness to host endianness. + // Check the size of slice, and return error only if the size of the slice < 8. + let Some(bytes) = bytes.first_chunk::() else { + return Ok(Err(Error::from(ErrorKind::InvalidInput))); + }; + // Convert from bytes to int according to host endianness. let num = match ecx.tcx.sess.target.endian { - Endian::Little => u64::from_le_bytes(bytes), - Endian::Big => u64::from_be_bytes(bytes), + Endian::Little => u64::from_le_bytes(*bytes), + Endian::Big => u64::from_be_bytes(*bytes), + }; + // u64::MAX as input is invalid because the maximum value of counter is u64::MAX - 1. + if num == u64::MAX { + return Ok(Err(Error::from(ErrorKind::InvalidInput))); + } + // If the addition does not let the counter to exceed the maximum value, update the counter. + // Else, block. + match self.counter.checked_add(num) { + Some(new_count @ 0..=MAX_COUNTER) => { + // Future `read` calls will synchronize with this write, so update the FD clock. + if let Some(clock) = &ecx.release_clock() { + self.clock.join(clock); + } + self.counter = new_count; + } + None | Some(u64::MAX) => { + if self.is_nonblock { + return Ok(Err(Error::from(ErrorKind::WouldBlock))); + } else { + //FIXME: blocking is not supported + throw_unsup_format!("eventfd: blocking is unsupported"); + } + } }; - // FIXME handle blocking when addition results in exceeding the max u64 value - // or fail with EAGAIN if the file descriptor is nonblocking. - self.val = self.val.checked_add(num).unwrap(); - Ok(Ok(8)) + Ok(Ok(U64_ARRAY_SIZE)) } } @@ -84,34 +148,43 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// `EFD_SEMAPHORE` - miri does not support semaphore-like semantics. /// /// - fn eventfd( - &mut self, - val: &OpTy<'tcx, Provenance>, - flags: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, Scalar> { + fn eventfd(&mut self, val: &OpTy<'tcx>, flags: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); + // eventfd is Linux specific. + this.assert_target_os("linux", "eventfd"); + let val = this.read_scalar(val)?.to_u32()?; - let flags = this.read_scalar(flags)?.to_i32()?; + let mut flags = this.read_scalar(flags)?.to_i32()?; let efd_cloexec = this.eval_libc_i32("EFD_CLOEXEC"); let efd_nonblock = this.eval_libc_i32("EFD_NONBLOCK"); let efd_semaphore = this.eval_libc_i32("EFD_SEMAPHORE"); - if flags & (efd_cloexec | efd_nonblock | efd_semaphore) != flags { - throw_unsup_format!("eventfd: flag {flags:#x} is unsupported"); + if flags & efd_semaphore == efd_semaphore { + throw_unsup_format!("eventfd: EFD_SEMAPHORE is unsupported"); } + + let mut is_nonblock = false; + // Unset the flag that we support. + // After unloading, flags != 0 means other flags are used. if flags & efd_cloexec == efd_cloexec { - // cloexec does nothing as we don't support `exec` + // cloexec is ignored because Miri does not support exec. + flags &= !efd_cloexec; } if flags & efd_nonblock == efd_nonblock { - // FIXME remember the nonblock flag + flags &= !efd_nonblock; + is_nonblock = true; } - if flags & efd_semaphore == efd_semaphore { - throw_unsup_format!("eventfd: EFD_SEMAPHORE is unsupported"); + if flags != 0 { + throw_unsup_format!("eventfd: encountered unknown unsupported flags {:#x}", flags); } - let fd = this.machine.fds.insert_fd(FileDescriptor::new(Event { val: val.into() })); + let fd = this.machine.fds.insert_fd(FileDescriptor::new(Event { + counter: val.into(), + is_nonblock, + clock: VClock::default(), + })); Ok(Scalar::from_i32(fd)) } } diff --git a/src/tools/miri/src/shims/unix/linux/foreign_items.rs b/src/tools/miri/src/shims/unix/linux/foreign_items.rs index 7d0c8be1eaa08..e31d43d9190a0 100644 --- a/src/tools/miri/src/shims/unix/linux/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/linux/foreign_items.rs @@ -20,8 +20,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { &mut self, link_name: Symbol, abi: Abi, - args: &[OpTy<'tcx, Provenance>], - dest: &MPlaceTy<'tcx, Provenance>, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, EmulateItemResult> { let this = self.eval_context_mut(); diff --git a/src/tools/miri/src/shims/unix/linux/mem.rs b/src/tools/miri/src/shims/unix/linux/mem.rs index 5f5d2b0c739de..c430eff0180ea 100644 --- a/src/tools/miri/src/shims/unix/linux/mem.rs +++ b/src/tools/miri/src/shims/unix/linux/mem.rs @@ -8,11 +8,11 @@ impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn mremap( &mut self, - old_address: &OpTy<'tcx, Provenance>, - old_size: &OpTy<'tcx, Provenance>, - new_size: &OpTy<'tcx, Provenance>, - flags: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, Scalar> { + old_address: &OpTy<'tcx>, + old_size: &OpTy<'tcx>, + new_size: &OpTy<'tcx>, + flags: &OpTy<'tcx>, + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let old_address = this.read_pointer(old_address)?; diff --git a/src/tools/miri/src/shims/unix/linux/sync.rs b/src/tools/miri/src/shims/unix/linux/sync.rs index de83a358db92d..bd21203907419 100644 --- a/src/tools/miri/src/shims/unix/linux/sync.rs +++ b/src/tools/miri/src/shims/unix/linux/sync.rs @@ -1,13 +1,11 @@ -use std::time::SystemTime; - use crate::*; /// Implementation of the SYS_futex syscall. /// `args` is the arguments *after* the syscall number. pub fn futex<'tcx>( this: &mut MiriInterpCx<'tcx>, - args: &[OpTy<'tcx, Provenance>], - dest: &MPlaceTy<'tcx, Provenance>, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx> { // The amount of arguments used depends on the type of futex operation. // The full futex syscall takes six arguments (excluding the syscall @@ -84,15 +82,9 @@ pub fn futex<'tcx>( } let timeout = this.deref_pointer_as(&args[3], this.libc_ty_layout("timespec"))?; - let timeout_time = if this.ptr_is_null(timeout.ptr())? { + let timeout = if this.ptr_is_null(timeout.ptr())? { None } else { - let realtime = op & futex_realtime == futex_realtime; - if realtime { - this.check_no_isolation( - "`futex` syscall with `op=FUTEX_WAIT` and non-null timeout with `FUTEX_CLOCK_REALTIME`", - )?; - } let duration = match this.read_timespec(&timeout)? { Some(duration) => duration, None => { @@ -102,23 +94,22 @@ pub fn futex<'tcx>( return Ok(()); } }; - Some(if wait_bitset { + let timeout_clock = if op & futex_realtime == futex_realtime { + this.check_no_isolation( + "`futex` syscall with `op=FUTEX_WAIT` and non-null timeout with `FUTEX_CLOCK_REALTIME`", + )?; + TimeoutClock::RealTime + } else { + TimeoutClock::Monotonic + }; + let timeout_anchor = if wait_bitset { // FUTEX_WAIT_BITSET uses an absolute timestamp. - if realtime { - Timeout::RealTime(SystemTime::UNIX_EPOCH.checked_add(duration).unwrap()) - } else { - Timeout::Monotonic( - this.machine.clock.anchor().checked_add(duration).unwrap(), - ) - } + TimeoutAnchor::Absolute } else { // FUTEX_WAIT uses a relative timestamp. - if realtime { - Timeout::RealTime(SystemTime::now().checked_add(duration).unwrap()) - } else { - Timeout::Monotonic(this.machine.clock.now().checked_add(duration).unwrap()) - } - }) + TimeoutAnchor::Relative + }; + Some((timeout_clock, timeout_anchor, duration)) }; // There may be a concurrent thread changing the value of addr // and then invoking the FUTEX_WAKE syscall. It is critical that the @@ -172,7 +163,7 @@ pub fn futex<'tcx>( this.futex_wait( addr_usize, bitset, - timeout_time, + timeout, Scalar::from_target_isize(0, this), // retval_succ Scalar::from_target_isize(-1, this), // retval_timeout dest.clone(), diff --git a/src/tools/miri/src/shims/unix/macos/foreign_items.rs b/src/tools/miri/src/shims/unix/macos/foreign_items.rs index a1e9ccec676ec..25002f0a611c7 100644 --- a/src/tools/miri/src/shims/unix/macos/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/macos/foreign_items.rs @@ -14,8 +14,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { &mut self, link_name: Symbol, abi: Abi, - args: &[OpTy<'tcx, Provenance>], - dest: &MPlaceTy<'tcx, Provenance>, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, EmulateItemResult> { let this = self.eval_context_mut(); diff --git a/src/tools/miri/src/shims/unix/mem.rs b/src/tools/miri/src/shims/unix/mem.rs index 4d727c0b1804f..de5a5d0759c4b 100644 --- a/src/tools/miri/src/shims/unix/mem.rs +++ b/src/tools/miri/src/shims/unix/mem.rs @@ -21,13 +21,13 @@ impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn mmap( &mut self, - addr: &OpTy<'tcx, Provenance>, - length: &OpTy<'tcx, Provenance>, - prot: &OpTy<'tcx, Provenance>, - flags: &OpTy<'tcx, Provenance>, - fd: &OpTy<'tcx, Provenance>, + addr: &OpTy<'tcx>, + length: &OpTy<'tcx>, + prot: &OpTy<'tcx>, + flags: &OpTy<'tcx>, + fd: &OpTy<'tcx>, offset: i128, - ) -> InterpResult<'tcx, Scalar> { + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); // We do not support MAP_FIXED, so the addr argument is always ignored (except for the MacOS hack) @@ -123,11 +123,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Ok(Scalar::from_pointer(ptr, this)) } - fn munmap( - &mut self, - addr: &OpTy<'tcx, Provenance>, - length: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, Scalar> { + fn munmap(&mut self, addr: &OpTy<'tcx>, length: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let addr = this.read_pointer(addr)?; diff --git a/src/tools/miri/src/shims/unix/socket.rs b/src/tools/miri/src/shims/unix/socket.rs index a0fa3bcee3427..7eb7e28ea367d 100644 --- a/src/tools/miri/src/shims/unix/socket.rs +++ b/src/tools/miri/src/shims/unix/socket.rs @@ -35,11 +35,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// fn socketpair( &mut self, - domain: &OpTy<'tcx, Provenance>, - type_: &OpTy<'tcx, Provenance>, - protocol: &OpTy<'tcx, Provenance>, - sv: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, Scalar> { + domain: &OpTy<'tcx>, + type_: &OpTy<'tcx>, + protocol: &OpTy<'tcx>, + sv: &OpTy<'tcx>, + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let _domain = this.read_scalar(domain)?.to_i32()?; diff --git a/src/tools/miri/src/shims/unix/solarish/foreign_items.rs b/src/tools/miri/src/shims/unix/solarish/foreign_items.rs index 38cd83edd24ac..a0cc4a62bfd2b 100644 --- a/src/tools/miri/src/shims/unix/solarish/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/solarish/foreign_items.rs @@ -14,8 +14,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { &mut self, link_name: Symbol, abi: Abi, - args: &[OpTy<'tcx, Provenance>], - dest: &MPlaceTy<'tcx, Provenance>, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, EmulateItemResult> { let this = self.eval_context_mut(); match link_name.as_str() { @@ -69,6 +69,36 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_null(dest)?; } + "pset_info" => { + let [pset, tpe, cpus, list] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + // We do not need to handle the current process cpu mask, available_parallelism + // implementation pass null anyway. We only care for the number of + // cpus. + // https://docs.oracle.com/cd/E88353_01/html/E37841/pset-info-2.html + + let pset = this.read_scalar(pset)?.to_i32()?; + let tpe = this.read_pointer(tpe)?; + let list = this.read_pointer(list)?; + + let ps_myid = this.eval_libc_i32("PS_MYID"); + if ps_myid != pset { + throw_unsup_format!("pset_info is only supported with pset==PS_MYID"); + } + + if !this.ptr_is_null(tpe)? { + throw_unsup_format!("pset_info is only supported with type==NULL"); + } + + if !this.ptr_is_null(list)? { + throw_unsup_format!("pset_info is only supported with list==NULL"); + } + + let cpus = this.deref_pointer(cpus)?; + this.write_scalar(Scalar::from_u32(this.machine.num_cpus), &cpus)?; + this.write_null(dest)?; + } + _ => return Ok(EmulateItemResult::NotSupported), } Ok(EmulateItemResult::NeedsReturn) diff --git a/src/tools/miri/src/shims/unix/sync.rs b/src/tools/miri/src/shims/unix/sync.rs index 0743ad14495d4..be6732b1b67ed 100644 --- a/src/tools/miri/src/shims/unix/sync.rs +++ b/src/tools/miri/src/shims/unix/sync.rs @@ -1,5 +1,4 @@ use std::sync::atomic::{AtomicBool, Ordering}; -use std::time::SystemTime; use rustc_target::abi::Size; @@ -10,9 +9,7 @@ use crate::*; // - kind: i32 #[inline] -fn mutexattr_kind_offset<'tcx>( - ecx: &MiriInterpCx<'tcx>, -) -> InterpResult<'tcx, u64> { +fn mutexattr_kind_offset<'tcx>(ecx: &MiriInterpCx<'tcx>) -> InterpResult<'tcx, u64> { Ok(match &*ecx.tcx.sess.target.os { "linux" | "illumos" | "solaris" | "macos" => 0, os => throw_unsup_format!("`pthread_mutexattr` is not supported on {os}"), @@ -21,7 +18,7 @@ fn mutexattr_kind_offset<'tcx>( fn mutexattr_get_kind<'tcx>( ecx: &MiriInterpCx<'tcx>, - attr_op: &OpTy<'tcx, Provenance>, + attr_op: &OpTy<'tcx>, ) -> InterpResult<'tcx, i32> { ecx.deref_pointer_and_read( attr_op, @@ -34,7 +31,7 @@ fn mutexattr_get_kind<'tcx>( fn mutexattr_set_kind<'tcx>( ecx: &mut MiriInterpCx<'tcx>, - attr_op: &OpTy<'tcx, Provenance>, + attr_op: &OpTy<'tcx>, kind: i32, ) -> InterpResult<'tcx, ()> { ecx.deref_pointer_and_write( @@ -53,17 +50,11 @@ fn mutexattr_set_kind<'tcx>( /// in `pthread_mutexattr_settype` function. const PTHREAD_MUTEX_NORMAL_FLAG: i32 = 0x8000000; -fn is_mutex_kind_default<'tcx>( - ecx: &MiriInterpCx<'tcx>, - kind: i32, -) -> InterpResult<'tcx, bool> { +fn is_mutex_kind_default<'tcx>(ecx: &MiriInterpCx<'tcx>, kind: i32) -> InterpResult<'tcx, bool> { Ok(kind == ecx.eval_libc_i32("PTHREAD_MUTEX_DEFAULT")) } -fn is_mutex_kind_normal<'tcx>( - ecx: &MiriInterpCx<'tcx>, - kind: i32, -) -> InterpResult<'tcx, bool> { +fn is_mutex_kind_normal<'tcx>(ecx: &MiriInterpCx<'tcx>, kind: i32) -> InterpResult<'tcx, bool> { let mutex_normal_kind = ecx.eval_libc_i32("PTHREAD_MUTEX_NORMAL"); Ok(kind == (mutex_normal_kind | PTHREAD_MUTEX_NORMAL_FLAG)) } @@ -125,7 +116,7 @@ fn mutex_kind_offset<'tcx>(ecx: &MiriInterpCx<'tcx>) -> u64 { fn mutex_get_id<'tcx>( ecx: &mut MiriInterpCx<'tcx>, - mutex_op: &OpTy<'tcx, Provenance>, + mutex_op: &OpTy<'tcx>, ) -> InterpResult<'tcx, MutexId> { ecx.mutex_get_or_create_id( mutex_op, @@ -136,7 +127,7 @@ fn mutex_get_id<'tcx>( fn mutex_reset_id<'tcx>( ecx: &mut MiriInterpCx<'tcx>, - mutex_op: &OpTy<'tcx, Provenance>, + mutex_op: &OpTy<'tcx>, ) -> InterpResult<'tcx, ()> { ecx.deref_pointer_and_write( mutex_op, @@ -149,7 +140,7 @@ fn mutex_reset_id<'tcx>( fn mutex_get_kind<'tcx>( ecx: &MiriInterpCx<'tcx>, - mutex_op: &OpTy<'tcx, Provenance>, + mutex_op: &OpTy<'tcx>, ) -> InterpResult<'tcx, i32> { ecx.deref_pointer_and_read( mutex_op, @@ -162,7 +153,7 @@ fn mutex_get_kind<'tcx>( fn mutex_set_kind<'tcx>( ecx: &mut MiriInterpCx<'tcx>, - mutex_op: &OpTy<'tcx, Provenance>, + mutex_op: &OpTy<'tcx>, kind: i32, ) -> InterpResult<'tcx, ()> { ecx.deref_pointer_and_write( @@ -206,7 +197,7 @@ fn rwlock_id_offset<'tcx>(ecx: &MiriInterpCx<'tcx>) -> InterpResult<'tcx, u64> { fn rwlock_get_id<'tcx>( ecx: &mut MiriInterpCx<'tcx>, - rwlock_op: &OpTy<'tcx, Provenance>, + rwlock_op: &OpTy<'tcx>, ) -> InterpResult<'tcx, RwLockId> { ecx.rwlock_get_or_create_id( rwlock_op, @@ -220,9 +211,7 @@ fn rwlock_get_id<'tcx>( // - clock: i32 #[inline] -fn condattr_clock_offset<'tcx>( - ecx: &MiriInterpCx<'tcx>, -) -> InterpResult<'tcx, u64> { +fn condattr_clock_offset<'tcx>(ecx: &MiriInterpCx<'tcx>) -> InterpResult<'tcx, u64> { Ok(match &*ecx.tcx.sess.target.os { "linux" | "illumos" | "solaris" => 0, // macOS does not have a clock attribute. @@ -232,7 +221,7 @@ fn condattr_clock_offset<'tcx>( fn condattr_get_clock_id<'tcx>( ecx: &MiriInterpCx<'tcx>, - attr_op: &OpTy<'tcx, Provenance>, + attr_op: &OpTy<'tcx>, ) -> InterpResult<'tcx, i32> { ecx.deref_pointer_and_read( attr_op, @@ -245,7 +234,7 @@ fn condattr_get_clock_id<'tcx>( fn condattr_set_clock_id<'tcx>( ecx: &mut MiriInterpCx<'tcx>, - attr_op: &OpTy<'tcx, Provenance>, + attr_op: &OpTy<'tcx>, clock_id: i32, ) -> InterpResult<'tcx, ()> { ecx.deref_pointer_and_write( @@ -323,7 +312,7 @@ fn cond_clock_offset<'tcx>(ecx: &MiriInterpCx<'tcx>) -> u64 { fn cond_get_id<'tcx>( ecx: &mut MiriInterpCx<'tcx>, - cond_op: &OpTy<'tcx, Provenance>, + cond_op: &OpTy<'tcx>, ) -> InterpResult<'tcx, CondvarId> { ecx.condvar_get_or_create_id( cond_op, @@ -334,7 +323,7 @@ fn cond_get_id<'tcx>( fn cond_reset_id<'tcx>( ecx: &mut MiriInterpCx<'tcx>, - cond_op: &OpTy<'tcx, Provenance>, + cond_op: &OpTy<'tcx>, ) -> InterpResult<'tcx, ()> { ecx.deref_pointer_and_write( cond_op, @@ -347,7 +336,7 @@ fn cond_reset_id<'tcx>( fn cond_get_clock_id<'tcx>( ecx: &MiriInterpCx<'tcx>, - cond_op: &OpTy<'tcx, Provenance>, + cond_op: &OpTy<'tcx>, ) -> InterpResult<'tcx, i32> { ecx.deref_pointer_and_read( cond_op, @@ -360,7 +349,7 @@ fn cond_get_clock_id<'tcx>( fn cond_set_clock_id<'tcx>( ecx: &mut MiriInterpCx<'tcx>, - cond_op: &OpTy<'tcx, Provenance>, + cond_op: &OpTy<'tcx>, clock_id: i32, ) -> InterpResult<'tcx, ()> { ecx.deref_pointer_and_write( @@ -374,10 +363,7 @@ fn cond_set_clock_id<'tcx>( impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { - fn pthread_mutexattr_init( - &mut self, - attr_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, i32> { + fn pthread_mutexattr_init(&mut self, attr_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let default_kind = this.eval_libc_i32("PTHREAD_MUTEX_DEFAULT"); @@ -388,8 +374,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn pthread_mutexattr_settype( &mut self, - attr_op: &OpTy<'tcx, Provenance>, - kind_op: &OpTy<'tcx, Provenance>, + attr_op: &OpTy<'tcx>, + kind_op: &OpTy<'tcx>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -427,10 +413,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Ok(0) } - fn pthread_mutexattr_destroy( - &mut self, - attr_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, i32> { + fn pthread_mutexattr_destroy(&mut self, attr_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); // Destroying an uninit pthread_mutexattr is UB, so check to make sure it's not uninit. @@ -457,8 +440,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn pthread_mutex_init( &mut self, - mutex_op: &OpTy<'tcx, Provenance>, - attr_op: &OpTy<'tcx, Provenance>, + mutex_op: &OpTy<'tcx>, + attr_op: &OpTy<'tcx>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -479,8 +462,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn pthread_mutex_lock( &mut self, - mutex_op: &OpTy<'tcx, Provenance>, - dest: &MPlaceTy<'tcx, Provenance>, + mutex_op: &OpTy<'tcx>, + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -518,10 +501,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Ok(()) } - fn pthread_mutex_trylock( - &mut self, - mutex_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, i32> { + fn pthread_mutex_trylock(&mut self, mutex_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let kind = mutex_get_kind(this, mutex_op)?; @@ -553,10 +533,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } } - fn pthread_mutex_unlock( - &mut self, - mutex_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, i32> { + fn pthread_mutex_unlock(&mut self, mutex_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let kind = mutex_get_kind(this, mutex_op)?; @@ -587,10 +564,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } } - fn pthread_mutex_destroy( - &mut self, - mutex_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, i32> { + fn pthread_mutex_destroy(&mut self, mutex_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let id = mutex_get_id(this, mutex_op)?; @@ -614,8 +588,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn pthread_rwlock_rdlock( &mut self, - rwlock_op: &OpTy<'tcx, Provenance>, - dest: &MPlaceTy<'tcx, Provenance>, + rwlock_op: &OpTy<'tcx>, + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -631,10 +605,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Ok(()) } - fn pthread_rwlock_tryrdlock( - &mut self, - rwlock_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, i32> { + fn pthread_rwlock_tryrdlock(&mut self, rwlock_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let id = rwlock_get_id(this, rwlock_op)?; @@ -649,8 +620,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn pthread_rwlock_wrlock( &mut self, - rwlock_op: &OpTy<'tcx, Provenance>, - dest: &MPlaceTy<'tcx, Provenance>, + rwlock_op: &OpTy<'tcx>, + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -678,10 +649,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Ok(()) } - fn pthread_rwlock_trywrlock( - &mut self, - rwlock_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, i32> { + fn pthread_rwlock_trywrlock(&mut self, rwlock_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let id = rwlock_get_id(this, rwlock_op)?; @@ -694,10 +662,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } } - fn pthread_rwlock_unlock( - &mut self, - rwlock_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, i32> { + fn pthread_rwlock_unlock(&mut self, rwlock_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let id = rwlock_get_id(this, rwlock_op)?; @@ -712,10 +677,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } } - fn pthread_rwlock_destroy( - &mut self, - rwlock_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, i32> { + fn pthread_rwlock_destroy(&mut self, rwlock_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let id = rwlock_get_id(this, rwlock_op)?; @@ -736,10 +698,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Ok(0) } - fn pthread_condattr_init( - &mut self, - attr_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, i32> { + fn pthread_condattr_init(&mut self, attr_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); // no clock attribute on macOS @@ -756,9 +715,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn pthread_condattr_setclock( &mut self, - attr_op: &OpTy<'tcx, Provenance>, - clock_id_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, Scalar> { + attr_op: &OpTy<'tcx>, + clock_id_op: &OpTy<'tcx>, + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let clock_id = this.read_scalar(clock_id_op)?.to_i32()?; @@ -776,9 +735,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn pthread_condattr_getclock( &mut self, - attr_op: &OpTy<'tcx, Provenance>, - clk_id_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, Scalar> { + attr_op: &OpTy<'tcx>, + clk_id_op: &OpTy<'tcx>, + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let clock_id = condattr_get_clock_id(this, attr_op)?; @@ -787,10 +746,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Ok(Scalar::from_i32(0)) } - fn pthread_condattr_destroy( - &mut self, - attr_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, i32> { + fn pthread_condattr_destroy(&mut self, attr_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); // Destroying an uninit pthread_condattr is UB, so check to make sure it's not uninit. @@ -810,8 +766,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn pthread_cond_init( &mut self, - cond_op: &OpTy<'tcx, Provenance>, - attr_op: &OpTy<'tcx, Provenance>, + cond_op: &OpTy<'tcx>, + attr_op: &OpTy<'tcx>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -831,17 +787,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Ok(0) } - fn pthread_cond_signal(&mut self, cond_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> { + fn pthread_cond_signal(&mut self, cond_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let id = cond_get_id(this, cond_op)?; this.condvar_signal(id)?; Ok(0) } - fn pthread_cond_broadcast( - &mut self, - cond_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, i32> { + fn pthread_cond_broadcast(&mut self, cond_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let id = cond_get_id(this, cond_op)?; while this.condvar_signal(id)? {} @@ -850,9 +803,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn pthread_cond_wait( &mut self, - cond_op: &OpTy<'tcx, Provenance>, - mutex_op: &OpTy<'tcx, Provenance>, - dest: &MPlaceTy<'tcx, Provenance>, + cond_op: &OpTy<'tcx>, + mutex_op: &OpTy<'tcx>, + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -873,10 +826,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn pthread_cond_timedwait( &mut self, - cond_op: &OpTy<'tcx, Provenance>, - mutex_op: &OpTy<'tcx, Provenance>, - abstime_op: &OpTy<'tcx, Provenance>, - dest: &MPlaceTy<'tcx, Provenance>, + cond_op: &OpTy<'tcx>, + mutex_op: &OpTy<'tcx>, + abstime_op: &OpTy<'tcx>, + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -895,11 +848,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { return Ok(()); } }; - let timeout_time = if is_cond_clock_realtime(this, clock_id) { + let timeout_clock = if is_cond_clock_realtime(this, clock_id) { this.check_no_isolation("`pthread_cond_timedwait` with `CLOCK_REALTIME`")?; - Timeout::RealTime(SystemTime::UNIX_EPOCH.checked_add(duration).unwrap()) + TimeoutClock::RealTime } else if clock_id == this.eval_libc_i32("CLOCK_MONOTONIC") { - Timeout::Monotonic(this.machine.clock.anchor().checked_add(duration).unwrap()) + TimeoutClock::Monotonic } else { throw_unsup_format!("unsupported clock id: {}", clock_id); }; @@ -907,7 +860,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.condvar_wait( id, mutex_id, - Some(timeout_time), + Some((timeout_clock, TimeoutAnchor::Absolute, duration)), Scalar::from_i32(0), this.eval_libc("ETIMEDOUT"), // retval_timeout dest.clone(), @@ -916,10 +869,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Ok(()) } - fn pthread_cond_destroy( - &mut self, - cond_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, i32> { + fn pthread_cond_destroy(&mut self, cond_op: &OpTy<'tcx>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let id = cond_get_id(this, cond_op)?; diff --git a/src/tools/miri/src/shims/unix/thread.rs b/src/tools/miri/src/shims/unix/thread.rs index 323b5c1992ebb..6fe331ba623a1 100644 --- a/src/tools/miri/src/shims/unix/thread.rs +++ b/src/tools/miri/src/shims/unix/thread.rs @@ -6,10 +6,10 @@ impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn pthread_create( &mut self, - thread: &OpTy<'tcx, Provenance>, - _attr: &OpTy<'tcx, Provenance>, - start_routine: &OpTy<'tcx, Provenance>, - arg: &OpTy<'tcx, Provenance>, + thread: &OpTy<'tcx>, + _attr: &OpTy<'tcx>, + start_routine: &OpTy<'tcx>, + arg: &OpTy<'tcx>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -32,8 +32,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn pthread_join( &mut self, - thread: &OpTy<'tcx, Provenance>, - retval: &OpTy<'tcx, Provenance>, + thread: &OpTy<'tcx>, + retval: &OpTy<'tcx>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -48,7 +48,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Ok(0) } - fn pthread_detach(&mut self, thread: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> { + fn pthread_detach(&mut self, thread: &OpTy<'tcx>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let thread_id = this.read_scalar(thread)?.to_int(this.libc_ty_layout("pthread_t").size)?; @@ -60,7 +60,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Ok(0) } - fn pthread_self(&mut self) -> InterpResult<'tcx, Scalar> { + fn pthread_self(&mut self) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let thread_id = this.active_thread(); @@ -71,10 +71,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// including the null terminator. fn pthread_setname_np( &mut self, - thread: Scalar, - name: Scalar, + thread: Scalar, + name: Scalar, max_name_len: usize, - ) -> InterpResult<'tcx, Scalar> { + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let thread = thread.to_int(this.libc_ty_layout("pthread_t").size)?; @@ -95,10 +95,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn pthread_getname_np( &mut self, - thread: Scalar, - name_out: Scalar, - len: Scalar, - ) -> InterpResult<'tcx, Scalar> { + thread: Scalar, + name_out: Scalar, + len: Scalar, + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let thread = thread.to_int(this.libc_ty_layout("pthread_t").size)?; diff --git a/src/tools/miri/src/shims/wasi/foreign_items.rs b/src/tools/miri/src/shims/wasi/foreign_items.rs index b81b35bd963ef..e9fe90081d09c 100644 --- a/src/tools/miri/src/shims/wasi/foreign_items.rs +++ b/src/tools/miri/src/shims/wasi/foreign_items.rs @@ -14,8 +14,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { &mut self, link_name: Symbol, abi: Abi, - args: &[OpTy<'tcx, Provenance>], - dest: &MPlaceTy<'tcx, Provenance>, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, EmulateItemResult> { let this = self.eval_context_mut(); match link_name.as_str() { diff --git a/src/tools/miri/src/shims/windows/env.rs b/src/tools/miri/src/shims/windows/env.rs index 488a05366d238..ed3eb69798637 100644 --- a/src/tools/miri/src/shims/windows/env.rs +++ b/src/tools/miri/src/shims/windows/env.rs @@ -38,10 +38,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { #[allow(non_snake_case)] fn GetEnvironmentVariableW( &mut self, - name_op: &OpTy<'tcx, Provenance>, // LPCWSTR - buf_op: &OpTy<'tcx, Provenance>, // LPWSTR - size_op: &OpTy<'tcx, Provenance>, // DWORD - ) -> InterpResult<'tcx, Scalar> { + name_op: &OpTy<'tcx>, // LPCWSTR + buf_op: &OpTy<'tcx>, // LPWSTR + size_op: &OpTy<'tcx>, // DWORD + ) -> InterpResult<'tcx, Scalar> { // ^ Returns DWORD (u32 on Windows) let this = self.eval_context_mut(); @@ -71,7 +71,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } #[allow(non_snake_case)] - fn GetEnvironmentStringsW(&mut self) -> InterpResult<'tcx, Pointer>> { + fn GetEnvironmentStringsW(&mut self) -> InterpResult<'tcx, Pointer> { let this = self.eval_context_mut(); this.assert_target_os("windows", "GetEnvironmentStringsW"); @@ -93,10 +93,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } #[allow(non_snake_case)] - fn FreeEnvironmentStringsW( - &mut self, - env_block_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, Scalar> { + fn FreeEnvironmentStringsW(&mut self, env_block_op: &OpTy<'tcx>) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); this.assert_target_os("windows", "FreeEnvironmentStringsW"); @@ -109,9 +106,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { #[allow(non_snake_case)] fn SetEnvironmentVariableW( &mut self, - name_op: &OpTy<'tcx, Provenance>, // LPCWSTR - value_op: &OpTy<'tcx, Provenance>, // LPCWSTR - ) -> InterpResult<'tcx, Scalar> { + name_op: &OpTy<'tcx>, // LPCWSTR + value_op: &OpTy<'tcx>, // LPCWSTR + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); this.assert_target_os("windows", "SetEnvironmentVariableW"); @@ -142,9 +139,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { #[allow(non_snake_case)] fn GetCurrentDirectoryW( &mut self, - size_op: &OpTy<'tcx, Provenance>, // DWORD - buf_op: &OpTy<'tcx, Provenance>, // LPTSTR - ) -> InterpResult<'tcx, Scalar> { + size_op: &OpTy<'tcx>, // DWORD + buf_op: &OpTy<'tcx>, // LPTSTR + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); this.assert_target_os("windows", "GetCurrentDirectoryW"); @@ -174,8 +171,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { #[allow(non_snake_case)] fn SetCurrentDirectoryW( &mut self, - path_op: &OpTy<'tcx, Provenance>, // LPCTSTR - ) -> InterpResult<'tcx, Scalar> { + path_op: &OpTy<'tcx>, // LPCTSTR + ) -> InterpResult<'tcx, Scalar> { // ^ Returns BOOL (i32 on Windows) let this = self.eval_context_mut(); @@ -211,10 +208,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { #[allow(non_snake_case)] fn GetUserProfileDirectoryW( &mut self, - token: &OpTy<'tcx, Provenance>, // HANDLE - buf: &OpTy<'tcx, Provenance>, // LPWSTR - size: &OpTy<'tcx, Provenance>, // LPDWORD - ) -> InterpResult<'tcx, Scalar> // returns BOOL + token: &OpTy<'tcx>, // HANDLE + buf: &OpTy<'tcx>, // LPWSTR + size: &OpTy<'tcx>, // LPDWORD + ) -> InterpResult<'tcx, Scalar> // returns BOOL { let this = self.eval_context_mut(); this.assert_target_os("windows", "GetUserProfileDirectoryW"); diff --git a/src/tools/miri/src/shims/windows/foreign_items.rs b/src/tools/miri/src/shims/windows/foreign_items.rs index a60c2a337cfc5..bfa14bcb5fad4 100644 --- a/src/tools/miri/src/shims/windows/foreign_items.rs +++ b/src/tools/miri/src/shims/windows/foreign_items.rs @@ -82,8 +82,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { &mut self, link_name: Symbol, abi: Abi, - args: &[OpTy<'tcx, Provenance>], - dest: &MPlaceTy<'tcx, Provenance>, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, EmulateItemResult> { let this = self.eval_context_mut(); diff --git a/src/tools/miri/src/shims/windows/handle.rs b/src/tools/miri/src/shims/windows/handle.rs index 3e274a5b80285..58c8683ff2777 100644 --- a/src/tools/miri/src/shims/windows/handle.rs +++ b/src/tools/miri/src/shims/windows/handle.rs @@ -119,7 +119,7 @@ impl Handle { Self::new(discriminant, data) } - pub fn to_scalar(self, cx: &impl HasDataLayout) -> Scalar { + pub fn to_scalar(self, cx: &impl HasDataLayout) -> Scalar { // 64-bit handles are sign extended 32-bit handles // see https://docs.microsoft.com/en-us/windows/win32/winprog64/interprocess-communication #[allow(clippy::cast_possible_wrap)] // we want it to wrap @@ -128,7 +128,7 @@ impl Handle { } pub fn from_scalar<'tcx>( - handle: Scalar, + handle: Scalar, cx: &impl HasDataLayout, ) -> InterpResult<'tcx, Option> { let sign_extended_handle = handle.to_target_isize(cx)?; @@ -155,7 +155,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { ))) } - fn CloseHandle(&mut self, handle_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx> { + fn CloseHandle(&mut self, handle_op: &OpTy<'tcx>) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let handle = this.read_scalar(handle_op)?; diff --git a/src/tools/miri/src/shims/windows/sync.rs b/src/tools/miri/src/shims/windows/sync.rs index d5fe15b401bc7..e1fbb77037cfb 100644 --- a/src/tools/miri/src/shims/windows/sync.rs +++ b/src/tools/miri/src/shims/windows/sync.rs @@ -10,10 +10,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { // Windows sync primitives are pointer sized. // We only use the first 4 bytes for the id. - fn init_once_get_id( - &mut self, - init_once_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, InitOnceId> { + fn init_once_get_id(&mut self, init_once_op: &OpTy<'tcx>) -> InterpResult<'tcx, InitOnceId> { let this = self.eval_context_mut(); this.init_once_get_or_create_id(init_once_op, this.windows_ty_layout("INIT_ONCE"), 0) } @@ -22,8 +19,8 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { fn init_once_try_begin( &mut self, id: InitOnceId, - pending_place: &MPlaceTy<'tcx, Provenance>, - dest: &MPlaceTy<'tcx, Provenance>, + pending_place: &MPlaceTy<'tcx>, + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); Ok(match this.init_once_status(id) { @@ -49,11 +46,11 @@ impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn InitOnceBeginInitialize( &mut self, - init_once_op: &OpTy<'tcx, Provenance>, - flags_op: &OpTy<'tcx, Provenance>, - pending_op: &OpTy<'tcx, Provenance>, - context_op: &OpTy<'tcx, Provenance>, - dest: &MPlaceTy<'tcx, Provenance>, + init_once_op: &OpTy<'tcx>, + flags_op: &OpTy<'tcx>, + pending_op: &OpTy<'tcx>, + context_op: &OpTy<'tcx>, + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -82,8 +79,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { callback!( @capture<'tcx> { id: InitOnceId, - pending_place: MPlaceTy<'tcx, Provenance>, - dest: MPlaceTy<'tcx, Provenance>, + pending_place: MPlaceTy<'tcx>, + dest: MPlaceTy<'tcx>, } @unblock = |this| { let ret = this.init_once_try_begin(id, &pending_place, &dest)?; @@ -97,10 +94,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn InitOnceComplete( &mut self, - init_once_op: &OpTy<'tcx, Provenance>, - flags_op: &OpTy<'tcx, Provenance>, - context_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, Scalar> { + init_once_op: &OpTy<'tcx>, + flags_op: &OpTy<'tcx>, + context_op: &OpTy<'tcx>, + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let id = this.init_once_get_id(init_once_op)?; @@ -137,11 +134,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn WaitOnAddress( &mut self, - ptr_op: &OpTy<'tcx, Provenance>, - compare_op: &OpTy<'tcx, Provenance>, - size_op: &OpTy<'tcx, Provenance>, - timeout_op: &OpTy<'tcx, Provenance>, - dest: &MPlaceTy<'tcx, Provenance>, + ptr_op: &OpTy<'tcx>, + compare_op: &OpTy<'tcx>, + size_op: &OpTy<'tcx>, + timeout_op: &OpTy<'tcx>, + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -160,11 +157,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { }; let size = Size::from_bytes(size); - let timeout_time = if timeout_ms == this.eval_windows_u32("c", "INFINITE") { + let timeout = if timeout_ms == this.eval_windows_u32("c", "INFINITE") { None } else { let duration = Duration::from_millis(timeout_ms.into()); - Some(Timeout::Monotonic(this.machine.clock.now().checked_add(duration).unwrap())) + Some((TimeoutClock::Monotonic, TimeoutAnchor::Relative, duration)) }; // See the Linux futex implementation for why this fence exists. @@ -180,7 +177,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.futex_wait( addr, u32::MAX, // bitset - timeout_time, + timeout, Scalar::from_i32(1), // retval_succ Scalar::from_i32(0), // retval_timeout dest.clone(), @@ -193,7 +190,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Ok(()) } - fn WakeByAddressSingle(&mut self, ptr_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx> { + fn WakeByAddressSingle(&mut self, ptr_op: &OpTy<'tcx>) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let ptr = this.read_pointer(ptr_op)?; @@ -206,7 +203,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Ok(()) } - fn WakeByAddressAll(&mut self, ptr_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx> { + fn WakeByAddressAll(&mut self, ptr_op: &OpTy<'tcx>) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let ptr = this.read_pointer(ptr_op)?; diff --git a/src/tools/miri/src/shims/windows/thread.rs b/src/tools/miri/src/shims/windows/thread.rs index a9ef03d14ae4f..f3ddf6072af1f 100644 --- a/src/tools/miri/src/shims/windows/thread.rs +++ b/src/tools/miri/src/shims/windows/thread.rs @@ -10,12 +10,12 @@ impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn CreateThread( &mut self, - security_op: &OpTy<'tcx, Provenance>, - stacksize_op: &OpTy<'tcx, Provenance>, - start_op: &OpTy<'tcx, Provenance>, - arg_op: &OpTy<'tcx, Provenance>, - flags_op: &OpTy<'tcx, Provenance>, - thread_op: &OpTy<'tcx, Provenance>, + security_op: &OpTy<'tcx>, + stacksize_op: &OpTy<'tcx>, + start_op: &OpTy<'tcx>, + arg_op: &OpTy<'tcx>, + flags_op: &OpTy<'tcx>, + thread_op: &OpTy<'tcx>, ) -> InterpResult<'tcx, ThreadId> { let this = self.eval_context_mut(); @@ -57,8 +57,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn WaitForSingleObject( &mut self, - handle_op: &OpTy<'tcx, Provenance>, - timeout_op: &OpTy<'tcx, Provenance>, + handle_op: &OpTy<'tcx>, + timeout_op: &OpTy<'tcx>, ) -> InterpResult<'tcx, u32> { let this = self.eval_context_mut(); diff --git a/src/tools/miri/src/shims/x86/aesni.rs b/src/tools/miri/src/shims/x86/aesni.rs index c1be1d4582a7a..e4e1531157a42 100644 --- a/src/tools/miri/src/shims/x86/aesni.rs +++ b/src/tools/miri/src/shims/x86/aesni.rs @@ -6,15 +6,13 @@ use rustc_target::spec::abi::Abi; use crate::*; impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} -pub(super) trait EvalContextExt<'tcx>: - crate::MiriInterpCxExt<'tcx> -{ +pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn emulate_x86_aesni_intrinsic( &mut self, link_name: Symbol, abi: Abi, - args: &[OpTy<'tcx, Provenance>], - dest: &MPlaceTy<'tcx, Provenance>, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, EmulateItemResult> { let this = self.eval_context_mut(); this.expect_target_feature_for_intrinsic(link_name, "aes")?; @@ -135,9 +133,9 @@ pub(super) trait EvalContextExt<'tcx>: // `state` with the corresponding 128-bit key of `key`. fn aes_round<'tcx>( this: &mut crate::MiriInterpCx<'tcx>, - state: &OpTy<'tcx, Provenance>, - key: &OpTy<'tcx, Provenance>, - dest: &MPlaceTy<'tcx, Provenance>, + state: &OpTy<'tcx>, + key: &OpTy<'tcx>, + dest: &MPlaceTy<'tcx>, f: impl Fn(u128, u128) -> u128, ) -> InterpResult<'tcx, ()> { assert_eq!(dest.layout.size, state.layout.size); diff --git a/src/tools/miri/src/shims/x86/avx.rs b/src/tools/miri/src/shims/x86/avx.rs index f782fbfff4e74..07d737e06635e 100644 --- a/src/tools/miri/src/shims/x86/avx.rs +++ b/src/tools/miri/src/shims/x86/avx.rs @@ -13,15 +13,13 @@ use super::{ use crate::*; impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} -pub(super) trait EvalContextExt<'tcx>: - crate::MiriInterpCxExt<'tcx> -{ +pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn emulate_x86_avx_intrinsic( &mut self, link_name: Symbol, abi: Abi, - args: &[OpTy<'tcx, Provenance>], - dest: &MPlaceTy<'tcx, Provenance>, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, EmulateItemResult> { let this = self.eval_context_mut(); this.expect_target_feature_for_intrinsic(link_name, "avx")?; diff --git a/src/tools/miri/src/shims/x86/avx2.rs b/src/tools/miri/src/shims/x86/avx2.rs index 91764a20572a6..016c525e57b41 100644 --- a/src/tools/miri/src/shims/x86/avx2.rs +++ b/src/tools/miri/src/shims/x86/avx2.rs @@ -11,15 +11,13 @@ use super::{ use crate::*; impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} -pub(super) trait EvalContextExt<'tcx>: - crate::MiriInterpCxExt<'tcx> -{ +pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn emulate_x86_avx2_intrinsic( &mut self, link_name: Symbol, abi: Abi, - args: &[OpTy<'tcx, Provenance>], - dest: &MPlaceTy<'tcx, Provenance>, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, EmulateItemResult> { let this = self.eval_context_mut(); this.expect_target_feature_for_intrinsic(link_name, "avx2")?; diff --git a/src/tools/miri/src/shims/x86/mod.rs b/src/tools/miri/src/shims/x86/mod.rs index b5951e9e895bb..f2d120df21c41 100644 --- a/src/tools/miri/src/shims/x86/mod.rs +++ b/src/tools/miri/src/shims/x86/mod.rs @@ -26,8 +26,8 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { &mut self, link_name: Symbol, abi: Abi, - args: &[OpTy<'tcx, Provenance>], - dest: &MPlaceTy<'tcx, Provenance>, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, EmulateItemResult> { let this = self.eval_context_mut(); // Prefix should have already been checked. @@ -105,6 +105,13 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } } + "pclmulqdq" => { + let [left, right, imm] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + + pclmulqdq(this, left, right, imm, dest)?; + } + name if name.starts_with("sse.") => { return sse::EvalContextExt::emulate_x86_sse_intrinsic( this, link_name, abi, args, dest, @@ -244,9 +251,9 @@ impl FloatBinOp { fn bin_op_float<'tcx, F: rustc_apfloat::Float>( this: &crate::MiriInterpCx<'tcx>, which: FloatBinOp, - left: &ImmTy<'tcx, Provenance>, - right: &ImmTy<'tcx, Provenance>, -) -> InterpResult<'tcx, Scalar> { + left: &ImmTy<'tcx>, + right: &ImmTy<'tcx>, +) -> InterpResult<'tcx, Scalar> { match which { FloatBinOp::Arith(which) => { let res = this.binary_op(which, left, right)?; @@ -306,9 +313,9 @@ fn bin_op_float<'tcx, F: rustc_apfloat::Float>( fn bin_op_simd_float_first<'tcx, F: rustc_apfloat::Float>( this: &mut crate::MiriInterpCx<'tcx>, which: FloatBinOp, - left: &OpTy<'tcx, Provenance>, - right: &OpTy<'tcx, Provenance>, - dest: &MPlaceTy<'tcx, Provenance>, + left: &OpTy<'tcx>, + right: &OpTy<'tcx>, + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, ()> { let (left, left_len) = this.operand_to_simd(left)?; let (right, right_len) = this.operand_to_simd(right)?; @@ -337,9 +344,9 @@ fn bin_op_simd_float_first<'tcx, F: rustc_apfloat::Float>( fn bin_op_simd_float_all<'tcx, F: rustc_apfloat::Float>( this: &mut crate::MiriInterpCx<'tcx>, which: FloatBinOp, - left: &OpTy<'tcx, Provenance>, - right: &OpTy<'tcx, Provenance>, - dest: &MPlaceTy<'tcx, Provenance>, + left: &OpTy<'tcx>, + right: &OpTy<'tcx>, + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, ()> { let (left, left_len) = this.operand_to_simd(left)?; let (right, right_len) = this.operand_to_simd(right)?; @@ -384,8 +391,8 @@ enum FloatUnaryOp { fn unary_op_f32<'tcx>( this: &mut crate::MiriInterpCx<'tcx>, which: FloatUnaryOp, - op: &ImmTy<'tcx, Provenance>, -) -> InterpResult<'tcx, Scalar> { + op: &ImmTy<'tcx>, +) -> InterpResult<'tcx, Scalar> { match which { FloatUnaryOp::Sqrt => { let op = op.to_scalar(); @@ -435,8 +442,8 @@ fn apply_random_float_error( fn unary_op_ss<'tcx>( this: &mut crate::MiriInterpCx<'tcx>, which: FloatUnaryOp, - op: &OpTy<'tcx, Provenance>, - dest: &MPlaceTy<'tcx, Provenance>, + op: &OpTy<'tcx>, + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, ()> { let (op, op_len) = this.operand_to_simd(op)?; let (dest, dest_len) = this.mplace_to_simd(dest)?; @@ -458,8 +465,8 @@ fn unary_op_ss<'tcx>( fn unary_op_ps<'tcx>( this: &mut crate::MiriInterpCx<'tcx>, which: FloatUnaryOp, - op: &OpTy<'tcx, Provenance>, - dest: &MPlaceTy<'tcx, Provenance>, + op: &OpTy<'tcx>, + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, ()> { let (op, op_len) = this.operand_to_simd(op)?; let (dest, dest_len) = this.mplace_to_simd(dest)?; @@ -494,10 +501,10 @@ enum ShiftOp { /// bit is copied to all bits. fn shift_simd_by_scalar<'tcx>( this: &mut crate::MiriInterpCx<'tcx>, - left: &OpTy<'tcx, Provenance>, - right: &OpTy<'tcx, Provenance>, + left: &OpTy<'tcx>, + right: &OpTy<'tcx>, which: ShiftOp, - dest: &MPlaceTy<'tcx, Provenance>, + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, ()> { let (left, left_len) = this.operand_to_simd(left)?; let (dest, dest_len) = this.mplace_to_simd(dest)?; @@ -550,10 +557,10 @@ fn shift_simd_by_scalar<'tcx>( /// bit is copied to all bits. fn shift_simd_by_simd<'tcx>( this: &mut crate::MiriInterpCx<'tcx>, - left: &OpTy<'tcx, Provenance>, - right: &OpTy<'tcx, Provenance>, + left: &OpTy<'tcx>, + right: &OpTy<'tcx>, which: ShiftOp, - dest: &MPlaceTy<'tcx, Provenance>, + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, ()> { let (left, left_len) = this.operand_to_simd(left)?; let (right, right_len) = this.operand_to_simd(right)?; @@ -602,7 +609,7 @@ fn shift_simd_by_simd<'tcx>( /// the first value. fn extract_first_u64<'tcx>( this: &crate::MiriInterpCx<'tcx>, - op: &OpTy<'tcx, Provenance>, + op: &OpTy<'tcx>, ) -> InterpResult<'tcx, u64> { // Transmute vector to `[u64; 2]` let array_layout = this.layout_of(Ty::new_array(this.tcx.tcx, this.tcx.types.u64, 2))?; @@ -616,10 +623,10 @@ fn extract_first_u64<'tcx>( // and copies the remaining elements from `left`. fn round_first<'tcx, F: rustc_apfloat::Float>( this: &mut crate::MiriInterpCx<'tcx>, - left: &OpTy<'tcx, Provenance>, - right: &OpTy<'tcx, Provenance>, - rounding: &OpTy<'tcx, Provenance>, - dest: &MPlaceTy<'tcx, Provenance>, + left: &OpTy<'tcx>, + right: &OpTy<'tcx>, + rounding: &OpTy<'tcx>, + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, ()> { let (left, left_len) = this.operand_to_simd(left)?; let (right, right_len) = this.operand_to_simd(right)?; @@ -647,9 +654,9 @@ fn round_first<'tcx, F: rustc_apfloat::Float>( // Rounds all elements of `op` according to `rounding`. fn round_all<'tcx, F: rustc_apfloat::Float>( this: &mut crate::MiriInterpCx<'tcx>, - op: &OpTy<'tcx, Provenance>, - rounding: &OpTy<'tcx, Provenance>, - dest: &MPlaceTy<'tcx, Provenance>, + op: &OpTy<'tcx>, + rounding: &OpTy<'tcx>, + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, ()> { let (op, op_len) = this.operand_to_simd(op)?; let (dest, dest_len) = this.mplace_to_simd(dest)?; @@ -699,9 +706,9 @@ fn rounding_from_imm<'tcx>(rounding: i32) -> InterpResult<'tcx, rustc_apfloat::R /// has less elements than `dest`, the rest is filled with zeros. fn convert_float_to_int<'tcx>( this: &mut crate::MiriInterpCx<'tcx>, - op: &OpTy<'tcx, Provenance>, + op: &OpTy<'tcx>, rnd: rustc_apfloat::Round, - dest: &MPlaceTy<'tcx, Provenance>, + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, ()> { let (op, op_len) = this.operand_to_simd(op)?; let (dest, dest_len) = this.mplace_to_simd(dest)?; @@ -734,8 +741,8 @@ fn convert_float_to_int<'tcx>( /// will wrap around. fn int_abs<'tcx>( this: &mut crate::MiriInterpCx<'tcx>, - op: &OpTy<'tcx, Provenance>, - dest: &MPlaceTy<'tcx, Provenance>, + op: &OpTy<'tcx>, + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, ()> { let (op, op_len) = this.operand_to_simd(op)?; let (dest, dest_len) = this.mplace_to_simd(dest)?; @@ -802,9 +809,9 @@ fn horizontal_bin_op<'tcx>( this: &mut crate::MiriInterpCx<'tcx>, which: mir::BinOp, saturating: bool, - left: &OpTy<'tcx, Provenance>, - right: &OpTy<'tcx, Provenance>, - dest: &MPlaceTy<'tcx, Provenance>, + left: &OpTy<'tcx>, + right: &OpTy<'tcx>, + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, ()> { assert_eq!(left.layout, dest.layout); assert_eq!(right.layout, dest.layout); @@ -853,10 +860,10 @@ fn horizontal_bin_op<'tcx>( /// 128-bit blocks of `left` and `right`). fn conditional_dot_product<'tcx>( this: &mut crate::MiriInterpCx<'tcx>, - left: &OpTy<'tcx, Provenance>, - right: &OpTy<'tcx, Provenance>, - imm: &OpTy<'tcx, Provenance>, - dest: &MPlaceTy<'tcx, Provenance>, + left: &OpTy<'tcx>, + right: &OpTy<'tcx>, + imm: &OpTy<'tcx>, + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, ()> { assert_eq!(left.layout, dest.layout); assert_eq!(right.layout, dest.layout); @@ -911,8 +918,8 @@ fn conditional_dot_product<'tcx>( /// The second is true when `(op & mask) == mask` fn test_bits_masked<'tcx>( this: &crate::MiriInterpCx<'tcx>, - op: &OpTy<'tcx, Provenance>, - mask: &OpTy<'tcx, Provenance>, + op: &OpTy<'tcx>, + mask: &OpTy<'tcx>, ) -> InterpResult<'tcx, (bool, bool)> { assert_eq!(op.layout, mask.layout); @@ -942,8 +949,8 @@ fn test_bits_masked<'tcx>( /// The second is true when the highest bit of each element of `!op & mask` is zero. fn test_high_bits_masked<'tcx>( this: &crate::MiriInterpCx<'tcx>, - op: &OpTy<'tcx, Provenance>, - mask: &OpTy<'tcx, Provenance>, + op: &OpTy<'tcx>, + mask: &OpTy<'tcx>, ) -> InterpResult<'tcx, (bool, bool)> { assert_eq!(op.layout, mask.layout); @@ -973,9 +980,9 @@ fn test_high_bits_masked<'tcx>( /// element of `mask`. `ptr` does not need to be aligned. fn mask_load<'tcx>( this: &mut crate::MiriInterpCx<'tcx>, - ptr: &OpTy<'tcx, Provenance>, - mask: &OpTy<'tcx, Provenance>, - dest: &MPlaceTy<'tcx, Provenance>, + ptr: &OpTy<'tcx>, + mask: &OpTy<'tcx>, + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, ()> { let (mask, mask_len) = this.operand_to_simd(mask)?; let (dest, dest_len) = this.mplace_to_simd(dest)?; @@ -1006,9 +1013,9 @@ fn mask_load<'tcx>( /// element of `mask`. `ptr` does not need to be aligned. fn mask_store<'tcx>( this: &mut crate::MiriInterpCx<'tcx>, - ptr: &OpTy<'tcx, Provenance>, - mask: &OpTy<'tcx, Provenance>, - value: &OpTy<'tcx, Provenance>, + ptr: &OpTy<'tcx>, + mask: &OpTy<'tcx>, + value: &OpTy<'tcx>, ) -> InterpResult<'tcx, ()> { let (mask, mask_len) = this.operand_to_simd(mask)?; let (value, value_len) = this.operand_to_simd(value)?; @@ -1046,10 +1053,10 @@ fn mask_store<'tcx>( /// 128-bit chunks of `left` and `right`). fn mpsadbw<'tcx>( this: &mut crate::MiriInterpCx<'tcx>, - left: &OpTy<'tcx, Provenance>, - right: &OpTy<'tcx, Provenance>, - imm: &OpTy<'tcx, Provenance>, - dest: &MPlaceTy<'tcx, Provenance>, + left: &OpTy<'tcx>, + right: &OpTy<'tcx>, + imm: &OpTy<'tcx>, + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, ()> { assert_eq!(left.layout, right.layout); assert_eq!(left.layout.size, dest.layout.size); @@ -1103,9 +1110,9 @@ fn mpsadbw<'tcx>( /// fn pmulhrsw<'tcx>( this: &mut crate::MiriInterpCx<'tcx>, - left: &OpTy<'tcx, Provenance>, - right: &OpTy<'tcx, Provenance>, - dest: &MPlaceTy<'tcx, Provenance>, + left: &OpTy<'tcx>, + right: &OpTy<'tcx>, + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, ()> { let (left, left_len) = this.operand_to_simd(left)?; let (right, right_len) = this.operand_to_simd(right)?; @@ -1133,6 +1140,68 @@ fn pmulhrsw<'tcx>( Ok(()) } +/// Perform a carry-less multiplication of two 64-bit integers, selected from `left` and `right` according to `imm8`, +/// and store the results in `dst`. +/// +/// `left` and `right` are both vectors of type 2 x i64. Only bits 0 and 4 of `imm8` matter; +/// they select the element of `left` and `right`, respectively. +/// +/// +fn pclmulqdq<'tcx>( + this: &mut MiriInterpCx<'tcx>, + left: &OpTy<'tcx>, + right: &OpTy<'tcx>, + imm8: &OpTy<'tcx>, + dest: &MPlaceTy<'tcx>, +) -> InterpResult<'tcx, ()> { + assert_eq!(left.layout, right.layout); + assert_eq!(left.layout.size, dest.layout.size); + + // Transmute to `[u64; 2]` + + let array_layout = this.layout_of(Ty::new_array(this.tcx.tcx, this.tcx.types.u64, 2))?; + let left = left.transmute(array_layout, this)?; + let right = right.transmute(array_layout, this)?; + let dest = dest.transmute(array_layout, this)?; + + let imm8 = this.read_scalar(imm8)?.to_u8()?; + + // select the 64-bit integer from left that the user specified (low or high) + let index = if (imm8 & 0x01) == 0 { 0 } else { 1 }; + let left = this.read_scalar(&this.project_index(&left, index)?)?.to_u64()?; + + // select the 64-bit integer from right that the user specified (low or high) + let index = if (imm8 & 0x10) == 0 { 0 } else { 1 }; + let right = this.read_scalar(&this.project_index(&right, index)?)?.to_u64()?; + + // Perform carry-less multiplication + // + // This operation is like long multiplication, but ignores all carries. + // That idea corresponds to the xor operator, which is used in the implementation. + // + // Wikipedia has an example https://en.wikipedia.org/wiki/Carry-less_product#Example + let mut result: u128 = 0; + + for i in 0..64 { + // if the i-th bit in right is set + if (right & (1 << i)) != 0 { + // xor result with `left` shifted to the left by i positions + result ^= (left as u128) << i; + } + } + + let result_low = (result & 0xFFFF_FFFF_FFFF_FFFF) as u64; + let result_high = (result >> 64) as u64; + + let dest_low = this.project_index(&dest, 0)?; + this.write_scalar(Scalar::from_u64(result_low), &dest_low)?; + + let dest_high = this.project_index(&dest, 1)?; + this.write_scalar(Scalar::from_u64(result_high), &dest_high)?; + + Ok(()) +} + /// Packs two N-bit integer vectors to a single N/2-bit integers. /// /// The conversion from N-bit to N/2-bit should be provided by `f`. @@ -1142,10 +1211,10 @@ fn pmulhrsw<'tcx>( /// 128-bit chunks of `left` and `right`). fn pack_generic<'tcx>( this: &mut crate::MiriInterpCx<'tcx>, - left: &OpTy<'tcx, Provenance>, - right: &OpTy<'tcx, Provenance>, - dest: &MPlaceTy<'tcx, Provenance>, - f: impl Fn(Scalar) -> InterpResult<'tcx, Scalar>, + left: &OpTy<'tcx>, + right: &OpTy<'tcx>, + dest: &MPlaceTy<'tcx>, + f: impl Fn(Scalar) -> InterpResult<'tcx, Scalar>, ) -> InterpResult<'tcx, ()> { assert_eq!(left.layout, right.layout); assert_eq!(left.layout.size, dest.layout.size); @@ -1187,9 +1256,9 @@ fn pack_generic<'tcx>( /// 128-bit chunks of `left` and `right`). fn packsswb<'tcx>( this: &mut crate::MiriInterpCx<'tcx>, - left: &OpTy<'tcx, Provenance>, - right: &OpTy<'tcx, Provenance>, - dest: &MPlaceTy<'tcx, Provenance>, + left: &OpTy<'tcx>, + right: &OpTy<'tcx>, + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, ()> { pack_generic(this, left, right, dest, |op| { let op = op.to_i16()?; @@ -1206,9 +1275,9 @@ fn packsswb<'tcx>( /// 128-bit chunks of `left` and `right`). fn packuswb<'tcx>( this: &mut crate::MiriInterpCx<'tcx>, - left: &OpTy<'tcx, Provenance>, - right: &OpTy<'tcx, Provenance>, - dest: &MPlaceTy<'tcx, Provenance>, + left: &OpTy<'tcx>, + right: &OpTy<'tcx>, + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, ()> { pack_generic(this, left, right, dest, |op| { let op = op.to_i16()?; @@ -1225,9 +1294,9 @@ fn packuswb<'tcx>( /// 128-bit chunks of `left` and `right`). fn packssdw<'tcx>( this: &mut crate::MiriInterpCx<'tcx>, - left: &OpTy<'tcx, Provenance>, - right: &OpTy<'tcx, Provenance>, - dest: &MPlaceTy<'tcx, Provenance>, + left: &OpTy<'tcx>, + right: &OpTy<'tcx>, + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, ()> { pack_generic(this, left, right, dest, |op| { let op = op.to_i32()?; @@ -1244,9 +1313,9 @@ fn packssdw<'tcx>( /// 128-bit chunks of `left` and `right`). fn packusdw<'tcx>( this: &mut crate::MiriInterpCx<'tcx>, - left: &OpTy<'tcx, Provenance>, - right: &OpTy<'tcx, Provenance>, - dest: &MPlaceTy<'tcx, Provenance>, + left: &OpTy<'tcx>, + right: &OpTy<'tcx>, + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, ()> { pack_generic(this, left, right, dest, |op| { let op = op.to_i32()?; @@ -1261,9 +1330,9 @@ fn packusdw<'tcx>( /// In other words, multiplies `left` with `right.signum()`. fn psign<'tcx>( this: &mut crate::MiriInterpCx<'tcx>, - left: &OpTy<'tcx, Provenance>, - right: &OpTy<'tcx, Provenance>, - dest: &MPlaceTy<'tcx, Provenance>, + left: &OpTy<'tcx>, + right: &OpTy<'tcx>, + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, ()> { let (left, left_len) = this.operand_to_simd(left)?; let (right, right_len) = this.operand_to_simd(right)?; diff --git a/src/tools/miri/src/shims/x86/sse.rs b/src/tools/miri/src/shims/x86/sse.rs index 0afb2090cad63..32e8e8a66c13c 100644 --- a/src/tools/miri/src/shims/x86/sse.rs +++ b/src/tools/miri/src/shims/x86/sse.rs @@ -10,15 +10,13 @@ use super::{ use crate::*; impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} -pub(super) trait EvalContextExt<'tcx>: - crate::MiriInterpCxExt<'tcx> -{ +pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn emulate_x86_sse_intrinsic( &mut self, link_name: Symbol, abi: Abi, - args: &[OpTy<'tcx, Provenance>], - dest: &MPlaceTy<'tcx, Provenance>, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, EmulateItemResult> { let this = self.eval_context_mut(); this.expect_target_feature_for_intrinsic(link_name, "sse")?; diff --git a/src/tools/miri/src/shims/x86/sse2.rs b/src/tools/miri/src/shims/x86/sse2.rs index bdff22cfa95b2..e10047fefe6a8 100644 --- a/src/tools/miri/src/shims/x86/sse2.rs +++ b/src/tools/miri/src/shims/x86/sse2.rs @@ -9,15 +9,13 @@ use super::{ use crate::*; impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} -pub(super) trait EvalContextExt<'tcx>: - crate::MiriInterpCxExt<'tcx> -{ +pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn emulate_x86_sse2_intrinsic( &mut self, link_name: Symbol, abi: Abi, - args: &[OpTy<'tcx, Provenance>], - dest: &MPlaceTy<'tcx, Provenance>, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, EmulateItemResult> { let this = self.eval_context_mut(); this.expect_target_feature_for_intrinsic(link_name, "sse2")?; diff --git a/src/tools/miri/src/shims/x86/sse3.rs b/src/tools/miri/src/shims/x86/sse3.rs index 7dbe5163199b8..ef5a55d6eb28e 100644 --- a/src/tools/miri/src/shims/x86/sse3.rs +++ b/src/tools/miri/src/shims/x86/sse3.rs @@ -6,15 +6,13 @@ use super::horizontal_bin_op; use crate::*; impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} -pub(super) trait EvalContextExt<'tcx>: - crate::MiriInterpCxExt<'tcx> -{ +pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn emulate_x86_sse3_intrinsic( &mut self, link_name: Symbol, abi: Abi, - args: &[OpTy<'tcx, Provenance>], - dest: &MPlaceTy<'tcx, Provenance>, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, EmulateItemResult> { let this = self.eval_context_mut(); this.expect_target_feature_for_intrinsic(link_name, "sse3")?; diff --git a/src/tools/miri/src/shims/x86/sse41.rs b/src/tools/miri/src/shims/x86/sse41.rs index b3880fec3e034..9e048fb9eb841 100644 --- a/src/tools/miri/src/shims/x86/sse41.rs +++ b/src/tools/miri/src/shims/x86/sse41.rs @@ -5,15 +5,13 @@ use super::{conditional_dot_product, mpsadbw, packusdw, round_all, round_first, use crate::*; impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} -pub(super) trait EvalContextExt<'tcx>: - crate::MiriInterpCxExt<'tcx> -{ +pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn emulate_x86_sse41_intrinsic( &mut self, link_name: Symbol, abi: Abi, - args: &[OpTy<'tcx, Provenance>], - dest: &MPlaceTy<'tcx, Provenance>, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, EmulateItemResult> { let this = self.eval_context_mut(); this.expect_target_feature_for_intrinsic(link_name, "sse4.1")?; diff --git a/src/tools/miri/src/shims/x86/ssse3.rs b/src/tools/miri/src/shims/x86/ssse3.rs index 1f7870f8ca03b..6a815e4cea3c6 100644 --- a/src/tools/miri/src/shims/x86/ssse3.rs +++ b/src/tools/miri/src/shims/x86/ssse3.rs @@ -6,15 +6,13 @@ use super::{horizontal_bin_op, int_abs, pmulhrsw, psign}; use crate::*; impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} -pub(super) trait EvalContextExt<'tcx>: - crate::MiriInterpCxExt<'tcx> -{ +pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { fn emulate_x86_ssse3_intrinsic( &mut self, link_name: Symbol, abi: Abi, - args: &[OpTy<'tcx, Provenance>], - dest: &MPlaceTy<'tcx, Provenance>, + args: &[OpTy<'tcx>], + dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, EmulateItemResult> { let this = self.eval_context_mut(); this.expect_target_feature_for_intrinsic(link_name, "ssse3")?; diff --git a/src/tools/miri/test-cargo-miri/Cargo.lock b/src/tools/miri/test-cargo-miri/Cargo.lock index 4783f79ea8fb4..8f618e7ffb38f 100644 --- a/src/tools/miri/test-cargo-miri/Cargo.lock +++ b/src/tools/miri/test-cargo-miri/Cargo.lock @@ -123,6 +123,10 @@ dependencies = [ "byteorder 1.5.0", ] +[[package]] +name = "test-local-crate-detection" +version = "0.1.0" + [[package]] name = "unicode-ident" version = "1.0.12" diff --git a/src/tools/miri/test-cargo-miri/Cargo.toml b/src/tools/miri/test-cargo-miri/Cargo.toml index bfef388669d17..574f1d05a6fae 100644 --- a/src/tools/miri/test-cargo-miri/Cargo.toml +++ b/src/tools/miri/test-cargo-miri/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -members = ["subcrate", "issue-1567", "exported-symbol-dep"] +members = ["subcrate", "issue-1567", "exported-symbol-dep", "test-local-crate-detection"] exclude = ["no-std-smoke"] # it wants to be panic="abort" [package] diff --git a/src/tools/miri/test-cargo-miri/run-test.py b/src/tools/miri/test-cargo-miri/run-test.py index 83f3e4c919b9a..d855c333a7568 100755 --- a/src/tools/miri/test-cargo-miri/run-test.py +++ b/src/tools/miri/test-cargo-miri/run-test.py @@ -131,6 +131,10 @@ def test_cargo_miri_run(): cargo_miri("run") + ["--target-dir=custom-run", "--", "--target-dir=target/custom-run"], "run.args.stdout.ref", "run.custom-target-dir.stderr.ref", ) + test("`cargo miri run --package=test-local-crate-detection` (test local crate detection)", + cargo_miri("run") + ["--package=test-local-crate-detection"], + "run.local_crate.stdout.ref", "run.local_crate.stderr.ref", + ) def test_cargo_miri_test(): # rustdoc is not run on foreign targets diff --git a/src/tools/miri/test-cargo-miri/run.local_crate.stderr.ref b/src/tools/miri/test-cargo-miri/run.local_crate.stderr.ref new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/src/tools/miri/test-cargo-miri/run.local_crate.stdout.ref b/src/tools/miri/test-cargo-miri/run.local_crate.stdout.ref new file mode 100644 index 0000000000000..1587de9ff3f87 --- /dev/null +++ b/src/tools/miri/test-cargo-miri/run.local_crate.stdout.ref @@ -0,0 +1 @@ +subcrate,issue_1567,exported_symbol_dep,test_local_crate_detection,cargo_miri_test,cdylib,exported_symbol,issue_1691,issue_1705,issue_rust_86261,proc_macro_crate diff --git a/src/tools/miri/test-cargo-miri/test-local-crate-detection/Cargo.toml b/src/tools/miri/test-cargo-miri/test-local-crate-detection/Cargo.toml new file mode 100644 index 0000000000000..2d41b210d4c1a --- /dev/null +++ b/src/tools/miri/test-cargo-miri/test-local-crate-detection/Cargo.toml @@ -0,0 +1,4 @@ +[package] +name = "test-local-crate-detection" +version = "0.1.0" +edition = "2021" diff --git a/src/tools/miri/test-cargo-miri/test-local-crate-detection/src/main.rs b/src/tools/miri/test-cargo-miri/test-local-crate-detection/src/main.rs new file mode 100644 index 0000000000000..0991aa384607b --- /dev/null +++ b/src/tools/miri/test-cargo-miri/test-local-crate-detection/src/main.rs @@ -0,0 +1,5 @@ +fn main() { + // Make sure we detect all crates from this workspace as "local". + // The env var is set during the "build" so we can use `env!` to access it directly. + println!("{}", env!("MIRI_LOCAL_CRATES")); +} diff --git a/src/tools/miri/tests/fail-dep/libc/libc_eventfd_read_block.rs b/src/tools/miri/tests/fail-dep/libc/libc_eventfd_read_block.rs new file mode 100644 index 0000000000000..fb9a23206c604 --- /dev/null +++ b/src/tools/miri/tests/fail-dep/libc/libc_eventfd_read_block.rs @@ -0,0 +1,11 @@ +//@only-target-linux +fn main() { + // eventfd read will block when EFD_NONBLOCK flag is clear and counter = 0. + // This will pass when blocking is implemented. + let flags = libc::EFD_CLOEXEC; + let fd = unsafe { libc::eventfd(0, flags) }; + let mut buf: [u8; 8] = [0; 8]; + let _res: i32 = unsafe { + libc::read(fd, buf.as_mut_ptr().cast(), buf.len() as libc::size_t).try_into().unwrap() //~ERROR: blocking is unsupported + }; +} diff --git a/src/tools/miri/tests/fail-dep/libc/libc_eventfd_read_block.stderr b/src/tools/miri/tests/fail-dep/libc/libc_eventfd_read_block.stderr new file mode 100644 index 0000000000000..fdd0b4272cafb --- /dev/null +++ b/src/tools/miri/tests/fail-dep/libc/libc_eventfd_read_block.stderr @@ -0,0 +1,14 @@ +error: unsupported operation: eventfd: blocking is unsupported + --> $DIR/libc_eventfd_read_block.rs:LL:CC + | +LL | libc::read(fd, buf.as_mut_ptr().cast(), buf.len() as libc::size_t).try_into().unwrap() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ eventfd: blocking is unsupported + | + = help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support + = note: BACKTRACE: + = note: inside `main` at $DIR/libc_eventfd_read_block.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail-dep/libc/libc_eventfd_write_block.rs b/src/tools/miri/tests/fail-dep/libc/libc_eventfd_write_block.rs new file mode 100644 index 0000000000000..2037a516dea1c --- /dev/null +++ b/src/tools/miri/tests/fail-dep/libc/libc_eventfd_write_block.rs @@ -0,0 +1,21 @@ +//@only-target-linux +fn main() { + // eventfd write will block when EFD_NONBLOCK flag is clear + // and the addition caused counter to exceed u64::MAX - 1. + // This will pass when blocking is implemented. + let flags = libc::EFD_CLOEXEC; + let fd = unsafe { libc::eventfd(0, flags) }; + // Write u64 - 1. + let mut sized_8_data: [u8; 8] = (u64::MAX - 1).to_ne_bytes(); + let res: i64 = unsafe { + libc::write(fd, sized_8_data.as_ptr() as *const libc::c_void, 8).try_into().unwrap() + }; + assert_eq!(res, 8); + + // Write 1. + sized_8_data = 1_u64.to_ne_bytes(); + // Write 1 to the counter. + let _res: i64 = unsafe { + libc::write(fd, sized_8_data.as_ptr() as *const libc::c_void, 8).try_into().unwrap() //~ERROR: blocking is unsupported + }; +} diff --git a/src/tools/miri/tests/fail-dep/libc/libc_eventfd_write_block.stderr b/src/tools/miri/tests/fail-dep/libc/libc_eventfd_write_block.stderr new file mode 100644 index 0000000000000..f12c0ddfb1717 --- /dev/null +++ b/src/tools/miri/tests/fail-dep/libc/libc_eventfd_write_block.stderr @@ -0,0 +1,14 @@ +error: unsupported operation: eventfd: blocking is unsupported + --> $DIR/libc_eventfd_write_block.rs:LL:CC + | +LL | libc::write(fd, sized_8_data.as_ptr() as *const libc::c_void, 8).try_into().unwrap() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ eventfd: blocking is unsupported + | + = help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support + = note: BACKTRACE: + = note: inside `main` at $DIR/libc_eventfd_write_block.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/pass-dep/libc/libc-eventfd.rs b/src/tools/miri/tests/pass-dep/libc/libc-eventfd.rs new file mode 100644 index 0000000000000..a3567eeb7cb4a --- /dev/null +++ b/src/tools/miri/tests/pass-dep/libc/libc-eventfd.rs @@ -0,0 +1,108 @@ +//@only-target-linux +// test_race depends on a deterministic schedule. +//@compile-flags: -Zmiri-preemption-rate=0 + +use std::thread; + +fn main() { + test_read_write(); + test_race(); +} + +fn read_bytes(fd: i32, buf: &mut [u8; N]) -> i32 { + let res: i32 = unsafe { libc::read(fd, buf.as_mut_ptr().cast(), N).try_into().unwrap() }; + return res; +} + +fn write_bytes(fd: i32, data: [u8; N]) -> i32 { + let res: i32 = + unsafe { libc::write(fd, data.as_ptr() as *const libc::c_void, N).try_into().unwrap() }; + return res; +} + +fn test_read_write() { + let flags = libc::EFD_NONBLOCK | libc::EFD_CLOEXEC; + let fd = unsafe { libc::eventfd(0, flags) }; + let sized_8_data: [u8; 8] = 1_u64.to_ne_bytes(); + // Write 1 to the counter. + let res = write_bytes(fd, sized_8_data); + assert_eq!(res, 8); + + // Read 1 from the counter. + let mut buf: [u8; 8] = [0; 8]; + let res = read_bytes(fd, &mut buf); + // Read returns number of bytes has been read, which is always 8. + assert_eq!(res, 8); + // Check the value of counter read. + let counter = u64::from_ne_bytes(buf); + assert_eq!(counter, 1); + + // After read, the counter is currently 0, read counter 0 should fail with return + // value -1. + let mut buf: [u8; 8] = [0; 8]; + let res = read_bytes(fd, &mut buf); + let e = std::io::Error::last_os_error(); + assert_eq!(e.raw_os_error(), Some(libc::EAGAIN)); + assert_eq!(res, -1); + + // Write with supplied buffer bigger than 8 bytes should be allowed. + let sized_9_data: [u8; 9]; + if cfg!(target_endian = "big") { + // Adjust the data based on the endianness of host system. + sized_9_data = [0, 0, 0, 0, 0, 0, 0, 1, 0]; + } else { + sized_9_data = [1, 0, 0, 0, 0, 0, 0, 0, 0]; + } + let res = write_bytes(fd, sized_9_data); + assert_eq!(res, 8); + + // Read with supplied buffer smaller than 8 bytes should fail with return + // value -1. + let mut buf: [u8; 7] = [1; 7]; + let res = read_bytes(fd, &mut buf); + let e = std::io::Error::last_os_error(); + assert_eq!(e.raw_os_error(), Some(libc::EINVAL)); + assert_eq!(res, -1); + + // Write with supplied buffer smaller than 8 bytes should fail with return + // value -1. + let size_7_data: [u8; 7] = [1; 7]; + let res = write_bytes(fd, size_7_data); + let e = std::io::Error::last_os_error(); + assert_eq!(e.raw_os_error(), Some(libc::EINVAL)); + assert_eq!(res, -1); + + // Read with supplied buffer bigger than 8 bytes should be allowed. + let mut buf: [u8; 9] = [1; 9]; + let res = read_bytes(fd, &mut buf); + assert_eq!(res, 8); + + // Write u64::MAX should fail. + let u64_max_bytes: [u8; 8] = [255; 8]; + let res = write_bytes(fd, u64_max_bytes); + let e = std::io::Error::last_os_error(); + assert_eq!(e.raw_os_error(), Some(libc::EINVAL)); + assert_eq!(res, -1); +} + +fn test_race() { + static mut VAL: u8 = 0; + let flags = libc::EFD_NONBLOCK | libc::EFD_CLOEXEC; + let fd = unsafe { libc::eventfd(0, flags) }; + let thread1 = thread::spawn(move || { + let mut buf: [u8; 8] = [0; 8]; + let res = read_bytes(fd, &mut buf); + // read returns number of bytes has been read, which is always 8. + assert_eq!(res, 8); + let counter = u64::from_ne_bytes(buf); + assert_eq!(counter, 1); + unsafe { assert_eq!(VAL, 1) }; + }); + unsafe { VAL = 1 }; + let data: [u8; 8] = 1_u64.to_ne_bytes(); + let res = write_bytes(fd, data); + // write returns number of bytes written, which is always 8. + assert_eq!(res, 8); + thread::yield_now(); + thread1.join().unwrap(); +} diff --git a/src/tools/miri/tests/pass/drop_in_place.rs b/src/tools/miri/tests/pass/drop_in_place.rs index 0615a43c80003..cac8d76dd9d41 100644 --- a/src/tools/miri/tests/pass/drop_in_place.rs +++ b/src/tools/miri/tests/pass/drop_in_place.rs @@ -6,7 +6,5 @@ use std::ptr; fn main() { let mut not_a_bool = 13u8; - unsafe { - ptr::drop_in_place(&mut not_a_bool as *mut u8 as *mut bool) - }; + unsafe { ptr::drop_in_place(&mut not_a_bool as *mut u8 as *mut bool) }; } diff --git a/src/tools/miri/tests/pass/intrinsics/portable-simd.rs b/src/tools/miri/tests/pass/intrinsics/portable-simd.rs index 248a57d68504d..c4ec45e4bbef9 100644 --- a/src/tools/miri/tests/pass/intrinsics/portable-simd.rs +++ b/src/tools/miri/tests/pass/intrinsics/portable-simd.rs @@ -1,5 +1,5 @@ //@compile-flags: -Zmiri-strict-provenance -#![feature(portable_simd, adt_const_params, core_intrinsics)] +#![feature(portable_simd, adt_const_params, core_intrinsics, repr_simd)] #![allow(incomplete_features, internal_features)] use std::intrinsics::simd as intrinsics; use std::ptr; @@ -318,6 +318,83 @@ fn simd_mask() { assert_eq!(selected1, i32x4::from_array([0, 0, 0, 1])); assert_eq!(selected2, selected1); } + + // Non-power-of-2 multi-byte mask. + #[repr(simd, packed)] + #[allow(non_camel_case_types)] + #[derive(Copy, Clone, Debug, PartialEq)] + struct i32x10([i32; 10]); + impl i32x10 { + fn splat(x: i32) -> Self { + Self([x; 10]) + } + } + unsafe { + let mask = i32x10([!0, !0, 0, !0, 0, 0, !0, 0, !0, 0]); + let mask_bits = if cfg!(target_endian = "little") { 0b0101001011 } else { 0b1101001010 }; + let mask_bytes = + if cfg!(target_endian = "little") { [0b01001011, 0b01] } else { [0b11, 0b01001010] }; + + let bitmask1: u16 = simd_bitmask(mask); + let bitmask2: [u8; 2] = simd_bitmask(mask); + assert_eq!(bitmask1, mask_bits); + assert_eq!(bitmask2, mask_bytes); + + let selected1 = simd_select_bitmask::( + mask_bits, + i32x10::splat(!0), // yes + i32x10::splat(0), // no + ); + let selected2 = simd_select_bitmask::<[u8; 2], _>( + mask_bytes, + i32x10::splat(!0), // yes + i32x10::splat(0), // no + ); + assert_eq!(selected1, mask); + assert_eq!(selected2, mask); + } + + // Test for a mask where the next multiple of 8 is not a power of two. + #[repr(simd, packed)] + #[allow(non_camel_case_types)] + #[derive(Copy, Clone, Debug, PartialEq)] + struct i32x20([i32; 20]); + impl i32x20 { + fn splat(x: i32) -> Self { + Self([x; 20]) + } + } + unsafe { + let mask = i32x20([!0, !0, 0, !0, 0, 0, !0, 0, !0, 0, 0, 0, 0, !0, !0, !0, !0, !0, !0, !0]); + let mask_bits = if cfg!(target_endian = "little") { + 0b11111110000101001011 + } else { + 0b11010010100001111111 + }; + let mask_bytes = if cfg!(target_endian = "little") { + [0b01001011, 0b11100001, 0b1111] + } else { + [0b1101, 0b00101000, 0b01111111] + }; + + let bitmask1: u32 = simd_bitmask(mask); + let bitmask2: [u8; 3] = simd_bitmask(mask); + assert_eq!(bitmask1, mask_bits); + assert_eq!(bitmask2, mask_bytes); + + let selected1 = simd_select_bitmask::( + mask_bits, + i32x20::splat(!0), // yes + i32x20::splat(0), // no + ); + let selected2 = simd_select_bitmask::<[u8; 3], _>( + mask_bytes, + i32x20::splat(!0), // yes + i32x20::splat(0), // no + ); + assert_eq!(selected1, mask); + assert_eq!(selected2, mask); + } } fn simd_cast() { diff --git a/src/tools/miri/tests/pass/shims/env/var.rs b/src/tools/miri/tests/pass/shims/env/var.rs index babaf00578a7a..a576c1fc8bb8c 100644 --- a/src/tools/miri/tests/pass/shims/env/var.rs +++ b/src/tools/miri/tests/pass/shims/env/var.rs @@ -1,3 +1,4 @@ +//@compile-flags: -Zmiri-preemption-rate=0 use std::env; use std::thread; @@ -26,6 +27,8 @@ fn main() { println!("{:#?}", env::vars().collect::>()); // Do things concurrently, to make sure there's no data race. + // We disable preemption to make sure the lock is not contended; + // that means we don't hit e.g. the futex codepath on Android (which we don't support). let t = thread::spawn(|| { env::set_var("MIRI_TEST", "42"); }); diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-pclmulqdq.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-pclmulqdq.rs new file mode 100644 index 0000000000000..2f242dd5379d2 --- /dev/null +++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-pclmulqdq.rs @@ -0,0 +1,48 @@ +// Ignore everything except x86 and x86_64 +// Any new targets that are added to CI should be ignored here. +// (We cannot use `cfg`-based tricks here since the `target-feature` flags below only work on x86.) +//@ignore-target-aarch64 +//@ignore-target-arm +//@ignore-target-avr +//@ignore-target-s390x +//@ignore-target-thumbv7em +//@ignore-target-wasm32 +//@compile-flags: -C target-feature=+pclmulqdq + +#[cfg(target_arch = "x86")] +use std::arch::x86::*; +#[cfg(target_arch = "x86_64")] +use std::arch::x86_64::*; + +fn main() { + assert!(is_x86_feature_detected!("pclmulqdq")); + + let a = (0x7fffffffffffffff, 0x4317e40ab4ddcf05); + let b = (0xdd358416f52ecd34, 0x633d11cc638ca16b); + + unsafe { + assert_eq!(clmulepi64_si128::<0x00>(a, b), (13036940098130298092, 2704901987789626761)); + assert_eq!(clmulepi64_si128::<0x01>(a, b), (6707488474444649956, 3901733953304450635)); + assert_eq!(clmulepi64_si128::<0x10>(a, b), (11607166829323378905, 1191897396234301548)); + assert_eq!(clmulepi64_si128::<0x11>(a, b), (7731954893213347271, 1760130762532070957)); + } +} + +#[target_feature(enable = "pclmulqdq")] +unsafe fn clmulepi64_si128( + (a1, a2): (u64, u64), + (b1, b2): (u64, u64), +) -> (u64, u64) { + // SAFETY: There are no safety requirements for calling `_mm_clmulepi64_si128`. + // It's just unsafe for API consistency with other intrinsics. + unsafe { + let a = core::mem::transmute::<_, __m128i>([a1, a2]); + let b = core::mem::transmute::<_, __m128i>([b1, b2]); + + let out = _mm_clmulepi64_si128::(a, b); + + let [c1, c2] = core::mem::transmute::<_, [u64; 2]>(out); + + (c1, c2) + } +} diff --git a/src/tools/opt-dist/src/training.rs b/src/tools/opt-dist/src/training.rs index 09263dc645e2d..89f4d8957c8bf 100644 --- a/src/tools/opt-dist/src/training.rs +++ b/src/tools/opt-dist/src/training.rs @@ -3,30 +3,10 @@ use crate::exec::{cmd, CmdBuilder}; use crate::utils::io::{count_files, delete_directory}; use crate::utils::with_log_group; use anyhow::Context; +use build_helper::{LLVM_PGO_CRATES, RUSTC_PGO_CRATES}; use camino::{Utf8Path, Utf8PathBuf}; use humansize::BINARY; -const LLVM_PGO_CRATES: &[&str] = &[ - "syn-1.0.89", - "cargo-0.60.0", - "serde-1.0.136", - "ripgrep-13.0.0", - "regex-1.5.5", - "clap-3.1.6", - "hyper-0.14.18", -]; - -const RUSTC_PGO_CRATES: &[&str] = &[ - "externs", - "ctfe-stress-5", - "cargo-0.60.0", - "token-stream-stress", - "match-stress", - "tuple-stress", - "diesel-1.4.8", - "bitmaps-3.1.0", -]; - fn init_compiler_benchmarks( env: &Environment, profiles: &[&str], diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index b17f217c133b8..cea1313e29d75 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -318,38 +318,30 @@ pub fn run_in_tmpdir(callback: F) { } /// Implement common helpers for command wrappers. This assumes that the command wrapper is a struct -/// containing a `cmd: Command` field and a `output` function. The provided helpers are: +/// containing a `cmd: Command` field. The provided helpers are: /// /// 1. Generic argument acceptors: `arg` and `args` (delegated to [`Command`]). These are intended /// to be *fallback* argument acceptors, when specific helpers don't make sense. Prefer to add /// new specific helper methods over relying on these generic argument providers. /// 2. Environment manipulation methods: `env`, `env_remove` and `env_clear`: these delegate to /// methods of the same name on [`Command`]. -/// 3. Output and execution: `output`, `run` and `run_fail` are provided. `output` waits for the -/// command to finish running and returns the process's [`Output`]. `run` and `run_fail` are -/// higher-level convenience methods which waits for the command to finish running and assert -/// that the command successfully ran or failed as expected. Prefer `run` and `run_fail` when -/// possible. +/// 3. Output and execution: `run` and `run_fail` are provided. These are +/// higher-level convenience methods which wait for the command to finish running and assert +/// that the command successfully ran or failed as expected. They return +/// [`CompletedProcess`], which can be used to assert the stdout/stderr/exit code of the executed +/// process. /// /// Example usage: /// /// ```ignore (illustrative) /// struct CommandWrapper { cmd: Command } // <- required `cmd` field /// -/// impl CommandWrapper { -/// /// Get the [`Output`][::std::process::Output] of the finished process. -/// pub fn command_output(&mut self) -> Output { /* ... */ } // <- required `command_output()` method -/// } -/// /// crate::impl_common_helpers!(CommandWrapper); /// /// impl CommandWrapper { /// // ... additional specific helper methods /// } /// ``` -/// -/// [`Command`]: ::std::process::Command -/// [`Output`]: ::std::process::Output macro_rules! impl_common_helpers { ($wrapper: ident) => { impl $wrapper { diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index efcd2a181ffa2..2dd3d17f9e3e7 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -27,7 +27,8 @@ const LICENSES: &[&str] = &[ "MIT OR Zlib OR Apache-2.0", // miniz_oxide "MIT", "MIT/Apache-2.0", - "Unicode-DFS-2016", // tinystr and icu4x + "Unicode-3.0", // icu4x + "Unicode-DFS-2016", // tinystr "Unlicense OR MIT", "Unlicense/MIT", "Zlib OR Apache-2.0 OR MIT", // tinyvec @@ -67,6 +68,7 @@ pub(crate) const WORKSPACES: &[(&str, ExceptionList, Option<(&[&str], &[&str])>) //("src/tools/miri/test-cargo-miri", &[], None), // FIXME uncomment once all deps are vendored //("src/tools/miri/test_dependencies", &[], None), // FIXME uncomment once all deps are vendored ("src/tools/rust-analyzer", EXCEPTIONS_RUST_ANALYZER, None), + ("src/tools/rustc-perf", EXCEPTIONS_RUSTC_PERF, None), ("src/tools/x", &[], None), // tidy-alphabetical-end ]; @@ -142,6 +144,22 @@ const EXCEPTIONS_RUST_ANALYZER: ExceptionList = &[ // tidy-alphabetical-end ]; +const EXCEPTIONS_RUSTC_PERF: ExceptionList = &[ + // tidy-alphabetical-start + ("alloc-no-stdlib", "BSD-3-Clause"), + ("alloc-stdlib", "BSD-3-Clause"), + ("brotli", "BSD-3-Clause/MIT"), + ("brotli-decompressor", "BSD-3-Clause/MIT"), + ("encoding_rs", "(Apache-2.0 OR MIT) AND BSD-3-Clause"), + ("inferno", "CDDL-1.0"), + ("instant", "BSD-3-Clause"), + ("ring", NON_STANDARD_LICENSE), // see EXCEPTIONS_NON_STANDARD_LICENSE_DEPS for more. + ("ryu", "Apache-2.0 OR BSL-1.0"), + ("snap", "BSD-3-Clause"), + ("subtle", "BSD-3-Clause"), + // tidy-alphabetical-end +]; + const EXCEPTIONS_CRANELIFT: ExceptionList = &[ // tidy-alphabetical-start ("cranelift-bforest", "Apache-2.0 WITH LLVM-exception"), @@ -178,6 +196,20 @@ const EXCEPTIONS_UEFI_QEMU_TEST: ExceptionList = &[ ("r-efi", "MIT OR Apache-2.0 OR LGPL-2.1-or-later"), // LGPL is not acceptible, but we use it under MIT OR Apache-2.0 ]; +/// Placeholder for non-standard license file. +const NON_STANDARD_LICENSE: &str = "NON_STANDARD_LICENSE"; + +/// These dependencies have non-standard licenses but are genenrally permitted. +const EXCEPTIONS_NON_STANDARD_LICENSE_DEPS: &[&str] = &[ + // `ring` is included because it is an optional dependency of `hyper`, + // which is a training data in rustc-perf for optimized build. + // The license of it is generally `ISC AND MIT AND OpenSSL`, + // though the `package.license` field is not set. + // + // See https://github.com/briansmith/ring/issues/902 + "ring", +]; + /// These are the root crates that are part of the runtime. The licenses for /// these and all their dependencies *must not* be in the exception list. const RUNTIME_CRATES: &[&str] = &["std", "core", "alloc", "test", "panic_abort", "panic_unwind"]; @@ -411,32 +443,6 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ // tidy-alphabetical-end ]; -// These crates come from ICU4X and are licensed under the unicode license. -// It currently doesn't have an SPDX identifier, so they cannot put one there. -// See https://github.com/unicode-org/icu4x/pull/3875 -// FIXME: This should be removed once ICU4X crates update. -const ICU4X_UNICODE_LICENSE_DEPENDENCIES: &[&str] = &[ - // tidy-alphabetical-start - "icu_list", - "icu_list_data", - "icu_locid", - "icu_locid_transform", - "icu_locid_transform_data", - "icu_provider", - "icu_provider_adapters", - "icu_provider_macros", - "litemap", - "tinystr", - "writeable", - "yoke", - "yoke-derive", - "zerofrom", - "zerofrom-derive", - "zerovec", - "zerovec-derive", - // tidy-alphabetical-end -]; - const PERMITTED_CRANELIFT_DEPENDENCIES: &[&str] = &[ // tidy-alphabetical-start "ahash", @@ -610,6 +616,11 @@ fn check_license_exceptions(metadata: &Metadata, exceptions: &[(&str, &str)], ba for pkg in metadata.packages.iter().filter(|p| p.name == *name) { match &pkg.license { None => { + if *license == NON_STANDARD_LICENSE + && EXCEPTIONS_NON_STANDARD_LICENSE_DEPS.contains(&pkg.name.as_str()) + { + continue; + } tidy_error!( bad, "dependency exception `{}` does not declare a license expression", @@ -642,10 +653,6 @@ fn check_license_exceptions(metadata: &Metadata, exceptions: &[(&str, &str)], ba let license = match &pkg.license { Some(license) => license, None => { - if ICU4X_UNICODE_LICENSE_DEPENDENCIES.contains(&pkg.name.as_str()) { - // See the comment on ICU4X_UNICODE_LICENSE_DEPENDENCIES. - continue; - } tidy_error!(bad, "dependency `{}` does not define a license expression", pkg.id); continue; } diff --git a/src/tools/tidy/src/ext_tool_checks.rs b/src/tools/tidy/src/ext_tool_checks.rs index 40e75d1d3fac1..2c97a39f1008b 100644 --- a/src/tools/tidy/src/ext_tool_checks.rs +++ b/src/tools/tidy/src/ext_tool_checks.rs @@ -320,7 +320,7 @@ fn install_requirements( } let stat = Command::new(py_path) - .args(["-m", "pip", "install", "--require-hashes", "-r"]) + .args(["-m", "pip", "install", "--quiet", "--require-hashes", "-r"]) .arg(src_reqs_path) .status()?; if !stat.success() { diff --git a/src/tools/tidy/src/extdeps.rs b/src/tools/tidy/src/extdeps.rs index ff71ca537256f..2118de5f20411 100644 --- a/src/tools/tidy/src/extdeps.rs +++ b/src/tools/tidy/src/extdeps.rs @@ -4,7 +4,11 @@ use std::fs; use std::path::Path; /// List of allowed sources for packages. -const ALLOWED_SOURCES: &[&str] = &["\"registry+https://github.com/rust-lang/crates.io-index\""]; +const ALLOWED_SOURCES: &[&str] = &[ + r#""registry+https://github.com/rust-lang/crates.io-index""#, + // This is `rust_team_data` used by `site` in src/tools/rustc-perf, + r#""git+https://github.com/rust-lang/team#a5260e76d3aa894c64c56e6ddc8545b9a98043ec""#, +]; /// Checks for external package sources. `root` is the path to the directory that contains the /// workspace `Cargo.toml`. diff --git a/tests/assembly/asm/global_asm.rs b/tests/assembly/asm/global_asm.rs index 8f824563e8ae5..22cf4bdb15b70 100644 --- a/tests/assembly/asm/global_asm.rs +++ b/tests/assembly/asm/global_asm.rs @@ -25,9 +25,9 @@ global_asm!("movl ${}, %ecx", const 5, options(att_syntax)); global_asm!("call {}", sym my_func); // CHECK: lea rax, [rip + MY_STATIC] global_asm!("lea rax, [rip + {}]", sym MY_STATIC); -// CHECK: call _RNvCsddMtV7nAi4C_10global_asm6foobar +// CHECK: call _RNvC[[CRATE_IDENT:[a-zA-Z0-9]{12}]]_10global_asm6foobar global_asm!("call {}", sym foobar); -// CHECK: _RNvCsddMtV7nAi4C_10global_asm6foobar: +// CHECK: _RNvC[[CRATE_IDENT]]_10global_asm6foobar: fn foobar() { loop {} } diff --git a/tests/codegen/consts.rs b/tests/codegen/consts.rs index 93c58c37c2873..42ce7679d1acb 100644 --- a/tests/codegen/consts.rs +++ b/tests/codegen/consts.rs @@ -9,11 +9,11 @@ // CHECK: @STATIC = {{.*}}, align 4 // This checks the constants from inline_enum_const -// CHECK: @alloc_af1f8e8e6f4b341431a1d405e652df2d = {{.*}}, align 2 +// CHECK: @alloc_[[INLINE_ENUM_HASH:[a-f0-9]{32}]] = {{.*}}, align 2 // This checks the constants from {low,high}_align_const, they share the same // constant, but the alignment differs, so the higher one should be used -// CHECK: [[LOW_HIGH:@alloc_[a-f0-9]+]] = {{.*}}, align 4 +// CHECK: [[LOW_HIGH:@alloc_[a-f0-9]{32}]] = {{.*}}, align 4 #[derive(Copy, Clone)] // repr(i16) is required for the {low,high}_align_const test diff --git a/tests/codegen/pattern_type_symbols.rs b/tests/codegen/pattern_type_symbols.rs index dfe8344334870..a99b3efca415b 100644 --- a/tests/codegen/pattern_type_symbols.rs +++ b/tests/codegen/pattern_type_symbols.rs @@ -15,9 +15,9 @@ fn foo() {} pub fn bar() { // CHECK: call pattern_type_symbols::foo:: - // CHECK: call void @_RINvCs3QvG2ESzx2Q_20pattern_type_symbols3foomEB2_ + // CHECK: call void @_RINvC[[CRATE_IDENT:[a-zA-Z0-9]{12}]]_20pattern_type_symbols3foomEB2_ foo::(); // CHECK: call pattern_type_symbols::foo::<(u32, [(); 0], [(); 999999999], [(); true])> - // CHECK: call void @_RINvCs3QvG2ESzx2Q_20pattern_type_symbols3fooTmAum0_Aum3b9ac9ff_Aub1_EEB2_ + // CHECK: call void @_RINvC[[CRATE_IDENT]]_20pattern_type_symbols3fooTmAum0_Aum3b9ac9ff_Aub1_EEB2_ foo::(); } diff --git a/tests/codegen/simd/packed-simd.rs b/tests/codegen/simd/packed-simd.rs index f0911b6e3602a..1df09c96e6cc0 100644 --- a/tests/codegen/simd/packed-simd.rs +++ b/tests/codegen/simd/packed-simd.rs @@ -9,10 +9,11 @@ use core::intrinsics::simd as intrinsics; use core::{mem, ptr}; // Test codegen for not only "packed" but also "fully aligned" SIMD types, and conversion between -// A repr(packed,simd) type with 3 elements can't exceed its element alignment, -// whereas the same type as repr(simd) will instead have padding. +// them. A repr(packed,simd) type with 3 elements can't exceed its element alignment, whereas the +// same type as repr(simd) will instead have padding. #[repr(simd, packed)] +#[derive(Copy, Clone)] pub struct Simd([T; N]); #[repr(simd)] @@ -28,11 +29,11 @@ fn load(v: Simd) -> FullSimd { } } -// CHECK-LABEL: square_packed +// CHECK-LABEL: square_packed_full // CHECK-SAME: ptr{{[a-z_ ]*}} sret([[RET_TYPE:[^)]+]]) [[RET_ALIGN:align (8|16)]]{{[^%]*}} [[RET_VREG:%[_0-9]*]] // CHECK-SAME: ptr{{[a-z_ ]*}} align 4 #[no_mangle] -pub fn square_packed(x: Simd) -> FullSimd { +pub fn square_packed_full(x: Simd) -> FullSimd { // CHECK-NEXT: start // noopt: alloca [[RET_TYPE]], [[RET_ALIGN]] // CHECK: load <3 x float> @@ -42,3 +43,17 @@ pub fn square_packed(x: Simd) -> FullSimd { // CHECK-NEXT: ret void unsafe { intrinsics::simd_mul(x, x) } } + +// CHECK-LABEL: square_packed +// CHECK-SAME: ptr{{[a-z_ ]*}} sret([[RET_TYPE:[^)]+]]) [[RET_ALIGN:align 4]]{{[^%]*}} [[RET_VREG:%[_0-9]*]] +// CHECK-SAME: ptr{{[a-z_ ]*}} align 4 +#[no_mangle] +pub fn square_packed(x: Simd) -> Simd { + // CHECK-NEXT: start + // CHECK-NEXT: load <3 x float> + // noopt-NEXT: load <3 x float> + // CHECK-NEXT: [[VREG:%[a-z0-9_]+]] = fmul <3 x float> + // CHECK-NEXT: store <3 x float> [[VREG]], ptr [[RET_VREG]], [[RET_ALIGN]] + // CHECK-NEXT: ret void + unsafe { intrinsics::simd_mul(x, x) } +} diff --git a/tests/codegen/virtual-function-elimination.rs b/tests/codegen/virtual-function-elimination.rs index 6c391d9114b42..23d7657baa99b 100644 --- a/tests/codegen/virtual-function-elimination.rs +++ b/tests/codegen/virtual-function-elimination.rs @@ -81,7 +81,7 @@ fn taking_u(u: &dyn U) -> i32 { } pub fn taking_v(v: &dyn V) -> i32 { - // CHECK: @llvm.type.checked.load({{.*}}, i32 24, metadata !"NtCs64ITQYi9761_28virtual_function_elimination1V") + // CHECK: @llvm.type.checked.load({{.*}}, i32 24, metadata !"NtC[[CRATE_IDENT:[a-zA-Z0-9]{12}]]_28virtual_function_elimination1V") v.public_function() } @@ -96,5 +96,5 @@ pub fn main() { // CHECK: ![[TYPE0]] = !{i64 0, !"[[MANGLED_TYPE0]]"} // CHECK: ![[VCALL_VIS0]] = !{i64 2} // CHECK: ![[TYPE1]] = !{i64 0, !"[[MANGLED_TYPE1]]"} -// CHECK: ![[TYPE2]] = !{i64 0, !"NtCs64ITQYi9761_28virtual_function_elimination1V"} +// CHECK: ![[TYPE2]] = !{i64 0, !"NtC[[CRATE_IDENT]]_28virtual_function_elimination1V"} // CHECK: ![[VCALL_VIS2]] = !{i64 1} diff --git a/tests/crashes/125655.rs b/tests/crashes/125655.rs new file mode 100644 index 0000000000000..fbf92ca22be7e --- /dev/null +++ b/tests/crashes/125655.rs @@ -0,0 +1,8 @@ +//@ known-bug: rust-lang/rust#125655 + +fn main() { + static foo: dyn Fn() -> u32 = || -> u32 { + ... + 0 + }; +} diff --git a/tests/crashes/125680.rs b/tests/crashes/125680.rs new file mode 100644 index 0000000000000..09f4f318bdddf --- /dev/null +++ b/tests/crashes/125680.rs @@ -0,0 +1,15 @@ +//@ known-bug: rust-lang/rust#125680 +//@ edition:2021 + +#![feature(generic_const_exprs)] + +use core::fmt::Debug; + +struct Inline +where + [(); std::mem::offset_of!((T,), 0)]:, +{} + +fn main() { + let dst = Inline::::new(0); // BANG! +} diff --git a/tests/crashes/125758.rs b/tests/crashes/125758.rs new file mode 100644 index 0000000000000..86c3b80abab9d --- /dev/null +++ b/tests/crashes/125758.rs @@ -0,0 +1,26 @@ +//@ known-bug: rust-lang/rust#125758 +#![feature(impl_trait_in_assoc_type)] + +trait Trait: Sized { + type Assoc2; +} + +impl Trait for Bar { + type Assoc2 = impl std::fmt::Debug; +} + +struct Foo { + field: ::Assoc2, +} + +enum Bar { + C = 42, + D = 99, +} + +static BAR: u8 = 42; + +static FOO2: (&Foo, &::Assoc2) = + unsafe { (std::mem::transmute(&BAR), std::mem::transmute(&BAR)) }; + +fn main() {} diff --git a/tests/crashes/125768.rs b/tests/crashes/125768.rs new file mode 100644 index 0000000000000..3c04431baa0ad --- /dev/null +++ b/tests/crashes/125768.rs @@ -0,0 +1,15 @@ +//@ known-bug: rust-lang/rust#125768 + +#![feature(generic_const_exprs)] + +struct Outer(); +impl Outer +where + [(); A + (B * 2)]:, +{ + fn o() -> Union {} +} + +fn main() { + Outer::<1, 1>::o(); +} diff --git a/tests/crashes/125769.rs b/tests/crashes/125769.rs new file mode 100644 index 0000000000000..da19458f7ca71 --- /dev/null +++ b/tests/crashes/125769.rs @@ -0,0 +1,14 @@ +//@ known-bug: rust-lang/rust#125769 + +#![feature(generic_const_exprs)] + +trait Trait {} + +struct HasCastInTraitImpl; +impl Trait for HasCastInTraitImpl {} + +pub fn use_trait_impl() { + fn assert_impl() {} + + assert_impl::>(); +} diff --git a/tests/crashes/125772.rs b/tests/crashes/125772.rs new file mode 100644 index 0000000000000..2965cfc9e7c3c --- /dev/null +++ b/tests/crashes/125772.rs @@ -0,0 +1,17 @@ +//@ known-bug: rust-lang/rust#125772 +//@ only-x86_64 +#![feature(generic_const_exprs)] + +struct Outer(); +impl Outer +where + [(); A + (B * 2)]:, +{ + fn i() -> Self { + Self + } +} + +fn main() { + Outer::<1, 1>::o(); +} diff --git a/tests/crashes/125799.rs b/tests/crashes/125799.rs new file mode 100644 index 0000000000000..62d5438b4e400 --- /dev/null +++ b/tests/crashes/125799.rs @@ -0,0 +1,22 @@ +//@ known-bug: rust-lang/rust#125799 +//@ only-x86_64 + +trait Trait { + type Assoc; +} + +impl Trait for Vec { + type Assoc = (); +} + +impl Trait for Vec {} + +const BAR: as Trait>::Assoc = 3; + +pub fn main() { + let x: isize = 3; + let _ = match x { + BAR => 2, + _ => 3, + }; +} diff --git a/tests/crashes/125801.rs b/tests/crashes/125801.rs new file mode 100644 index 0000000000000..aaa76bd0ba699 --- /dev/null +++ b/tests/crashes/125801.rs @@ -0,0 +1,20 @@ +//@ known-bug: rust-lang/rust#125801 + +#![feature(generic_const_exprs)] +#![allow(incomplete_features)] + +trait Foo { + type Output; +} + +impl Foo for [u8; 3] { + type Output = [u8; 3]; +} + +static A: <[u8; N] as Foo>::Output = [1, 2, 3]; + +fn main() { + || { + let _ = A[1]; + }; +} diff --git a/tests/crashes/125810.rs b/tests/crashes/125810.rs new file mode 100644 index 0000000000000..4a152da8ddf34 --- /dev/null +++ b/tests/crashes/125810.rs @@ -0,0 +1,10 @@ +//@ known-bug: rust-lang/rust#125810 +#![feature(arbitrary_self_types, dispatch_from_dyn)] + +use std::ops::{Deref, DispatchFromDyn}; + +trait Trait + DispatchFromDyn> { + fn MONO_BUF(self: T) -> dyn Trait; +} + +fn main() {} diff --git a/tests/crashes/125811.rs b/tests/crashes/125811.rs new file mode 100644 index 0000000000000..eb764e8d15228 --- /dev/null +++ b/tests/crashes/125811.rs @@ -0,0 +1,34 @@ +//@ known-bug: rust-lang/rust#125811 +mod assert { + use std::mem::{Assume, BikeshedIntrinsicFrom}; + + pub fn is_transmutable() + where + Dst: BikeshedIntrinsicFrom, + { + } +} + +#[repr(C)] +struct Zst; + +enum V0 { + B(!), +} + +enum V2 { + V = 2, +} + +enum Lopsided { + Smol(Zst), + Lorg(V0), +} + +#[repr(C)] +#[repr(C)] +struct Dst(Lopsided, V2); + +fn should_pad_variants() { + assert::is_transmutable::(); +} diff --git a/tests/crashes/125841.rs b/tests/crashes/125841.rs new file mode 100644 index 0000000000000..e2e61071f1df9 --- /dev/null +++ b/tests/crashes/125841.rs @@ -0,0 +1,14 @@ +//@ known-bug: rust-lang/rust#125841 +#![feature(non_lifetime_binders)] +fn take(id: impl for Fn(T) -> T) { + id(0); + id(""); +} + +fn take2() -> impl for Fn(T) -> T { + |x| x +} + +fn main() { + take(|x| take2) +} diff --git a/tests/crashes/125843.rs b/tests/crashes/125843.rs new file mode 100644 index 0000000000000..8b9a3913c7e62 --- /dev/null +++ b/tests/crashes/125843.rs @@ -0,0 +1,4 @@ +//@ known-bug: rust-lang/rust#125843 +#![feature(non_lifetime_binders)] +trait v0<> {} +fn kind :(v3main impl for v0<'_, v2 = impl v0 + '_>) {} diff --git a/tests/crashes/125874.rs b/tests/crashes/125874.rs new file mode 100644 index 0000000000000..6a2713cd7c896 --- /dev/null +++ b/tests/crashes/125874.rs @@ -0,0 +1,22 @@ +//@ known-bug: rust-lang/rust#125874 +pub trait A {} + +pub trait Mirror { + type Assoc: ?Sized; +} +impl Mirror for dyn A { + type Assoc = T; +} + +struct Bar { + foo: ::Assoc, +} + +pub fn main() { + let strct = Bar { foo: 3 }; + + match strct { + Bar { foo: 1, .. } => {} + _ => (), + }; +} diff --git a/tests/crashes/125879.rs b/tests/crashes/125879.rs new file mode 100644 index 0000000000000..4318842e45518 --- /dev/null +++ b/tests/crashes/125879.rs @@ -0,0 +1,18 @@ +//@ known-bug: rust-lang/rust#125879 +#![feature(inherent_associated_types)] +#![allow(incomplete_features)] + +pub type PubAlias0 = PubTy::PrivAssocTy; + +pub struct PubTy; +impl PubTy { + type PrivAssocTy = (); +} + +pub struct S(pub PubAlias0); + +pub unsafe fn foo(a: S) -> S { + a +} + +fn main() {} diff --git a/tests/crashes/125881.rs b/tests/crashes/125881.rs new file mode 100644 index 0000000000000..98331d3c97484 --- /dev/null +++ b/tests/crashes/125881.rs @@ -0,0 +1,8 @@ +//@ known-bug: rust-lang/rust#125881 +#![crate_type = "lib"] +#![feature(transmutability)] +#![feature(unboxed_closures,effects)] + +const fn test() -> impl std::mem::BikeshedIntrinsicFrom() { + || {} +} diff --git a/tests/crashes/125888.rs b/tests/crashes/125888.rs new file mode 100644 index 0000000000000..ae8f2d6576b74 --- /dev/null +++ b/tests/crashes/125888.rs @@ -0,0 +1,17 @@ +//@ known-bug: rust-lang/rust#125888 +enum NestedEnum { + First, + Second, +} + +enum Enum { + Variant(*const &'a ()), +} + +fn foo(x: Enum) { + match x { + Enum::Variant(NestedEnum::Second) => {} + } +} + +fn main() {} diff --git a/tests/crashes/125914.rs b/tests/crashes/125914.rs new file mode 100644 index 0000000000000..77ccb9fb0978d --- /dev/null +++ b/tests/crashes/125914.rs @@ -0,0 +1,20 @@ +//@ known-bug: rust-lang/rust#125914 +enum AstKind<'ast> { + ExprInt, +} + +enum Foo { + Bar(isize), + Baz, +} + +enum Other { + Other1(Foo), + Other2(AstKind), +} + +fn main() { + match Other::Other1(Foo::Baz) { + ::Other::Other2(::Foo::Bar(..)) => {} + } +} diff --git a/tests/crashes/125957.rs b/tests/crashes/125957.rs new file mode 100644 index 0000000000000..e3abe5262eb90 --- /dev/null +++ b/tests/crashes/125957.rs @@ -0,0 +1,20 @@ +//@ known-bug: rust-lang/rust#125957 +#![feature(generic_const_exprs)] +#![allow(incomplete_features)] +#![feature(associated_const_equality)] + +pub struct Equal(); + +pub enum ParseMode { + Raw, +} +pub trait Parse { + const PARSE_MODE: ParseMode; +} +pub trait RenderRaw: Parse {} + +trait GenericVec { + fn unwrap() -> dyn RenderRaw; +} + +fn main() {} diff --git a/tests/crashes/125992.rs b/tests/crashes/125992.rs new file mode 100644 index 0000000000000..d78f28ce6de41 --- /dev/null +++ b/tests/crashes/125992.rs @@ -0,0 +1,19 @@ +//@ known-bug: rust-lang/rust#125992 +//@ compile-flags: -Zpolonius=next + +#![feature(inherent_associated_types)] + +type Function = for<'a> fn(&'a i32) -> S<'a>::P; + +struct S<'a>(&'a ()); + +impl<'a> S { + type P = &'a i32; +} + +fn ret_ref_local<'e>() -> &'e i32 { + let f: Function = |x| x; + + let local = 0; + f(&local) +} diff --git a/tests/mir-opt/gvn.casts_before_aggregate_raw_ptr.GVN.panic-abort.diff b/tests/mir-opt/gvn.casts_before_aggregate_raw_ptr.GVN.panic-abort.diff new file mode 100644 index 0000000000000..6e5bdb16595be --- /dev/null +++ b/tests/mir-opt/gvn.casts_before_aggregate_raw_ptr.GVN.panic-abort.diff @@ -0,0 +1,60 @@ +- // MIR for `casts_before_aggregate_raw_ptr` before GVN ++ // MIR for `casts_before_aggregate_raw_ptr` after GVN + + fn casts_before_aggregate_raw_ptr(_1: *const u32) -> *const [u8] { + debug x => _1; + let mut _0: *const [u8]; + let _2: *const [u8; 4]; + let mut _3: *const u32; + let mut _5: *const [u8; 4]; + let mut _7: *const u8; + let mut _8: *const (); + scope 1 { + debug x => _2; + let _4: *const u8; + scope 2 { + debug x => _4; + let _6: *const (); + scope 3 { + debug x => _6; + } + } + } + + bb0: { +- StorageLive(_2); ++ nop; + StorageLive(_3); + _3 = _1; +- _2 = move _3 as *const [u8; 4] (PtrToPtr); ++ _2 = _1 as *const [u8; 4] (PtrToPtr); + StorageDead(_3); +- StorageLive(_4); ++ nop; + StorageLive(_5); + _5 = _2; +- _4 = move _5 as *const u8 (PtrToPtr); ++ _4 = _1 as *const u8 (PtrToPtr); + StorageDead(_5); +- StorageLive(_6); ++ nop; + StorageLive(_7); + _7 = _4; +- _6 = move _7 as *const () (PtrToPtr); ++ _6 = _1 as *const () (PtrToPtr); + StorageDead(_7); + StorageLive(_8); + _8 = _6; +- _0 = *const [u8] from (move _8, const 4_usize); ++ _0 = *const [u8] from (_1, const 4_usize); + StorageDead(_8); +- StorageDead(_6); +- StorageDead(_4); +- StorageDead(_2); ++ nop; ++ nop; ++ nop; + return; + } + } + diff --git a/tests/mir-opt/gvn.casts_before_aggregate_raw_ptr.GVN.panic-unwind.diff b/tests/mir-opt/gvn.casts_before_aggregate_raw_ptr.GVN.panic-unwind.diff new file mode 100644 index 0000000000000..6e5bdb16595be --- /dev/null +++ b/tests/mir-opt/gvn.casts_before_aggregate_raw_ptr.GVN.panic-unwind.diff @@ -0,0 +1,60 @@ +- // MIR for `casts_before_aggregate_raw_ptr` before GVN ++ // MIR for `casts_before_aggregate_raw_ptr` after GVN + + fn casts_before_aggregate_raw_ptr(_1: *const u32) -> *const [u8] { + debug x => _1; + let mut _0: *const [u8]; + let _2: *const [u8; 4]; + let mut _3: *const u32; + let mut _5: *const [u8; 4]; + let mut _7: *const u8; + let mut _8: *const (); + scope 1 { + debug x => _2; + let _4: *const u8; + scope 2 { + debug x => _4; + let _6: *const (); + scope 3 { + debug x => _6; + } + } + } + + bb0: { +- StorageLive(_2); ++ nop; + StorageLive(_3); + _3 = _1; +- _2 = move _3 as *const [u8; 4] (PtrToPtr); ++ _2 = _1 as *const [u8; 4] (PtrToPtr); + StorageDead(_3); +- StorageLive(_4); ++ nop; + StorageLive(_5); + _5 = _2; +- _4 = move _5 as *const u8 (PtrToPtr); ++ _4 = _1 as *const u8 (PtrToPtr); + StorageDead(_5); +- StorageLive(_6); ++ nop; + StorageLive(_7); + _7 = _4; +- _6 = move _7 as *const () (PtrToPtr); ++ _6 = _1 as *const () (PtrToPtr); + StorageDead(_7); + StorageLive(_8); + _8 = _6; +- _0 = *const [u8] from (move _8, const 4_usize); ++ _0 = *const [u8] from (_1, const 4_usize); + StorageDead(_8); +- StorageDead(_6); +- StorageDead(_4); +- StorageDead(_2); ++ nop; ++ nop; ++ nop; + return; + } + } + diff --git a/tests/mir-opt/gvn.meta_of_ref_to_slice.GVN.panic-abort.diff b/tests/mir-opt/gvn.meta_of_ref_to_slice.GVN.panic-abort.diff new file mode 100644 index 0000000000000..73dbabb56b353 --- /dev/null +++ b/tests/mir-opt/gvn.meta_of_ref_to_slice.GVN.panic-abort.diff @@ -0,0 +1,32 @@ +- // MIR for `meta_of_ref_to_slice` before GVN ++ // MIR for `meta_of_ref_to_slice` after GVN + + fn meta_of_ref_to_slice(_1: *const i32) -> usize { + debug x => _1; + let mut _0: usize; + let _2: *const [i32]; + let mut _3: *const i32; + let mut _4: *const [i32]; + scope 1 { + debug ptr => _2; + } + + bb0: { +- StorageLive(_2); ++ nop; + StorageLive(_3); + _3 = _1; +- _2 = *const [i32] from (move _3, const 1_usize); ++ _2 = *const [i32] from (_1, const 1_usize); + StorageDead(_3); + StorageLive(_4); + _4 = _2; +- _0 = PtrMetadata(move _4); ++ _0 = const 1_usize; + StorageDead(_4); +- StorageDead(_2); ++ nop; + return; + } + } + diff --git a/tests/mir-opt/gvn.meta_of_ref_to_slice.GVN.panic-unwind.diff b/tests/mir-opt/gvn.meta_of_ref_to_slice.GVN.panic-unwind.diff new file mode 100644 index 0000000000000..73dbabb56b353 --- /dev/null +++ b/tests/mir-opt/gvn.meta_of_ref_to_slice.GVN.panic-unwind.diff @@ -0,0 +1,32 @@ +- // MIR for `meta_of_ref_to_slice` before GVN ++ // MIR for `meta_of_ref_to_slice` after GVN + + fn meta_of_ref_to_slice(_1: *const i32) -> usize { + debug x => _1; + let mut _0: usize; + let _2: *const [i32]; + let mut _3: *const i32; + let mut _4: *const [i32]; + scope 1 { + debug ptr => _2; + } + + bb0: { +- StorageLive(_2); ++ nop; + StorageLive(_3); + _3 = _1; +- _2 = *const [i32] from (move _3, const 1_usize); ++ _2 = *const [i32] from (_1, const 1_usize); + StorageDead(_3); + StorageLive(_4); + _4 = _2; +- _0 = PtrMetadata(move _4); ++ _0 = const 1_usize; + StorageDead(_4); +- StorageDead(_2); ++ nop; + return; + } + } + diff --git a/tests/mir-opt/gvn.rs b/tests/mir-opt/gvn.rs index 315377e4356f7..720018f112e5a 100644 --- a/tests/mir-opt/gvn.rs +++ b/tests/mir-opt/gvn.rs @@ -783,6 +783,39 @@ fn non_freeze(x: T) { } } +// Check that we can const-prop into `from_raw_parts` +fn slice_const_length(x: &[i32]) -> *const [i32] { + // CHECK-LABEL: fn slice_const_length( + // CHECK: _0 = *const [i32] from ({{_[0-9]+}}, const 123_usize); + let ptr = x.as_ptr(); + let len = 123; + std::intrinsics::aggregate_raw_ptr(ptr, len) +} + +fn meta_of_ref_to_slice(x: *const i32) -> usize { + // CHECK-LABEL: fn meta_of_ref_to_slice + // CHECK: _0 = const 1_usize + let ptr: *const [i32] = std::intrinsics::aggregate_raw_ptr(x, 1); + std::intrinsics::ptr_metadata(ptr) +} + +fn slice_from_raw_parts_as_ptr(x: *const u16, n: usize) -> (*const u16, *const f32) { + // CHECK-LABEL: fn slice_from_raw_parts_as_ptr + // CHECK: _8 = _1 as *const f32 (PtrToPtr); + // CHECK: _0 = (_1, move _8); + let ptr: *const [u16] = std::intrinsics::aggregate_raw_ptr(x, n); + (ptr as *const u16, ptr as *const f32) +} + +fn casts_before_aggregate_raw_ptr(x: *const u32) -> *const [u8] { + // CHECK-LABEL: fn casts_before_aggregate_raw_ptr + // CHECK: _0 = *const [u8] from (_1, const 4_usize); + let x = x as *const [u8; 4]; + let x = x as *const u8; + let x = x as *const (); + std::intrinsics::aggregate_raw_ptr(x, 4) +} + fn main() { subexpression_elimination(2, 4, 5); wrap_unwrap(5); @@ -807,6 +840,9 @@ fn main() { wide_ptr_integer(); borrowed(5); non_freeze(5); + slice_const_length(&[1]); + meta_of_ref_to_slice(&42); + slice_from_raw_parts_as_ptr(&123, 456); } #[inline(never)] @@ -840,3 +876,7 @@ fn identity(x: T) -> T { // EMIT_MIR gvn.wide_ptr_integer.GVN.diff // EMIT_MIR gvn.borrowed.GVN.diff // EMIT_MIR gvn.non_freeze.GVN.diff +// EMIT_MIR gvn.slice_const_length.GVN.diff +// EMIT_MIR gvn.meta_of_ref_to_slice.GVN.diff +// EMIT_MIR gvn.slice_from_raw_parts_as_ptr.GVN.diff +// EMIT_MIR gvn.casts_before_aggregate_raw_ptr.GVN.diff diff --git a/tests/mir-opt/gvn.slice_const_length.GVN.panic-abort.diff b/tests/mir-opt/gvn.slice_const_length.GVN.panic-abort.diff new file mode 100644 index 0000000000000..fd5fa035d816c --- /dev/null +++ b/tests/mir-opt/gvn.slice_const_length.GVN.panic-abort.diff @@ -0,0 +1,48 @@ +- // MIR for `slice_const_length` before GVN ++ // MIR for `slice_const_length` after GVN + + fn slice_const_length(_1: &[i32]) -> *const [i32] { + debug x => _1; + let mut _0: *const [i32]; + let _2: *const i32; + let mut _3: &[i32]; + let mut _5: *const i32; + let mut _6: usize; + scope 1 { + debug ptr => _2; + let _4: usize; + scope 2 { + debug len => _4; + } + } + + bb0: { +- StorageLive(_2); ++ nop; + StorageLive(_3); + _3 = &(*_1); + _2 = core::slice::::as_ptr(move _3) -> [return: bb1, unwind unreachable]; + } + + bb1: { + StorageDead(_3); +- StorageLive(_4); ++ nop; + _4 = const 123_usize; + StorageLive(_5); + _5 = _2; + StorageLive(_6); +- _6 = _4; +- _0 = *const [i32] from (move _5, move _6); ++ _6 = const 123_usize; ++ _0 = *const [i32] from (_2, const 123_usize); + StorageDead(_6); + StorageDead(_5); +- StorageDead(_4); +- StorageDead(_2); ++ nop; ++ nop; + return; + } + } + diff --git a/tests/mir-opt/gvn.slice_const_length.GVN.panic-unwind.diff b/tests/mir-opt/gvn.slice_const_length.GVN.panic-unwind.diff new file mode 100644 index 0000000000000..98945cf9724db --- /dev/null +++ b/tests/mir-opt/gvn.slice_const_length.GVN.panic-unwind.diff @@ -0,0 +1,48 @@ +- // MIR for `slice_const_length` before GVN ++ // MIR for `slice_const_length` after GVN + + fn slice_const_length(_1: &[i32]) -> *const [i32] { + debug x => _1; + let mut _0: *const [i32]; + let _2: *const i32; + let mut _3: &[i32]; + let mut _5: *const i32; + let mut _6: usize; + scope 1 { + debug ptr => _2; + let _4: usize; + scope 2 { + debug len => _4; + } + } + + bb0: { +- StorageLive(_2); ++ nop; + StorageLive(_3); + _3 = &(*_1); + _2 = core::slice::::as_ptr(move _3) -> [return: bb1, unwind continue]; + } + + bb1: { + StorageDead(_3); +- StorageLive(_4); ++ nop; + _4 = const 123_usize; + StorageLive(_5); + _5 = _2; + StorageLive(_6); +- _6 = _4; +- _0 = *const [i32] from (move _5, move _6); ++ _6 = const 123_usize; ++ _0 = *const [i32] from (_2, const 123_usize); + StorageDead(_6); + StorageDead(_5); +- StorageDead(_4); +- StorageDead(_2); ++ nop; ++ nop; + return; + } + } + diff --git a/tests/mir-opt/gvn.slice_from_raw_parts_as_ptr.GVN.panic-abort.diff b/tests/mir-opt/gvn.slice_from_raw_parts_as_ptr.GVN.panic-abort.diff new file mode 100644 index 0000000000000..75bcd2a8d72cf --- /dev/null +++ b/tests/mir-opt/gvn.slice_from_raw_parts_as_ptr.GVN.panic-abort.diff @@ -0,0 +1,51 @@ +- // MIR for `slice_from_raw_parts_as_ptr` before GVN ++ // MIR for `slice_from_raw_parts_as_ptr` after GVN + + fn slice_from_raw_parts_as_ptr(_1: *const u16, _2: usize) -> (*const u16, *const f32) { + debug x => _1; + debug n => _2; + let mut _0: (*const u16, *const f32); + let _3: *const [u16]; + let mut _4: *const u16; + let mut _5: usize; + let mut _6: *const u16; + let mut _7: *const [u16]; + let mut _8: *const f32; + let mut _9: *const [u16]; + scope 1 { + debug ptr => _3; + } + + bb0: { +- StorageLive(_3); ++ nop; + StorageLive(_4); + _4 = _1; + StorageLive(_5); + _5 = _2; +- _3 = *const [u16] from (move _4, move _5); ++ _3 = *const [u16] from (_1, _2); + StorageDead(_5); + StorageDead(_4); + StorageLive(_6); + StorageLive(_7); + _7 = _3; +- _6 = move _7 as *const u16 (PtrToPtr); ++ _6 = _1; + StorageDead(_7); + StorageLive(_8); + StorageLive(_9); + _9 = _3; +- _8 = move _9 as *const f32 (PtrToPtr); ++ _8 = _1 as *const f32 (PtrToPtr); + StorageDead(_9); +- _0 = (move _6, move _8); ++ _0 = (_1, move _8); + StorageDead(_8); + StorageDead(_6); +- StorageDead(_3); ++ nop; + return; + } + } + diff --git a/tests/mir-opt/gvn.slice_from_raw_parts_as_ptr.GVN.panic-unwind.diff b/tests/mir-opt/gvn.slice_from_raw_parts_as_ptr.GVN.panic-unwind.diff new file mode 100644 index 0000000000000..75bcd2a8d72cf --- /dev/null +++ b/tests/mir-opt/gvn.slice_from_raw_parts_as_ptr.GVN.panic-unwind.diff @@ -0,0 +1,51 @@ +- // MIR for `slice_from_raw_parts_as_ptr` before GVN ++ // MIR for `slice_from_raw_parts_as_ptr` after GVN + + fn slice_from_raw_parts_as_ptr(_1: *const u16, _2: usize) -> (*const u16, *const f32) { + debug x => _1; + debug n => _2; + let mut _0: (*const u16, *const f32); + let _3: *const [u16]; + let mut _4: *const u16; + let mut _5: usize; + let mut _6: *const u16; + let mut _7: *const [u16]; + let mut _8: *const f32; + let mut _9: *const [u16]; + scope 1 { + debug ptr => _3; + } + + bb0: { +- StorageLive(_3); ++ nop; + StorageLive(_4); + _4 = _1; + StorageLive(_5); + _5 = _2; +- _3 = *const [u16] from (move _4, move _5); ++ _3 = *const [u16] from (_1, _2); + StorageDead(_5); + StorageDead(_4); + StorageLive(_6); + StorageLive(_7); + _7 = _3; +- _6 = move _7 as *const u16 (PtrToPtr); ++ _6 = _1; + StorageDead(_7); + StorageLive(_8); + StorageLive(_9); + _9 = _3; +- _8 = move _9 as *const f32 (PtrToPtr); ++ _8 = _1 as *const f32 (PtrToPtr); + StorageDead(_9); +- _0 = (move _6, move _8); ++ _0 = (_1, move _8); + StorageDead(_8); + StorageDead(_6); +- StorageDead(_3); ++ nop; + return; + } + } + diff --git a/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-abort.mir index 2c6d93e10c11e..2f6139712ffc1 100644 --- a/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-abort.mir @@ -12,8 +12,7 @@ fn demo_byte_add_fat(_1: *const [u32], _2: usize) -> *const [u32] { scope 3 (inlined std::ptr::const_ptr::::add) { } scope 4 (inlined std::ptr::const_ptr::::with_metadata_of::<[u32]>) { - let mut _5: *const (); - let mut _6: usize; + let mut _5: usize; scope 5 (inlined std::ptr::metadata::<[u32]>) { } scope 6 (inlined std::ptr::from_raw_parts::<[u32], ()>) { @@ -28,11 +27,8 @@ fn demo_byte_add_fat(_1: *const [u32], _2: usize) -> *const [u32] { _4 = Offset(_3, _2); StorageDead(_3); StorageLive(_5); - _5 = _4 as *const () (PtrToPtr); - StorageLive(_6); - _6 = PtrMetadata(_1); - _0 = *const [u32] from (_5, _6); - StorageDead(_6); + _5 = PtrMetadata(_1); + _0 = *const [u32] from (_4, _5); StorageDead(_5); StorageDead(_4); return; diff --git a/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-unwind.mir index 2c6d93e10c11e..2f6139712ffc1 100644 --- a/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-unwind.mir @@ -12,8 +12,7 @@ fn demo_byte_add_fat(_1: *const [u32], _2: usize) -> *const [u32] { scope 3 (inlined std::ptr::const_ptr::::add) { } scope 4 (inlined std::ptr::const_ptr::::with_metadata_of::<[u32]>) { - let mut _5: *const (); - let mut _6: usize; + let mut _5: usize; scope 5 (inlined std::ptr::metadata::<[u32]>) { } scope 6 (inlined std::ptr::from_raw_parts::<[u32], ()>) { @@ -28,11 +27,8 @@ fn demo_byte_add_fat(_1: *const [u32], _2: usize) -> *const [u32] { _4 = Offset(_3, _2); StorageDead(_3); StorageLive(_5); - _5 = _4 as *const () (PtrToPtr); - StorageLive(_6); - _6 = PtrMetadata(_1); - _0 = *const [u32] from (_5, _6); - StorageDead(_6); + _5 = PtrMetadata(_1); + _0 = *const [u32] from (_4, _5); StorageDead(_5); StorageDead(_4); return; diff --git a/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_thin.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_thin.PreCodegen.after.panic-abort.mir index 04fb6b838f024..8d47e63eff2ac 100644 --- a/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_thin.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_thin.PreCodegen.after.panic-abort.mir @@ -20,11 +20,13 @@ fn demo_byte_add_thin(_1: *const u32, _2: usize) -> *const u32 { } bb0: { + StorageLive(_4); StorageLive(_3); _3 = _1 as *const u8 (PtrToPtr); _4 = Offset(_3, _2); StorageDead(_3); _0 = _4 as *const u32 (PtrToPtr); + StorageDead(_4); return; } } diff --git a/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_thin.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_thin.PreCodegen.after.panic-unwind.mir index 04fb6b838f024..8d47e63eff2ac 100644 --- a/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_thin.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_thin.PreCodegen.after.panic-unwind.mir @@ -20,11 +20,13 @@ fn demo_byte_add_thin(_1: *const u32, _2: usize) -> *const u32 { } bb0: { + StorageLive(_4); StorageLive(_3); _3 = _1 as *const u8 (PtrToPtr); _4 = Offset(_3, _2); StorageDead(_3); _0 = _4 as *const u32 (PtrToPtr); + StorageDead(_4); return; } } diff --git a/tests/run-make-fulldeps/README.md b/tests/run-make-fulldeps/README.md deleted file mode 100644 index dd1788390220f..0000000000000 --- a/tests/run-make-fulldeps/README.md +++ /dev/null @@ -1,4 +0,0 @@ -If this directory is empty, Git won't create it, and compiletest will complain -that it can't find a nonexistent test suite directory. - -FIXME(#126111): Remove `run-make-fulldeps` from bootstrap. diff --git a/tests/run-make/README.md b/tests/run-make/README.md new file mode 100644 index 0000000000000..a6c1b4b7db76a --- /dev/null +++ b/tests/run-make/README.md @@ -0,0 +1,43 @@ +# The `run-make` test suite + +The `run-make` test suite contains tests which are the most flexible out of all +the [rust-lang/rust](https://github.com/rust-lang/rust) test suites. `run-make` +tests can basically contain arbitrary code, and are supported by the +[`run_make_support`] library. + +## Infrastructure + +There are two kinds of run-make tests: + +1. The new `rmake.rs` version: this allows run-make tests to be written in Rust + (with `rmake.rs` as the main test file). +2. The legacy `Makefile` version: this is what run-make tests were written with + before support for `rmake.rs` was introduced. + +The implementation for collecting and building the `rmake.rs` recipes (or +`Makefile`s) are in +[`src/tools/compiletest/src/runtest.rs`](../../src/tools/compiletest/src/runtest.rs), +in `run_rmake_v2_test` and `run_rmake_legacy_test`. + +### Rust-based `run-make` tests: `rmake.rs` + +The setup for the `rmake.rs` version is a 3-stage process: + +1. First, we build the [`run_make_support`] library in bootstrap as a tool lib. +2. Then, we compile the `rmake.rs` "recipe" linking the support library and its + dependencies in, and provide a bunch of env vars. We setup a directory + structure within `build//test/run-make/` + + ``` + / + rmake.exe # recipe binary + rmake_out/ # sources from test sources copied over + ``` + + and copy non-`rmake.rs` input support files over to `rmake_out/`. The + support library is made available as an [*extern prelude*][extern_prelude]. +3. Finally, we run the recipe binary and set `rmake_out/` as the working + directory. + +[`run_make_support`]: ../../src/tools/run-make-support +[extern_prelude]: https://doc.rust-lang.org/reference/names/preludes.html#extern-prelude diff --git a/tests/run-make/issue-88756-default-output/output-default.stdout b/tests/run-make/issue-88756-default-output/output-default.stdout index 12c1b389fb340..bc38d9e9dc6b3 100644 --- a/tests/run-make/issue-88756-default-output/output-default.stdout +++ b/tests/run-make/issue-88756-default-output/output-default.stdout @@ -157,6 +157,8 @@ Options: Comma separated list of types of output for rustdoc to emit --no-run Compile doctests without running them + --remap-path-prefix FROM=TO + Remap source names in compiler messages --show-type-layout Include the memory layout of types in the docs --nocapture Don't capture stdout and stderr of tests diff --git a/tests/rustdoc-js/underscoredtype.js b/tests/rustdoc-js/underscoredtype.js new file mode 100644 index 0000000000000..06e3b07b0960c --- /dev/null +++ b/tests/rustdoc-js/underscoredtype.js @@ -0,0 +1,62 @@ +const EXPECTED = [ + { + 'query': 'pid_t', + 'correction': null, + 'proposeCorrectionFrom': null, + 'proposeCorrectionTo': null, + 'others': [ + { 'path': 'underscoredtype::unix', 'name': 'pid_t' }, + ], + 'returned': [ + { 'path': 'underscoredtype::unix', 'name': 'set_pid' }, + ], + 'returned': [ + { 'path': 'underscoredtype::unix', 'name': 'get_pid' }, + ], + }, + { + 'query': 'pidt', + 'correction': 'pid_t', + 'proposeCorrectionFrom': null, + 'proposeCorrectionTo': null, + 'others': [ + { 'path': 'underscoredtype::unix', 'name': 'pid_t' }, + ], + 'returned': [ + { 'path': 'underscoredtype::unix', 'name': 'set_pid' }, + ], + 'returned': [ + { 'path': 'underscoredtype::unix', 'name': 'get_pid' }, + ], + }, + { + 'query': 'unix::pid_t', + 'correction': null, + 'proposeCorrectionFrom': null, + 'proposeCorrectionTo': null, + 'others': [ + { 'path': 'underscoredtype::unix', 'name': 'pid_t' }, + ], + 'returned': [ + { 'path': 'underscoredtype::unix', 'name': 'set_pid' }, + ], + 'returned': [ + { 'path': 'underscoredtype::unix', 'name': 'get_pid' }, + ], + }, + { + 'query': 'unix::pidt', + 'correction': 'pid_t', + 'proposeCorrectionFrom': null, + 'proposeCorrectionTo': null, + 'others': [ + { 'path': 'underscoredtype::unix', 'name': 'pid_t' }, + ], + 'returned': [ + { 'path': 'underscoredtype::unix', 'name': 'set_pid' }, + ], + 'returned': [ + { 'path': 'underscoredtype::unix', 'name': 'get_pid' }, + ], + }, +]; diff --git a/tests/rustdoc-js/underscoredtype.rs b/tests/rustdoc-js/underscoredtype.rs new file mode 100644 index 0000000000000..83c532cf855dd --- /dev/null +++ b/tests/rustdoc-js/underscoredtype.rs @@ -0,0 +1,8 @@ +pub mod unix { + #[allow(non_camel_case_types)] + pub type pid_t = i32; + pub fn get_pid() -> pid_t { + 0 + } + pub fn set_pid(_: pid_t) {} +} diff --git a/tests/rustdoc-ui/remap-path-prefix-failed-doctest-output.rs b/tests/rustdoc-ui/remap-path-prefix-failed-doctest-output.rs new file mode 100644 index 0000000000000..2b220370d77aa --- /dev/null +++ b/tests/rustdoc-ui/remap-path-prefix-failed-doctest-output.rs @@ -0,0 +1,14 @@ +// FIXME: if/when the output of the test harness can be tested on its own, this test should be +// adapted to use that, and that normalize line can go away + +//@ failure-status: 101 +//@ compile-flags:--test -Z unstable-options --remap-path-prefix={{src-base}}=remapped_path --test-args --test-threads=1 +//@ rustc-env:RUST_BACKTRACE=0 +//@ normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME" +//@ normalize-stdout-test "exit (status|code): 101" -> "exit status: 101" + +// doctest fails at runtime +/// ``` +/// panic!("oh no"); +/// ``` +pub struct SomeStruct; diff --git a/tests/rustdoc-ui/remap-path-prefix-failed-doctest-output.stdout b/tests/rustdoc-ui/remap-path-prefix-failed-doctest-output.stdout new file mode 100644 index 0000000000000..2102e2c389184 --- /dev/null +++ b/tests/rustdoc-ui/remap-path-prefix-failed-doctest-output.stdout @@ -0,0 +1,21 @@ + +running 1 test +test remapped_path/remap-path-prefix-failed-doctest-output.rs - SomeStruct (line 11) ... FAILED + +failures: + +---- remapped_path/remap-path-prefix-failed-doctest-output.rs - SomeStruct (line 11) stdout ---- +Test executable failed (exit status: 101). + +stderr: +thread 'main' panicked at remapped_path/remap-path-prefix-failed-doctest-output.rs:3:1: +oh no +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace + + + +failures: + remapped_path/remap-path-prefix-failed-doctest-output.rs - SomeStruct (line 11) + +test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/tests/rustdoc-ui/remap-path-prefix-invalid-doctest.rs b/tests/rustdoc-ui/remap-path-prefix-invalid-doctest.rs new file mode 100644 index 0000000000000..2e023e32d7a7b --- /dev/null +++ b/tests/rustdoc-ui/remap-path-prefix-invalid-doctest.rs @@ -0,0 +1,13 @@ +// FIXME: if/when the output of the test harness can be tested on its own, this test should be +// adapted to use that, and that normalize line can go away + +//@ failure-status: 101 +//@ compile-flags:--test -Z unstable-options --remap-path-prefix={{src-base}}=remapped_path --test-args --test-threads=1 +//@ rustc-env:RUST_BACKTRACE=0 +//@ normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME" + +// doctest fails to compile +/// ``` +/// this is not real code +/// ``` +pub struct SomeStruct; diff --git a/tests/rustdoc-ui/remap-path-prefix-invalid-doctest.stdout b/tests/rustdoc-ui/remap-path-prefix-invalid-doctest.stdout new file mode 100644 index 0000000000000..a05b51699894b --- /dev/null +++ b/tests/rustdoc-ui/remap-path-prefix-invalid-doctest.stdout @@ -0,0 +1,22 @@ + +running 1 test +test remapped_path/remap-path-prefix-invalid-doctest.rs - SomeStruct (line 10) ... FAILED + +failures: + +---- remapped_path/remap-path-prefix-invalid-doctest.rs - SomeStruct (line 10) stdout ---- +error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `is` + --> remapped_path/remap-path-prefix-invalid-doctest.rs:11:6 + | +LL | this is not real code + | ^^ expected one of 8 possible tokens + +error: aborting due to 1 previous error + +Couldn't compile the test. + +failures: + remapped_path/remap-path-prefix-invalid-doctest.rs - SomeStruct (line 10) + +test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/tests/rustdoc-ui/remap-path-prefix-passed-doctest-output.rs b/tests/rustdoc-ui/remap-path-prefix-passed-doctest-output.rs new file mode 100644 index 0000000000000..c58f3faeb5323 --- /dev/null +++ b/tests/rustdoc-ui/remap-path-prefix-passed-doctest-output.rs @@ -0,0 +1,14 @@ +//@ check-pass +//@ check-run-results + +// FIXME: if/when the output of the test harness can be tested on its own, this test should be +// adapted to use that, and that normalize line can go away + +//@ compile-flags:--test -Z unstable-options --remap-path-prefix={{src-base}}=remapped_path --test-args --test-threads=1 +//@ normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME" + +// doctest passes at runtime +/// ``` +/// assert!(true); +/// ``` +pub struct SomeStruct; diff --git a/tests/rustdoc-ui/remap-path-prefix-passed-doctest-output.stdout b/tests/rustdoc-ui/remap-path-prefix-passed-doctest-output.stdout new file mode 100644 index 0000000000000..8ffb569488563 --- /dev/null +++ b/tests/rustdoc-ui/remap-path-prefix-passed-doctest-output.stdout @@ -0,0 +1,6 @@ + +running 1 test +test remapped_path/remap-path-prefix-passed-doctest-output.rs - SomeStruct (line 11) ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/tests/ui/feature-gates/feature-gate-extern_prelude.rs b/tests/ui/feature-gates/feature-gate-extern_prelude.rs deleted file mode 100644 index 237099e790107..0000000000000 --- a/tests/ui/feature-gates/feature-gate-extern_prelude.rs +++ /dev/null @@ -1 +0,0 @@ -can-only-test-this-in-run-make-fulldeps //~ ERROR expected one of `!` or `::`, found `-` diff --git a/tests/ui/feature-gates/feature-gate-extern_prelude.stderr b/tests/ui/feature-gates/feature-gate-extern_prelude.stderr deleted file mode 100644 index 3b0ffae869653..0000000000000 --- a/tests/ui/feature-gates/feature-gate-extern_prelude.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: expected one of `!` or `::`, found `-` - --> $DIR/feature-gate-extern_prelude.rs:1:4 - | -LL | can-only-test-this-in-run-make-fulldeps - | ^ expected one of `!` or `::` - -error: aborting due to 1 previous error - diff --git a/tests/ui/feature-gates/feature-gate-offset-of-slice.rs b/tests/ui/feature-gates/feature-gate-offset-of-slice.rs new file mode 100644 index 0000000000000..23e8668bc685e --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-offset-of-slice.rs @@ -0,0 +1,26 @@ +use std::mem::offset_of; + +struct S { + a: u8, + b: (u8, u8), + c: [i32], +} + +struct T { + x: i32, + y: S, +} + +type Tup = (i32, [i32]); + +fn main() { + offset_of!(S, c); //~ ERROR size for values of type `[i32]` cannot be known at compilation time +} + +fn other() { + offset_of!(T, y); //~ ERROR size for values of type `[i32]` cannot be known at compilation time +} + +fn tuple() { + offset_of!(Tup, 1); //~ ERROR size for values of type `[i32]` cannot be known at compilation time +} diff --git a/tests/ui/feature-gates/feature-gate-offset-of-slice.stderr b/tests/ui/feature-gates/feature-gate-offset-of-slice.stderr new file mode 100644 index 0000000000000..5cf34a897f4d7 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-offset-of-slice.stderr @@ -0,0 +1,35 @@ +error[E0277]: the size for values of type `[i32]` cannot be known at compilation time + --> $DIR/feature-gate-offset-of-slice.rs:17:5 + | +LL | offset_of!(S, c); + | ^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[i32]` + = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[i32]` cannot be known at compilation time + --> $DIR/feature-gate-offset-of-slice.rs:21:5 + | +LL | offset_of!(T, y); + | ^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: within `S`, the trait `Sized` is not implemented for `[i32]`, which is required by `S: Sized` +note: required because it appears within the type `S` + --> $DIR/feature-gate-offset-of-slice.rs:3:8 + | +LL | struct S { + | ^ + = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[i32]` cannot be known at compilation time + --> $DIR/feature-gate-offset-of-slice.rs:25:5 + | +LL | offset_of!(Tup, 1); + | ^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[i32]` + = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/higher-ranked/trait-bounds/rigid-equate-projections-in-higher-ranked-fn-signature.next.stderr b/tests/ui/higher-ranked/trait-bounds/rigid-equate-projections-in-higher-ranked-fn-signature.next.stderr new file mode 100644 index 0000000000000..14a3d5e178d43 --- /dev/null +++ b/tests/ui/higher-ranked/trait-bounds/rigid-equate-projections-in-higher-ranked-fn-signature.next.stderr @@ -0,0 +1,9 @@ +error[E0284]: type annotations needed: cannot satisfy `for<'a> <_ as Trait<'a>>::Assoc <: >::Assoc` + --> $DIR/rigid-equate-projections-in-higher-ranked-fn-signature.rs:27:50 + | +LL | let _: for<'a> fn(<_ as Trait<'a>>::Assoc) = foo::(); + | ^^^^^^^^^^ cannot satisfy `for<'a> <_ as Trait<'a>>::Assoc <: >::Assoc` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0284`. diff --git a/tests/ui/higher-ranked/trait-bounds/rigid-equate-projections-in-higher-ranked-fn-signature.rs b/tests/ui/higher-ranked/trait-bounds/rigid-equate-projections-in-higher-ranked-fn-signature.rs new file mode 100644 index 0000000000000..10dbc2a4a825c --- /dev/null +++ b/tests/ui/higher-ranked/trait-bounds/rigid-equate-projections-in-higher-ranked-fn-signature.rs @@ -0,0 +1,30 @@ +//@ revisions: current next +//@[current] check-pass +//@[next] compile-flags: -Znext-solver +//@[next] check-fail +//@ ignore-compare-mode-next-solver (explicit revisions) + +/// This triggers an ICE with (and without) `--emit metadata` using the old +/// trait solver: +/// ``` +/// rustc +nightly-2023-01-09 \ +/// tests/ui/higher-ranked/trait-bounds/rigid-equate-projections-in-higher-ranked-fn-signature.rs +/// ``` +/// The ICE was unknowingly fixed by +/// in `nightly-2023-01-10`. +/// This is a regression test for that fixed ICE. For the next solver we simply +/// make sure there is a compiler error. + +trait Trait<'a> { + type Assoc; +} + +fn foo Trait<'a>>() -> for<'a> fn(>::Assoc) { + todo!() +} + +fn bar Trait<'a>>() { + let _: for<'a> fn(<_ as Trait<'a>>::Assoc) = foo::(); //[next]~ ERROR type annotations needed +} + +fn main() {} diff --git a/tests/ui/offset-of/offset-of-dst-field.rs b/tests/ui/offset-of/offset-of-dst-field.rs index 016ebfadd1420..5ae15f323577f 100644 --- a/tests/ui/offset-of/offset-of-dst-field.rs +++ b/tests/ui/offset-of/offset-of-dst-field.rs @@ -49,3 +49,7 @@ fn delta() { fn generic_with_maybe_sized() -> usize { offset_of!(Delta, z) //~ ERROR the size for values of type } + +fn illformed_tuple() { + offset_of!(([u8], u8), 1); //~ ERROR the size for values of type +} diff --git a/tests/ui/offset-of/offset-of-dst-field.stderr b/tests/ui/offset-of/offset-of-dst-field.stderr index adfd16c6f2b98..bcfe796897e0c 100644 --- a/tests/ui/offset-of/offset-of-dst-field.stderr +++ b/tests/ui/offset-of/offset-of-dst-field.stderr @@ -81,6 +81,15 @@ LL - fn generic_with_maybe_sized() -> usize { LL + fn generic_with_maybe_sized() -> usize { | -error: aborting due to 8 previous errors +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> $DIR/offset-of-dst-field.rs:54:16 + | +LL | offset_of!(([u8], u8), 1); + | ^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` + = note: only the last element of a tuple may have a dynamically sized type + +error: aborting due to 9 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/offset-of/offset-of-slice.rs b/tests/ui/offset-of/offset-of-slice.rs new file mode 100644 index 0000000000000..a0fe3198f6869 --- /dev/null +++ b/tests/ui/offset-of/offset-of-slice.rs @@ -0,0 +1,26 @@ +//@run-pass +#![feature(offset_of_slice, offset_of_nested)] + +use std::mem::offset_of; + +#[repr(C)] +struct S { + a: u8, + b: (u8, u8), + c: [i32], +} + +#[repr(C)] +struct T { + x: i8, + y: S, +} + +type Tup = (i16, [i32]); + +fn main() { + assert_eq!(offset_of!(S, c), 4); + assert_eq!(offset_of!(T, y), 4); + assert_eq!(offset_of!(T, y.c), 8); + assert_eq!(offset_of!(Tup, 1), 4); +} diff --git a/triagebot.toml b/triagebot.toml index 55f63ef2567c1..3abff0f1c784e 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -429,6 +429,12 @@ trigger_files = [ "tests/ui/stack-protector" ] +[autolabel."A-run-make"] +trigger_files = [ + "tests/run-make", + "src/tools/run-make-support" +] + [notify-zulip."I-prioritize"] zulip_stream = 245100 # #t-compiler/wg-prioritization/alerts topic = "#{number} {title}" @@ -684,7 +690,13 @@ message = "Some changes occurred in GUI tests." cc = ["@GuillaumeGomez"] [mentions."tests/run-make/"] -message = "Some changes occurred in run-make tests." +message = """ +This PR modifies `tests/run-make/`. If this PR is trying to port a Makefile +run-make test to use rmake.rs, please update the +[run-make port tracking issue](https://github.com/rust-lang/rust/issues/121876) +so we can track our progress. You can either modify the tracking issue +directly, or you can comment on the tracking issue and link this PR. +""" cc = ["@jieyouxu"] [mentions."src/librustdoc/html/static/css/themes/ayu.css"]